Repository navigation
Commit 2dfeb1a
<!-- 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 7 of the `security-plugin.ts` split: the RLS filter layers, row 5 of
the series plan. The claim is 6361091603. The bodies of four private
async methods move unedited out of the class, to the new module
`packages/plugins/plugin-security/src/security-plugin-rls-filter.ts`:
- `computeLayeredRlsFilter`, the ADR-0095 D1 split every row filter is
composed from: Layer 0 (the tenant wall, its one platform-admin
exemption and the verified platform owner's read crossing, #12974) and
Layer 1 (business RLS, the ownership floor's replacements, the #7665
derived write scope and the field-existence net), before the
AND-compose. `computeRlsFilter`, `checkAuthoredRowWrite`,
`explainAccessForCaller`, the write wall's adapter
`computeWriteTenantWall` and the middleware in `start()` call it, and
the explain engine reads it through the plugin.
- `isVerifiedPlatformOwnerSession`, the fail-closed probe the owner
crossing asks (#12974, #13147).
- `computeWriteCheckFilter`, the ADR-0058 D4 post-image `check` compile.
- `stageRlsMembership`, the ADR-0105 D11 membership staging both
compiles ask.
It is move-only, and the card stays open for the later cuts. Branch:
`claude/project-thread-3fzya4`, the harness-pinned branch for this
session, restarted from `origin/main` at `77a77e42f8`, cut 6's merge. It
names no issue, so the claim comment is the identity record.
**What stays in the class.** Each moved method keeps its name,
signature, docblock and position, less `async`. Three thin members of
the plan row stay whole: `computeRlsFilter`, `hasPlatformAdminPosture`
and `platformFloorYieldsToObjectWriteModel`. Each body is shorter than
its stub would be. Every caller still calls the methods.
**Module-level declarations.**
- Two stay and gain `export`. The module imports both by value, as cuts
3, 5 and 6 import theirs.
- `writeCheckPolicies`: ADR-0066:112 anchors it in `security-plugin.ts`,
and so do two evidence anchors of the spec liveness ledger
(`object.json`, `permission.json`), a file this project does not own.
- `isCarriedPosture`: the `PLATFORM_ADMIN_ONLY_CAPABILITIES` docblock
names it in place, with a `{@link}`.
- The cut 6 `.d.ts` trap was checked before the claim: an export whose
signature names another file's type moved a declaration in the published
`.d.ts` then. `writeCheckPolicies` names `RowLevelSecurityPolicy`, so a
local trial build ran first. With both exports in place, the head
`dist/index.d.ts` is byte-identical to base (below).
- `RlsFilterOptions` keeps its one declaration, unexported. The
middleware, the explain path and the floor-drop resolution read it. The
module names it through the class's own signature, as the type of
`computeLayeredRlsFilter`'s fifth parameter less `undefined`, as cuts 2
to 6 name theirs.
- Import names only the moved bodies read leave `security-plugin.ts`,
and the module imports them from the same specifiers:
- `computeTenantLayer0Verdict`, `tenantLayer0FilterOf` and the type
`TenantLayer0Input` from `./tenant-layer.js`;
- `PLATFORM_OWNER_WALL_BYPASS_EVENT` from
`./platform-owner-wall-bypass.js`;
- `resolvePlatformAdminEmails` from `@objectstack/core`;
- `RESERVED_RLS_MEMBERSHIP_KEYS` from `@objectstack/spec/contracts`.
- `isConfiguredPlatformAdminEmail` and `isVerifiedPlatformOwnerRow` stay
imported in `security-plugin.ts` too, unchanged, because the probe's
docblock links to both with `{@link}`, and that docblock stays.
TypeScript counts a `{@link}` as a use, so typecheck and lint pass with
them. No code there reads them any more, so the bundler drops that
file's import of `./platform-owner-wall-bypass.js`, and the bundle now
places that module (one string constant and two functions, no top-level
effect) inside the new module's segment instead of before it.
- Each value import is read only inside a function body, at call time,
never while either module evaluates. `index.ts` still exports only
`SecurityPlugin`, so the published surface does not move (measured
below).
**Readers.** No reader outside the moved code reads the moved lines by
path, so this PR changes only the two source files (see Readers below).
## The published `.d.ts` does not change
Under the series bar (ruling 6348891160 item 1), measured on base
`77a77e42f8` and on the head (the tree of this PR's commit):
- Raw sha256 of `dist/index.d.ts` and `dist/index.d.mts`, base and head,
all four the same:
`af5dee1bebafa0376a876d1e7b247c878ea42ac35c7336a6d3c12a7953143156`. The
raw diff is 0 lines, so no union order moved either.
- Normalised sha256, all four the same:
`431e7f5097ac1c220bc840188aef02105bc0b16e845e976dd562d02cc79be8bd`.
- These are the same hashes as cut 6's report. Nothing that landed on
`origin/main` between cut 6's base `bdf762c9bd` and this base changed
the published `.d.ts`. Base and head here are both built against
`77a77e42f8`'s dependencies, rebuilt on that commit first.
- `writeCheckPolicies` and `isCarriedPosture` gain `export` in
`security-plugin.ts`. A local trial build measured this before the
claim, because at cut 6 an export whose signature names another file's
type moved a declaration. Here the `.d.ts` did not change by a byte.
- The normaliser, run from `packages/plugins/plugin-security` (it 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 on a copy of the head `dist/index.d.ts`, line 1707
(`private computeLayeredRlsFilter;`):
- Made public (`computeLayeredRlsFilter;`): raw
`e247cabdd554c6601280095ccd71226e90fb217fd05c87901921812fa2a33fd0`,
normalised
`591d99b9859452aa1906d0303d4e17dac91bea54e192a7654be58c60d18364b6`.
- Renamed (`private computeLayeredRlsFilterRenamed;`): raw
`5a474968b2a42ea1a06cfa814dd95074ae24cf4bc27a7b8ec08a1e617f3dedef`,
normalised
`ad123c5a9397c5684e008a4f7924e7d8e0b70de181f7a0c79cadc2330f805e38`.
- Both differ from the real hashes, so the comparison does see a
visibility change and a rename.
- The four moved methods are private, so the `.d.ts` carries each one's
name and docblock only (lines 1707, 1751, 1761 and 1798 of both).
- Export tables: the ESM and CJS bundles each export the same 66 names
at base and head. The lists were loaded at runtime (`require` and
`import()` of the built bundles), not parsed. The sorted name list
hashes
`83576430f83cf60cecbcc5c0e80214f16c626a8e66f700294fc6a44361423116` on
all four, as at cut 6. The new exports of `security-plugin.ts` do not
reach the entry.
- The bundle JS bytes differ (`index.js` `77ef1113` to `cf7a65c1`,
`index.mjs` `f604cc07` to `d4178511`), because code moved within them.
That includes `platform-owner-wall-bypass.ts`, which the bundle now
places inside the new module's segment (above).
No changeset: `skip-changeset`, per ruling 6348891160 item 4.
## What moved
The base line numbers are each method's signature and closing brace at
`77a77e42f8`. The last column lists the members the body reads, which is
exactly what its host carries.
| method | base lines | host members |
|---|---|---|
| `computeLayeredRlsFilter` (private, async) | `:7721`-`:8133` |
`collectRLSPolicies`, `datetimeFieldNamesCache`, `extractTargetField`,
`getObjectFieldNames`, `getObjectSecurityMeta`,
`hasPlatformAdminPosture`, `isVerifiedPlatformOwnerSession`, `logger`,
`metadata`, `numberComparandFieldsCache`, `permissionEvaluator`,
`platformFloorYieldsToObjectWriteModel`, `ql`, `rlsCompiler`,
`stageRlsMembership`, `tenancyDisabledCache`, `tenancyPosture` |
| `isVerifiedPlatformOwnerSession` (private, async) | `:8178`-`:8205` |
`ql` |
| `computeWriteCheckFilter` (private, async) | `:8216`-`:8305` |
`collectRLSPolicies`, `datetimeFieldNamesCache`, `getObjectFieldNames`,
`getObjectSecurityMeta`, `metadata`, `numberComparandFieldsCache`,
`permissionEvaluator`, `platformFloorYieldsToObjectWriteModel`, `ql`,
`rlsCompiler`, `stageRlsMembership` |
| `stageRlsMembership` (private, async) | `:8343`-`:8383` | `logger`,
`rlsMembershipResolver` |
Each stub drops `async` and returns the moved function's promise, as
cuts 1, 3, 5 and 6 did for their async methods. All four methods are
private, so the `.d.ts` carries each one's name and docblock only.
`computeLayeredRlsFilter` declares a multi-line return type, an object
type whose two last members carry docblocks. The moved function repeats
it as the method declares it, one indentation level in. The method has
no docblock of its own: its `[C2 / ADR-0095 D1]` docblock sits above
`hasPlatformAdminPosture`'s at base, and stays there. The moved
function's pointer comment says so.
## The shape (#23050 shape B, as cuts 1 to 6 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 7]`.
- `RlsFilterHost` is new. It types every member as the class member
itself (`SecurityPlugin['m']`). Each moved function types its `this` as
the `Pick` of the 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. A spy or test double set on the plugin is still the
one the body reaches:
- the layered computation still stages membership, asks the owner probe
and the platform-admin probe, and reads the floor predicate through the
plugin;
- the write check still stages membership and reads the floor predicate
through the plugin;
- a test that replaces `plugin.computeLayeredRlsFilter` on the instance
(`explain-dependency-fault.test.ts`) still replaces it for
`computeRlsFilter` and every other caller.
No moved body calls a function-valued field, so no receiver changes:
`permissionEvaluator`, `rlsCompiler`, `rlsMembershipResolver`, `ql` and
the caches are objects whose own methods the bodies call.
- Fields follow the rule cut 1 set, on each field's own declaration.
- `datetimeFieldNamesCache`, `numberComparandFieldsCache` and
`tenancyDisabledCache` are declared `readonly` and go by value, so the
bodies read the plugin's own maps.
- `logger`, `metadata`, `permissionEvaluator`, `ql`, `rlsCompiler`,
`rlsMembershipResolver` and `tenancyPosture` are not declared
`readonly`, so they go as getters, and each read happens when the body
makes it.
- The host declares every field `readonly`, so a moved body cannot
assign a member through it; the typecheck passes, so none does.
- Nothing re-exports the module, 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, and each of its 536
lines is the base line with two leading spaces removed. Parameters and
`async` match. The return types match by token too; the two docblock
tokens inside `computeLayeredRlsFilter`'s are compared one indentation
level in. Three negative controls fail the check:
- in `computeLayeredRlsFilter`, `superuserBypass && platformPosture`
changed to `superuserBypass || platformPosture`;
- in `computeWriteCheckFilter`, `withCheck.length === 0` changed to
`withCheck.length !== 0`;
- in `computeLayeredRlsFilter`'s return type, `crossedByPlatformAdmin:
boolean` changed to `boolean | undefined`.
- **Class side**: each moved method keeps its docblock and signature,
less `async`. Every other class member, 122 named members plus the
constructor, is byte-identical to base. That includes
`computeRlsFilter`, `hasPlatformAdminPosture`,
`platformFloorYieldsToObjectWriteModel`, `getReadFilter`, the wall
adapters and `start()`. The class has 127 members at base and at head.
- **Top level of `security-plugin.ts`**: 96 of the 102 base top-level
statements other than the class are byte-identical to base,
`RlsFilterOptions` included. The six that differ:
- two are the base text with `export ` before `function`:
`isCarriedPosture`, `writeCheckPolicies`;
- four imports lose the names listed above: `./tenant-layer.js`,
`./platform-owner-wall-bypass.js`, `@objectstack/core` and
`@objectstack/spec/contracts`.
The one new statement is the import of the new module.
- **git's own view** (`git diff --color-moved=plain
--color-moved-ws=allow-indentation-change 77a77e4 HEAD` over the two
source files): of the 547 deleted lines, git sees 539 as moved. The
other 8 are the four signatures that lose `async`, the two `function`
lines that gain `export`, the `@objectstack/core` import line that loses
`resolvePlatformAdminEmails`, and the `RESERVED_RLS_MEMBERSHIP_KEYS`
line. Of the 799 added lines, 552 show as moved. The other 247 are the
new module's header, imports, alias and host interface, the four stubs,
the new import with its comment, and the edited lines above.
- **Size**: 1,346 changed lines (+799 / -547) over 2 files, under the
3,000-line manual-merge line. `security-plugin.ts` goes from 9,863 to
9,394 lines, and the new module has 721.
## ADR anchors (ruling 6353073966 item 2)
- `node scripts/check-adr-symbol-anchors.mjs`: exit 0 at base
`77a77e42f8` and exit 0 at head, both with `2384 anchors across 142
records resolve — 466 symbol (440 declaration, 26 literal), 1890
file-level, 28 cross-repo, 6 exempt, 18 continuation`. CI runs this gate
(`lint.yml`), but `dispatch-gates --commands` does not derive it for
this change set (#21697), so it is run by hand here.
- `pnpm check:adr-anchors`: exit 0 at base and at head, both with 80
anchored files. The decision-letter count on the anchored surface goes
from 2014 to 2004. That gate counts `ADR-NNNN Dk` citations in anchored
files only, and the new module has no entry:
- 13 citations leave `security-plugin.ts` with the moved bodies: 12 in
`computeLayeredRlsFilter` (ADR-0095 D1, D2 and D3, ADR-0099 D1, ADR-0105
D2, D3 twice and D11, ADR-0058 D4, ADR-0139 D2, ADR-0123 D2 twice) and 1
in `computeWriteCheckFilter` (ADR-0105 D11);
- 3 arrive in the new import's comment (ADR-0095 D1, ADR-0058 D4,
ADR-0105 D11).
- `grep -oE 'ADR-[0-9]{4} D[0-9]+'` counts 294 in `security-plugin.ts`
at base and 284 at head. Each moved citation is still in the tree, in
the new module, which counts 18: the 13, the return type's ADR-0095 D3,
3 in its header and 1 in `computeLayeredRlsFilter`'s pointer comment.
- `scripts/adr-anchors/` is unchanged. No paragraph of the
`security-plugin.ts` entry (ADR-0055 §1, ADR-0106 D7, ADR-0123 D2,
ADR-0138 D1) describes the RLS layers, so the new module gets no entry,
as the modules of cuts 1 and 6 have none, and none is invented to hold
the count. The `security-plugin.ts` entry is unchanged. `docs/adr/**` is
not touched.
- The anchor map covers every ADR symbol anchor naming
`security-plugin.ts`: 27 anchors, 18 symbols. It was measured with
`extractAnchors` and `symbolSegmentResolution` from
`scripts/symbol-anchors.mjs`, which is measurement, not a new gate. It
was read on `77a77e42f8` BEFORE the cut, with the four bodies blanked:
no anchor changed class. Every anchor resolves at head in
`security-plugin.ts` with its base class.
The table gives each anchor's class at base and head and the line its
own declaration resolves on. Every anchor stays in `security-plugin.ts`.
| anchor | cited at | base class · line (member) | head class · line
(member) |
|---|---|---|---|
| `#CBP_MAX_CHAIN_DEPTH` | ADR-0055:135 | declaration · `:658`
(top-level) | declaration · `:665` (top-level) |
| `#SecurityPlugin` | ADR-0049:49, ADR-0138:248, ADR-0138:265 |
declaration · `:1290` (class) | declaration · `:1297` (class) |
| `#SecurityPlugin.getMetadataReadableFields` | ADR-0138:153 |
declaration · `:6085` (method) | declaration · `:6092` (method) |
| `#SecurityPlugin.resolvePermissionSetsForContextUnmemoized` |
ADR-0138:427 | declaration · `:6996` (method) | declaration · `:7003`
(method) |
| `#assertControlledByParentWrite` | ADR-0055:58, ADR-0055:125 |
declaration · `:9120` (method) | declaration · `:8651` (method) |
| `#assertMasterRowEditable` | ADR-0055:125 | declaration · `:9246`
(method) | declaration · `:8777` (method) |
| `#collectRLSPolicies` | ADR-0105:93 | declaration · `:9300` (method) |
declaration · `:8831` (method) |
| `#composeWriteTenantWall` | ADR-0123:4 | declaration · `:8458`
(method) | declaration · `:7989` (method) |
| `#computeControlledByParentFilter` | ADR-0055:5, ADR-0055:123,
ADR-0139:246 | declaration · `:8766` (method) | declaration · `:8297`
(method) |
| `#computeDelegatedReadFilter` | ADR-0139:223 | declaration · `:5963`
(method) | declaration · `:5970` (method) |
| `#computeRlsFilter` | ADR-0055:24 | declaration · `:7690` (method) |
declaration · `:7697` (method) |
| `#getReadFilter` | ADR-0096:181, ADR-0096:182, ADR-0096:183,
ADR-0096:199, ADR-0139:222 | declaration · `:5841` (method) |
declaration · `:5848` (method) |
| `#hasPlatformAdminPosture` | ADR-0099:317 | declaration · `:7717`
(method) | declaration · `:7724` (method) |
| `#isPrincipalLessContext` | ADR-0138:152 | declaration · `:531`
(top-level) | declaration · `:538` (top-level) |
| `#manage_metadata` | ADR-0099:68 | literal · `:280` (top-level) |
literal · `:287` (top-level) |
| `#nav_permission_sets` | ADR-0126:406 | literal · `:1718` (`init`) |
literal · `:1725` (`init`) |
| `#rlsFilter` | ADR-0055:24 | declaration · `:4292` (`start`) |
declaration · `:4299` (`start`) |
| `#writeCheckPolicies` | ADR-0066:112 | declaration · `:1185`
(top-level) | declaration · `:1192` (top-level) |
No resolving site moves out of the file. Two anchors gain sites, and
neither changes class:
- ADR-0099:317 `#hasPlatformAdminPosture` still resolves on the method,
which stays whole. At head the name also starts a line in
`computeLayeredRlsFilter`'s stub, as its host-literal key (`:7764`), and
appears quoted in that stub's `Pick` (`:7758`).
- ADR-0105:93 `#collectRLSPolicies` still resolves on the method. At
head it also keys the host literals of `computeLayeredRlsFilter`'s and
`computeWriteCheckFilter`'s stubs (`:7759`, `:7854`), as it already
keyed `assertMasterRowEditable`'s (cut 3, `:8790`).
Cuts 3 and 6 added the same kind of site for
`#assertControlledByParentWrite` and `#composeWriteTenantWall`. An
anchor is judged by its class, which is `declaration` at base and at
head for both. ADR-0066:112 `#writeCheckPolicies` resolves on the
declaration, which stays and gains `export`. The spec liveness ledger's
two `#writeCheckPolicies` evidence anchors resolve on the same line.
## Readers
No reader outside the moved code reads the moved lines by path, so no
gate, baseline, docs anchor or test moves with this cut. Each kind was
read:
- **The system-context census.** The moved bodies hold no elevation
read: `isVerifiedPlatformOwnerSession`'s `isSystem: true` is a key of
its own system read of `sys_user`. `check-system-context-census` exits 0
at base and at head with the same output. `node
scripts/isystem-census.mjs --json` gives the same 148 sites at base and
head, compared without line numbers and with the new module mapped back
to `security-plugin.ts`: 0 differences, and no site in the new module.
The role counts are the same (`read` 153, `declaration` 38, `key` 438,
`other` 9). Only the scanned file count moves, 392 to 393: the new
module.
- **The tenant-audit census.** The moved bodies hold no engine write:
the probe's `ql.findOne` and `ql.find` are reads. `node
scripts/tenant-audit-census.mjs --json` gives the same 238 write call
sites at base and head, compared the same way: 0 differences, the same
totals, 0 unresolved, 0 unledgered. Only `scannedSources` moves, 718 to
719, plus the measured-at ref. `check-tenant-audit-census` prints the
same output at both.
- **The #25107 enumeration pin**
(`delegated-organization-membership.test.ts`) counts
`resolveDelegatorContext(` and `delegatedOrganizationRefusal(` per
source file. The moved bodies call neither, so its list of three files
is unchanged, and it passes at head.
- **`packages/core/src/security/row-serving-door-exposure.pin.test.ts`**
classifies every caller of the read admission. The moved bodies call no
admission, so the new module needs no row. Run on its own: 3 of 3 pass.
- **Other source readers by path.** The tests and scripts that read
`security-plugin.ts` as text were read:
`engine-middleware-operation-vocabulary.test.ts` (objectql),
`rls-predicate.test.ts` (formula), `seed-write-refusal.test.ts`,
`open-only-wall-acceptance.test.ts` (organizations),
`check-runtime-services-index.mjs`,
`check-position-name-fold-loaders.mjs` and
`check-system-context-census.mjs`. None reads text inside the moved
bodies.
- **The platform checklist.** `check-platform-checklist` exits 0 at base
and head with the same output. No checklist citation names a moved
symbol or a local inside a moved body.
- **Symbol anchors outside the ADRs.** The spec liveness ledger
(`object.json`, `permission.json`), the platform checklist areas,
`system-context.mdx` and spec `conversions/registry.ts` hold 27 anchors
into `security-plugin.ts`, over 17 symbols. None names a moved method;
`#writeCheckPolicies` (four of them) and `#collectRLSPolicies` name
declarations that stay. With `symbolSegmentResolution`, each resolves at
head with its base class: 0 changed.
- **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:
- tests that call `(plugin as any).computeWriteCheckFilter(…)`
(`rls-check-membership-staging.test.ts`,
`rls-shared-lowering-seam.test.ts`) or replace
`stack.plugin.computeLayeredRlsFilter`
(`explain-dependency-fault.test.ts`), and the explain tests that pass a
`computeLayeredRlsFilter` dependency;
- comments and prose naming the four methods in `explain-engine.ts`,
`rls-compiler.ts`, `platform-ownership-policies.ts`,
`lifecycle-verb-rls-operation.ts`, `platform-owner-wall-bypass.ts`, the
lint package, the dogfood matrix, and two docs pages
(`permissions-matrix.mdx` and `sharing-rules.mdx`, which say
`security-plugin.ts` (`computeLayeredRlsFilter`): the method is still
there, and its body is one call away).
- **Line citations**: no `security-plugin.ts:N` citation in the repo
points into the moved ranges (base `:7721`-`:8133`, `:8178`-`:8205`,
`:8216`-`:8305`, `:8343`-`:8383`). The citations found are the list cuts
2 to 6 read (`docs/launch-readiness.md` `:309`,
`packages/objectql/src/engine.ts` `:1614`, `:1690`, `:1736`, spec
liveness `:3281` and the rest). Each already pointed at an unrelated
line before cut 2, so this cut does not make any of them wrong.
- **Docs Drift Check**, re-derived with `node
scripts/docs-audit/affected-docs.mjs --json 77a77e4` (advisory): 25
pages. Each is reached through a literal inside the moved bodies
(`PLATFORM_ADMIN`, and `public_read_write` and `org_member` in
comments), and `permissions-matrix.mdx` and `sharing-rules.mdx` also
through the `computeLayeredRlsFilter` name. Every literal is unchanged
and still in the tree, and the method still exists under its name, so no
page's claim changes. This PR edits no page.
- **Census gates, run on base `77a77e42f8` and head and compared:**
- Identical output: `check-adr-symbol-anchors`,
`check-platform-checklist`, `check-platform-object-tenancy-census`,
`check-registry-log-declared`, `check-rest-log-spy-declared`,
`check-system-context-census`, `check-tenant-audit-census`,
`check:cross-package-test-inputs`, `check:driver-memory-census`,
`check:issue-citations` and `check:query-options-erasure`. The last
reports the same counts at both, and `security-plugin.ts` is not a
baseline key.
- Only scanned counts move:
- `check-undeclared-dep-imports`: 3304 to 3305 files, and 2847 to 2850
specifiers. The new module imports `@objectstack/spec/security`,
`@objectstack/spec/contracts` and `@objectstack/core`, all declared
dependencies, and `security-plugin.ts` still imports from all three.
- `check:org-identifier`: 3646 to 3647 files.
- `check:doc-authoring`: 1423 to 1424 parsed sources. Its clean-file
count goes from 424 to 427 because the head worktree holds three
gitignored generated pages that the base worktree does not
(`content/docs/protocol-upgrade/17.md`, `18.md` and `index.md`), as at
cut 6. CI's checkout does not have them.
- `check:logger-receiver-detach`: 3620 to 3622 files: the new module,
and a local build output under `apps/docs/.next` that exists only in the
head worktree.
- `check-position-name-fold-loaders`: 12337 to 12341 files, with the
same 8 references (6 test, 2 declared instrument, 0 loader). It walks
the working tree: the new module plus local build outputs that exist
only in the head worktree.
- `check-issue-citations` judges a change set, so it has nothing to read
at base. At head it judged 45 citations across 2 files, and all resolve
(42 issues, 3 pull requests).
## Acceptance notes
- Nothing outside this cut is touched: no other section of the class, no
behaviour, no `docs/adr/**`, no `scripts/adr-anchors/` entry, and no
file outside the package.
- Serial check, also in the claim: of the 13 open PRs at claim time,
none touched `security-plugin.ts`, `explain-engine.ts`, the `rls-*` or
`platform-owner-*` sources, the permissions pages or the plugin-security
anchor entries.
- Since the local runs, `origin/main` gained 3 commits (to
`c6bdcaccb7`). None touches this cut's files. On a scratch merge of this
head onto that main, `check-adr-symbol-anchors`, `check:adr-anchors`,
`check-platform-checklist`, `check-system-context-census` and
`check-tenant-audit-census` all exit 0. `check:adr-anchors` there counts
80 anchored files and 2005 decision-letter citations; that main alone
counts 2015, so the shift this cut makes is the same 10.
- What is left of the plan's row 5 in `security-plugin.ts` after this
cut: the three thin members (`computeRlsFilter`,
`hasPlatformAdminPosture`, `platformFloorYieldsToObjectWriteModel`) and
the four method shells. `security-plugin.ts` has 9,394 lines at head,
9,863 at base.
## Gates
All gates ran at the head, the tree of `41c661896c`, on base
`77a77e42f8`.
- `pnpm --filter @objectstack/plugin-security test` (`vitest run
--maxWorkers=3`, under the verify lock): Test Files 214 passed (214),
Tests 4465 passed, 45 skipped (4510). Base `77a77e42f8` gives the same
counts. VERDICT command-exit 0 on both.
- `pnpm --filter @objectstack/plugin-security typecheck`: exit 0. It
runs `tsc --noEmit`, the scripts tsconfig, and `check:test-typecheck`.
- `eslint --no-inline-config` over the two touched source files: exit 0.
- `pnpm --filter @objectstack/plugin-security build`: exit 0. It
produced the `.d.ts` and bundles measured above. The package's
dependencies were rebuilt on `77a77e42f8` first.
- `packages/core/src/security/row-serving-door-exposure.pin.test.ts`: 3
of 3 pass.
- `node scripts/check-adr-symbol-anchors.mjs`, `pnpm check:adr-anchors`,
`pnpm check:platform-checklist` (and its script),
`check-scripts-symbol-anchors` (and `--self-test`), and the two census
`--json` reads. None of these is derived for this change set; each was
run by hand, and each exit is listed below.
- `dispatch-gates --commands`: 52 commands. The `--ran` reconciliation
shows 52 derived, 52 run, 0 NOT-MEASURED, 0 UNRUN. The zero is derived:
all 52 recorded an exit code and none is 3. No docs family is derived,
because this cut touches no page.
Per command (exit code), the derived first and the hand-run after:
- `node scripts/check-ci-filter-parity.mjs` exit 0
- `node scripts/check-closing-keyword-parity.mjs` exit 0
- `node scripts/check-closing-keyword-parity.mjs --self-test` exit 0
- `node scripts/check-comment-mask-adoption.mjs` exit 0
- `node scripts/check-comment-mask-adoption.mjs --self-test` exit 0
- `node scripts/check-comment-mask-corpus.mjs` exit 0
- `node scripts/check-dts-emitted.mjs --self-test` exit 0
- `node scripts/check-issue-citations.mjs` exit 0
- `node scripts/check-keyed-text-bounds.mjs` exit 0
- `node scripts/check-keyed-text-bounds.mjs --self-test` exit 0
- `node scripts/check-platform-object-tenancy-census.mjs` exit 0
- `node scripts/check-platform-object-tenancy-census.mjs --self-test`
exit 0
- `node scripts/check-plugin-teardown-shape.mjs` exit 0
- `node scripts/check-plugin-teardown-shape.mjs --self-test` exit 0
- `node scripts/check-position-name-fold-loaders.mjs` exit 0
- `node scripts/check-position-name-fold-loaders.mjs --self-test` exit 0
- `node scripts/check-registry-log-declared.mjs` exit 0
- `node scripts/check-registry-log-declared.mjs --self-test` exit 0
- `node scripts/check-rest-log-spy-declared.mjs` exit 0
- `node scripts/check-rest-log-spy-declared.mjs --self-test` exit 0
- `node scripts/check-system-context-census.mjs` exit 0
- `node scripts/check-system-context-census.mjs --self-test` exit 0
- `node scripts/check-tenant-audit-census.mjs` exit 0
- `node scripts/check-tenant-audit-census.mjs --self-test` exit 0
- `node scripts/check-undeclared-dep-imports.mjs` exit 0
- `node scripts/check-undeclared-dep-imports.mjs --self-test` exit 0
- `node scripts/docs-audit/check-affected-docs.mjs` exit 0
- `node scripts/docs-audit/check-drift-comment.mjs` exit 0
- `pnpm --filter @objectstack/spec run check:duration-unit-keys` exit 0
- `pnpm check:closed-ceremony-text` exit 0
- `pnpm check:cross-package-test-inputs` exit 0
- `pnpm check:doc-authoring` exit 0
- `pnpm check:driver-memory-census` exit 0
- `pnpm check:dts-closure` exit 0
- `pnpm check:dual-build-cjs-loads` exit 0
- `pnpm check:error-status-conformance` exit 0
- `pnpm check:gitlink-declared` exit 0
- `pnpm check:i18n` exit 0
- `pnpm check:i18n-stale-fill` exit 0
- `pnpm check:issue-citations` exit 0
- `pnpm check:lean-entry-closure` exit 0
- `pnpm check:logger-receiver-detach` exit 0
- `pnpm check:nul-bytes` exit 0
- `pnpm check:org-identifier` exit 0
- `pnpm check:page-declaration-shape` exit 0
- `pnpm check:published-files` exit 0
- `pnpm check:refd-timer-probe` exit 0
- `pnpm check:slot-lookup` exit 0
- `pnpm check:sourcemap-no-sources-content` exit 0
- `pnpm check:test-source-alias` exit 0
- `pnpm check:tier-file-adoption` exit 0
- `pnpm check:watch-hint-literal` exit 0
- `node scripts/check-adr-symbol-anchors.mjs` exit 0
- `node scripts/check-platform-checklist.mjs` exit 0
- `node scripts/check-scripts-symbol-anchors.mjs` exit 0
- `node scripts/check-scripts-symbol-anchors.mjs --self-test` exit 0
- `node scripts/isystem-census.mjs --json` exit 0
- `node scripts/tenant-audit-census.mjs --json` exit 0
- `pnpm check:adr-anchors` exit 0
- `pnpm check:platform-checklist` exit 0
- `pnpm check:query-options-erasure` exit 0
---
_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 860f002 commit 2dfeb1a
2 files changed
Lines changed: 799 additions & 547 deletions
0 commit comments