Rule on unknown and the scoping axis as GH-DEC-2026-009

access-engine exercised the divergence capability it claimed in the v0.6
round, on the first occasion §13.1 held two rows. ops-warden resolves
unknown to fail_open, secrets-engine to fail_closed; both conformant,
both total, both test-pinned, disagreeing about the one case that by
construction nobody planned for. They also scope over different axes, so
the register cannot answer what an inventory exists to answer.

Ruling 1: unknown is not a zone and MUST fail closed. §9.3 permits
trading availability for openness per zone — and that trade requires
knowing the zone. Where the scope is unknown the trade cannot have been
made for it, so a permissive unknown does not extend a considered
decision, it invents the most permissive one. An unreachable engine is a
known request in a degraded system; an unclassified subject is not.
unknown is the cheapest state for an attacker to induce, so failing open
on it makes being unclassifiable a privilege escalation requiring no
credential, which §8's asymmetry forbids wherever it appears.

Ruling 2: each map declares its scoping axis and its relation to zone.
Forcing everyone onto zones would make secrets-engine assert a zone it
cannot know, and a fiction in a runtime-read test-pinned file is worse
than an honest incommensurability. The register records the axes and
states that cross-axis aggregation is unavailable.

ops-warden acquires one non-conformant cell at v0.8. It did everything
asked — published first, built the reference form, offered it estate-wide
— so this goes to the assent round rather than being imposed quietly.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WtJBr77gMFLrN93iEevqQJ

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 425128@bnt-lap001
Assistant-Session: f5944d8b-dac4-4e1a-87eb-8b3d8f314a63
This commit is contained in:
tegwick 2026-09-06 14:18:36 +02:00
parent 45a65c0748
commit 22915cf2a0
3 changed files with 187 additions and 6 deletions

View file

@ -30,6 +30,7 @@ Assembly and circulation are `GH-WP-0003-T06`.
| A5 | §6.4, §8 | `GH-DEC-2026-005`, `GH-DEC-2026-008` | T05 |
| A6 | §17 | `GH-DEC-2026-004` | T07 |
| A7 | §11, §12 | four observed instances; proposed by `approval-engine` | T08 |
| A8 | §6.4, §13.1 | `GH-DEC-2026-009` | T09 |
---
@ -130,12 +131,13 @@ one.
**§13.1 rows to transcribe at the cut** — carried here so the cut is mechanical:
| Consumer | Stance map | Shape |
| --- | --- | --- |
| `ops-warden` | `ops-warden/pep-stance.yaml` | total per zone; `fail_open` for `z0``z2` and unknown, sanctioned by §9.3 and recorded per §6.4 obligation 1 limb two; test asserts published map equals shipped default |
| `user-engine` | `user-engine/pep-stance.yaml` | total per zone; `fail_closed` for `z0``z3`, unknown, and not-applicable; test asserts published map equals `user_engine.pep_stance` |
| `tenant-engine` | `tenant-engine/pep-stance.yaml` | total; `fail_closed` for unset, unreachable, non-allow, unknown; test asserts file equals shipped behaviour |
| `ops-mason` | — | **unpublished**; PEP-shaped under §6.4 (opening a route). Recorded as a gap, not a stance |
| Consumer | Stance map | Axis | Shape |
| --- | --- | --- | --- |
| `ops-warden` | `ops-warden/pep-stance.yaml` | security zone | total per zone; `fail_open` for `z0``z2` and unknown, sanctioned by §9.3 and recorded per §6.4 obligation 1 limb two; test asserts published map equals shipped default |
| `user-engine` | `user-engine/pep-stance.yaml` | security zone | total per zone; `fail_closed` for `z0``z3`, unknown, and not-applicable; test asserts published map equals `user_engine.pep_stance` |
| `tenant-engine` | `tenant-engine/pep-stance.yaml` | security zone | total; `fail_closed` for unset, unreachable, non-allow, unknown; test asserts file equals shipped behaviour |
| `secrets-engine` | `secrets-engine/pep-stance.yaml` | catalog stage — interim, pending zone membership as a claim | total over stage plus unknown; no implicit default; runtime-read; pinned to `SHIPPED_STANCE` by test |
| `ops-mason` | — | — | **unpublished**; PEP-shaped under §6.4 (opening a route). Recorded as a gap, not a stance |
Three of four are total and fail-closed. The `ops-mason` row is the finding §6.4's
closing paragraph anticipated, and it is more useful in the register than absent from
@ -338,6 +340,58 @@ as stronger than it is, which would be the same defect one layer up.
---
## A8 — §6.4 and §13.1, `unknown` and the scoping axis (T09)
Settled by `GH-DEC-2026-009`, on the first occasion §13.1 held enough rows to diverge.
**Add to §6.4 obligation 3:**
> **`unknown` is not a zone and MUST resolve to `fail_closed`.** §9.3 permits trading
> availability for openness *per zone* — knowingly, for a named scope, at a declared
> cost. That trade requires knowing the zone. Where the scope is unknown it cannot
> have been made for this request, so resolving `unknown` permissively does not extend
> a considered decision, it invents the most permissive one available.
>
> An unreachable engine and an unclassified subject are different failure cases. The
> first is a known request in a degraded system and the trade is available for it. The
> second is not: `unknown` is the cheapest state for an attacker to induce — an
> unregistered workload, a malformed label, a resource created before classification,
> a race against registry propagation — and a permissive `unknown` makes being
> unclassifiable a privilege escalation requiring no credential. §8's asymmetry
> forbids that wherever it appears.
>
> Zone stances are untouched by this. Raised by `access-engine` as an observation on
> two conformant maps that disagree, and explicitly not as a request that either
> consumer change its stance — a PDP does not set a consumer's stance.
**Add to §6.4 obligation 3, and to the §13.1 register columns:**
> A published map MUST name the **axis** it scopes over and state its relationship to
> security zone: either a mapping, or an explicit declaration that none exists yet and
> why. §13.1 carries the axis per row.
>
> "Per zone **or equivalent scope**" permits axes that cannot be aggregated, and the
> register cannot then answer *"what is the estate's stance for a `z2`-protected
> workload"* — the question an inventory exists to answer. Forcing every consumer onto
> zones is the wrong repair where zone membership is not yet available as a claim;
> asserting a zone one cannot know is a fiction, and a fiction in a runtime-read,
> test-pinned file is worse than an honest incommensurability. **The register therefore
> records the axes and states that cross-axis aggregation is unavailable**, rather than
> implying an answer it does not have. An inventory that silently cannot answer its own
> question is §9.1's defect in another place.
>
> The convergence path is zone membership reaching the decision as a claim, after
> which a stage-scoped map converges onto zones without either side inventing a
> mapping. Until then the axes are recorded, not reconciled.
**Register impact at the cut.** `ops-warden`'s `unknown``fail_open` cell becomes
non-conformant under this amendment; its `z0``z2` stances do not. That is a real cost
to the repository that published first, built the reference form, and offered it
estate-wide, and it is put to the assent round rather than imposed — the A3 row stays
as written until v0.8 is accepted.
---
## Not in this set
Recorded so the omissions are deliberate rather than forgotten.