Repository navigation
Commit c15fd9a
<!-- claude-projects-attribution: {"github_login":"os-sales"} -->
_Requested by **Sales** · [project
thread](https://claude.ai/code/project/chan_01D5bWFY3rFzgJcytD5gD4Uu?thread=cmsg_01D5bWFY3rFzgJcytD5gD4UuMYdF2uchcinMphEKW4sYxd)_
Part of #25223
Clause-②: no
Metadata-protocol: none
Ruling-ref: 6353073966
Cut 11 of the `security-plugin.ts` split is the first part of the
`start()` row. The claim is 6373426297. Before any claim, the card
thread mapped `start()` 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 merged `main`. 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 of `start()`. It is
the `try` that builds the `ISecurityService` literal and registers it as
the `security` kernel 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/explain` and
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`:
- the body of `claimSeedOwnershipOnSettle`, the seed-ownership claim
that `init()` subscribes to `app:seeded` (ADR-0138 D1);
- the two readers it asks the published `seed-settlement` contract
through, `readSeedSettlementSnapshot` and `readSeededRecordIds`.
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 from `origin/main` at `82f5a111b4`, 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()` moves
This 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.
- The statement is `:2266`-`:2560` at base (295 lines). It closes over
three of `start()`'s locals and nothing else: `ctx`, `ql` and
`metadata`. It uses no `arguments`, `super`, `new.target` or bare
`this`. It has no `return`, `await`, `break` or `continue` at its top
level that would act on `start()`. All of that was measured on the AST.
- So the function takes the three locals as parameters, typed as the
statement saw them there: `PluginContext`, `IObjectQLEngine` and
`IMetadataService`. Both handles are already known to be present at that
point. Its body is the statement, re-indented one level and otherwise
unedited. It returns `void`, 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 the `Pick` of `SecurityServiceHost`, and
`registerSecurityService.call(host, ctx, ql, metadata);`. Because it is
a block, its `const`s stay inside it and cannot collide with anything
later in `start()`.
- The statement ran synchronously and still does. The call is in the
same place in `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.
| code | base lines | module | host members |
|---|---|---|---|
| the `security` service registration (one statement of `start()`) |
`:2266`-`:2560` | security-service | methods: `canExport`,
`canReadObject`, `checkAuthoredRowWrite`,
`checkControlledByParentWrite`, `declareEveryone`,
`describePositionGrants`, `explainAccessForCaller`,
`getEffectiveObjectPermissions`, `getMetadataReadableFields`,
`getObjectSecurityMeta`, `getQueryableFields`, `getReadFilter`,
`getReadableFields`, `getWritableFields`,
`resolvePermissionSetsForContext`; by value:
`acceptedDefaultPermissionSets`, `ownershipFloorAlternates`; getters:
`delegatedAdminGate`, `logger`, `permissionEvaluator`, `ql`,
`tenancyPosture` |
| `claimSeedOwnershipOnSettle` (private, async) | `:1873`-`:1905` |
seed-claim | by value: `bootstrapPermissionSets`; getter:
`claimTargetAdminUserId` |
| `readSeedSettlementSnapshot` (module function, with its docblock) |
`:1254`-`:1273` | seed-claim | none |
| `readSeededRecordIds` (module function, with its docblock) |
`:1275`-`:1293` | seed-claim | none |
- `claimSeedOwnershipOnSettle` keeps its name, signature, docblock and
position, less `async`. It returns the moved function's promise, as cuts
1 and 3 to 10 did for their async methods. `init()`'s `app:seeded`
subscription still calls it on the plugin.
- The two readers move with their docblocks, unedited, and gain `export`
and nothing else. `security-plugin.ts` imports both back, because R4's
promotion-time pass on `kernel:ready` reads both (`:4550`, `:4590`).
- Why they move rather than gain `export` where they stood: each
signature names a contract type. Cut 6 measured that an export from
`security-plugin.ts` whose signature names another module's type
reorders the `.d.ts`. So they moved, and the `.d.ts` was measured anyway
(below).
- Import names that only the moved code reads leave
`security-plugin.ts`, 16 in all. The modules import them from the same
specifiers.
- From the registration:
- `resolveDelegatorContext`, `delegatedOrganizationRefusal` and
`d10NarrowingStatement` (`./explain-engine.js`);
- `listAudienceBindingSuggestions`, `confirmAudienceBindingSuggestion`,
`dismissAudienceBindingSuggestion` and the types `SuggestionDeps` and
`SuggestionListFilter` (`./suggested-audience-bindings.js`);
- the type `OwnershipFloorAlternate`
(`./platform-ownership-policies.js`);
- the type `ObjectAccessScope` (`@objectstack/spec/security`);
- the types `ISecurityService` and `DelegationNarrowing`
(`@objectstack/spec/contracts`).
- From the seed claim:
- `SEED_SETTLEMENT_SERVICE` and the type `ISeedSettlementService`
(`@objectstack/spec/contracts`);
- `findExistingPlatformAdmin` (`./bootstrap-platform-admin.js`);
- the whole `./claim-seed-ownership.js` import (`claimSeedOwnership`).
- Disclosed: one staying docblock, `computeDelegatedReadFilter`'s, names
`resolveDelegatorContext` in 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.
- Each value import is read only inside a function body, at call time,
never while a module evaluates. `index.ts` exports 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)
- `SecurityServiceHost` and `SeedClaimHost` are new. Each types every
member as the class member itself (`SecurityPlugin['m']`). Each moved
function types its `this` as the `Pick` of its host over exactly the
members its code reads, and the stub annotates its literal with the same
`Pick`. There is no cast, and no member becomes public or protected.
- Methods go in as late-bound closures that call `this.m(...a)` on the
plugin at call time. Every member of the registered service that binds a
plugin method was already an arrow calling `this.m(…)`. `this.m` is 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.
- Fields follow the rule cut 1 set, judged on each field's own
declaration:
- `acceptedDefaultPermissionSets`, `ownershipFloorAlternates` and
`bootstrapPermissionSets` are declared `readonly`, so they go by value:
the same object references.
- `delegatedAdminGate`, `logger`, `permissionEvaluator`, `ql`,
`tenancyPosture` and `claimTargetAdminUserId` are 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.
- None of them is function-valued: each is an object whose own methods
the code calls, or a value it reads. No receiver changes.
- The hosts declare every field `readonly`, so moved code cannot assign
a member through them. The typecheck passes, so none does. Neither moved
region writes a member.
- Nothing re-exports either module, so the package entry does not move.
## 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 of `start()`'s 4 `isSystem` reads: `hasWriteBypass`'s,
`resolveWriteScope`'s and `describeDelegationNarrowing`'s system
short-circuits. `check-system-context-census` keys each read by file and
enclosing symbol, so row 7's anchor changes from
`security-plugin.ts#start` to
`security-plugin-security-service.ts#registerSecurityService`.
- The symbol changes because the reads now sit in the function. The
row's text and every other anchor stay. Rows 1, 2 and 30 keep `#start`,
which still holds the middleware's read.
- With the page untouched, the census reports 1 problem:
`[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 #25107 enumeration pin. The registration holds the only delegator
resolution in `security-plugin.ts`, and the organization ask beside it.
So in the expected list, `security-plugin-security-service.ts` replaces
`security-plugin.ts`, and the count stays at seven files.
- The rule it pins is unchanged: asks equal resolutions in every file.
It holds: the new module has 1 and 1, and `security-plugin.ts` has 0 and
0.
- Unedited, it fails on the list.
- `packages/core/src/security/row-serving-door-exposure.pin.test.ts`.
Every file that calls `canReadObject` must be classified, and the
service literal's binding `this.canReadObject(…)` now sits in the new
module.
- The new module gains a `not-a-door` entry: "the provider's service
registration: it binds the admission into the `security` service the
plugin registers; it serves no rows".
- `security-plugin.ts` stays a caller, through the stub's closure and
`describePositionGrants`' 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 whether `describePositionGrants` may count a position's
holders; it serves no rows".
- Unedited, it fails with the new module unclassified.
## One new anchor entry
`scripts/adr-anchors/packages__plugins__plugin-security__src__security-plugin-seed-claim.ts.json`
(`adrs: ["ADR-0138"]`).
- Its invariant is the ADR-0138 D1 paragraph of the `security-plugin.ts`
entry, verbatim. That paragraph names `claimSeedOwnershipOnSettle` and
`readSeededRecordIds`, whose bodies now sit in the module. Cut 9 carried
ADR-0106 D7 into `security-plugin-field-readers.ts` the same way.
- The `security-plugin.ts` entry is unchanged and stays true: the
method, the promotion-time pass and the import of `readSeededRecordIds`
stay in that file.
- The security-service module gets no entry, because no paragraph
describes the registration:
- ADR-0055 §1 is the relation reader;
- ADR-0106 D7 is the readable-field asymmetry, in the field-readers
module since cut 9;
- ADR-0123 D2 is step 3.7's refusal, in the middleware.
`docs/adr/**` is not touched, and no other governed path is, so this is
a normal landing.
## The published `.d.ts` does not change
Measured under the series bar (ruling 6348891160 item 1), on base
`82f5a111b4` and on head `5a4747b9c7`. Each was a full `turbo run build`
in its own worktree (both exit 0).
- Raw sha256 of `dist/index.d.ts` and `dist/index.d.mts` is 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.
- Normalised sha256 is the same for all four:
`1e2e8299c2b3aa8502ae3684a5a8a4f7148b2211876a0a581f20d27677531ed9`.
- `security-plugin.ts` gains no export. The two readers gained `export`
in the new module, which nothing re-exports, so the cut 6 trap does not
arise.
- The normaliser, run from `packages/plugins/plugin-security`, sorts the
members of each string-literal union and changes nothing else:
```sh
node -e 'const s=require("fs").readFileSync(process.argv[1],"utf8");process.stdout.write(s.replace(/"[^"\n]*"(?:\s*\|\s*"[^"\n]*")+/g,r=>r.split(/\s*\|\s*/).sort().join(" | ")))' dist/index.d.ts | sha256sum
```
- Positive control, a real package build rather than an edit of the
emitted file. With `private` removed from `claimSeedOwnershipOnSettle`
in the head source, `pnpm --filter @objectstack/plugin-security build`
emits line 431 as the full public signature instead of `private
claimSeedOwnershipOnSettle;`. That gives raw
`12beec21603e70025c7a1b70d2c49fd0dd110d66a61b57e82098a6eb903fe08c` and
normalised
`0509461ad52776d160e6875c3a99cee28dda954089413b05db158aabda6d52ff`, both
different from the real hashes. So the comparison does see a visibility
change. With the source restored, a rebuild gives `5e7e8df6…` again for
both files.
- `claimSeedOwnershipOnSettle` is private, so the `.d.ts` carries only
its name and docblock (line 431). `registerSecurityService` and the two
readers are in no published file.
- Export tables: the ESM and CJS bundles each export the same 66 names
at base and at head. The lists were loaded at runtime, with `require`
and `import()` of the built bundles, not parsed. The sorted name list
hashes to
`83576430f83cf60cecbcc5c0e80214f16c626a8e66f700294fc6a44361423116` for
all four, as at cuts 6 to 10.
- The bundle JS bytes differ, because code moved within them: `index.js`
goes from `a0d05e78` to `b734b9f0`, and `index.mjs` from `1080b070` to
`51498bc7`. Every value the new modules import comes from a file inside
this package or from a specifier `security-plugin.ts` already imports.
So the set of external specifiers each bundle loads is the same at base
and head: 17 distinct `require(…)` specifiers in `index.js` and 24
distinct `from` specifiers in `index.mjs`, counted the same way at both
ends.
- Bundle order, disclosed. The seed-claim module imports
`bootstrap-platform-admin.ts` and `claim-seed-ownership.ts`. So those
two, and `platform-admin-standing-audit.ts`, are now emitted after the
two new modules and ahead of `ownership-floor-alternates.ts` and
`security-plugin.ts`'s first chunk, instead of after
`predicate-guard.ts`. None of the three imports `security-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 base `try`
statement: 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 of `start()` 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 and `async` match. The class keeps the
method's docblock and signature, less `async`.
- **The two readers.** Each one's text in the module, docblock included,
is the base text with `export` added, and nothing else. Neither is left
in `security-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:
- six imports that each lose the names listed above;
- the `./claim-seed-ownership.js` import, which is gone;
- the two readers, which are gone from the file.
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:
- in the registration, `ctx.logger.info(` changed to
`ctx.logger.debug(`;
- in the registration, one line indented by one more space, with the
tokens unchanged;
- in `start()`, one edit in R1 (`:1914`), ahead of the stub;
- in `start()`, one edit in the middleware, after the stub;
- in `readSeedSettlementSnapshot`, `return undefined` changed to `return
null`;
- in `claimSeedOwnershipOnSettle`, `ctx.logger.warn(` changed to
`ctx.logger.error(`;
- in a top-level docblock of `security-plugin.ts`, one trailing space
added.
- **git's own view.** This is `git diff --color-moved=plain
--color-moved-ws=allow-indentation-change 82f5a11 HEAD` over the
three source files.
- Of the 378 deleted lines, git sees 370 as moved. The other 8 are four
type-import lines and the `./bootstrap-platform-admin.js` import line,
which the modules group differently; the two reader signatures that gain
`export`; and the method signature that loses `async`.
- Of the 613 added lines, 391 show as moved: 311 in the security-service
module, 79 in the seed-claim module, and 1 in `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.ts` goes from 8,442 to 8,120 lines.
- `security-plugin-security-service.ts` has 418 lines, and
`security-plugin-seed-claim.ts` 139.
- The other four files are the page (+1 / -1), the two pins (+1 / -1 and
+7 / -1) and the anchor entry (+7).
## ADR anchors (ruling 6353073966 item 2)
- `node scripts/check-adr-symbol-anchors.mjs` exits 0 and gives the same
output at base `82f5a111b4` and at head.
- `pnpm check:adr-anchors` exits 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 Dk` citations in each anchored file
and in each entry's own invariant text. The −12 is:
- −13: the registration's letters leave the anchored surface with it
(ADR-0090 D5 three times, D6, D10 and D12; ADR-0105 D3 and D8; ADR-0106
D7 twice; ADR-0111 D1 and D2; ADR-0131 D3);
- 0: `readSeededRecordIds`' docblock carries ADR-0138 D1, and it stays
on the anchored surface, now in an anchored module;
- +1: the new entry's invariant text.
The method body, the module headers, the stubs and the new import
comments cite none. Measured per file: `security-plugin.ts` holds 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 `adrs` list 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.
- It was measured with `extractAnchors` and `symbolSegmentResolution`
from `scripts/symbol-anchors.mjs`. That is measurement, not a new gate.
- It was read on `82f5a111b4` BEFORE the claim, with the whole cut
applied as a local trial, and no anchor changed class.
- No ADR anchors the moved method, the two readers or the new function.
Two anchored members are named inside the service literal:
`#getReadFilter` and `#SecurityPlugin.getMetadataReadableFields`. Their
names now also appear in the stub's host literal and its `Pick`. Both
still resolve as `declaration`, 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`.
| anchor | cited at | base class · line (member) | head class · line
(member) |
|---|---|---|---|
| `#CBP_MAX_CHAIN_DEPTH` | ADR-0055:135 | declaration · `:746`
(top-level) | declaration · `:748` (top-level) |
| `#SecurityPlugin` | ADR-0049:49, ADR-0138:248, ADR-0138:265 |
declaration · `:1348` (class) | declaration · `:1309` (class) |
| `#SecurityPlugin.getMetadataReadableFields` | ADR-0138:153 |
declaration · `:5620` (method) | declaration · `:5298` (method) |
| `#SecurityPlugin.resolvePermissionSetsForContextUnmemoized` |
ADR-0138:427 | declaration · `:6214` (method) | declaration · `:5892`
(method) |
| `#assertControlledByParentWrite` | ADR-0055:58, ADR-0055:125 |
declaration · `:7699` (method) | declaration · `:7377` (method) |
| `#assertMasterRowEditable` | ADR-0055:125 | declaration · `:7825`
(method) | declaration · `:7503` (method) |
| `#collectRLSPolicies` | ADR-0105:93 | declaration · `:7879` (method) |
declaration · `:7557` (method) |
| `#composeWriteTenantWall` | ADR-0123:4 | declaration · `:7037`
(method) | declaration · `:6715` (method) |
| `#computeControlledByParentFilter` | ADR-0055:5, ADR-0055:123,
ADR-0139:246 | declaration · `:7345` (method) | declaration · `:7023`
(method) |
| `#computeDelegatedReadFilter` | ADR-0139:223 | declaration · `:5539`
(method) | declaration · `:5217` (method) |
| `#computeRlsFilter` | ADR-0055:24 | declaration · `:6745` (method) |
declaration · `:6423` (method) |
| `#getReadFilter` | ADR-0096:181, ADR-0096:182, ADR-0096:183,
ADR-0096:199, ADR-0139:222 | declaration · `:5485` (method) |
declaration · `:5163` (method) |
| `#hasPlatformAdminPosture` | ADR-0099:317 | declaration · `:6772`
(method) | declaration · `:6450` (method) |
| `#isPrincipalLessContext` | ADR-0138:152 | declaration · `:619`
(top-level) | declaration · `:621` (top-level) |
| `#manage_metadata` | ADR-0099:68 | literal · `:372` (top-level) |
literal · `:374` (top-level) |
| `#nav_permission_sets` | ADR-0126:406 | literal · `:1776` (`init`) |
literal · `:1737` (`init`) |
| `#rlsFilter` | ADR-0055:24 | declaration · `:4360` (`start`) |
declaration · `:4038` (`start`) |
| `#writeCheckPolicies` | ADR-0066:112 | declaration · `:1243`
(top-level) | declaration · `: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:
- **The system-context census.**
- `node scripts/isystem-census.mjs --json` gives the same 149 sites at
base and at head, with 0 differences. The comparison ignores line
numbers, maps the two modules back to `security-plugin.ts`, and maps the
symbol `registerSecurityService` back to `start`.
- Three head sites are in the security-service module: the three
short-circuits, which the re-pointed row 7 names.
- The role counts are the same (`read` 154, `declaration` 39, `key` 440,
`other` 9), 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-census` and its `--self-test` exit 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).
- **The tenant-audit census.** No moved code holds an engine write. The
seed claim writes through `claimSeedOwnership`, which stays in its own
file, and the registration only reads.
- `node scripts/tenant-audit-census.mjs --json` gives 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. Only
`scannedSources` moves, from 739 to 741: the two modules.
- `check-tenant-audit-census` exits 0 at base and at head, and
`tenant-audit-census.mdx` is not touched.
- **The two pins** are described above.
`operation-private-keys.pin.test.ts` (`@objectstack/core`) names no
moved code, and it passes at head.
- **Symbol anchors outside the ADRs.** Across the ADR, spec liveness,
platform checklist, system-context page and spec
`conversions/registry.ts` corpora, `security-plugin.ts#X` is cited 48
times over 26 symbols at base and 47 at head. With
`symbolSegmentResolution`, each resolves at head with its base class: 0
changed. The one ref that leaves is row 7's.
- `check-platform-checklist` (the script and `pnpm
check:platform-checklist`), `check-scripts-symbol-anchors` and its
`--self-test`, and `pnpm --filter @objectstack/spec check:liveness` were
run at base and at head (Gates).
- **Readers by name, not by path.** These were read, and none needs a
change:
- the behaviour tests of the `security` service and the seed claim in
this package. Each drives the plugin or the registered service, and none
calls the moved code directly. No test replaces
`claimSeedOwnershipOnSettle` on the plugin instance;
- the page's row text and the docblocks that stay in the class, which
name these members and stay true by name.
- **Line citations.** No `security-plugin.ts:N` citation in the repo
points into the moved ranges (base `:1254` to `:1293`, `:1873` to
`:1905` and `:2266` to `:2560`).
## Gates
All gates ran against base `82f5a111b4` and on head `5a4747b9c7`, each
in its own worktree after a full `turbo run build` there (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). Base
`82f5a111b4` gives the same counts.
- `pnpm --filter @objectstack/plugin-security typecheck`: exit 0 at head
and at base. It runs `tsc --noEmit`, the scripts tsconfig, and
`check: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.ts` and the bundles measured above.
- `row-serving-door-exposure.pin.test.ts` and
`operation-private-keys.pin.test.ts` (`@objectstack/core`): 8 of 8 pass
at head and at base.
- `dispatch-gates --commands`: 101 commands. The `--ran` reconciliation
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 and `pnpm
check:platform-checklist`;
- the two census `--json` reads;
- `pnpm --filter @objectstack/spec check:liveness`.
`pnpm check:adr-anchors`, `check-scripts-symbol-anchors` and its
`--self-test`, and `pnpm check:query-options-erasure` are derived for
this change set this time.
- Nine more were run at base and at head:
- Ten artifact-roster families keep their roster in a directory this
change touches, so `dispatch-gates` marks their silence as no evidence.
Two of them, `check:engine-double-contract` and `check:i18n-stale-fill`,
are derived anyway. The other eight were run:
`check-published-list-mirrors` and its `--self-test`,
`check:authz-resolver`, `check:console-injection`,
`check:error-code-casing`, `check:filter-alias-parity`,
`check:published-readme-exports` and `check-dts-references --self-test`.
- The ninth is the package typecheck.
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:
- These move as described above: `check:adr-anchors`,
`check-system-context-census` and the two census `--json` reads. The
tenant read moves only by `scannedSources` and its own ref.
- The plugin-security suite's console output is not stable between runs:
log lines from parallel workers, generated ids and timestamps. Its stack
frames into `security-plugin.ts` carry the file's new line numbers. Its
counts are the same at both ends (above).
- `check-issue-citations` judges a change set, so it has nothing to read
at base. At head it judged 22 citations across 3 files, and all resolve.
- These counts move by the two modules (and the anchor entry, for the
whole-index readers):
- `check-closing-keyword-parity` 12065 to 12068 tracked files;
- `check:gitlink-declared` 12065 to 12068 index entries;
- `check:nul-bytes` 12056 to 12059;
- `check-comment-mask-corpus` 10030 to 10032;
- `check-plugin-teardown-shape` 9421 to 9423 sources;
- `check-position-name-fold-loaders` 12399 to 12402 files, with the same
8 references;
- `check-undeclared-dep-imports` 3326 to 3328 files;
- the spec package's `check:duration-unit-keys` 3331 to 3333;
- `check:closed-ceremony-text` 4594 to 4596;
- `check:doc-authoring` 1445 to 1447 parsed sources;
- `check:engine-double-contract` 3636 to 3638 production files;
- `check:error-status-conformance` 3424 to 3426, with the same 510
producer sites;
- `check:error-code-casing` 9404 to 9406;
- `check:logger-receiver-detach` 3644 to 3646;
- `check:org-identifier` 3669 to 3671;
- `check:page-declaration-shape` 3677 to 3679;
- `check:refd-timer-probe` 10023 to 10025;
- `check:type-check-coverage` and `check:type-check-debt` 3553 to 3555
walked sources;
- `check:vendor-version-stamps` 10422 to 10424;
- `check:agent-test-spelling` 613 to 614 files, with the same tokens and
runs;
- `check:pnpm-flag-spellings` 454 to 455 files under `scripts/` (the
anchor entry), with the same scripts read.
- `check-undeclared-dep-imports` also reads 2885 to 2890
`@objectstack/*` specifiers. Those are the ones the two modules import,
all declared dependencies. `security-plugin.ts` keeps every specifier it
still uses.
- `check:doc-authoring` also reads 105072 to 105157 strings, the strings
of the new headers and stubs.
- `check:skill-identifier-liveness` reads 140073 to 140077
implementation word tokens. Those are the four words new to the tree:
`SecurityServiceHost`, `SeedClaimHost`, `registerSecurityService` and
the stub's getter local `readClaimTargetAdminUserId`. No citation
changes.
- `check:merge-driver` differs 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.mjs` exit 0 (base 0)
- `node scripts/check-closing-keyword-parity.mjs` exit 0 (base 0)
- `node scripts/check-closing-keyword-parity.mjs --self-test` exit 0
(base 0)
- `node scripts/check-comment-mask-adoption.mjs` exit 0 (base 0)
- `node scripts/check-comment-mask-adoption.mjs --self-test` exit 0
(base 0)
- `node scripts/check-comment-mask-corpus.mjs` exit 0 (base 0)
- `node scripts/check-dev-prereqs.mjs --self-test` exit 0 (base 0)
- `node scripts/check-doc-frontmatter.mjs` exit 0 (base 0)
- `node scripts/check-doc-frontmatter.mjs --self-test` exit 0 (base 0)
- `node scripts/check-doc-route-spelling.mjs --advisory` exit 0 (base 0)
- `node scripts/check-doc-route-spelling.mjs --self-test` exit 0 (base
0)
- `node scripts/check-docs-section-name.mjs` exit 0 (base 0)
- `node scripts/check-docs-section-name.mjs --self-test` exit 0 (base 0)
- `node scripts/check-dts-emitted.mjs --self-test` exit 0 (base 0)
- `node scripts/check-issue-citations.mjs` exit 0 (base 0)
- `node scripts/check-keyed-text-bounds.mjs` exit 0 (base 0)
- `node scripts/check-keyed-text-bounds.mjs --self-test` exit 0 (base 0)
- `node scripts/check-platform-object-tenancy-census.mjs` exit 0 (base
0)
- `node scripts/check-platform-object-tenancy-census.mjs --self-test`
exit 0 (base 0)
- `node scripts/check-plugin-teardown-shape.mjs` exit 0 (base 0)
- `node scripts/check-plugin-teardown-shape.mjs --self-test` exit 0
(base 0)
- `node scripts/check-position-name-fold-loaders.mjs` exit 0 (base 0)
- `node scripts/check-position-name-fold-loaders.mjs --self-test` exit 0
(base 0)
- `node scripts/check-registry-log-declared.mjs` exit 0 (base 0)
- `node scripts/check-registry-log-declared.mjs --self-test` exit 0
(base 0)
- `node scripts/check-rest-log-spy-declared.mjs` exit 0 (base 0)
- `node scripts/check-rest-log-spy-declared.mjs --self-test` exit 0
(base 0)
- `node scripts/check-scripts-symbol-anchors.mjs` exit 0 (base 0)
- `node scripts/check-scripts-symbol-anchors.mjs --self-test` exit 0
(base 0)
- `node scripts/check-section-landing-index.mjs` exit 0 (base 0)
- `node scripts/check-section-landing-index.mjs --self-test` exit 0
(base 0)
- `node scripts/check-system-context-census.mjs` exit 0 (base 0)
- `node scripts/check-system-context-census.mjs --self-test` exit 0
(base 0)
- `node scripts/check-tenant-audit-census.mjs` exit 0 (base 0)
- `node scripts/check-tenant-audit-census.mjs --self-test` exit 0 (base
0)
- `node scripts/check-undeclared-dep-imports.mjs` exit 0 (base 0)
- `node scripts/check-undeclared-dep-imports.mjs --self-test` exit 0
(base 0)
- `node scripts/ci/assert-turbo-remote-cache.mjs --self-test` exit 0
(base 0)
- `node scripts/docs-audit/check-affected-docs.mjs` exit 0 (base 0)
- `node scripts/docs-audit/check-drift-comment.mjs` exit 0 (base 0)
- `pnpm --filter @objectstack/lint run check:doc-formula-expressions`
exit 0 (base 0)
- `pnpm --filter @objectstack/lint run check:doc-security-posture` exit
0 (base 0)
- `pnpm --filter @objectstack/spec run check:docs` exit 0 (base 0)
- `pnpm --filter @objectstack/spec run check:duration-unit-keys` exit 0
(base 0)
- `pnpm --filter @objectstack/spec run check:empty-state` exit 0 (base
0)
- `pnpm --filter @objectstack/spec run check:liveness` exit 0 (base 0)
- `pnpm --filter @objectstack/spec run check:skill-examples` exit 0
(base 0)
- `pnpm --filter @objectstack/spec run check:strictness-ledger` exit 0
(base 0)
- `pnpm --filter @objectstack/spec run check:variant-docs` exit 0 (base
0)
- `pnpm --filter @objectstack/spec run check:yaml-examples` exit 0 (base
0)
- `pnpm check:adr-anchors` exit 0 (base 0)
- `pnpm check:agent-test-spelling` exit 0 (base 0)
- `pnpm check:bash32-floor` exit 0 (base 0)
- `pnpm check:cli-command-ids` exit 0 (base 0)
- `pnpm check:closed-ceremony-text` exit 0 (base 0)
- `pnpm check:corpus-claim-drift` exit 0 (base 0)
- `pnpm check:cross-package-test-inputs` exit 0 (base 0)
- `pnpm check:doc-anchors` exit 0 (base 0)
- `pnpm check:doc-authoring` exit 0 (base 0)
- `pnpm check:docs-audit-scope` exit 0 (base 0)
- `pnpm check:docs-redirects` exit 0 (base 0)
- `pnpm check:docs-single-h1` exit 0 (base 0)
- `pnpm check:docs-spec-enumerations` exit 0 (base 0)
- `pnpm check:docs-transcript-drift` exit 0 (base 0)
- `pnpm check:driver-memory-census` exit 0 (base 0)
- `pnpm check:dts-closure` exit 0 (base 0)
- `pnpm check:dual-build-cjs-loads` exit 0 (base 0)
- `pnpm check:engine-double-contract` exit 0 (base 0)
- `pnpm check:entry-guard` exit 0 (base 0)
- `pnpm check:error-status-conformance` exit 0 (base 0)
- `pnpm check:gitlink-declared` exit 0 (base 0)
- `pnpm check:i18n` exit 0 (base 0)
- `pnpm check:i18n-stale-fill` exit 0 (base 0)
- `pnpm check:issue-citations` exit 0 (base 0)
- `pnpm check:kernel-hook-pairs` exit 0 (base 0)
- `pnpm check:lean-entry-closure` exit 0 (base 0)
- `pnpm check:logger-receiver-detach` exit 0 (base 0)
- `pnpm check:merge-driver` exit 0 (base 0)
- `pnpm check:nul-bytes` exit 0 (base 0)
- `pnpm check:objectql-double-limit` exit 0 (base 0)
- `pnpm check:org-identifier` exit 0 (base 0)
- `pnpm check:page-declaration-shape` exit 0 (base 0)
- `pnpm check:parse-guard` exit 0 (base 0)
- `pnpm check:pnpm-filter-targets` exit 0 (base 0)
- `pnpm check:pnpm-flag-spellings` exit 0 (base 0)
- `pnpm check:published-files` exit 0 (base 0)
- `pnpm check:published-readme-links` exit 0 (base 0)
- `pnpm check:query-options-erasure` exit 0 (base 0)
- `pnpm check:react-page-adapter-contract` exit 0 (base 0)
- `pnpm check:refd-timer-probe` exit 0 (base 0)
- `pnpm check:role-word` exit 0 (base 0)
- `pnpm check:skill-identifier-liveness` exit 0 (base 0)
- `pnpm check:slot-lookup` exit 0 (base 0)
- `pnpm check:sourcemap-no-sources-content` exit 0 (base 0)
- `pnpm check:test-source-alias` exit 0 (base 0)
- `pnpm check:tier-file-adoption` exit 0 (base 0)
- `pnpm check:type-check-coverage` exit 0 (base 0)
- `pnpm check:type-check-debt` exit 0 (base 0)
- `pnpm check:vendor-version-stamps` exit 0 (base 0)
- `pnpm check:watch-hint-literal` exit 0 (base 0)
- `pnpm check:where-matcher` exit 0 (base 0)
- `node scripts/check-adr-symbol-anchors.mjs` exit 0 (base 0)
- `node scripts/check-platform-checklist.mjs` exit 0 (base 0)
- `pnpm check:platform-checklist` exit 0 (base 0)
- `node scripts/isystem-census.mjs --json` exit 0 (base 0)
- `node scripts/tenant-audit-census.mjs --json` exit 0 (base 0)
- `pnpm --filter @objectstack/spec check:liveness` exit 0 (base 0)
- `node scripts/check-published-list-mirrors.mjs` exit 0 (base 0)
- `pnpm check:authz-resolver` exit 0 (base 0)
- `pnpm check:console-injection` exit 0 (base 0)
- `pnpm check:error-code-casing` exit 0 (base 0)
- `pnpm check:filter-alias-parity` exit 0 (base 0)
- `pnpm check:published-readme-exports` exit 0 (base 0)
- `pnpm --filter @objectstack/plugin-security typecheck` exit 0 (base 0)
- `pnpm --filter @objectstack/plugin-security test` exit 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.ts` exit 0 (base 0)
- `node scripts/check-dts-references.mjs --self-test` exit 0 (base 0)
- `node scripts/check-published-list-mirrors.mjs --self-test` exit 0
(base 0)
## Acceptance notes
- Nothing outside this cut is touched: no other section of the class or
of `start()`, no behaviour, no `docs/adr/**`, no census ledger and no
`packages/spec/**`. Outside the package, two files change: the one
anchor path on the system-context page, and the core pin's
classification.
- Serial check, also in the claim: of the 9 open PRs, one touches
`security-plugin.ts`: #25528 (#25234's second PR, another project's). It
adds one import after the rls-filter import (`:173` here), a loop in R1
after the resolver's registration log (`:2167` here), and edits
`stageRlsMembership`. None of those lines is in the registration, the
seed claim, the readers or an import line this cut edits. A scratch
merge of #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.
- After this cut, `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 merged `main`. It is Tier H on two counts, the ADR-0055:24
`#rlsFilter` re-anchor (ruling 6353073966 item 5) and its size, and its
claim says so up front.
---
_Generated by [Claude
Code](https://claude.ai/code/session_017BoLT8Gaa8t9a7AWVH8qZa)_
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_017BoLT8Gaa8t9a7AWVH8qZa
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 5ea211c commit c15fd9a
7 files changed
Lines changed: 629 additions & 381 deletions
File tree
- content/docs/permissions
- packages
- core/src/security
- plugins/plugin-security/src
- scripts/adr-anchors
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
105 | 105 | | |
106 | 106 | | |
107 | 107 | | |
108 | | - | |
| 108 | + | |
109 | 109 | | |
110 | 110 | | |
111 | 111 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
93 | 93 | | |
94 | 94 | | |
95 | 95 | | |
96 | | - | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
97 | 103 | | |
98 | 104 | | |
99 | 105 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
701 | 701 | | |
702 | 702 | | |
703 | 703 | | |
704 | | - | |
| 704 | + | |
705 | 705 | | |
706 | 706 | | |
707 | 707 | | |
| |||
0 commit comments