refactor(spec)!: close the three #3980 triage items — remove rls.priority, bind tabPermissions + writeScope proofs - #3990
Merged
Conversation
…oof — after making the proof author it
The me-apps dogfood test only MENTIONED tabPermissions in its header while
exercising the route and app.requiredPermissions — binding then would have
been the owner-anchor/allowTransfer mistake the proof-registry warns about
(a proof cited for a property it never authors). It now authors the property
on the PERMISSION-SET side: a set whose only content is
tabPermissions:{showcase_app:'hidden'} drops the app from /me/apps for its
holder, a second more-visible grant wins it back (tabRank most-visible-wins),
and unrelated principals are asserted untouched.
Registry: app-tab-permissions bound → permission/tabPermissions (the governed
surface; app remains ungoverned). Ledger entry carries the proof ref. README
proof tables updated. Dogfood file: 6/6 green against a booted stack;
liveness gate + 88 registry tests green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QuViRSR1j6GJjf9qGbnqFX
…e axis without one Three postures asserted on POST-STATE (a system read of the row after each attempt), not just HTTP status: writeScope 'unit' edits a BU co-member's row and does NOT descend into a child BU; an ABSENT writeScope stays owner-only even under a 'unit' readScope, proving the two axes gate independently; and the hierarchy seam fails CLOSED to owner-only without the enterprise resolver. 9/9 against booted stacks. Registered + bound as the scope-depth-write class (ADR-0054): ledger entry carries the proof, README bound table + registry tests updated (89 green). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QuViRSR1j6GJjf9qGbnqFX
…lution that cannot exist (#3896 audit) The 2026-07-30 security-subset re-verification found priority unread — and, stronger, unreadable-with-effect: applicable policies OR-combine (any match allows access, most permissive wins, per the schema's own describe), so there is never a conflict to order and evaluation order cannot change an outcome. A semantically-void knob on a security policy is worse than dead: an author — very often an AI (ADR-0033) — reads it as a precedence lever and reasons about policy interactions that do not exist. Removed per the #3715/#3950 precedent inside the v17 breaking window: - Tombstoned via retiredKey (#3855): authored priority fails tsc (never) and rejects at parse with the prescription itself; absence parses clean. Both directions pinned in rls.test.ts. - ADR-0087 D2 conversion + D3 chain step (permission-rls-priority-removed): `os migrate meta` deletes the key mechanically — a pure lossless delete. spec-changes.json + protocol upgrade guide regenerated with the entry. - Policy factory helpers, the showcase example permission sets, and content/docs/permissions/rls.mdx no longer author it; the docs table's `enabled` row now states the (since-enforced) contract. - authorable-surface + json-schema baselines regenerated ([RETIRED] recorded); reference docs regenerated (the tombstone prescription shows in the table). - Ledger entry updated to record the removal; tombstone + entry age out ~two majors from now. spec: 6866 tests green (incl. the chain-replay composability gate), tsc clean here and in plugin-security, showcase boots (6/6 me-apps dogfood), liveness gate green, all generated-artifact checks green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QuViRSR1j6GJjf9qGbnqFX
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 3 package(s): 109 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
…e retired rls priority The tombstone did its job on the first authored value it met in CI — this fixture parsed a policy with priority:10 at module top level and got the prescription. Missed by the pre-removal sweep because that grep filtered on rls/policy keywords appearing on the SAME LINE as priority, which a key inside a policy literal does not satisfy — the exact filtered-search false absence the liveness README warns about. The re-sweep that found this one checked every file containing rowLevelSecurity for a priority key; the two other hits are different features (nav contribution ordering, hook priority). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QuViRSR1j6GJjf9qGbnqFX
os-zhuang
marked this pull request as ready for review
July 30, 2026 02:09
This was referenced Jul 30, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The three items #3980 (merged) flagged for the v17 window, one commit each.
1.
rls.priorityremoved — it promised conflict resolution that cannot existThe audit corrected
priorityto dead; this finishes the disposition. It was documented as "Policy priority for conflict resolution" — but applicable policies OR-combine (any match allows access, most permissive wins, per the schema's own describe), so there is never a conflict to order and evaluation order cannot change an outcome. Nothing ever read it. A semantically-void knob on a security policy is worse than dead: an author — very often an AI (ADR-0033) — reads it as a precedence lever and reasons about policy interactions that do not exist.Removed per the #3715/#3950 precedent, with the full retirement kit:
retiredKey, [P3] Retire the three deprecated aliases — via the ADR-0087 D2 conversion layer, not by deleting the keys #3855): an authoredpriorityfailstsc(input typenever) and rejects at parse with the prescription itself. Both directions pinned inrls.test.ts.permission-rls-priority-removed):os migrate metadeletes the key mechanically — a pure lossless delete,expectedNotices: 1, replayed by the chain-composability gate.spec-changes.jsonand the protocol upgrade guide carry the entry.content/docs/permissions/rls.mdxno longer author it. The docs table'senabledrow now states the (since-fix(security)!: a disabled RLS policy no longer grants — security-subset liveness re-verification (#3896 follow-up) #3980-enforced) contract: "falseswitches the policy off — a disabled policy is not evaluated."authorable-surface.jsonrecords the key[RETIRED]; reference docs regenerated (the table shows the prescription).Changeset: major — folds into the unreleased 17.0.0, which is the point of doing it this week.
2.
permission.tabPermissionsbound to the me-apps proof — after making the proof author itThe precondition #3980 named ("确认 proof 作者面是 permission-set 侧") failed on inspection: the me-apps dogfood test only mentioned
tabPermissionsin its header while exercising the route andapp.requiredPermissions. Binding it as-is would have been the exact anti-pattern the proof-registry documents — owner-anchor bindsmodifyAllRecordswhich it exercises, NOT the siblingallowTransferit only mentions in a comment.So the proof was extended first: it now authors the property on the permission-set side — a set whose only content is
tabPermissions: { showcase_app: 'hidden' }drops the app from/me/appsfor its holder, a second more-visible grant wins it back (pinning hono's tabRank most-visible-wins merge), and an unrelated principal is asserted untouched. 6/6 against a booted stack.Then bound:
app-tab-permissions→bound: true,ledgerBindings: [{permission, tabPermissions}](the governed surface;appremains ungoverned). Ledger entry carries the proof ref; README's bound/unbound tables updated. From now on, deleting or renaming that dogfood test fails the liveness gate.3.
writeScopegets its runtime proof — the only scope axis without onereadScopehas carried a proof since ADR-0054 phase 1;writeScopewas live on two confirmed readers but nothing re-proved it end-to-end. New dogfood file (showcase-scope-depth-write, 9/9), asserting post-state (a system read of the row after each attempt), not just HTTP status:writeScope: 'unit'→ a BU co-member's note is editable; a child-BU member's note is not ('unit' does not descend).writeScopeunder a'unit'readScope → the co-member's note is readable yet not editable — the write axis defaults to'own'and gates independently of how wide reads are. This is the case that isolates the property.Registered + bound as the
scope-depth-writeclass; ledger entry carries the proof.Verification
packages/spec: 6879 tests green (incl. the migration chain-replay gate, now composing feat(runtime)!: the undeclared-action refusal has no opt-out — dropOS_ALLOW_UNDECLARED_ACTIONS(ADR-0110 D3 revised) #3987's flow-node conversions with this one).tscclean here and inplugin-security.check:liveness(both new proof bindings resolve),check:empty-state,check:authorable-surface,check:spec-changes,check:upgrade-guide,check:docs.prioritytombstone in place.OS_ALLOW_UNDECLARED_ACTIONS(ADR-0110 D3 revised) #3987 (both added protocol-17 conversions; union-merged, chain replay green).Generated by Claude Code