Repository navigation
refactor(metadata-protocol): move the object-extender fold out of protocol.ts into protocol-object-extender-fold.ts (#25467 cut 30) - #27129
Conversation
…tocol.ts into protocol-object-extender-fold.ts (#25467 cut 30) Move-only, shape B. foldObjectExtendersFromRegistry moves, unedited, into its own module. The engine field is handed over as a getter. Claude-Session: https://claude.ai/code/session_016SP1spj613tyGCgxoD1An6 Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift Check2 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run. What this run could not see
Coarse fallback — 10 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 78ddaaefede4c10a278b361e906f04b24b9b9b21 && git checkout 78ddaaefede4c10a278b361e906f04b24b9b9b21
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin e6e41998a8d4543f5935e7c45145dfc3d6fe0e26 307e5c9975026ddc0bfd7e0a27f27411939ed779 && git checkout -B drift-repro e6e41998a8d4543f5935e7c45145dfc3d6fe0e26 && git merge --no-ff 307e5c9975026ddc0bfd7e0a27f27411939ed779
node scripts/docs-audit/affected-docs.mjs --json e6e41998a8d4543f5935e7c45145dfc3d6fe0e26 |
席位核对 · ACCEPT ·
|
| item | reading |
|---|---|
| Shape | Draft, base main, Part of #25467 (cut 30). 2 files: protocol.ts and one new module for the claimed member, protocol-object-extender-fold.ts (foldObjectExtendersFromRegistry). skip-changeset (move-only). Clause-②: no, Metadata-protocol: none. |
| Move check (seat) | All 18 non-blank lines the PR removes from protocol.ts are found verbatim (indent-stripped) in the new module, the try/catch included. The added lines in protocol.ts are the import with its header comment and one stub through ObjectExtenderFoldHost, with engine handed over as a getter. All six callers still call the class member. |
| Evidence | CI green on head 307e5c9975 (34 success, 18 skipped, 0 failed). Governed check: NOT governed, 94 changed lines. The report gives an AST compare of 112 tokens with 0 differ (both negative controls differ by 1), raw and sorted-union .d.ts identity (ruling 6348891160) at both ends and on merged vs main, identical suites, the read-seam census at 89 with an identical --list, and 46 of 46 derived gates. |
| Disclosed | (1) The cut 25 comment-offset trap fired on the first layout: raw .d.ts was 4,967 bytes larger but identical with comments stripped. The dev shortened the cut's own import comment by 21 characters, amended the move commit to b542764e48, got raw identity back, and re-ran every head reading on it. The .d.ts bar was not touched. (2) Three main merges instead of one, because the first two derivations reported STALE TREE; the second brought #27084's protocol.ts change. The derivation re-run on the merge-tree with main 07d18e6927 reports no stale finding and the same 46 commands. No open PR edits protocol.ts at pr_create. |
| Landing | 「按照 pm-dispatch 规则复核过的都授权」 (Leehom, 2026-10-25T11:35Z): ready and auto-merge through the relay, once every check on this head is green or an expected skip. |
Generated by Claude Code
Requested by Leehom · project thread
Part of #25467
Clause-②: no
Metadata-protocol: none
Ruling-ref: 6270097840
Cut 30 of the
protocol.tssplit (#24586 ruling A, recorded in6270097840). Cuts 1–29 landed as #25494, #25518, #25538, #25589, #25601, #25623, #25642, #25719, #25731, #25740, #25797, #25939, #25972, #26014, #26104, #26168, #26264, #26317, #26350, #26366, #26404, #26449, #26654, #26704, #26807, #26873, #26933, #26980 and #27029. The claim is6460856054. It takes the cut 30 proposal of the cut 29 report (6458845738): one member on its own theme. It passed the AST screen and the read-seam census and moved unedited.One
ObjectStackProtocolImplementationmember moves unedited into a new module,packages/metadata-protocol/src/protocol-object-extender-fold.ts(#23050 shape B):foldObjectExtendersFromRegistry. It folds the registry'sextendcontributors onto an OBJECT body that came from the MetadataService, so that the by-name read serves the object's resolved schema as the list read does (#7556).protocol.tsloses 10 net lines (29,425 to 29,415). The cut is move-only, and the card stays open for later cuts.Branch
claude/project-thread-ybjm3his the harness-pinned branch for this thread. It was restarted frommaincbb3a1a1a5(after cut 29's merge). It names no issue, so the claim comment is the identity record. It holds the move commitb542764e48and three merges ofmain:29cc169592(7 commits): nothing in this package.752f03c260(12 commits): brings fix(metadata-protocol)!: refuse the per-item publish and a package-less save over a binding to an uninstalled package #27084'sprotocol.tschange (+95 / −15), which auto-merged. The first merge's derivation had reported a STALE TREE.307e5c9975(13 commits): nothing in this package. The second merge's derivation reported a STALE TREE on CI workflow files.The claim asked for one merge. The extra two follow the derivation's STALE TREE findings. The merged tree was measured against
mainitself (see "The merged tree againstmain").A deviation, disclosed: the cut 25 comment-offset trap fired, and the cut's own comment was shortened
The first layout of this cut (move commit
cc3ec04204, never pushed) broke raw and sorted-union.d.tsidentity:701056df78aed858…, 788,085 bytes (+4,967);522aaecdadbe5b51….The only hunk was the one cut 25 met. tsc's declaration emitter reused an inferred
@objectstack/specnode (ast?: unknown) and printed comment ranges read fromprotocol.tsat that node's offset. That pasted the "Zod schemas used to validate overlay items" docblock into the type.Printed with comments removed (the TS printer's
removeComments), base and that head were identical (1583192e38f78f85). It was still a published.d.tschange, so it failed the ruling6348891160bar. As the claim's carried note directs, the fix was the cut's own added text, never the bar.The import comment the cut adds was reworded 21 characters shorter, and the move commit was amended to
b542764e48. Raw identity came back. Every head reading below is fromb542764e48, including the tsc, hand-gate, positive-control and suite legs, which were re-run on it.Serial with the file's in-flight PRs
The claim found no open PR editing
protocol.tsand asked for a re-check before this PR was opened.protocol.ts, but it merged intomainbefore this PR. It is part of the second merge above, and it names no moved member.pr_create, of the 26 open PRs, two touch this package: feat(spec, formula, plugin-email, lint): a mail template formats an amount in the record's own currency with currency:@path #26937 (one test) and chore: version packages #26517 (CHANGELOG.md/package.json). None editsprotocol.ts. Both are merge-tree clean against this head and againstmain.mainmoved 5 commits after the third merge (to07d18e6927). Theirgit merge-treewith this head is clean, and none touches this package. The derivation on307e5c9975still names one stale file,.github/workflows/lint.yml. So the gates were derived again on that merge-tree (this head with07d18e6927): it reads no stale finding and the same 46 gate commands, line for line.mainwas not merged a fourth time. The PR's merge ref runs CI against currentmain.The order's screen (private statics,
new Error(, the read-seam census)The member passed:
ObjectStackProtocolImplementationidentifier and none onthis.constructor.new Error(, so noPRODUCERSrow is owed.check-durability-degradation-log-level --listwas taken on the base and again on the cut. Both read89 read seam(s), the claim's base, and the lists are identical once[@:][0-9]+is stripped. The full readings are under "The durability--list".What moves
foldObjectExtendersFromRegistry:8901engine(field); module-levelPLURAL_TO_SINGULARprotocol-object-extender-fold.tshas 68 lines.The shape (#23050 shape B, as cuts 1–29 apply it)
[#25467 cut 30].ObjectExtenderFoldHosttypes the one member the body reads as the class member itself (ObjectStackProtocolImplementation['engine']).enginefield is handed over as a getter, so the read finds it at call time, as before.try/catcharound the in-memoryregistry.foldObjectExtendersOntocall moves with the body, unedited, as the claim says.:7412,:9613,:11092,:11144,:11493and:11723(base). None changes.Module-level declarations, by reader: no import leaves
protocol.tsThe one module-level name the body reads is
PLURAL_TO_SINGULAR, from@objectstack/spec/shared. It has many other readers inprotocol.tsand stays. The new module imports it from there too. So the top level ofprotocol.tschanges by the new module's import alone.The published
.d.tsThe series bar is ruling
6348891160: sorted-union identity, measured first, with raw identity reported when it holds. Both hold for this cut atb542764e48, and on the merged tree againstmain. See the deviation above for the first layout.Base
cbb3a1a1a5and headb542764e48were built withpnpm --filter @objectstack/metadata-protocol buildagainst one dependency tree. The closure was built at head by a fullpnpm build(116/116). For the base build, the package'ssrc/was swapped tree-only to base (the new module removed) and restored fromHEADunder a trap. Afterwardsgit diff HEADwas empty,git statuswas clean, and both touched blobs equalledHEAD's.cd4b7becaeffffd99b2e6db36c0147efbcaf17948bf2301a02cf203b45b9e504at both ends, ondist/index.d.tsanddist/index.d.cts. The normaliser sorted 80 string-literal union runs. Sorted-union identity holds.7a0b7ca10b7be13b346d7034f854267d57a8efbc41350f12aab769c36ee78a88at both ends, 783,118 bytes. Raw identity holds.index.jshashes5376c52e2c80abdd…at base and5dd2faad4fb4d0c3…at head (index.cjs84507a06aac8b045…→e347dd6c9b78122c…).foldObjectExtendersFromRegistry.call(hostgoes 0 → 1 in both bundles.function …(declaration goes 0 → 1.privatewas dropped fromfoldObjectExtendersFromRegistryon disk (restored fromHEADunder a trap) and the package rebuilt. Both.d.tsfiles move to04fd085e8a03776c…(normalisedaa13275083654b7a…, which differs from the bar'scd4b7bec…) and printfoldObjectExtendersFromRegistry(type: string, name: unknown, body: unknown): unknown;. So the bar can see a change on this member.9f18a0177ac736ed…on all of them. Neither the function norObjectExtenderFoldHostappears.The merged tree against
mainThe merged tree
307e5c9975was measured againstmain6817bf1eae, its second parent, in the same way. The closure was rebuilt by a fullpnpm build(116/116), andmain's packagesrc/was swapped in tree-only and restored under a trap. The merged tree differs frommainonly by this cut: 2 files, +76 / −18..d.ts: raw9f7d69b1624e9398…(784,351 bytes) and normalisedfd5431a235098745…, the same atmainand merged. Both identities hold. The offset trap did not fire after fix(metadata-protocol)!: refuse the per-item publish and a package-less save over a binding to an uninstalled package #27084'sprotocol.tschange.index.js:aa69b0ce794c8221…atmain,18aded551747cdaa…merged. Export tables: 78 names,9f18a0177ac736ed…on both.main'sprotocol.tsagainst the merged one: 112 tokens, 0 differ.mainand merged both give 21,775 tests (21,749 passed, 0 failed, 26 skipped, 281 files), per test identical.The second merge
752f03c260was measured the same way againstmain6845035c6b, with the same.d.tsresult.No changeset:
skip-changeset, per ruling6348891160.The durability
--listcheck-durability-degradation-log-levelexits 0 at both ends with identical output:89 read seam(s)at both ends. Its--listis identical once[@:][0-9]+is stripped (165 lines, and no entry changes file).tryguards the in-memoryregistry.foldObjectExtendersOntocall, not the gate's read vocabulary (find/findOne/count).89 read seam(s).Proof of move-only
Body, by AST token. The compare reads the TypeScript compiler's AST leaf tokens, with JSDoc skipped, over the parameters (less the added
this), the return type and the body. It compares baseprotocol.tsatcbb3a1a1a5against the head module:Negative controls. Each changed one token in an in-memory copy of the head module, and the member moved (differ 1):
protocol.ts. All 263 base statements are byte-identical, leading comments included. Head adds one statement, the new module's import.Readers of the moved lines
These were grepped for the member name and the body's tags and distinctive text (
foldObjectExtendersOnto,#8027,#7556):the 24 files that name
protocol.tsand callreadFileSync;the test files in
packages/,docs/qa/andscripts/;the
@objectstack/specliveness ledgers.By path: none reads a moved line.
The one other mention.
protocol.runtime-gate-stored-universe.test.tsnames the member in a comment only. It and the doors that serve an object by name are driven by the package suite, which passes at both ends.The liveness ledgers. No row points at the member. Carried forward:
manifest.json'sdependenciesrow →protocol.ts#resolveWritePackageScope(cut 19), andseed.json→protocol.ts#applySeedBodies(cut 14). These arepackages/spec/**, outside this card.ADR anchors.
check-adr-anchorsexits 0 with identical output at both ends (1,898 decision-letter citations, 60,136 citations). No moved line cites an ADR.Engine-double contract (
check-engine-double-contract): exits 0 at both ends.updateData/deleteDataseams keep their entries at new line numbers (14009 → 13999, 14034 → 14024).productionFilesis 3,826 at base and 3,828 at head. The +2 are the new file and the gitignoredpackages/spec/src/migrations/registry.tsthat the spec build writes in the head tree, as in cuts 20–29.Identical output at both ends:
check-adr-anchors,check-adr-symbol-anchors,check-system-context-census,check-tenant-audit-census,check-query-options-erasure-ratchet,check-filter-alias-parityandcheck-durability-degradation-log-level.check-nul-bytesdiffers only in the scanned file count, +1. The base-end readings were taken in a clean detached worktree atcbb3a1a1a5.Verification
tsc --noEmitinpackages/metadata-protocolexits 0 at head and on the merged tree.pnpm exec eslint --no-inline-config packages/metadata-protocolexits 0 with no output (the whole touched package, with the rootlintscript's flags).packages/metadata-protocolsuite, compared per test name and status. Each leg ran vitest--maxWorkers=2with the JSON reporter under the shared verify lock.cbb3a1a1a5: 21,761 tests (21,735 passed, 0 failed, 26 skipped), 280 files.b542764e48: 21,761 tests (21,735 passed, 0 failed, 26 skipped), 280 files.src/swapped tree-only fromcbb3a1a1a5(the new module removed) and restored fromHEADunder a trap.307e5c9975andmain6817bf1eaeboth give 21,775 tests, per test identical (0 lost, 0 added, 0 changed).check-platform-checklist --changed-from origin/main(merged tree): OK, 31 anchors judged, 0 lost.check-governed-merges --branch claude/project-thread-ybjm3hfinds 0 of 2 paths in the register (13 surfaces), so the PR is NOT governed. It has 94 changed lines, under the 3,000-line human-merge bar.dispatch-gates --commands --repo objectstack-ai/objectstackderives 46 gates on 2 changed paths from307e5c9975. All 46 exit 0 after the fullpnpm build(116/116).dispatch-gates --ranreports 46 derived, 46 run, 0 NOT-MEASURED and 0 UNRUN, and exits 0. The stale-tree finding and its re-derivation are under "Serial with the file's in-flight PRs".Carry-forward
These stay in
protocol.ts:findEnvironmentRows,findEnvironmentRow,packagelessAddress,findServedOverlayRow,foldStoredCollection,applyObjectRegistryMutation,unmanagedImportCollisions,rollBackUnmanagedImport,readRevertableCommitandstoredFlowBindingAgrees.rethrowUnlessMetadataStoreUnprovisionedcannot move at all.probeRecord,getMetaItemCached,findReferencesToMeta,refuseUnmintableMetaTypeandmetaTypeNamespaceExists.viewContainerNameCollisionRefusalwithoverlaidShippedContainerViewNames, andreportPageRequiresAbsentAtLoad.applyRegistryWriteThroughcallers,readCodeLayerForCarryForward,ensureObjectStorage,dropObjectStorageandapplyRemoteMetadataMutation.emitMetadataMutation, andgetOverlayRepo.isArtifactBacked,isNestedArtifactFieldandpackagedArtifactBase(thelookupArtifactItemsite pins).refusePackagedBaseRemoval,packagedBaseRefusal,runPublishSideEffects,promoteDraftForPublish,publishPackageDraftsanddiscardPackageDrafts.warnClosureReadUnavailableandresolveSduiManifest.🤖 Generated with Claude Code
https://claude.ai/code/session_016SP1spj613tyGCgxoD1An6