Skip to content

Commit 4893a2f

Browse files
refactor(metadata-protocol): move the registry materialize/strip pair out of protocol.ts into protocol-registry-materialize.ts (#25467 cut 11) (#25797)
<!-- claude-projects-attribution: {"github_login":"os-project-manager"} --> _Requested by **Leehom** · [project thread](https://claude.ai/code/project/chan_01TenzsRopZj4jMbvjX8uz1X?thread=cmsg_01TenzsRopZj4jMbvjX8uz1X1aK1TeYpi6AVkN7j6eFxUU)_ Part of #25467 Clause-②: no Metadata-protocol: none Ruling-ref: 6270097840 Cut 11 of the `protocol.ts` split (#24586 ruling A, recorded in `6270097840`). Cuts 1–10 landed as #25494, #25518, #25538, #25589, #25601, #25623, #25642, #25719, #25731 and #25740. The claim is `6397346543`; the scope is the registry materialize/strip group the cut 10 report (`6393303455`) proposed from Release `6385903828`, as the server seat approved it in its dispatch order. Four `ObjectStackProtocolImplementation` members move unedited into a new module, `packages/metadata-protocol/src/protocol-registry-materialize.ts` (#23050 shape B, one `engine` getter). `protocol.ts` loses 22 net lines (29,791 to 29,769). The cut is move-only, and the card stays open for later cuts. Branch `claude/project-thread-f0qmfa` is the harness-pinned branch for this thread. It names no issue, so the claim comment is the identity record. It holds one commit, `f081d777`, on `main` `0790d0a469` (cut 10's merge `2c86039515` is in its history). **Serial with the file's in-flight PRs.** Measured just before this PR was opened: none of the 12 open PRs touches `packages/metadata-protocol/src/` (each file list read in full; the release PR #25640's 226 files include the package's `CHANGELOG.md` and `package.json` only). `git log 0790d0a..origin/main` is empty at that moment. ## What moves | Member | Base line | Visibility | AST tokens (type params + params + return + body) | |---|---|---|---| | `materializeFromRegistry` | `:9071` | private | 119 | | `governServedObject` | `:9109` | private | 28 | | `stripMaterializedFromRegistry` | `:9134` | private | 119 | | `stripServedObjectColumns` | `:9165` | private | 28 | ## The shape (#23050 shape B, as cuts 1–10 apply it) - **The class keeps every member** with its name, docblock, signature and position. Each body is now one host literal plus a `.call`, marked `[#25467 cut 11]`. - **Typing.** `RegistryMaterializeHost` types every member as the class member itself (an indexed access on `ObjectStackProtocolImplementation`). Each moved function keeps the method's type parameter `T` and types its `this` as the `Pick` of the host over exactly the members its body reads. Each stub annotates its literal as `ThisParameterType` of `typeof fn`. No cast, and no member changes visibility. - **One new spelling, forced by the generics.** The four members are generic (`T` in, `T` out). `Function.prototype.call` on a generic function erases `T` to `unknown`, which `tsc` rejects against the method's declared `T` return (TS2322). So each stub instantiates the function first: the stub calls `.call` on the parenthesised instantiation expression of the function at `T` (`tsc` refuses an instantiation expression followed directly by a property access, TS1477, hence the parentheses). The emitted JavaScript is a plain `.call(host, …)`; cuts 1–10 moved no generic member, so no earlier cut needed it. - **Members read.** `materializeFromRegistry` and `stripMaterializedFromRegistry` read the field `engine`, handed over as a GETTER so the read happens when the body makes it (tests replace `engine` on a constructed protocol). `governServedObject` calls `materializeFromRegistry` and `stripServedObjectColumns` calls `stripMaterializedFromRegistry`, each through a late-bound closure on the protocol. No private-static member, and nothing on the Release's stay list. **The order's hypothesis holds.** - **Every other caller still calls the class method**: the five `governServedObject` read exits (one in `readFlattenedMetaItems`, three in `readMetaItem`, one on `getMetaItemLayered`'s effective layer) and the one `stripServedObjectColumns` write site in `saveMetaItem`. ## Module-level declarations, by reader - **Two gain `export`, none moves.** The bodies read three module-level functions of `protocol.ts`: `canonicalMetaType` (already exported), and `governServedItem` and `stripServedSystemColumns`, which gain `export` in place, as cut 8 exported `permissionSetOwnerBindingRefusal` and `runtimeHookWithoutBodyRefusal`. The new module imports all three from `protocol.js`; the cycle is evaluation-safe because each is read only inside a function body. `index.ts` names what it publishes from `protocol.ts` one by one, so the published surface does not move (measured below). - **Measured, not assumed:** after the move, the two exported helpers have no caller left in `protocol.ts`; the moved bodies were their only callers at base too. They stay there because the class's read and write paths cite them by name in prose (for example the `getMetaItemLayered` comment on why `governServedItem` never runs on `overlay`). Moving them is noted below, not done here. - **Imports in `protocol.ts`.** No import loses its last reader. The one new statement is the import of the new module. ## The published `.d.ts` The series bar is ruling `6348891160`, sorted-union identity, measured first. Base `0790d0a469` and head `f081d777` were built with `pnpm --filter @objectstack/metadata-protocol build` against one dependency tree (the closure built once at head, then the package's `src/` swapped tree-only to base for the base build and restored from `HEAD` under a trap; `git diff HEAD` empty and `git status` clean after, both blobs equal to `HEAD`'s). - **Raw sha256**: `325970c1661efaa6a3762ce7de9e6bb205ea16099784f2b6c5950d62d175b331` at base and at head, on both `dist/index.d.ts` and `dist/index.d.cts`, 772,838 bytes each (the hash cuts 8–10 reported). `cmp` exits 0 on both pairs. **Raw identity holds**, so sorted-union identity holds too. The four members are private, so each stays a `private NAME;` line. - **Normalised sha256**: `9562749edf7b8bba67ed2f1779799a68b3d6934a8605074934572d9507c55ba6` at both ends (109 string-literal union runs sorted; this run's own normaliser). - **The two builds differ where they should**: `index.js` hashes `b99c5148b08d3fc5…` at base (cut 10's head hash) and `bbe1a227b80604e0…` at head; the four functions' `.call(` sites occur 0 times in the base bundles and 4 times in the head bundles (ESM and CJS alike). - **Positive control** on the head tree (on disk, restored from `HEAD` under a trap, hash equal to `HEAD`'s after): `private` dropped from `stripServedObjectColumns` and the package rebuilt. Both `.d.ts` files move to `06884ae21a4b72b4…` and print the member's full generic signature (type parameter `T`, then `(type: string, item: T): T;`), so the bar can see a change on this member. - **Export tables.** The ESM and CJS bundles, loaded at runtime from the package, each export the same 78 names at base and head; the sorted list hashes to `9f18a0177ac736ed…` on all four. None of the moved functions, the two newly exported helpers or the host type appears. No changeset: `skip-changeset`, per ruling `6348891160`. ## Proof of move-only - **Bodies, by AST token** (the TypeScript compiler's AST leaf tokens, JSDoc skipped, over type parameters, parameters less the added `this`, return type and body): 294 tokens compared, **0 differ**. The type-parameter, parameter, return-type and body text, comments included, is also equal with whitespace collapsed, for all four. Negative control: one changed token in `stripMaterializedFromRegistry`'s body (`item === null` to `item !== null`, on a copy) makes the check report `differ=1`. - **Class side.** 299 members at base and at head, in the same order. The 295 that did not move are byte-identical to base, leading comments included. Each of the 4 stubs sits at its base position and keeps its docblock and signature byte-identical. - **Top level of `protocol.ts`.** 236 of the 238 base statements other than the class are byte-identical, leading comments included. The other two are `governServedItem` and `stripServedSystemColumns`, which gain the `export` keyword and nothing else. Head adds one statement, the new module's import. - **Size.** +165 / −53 over 2 files, 218 changed lines. `protocol-registry-materialize.ts` has 134 lines. ## Readers of the moved lines Every test and script that reads `protocol.ts` by path, and every test file in `packages/` and `scripts/`, was grepped for the four member names, for `governServedItem` and `stripServedSystemColumns`, and for the four registry seam names the bodies call (`materializeServedObjectOnto`, `provisionSearchCompanionOnto`, `stripMaterializedStampsFrom`, `stripProvisionedSearchCompanionFrom`). - **No by-path reader.** Outside `protocol.ts` the member names occur only in prose: `metadata-diagnostics.ts` (a comment naming `governServedObject`'s docblock), two `CHANGELOG.md` entries, and comments in `packages/objectql` and `packages/rest` tests. No gate, baseline or ADR anchor names them. - **The partial-registry-double fallbacks.** Six test files name the seam methods: `packages/objectql/src/protocol-meta-effective-schema.test.ts`, `registry-deployment-platform-global.test.ts`, `registry-tenant-index-author-declared-column.test.ts`, `registry-tenant-index-follows-wall.test.ts`, `meta-object-primary-designation-roundtrip.test.ts`, and `packages/rest/src/meta-object-materialization-agreement.test.ts`. Each builds the protocol over a REAL `SchemaRegistry` (which defines all four seam methods, `packages/objectql/src/registry.ts`) or calls the registry directly; none reads `protocol.ts` by path, and none builds a double that answers only the narrower `provisionSearchCompanionOnto` / `stripProvisionedSearchCompanionFrom` spelling. Verdict: the fallback arms move verbatim and no in-repo test reaches them (see Acceptance notes). At head, those six files plus `meta-object-search-companion-roundtrip.test.ts` pass: objectql 6 files / 57 tests, rest 1 file / 12 tests, each `VERDICT command-exit 0`. - **Bracketed-refusal pin** (`PRODUCERS`): no row owed. The four bodies hold no `new Error(` (0 by count in base lines 9032–9167); `protocol.ts` keeps its 74 such sites. - **ADR anchors and decision letters.** `check-adr-anchors` exits 0 at both ends with **identical output**: 85 anchored files, 52,707 citations across 6,638 files, **1,846 → 1,846** decision-letter citations. The `protocol.ts` anchor file names none of the four members, and the moved bodies are not the mechanism of any entry paragraph, so the new module gets no entry. - **Durability checker** (`check-durability-degradation-log-level --list`): identical at both ends once `[@:][0-9]+` is stripped (159 lines). The gate exits 0 at both ends with identical output. The moved `try`/`catch` arms wrap registry seam calls, not storage reads, so neither rule reads them. - **Engine-double contract** (`check-engine-double-contract`): exits 0 at both ends. The `updateData`/`deleteData` seams keep their entries at new line numbers (14044 → 14022, 14069 → 14047). `productionFiles` is 3,690 at base and 3,692 at head: +1 is the new file, +1 is the gitignored `packages/spec/src/migrations/registry.ts`, which the spec build writes in the head tree and the clean base tree had not built. - **Identical output at both ends:** `check-adr-symbol-anchors`, `check-system-context-census`, `check-tenant-audit-census`, `check-query-options-erasure-ratchet`, `check-filter-alias-parity`. `check-nul-bytes` differs only in the scanned file count, +1. The base-end readings were taken in a clean detached worktree at `0790d0a469`. - **Platform checklist.** `check-platform-checklist --changed-from origin/main`: OK, 29 anchors judged, 0 lost. - **Governed surface.** `check-governed-merges --branch claude/project-thread-f0qmfa`: 0 of 2 paths hit the register, NOT governed; 218 changed lines, under the 3,000-line human-merge bar. ## Verification All at head `f081d777`. - `tsc --noEmit` in `packages/metadata-protocol` exits 0. `pnpm exec eslint --no-inline-config` on the two changed files exits 0, no output. - **`packages/metadata-protocol` suite**, base and head, compared per test name and status (vitest `--maxWorkers=2`, JSON reporter, each run under the shared verify lock, `VERDICT command-exit 0` both legs): - Base `0790d0a469`: 21,509 tests (21,490 passed, 0 failed, 19 skipped), 266 files. - Head `f081d777`: 21,509 tests (21,490 passed, 0 failed, 19 skipped), 266 files. - None lost, none changed status, none added. The base leg is the package `src/` swapped tree-only from `0790d0a469` (the new module removed from the tree) and restored from `HEAD` under a trap. - **Derived gates.** `dispatch-gates --commands --repo objectstack-ai/objectstack` derives 53 gates on 2 changed paths; all 53 exit 0. `check:dual-build-cjs-loads` and `check:lean-entry-closure` first answered PREREQUISITE NOT MET (exit 3, unbuilt `dist/`) and exit 0 after a full `pnpm build` (76/76 tasks, `VERDICT command-exit 0`); the plugin-teardown fixture commit was fetched before the first run. `dispatch-gates --ran`: 53 derived, 53 run, 0 NOT-MEASURED, 0 UNRUN, exit 0. ## Acceptance notes - The fallback arms of `materializeFromRegistry` and `stripMaterializedFromRegistry` (the narrower `provisionSearchCompanionOnto` / `stripProvisionedSearchCompanionFrom` spellings for partial registry doubles) are reached by no test in this repository: every protocol in the six named test files is built over a real `SchemaRegistry`, which answers the wider seam first. They move verbatim; whether to keep them is not this cut's question. Not class a/b/c. - `governServedItem` and `stripServedSystemColumns` now have their only callers in `protocol-registry-materialize.ts`. A later cut could move them there; it would re-point the `{@link}` references in the class docblocks and the prose comments that name them. ## Carry-forward Unchanged from cut 10: public members whose return type is inferred, the bodies kept by a reader (`probeRecord`, `getMetaItemCached`, `findReferencesToMeta`, `packagelessAddress`, `refuseUnmintableMetaType`, `metaTypeNamespaceExists`, `viewContainerNameCollisionRefusal` with `overlaidShippedContainerViewNames`, `reportPageRequiresAbsentAtLoad`, the 7 `applyRegistryWriteThrough` callers, `readCodeLayerForCarryForward`), and the private-static readers stay in `protocol.ts`. --- _Generated by [Claude Code](https://claude.ai/code/session_011WCU5ZbGMk9LUhayKvYPsx)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent e2a4b6a commit 4893a2f

2 files changed

Lines changed: 165 additions & 53 deletions

File tree

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
2+
3+
/**
4+
* [#25467 cut 11] The registry materialize/strip pair of
5+
* `ObjectStackProtocolImplementation` — the read exits' registry-side
6+
* convergence of a served object document (`materializeFromRegistry`), the
7+
* whole of what a `/meta` read exit owes an object document
8+
* (`governServedObject`), the write path's inverse of the registry seam
9+
* (`stripMaterializedFromRegistry`) and the whole of what the write path owes
10+
* the read (`stripServedObjectColumns`) — moved out of `protocol.ts` whole.
11+
*
12+
* A MOVE, not a redesign. Each function below is the body of the
13+
* `ObjectStackProtocolImplementation` method of the same name as it stood,
14+
* re-indented one level and otherwise unedited: the same reads, in the same
15+
* order, with the same `try`/`catch` fallbacks for partial registry doubles.
16+
*
17+
* ## How the moved bodies reach the class
18+
*
19+
* The shape #23050 set for `rest-server.ts` (its `data-action-routes.ts`
20+
* header carries the full reasoning), as `protocol-batch-data.ts` applies it.
21+
* The class keeps every method — the published `dist/*.d.ts` lists each one's
22+
* name, docblock and declared signature — and each body is one literal of
23+
* exactly the {@link RegistryMaterializeHost} members that method reads, plus
24+
* a `.call`. A method is handed over as a closure that calls it on the
25+
* protocol at call time, so a test double or spy set on the instance is still
26+
* the one the body reaches, and the moved bodies that call one another do so
27+
* through the protocol, exactly as before. Every other reader of these four
28+
* methods keeps calling the class method.
29+
*
30+
* The field the bodies read, `engine`, goes as a GETTER, so each read happens
31+
* when the body makes it: tests replace it on a constructed protocol.
32+
*
33+
* The module-level declarations of `protocol.ts` the bodies read stay there
34+
* and are imported from there: `canonicalMetaType`, which code that did not
35+
* move reads too, and `governServedItem` / `stripServedSystemColumns`, whose
36+
* docblocks the class's read and write paths cite by name. The module cycle is
37+
* evaluation-safe because every one of them is read only inside a function
38+
* body, never while the two modules are first evaluated. `index.ts` names what
39+
* it publishes from `protocol.ts` one by one, so the `export` the last two
40+
* gained for this keeps them off the published surface, and nothing
41+
* re-exports this module, so the published surface does not move.
42+
*/
43+
44+
import type { ObjectStackProtocolImplementation } from './protocol.js';
45+
import { canonicalMetaType, governServedItem, stripServedSystemColumns } from './protocol.js';
46+
47+
/**
48+
* The `ObjectStackProtocolImplementation` members the functions below read —
49+
* every one of them, and no other; each function's `this` is the `Pick` of the
50+
* members IT reads. Each is typed AS the class member (an indexed access on
51+
* the class), so a change to a member's signature on the class is a change
52+
* here too, and naming a member the class does not have is a compile error.
53+
* See the module header for which members are getters.
54+
*/
55+
export interface RegistryMaterializeHost {
56+
readonly engine: ObjectStackProtocolImplementation['engine'];
57+
materializeFromRegistry: ObjectStackProtocolImplementation['materializeFromRegistry'];
58+
stripMaterializedFromRegistry: ObjectStackProtocolImplementation['stripMaterializedFromRegistry'];
59+
}
60+
61+
/** The body of `ObjectStackProtocolImplementation#materializeFromRegistry`; the method's docblock there is its contract. */
62+
export function materializeFromRegistry<T>(
63+
this: Pick<RegistryMaterializeHost, 'engine'>,
64+
type: string, body: T): T {
65+
if (canonicalMetaType(type) !== 'object') return body;
66+
if (body === null || typeof body !== 'object') return body;
67+
const registry = (this.engine as any)?.registry;
68+
// Partial registry doubles in tests predate this method; a host that
69+
// cannot answer the gate answers exactly as it did before. The
70+
// `provisionSearchCompanionOnto` fallback keeps a double that was
71+
// written against #8038's narrower seam serving what it served then,
72+
// rather than silently losing the companion convergence to a rename.
73+
if (registry && typeof registry.materializeServedObjectOnto === 'function') {
74+
try {
75+
return registry.materializeServedObjectOnto(body) as T;
76+
} catch {
77+
// A read over an in-memory flag, the registry's own resolved
78+
// answer and the body's own fields; a failure here must not turn
79+
// a served schema into a 5xx.
80+
return body;
81+
}
82+
}
83+
if (registry && typeof registry.provisionSearchCompanionOnto === 'function') {
84+
try {
85+
return registry.provisionSearchCompanionOnto(body) as T;
86+
} catch {
87+
return body;
88+
}
89+
}
90+
return body;
91+
}
92+
93+
/** The body of `ObjectStackProtocolImplementation#governServedObject`; the method's docblock there is its contract. */
94+
export function governServedObject<T>(
95+
this: Pick<RegistryMaterializeHost, 'materializeFromRegistry'>,
96+
type: string, item: T): T {
97+
return this.materializeFromRegistry(type, governServedItem(type, item));
98+
}
99+
100+
/** The body of `ObjectStackProtocolImplementation#stripMaterializedFromRegistry`; the method's docblock there is its contract. */
101+
export function stripMaterializedFromRegistry<T>(
102+
this: Pick<RegistryMaterializeHost, 'engine'>,
103+
type: string, item: T): T {
104+
if (canonicalMetaType(type) !== 'object') return item;
105+
if (item === null || typeof item !== 'object') return item;
106+
const registry = (this.engine as any)?.registry;
107+
// Partial registry doubles in tests predate this method; the narrower
108+
// #8038 spelling keeps such a host stripping what it stripped before
109+
// rather than silently losing the companion strip to a rename.
110+
if (registry && typeof registry.stripMaterializedStampsFrom === 'function') {
111+
try {
112+
return registry.stripMaterializedStampsFrom(item) as T;
113+
} catch {
114+
// A read over the body's own fields; a failure here must not
115+
// turn a save into a 5xx.
116+
return item;
117+
}
118+
}
119+
if (registry && typeof registry.stripProvisionedSearchCompanionFrom === 'function') {
120+
try {
121+
return registry.stripProvisionedSearchCompanionFrom(item) as T;
122+
} catch {
123+
return item;
124+
}
125+
}
126+
return item;
127+
}
128+
129+
/** The body of `ObjectStackProtocolImplementation#stripServedObjectColumns`; the method's docblock there is its contract. */
130+
export function stripServedObjectColumns<T>(
131+
this: Pick<RegistryMaterializeHost, 'stripMaterializedFromRegistry'>,
132+
type: string, item: T): T {
133+
return this.stripMaterializedFromRegistry(type, stripServedSystemColumns(type, item));
134+
}

‎packages/metadata-protocol/src/protocol.ts‎

Lines changed: 31 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,13 @@ import {
386386
isUnservedSealedOverlay,
387387
servedLockState,
388388
} from './protocol-lock-state.js';
389+
// [#25467 cut 11] The registry materialize/strip pair of the served object document.
390+
import {
391+
governServedObject,
392+
materializeFromRegistry,
393+
stripMaterializedFromRegistry,
394+
stripServedObjectColumns,
395+
} from './protocol-registry-materialize.js';
389396

390397
/**
391398
* Canonical Zod schema per metadata type lives in
@@ -560,7 +567,7 @@ function canonicalizeMetaRequestType<T extends { type: string }>(request: T): T
560567
* PUT round-trip would persist the injected columns into `sys_metadata`, and the
561568
* #4326 byte-identical invariant would break the day this shipped.
562569
*/
563-
function governServedItem<T>(type: string, item: T): T {
570+
export function governServedItem<T>(type: string, item: T): T {
564571
if (canonicalMetaType(type) !== 'object') return item;
565572
return applyInjectedSystemColumns(applyAuditFieldGovernance(item));
566573
}
@@ -583,7 +590,7 @@ function governServedItem<T>(type: string, item: T): T {
583590
* the platform's own definition, and a declared `owner_id` carrying the author's
584591
* own label survives untouched.
585592
*/
586-
function stripServedSystemColumns<T>(type: string, item: T): T {
593+
export function stripServedSystemColumns<T>(type: string, item: T): T {
587594
return canonicalMetaType(type) === 'object' ? stripInjectedSystemColumns(item) : item;
588595
}
589596

@@ -9069,32 +9076,12 @@ export class ObjectStackProtocolImplementation implements
90699076
* which is the majority path this converges the minority onto).
90709077
*/
90719078
private materializeFromRegistry<T>(type: string, body: T): T {
9072-
if (canonicalMetaType(type) !== 'object') return body;
9073-
if (body === null || typeof body !== 'object') return body;
9074-
const registry = (this.engine as any)?.registry;
9075-
// Partial registry doubles in tests predate this method; a host that
9076-
// cannot answer the gate answers exactly as it did before. The
9077-
// `provisionSearchCompanionOnto` fallback keeps a double that was
9078-
// written against #8038's narrower seam serving what it served then,
9079-
// rather than silently losing the companion convergence to a rename.
9080-
if (registry && typeof registry.materializeServedObjectOnto === 'function') {
9081-
try {
9082-
return registry.materializeServedObjectOnto(body) as T;
9083-
} catch {
9084-
// A read over an in-memory flag, the registry's own resolved
9085-
// answer and the body's own fields; a failure here must not turn
9086-
// a served schema into a 5xx.
9087-
return body;
9088-
}
9089-
}
9090-
if (registry && typeof registry.provisionSearchCompanionOnto === 'function') {
9091-
try {
9092-
return registry.provisionSearchCompanionOnto(body) as T;
9093-
} catch {
9094-
return body;
9095-
}
9096-
}
9097-
return body;
9079+
// [#25467 cut 11] The body moved to `protocol-registry-materialize.ts` (see `RegistryMaterializeHost`).
9080+
const readEngine = () => this.engine;
9081+
const host: ThisParameterType<typeof materializeFromRegistry> = {
9082+
get engine() { return readEngine(); },
9083+
};
9084+
return (materializeFromRegistry<T>).call(host, type, body);
90989085
}
90999086

91009087
/**
@@ -9107,7 +9094,11 @@ export class ObjectStackProtocolImplementation implements
91079094
* #7556's boundary).
91089095
*/
91099096
private governServedObject<T>(type: string, item: T): T {
9110-
return this.materializeFromRegistry(type, governServedItem(type, item));
9097+
// [#25467 cut 11] The body moved to `protocol-registry-materialize.ts` (see `RegistryMaterializeHost`).
9098+
const host: ThisParameterType<typeof governServedObject> = {
9099+
materializeFromRegistry: (...a) => this.materializeFromRegistry(...a),
9100+
};
9101+
return (governServedObject<T>).call(host, type, item);
91119102
}
91129103

91139104
/**
@@ -9132,29 +9123,12 @@ export class ObjectStackProtocolImplementation implements
91329123
* named stamp — the same reason {@link materializeFromRegistry} does.
91339124
*/
91349125
private stripMaterializedFromRegistry<T>(type: string, item: T): T {
9135-
if (canonicalMetaType(type) !== 'object') return item;
9136-
if (item === null || typeof item !== 'object') return item;
9137-
const registry = (this.engine as any)?.registry;
9138-
// Partial registry doubles in tests predate this method; the narrower
9139-
// #8038 spelling keeps such a host stripping what it stripped before
9140-
// rather than silently losing the companion strip to a rename.
9141-
if (registry && typeof registry.stripMaterializedStampsFrom === 'function') {
9142-
try {
9143-
return registry.stripMaterializedStampsFrom(item) as T;
9144-
} catch {
9145-
// A read over the body's own fields; a failure here must not
9146-
// turn a save into a 5xx.
9147-
return item;
9148-
}
9149-
}
9150-
if (registry && typeof registry.stripProvisionedSearchCompanionFrom === 'function') {
9151-
try {
9152-
return registry.stripProvisionedSearchCompanionFrom(item) as T;
9153-
} catch {
9154-
return item;
9155-
}
9156-
}
9157-
return item;
9126+
// [#25467 cut 11] The body moved to `protocol-registry-materialize.ts` (see `RegistryMaterializeHost`).
9127+
const readEngine = () => this.engine;
9128+
const host: ThisParameterType<typeof stripMaterializedFromRegistry> = {
9129+
get engine() { return readEngine(); },
9130+
};
9131+
return (stripMaterializedFromRegistry<T>).call(host, type, item);
91589132
}
91599133

91609134
/**
@@ -9163,7 +9137,11 @@ export class ObjectStackProtocolImplementation implements
91639137
* path owes {@link governServedObject}.
91649138
*/
91659139
private stripServedObjectColumns<T>(type: string, item: T): T {
9166-
return this.stripMaterializedFromRegistry(type, stripServedSystemColumns(type, item));
9140+
// [#25467 cut 11] The body moved to `protocol-registry-materialize.ts` (see `RegistryMaterializeHost`).
9141+
const host: ThisParameterType<typeof stripServedObjectColumns> = {
9142+
stripMaterializedFromRegistry: (...a) => this.stripMaterializedFromRegistry(...a),
9143+
};
9144+
return (stripServedObjectColumns<T>).call(host, type, item);
91679145
}
91689146

91699147
/**

0 commit comments

Comments
 (0)