Repository navigation
refactor(metadata-protocol): move saveConflict and listLiveMetadataTypes out of protocol.ts, each into its own module (#25467 cut 24) - #26704
Conversation
…pes out of protocol.ts into their own modules (#25467 cut 24) Move-only, shape B. saveConflict (the save door's 409 for a ConflictError, with its decision-audit row) moves to protocol-save-conflict.ts; listLiveMetadataTypes (the SchemaRegistry's types and the metadata service's, de-duplicated) moves to protocol-live-metadata-types.ts. Each class member keeps its name, docblock and signature as a stub that hands a host to the moved function. Claude-Session: https://claude.ai/code/session_016SP1spj613tyGCgxoD1An6 Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift Check10 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 95f47c7c558cf9d037a307a01a21c791b04ef5bb && git checkout 95f47c7c558cf9d037a307a01a21c791b04ef5bb
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 43731031654ddabb4f87844140b8c872845ab5c0 f430c6a9471ee1609b4b3b06237a17ff255ff428 && git checkout -B drift-repro 43731031654ddabb4f87844140b8c872845ab5c0 && git merge --no-ff f430c6a9471ee1609b4b3b06237a17ff255ff428
node scripts/docs-audit/affected-docs.mjs --json 43731031654ddabb4f87844140b8c872845ab5c0 |
席位核对 · ACCEPT ·
|
| item | reading |
|---|---|
| Shape | Draft, base main, Part of #25467 (cut 24). 3 files: protocol.ts and two new modules, one per theme as the claim asked: protocol-save-conflict.ts (saveConflict) and protocol-live-metadata-types.ts (listLiveMetadataTypes). skip-changeset (move-only). Clause-②: no, Metadata-protocol: none. |
| Move check (seat) | All 29 non-blank lines the PR removes from protocol.ts are found verbatim (indent-stripped) in the two new modules. The 18 added lines are the two imports with their header comments and the two stubs: listLiveMetadataTypes through LiveMetadataTypesHost with getters for engine and getServicesRegistry, saveConflict through SaveConflictHost with closures for metadataConflictRefusal and recordOptimisticConflictAudit. Every caller keeps calling the class members. |
| Evidence | CI green on head f430c6a947 (34 success, 16 skipped, 0 failed). Governed check: NOT governed, 183 changed lines. The report gives an AST compare of 268 tokens with 0 differ (each negative control at 1), raw and sorted-union .d.ts identity (ruling 6348891160) with the positive control moving the hash, the suite at 21,599 tests per-test identical at base, head and merged, the read-seam census at 82 with an identical --list, and 46 of 46 derived gates. No open PR edits protocol.ts. |
| 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 24 of the
protocol.tssplit (#24586 ruling A, recorded in6270097840). Cuts 1–23 landed as #25494, #25518, #25538, #25589, #25601, #25623, #25642, #25719, #25731, #25740, #25797, #25939, #25972, #26014, #26104, #26168, #26264, #26317, #26350, #26366, #26404, #26449 and #26654. The claim is6441745164. It takes the cut 24 proposal of the cut 23 report (6440919239). As the claim orders, the two members are not one theme, so each moves into its own module. Both passed the AST screen and the read-seam census, and both moved unedited.Two
ObjectStackProtocolImplementationmembers move unedited, each into a new module (#23050 shape B):saveConflict→packages/metadata-protocol/src/protocol-save-conflict.ts: the optimistic-save conflict answer. It builds the save door's 409 for aConflictErrorthrough the one conflict builder and writes its decision-audit row ([security] Stored-metadata-body family: two exits #21120 did not reach. An engine-only door serves an administrator credential material in cleartext, and the data door serves a content hash computed over the withheld credentials #21207, metadata-protocol: a first draft pinnedIf-None-Match: *on a sealed package-shipped item gets the create remedy ("name is taken"):sealedWritereads anullparent as a create, the spec as "no row of this lifecycle" #23406).listLiveMetadataTypes→packages/metadata-protocol/src/protocol-live-metadata-types.ts: the live metadata-type listing. It returns the engine SchemaRegistry's types plus themetadataservice's, de-duplicated (Plugin-registered metadata types can carry org-scoped rows that cold boot skips — neither refused nor reported #6992).protocol.tsloses 13 net lines (29,165 to 29,152). 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 frommainfe53769a8e(cut 23's merge). It names no issue, so the claim comment is the identity record. It holds the move commit34b0e4a3c9and one merge ofmain,f430c6a947(8 commits). The merge touches no file ofpackages/metadata-protocol/. The package'ssrc/tree is917e56beat the move commit and at the merge.Serial with the file's in-flight PRs
Measured just before this PR was opened, against the merged head
f430c6a947: of the 16 open PRs, none editsprotocol.ts, and none names either member or either new module. Three touchpackages/metadata-protocol/src/test files: #26337 (3 files, among themprotocol.recovery-doors-emit-mutation.test.ts), #26628 (protocol.meta-types-degenerate-derivation.test.ts) and #26701 (protocol.metadata-store-outage.test.ts). Each one'sgit merge-treeis clean against this head. #26628's test drivesgetMetaTypes, solistLiveMetadataTypesruns through the class method there. It stubsgetRegisteredTypesand does not readprotocol.tsby path.mainmoved one commit after the merge: #26682 (4373103165, auth sign-out). It touches no file of this package,git merge-treewith this head is clean, and the derivation found nothing stale, somainwas not merged again.The order's screen (private statics,
new Error(, the read-seam census)Both members passed:
ObjectStackProtocolImplementationidentifier and none onthis.constructor.new Error(.saveConflictreturns the refusal thatmetadataConflictRefusalbuilds. 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
listLiveMetadataTypes:8494protocol-live-metadata-types.ts(66 lines)saveConflict:21469protocol-save-conflict.ts(68 lines)The shape (#23050 shape B, as cuts 1–23 apply it)
[#25467 cut 24].saveConflictreads two members, both methods.SaveConflictHosttypes each as the class member itself (ObjectStackProtocolImplementation['…']). The function types itsthisas theirPick, and the stub annotates its literal asThisParameterType<typeof saveConflict>.metadataConflictRefusalandrecordOptimisticConflictAuditare handed over as closures, so the body's calls reach the class methods exactly as before.listLiveMetadataTypesreads two members, both fields.LiveMetadataTypesHosttypes them the same way.engine(aprivatefield) andgetServicesRegistry(the constructor-supplied optional function field) are handed over as getters. This is the hand-over cut 20 used forgetServicesRegistry. So the body reads the protocol's own values at call time, and the?.()on an absent registry behaves as before.getMetaTypes'this.listLiveMetadataTypes()(:8513, base) does not change, and neither do the save door's twothrow await this.saveConflict(err, request, writeSource)sites (:21243,:21454).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.tsConflictError(type position,saveConflict's parameter)@objectstack/metadata-coreimportinstanceofsites, among them the save door's two,metadataConflictRefusal's parameter and the stub's signature)listLiveMetadataTypes' body reads no module-level declaration. Its module imports nothing but the class's type. No import ofprotocol.tsloses its last reader, and no declaration gainsexport.The
:172comment is not touched. The claim allowed correcting the stale[commit ece4dad31]emitted-specifier comment (disclosed in cut 23) if this cut touched that import block. This cut adds its two imports after cut 23's import and does not touch the@objectstack/specblock, so the comment stays 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).listLiveMetadataTypeshas atryaround themetadataservice'sgetRegisteredTypes(). That callee is outside the gate's read vocabulary (find/findOne/count), so the catch was not a read seam before the move and is not one after it.saveConflicthas notry.82 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
fe53769a8eand head34b0e4a3c9were 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 (both new modules removed) and restored fromHEADunder a trap. Afterwardsgit diff HEADwas empty,git statuswas clean, and all three touched blobs equalledHEAD's.310d157f1455a7b76c3d9a60e905ac5e07debb23ec4a6a615b510870341bdbecat both ends, ondist/index.d.tsanddist/index.d.cts. The normaliser sorted 80 string-literal union runs. Sorted-union identity holds.724eaa784128c37a7e4b59d85e21212ba6378a5b07279853c97828cd8368e932at both ends, 777,143 bytes. Raw identity holds.f430c6a947(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.index.jshashes8cc705b2d0a6a59b…at base and0cb9bc1754636851…at head (index.cjs8af96d570232787c…→40c568bf03d0672b…).listLiveMetadataTypes.call(hostandsaveConflict.call(hosteach occur 0 times in the base bundles and once in the head bundles (ESM and CJS alike).function listLiveMetadataTypes(andfunction saveConflict(each go 0 → 1.privatewas dropped fromsaveConflicton disk (restored fromHEADunder a trap) and the package rebuilt. Both.d.tsfiles move to980c4b207280c4e8…(normalisedf5a4a75faae310fd…, which differs from the bar's310d157f…). So the bar can see a change on these members.9f18a0177ac736ed…on all of them. Neither moved function nor either…Hostinterface appears.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.tsatfe53769a8eagainst the two head modules:Negative controls, one per member. Each changed one token in an in-memory copy of a head module:
protocol.ts. All 252 base statements are byte-identical, leading comments included. Head adds two statements, the new modules' imports.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:metadataConflictRefusal,recordOptimisticConflictAudit,has been modified since you loaded it,schemaTypes,runtimeTypes,MetadataService not available. So were the test files inpackages/,docs/qa/and the@objectstack/specliveness ledgers.// MetadataService not availablecomment inside an inline fixture ofscripts/check-durability-degradation-log-level.mjs. That fixture is its own code string and does not readprotocol.ts.packages/spec/src/meta-spelling/metadata-url-spelling.tsnameslistLiveMetadataTypes()in a comment only. No edit is owed.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-anchorsgives identical output at both ends: 1,871 decision-letter citations, and 59,671 citations across 8,363 files. Neither moved body cites an ADR.listLiveMetadataTypes' docblock (ADR-0131 D6) stays on the stub, and neither new module's header cites one.check-engine-double-contract): exits 0 at both ends.updateData/deleteDataseams keep their entries at new line numbers (13866 → 13863, 13891 → 13888).productionFilesis 3,777 at base and 3,780 at head. The +3 are the two new files and the gitignoredpackages/spec/src/migrations/registry.tsthat the spec build writes in the head tree, as in cuts 20–23.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, +2. The base-end readings were taken in a clean detached worktree atfe53769a8e.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.fe53769a8e: 21,599 tests (21,580 passed, 0 failed, 19 skipped), 272 files.34b0e4a3c9: 21,599 tests (21,580 passed, 0 failed, 19 skipped), 272 files.src/swapped tree-only fromfe53769a8e(both new modules removed) and restored fromHEADunder a trap.f430c6a947gives the same 21,599 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 3 paths in the register (13 surfaces), so the PR is NOT governed. It has 183 changed lines, under the 3,000-line human-merge bar.dispatch-gates --commands --repo objectstack-ai/objectstackderives 46 gates on 3 changed paths fromf430c6a947, with no stale-tree finding, and 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.check-durability-degradation-log-level --listonf430c6a947: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-negative set is the one cuts 22–23 measured (this cut re-trialled only its own members and the cut 25 candidates):findEnvironmentRows,packagelessAddress,findServedOverlayRow,foldStoredCollection,applyObjectRegistryMutation,unmanagedImportCollisions,rollBackUnmanagedImport,readRevertableCommitandstoredFlowBindingAgrees.rethrowUnlessMetadataStoreUnprovisionedcannot move at all.probeRecord,getMetaItemCached,findReferencesToMeta,refuseUnmintableMetaTypeandmetaTypeNamespaceExists.viewContainerNameCollisionRefusalwithoverlaidShippedContainerViewNames, andreportPageRequiresAbsentAtLoad.applyRegistryWriteThroughcallers (among themapplyRemoteMetadataMutation),readCodeLayerForCarryForwardandensureObjectStorage.emitMetadataMutation: its body is one of the twothis.notifyMutationListenersLocal(sites thatprotocol.recovery-doors-emit-mutation.test.tscounts inprotocol.ts.refusePackagedBaseRemoval,packagedBaseRefusal,runPublishSideEffects,promoteDraftForPublish,publishPackageDraftsanddiscardPackageDrafts.warnClosureReadUnavailable.🤖 Generated with Claude Code
https://claude.ai/code/session_016SP1spj613tyGCgxoD1An6