Repository navigation
refactor(plugin-security): move the security service registration and the seed-ownership claim out of security-plugin.ts (#25223 cut 11) - #25530
Conversation
… the seed-ownership claim out of security-plugin.ts The one statement of start() that builds the ISecurityService literal and registers it as the security kernel service moves unedited to security-plugin-security-service.ts as registerSecurityService. It closed over start()'s ctx, ql and metadata and nothing else, so it takes them as parameters; start() keeps the statement's position and its comment, and calls it from one block that hands it a host literal of exactly the members it reads. The body of claimSeedOwnershipOnSettle moves unedited to security-plugin-seed-claim.ts, with the two seed-settlement readers it shares with the promotion-time pass; they gain export and nothing else, and security-plugin.ts imports them back. The method keeps its name, signature, docblock and position. Import names only the moved code reads leave security-plugin.ts. The three readers that read the moved lines by path are re-pointed: the system-context page's write-bypass row names the new module, the delegator enumeration pin lists it instead of security-plugin.ts, and the core canReadObject caller pin classifies it. The seed-claim module gets the anchor entry carrying the ADR-0138 D1 paragraph that names its bodies. Move-only: no verdict changes. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017BoLT8Gaa8t9a7AWVH8qZa
📓 Docs Drift CheckThis PR changes 1 package(s): 13 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 6 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 17 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 d6f7597e1250dcf37a1d90babb7dc79ad2d811f9 && git checkout d6f7597e1250dcf37a1d90babb7dc79ad2d811f9
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 1ff43b67ea739739ef0870fe5dede5afe51f15f3 5a4747b9c7ca0060ff927391485247b6f0e5855b && git checkout -B drift-repro 1ff43b67ea739739ef0870fe5dede5afe51f15f3 && git merge --no-ff 5a4747b9c7ca0060ff927391485247b6f0e5855b
node scripts/docs-audit/affected-docs.mjs --json 1ff43b67ea739739ef0870fe5dede5afe51f15f3
|
席位核对 · ACCEPT · 2026-10-23T20:58Z
Generated by Claude Code |
Requested by Sales · project thread
Part of #25223
Clause-②: no
Metadata-protocol: none
Ruling-ref: 6353073966
Cut 11 of the
security-plugin.tssplit is the first part of thestart()row. The claim is 6373426297. Before any claim, the card thread mappedstart()into four regions and took the plan to the seat, as cut 10's landing note asked. The seat agreed the order: this cut first, through the normal path, then cut 12 (the middleware, Tier H) claimed afresh on the mergedmain. This PR moves two seams into two new modules, unedited.To
packages/plugins/plugin-security/src/security-plugin-security-service.ts:registerSecurityService, which is ONE STATEMENT ofstart(). It is thetrythat builds theISecurityServiceliteral and registers it as thesecuritykernel service. That literal is what every door bypassing the engine middleware asks: the analytics raw-SQL path, the REST export route, the sharing service's management probes,security/explainand the metadata plane (ADR-0021 D-C, ADR-0090 D5/D6/D10/D12, ADR-0105 D3/D8, ADR-0106 D7, ADR-0111 D1/D2, ADR-0131 D3).To
packages/plugins/plugin-security/src/security-plugin-seed-claim.ts:claimSeedOwnershipOnSettle, the seed-ownership claim thatinit()subscribes toapp:seeded(ADR-0138 D1);seed-settlementcontract through,readSeedSettlementSnapshotandreadSeededRecordIds.The change is move-only, and the card stays open for cut 12. The branch is
claude/project-thread-3fzya4, the harness-pinned branch for this session. It was restarted fromorigin/mainat82f5a111b4, which contains cut 10's merge. The branch name names no issue, so the claim comment is the identity record.How one statement of
start()movesThis is the first cut to move a statement out of a method rather than a whole method body. The seat agreed the plan's form for it before the claim.
:2266-:2560at base (295 lines). It closes over three ofstart()'s locals and nothing else:ctx,qlandmetadata. It uses noarguments,super,new.targetor barethis. It has noreturn,await,breakorcontinueat its top level that would act onstart(). All of that was measured on the AST.PluginContext,IObjectQLEngineandIMetadataService. Both handles are already known to be present at that point. Its body is the statement, re-indented one level and otherwise unedited. It returnsvoid, as the statement produced no value.start()keeps the statement's position and the comment above it (:2259-:2265). In its place is one BLOCK: the getter reads, one host literal annotated with thePickofSecurityServiceHost, andregisterSecurityService.call(host, ctx, ql, metadata);. Because it is a block, itsconsts stay inside it and cannot collide with anything later instart().start()'s order: after the invitation placement service is registered and before the middleware is registered.What moved
The base line numbers are at
82f5a111b4. The last column lists the members the moved code reads, which is exactly what its host carries.securityservice registration (one statement ofstart()):2266-:2560canExport,canReadObject,checkAuthoredRowWrite,checkControlledByParentWrite,declareEveryone,describePositionGrants,explainAccessForCaller,getEffectiveObjectPermissions,getMetadataReadableFields,getObjectSecurityMeta,getQueryableFields,getReadFilter,getReadableFields,getWritableFields,resolvePermissionSetsForContext; by value:acceptedDefaultPermissionSets,ownershipFloorAlternates; getters:delegatedAdminGate,logger,permissionEvaluator,ql,tenancyPostureclaimSeedOwnershipOnSettle(private, async):1873-:1905bootstrapPermissionSets; getter:claimTargetAdminUserIdreadSeedSettlementSnapshot(module function, with its docblock):1254-:1273readSeededRecordIds(module function, with its docblock):1275-:1293claimSeedOwnershipOnSettlekeeps its name, signature, docblock and position, lessasync. It returns the moved function's promise, as cuts 1 and 3 to 10 did for their async methods.init()'sapp:seededsubscription still calls it on the plugin.exportand nothing else.security-plugin.tsimports both back, because R4's promotion-time pass onkernel:readyreads both (:4550,:4590).exportwhere they stood: each signature names a contract type. Cut 6 measured that an export fromsecurity-plugin.tswhose signature names another module's type reorders the.d.ts. So they moved, and the.d.tswas measured anyway (below).security-plugin.ts, 16 in all. The modules import them from the same specifiers.resolveDelegatorContext,delegatedOrganizationRefusalandd10NarrowingStatement(./explain-engine.js);listAudienceBindingSuggestions,confirmAudienceBindingSuggestion,dismissAudienceBindingSuggestionand the typesSuggestionDepsandSuggestionListFilter(./suggested-audience-bindings.js);OwnershipFloorAlternate(./platform-ownership-policies.js);ObjectAccessScope(@objectstack/spec/security);ISecurityServiceandDelegationNarrowing(@objectstack/spec/contracts).SEED_SETTLEMENT_SERVICEand the typeISeedSettlementService(@objectstack/spec/contracts);findExistingPlatformAdmin(./bootstrap-platform-admin.js);./claim-seed-ownership.jsimport (claimSeedOwnership).computeDelegatedReadFilter's, namesresolveDelegatorContextin a{@link}. The name is no longer imported, so that link is now plain text, like the bare-member{@link computeRlsFilter}beside it. No docblock is edited. Every other staying mention of a dropped name is in backticks or prose.index.tsexports only what it did, so the published surface does not move (measured below).The shape (#23050 shape B, as cuts 1 to 10 applied it)
SecurityServiceHostandSeedClaimHostare new. Each types every member as the class member itself (SecurityPlugin['m']). Each moved function types itsthisas thePickof its host over exactly the members its code 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. Every member of the registered service that binds a plugin method was already an arrow callingthis.m(…).this.mis now the host's closure, which calls the plugin's method on the plugin. So every call reaches the same method on the same receiver, and a spy or test double set on the plugin is still the one the service reaches.acceptedDefaultPermissionSets,ownershipFloorAlternatesandbootstrapPermissionSetsare declaredreadonly, so they go by value: the same object references.delegatedAdminGate,logger,permissionEvaluator,ql,tenancyPostureandclaimTargetAdminUserIdare not. So they go as getters, and each read happens when the code makes it. For example, the posture the suggestion deps hand out is still read per call, and the claim still reads the admin R4 names when it runs.readonly, so moved code cannot assign a member through them. The typecheck passes, so none does. Neither moved region writes a member.Three readers read the moved lines by path, and all three are re-pointed in this PR
These are the three the seat named. Each was run with its edit reverted, and each fails without it.
content/docs/permissions/system-context.mdx, row 7. The registration holds 3 ofstart()'s 4isSystemreads:hasWriteBypass's,resolveWriteScope's anddescribeDelegationNarrowing's system short-circuits.check-system-context-censuskeys each read by file and enclosing symbol, so row 7's anchor changes fromsecurity-plugin.ts#starttosecurity-plugin-security-service.ts#registerSecurityService.#start, which still holds the middleware's read.[file-without-a-row]for the new module. With the re-point it exits 0.packages/plugins/plugin-security/src/delegated-organization-membership.test.ts, the plugin-security: delegation probes and diagnostics (canReadObject / canWriteObject / canExport, field mask, explain) answer for an on-behalf-of context the operation prologue now refuses (PR #25101) #25107 enumeration pin. The registration holds the only delegator resolution insecurity-plugin.ts, and the organization ask beside it. So in the expected list,security-plugin-security-service.tsreplacessecurity-plugin.ts, and the count stays at seven files.security-plugin.tshas 0 and 0.packages/core/src/security/row-serving-door-exposure.pin.test.ts. Every file that callscanReadObjectmust be classified, and the service literal's bindingthis.canReadObject(…)now sits in the new module.not-a-doorentry: "the provider's service registration: it binds the admission into thesecurityservice the plugin registers; it serves no rows".security-plugin.tsstays a caller, through the stub's closure anddescribePositionGrants' own ask. Its reason no longer says it binds the admission into the service. It now says "the provider: it implements the admission, hands it to its service registration, and asks it itself only to decide whetherdescribePositionGrantsmay count a position's holders; it serves no rows".One new anchor entry
scripts/adr-anchors/packages__plugins__plugin-security__src__security-plugin-seed-claim.ts.json(adrs: ["ADR-0138"]).security-plugin.tsentry, verbatim. That paragraph namesclaimSeedOwnershipOnSettleandreadSeededRecordIds, whose bodies now sit in the module. Cut 9 carried ADR-0106 D7 intosecurity-plugin-field-readers.tsthe same way.security-plugin.tsentry is unchanged and stays true: the method, the promotion-time pass and the import ofreadSeededRecordIdsstay in that file.docs/adr/**is not touched, and no other governed path is, so this is a normal landing.The published
.d.tsdoes not changeMeasured under the series bar (ruling 6348891160 item 1), on base
82f5a111b4and on head5a4747b9c7. Each was a fullturbo run buildin its own worktree (both exit 0).dist/index.d.tsanddist/index.d.mtsis the same for all four files, base and head:5e7e8df69375e6606767eee938111aaaf0b9bac4dd9c728689c343be9e5f7702(14,696 lines). The raw diff is 0 lines, so no union order moved either.1e2e8299c2b3aa8502ae3684a5a8a4f7148b2211876a0a581f20d27677531ed9.security-plugin.tsgains no export. The two readers gainedexportin the new module, which nothing re-exports, so the cut 6 trap does not arise.packages/plugins/plugin-security, sorts the members of each string-literal union and changes nothing else:privateremoved fromclaimSeedOwnershipOnSettlein the head source,pnpm --filter @objectstack/plugin-security buildemits line 431 as the full public signature instead ofprivate claimSeedOwnershipOnSettle;. That gives raw12beec21603e70025c7a1b70d2c49fd0dd110d66a61b57e82098a6eb903fe08cand normalised0509461ad52776d160e6875c3a99cee28dda954089413b05db158aabda6d52ff, both different from the real hashes. So the comparison does see a visibility change. With the source restored, a rebuild gives5e7e8df6…again for both files.claimSeedOwnershipOnSettleis private, so the.d.tscarries only its name and docblock (line 431).registerSecurityServiceand the two readers are in no published file.requireandimport()of the built bundles, not parsed. The sorted name list hashes to83576430f83cf60cecbcc5c0e80214f16c626a8e66f700294fc6a44361423116for all four, as at cuts 6 to 10.index.jsgoes froma0d05e78tob734b9f0, andindex.mjsfrom1080b070to51498bc7. Every value the new modules import comes from a file inside this package or from a specifiersecurity-plugin.tsalready imports. So the set of external specifiers each bundle loads is the same at base and head: 17 distinctrequire(…)specifiers inindex.jsand 24 distinctfromspecifiers inindex.mjs, counted the same way at both ends.bootstrap-platform-admin.tsandclaim-seed-ownership.ts. So those two, andplatform-admin-standing-audit.ts, are now emitted after the two new modules and ahead ofownership-floor-alternates.tsandsecurity-plugin.ts's first chunk, instead of afterpredicate-guard.ts. None of the three importssecurity-plugin.ts. Their top level only declares (one constant is computed from an imported constant,CLAIM_PAGE_ROWS).No changeset:
skip-changeset, per ruling 6348891160 item 4.Proof of move-only
The statement, by AST token.
registerSecurityService's body is one statement, with the same TypeScript token sequence as the basetrystatement: 1,296 tokens. Each of its 295 lines is the base line with two leading spaces removed. Multi-line JSDoc text tokens inside it are re-indented one level, like every other line, so the comparison dedents those tokens one level, and only those.start()outside the statement. The head text ofstart()equals the base text exactly, outside the one statement, which is now a 33-line stub block ending in the.call. Its signature, docblock and every other statement are byte-identical. That covers R1, the comment above the statement, the middleware and R4.The method, by AST token.
claimSeedOwnershipOnSettle's function body has the same token sequence as the base method body (136 tokens), and each of its 28 lines is the base line less two spaces. The parameters, the return type andasyncmatch. The class keeps the method's docblock and signature, lessasync.The two readers. Each one's text in the module, docblock included, is the base text with
exportadded, and nothing else. Neither is left insecurity-plugin.ts.Class side. Every other class member is byte-identical to base: 124 named members plus the constructor. The class has 127 members at base and at head.
Top level of
security-plugin.ts. Of the 110 top-level statements at base other than the class, 101 are byte-identical at head. The other nine are:./claim-seed-ownership.jsimport, which is gone;The two new statements are the imports of the new modules, with their comments. The check asserts the exact list of 16 dropped names and 6 added names, and that no dropped name is still referenced in the file.
Negative controls. Seven fail the check:
ctx.logger.info(changed toctx.logger.debug(;start(), one edit in R1 (:1914), ahead of the stub;start(), one edit in the middleware, after the stub;readSeedSettlementSnapshot,return undefinedchanged toreturn null;claimSeedOwnershipOnSettle,ctx.logger.warn(changed toctx.logger.error(;security-plugin.ts, one trailing space added.git's own view. This is
git diff --color-moved=plain --color-moved-ws=allow-indentation-change 82f5a111b4 HEADover the three source files../bootstrap-platform-admin.jsimport line, which the modules group differently; the two reader signatures that gainexport; and the method signature that losesasync.security-plugin.ts(a stub's};). The rest are the modules' headers, imports, host interfaces and function signatures, the two stubs, and the two new imports with their comments.Size. 1,010 changed lines (+629 / -381) over 7 files, under the 3,000-line manual-merge line.
security-plugin.tsgoes from 8,442 to 8,120 lines.security-plugin-security-service.tshas 418 lines, andsecurity-plugin-seed-claim.ts139.ADR anchors (ruling 6353073966 item 2)
node scripts/check-adr-symbol-anchors.mjsexits 0 and gives the same output at base82f5a111b4and at head.pnpm check:adr-anchorsexits 0 at base and at head. Anchored files go from 82 to 83, the new entry.The decision-letter count on the anchored surface goes from 1970 to 1958. That gate counts
ADR-NNNN Dkcitations in each anchored file and in each entry's own invariant text. The −12 is:readSeededRecordIds' docblock carries ADR-0138 D1, and it stays on the anchored surface, now in an anchored module;The method body, the module headers, the stubs and the new import comments cite none. Measured per file:
security-plugin.tsholds 250 such citations at base and 236 at head. The security-service module holds the 13, and the seed-claim module the 1.Every moved citation is still in the tree, in the module its code moved to. Citations that resolve tree-wide go from 52262 across 6671 files at base to 52264 across 6674 at head. The two added citations are the new entry's
adrslist and its invariant. The three added files are the two modules and the entry.docs/adr/**is not touched, and no anchor token is planted.The anchor map covers every ADR symbol anchor that names
security-plugin.ts: 18 symbols.extractAnchorsandsymbolSegmentResolutionfromscripts/symbol-anchors.mjs. That is measurement, not a new gate.82f5a111b4BEFORE the claim, with the whole cut applied as a local trial, and no anchor changed class.#getReadFilterand#SecurityPlugin.getMetadataReadableFields. Their names now also appear in the stub's host literal and itsPick. Both still resolve asdeclaration, on the methods.The table gives each anchor's class at base and at head, and the line its own declaration resolves on. Every anchor stays in
security-plugin.ts.#CBP_MAX_CHAIN_DEPTH:746(top-level):748(top-level)#SecurityPlugin:1348(class):1309(class)#SecurityPlugin.getMetadataReadableFields:5620(method):5298(method)#SecurityPlugin.resolvePermissionSetsForContextUnmemoized:6214(method):5892(method)#assertControlledByParentWrite:7699(method):7377(method)#assertMasterRowEditable:7825(method):7503(method)#collectRLSPolicies:7879(method):7557(method)#composeWriteTenantWall:7037(method):6715(method)#computeControlledByParentFilter:7345(method):7023(method)#computeDelegatedReadFilter:5539(method):5217(method)#computeRlsFilter:6745(method):6423(method)#getReadFilter:5485(method):5163(method)#hasPlatformAdminPosture:6772(method):6450(method)#isPrincipalLessContext:619(top-level):621(top-level)#manage_metadata:372(top-level):374(top-level)#nav_permission_sets:1776(init):1737(init)#rlsFilter:4360(start):4038(start)#writeCheckPolicies:1243(top-level):1245(top-level)Readers
The three readers above are the only ones that read the moved lines by path. No other gate, baseline, docs anchor or test does. Each kind was read:
node scripts/isystem-census.mjs --jsongives the same 149 sites at base and at head, with 0 differences. The comparison ignores line numbers, maps the two modules back tosecurity-plugin.ts, and maps the symbolregisterSecurityServiceback tostart.read154,declaration39,key440,other9), and so are the 5 non-elevation reads. Files holding a site go from 76 to 77, and scanned files from 402 to 403.check-system-context-censusand its--self-testexit 0 at base and at head. The totals: 149 sites at both; symbols 128 to 129; cited 141 to 142 against as many required; files 76 to 77. With the page untouched, it reports 1 problem (above).claimSeedOwnership, which stays in its own file, and the registration only reads.node scripts/tenant-audit-census.mjs --jsongives the same 238 write call sites at base and at head, compared the same way: 0 differences, none in the modules, and the same 176 non-engine calls. OnlyscannedSourcesmoves, from 739 to 741: the two modules.check-tenant-audit-censusexits 0 at base and at head, andtenant-audit-census.mdxis not touched.operation-private-keys.pin.test.ts(@objectstack/core) names no moved code, and it passes at head.conversions/registry.tscorpora,security-plugin.ts#Xis cited 48 times over 26 symbols at base and 47 at head. WithsymbolSegmentResolution, each resolves at head with its base class: 0 changed. The one ref that leaves is row 7's.check-platform-checklist(the script andpnpm check:platform-checklist),check-scripts-symbol-anchorsand its--self-test, andpnpm --filter @objectstack/spec check:livenesswere run at base and at head (Gates).securityservice and the seed claim in this package. Each drives the plugin or the registered service, and none calls the moved code directly. No test replacesclaimSeedOwnershipOnSettleon the plugin instance;security-plugin.ts:Ncitation in the repo points into the moved ranges (base:1254to:1293,:1873to:1905and:2266to:2560).Gates
All gates ran against base
82f5a111b4and on head5a4747b9c7, each in its own worktree after a fullturbo run buildthere (both exit 0). The CI run on this head is green: 36 checks passed and 11 were skipped by their path filters.pnpm --filter @objectstack/plugin-security test(vitest run): Test Files 218 passed (218); Tests 4573 passed, 45 skipped (4618). Base82f5a111b4gives the same counts.pnpm --filter @objectstack/plugin-security typecheck: exit 0 at head and at base. It runstsc --noEmit, the scripts tsconfig, andcheck:test-typecheck.eslint over the five touched source and test files: exit 0.
pnpm --filter @objectstack/plugin-security build: exit 0. It produced the.d.tsand the bundles measured above.row-serving-door-exposure.pin.test.tsandoperation-private-keys.pin.test.ts(@objectstack/core): 8 of 8 pass at head and at base.dispatch-gates --commands: 101 commands. The--ranreconciliation shows 101 derived, 101 run, 0 NOT-MEASURED and 0 UNRUN. The zero is derived: all 101 recorded an exit code, and none is 3.Six commands are not derived for this change set. Each was run by hand:
node scripts/check-adr-symbol-anchors.mjs;check-platform-checklist, both the script andpnpm check:platform-checklist;--jsonreads;pnpm --filter @objectstack/spec check:liveness.pnpm check:adr-anchors,check-scripts-symbol-anchorsand its--self-test, andpnpm check:query-options-erasureare derived for this change set this time.Nine more were run at base and at head:
dispatch-gatesmarks their silence as no evidence. Two of them,check:engine-double-contractandcheck:i18n-stale-fill, are derived anyway. The other eight were run:check-published-list-mirrorsand its--self-test,check:authz-resolver,check:console-injection,check:error-code-casing,check:filter-alias-parity,check:published-readme-exportsandcheck-dts-references --self-test.All of them exit 0 at both ends.
Base against head, all 118 commands. All 118 exit 0 at head and at base. 88 give identical output at both, once the worktree path and timings are masked. The other 30, each read line by line:
check:adr-anchors,check-system-context-censusand the two census--jsonreads. The tenant read moves only byscannedSourcesand its own ref.security-plugin.tscarry the file's new line numbers. Its counts are the same at both ends (above).check-issue-citationsjudges a change set, so it has nothing to read at base. At head it judged 22 citations across 3 files, and all resolve.check-closing-keyword-parity12065 to 12068 tracked files;check:gitlink-declared12065 to 12068 index entries;check:nul-bytes12056 to 12059;check-comment-mask-corpus10030 to 10032;check-plugin-teardown-shape9421 to 9423 sources;check-position-name-fold-loaders12399 to 12402 files, with the same 8 references;check-undeclared-dep-imports3326 to 3328 files;check:duration-unit-keys3331 to 3333;check:closed-ceremony-text4594 to 4596;check:doc-authoring1445 to 1447 parsed sources;check:engine-double-contract3636 to 3638 production files;check:error-status-conformance3424 to 3426, with the same 510 producer sites;check:error-code-casing9404 to 9406;check:logger-receiver-detach3644 to 3646;check:org-identifier3669 to 3671;check:page-declaration-shape3677 to 3679;check:refd-timer-probe10023 to 10025;check:type-check-coverageandcheck:type-check-debt3553 to 3555 walked sources;check:vendor-version-stamps10422 to 10424;check:agent-test-spelling613 to 614 files, with the same tokens and runs;check:pnpm-flag-spellings454 to 455 files underscripts/(the anchor entry), with the same scripts read.check-undeclared-dep-importsalso reads 2885 to 2890@objectstack/*specifiers. Those are the ones the two modules import, all declared dependencies.security-plugin.tskeeps every specifier it still uses.check:doc-authoringalso reads 105072 to 105157 strings, the strings of the new headers and stubs.check:skill-identifier-livenessreads 140073 to 140077 implementation word tokens. Those are the four words new to the tree:SecurityServiceHost,SeedClaimHost,registerSecurityServiceand the stub's getter localreadClaimTargetAdminUserId. No citation changes.check:merge-driverdiffers only in its temporary directory names.The Docs Drift Check comment lists pages that name identifiers in the moved text. The change is move-only, so none of them describes behaviour that changed, and no page is edited.
Per command (exit code at head, then at base), the derived first, then the hand-run, the roster and the two suites:
node scripts/check-ci-filter-parity.mjsexit 0 (base 0)node scripts/check-closing-keyword-parity.mjsexit 0 (base 0)node scripts/check-closing-keyword-parity.mjs --self-testexit 0 (base 0)node scripts/check-comment-mask-adoption.mjsexit 0 (base 0)node scripts/check-comment-mask-adoption.mjs --self-testexit 0 (base 0)node scripts/check-comment-mask-corpus.mjsexit 0 (base 0)node scripts/check-dev-prereqs.mjs --self-testexit 0 (base 0)node scripts/check-doc-frontmatter.mjsexit 0 (base 0)node scripts/check-doc-frontmatter.mjs --self-testexit 0 (base 0)node scripts/check-doc-route-spelling.mjs --advisoryexit 0 (base 0)node scripts/check-doc-route-spelling.mjs --self-testexit 0 (base 0)node scripts/check-docs-section-name.mjsexit 0 (base 0)node scripts/check-docs-section-name.mjs --self-testexit 0 (base 0)node scripts/check-dts-emitted.mjs --self-testexit 0 (base 0)node scripts/check-issue-citations.mjsexit 0 (base 0)node scripts/check-keyed-text-bounds.mjsexit 0 (base 0)node scripts/check-keyed-text-bounds.mjs --self-testexit 0 (base 0)node scripts/check-platform-object-tenancy-census.mjsexit 0 (base 0)node scripts/check-platform-object-tenancy-census.mjs --self-testexit 0 (base 0)node scripts/check-plugin-teardown-shape.mjsexit 0 (base 0)node scripts/check-plugin-teardown-shape.mjs --self-testexit 0 (base 0)node scripts/check-position-name-fold-loaders.mjsexit 0 (base 0)node scripts/check-position-name-fold-loaders.mjs --self-testexit 0 (base 0)node scripts/check-registry-log-declared.mjsexit 0 (base 0)node scripts/check-registry-log-declared.mjs --self-testexit 0 (base 0)node scripts/check-rest-log-spy-declared.mjsexit 0 (base 0)node scripts/check-rest-log-spy-declared.mjs --self-testexit 0 (base 0)node scripts/check-scripts-symbol-anchors.mjsexit 0 (base 0)node scripts/check-scripts-symbol-anchors.mjs --self-testexit 0 (base 0)node scripts/check-section-landing-index.mjsexit 0 (base 0)node scripts/check-section-landing-index.mjs --self-testexit 0 (base 0)node scripts/check-system-context-census.mjsexit 0 (base 0)node scripts/check-system-context-census.mjs --self-testexit 0 (base 0)node scripts/check-tenant-audit-census.mjsexit 0 (base 0)node scripts/check-tenant-audit-census.mjs --self-testexit 0 (base 0)node scripts/check-undeclared-dep-imports.mjsexit 0 (base 0)node scripts/check-undeclared-dep-imports.mjs --self-testexit 0 (base 0)node scripts/ci/assert-turbo-remote-cache.mjs --self-testexit 0 (base 0)node scripts/docs-audit/check-affected-docs.mjsexit 0 (base 0)node scripts/docs-audit/check-drift-comment.mjsexit 0 (base 0)pnpm --filter @objectstack/lint run check:doc-formula-expressionsexit 0 (base 0)pnpm --filter @objectstack/lint run check:doc-security-postureexit 0 (base 0)pnpm --filter @objectstack/spec run check:docsexit 0 (base 0)pnpm --filter @objectstack/spec run check:duration-unit-keysexit 0 (base 0)pnpm --filter @objectstack/spec run check:empty-stateexit 0 (base 0)pnpm --filter @objectstack/spec run check:livenessexit 0 (base 0)pnpm --filter @objectstack/spec run check:skill-examplesexit 0 (base 0)pnpm --filter @objectstack/spec run check:strictness-ledgerexit 0 (base 0)pnpm --filter @objectstack/spec run check:variant-docsexit 0 (base 0)pnpm --filter @objectstack/spec run check:yaml-examplesexit 0 (base 0)pnpm check:adr-anchorsexit 0 (base 0)pnpm check:agent-test-spellingexit 0 (base 0)pnpm check:bash32-floorexit 0 (base 0)pnpm check:cli-command-idsexit 0 (base 0)pnpm check:closed-ceremony-textexit 0 (base 0)pnpm check:corpus-claim-driftexit 0 (base 0)pnpm check:cross-package-test-inputsexit 0 (base 0)pnpm check:doc-anchorsexit 0 (base 0)pnpm check:doc-authoringexit 0 (base 0)pnpm check:docs-audit-scopeexit 0 (base 0)pnpm check:docs-redirectsexit 0 (base 0)pnpm check:docs-single-h1exit 0 (base 0)pnpm check:docs-spec-enumerationsexit 0 (base 0)pnpm check:docs-transcript-driftexit 0 (base 0)pnpm check:driver-memory-censusexit 0 (base 0)pnpm check:dts-closureexit 0 (base 0)pnpm check:dual-build-cjs-loadsexit 0 (base 0)pnpm check:engine-double-contractexit 0 (base 0)pnpm check:entry-guardexit 0 (base 0)pnpm check:error-status-conformanceexit 0 (base 0)pnpm check:gitlink-declaredexit 0 (base 0)pnpm check:i18nexit 0 (base 0)pnpm check:i18n-stale-fillexit 0 (base 0)pnpm check:issue-citationsexit 0 (base 0)pnpm check:kernel-hook-pairsexit 0 (base 0)pnpm check:lean-entry-closureexit 0 (base 0)pnpm check:logger-receiver-detachexit 0 (base 0)pnpm check:merge-driverexit 0 (base 0)pnpm check:nul-bytesexit 0 (base 0)pnpm check:objectql-double-limitexit 0 (base 0)pnpm check:org-identifierexit 0 (base 0)pnpm check:page-declaration-shapeexit 0 (base 0)pnpm check:parse-guardexit 0 (base 0)pnpm check:pnpm-filter-targetsexit 0 (base 0)pnpm check:pnpm-flag-spellingsexit 0 (base 0)pnpm check:published-filesexit 0 (base 0)pnpm check:published-readme-linksexit 0 (base 0)pnpm check:query-options-erasureexit 0 (base 0)pnpm check:react-page-adapter-contractexit 0 (base 0)pnpm check:refd-timer-probeexit 0 (base 0)pnpm check:role-wordexit 0 (base 0)pnpm check:skill-identifier-livenessexit 0 (base 0)pnpm check:slot-lookupexit 0 (base 0)pnpm check:sourcemap-no-sources-contentexit 0 (base 0)pnpm check:test-source-aliasexit 0 (base 0)pnpm check:tier-file-adoptionexit 0 (base 0)pnpm check:type-check-coverageexit 0 (base 0)pnpm check:type-check-debtexit 0 (base 0)pnpm check:vendor-version-stampsexit 0 (base 0)pnpm check:watch-hint-literalexit 0 (base 0)pnpm check:where-matcherexit 0 (base 0)node scripts/check-adr-symbol-anchors.mjsexit 0 (base 0)node scripts/check-platform-checklist.mjsexit 0 (base 0)pnpm check:platform-checklistexit 0 (base 0)node scripts/isystem-census.mjs --jsonexit 0 (base 0)node scripts/tenant-audit-census.mjs --jsonexit 0 (base 0)pnpm --filter @objectstack/spec check:livenessexit 0 (base 0)node scripts/check-published-list-mirrors.mjsexit 0 (base 0)pnpm check:authz-resolverexit 0 (base 0)pnpm check:console-injectionexit 0 (base 0)pnpm check:error-code-casingexit 0 (base 0)pnpm check:filter-alias-parityexit 0 (base 0)pnpm check:published-readme-exportsexit 0 (base 0)pnpm --filter @objectstack/plugin-security typecheckexit 0 (base 0)pnpm --filter @objectstack/plugin-security testexit 0 (base 0)pnpm --filter @objectstack/core exec vitest run src/security/row-serving-door-exposure.pin.test.ts src/security/operation-private-keys.pin.test.tsexit 0 (base 0)node scripts/check-dts-references.mjs --self-testexit 0 (base 0)node scripts/check-published-list-mirrors.mjs --self-testexit 0 (base 0)Acceptance notes
start(), no behaviour, nodocs/adr/**, no census ledger and nopackages/spec/**. Outside the package, two files change: the one anchor path on the system-context page, and the core pin's classification.security-plugin.ts: feat(plugin-security): a declared membership key is staged per request, beside the registered resolver #25528 (Spec design: declarative membership keys for RLS (current_user.<key> from a lookup on records whose user field is the current user) #25234's second PR, another project's). It adds one import after the rls-filter import (:173here), a loop in R1 after the resolver's registration log (:2167here), and editsstageRlsMembership. None of those lines is in the registration, the seed claim, the readers or an import line this cut edits. A scratch merge of feat(plugin-security): a declared membership key is staged per request, beside the registered resolver #25528's head with this cut is clean (git merge-tree, exit 0). No open PR touches the two module names,system-context.mdx, the two pins, the census scripts or the plugin-security anchor entries.start()holds R1, the registration's stub block, the middleware (R3) and R4. Next is cut 12: R3 moves out on a fresh claim on the mergedmain. It is Tier H on two counts, the ADR-0055:24#rlsFilterre-anchor (ruling 6353073966 item 5) and its size, and its claim says so up front.Generated by Claude Code
🤖 Generated with Claude Code
https://claude.ai/code/session_017BoLT8Gaa8t9a7AWVH8qZa