Access-Matrix Snapshot Gate
A committed (permission set × object) capability matrix that fails the build on any grant drift, with the semantic diff as the review artifact (ADR-0090 D6).
Access-Matrix Snapshot Gate
AI drafts permission metadata on this platform; the one thing it must never do
is silently change who can do what. The access-matrix gate makes every
capability change a visible, reviewable build event: the
(permission set × object) matrix is derived purely from metadata on every
os compile, diffed against a committed snapshot, and any drift fails the
build with a semantic explanation until a human regenerates the snapshot.
Opting in
The gate is per-app: commit an access-matrix.json next to
objectstack.config.ts. Generate the first snapshot with:
os compile --update-access-matrixNo access-matrix.json → the gate is skipped (not opted in). Both
examples/app-crm and examples/app-showcase are opted in.
What a drift failure looks like
Change a grant — say, giving the showcase baseline set access to the private
notes object — and the next os compile fails:
→ Checking access-matrix snapshot (ADR-0090 D6)...
✗ Access matrix drift (1 change) — capability changes must be reviewed
• 'showcase_member_default' gains access to 'showcase_private_note' (create, read, edit)
If intended, re-run with --update-access-matrix and commit the snapshot — its diff IS the review artifact.The diff lines are semantic, not JSON: gained/lost operations, View/Modify All changes, depth changes, OWD swings. If the change is intended, regenerate and commit — the snapshot's git diff then rides the pull request, where a reviewer sees the capability delta in plain language instead of spelunking through metadata files.
The snapshot format
One entry per (permission set × object) grant, sorted for stable diffs
(AccessMatrixSchema, version 1):
{
"version": 1,
"entries": [
{
"permissionSet": "showcase_auditor",
"object": "showcase_private_note",
"create": false,
"read": true,
"edit": false,
"delete": false,
"viewAllRecords": true,
"modifyAllRecords": false,
"sharingModel": "private"
}
]
}read is also true when View/Modify All grants it; edit/delete are also
true under Modify All — the matrix reports effective capability, not the
raw flags. Each row carries the object's OWD so a baseline swing
(private → public_read_write) is a visible diff too.
How it relates to the rest of the defense
- The security posture linter (ADR-0090 D7) rejects individually dangerous declarations (unset OWD, high-privilege anchor suggestions, retired aliases). The matrix gate catches what the linter can't: a legitimate-looking change whose blast radius a human should still sign off.
- The explain engine is the same evaluation logic pointed at one decision at runtime; the matrix is the build-time sweep across all of them.
- Both are only possible because grants are structured data — the standing argument for the closed authoring vocabulary over freeform predicates.
See also
- Authorization Architecture
- Explain Engine
- Security Permissions Matrix — the human-readable capability tables