Skip to content

feat(security): ADR-0090 P4 — explain engine (D6), access-matrix snapshot gate, recalibrated benchmark#2716

Merged
os-zhuang merged 2 commits into
mainfrom
claude/adr-0090-p4-explain-matrix
Jul 9, 2026
Merged

feat(security): ADR-0090 P4 — explain engine (D6), access-matrix snapshot gate, recalibrated benchmark#2716
os-zhuang merged 2 commits into
mainfrom
claude/adr-0090-p4-explain-matrix

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

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")

  • Contract (@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).
  • Engine (@objectstack/plugin-security): explainAccess receives the middleware's OWN internals injected from SecurityPlugin — the shared set resolution, PermissionEvaluator, folded FLS mask, and RLS composition — so the report cannot drift from enforcement. Exposed on the security kernel service as explain(request, callerContext).
  • Authorization: explaining another user requires manage_users (or system); the target's context is reconstructed from sys_user_position / sys_user_permission_set with everyone-anchor semantics (buildContextForUser).
  • Answers the dogfood incident's question directly: "why can 张三 PATCH 李四's leave_request?" — including the D1 fail-closed reading of an unset OWD.

D6 — access-matrix snapshot gate

  • @objectstack/lint: buildAccessMatrix(stack) derives the (permission set × object) capability matrix purely from metadata; diffAccessMatrix renders semantic review lines — 'crm_admin' gains delete on 'crm_lead', depth changes (unit → org), OWD swings, entry additions/removals.
  • os compile: opt-in gate — when access-matrix.json is 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).
  • Seeded for 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-resolver implementation (cloud repo).

Verification

  • New: explain engine 10/10, access matrix 5/5 (both suites include the leave_request incident shape)
  • Suites: plugin-security 235, lint 161, spec-security 111, cli 466 (green in isolation; 3-file parallel-load flake reconfirmed unrelated)
  • Dogfood 38 files passed + 1 conditional skip / 189 tests passed, 0 failures
  • All four examples compile with the new gate active; app-crm exercises the snapshot check
  • check:liveness ✓ · gen:api-surface committed · changeset: minor × 4 (additive)
  • Full 10k×1M bench run included in the summary above

🤖 Generated with Claude Code

https://claude.ai/code/session_012oLzaP8n7A3YKFmgaHWC8H


Generated by Claude Code

…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
@vercel

vercel Bot commented Jul 9, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jul 9, 2026 7:27am

Request Review

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

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 4 package(s): @objectstack/cli, @objectstack/lint, @objectstack/plugin-security, @objectstack/spec.

100 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 packages/cli, @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/api/data-flow.mdx (via @objectstack/cli)
  • content/docs/api/environment-routing.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/cli, @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/cli, 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/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/cli.mdx (via @objectstack/cli, @objectstack/plugin-security, @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/validating-metadata.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/data-service.mdx (via packages/cli)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/cli, packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-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/authentication.mdx (via @objectstack/cli)
  • content/docs/permissions/authorization.mdx (via @objectstack/lint, packages/plugins/plugin-security, @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx (via packages/plugins/plugin-security, @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via packages/plugins/plugin-security, @objectstack/spec)
  • content/docs/permissions/profiles.mdx (via @objectstack/spec)
  • content/docs/permissions/roles.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/cli, @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/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/plugin-spec.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/protocol/objectos/realtime-protocol.mdx (via @objectstack/cli)
  • content/docs/protocol/objectos/runtime-capabilities.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via packages/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 packages/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/cli, @objectstack/plugin-security, @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)
  • 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/role-based-interfaces.mdx (via packages/plugins/plugin-security)
  • content/docs/ui/setup-app.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.

Comment thread packages/cli/src/commands/compile.ts Fixed
Comment thread packages/cli/src/commands/compile.ts Fixed
@os-zhuang
os-zhuang marked this pull request as ready for review July 9, 2026 08:11
@os-zhuang
os-zhuang merged commit a5a1e41 into main Jul 9, 2026
17 checks passed
@os-zhuang
os-zhuang deleted the claude/adr-0090-p4-explain-matrix branch 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>
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/l tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants