Repository navigation
Commit 82f5a11
<!-- 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 10 of the `security-plugin.ts` split covers row 8 of the series
plan: the everyone anchor, the explanation, the sharing verdicts and the
authored-row write verdict. The claim is 6369634056. The row has four
seams, so this one PR moves the bodies of ten methods out of the class,
unedited, into four new modules. Cut 9 split its row the same way, over
three.
To
`packages/plugins/plugin-security/src/security-plugin-everyone-anchor.ts`:
- `declareEveryone`: the `everyone` anchor's definition, as a started
kernel derives it. It is the deployment's baseline plus every package
default a `manage_metadata` holder accepted. Each withheld acceptance is
reported with its reason (ADR-0090 D5/D7, ADR-0131 D3, #22801).
- `declareBuiltinPositions`: the six built-in positions, declared to the
engine registry from `init()`. `everyone` names the fail-closed baseline
(ADR-0131 D2). It is synchronous and stays synchronous.
To
`packages/plugins/plugin-security/src/security-plugin-explain-access.ts`:
- `explainAccessForCaller` (public): the `security/explain` answer for a
caller. It covers:
- who may explain whom (ADR-0090 D6, D12);
- the explained user's context, built and vetted against the caller's
organization;
- the evaluation through the explain engine, with the CALLER as the
asker of the record's read (#22792, #22851).
To
`packages/plugins/plugin-security/src/security-plugin-sharing-verdicts.ts`:
- `resolveSharingReadFilter`: the owner/share half of the read scope. It
throws on a resolution failure, so its callers fail closed (#4467).
- `resolveSharingCanEdit`: the sharing gate of a single-record write. It
fails closed when the probe throws (#5386).
- `resolveWriteScopeForSharing`: the write-depth stash that both write
probes hand the service (ADR-0057 D1).
- `resolveSharingWriteVerdict`: the tri-state write verdict (#5492,
#6428).
- `resolvePreImageFloorDrop`: the floor decision of the by-id pre-image
gate. `security/explain` asks it too (#19963).
- `delegatorOwnWriteFloorOptions`: the composition knobs the delegator's
own direct by-id write would get (ADR-0090 D10).
To
`packages/plugins/plugin-security/src/security-plugin-authored-row-write.ts`:
- `checkAuthoredRowWrite` (public): the
`ISecurityService.checkAuthoredRowWrite` verdict, `admit` or `abstain`
(#5493, #7281, #8059). The scope its probe read runs under moves with
it: `AUTHORED_ROW_WRITE_PROBE_CONTEXT`, which nothing else reads.
The change is move-only, and the card stays open for `start()`. The
branch is `claude/project-thread-3fzya4`, the harness-pinned branch for
this session. It was restarted from `origin/main` at `05cc3ee953`, which
contains cut 9's merge `dd124e9466`. The branch name 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
reaches the methods through the plugin:
- the `security` service binding (`explain`, `checkAuthoredRowWrite`);
- `init()` and `kernel:ready`;
- the middleware;
- the read scope;
- the master gate.
Two members of the row stay whole, `everyoneBaseline` (6 body lines) and
`destroy` (3). Neither body is longer than its stub would be:
`everyoneBaseline`'s stub would also be 6 lines.
**Module-level declarations.**
- `AUTHORED_ROW_WRITE_PROBE_CONTEXT` is read only by
`checkAuthoredRowWrite`'s body. It moves with its docblock, unedited and
still unexported, as cuts 1 to 4 and 9 moved declarations that only
their bodies read. Its docblock's `{@link
SecurityPlugin.checkAuthoredRowWrite}` resolves through the module's
type import of the class.
- `absentUnderCallerRead` and `unreadableUnderCallerRead` stay in
`security-plugin.ts`, and each gains `export` and nothing else. The
explanation reads both. `absentUnderCallerRead` is shared with the write
path's step 2.7, which stays. `unreadableUnderCallerRead` is defined and
documented beside it. Its docblock links to `absentUnderCallerRead`, and
cut 8's `security-plugin-addressed-writes.ts` header names both as
living in `security-plugin.ts`.
- `requiredCapsForOperation` is already exported. The explanation
imports it by value, as the object-admission module does.
- Import names that only the moved bodies read leave
`security-plugin.ts`. The modules import them from the same specifiers:
- `explainAccessForAsker` and `buildContextForUser`
(`./explain-engine.js`);
- the whole `./builtin-positions.js` import (`declareEveryoneBaseline`,
`registerBuiltinPositions`);
- `readAcceptedEveryoneSets` (`./suggested-audience-bindings.js`);
- `readDeclaredCapabilityContext` (`./declared-capability-context.js`);
- `vetOrganizationClaim` (`@objectstack/core`);
- the type `ExplainOperation` (`@objectstack/spec/security`).
No staying docblock links to any of them. Two staying docblocks name
`readAcceptedEveryoneSets` and `vetOrganizationClaim`, in backticks
only.
- The unexported interface `RlsFilterOptions` stays where every gate
reads it. The explanation and the sharing verdicts name it through the
class's own signature, as the type of `computeLayeredRlsFilter`'s fifth
parameter less `undefined`, so the moved text names it exactly as
before. Cut 9's modules name `ObjectSecurityMeta` the same way.
- Each value import is read only inside a function body, at call time,
and never while a module evaluates. `index.ts` still exports only what
it did, so the published surface does not move (measured below).
**Two readers outside the moved code read the moved lines by path. Both
are re-pointed in this PR, as cut 9 re-pointed the same two.**
- `content/docs/permissions/system-context.mdx`, row 9.
`check-system-context-census` keys each elevation read by file and
enclosing symbol, and `explainAccessForCaller`'s
`callerContext?.isSystem` read now sits in the explain module.
- A trial cut measured the page left untouched. The census reports 2
problems: the new file has no row, and the old anchor is no longer a
read site.
- The anchor keeps its symbol and changes only its path, from
`security-plugin.ts#explainAccessForCaller` to
`security-plugin-explain-access.ts#explainAccessForCaller`. No row's
text changes.
-
`packages/plugins/plugin-security/src/delegated-organization-membership.test.ts`,
the #25107 enumeration pin. The explanation resolves a delegator and
asks the organization check beside it. So the expected list gains
`security-plugin-explain-access.ts`, and the title says seven files
instead of six.
- The rule it pins is unchanged: asks equal resolutions in every file.
It holds at head: the explain module counts 1 and 1, and
`security-plugin.ts` counts 1 and 1 (`start()`; it counted 2 and 2 at
base).
**No ADR anchor entry is added.** No paragraph of the
`security-plugin.ts` entry describes these bodies (see ADR anchors
below).
**One receiver changes, disclosed.** `resolveKernelService` is a
function-valued field. The explanation and three of the sharing verdicts
call it through the host, so its `this` is now the host, not the plugin.
Two facts keep every call answering as it did:
- the only function ever assigned to the field is the arrow function
`start()` assigns, which returns `ctx.getService(name)` and answers
`undefined` when that throws, and it reads no `this`;
- no test or other file assigns the field.
Cut 9's report said that no body it moved calls a function-valued field.
This cut's bodies do, so it is stated here.
## The published `.d.ts` does not change
Measured under the series bar (ruling 6348891160 item 1), on base
`05cc3ee953` and on head `38392cb1b7`. Each was a full `turbo run build`
in its own worktree. A package build of the same trees before the claim
gave the same bytes.
- Raw sha256 of `dist/index.d.ts` and `dist/index.d.mts` is the same for
all four files, base and head:
`7d67966ce82e00a1531807b3b0008f16c489fc2c3199f9ad67078302eb2803da`. The
raw diff is 0 lines, so no union order moved either. These are the same
bytes cut 9 measured, so neither cut 9's merge nor main's later commits
moved this package's `.d.ts`.
- Normalised sha256 is the same for all four:
`b53e9025f794e20debd2245afed5ceb1a0ad48109a2a21cc19232a562ccd9cb4`.
- `security-plugin.ts` gains two exports, `absentUnderCallerRead` and
`unreadableUnderCallerRead`. Each takes one read callback and answers a
boolean promise, so its signature names no type from another module, so
the cut 6 trap does not arise. `index.ts` re-exports neither.
- 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 controls, each a one-line edit on a copy of the head
`dist/index.d.ts`:
- line 557 (`private resolveSharingReadFilter;`) made public: raw
`8c8fad488058d08a54e23b5410b539b7eecad71a0e749b0133a61280e146bdde`,
normalised
`f02f50957a57e31fd943e00fa0ef74113a2f0efdc4af8e3ee5b963c7e932a3c6`;
- line 447 renamed (`private declareEveryoneRenamed;`): raw
`7af56294d477cdbc07b22567c87a110bbc2c36d37724cc47ed3652dc085a8ab4`,
normalised
`44d50a2b10e166373f11f31ef5e046c1a05ab9f5613e9d6b762c03c7ca15ec88`;
- line 745, the public `checkAuthoredRowWrite` signature, with
`context?: any` changed to `context?: unknown`: raw
`b75e990785a61245092adf8414acba79b6fe27f330ebd7555e9a808642802556`,
normalised
`6b7331a568193fda94c1e45eabe85f5704d61c6ef99639bb197b7f11510b81b6`.
All three differ from the real hashes, so the comparison does see a
visibility change, a rename and a change to a public signature.
- The two public methods carry their full signatures and docblocks in
the `.d.ts`: `explainAccessForCaller` (line 525) and
`checkAuthoredRowWrite` (745). The eight private methods carry only
their name and docblock: `declareEveryone` (447),
`declareBuiltinPositions` (483), and the six sharing verdicts (557 to
676). Those lines are the same in both files.
- 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 9.
- The bundle JS bytes differ, because code moved within them: `index.js`
goes from `dfa83a54` to `78d8f0eb`, and `index.mjs` from `18c4d919` to
`5d290484`. 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: 16 distinct `require` specifiers in `index.js` and 19 distinct
`from` specifiers in `index.mjs`.
- Bundle order, disclosed: `builtin-positions.ts`, `manifest.ts` and
`objects/sys-audience-binding-suggestion.object.ts` are now emitted just
ahead of the four modules, where before they sat between
`security-plugin.ts`'s chunks. None of them imports
`security-plugin.ts`, and their top level only declares constants.
No changeset: `skip-changeset`, per ruling 6348891160 item 4.
## What moved
The base line numbers are each method's signature and closing brace at
`05cc3ee953`. The last column lists the members the body reads, which is
exactly what its host carries.
| method | base lines | module | host members |
|---|---|---|---|
| `declareEveryone` (private, async) | `:4912`-`:4946` | everyone-anchor
| `deploymentAcceptance`, `epoch`, `everyoneBaseline`, `metadata`, `ql`
|
| `declareBuiltinPositions` (private) | `:4994`-`:5013` |
everyone-anchor | `everyoneBaseline` |
| `explainAccessForCaller` (public, async) | `:5061`-`:5373` |
explain-access | `baselinePermissionSets`,
`checkControlledByParentWrite`, `computeLayeredRlsFilter`,
`computeReadPartialMaskRules`, `computeRlsFilter`, `delegatedAdminGate`,
`foldFieldRequiredPermissions`, `getObjectSecurityMeta`,
`permissionEvaluator`, `ql`, `readRowById`, `resolveKernelService`,
`resolvePermissionSetsForContext`, `resolvePreImageFloorDrop`,
`resolveSharingReadFilter`, `resolveWriteScopeForSharing`,
`tenancyPosture` |
| `resolveSharingReadFilter` (private, async) | `:5401`-`:5449` |
sharing-verdicts | `getObjectSecurityMeta`, `permissionEvaluator`,
`resolveKernelService`, `resolvePermissionSetsForContext` |
| `resolveSharingCanEdit` (private, async) | `:5468`-`:5493` |
sharing-verdicts | `logger`, `resolveKernelService`,
`resolveWriteScopeForSharing` |
| `resolveWriteScopeForSharing` (private, async) | `:5513`-`:5531` |
sharing-verdicts | `getObjectSecurityMeta`, `permissionEvaluator`,
`resolvePermissionSetsForContext` |
| `resolveSharingWriteVerdict` (private, async) | `:5563`-`:5593` |
sharing-verdicts | `logger`, `resolveKernelService`,
`resolveWriteScopeForSharing` |
| `resolvePreImageFloorDrop` (private, async) | `:5621`-`:5642` |
sharing-verdicts | `collectRLSPolicies`, `resolveSharingWriteVerdict` |
| `delegatorOwnWriteFloorOptions` (private, async) | `:5667`-`:5684` |
sharing-verdicts | `resolvePreImageFloorDrop` |
| `checkAuthoredRowWrite` (public, async) | `:5754`-`:5838` |
authored-row-write | `collectRLSPolicies`, `computeLayeredRlsFilter`,
`logger`, `ql`, `resolvePermissionSetsForContext` |
Each async stub drops `async` and returns the moved function's promise,
as cuts 1 and 3 to 9 did for their async methods.
`declareBuiltinPositions` was synchronous, and its stub returns its
function's `void`. Two of the ten are public, so the `.d.ts` carries
their full signatures. A body move does not touch a signature, and those
lines do not change (above).
## The shape (#23050 shape B, as cuts 1 to 9 applied it)
- The class keeps each method with its name, signature, docblock and
position, because tsup emits members with their JSDoc into the `.d.ts`.
Each body is now one host literal plus `fn.call(host, …)`, marked
`[#25223 cut 10]`.
- `EveryoneAnchorHost`, `ExplainAccessHost`, `SharingVerdictsHost` and
`AuthoredRowWriteHost` 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 body
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. So a spy or test double set on the plugin is still
the one the body reaches:
- the everyone declarations still ask the plugin's baseline and
deployment acceptance;
- the explanation still asks the plugin's set resolution, RLS filters,
sharing read filter, write-depth stash, floor decision,
controlled-by-parent check, field folds, posture reader and by-id read;
- the sharing verdicts still ask the plugin's set resolution, posture
reader and RLS policy collection, and they still ask each other through
the plugin;
- the authored-row verdict still asks the plugin's set resolution,
policy collection and layered RLS filter.
No test replaces a moved method on the plugin instance today. One that
did would still replace it for every caller.
- Fields follow the rule cut 1 set, judged on each field's own
declaration:
- `baselinePermissionSets` is declared `readonly`, so it goes by value.
- None of the other eight fields the bodies read is declared `readonly`:
`delegatedAdminGate`, `epoch`, `logger`, `metadata`,
`permissionEvaluator`, `ql`, `resolveKernelService` and
`tenancyPosture`. So they go as getters, and each read happens when the
body makes it. `start()` assigns all of them except
`permissionEvaluator` after construction, and tests replace
`permissionEvaluator` on a constructed plugin.
- `delegatedAdminGate`, `epoch`, `logger`, `permissionEvaluator` and
`ql` are objects whose own methods the bodies call.
`resolveKernelService` is the one function-valued field (disclosed
above).
- The hosts declare every field `readonly`, so a moved body cannot
assign a member through them. The typecheck passes, so none does.
- Nothing re-exports any of the modules, so the package entry does not
move.
## Proof of move-only
- **Bodies, by AST token.** Each moved function's body has the same
TypeScript token sequence as the base method body. Each of the 549 body
lines is the base line with two leading spaces removed. Parameters,
return types and `async` match.
- The explanation's body holds five multi-line JSDoc text tokens, the
docblocks of its inner closures. Their continuation lines are
re-indented one level, like every other body line. So the comparison
dedents those JSDoc tokens one level, and only those. A string or
template token that spans lines is compared byte for byte. The
explanation's 1,731 tokens are then equal.
- Four negative controls fail the check:
- in `explainAccessForCaller`, `callerContext?.isSystem === true`
changed to `=== false`;
- in `resolveSharingCanEdit`, the fail-closed `return false;` of the
probe's `catch` changed to `return true;`;
- in `checkAuthoredRowWrite`, the non-write abstention `return
'abstain';` changed to `return 'admit';`;
- in one of the explanation's inner JSDoc blocks, "The two contexts"
changed to "The three contexts". This control shows that the JSDoc
dedent does not hide a change of words.
- **Class side.** Each moved method keeps its docblock and signature,
less `async`. Every other class member is byte-identical to base: 116
named members plus the constructor, including `everyoneBaseline` and
`destroy`. The class has 127 members at base and at head.
- **Top level of `security-plugin.ts`.** Of the 106 top-level statements
at base other than the class, 97 are byte-identical at head. The other
nine:
- five imports each lose the names listed above, and the
`./builtin-positions.js` import is gone;
- `AUTHORED_ROW_WRITE_PROBE_CONTEXT` is gone from the file. The
authored-row module holds the same statement and docblock, byte for
byte;
- `absentUnderCallerRead` and `unreadableUnderCallerRead` are the base
text with `export` added.
The four new statements are the imports of the new modules.
- **The two re-pointed readers.** The page diff is one line, the
anchor's path. The pin diff is the title's count and one added list
entry.
- **git's own view.** This is `git diff --color-moved=plain
--color-moved-ws=allow-indentation-change 05cc3ee HEAD` over the five
source files. Of the 596 deleted lines, git sees 581 as moved. The other
15 are the nine signatures that lose `async`, four of the import lines
that change, and the two functions that gain `export`. Of the 1,184
added lines, 679 show as moved: 669 in the four modules, and 10 in
`security-plugin.ts` whose text git also finds among the deleted lines
(nine stub `};` lines and the host line `baselinePermissionSets:
this.baselinePermissionSets,`). The rest are the modules' headers,
imports, host interfaces, type aliases and function signatures, the ten
stubs, and the four new imports with their comments.
- **Size.** 1,785 changed lines (+1,187 / -598) over 7 files, under the
3,000-line manual-merge line.
- `security-plugin.ts` goes from 8,852 to 8,406 lines.
- `security-plugin-everyone-anchor.ts` has 140 lines,
`security-plugin-explain-access.ts` 433,
`security-plugin-sharing-verdicts.ts` 277 and
`security-plugin-authored-row-write.ts` 184.
- The other two files are the page (+1 / -1) and the pin (+2 / -1).
## ADR anchors (ruling 6353073966 item 2)
- `node scripts/check-adr-symbol-anchors.mjs` exits 0 and gives
byte-identical output at base `05cc3ee953` and at head. `dispatch-gates
--commands` does not derive it for this change set, so it was run by
hand.
- `pnpm check:adr-anchors` exits 0 at base and at head, with 81 anchored
files at both ends.
- **No new entry.** No paragraph of the `security-plugin.ts` entry
describes a moved body:
- ADR-0055 §1 is the controlled-by-parent relation (cuts 2 to 4);
- ADR-0106 D7 is the projection asymmetry (cut 9's field-readers module
carries it);
- ADR-0123 D2 is the write wall's no-organization refusal (cut 5);
- ADR-0138 D1 is the seed-ownership claim.
So no module of this cut gets an entry, as the modules of cuts 1 and 6
to 8 have none.
- **The decision-letter count on the anchored surface goes from 1978 to
1969.** That gate counts `ADR-NNNN Dk` citations in each anchored file
and in each entry's own invariant text. Nine citations leave the
anchored surface with the moved bodies:
- `explainAccessForCaller` 7: ADR-0090 D6, ADR-0090 D10, ADR-0090 D12,
ADR-0105 D3 twice, ADR-0111 D3, ADR-0111 D5;
- `resolveSharingReadFilter` 1: ADR-0057 D1;
- `checkAuthoredRowWrite` 1: ADR-0058 D4.
The other bodies, the moved constant's docblock, the four module headers
and the four new import comments cite none.
`resolveSharingReadFilter`'s `depth` parameter comment also cites
ADR-0090 D10. The parameter list belongs to the signature, which stays
in the class, so that letter stays on the anchored surface. The move
copies each signature unedited, so the function's parameter list carries
it too.
Measured directly: `security-plugin.ts` holds 258 such citations at base
and 249 at head, and the 9 that leave are exactly these.
- Every moved citation is still in the tree, in the module its body
moved to. Citations that resolve tree-wide go from 52223 across 6651
files at base to 52224 across 6654 at head. Three of the modules cite an
ADR. The one added citation is the `depth` parameter comment, which both
signatures now carry.
- `docs/adr/**` is not touched, and no anchor token is planted.
- The anchor map covers every ADR symbol anchor that names
`security-plugin.ts`: 27 anchors over 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 `05cc3ee953` BEFORE the claim, with the whole cut
applied as a local trial, and no anchor changed class.
- No ADR anchors a row 8 member or the moved constant. Every anchor
resolves at head in `security-plugin.ts`, with its base class.
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 · `:712`
(top-level) | declaration · `:744` (top-level) |
| `#SecurityPlugin` | ADR-0049:49, ADR-0138:248, ADR-0138:265 |
declaration · `:1344` (class) | declaration · `:1346` (class) |
| `#SecurityPlugin.getMetadataReadableFields` | ADR-0138:153 |
declaration · `:6030` (method) | declaration · `:5584` (method) |
| `#SecurityPlugin.resolvePermissionSetsForContextUnmemoized` |
ADR-0138:427 | declaration · `:6624` (method) | declaration · `:6178`
(method) |
| `#assertControlledByParentWrite` | ADR-0055:58, ADR-0055:125 |
declaration · `:8109` (method) | declaration · `:7663` (method) |
| `#assertMasterRowEditable` | ADR-0055:125 | declaration · `:8235`
(method) | declaration · `:7789` (method) |
| `#collectRLSPolicies` | ADR-0105:93 | declaration · `:8289` (method) |
declaration · `:7843` (method) |
| `#composeWriteTenantWall` | ADR-0123:4 | declaration · `:7447`
(method) | declaration · `:7001` (method) |
| `#computeControlledByParentFilter` | ADR-0055:5, ADR-0055:123,
ADR-0139:246 | declaration · `:7755` (method) | declaration · `:7309`
(method) |
| `#computeDelegatedReadFilter` | ADR-0139:223 | declaration · `:5949`
(method) | declaration · `:5503` (method) |
| `#computeRlsFilter` | ADR-0055:24 | declaration · `:7155` (method) |
declaration · `:6709` (method) |
| `#getReadFilter` | ADR-0096:181, ADR-0096:182, ADR-0096:183,
ADR-0096:199, ADR-0139:222 | declaration · `:5895` (method) |
declaration · `:5449` (method) |
| `#hasPlatformAdminPosture` | ADR-0099:317 | declaration · `:7182`
(method) | declaration · `:6736` (method) |
| `#isPrincipalLessContext` | ADR-0138:152 | declaration · `:585`
(top-level) | declaration · `:617` (top-level) |
| `#manage_metadata` | ADR-0099:68 | literal · `:338` (top-level) |
literal · `:370` (top-level) |
| `#nav_permission_sets` | ADR-0126:406 | literal · `:1772` (`init`) |
literal · `:1774` (`init`) |
| `#rlsFilter` | ADR-0055:24 | declaration · `:4346` (`start`) |
declaration · `:4348` (`start`) |
| `#writeCheckPolicies` | ADR-0066:112 | declaration · `:1239`
(top-level) | declaration · `:1241` (top-level) |
## Readers
Two readers outside the moved code read the moved lines by path: the
system-context page and the #25107 enumeration pin. Both are re-pointed
in this PR (above). No other gate, baseline, docs anchor or test reads
the moved lines by path. Each kind was read:
- **The system-context census.**
- `node scripts/isystem-census.mjs --json` gives the same 148 sites at
base and at head, 0 differences. The comparison ignores line numbers and
maps the four modules back to `security-plugin.ts`.
- One head site is in the modules: `explainAccessForCaller`'s
`callerContext?.isSystem` read, which the page's re-pointed anchor
names. The moved bodies' `isSystem: true` keys and the probe constant's
key are counted the same way at both ends.
- The role counts are the same (`read` 153, `declaration` 38, `key` 438,
`other` 9), and so are the 5 non-elevation reads and the 22 packages.
The files holding a site go from 74 to 75, and the scanned files from
397 to 399, the two modules that name `isSystem`.
- `check-system-context-census` and its `--self-test` exit 0 at base and
at head. The totals are the same (148 sites, 127 symbols, 140 cited
against 140 required, 163 anchors), and files go from 74 to 75. With the
page left untouched, it reports 2 problems (claim).
- **The tenant-audit census.** No moved body holds an engine write. The
explanation and the authored-row verdict read through `ql.findOne` and
`ql.find`, and the everyone declaration hands `ql` to the derivation's
readers. `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 175 non-engine calls.
Only `scannedSources` moves, from 730 to 734, the four modules.
`check-tenant-audit-census` exits 0 at base and at head with the same
output, and `tenant-audit-census.mdx` is not touched.
- **The #25107 enumeration pin** is described above. It is part of the
plugin-security suite, which passes at head with the same counts as
base.
- **`packages/core/src/security/row-serving-door-exposure.pin.test.ts`
and `operation-private-keys.pin.test.ts`.** No moved body names the read
admission or the operation-private keys. Run on their own at head: 8 of
8 pass.
- **The platform checklist.** `access-security.json:2032` cites
`security-plugin.ts#declareEveryone` (the everyone derivation). The
anchor resolves on the method, which stays with its docblock.
`check-platform-checklist` (the script and `pnpm
check:platform-checklist`) exits 0 at base and at head with the same
output.
- **Symbol anchors outside the ADRs.** Every path-qualified
`plugin-security/src/security-plugin*.ts#…` anchor outside `docs/adr/`
was resolved in its own file at base and at head: 32 at both, 0
unresolved. At head, 22 point into `security-plugin.ts`, 1 into the
explain module (the re-pointed row 9), and 9 into the modules of cuts 3,
5 and 9, as at base.
- **The non-ADR corpora.** The non-ADR corpora that cuts 2 to 9 read are
spec liveness, the platform checklist, `system-context.mdx` and spec
`conversions/registry.ts`. They hold 22 anchors over 13 symbols that
name `security-plugin.ts`. With `symbolSegmentResolution`, each resolves
at head with its base class: 0 changed. `check-scripts-symbol-anchors`
and its `--self-test`, and `pnpm --filter @objectstack/spec
check:liveness`, give the same output at base and at head.
- **Readers by name, not by path.** These were read, and none needs a
change, because each method still exists in the class under the same
name and signature:
- `rest-server.ts:5953`, which names
`SecurityPlugin.explainAccessForCaller` in prose;
- the behaviour tests of the explanation, the sharing verdicts, the
authored-row verdict and the everyone anchor in this package. Each
drives the plugin, and none calls or replaces a moved method directly;
- the page's row text and the docblocks that stay in the class, which
name these methods and stay true by method.
- **Links in the moved text.** These are unedited. Where one named a
class member from inside a body or a signature, the function's copy
still names that member as text. Examples are `{@link
computeDelegatedReadFilter}` in `resolveSharingReadFilter`'s `depth`
comment, and the explanation's inner links to `resolvePreImageFloorDrop`
and `checkControlledByParentWrite`. The class keeps the docblocks those
links belong to.
- **Line citations.** No `security-plugin.ts:N` citation in the repo
points into the moved ranges (base `:760` to `:788` and `:4912` to
`:5838`).
## Gates
All gates ran against base `05cc3ee953` and on head `38392cb1b7`, each
in its own worktree after a full `turbo run build` there (both exit 0).
- `pnpm --filter @objectstack/plugin-security test` (`vitest run`): Test
Files 214 passed (214); Tests 4465 passed, 45 skipped (4510). Base
`05cc3ee953` 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 six 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.
- `dispatch-gates --commands`: 88 commands. The `--ran` reconciliation
shows 88 derived, 88 run, 0 NOT-MEASURED and 0 UNRUN. The zero is
derived: all 88 recorded an exit code, and none is 3.
- Nine commands are not derived for this change set, and the
reconciliation names them as recorded outside the derivation. Each was
run by hand:
- `node scripts/check-adr-symbol-anchors.mjs`;
- `pnpm check:adr-anchors`;
- `check-platform-checklist`, both the script and `pnpm
check:platform-checklist`;
- `check-scripts-symbol-anchors` and its `--self-test`;
- the two census `--json` reads;
- `pnpm --filter @objectstack/spec check:liveness`.
`pnpm check:query-options-erasure` is derived for this change set this
time.
- Seven more were run at base and at head. Six keep a roster in a
directory this change touches, so `dispatch-gates` marks their silence
as no evidence: `check-published-list-mirrors`, `check:authz-resolver`,
`check:console-injection`, `check:error-code-casing`,
`check:filter-alias-parity` and `check:published-readme-exports`. The
seventh is the package typecheck. All seven exit 0 at both.
- **Base against head, all 97 commands.** All 97 (the 88 derived and the
9 hand-run) exit 0 at head and at base. 72 give identical output at
both, once the worktree path and timings are masked. The other 25, each
read line by line:
- `check:adr-anchors`, `check-system-context-census` and the two census
`--json` reads move as described above.
- `check-issue-citations` judges a change set, so it has nothing to read
at base. At head it judged 42 citations across 5 files, and all resolve.
- Counts that move by exactly the four modules:
- `check-closing-keyword-parity` 12029 to 12033 tracked files;
- `check:gitlink-declared` 12029 to 12033 index entries;
- `check:nul-bytes` 12020 to 12024;
- `check-comment-mask-corpus` 10005 to 10009;
- `check-plugin-teardown-shape` 9397 to 9401 sources;
- `check-position-name-fold-loaders` 12370 to 12374 files, with the same
8 references;
- `check-undeclared-dep-imports` 3316 to 3320 files;
- the spec package's `check:duration-unit-keys` 3321 to 3325;
- `check:closed-ceremony-text` 4573 to 4577;
- `check:doc-authoring` 1434 to 1438 parsed sources;
- `check:engine-double-contract` 3625 to 3629 production files;
- `check:error-status-conformance` 3413 to 3417;
- `check:logger-receiver-detach` 3633 to 3637;
- `check:org-identifier` 3658 to 3662;
- `check:page-declaration-shape` 3666 to 3670;
- `check:refd-timer-probe` 9998 to 10002;
- `check:type-check-coverage` and `check:type-check-debt` 3542 to 3546
walked sources;
- `check:vendor-version-stamps` 10397 to 10401.
- `check-undeclared-dep-imports` also reads 2865 to 2872
`@objectstack/*` specifiers. Those are the seven the modules import, all
declared dependencies. `security-plugin.ts` keeps every specifier it
had.
- `check:doc-authoring` also reads 104377 to 104528 strings, the strings
of the new headers and stubs.
- `check:skill-identifier-liveness` reads 139798 to 139805
implementation word tokens. Those are the seven words new to the tree:
the four host names, the stubs' two getter locals `readEpoch` and
`readResolveKernelService`, and the word "abstentions" in the
authored-row module's header. No citation changes.
Per command (exit code at head, then at base), the derived first and the
hand-run after:
- `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-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-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/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: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: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: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: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)
- `pnpm check:adr-anchors` exit 0 (base 0)
- `node scripts/check-platform-checklist.mjs` exit 0 (base 0)
- `pnpm check:platform-checklist` 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/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)
## Acceptance notes
- Nothing outside this cut is touched: no other section of the class, no
behaviour, no `docs/adr/**`, no `scripts/adr-anchors/` entry, no census
ledger and no `packages/spec/**`. Outside the package, one file changes:
the one anchor path on the system-context page.
- Serial check, also in the claim: of the 20 open PRs at claim time, one
touched `security-plugin.ts` and `system-context.mdx`. That was #25483
(#25251's first PR): one import near `:29`, a call in `start()` near
`:2577`, and a new page row 1b. None of those lines is in row 8 or in an
import line this cut edits. #25483 has since merged (`a285ff29a1`).
Re-checked before opening this PR: of the 13 open PRs now, two more
touch the package:
- #25512 (#24447) adds an import near `:47` and a block in `start()`
near `:4759`, ahead of row 8;
- #25515 (#25233) edits `builtin-positions.ts`, whose two functions the
everyone-anchor module imports, and keeps both signatures unchanged.
A scratch merge of `5188e7f18f`, #25512, #25515 and this head merges
cleanly. Neither PR touches a moved line or a name this cut moves.
- Since the local runs, `origin/main` gained 13 commits, up to
`5188e7f18f`, #25483 among them. They touch two of this cut's files, at
the #25483 hunks above.
- A scratch merge of this head onto `5188e7f18f` is clean. On it, these
all exit 0:
- `check-adr-symbol-anchors`, `check:adr-anchors`,
`check-platform-checklist`, `check-system-context-census` and
`check-tenant-audit-census`;
- the `isystem-census` read;
- `tsc --noEmit` for the package;
- the #25107 pin, #25483's refusal test and the authored-row verdict
test (3 files, 127 tests).
- There, `check:adr-anchors` counts 82 anchored files and 1970
decision-letter citations, against 82 and 1979 on `5188e7f18f` alone:
the same 9 leave. The system-context census counts 149 sites across 76
files, against 75 files on `5188e7f18f` alone: #25483's new read is the
149th site.
- After this cut, row 8 leaves `everyoneBaseline` and `destroy` whole in
`security-plugin.ts`, plus the ten method shells. `security-plugin.ts`
has 8,406 lines at head and 8,852 at base. Next is `start()`. It is Tier
H, and it goes to the seat with its scope before any PR.
---
_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 aa2dbab commit 82f5a11
7 files changed
Lines changed: 1187 additions & 598 deletions
File tree
- content/docs/permissions
- packages/plugins/plugin-security/src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
108 | 108 | | |
109 | 109 | | |
110 | 110 | | |
111 | | - | |
| 111 | + | |
112 | 112 | | |
113 | 113 | | |
114 | 114 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
685 | 685 | | |
686 | 686 | | |
687 | 687 | | |
688 | | - | |
| 688 | + | |
689 | 689 | | |
690 | 690 | | |
691 | 691 | | |
| |||
696 | 696 | | |
697 | 697 | | |
698 | 698 | | |
| 699 | + | |
699 | 700 | | |
700 | 701 | | |
701 | 702 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
0 commit comments