You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs(adr): ADR-0099 two-axis amendment — Layer 1 tier stays the per-object scope bit; P2 superseded by P2' (#3211)
The pre-P2 verification found D2's Layer 1 row was not behavior-preserving
as written: Layer 1's tier input is the per-object super-bit, a
per-principal-x-per-object delegation primitive (custom set granting
viewAllRecords on one object to a non-admin position — the auditor
pattern, the industry-standard shape). Posture is per-principal and
structurally cannot carry per-object scope; enforcing the MEMBER cell
literally would inert a declared grantable bit (the ADR-0049
declared-but-unenforced class) and delete a mainstream delegation
capability.
Amendment (maintainer, 2026-07-18): two orthogonal axes, each with a
single authority — posture is the boundary axis (Layer 0 exemption at
PLATFORM_ADMIN, EXTERNAL replacement; both ladder ends), the per-object
super-bits are the scope axis (the only Layer 1 tier input, unchanged).
D1's single-input principle refines to single-authority-per-axis; new
invariant I7 (scope never crosses a boundary posture has not opened —
enforced by P1); I2 clarified as a per-rung floor. Original P2 rejected;
P2' = documentation cells only (seeded-face agreement, the delegation
cell, I7), zero behavior change.
Inline markers added at the D1 bullet, D2 table, and Sequencing P2 entry;
full rationale in the Amendment section. Docs-only; no changeset.
check:role-word OK - check:doc-authoring 200 files clean.
Refs #3211 - ADR-0099 / #3109 / #3218 / #3226
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DAHp4K7FvyMPBY1DPNkmRu
Copy file name to clipboardExpand all lines: docs/adr/0099-posture-adjudicated-tiering-and-external-rung.md
+80-6Lines changed: 80 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
# ADR-0099: Posture-Adjudicated Tiering — one axis for tier decisions, the EXTERNAL rung's enforcement path, no explicit deny
2
2
3
-
**Status**: Accepted (2026-07-18; proposed 2026-07-17) — P0 equivalence gate landed with the acceptance (see the Acceptance addendum); P1/P2 flips gated on the #3211 G1 delta adjudication
3
+
**Status**: Accepted (2026-07-18; proposed 2026-07-17) — P0 equivalence gate landed with the acceptance (see the Acceptance addendum); P1 shipped (#3226). Amended 2026-07-18: **two-axis correction** — D2's Layer 1 tier input corrected to the per-object scope bits, original P2 superseded by P2′ (see the Amendment)
4
4
**Deciders**: ObjectStack Protocol Architects
5
5
**Builds on**: [ADR-0095](./0095-authz-kernel-tenant-layer-and-posture-ladder.md) (the posture ladder + Layer 0 — Accepted, implemented; this ADR is its adjudication follow-through), [ADR-0066](./0066-unified-authorization-model.md) (superuser bypass ①; precedence), [ADR-0090](./0090-permission-model-v2-concept-convergence.md) (D10 principal taxonomy / `audience`, D11 external OWD), [ADR-0093](./0093-tenancy-mode-and-membership-lifecycle.md) (membership lifecycle — where an external principal type would come from), [ADR-0094](./0094-sys-permission-set-pure-projection.md) (one-authority precedent)
6
6
**Composes with**: [ADR-0096](./0096-execution-surface-identity-admission.md) — 0096 governs **admission** (may this call reach the engine, as whom); this ADR governs **tiering** (given an admitted principal, which tier of rows each layer grants). Orthogonal axes, deliberately separate ADRs.
@@ -121,9 +121,13 @@ Every enforcement-time **tier** decision reads `ctx.posture`:
121
121
ADR-0096 D3 is progressively eliminating). When both signals are present
122
122
the carried rung wins; a disagreement is logged as a defect signal, and the
123
123
**narrower** verdict is enforced (fail-safe).
124
-
-**Layer 1 short-circuit**: the *tier* question ("does business RLS apply at
125
-
all inside the org") reads posture (`>= TENANT_ADMIN` short-circuits, per
126
-
today's semantics); the *side* question keeps its per-side capability bit —
124
+
-**Layer 1 short-circuit***(superseded by the two-axis Amendment below)*: the
125
+
original text read the tier from posture (`>= TENANT_ADMIN`) and claimed
126
+
today's semantics. The pre-P2 verification (framework#3211) showed that is
127
+
NOT today's semantics: the tier input is the **per-object** super-bit, which
128
+
a custom set can delegate to a non-admin principal — a per-principal ×
129
+
per-object fact the per-principal posture cannot represent. Layer 1's tier
130
+
input therefore **stays the per-side, per-object capability bit**;
127
131
`viewAllRecords` gates the read bypass, `modifyAllRecords` the write bypass,
128
132
exactly as today. Posture never grants a side the bits don't.
129
133
-**Explain** reports the carried rung it read — the same field, not a
@@ -148,6 +152,12 @@ it would have caught).
148
152
|**Write path**| tier does not bypass write guards: readonly strip (#2957), identity write guard (ADR-0092), Layer 0 write wall (#2946) all still apply | same | same | shares with edit access only |
149
153
|**Explain**| reports the carried rung — identical input as enforcement, by construction | same | same | same |
150
154
155
+
> **Amendment note (2026-07-18):** the **Layer 1** row above is corrected by
156
+
> the two-axis Amendment — the tier at Layer 1 is *not* selected by posture;
157
+
> it is selected by the per-object super-bits (a `MEMBER` holding a delegated
158
+
> per-object `viewAllRecords` short-circuits business RLS on that object,
159
+
> tenant-walled as ever). The Layer 0 and EXTERNAL rows stand as written.
160
+
151
161
Invariants (each carries a matrix cell):
152
162
153
163
-**I1** — `TENANT_ADMIN` never crosses Layer 0. No capability composition may
@@ -233,8 +243,11 @@ Strictly serial, each step behind the matrix:
233
243
rung (probe demoted to fallback; stale comment at
234
244
`security-plugin.ts:71-77` retired). Behavior-preserving under P0's gate.
0 commit comments