Repository navigation
refactor(metadata-protocol): move the write package scope resolution out of protocol.ts into protocol-write-package-scope.ts (#25467 cut 19) - #26350
Conversation
…out of protocol.ts (#25467 cut 19) Move the body of resolveWritePackageScope unedited into protocol-write-package-scope.ts, behind a WritePackageScopeHost that hands over the engine as a getter. The class keeps the method, its docblock and declared signature; its body becomes a host literal plus a .call. The authoring gate's host closure keeps calling the class method. Claude-Session: https://claude.ai/code/session_016SP1spj613tyGCgxoD1An6 Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 18 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 9 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. 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 4ac3fddada4a747ecf0afb8029161735f7a8e39a && git checkout 4ac3fddada4a747ecf0afb8029161735f7a8e39a
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 83e9d718718508cc27cc3e889ea594b2b0d1d221 f4eb4330f3f8d23f276e4bcc58e74f09ca21712c && git checkout -B drift-repro 83e9d718718508cc27cc3e889ea594b2b0d1d221 && git merge --no-ff f4eb4330f3f8d23f276e4bcc58e74f09ca21712c
node scripts/docs-audit/affected-docs.mjs --json 83e9d718718508cc27cc3e889ea594b2b0d1d221
|
席位核对 · ACCEPT ·
|
| item | reading |
|---|---|
| Shape | Draft, base main, Part of #25467 (cut 19), skip-changeset (no published behaviour moves), mergeable clean. |
| Files | 2 files, +96/−38. resolveWritePackageScope moves into protocol-write-package-scope.ts (#23050 shape B). The host is an engine getter only, and the new module imports only the class type. The class member stays as a delegating stub, so the authoring-gate closure at :7107 and every other caller still call the class method. Not governed. |
| Fix | A pure move. Seat probe: all 37 removed protocol.ts lines reappear in the new module, identical once the class indent is stripped, 0 missing. No module-level declaration moves or gains export, and no import changes. Dev: AST compare 252 tokens, 0 differ (the negative control gives 1). .d.ts is raw-identical (a8f6adb6…) before and after the merge, and the positive control moves it. Export tables are equal at 78 names. |
| Order questions | The silent catch moves file. The durability --list is identical once line numbers are stripped, and no entry names the member at either end; the catch guards registry.getPackage, not an engine call. No body constructs an error, so no PRODUCERS row is owed. |
| Evidence | 36 check runs succeeded and 16 were expected skips on this head, 0 failed. The suite ran 21,568 tests at both ends, with 0 lost, 0 added and 0 changed. Derived gates: 51 of 51 exit 0, and --ran reconciles. The merge-tree reading against #26244 and #26138 adds no conflict beyond what they already have with main. |
| Carried | Disclosure, not a defect: packages/spec/liveness/manifest.json's dependencies row still points at protocol.ts#resolveWritePackageScope and quotes a line that now lives in the new module (check:liveness checks only the symbol, which the stub keeps). seed.json's applySeedBodies pointer has been in the same state since cut 14. Re-pointing them is a spec patch, and it is left for the series' close-out. Cut 20 goes to the same thread once this lands: readItemFromMetadataService (about 40 lines, reads getServicesRegistry only). |
| Landing | 「按照 pm-dispatch 规则复核过的都授权」 (Leehom, 2026-10-25T11:35Z): ready and auto-merge through the relay, now that 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
This is cut 19 of the
protocol.tssplit (#24586 ruling A, recorded in6270097840). Cuts 1–18 landed as #25494, #25518, #25538, #25589, #25601, #25623, #25642, #25719, #25731, #25740, #25797, #25939, #25972, #26014, #26104, #26168, #26264 and #26317.The claim is
6427907689. The scope is the cut 19 proposal of the cut 18 report (6426921154), as the server seat approved it in its dispatch order. The member passed the AST screen and moved unedited.One
ObjectStackProtocolImplementationmember moves unedited into a new module,packages/metadata-protocol/src/protocol-write-package-scope.ts(#23050 shape B):resolveWritePackageScoperesolves a package write's validation scope. That is the written package plus the closure of the dependencies its manifest declares, read from the registry. It answersundefinedwherever the registry cannot be read.protocol.tsloses 30 net lines (29,270 to 29,240). 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 frommain77dc7062e5after cut 18 merged. It names no issue, so the claim comment is the identity record.The branch holds the move commit
c5f1351978and the merge ofmaina8e7393dda(f4eb4330f3). That merge touches no file ofpackages/metadata-protocol/: the package'ssrc/tree ise8f66938at both ends.Serial with the file's in-flight PRs. Measured just before this PR was opened: of the 29 open PRs, two touch
packages/metadata-protocol/src/, and neither namesresolveWritePackageScope. Each was checked withgit merge-treeagainst this branch's head (f4eb4330f3).c33b95d89f) editsprotocol.tsat:163(imports) and:23178, far from:7361. Its merge-tree conflicts inprotocol.tsand inpackages/spec/src/type-alias-convention.pin.test.ts. Both conflicts are ones feat(spec,metadata-protocol,service-storage,runtime,cli)!: a seed record can carry a file the package ships, seedFile(path) #26244 has withmainalone: a merge-tree of feat(spec,metadata-protocol,service-storage,runtime,cli)!: a seed record can carry a file the package ships, seedFile(path) #26244 withorigin/mainreports the same two files. Theprotocol.tsone is the import-line conflict with cut 18'sALL_CONVERSIONSdrop, whose union resolution refactor(metadata-protocol): move the flow save's retired-spelling replay verdict out of protocol.ts into protocol-flow-save-replay.ts (#25467 cut 18) #26317 spelled out. This cut adds no conflict.protocol.*.test.tsfiles. Its two conflicts (visibility-alias-keys-retirement.test.ts,scripts/sdui-manifest.sources/core.json) are likewise withmainalone.No open PR edits the new module.
The order's screen (private statics,
new Error()The member passed:
ObjectStackProtocolImplementationidentifier and none onthis.constructor.new Error(and no other error constructor, so noPRODUCERSrow is owed. There is no log line.catcharound the registry reads. It answersundefined, meaning "an unreadable registry means an unnarrowed gate". It moves with the body. See the durability--listbelow.What moves
resolveWritePackageScope:7361The proposal also said 40 body lines.
The shape (#23050 shape B, as cuts 1–18 apply it)
[#25467 cut 19].WritePackageScopeHosttypes its one member as the class member itself (ObjectStackProtocolImplementation['engine']). The function types itsthisasPick<WritePackageScopeHost, 'engine'>, and the stub annotates its literal asThisParameterType<typeof resolveWritePackageScope>. No member changes visibility.this, withascasts, parentheses and!stripped, and barethischecked too. It findsengineonly, read asthis.engine.registry. The engine is handed over as a live getter, so the body reads the protocol's engine, and so its registry, at call time.:7107(cut 8,assertRuntimeAuthoringRules→protocol-authoring-gate.ts) is unchanged. It still hands overresolveWritePackageScope: (...a) => this.resolveWritePackageScope(...a), which reaches the class stub and then the moved body.tenantAuthoredWriteRefusal(:16132) is the other caller, throughthis..Module-level declarations
protocol.tsand no import binding, measured by an AST identifier walk against the file's top-level declarations and imports. Nothing gainsexport, and no import ofprotocol.tschanges.import typefrom./protocol.js), so it adds no runtime edge to theprotocol.tscycle. The one new statement inprotocol.tsis the import of the new module.The durability
--list(the order's re-measure)The silent
catchmoved file, so the list was read at both ends.check-durability-degradation-log-levelexits 0 at both ends with identical output.--listis identical once[@:][0-9]+is stripped: 159 lines, and no entry changes file.resolveWritePackageScopeor the new module. Thecatchguards registry reads (registry.getPackage), not an engine call the list enumerates.The published
.d.tsThe series bar is ruling
6348891160, sorted-union identity, measured first.How it was built. Base
77dc7062e5and headc5f1351978were built withpnpm --filter @objectstack/metadata-protocol buildagainst one dependency tree. The closure was built at head by a fullpnpm build(119/119).For the base build, the package's
src/was swapped tree-only to base and restored fromHEADunder a trap. Afterwardsgit diff HEADwas empty,git statuswas clean, and both touched blobs equalledHEAD's.The
.d.tswas measured twice: on the pre-merge tree, and after mergingmain(headf4eb4330f3, closure rebuilt by a fullpnpm build, 119/119). The readings below hold for both. The base.d.tsdiffers from cut 18's readings because #26305 landed in between.a8f6adb6f9c56b8f441b7224ca8c4d43b84891bce0373446e1577a7884079dd8at base and at head, on bothdist/index.d.tsanddist/index.d.cts, 776,660 bytes each. Raw identity holds, so sorted-union identity holds too. The member stays aprivate NAME;line.f7f9306ed46a5605c5e4c59bbc212a7d5288061760ec85d473d2f3047a836ba5at both ends (80 string-literal union runs sorted; the cut 12 normaliser).index.jshashes4f35935b2eaf7f2b…at base and9495894cdf5ce39b…at head..call(hostsite ofresolveWritePackageScopeoccurs 0 times in the base bundles and once in the head bundles (ESM and CJS alike).function resolveWritePackageScope(appears 0 times at base and once at head.privatewas dropped fromresolveWritePackageScope(on disk, restored fromHEADunder a trap) and the package rebuilt. Both.d.tsfiles move tocf7f37aa818a9795…(normaliseda7662435fc695cad…) and printresolveWritePackageScope(packageId: string | null | undefined): { packageId: string; dependencies: string[]; } | undefined;. So the bar can see a change on this member.9f18a0177ac736ed…on all four. Neither the moved function norWritePackageScopeHostappears.No changeset:
skip-changeset, per ruling6348891160.Proof of move-only
Body, by AST token. The compare uses the TypeScript compiler's AST leaf tokens, with JSDoc skipped. It covers the parameters (less the added
this), the return type and the body. Baseprotocol.tsat77dc7062e5is compared against the head module:Negative control. One token was changed in an in-memory copy of the head module (
if (dep === packageId ||toif (dep !== packageId ||, one occurrence):protocol.ts. All 247 base statements are byte-identical, leading comments included. Head adds one statement, the new module's import.protocol-write-package-scope.tshas 88 lines.Readers of the moved lines
I grepped every test and script that reads
protocol.tsby path (70 files) for the member name and for its body's text (getPackage,frontier, thecatchcomment). I also grepped every test file inpackages/andui/, anddocs/qa/.getPackage, but as a registry test double (getPackage: () => undefinedand the like) or a direct registry call (package-dependencies-patch.integration.test.ts), not as the moved text.protocol-publish-drafts-closure.test.ts(line 228),packages/core/src/artifact-packages.ts(line 130) andpackages/lint/src/validate-list-view-field-refs.ts(line 272) name the method in comments. It still exists, on the class.@objectstack/specliveness ledger.packages/spec/liveness/manifest.json(dependenciesrow) carries the evidence pointerpackages/metadata-protocol/src/protocol.ts#resolveWritePackageScope (\const declared = manifest?.dependencies` inside the frontier loop …)`.check:livenesschecks that the#symbolis named in the file. The method is still declared inprotocol.ts, so the pointer resolves andpnpm --filter @objectstack/spec check:livenessexits 0 at head.protocol-write-package-scope.ts. That is the same state cut 14 leftseed.json'sprotocol.ts#applySeedBodiespointer in.packages/spec/**edit, which this card does not make. It is disclosed here and in the report as a follow-up.docs/qa/.check-adr-anchorsexits 0 with identical output at both ends.check-engine-double-contract). It exits 0 at both ends.updateData/deleteDataseams keep their entries at new line numbers (13956 → 13926, 13981 → 13951).productionFilesis 3,743 at base and 3,745 at head. One of the +2 is the new file; the other is the gitignoredpackages/spec/src/migrations/registry.tsthat the spec build writes in the head tree.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 at77dc7062e5.check-governed-merges --branch claude/project-thread-ybjm3hfinds 0 of 2 paths in the register, so this is NOT governed. It has 134 changed lines, under the 3,000-line human-merge bar.Verification
tsc --noEmitinpackages/metadata-protocolexits 0 before and after the merge.pnpm exec eslint --no-inline-config packages/metadata-protocolexits 0 with no output. It covers the whole touched package, which has nolintscript; these are the rootlintscript's flags.packages/metadata-protocolsuite, base and head, compared per test name and status. Both runs used vitest--maxWorkers=2with the JSON reporter under the shared verify lock, withVERDICT command-exit 0on both legs. They ran on the pre-merge tree; the merge changed no file of the package.77dc7062e5: 21,568 tests (21,549 passed, 0 failed, 19 skipped), 270 files.c5f1351978: 21,568 tests (21,549 passed, 0 failed, 19 skipped), 270 files.src/swapped tree-only from77dc7062e5(the new module removed) and restored fromHEADunder a trap.check-platform-checklist --changed-from origin/main(merged tree): OK, 1 anchored file in the change set, 29 anchors judged, 0 lost.dispatch-gates --commands --repo objectstack-ai/objectstackderives 51 gates on 2 changed paths from the merged treef4eb4330f3. All 51 exit 0 after the fullpnpm build(119/119).dispatch-gates --ran: 51 derived, 51 run, 0 NOT-MEASURED, 0 UNRUN, exit 0.mainonly forscripts/sdui-manifest.sources/plugin-grid.json, which feeds none of these 51 families. The list is the same 51 as cut 18's, somainwas not merged again.pnpm --filter @objectstack/spec check:livenessexits 0 at head (see the liveness ledger above).Carry-forward
Unchanged from cut 18. These stay in
protocol.ts:probeRecord,getMetaItemCached,findReferencesToMeta,packagelessAddress,refuseUnmintableMetaType,metaTypeNamespaceExists,viewContainerNameCollisionRefusalwithoverlaidShippedContainerViewNames,reportPageRequiresAbsentAtLoad, the 7applyRegistryWriteThroughcallers,readCodeLayerForCarryForwardandensureObjectStorage.refusePackagedBaseRemoval,packagedBaseRefusal,runPublishSideEffects,promoteDraftForPublish,publishPackageDraftsanddiscardPackageDrafts.warnClosureReadUnavailable.🤖 Generated with Claude Code
https://claude.ai/code/session_016SP1spj613tyGCgxoD1An6