@@ -4261,97 +4261,138 @@ export class ObjectStackProtocolImplementation implements
42614261 }
42624262
42634263 /**
4264- * [#8038] The `__search` half of {@link governServedItem}'s presence
4265- * convergence — the third stamp in the same family, and the one the
4266- * module-level function cannot carry on its own .
4264+ * [#8268, generalising # 8038] The REGISTRY-SIDE half of
4265+ * {@link governServedItem}'s presence convergence: replay the registry's
4266+ * object-materialization seam onto the served body .
42674267 *
42684268 * `applyInjectedSystemColumns` (#6562) converges the columns whose
42694269 * membership is a pure function of the document
42704270 * (`resolveInjectedSystemColumns`), so it needs nothing but the body. The
4271- * search companion is DEPLOYMENT-gated: `SchemaRegistry` provisions it at
4272- * the object-materialization seam only when its own `searchCompanion` flag
4271+ * materialization stamps are not like that. `__search` is DEPLOYMENT-gated
4272+ * (`SchemaRegistry` provisions it only when its own `searchCompanion` flag
42734273 * is on, and that flag is `options.searchCompanion ??
4274- * resolveSearchPinyinEnabled()` — a host may set it explicitly. So the
4275- * answer has to come from the registry that made the decision, which is why
4276- * this is a method here and a `provisionSearchCompanionOnto` there, exactly
4277- * as {@link foldObjectExtendersFromRegistry} is a method here and a
4274+ * resolveSearchPinyinEnabled()`, which a host may set explicitly), and the
4275+ * ADR-0079 `nameField` designation must match the answer THAT registry
4276+ * reached over THAT object's contributors. So the answer has to come from
4277+ * the registry that made the decision, which is why this is a method here
4278+ * and a `materializeServedObjectOnto` there, exactly as
4279+ * {@link foldObjectExtendersFromRegistry} is a method here and a
42784280 * `foldObjectExtendersOnto` there (#7556).
42794281 *
4282+ * ⛔ It asks for the WHOLE seam, deliberately, and this is the point of
4283+ * #8268 rather than an implementation detail. Three stamps of one seam —
4284+ * #6562's injected system columns, #8038's `__search`, #8268's `nameField`
4285+ * — diverged on this exact read path and were found, filed and fixed ONE AT
4286+ * A TIME, because each convergence reached for one named stamp. A stamp
4287+ * added to `materializeBaseLayer` now arrives here already converged, with
4288+ * no fourth method and no fourth card.
4289+ *
42804290 * Applied AFTER `governServedItem` at each exit, because the registry
4281- * provisions the companion after `applySystemFields` too: the source field
4282- * is resolved by `resolveDisplayField` over the POST-injection field set,
4283- * so injecting first is what makes this pass and the registry's own answer
4284- * the same answer rather than two independent guesses.
4291+ * materializes after `applySystemFields` too: the title is resolved by
4292+ * `resolveDisplayField` over the POST-injection field set, so injecting
4293+ * first is what makes this pass and the registry's own answer the same
4294+ * answer rather than two independent guesses.
42854295 *
42864296 * No-op for every type but `object`, and — via the registry — for a
42874297 * deployment with companions off, an object with no eligible display field,
4288- * and a body that already carries the column (every registry-backed read,
4298+ * and a body already carrying every stamp (every registry-backed read,
42894299 * which is the majority path this converges the minority onto).
42904300 */
4291- private provisionSearchCompanionFromRegistry <T>(type: string, body: T): T {
4301+ private materializeFromRegistry <T>(type: string, body: T): T {
42924302 if (canonicalMetaType(type) !== 'object') return body;
42934303 if (body === null || typeof body !== 'object') return body;
42944304 const registry = (this.engine as any)?.registry;
42954305 // Partial registry doubles in tests predate this method; a host that
4296- // cannot answer the gate answers exactly as it did before.
4297- if (!registry || typeof registry.provisionSearchCompanionOnto !== 'function') return body;
4298- try {
4299- return registry.provisionSearchCompanionOnto(body) as T;
4300- } catch {
4301- // A read over an in-memory flag and the body's own fields; a failure
4302- // here must not turn a served schema into a 5xx.
4303- return body;
4306+ // cannot answer the gate answers exactly as it did before. The
4307+ // `provisionSearchCompanionOnto` fallback keeps a double that was
4308+ // written against #8038's narrower seam serving what it served then,
4309+ // rather than silently losing the companion convergence to a rename.
4310+ if (registry && typeof registry.materializeServedObjectOnto === 'function') {
4311+ try {
4312+ return registry.materializeServedObjectOnto(body) as T;
4313+ } catch {
4314+ // A read over an in-memory flag, the registry's own resolved
4315+ // answer and the body's own fields; a failure here must not turn
4316+ // a served schema into a 5xx.
4317+ return body;
4318+ }
4319+ }
4320+ if (registry && typeof registry.provisionSearchCompanionOnto === 'function') {
4321+ try {
4322+ return registry.provisionSearchCompanionOnto(body) as T;
4323+ } catch {
4324+ return body;
4325+ }
43044326 }
4327+ return body;
43054328 }
43064329
43074330 /**
4308- * {@link governServedItem} plus the deployment -gated half it cannot reach
4309- * ({@link provisionSearchCompanionFromRegistry }) — the whole of what a
4310- * `/meta` READ EXIT owes an object document. Every call site of the free
4311- * function that is a read exit goes through this instead; the one call site
4312- * that is not — `getMetaItemLayered`'s `code` / `overlay` layers, which are
4313- * deliberately raw — never called it in the first place (#6562 ruling
4314- * constraint 1, #7556's boundary).
4331+ * {@link governServedItem} plus the registry -gated half it cannot reach
4332+ * ({@link materializeFromRegistry }) — the whole of what a `/meta` READ EXIT
4333+ * owes an object document. Every call site of the free function that is a
4334+ * read exit goes through this instead; the one call site that is not —
4335+ * `getMetaItemLayered`'s `code` / `overlay` layers, which are deliberately
4336+ * raw — never called it in the first place (#6562 ruling constraint 1,
4337+ * #7556's boundary).
43154338 */
43164339 private governServedObject<T>(type: string, item: T): T {
4317- return this.provisionSearchCompanionFromRegistry (type, governServedItem(type, item));
4340+ return this.materializeFromRegistry (type, governServedItem(type, item));
43184341 }
43194342
43204343 /**
4321- * [#8038] The write-side counterpart of
4322- * {@link provisionSearchCompanionFromRegistry }, owed for the reason
4344+ * [#8268, generalising # 8038] The write-side counterpart of
4345+ * {@link materializeFromRegistry }, owed for the reason
43234346 * {@link stripServedSystemColumns} is owed one field family over: the write
43244347 * path persists the request body verbatim (ADR-0005 §Validation), so a
4325- * document this service's read added the companion to would otherwise be
4326- * handed straight back and stored carrying it.
4348+ * document this service's read added a stamp to would otherwise be handed
4349+ * straight back and stored carrying it.
43274350 *
43284351 * Measured on the runtime-created object path — the write door type
43294352 * `object` has open by default, an artifact-backed object refusing the save
43304353 * outright with `NOT_OVERRIDABLE` — the stored row went from
43314354 * `fields: [name]` to `fields: [__search, name]` on a single GET → PUT
4332- * before this was added.
4355+ * before #8038 added the companion half, and gained a `nameField` the
4356+ * author never wrote on the same round trip before #8268 added the title
4357+ * half. The landed `#4326` round-trip pin catches either omission, which is
4358+ * why the read half and this half must move together.
4359+ *
4360+ * ⛔ Asks the registry for the WHOLE seam's inverse rather than for one
4361+ * named stamp — the same reason {@link materializeFromRegistry} does.
43334362 */
4334- private stripSearchCompanionFromRegistry <T>(type: string, item: T): T {
4363+ private stripMaterializedFromRegistry <T>(type: string, item: T): T {
43354364 if (canonicalMetaType(type) !== 'object') return item;
43364365 if (item === null || typeof item !== 'object') return item;
43374366 const registry = (this.engine as any)?.registry;
4338- if (!registry || typeof registry.stripProvisionedSearchCompanionFrom !== 'function') return item;
4339- try {
4340- return registry.stripProvisionedSearchCompanionFrom(item) as T;
4341- } catch {
4342- // A read over the body's own fields; a failure here must not turn a
4343- // save into a 5xx.
4344- return item;
4367+ // Partial registry doubles in tests predate this method; the narrower
4368+ // #8038 spelling keeps such a host stripping what it stripped before
4369+ // rather than silently losing the companion strip to a rename.
4370+ if (registry && typeof registry.stripMaterializedStampsFrom === 'function') {
4371+ try {
4372+ return registry.stripMaterializedStampsFrom(item) as T;
4373+ } catch {
4374+ // A read over the body's own fields; a failure here must not
4375+ // turn a save into a 5xx.
4376+ return item;
4377+ }
43454378 }
4379+ if (registry && typeof registry.stripProvisionedSearchCompanionFrom === 'function') {
4380+ try {
4381+ return registry.stripProvisionedSearchCompanionFrom(item) as T;
4382+ } catch {
4383+ return item;
4384+ }
4385+ }
4386+ return item;
43464387 }
43474388
43484389 /**
4349- * {@link stripServedSystemColumns} plus the companion half
4350- * ({@link stripSearchCompanionFromRegistry }) — the whole of what the write
4390+ * {@link stripServedSystemColumns} plus the registry-seam half
4391+ * ({@link stripMaterializedFromRegistry }) — the whole of what the write
43514392 * path owes {@link governServedObject}.
43524393 */
43534394 private stripServedObjectColumns<T>(type: string, item: T): T {
4354- return this.stripSearchCompanionFromRegistry (type, stripServedSystemColumns(type, item));
4395+ return this.stripMaterializedFromRegistry (type, stripServedSystemColumns(type, item));
43554396 }
43564397
43574398 /**
0 commit comments