Repository navigation
refactor(metadata-protocol): move the stored-item conversion read out of protocol.ts into protocol-stored-item-conversion.ts (#25467 cut 23) - #26654
Conversation
… of protocol.ts (#25467 cut 23) Move the bodies of convertStoredItem and convertStoredItemDetailed unedited into protocol-stored-item-conversion.ts. convertStoredItem sits behind a StoredItemConversionHost that hands over convertStoredItemDetailed as a closure and the storedConversionWarned field as a getter; convertStoredItemDetailed reads no member, so its stub calls the plain function directly. withDeclaredPageTypeDefault gains export in place, and applyConversionsToStoredItem, whose last reader moved, leaves protocol.ts's @objectstack/spec import. The class keeps both methods, their docblocks and declared signatures; their callers keep calling the class methods. Claude-Session: https://claude.ai/code/session_016SP1spj613tyGCgxoD1An6 Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift Check7 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 — 11 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 62f5eedc0c1ac5af6b8d050665dd68889385ef81 && git checkout 62f5eedc0c1ac5af6b8d050665dd68889385ef81
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin dbf7e04adff66aba72e634c65aae754440a8d89d 0741a0f66b99bf7982870047c5b484d913432454 && git checkout -B drift-repro dbf7e04adff66aba72e634c65aae754440a8d89d && git merge --no-ff 0741a0f66b99bf7982870047c5b484d913432454
node scripts/docs-audit/affected-docs.mjs --json dbf7e04adff66aba72e634c65aae754440a8d89d |
席位核对 · ACCEPT ·
|
| item | reading |
|---|---|
| Shape | Draft, base main, Part of #25467 (cut 23, the first cut after the 18.2.0 restart). 2 files: protocol.ts and the new protocol-stored-item-conversion.ts. skip-changeset (move-only). Clause-②: no, Metadata-protocol: none. |
| Move check (seat) | Of the 30 non-blank lines the PR removes from protocol.ts, 28 are found verbatim (indent-stripped) in the new module. The other 2 are the @objectstack/spec import losing applyConversionsToStoredItem (its last reader moved) and withDeclaredPageTypeDefault gaining export in place. The 13 added lines in protocol.ts are that import, the new module's import, the export, and the two stubs (convertStoredItem through StoredItemConversionHost with a getter for storedConversionWarned; convertStoredItemDetailed as a direct call). |
| Evidence | CI green on head 0741a0f66b (34 success, 16 skipped, 0 failed). Governed check: NOT governed, 141 changed lines. The report gives an AST compare of 325 tokens with 0 differ (two negative controls at 1), raw and sorted-union .d.ts identity (ruling 6348891160), the suite at 21,595 of 21,595 with 0 lost, added or changed, the read-seam census at 82 with an identical --list at base, head and merged, and 46 of 46 derived gates. |
| Disclosed | The emitted-specifier comment at protocol.ts:172 (ece4dad) still names applyConversionsToStoredItem. The root import stays and the raw .d.ts did not move, so its pin holds. Left as is. |
| 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 23 of the
protocol.tssplit (#24586 ruling A, recorded in6270097840), the first after the release pause (restart recorded on #25467 once 18.2.0 shipped). Cuts 1–22 landed as #25494, #25518, #25538, #25589, #25601, #25623, #25642, #25719, #25731, #25740, #25797, #25939, #25972, #26014, #26104, #26168, #26264, #26317, #26350, #26366, #26404 and #26449. The claim is6439185861. It takes the cut 23 proposal of the cut 22 report (6433520681). Both members passed the AST screen and the read-seam census, and both moved unedited.Two
ObjectStackProtocolImplementationmembers move unedited into a new module,packages/metadata-protocol/src/protocol-stored-item-conversion.ts(#23050 shape B):convertStoredItemDetailed: the ADR-0087 conversion chain over a stored body, with its notices and TODOs handed back.migrateStoredMetadatareports these per row ([P3] os migrate meta --stored: rewrite sys_metadata rows in place so the read-path chain has a finish line #4327, decision: should the losslessly mappable subset of the record-formfilterget a real D2 conversion, or is "stored rows keep loading, re-saving is refused" the final answer? #17321, spec: the stored-shape detector for an external binding on a managed datasource resolves the datasource from the same stack only, so os migrate meta --stored misses a stored object bound to a stored managed datasource #25279).convertStoredItem: the read every stored row goes through. It warns once per conversion, row and process, and fills a page's declaredtypedefault (metadata: a page saved withouttypeis stored and served without it, soPageSchema's declaredtypedefault (record) never reaches a consumer that reads the served body #20101).protocol.tsloses 17 net lines (29,182 to 29,165). 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 frommainf9867020c6after the restart. It names no issue, so the claim comment is the identity record. It holds the move commit1d1579ed11and two merges ofmain:6d09a4555e, and0741a0f66b, which was made becausedispatch-gatesitself had changed onmain(scripts and docs only). Neither merge touches a file ofpackages/metadata-protocol/. The package'ssrc/tree isc7cd94f5at the move commit and at both merges.Serial with the file's in-flight PRs
Measured just before this PR was opened, against the merged head
0741a0f66b: of the 15 open PRs, none editsprotocol.ts, and none names either member,withDeclaredPageTypeDefaultorapplyConversionsToStoredItem. One touchespackages/metadata-protocol/src/test files: #26337 (3 files). Itsgit merge-treeis clean against this head and againstorigin/mainalone. No open PR edits the new module.mainmoved one commit after the last merge: #26599 (dbf7e04adf), the spec retirement of conversion kits at or below 16.x. It does not touchprotocol.ts. It does edit sevenprotocol.*stored*/conversion test files in this package and the spec conversion chain thatapplyConversionsToStoredItemruns. Itsgit merge-treewith this head is clean. This cut moves the call to that chain unedited, so the PR's merge ref runs #26599's tests against the moved code. Its one stale gate file (scripts/check-spec-docblock-symbol-anchors.mjs) is not among this cut's 46 derived commands, somainwas not merged a third time.The order's screen (private statics,
new Error(, the read-seam census)Both members 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:82 read seam(s)and an identical list once[@:][0-9]+is stripped. The full readings are under "The durability--list".What moves
convertStoredItem:6416convertStoredItemDetailed:6452The shape (#23050 shape B, as cuts 1–22 apply it)
[#25467 cut 23].convertStoredItemDetailedreads no member. This was measured by an AST walk overthisaccesses, withascasts, parentheses and!stripped, and barethischecked. So its stub is a plain call,return convertStoredItemDetailed(type, data, onNotice, knownDatasources);, as cuts 16 and 21 did. The class signature keeps theConversionNotice/ConversionTodoNoticetypes, so those type imports stay inprotocol.ts.convertStoredItemreads two members.StoredItemConversionHosttypes each as the class member itself (ObjectStackProtocolImplementation['…']). The function types itsthisas theirPick, and the stub annotates its literal asThisParameterType<typeof convertStoredItem>.convertStoredItemDetailedis handed over as a closure, so the body's call still reaches the class method and, through its stub, the moved function.storedConversionWarnedis a private FIELD, aSet<string>, so it is handed over as a getter. The body only calls.hasand.addon it, inside theonNoticearrow, and never reassigns it. So the warn-once set it reads and adds to is the protocol's own, shared with every other read, exactly as before.getServicesRegistryfield.this.convertStoredItem(sites at:7277,:9812,:10857,:10922,:11498,:18885,:25342,:25576and:28359(base) do not change. Neither does the cut 16 closure that hands it tostoredOverlayEntries(:10211), or the remainingthis.convertStoredItemDetailed(site (:21925).Module-level declarations, by reader
Measured by an AST walk over each body's identifiers, against
protocol.ts's top-level declarations and import bindings (property names excluded):protocol.tshas itprotocol.tswithDeclaredPageTypeDefault:2263:20924)exportin place; the new module imports it from./protocol.jsapplyConversionsToStoredItem@objectstack/specimport,:170@objectstack/specConversionNotice,ConversionTodoNoticePLURAL_TO_SINGULAR@objectstack/spec/sharedimportindex.tsnames its exports one by one, so the in-placeexportdoes not reach the published surface.One stale prose reference, disclosed and not edited. The
[commit ece4dad31]emitted-specifier comment under the imports (:172) says the file imports the@objectstack/specroot "forapplyConversionsToStoredItemabove". The root import stays, forapplyConversionsToFlowand the two notice types, so the pin it explains still holds. The.d.tsreadings below confirm that nothing about the emitted declarations moved. Editing that sentence is not move-only, so this PR leaves it for a later edit.The durability
--listcheck-durability-degradation-log-levelexits 0 at both ends with identical output:82 read seam(s)at both ends. Its--listis identical once[@:][0-9]+is stripped (158 lines, and no entry changes file). Neither body has atry.convertStoredItem'sconsole.warnsits in anonNoticecallback, not acatch, so the log-level rule does not grade it. On the merged tree the verdict still reads82 read seam(s).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.Base
f9867020c6and head1d1579ed11were 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 and restored fromHEADunder a trap. Afterwardsgit diff HEADwas empty,git statuswas clean, and both touched blobs equalledHEAD's.dd66cd91652093f2a0ce9a3b990290291bf3bcc40379d196a1bbe897c1ec43d7at both ends, ondist/index.d.tsanddist/index.d.cts. The normaliser sorted 80 string-literal union runs. Sorted-union identity holds.f4f602c840264aa052ee96788778479ba2ddccbd68199ad68f4419ff564f6ccdat both ends, 778,346 bytes. Raw identity holds. The emitted specifiers did not move with the import change.6d09a4555e(closure rebuilt by a fullpnpm build, 116/116): the same raw and normalised sha256, and the sameindex.js/index.cjshashes, as the pre-merge head. The second merge changed no package and no build input.index.jshashes3aedf79b4657c927…at base and8cc705b2d0a6a59b…at head (index.cjsb1d7383e753c4e1a…→8af96d570232787c…).convertStoredItem.call(hostoccurs 0 times in the base bundles and once in the head bundles (ESM and CJS alike).function convertStoredItem(goes 0 → 1.privatewas dropped fromconvertStoredItemon disk (restored fromHEADunder a trap) and the package rebuilt. Both.d.tsfiles move toa39e3a50ba0baab4…(normalised573d8a0a1d7bb1ca…, which differs from the bar'sdd66cd91…) and printconvertStoredItem(type: string, data: unknown): unknown;. So the bar can see a change on these members.9f18a0177ac736ed…on all of them. None of the moved functions,StoredItemConversionHostorwithDeclaredPageTypeDefaultappears.No changeset:
skip-changeset, per ruling6348891160.Proof of move-only
Bodies, 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.tsatf9867020c6against the head module:The two top-level statements that are not byte-identical are the
@objectstack/specimport, which lostapplyConversionsToStoredItem, andwithDeclaredPageTypeDefault, which gainedexport. Nothing else changed in either.Negative controls, one per member. Each changed one token in an in-memory copy of the head module:
protocol.ts. Of the 251 base statements, 249 are byte-identical, leading comments included; the other two are the import and theexportabove. Head adds one statement, the new module's import.protocol-stored-item-conversion.tshas 98 lines.Readers of the moved lines
The tests and scripts that read
protocol.tsby path (the files that nameprotocol.tsand callreadFileSync) were grepped for both member names and for the bodies' text:storedConversionWarned,applyConversionsToStoredItem,withDeclaredPageTypeDefault,carries a pre-protocol shape. So were the test files inpackages/,docs/qa/and the@objectstack/specliveness ledgers.packages/spec/src/migrations/registry.ts, which namesapplyConversionsToStoredItem(a@objectstack/specexport) in its migration entries and does not readprotocol.ts.protocol.flow-canonicalizer.test.tsandmetadata-diagnostics.union-issues.test.ts(metadata-protocol) andview-overlay-owner-hidden-retirement.test.ts(spec) nameconvertStoredItemin comments only, and drive the read through the protocol. The first two pass at both ends, in the package suite.manifest.json'sdependenciesrow →protocol.ts#resolveWritePackageScope(cut 19), andseed.json→protocol.ts#applySeedBodies(cut 14). Both still quote lines that moved to a seam module.check:livenesschecks only that the#symbolis named in the file, and both stubs keep it. Re-pointing them is apackages/spec/**edit, outside this card.check-adr-anchorsexits 0 at both ends.check-engine-double-contract): exits 0 at both ends.updateData/deleteDataseams keep their entries at new line numbers (13883 → 13866, 13908 → 13891).productionFilesis 3,773 at base and 3,775 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–22.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 atf9867020c6.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, base and head, compared per test name and status. Each leg ran vitest--maxWorkers=2with the JSON reporter under the shared verify lock.f9867020c6: 21,595 tests (21,576 passed, 0 failed, 19 skipped), 272 files.1d1579ed11: 21,595 tests (21,576 passed, 0 failed, 19 skipped), 272 files.src/swapped tree-only fromf9867020c6(the new module removed) and restored fromHEADunder a trap.6d09a4555egives the same 21,595 tests, per test identical to the pre-merge head (0 lost, 0 added, 0 changed).check-platform-checklist --changed-from origin/main(merged tree): OK. 1 anchored file is in the change set, 29 anchors were judged, and 0 were 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 141 changed lines, under the 3,000-line human-merge bar.dispatch-gates --commands --repo objectstack-ai/objectstackderives 46 gates on 2 changed paths from0741a0f66b, with no stale-tree warning, and all 46 exit 0.dispatch-gates --ranreports 46 derived, 46 run, 0 NOT-MEASURED and 0 UNRUN, and exits 0.6d09a4555e, after the fullpnpm build(116/116).scripts/pm/dispatch-gates.mjsitself as stale againstmain, somainwas merged again, and the derivation and every gate re-run.check-durability-degradation-log-level --liston0741a0f66b:82 read seam(s).Carry-forward
These stay in
protocol.ts:protocol.tsread-seam entry ofcheck-durability-degradation-log-level --list, as the guarded wrapper or the guarding member, stays until the gate follows imported wrappers or a ruling accepts the loss. The census trial on this base, over 50 members, measured the same census-negative set as cut 22's trial:findEnvironmentRows66,packagelessAddress78,findServedOverlayRow79, andfoldStoredCollection,applyObjectRegistryMutation,unmanagedImportCollisions,rollBackUnmanagedImport,readRevertableCommitandstoredFlowBindingAgrees81.rethrowUnlessMetadataStoreUnprovisionedcannot move at all.probeRecord,getMetaItemCached,findReferencesToMeta,refuseUnmintableMetaType,metaTypeNamespaceExists,viewContainerNameCollisionRefusalwithoverlaidShippedContainerViewNames,reportPageRequiresAbsentAtLoad, the 7applyRegistryWriteThroughcallers,readCodeLayerForCarryForwardandensureObjectStorage.refusePackagedBaseRemoval,packagedBaseRefusal,runPublishSideEffects,promoteDraftForPublish,publishPackageDraftsanddiscardPackageDrafts.warnClosureReadUnavailable.🤖 Generated with Claude Code
https://claude.ai/code/session_016SP1spj613tyGCgxoD1An6