2026-08-28 21:15:15 +02:00
|
|
|
|
# Decision records
|
|
|
|
|
|
|
|
|
|
|
|
## GH-DEC-2026-001 — NetKingdom security layer model, the gate-house re-cut, and the access-engine reframing
|
|
|
|
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
|
|
id: GH-DEC-2026-001
|
|
|
|
|
|
kind: decision
|
|
|
|
|
|
title: NetKingdom security layer model, the gate-house re-cut, and the access-engine
|
|
|
|
|
|
reframing
|
2026-08-28 21:16:01 +02:00
|
|
|
|
status: resolved
|
2026-08-28 21:15:15 +02:00
|
|
|
|
owner: Bernd Worsch
|
|
|
|
|
|
repo: gate-house
|
|
|
|
|
|
standard: net-kingdom/canon/standards/security-layer-model_v0.1.md
|
|
|
|
|
|
source_note: history/2026-08-28-security-layer-model-and-gate-house-recut.md
|
|
|
|
|
|
requested_dispositions:
|
|
|
|
|
|
- approved
|
|
|
|
|
|
- revised
|
|
|
|
|
|
- rejected
|
|
|
|
|
|
affects:
|
|
|
|
|
|
- gate-house
|
|
|
|
|
|
- flex-auth
|
|
|
|
|
|
- ops-warden
|
|
|
|
|
|
- ops-mason
|
|
|
|
|
|
- kings-guard
|
|
|
|
|
|
- whitehat-security
|
|
|
|
|
|
- net-kingdom
|
|
|
|
|
|
- zone-engine
|
|
|
|
|
|
created: '2026-08-28T19:15:15.607849Z'
|
2026-08-28 21:16:01 +02:00
|
|
|
|
updated: '2026-08-28T19:16:01.456127Z'
|
|
|
|
|
|
rationale: 'Approved in session on 2026-08-28. The three rulings were taken interactively:
|
|
|
|
|
|
Staff as the layer name, net-kingdom canon as the model''s home, and access-engine
|
|
|
|
|
|
as the rename target with the lane/rule demarcation accepted as its cost. Approval
|
|
|
|
|
|
covers the doctrine and documents only; the flex-auth rename remains a separate
|
|
|
|
|
|
governed migration, and the standard stays proposed pending assent from flex-auth,
|
|
|
|
|
|
kings-guard, and ops-warden.'
|
|
|
|
|
|
decided_by: Bernd Worsch
|
|
|
|
|
|
decided_at: '2026-08-28T19:16:01.456127Z'
|
2026-08-28 21:17:05 +02:00
|
|
|
|
state_hub_decision_id: "2d6509d0-ffd2-4209-89ab-bf68a4945ada"
|
2026-08-28 21:15:15 +02:00
|
|
|
|
```
|
2026-08-28 21:16:01 +02:00
|
|
|
|
|
|
|
|
|
|
## Context
|
|
|
|
|
|
|
|
|
|
|
|
The security estate acquired overlapping claims to the same responsibility, and
|
|
|
|
|
|
the overlap was invisible in each repository's own documents. `gate-house` was
|
|
|
|
|
|
seeded as a deterministic authority plane — a policy decision point with an
|
|
|
|
|
|
`/authorize` API, grant storage, and a revocation service — while `flex-auth`
|
|
|
|
|
|
already described itself as the authorization control plane and was actively
|
|
|
|
|
|
delivering `FLEX-WP-0017`, an approval contract binding approvals to action,
|
|
|
|
|
|
actor, target, and validity window. Neither repository's INTENT named the other.
|
|
|
|
|
|
`zone-engine` had already been ruled against on the same question.
|
|
|
|
|
|
|
|
|
|
|
|
Full review and evidence: `history/2026-08-28-security-layer-model-and-gate-house-recut.md`.
|
|
|
|
|
|
|
|
|
|
|
|
## Decision requested
|
|
|
|
|
|
|
|
|
|
|
|
Ratify three linked rulings. They are one decision because the second does not
|
|
|
|
|
|
hold without the first, and the third is the first applied to the repository
|
|
|
|
|
|
that was already right.
|
|
|
|
|
|
|
|
|
|
|
|
### Ruling 1 — Adopt the NetKingdom security layer model
|
|
|
|
|
|
|
|
|
|
|
|
The estate is layered **Taxonomy → Tooling → Engines → Staff**, distinguished by
|
|
|
|
|
|
determinism and by the kind of artifact each layer produces. The top layer is
|
|
|
|
|
|
named **Staff** — the general-staff sense of plans and doctrine without
|
|
|
|
|
|
execution — not "Helpers", which undersold a layer holding architecture,
|
|
|
|
|
|
controlling, and change.
|
|
|
|
|
|
|
|
|
|
|
|
The model is published as `net-kingdom/canon/standards/security-layer-model_v0.1.md`,
|
|
|
|
|
|
owned by gate-house, status `proposed`. It belongs in net-kingdom canon rather
|
|
|
|
|
|
than info-tech-canon because it is NetKingdom-flavored security architecture,
|
|
|
|
|
|
not general semantic contract.
|
|
|
|
|
|
|
|
|
|
|
|
It carries two normative rules:
|
|
|
|
|
|
|
|
|
|
|
|
- **Staff never touches Tooling directly. It acts only through Engine APIs.**
|
|
|
|
|
|
- **`access-engine` is the only policy decision point**, generalizing to the
|
|
|
|
|
|
whole estate the ruling first drawn in `zone-engine/INTENT.md` §5.
|
|
|
|
|
|
|
|
|
|
|
|
### Ruling 2 — Re-cut gate-house as the doctrine council
|
|
|
|
|
|
|
|
|
|
|
|
Gate House is Staff: the council where NetKingdom's security and defence
|
|
|
|
|
|
doctrine is established, documented, taught, and supervised. It holds no
|
|
|
|
|
|
runtime position.
|
|
|
|
|
|
|
|
|
|
|
|
The decisive argument is gate-house's own: **a decision point inside gate-house
|
|
|
|
|
|
would place the deterministic authority boundary inside the non-deterministic
|
|
|
|
|
|
management layer, violating INV-02 — the first invariant the repository exists
|
|
|
|
|
|
to defend.** The repository would have been the clearest available
|
|
|
|
|
|
counterexample to the canon it hosts.
|
|
|
|
|
|
|
|
|
|
|
|
Boundary: *the mandate and the operating mode are gate-house's; the decision is
|
|
|
|
|
|
access-engine's; the credential is secrets-engine's; the perimeter is
|
|
|
|
|
|
ops-mason's and ops-warden's.*
|
|
|
|
|
|
|
|
|
|
|
|
gate-house keeps what no other repository owns — the operating modes, the
|
|
|
|
|
|
principal/actor/runtime triple, mandates and authority ceilings, the change
|
|
|
|
|
|
dynamics envelope, the MCP doctrine, the posture asymmetry, the assurance
|
|
|
|
|
|
specifications, and the curriculum. It gives up `/authorize`, policy evaluation,
|
|
|
|
|
|
policy engine selection, grant storage, and revocation.
|
|
|
|
|
|
|
|
|
|
|
|
### Ruling 3 — Reframe flex-auth as an Engine and rename it access-engine
|
|
|
|
|
|
|
|
|
|
|
|
`flex-auth` is Engine-layer and remains the only policy decision point. It is
|
|
|
|
|
|
renamed **`access-engine`**. `auth-engine` was rejected: key-cape owns
|
|
|
|
|
|
authentication, and `auth-` preserves the ambiguity the rename exists to remove.
|
|
|
|
|
|
`permission-engine` was rejected as ageing badly against a future `role-engine`.
|
|
|
|
|
|
|
|
|
|
|
|
The name's one cost is that "access" is already spoken for operationally by
|
|
|
|
|
|
ops-warden and ops-mason. It is paid by a demarcation, now normative in §8 of
|
|
|
|
|
|
the standard: **ops-warden and ops-mason own access lanes — how a worker reaches
|
|
|
|
|
|
a host; access-engine owns access rules — whether they may.**
|
|
|
|
|
|
|
|
|
|
|
|
Sequence is binding: **reframe the INTENT first, rename second**, as a governed
|
|
|
|
|
|
migration. The rename touches `FLEX-WP` prefix ownership, State Hub identifiers,
|
|
|
|
|
|
ops-warden's routing tables, zone-engine's binding boundary text, and
|
|
|
|
|
|
secrets-engine integrations.
|
|
|
|
|
|
|
|
|
|
|
|
The reframing also splits a responsibility flex-auth currently holds whole:
|
|
|
|
|
|
**authoring and governing policy is Staff work (gate-house); evaluating it
|
|
|
|
|
|
deterministically and in-path is access-engine's, exclusively.** This is the
|
|
|
|
|
|
constructive resolution of the `FLEX-WP-0017` overlap — gate-house designs the
|
|
|
|
|
|
approval contract, access-engine validates approvals at decision time.
|
|
|
|
|
|
|
|
|
|
|
|
## What approval authorizes
|
|
|
|
|
|
|
|
|
|
|
|
- Publication of the layer model as a proposed net-kingdom standard.
|
|
|
|
|
|
- The gate-house INTENT re-cut, already applied at `7f13f72`.
|
|
|
|
|
|
- The layering review notes placed at the top of twelve estate INTENT files.
|
|
|
|
|
|
- Starting the flex-auth INTENT reframe.
|
|
|
|
|
|
- Retiring the gate-house artifacts that describe an engine: ADR-003 (policy
|
|
|
|
|
|
engine selection), milestones M0, M3, and M4, and `GH-WP-0001-T04`
|
|
|
|
|
|
(`/authorize` skeleton). `GH-WP-0001` is rewritten against the re-cut before
|
|
|
|
|
|
it is promoted to active.
|
|
|
|
|
|
|
|
|
|
|
|
## What approval does not authorize
|
|
|
|
|
|
|
|
|
|
|
|
- The `flex-auth` → `access-engine` rename itself. That is a separate governed
|
|
|
|
|
|
migration with its own record, and it must not begin before the INTENT
|
|
|
|
|
|
reframe lands.
|
|
|
|
|
|
- Any change to `zone-engine`'s 2026-08-23 disposition.
|
|
|
|
|
|
- Promoting the standard from `proposed` to `accepted`.
|
|
|
|
|
|
- Any change to another repository's workplans. Work structure stays with the
|
|
|
|
|
|
repository doing the work.
|
|
|
|
|
|
|
|
|
|
|
|
## Assent still required
|
|
|
|
|
|
|
|
|
|
|
|
Two adaptations move vocabulary away from repositories that currently use it,
|
|
|
|
|
|
and follow the estate's precedent that a boundary is drawn on review by the
|
|
|
|
|
|
other side rather than asserted — as flex-auth did to zone-engine:
|
|
|
|
|
|
|
|
|
|
|
|
1. **flex-auth** — Engine framing, the rename, and the authoring/evaluation split.
|
|
|
|
|
|
2. **kings-guard** and **ops-warden** — releasing "control plane" and the
|
|
|
|
|
|
security curriculum respectively to the layers that own them.
|
|
|
|
|
|
|
|
|
|
|
|
## Reversal
|
|
|
|
|
|
|
|
|
|
|
|
The rulings are documents; nothing executable depends on them yet, and no code
|
|
|
|
|
|
exists in gate-house. Reversal is reverting the INTENT and standard commits.
|
|
|
|
|
|
The falsifiers that should trigger reconsideration are in
|
|
|
|
|
|
`gate-house/INTENT.md` § "What Would Make This Repository Wrong" — principally
|
|
|
|
|
|
gate-house becoming a paper generator whose conformance loop never turns, or
|
|
|
|
|
|
the estate declining to adopt the authority vocabulary.
|
2026-08-29 14:50:04 +02:00
|
|
|
|
|
|
|
|
|
|
## GH-DEC-2026-002 — Revocation fails closed only when approval-engine's own store is down
|
|
|
|
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
|
|
id: GH-DEC-2026-002
|
|
|
|
|
|
kind: decision
|
|
|
|
|
|
title: Revocation fails closed only when approval-engine's own store is down
|
2026-08-29 14:50:58 +02:00
|
|
|
|
status: resolved
|
2026-08-29 14:50:04 +02:00
|
|
|
|
owner: Bernd Worsch
|
|
|
|
|
|
repo: gate-house
|
|
|
|
|
|
standard: net-kingdom/canon/standards/security-layer-model_v0.7.md
|
|
|
|
|
|
source_note: history/2026-08-29-approval-evidence-integrity-contracts.md
|
|
|
|
|
|
requested_dispositions:
|
|
|
|
|
|
- approved
|
|
|
|
|
|
- revised
|
|
|
|
|
|
- rejected
|
|
|
|
|
|
affects:
|
|
|
|
|
|
- gate-house
|
|
|
|
|
|
- approval-engine
|
|
|
|
|
|
- audit-core
|
|
|
|
|
|
- flex-auth
|
|
|
|
|
|
created: '2026-08-29T12:50:04.747439Z'
|
2026-08-29 14:50:58 +02:00
|
|
|
|
updated: '2026-08-29T12:50:58.873684Z'
|
|
|
|
|
|
rationale: 'Approved as GH-WP-0002-T03. Local-outbox fail-closed is the only remaining
|
|
|
|
|
|
closed path: if approval-engine cannot insert the outbox row, the revocation does
|
|
|
|
|
|
not commit. An audit-core outage must not block a revocation. Synchronous emission
|
|
|
|
|
|
inside the mutation is forbidden even though it is atomic. Proceed-with-gap is rejected
|
|
|
|
|
|
for load-bearing approval evidence.'
|
|
|
|
|
|
decided_by: Bernd Worsch
|
|
|
|
|
|
decided_at: '2026-08-29T12:50:58.873684Z'
|
2026-08-29 14:50:04 +02:00
|
|
|
|
```
|
2026-08-29 14:50:06 +02:00
|
|
|
|
|
2026-08-29 14:50:58 +02:00
|
|
|
|
## Context
|
|
|
|
|
|
|
|
|
|
|
|
`GH-IN-0001` (from `audit-core`) required that the revocation failure mode be a
|
|
|
|
|
|
recorded decision rather than an implementation accident. Both sides are
|
|
|
|
|
|
defensible on their own: fail-closed makes an audit dependency into an
|
|
|
|
|
|
availability risk on the revocation path; proceed-with-gap needs a detectable
|
|
|
|
|
|
marker so the gap is visible rather than silent.
|
|
|
|
|
|
|
|
|
|
|
|
v0.5's local-outbox rule already narrowed this. With the queue in
|
|
|
|
|
|
`approval-engine`'s own store, fail-closed triggers only when that store is
|
|
|
|
|
|
down — where the change could not have been recorded anyway — and an
|
|
|
|
|
|
`audit-core` outage does not block a revocation. Satisfying atomicity by
|
|
|
|
|
|
emitting synchronously to `audit-core` inside the mutation is also atomic, and
|
|
|
|
|
|
turns an audit outage into an inability to revoke: the operation least
|
|
|
|
|
|
tolerable to block during an incident.
|
|
|
|
|
|
|
|
|
|
|
|
The statute states the locality rule at §9.4. This record is the decision the
|
|
|
|
|
|
workplan still owed, so an implementer cannot pick the other side by accident.
|
|
|
|
|
|
|
|
|
|
|
|
Wire: `docs/contracts/approval-outbox.md`.
|
|
|
|
|
|
|
|
|
|
|
|
## Decision
|
|
|
|
|
|
|
|
|
|
|
|
**If the local outbox insert cannot commit, the revocation does not commit.**
|
|
|
|
|
|
The same rule applies to issuance, use, and supersession.
|
|
|
|
|
|
|
|
|
|
|
|
**An `audit-core` outage MUST NOT block a revocation.** Drain is asynchronous
|
|
|
|
|
|
and at-least-once. `audit-core` dedupes on `event_id`.
|
|
|
|
|
|
|
|
|
|
|
|
**Synchronous emission to `audit-core` inside the state-change transaction is
|
|
|
|
|
|
forbidden**, even though it is atomic.
|
|
|
|
|
|
|
|
|
|
|
|
Proceed-with-gap is rejected for load-bearing approval evidence. A revocation
|
|
|
|
|
|
that succeeds while its event is lost is the exact case `AUDIT-IN-0001`
|
|
|
|
|
|
conditioned assent on.
|
|
|
|
|
|
|
|
|
|
|
|
## What this authorizes
|
|
|
|
|
|
|
|
|
|
|
|
- `approval-engine` failing a revoke (and any other mutation) when its own
|
|
|
|
|
|
store cannot insert the outbox row.
|
|
|
|
|
|
- Continuing to revoke while `audit-core` is down, with the row draining later.
|
|
|
|
|
|
- Treating emit-after-commit, a second non-local queue, or a sync `audit-core`
|
|
|
|
|
|
call inside `BEGIN`…`COMMIT` as out of contract.
|
|
|
|
|
|
|
|
|
|
|
|
## What this does not authorize
|
|
|
|
|
|
|
|
|
|
|
|
- Claiming the outbox closes adversarial omission. Atomicity prevents crash;
|
|
|
|
|
|
cadence and reconciliation detect suppression after the fact (§9.6).
|
|
|
|
|
|
- A validity query on `audit-core`.
|
|
|
|
|
|
- Any change to another repository's workplans.
|
|
|
|
|
|
|
|
|
|
|
|
## Reversal
|
|
|
|
|
|
|
|
|
|
|
|
Revert this record and the outbox contract. The falsifier is operational: if
|
|
|
|
|
|
failing closed on the local store removes the ability to revoke during the
|
|
|
|
|
|
incidents this engine exists for, the trade needs revisiting — but the
|
|
|
|
|
|
alternative is a silent evidence gap on the event an attacker most wants
|
|
|
|
|
|
missing, which is worse.
|
|
|
|
|
|
|
2026-08-29 14:50:06 +02:00
|
|
|
|
## GH-DEC-2026-003 — The PEP consumes an approval before the protected side effect
|
|
|
|
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
|
|
id: GH-DEC-2026-003
|
|
|
|
|
|
kind: decision
|
|
|
|
|
|
title: The PEP consumes an approval before the protected side effect
|
2026-08-29 14:51:01 +02:00
|
|
|
|
status: resolved
|
2026-08-29 14:50:06 +02:00
|
|
|
|
owner: Bernd Worsch
|
|
|
|
|
|
repo: gate-house
|
|
|
|
|
|
standard: net-kingdom/canon/standards/security-layer-model_v0.7.md
|
|
|
|
|
|
source_note: docs/contracts/approval-consumption.md
|
|
|
|
|
|
requested_dispositions:
|
|
|
|
|
|
- approved
|
|
|
|
|
|
- revised
|
|
|
|
|
|
- rejected
|
|
|
|
|
|
affects:
|
|
|
|
|
|
- gate-house
|
|
|
|
|
|
- approval-engine
|
|
|
|
|
|
- flex-auth
|
|
|
|
|
|
- secrets-engine
|
|
|
|
|
|
- ops-warden
|
|
|
|
|
|
created: '2026-08-29T12:50:06.944092Z'
|
2026-08-29 14:51:01 +02:00
|
|
|
|
updated: '2026-08-29T12:51:01.355583Z'
|
|
|
|
|
|
rationale: Approved as GH-WP-0002-T06. The PEP consumes by compare-and-swap before
|
|
|
|
|
|
the protected side effect; the PDP never mutates; there is no unconsume. Same request
|
|
|
|
|
|
digest is idempotent success; a different digest against a consumed object is conflict.
|
|
|
|
|
|
This closes the three named races and unblocks APPROVAL-WP-0001-T05 and FLEX-WP-0017-T05.
|
|
|
|
|
|
decided_by: Bernd Worsch
|
|
|
|
|
|
decided_at: '2026-08-29T12:51:01.355583Z'
|
2026-08-29 14:50:06 +02:00
|
|
|
|
```
|
2026-08-29 14:50:58 +02:00
|
|
|
|
|
|
|
|
|
|
## Context
|
|
|
|
|
|
|
|
|
|
|
|
Statute §16 left open who marks an approval consumed, and at what point
|
|
|
|
|
|
relative to the decision. `flex-auth` named three failure modes neither engine
|
|
|
|
|
|
closes alone: an ALLOW never consumed; a double consumption by racing callers;
|
|
|
|
|
|
consumption after a failed action. `approval-engine` performs the mutation
|
|
|
|
|
|
because `access-engine` never mutates, and refused to wire a public consume by
|
|
|
|
|
|
guessing the contract. `APPROVAL-WP-0001-T05` and `FLEX-WP-0017-T05` are wait
|
|
|
|
|
|
on this record.
|
|
|
|
|
|
|
|
|
|
|
|
§9.7.3 forbids inferring consumption from a decision record. That stands. The
|
|
|
|
|
|
same paragraph currently reads as if the action must precede the consume call.
|
|
|
|
|
|
That reading cannot enforce single use: two racing PEPs can both act, and CAS
|
|
|
|
|
|
then prevents only the second record.
|
|
|
|
|
|
|
|
|
|
|
|
## Decision
|
|
|
|
|
|
|
|
|
|
|
|
**The PEP-shaped consumer consumes, by compare-and-swap, before the protected
|
|
|
|
|
|
side effect.** The PDP never mutates. Staff never calls consume.
|
|
|
|
|
|
|
|
|
|
|
|
**There is no unconsume and no reserve/release.** An approval authorizes one
|
|
|
|
|
|
attempt, not one success. A consume followed by a failed action spends the
|
|
|
|
|
|
object; retry is a new approval.
|
|
|
|
|
|
|
|
|
|
|
|
**Same `request_digest` against an already-consumed object is idempotent
|
|
|
|
|
|
success** (a retry of one logical request). A different digest is conflict,
|
|
|
|
|
|
and the PEP MUST NOT act.
|
|
|
|
|
|
|
|
|
|
|
|
The three failure modes have owners:
|
|
|
|
|
|
|
|
|
|
|
|
1. *Allow never consumed* — PEP duty to consume; PDP lifetime bounds the
|
|
|
|
|
|
window; a stale ALLOW without a matching `use` is a finding, not a consume.
|
|
|
|
|
|
2. *Double consumption* — `approval-engine` CAS; the PEP that receives
|
|
|
|
|
|
conflict does not act.
|
|
|
|
|
|
3. *Consumed then the action fails* — accepted as the cost of closing (2).
|
|
|
|
|
|
|
|
|
|
|
|
Protocol: `docs/contracts/approval-consumption.md`. Statute v0.8 will replace
|
|
|
|
|
|
the §9.7.3 implication that action precedes the consume call; until then this
|
|
|
|
|
|
record governs the blocked implementers.
|
|
|
|
|
|
|
|
|
|
|
|
## What this authorizes
|
|
|
|
|
|
|
|
|
|
|
|
- `approval-engine` exposing `POST /v1/approvals/{id}/consume` against this
|
|
|
|
|
|
contract, including the digest column the internal CAS does not yet store.
|
|
|
|
|
|
- `FLEX-WP-0017-T05` requiring the PEP (secrets-engine, for that task) to
|
|
|
|
|
|
consume before the OpenBao call.
|
|
|
|
|
|
- Canon `T-06` consume-side replay (a second, different digest against a
|
|
|
|
|
|
consumed object) becoming in-scope once the endpoint exists.
|
|
|
|
|
|
|
|
|
|
|
|
## What this does not authorize
|
|
|
|
|
|
|
|
|
|
|
|
- The PDP consuming, or inferring consumption from a decision record.
|
|
|
|
|
|
- Unconsume, reserve, or any path that returns a consumed object to `approved`.
|
|
|
|
|
|
- A consume that is a decision ("may this actor do X").
|
|
|
|
|
|
- Any change to another repository's workplans. Work structure stays with the
|
|
|
|
|
|
repository doing the work.
|
|
|
|
|
|
|
|
|
|
|
|
## Reversal
|
|
|
|
|
|
|
|
|
|
|
|
Revert this record and the consumption contract. The falsifier is operational:
|
|
|
|
|
|
if spending an approval on a failed attempt makes the estate unable to
|
|
|
|
|
|
complete the actions this object exists for, a reserve/commit protocol can be
|
|
|
|
|
|
raised then. Unconsume is not the alternative — it reopens replay.
|
2026-09-04 02:59:35 +02:00
|
|
|
|
|
|
|
|
|
|
## GH-DEC-2026-004 — Layer emission-cadence ownership between Info Tech Canon and Net Kingdom
|
|
|
|
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
|
|
id: GH-DEC-2026-004
|
|
|
|
|
|
kind: decision
|
|
|
|
|
|
title: Layer emission-cadence ownership between Info Tech Canon and Net Kingdom
|
|
|
|
|
|
status: resolved
|
|
|
|
|
|
owner: Bernd Worsch
|
|
|
|
|
|
repo: gate-house
|
|
|
|
|
|
standard: net-kingdom/canon/standards/security-layer-model_v0.7.md
|
|
|
|
|
|
source_note: kings-guard/specs/EmissionCadenceDeclaration.md
|
|
|
|
|
|
requested_dispositions:
|
|
|
|
|
|
- approved
|
|
|
|
|
|
- revised
|
|
|
|
|
|
- rejected
|
|
|
|
|
|
affects:
|
|
|
|
|
|
- gate-house
|
|
|
|
|
|
- info-tech-canon
|
|
|
|
|
|
- net-kingdom
|
|
|
|
|
|
- kings-guard
|
|
|
|
|
|
- qonto-assistant
|
|
|
|
|
|
created: '2026-09-04T00:55:29Z'
|
|
|
|
|
|
updated: '2026-09-04T00:55:29Z'
|
|
|
|
|
|
rationale: >-
|
|
|
|
|
|
Approved interactively on 2026-09-04. The layered split gives each artifact
|
|
|
|
|
|
one owner: ecosystem-wide semantics belong to info-tech-canon; NetKingdom-
|
|
|
|
|
|
specific MUST/SHOULD rules and the low-volume load-bearing heartbeat-plus-
|
|
|
|
|
|
reconciliation profile belong to net-kingdom. This avoids both a Staff-local
|
|
|
|
|
|
consumer schema and competing Taxonomy definitions.
|
|
|
|
|
|
decided_by: Bernd Worsch
|
|
|
|
|
|
decided_at: '2026-09-04T00:55:29Z'
|
|
|
|
|
|
state_hub_decision_id: "89c73f45-d07b-40ea-b428-5a7375ce4b09"
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Context
|
|
|
|
|
|
|
|
|
|
|
|
Security-layer-model v0.7 §§9.6 and 17 require evidence sources to declare an
|
|
|
|
|
|
expected emission cadence so silence can become a finding. King's Guard is the
|
|
|
|
|
|
only current consumer and drafted `EmissionCadenceDeclaration.md` against the
|
|
|
|
|
|
real `qonto-assistant` source, but correctly declined to keep a Staff-local
|
|
|
|
|
|
schema. The standard left ownership between the two Taxonomy repositories:
|
|
|
|
|
|
`info-tech-canon` for ecosystem-wide semantic contracts and `net-kingdom` for
|
|
|
|
|
|
NetKingdom standards of record.
|
|
|
|
|
|
|
|
|
|
|
|
Treating that as joint ownership would leave version authority ambiguous.
|
|
|
|
|
|
Giving the entire artifact to either repository would instead conflate a
|
|
|
|
|
|
reusable evidence/observability contract with the security obligations of one
|
|
|
|
|
|
estate. The split is therefore made by artifact, with one owner for each.
|
|
|
|
|
|
|
|
|
|
|
|
## Decision
|
|
|
|
|
|
|
|
|
|
|
|
**`info-tech-canon` owns the versioned, ecosystem-wide
|
|
|
|
|
|
`EmissionCadenceDeclaration` semantic contract.** It owns the generic forms,
|
|
|
|
|
|
fields, vocabulary, validation semantics, compatibility rules, and evolution
|
|
|
|
|
|
of the contract.
|
|
|
|
|
|
|
|
|
|
|
|
**`net-kingdom` imports that contract and owns the NetKingdom security
|
|
|
|
|
|
profile.** It owns which evidence classes MUST or SHOULD declare cadence, the
|
|
|
|
|
|
rule that rate monitoring is forbidden for rare load-bearing classes, and the
|
|
|
|
|
|
heartbeat-plus-reconciliation obligations that satisfy security-layer-model
|
|
|
|
|
|
§9.6.
|
|
|
|
|
|
|
|
|
|
|
|
The remaining ownership boundaries are unchanged:
|
|
|
|
|
|
|
|
|
|
|
|
- each source repository owns its declaration instance and emission behavior;
|
|
|
|
|
|
- `kings-guard` owns stream evaluation and silence findings, not the schema;
|
|
|
|
|
|
- Gate House owns doctrine and conformance supervision, not publication or
|
|
|
|
|
|
runtime behavior.
|
|
|
|
|
|
|
|
|
|
|
|
The King's Guard draft remains the provenance and handover input. Once the
|
|
|
|
|
|
Taxonomy artifacts are published, it becomes historical rather than a second
|
|
|
|
|
|
contract.
|
|
|
|
|
|
|
|
|
|
|
|
## What this authorizes
|
|
|
|
|
|
|
|
|
|
|
|
- Requesting `info-tech-canon` to adopt, revise, or contest the generic
|
|
|
|
|
|
contract and create its own owning work record.
|
|
|
|
|
|
- Requesting `net-kingdom` to adopt, revise, or contest the security profile
|
|
|
|
|
|
and create its own owning work record.
|
|
|
|
|
|
- Sources such as `qonto-assistant`, `approval-engine`, and `secrets-engine`
|
|
|
|
|
|
publishing instances against the eventual canonical contract and profile.
|
|
|
|
|
|
- King's Guard replacing its draft-shaped fixture with the published contract
|
|
|
|
|
|
without changing its consumer ownership.
|
|
|
|
|
|
|
|
|
|
|
|
## What this does not authorize
|
|
|
|
|
|
|
|
|
|
|
|
- Joint ownership or two independently versioned definitions of the generic
|
|
|
|
|
|
schema.
|
|
|
|
|
|
- Gate House or King's Guard retaining the schema as a local contract.
|
|
|
|
|
|
- Gate House creating workplans in either Taxonomy repository.
|
|
|
|
|
|
- Treating ownership as source conformance: `qonto-assistant` remains
|
|
|
|
|
|
incomplete until it publishes and emits the required positive claim.
|
|
|
|
|
|
|
|
|
|
|
|
## Assent and completion
|
|
|
|
|
|
|
|
|
|
|
|
The ownership ruling is resolved. Publication is complete only when both
|
|
|
|
|
|
Taxonomy owners reply in their own voice and publish or explicitly schedule
|
|
|
|
|
|
their respective artifacts. Until then the prior handover residual remains
|
|
|
|
|
|
open, now with an unambiguous requested disposition.
|
|
|
|
|
|
|
|
|
|
|
|
## Reversal
|
|
|
|
|
|
|
|
|
|
|
|
Supersede this record if the generic contract proves inseparable from the
|
|
|
|
|
|
NetKingdom security profile, or if Info Tech Canon cannot provide a stable
|
|
|
|
|
|
cross-domain contract boundary. Reversal must still name one owner for every
|
|
|
|
|
|
artifact; returning to undifferentiated "Taxonomy ownership" is not an
|
|
|
|
|
|
acceptable outcome.
|
2026-09-06 01:28:23 +02:00
|
|
|
|
|
|
|
|
|
|
## GH-DEC-2026-005 — The approval-claim is the step-1 artifact on the PEP consumption path
|
|
|
|
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
|
|
id: GH-DEC-2026-005
|
|
|
|
|
|
kind: decision
|
|
|
|
|
|
title: The approval-claim is the step-1 artifact on the PEP consumption path
|
|
|
|
|
|
status: resolved
|
|
|
|
|
|
owner: Bernd Worsch
|
|
|
|
|
|
repo: gate-house
|
|
|
|
|
|
standard: net-kingdom/canon/standards/security-layer-model_v0.7.md
|
|
|
|
|
|
source_note: docs/contracts/approval-consumption.md
|
|
|
|
|
|
origin: GH-IN-0002
|
|
|
|
|
|
requested_dispositions:
|
|
|
|
|
|
- approved
|
|
|
|
|
|
- revised
|
|
|
|
|
|
- rejected
|
|
|
|
|
|
affects:
|
|
|
|
|
|
- gate-house
|
|
|
|
|
|
- approval-engine
|
|
|
|
|
|
- flex-auth
|
|
|
|
|
|
- secrets-engine
|
|
|
|
|
|
- ops-warden
|
|
|
|
|
|
rationale: 'Confirmed, with one addition. GH-DEC-2026-003 already named step 1 by
|
|
|
|
|
|
endpoint and by field; the approval-claim is what that endpoint serves and valid_now
|
|
|
|
|
|
is its field. ActionAuthorization is a proposed, unratified shape carrying no doctrine
|
|
|
|
|
|
standing here. The addition is that the split validation is stated as doctrine rather
|
|
|
|
|
|
than left implicit: each artifact is checked by the consumer against the layer that
|
|
|
|
|
|
owns its data, and no PIP republishes a PDP decision. The state-hub authority requirement
|
|
|
|
|
|
in the secrets-engine validator is struck because State Hub is a read model and
|
|
|
|
|
|
holds no runtime approval authority.'
|
|
|
|
|
|
decided_by: Bernd Worsch
|
2026-09-06 09:30:42 +02:00
|
|
|
|
state_hub_decision_id: "b606e8ce-f1fa-4b39-bfe9-c11e88a3cde6"
|
2026-09-06 01:28:23 +02:00
|
|
|
|
created: '2026-09-05T23:28:23.931441Z'
|
|
|
|
|
|
updated: '2026-09-05T23:28:23.931441Z'
|
|
|
|
|
|
```
|
2026-09-06 01:29:28 +02:00
|
|
|
|
|
|
|
|
|
|
## Context
|
|
|
|
|
|
|
|
|
|
|
|
`GH-DEC-2026-003` settled the consumption sequence and named step 1 by endpoint and
|
|
|
|
|
|
by field: `GET /v1/approvals/{id}/claim` → `valid_now` (a fact, not permission).
|
|
|
|
|
|
`approval-engine` serves the approval-claim at that endpoint
|
|
|
|
|
|
(`approval-engine/docs/approval-claim.md`). `secrets-engine`'s PEP validator
|
|
|
|
|
|
(`validate_action_authorization`, `src/secrets_engine/authorization.py`) calls the
|
|
|
|
|
|
same endpoint but expects a flex-auth `ActionAuthorization`. Two different objects
|
|
|
|
|
|
were being assumed on one path, and the divergence would have surfaced at first live
|
|
|
|
|
|
consume rather than at deployment.
|
|
|
|
|
|
|
|
|
|
|
|
`ActionAuthorization` originates in `flex-auth/docs/action-bound-authorization-contract.md`
|
|
|
|
|
|
as a proposed shape for durable approval storage that the same document assigns to
|
|
|
|
|
|
`approval-engine`. It was never ratified, appears nowhere in this repository's
|
|
|
|
|
|
doctrine, and has no `valid_now` field. `GH-DEC-2026-003` was issued after it without
|
|
|
|
|
|
reference to it. There is therefore nothing to reconcile: the claim was the step-1
|
|
|
|
|
|
artifact all along, and this record says so where implementers will find it.
|
|
|
|
|
|
|
|
|
|
|
|
`approval-engine` raised the question rather than guessing, which is the behaviour
|
|
|
|
|
|
§12 asks for. The three substantive assertions in the request were checked here
|
|
|
|
|
|
independently before confirmation.
|
|
|
|
|
|
|
|
|
|
|
|
## Decision
|
|
|
|
|
|
|
|
|
|
|
|
**1. The approval-claim is the step-1 artifact on the `GH-DEC-2026-003` path.**
|
|
|
|
|
|
It carries the approval fact: binding digest, validity window, consumption state,
|
|
|
|
|
|
observation freshness, and issuer. Holding one with `valid_now: true` remains not
|
|
|
|
|
|
authority to act.
|
|
|
|
|
|
|
|
|
|
|
|
**2. `ActionAuthorization` is not required on that path.** `approval-engine` is not
|
|
|
|
|
|
expected to serve it and MUST NOT serve it from the claim endpoint. A step-1 response
|
|
|
|
|
|
cannot contain a step-2 decision; any composed post-decision artifact would be a new
|
|
|
|
|
|
artifact at a new endpoint. The proposal is shelved on this path, not withdrawn.
|
|
|
|
|
|
|
|
|
|
|
|
**3. A PEP validates across the two artifacts it already fetches.** The claim is
|
|
|
|
|
|
checked for the approval fact; the flex-auth `DecisionEnvelope` from step 2 is checked
|
|
|
|
|
|
for exact `CheckRequest` match and policy package/version pin. This is doctrine, not
|
|
|
|
|
|
merely an implementation convenience: **each artifact is validated against the layer
|
|
|
|
|
|
that owns its data.** A PIP republishing the PDP's decision would put a copy of the
|
|
|
|
|
|
authority decision in a repository that did not render it — the same shape of error
|
|
|
|
|
|
the re-cut removed from Gate House itself. No safety property is lost, because
|
|
|
|
|
|
`ActionAuthorization` is a bundle of exactly these two checks.
|
|
|
|
|
|
|
|
|
|
|
|
**4. The `provenance.authority == "state-hub"` requirement is struck.** State Hub is
|
|
|
|
|
|
a read model. It is not the runtime approval authority and never was; flex-auth's own
|
|
|
|
|
|
contract says so. A validator that requires it would fail closed against every
|
|
|
|
|
|
correctly issued claim. `secrets-engine` removes the constant with the validator split.
|
|
|
|
|
|
|
|
|
|
|
|
Consequent changes: `approval-engine` none — the claim schema stands as published;
|
|
|
|
|
|
`secrets-engine` splits its validator and drops the authority constant; `flex-auth`
|
|
|
|
|
|
records that the proposal is shelved on this path. Nothing here gates
|
|
|
|
|
|
`APPROVAL-WP-0002-T03` — `secrets-engine` is fail-closed until its own gates land,
|
|
|
|
|
|
and this record governs first live consume, not deployment.
|
|
|
|
|
|
|
|
|
|
|
|
## Deferred
|
|
|
|
|
|
|
|
|
|
|
|
A ratified post-decision `ActionAuthorization` — one composed, signed, forwardable
|
|
|
|
|
|
object — remains coherent and is recorded here so it is not rediscovered as new. It
|
|
|
|
|
|
is not adopted now because it has no named issuer or lifecycle owner and the sequence
|
|
|
|
|
|
is already settled without one. Revisit on any of: a third or fourth PEP-shaped
|
|
|
|
|
|
consumer; a requirement for a single signed forwardable artifact (offline
|
2026-09-06 08:05:01 +02:00
|
|
|
|
verification, or an audit that must replay one object rather than a join);
|
|
|
|
|
|
~~resolution of flex-auth's open G3 finding by composition rather than by adding a
|
|
|
|
|
|
lifetime to the envelope~~ — **struck, see the amendment below**; or assent of the
|
|
|
|
|
|
statute §17 Taxonomy request-claim schema
|
2026-09-06 01:29:28 +02:00
|
|
|
|
(`APPROVAL-IN-0001`) — in which case converge there and do **not** revive this
|
|
|
|
|
|
separately.
|
|
|
|
|
|
|
|
|
|
|
|
Also rejected, so they are not re-proposed: serving `ActionAuthorization` at the claim
|
|
|
|
|
|
endpoint (structurally impossible for step 1, and it would assert an authority
|
|
|
|
|
|
`approval-engine` does not hold); and extending the claim with `approvals.required_count`
|
|
|
|
|
|
or `entries` (publishing approver identities is a deliberate least-disclosure non-goal,
|
|
|
|
|
|
and it would still not satisfy the validator).
|
|
|
|
|
|
|
2026-09-06 08:05:01 +02:00
|
|
|
|
### Amendment, 2026-09-06 — the G3 trigger is struck
|
|
|
|
|
|
|
|
|
|
|
|
Recorded the day after this decision, on corrections volunteered independently by
|
|
|
|
|
|
`approval-engine` and `access-engine`, and verified here against
|
|
|
|
|
|
`flex-auth/schemas/decision_envelope.schema.json`.
|
|
|
|
|
|
|
|
|
|
|
|
`FLEX-WP-0019` closed G3 on 2026-09-02 by **adding** the field: the schema requires
|
|
|
|
|
|
`lifetime` whenever `effect` is `allow`, sourced from the policy package's
|
|
|
|
|
|
`allow_ttl` with a 15-minute engine default, and `allow_ttl: none` renders a DENY
|
|
|
|
|
|
with reason `allow_lifetime_unstated` rather than a standing grant.
|
|
|
|
|
|
|
|
|
|
|
|
The trigger was therefore already spent when this decision was written, and it
|
|
|
|
|
|
resolved on the branch that removes the argument rather than the one that supports
|
|
|
|
|
|
it. This is not bookkeeping. Carrying its own end was the one structural thing the
|
|
|
|
|
|
composed bundle did that the split does not, so the strongest available case for
|
|
|
|
|
|
ratifying option D is not merely unspent — **it is answered, and the answer is no.**
|
|
|
|
|
|
A `DecisionEnvelope` now states its own lifetime without borrowing an
|
|
|
|
|
|
`ActionAuthorizationValidity`.
|
|
|
|
|
|
|
|
|
|
|
|
Three revisit triggers remain: a third or fourth PEP-shaped consumer; a requirement
|
|
|
|
|
|
for a single signed forwardable artifact; and assent of the §17 request-claim schema,
|
|
|
|
|
|
where the instruction is to converge rather than revive.
|
|
|
|
|
|
|
|
|
|
|
|
The error came from sourcing the trigger from a 2026-08-29 alignment record rather
|
|
|
|
|
|
than from current state — the same class of mistake as reading a change log for what
|
|
|
|
|
|
the body says, which the v0.6 findings audit hit on the same day
|
|
|
|
|
|
(`docs/conformance/2026-09-06-v06-findings-audit.md`). Both repositories reported it
|
|
|
|
|
|
against their own interest, which is why it was caught within a day.
|
|
|
|
|
|
|
|
|
|
|
|
### Stated consequence, 2026-09-06 — what the PEP stopped checking
|
|
|
|
|
|
|
|
|
|
|
|
Raised by `secrets-engine` on implementing the split, against its own position, and
|
|
|
|
|
|
recorded here rather than left in a commit message.
|
|
|
|
|
|
|
|
|
|
|
|
The distinct-approver threshold is no longer verified independently at the PEP. The
|
|
|
|
|
|
claim exposes no approver entries — publishing approver identities is the deliberate
|
|
|
|
|
|
least-disclosure non-goal this decision upheld — so `approval-engine` folds the
|
|
|
|
|
|
threshold into `valid_now`. That is the correct layer under this doctrine and it is
|
|
|
|
|
|
also **a genuine reduction in what the PEP checks on its own**, and the second thing
|
|
|
|
|
|
does not stop being true because the first one is.
|
|
|
|
|
|
|
|
|
|
|
|
The estate should hold this consciously. `valid_now` is a summary predicate, and a
|
|
|
|
|
|
consumer of a summary trusts the issuer's evaluation of everything folded into it.
|
|
|
|
|
|
The compensating property is not a second check at the PEP — that is the duplication
|
|
|
|
|
|
the split removes — but reconstructability at the issuer: `approval-engine`'s state
|
|
|
|
|
|
transitions and its `use` outbox row must make the threshold evaluation recoverable
|
|
|
|
|
|
after the fact under §9.6. Detection, not prevention, and it should be named as such
|
|
|
|
|
|
in the same register as §9.6's other residual.
|
|
|
|
|
|
|
|
|
|
|
|
A second consequence, also from `secrets-engine` and also correct: two digests now
|
|
|
|
|
|
cover the same proposed action and are never compared — `approval-engine`'s binding
|
|
|
|
|
|
digest over `{action, actor, principal, purpose, target}` and the flex-auth
|
|
|
|
|
|
`CheckRequest` digest, with `claim.binding.pdp_digest` preferred where the issuer
|
|
|
|
|
|
recorded one. They answer different questions at different layers and collapsing them
|
|
|
|
|
|
would be a layer violation wearing the costume of a refactor. `secrets-engine` holds
|
|
|
|
|
|
a test asserting the two functions disagree, which is the right way to defend a
|
|
|
|
|
|
distinction that looks like duplication.
|
|
|
|
|
|
|
2026-09-06 09:30:42 +02:00
|
|
|
|
**Narrowed, 2026-09-06, by `approval-engine` on implementing the §9.6 obligation.**
|
|
|
|
|
|
The framing above was too broad. `entries` is UNIQUE on `(approval_id, subject_id)`,
|
|
|
|
|
|
so a repeat approver is refused at insert: distinctness is a **storage invariant** in
|
|
|
|
|
|
that engine, not something a consumer or an auditor recomputes. What the PEP stopped
|
|
|
|
|
|
checking is therefore that *this engine applied its own invariant correctly* — not
|
|
|
|
|
|
whether dual control could be forged by a repeated signature, which the schema
|
|
|
|
|
|
forecloses. The reduction is real and it is narrower than "the threshold is now
|
|
|
|
|
|
unverified". `approval-engine` found this by writing a test that expected duplicate
|
|
|
|
|
|
entries to collapse to one distinct approver, watching it fail, and reporting the
|
|
|
|
|
|
result against its own earlier framing; it also dropped an `entry_count` field rather
|
|
|
|
|
|
than ship a number that by construction can never differ from the distinct count.
|
|
|
|
|
|
|
|
|
|
|
|
The compensating property is now implemented rather than asserted: `approval.issuance`
|
|
|
|
|
|
and `approval.use` both carry a `threshold` object — `required_count`,
|
|
|
|
|
|
`distinct_approver_count`, `threshold_met`, and approver `subject_id`, `approved_at`
|
|
|
|
|
|
and evidence reference — with tests asserting reconstruction from the `use` row
|
|
|
|
|
|
**alone**, performing the recomputation an auditor would. The disclosure boundary is
|
|
|
|
|
|
pinned by test: identities are on the outbox, never on the claim. The evidence path
|
|
|
|
|
|
carries them because that is what audit is for; the consumer-facing artifact discloses
|
|
|
|
|
|
the least it can. The split did not push identities to consumers by another route.
|
|
|
|
|
|
|
|
|
|
|
|
**Hub row provenance.** `approval-engine`'s `fix-consistency` C-32 check registered
|
|
|
|
|
|
the drafted record block in its own request document as a hub decision
|
|
|
|
|
|
(`b606e8ce-f1fa-4b39-bfe9-c11e88a3cde6`), which it then resolved rather than leave an
|
|
|
|
|
|
open row for a settled question. Gate House **adopts that row as canonical** and
|
|
|
|
|
|
records its id above, rather than registering a second one — the row's content is
|
|
|
|
|
|
correct and a duplicate would be worse than an imperfectly-provenanced single row. A
|
|
|
|
|
|
drafted decision block inside a requesting repository's document is machine-readable
|
|
|
|
|
|
to that repository's own consistency checks, which is a trap in this workflow; the
|
|
|
|
|
|
disposition is recorded here so the next request does not rediscover it.
|
|
|
|
|
|
|
2026-09-06 01:29:28 +02:00
|
|
|
|
## Reversal
|
|
|
|
|
|
|
|
|
|
|
|
Revert this record and the amendment to `docs/contracts/approval-consumption.md`. The
|
|
|
|
|
|
falsifier is a demonstrated check that two-artifact validation cannot perform and a
|
|
|
|
|
|
single composed artifact can — most plausibly offline or forwarded verification with
|
|
|
|
|
|
no access to the PDP. That is a trigger for the deferred option above, not for
|
|
|
|
|
|
returning `ActionAuthorization` to the claim endpoint, which stays forbidden on
|
|
|
|
|
|
structural grounds regardless.
|
2026-09-06 01:38:49 +02:00
|
|
|
|
|
|
|
|
|
|
## GH-DEC-2026-006 — The §13 registers become pointers only once maturity-engine publishes a readable export
|
|
|
|
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
|
|
id: GH-DEC-2026-006
|
|
|
|
|
|
kind: decision
|
|
|
|
|
|
title: The §13 registers become pointers only once maturity-engine publishes a readable
|
|
|
|
|
|
export
|
|
|
|
|
|
status: resolved
|
|
|
|
|
|
owner: Bernd Worsch
|
|
|
|
|
|
repo: gate-house
|
|
|
|
|
|
standard: net-kingdom/canon/standards/security-layer-model_v0.7.md
|
|
|
|
|
|
source_note: workplans/GH-WP-0003-statute-v08-amendment-set.md (T03)
|
|
|
|
|
|
requested_dispositions:
|
|
|
|
|
|
- approved
|
|
|
|
|
|
- revised
|
|
|
|
|
|
- rejected
|
|
|
|
|
|
affects:
|
|
|
|
|
|
- gate-house
|
|
|
|
|
|
- net-kingdom
|
|
|
|
|
|
- maturity-engine
|
|
|
|
|
|
- ops-warden
|
|
|
|
|
|
- ops-mason
|
|
|
|
|
|
- user-engine
|
|
|
|
|
|
- tenant-engine
|
|
|
|
|
|
- access-engine
|
|
|
|
|
|
rationale: 'A statute of record should not carry state, and §13 and §13.1 are state:
|
|
|
|
|
|
they change without the doctrine changing, and a hand-maintained table inside a
|
|
|
|
|
|
standard is a register that drifts. maturity-engine is the right holder. But a pointer
|
|
|
|
|
|
is only an improvement once there is something readable to point at — a standard
|
|
|
|
|
|
that can only be understood by querying a live engine has traded one defect for
|
|
|
|
|
|
a worse one, and it would make the statute unreadable to exactly the auditor it
|
|
|
|
|
|
exists for. The migration is therefore conditioned on a committed, versioned export
|
|
|
|
|
|
rather than declared outright. Until that export exists the tables stay and rows
|
|
|
|
|
|
are transcribed, so no repository is left without an answer while the condition
|
|
|
|
|
|
is outstanding.'
|
|
|
|
|
|
decided_by: Bernd Worsch
|
|
|
|
|
|
created: '2026-09-05T23:38:49.777532Z'
|
|
|
|
|
|
updated: '2026-09-05T23:38:49.777532Z'
|
|
|
|
|
|
```
|
2026-09-06 08:02:05 +02:00
|
|
|
|
|
|
|
|
|
|
## Context
|
|
|
|
|
|
|
|
|
|
|
|
`security-layer-model` v0.7 §13 holds the open-gap register and §13.1 the PEP
|
|
|
|
|
|
stance-map register. Both were created because the obligations above them named a
|
|
|
|
|
|
register that did not exist — §9.1's own logic, that a requirement whose register is
|
|
|
|
|
|
missing is a capability catalogued without a surface. They did their job.
|
|
|
|
|
|
|
|
|
|
|
|
`maturity-engine` (MAT-WP-0001) now holds both as queryable data: the §13 snapshot
|
|
|
|
|
|
with state and owner-status intact, the §13.1 inventory, `ASM-0`…`ASM-6` registered
|
|
|
|
|
|
as data owned by gate-house, `pep-stance-publication` owned by ops-warden, and
|
|
|
|
|
|
blocked-clean scored equal to conforming by test. It proposes that the statute table
|
|
|
|
|
|
become a pointer.
|
|
|
|
|
|
|
|
|
|
|
|
Four repositories are waiting behind the answer. `user-engine` and `tenant-engine`
|
|
|
|
|
|
have published stance maps and asked for §13.1 rows; ops-warden is published and
|
|
|
|
|
|
ops-mason is not. §6.4 obliges every PEP-shaped consumer to publish and obliges those
|
|
|
|
|
|
maps to be inventoried. Each week the question stays open, the register either
|
|
|
|
|
|
accumulates transcription or accumulates silence.
|
|
|
|
|
|
|
|
|
|
|
|
## Decision
|
|
|
|
|
|
|
|
|
|
|
|
**§13 and §13.1 become pointers to `maturity-engine`, and not before it publishes a
|
|
|
|
|
|
committed, versioned export of both registers that is readable without a live query.**
|
|
|
|
|
|
|
|
|
|
|
|
Two things are true at once and the ruling holds both.
|
|
|
|
|
|
|
|
|
|
|
|
**A statute should not carry state.** §13 and §13.1 change without the doctrine
|
|
|
|
|
|
changing. A table maintained by hand inside a standard of record drifts, and every
|
|
|
|
|
|
row transcribed into it is the manual step `maturity-engine` exists to remove. This
|
|
|
|
|
|
is the same rule as `GH-DEC-2026-005`: the artifact is held by the layer that owns
|
|
|
|
|
|
its data, and a repository that neither computes nor owns a fact should not be its
|
|
|
|
|
|
register of record.
|
|
|
|
|
|
|
|
|
|
|
|
**A standard must be readable on its own.** A pointer to a live engine is not a
|
|
|
|
|
|
register an auditor can read; it is an instruction to run software. Whatever else the
|
|
|
|
|
|
statute is, it must be legible in git, at a version, to a reader with no cluster
|
|
|
|
|
|
access — including a reader auditing the estate precisely because they do not trust
|
|
|
|
|
|
its running systems. Replacing a drifting table with an unreadable reference trades a
|
|
|
|
|
|
known defect for a worse one.
|
|
|
|
|
|
|
|
|
|
|
|
The condition reconciles them. `maturity-engine` computes and remembers; it also
|
|
|
|
|
|
publishes the result as a committed artifact at a stated path and version, and the
|
|
|
|
|
|
statute cites that path. The rows are then computed rather than transcribed, and
|
|
|
|
|
|
still readable without a query. **Publication is the migration's precondition, not
|
|
|
|
|
|
its follow-up.**
|
|
|
|
|
|
|
|
|
|
|
|
### What happens meanwhile
|
|
|
|
|
|
|
|
|
|
|
|
The tables stay, and rows continue to be transcribed into §13.1 at each version cut.
|
|
|
|
|
|
No repository waits on the export to get an answer. `user-engine`, `tenant-engine`,
|
|
|
|
|
|
ops-warden and ops-mason are inventoried in v0.8 whether or not the export has
|
|
|
|
|
|
landed by then.
|
|
|
|
|
|
|
|
|
|
|
|
This is deliberately the slower path. The alternative — strike the tables now and
|
|
|
|
|
|
point at the engine — would close four open requests immediately and leave the
|
|
|
|
|
|
statute stating an obligation whose register no reader can open, which is the exact
|
|
|
|
|
|
defect §13.1 was created to fix. Repeating a defect in the other direction is not
|
|
|
|
|
|
progress.
|
|
|
|
|
|
|
|
|
|
|
|
### What is asked of `maturity-engine`
|
|
|
|
|
|
|
|
|
|
|
|
Not a new capability, a published form of one it has. The export must be a file in
|
|
|
|
|
|
the repository, versioned, generated rather than hand-edited, carrying the same
|
|
|
|
|
|
fields the statute tables carry today (§13: capability, kind, declarer, owner, state,
|
|
|
|
|
|
owner-status; §13.1: consumer, stance map path, shape), and regenerable so drift
|
|
|
|
|
|
between the export and the engine's own state is detectable. `layer.yaml` and
|
|
|
|
|
|
`pep-stance.yaml` are the shape to follow: published, machine-readable, and asserted
|
|
|
|
|
|
equal to shipped behaviour by a test. §6.4 obligation 3 already requires that
|
|
|
|
|
|
equality of every PEP; a register of those maps should not hold itself to less.
|
|
|
|
|
|
|
|
|
|
|
|
When it exists, the §13 and §13.1 tables are replaced by a citation of it, and
|
|
|
|
|
|
`maturity-engine` becomes the register of record.
|
|
|
|
|
|
|
|
|
|
|
|
## Reversal
|
|
|
|
|
|
|
|
|
|
|
|
Revert to tables if the export proves to drift from the engine's computed state
|
|
|
|
|
|
faster than a hand-maintained table drifted from reality — that is, if generation and
|
|
|
|
|
|
publication decouple. The falsifier is mechanical: a regeneration that changes the
|
|
|
|
|
|
committed export without any underlying evidence having changed, or an underlying
|
|
|
|
|
|
change that does not reach the export.
|
2026-09-06 08:07:34 +02:00
|
|
|
|
|
|
|
|
|
|
## GH-DEC-2026-007 — The posture/maturity boundary is recomputability, bounded by a criteria-grounding rule
|
|
|
|
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
|
|
id: GH-DEC-2026-007
|
|
|
|
|
|
kind: decision
|
|
|
|
|
|
title: The posture/maturity boundary is recomputability, bounded by a criteria-grounding
|
|
|
|
|
|
rule
|
|
|
|
|
|
status: resolved
|
|
|
|
|
|
owner: Bernd Worsch
|
|
|
|
|
|
repo: gate-house
|
|
|
|
|
|
standard: net-kingdom/canon/standards/security-layer-model_v0.7.md
|
|
|
|
|
|
source_note: kings-guard/docs/PostureMaturityBoundary.md (KG-DEC-2026-002, KG-COM-0001)
|
|
|
|
|
|
requested_dispositions:
|
|
|
|
|
|
- approved
|
|
|
|
|
|
- revised
|
|
|
|
|
|
- rejected
|
|
|
|
|
|
affects:
|
|
|
|
|
|
- gate-house
|
|
|
|
|
|
- net-kingdom
|
|
|
|
|
|
- kings-guard
|
|
|
|
|
|
- maturity-engine
|
|
|
|
|
|
- access-engine
|
|
|
|
|
|
rationale: 'Adopted with one addition. kings-guard is right that volatility describes
|
|
|
|
|
|
the two categories without partitioning them, and right that the discriminator is
|
|
|
|
|
|
already in §9.5''s determinism clause rather than being a new rule. The addition
|
|
|
|
|
|
closes the loophole the test leaves open: recomputability is assessed over the stated
|
|
|
|
|
|
criteria, so any judgment can be made to look recomputable by writing a criterion
|
|
|
|
|
|
that dereferences it. Criteria must bottom out in evidence about the subject, not
|
|
|
|
|
|
in another party''s opinion recorded as evidence. Without that clause the test is
|
|
|
|
|
|
satisfiable in form by exactly the inference it exists to exclude.'
|
|
|
|
|
|
decided_by: Bernd Worsch
|
|
|
|
|
|
created: '2026-09-06T06:07:34.017316Z'
|
|
|
|
|
|
updated: '2026-09-06T06:07:34.017316Z'
|
|
|
|
|
|
```
|
2026-09-06 08:08:32 +02:00
|
|
|
|
|
|
|
|
|
|
## Context
|
|
|
|
|
|
|
|
|
|
|
|
`GH-WP-0003-T04`. v0.7 §9.5 states the maturity half of the boundary — *"Given the
|
|
|
|
|
|
same criteria and the same evidence it MUST return the same level; that determinism
|
|
|
|
|
|
is what makes it an Engine rather than an opinion"*, and *"A criterion that cannot be
|
|
|
|
|
|
evaluated by rule is not yet a criterion."* It does not state the posture half.
|
|
|
|
|
|
|
|
|
|
|
|
Gate House had proposed drawing the line on volatility: posture is fast-moving,
|
|
|
|
|
|
maturity is slow. `kings-guard` answered `KG-IN-0003` with a proposed revision
|
|
|
|
|
|
(`KG-DEC-2026-002`, argued in `kings-guard/docs/PostureMaturityBoundary.md`) rejecting
|
|
|
|
|
|
that line and offering recomputability instead. The commentary was also sent to
|
|
|
|
|
|
`maturity-engine`.
|
|
|
|
|
|
|
|
|
|
|
|
The concern behind the original question stands and is why the line has to be exact:
|
|
|
|
|
|
a second grading authority would be the same shape of mistake as a second decision
|
|
|
|
|
|
point, and §6 says it would arrive the same way — gradually, each time for a good
|
|
|
|
|
|
local reason.
|
|
|
|
|
|
|
|
|
|
|
|
## Decision
|
|
|
|
|
|
|
|
|
|
|
|
**The boundary is recomputability, not volatility.**
|
|
|
|
|
|
|
|
|
|
|
|
> Given the same criteria and the same evidence, recompute. If you MUST get the same
|
|
|
|
|
|
> answer, it is maturity and it belongs in an engine. If you CANNOT promise the same
|
|
|
|
|
|
> answer, it is posture and it belongs in Staff.
|
|
|
|
|
|
|
|
|
|
|
|
The volatility line is withdrawn. `kings-guard`'s argument against it is accepted in
|
|
|
|
|
|
full: volatility is an observation about how a value has behaved, not a definition of
|
|
|
|
|
|
what it is. It fails at both edges — a maturity criterion moves fast when evidence
|
|
|
|
|
|
lands in a burst, and a posture sits unchanged for months on a healthy subject — and,
|
|
|
|
|
|
more seriously, it *describes* the two categories without *partitioning* them. Every
|
|
|
|
|
|
case it does not obviously cover becomes an argument, and arguments at a boundary are
|
|
|
|
|
|
the mechanism §6 exists to prevent.
|
|
|
|
|
|
|
|
|
|
|
|
Recomputability is not a new rule. It is §9.5's own determinism clause pointed at the
|
|
|
|
|
|
one boundary where it had not been pointed, which is why it can be adopted without
|
|
|
|
|
|
enlarging the standard. §9.5 already states the maturity half; the posture half is its
|
|
|
|
|
|
mirror, and the pair partitions: **a criterion that cannot be evaluated by rule is not
|
|
|
|
|
|
yet a criterion; a judgment that can be evaluated by rule is not posture — it is a
|
|
|
|
|
|
criterion sitting in the wrong repository.**
|
|
|
|
|
|
|
|
|
|
|
|
### The addition — criteria must be grounded
|
|
|
|
|
|
|
|
|
|
|
|
Adopted with one clause `kings-guard` did not propose, and the reason is the loophole
|
|
|
|
|
|
their own framing opens.
|
|
|
|
|
|
|
|
|
|
|
|
Recomputability is assessed **over the stated criteria**. That makes it mechanical,
|
|
|
|
|
|
which is its virtue, and it also makes it satisfiable in form by the thing it exists
|
|
|
|
|
|
to exclude. Any judgment can be made to look recomputable by writing a criterion that
|
|
|
|
|
|
dereferences it: *"level 2 iff the reviewer marked the control adequate"* is perfectly
|
|
|
|
|
|
deterministic — recompute it and you get the same answer every time — and it has
|
|
|
|
|
|
smuggled an opinion into an engine wearing a rule's clothes. The engine would then be
|
|
|
|
|
|
grading, deterministically, on someone's judgment, which is precisely the second
|
|
|
|
|
|
grading authority the boundary is drawn to prevent.
|
|
|
|
|
|
|
|
|
|
|
|
Therefore:
|
|
|
|
|
|
|
|
|
|
|
|
> **A criterion MUST bottom out in evidence about the subject, not in another party's
|
|
|
|
|
|
> conclusion about the subject.** A recorded judgment may be evidence *that the
|
|
|
|
|
|
> judgment was made* — a fact with an issuer and a timestamp. It MUST NOT be evidence
|
|
|
|
|
|
> *that the thing judged is so*.
|
|
|
|
|
|
|
|
|
|
|
|
This is the same distinction §9.6 draws between what an archive proves and what it is
|
|
|
|
|
|
read as proving, and the same one this repository applies to `valid_now` in
|
|
|
|
|
|
`GH-DEC-2026-005`: a summary predicate is a fact about the issuer's evaluation, not a
|
|
|
|
|
|
substitute for the evaluation. Without the clause the test is mechanical and
|
|
|
|
|
|
circumventable; with it, the test is mechanical and the circumvention is itself
|
|
|
|
|
|
checkable.
|
|
|
|
|
|
|
|
|
|
|
|
### Consequences carried
|
|
|
|
|
|
|
|
|
|
|
|
The three `kings-guard` names are adopted as stated.
|
|
|
|
|
|
|
|
|
|
|
|
1. **The migration direction is permanent.** Anything called posture that turns out to
|
|
|
|
|
|
be recomputable moves to `maturity-engine` as a criterion; anything in
|
|
|
|
|
|
`maturity-engine` that needs judgment is not yet a criterion and moves back to
|
|
|
|
|
|
Staff. The boundary maintains itself under change because the test applies to each
|
|
|
|
|
|
item rather than to the category.
|
|
|
|
|
|
2. **Two authorities cannot grade the same subject property**, because a property is
|
|
|
|
|
|
either recomputable or it is not, and that fact does not depend on which repository
|
|
|
|
|
|
claims it. The failure becomes structurally prevented rather than conventionally
|
|
|
|
|
|
avoided.
|
|
|
|
|
|
3. **Capability readiness MUST NOT be an input to posture.** Readiness is
|
|
|
|
|
|
deterministic; posture is not; feeding one into the other would make posture partly
|
|
|
|
|
|
recomputable and blur the boundary from the `kings-guard` side. Volunteered by
|
|
|
|
|
|
`kings-guard` as a constraint on itself and accepted as normative.
|
|
|
|
|
|
|
|
|
|
|
|
Consequence 3 also answers the second half of `KG-IN-0003`: tracking kings-guard's
|
|
|
|
|
|
own gaps in `maturity-engine` creates no incident-time dependency, because posture
|
|
|
|
|
|
evaluation never consults readiness. The dependency would exist only if the mistake
|
|
|
|
|
|
consequence 3 forbids had already been made.
|
|
|
|
|
|
|
|
|
|
|
|
### The limit is recorded, not resolved
|
|
|
|
|
|
|
|
|
|
|
|
`kings-guard` flagged, against its own proposal, that *"the same evidence"* is not
|
|
|
|
|
|
well defined anywhere in the estate, so until §17's request-claim and gap-record
|
|
|
|
|
|
schemas exist, recomputability is a thought experiment rather than a check. That is
|
|
|
|
|
|
recorded in the statute alongside the test rather than left in the commentary. A
|
|
|
|
|
|
boundary that is correct but not yet mechanically checkable does beat one that is
|
|
|
|
|
|
checkable and wrong — but a reader is entitled to know which of the two they are
|
|
|
|
|
|
holding. It makes §17 load-bearing for this rule.
|
|
|
|
|
|
|
|
|
|
|
|
The caution is also recorded: *"posture"* has the drift profile *"control plane"* had
|
|
|
|
|
|
— it sounds specific and quietly absorbs whatever sits next to it. §8 exists because
|
|
|
|
|
|
the estate has been bitten by exactly that, and this repository described itself as a
|
|
|
|
|
|
control plane before the re-cut. The recomputability test is a defence against that
|
|
|
|
|
|
drift because it can be applied to a candidate *before* the word is stretched to cover
|
|
|
|
|
|
it. `kings-guard` asked to be held to it rather than trusted about it, and that is the
|
|
|
|
|
|
standing it gets.
|
|
|
|
|
|
|
|
|
|
|
|
No change to §8's three-way split and no §4 catalog change. Posture stays
|
|
|
|
|
|
non-deterministic and stays Staff; the test explains why, which is what was missing.
|
|
|
|
|
|
|
|
|
|
|
|
## Reversal
|
|
|
|
|
|
|
|
|
|
|
|
Revert if the grounding clause proves to exclude criteria the estate needs — that is,
|
|
|
|
|
|
if a legitimate maturity criterion cannot be expressed without dereferencing a
|
|
|
|
|
|
judgment. The falsifier is a concrete criterion, not an argument that one might exist.
|
|
|
|
|
|
The likely candidates are human-attested controls (a policy was reviewed, a drill was
|
|
|
|
|
|
run); the expected resolution is that the *attestation event* is the evidence and the
|
|
|
|
|
|
criterion grades on its existence, freshness, and issuer rather than on its verdict.
|
|
|
|
|
|
If that resolution does not hold for some real criterion, this clause is wrong.
|
2026-09-06 09:30:42 +02:00
|
|
|
|
|
|
|
|
|
|
## GH-DEC-2026-008 — The PDP digest is the binding correspondence; no cross-engine vocabulary mapping is published
|
|
|
|
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
|
|
id: GH-DEC-2026-008
|
|
|
|
|
|
kind: decision
|
|
|
|
|
|
title: The PDP digest is the binding correspondence; no cross-engine vocabulary mapping
|
|
|
|
|
|
is published
|
|
|
|
|
|
status: resolved
|
|
|
|
|
|
owner: Bernd Worsch
|
|
|
|
|
|
repo: gate-house
|
|
|
|
|
|
standard: net-kingdom/canon/standards/security-layer-model_v0.7.md
|
|
|
|
|
|
source_note: docs/contracts/approval-consumption.md; approval-engine/docs/approval-claim.md
|
|
|
|
|
|
requested_dispositions:
|
|
|
|
|
|
- approved
|
|
|
|
|
|
- revised
|
|
|
|
|
|
- rejected
|
|
|
|
|
|
affects:
|
|
|
|
|
|
- gate-house
|
|
|
|
|
|
- approval-engine
|
|
|
|
|
|
- access-engine
|
|
|
|
|
|
- secrets-engine
|
|
|
|
|
|
- ops-warden
|
|
|
|
|
|
rationale: 'Raised by access-engine. approval-claim verification item 4 is a disjunction:
|
|
|
|
|
|
the consumer recomputes approval-engine''s native binding from the proposed action,
|
|
|
|
|
|
OR compares binding.pdp_digest to the decision''s request digest. The first limb
|
|
|
|
|
|
needs a cross-engine vocabulary mapping nobody owns and nobody has published; the
|
|
|
|
|
|
second is optional in the schema. Together that leaves ''approved for THIS request''
|
|
|
|
|
|
unestablished whenever the PDP digest is absent, while the claim still reads valid_now
|
|
|
|
|
|
true. The mapping is rejected because a translation between two engines'' vocabularies
|
|
|
|
|
|
can be silently wrong and would be owned by neither, and because recomputing another
|
|
|
|
|
|
layer''s binding is the re-derivation GH-DEC-2026-005 forbids. The digest is identity
|
|
|
|
|
|
rather than translation, so it is made required on the PDP path and consumers fail
|
|
|
|
|
|
closed without it.'
|
|
|
|
|
|
decided_by: Bernd Worsch
|
|
|
|
|
|
created: '2026-09-06T07:30:42.213794Z'
|
|
|
|
|
|
updated: '2026-09-06T07:30:42.213794Z'
|
|
|
|
|
|
```
|
Close the binding-correspondence gap as GH-DEC-2026-008
access-engine raised, and declined to solve locally, a hole in the split
GH-DEC-2026-005 ruled on. approval-claim verification item 4 is a
disjunction and neither limb delivers "approved for THIS request" on the
PDP path: limb one requires translating between two engines' vocabularies
and no mapping is published, limb two (pdp_digest) is optional. Where the
digest is absent a consumer can hold valid_now true, receive an ALLOW,
consume and act with nothing establishing that approval and decision
concern the same action and target.
Ruled: the PDP digest is the correspondence and is required on that path;
a claim without one fails closed; the native limb survives only for
consumers already in approval-engine's vocabulary, including T-06. No
mapping is published — a translation can be wrong while still producing a
confident answer, it fails open, it would be owned by neither engine, and
recomputing another layer's binding is the re-derivation GH-DEC-2026-005
already forbids. The cost is stated: an approval issued without a bound
CheckRequest is unusable on this path, which is correct behaviour.
Also: adopted hub row b606e8ce as canonical for GH-DEC-2026-005 rather
than registering a duplicate; recorded approval-engine's narrowing of the
approver-threshold consequence (distinctness is a UNIQUE storage
invariant, so the PEP stopped checking that the engine applied its own
invariant, not whether dual control could be forged); and drafted A7/T08,
a §11 marking obligation and §12 consumer rule for derived summaries,
after four instances in one week across four repositories.
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
2026-09-06 09:32:20 +02:00
|
|
|
|
|
|
|
|
|
|
## Context
|
|
|
|
|
|
|
|
|
|
|
|
Raised by `access-engine` while implementing `GH-DEC-2026-005`, and declined by it
|
|
|
|
|
|
rather than solved locally — the right call, and the reason it reached a decision
|
|
|
|
|
|
record instead of a commit.
|
|
|
|
|
|
|
|
|
|
|
|
`approval-engine/docs/approval-claim.md` verification item 4 is a **disjunction**:
|
|
|
|
|
|
|
|
|
|
|
|
> `binding.digest` equals the digest of the binding the consumer computed from the
|
|
|
|
|
|
> proposed action, **or** `binding.pdp_digest` equals the `NewDecisionBinding` digest
|
|
|
|
|
|
> of that request.
|
|
|
|
|
|
|
|
|
|
|
|
Both limbs are load-bearing for one property — *approved for **this** request*, as
|
|
|
|
|
|
distinct from *approved*. Neither limb currently delivers it on the PDP path.
|
|
|
|
|
|
|
|
|
|
|
|
**Limb one requires a mapping nobody owns.** The claim's `binding.action` and
|
|
|
|
|
|
`binding.target` are in `approval-engine`'s vocabulary, over
|
|
|
|
|
|
`{action, actor, principal, purpose, target}`. `access-engine`'s policy package and
|
|
|
|
|
|
`CheckRequest` are in its own. To compute limb one, a consumer must translate between
|
|
|
|
|
|
them. No mapping is published. `access-engine` declined to invent one on the correct
|
|
|
|
|
|
ground that a wrong mapping fails **open** in the worst way available: it silently
|
|
|
|
|
|
accepts a claim approved for something else.
|
|
|
|
|
|
|
|
|
|
|
|
**Limb two is optional.** `binding.pdp_digest` is present only *"when recorded at
|
|
|
|
|
|
issue"*.
|
|
|
|
|
|
|
|
|
|
|
|
So on the path this estate actually runs, correspondence rests entirely on an optional
|
|
|
|
|
|
field, and where that field is absent a consumer can hold a claim with
|
|
|
|
|
|
`valid_now: true`, receive an ALLOW, consume, and act — with nothing having
|
|
|
|
|
|
established that the approval and the decision concern the same action and target.
|
|
|
|
|
|
The claim would not be lying; `valid_now` answers a different question.
|
|
|
|
|
|
|
|
|
|
|
|
## Decision
|
|
|
|
|
|
|
|
|
|
|
|
**`binding.pdp_digest` is the binding correspondence on the `GH-DEC-2026-003` path,
|
|
|
|
|
|
and it is required there. No cross-engine vocabulary mapping is published.**
|
|
|
|
|
|
|
|
|
|
|
|
1. **A consumer on the PDP path MUST verify `claim.binding.pdp_digest` equals the
|
|
|
|
|
|
decision's `NewDecisionBinding.request_digest`.** It is no longer a preferred
|
|
|
|
|
|
comparison; it is the comparison.
|
|
|
|
|
|
2. **A claim carrying no `pdp_digest` MUST NOT be used on that path.** The consumer
|
|
|
|
|
|
fails closed. It is not an error to be worked around, and specifically it is not a
|
|
|
|
|
|
licence to fall back to limb one.
|
|
|
|
|
|
3. **Limb one survives only where the consumer is natively in `approval-engine`'s
|
|
|
|
|
|
vocabulary** — that engine's own tests, and the `T-06` assurance case, which uses
|
|
|
|
|
|
the native binding precisely because no PDP digest exists there. It is not a
|
|
|
|
|
|
fallback for a PDP-path consumer.
|
|
|
|
|
|
4. **`approval-engine` MUST record the PDP digest at issue for any approval intended
|
|
|
|
|
|
for use on the PDP path**, and the claim schema states which approvals those are
|
|
|
|
|
|
rather than leaving it to the requester's memory.
|
|
|
|
|
|
|
|
|
|
|
|
### Why not publish the mapping
|
|
|
|
|
|
|
|
|
|
|
|
`access-engine` offered to co-author one. Declining is the substantive half of this
|
|
|
|
|
|
record.
|
|
|
|
|
|
|
|
|
|
|
|
**A mapping is a translation; a digest is an identity.** A translation can be wrong in
|
|
|
|
|
|
a way that still produces a confident answer — the failure mode `access-engine` named,
|
|
|
|
|
|
and it fails open. A digest comparison has no wrong-but-plausible result: it matches
|
|
|
|
|
|
or it does not.
|
|
|
|
|
|
|
|
|
|
|
|
**A published mapping would be owned by neither engine.** It would sit between two
|
|
|
|
|
|
vocabularies, each of which is its own repository's to evolve under §2, and it would
|
|
|
|
|
|
have to be revised whenever either side changed. That artifact is a third authority on
|
|
|
|
|
|
what a request *is* — the shape §6 exists to prevent, arriving as plumbing rather than
|
|
|
|
|
|
as a decision point.
|
|
|
|
|
|
|
|
|
|
|
|
**And computing limb one is the re-derivation `GH-DEC-2026-005` forbids.** A consumer
|
|
|
|
|
|
recomputing `approval-engine`'s native binding from its own vocabulary is a consumer
|
|
|
|
|
|
deriving another layer's data instead of validating against the layer that owns it.
|
|
|
|
|
|
The rule this estate just adopted answers this question on its own terms.
|
|
|
|
|
|
|
|
|
|
|
|
### The cost, stated
|
|
|
|
|
|
|
|
|
|
|
|
An approval requested without a known `CheckRequest` cannot be used on the PDP path,
|
|
|
|
|
|
because there was no PDP digest to record. That is a real constraint and it is
|
|
|
|
|
|
**correct behaviour, not a defect**: an approval granted against an unspecified action
|
|
|
|
|
|
does not become an approval for a specific one because a consumer later found a use
|
|
|
|
|
|
for it. Any workflow needing detached approval must either bind the request at issue
|
|
|
|
|
|
or accept that its approvals are not usable here.
|
|
|
|
|
|
|
|
|
|
|
|
This narrows what `approval-engine` may issue for this path. It does not narrow what
|
|
|
|
|
|
it may issue.
|
|
|
|
|
|
|
|
|
|
|
|
## Reversal
|
|
|
|
|
|
|
|
|
|
|
|
Revert if a legitimate workflow genuinely cannot bind the `CheckRequest` at approval
|
|
|
|
|
|
time — a standing human authorization for an action whose exact parameters are not
|
|
|
|
|
|
knowable until execution is the plausible candidate. The falsifier is a concrete
|
|
|
|
|
|
workflow, not the possibility of one. The expected resolution is that such a case
|
|
|
|
|
|
needs a *class* binding with its own contract, not a relaxation of this one to an
|
|
|
|
|
|
optional field, because an optional correspondence is indistinguishable at the
|
|
|
|
|
|
consumer from no correspondence at all.
|
2026-09-06 14:17:19 +02:00
|
|
|
|
|
|
|
|
|
|
## GH-DEC-2026-009 — Unknown is not a zone and fails closed; stance maps declare their scoping axis
|
|
|
|
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
|
|
id: GH-DEC-2026-009
|
|
|
|
|
|
kind: decision
|
|
|
|
|
|
title: Unknown is not a zone and fails closed; stance maps declare their scoping axis
|
|
|
|
|
|
status: resolved
|
|
|
|
|
|
owner: Bernd Worsch
|
|
|
|
|
|
repo: gate-house
|
|
|
|
|
|
standard: net-kingdom/canon/standards/security-layer-model_v0.7.md
|
|
|
|
|
|
source_note: flex-auth/docs/stance-register-review.md
|
|
|
|
|
|
requested_dispositions:
|
|
|
|
|
|
- approved
|
|
|
|
|
|
- revised
|
|
|
|
|
|
- rejected
|
|
|
|
|
|
affects:
|
|
|
|
|
|
- gate-house
|
|
|
|
|
|
- net-kingdom
|
|
|
|
|
|
- ops-warden
|
|
|
|
|
|
- secrets-engine
|
|
|
|
|
|
- user-engine
|
|
|
|
|
|
- tenant-engine
|
|
|
|
|
|
- ops-mason
|
|
|
|
|
|
- access-engine
|
|
|
|
|
|
- zone-engine
|
|
|
|
|
|
rationale: 'Raised by access-engine on the first occasion the §13.1 register held
|
|
|
|
|
|
enough rows to diverge. Two rulings. First: an unreachable engine and an unclassifiable
|
|
|
|
|
|
subject are different failure cases, and §9.3''s per-zone availability trade is
|
|
|
|
|
|
only available for the first. Trading openness for a zone requires knowing the zone;
|
|
|
|
|
|
where the scope is unknown the trade cannot have been made for it, and fail_open
|
|
|
|
|
|
on unknown hands the most permissive stance to exactly the request an attacker can
|
|
|
|
|
|
most easily make unclassifiable. unknown is therefore not a zone and MUST fail closed.
|
|
|
|
|
|
Second: the register cannot aggregate across incommensurable scoping axes, so each
|
|
|
|
|
|
map declares its axis and its relationship to zone, and the register states what
|
|
|
|
|
|
it cannot answer rather than implying it can.'
|
|
|
|
|
|
decided_by: Bernd Worsch
|
|
|
|
|
|
created: '2026-09-06T12:17:19.104531Z'
|
|
|
|
|
|
updated: '2026-09-06T12:17:19.104531Z'
|
|
|
|
|
|
```
|
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
2026-09-06 14:18:36 +02:00
|
|
|
|
|
|
|
|
|
|
## Context
|
|
|
|
|
|
|
|
|
|
|
|
On 2026-08-29 `access-engine` told this repository it was the party positioned to
|
|
|
|
|
|
notice when the aggregate of consumer stances diverged from what the policy packages
|
|
|
|
|
|
say — and then recorded that the claim was sound but the data was not there, because
|
|
|
|
|
|
§13.1 held one row and one row cannot diverge from anything. `secrets-engine`'s
|
|
|
|
|
|
publication made it two, and the divergence appeared immediately.
|
|
|
|
|
|
|
|
|
|
|
|
That is worth noting on its own: the register earned its existence the first time it
|
|
|
|
|
|
had two entries.
|
|
|
|
|
|
|
|
|
|
|
|
**`ops-warden` declares `unknown` → `fail_open`.** Explicit, versioned, under
|
|
|
|
|
|
`ADR-0009`. **`secrets-engine` declares `unknown` → `fail_closed`.** Both maps are
|
|
|
|
|
|
total, published, test-pinned, and §6.4-conformant. Neither is a defect under v0.7.
|
|
|
|
|
|
They disagree about the one case that by construction is the one nobody planned for.
|
|
|
|
|
|
|
|
|
|
|
|
They are also **not comparable**: `ops-warden` scopes by security zone,
|
|
|
|
|
|
`secrets-engine` by catalog stage — explicitly as the "equivalent scope" §6.4 permits,
|
|
|
|
|
|
until zone membership arrives as a claim. So the register cannot answer *"what is the
|
|
|
|
|
|
estate's stance for a `z2`-protected workload"*, which is the question an inventory
|
|
|
|
|
|
exists to answer.
|
|
|
|
|
|
|
|
|
|
|
|
`access-engine` reported both as observations and explicitly **not** as a request that
|
|
|
|
|
|
either repository change its stance, on the ground that a PDP does not set a
|
|
|
|
|
|
consumer's stance — §9.3's two-owner split, which was its own finding, cutting against
|
|
|
|
|
|
its own convenience. That restraint is correct and it is why the question arrives here:
|
|
|
|
|
|
setting a consumer's stance is not the PDP's to do, but doctrine is Gate House's.
|
|
|
|
|
|
|
|
|
|
|
|
## Decision
|
|
|
|
|
|
|
|
|
|
|
|
### 1. `unknown` is not a zone, and it fails closed
|
|
|
|
|
|
|
|
|
|
|
|
**A stance map MUST resolve `unknown` to `fail_closed`.** It is not a scope over which
|
|
|
|
|
|
the §9.3 availability trade may be made.
|
|
|
|
|
|
|
|
|
|
|
|
The reasoning is a distinction v0.7 does not draw, and the two maps are the proof it
|
|
|
|
|
|
is needed. §9.3 sanctions trading availability for openness **per zone** — knowingly,
|
|
|
|
|
|
for a named scope, at a declared cost. `ops-warden`'s `fail_open` for `z0`–`z2` is
|
|
|
|
|
|
exactly that and remains sanctioned: it is a *known* request in a *degraded* system.
|
|
|
|
|
|
The consumer knows what it is being asked and cannot reach the engine to ask.
|
|
|
|
|
|
|
|
|
|
|
|
`unknown` is a different failure. It is not a degraded system; it is an
|
|
|
|
|
|
**unclassified subject**. The consumer does not know what it is being asked.
|
|
|
|
|
|
|
|
|
|
|
|
**A per-zone trade requires knowing the zone.** Where the scope is unknown, the trade
|
|
|
|
|
|
cannot have been made *for* it — there was no zone in hand when the profile was
|
|
|
|
|
|
written, so no one weighed this request's cost. Resolving `unknown` to the permissive
|
|
|
|
|
|
answer therefore does not extend a considered decision; it invents one, and it invents
|
|
|
|
|
|
the most permissive one available.
|
|
|
|
|
|
|
|
|
|
|
|
The adversarial reading settles it. `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. `fail_open` on `unknown` makes
|
|
|
|
|
|
"be unclassifiable" a privilege escalation, and it is the one escalation that requires
|
|
|
|
|
|
no credential. This is the §8 asymmetry — nothing may manufacture privilege — applied
|
|
|
|
|
|
where the estate had left a gap open by symmetry with a rule that does not reach it.
|
|
|
|
|
|
|
|
|
|
|
|
`ops-warden`'s map is conformant today and this makes one cell of it non-conformant at
|
|
|
|
|
|
v0.8. That is a doctrine change with a cost to a repository that did everything asked
|
|
|
|
|
|
of it — published early, built the reference form, and offered it estate-wide — and it
|
|
|
|
|
|
should be argued in the assent round rather than imposed quietly. Their `z0`–`z2`
|
|
|
|
|
|
zone stances are untouched.
|
|
|
|
|
|
|
|
|
|
|
|
### 2. A stance map declares its scoping axis and its relation to zone
|
|
|
|
|
|
|
|
|
|
|
|
**Each published map MUST name the axis it scopes over, and state its relationship to
|
|
|
|
|
|
security zone: a mapping, or an explicit declaration that none exists yet and why.**
|
|
|
|
|
|
|
|
|
|
|
|
The register is not repaired by forcing everyone onto zones. `secrets-engine` chose
|
|
|
|
|
|
catalog stage because zone membership is not yet available to it as a claim; making it
|
|
|
|
|
|
assert zones now would produce a fiction, and a fiction in a runtime-read,
|
|
|
|
|
|
test-pinned file is worse than an honest incommensurability.
|
|
|
|
|
|
|
|
|
|
|
|
**The register instead states what it cannot answer.** §13.1 carries the axis per row
|
|
|
|
|
|
and records that cross-axis aggregation is not available. An inventory that silently
|
|
|
|
|
|
cannot answer its own question is the §9.1 defect again — a surface catalogued without
|
|
|
|
|
|
the capability behind it.
|
|
|
|
|
|
|
|
|
|
|
|
`access-engine` notes the convergence path and it is the right one: zone *membership*
|
|
|
|
|
|
compiles into the registry snapshot it already consumes, while per-zone *stance*
|
|
|
|
|
|
belongs to the consumer. If membership reaches the decision as a claim,
|
|
|
|
|
|
`secrets-engine`'s axis converges onto zones with neither side inventing a mapping.
|
|
|
|
|
|
Until then the axes are recorded, not reconciled.
|
|
|
|
|
|
|
|
|
|
|
|
The cost of two incommensurable axes is small; the cost of five is not. This lands
|
|
|
|
|
|
before the third row rather than after the fifth.
|
|
|
|
|
|
|
|
|
|
|
|
### What is not decided here
|
|
|
|
|
|
|
|
|
|
|
|
Neither repository is asked to change its zone stances. `secrets-engine`'s stale
|
|
|
|
|
|
reference to a durable `ActionAuthorization` record in its map — the artifact
|
|
|
|
|
|
`GH-DEC-2026-005` shelved — is theirs to correct and `access-engine` has already told
|
|
|
|
|
|
them; it is a naming error in a runtime-read file, where a stale name outlives a stale
|
|
|
|
|
|
comment, and it does not change the stance.
|
|
|
|
|
|
|
|
|
|
|
|
## Reversal
|
|
|
|
|
|
|
|
|
|
|
|
Reverse ruling 1 if a consumer demonstrates a scope that is genuinely unknown *and*
|
|
|
|
|
|
genuinely low-consequence, where failing closed on it costs availability with no
|
|
|
|
|
|
security gain — the plausible candidate is a read-only diagnostic path under §5.1. The
|
|
|
|
|
|
expected resolution is that such a path is not a protected side effect and therefore
|
|
|
|
|
|
has no PEP obligation at all, rather than that it needs a permissive `unknown`. If
|
|
|
|
|
|
that resolution fails on a real path, this ruling is too broad.
|
|
|
|
|
|
|
|
|
|
|
|
Reverse ruling 2 if declaring the axis proves to be all the register needed, in which
|
|
|
|
|
|
case the "states what it cannot answer" half is redundant rather than wrong.
|
2026-09-06 15:28:01 +02:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### Amendment to GH-DEC-2026-008, 2026-09-06 — the comparison as written could never pass
|
|
|
|
|
|
|
|
|
|
|
|
Found by `secrets-engine` re-verifying a replay fixture within hours of the ruling,
|
|
|
|
|
|
and reported independently by `access-engine` and `approval-engine`. Verified here
|
|
|
|
|
|
against `flex-auth/schemas/decision_envelope.schema.json` and `pkg/api/canonical.go`
|
|
|
|
|
|
before amending.
|
|
|
|
|
|
|
|
|
|
|
|
**The defect.** The ruling required `claim.binding.pdp_digest` to equal the decision's
|
|
|
|
|
|
`NewDecisionBinding.request_digest`. `access-engine` hashes context into the request
|
|
|
|
|
|
digest, and the dual-control pattern carries the claim in `context.approval`.
|
|
|
|
|
|
Embedding the claim therefore changes the digest of the request that carries it, so a
|
|
|
|
|
|
digest recorded at issue can never equal the final one.
|
|
|
|
|
|
|
|
|
|
|
|
This is a **hash cycle**, and `approval-engine` put the resolution correctly: it is
|
|
|
|
|
|
forced rather than chosen. A claim cannot carry the digest of a document containing
|
|
|
|
|
|
that claim — the value would have to be known before it could be computed. The
|
|
|
|
|
|
recorded digest is necessarily of the underlying action *before* any claim was
|
|
|
|
|
|
embedded.
|
|
|
|
|
|
|
|
|
|
|
|
**The consequence had it shipped.** A consumer obeying the rule and failing closed
|
|
|
|
|
|
would have denied `destroy` permanently — failing closed forever on a check that
|
|
|
|
|
|
cannot pass. The ruling's own fail-closed requirement is what would have made it
|
|
|
|
|
|
harmful rather than merely wrong.
|
|
|
|
|
|
|
|
|
|
|
|
**The fix, and whose it was.** `access-engine` publishes
|
|
|
|
|
|
`binding.approval_binding_digest` — the same canonical material with
|
|
|
|
|
|
`context.approval` removed, emitted only where a claim was carried
|
|
|
|
|
|
(`FLEX-DEC-2026-007`). An approval issued against a claim-free `Check` records that
|
|
|
|
|
|
`Check`'s digest, and the claim-bearing request reproduces it. The comparison becomes
|
|
|
|
|
|
implementable without changing what it requires: correspondence by identity, no
|
|
|
|
|
|
translation, nobody asserting an equivalence between vocabularies. **The A5 property
|
|
|
|
|
|
holds exactly as drafted.**
|
|
|
|
|
|
|
|
|
|
|
|
`approval-engine` was right that what was missing was a published statement of which
|
|
|
|
|
|
fields the PDP excludes, and right not to make that statement on `access-engine`'s
|
|
|
|
|
|
behalf. **A consumer MUST NOT guess the exclusion rule**: a digest computed under an
|
|
|
|
|
|
assumed rule produces a confident wrong answer, and comparing two digests derived
|
|
|
|
|
|
under different rules fails open toward accepting a claim bound to a different
|
|
|
|
|
|
request — the same failure direction as the vocabulary mapping this decision rejected,
|
|
|
|
|
|
reached by another road. Until a PDP publishes its exclusion rule, the path is
|
|
|
|
|
|
correctly fail-closed rather than complete: a gap in a dependency, not in the ruling.
|
|
|
|
|
|
|
|
|
|
|
|
**What this changes in the record.** The ruling stands. Its four numbered obligations
|
|
|
|
|
|
stand. Obligation 1's comparison target is corrected from the request digest to the
|
|
|
|
|
|
PDP's published exclusion-scoped digest. v0.8 §9.7.3 carries the corrected form.
|
|
|
|
|
|
|
|
|
|
|
|
**And a general property, flagged by `access-engine` as a near miss it does not ask
|
|
|
|
|
|
for.** The obvious fix is to drop `context.approval` from the request digest
|
|
|
|
|
|
entirely. That is unsafe, and the reason generalises: **an evidence-bearing input may
|
|
|
|
|
|
be excluded from a correspondence digest but never from the replay identity.** Two
|
|
|
|
|
|
requests differing only in which approval was presented decide differently — one
|
|
|
|
|
|
allows, one denies `dual_control_required` — so collapsing them would let an allow
|
|
|
|
|
|
obtained with a valid claim be replayed against a request carrying none. A fail-open
|
|
|
|
|
|
hole reached by a refactor that looks like simplification. It is in v0.8 §6.4
|
|
|
|
|
|
obligation 5 because the shape recurs wherever evidence travels inside a hashed
|
|
|
|
|
|
request, and because a property discovered by nearly getting it wrong is worth more
|
|
|
|
|
|
written down than remembered.
|
|
|
|
|
|
|
|
|
|
|
|
**Implementation status.** `access-engine`: `FLEX-DEC-2026-007`, `dd3ce4c`.
|
|
|
|
|
|
`approval-engine`: schema v3 adds a declared `pdp_path`; `create()` refuses
|
|
|
|
|
|
`pdp_path: true` without a `pdp_digest`, so an approval that would be unusable on the
|
|
|
|
|
|
path fails **at issue** rather than at the protected side effect. Intent is declared,
|
|
|
|
|
|
never inferred — a digest that happens to be present is not a declaration anybody
|
|
|
|
|
|
made, legacy rows migrate to `false` rather than being back-filled, and a successor
|
|
|
|
|
|
inherits its predecessor's declaration. Back-filling would have manufactured a
|
|
|
|
|
|
statement no requester made, which is this decision's own objection to translation in
|
|
|
|
|
|
another form.
|
|
|
|
|
|
|
|
|
|
|
|
**What this says about the ruling process.** The ruling was right and its mechanism
|
|
|
|
|
|
was missing, and that combination is only survivable because the repositories
|
|
|
|
|
|
implementing it read it against their own fixtures rather than accepting it. The
|
|
|
|
|
|
defect was found in hours by the repository that would have been broken by it, and
|
|
|
|
|
|
reported by two others who had no obligation to look.
|
Close the v0.8 assent round: two rulings, nine corrections, one decline
Four repositories returned text reviews. Every substantive finding was
about a rule that read as satisfied by a check that did not satisfy it,
which is the failure mode this repo is structurally prone to: doctrine
is graded on whether it is right and consumed on whether it is
checkable, and only the implementers can tell those apart.
GH-DEC-2026-010 — attribution is not identity. Obligation 1 said a PEP
must hold a decision from access-engine; obligation 2 supplied a digest
test emphatic that it was mechanical rather than a matter of judgement.
That test establishes which request a decision is for and nothing about
who issued it, and it cannot: every input to it is either sent by the
caller or published, so a responder knowing a published package id and
version returns a well-formed allow. Fail-closed protects against a
decision point that is absent, not against one that lies. Section 9.4
required authenticated entries of the approval object and nothing
required it of the decision, so obligation 5 was written over a pair a
PEP could only half validate. The mechanism is access-engine's under
section 17 and it is not the standard's to choose, so the condition is
a declared section 13 gap rather than a rule invented here. Raised by
access-engine against its own artifact, which had already recorded it
as its own defect before reading our text.
GH-DEC-2026-011 — ops-warden assented to GH-DEC-2026-009 on the
falsifier's own terms, went looking for the section 5.1 escape hatch
the reversal clause predicted, and reported it does not have one. Then
it priced adoption: 0 of 3 signing targets and 3 of 21 routing lanes
resolve to a zone, so the cell adopted today fails closed on nearly
every certificate it issues whenever the engine is unreachable —
including the continuity path an operator needs to repair that
unreachability. Its ask for a dated transitional unknown: fail_open is
declined; it is indistinguishable at runtime from the stance the rule
forbids and would make the rule optional at the only moment it costs
anything. Its second preference is adopted instead: 13.1 records a
dated coverage figure beside each stance, so a strict consumer and an
unclassified one stop reading alike. Coverage is disclosure and does
not soften the stance — the record says so, and says what would make
the column come out again.
The round record is closed and carries the rest: totality by catch-all,
absent versus unknown (closing the section 16 question this version
opened), the drift test promoted to MUST, ops-mason marked, and
approval-engine's four editorial-but-load-bearing findings. Its own
finding ids are used rather than renumbered.
kings-guard and audit-core did not return a review. Section 14 records
that as not claimed rather than counting silence as assent, and names
the sections that therefore carry no assent from the repository best
placed to test them.
Standard amended at net-kingdom@64394e9; it stays proposed, and
publication and the acceptance flip are net-kingdom's.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012viPor8WJNCbV64ipwewrm
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 1754332@bnt-lap001
Assistant-Session: 9c8ac536-ff5e-46a3-8ab1-a548bde25fc0
2026-09-09 20:15:12 +02:00
|
|
|
|
|
|
|
|
|
|
## GH-DEC-2026-010 — A PEP must be able to attribute a decision to access-engine; the digest test does not do it
|
|
|
|
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
|
|
id: GH-DEC-2026-010
|
|
|
|
|
|
kind: decision
|
|
|
|
|
|
title: A PEP must be able to attribute a decision to access-engine; the digest test
|
|
|
|
|
|
does not do it
|
|
|
|
|
|
status: resolved
|
|
|
|
|
|
owner: Bernd Worsch
|
|
|
|
|
|
repo: gate-house
|
|
|
|
|
|
standard: net-kingdom/canon/standards/security-layer-model_v0.8.md
|
|
|
|
|
|
source_note: flex-auth FLEX-DEC-2026-010; approval-engine docs/reviews/2026-09-07-security-layer-model-v08.md
|
|
|
|
|
|
requested_dispositions:
|
|
|
|
|
|
- approved
|
|
|
|
|
|
- revised
|
|
|
|
|
|
- rejected
|
|
|
|
|
|
affects:
|
|
|
|
|
|
- gate-house
|
|
|
|
|
|
- net-kingdom
|
|
|
|
|
|
- access-engine
|
|
|
|
|
|
- approval-engine
|
|
|
|
|
|
- secrets-engine
|
|
|
|
|
|
- ops-warden
|
|
|
|
|
|
- ops-mason
|
|
|
|
|
|
- user-engine
|
|
|
|
|
|
- tenant-engine
|
|
|
|
|
|
- audit-core
|
|
|
|
|
|
decided_by: Bernd Worsch
|
|
|
|
|
|
rationale: 'Raised by access-engine against its own artifact during the v0.8 assent
|
|
|
|
|
|
round, having recorded it as its own defect (FLEX-DEC-2026-010) before reviewing
|
|
|
|
|
|
this text. Section 6.4 obligation 1 required a PEP to hold a decision from access-engine,
|
|
|
|
|
|
and obligation 2 supplied a test emphatic that it was mechanical rather than a matter
|
|
|
|
|
|
of implementer judgement. That test establishes which request a decision was rendered
|
|
|
|
|
|
for and nothing about who rendered it, and it cannot: every input to it is either
|
|
|
|
|
|
sent by the caller or published, so a responder knowing a published package id and
|
|
|
|
|
|
version reproduces all of it and returns a well-formed allow. Fail-closed protects
|
|
|
|
|
|
against a decision point that is absent, not against one that lies. The asymmetry
|
|
|
|
|
|
with obligation 5 is the sharp form, since section 9.4 requires the approval object
|
|
|
|
|
|
to have authenticated entries and nothing required it of the decision, leaving an
|
|
|
|
|
|
obligation written over a pair of artifacts satisfiable for only one half. The obligation
|
|
|
|
|
|
now requires attribution and states that the digest comparison does not discharge
|
|
|
|
|
|
it; the mechanism is the owner s under section 17 and the gap is declared in section
|
|
|
|
|
|
13 rather than papered by a rule the standard does not get to choose.'
|
|
|
|
|
|
created: '2026-09-09T18:11:20.071372Z'
|
|
|
|
|
|
updated: '2026-09-09T18:11:20.071372Z'
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Context
|
|
|
|
|
|
|
|
|
|
|
|
`access-engine` returned its v0.8 review on 2026-09-07 and ranked this finding
|
|
|
|
|
|
blocking for calling §6.4's PEP obligations complete — explicitly **not** blocking
|
|
|
|
|
|
anyone's adoption, since the condition already exists under v0.7 and v0.8 does not
|
|
|
|
|
|
create it. It had already recorded the defect against its own artifact as
|
|
|
|
|
|
`FLEX-DEC-2026-010`, with `FLEX-WP-0024` carrying the fix, before it read this text.
|
|
|
|
|
|
|
|
|
|
|
|
The finding is that the standard is not merely silent. Obligation 1 says a PEP must
|
|
|
|
|
|
hold *"a decision from `access-engine` identifying the request it was rendered for"*,
|
|
|
|
|
|
and obligation 2 supplies a test and is emphatic that it is not a judgement call:
|
|
|
|
|
|
replay is permitted iff the canonical request digest matches and the lifetime holds,
|
|
|
|
|
|
*"mechanical, not a matter of implementer judgement"*. A careful implementer reads the
|
|
|
|
|
|
mechanical test as discharging the obligation above it. It does not.
|
|
|
|
|
|
|
|
|
|
|
|
Every input to that comparison is either sent by the caller or published by the PDP.
|
|
|
|
|
|
The request material is what the PEP transmitted; `policy_package_digest` and
|
|
|
|
|
|
`registry_snapshot_digest` are computable from files in a public repository. A
|
|
|
|
|
|
responder that knows the package id and version — both published — reproduces all
|
|
|
|
|
|
three and returns a well-formed allow. Publishing more digests makes a forged envelope
|
|
|
|
|
|
look **more** authenticated, not less.
|
|
|
|
|
|
|
|
|
|
|
|
`secrets-engine` put the consequence better than either of us: its posture *"silently
|
|
|
|
|
|
assumes the PDP is the PDP"*. `approval-engine` carried it into the correspondence
|
|
|
|
|
|
chain — an approval whose `pdp_digest` matches a **forged** decision matches perfectly.
|
|
|
|
|
|
Identity comparison proves two artifacts describe one request. It proves nothing about
|
|
|
|
|
|
whether the decision is authentic.
|
|
|
|
|
|
|
|
|
|
|
|
**The gap was visible from inside and was recorded against the wrong artifact.** §16
|
|
|
|
|
|
already carried *"publication integrity of the Taxonomy layer itself… while its own
|
|
|
|
|
|
publication path has no digest, freeze, or rollback discipline"*. That is this
|
|
|
|
|
|
observation one layer up. Applied to the artifact the standard regulates rather than to
|
|
|
|
|
|
the standard, it is this decision.
|
|
|
|
|
|
|
|
|
|
|
|
## Decision
|
|
|
|
|
|
|
|
|
|
|
|
### 1. Attribution is required, and is a separate property from identity
|
|
|
|
|
|
|
|
|
|
|
|
**A PEP MUST hold a decision that is *attributable to* `access-engine`, not merely
|
|
|
|
|
|
present and well-formed.** Obligation 2's digest test establishes **which request** a
|
|
|
|
|
|
decision was rendered for. It establishes nothing about **who rendered it**.
|
|
|
|
|
|
|
|
|
|
|
|
**Obligation 1 is not discharged by a digest comparison**, and an implementer MUST NOT
|
|
|
|
|
|
read obligation 2's mechanical test as discharging it. This is the whole of the change:
|
|
|
|
|
|
the obligation stops reading as satisfied by a check that does not satisfy it.
|
|
|
|
|
|
|
|
|
|
|
|
### 2. Fail-closed does not reach this
|
|
|
|
|
|
|
|
|
|
|
|
§9.3's apparatus — two failure cases, two owners, published stance maps — addresses
|
|
|
|
|
|
**absence**. An unreachable PDP denies. A responder impersonating one allows. Nothing
|
|
|
|
|
|
in the standard addressed a responder, and no stance value can: the stance is consulted
|
|
|
|
|
|
when the engine is unreachable, and a lying responder is reachable by construction.
|
|
|
|
|
|
|
|
|
|
|
|
### 3. Obligation 5 was written over a pair it could only half satisfy
|
|
|
|
|
|
|
|
|
|
|
|
§9.4 requires the approval object to have *"durable, authenticated entries"*. §6.4
|
|
|
|
|
|
obligation 5 then requires that where a PEP's decision rests on more than one artifact,
|
|
|
|
|
|
each MUST be validated against the layer that owns its data — and names the
|
|
|
|
|
|
approval-claim / `DecisionEnvelope` pair as the live instance.
|
|
|
|
|
|
|
|
|
|
|
|
So the standard required authenticity of the **PIP's** artifact and not of the
|
|
|
|
|
|
**PDP's**, and wrote an obligation across both. That asymmetry was argued nowhere. It
|
|
|
|
|
|
is oversight, not position, and it is corrected here rather than defended.
|
|
|
|
|
|
|
|
|
|
|
|
### 4. The mechanism is not the standard's to choose
|
|
|
|
|
|
|
|
|
|
|
|
`access-engine` did not ask for a signature scheme in the statute, and it does not get
|
|
|
|
|
|
one. The shape is the owner's under §17. What the standard names is the property.
|
|
|
|
|
|
|
|
|
|
|
|
Until a mechanism ships, the condition is a **declared §13 gap** with `access-engine`
|
|
|
|
|
|
as owner (`FLEX-DEC-2026-010`, `FLEX-WP-0024`; `FLEX-DEC-2026-009` puts the
|
|
|
|
|
|
authenticated caller in provenance, so a record eventually attests both ends of the
|
|
|
|
|
|
channel rather than neither). A declared gap is honest. An unstated assumption inside a
|
|
|
|
|
|
test called mechanical is not.
|
|
|
|
|
|
|
|
|
|
|
|
## What this does not do
|
|
|
|
|
|
|
|
|
|
|
|
It does not close the gap. `access-engine`'s note that Glas completed operator
|
|
|
|
|
|
caller-auth mid-review is correctly self-limited: an authenticated API-server
|
|
|
|
|
|
port-forward authenticates the responder for one operator path and produces no signed
|
|
|
|
|
|
portable artifact.
|
|
|
|
|
|
|
|
|
|
|
|
It also does not create an adoption blocker. The condition predates v0.8 and every
|
|
|
|
|
|
PEP-shaped consumer is in it today. What changes is that they can now see they are.
|
|
|
|
|
|
|
|
|
|
|
|
## Reversal condition
|
|
|
|
|
|
|
|
|
|
|
|
If a PEP can verify the decision's origin by a mechanism that does not itself rest on
|
|
|
|
|
|
material the caller supplies or the PDP publishes openly, the §13 gap closes and this
|
|
|
|
|
|
record's second half becomes historical. The first half — that identity is not
|
|
|
|
|
|
attribution — does not revert; it is a property of hashing, not of the current channel.
|
|
|
|
|
|
|
|
|
|
|
|
## Provenance
|
|
|
|
|
|
|
|
|
|
|
|
Raised by `access-engine` (`FLEX-DEC-2026-011`, v0.8 assent, F1), against its own
|
|
|
|
|
|
artifact and having recorded the defect on its own side first. Independently framed by
|
|
|
|
|
|
`secrets-engine`. Carried into the correspondence chain by `approval-engine`, which
|
|
|
|
|
|
noted its own `docs/approval-claim.md` said what `pdp_digest` cannot cover without
|
|
|
|
|
|
saying it cannot detect a forged decision. Applied to
|
|
|
|
|
|
`security-layer-model_v0.8.md` §6.4 obligation 1 and §13 at `net-kingdom@64394e9`.
|
|
|
|
|
|
|
|
|
|
|
|
## GH-DEC-2026-011 — Classification coverage is published beside the stance; a transitional fail_open is declined
|
|
|
|
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
|
|
id: GH-DEC-2026-011
|
|
|
|
|
|
kind: decision
|
|
|
|
|
|
title: Classification coverage is published beside the stance; a transitional fail_open
|
|
|
|
|
|
is declined
|
|
|
|
|
|
status: resolved
|
|
|
|
|
|
owner: Bernd Worsch
|
|
|
|
|
|
repo: gate-house
|
|
|
|
|
|
standard: net-kingdom/canon/standards/security-layer-model_v0.8.md
|
|
|
|
|
|
source_note: ops-warden history/2026-09-09-layer-model-v08-review.md @ 8e1b621; flex-auth
|
|
|
|
|
|
FLEX-DEC-2026-011 F2
|
|
|
|
|
|
requested_dispositions:
|
|
|
|
|
|
- approved
|
|
|
|
|
|
- revised
|
|
|
|
|
|
- rejected
|
|
|
|
|
|
affects:
|
|
|
|
|
|
- gate-house
|
|
|
|
|
|
- net-kingdom
|
|
|
|
|
|
- ops-warden
|
|
|
|
|
|
- ops-mason
|
|
|
|
|
|
- secrets-engine
|
|
|
|
|
|
- user-engine
|
|
|
|
|
|
- tenant-engine
|
|
|
|
|
|
- access-engine
|
|
|
|
|
|
- zone-engine
|
|
|
|
|
|
decided_by: Bernd Worsch
|
|
|
|
|
|
rationale: 'ops-warden assented to GH-DEC-2026-009 on its own terms and then reported
|
|
|
|
|
|
what adopting it costs: zero of three signing targets and three of twenty-one routing
|
|
|
|
|
|
lanes resolve to a zone, so unknown fail_closed adopted today would fail closed
|
|
|
|
|
|
on essentially every certificate it issues whenever access-engine is unreachable,
|
|
|
|
|
|
including the continuity path an operator needs to repair that unreachability. It
|
|
|
|
|
|
asked for a dated transitional unknown fail_open converting on coverage rather than
|
|
|
|
|
|
calendar. Declined: a sanctioned transitional fail_open is indistinguishable at
|
|
|
|
|
|
runtime from the stance the rule forbids and would make the rule optional at the
|
|
|
|
|
|
only moment it costs anything, while section 11 s declared-gap mark already expresses
|
|
|
|
|
|
a correct rule whose adoption is not yet affordable. Its second preference is adopted
|
|
|
|
|
|
instead. Section 13.1 records a dated classification-coverage figure beside each
|
|
|
|
|
|
stance, because unknown fail_closed over an entirely unclassified population is
|
|
|
|
|
|
conformant and materially misleading. access-engine reached the same place from
|
|
|
|
|
|
the other side: totality satisfied by a catch-all is satisfied vacuously, so a map
|
|
|
|
|
|
must enumerate its axis and an absent scope must be distinguishable in the record
|
|
|
|
|
|
from an unknown one and surface as a conformance failure.'
|
|
|
|
|
|
created: '2026-09-09T18:12:02.553370Z'
|
|
|
|
|
|
updated: '2026-09-09T18:12:02.553370Z'
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Context
|
|
|
|
|
|
|
|
|
|
|
|
`GH-DEC-2026-009` made `unknown` → `fail_closed` normative and made one cell of
|
|
|
|
|
|
`ops-warden`'s published stance map non-conformant. That ruling was circulated with
|
|
|
|
|
|
v0.8 rather than imposed, precisely because the repository bearing its cost had not
|
|
|
|
|
|
reviewed it. `ops-warden` returned the review on 2026-09-09
|
|
|
|
|
|
(`history/2026-09-09-layer-model-v08-review.md`, `8e1b621`).
|
|
|
|
|
|
|
|
|
|
|
|
**It assented to the rule, on the falsifier's own terms.** The reversal clause
|
|
|
|
|
|
anticipated that such a path would be a §5.1 read-only diagnostic carrying no PEP
|
|
|
|
|
|
obligation. `ops-warden` went looking for that escape hatch on its own side and
|
|
|
|
|
|
reported that it does not have one: the stance map governs exactly one protected
|
|
|
|
|
|
action, `warden sign`, which is a credential-issuing side effect that §5.1 does not
|
|
|
|
|
|
reach. The predicted defence is absent and the argument stands unrebutted.
|
|
|
|
|
|
|
|
|
|
|
|
**Then it priced the adoption.** Measured 2026-09-09:
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
signing targets (actor resources in snapshot): 0 resolved, 3 unknown, 1 n/a
|
|
|
|
|
|
routing catalog lanes: 3 resolved, 18 unknown, 12 n/a
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Zero of its signing targets resolve to a zone. So `unknown` → `fail_closed` adopted
|
|
|
|
|
|
today does not fail closed on an edge case; it fails closed on essentially every
|
|
|
|
|
|
certificate `ops-warden` issues, whenever `access-engine` is unreachable. That is the
|
|
|
|
|
|
configuration `ADR-0006` rejected, reached by another route: one value making the
|
|
|
|
|
|
decision engine a uniform dependency of every signing path, **including the continuity
|
|
|
|
|
|
path needed to repair that dependency**. Engine down → operator needs an SSH
|
|
|
|
|
|
certificate to reach the host and restore it → the repair target is unknown because
|
|
|
|
|
|
nobody classified it → denied.
|
|
|
|
|
|
|
|
|
|
|
|
Eighteen of its eighteen unknown lanes are unknown because **another** repository has
|
|
|
|
|
|
not published a workload-identity declaration, and `ADR-0009` rule 3 forbids closing
|
|
|
|
|
|
that by inference.
|
|
|
|
|
|
|
|
|
|
|
|
`access-engine` arrived at the same register from the opposite side (`FLEX-DEC-2026-011`,
|
|
|
|
|
|
F2): a map carrying `unknown` → `fail_closed` satisfies obligation 3's totality
|
|
|
|
|
|
requirement **vacuously**. Every scope the author never enumerated lands in `unknown`,
|
|
|
|
|
|
fails closed, and nobody ever learns which those were. It recognised the shape because
|
|
|
|
|
|
it published it — `FLEX-DEC-2026-008`, a policy package shipped with no tenant rule at
|
|
|
|
|
|
all while 29 fixtures passed, because every fixture carried the same tenant.
|
|
|
|
|
|
|
|
|
|
|
|
## Decision
|
|
|
|
|
|
|
|
|
|
|
|
### 1. A dated transitional `unknown: fail_open` is declined
|
|
|
|
|
|
|
|
|
|
|
|
`ops-warden`'s first preference was that obligation 3 name a transition: a consumer may
|
|
|
|
|
|
declare `unknown: fail_open` as a dated, published transitional state with a coverage
|
|
|
|
|
|
figure attached, converting on coverage rather than on calendar.
|
|
|
|
|
|
|
|
|
|
|
|
**Declined.** A sanctioned transitional `fail_open` is indistinguishable at runtime from
|
|
|
|
|
|
the stance the rule forbids. It makes the rule optional at the moment of adoption — the
|
|
|
|
|
|
only moment it costs anything — and `unknown` is the cheapest state for an attacker to
|
|
|
|
|
|
induce whether or not the consumer has dated its intention to stop being permissive.
|
|
|
|
|
|
|
|
|
|
|
|
The mechanism asked for already exists and does not have that defect: §11's
|
|
|
|
|
|
**declared-gap** mark says *"correct rule, adoption not yet affordable"* without
|
|
|
|
|
|
inverting the rule's effect. `ops-warden` proposed exactly that as its own second
|
|
|
|
|
|
preference and named `WARDEN-WP-0040` as the route.
|
|
|
|
|
|
|
|
|
|
|
|
The deadlock is real and the answer is classification, not a permissive axis: continuity
|
|
|
|
|
|
paths are classified into a scope whose stance is open, and the deadlock does not arise.
|
|
|
|
|
|
`ops-warden` accepted that answer and correctly observed that it is work not yet done.
|
|
|
|
|
|
Work not yet done is a gap. It is not a reason to hold the axis open.
|
|
|
|
|
|
|
|
|
|
|
|
**And a stricter stance is not a licence to manufacture the membership that makes it
|
|
|
|
|
|
survivable.** `ADR-0009` rule 3 is right and must hold under pressure from this ruling.
|
|
|
|
|
|
A consumer MUST NOT infer a scope another repository has not declared.
|
|
|
|
|
|
|
|
|
|
|
|
### 2. Classification coverage is published beside the stance
|
|
|
|
|
|
|
|
|
|
|
|
**§13.1 records a dated classification-coverage figure for each consumer.** A row
|
|
|
|
|
|
reading `unknown` → `fail_closed` while 100% of that consumer's targets are unknown is
|
|
|
|
|
|
conformant and materially misleading: a reader cannot distinguish a strict consumer from
|
|
|
|
|
|
an unclassified one. It is §11's published-map-equals-shipped-behaviour rule one level
|
|
|
|
|
|
up — the map becomes accurate about itself and inaccurate about its effect.
|
|
|
|
|
|
|
|
|
|
|
|
Coverage is **disclosure, not a licence**. It does not soften the stance, gate it, or
|
|
|
|
|
|
create a state in which a non-conformant cell becomes conformant. It reports.
|
|
|
|
|
|
|
|
|
|
|
|
Coverage is reported by the consumer and never computed here. A blank means *"not
|
|
|
|
|
|
reported"*, never *"complete"*.
|
|
|
|
|
|
|
|
|
|
|
|
### 3. A map must enumerate its axis; `absent` is not `unknown`
|
|
|
|
|
|
|
|
|
|
|
|
**Totality MUST NOT be satisfied by a catch-all.** A published map enumerates the axis
|
|
|
|
|
|
it scopes over. Otherwise obligation 3's totality requirement is unfalsifiable and its
|
|
|
|
|
|
drift test passes by exercising the default rather than the axis.
|
|
|
|
|
|
|
|
|
|
|
|
**`unknown` and `absent` are one runtime behaviour and two meanings.** Both fail closed
|
|
|
|
|
|
— `absent` for the stronger reason, since it is the branch reached by discovering that
|
|
|
|
|
|
the author's model of their own axis was wrong, and §8's asymmetry forbids being more
|
|
|
|
|
|
permissive on surprise. But an `unknown` hit is normal operation under a considered
|
|
|
|
|
|
stance, while an `absent` hit is evidence this obligation is violated. **An `absent` hit
|
|
|
|
|
|
MUST be distinguishable in the record and MUST surface as a conformance failure** rather
|
|
|
|
|
|
than be absorbed by the catch-all.
|
|
|
|
|
|
|
|
|
|
|
|
This closes the question §16 opened at the v0.8 cut.
|
|
|
|
|
|
|
|
|
|
|
|
### 4. `ops-mason` is marked
|
|
|
|
|
|
|
|
|
|
|
|
An unpublished stance map is a plainer violation of obligation 3 than a wrongly-valued
|
|
|
|
|
|
cell in a published one, and §13.1 stated it as bare fact while bolding the other. A
|
|
|
|
|
|
reader scanning for marks found one row and concluded the other four were fine. That is
|
|
|
|
|
|
Gate House's own §11 marking obligation applied to Gate House's own register, returned
|
|
|
|
|
|
unchanged by `access-engine` after receiving the same argument about a stale row of its
|
|
|
|
|
|
own. `ops-mason`'s row is now marked, with no route recorded.
|
|
|
|
|
|
|
|
|
|
|
|
## Reversal condition
|
|
|
|
|
|
|
|
|
|
|
|
If a consumer demonstrates a scope that is genuinely unclassifiable, genuinely
|
|
|
|
|
|
low-consequence, and whose permissive resolution cannot be induced by an unprivileged
|
|
|
|
|
|
party, §1 is open to revision — that falsifier is `GH-DEC-2026-009`'s and survives here.
|
|
|
|
|
|
`ops-warden` went looking for it and reported its absence, which is evidence and not
|
|
|
|
|
|
proof.
|
|
|
|
|
|
|
|
|
|
|
|
§2 reverses if coverage figures start being read as a stance qualifier rather than as
|
|
|
|
|
|
disclosure. If a row is ever argued to be conformant *because* its coverage is low, the
|
|
|
|
|
|
column is doing harm and comes out.
|
|
|
|
|
|
|
|
|
|
|
|
## Provenance
|
|
|
|
|
|
|
|
|
|
|
|
Raised by `ops-warden` (v0.8 assent, two findings and one agreement), which bears the
|
|
|
|
|
|
entire cost of the ruling it assented to and asked for the transition it did not get.
|
|
|
|
|
|
Its measured figures are the first entries in the coverage column. §3 raised by
|
|
|
|
|
|
`access-engine` (`FLEX-DEC-2026-011`, F2); §4 by `access-engine` (F4). Applied to
|
|
|
|
|
|
`security-layer-model_v0.8.md` §6.4 obligation 3 and §13.1 at `net-kingdom@64394e9`.
|
|
|
|
|
|
|
|
|
|
|
|
`access-engine` added, unprompted, that its concurrence with `GH-DEC-2026-009` cost it
|
|
|
|
|
|
nothing — it is not PEP-shaped and publishes no stance map — and that a PDP's assent to
|
|
|
|
|
|
a ruling falling entirely on other repositories is weak evidence for it. That is
|
|
|
|
|
|
recorded because it is right: the strength here is the asymmetry argument and
|
|
|
|
|
|
`ops-warden`'s assent against its own interest, not the count of repositories agreeing.
|