From f5e49182b6fa4ef58b89ae7245e9651bd60e07a7 Mon Sep 17 00:00:00 2001 From: repo-manager Date: Sat, 29 Aug 2026 02:42:13 +0200 Subject: [PATCH] repo.work.resolve_decision FLEX-DEC-2026-002 correlation_id: c08c9fd9-29e5-472f-bf10-26c62d6dd597 reason: rmgr CLI source: repo-manager Assistant: claude-code Assistant-Model: opus Assistant-Process: 4014348@bnt-lap001 Assistant-Session: a993abda-65a0-4ea8-8ccd-0fcd78c92ac0 --- decisions/decisions.md | 150 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 148 insertions(+), 2 deletions(-) diff --git a/decisions/decisions.md b/decisions/decisions.md index 465c235..7c830ce 100644 --- a/decisions/decisions.md +++ b/decisions/decisions.md @@ -177,7 +177,7 @@ an engine gap under §5, not solved locally. id: FLEX-DEC-2026-002 kind: decision title: 'Review of security layer model v0.4: assent with findings, one rule contested' -status: open +status: resolved origin: cross-repo origin_ref: net-kingdom security-layer-model_v0.4 standard: net-kingdom/canon/standards/security-layer-model_v0.4.md @@ -195,5 +195,151 @@ requested_dispositions: - revise - reject created: '2026-08-29T00:41:21.171665Z' -updated: '2026-08-29T00:41:21.171665Z' +updated: '2026-08-29T00:42:13.009799Z' +rationale: 'Assent to security-layer-model v0.4, with one rule contested and two capability + assignments not accepted as assented. Section 9.3 conflicts with shipped assented + behavior: it rules engine-unreachability fallback into the engine, where it cannot + live, and collides with ops-warden ADR-0009''s per-zone consumer PEP map. Section + 13 names access-engine as intended owner of containment (accept as proposed owner + only, pending per 9.2) and of authentication/assurance evidence (declined as stated; + the identity layer and audit-core own that). Three consistency defects: frontmatter + status proposed contradicts section 14 ''accepted''; the adoption count reads seven + of fifteen with remaining eight against sixteen estate-authored repositories and + nine listed; section 14 says three repositories above a table of four. FLEX-IN-0002 + answered: the approval boundary unblocks T03 design, T05 additionally needs the + approval claim bound to the NewDecisionBinding request digest and a named owner + and ordering for single consumption; the maturity claim route is practical as a + request claim but not as registry content until the self-declared provenance digest + gap closes.' +decided_by: flex-auth (reviewing side) +decided_at: '2026-08-29T00:42:13.009799Z' ``` + +## Context + +`FLEX-IN-0002` asked flex-auth to review v0.3. By the time of review the current +text is **v0.4** (plus the in-place §11 amendment at `2aaf46c`), which supersedes +v0.3. This record reviews v0.4 and answers the two questions `FLEX-IN-0002` put. + +Three versions have landed since `FLEX-DEC-2026-001`, which answered **v0.1**. + +## Disposition + +**Assent to v0.4, with one rule contested, two capability assignments not +accepted as assented, and three consistency defects.** Nothing here blocks +adoption; §9.3 needs correction before it is relied on. + +### What v0.4 gets right, from flex-auth's side + +§6.2 adopts flex-auth's boundary from `FLEX-DEC-2026-001` in substance and binds +gate-house on the same terms. §9.4 upholds the self-dealing objection: the +evaluator does not own the object it evaluates, `access-engine` consumes +approvals as input claims and never mutates them. §13 attributes the +registry-snapshot digest gap to flex-auth as self-declared, which is correct. +§9.5's guardrail — a maturity level MUST NOT gate a decision directly — is §6.1 +applied to a new engine, and flex-auth endorses it. + +### Contested — §9.3 conflicts with shipped, assented behavior + +> *"The deterministic fail to reduced authority default is `access-engine`'s, +> applied when it cannot reach its own inputs."* + +Two different failure cases are conflated: + +1. **access-engine is reachable but cannot reach its own inputs.** The fallback + is flex-auth's, it is deterministic, and §9.3 is right. flex-auth accepts it. +2. **access-engine is not reachable at all.** The engine applies nothing, + because it is not running. Whatever happens next is the consumer's behavior, + necessarily. flex-auth has held since 2026-08-19 that **fail-open is not + expressible by a PDP at all** — not as a preference, but because there is no + evaluator in the path to express it. + +§9.3 as written rules case 2 into the engine, where it cannot live. It also +collides with shipped behavior in a repository that has assented to this +standard: **ops-warden `ADR-0009`** (accepted 2026-08-22, superseding `ADR-0006`) +retires the global `policy.enabled` and `policy.fail_closed` and replaces them +with a **total per-zone map in the consumer PEP** — fails open for +`z0-experimental`, `z1-operational`, `z2-protected`, `z2-continuity` and +`unknown`; fails closed for `z3-critical`. That map is a Staff-layer +degraded-mode fallback, and it is the correct design: the alternative makes +flex-auth a hard dependency of every `warden sign`, including the SSH +certificate the ops-bridge tunnel carrying the policy call depends on. + +Proposed correction: §9.3 should rule the **input-degradation** fallback into the +engine and state that **engine-unreachability residue is the consumer's**, +bounded by a requirement that the consumer's stance be declared per zone and +auditable — which `ADR-0009` already satisfies. The sentence *"engine-unavailable +is not grounds for a Staff break-glass path"* is sound and should be kept: a +bypass path around a **reachable** engine is a second decision point. A consumer +choosing its own behavior when there is no engine to ask is not. + +### Not accepted as assented — two capability assignments + +v0.4's frontmatter lists `flex-auth FLEX-DEC-2026-001` under `assented_by`, and +§14 presents it as adoption of the current text. That record answered v0.1. +Since then §13 names `access-engine` as intended owner of two capabilities +flex-auth has never reviewed: + +| Gap row | Position | +| --- | --- | +| Containment surface → `access-engine` + runtime engines | Plausible and consistent with §8's posture asymmetry — rendering reduced authority is what a PDP does. Not yet reviewed, and §9.2 marks it pending anyway. Record it as **proposed owner**, not owner. | +| Authentication / assurance evidence → `user-engine`, `access-engine` | **Declined as stated.** flex-auth consumes assurance claims as input and never re-defines them; `INTENT.md` is explicit that the identity layer owns authentication. Evidence *of authentication* belongs to the identity layer and `audit-core`. flex-auth owns evidence of the **decision**, which it already emits. | + +An `intended_owner` in a gap register is a proposal to the named repository, not +an assignment to it — §2 keeps what a repository owns in that repository's own +`INTENT.md`. flex-auth suggests §13 gain a column distinguishing a proposed owner +from an assented one, so the register does not accumulate silent assignments the +way §14's assent row nearly did. + +### Consistency defects + +1. **Frontmatter `status: proposed` contradicts §14 "Status is accepted."** + Material, because §2 makes this standard the authority for layer assignment. + The change log records v0.2 as accepted and v0.3/v0.4 as proposed, so §14 + appears to be a carryover. +2. **§14's adoption count does not add up.** "seven of fifteen" and "the + remaining eight" against a §4 catalog of 17 rows, 16 of them estate-authored + (`OpenBao` excepted by §11's own who-must-declare rule). Seven declared plus + the nine repositories actually listed is sixteen. Should read **seven of + sixteen** and **the remaining nine**. +3. **§14 says "All three repositories whose boundaries moved"** above a table of + four. `audit-core` is the fourth. + +## Answers to FLEX-IN-0002 + +**(1) Is the boundary enough to unblock `FLEX-WP-0017` T03/T05 design?** +Yes for T03. Not quite for T05, which needs two things specified in +`approval-engine`'s contract first: + +- **Claim shape must bind to the request digest flex-auth already computes.** + The approval claim should carry the approval id plus the digest of the action + it approves, computed over the same canonical binding as + `NewDecisionBinding` (`FLEX-WP-0017-T01`). Otherwise "approved" and "approved + *for this exact request*" are not distinguishable at decision time, and T05's + wrong-action/lane/stage/targets proofs have nothing to compare against. +- **Single consumption needs an owner and an ordering.** flex-auth never mutates + approvals, so consumption is `approval-engine`'s. But the decision precedes the + action, and the action precedes consumption — so an allow rendered against an + approval that is then never consumed, or consumed twice by a racing caller, is + a gap neither engine closes alone. Naming who marks consumed and at what point + relative to the decision belongs in the contract before T05, not after. + +**(2) Is the maturity claim route practical from where flex-auth sits?** +Yes, with one caveat that is flex-auth's own fault rather than +`maturity-engine`'s. A level reaching flex-auth as a **request claim** is +practical today and lands in the decision binding. A level reaching flex-auth as +**registry content** is not reconstructable, because `DecisionProvenance` carries +no registry-snapshot digest — the gap flex-auth self-declared in §13. Until that +closes, maturity levels should arrive as request claims or versioned policy +rules, never compiled into the registry snapshot. This is the same constraint +flex-auth placed on zone stance, for the same reason. + +## Consequences + +- `FLEX-IN-0002` is closed; the assessment covers v0.4 rather than v0.3. +- flex-auth's assent now attaches to **v0.4** for §§1–8, §9.1–9.2, §9.4–9.6, + and §§10–16, and to §9.3 only in its input-degradation half. +- `FLEX-WP-0017` T03/T05 stay `wait` on `approval-engine`, with the two contract + items above raised as prerequisites for T05. +- `SCOPE.md` cites ops-warden `ADR-0006` as current; it is superseded by + `ADR-0009`. Correcting that is flex-auth's own housekeeping.