Skip to content

refactor(spec)!: close the three #3980 triage items — remove rls.priority, bind tabPermissions + writeScope proofs - #3990

Merged
os-zhuang merged 4 commits into
mainfrom
claude/sharing-rules-schema-bypass-h4c7xr
Jul 30, 2026
Merged

refactor(spec)!: close the three #3980 triage items — remove rls.priority, bind tabPermissions + writeScope proofs#3990
os-zhuang merged 4 commits into
mainfrom
claude/sharing-rules-schema-bypass-h4c7xr

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

The three items #3980 (merged) flagged for the v17 window, one commit each.

1. rls.priority removed — it promised conflict resolution that cannot exist

The audit corrected priority to 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:

Changeset: major — folds into the unreleased 17.0.0, which is the point of doing it this week.

2. permission.tabPermissions bound to the me-apps proof — after making the proof author it

The precondition #3980 named ("确认 proof 作者面是 permission-set 侧") failed on inspection: the me-apps dogfood test only mentioned tabPermissions in its header while exercising the route and app.requiredPermissions. Binding it as-is would have been the exact anti-pattern the proof-registry documents — owner-anchor binds modifyAllRecords which it exercises, NOT the sibling allowTransfer it 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/apps for 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-permissionsbound: true, ledgerBindings: [{permission, tabPermissions}] (the governed surface; app remains 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. writeScope gets its runtime proof — the only scope axis without one

readScope has carried a proof since ADR-0054 phase 1; writeScope was 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).
  • Absent writeScope under 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.
  • The hierarchy seam fails closed: same 'unit' grant, no enterprise resolver → co-member edit denied, never fail-open.

Registered + bound as the scope-depth-write class; ledger entry carries the proof.

Verification


Generated by Claude Code

claude added 3 commits July 30, 2026 01:34
…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
@vercel

vercel Bot commented Jul 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Jul 30, 2026 1:46am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling size/m labels Jul 30, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/plugin-security, packages/qa, @objectstack/spec.

109 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx (via @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/spec)
  • content/docs/api/environment-routing.mdx (via @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/spec)
  • content/docs/automation/approvals.mdx (via packages/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/cli.mdx (via @objectstack/plugin-security, @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via packages/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via @objectstack/plugin-security, packages/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/spec)
  • content/docs/permissions/access-recipes.mdx (via packages/plugins/plugin-security)
  • content/docs/permissions/authorization.mdx (via @objectstack/plugin-security, packages/qa, @objectstack/spec)
  • content/docs/permissions/delegated-administration.mdx (via packages/qa)
  • content/docs/permissions/explain.mdx (via @objectstack/plugin-security)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via packages/plugins/plugin-security, @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/rls.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/plugin-security, @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/plugin-security, @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/plugin-security, @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/runtime-capabilities.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx (via @objectstack/plugin-security, @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v16.mdx (via @objectstack/spec)
  • content/docs/releases/v17.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)
  • content/docs/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/audience-based-interfaces.mdx (via packages/plugins/plugin-security)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/plugin-security, @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)
  • content/docs/ui/translations.mdx (via @objectstack/spec)
  • content/docs/ui/views.mdx (via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

…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
os-zhuang marked this pull request as ready for review July 30, 2026 02:09
@os-zhuang
os-zhuang merged commit d6bfb3d into main Jul 30, 2026
18 checks passed
@os-zhuang
os-zhuang deleted the claude/sharing-rules-schema-bypass-h4c7xr branch July 30, 2026 02:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants