Repository navigation
refactor(metadata-protocol): move the automation service's flow reads out of protocol.ts into protocol-automation-flow-reads.ts (#25467 cut 27) - #26933
Conversation
… out of protocol.ts into protocol-automation-flow-reads.ts (#25467 cut 27) Move-only, shape B. resolveFlowCanonicalizer, resolveFlowRegistrationReader and flowRegistrationsOf move, unedited, into one module. The getServicesRegistry field is handed over as a getter; flowRegistrationsOf's call to resolveFlowRegistrationReader is handed over as a closure, so it still reaches the class method. 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 fba4d54a2db4afd06aef475c8e7524d44bf2c675 && git checkout fba4d54a2db4afd06aef475c8e7524d44bf2c675
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin e1ab32ed0b68a58096dd9d1c5e2e510e6bbb3a79 e78313a06845a0d6303cc94fec0c4a4aa5b0da6c && git checkout -B drift-repro e1ab32ed0b68a58096dd9d1c5e2e510e6bbb3a79 && git merge --no-ff e78313a06845a0d6303cc94fec0c4a4aa5b0da6c
node scripts/docs-audit/affected-docs.mjs --json e1ab32ed0b68a58096dd9d1c5e2e510e6bbb3a79 |
席位核对 · ACCEPT ·
|
| item | reading |
|---|---|
| Shape | Draft, base main, Part of #25467 (cut 27). 2 files: protocol.ts and one new module for the claimed theme, protocol-automation-flow-reads.ts (resolveFlowCanonicalizer, resolveFlowRegistrationReader, flowRegistrationsOf). skip-changeset (move-only). Clause-②: no, Metadata-protocol: none. |
| Move check (seat) | All 28 non-blank lines the PR removes from protocol.ts are found verbatim (indent-stripped) in the new module. The added lines in protocol.ts are the import with its header comment and three stubs, each through AutomationFlowReadsHost: the two resolvers read getServicesRegistry through a getter, and flowRegistrationsOf reaches resolveFlowRegistrationReader through the class member, so callers and overrides still go through the class. |
| Evidence | CI green on head e78313a068 (34 success, 16 skipped, 0 failed). Governed check: NOT governed, 151 changed lines. The report gives an AST compare of 371 tokens with 0 differ (each negative control differs by 1), raw and sorted-union .d.ts identity (ruling 6348891160) at both ends and on merged vs main 57820085fa, the suite at 21,692 tests per-test identical at base and head (21,719 merged and main), the read-seam census at 88 with an identical --list, and 46 of 46 derived gates. |
| Overlap | The claim named #26856, #26861 and #26880. All three have merged and are inside this head or main; against main 8074feb642 the head merge-tree is clean, AST 0 differ, tsc 0. Open #26912 and #26928 are clean against it. #26920 and #26831 conflict with main itself on their own paths, not with this cut. |
| 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 27 of the
protocol.tssplit (#24586 ruling A, recorded in6270097840). Cuts 1–26 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 and #26873. The claim is6452474807. It takes the cut 27 proposal of the cut 26 report (6451437092), a themed group. All three members passed the AST screen and the read-seam census, and all three moved unedited.Three
ObjectStackProtocolImplementationmembers move unedited into one new module,packages/metadata-protocol/src/protocol-automation-flow-reads.ts(#23050 shape B). They are the protocol's flow reads from theautomationservice, the engine of this process:resolveFlowCanonicalizer: the service'scanonicalizeStoredFlow, bound, for the doors that canonicalize a stored flow body. It returns nothing when the service offers none.resolveFlowRegistrationReader: the service'sgetFlowRegistration, bound, for aflowtype only ([Decision] The metadata save door lifts a retired flow spelling on a NEW flow and stores it, where every other authoring door refuses it — refuse on a new flow, or keep the door a rehydration seam? #23775).flowRegistrationsOf: the list'sregistrations, that reader's verdict per listed non-draft item (automation: a stored flow the engine refuses at cold boot is withdrawn with a warn, while the metadata read keeps serving it asstatus: 'active'— after the v18 upgrade, every refused flow reads as running #23316).protocol.tsloses 9 net lines (29,187 to 29,178). 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 frommain161e00e4ea(after cut 26's merge). It names no issue, so the claim comment is the identity record. It holds the move commit13cd879d32and two merges ofmain:4581139c4e(10 commits) brings in fix(metadata-protocol): the save door stores an action as its ActionSchema parse, so requiresFeature / requiresMembershipReach are lowered into visible #26880, whoseprotocol.tschange (+5) auto-merged.e78313a068(8 commits) brings in fix(metadata-protocol): a draft's _diagnostics reports what its publish will refuse #26856 (+76 / −3 inprotocol.ts) and fix(spec)!: the view write door refuses an unknown top-level key #26851. The first merge's derivation reported a STALE TREE on two scripts, somainwas merged again.protocol.tsauto-merged both times with no conflict. So the merged tree was measured againstmainitself as well (see "The merged tree againstmain").Serial with the file's in-flight PRs
The claim named #26856, #26861 and #26880 as also editing
protocol.tsand asked for agit merge-treeagainst each before this PR was opened. All three had merged by then:protocol.tshunks auto-merged, and none of their changed lines falls in the three moved bodies or their stubs.mainafter the second merge. It editsprotocol.ts(+44 / −9 betweenmainand this head) andprotocol.lookup-artifact-item-call-sites.test.ts. It names none of the three members.git merge-treeof this head withmain8074feb642is clean. On that merged tree:main'sprotocol.tsreads 371 tokens, 0 differ, with 302 class members, 299 byte-identical and 3 stubs;tsc --noEmitinpackages/metadata-protocolexits 0;mainby this cut alone, 2 files, +123 / −28.The open PRs were checked against the head
e78313a068too. Of the 38 open, four touch this package:fix(metadata-protocol)!: refuse an object whose datasource names no datasource at save and publish #26912 edits
protocol.ts(+703 / −2 over 8 files) and names none of the three. Its merge-tree is clean.fix(lint)!: a field group's visibleWhen is judged like a field's own, at build and at the object save door #26928 touches one test file. Its merge-tree is clean.
fix(metadata-protocol,runtime,app-shell)!: refuse a save or draft publish naming a package that is not installed #26920 and feat(spec): a hook declares its refusal catalogue, and its body refuses by code, answered in the caller's language #26831 report conflicts, but not with this cut. Each conflicts with
mainalone on exactly the same paths, and none of those paths is in this change:scripts/engine-double-contract.pinned.jsonandui/packages/app-shell/src/views/metadata-admin/i18n.ts;content/docs/protocol/kernel/i18n-standard.mdx,packages/lint/src/validate-translation-references.test.ts,packages/spec/src/system/translation.zod.tsandui/packages/i18n/src/utils/spec-translations.ts.Against the move commit alone, both are clean.
mainmoved seven commits after the second merge: #26894, #26901, #26905, #26908, #26861, #26913 and #26915. Only #26861 touches this package (above). The derivation one78313a068found nothing stale, somainwas not merged a third time. The PR's merge ref runs them against this cut.The order's screen (private statics,
new Error(, the read-seam census)All three 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:88 read seam(s)and an identical list once[@:][0-9]+is stripped. The full readings are under "The durability--list".What moves
resolveFlowCanonicalizer:6585getServicesRegistry(field)resolveFlowRegistrationReader:6693getServicesRegistry(field); module-levelcanonicalMetaTypeflowRegistrationsOf:6711resolveFlowRegistrationReader(method)protocol-automation-flow-reads.tshas 104 lines.The shape (#23050 shape B, as cuts 1–26 apply it)
The class keeps all three members. Each keeps its name, docblock, signature and position. Each body now delegates, marked
[#25467 cut 27].AutomationFlowReadsHosttypes the two members the bodies read as the class members themselves (ObjectStackProtocolImplementation['getServicesRegistry']and['resolveFlowRegistrationReader']). Each function'sthisis aPickof the members it reads.getServicesRegistry, the constructor-supplied field, is handed over as a getter (the hand-over of cuts 20, 24 and 26). So each read finds the registry at call time, as before.flowRegistrationsOf's call toresolveFlowRegistrationReaderis handed over as a closure,(...a) => this.resolveFlowRegistrationReader(...a), as the order asked. So that call still reaches the class method (now its stub), not the moved function directly.No member changes visibility.
Every caller still calls the class method:
resolveFlowCanonicalizer: 4 callers (:20784,:21680,:25284,:25575, base);resolveFlowRegistrationReader:flowRegistrationsOfand:11244;flowRegistrationsOf::10100.None changes.
Module-level declarations, by reader: no import leaves
protocol.tsMeasured 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.tscanonicalMetaType./protocol.js, read at call time onlyFlowRegistration(type)@objectstack/spec/apiStoredFlowCanonicalization(type)./stored-migration.jsSo the top level of
protocol.tschanges by the new module's import alone. No import comment moves.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, including on the merged tree againstmain. The cut adds one import statement and its comment ahead of every class docblock, so the cut 25 comment-offset trap was watched. It did not fire: the raw hash is identical at both ends.Base
161e00e4eaand head13cd879d32were 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.c5edca148ff159d4ee49cb2a2b739a2db8695df0267142816c084fb94ca80dceat both ends, ondist/index.d.tsanddist/index.d.cts. The normaliser sorted 80 string-literal union runs. Sorted-union identity holds.455d53280fb9c9226324aeb678e5da84e5a0efae88a4bf210d35c4405942d1b5at both ends, 777,661 bytes. Raw identity holds.index.jshashesc9423dc904760728…at base and2dcd91000df2937a…at head (index.cjs599562da548797ec…→362063271dc2cdba…).….call(hostgoes 0 → 1 for each of the three members in both bundles.function …(declaration goes 0 → 1.privatewas dropped fromresolveFlowRegistrationReaderon disk (restored fromHEADunder a trap) and the package rebuilt. Both.d.tsfiles move to409763bd3a5619d6…(normalised2856b5a8fc02c6ba…, which differs from the bar'sc5edca14…) and printresolveFlowRegistrationReader(type: string): ((name: string) => FlowRegistration) | undefined;. So the bar can see a change on these members.9f18a0177ac736ed…on all of them. None of the three functions, and notAutomationFlowReadsHost, appears.The merged tree against
mainThe merges brought in #26880's and #26856's
protocol.tschanges, so the merged treee78313a068was measured againstmain57820085fa, 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, +123 / −28..d.ts: raw4f48a58b638106f9…(779,140 bytes) and normalised6b3acbaf32ddd812…, the same atmainand merged. Both identities hold.index.js:9c5d5525453d5395…atmain,3f469d2dc9064d24…merged. Export tables: 78 names,9f18a0177ac736ed…on both.main'sprotocol.tsagainst the merged one: 371 tokens, 0 differ.mainand merged both give 21,719 tests (21,693 passed, 0 failed, 26 skipped, 277 files), per test identical.No changeset:
skip-changeset, per ruling6348891160.The durability
--listcheck-durability-degradation-log-levelexits 0 at both ends with identical output:88 read seam(s)at both ends. Its--listis identical once[@:][0-9]+is stripped (164 lines, and no entry changes file).try, and none reads the gate's read vocabulary (find/findOne/count).88 read seam(s).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.tsat161e00e4eaagainst the head module:Negative controls, one per member. Each changed one token in an in-memory copy of the head module, and only the mutated member moved (differ 1; the other two stayed 0):
protocol.ts. All 259 base statements are byte-identical, leading comments included. Head adds one statement, the new module's import.Readers of the moved lines
The tests and scripts that read
protocol.tsby path, the test files inpackages/,docs/qa/,scripts/and the@objectstack/specliveness ledgers were grepped for the three member names.protocol.flow-canonicalizer.test.tsand a docblock inruntime-authoring-gate.ts. The two CHANGELOGs also mention them.protocol.flow-canonicalizer.test.tsdrivesresolveFlowCanonicalizerthrough the protocol's doors. It passes at both ends, in the package suite.manifest.json'sdependenciesrow →protocol.ts#resolveWritePackageScope(cut 19), andseed.json→protocol.ts#applySeedBodies(cut 14). These arepackages/spec/**, outside this card.check-adr-anchorsexits 0 with identical output at both ends (1,897 decision-letter citations, 60,008 citations). No moved line cites an ADR.check-engine-double-contract): exits 0 at both ends.updateData/deleteDataseams keep their entries at new line numbers (13898 → 13889, 13923 → 13914).productionFilesis 3,810 at base and 3,812 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–26.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 at161e00e4ea.Verification
tsc --noEmitinpackages/metadata-protocolexits 0 at head, on the merged tree, and on the merge-tree withmain8074feb642.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.161e00e4ea: 21,692 tests (21,666 passed, 0 failed, 26 skipped), 274 files.13cd879d32: 21,692 tests (21,666 passed, 0 failed, 26 skipped), 274 files.src/swapped tree-only from161e00e4ea(the new module removed) and restored fromHEADunder a trap.e78313a068andmain57820085faboth give 21,719 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 151 changed lines, under the 3,000-line human-merge bar.dispatch-gates --commands --repo objectstack-ai/objectstackderives 46 gates on 2 changed paths frome78313a068, with no stale-tree finding. 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.Carry-forward
These stay in
protocol.ts:findEnvironmentRows,packagelessAddress,findServedOverlayRow,foldStoredCollection,applyObjectRegistryMutation,unmanagedImportCollisions,rollBackUnmanagedImport,readRevertableCommitandstoredFlowBindingAgrees.rethrowUnlessMetadataStoreUnprovisionedcannot move at all.probeRecord,getMetaItemCached,findReferencesToMeta,refuseUnmintableMetaTypeandmetaTypeNamespaceExists.viewContainerNameCollisionRefusalwithoverlaidShippedContainerViewNames, andreportPageRequiresAbsentAtLoad.applyRegistryWriteThroughcallers,readCodeLayerForCarryForwardandensureObjectStorage.emitMetadataMutation,isArtifactBackedandisNestedArtifactField(thelookupArtifactItemsite pins), andgetOverlayRepo.refusePackagedBaseRemoval,packagedBaseRefusal,runPublishSideEffects,promoteDraftForPublish,publishPackageDraftsanddiscardPackageDrafts.warnClosureReadUnavailableandresolveSduiManifest.🤖 Generated with Claude Code
https://claude.ai/code/session_016SP1spj613tyGCgxoD1An6