Repository navigation
refactor(plugin-security): move SecurityPlugin's controlled-by-parent write gate into security-plugin-cbp-write-gate.ts (#25223 cut 3) - #25324
Conversation
… write gate into security-plugin-cbp-write-gate.ts Cut 3 of the security-plugin.ts split, move-only. The bodies of checkControlledByParentWrite, assertControlledByParentWrite, assertControlledByParentChainEditable, controlledByParentPredicateWriteMasters and assertMasterRowEditable move unedited to a new module beside it, with MASTER_EDIT_DENIAL_LEG, controlledByParentWriteOutcomeOf, writesMasterReference and the error imports only they read. Each method keeps its name, signature, docblock and position and hands its body one Pick-typed host (ql and permissionEvaluator as getters, methods as late-bound closures); the stubs drop async and return the moved function's promise. Five module-level values the bodies read stay in security-plugin.ts and are exported for the module's call-time import: CBP_MAX_CHAIN_DEPTH (ADR-0055 symbol anchor), requiredCapsForOperation (spec liveness anchor), and the three predicate-write helpers readableRowsScopeForPredicateWrite shares. index.ts re-exports only SecurityPlugin, so the package surface is unchanged. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017BoLT8Gaa8t9a7AWVH8qZa
…-detail write check at the module its body moved to The served check's elevation read (`context?.isSystem`, the write path's own first exit) now lives in `security-plugin-cbp-write-gate.ts`, inside `checkControlledByParentWrite`. Row 9b's anchor follows it; the row's prose, and every other row, is unchanged. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017BoLT8Gaa8t9a7AWVH8qZa
📓 Docs Drift CheckThis PR changes 1 package(s): 4 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
What this run could not see
Coarse fallback — 16 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 34a34a959934e0ef69cfac76bd18202c7a787a43 && git checkout 34a34a959934e0ef69cfac76bd18202c7a787a43
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 7b047b4483cbdc5423a879be5d604e09986678f6 d87954919b0a3720ee318253b45263ea826e9733 && git checkout -B drift-repro 7b047b4483cbdc5423a879be5d604e09986678f6 && git merge --no-ff d87954919b0a3720ee318253b45263ea826e9733
node scripts/docs-audit/affected-docs.mjs --json 7b047b4483cbdc5423a879be5d604e09986678f6
|
席位核对 · ACCEPT · 2026-10-23T01:42Z
Generated by Claude Code |
Requested by Sales · project thread
Part of #25223
Clause-②: no
Metadata-protocol: none
Ruling-ref: 6353073966
Cut 3 of the
security-plugin.tssplit. The claim is 6354388643. The bodies of five async methods move unedited to the new modulepackages/plugins/plugin-security/src/security-plugin-cbp-write-gate.ts:checkControlledByParentWriteassertControlledByParentWriteassertControlledByParentChainEditablecontrolledByParentPredicateWriteMastersassertMasterRowEditableTogether they are the ADR-0055 §3 controlled-by-parent write gate the write path runs at step 2.8, and the check the
securityservice serves. The three module-level declarations only those bodies read move with them:MASTER_EDIT_DENIAL_LEG,controlledByParentWriteOutcomeOfandwritesMasterReference. So do the four error classes only those bodies construct or test.It is move-only, and the card stays open for the later cuts. Branch:
claude/project-thread-3fzya4, the harness-pinned branch for this session, restarted fromorigin/mainat21a25dd9f1(cut 2's merge). It names no issue, so the claim comment is the identity record.Five exports, said up front.
security-plugin.tsadds theexportkeyword to five module-level declarations, and the new module imports them by value. Each line is otherwise byte-identical to base, andindex.tsre-exports onlySecurityPlugin, so none reaches the package's surface (the export tables below are unchanged). They stay insecurity-plugin.tsfor these reasons:CBP_MAX_CHAIN_DEPTH: ADR-0055:135 anchors it by symbol in that file (ruling 6353073966 item 5), andcontrolledByParentChainRefusalthere walks it too.requiredCapsForOperation:packages/spec/liveness/object.jsonanchors it by symbol in that file, and that file belongs to the spec lane. The CRUD gate reads it too.PREDICATE_WRITE_READABLE_ID_CAP,predicateWriteReadableCapErrorandcopyOfCallerPredicate:readableRowsScopeForPredicateWrite, which stays, reads all three. Moving them would leave a value import running the other way.Each value is read only inside a function body, at call time, never while either module evaluates. So the two-way import is safe under ESM, and the published bundle holds one module. The plugin's 4403 tests run on the source modules, cycle included, and pass.
These stay in
security-plugin.tsbyte for byte, by ruling item 4, until docs PR #25316 (card #25314) lands:computeControlledByParentFilter,controlledByParentChainRefusalandcomposeWriteTenantWall.The published
.d.tsdoes not changeUnder the series bar (ruling 6348891160 item 1), measured on base
21a25dd9f1and on the head (the tree of this PR's commit):dist/index.d.tsanddist/index.d.mts, base and head, all four the same:803f5bfb7da0b00f8cd8d8f25172463d8dfb07d93fbdd8a9c6f4d4b7435e429a. The raw diff is 0 lines, so no union order moved either.b6b5c1b7fa6fa188f6e2f7e4cca3816a246b570f20d708643d116012aa86fa77.packages/plugins/plugin-security(it sorts the members of each string-literal union and changes nothing else):dist/index.d.ts, line 2308 (private assertControlledByParentWrite;):assertControlledByParentWrite;): rawea8bebdf8cd6c0e974393bf00a9434fce8ec2ba1c3cb816549fd203c39cb90c7, normalised1a405f50b386e1209593962447896d000b736456d5dcaa64ab8f9921522053bb.private assertControlledByParentWriteRenamed;): raw7a055168bef89d872b54102a60b735a6f12e7bf1af7f367ea67531e10b56654e, normalised5f730b82bac2ce457a64717cd57973fa75fcf06d0aee180f1b5cb86c8e4d83ab.f607fd765d6b277e08b3b46ccb16d1e2d133ec55658ffe40155aef25e1bf54f0on all four, the same as at cut 2.index.js6d2a398ftoaece9708,index.mjs953c5d9ato38b8f218), because code moved within them.No changeset:
skip-changeset, per ruling 6348891160 item 4.What moved
Base line numbers are each member's signature at
21a25dd9f1. The last column lists the members the body reads, which is exactly what its host carries.checkControlledByParentWrite:9363-:9390assertControlledByParentWrite,declaresControlledByParent,resolveOperationPrincipalsassertControlledByParentWrite:9525-:9780assertControlledByParentChainEditable,controlledByParentPredicateWriteMasters,declaresControlledByParent,extractSingleId,readRowById,resolveCbpRelationassertControlledByParentChainEditable:9804-:9899assertMasterRowEditable,declaresControlledByParent,readRowById,resolveCbpRelationcontrolledByParentPredicateWriteMasters:9937-:9986qlassertMasterRowEditable:10003-:10230checkAuthoredRowWrite,collectRLSPolicies,computeRlsFilter,declaresControlledByParent,delegatorOwnWriteFloorOptions,getObjectSecurityMeta,permissionEvaluator,ql,resolveSharingCanEdit,resolveSharingWriteVerdictAll five methods are async, and every moved function is async too.
Module-level declarations that move, each with its docblock and verbatim:
MASTER_EDIT_DENIAL_LEG(base:659, 11 lines with its docblock),controlledByParentWriteOutcomeOf(:673, 24 lines) andwritesMasterReference(:740, 15 lines). No code left insecurity-plugin.tsreads them.Imports:
MasterDetailRelationMissingError,DetailRecordNotFoundError,MasterReferenceMissingErrorandMasterReferenceNotWritableErrorleave theerrors.jsimport ofsecurity-plugin.ts. No code there reads them any more. The module imports them, plus the names its bodies share with code that stays (withoutOperationPrivateKeys, the metadata-core engine dispatch resolvers,PermissionSet, the two contract types andisPlatformOwnershipFloorPolicy). Those stay imported insecurity-plugin.tstoo.The shape (#23050 shape B, as cuts 1 and 2 applied it)
.d.ts. Each body is now one host literal plusfn.call(host, …), marked[#25223 cut 3].CbpWriteGateHosttypes every member as the class member itself (SecurityPlugin['m']). Each moved function types itsthisas thePickof the host over exactly the members its body reads, and each stub annotates its literal with the samePick. There is no cast, and no member becomes public or protected.SecurityPlugintype-only.CbpRelationkeeps its one declaration insecurity-plugin.ts, and the module names it through the class's own signature, as cut 2's module does (an alias over the non-null return type ofSecurityPlugin['resolveCbpRelation']).this.m(...a)on the plugin at call time. A spy or test double set on the plugin is still the one the gate reaches. The bodies that call one another (the check and the gate, the gate and its chain walk, each leg and the master-row verdict) still do so through the plugin. No moved body calls a function-valued field, so no receiver changes.qlandpermissionEvaluatorgo as getters, because neither is declaredreadonly.start()assignsqlafter construction, andsecurity-plugin.test.tsreplacespermissionEvaluatoron a constructed plugin. The host declares bothreadonly, so a moved body cannot assign a member through it; the typecheck passes, so none does.asyncand returns the moved function's own promise. Building the host reads no field and runs no getter, and calling an async function never throws synchronously, so a caller awaits a promise that settles exactly as the old method's did.{@link}tags to the four error classes, byte for byte. Those names are no longer imported insecurity-plugin.ts, so an editor shows the links unresolved there. No gate resolves docblock links, and the.d.tsis unchanged.Proof of move-only
asyncmatch. A negative control,if (context?.isSystem)changed toif (!context?.isSystem), fails the check.asyncdropped. The three moved declarations are verbatim in the module and absent fromsecurity-plugin.ts. Each of the five exported values is its base text withexportadded and nothing else.CbpRelation,computeControlledByParentFilter,controlledByParentChainRefusalandcomposeWriteTenantWallare byte-identical to base.git diff --color-moved=plain --color-moved-ws=allow-indentation-change 21a25dd9f1 HEADover the two source files): 673 of 683 deleted lines and 709 of 923 added lines are detected as moved.export, and the fiveprivate asyncsignature lines that loseasync.CbpRelationalias,CbpWriteGateHost, one pointer docblock per function and the rewritten signature heads. The rest are lines git does not pair with a moved block, such as blanks and closing braces.security-plugin.tsgoes from 10,823 to 10,208 lines.ADR anchors (ruling 6353073966 item 2)
node scripts/check-adr-symbol-anchors.mjs: exit 0 at base21a25dd9f1and exit 0 at head, both with2383 anchors across 142 records resolve — 467 symbol (440 declaration, 27 literal), 1888 file-level, 28 cross-repo, 6 exempt, 18 continuation. CI runs this gate (lint.yml), butdispatch-gates --commandsdoes not derive it for this change set ([finding] dispatch-gates derives the symbol-anchor sweeps only from their corpus paths, so a change that removes an anchored symbol from a TARGET file passes every local gate and reds CI #21697), so it is run by hand here.pnpm check:adr-anchors: exit 0, 77 anchored files (76 at base, plus the new entry). The new entry isscripts/adr-anchors/packages__plugins__plugin-security__src__security-plugin-cbp-write-gate.ts.json. It carries ADR-0055 and the §1 invariant paragraph of thesecurity-plugin.tsentry, verbatim, as cut 2's entry does. Its "writes throw MasterDetailRelationMissingError" half is the gate's relation leg, which now lives here. The moved comments also cite ADR-0066 and ADR-0090. Like thesecurity-plugin.tsentry, which lists four of the many ADRs that file cites, the new entry does not list them, and the gate passes. Thesecurity-plugin.tsentry is unchanged, because the methods, their docblocks and the read half remain in that file.docs/adr/**is not touched.security-plugin.ts: 28 anchors, 20 symbols, 10 ADRs. It was measured withextractAnchorsandsymbolSegmentResolutionfromscripts/symbol-anchors.mjs, which is measurement, not a new gate. It was read on21a25dd9f1BEFORE the cut, with the five ranges blanked: no anchor changed class. Every anchor resolves at head insecurity-plugin.tswith its base class.The table gives each anchor's class at base and head, the code lines it resolves on, and the member each line sits in. The member is shown after the line number. Every anchor stays in
security-plugin.ts.#CBP_MAX_CHAIN_DEPTH:635(top-level):643(top-level, now exported)#SecurityPlugin:1377(class):1332(class)#SecurityPlugin.getMetadataReadableFields:2526(start),:6119(method):2481,:6074#SecurityPlugin.resolvePermissionSetsForContextUnmemoized:7030(method):6985(method)#assertControlledByParentWrite:9525(method):9465(method shell)#assertMasterRowEditable:10003(method):9591(method shell)#collectRLSPolicies:10260(method):9645(method)#computeControlledByParentFilter:9071(method):9026(method)#computeDelegatedReadFilter:5997(method):5952(method)#computeRlsFilter:5249(explainAccessForCaller),:7652(method):5204,:7607#controlled_by_parent:9080(computeControlledByParentFilter),:9146(controlledByParentChainRefusal):9035,:9101#getReadFilter:2289(start),:5875(method):2244,:5830#hasPlatformAdminPosture:7679(method):7634(method)#isPrincipalLessContext:489(top-level):497(top-level)#manage_metadata:238(PLATFORM_ADMIN_ONLY_CAPABILITIES):246#nav_permission_sets:1782(init):1737#refuseNoActiveOrganization:8492(local incomposeWriteTenantWall):8447#rlsFilter:4352(local instart):4307#sharingModel:9079(local incomputeControlledByParentFilter):9034#writeCheckPolicies:1272(top-level):1227(top-level)No resolving site moves. The two anchors that name a moved method resolve on its declaration, which stays as a shell.
#collectRLSPoliciesand#computeRlsFilterare read byassertMasterRowEditable, but they resolve on their own declarations, which do not move.At head, four of these names appear on extra lines inside the stubs:
assertControlledByParentWrite,assertMasterRowEditable,collectRLSPoliciesandcomputeRlsFilter. Each is a key of a host literal (a line-start member key, so declaration-class) and a quoted member of the stub'sPicklist (a literal). The class each anchor resolves with is the same at head as at base.The three anchors ruling item 4 holds for #25316 (ADR-0055:26
#sharingModel, ADR-0055:58#controlled_by_parentand ADR-0123:4#refuseNoActiveOrganization) still resolve only insidecomputeControlledByParentFilter,controlledByParentChainRefusalandcomposeWriteTenantWall. This cut does not touch those bodies.Readers
One docs anchor reads a moved line by path: row 9b of
content/docs/permissions/system-context.mdx, re-pointed below. No test, script, gate or baseline does. (Corrected by the seat; the report6355294898carries the same correction.)check-system-context-censusexits 1 on the cut without it. The served check's elevation read,if (context?.isSystem) return { outcome: 'allow' };, is the first line ofcheckControlledByParentWrite's body, so it moved with the body. The census then finds that read in the new module with no row pointing at it (file-without-a-row). The page's row 9b still namessecurity-plugin.ts#checkControlledByParentWrite, where the census no longer sees a read (anchor-is-not-a-read-site).d87954919b. Row 9b ofcontent/docs/permissions/system-context.mdxnow anchorspackages/plugins/plugin-security/src/security-plugin-cbp-write-gate.ts#checkControlledByParentWrite. That is a one-line change, and the row's prose and every other row are unchanged. The page is hand-written and not a governed surface. The claim's surface covers it: a docs anchor that reads a moved line by path moves in the same PR.21a25dd9f1and head, compared withnode scripts/isystem-census.mjs --json: the same 148 elevation read sites, the same symbols, receivers and text, once the one moved site's file is mapped back tosecurity-plugin.ts.nonElevationReads,roleCountsandstaleLedgerRowsare identical. The gate then exits 0 at head with the same summary as base, except that the sites now span 70 files instead of 69. Its--self-testexits 0 too.check-scripts-symbol-anchors,check-spec-docblock-symbol-anchors,pnpm --filter @objectstack/spec check:liveness, andcheck-platform-checklist --changed-from origin/main. The last of these judged 6 anchors and lost 0.packages/spec/liveness/object.jsonanchorssecurity-plugin.ts#requiredCapsForOperation, which stays.security-plugin.ts:Ncitation in the repo points into a moved range. The moved ranges at21a25dd9f1are:649-:684,:732-:746and the five method bodies between:9363and:10230.:120-:167(the new import), by +8 for base:172-:648(four error names left theerrors.jsimport), by -29 for base:686-:731and by -45 for base:747-:9362.:132,:303,:309,:1614,:1690,:1736,:3215,:3281,:3519and:4344all land in those shifted ranges. They are the same list cut 2 read, inCHANGELOG.md,docs/launch-readiness.md,docs/design/predicate-compilation-convergence.md,packages/objectql/src/engine.tsandpackages/spec/liveness/object.json. Cut 2's report found every one of them already pointing at an unrelated line, so this cut does not make any of them wrong.node scripts/docs-audit/affected-docs.mjs --json 21a25dd9f1(advisory): 4 pages.system-context.mdxis the page re-pointed above.authorization.mdx,explain.mdxandrls.mdxare reached only through the string literal'not_applicable'insidecheckControlledByParentWrite. The literal moved unchanged and its behaviour is the same, so there is nothing to edit on those pages.21a25dd9f1and head and compared:check-platform-object-tenancy-census,check-position-name-fold-loaders,check-registry-log-declared,check-rest-log-spy-declared,check-tenant-audit-census(237 write call sites at both),check:cross-package-test-inputs,check:driver-memory-censusandcheck:query-options-erasure. The last of these reports the same counts at both, andsecurity-plugin.tsis not a baseline key. The moved bodies carry no erasure site the baseline counts.check-undeclared-dep-imports: 3288 to 3289 files, and 2827 to 2831 specifiers. The 4 are the new module's package imports (@objectstack/core,@objectstack/spec/security,@objectstack/metadata-coreand@objectstack/spec/contracts), all declared dependencies.check:doc-authoring: 1411 to 1412 sources.check:org-identifier: 3630 to 3631 files.check:logger-receiver-detach: 3604 to 3606 files. The second extra file isapps/docs/.next/types/validator.ts, a gitignored local build output of the docs app, as at cut 2. It is not in the tree CI checks out.check-system-context-census: compared above.check-issue-citationsjudges a change set, so it has nothing to read at base. At head it judged 40 citations across 2 files, and all resolve.Acceptance notes
docs/adr/**.security-plugin.ts, with one import after thecatalog-reference-report.jsimport and one block insidestart(). This cut has no hunk in either place. docs(adr): repoint three security-plugin.ts symbol anchors to declarations the class keeps #25316 touches onlydocs/adr/0055anddocs/adr/0123.composeWriteTenantWall,computeControlledByParentFilterorcontrolledByParentChainRefusaluntil docs(adr): repoint three security-plugin.ts symbol anchors to declarations the class keeps #25316 lands (ruling item 4).Gates
All gates ran at the head, the tree of
d87954919b, on base21a25dd9f1.origin/mainhas not moved since that base.pnpm --filter @objectstack/plugin-security test(vitest run --maxWorkers=3, under the verify lock): Test Files 210 passed (210), Tests 4403 passed, 45 skipped (4448). Base21a25dd9f1gives the same counts. VERDICT command-exit 0 on both. This ran on the cut commitc3e6ac12cd; the second commit changes only the docs page.pnpm --filter @objectstack/plugin-security typecheck: exit 0. It runstsc --noEmit, the scripts tsconfig, andcheck:test-typecheck.eslint --no-inline-configover the two touched source files: exit 0.pnpm --filter @objectstack/plugin-security build: exit 0. It produced the.d.tsand bundles measured above.node scripts/check-adr-symbol-anchors.mjsexit 0,pnpm check:query-options-erasureexit 0, plus the three symbol-anchor gates under Readers. None of these is derived for this change set; each was run by hand.dispatch-gates --commands: 92 commands on the 4 changed paths (62 for the cut alone; the docs page adds 30 docs-family gates). The--ranreconciliation shows 92 derived, 92 run, 0 NOT-MEASURED, 0 UNRUN. The zero is derived: all 92 recorded an exit code and none is 3.pnpm --filter @objectstack/spec run check:docsexited 1 because the localpackages/spec/json-schematree was older thanpackages/spec/src, andpnpm --filter @objectstack/spec run check:skill-examplesexited 3 because the local specdistwas stale. Afterpnpm --filter @objectstack/spec build(which left the tree clean), both exit 0. The list below records those re-runs.Per command (exit code):
node scripts/check-ci-filter-parity.mjsexit 0node scripts/check-closing-keyword-parity.mjsexit 0node scripts/check-closing-keyword-parity.mjs --self-testexit 0node scripts/check-comment-mask-adoption.mjsexit 0node scripts/check-comment-mask-adoption.mjs --self-testexit 0node scripts/check-comment-mask-corpus.mjsexit 0node scripts/check-doc-frontmatter.mjsexit 0node scripts/check-doc-frontmatter.mjs --self-testexit 0node scripts/check-doc-route-spelling.mjs --advisoryexit 0node scripts/check-doc-route-spelling.mjs --self-testexit 0node scripts/check-docs-section-name.mjsexit 0node scripts/check-docs-section-name.mjs --self-testexit 0node scripts/check-dts-emitted.mjs --self-testexit 0node scripts/check-issue-citations.mjsexit 0node scripts/check-keyed-text-bounds.mjsexit 0node scripts/check-keyed-text-bounds.mjs --self-testexit 0node scripts/check-platform-object-tenancy-census.mjsexit 0node scripts/check-platform-object-tenancy-census.mjs --self-testexit 0node scripts/check-plugin-teardown-shape.mjsexit 0node scripts/check-plugin-teardown-shape.mjs --self-testexit 0node scripts/check-position-name-fold-loaders.mjsexit 0node scripts/check-position-name-fold-loaders.mjs --self-testexit 0node scripts/check-registry-log-declared.mjsexit 0node scripts/check-registry-log-declared.mjs --self-testexit 0node scripts/check-rest-log-spy-declared.mjsexit 0node scripts/check-rest-log-spy-declared.mjs --self-testexit 0node scripts/check-scripts-symbol-anchors.mjsexit 0node scripts/check-scripts-symbol-anchors.mjs --self-testexit 0node scripts/check-section-landing-index.mjsexit 0node scripts/check-section-landing-index.mjs --self-testexit 0node scripts/check-system-context-census.mjsexit 0node scripts/check-system-context-census.mjs --self-testexit 0node scripts/check-tenant-audit-census.mjsexit 0node scripts/check-tenant-audit-census.mjs --self-testexit 0node scripts/check-undeclared-dep-imports.mjsexit 0node scripts/check-undeclared-dep-imports.mjs --self-testexit 0node scripts/docs-audit/check-affected-docs.mjsexit 0node scripts/docs-audit/check-drift-comment.mjsexit 0pnpm --filter @objectstack/lint run check:doc-formula-expressionsexit 0pnpm --filter @objectstack/lint run check:doc-security-postureexit 0pnpm --filter @objectstack/spec run check:docsexit 0pnpm --filter @objectstack/spec run check:duration-unit-keysexit 0pnpm --filter @objectstack/spec run check:empty-stateexit 0pnpm --filter @objectstack/spec run check:livenessexit 0pnpm --filter @objectstack/spec run check:skill-examplesexit 0pnpm --filter @objectstack/spec run check:strictness-ledgerexit 0pnpm --filter @objectstack/spec run check:variant-docsexit 0pnpm --filter @objectstack/spec run check:yaml-examplesexit 0pnpm check:adr-anchorsexit 0pnpm check:agent-test-spellingexit 0pnpm check:bash32-floorexit 0pnpm check:cli-command-idsexit 0pnpm check:closed-ceremony-textexit 0pnpm check:corpus-claim-driftexit 0pnpm check:cross-package-test-inputsexit 0pnpm check:doc-anchorsexit 0pnpm check:doc-authoringexit 0pnpm check:docs-audit-scopeexit 0pnpm check:docs-redirectsexit 0pnpm check:docs-single-h1exit 0pnpm check:docs-spec-enumerationsexit 0pnpm check:docs-transcript-driftexit 0pnpm check:driver-memory-censusexit 0pnpm check:dts-closureexit 0pnpm check:dual-build-cjs-loadsexit 0pnpm check:entry-guardexit 0pnpm check:error-status-conformanceexit 0pnpm check:gitlink-declaredexit 0pnpm check:i18nexit 0pnpm check:i18n-stale-fillexit 0pnpm check:issue-citationsexit 0pnpm check:lean-entry-closureexit 0pnpm check:logger-receiver-detachexit 0pnpm check:merge-driverexit 0pnpm check:nul-bytesexit 0pnpm check:org-identifierexit 0pnpm check:page-declaration-shapeexit 0pnpm check:parse-guardexit 0pnpm check:pnpm-filter-targetsexit 0pnpm check:pnpm-flag-spellingsexit 0pnpm check:published-filesexit 0pnpm check:published-readme-linksexit 0pnpm check:react-page-adapter-contractexit 0pnpm check:refd-timer-probeexit 0pnpm check:role-wordexit 0pnpm check:skill-identifier-livenessexit 0pnpm check:slot-lookupexit 0pnpm check:sourcemap-no-sources-contentexit 0pnpm check:test-source-aliasexit 0pnpm check:tier-file-adoptionexit 0pnpm check:vendor-version-stampsexit 0pnpm check:watch-hint-literalexit 0pnpm check:query-options-erasureexit 0node scripts/check-adr-symbol-anchors.mjsexit 0node scripts/check-spec-docblock-symbol-anchors.mjsexit 0pnpm --filter @objectstack/spec check:livenessexit 0node scripts/check-platform-checklist.mjs --changed-from origin/mainexit 0Generated by Claude Code
🤖 Generated with Claude Code
https://claude.ai/code/session_017BoLT8Gaa8t9a7AWVH8qZa