Repository navigation
refactor(metadata-protocol): move the authoring gate's deployment-posture probes out of protocol.ts into protocol-authoring-posture-probes.ts (#25467 cut 26) - #26873
Conversation
…ture probes out of protocol.ts into protocol-authoring-posture-probes.ts (#25467 cut 26) Move-only, shape B. orgWallEnforced, tenancyPostureInForce, rlsMembershipResolverKeys and hierarchyResolverMounted move, unedited, into one module. orgWallEnforced reads no member, so its stub calls the plain function; the other three get the getServicesRegistry field as a getter. postureEnforcesWall, anonymousFormIntakePosture, RLS_MEMBERSHIP_RESOLVER_SERVICE and HIERARCHY_SCOPE_RESOLVER_SERVICE lose their last reader in protocol.ts and leave its imports, with the comments that explained them. 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 a76bfc329a649a034abe5d2ccaa291d67db278cf && git checkout a76bfc329a649a034abe5d2ccaa291d67db278cf
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin a20824f3661810909cfd701c29da1ba04e4a081d a885bdbbdfd48144b2d2608637795f60c348e271 && git checkout -B drift-repro a20824f3661810909cfd701c29da1ba04e4a081d && git merge --no-ff a885bdbbdfd48144b2d2608637795f60c348e271
node scripts/docs-audit/affected-docs.mjs --json a20824f3661810909cfd701c29da1ba04e4a081d |
席位核对 · ACCEPT ·
|
| item | reading |
|---|---|
| Shape | Draft, base main, Part of #25467 (cut 26). 2 files: protocol.ts and one new module for the claimed theme, protocol-authoring-posture-probes.ts (orgWallEnforced, tenancyPostureInForce, rlsMembershipResolverKeys, hierarchyResolverMounted). skip-changeset (move-only). Clause-②: no, Metadata-protocol: none. |
| Move check (seat) | 38 of the 41 non-blank lines the PR removes from protocol.ts are found verbatim (indent-stripped) in the new module. The other 3 are import lines that lost specifiers whose last reader moved: postureEnforcesWall, RLS_MEMBERSHIP_RESOLVER_SERVICE and HIERARCHY_SCOPE_RESOLVER_SERVICE. Each specifier is imported again in the new module, and protocol.ts keeps the narrowed imports. The added lines are the module's import and four stubs: orgWallEnforced is a plain call, since it reads no member, and the other three go through AuthoringPostureProbesHost with getServicesRegistry as a getter. Cut 8's gate-stub closures keep calling the class members. |
| Evidence | CI green on head a885bdbbdf (34 success, 16 skipped, 0 failed). Governed check: NOT governed, 179 changed lines. The report gives an AST compare of 233 tokens with 0 differ (each negative control moves only its own member), raw .d.ts identity at both ends with the normalised hash identical (ruling 6348891160), the suite at 21,648 tests per-test identical, the read-seam census at 88 with an identical --list, and 46 of 46 derived gates. After the merge brought in #26811, the merged tree against main gave .d.ts identity, 21,688 tests per-test identical and an AST compare with 0 differ. #26856 and #26861 also edit protocol.ts; both are merge-tree clean against this head, and tsc exits 0 on the head merged with #26856. |
| Disclosed | The check-adr-anchors decision-letter count goes from 1,898 to 1,897, because the moved [#6285] comment cites ADR-0105 D1 and leaves the anchored protocol.ts (as in cuts 8 and 12). |
| 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 26 of the
protocol.tssplit (#24586 ruling A, recorded in6270097840). Cuts 1–25 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 and #26807. The claim is6449989109. It takes the cut 26 proposal of the cut 25 report (6448075845), a themed group. All four members passed the AST screen and the read-seam census, and all four moved unedited.Four
ObjectStackProtocolImplementationmembers move unedited into one new module,packages/metadata-protocol/src/protocol-authoring-posture-probes.ts(#23050 shape B). They are the runtime authoring gate's deployment-posture probes: the four reads of this deployment thatassertRuntimeAuthoringRuleshands the gate on every write.orgWallEnforced: does the configured tenancy posture wall organizations ([转移] 发布期护栏:多组织下「平台级 + schedule + create_record + 未显式 organization_id」拒绝——#6155 Q3=A 裁决的 lint 半边 #6285)? An unreadable posture reads as walled.tenancyPostureInForce: the posture thetenancyservice reports in force, for the public-form intake advisory (forms: on a walled tenancy posture a published public form bound to a tenant-scoped object is served (GET 200) but every anonymous submit answers 500 ERR_SYSTEM_WRITE_ORGANIZATION_REQUIRED #21476).rlsMembershipResolverKeys: the membership keys the mounted RLS resolver declares.hierarchyResolverMounted: is a hierarchy resolver mounted (metadata save + explain: an unlicensed hierarchy scope saves silently at runtime though defineStack refuses it, and explain blames the depth #26188)?protocol.tsloses 17 net lines (29,127 to 29,110). 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 frommainaeb9cf0ddc(after cut 25's merge). It names no issue, so the claim comment is the identity record. It holds the move commit98200caa10and one merge ofmain,a885bdbbdf(10 commits). Unlike the last cuts, this merge does touchpackages/metadata-protocol/. It brings in #26811 (#26644,findData/getDatainprotocol.ts), which merged while this cut was being measured, and the seed-loader change.protocol.tsauto-merged 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
Measured just before this PR was opened, against the merged head
a885bdbbdf: of the 38 open PRs, two editprotocol.ts, and each one'sgit merge-treeis clean against this head.fix(metadata-protocol): a draft's _diagnostics reports what its publish will refuse #26856 (the draft verdict harness) edits
protocol-authoring-gate.tsandprotocol.ts. It names three of the moved members, in two ways:RuntimeRulesHostPickoverAuthoringGateHostthat lists them;(...a) => this.hierarchyResolverMounted(...a)-style closures inprotocol.ts.Both reach the class methods, which this cut keeps as stubs with unchanged signatures. Its merge with this head was built and type-checked:
git merge-treeto a tree, thentsc --noEmitinpackages/metadata-protocolon that tree exits 0.feat(metadata): the layered read takes the bundle member selector #26861 edits
protocol.tsaround:11300–11500(thelookupArtifactItemcall sites), far from this cut's hunks.Two more touch only test files of this package, each merge-tree clean against head: #26851 (2 files) and #26831 (1). #26811, which the claim asked about, had merged before this PR was opened, so it is part of the merge above rather than an overlap.
mainmoved six commits after the merge: #26742, #26769, #26799, #26823, #26827 and #26829. Two edit test files of this package:protocol.item-name-grammar.test.ts(#26769) andruntime-authoring-gate.email-template-writes.test.ts(#26799). None editsprotocol.tsor the gate's source, andgit merge-treewith this head is clean. The derivation found nothing stale, somainwas not merged again. The PR's merge ref runs those tests against this cut.The order's screen (private statics,
new Error(, the read-seam census)All four 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
orgWallEnforced:7394tenancyPostureInForce:7428getServicesRegistry(field)rlsMembershipResolverKeys:7450getServicesRegistry(field)hierarchyResolverMounted:7478getServicesRegistry(field)protocol-authoring-posture-probes.tshas 114 lines.The shape (#23050 shape B, as cuts 1–25 apply it)
[#25467 cut 26].orgWallEnforcedreads no member. This was measured by an AST walk overthisaccesses, withascasts, parentheses and!stripped, and barethischecked. So its stub is a plain call,return orgWallEnforced();, as cuts 16, 21 and 23 did.getServicesRegistryfield.AuthoringPostureProbesHosttypes it as the class member itself (ObjectStackProtocolImplementation['getServicesRegistry']). Each stub hands it over as a getter (the hand-over of cuts 20 and 24). So each probe reads the registry at call time, and a resolver registered after this protocol is assembled is seen by the next write, as before.assertRuntimeAuthoringRulesstub (:7102,:7103,:7106,:7107, base). They do not change.Module-level declarations, by reader: four imports leave
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.tsimported itprotocol.tspostureEnforcesWall@objectstack/spec/securityanonymousFormIntakePosture@objectstack/metadata-coreRLS_MEMBERSHIP_RESOLVER_SERVICE@objectstack/spec/contractsFIELD_FILE_SERVICEstays)HIERARCHY_SCOPE_RESOLVER_SERVICE./runtime-authoring-gate.jsresolveTenancyPosture@objectstack/types:15259)TenancyPosture(type)@objectstack/spec/securityTwo import comments move with their imports. Each explained exactly the name that left:
[#6285]comment over the@objectstack/spec/securityimport ("ADR-0105 D1's authority on 'does this deployment wall organizations?'… the posture, and only the posture, is what the runtime authoring gate is told");[#21476]comment overanonymousFormIntakePostureinside the@objectstack/metadata-coreimport.Both now sit, byte-identical, over the same imports in the new module. Leaving them in
protocol.tswould have left two comments explaining imports it no longer has.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. As the claim warned, four imports leaveprotocol.tsand nine lines leave the import block, so the emitted specifiers and the cut 25 comment-offset trap were watched. Neither moved: the raw hash is identical at both ends.Base
aeb9cf0ddcand head98200caa10were 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.6de2d665caaedb0a17a1db1c77288a3a8108df3e78edb5f7d4e490f09fbccde4at both ends, ondist/index.d.tsanddist/index.d.cts. The normaliser sorted 80 string-literal union runs. Sorted-union identity holds.b73f06345eff65ebf7ffa0180caf62d8b3ebb16a29931060a115b6d949d4e203at both ends, 777,497 bytes. Raw identity holds.index.jshashesf40d769609a618d7…at base andfda9ac7d969284cc…at head (index.cjs4144276cf3ac53bc…→736a7dde582b26bb…).….call(hostgoes 0 → 1 for the three host-reading members in both bundles, andorgWallEnforcedhas no.call.function …(declaration goes 0 → 1.privatewas dropped fromrlsMembershipResolverKeyson disk (restored fromHEADunder a trap) and the package rebuilt. Both.d.tsfiles move to90baecbeff563e05…(normalisedf75a46f7798ad08d…, which differs from the bar's6de2d665…) and printrlsMembershipResolverKeys(): readonly string[] | undefined;. So the bar can see a change on these members.9f18a0177ac736ed…on all of them. None of the four functions, and notAuthoringPostureProbesHost, appears.The merged tree against
mainThe merge brought in #26811's
protocol.tschange, so the merged treea885bdbbdfwas measured againstmaine1bfde3601, 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, +138 / −41..d.ts: raw455d53280fb9c922…(777,661 bytes) and normalisedc5edca148ff159d4…, the same atmainand merged. Both identities hold.index.js:c2202f9429366633…atmain,c9423dc904760728…merged. Export tables: 78 names,9f18a0177ac736ed…on both.main'sprotocol.tsagainst the merged one: 233 tokens, 0 differ.mainand merged both give 21,688 tests (21,662 passed, 0 failed, 26 skipped, 274 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).tryguards a service-registrygetor the posture read, none in 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.tsataeb9cf0ddcagainst 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 three stayed 0):
Class side. There are 301 members at base and at head, in the same order. The 297 that did not move are byte-identical to base, leading comments included. All four stubs sit at their base positions and keep their docblocks and signatures byte-identical.
Top level of
protocol.ts. Of the 255 base statements, 251 are byte-identical, leading comments included. The other four are the import statements that each lost one name:@objectstack/spec/security(with its[#6285]comment);./runtime-authoring-gate.js;@objectstack/metadata-core(with the[#21476]comment inside it);@objectstack/spec/contracts.Nothing else changed in any of them. Head adds one statement, the new module's import.
Size. +138 / −41 over 2 files, 179 changed lines (the proposal's estimate was 160–220).
Readers of the moved lines
The tests and scripts that read
protocol.tsby path were grepped for the four member names, the four dropped imports and the two moved comments' tags (#6285,#21476). These are the 26 files that nameprotocol.tsand callreadFileSync. So were the test files inpackages/,docs/qa/and the@objectstack/specliveness ledgers.By path: none reads a moved line. The one textual hit is
orgWallEnforcedinprotocol.bracketed-refusal-opener-absence.test.ts. It is the gate's input key, passed toevaluateRuntimeAuthoringGate, not the member.Behaviour through the gate, no edit owed. These pass the same keys as gate inputs, or drive the gate through the protocol:
protocol.platform-schedule-org-gate.test.ts,runtime-authoring-gate.public-form-intake.test.tsandruntime-authoring-gate.hierarchy-scope.test.ts(metadata-protocol);validate-membership-key-declarations.test.tsandvalidate-rls-predicate-enforceability.membership-keys.test.ts(lint);explain-engine.test.ts(plugin-security).The metadata-protocol ones pass at both ends, in the package suite.
The liveness ledgers. No row points at any of the four. 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 at both ends.[#6285]comment citesADR-0105 D1and left the anchoredprotocol.ts, as in cuts 8 and 12.Engine-double contract (
check-engine-double-contract): exits 0 at both ends.updateData/deleteDataseams keep their entries at new line numbers (13838 → 13821, 13863 → 13846).productionFilesis 3,804 at base and 3,806 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–25.Identical output at both ends:
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 ataeb9cf0ddc.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.aeb9cf0ddc: 21,648 tests (21,622 passed, 0 failed, 26 skipped), 273 files.98200caa10: 21,648 tests (21,622 passed, 0 failed, 26 skipped), 273 files.src/swapped tree-only fromaeb9cf0ddc(the new module removed) and restored fromHEADunder a trap.a885bdbbdfandmaine1bfde3601both give 21,688 tests, per test identical (0 lost, 0 added, 0 changed).check-platform-checklist --changed-from origin/main(merged tree): OK, 0 anchors 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 179 changed lines, under the 3,000-line human-merge bar.dispatch-gates --commands --repo objectstack-ai/objectstackderives 46 gates on 2 changed paths froma885bdbbdf, 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.check-durability-degradation-log-level --listona885bdbbdf:88 read seam(s).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.refusePackagedBaseRemoval,packagedBaseRefusal,runPublishSideEffects,promoteDraftForPublish,publishPackageDraftsanddiscardPackageDrafts.warnClosureReadUnavailableandresolveSduiManifest.🤖 Generated with Claude Code
https://claude.ai/code/session_016SP1spj613tyGCgxoD1An6