Uh oh!
There was an error while loading. Please reload this page.
feat(lint): runtime-gate snapshot carries permissions/books; permission/book stack-key wiring (#8309) - #8491
Conversation
…/books, and permission/book map to stack keys (#8309) Slice 2 of #7891. RuntimeStackContext gains permissions and books; the baseline/candidate differential carries every context collection in both passes with replace-not-erase semantics generalized from objects; the construction is extracted and exported as buildRuntimeWriteSnapshots so tests drive the real thing instead of a mirror. TYPE_TO_STACK_KEY maps permission -> permissions and book -> books ahead of their runtimeTypes registration (#8310 remains open; no registration flip here). The metadata-protocol gate call site gathers both collections from the live registry per publish, the same best-effort pattern objects always used. Kills the measured RUNTIME_NEEDS_FULL_SNAPSHOT defect for the three cross-collection rules: 38 phantom security-master-detail-ungranted findings per-write vs 4 whole-stack (PR #7886). Agreement between the per-write and whole-stack verdicts is pinned, with the pre-#8309 phantom shape kept executable as in-tree reverse verification. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012MNV7ZSCjNfA38eDCjsXQL
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
📓 Docs Drift CheckThis PR changes 2 package(s): 6 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
⛔ 2 release-owned page(s) also reference the affected code. These are read-only:
|
Uh oh!
There was an error while loading. Please reload this page.
Fixes#8309
Programme slice [2 of #7891] (the strictness-rollout direction is ruled there, not re-decidable in this slice). Direct precedent: PR #8390 ([1 of #7891], merged today on this same runtime-gate surface — its scope note deliberately left this card's wiring undone).
What changed
Both halves the re-priced card asks for, bounded to what the three cross-collection rules need:
1. Snapshot enrichment (
packages/lint/src/runtime-gate.ts):RuntimeStackContextgainspermissionsandbooksbesideobjects. Which collections was MEASURED, not guessed: the three cross-collection rules read exactlystack.objects×stack.permissions(security-master-detail-ungranted,security-private-no-readscope) andstack.books×stack.permissions(security-book-audience-unknown-set).positions/appsare read only bysecurity-role-word— the excluded family (#7220 constraint; #8310's call) — so they are deliberately NOT carried, and the test suite pins that boundary.The baseline/candidate differential now carries every context collection in BOTH passes (so sibling-derived findings cancel), and the replace-not-erase rule that protected
objectswrites is generalized to every context collection — an updated permission set or book judges a universe with one copy of itself, not two. The construction is extracted into an exportedbuildRuntimeWriteSnapshots, so the runtime-surface tests exercise the gate's real construction instead of the hand-kept mirror this file previously maintained (the mirror is retired).2. The wiring:
TYPE_TO_STACK_KEYgainspermission→permissionsandbook→books, ahead of their registration — the same orderseedlanded in (#7576 → #8307). The entries are inert until a rule declares those types inruntimeTypes, because dispatch filters by declared type before consulting the table; the registration flip itself is deliberately NOT here (#8310 remains open; noruntimeTypeschange, nosecurity-role-wordwiring in this diff).3. Call-site plumbing in
packages/metadata-protocol(declared-allowed by the dispatch, listed explicitly):evaluateRuntimeAuthoringGateaccepts optionalpermissions/booksand forwards them into the gate context;assertRuntimeAuthoringRulesinprotocol.tsgathers both from the live registry per publish, through the same best-effort singular-then-plurallistItemspatternobjectsalways used (each collection guarded independently so a registry that can answer one question still answers the others). Files touched there:src/runtime-authoring-gate.ts,src/protocol.ts— nothing else in that package.The #4463 D2 cost question — per-write, not cached (measured)
The snapshot is built per write: one
filter+ one spread over the written type's collection, sibling collections passed by reference; the registry read is one map walk + array copy of item references per collection. It runs only on anactive-state publish (D1 — never a draft autosave), and the shipped corpus is 30 objects / 10 permission sets / 1 book, so the cost is microseconds per publish. A cache would buy nothing and would need cross-org invalidation the gate has no seam for. The choice and the numbers are recorded inbuildRuntimeWriteSnapshots's docblock.Per-write vs whole-stack agreement — the PM mechanism assumption, pinned
The measured defect (PR #7886): 38 phantom
security-master-detail-ungrantedfindings per-write vs 4 whole-stack.validate-security-posture.runtime-surface.test.tsnow pins the agreement AND keeps the defect executable as an in-tree reverse verification:permission/bookwiring:TYPE_TO_STACK_KEYentries + the cross-collection snapshot the three comparison rules need #8309 snapshot) still reproduces the phantom finding — so deleting the enrichment turns the agreement pin red in the predicted direction (MORE findings than whole-stack, not fewer);audience.permissionSetis clean with the full context and phantom-flagged without it, while a genuinely dangling audience is still caught with it;runtime-gate.test.tspins the construction directly: every context collection identical across both passes for a non-context write (the isolation property PR feat(lint): ADR-0091 seed pair crosses the runtime publish gate (#8307) #8390's seed proof rests on, extended to all three collections), replace semantics for a context-collection write, null for unmapped types, and safe behavior with no context at all.No verdict changes at the door until #8310 flips registration:
permission/bookwrites still reach no rule (pinned), and for every currently-gated type the sibling collections cancel in the differential.Prose kept honest
authoring-rules.ts'sRUNTIME_NEEDS_FULL_SNAPSHOTdocblock, thevalidateSecurityPostureentry comment, andvalidateRlsPredicateEnforceability'ssurfaceReasonall claimed the snapshot carriesobjectsonly — updated to record what #8309 changed and that the remaining gap forpermission/bookis the declaration alone.Tests
Local gates
Re-derived against the actual committed diff with
node scripts/pm/dispatch-gates.mjs— it surfaced two families beyond the dispatch prompt's list, both via thepackages/metadata-protocolpaths, and both were run:check:durability-log-level,check:filter-alias-parity. Full local pass:check:cross-package-test-inputs(12 self-test cases + real run OK),check:spec-parsed-alias(OK),check:changeset-gate-self-tests(empty-changeset / adr-0087 / changeset-no-major self-tests OK),check:nul-bytes(7612 files, no raw control bytes),check:durability-log-level(25 seams loud/propagating; 65 read seams clean),check:filter-alias-parity(4 spellings identical both sides),check:query-options-erasure(240 sites, at the ceiling, no new files),check:type-check-coverage(OK, ledger unchanged),check:objectui-changesetself-test (OK),node scripts/check-changeset-no-major.mjs("nomajorbump"). One red, pre-existing and unrelated:check:objectui-pin-freshreports the.objectui-shapin stale — it is equally red on unmodifiedorigin/main(verified side by side), this diff never touches the pin, and refreshing it is release-adjacent work owned elsewhere. Nopackages/specpath is in the diff, so the spec artifact families are untouched.Changeset
.changeset/permission-book-snapshot-wiring.md—@objectstack/lint: minor,@objectstack/metadata-protocol: minor (precedent: PR #8390'sminorfor the same surface; the metadata-protocol half widens a public function's accepted inputs).Scope note
File surface matches the dispatch exactly:
packages/lint/src(runtime-gate.ts, authoring-rules.ts prose, the two test files, both barrels) plus the two declared-allowed metadata-protocol call-site files, plus the changeset. NoruntimeTypesflip, no partialsecurity-role-wordwiring, nocontent/docs/releases/**, none of the files other in-flight cards own.Generated by Claude Code