Repository navigation
refactor(plugin-security): move the permission-set resolution and addressed-write readers out of security-plugin.ts (#25223 cut 8) - #25406
Conversation
…ressed-write readers out of security-plugin.ts The bodies of resolvePermissionSetsForContextUnmemoized (the resolution itself: the position fold, the human baseline or the agent ceiling, the fallback), dropDeactivatedFoldedSets, reportNameFoldCollisions and permissionSetMemoKey move unedited to security-plugin-permission-sets.ts. The bodies of addressedByIdWriteId, addressedPredicateWrite, readableRowsScopeForPredicateWrite, extractSingleId and readRowById move unedited to security-plugin-addressed-writes.ts. Each takes the import names only it reads. Each method keeps its name, signature, docblock and position and hands its body one host literal of exactly the members it reads; a body that reads no member is called directly. The memo, the position-grant description and five thin members stay whole. readUnlessRefused and POSITION_NAME_FOLD_EVENT stay and are exported and imported by value. Move-only: no verdict changes. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017BoLT8Gaa8t9a7AWVH8qZa
📓 Docs Drift Check29 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 — 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 0b3bb72cb95aa657cbcf25730cf43f086ec44598 && git checkout 0b3bb72cb95aa657cbcf25730cf43f086ec44598
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 830a63a6805ff03824b55ab50f91c4aeead59ee4 23b0616bae8c661ca7dfcf8b6f85630ea04b509a && git checkout -B drift-repro 830a63a6805ff03824b55ab50f91c4aeead59ee4 && git merge --no-ff 23b0616bae8c661ca7dfcf8b6f85630ea04b509a
node scripts/docs-audit/affected-docs.mjs --json 830a63a6805ff03824b55ab50f91c4aeead59ee4 |
席位核对 · ACCEPT · 2026-10-23T12:34Z
Generated by Claude Code |
Requested by Sales · project thread
Part of #25223
Clause-②: no
Metadata-protocol: none
Ruling-ref: 6353073966
Cut 8 of the
security-plugin.tssplit: row 6 of the series plan, the permission-set resolution and the addressed-write readers. The claim is 6363282332. The row has two seams, so the bodies of nine private methods move unedited out of the class to two new modules in this one PR, as cut 6 split its bodies over two modules.To
packages/plugins/plugin-security/src/security-plugin-permission-sets.ts:resolvePermissionSetsForContextUnmemoized, the resolution itself. It folds the positions into the request (never the guest's), applies the additive human baseline or the agent's restricted ceiling, and runs the post-resolution fallback for an authenticated caller whose positions resolved nothing.dropDeactivatedFoldedSets, the activation ledger's say over a set that reached the resolution only through a position of the same name.reportNameFoldCollisions, the Permission-set resolution binds by POSITION NAME while sys_position_permission_set sits near-empty — confirm name-based resolution is the intended mechanism, not an accident the empty junction hides #13419 / Setup: a position's same-named permission set is in force but invisible — the set's Assigned Users panel is empty and the position reads as granting nothing #24757 warning for a grant that exists only because a position and a permission set share a name.permissionSetMemoKey, the fields of the context the per-context memo is keyed on (Authenticated data requests issue ~20 DB queries in ~17 sequential legs — per-request auth/session/localization/metadata resolution has no cross-request caching, costing ~1.5s/request on remote Postgres #10757).To
packages/plugins/plugin-security/src/security-plugin-addressed-writes.ts:addressedByIdWriteIdandaddressedPredicateWrite, which say whether an update or delete is the by-id or the predicate write the caller addressed, read from the engine's own dispatch predicates (security(data): a by-id write answers 403 for a row the caller cannot read and 404 for an id that does not exist, for principals the write pre-image check does not bind: an existence signal the read door withholds #21771, security(data): a predicate-scoped update or delete is refused when its predicate matches only rows the caller cannot read, and succeeds with zero rows when it matches nothing: an existence signal the read door withholds #21829).readableRowsScopeForPredicateWrite, the read door's answer for the caller's own predicate, as the id scope a predicate write is narrowed to (security(data): a predicate-scoped update or delete is refused when its predicate matches only rows the caller cannot read, and succeeds with zero rows when it matches nothing: an existence signal the read door withholds #21829).extractSingleId, the single scalar id an update or delete names.readRowById, the by-id row read the provenance and pre-image gates share, whosenullmeans absent and only absent (readRowByIdswallows engine failures intonull, so a store outage is indistinguishable from an absent row at every gate that probes with it #7505).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/mainat2dfeb1a772, cut 7's merge. It names no issue, so the claim comment is the identity record.What stays in the class. Each moved method keeps its name, signature, docblock and position, less
async. Every caller still calls the methods. Seven members of the row stay whole:getEffectiveObjectPermissions,resolveFallbackPermissionSets,declaresControlledByParent,callerCannotReadAddressedRowandgetCallerPreImage: each body is no longer than its stub would be.resolvePermissionSetsForContext, the memo. Its body retires a rejected entry withthis.permissionSetMemo.delete(context). The tenant-audit census places that call by its receiver's declared type, aWeakMapthe class constructs, and subtracts it as a non-engine call. Read through a host, the receiver has no type the census can read. A trial cut measured it: the census exits 1 ([untyped-receiver]) and asks for anUNTYPED_RECEIVERSrow, in a ledger its own docblock declares shrink-only. So the memo stays.describePositionGrants. Its body callsthis.canReadObject(…), andpackages/core/src/security/row-serving-door-exposure.pin.test.tsclassifies every non-test source file that calls the read admission. Moved, the body would make the new module a caller the pin has no row for, and writing that row is a classification, not a move.extractSingleIdhas no docblock of its own. Its docblock is the first of the two that sit abovedeclaresControlledByParent's, and it stays there; the moved function's pointer comment says so.Module-level declarations.
export. The modules import both by value, as cuts 3, 5, 6 and 7 import theirs.readUnlessRefusedis shared:absentUnderCallerReadandunreadableUnderCallerReadask it too.POSITION_NAME_FOLD_EVENT: thereportNameFoldCollisionsdocblock, which stays, names it in place with a{@link}. Its own docblock says it is deliberately not exported from the package, and that stays true:index.tsexports onlySecurityPlugin, and the published.d.tsdoes not change (below).isGuestEnvelope(cut 6), andPREDICATE_WRITE_READABLE_ID_CAP,predicateWriteReadableCapErrorandcopyOfCallerPredicate(cut 3, whichsecurity-plugin-cbp-write-gate.tsimports fromsecurity-plugin.ts). Those stay where they are, so that module's import does not move..d.tstrap was checked before the claim. At cut 6, an export whose signature names another file's type moved a declaration in the published.d.ts. A local trial build with the whole cut in place ran first. With both new exports in place, the headdist/index.d.tsis byte-identical to base (below).security-plugin.ts, and the modules import them from the same specifiers:MCP_AGENT_PERMISSION_SET_RESTRICTEDfrom@objectstack/spec/ai(that whole import statement goes);readDisabledCatalogNamesandwithoutOperationPrivateKeysfrom@objectstack/core;resolveEngineDeleteDispatchand the typeEngineDeleteDispatchInputfrom@objectstack/metadata-core.No staying docblock links to any of them.
index.tsstill exports onlySecurityPlugin, so the published surface does not move (measured below).Readers. No reader outside the moved code reads the moved lines by path, so this PR changes only the three source files (see Readers below).
The published
.d.tsdoes not changeUnder the series bar (ruling 6348891160 item 1), measured on base
2dfeb1a772and on the head (the tree of this PR's commit):dist/index.d.tsanddist/index.d.mts, base and head, all four the same:af5dee1bebafa0376a876d1e7b247c878ea42ac35c7336a6d3c12a7953143156. The raw diff is 0 lines, so no union order moved either.431e7f5097ac1c220bc840188aef02105bc0b16e845e976dd562d02cc79be8bd.2dfeb1a772's dependencies, rebuilt on that commit first.readUnlessRefusedandPOSITION_NAME_FOLD_EVENTgainexportinsecurity-plugin.ts. A local trial build measured this before the claim, because at cut 6 an export whose signature names another file's type moved a declaration. Here the.d.tsdid not change by a byte.packages/plugins/plugin-security(it sorts the members of each string-literal union and changes nothing else):dist/index.d.ts, line 1307 (private resolvePermissionSetsForContextUnmemoized;):resolvePermissionSetsForContextUnmemoized;): raw19c84435e20b905ee3f3d43803961fa4f0475b04f5747e4662731d5c50432b45, normalisedcb6bcc7126d1a176815c99a2b9ad5a674d7b9f5f7b1c0dd43b47e39c5980f8a6.private resolvePermissionSetsForContextUnmemoizedRenamed;): rawbbfe2a4f35bc7a2f415852a2bb4ba3f35bd78391557b484e8638dee38b1b4039, normalised677731d933ae7a9ddf2e4c65135853065b58506a08d33b62dab1ed2d1a9fb974..d.tscarries each one's name and docblock only (lines 1261, 1307, 1326, 1448, 1542, 1574, 1600, 1601 and 1643 of both).requireandimport()of the built bundles), not parsed. The sorted name list hashes83576430f83cf60cecbcc5c0e80214f16c626a8e66f700294fc6a44361423116on all four, as at cuts 6 and 7. The new exports ofsecurity-plugin.tsdo not reach the entry.index.jscf7a65c1to3a109ef0,index.mjsd4178511to1c38ee91), because code moved within them. One consequence of the removed@objectstack/spec/aiimport: that import now sits in the new module's segment (index.mjsline 9232), so the bundle's first import of@objectstack/spec/aiis one it already had, at line 1046 (1047 at base), rather than line 664.@objectstack/specdeclares"sideEffects": false, so no evaluation order a caller can observe moves.No changeset:
skip-changeset, per ruling 6348891160 item 4.What moved
The base line numbers are each method's signature and closing brace at
2dfeb1a772. The last column lists the members the body reads, which is exactly what its host carries.permissionSetMemoKey(private):6906-:6915resolvePermissionSetsForContextUnmemoized(private, async):7003-:7085baselinePermissionSets,bootstrapPermissionSets,dbLoaderForContext,dropDeactivatedFoldedSets,logger,metadata,permissionEvaluator,reportNameFoldCollisionsdropDeactivatedFoldedSets(private, async):7105-:7122qlreportNameFoldCollisions(private):7279-:7324logger,nameFoldWarnedaddressedByIdWriteId(private):7437-:7450addressedPredicateWrite(private):7486-:7497readableRowsScopeForPredicateWrite(private, async):7524-:7556qlextractSingleId(private):7558-:7570readRowById(private, async):7613-:7630qlEach async stub drops
asyncand returns the moved function's promise, as cuts 1, 3, 5, 6 and 7 did for their async methods. A body that reads no member is called directly, with no host, as cut 1'sextractTargetFieldis. All nine methods are private, so the.d.tscarries each one's name and docblock only.The shape (#23050 shape B, as cuts 1 to 7 applied it)
.d.ts. Each body is now one host literal plusfn.call(host, …), or one direct call, marked[#25223 cut 8].PermissionSetsHostandAddressedWritesHostare new. Each types 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 the stub annotates its literal with the samePick. There is no cast, and no member becomes public or protected.this.m(...a)on the plugin at call time. A spy or test double set on the plugin is still the one the body reaches:describePositionGrantsand every other caller still reach the moved methods through the plugin. No test replaces a moved method on the instance today; one that did would still replace it for every caller.No moved body calls a function-valued field, so no receiver changes:
permissionEvaluator,ql,metadataandloggerare objects whose own methods the bodies call.baselinePermissionSets,bootstrapPermissionSetsandnameFoldWarnedare declaredreadonlyand go by value, so the bodies read the plugin's own lists and its own warned set.logger,metadata,permissionEvaluatorandqlare not declaredreadonly, so they go as getters, and each read happens when the body makes it.start()assignslogger,metadataandqlafter construction.readonly, so a moved body cannot assign a member through them; the typecheck passes, so none does.Proof of move-only
asyncmatch. Three negative controls fail the check:resolvePermissionSetsForContextUnmemoized,if (!isAgent && context?.userId)changed toif (isAgent && context?.userId);readableRowsScopeForPredicateWrite,PREDICATE_WRITE_READABLE_ID_CAP + 1changed to+ 2;reportNameFoldCollisions,removedIn: 'next_major'changed to'next_minor'.async. Every other class member, 117 named members plus the constructor, is byte-identical to base. That includes the seven staying members above. The class has 127 members at base and at head.security-plugin.ts: 97 of the 103 base top-level statements other than the class are byte-identical to base. The six that differ:exportbefore the declaration:readUnlessRefused,POSITION_NAME_FOLD_EVENT;@objectstack/core(twice) and@objectstack/metadata-core;@objectstack/spec/aiimport is gone.The two new statements are the imports of the new modules.
git diff --color-moved=plain --color-moved-ws=allow-indentation-change 2dfeb1a772 HEADover the three source files): of the 227 deleted lines, git sees 218 as moved. The other 9 are the four signatures that loseasync, the two declarations that gainexport, and the three import lines that lose names (@objectstack/coretwice,@objectstack/metadata-core). The deleted@objectstack/spec/aiimport line shows as moved, because the permission-sets module imports it with the same text. Of the 578 added lines, 229 show as moved. The other 349 are the two modules' headers, imports, host interfaces and pointer comments, the nine stubs, the two new imports with their comments, and the edited lines above.security-plugin.tsgoes from 9,394 to 9,248 lines;security-plugin-permission-sets.tshas 281 andsecurity-plugin-addressed-writes.ts216.ADR anchors (ruling 6353073966 item 2)
node scripts/check-adr-symbol-anchors.mjs: exit 0 at base2dfeb1a772and exit 0 at head, both with2384 anchors across 142 records resolve — 466 symbol (440 declaration, 26 literal), 1890 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 at base and at head, both with 80 anchored files. The decision-letter count on the anchored surface goes from 2005 to 2002. That gate countsADR-NNNN Dkcitations in anchored files only, and neither new module has an entry:security-plugin.tswith the moved bodies, all inresolvePermissionSetsForContextUnmemoized: ADR-0138 D3, ADR-0090 D10 and ADR-0090 D5;security-plugin-permission-sets.ts.scripts/adr-anchors/is unchanged. No paragraph of thesecurity-plugin.tsentry (ADR-0055 §1, ADR-0106 D7, ADR-0123 D2, ADR-0138 D1) describes these bodies, so neither new module gets an entry, as the modules of cuts 1, 6 and 7 have none, and none is invented to hold the count.docs/adr/**is not touched.security-plugin.ts: 27 anchors, 18 symbols. It was measured withextractAnchorsandsymbolSegmentResolutionfromscripts/symbol-anchors.mjs, which is measurement, not a new gate. It was read on2dfeb1a772BEFORE the claim, with the whole cut applied as a local trial: no anchor changed class. Every anchor resolves at head insecurity-plugin.tswith its base class, and neither new module resolves any of them.The table gives each anchor's class at base and head and the line its own declaration resolves on. Every anchor stays in
security-plugin.ts.#CBP_MAX_CHAIN_DEPTH:665(top-level):688(top-level)#SecurityPlugin:1297(class):1320(class)#SecurityPlugin.getMetadataReadableFields:6092(method):6115(method)#SecurityPlugin.resolvePermissionSetsForContextUnmemoized:7003(method):7020(method)#assertControlledByParentWrite:8651(method):8505(method)#assertMasterRowEditable:8777(method):8631(method)#collectRLSPolicies:8831(method):8685(method)#composeWriteTenantWall:7989(method):7843(method)#computeControlledByParentFilter:8297(method):8151(method)#computeDelegatedReadFilter:5970(method):5993(method)#computeRlsFilter:7697(method):7551(method)#getReadFilter:5848(method):5871(method)#hasPlatformAdminPosture:7724(method):7578(method)#isPrincipalLessContext:538(top-level):561(top-level)#manage_metadata:287(top-level):310(top-level)#nav_permission_sets:1725(init):1748(init)#rlsFilter:4299(start):4322(start)#writeCheckPolicies:1192(top-level):1215(top-level)No anchor gains or loses a resolving site; each line only shifts. ADR-0138:427
#SecurityPlugin.resolvePermissionSetsForContextUnmemoizedresolves on the method, which stays with its docblock; its body moved. The twoexports this cut adds (readUnlessRefused,POSITION_NAME_FOLD_EVENT) name no anchored symbol.Readers
No reader outside the moved code reads the moved lines by path, so no gate, baseline, docs anchor or test moves with this cut. Each kind was read:
readRowById'sql.findOneand the predicate write'sql.findare reads. The one write-verb call in the row, the memo'spermissionSetMemo.delete(…), stays in the class (above).node scripts/tenant-audit-census.mjs --jsongives the same 238 write call sites at base and head, compared without line numbers and with the new modules mapped back tosecurity-plugin.ts: 0 differences, the same totals, the same 174 non-engine subtractions with the same reasons, 0 unresolved, 0 unledgered. OnlyscannedSourcesmoves, 721 to 723: the two modules.check-tenant-audit-censusand its--self-testexit 0 at head.node scripts/isystem-census.mjs --jsongives the same 148 sites at base and head, compared the same way: 0 differences, and no site in either new module. The role counts are the same (read153,declaration38,key438,other9), and so are the 5 non-elevation reads. The scanned file count is 393 at both, because neither module mentions the flag.check-system-context-censusand its--self-testexit 0 at base and at head with the same output.packages/core/src/security/row-serving-door-exposure.pin.test.tsclassifies every non-test caller of the read admissioncanReadObject. No moved body calls it:describePositionGrants, the one row 6 member that does, stays (above).operation-private-keys.pin.test.tsin the same directory finds every declaration ofwithoutOperationPrivateKeysand the key prefix; the moved body only calls the helper. Run on their own at head: 8 of 8 pass. Open PR test: scope the tree-wide pin scans to the extensions they judge #25389 changes those two pins' scan scope (an extension-scoped prefilter), not what either discriminates on, and touches none of this cut's files.delegated-organization-membership.test.ts) countsresolveDelegatorContext(anddelegatedOrganizationRefusal(per source file. The moved bodies call neither, so its list of three files is unchanged, and it passes at head.security-plugin.tsby path is: thecheck-system-context-census.mjsrow for the file (keyed onstart, which this cut does not touch), the spec liveness ledger's file-level evidence infield.json, the file'sscripts/adr-anchors/entry, and the citation string inmeasure-position-name-fold-census.mjs. None reads text inside the moved bodies. The tree-wide scanners that read every source file are the gates and censuses below, each run at base and head.security-plugin.tsas where the fold happens: thelint.ymlcomment on the Permission-set resolution binds by POSITION NAME while sys_position_permission_set sits near-empty — confirm name-based resolution is the intended mechanism, not an accident the empty junction hides #13419 gate, the message text ofcheck-position-name-fold-loaders.mjs, the comment inmeasure-position-name-fold-census.mjs, which quotes the request line, and thedelegated-admin-gate.tsdocblock, which quotes the fold expression. Each stays true by method:SecurityPlugin#resolvePermissionSetsForContextUnmemoizedis still in that file, and its body is one call away. None of them is edited.check-position-name-fold-loaders.mjsscans the tree only for references to the HotCRM artifact, which no moved body names. It and its--self-testexit 0 at head.measure-position-name-fold-census.mjsscans plugin-security's sources forexport conststring constants, so it now also seesPOSITION_NAME_FOLD_EVENT, whose value names no position or set. Run at base and at head, its output is byte-identical: it already refuses on its own failing self-test at base. CI does not run it.check-platform-checklistexits 0 at base and head with the same output. No checklist citation names a moved symbol or a local inside a moved body.security-plugin.ts#…anchor anywhere in the repo was resolved at base and at head: 30 symbols, among them the 27 spec liveness, platform checklist,system-context.mdxand specconversions/registry.tsanchors cuts 2 to 7 read. WithsymbolSegmentResolution, each resolves at head with its base class: 0 changed.resolve-permission-sets-for-context.pin.test.ts,position-name-fold-warning.test.ts,orgless-position-name-fold.test.ts,permission-set-active.test.ts,explain-read-absent-every-write-verb.test.ts,vama-write-path-convergence.test.ts,store-fault-fail-closed.test.tsand the rest). Each drives the plugin; none calls or replaces a moved method directly;explain-engine.ts(addressedByIdWriteIdinsecurity-plugin.ts),security-plugin-cbp-write-gate.ts(whose header saysreadableRowsScopeForPredicateWriteinsecurity-plugin.tsshares its three values; it still does, through this module), and the tests above.security-plugin.ts:Ncitation in the repo points into the moved ranges (base:6906-:7630). The citations found are the list cuts 2 to 7 read (docs/launch-readiness.md:309,packages/objectql/src/engine.ts:1614,:1690,:1736, spec liveness:3281and the rest, and theL949ofengine-summary-recompute-context.test.ts). Each already pointed at an unrelated line before cut 2, so this cut does not make any of them wrong.node scripts/docs-audit/affected-docs.mjs --json 2dfeb1a772(advisory): 0 pages. The derivation reads 29 anchors (22 symbol, 9 literal) across the one changed package, and no page names any of them. This PR edits no page.2dfeb1a772and head and compared:check-adr-symbol-anchors,check-platform-checklist,check-platform-object-tenancy-census,check-registry-log-declared,check-rest-log-spy-declared,check-system-context-census,check-tenant-audit-census,check:cross-package-test-inputs,check:driver-memory-censusandcheck:query-options-erasure. The last reports the same counts at both, andsecurity-plugin.tsis not a baseline key.check:adr-anchors: the same 80 anchored files; the decision-letter count goes from 2005 to 2002 (above), and the files carrying citations from 6631 to 6632, the permission-sets module.check-undeclared-dep-imports: 3307 to 3309 files, and 2853 to 2857 specifiers. The modules import@objectstack/spec/security,@objectstack/spec/ai,@objectstack/coreand@objectstack/metadata-core, all declared dependencies.check:org-identifier3649 to 3651,check:page-declaration-shape3656 to 3659,check:logger-receiver-detach3623 to 3626,check:refd-timer-probe9976 to 9978,check-plugin-teardown-shape9377 to 9379,check-comment-mask-corpus9982 to 9985,check:closed-ceremony-text4548 to 4550,check:nul-bytes11979 to 11981,check:gitlink-declaredandcheck-closing-keyword-parity11988 to 11990,check:error-status-conformance3404 to 3406, and the spec package'scheck:duration-unit-keys3312 to 3314. Where a count moves by 3, the third file is a local build output or generated file that exists only in the head worktree.check:doc-authoring: 1426 to 1428 parsed sources. Its clean-file count goes from 424 to 427 because the head worktree holds three gitignored generated pages that the base worktree does not, as at cuts 6 and 7. CI's checkout does not have them.check-position-name-fold-loaders: 12343 to 12348 files, with the same 8 references (6 test, 2 declared instrument, 0 loader). It walks the working tree.check:dts-closureandcheck:sourcemap-no-sources-contentsweep built packages, and the head worktree has more of them built (76 and 72) than the base worktree (19). Both pass at both.check:dual-build-cjs-loadsandcheck:i18nanswer exit 3 at base, a missing-build prerequisite in the base worktree rather than a verdict, and exit 0 at head.check-issue-citationsjudges a change set, so it has nothing to read at base. At head it judged 26 citations across 3 files, and all resolve.Acceptance notes
docs/adr/**, noscripts/adr-anchors/entry, no census ledger, and no file outside the package.security-plugin.ts, the new module names,explain-engine.ts,delegated-admin-gate.ts, the census scripts, the permissions docs pages or the plugin-security anchor entry.origin/maingained 1 commit (830a63a680, feat(analytics): carry a dataset dimension's nullLabel on its column descriptor, and name System Overview's null user bucket "System" #25402, analytics). It touches none of this cut's files. On a scratch merge of this head onto that main,check-adr-symbol-anchors,check:adr-anchors,check-platform-checklist,check-system-context-censusandcheck-tenant-audit-censusall exit 0;check:adr-anchorsthere counts 80 anchored files and 2002 decision-letter citations.security-plugin.tsafter this cut: the seven members that stay whole (above) and the nine method shells.security-plugin.tshas 9,248 lines at head, 9,394 at base.Gates
All gates ran at the head, the tree of
23b0616bae, on base2dfeb1a772.pnpm --filter @objectstack/plugin-security test(vitest run --maxWorkers=3, under the verify lock): Test Files 214 passed (214), Tests 4465 passed, 45 skipped (4510). Base2dfeb1a772gives the same counts. VERDICT command-exit 0 on both.pnpm --filter @objectstack/plugin-security typecheck: exit 0. It runstsc --noEmit, the scripts tsconfig, andcheck:test-typecheck.eslint --no-inline-configover the three touched source files: exit 0.pnpm --filter @objectstack/plugin-security build: exit 0. It produced the.d.tsand bundles measured above. The package's dependencies were rebuilt on2dfeb1a772first.row-serving-door-exposure.pin.test.tsandoperation-private-keys.pin.test.ts(@objectstack/core): 8 of 8 pass.node scripts/check-adr-symbol-anchors.mjs,pnpm check:adr-anchors,pnpm check:platform-checklist(and its script),check-scripts-symbol-anchors(and--self-test),pnpm check:query-options-erasure, and the two census--jsonreads. None of these is derived for this change set; each was run by hand, and each exit is listed below.dispatch-gates --commands: 52 commands. The--ranreconciliation shows 52 derived, 52 run, 0 NOT-MEASURED, 0 UNRUN. The zero is derived: all 52 recorded an exit code and none is 3. No docs family is derived, because this cut touches no page.Per command (exit code), the derived first and the hand-run after:
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-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-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/spec run check:duration-unit-keysexit 0pnpm check:closed-ceremony-textexit 0pnpm check:cross-package-test-inputsexit 0pnpm check:doc-authoringexit 0pnpm check:driver-memory-censusexit 0pnpm check:dts-closureexit 0pnpm check:dual-build-cjs-loadsexit 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:nul-bytesexit 0pnpm check:org-identifierexit 0pnpm check:page-declaration-shapeexit 0pnpm check:published-filesexit 0pnpm check:refd-timer-probeexit 0pnpm check:slot-lookupexit 0pnpm check:sourcemap-no-sources-contentexit 0pnpm check:test-source-aliasexit 0pnpm check:tier-file-adoptionexit 0pnpm check:watch-hint-literalexit 0node scripts/check-adr-symbol-anchors.mjsexit 0pnpm check:adr-anchorsexit 0node scripts/check-platform-checklist.mjsexit 0pnpm check:platform-checklistexit 0node scripts/check-scripts-symbol-anchors.mjsexit 0node scripts/check-scripts-symbol-anchors.mjs --self-testexit 0pnpm check:query-options-erasureexit 0node scripts/isystem-census.mjs --jsonexit 0node scripts/tenant-audit-census.mjs --jsonexit 0Generated by Claude Code
🤖 Generated with Claude Code
https://claude.ai/code/session_017BoLT8Gaa8t9a7AWVH8qZa