feat(security): ADR-0090 P4 — explain engine (D6), access-matrix snapshot gate, recalibrated benchmark#2716
Merged
Merged
Conversation
…shot gate, recalibrated benchmark Explain contract (spec): ExplainRequest/ExplainDecision/ExplainLayer — nine pipeline layers reported in order with per-layer contributor attribution and the composed read filter as the machine artifact; carries D10 dual attribution (principalKind / onBehalfOf). Explain engine (plugin-security): explainAccess walks the SAME resolution/ evaluator/FLS/RLS code the enforcement middleware uses (injected from SecurityPlugin) — explained by construction. Exposed on the 'security' kernel service as explain(); explaining another user requires manage_users (target context reconstructed via buildContextForUser with everyone-anchor semantics). Access-matrix snapshot gate (lint + cli): buildAccessMatrix derives the (permission set × object) capability matrix purely from metadata; diffAccessMatrix renders semantic review lines; os compile fails on drift against a committed access-matrix.json until re-snapshotted with --update-access-matrix. Seeded for examples/app-crm. Benchmark (Addendum): scripts/bench/permission-bench.mts — single-org 10k users × 1M rows; asserts per-request cost independent of population. Passing at ~0.1µs/eval, 59ms per 1M-row IN-set scan. NOTE: code + unit suites verified (plugin-security 235, lint 161, spec-security 111, cli green); full dogfood + example builds pending — run before opening the PR. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012oLzaP8n7A3YKFmgaHWC8H
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📓 Docs Drift CheckThis PR changes 4 package(s): 100 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
…odeQL) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012oLzaP8n7A3YKFmgaHWC8H
os-zhuang
marked this pull request as ready for review
July 9, 2026 08:11
os-zhuang
added a commit
that referenced
this pull request
Jul 9, 2026
…on Model v2 vocabulary (ADR-0090) (#2717) - roles.mdx → positions.mdx: flat positions (岗位), assignment BU anchor, built-in identity positions, everyone/guest audience anchors; the hierarchy narrative moves to business units. - profiles.mdx → migration tombstone: the Profile concept was removed (D2); maps each former use to everyone-anchor bindings, isDefault suggestions, and position-bound sets. - permission-sets.mdx: rewritten as the single capability container — union semantics, access depth (moved here from profiles), capabilities, built-in sets (additive member_default baseline), governed assignment tables, isDefault suggestion, adminScope delegated administration, package provenance. - sharing-rules.mdx: OWD default corrected to fail-closed private (D1 — the page previously documented the pre-v2 fail-open default), canonical four values only, externalSharingModel dial (D11), recipient types position / unit_and_subordinates / team. - authorization.mdx: position vocabulary, D1/D11 in the enforcement chain, delegated-admin gate in anti-escalation, new explain-engine section (D6), D7 linter + access-matrix snapshot added to governance, ADR-0090 in the index. - permissions-matrix.mdx: role-hierarchy section replaced with business-unit hierarchy & positions; isProfile removed from samples; position recipients. - permission-metadata.mdx: isProfile → isDefault/adminScope in the field table; union-semantics section replaces Profile-vs-Set; current_user.positions. - index.mdx: five-concepts overview, v2 implementation-status callout, best practices and example updated. - access-recipes.mdx / field-level-security.mdx: link + heading fixes. Authoritative reference: docs/design/permission-model.md; decision record: ADR-0090 (P1 #2697, P2 #2708, P3 #2711, P4 #2716). Claude-Session: https://claude.ai/code/session_012oLzaP8n7A3YKFmgaHWC8H Co-authored-by: Claude <noreply@anthropic.com>
This was referenced Jul 10, 2026
Merged
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.
Summary
Fourth and final launch-shape wave of ADR-0090 (Permission Model v2): the D6 explain engine + access-matrix snapshot gate, plus the Addendum-recalibrated benchmark. Follows #2695 (ADR), #2697 (P1), #2708 (P2), #2711 (P3). Purely additive — no breaking changes.
D6 — explain engine ("explained by construction")
@objectstack/spec):ExplainRequestSchema/ExplainDecisionSchema/ExplainLayerSchema— the decision plus every pipeline layer's verdict in evaluation order (principal → required_permissions → object_crud → fls → owd_baseline → depth → sharing → vama_bypass → rls), per-layer contributor attribution (which permission set, reached via which position / additive baseline / direct grant), the composed read filter as the machine artifact, and D10 dual attribution (principalKind,onBehalfOf).@objectstack/plugin-security):explainAccessreceives the middleware's OWN internals injected fromSecurityPlugin— the shared set resolution,PermissionEvaluator, folded FLS mask, and RLS composition — so the report cannot drift from enforcement. Exposed on thesecuritykernel service asexplain(request, callerContext).manage_users(or system); the target's context is reconstructed fromsys_user_position/sys_user_permission_setwith everyone-anchor semantics (buildContextForUser).D6 — access-matrix snapshot gate
@objectstack/lint:buildAccessMatrix(stack)derives the (permission set × object) capability matrix purely from metadata;diffAccessMatrixrenders semantic review lines —'crm_admin' gains delete on 'crm_lead', depth changes (unit → org), OWD swings, entry additions/removals.os compile: opt-in gate — whenaccess-matrix.jsonis committed next to the config, any drift fails the build with those lines until re-snapshotted via--update-access-matrix; the snapshot's git diff is the review artifact. Unchanged matrix auto-passes (zero cost until someone changes who-can-do-what).examples/app-crm(6 entries) and verified live.Benchmark (ADR-0090 Addendum)
scripts/bench/permission-bench.mts— the recalibrated single-org gate (10k users × 1M rows; the 100k-user mega-unit moved to non-goal). Asserts the O()-shape property: per-request cost independent of user population; unit-depth IN-set cost tracks unit size. Passing: ~0.1µs/eval, 59ms per 1M-row IN-set scan.Out of scope (per ADR phasing)
Tiered human-approval publish workflow and the what-if simulator (product track on top of this substrate); D10 agent assignment ceilings (needs principal-linked user rows); enterprise
hierarchy-scope-resolverimplementation (cloud repo).Verification
app-crmexercises the snapshot checkcheck:liveness✓ ·gen:api-surfacecommitted · changeset: minor × 4 (additive)🤖 Generated with Claude Code
https://claude.ai/code/session_012oLzaP8n7A3YKFmgaHWC8H
Generated by Claude Code