Founder ruling 2026-11-01, relayed in session by the net-kingdom coordinator: "Accept GH-DEC-2026-026 as drafted". Reliance is the C2 trigger, C3 is reserved, the actor is not an approver of its own approval, and agents never approve at C1 or above. The record moves from decisions/drafts/ into decisions/decisions.md, status resolved, recorded as an asserted C1 disposition under relaxation B3. GH-WP-0005 is active: T01 and T02 done; T03 handed to informed-decision, approval-engine, state-hub and net-kingdom; T04 asked the-custodian to carry B1-B4 on the close-down checklist. T05 and T06 stay waiting. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 5502@bnt-lap001 Assistant-Session: 68b3b02f-5d0f-4e71-8421-796f62e50196
4665 lines
255 KiB
Markdown
4665 lines
255 KiB
Markdown
# 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
|
||
status: resolved
|
||
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'
|
||
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'
|
||
state_hub_decision_id: "2d6509d0-ffd2-4209-89ab-bf68a4945ada"
|
||
```
|
||
|
||
## 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.
|
||
|
||
## 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
|
||
status: resolved
|
||
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'
|
||
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'
|
||
state_hub_decision_id: "3b7c8336-ed0b-48ed-84e4-dee8cfdb50ae"
|
||
```
|
||
|
||
## 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.
|
||
|
||
## 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
|
||
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
|
||
requested_dispositions:
|
||
- approved
|
||
- revised
|
||
- rejected
|
||
affects:
|
||
- gate-house
|
||
- approval-engine
|
||
- flex-auth
|
||
- secrets-engine
|
||
- ops-warden
|
||
created: '2026-08-29T12:50:06.944092Z'
|
||
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'
|
||
state_hub_decision_id: "f768c894-7e68-4e23-93b5-f475f4b072e5"
|
||
```
|
||
|
||
## 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.
|
||
|
||
## 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.
|
||
|
||
## 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
|
||
state_hub_decision_id: "b606e8ce-f1fa-4b39-bfe9-c11e88a3cde6"
|
||
created: '2026-09-05T23:28:23.931441Z'
|
||
updated: '2026-09-05T23:28:23.931441Z'
|
||
```
|
||
|
||
## 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
|
||
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
|
||
(`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).
|
||
|
||
### 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.
|
||
|
||
**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.
|
||
|
||
## 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.
|
||
|
||
## 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'
|
||
state_hub_decision_id: "780e1117-57aa-49c7-bf59-f69df2a67a4e"
|
||
```
|
||
|
||
## 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.
|
||
|
||
## 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'
|
||
state_hub_decision_id: "9ece3338-0fc7-4741-bdfc-7fdea170dc0b"
|
||
```
|
||
|
||
## 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.
|
||
|
||
## 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'
|
||
state_hub_decision_id: "a36b3f02-fb08-47b5-9de3-c2d9e37678a4"
|
||
```
|
||
|
||
## 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.
|
||
|
||
## 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'
|
||
state_hub_decision_id: "009bc960-9029-4052-aaba-4c5e27a328dc"
|
||
```
|
||
|
||
## 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.
|
||
|
||
---
|
||
|
||
### 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.
|
||
|
||
## 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'
|
||
state_hub_decision_id: "046aa117-5b33-4fc2-b88c-313ad40f8e45"
|
||
```
|
||
|
||
## 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'
|
||
state_hub_decision_id: "6777f9d1-566d-4bc7-815e-e08582b8719a"
|
||
```
|
||
|
||
## 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.
|
||
|
||
## GH-DEC-2026-012 — informed-decision is PEP-shaped and may emit a presentation claim; view_hash and the binding digest are distinct and non-substitutable
|
||
|
||
```yaml
|
||
id: GH-DEC-2026-012
|
||
kind: decision
|
||
title: informed-decision is PEP-shaped and may emit a presentation claim; view_hash
|
||
and the binding digest are distinct and non-substitutable
|
||
status: resolved
|
||
owner: Bernd Worsch
|
||
repo: gate-house
|
||
standard: net-kingdom/canon/standards/security-layer-model_v0.8.md
|
||
source_note: informed-decision/docs/gate-house-decision-request-layer-placement.md
|
||
(INFD-IN-0001; hub intake 01a08610)
|
||
requested_dispositions:
|
||
- approved
|
||
- revised
|
||
- rejected
|
||
affects:
|
||
- gate-house
|
||
- informed-decision
|
||
- approval-engine
|
||
- access-engine
|
||
- audit-core
|
||
- key-cape
|
||
- net-kingdom
|
||
decided_by: Bernd Worsch
|
||
rationale: 'Three rulings requested before any architecture was written. R1: informed-decision
|
||
is PEP-shaped under section 6.4 and owes companion section 5, because it causes
|
||
a protected side effect on the far side of a decision. It is not an Engine and holds
|
||
no state another layer reads at runtime for a verdict. R2: a component may be PEP-shaped
|
||
and also emit a claim; PEP and PIP are shapes a repository has, not layers it occupies,
|
||
and the catalog rows are layers. The presentation claim is permitted as a claim
|
||
about presentation only, subject to three limits: it must not carry, restate or
|
||
imply the decision or the approval verdict, it must not be an input to the decision
|
||
it presents for, and its evidence copy reaches audit-core independently of the emitter.
|
||
R3: candidate (b). view_hash and the approval binding digest are distinct attestations
|
||
with an explicit authority rule. (a) is refused because merging them would make
|
||
one repository the authority on what another layer computes over a request, which
|
||
is the objection GH-DEC-2026-008 made to translation. (c) is refused because nesting
|
||
the binding digest inside view_hash creates an ordering dependency and reproduces
|
||
the hash-cycle shape that made GH-DEC-2026-008 unimplementable. The binding digest
|
||
is authoritative for what the request is; view_hash is authoritative only for what
|
||
was shown; neither may be substituted for the other, and a disagreement between
|
||
them is a finding against the presenting surface rather than a fact about the request.'
|
||
created: '2026-09-09T20:09:49.402289Z'
|
||
updated: '2026-09-09T20:09:49.402289Z'
|
||
state_hub_decision_id: "8c3c0d14-91ca-43fd-bef3-3bd01ff4213f"
|
||
```
|
||
|
||
## Context
|
||
|
||
`informed-decision` is a new repository claiming the browser-facing approver UI that
|
||
`approval-engine` names under its own Non-Goals. It filed `INFD-IN-0001` **before
|
||
writing any architecture**, asking for three rulings and stating what it would do on
|
||
each possible answer, including the answers it did not want. That order — ruling first,
|
||
architecture second — is what §17 exists to produce and it is worth recording as the
|
||
reason this was answered inside a day.
|
||
|
||
It also argued the self-dealing objection against itself in §3 of its request, and asked
|
||
that no ruling credit it with closing the residual it named. That request is honoured
|
||
below.
|
||
|
||
## Decision
|
||
|
||
### R1 — `informed-decision` is PEP-shaped, and is not an Engine
|
||
|
||
**Confirmed as proposed.** It causes a protected side effect on the far side of a
|
||
decision: it submits an approval entry carrying an authenticated human's identity. §6.4
|
||
applies in full, and companion §5 is owed.
|
||
|
||
It is **not** an Engine and takes no catalog row as one. It holds no state another layer
|
||
reads at runtime to reach a verdict, which is the test, and it renders no decision.
|
||
|
||
Being PEP-shaped does not move a repository out of its layer (§6.4). Its layer is its
|
||
own to declare in its own voice; this ruling settles its *shape*, which is what was
|
||
asked and what was blocking.
|
||
|
||
Consequences it should expect, stated so they are not discovered later:
|
||
|
||
- A published unreachable-engine stance map at a path named in its layer declaration,
|
||
and a row in statute §13.1. Build to **v0.8's** obligation 3 rather than v0.7's:
|
||
`unknown` MUST resolve to `fail_closed`, the map MUST enumerate its axis rather than
|
||
lean on a catch-all, an `absent` scope MUST be distinguishable in the record from an
|
||
`unknown` one, and the test asserting published-equals-shipped is a `MUST`. Publish a
|
||
classification-coverage figure beside the stance (`GH-DEC-2026-011`).
|
||
- §6.4 obligation 1 in its v0.8 form, including the attribution property it cannot
|
||
satisfy today (`GH-DEC-2026-010`). It inherits a declared gap, not a clean path, and
|
||
its own documents must say so rather than describing validation as complete.
|
||
|
||
### R2 — Yes, and it is not a second catalog row
|
||
|
||
**A component may be PEP-shaped and also emit a claim.** PEP and PIP are *shapes* a
|
||
repository has; the §4 catalog records *layers* a repository occupies. Nothing in the
|
||
statute forbids one component having two shapes, and the rule that looks like it does —
|
||
§6.4 obligation 5's *"a PIP MUST NOT republish the PDP's decision"* — is a prohibition on
|
||
**republishing a decision**, not on holding two shapes. `informed-decision` proposed
|
||
exactly this reading and it is right.
|
||
|
||
Three limits, and they are the substance of the permission:
|
||
|
||
1. **The presentation claim carries presentation and nothing else.** It MUST NOT carry,
|
||
restate, summarise, or imply the decision, the approval verdict, or whether the act
|
||
was permitted. A consumer must not be able to learn from this claim anything about
|
||
what was *decided* — only about what was *shown*. This is obligation 5 applied at
|
||
issue rather than at consumption.
|
||
2. **It MUST NOT be an input to the decision it presents for.** Presentation is evidence
|
||
about conduct, never a source of authority. A policy that reads `view_hash` to decide
|
||
whether an act is permitted would let the presenting surface contribute to its own
|
||
authorization, which is the estate's oldest rule in a new place: cognition proposes,
|
||
authority disposes.
|
||
3. **The evidence copy reaches `audit-core` independently of the emitter.** The claim
|
||
endpoint and the evidence path are different things and one does not substitute for
|
||
the other. Audit evidence is protected from the actor being audited, and here the
|
||
actor and the source are the same component — so the copy that is evidence must not
|
||
be reachable only through the party it is evidence about.
|
||
|
||
**The §17 yield is accepted as offered.** Whatever shape `informed-decision` publishes
|
||
yields to the shared request-claim schema when that schema has an owner, which it does
|
||
not yet (§17 records request-claim and gap-record as the two unsettled artifacts). The
|
||
position matches `approval-engine`'s in `APPROVAL-IN-0001` and is the right one: a local
|
||
invention declared temporary is tolerable, a local invention declared permanent is the
|
||
drift §17 exists to prevent.
|
||
|
||
### R3 — Candidate (b): distinct attestations, with the authority rule stated
|
||
|
||
**`view_hash` and `approval-engine`'s binding digest are two attestations over one act,
|
||
and neither may be substituted for the other.**
|
||
|
||
- **The binding digest is authoritative for what the request *is*.** Replay identity,
|
||
correspondence with the decision, and everything §6.4 obligation 5 governs.
|
||
- **`view_hash` is authoritative only for what was *shown*.** It attests presentation:
|
||
brief, packet, highlights, locale, UI release, and the binding material as rendered.
|
||
- **A disagreement between them is a finding against the presenting surface, never a
|
||
fact about the request.** This is the rule that keeps the two from becoming rival
|
||
answers to one question, and it is the thing `informed-decision` asked us to prevent.
|
||
|
||
**(a) is refused, and for a doctrinal reason rather than the cost given.** One digest
|
||
means one canonicalization authoritative for both, and the material is owned by
|
||
different layers: what a request *is* is computed by the decision path, what was *shown*
|
||
is known only to the presenting surface. Merging them makes one repository the authority
|
||
on what another layer computes over a request — a third authority on what a request is,
|
||
which is precisely the objection `GH-DEC-2026-008` made to cross-engine translation. The
|
||
cost `informed-decision` names is real and secondary: the binding digest must exist where
|
||
no human is in the loop, and `view_hash` cannot exist there at all.
|
||
|
||
**(c) is refused for two reasons, the second the stronger.** First, the ordering
|
||
dependency it admits: an approval would have to exist before a memo could be rendered,
|
||
which inverts the flow this repository exists to serve. Second, and this is why we will
|
||
not take it even if the ordering were acceptable — nesting one hash inside the other
|
||
reproduces the shape that made `GH-DEC-2026-008` unimplementable. That ruling required a
|
||
claim to name the digest of a request that would come to contain the claim: a hash cycle,
|
||
found by `secrets-engine` and reported independently by two engines within hours. If
|
||
`view_hash` ever travels inside hashed request material while containing the binding
|
||
digest, the same cycle reappears with the same fail-closed consequence. We have paid for
|
||
that lesson once this quarter and are not buying it a second time.
|
||
|
||
**How the two are linked, since they are no longer linked by nesting.** By
|
||
**co-reference, not by translation**: the presentation record carries the approval or
|
||
binding identifier explicitly, and both attestations are read against that one reference.
|
||
`informed-decision` MUST NOT recompute or restate `approval-engine`'s binding digest from
|
||
its own vocabulary — it references the digest the other layer computed and recorded. That
|
||
is `GH-DEC-2026-008`'s identity-not-translation rule applied here, and it is why the two
|
||
canonicalizations covering overlapping material is not a defect: they answer different
|
||
questions and are compared to nothing.
|
||
|
||
## The residual, not closed and not credited
|
||
|
||
`informed-decision` stated it against itself and asked not to be credited with closing
|
||
it. **It is not closed, and this ruling does not close it.** A compromised surface can
|
||
present X and attest Y, because `view_hash` is computed by the component that renders.
|
||
|
||
That is structurally the same residual `approval-engine` names for adversarial omission
|
||
at a compromised source, and it takes the same disposition: attestation and atomicity
|
||
cover accident and later tampering, never a compromised source. It belongs in the same
|
||
register as §6.4 obligation 5's summary-predicate residual and §9.6's — detection, not
|
||
prevention.
|
||
|
||
The §3 argument that this is *not* the failure that kept the approval object out of
|
||
`access-engine` is accepted. An evaluator owning what it evaluates can grade its own
|
||
inputs; a renderer attesting its own rendering is the only party able to produce the
|
||
record at all. The distinction holds — but limit 2 above is what keeps it holding, and
|
||
without it the two collapse.
|
||
|
||
## Reversal condition
|
||
|
||
R2's permission reverses if a presentation claim is ever found carrying decision
|
||
content, or if a policy is found reading `view_hash` as an authorization input. Either
|
||
would mean the shape cannot be held safely by one component and the claim moves to
|
||
`audit-core` as the request's own R2-refused branch describes.
|
||
|
||
R3 §(b) reverses if the shared request-claim schema (§17) arrives with a presentation
|
||
attestation already in it, in which case the local shape yields as offered.
|
||
|
||
## Provenance
|
||
|
||
Requested by `informed-decision` (`INFD-IN-0001`, hub intake `01a08610`) before writing
|
||
its architecture, with three candidate rulings, their costs, the self-dealing objection
|
||
argued against itself, and an explicit list of what it was *not* asking for. Unblocks
|
||
`INFD-WP-0001` T05 and T07, and `KEY-WP-0013-T02`.
|
||
|
||
## GH-DEC-2026-013 — A client registration may supply a human principal's tenant only as a declared bounded gap, and the claim must carry its provenance
|
||
|
||
```yaml
|
||
id: GH-DEC-2026-013
|
||
kind: decision
|
||
title: A client registration may supply a human principal's tenant only as a declared
|
||
bounded gap, and the claim must carry its provenance
|
||
status: resolved
|
||
owner: Bernd Worsch
|
||
repo: gate-house
|
||
standard: net-kingdom/canon/standards/security-layer-model_v0.8.md
|
||
source_note: key-cape/docs/tenant-claim-contract.md and src/internal/server/oidc/token.go
|
||
humanTenant (KEY-WP-0013-T05); relayed by informed-decision
|
||
requested_dispositions:
|
||
- approved
|
||
- revised
|
||
- rejected
|
||
affects:
|
||
- gate-house
|
||
- key-cape
|
||
- approval-engine
|
||
- access-engine
|
||
- user-engine
|
||
- informed-decision
|
||
- net-kingdom
|
||
- ops-warden
|
||
decided_by: Bernd Worsch
|
||
rationale: 'key-cape has no adapter populating the directory user tenant, so every
|
||
human token falls back to the default tenant and approval-engine refuses it by exact
|
||
match. Two resolutions were possible: source the tenant from the directory, or let
|
||
a client registration bind it. Directory-sourced is the terminal state, because
|
||
a tenant is a property of the principal and a registration is a statement about
|
||
the actor; sourcing a principal attribute from the actor collapses two identities
|
||
the estate keeps distinct, and supplying a tenant the directory has not assigned
|
||
widens rather than attenuates. The registration-bound shape is nonetheless admissible
|
||
as a declared bounded gap rather than refused, because its distinguishing case fails
|
||
closed: where the registration and the directory disagree, issuance is refused rather
|
||
than resolved in either direction. That is the general property this record states
|
||
— a transitional shape is admissible where it fails closed on exactly the case that
|
||
distinguishes it from the correct resolution, and inadmissible where it fails open
|
||
there, which is why GH-DEC-2026-011 declined ops-warden a transitional fail_open
|
||
and this record grants key-cape its transitional binding. Three conditions attach:
|
||
refusal on disagreement is normative rather than a design choice, the exclusion
|
||
of dynamic client registration is a normative precondition whose lifting voids the
|
||
rule rather than reopening it, and the gap is registered with an owner for the directory
|
||
adapter. One finding is added that was not asked for: the tenant claim is emitted
|
||
as a bare string, so a consumer cannot tell a tenant the directory asserted about
|
||
the person from one a registration supplied about the client, and a consumer relying
|
||
on it for the first is relying on the second. The claim MUST carry its provenance.'
|
||
created: '2026-09-09T21:18:11.679012Z'
|
||
updated: '2026-09-09T21:18:11.679012Z'
|
||
state_hub_decision_id: "fcc0c595-7081-404e-b2aa-1536e91a371c"
|
||
```
|
||
|
||
## Context
|
||
|
||
`key-cape` binds the approval chain to the landlord zone (`tenant:platform`), and
|
||
`approval-engine` compares the tenant claim by exact string equality. **No adapter
|
||
populates `domain.User.Tenant`**, so every human token fell back to `tenant:coulomb` and
|
||
an approver token would have been refused downstream — presenting as a *failed approval*
|
||
rather than as a *registration defect*, which is the failure mode that makes this worth
|
||
ruling on rather than leaving to implementation.
|
||
|
||
Two resolutions were available: source the tenant from the directory, or let a client
|
||
registration declare it. `key-cape` declined to choose unilaterally on the ground that
|
||
the second writes a cross-tenant capability into the issuer, which reads as doctrine
|
||
rather than implementation. That reading is correct and the question is Gate House's:
|
||
it is about what may be a source of a principal's identity, which is a Core Rule, not a
|
||
runbook.
|
||
|
||
It reached us relayed by `informed-decision`, which was asking about its own client
|
||
registration and passed on a question that was not its own. `key-cape` has already
|
||
built the registration-bound shape, and built it carefully — this record rules on a
|
||
design that exists rather than on a proposal.
|
||
|
||
## Decision
|
||
|
||
### 1. Directory-sourced is the terminal state
|
||
|
||
**A principal's tenant is sourced from the identity layer's record of the principal.**
|
||
A client registration is a statement about the **actor** — the client the person
|
||
authenticated through. A tenant is a property of the **principal**. Sourcing the second
|
||
from the first collapses two of the three identities the estate keeps distinct
|
||
(principal, actor, runtime identity), and it collapses them in the direction that
|
||
widens: a registration supplying a tenant the directory has not assigned gives the
|
||
principal an attribute the identity layer never asserted about them. **Delegation
|
||
attenuates and never widens.**
|
||
|
||
The condition being routed around is a missing adapter, not an absent owner. A missing
|
||
implementation in the identity layer is fixed in the identity layer.
|
||
|
||
### 2. The registration-bound shape is admissible as a declared, bounded gap
|
||
|
||
**Not refused, and not blessed as permanent.** `key-cape` may ship what it has built,
|
||
under §3's conditions and registered as a gap.
|
||
|
||
The reason it is admissible rather than forbidden is precise, and is not that the design
|
||
is careful. It is that **the case distinguishing it from the correct resolution fails
|
||
closed.** Where the registration declares a zone and the directory has placed the user
|
||
in a different one, `humanTenant` refuses to issue rather than picking a winner. Either
|
||
answer would be a silent cross-tenant assertion, and the design says so. A registration
|
||
can bind a zone for a user the directory has not placed; it can never relabel one it has.
|
||
|
||
`key-cape`'s further observation is what makes the gap bounded rather than open-ended:
|
||
the same code turns from *supplying* the zone into *enforcing agreement with* it the
|
||
moment the directory carries tenants — no second migration, and no window in which a
|
||
stale registration silently wins. A transitional shape that converges on the terminal
|
||
state by subtraction is a different object from one that will have to be unwound.
|
||
|
||
### 3. The general property, which is why this is granted and `GH-DEC-2026-011` was declined
|
||
|
||
**A transitional shape is admissible where it fails closed on exactly the case that
|
||
distinguishes it from the correct resolution, and inadmissible where it fails open
|
||
there.**
|
||
|
||
This is §8's asymmetry applied to transitions, and it is the rule that keeps these two
|
||
decisions consistent rather than merely both defensible:
|
||
|
||
- `ops-warden` asked for a dated transitional `unknown: fail_open` (`GH-DEC-2026-011`).
|
||
**Declined.** The distinguishing case — an unclassified subject reaching an unreachable
|
||
engine — is exactly where the transitional shape fails **open**. It is behaviourally
|
||
identical to the violation for the whole of its life, so the transition licenses the
|
||
thing the rule forbids and merely dates it.
|
||
- `key-cape` binds a tenant at registration. **Granted.** The distinguishing case —
|
||
registration and directory disagreeing — fails **closed**. The transitional shape and
|
||
the terminal state differ only where nobody is served either way.
|
||
|
||
A transition is a promise about the future. **A promise that fails open is a permission;
|
||
a promise that fails closed is a gap.** Only the second is a thing a register can hold.
|
||
|
||
### 4. Three conditions
|
||
|
||
1. **Refusal on disagreement is normative.** Row four of `key-cape`'s table is not a
|
||
design choice it may later optimise. A registration MUST NOT relabel a
|
||
directory-placed principal, and MUST NOT resolve the conflict in either direction.
|
||
Any future change that picks a winner — in either direction, including preferring the
|
||
directory — voids this permission, because it converts a refusal into a silent
|
||
cross-tenant assertion.
|
||
2. **The exclusion of dynamic client registration is a normative precondition, and
|
||
lifting it VOIDS this rule rather than reopening it.** `key-cape` writes that a
|
||
self-service client able to name its users' tenant would be a straightforward
|
||
escalation, and that the rule "must be revisited" if the exclusion is lifted. That is
|
||
too weak and we are strengthening it: revisiting implies the answer might survive
|
||
review. It does not. If dynamic client registration is ever admitted, the
|
||
registration-bound shape is void on that day and the directory becomes the only
|
||
source, whatever state the adapter is in. Stated that way so that lifting the
|
||
exclusion cannot be a small change made by someone who never reads this record.
|
||
3. **Registered as a declared gap under §13**, with an intended owner for the directory
|
||
adapter, so it cannot quietly become the permanent answer by nobody minding it. Per
|
||
§13, an intended owner is a proposal **to** a repository, not an assignment **onto**
|
||
it; this record does not name one.
|
||
|
||
### 5. The finding that was not asked for: the claim must carry its provenance
|
||
|
||
`key-cape` emits `tenant` as a bare string. A consumer cannot tell a tenant **the
|
||
directory asserted about the person** from a tenant **a registration supplied about the
|
||
client they came through**. `approval-engine` admits an approver by exact-matching that
|
||
string, and it is therefore relying on the second while its contract reads as though it
|
||
relies on the first.
|
||
|
||
**This is the shape of `GH-DEC-2026-010`, one layer down.** There, a PEP held a decision
|
||
and could establish which request it was for but not who issued it, while a mechanical
|
||
test read as though it discharged both. Here a consumer holds a tenant and can establish
|
||
that the string matches, but not whether the identity layer ever said it about this
|
||
person. In both cases the check is sound and the property a reader infers from it is not
|
||
present.
|
||
|
||
**The `tenant` claim MUST carry its provenance** — whether the value was asserted by the
|
||
directory about the principal, or supplied by the registration — and a consumer MUST NOT
|
||
treat the two as equivalent for any decision that turns on a fact about the *person*.
|
||
|
||
**Amended 2026-09-10 — `key-cape` emitted three values where this record named two, and
|
||
it was right to.** Its third is `default`: nobody asserted a zone and the profile's
|
||
non-empty fallback supplied one. Folding that into `directory` would have reproduced this
|
||
very finding one level down, since a consumer would read an assertion the identity layer
|
||
never made. `key-cape` applied A-16 to a route this record did not examine, and asked to
|
||
be corrected rather than assume — the correction is that there was nothing to correct.
|
||
|
||
Its second judgement is also endorsed: where registration and directory **agree**, the
|
||
value resolves to `directory`, because the directory did assert it about the person and
|
||
reporting the weaker source would understate what is known. That also makes the claim
|
||
strengthen on its own the day the adapter lands, with no reissue.
|
||
Exact-match admission on a registration-supplied tenant is admission on the client's
|
||
say-so.
|
||
|
||
The mechanism is `key-cape`'s: this record names the property, not the field. Note that
|
||
the same rule from `GH-DEC-2026-011` §3 applies to how it is recorded — two sources, one
|
||
claim value, and the record must distinguish them even though the string is identical.
|
||
It is `unknown` and `absent` again, in the identity layer.
|
||
|
||
**Sequencing:** this does not gate `KEY-WP-0013-T02`. The registration may be created
|
||
under §2 today. What must not happen is the path being described as validated while a
|
||
consumer cannot see which fact it is relying on.
|
||
|
||
### 6. `informed-decision`'s argument for registration-bound, answered
|
||
|
||
`INFD-IN-0002` arrived after this record was written, arguing for the registration-bound
|
||
resolution on a ground `key-cape` did not raise. `informed-decision`'s object model
|
||
separates a **pre-sign binding slice** — which commits which identity and which
|
||
scope/tenant is being entered — from awareness material shown but never signed. Under
|
||
registration-bound, it argues, the tenant is a property of the surface and its
|
||
registration, which is exactly what the binding slice commits; under directory-sourced it
|
||
describes the person, which sits closer to awareness than to binding.
|
||
|
||
**The argument is accepted, and it does not change §1. It sharpens the defect.**
|
||
|
||
What `informed-decision` describes is a real fact that deserves to be committed: *which
|
||
scope is this act being entered into*. That is a property of the **act**. It is not the
|
||
same fact as *which tenant is this person a member of*, which is a property of the
|
||
**principal** and is what `approval-engine` exact-matches to admit an approver.
|
||
|
||
The trouble is that one claim named `tenant` is being asked to carry both. That is why
|
||
the registration-bound shape feels correct to `informed-decision` and wrong to the
|
||
identity layer: each is looking at a different fact through the same field.
|
||
|
||
**Amended 2026-09-10: there are three facts, not two.** `approval-engine` answered this
|
||
record by naming the one it actually uses, and it is neither of the two above:
|
||
|
||
1. **Store isolation** — *did this caller arrive through a channel this store serves.* A
|
||
property of the **channel**. This is what `approval-engine`'s exact-match gate tests,
|
||
and it is what a registration-supplied tenant **is** adequate for: admission means
|
||
arrived through a registered channel, the approver client is static and
|
||
deployment-owned, and dynamic client registration is excluded.
|
||
2. **Act scope** — *which scope is this act being entered into.* A property of the
|
||
**act**. `informed-decision`'s binding slice needs this, and it resolved the point by
|
||
finding that its own `binding.target` already commits it — so the ruling required no
|
||
new field, only a statement that `binding.target` is the act-scope and MUST NOT be
|
||
derived from the token's `tenant` claim.
|
||
3. **Principal membership** — *is this person a member of this zone.* A property of the
|
||
**principal**. This is the one a registration-supplied tenant cannot carry, and the
|
||
one §1 reserves to the directory.
|
||
|
||
`approval-engine` committed to the consequence without being asked: a registration-
|
||
supplied tenant is admissible for (1) and **not** for any doctrine turning on (3), and it
|
||
asked to be held to that as *"the point at which a sound check silently becomes an unsound
|
||
one"*. Held. Note `GH-DEC-2026-016` §5 is the first place it bites.
|
||
|
||
Three facts in one field is a stronger case for §5 than two was. It also explains why
|
||
each party's intuition was locally correct: `approval-engine` reading (1) was right that
|
||
the registration suffices, `informed-decision` reading (2) was right that the fact is
|
||
act-scoped, and the identity layer reading (3) was right that a registration cannot supply
|
||
it. Nobody was wrong about their own fact; the field was wrong to hold all three. A binding
|
||
slice that must commit the scope being entered should **commit that scope**, not borrow
|
||
the principal's membership claim to stand in for it.
|
||
|
||
So `informed-decision` is right that its binding needs the fact, right that the fact is
|
||
act-scoped rather than person-scoped, and wrong that this makes the principal's `tenant`
|
||
claim the place to put it. Its argument is the best available evidence that §5's
|
||
provenance requirement is necessary: two facts sharing one field is exactly the condition
|
||
under which a consumer cannot tell what it is relying on.
|
||
|
||
This record does not design the second field. Whether the act-scope commitment is a
|
||
separate claim, part of the binding document, or something the request-claim schema
|
||
carries when §17 finds it an owner, is not doctrine and is not settled here.
|
||
|
||
## What this does not rule
|
||
|
||
Not ruled: whether `approval-engine`'s exact-match admission is the right gate, which is
|
||
`approval-engine`'s. Not ruled: which repository owns the directory adapter. Not ruled:
|
||
the choice of `tenant:platform` itself, which is settled by operator decision
|
||
`5ed3fb35-eca9-413a-82b9-95171ba85bf6` and is not doctrine.
|
||
|
||
## Reversal condition
|
||
|
||
§2 reverses on the day the directory populates the principal's tenant: the permission is
|
||
spent, not merely unused, and §1 governs alone.
|
||
|
||
§3's general property reverses if a case is found where a transitional shape failing
|
||
closed on its distinguishing case is nonetheless the more dangerous option — which would
|
||
mean the asymmetry rule has an exception, and §8 would be the thing under review rather
|
||
than this record.
|
||
|
||
§5 reverses if the two provenances are ever proven indistinguishable in effect, i.e. if
|
||
no consumer's decision turns on the difference. That is a claim about every present and
|
||
future consumer and we do not expect it to be made good.
|
||
|
||
## Provenance
|
||
|
||
Raised by `key-cape` (`KEY-WP-0013-T05`, `docs/tenant-claim-contract.md`), which built
|
||
the shape, documented its own escalation risk, and declined to ratify its own design.
|
||
Relayed by `informed-decision` while asking about its own registration — a repository
|
||
passing on a question that was not its to carry. `GH-DEC-2026-011`'s decline and this
|
||
record's grant are the two halves of §3, which neither request asked for and which is
|
||
the part of this record most likely to matter later.
|
||
|
||
## GH-DEC-2026-014 — A commitment-only evidence record satisfies non-alteration, never reconstructability, and its erasure must be detectable
|
||
|
||
```yaml
|
||
id: GH-DEC-2026-014
|
||
kind: decision
|
||
title: A commitment-only evidence record satisfies non-alteration, never reconstructability,
|
||
and its erasure must be detectable
|
||
status: resolved
|
||
owner: Bernd Worsch
|
||
repo: gate-house
|
||
standard: net-kingdom/canon/standards/security-layer-model_v0.8.md
|
||
source_note: informed-decision INFD-IN-0003
|
||
requested_dispositions:
|
||
- approved
|
||
- revised
|
||
- rejected
|
||
affects:
|
||
- gate-house
|
||
- informed-decision
|
||
- audit-core
|
||
- approval-engine
|
||
- net-kingdom
|
||
decided_by: Bernd Worsch
|
||
rationale: 'informed-decision asked what travels on the independent evidence path
|
||
that GH-DEC-2026-012 limit 3 requires, proposing commitment-only for stage 1 rather
|
||
than the full binding document, because the binding document carries commercial
|
||
and personal material that would enter the audit fabric under retention and export
|
||
entitlements designed for audit events. The payload schema and its retention are
|
||
audit-core custody and are not ruled here. Two things are doctrine. First, a commitment-only
|
||
record satisfies non-alteration and never reconstructability, and MUST NOT be described
|
||
as satisfying the second; this is the existing bound that an archive proves records
|
||
were not altered or truncated after arrival and never that one was never sent, applied
|
||
to a record that additionally does not carry what it commits to. Second, the gap
|
||
commitment-only leaves is availability rather than integrity, and it sits with the
|
||
actor being audited, so erasure or non-production of the committed content MUST
|
||
be detectable as a finding rather than present as an unremarkable absence. The independent
|
||
path therefore carries a declaration that content exists and where custody sits,
|
||
so that absence at retrieval is a conformance failure. Commitment-only is admissible
|
||
on the GH-DEC-2026-013 test because its distinguishing case fails closed: a reviewer
|
||
who cannot obtain the content gets no reconstruction rather than a wrong one. informed-decision
|
||
refusal of a separate evidence store is endorsed, on its own ground that it would
|
||
route around the section 16 archival-custody question by building a parallel archive
|
||
under another name.'
|
||
created: '2026-09-09T21:23:46.190170Z'
|
||
updated: '2026-09-09T21:23:46.190170Z'
|
||
state_hub_decision_id: "ae933280-873e-4226-b001-df94a1f00f50"
|
||
```
|
||
|
||
## Context
|
||
|
||
`GH-DEC-2026-012` limit 3 requires the evidence copy of a presentation record to reach
|
||
`audit-core` **independently of the emitter**, because in `informed-decision`'s case the
|
||
actor being audited and the evidence source are the same component. `INFD-IN-0003` asks
|
||
what travels on that path.
|
||
|
||
The candidate it rejects is emitting the **full binding document**, which would put
|
||
commercial and personal material — at L4, contract text — into the audit fabric under
|
||
retention and export entitlements designed for audit events. That objection is sound and
|
||
is not merely operational: an evidence path that forces content into a custody regime
|
||
built for a different class of data is a defect in the evidence path, not a cost of using
|
||
it.
|
||
|
||
It proposes **commitment-only** for Stage 1: hashes, principal, timestamps,
|
||
acknowledgements, co-referenced approval id, disposition verb, stance application. It
|
||
declares plainly that this leaves it able to **erase** the content, and asks not to be
|
||
credited with closing that.
|
||
|
||
It also refused a third option on its own initiative — a separate evidence store — on
|
||
the ground that it has no owner and would route around §16's open question on stronger
|
||
archival custody by building a parallel archive under another name.
|
||
|
||
## What is ruled here, and what is not
|
||
|
||
**Not ruled: the payload.** Which fields travel, in what schema, under what retention, is
|
||
`audit-core`'s custody question and it has it. This record does not design the record.
|
||
|
||
**Ruled: what may be claimed from a record of that shape, and what must remain visible
|
||
when it fails.** That is doctrine because it governs what a later reader is entitled to
|
||
conclude, and a reader's entitlement is not a custody decision.
|
||
|
||
## Decision
|
||
|
||
### 1. Commitment-only is admissible for Stage 1
|
||
|
||
Granted, on `GH-DEC-2026-013` §3's test: **its distinguishing case fails closed.** Where
|
||
the committed content is needed and cannot be obtained, a reviewer gets *no
|
||
reconstruction* rather than a *wrong* one. The record does not produce a confident
|
||
answer built on material nobody can check. Compare the shape refused there — a
|
||
transitional state that fails open on the case that distinguishes it is a permission
|
||
wearing a date.
|
||
|
||
The data-protection reason is accepted as a reason of the right kind. Forcing L4 contract
|
||
text into an audit fabric to satisfy an evidence obligation would trade one control for a
|
||
breach of another, and doctrine that produces that trade is wrong rather than merely
|
||
expensive.
|
||
|
||
### 2. It satisfies non-alteration. It does not satisfy reconstructability, and MUST NOT be described as doing so
|
||
|
||
This repository already holds that **an archive proves records were not altered or
|
||
truncated after arrival, never that one was never sent.** A commitment-only record is
|
||
weaker again: it additionally does not carry what it commits to. So it establishes that
|
||
the *commitment* was made when it says and has not changed since. It establishes nothing
|
||
about what was committed to, except conditionally — *if* a document is later produced,
|
||
whether it is the one.
|
||
|
||
**A commitment-only record MUST NOT be described as satisfying reconstructability**, in
|
||
`informed-decision`'s documents, in `audit-core`'s, or in any conformance claim. Every
|
||
privileged action being reconstructable from the evidence is a property of the estate's
|
||
audit obligation; a hash of an absent document does not have it and no amount of
|
||
integrity on the hash supplies it.
|
||
|
||
This is the same discipline the §6.4 obligation-1 gap has: the check is sound, and the
|
||
property a reader infers from it is not present unless it is stated to be absent.
|
||
|
||
### 3. The gap is availability, not integrity — and it sits with the audited party
|
||
|
||
Say it in those words, because "we can erase the content" understates where the problem
|
||
is. Commitment-only moves **integrity** out of the emitter's control and leaves
|
||
**availability** entirely inside it. The party that can withhold the content is the party
|
||
the evidence is about.
|
||
|
||
That is precisely the condition limit 3 exists to prevent, reduced but not removed. The
|
||
reduction is real — the emitter can no longer alter the record, which is the more common
|
||
failure — and it is not sufficient on its own.
|
||
|
||
### 4. Non-production MUST be detectable as a finding, not present as an absence
|
||
|
||
**This is the condition that makes §1's grant safe, and it is the part `INFD-IN-0003` did
|
||
not propose.**
|
||
|
||
If the independent path holds only a commitment, a reviewer who asks for the content and
|
||
receives nothing cannot distinguish *erased*, *withheld*, *lost*, and *never held*. The
|
||
absence reads as an unremarkable blank rather than as evidence of anything.
|
||
|
||
The independent path MUST therefore carry, alongside the commitment, **a declaration that
|
||
committed content exists and where custody sits**, such that failure to produce it at
|
||
retrieval is a **conformance failure** attributable to the custodian rather than a silent
|
||
gap in the record. A commitment with no accompanying assertion that something is being
|
||
committed to is indistinguishable from a commitment to nothing.
|
||
|
||
**Amended 2026-09-10 — detection sits with the reviewer, not with the archive.**
|
||
`audit-core` accepted this condition and corrected its wording, and the correction is
|
||
load-bearing enough that leaving it as an assumption would have made this section wrong.
|
||
The archive **carries** the declaration; it does not **detect** non-production. It
|
||
performs no retrieval, holds no client for the emitting repository, and its egress policy
|
||
permits nothing that would let it try — asserted by a test, because the claim silently
|
||
stops being true the day someone adds one.
|
||
|
||
So the mechanism is: the **reviewer** discovers non-production at retrieval, and the
|
||
stored declaration is what makes that discovery a **finding** rather than a blank —
|
||
because the reviewer holds a chained, timestamped statement that content existed and where
|
||
custody sat. Nothing in this section requires an archive to chase content, and it MUST NOT
|
||
be read as requiring it. An archive that fetched from the parties it audits would be
|
||
acquiring exactly the dependency that makes it corruptible by them.
|
||
|
||
**And the residual this creates, stated rather than left to be found.** A custodian that
|
||
never held the content can emit a false `content_exists`; the archive validates the
|
||
declaration's **shape**, never its **truth**. That is the same class as omission at source
|
||
— an archive cannot retrofit a property the boundary did not have — and it is closed by
|
||
neither the hash chain, nor attestation, nor `T-04`/`T-06`.
|
||
|
||
What §4 actually buys is narrower than it first reads, and this is the honest statement of
|
||
it: **the declaration converts an unattributable absence into an attributable false
|
||
statement.** Strictly better, and not the same as proof. Raised by `audit-core` against
|
||
its own delivered work, with the observation that the distinction is better in this text
|
||
now than in a conformance argument later.
|
||
|
||
This is `GH-DEC-2026-011` §3's rule in its third setting: two states, one observable
|
||
appearance, and the record must distinguish them. There it was `unknown` versus `absent`
|
||
in a stance map; in `GH-DEC-2026-013` §5 it was directory-asserted versus
|
||
registration-supplied in an identity claim; here it is *erased* versus *never held* in an
|
||
evidence path. The recurrence is the point — wherever a system can reach one appearance
|
||
by two routes, the record must say which route, or the safer reading of the appearance
|
||
becomes unavailable to everyone.
|
||
|
||
### 5. The refusal of a separate evidence store is endorsed
|
||
|
||
`informed-decision` refused it on the ground that it has no owner and would route around
|
||
§16's archival-custody question by building a parallel archive under another name. That
|
||
reasoning is correct and we would keep it as written.
|
||
|
||
Add one thing to it: an evidence store owned by the party whose conduct it evidences is
|
||
not an evidence store, whatever its integrity properties. The ownership objection is
|
||
prior to the custody one.
|
||
|
||
### 6. The residual is not closed and is not credited
|
||
|
||
`informed-decision` asked, again, not to be credited with closing what it has not closed.
|
||
Honoured, again. The erasure gap stands alongside the compromised-surface residual from
|
||
`GH-DEC-2026-012`, and §4 narrows the first without closing it: a detectable
|
||
non-production tells a reviewer that something is missing and who owed it. It does not
|
||
produce the missing thing.
|
||
|
||
## Reversal condition
|
||
|
||
§1 reverses if commitment-only is found to be load-bearing for a reconstruction that
|
||
actually had to be performed and could not be — i.e. if the availability gap is realised
|
||
rather than theorised. Stage 1 is a stage; the burden is on the shape to keep earning it.
|
||
|
||
§4 is not a reversal candidate. If it turns out to be expensive, the answer is a cheaper
|
||
mechanism for the same property, never the property's removal.
|
||
|
||
## Provenance
|
||
|
||
Raised by `informed-decision` (`INFD-IN-0003`), which proposed the shape, declared the
|
||
gap it leaves, refused a third option against its own convenience, and asked which half
|
||
of the question was doctrine. The half that was is ruled here; the payload is
|
||
`audit-core`'s and it has it. §4 was not requested by anyone.
|
||
|
||
## GH-DEC-2026-015 — GH-DEC-2026-012 R3 revised: nesting is permitted for this pair, conditioned on the exclusion being normative
|
||
|
||
```yaml
|
||
id: GH-DEC-2026-015
|
||
kind: decision
|
||
title: 'GH-DEC-2026-012 R3 revised: nesting is permitted for this pair, conditioned
|
||
on the exclusion being normative'
|
||
status: resolved
|
||
owner: Bernd Worsch
|
||
repo: gate-house
|
||
standard: net-kingdom/canon/standards/security-layer-model_v0.8.md
|
||
source_note: informed-decision/docs/finding-r3-linkage-conflict.md (INFD-IN-0004);
|
||
approval-engine docs/approval-claim.md @ 62233c7
|
||
requested_dispositions:
|
||
- approved
|
||
- revised
|
||
- rejected
|
||
affects:
|
||
- gate-house
|
||
- informed-decision
|
||
- approval-engine
|
||
- access-engine
|
||
- net-kingdom
|
||
decided_by: Bernd Worsch
|
||
rationale: 'GH-DEC-2026-012 R3 refused option (c) and required linkage by co-reference.
|
||
approval-engine, answering the same question from the layer that owns the digest,
|
||
recommended exactly (c). informed-decision could not comply with both and raised
|
||
it as a finding rather than choosing, which is the correct handling. The refusal
|
||
is revised on two grounds. First, the hash-cycle objection requires mutual containment,
|
||
and approval-engine has since published that its binding digest covers exactly five
|
||
act fields and that widening it to cover presentation would be a defect for an independent
|
||
reason - a new UI release would invalidate every prior approval - so one-directional
|
||
nesting raises no cycle. Second and decisively, co-reference by identifier alone
|
||
leaves informed-decision independently canonicalizing principal and target, two
|
||
of the five fields in the other layer digest, which is a partial recomputation of
|
||
one act in a second vocabulary and is closer to the translation R3 forbade than
|
||
nesting is. The original ruling therefore worked against its own rule. Nesting is
|
||
permitted for this pair, conditioned on approval-engine stating the presentation
|
||
exclusion as normative and testable rather than as design intent, because the cycle
|
||
cannot arise here is a belief and the cycle may not arise here is a rule with an
|
||
owner. The ordering objection is withdrawn as mistaken: the digest is over act material
|
||
and is computable before a human is presented anything.'
|
||
created: '2026-09-10T13:19:48.436344Z'
|
||
updated: '2026-09-10T13:19:48.436344Z'
|
||
state_hub_decision_id: "5063b6a3-5f99-4558-beb6-f4c494a46bfc"
|
||
```
|
||
|
||
## Context
|
||
|
||
`GH-DEC-2026-012` R3 ruled that `view_hash` and `approval-engine`'s binding digest are
|
||
distinct attestations linked by **co-reference**, and refused option (c) — `view_hash`
|
||
carrying the binding digest as a field — on two grounds: an ordering dependency, and the
|
||
`GH-DEC-2026-008` hash cycle.
|
||
|
||
`approval-engine` then answered the same question in `docs/approval-claim.md` (`62233c7`)
|
||
and recommended **exactly (c)**: that `informed-decision`'s binding document carry
|
||
`binding.digest` as a field rather than re-canonicalize `action`/`actor`/`principal`/
|
||
`purpose`/`target` itself, so there is one canonicalization of the act, computed by the
|
||
layer that owns it.
|
||
|
||
`informed-decision` could not comply with both, **made no design change**, and raised it
|
||
as a finding. That is the correct handling and it is worth naming: it declined to adopt a
|
||
recommendation that came from the layer owning the artifact, having previously offered to
|
||
let that layer settle R3 bilaterally, on the ground that a bilateral agreement produces
|
||
agreement rather than an authority rule. It applied that reasoning against its own
|
||
convenience twice.
|
||
|
||
## Decision
|
||
|
||
### 1. The refusal of (c) is revised. Nesting is permitted for this pair
|
||
|
||
**`view_hash` MAY carry `binding.digest` as a field**, and `informed-decision`'s binding
|
||
slice then stops independently canonicalizing act material. One canonicalization of the
|
||
act, computed by the layer that owns the act, committed to by reference.
|
||
|
||
### 2. The cycle objection does not hold here, and the reason it does not is narrow
|
||
|
||
`GH-DEC-2026-008`'s cycle required **mutual containment**: a claim had to name the digest
|
||
of a request that would come to contain that claim. `approval-engine` has since published
|
||
that `binding.digest` covers exactly five act fields, and that widening it to cover
|
||
presentation material **would be a defect** — a new UI release would change the digest of
|
||
an act whose act did not change, invalidating every prior approval. So the containment is
|
||
one-directional and no cycle arises.
|
||
|
||
`informed-decision` declined to assert that this settles it, on the ground that *"the
|
||
cycle cannot arise here"* is precisely the belief such failures punish. That caution is
|
||
correct and is why §4 exists rather than a bare permission.
|
||
|
||
### 3. The decisive ground is that the original ruling worked against its own rule
|
||
|
||
R3 required: *"You MUST NOT recompute or restate `approval-engine`'s binding digest from
|
||
your own vocabulary."* But `informed-decision`'s binding slice canonicalizes `principal`
|
||
and `target` — **two of the five fields in that digest**. Under co-reference by
|
||
identifier alone, two independent canonicalizations of one act exist, linked by a shared
|
||
id, and the presenting surface is performing a partial recomputation of the other layer's
|
||
material in its own vocabulary.
|
||
|
||
**That is closer to the translation R3 forbade than nesting is.** Co-reference by id
|
||
*manages* the duplication with an authority rule; nesting *removes* it. Removing a
|
||
failure mode beats managing one, and the original ruling reached for the management
|
||
option while stating the rule that recommends the removal.
|
||
|
||
This is the second time this month a Gate House ruling has been correct in substance and
|
||
wrong in the mechanism it prescribed, found by the repository that had to build on it.
|
||
The pattern is recorded rather than smoothed over: `GH-DEC-2026-008` mandated a
|
||
comparison that could never pass; this one mandated a linkage that reintroduced the thing
|
||
it forbade.
|
||
|
||
### 4. Condition: the exclusion becomes normative, not intentional
|
||
|
||
**Permission under §1 is conditioned on `approval-engine` stating, as a rule rather than
|
||
as design intent, that `binding.digest` MUST NOT cover presentation material** — and on
|
||
that constraint being asserted by a test, so that widening fails loudly rather than
|
||
silently.
|
||
|
||
`approval-engine` already holds the reason, and it is a good one that does not depend on
|
||
this ruling: widening would invalidate every prior approval on a UI release. What it does
|
||
not yet hold is the *rule*. The difference is exactly A-17's precondition — the
|
||
distinguishing case here is *someone widens the digest*, and today that case is
|
||
unobservable until approvals start failing. Making it observable is a precondition of the
|
||
permission, not a follow-up to it.
|
||
|
||
Until that lands, `GH-DEC-2026-012` R3's co-reference form remains in force.
|
||
`informed-decision` changes nothing on its own initiative; the permission activates when
|
||
the condition is met.
|
||
|
||
### 5. What does not change
|
||
|
||
- **The authority rule stands.** The binding digest is authoritative for what the request
|
||
*is*; `view_hash` is authoritative only for what was *shown*. Under §1 the two can no
|
||
longer disagree about the act, which retires the disagreement case rather than
|
||
reversing the rule that governed it.
|
||
- **(a) remains refused**, on its original and undisturbed ground: merging the two
|
||
canonicalizations would make one repository authoritative over another layer's
|
||
material.
|
||
- **`view_hash` still MUST NOT travel inside hashed request material while containing the
|
||
binding digest.** §2's one-directionality is a fact about the present pair, not a
|
||
licence. If a future design puts `view_hash` inside a hashed request, the cycle
|
||
reappears and this permission is void for that path.
|
||
|
||
### 6. The ordering objection is withdrawn as mistaken
|
||
|
||
`GH-DEC-2026-012` gave an ordering dependency as (c)'s first cost, taking it from
|
||
`informed-decision`'s own statement of it. It does not hold: `binding.digest` is computed
|
||
over **act material**, which is determined before a human is presented anything. The
|
||
approval need not exist before the memo is rendered — only the act need be determined,
|
||
which it is by construction.
|
||
|
||
Recorded rather than dropped, because a cost accepted from the requester and never
|
||
checked is how a wrong reason survives into a ruling.
|
||
|
||
## On the exposure `informed-decision` asked to have visible
|
||
|
||
It asked that if co-reference stood, the record show that it would be the party a
|
||
disagreement was a finding against, for a disagreement arising from **two correct
|
||
canonicalizations** rather than from any defect of its own — the design creating the
|
||
exposure, not its conduct.
|
||
|
||
That request is granted in a better form: §1 removes the exposure rather than documenting
|
||
it. The asymmetry it accepted was right in principle and it should not have had to carry
|
||
it in practice.
|
||
|
||
## Reversal condition
|
||
|
||
§1 reverses if `approval-engine`'s digest ever widens to cover presentation material,
|
||
which §4's rule exists to prevent and which would restore mutual containment. It also
|
||
reverses for any path that places `view_hash` inside hashed request material.
|
||
|
||
## Provenance
|
||
|
||
Raised by `informed-decision` (`INFD-IN-0004`), which made no design change, declined a
|
||
recommendation from the layer owning the artifact, applied Gate House's own bilateral-
|
||
settlement reasoning against its own convenience, and supplied the published-coverage
|
||
fact the original refusal did not have. `approval-engine` supplied the recommendation and
|
||
the structural reason behind it.
|
||
|
||
## GH-DEC-2026-016 — Where an approval discharges a human-in-the-loop control, the approver must be a human principal and the engine must refuse at bind time
|
||
|
||
```yaml
|
||
id: GH-DEC-2026-016
|
||
kind: decision
|
||
title: Where an approval discharges a human-in-the-loop control, the approver must
|
||
be a human principal and the engine must refuse at bind time
|
||
status: resolved
|
||
owner: Bernd Worsch
|
||
repo: gate-house
|
||
standard: net-kingdom/canon/standards/security-layer-model_v0.8.md
|
||
source_note: informed-decision INFD-IN-0004 section 6 (NC-03); approval-engine, which
|
||
declined to invent the rule
|
||
requested_dispositions:
|
||
- approved
|
||
- revised
|
||
- rejected
|
||
affects:
|
||
- gate-house
|
||
- approval-engine
|
||
- informed-decision
|
||
- access-engine
|
||
- audit-core
|
||
- net-kingdom
|
||
decided_by: Bernd Worsch
|
||
rationale: 'approval-engine records the approver principal type as auditable metadata
|
||
but restricts only /consume by principal type, and its own operator service client
|
||
holds approval:approve, so a service principal can supply approver evidence for
|
||
a control whose purpose is to put human judgment in the path. informed-decision
|
||
enforces humans-bind-agents-draft at its own surface and correctly observed that
|
||
without an engine-side refusal its enforcement is one component policy rather than
|
||
a property of the approval object. Both referred the question up rather than settling
|
||
it. Ruled: where an approval is declared as discharging a human-in-the-loop or dual-control
|
||
requirement, the approver MUST be a human principal and approval-engine MUST refuse
|
||
a non-human bind at issue rather than record it. Recording the principal type after
|
||
the fact is detection and not prevention, which is the distinction this repository
|
||
applies everywhere else, and an approval control satisfiable by the same class of
|
||
actor it exists to check is theatre. The rule attaches to approvals declared as
|
||
discharging such a control rather than to all approvals, because service-to-service
|
||
approvals are legitimate and the requirement must be declared at issue and never
|
||
inferred - the same shape approval-engine established for pdp_path. Enforcement
|
||
at one surface is insufficient because a second caller reaching the engine directly
|
||
bypasses it, and the property belongs to the object rather than to whichever component
|
||
happens to create it.'
|
||
created: '2026-09-10T13:20:35.560626Z'
|
||
updated: '2026-09-10T13:20:35.560626Z'
|
||
state_hub_decision_id: "1139bb2f-7774-4559-bd71-e9d5376b58f4"
|
||
```
|
||
|
||
## Context
|
||
|
||
`approval-engine` put the question rather than answering it, which is the right instinct:
|
||
|
||
> `entries[].principal_type` is the auditable half only. It tells you what bound an
|
||
> approval after the fact; it does not stop anything. If your doctrine needs a service
|
||
> principal refused at bind time, that is a `gate-house` question and we would implement
|
||
> a ruling — we simply will not invent one.
|
||
|
||
`informed-decision` enforces *"humans bind, agents draft"* at its own surface and observed
|
||
that there is **no upstream backstop**: `approval-engine` restricts only `/consume` by
|
||
principal type, and its own operator service client holds `approval:approve`. It is not
|
||
asking for the refusal on its own account — its surface enforces it for its own callers
|
||
regardless. Its question is whether the estate wants *approver evidence itself* to be
|
||
human-only at the engine, in which case its enforcement is a property of the approval
|
||
object rather than one component's policy.
|
||
|
||
Both referred it up rather than settling it between them. That is the same restraint that
|
||
produced `GH-DEC-2026-015`, and it is the reason this question is answerable at all.
|
||
|
||
## Decision
|
||
|
||
### 1. Where an approval discharges a human-in-the-loop control, the approver MUST be a human principal
|
||
|
||
**And `approval-engine` MUST refuse a non-human bind at issue, rather than record it.**
|
||
|
||
An approval control exists to put a judgment of a particular kind into the path of an
|
||
act. Where that kind is *human*, an approval bound by a service principal does not
|
||
weakly satisfy the control — it does not engage it at all. A control satisfiable by the
|
||
same class of actor it exists to check is theatre, and the estate's first rule is that
|
||
**no privilege comes from cognition**: an agent determining that an action is appropriate
|
||
never makes it authorized, and it does not become authorized because the agent recorded
|
||
its determination in an approval object.
|
||
|
||
### 2. Recording is detection. Refusal is prevention. The distinction is not new here
|
||
|
||
`entries[].principal_type` is exactly right as a record and is not the control.
|
||
`approval-engine`'s own framing — *"the auditable half only… it does not stop anything"* —
|
||
is the same distinction this repository applies to reconstructability at the issuer, to
|
||
audit completeness, and to `GH-DEC-2026-014`'s commitment-only records. Detection belongs
|
||
in the same register as the other residuals. It is not a substitute for a refusal that
|
||
can be made cheaply at issue.
|
||
|
||
The bind is the cheap moment. Refusing at `/consume` is refusing after the approval has
|
||
been presented as satisfying a control it never satisfied, and after anything relying on
|
||
its existence has relied on it.
|
||
|
||
### 3. The rule attaches to declared approvals, not to all approvals
|
||
|
||
**Service-to-service approvals are legitimate** and this ruling does not disturb them.
|
||
The requirement attaches where an approval is **declared** as discharging a human-in-the-
|
||
loop or dual-control requirement.
|
||
|
||
**Declared at issue, never inferred.** A human approver who happens to be present is not
|
||
a declaration, and an approval MUST NOT be retroactively read as human-discharging
|
||
because its entries turn out to be human. This is the shape `approval-engine` itself
|
||
established for `pdp_path`: intent is declared, `create()` refuses the declaration
|
||
without what it requires, legacy rows migrate to the negative rather than being
|
||
back-filled, and a successor inherits its predecessor's declaration. Back-filling would
|
||
manufacture a statement no requester made — `GH-DEC-2026-008`'s objection to translation,
|
||
in another form, and `approval-engine`'s own argument returned to it.
|
||
|
||
Where the requirement is declared and the binding principal is not human, `create()`
|
||
refuses — the same failure-at-issue shape that already refuses `pdp_path: true` without a
|
||
`pdp_digest`, so an approval that would be unusable fails when it is made rather than at
|
||
the protected side effect.
|
||
|
||
### 4. One surface enforcing it is not the property being held
|
||
|
||
`informed-decision`'s enforcement is correct and insufficient, exactly as it said. A
|
||
second caller reaching `approval-engine` directly bypasses it, and the estate's operator
|
||
service client holds `approval:approve` today. **The property belongs to the approval
|
||
object, not to whichever component happened to create it** — otherwise the guarantee is
|
||
"human-approved unless someone used a different client", which is not a guarantee.
|
||
|
||
`informed-decision` should keep its surface enforcement. Defence at the surface and at
|
||
the engine are not redundant: the surface refuses earlier and with a better error, and
|
||
the engine is what makes the refusal a property of the object.
|
||
|
||
### 5. What this does not rule
|
||
|
||
Not ruled: what makes a principal *human* — that is `key-cape`'s and the identity
|
||
layer's, and note it interacts with `GH-DEC-2026-013` §5. A principal-type claim is
|
||
subject to A-16 like any other: if `human` is reachable by two routes — asserted by the
|
||
directory about the person, or supplied by a registration about the client — the record
|
||
must say which, and a human-in-the-loop control MUST NOT be discharged on a
|
||
registration-supplied claim. Refusing a service principal while accepting an unverified
|
||
assertion of humanity would move the defect rather than close it.
|
||
|
||
Not ruled: which acts require human approval. That is doctrine, it is Gate House's, and
|
||
it is not settled here — this record says what a *declared* human control requires, not
|
||
where such controls are mandatory.
|
||
|
||
Not ruled: `approval-engine`'s scope model, or whether `approval:approve` on an operator
|
||
service client is itself correct. Flagged as worth their review, since it is the concrete
|
||
path by which the gap exists today.
|
||
|
||
## Reversal condition
|
||
|
||
§1 reverses if a case is found where a human-in-the-loop control is legitimately
|
||
discharged by a non-human principal — which would mean the control was misdeclared rather
|
||
than that the rule is wrong, and the correct repair is the declaration.
|
||
|
||
§3's declared-only scoping reverses if declarations turn out to be systematically omitted
|
||
where they are needed, making the rule vacuous in practice. That would be evidence for
|
||
requiring the declaration rather than for widening the enforcement.
|
||
|
||
## Provenance
|
||
|
||
Raised by `approval-engine`, which named the gap in its own enforcement, stated plainly
|
||
that its own operator client holds the permission that makes it reachable, and declined
|
||
to invent the rule. Carried by `informed-decision`, which enforces the property already,
|
||
does not need the ruling for itself, and asked anyway because a property held by one
|
||
component is not a property of the object. Neither repository asked for anything that
|
||
benefits it.
|
||
|
||
## GH-DEC-2026-017 — The layer declaration: `INTENT.md` governs, the §3 vocabulary is closed and case-insensitive, and a declaration carries no standard version
|
||
|
||
```yaml
|
||
id: GH-DEC-2026-017
|
||
kind: decision
|
||
title: The layer declaration — INTENT.md governs, the section 3 vocabulary is closed
|
||
and case-insensitive, and a declaration carries no standard version
|
||
status: resolved
|
||
owner: Bernd Worsch
|
||
repo: gate-house
|
||
standard: net-kingdom/canon/standards/security-layer-model_v0.8.md
|
||
source_note: access-engine (flex-auth) docs/conformance/boundaries-review.md, FLEX-WP-0030,
|
||
B1 as corrected 2026-09-21, plus B2 and B4; the-custodian docs/assessments/2026-09-21-layer-declaration-boundaries.md
|
||
for the three repositories outside the surveyed set; GH-IN-0003
|
||
requested_dispositions:
|
||
- approved
|
||
- revised
|
||
- rejected
|
||
affects:
|
||
- gate-house
|
||
- net-kingdom
|
||
- access-engine
|
||
- audit-core
|
||
- approval-engine
|
||
- maturity-engine
|
||
- secrets-engine
|
||
- user-engine
|
||
- tenant-engine
|
||
- zone-engine
|
||
- ops-warden
|
||
- ops-mason
|
||
- kings-guard
|
||
- key-cape
|
||
- whitehat-security
|
||
- informed-decision
|
||
- railiance-master
|
||
decided_by: Bernd Worsch
|
||
rationale: 'Section 11 permits a layer: key in INTENT.md frontmatter OR an equivalent
|
||
declaration file and does not say which governs when a repository carries both.
|
||
Nine repositories carry both and disagree in all nine, by casing only. Ruled in
|
||
four parts. (1) INTENT.md governs. Section 11 already says a repository declares
|
||
its layer in its own INTENT.md; the file alternative was added to give the declaration
|
||
a machine-readable form, not a second authority. A sidecar is therefore a derived
|
||
artifact under section 11 own derived-artifact rule and does not govern. (2) The
|
||
section 3 vocabulary is case-insensitive for comparison and a conformance run MUST
|
||
ASCII case-fold before comparing; the canonical spelling is the section 4 column
|
||
form. A check that fails eight of ten on orthography detects nothing about boundaries
|
||
and buries the one disagreement it exists to find. (3) The vocabulary is closed
|
||
and has FOUR tokens: Taxonomy, Tooling, Engine, Staff. access-engine validator admits
|
||
only three, omitting Taxonomy, so railiance-master Taxonomy is conforming and the
|
||
validator carries the defect. informed-decision surface is not a layer and is corrected
|
||
to Staff with role pep-shaped, which its own file already reasons from. Both repositories
|
||
are outside the section 4 catalog, so neither is a section 11 non-conformance; a
|
||
conformance run that grades non-catalogued repositories is over-scoped. (4) A layer
|
||
declaration MUST NOT carry a standard version. The declared layer is a standing
|
||
property that does not change when the standard is revised, and a version in the
|
||
declaration makes every revision read as invalidating it; version-scoped state belongs
|
||
in the derived conformance record, which already MUST carry the version it was derived
|
||
at. gate-house own INTENT.md gains frontmatter with layer: Staff in the same commit
|
||
as the ruling, because a doctrine owner ruling on an obligation it has not discharged
|
||
is the section 9.1 defect pointed at itself.'
|
||
created: '2026-09-21T00:00:00.000000Z'
|
||
updated: '2026-09-21T00:00:00.000000Z'
|
||
state_hub_decision_id: "82dd0fea-fabb-4940-92d5-d6e2ea9985f5"
|
||
```
|
||
|
||
## Context
|
||
|
||
`access-engine` set out to remove a version pin from its own `INTENT.md`, read what the
|
||
declaration asserts, and found four repositories that had never declared one. It then
|
||
published a §11 finding produced by a shell pipeline that could not say which file a
|
||
value came from — inside a review whose thesis is that a mechanical check nobody can
|
||
re-run is an assertion. It rebuilt the finding as a command with a receipt, ran it, and
|
||
the run **falsified the finding it was built to reproduce**.
|
||
|
||
That sequence is the reason this ruling exists at all, and it is worth saying before the
|
||
ruling rather than after. The corrected B1 is a stronger finding in a different class,
|
||
and it was reachable only because the repository that published the weak one went back
|
||
and mechanised it against itself.
|
||
|
||
The custodian then swept every repository in the estate carrying a declaration rather
|
||
than the twelve `access-engine` holds boundaries with, and found two more values —
|
||
`surface` and `Taxonomy` — that `access-engine`'s validator rejects. That sweep changes
|
||
one of this ruling's four parts and is credited where it does.
|
||
|
||
The declarations were re-verified here before ruling, from the repositories' own files,
|
||
rather than taken from either report.
|
||
|
||
## Decision
|
||
|
||
### 1. `INTENT.md` governs. A declaration file is derived and does not govern
|
||
|
||
**Where a repository carries both forms, the `layer:` key in its `INTENT.md` frontmatter
|
||
is the declaration.** A `layer.yaml` or equivalent is a **derived artifact**: it MUST be
|
||
marked as derived, MUST name `INTENT.md` as the artifact it derives from, and MUST agree
|
||
with it.
|
||
|
||
The ground is not a preference between two files. §11 already states the rule in its own
|
||
first paragraph — *"a repository the estate authors declares its layer in its own
|
||
`INTENT.md`"* — and the declaration-form paragraph was added for a different reason: that
|
||
**prose cannot distinguish a declaration from a transcribed review**, so the declaration
|
||
needs a machine-readable form. That paragraph gave the declaration a *form*; it was read
|
||
as giving it a second *authority*. Those are different things, and the second is what
|
||
produced nine disagreements nobody noticed.
|
||
|
||
This also settles what a conformance run does. It reads `INTENT.md`. Where a sidecar
|
||
exists it reads that too — not to choose between them, but because **a disagreement
|
||
between the two is itself a finding** and MUST be reported rather than resolved away by
|
||
precedence. Precedence says which value is the repository's answer. It does not say the
|
||
disagreement did not happen.
|
||
|
||
That second clause is A-16 in its plainest form. *"This repository is an Engine"* is an
|
||
appearance reachable by two routes, and until now the record could not say which route a
|
||
given checker took. Precedence alone would make the estate agree by making eight of the
|
||
nine disagreements invisible, which is the same shape as the check that cannot disagree
|
||
with anyone.
|
||
|
||
Eight repositories already declare `declared_by:` in their sidecar. Six of the eight name
|
||
`INTENT.md` or an ADR rather than the file itself, so most of the estate has been
|
||
treating the sidecar as derived in substance without the rule saying so.
|
||
|
||
### 2. The §3 vocabulary is case-insensitive; a conformance run MUST fold case
|
||
|
||
**Comparison is ASCII case-insensitive.** The canonical spelling for new and changed
|
||
declarations is the §4 catalog column form — `Taxonomy`, `Tooling`, `Engine`, `Staff` —
|
||
and a lowercase declaration is **conforming**, not tolerated.
|
||
|
||
`access-engine` offered to accept exactly this outcome and to change its own validator,
|
||
which is the disposition it argued for when its finding was still about casing and did
|
||
not withdraw when the finding changed shape. The offer is taken.
|
||
|
||
The reason is what §11 is for. Two spellings of `Engine` do not describe two boundaries.
|
||
A check that reports nine findings about capital letters and one about a real layer
|
||
disagreement has made the real one unfindable, and finding-fatigue is not a stylistic
|
||
cost — it is the failure mode of a mechanical check, which is the thing §11 claims to be.
|
||
|
||
**No repository is asked to re-spell anything.** The nine disagreements do not become
|
||
conformances by being forgiven; under §1 they were never disagreements about a layer.
|
||
|
||
**Related defect, recorded because it caused this.** §3 does not state a vocabulary. It
|
||
states a table whose header column reads `Taxonomy / Tooling / Engines / Staff` — with
|
||
**`Engines` plural** — while §4's column reads `Engine`. Every implementer has had to
|
||
infer the token set from two tables that disagree, and one of them inferred three tokens.
|
||
A vocabulary a checker must infer is not a vocabulary. §3 gains an explicit normative
|
||
token list (A9).
|
||
|
||
### 3. The vocabulary is closed, and it has four tokens — not three
|
||
|
||
**Closed.** A declaration whose value is outside `{Taxonomy, Tooling, Engine, Staff}` is
|
||
not conforming, and does not name a tier the model has not enumerated. The four layers
|
||
are the model's whole claim about how the estate is cut; a fifth arrives by amending §3,
|
||
in this repository's voice, not by a repository declaring one.
|
||
|
||
**But `Taxonomy` is in it.** `access-engine`'s validator admits `{Staff, Engine, Tooling}`
|
||
and rejects `Taxonomy`, which §3.1 defines, §4 catalogues twice (`info-tech-canon`,
|
||
`net-kingdom`), and this standard is itself an instance of. **`railiance-master` is
|
||
conforming and the validator carries the defect.**
|
||
|
||
This is the part of the finding that inverted on inspection, and how it inverted is worth
|
||
recording. The custodian's sweep reported `Taxonomy` as outside the vocabulary. It is not
|
||
— it was outside *a validator*, and the validator was read as the vocabulary because it
|
||
was the only executable statement of one. That is §11's derived-artifact rule inverted:
|
||
an artifact derived from canon came to stand in for canon, precisely because canon left
|
||
the token set to be inferred (§2's related defect). The custodian was right to raise it;
|
||
one of the two instances it raises is a finding against the checker.
|
||
|
||
**Found twice, independently, and the second finder is the repository it was a finding
|
||
against.** `railiance-master` corrected the custodian's record with the citations — §3.1,
|
||
§4, §7, §17 — and the custodian recorded its first reading as wrong in the circulated
|
||
document rather than quietly amending it. This ruling was drafted from the first version
|
||
and re-verified against §3.1 before it was issued, so it reached the same place by the
|
||
other route; the correction is credited because it arrived first and because it was made
|
||
by the party the finding accused.
|
||
|
||
**The §3-versus-§4 divergence is a second defect, and precedence does not reach it.**
|
||
`railiance-master` also observes that its `Taxonomy` matches §3's table spelling exactly,
|
||
so measured against §3 the nine lower-casing sidecars are the divergent ones, while
|
||
measured against §4 the disagreement is `Engines` versus `Engine` for every engine
|
||
repository in the estate. A run built from §3 and a run built from §4 disagree about eight
|
||
rows. That is B1's shape one level further in — two faithful readings of one standard —
|
||
and §1's precedence rule does not touch it, because it is a disagreement *inside the
|
||
standard* rather than inside a repository. §2 and A9 close it by stating the vocabulary
|
||
once, as a token list, rather than by choosing between two tables.
|
||
|
||
**The two off-vocabulary cases are ruled apart, as the custodian asked.** They do not
|
||
behave alike: `Taxonomy` is a conforming value reported by a defective checker, and
|
||
`surface` is a repository naming a tier the model does not have. Nothing in the disposition
|
||
of one carries to the other.
|
||
|
||
`access-engine` is asked to add `Taxonomy` to its validator. That is not a §4 scope
|
||
change — a NetKingdom checker run estate-wide will meet Taxonomy repositories, and
|
||
rejecting the layer this standard occupies is not a defensible default.
|
||
|
||
**`surface` is not a layer.** `informed-decision` declares `layer: surface, role:
|
||
pep-shaped`. Its correct declaration is **`layer: Staff`, `role: pep-shaped`**, which its
|
||
own file already reasons from two ways: it writes *"§5 applies to Staff. This is a
|
||
browser-facing surface with no Tooling contact,"* and `GH-DEC-2026-012` R1 ruled it is
|
||
PEP-shaped and **not** an Engine, which under §3's determinism cut leaves Staff.
|
||
`ops-mason` and `ops-warden` are the precedent: `Staff` in the layer column,
|
||
`PEP-shaped` in the role column. The correction is `informed-decision`'s to make.
|
||
|
||
`role:` is not part of this vocabulary and is not closed by this ruling. §3.3 enumerates
|
||
the Engine roles; `PEP-shaped` is a §6.4 shape; `GH-DEC-2026-012` R2 already holds that
|
||
shapes are not layers. The layer field takes a layer.
|
||
|
||
### 4. Both off-vocabulary repositories are outside §4, and §11 does not grade them
|
||
|
||
`informed-decision` and `railiance-master` are **not §4 catalog rows**. §11's obligation
|
||
attaches to *"every estate-authored repository in §4"*, so neither can be a §11
|
||
non-conformance, and an estate-wide run that grades them is over-scoped. `railiance-master`
|
||
says so in its own file — *"not a NetKingdom §4 catalog row… Railiance operations
|
||
Taxonomy"* — and declared anyway.
|
||
|
||
**A voluntary declaration is welcome and is not thereby enrolled.** The correct report for
|
||
both is *declared voluntarily, outside catalog scope*, and for `informed-decision`
|
||
additionally *value not in the vocabulary, correction identified*. Treating a volunteer's
|
||
declaration as a non-conformance is the fastest way to stop getting volunteers, and it is
|
||
also just wrong about who §11 binds.
|
||
|
||
**A conformance run MUST state its scope.** A run over §4 and a run over every repository
|
||
carrying a declaration answer different questions, and a report that does not say which it
|
||
did cannot be acted on — the same defect as a survey that does not record which file a
|
||
value came from, one level up.
|
||
|
||
**Not ruled: whether `informed-decision` should become a §4 row.** It holds a ruled
|
||
boundary, is PEP-shaped, and sits on the approval path, which is a real argument. Adding a
|
||
catalog row is a canon change, and a repository is *asked*, not enrolled — §11's own rule
|
||
that a layer stated about a repository by another is not a declaration applies to
|
||
catalogue membership at least as strongly. Raised with them; carried as an open item of
|
||
the amendment round (A11).
|
||
|
||
### 5. A layer declaration MUST NOT carry a standard version
|
||
|
||
`access-engine` removed `0.7` from its own declaration, enforced the absence by test, and
|
||
asked that §11 say so generally rather than leave each repository to work it out. **Ruled
|
||
as asked, and the general form is stated here.**
|
||
|
||
A layer declaration asserts a **standing property**: which layer this repository is. That
|
||
property does not change when the standard is revised. A version in the declaration makes
|
||
every revision read as though it invalidated every declaration, which is the same
|
||
confusion this standard's own frontmatter note exists to prevent — *assent records assent
|
||
to a boundary, given at the version named, and is not assent to the current text*.
|
||
`access-engine` is Engine/PDP at v0.6, v0.7, v0.8 and after.
|
||
|
||
**Version-scoped state belongs in the derived conformance record**, which under §11's
|
||
derived-artifact rule already MUST name what it derives from and carry the version or
|
||
commit it was derived at. That artifact exists; the version has a home.
|
||
|
||
**This is not one repository's habit — it is the reference form.** Every sidecar in the
|
||
estate carries `standard_version: "0.7"`, including `ops-warden`'s reference form and the
|
||
seven repositories that adopted it. So removing the field is a change to the reference
|
||
form, and `ops-warden` is asked to make it there rather than each adopter deciding.
|
||
`access-engine` found this in its own file and did not look at anyone else's; the field's
|
||
real distribution only appears from the sweep.
|
||
|
||
**Declined: keeping the field "for information".** A field that is present will be
|
||
branched on. The reason to remove it is that it is *readable as* a validity condition,
|
||
and a version kept as decoration is still readable as one.
|
||
|
||
**What happens when §3 changes.** If a future version changed the vocabulary so a declared
|
||
token no longer denoted the same layer, declarations do **not** silently retarget. That is
|
||
a re-declaration round, run by this repository in the standard's own voice — an explicit
|
||
canon obligation, not a per-file pin that would have made nobody re-read anything anyway.
|
||
|
||
### 6. `gate-house` declares `Staff`, in this commit
|
||
|
||
`access-engine` raised it plainly rather than politely: *"a doctrine owner that has not
|
||
discharged its own §11 obligation is the §9.1 defect pointed at itself, which is the
|
||
argument you accepted from us four times at v0.8."*
|
||
|
||
That is correct, it needs no ruling, and the appropriate response to it is the file rather
|
||
than a paragraph about the file. `gate-house/INTENT.md` gains frontmatter carrying
|
||
`layer: Staff` in the same commit as this record. Under §1 it writes **no** sidecar: the
|
||
governing form is the one §11 names first, and the repository ruling that the sidecar is
|
||
derived should not need a derived copy to be legible.
|
||
|
||
The prose line `**Layer:** Staff` has stood in `INTENT.md` since v0.1 and was believed to
|
||
be the declaration. It is exactly what §11's declaration-form paragraph says does not
|
||
count, written by the repository that wrote the paragraph.
|
||
|
||
`key-cape`, `ops-mason` and `net-kingdom` remain undeclared and each owes its own. Each is
|
||
told; none is declared for. `net-kingdom`'s is the odd one — it is the publisher of the
|
||
standard requiring it, and `Taxonomy` is its §4 row.
|
||
|
||
## What this does not rule
|
||
|
||
- **Not ruled: the `role:` vocabulary**, its case-sensitivity, or whether it is closed.
|
||
Raised by the same survey; deferred because §3.3 and §6.4 state roles in two places and
|
||
the token set needs the same repair §3's does before a ruling would mean anything.
|
||
- **Not ruled: what a conformance run does with a repository outside §4 that declares.**
|
||
§4 reports it as out of scope; whether a second, estate-wide report exists is
|
||
`maturity-engine`'s and the runner's, not doctrine's.
|
||
- **Not ruled: the sidecar's schema** beyond the derived marking and the absence of a
|
||
version. `ops-warden`'s form is the estate's and stays `ops-warden`'s.
|
||
|
||
## Reversal condition
|
||
|
||
§1 reverses if a repository is found for which `INTENT.md` cannot carry frontmatter — the
|
||
§9.1 shape, an obligation the holder cannot discharge. No such repository is known; the
|
||
three checked without frontmatter are three that can trivially gain it.
|
||
|
||
§2 reverses if two layer tokens are ever introduced that differ only in case, which would
|
||
be a defect in §3 rather than a reason to restore case-sensitivity.
|
||
|
||
§3's closure reverses on an argued amendment to §3, from a repository that bears a cost
|
||
under the four-layer cut. `informed-decision`'s `surface` is not that argument — it is an
|
||
undeclared fifth tier, and the repository's own file gives the Staff reasoning.
|
||
|
||
## Provenance
|
||
|
||
Raised by `access-engine` (`FLEX-WP-0030`), which found its own version pin, generalised
|
||
the question rather than fixing its file, published a finding it then mechanised and
|
||
falsified, corrected it inside a day, and put the correction to everyone who received the
|
||
original — including the three repositories the original had not reached. It also raised
|
||
`gate-house`'s own omission against `gate-house`, which is the finding it had least reason
|
||
to raise and the one this ruling is most improved by.
|
||
|
||
Extended by `the-custodian`, whose estate-wide sweep supplied both off-vocabulary values,
|
||
the observation that the two-generators reading does not hold estate-wide, and therefore §3
|
||
— including the half of §3 that is a finding against the reporting validator rather than
|
||
the reported repositories, and which it then corrected against itself on
|
||
`railiance-master`'s citation, in the circulated document, before this ruling issued.
|
||
|
||
`railiance-master` supplied that correction with the citations and asked for nothing. It is
|
||
the only repository in this record that was reported as non-conformant, was not, and said so
|
||
with the sections rather than with an objection.
|
||
|
||
`ops-warden` supplied the reference form eight repositories adopted, which is why §5 is a
|
||
single change rather than eight.
|
||
|
||
## GH-DEC-2026-018 — `access-engine` is a source of evidence for the decision record; custody is never source, and §4 must mark sources rather than leave the class to be inferred
|
||
|
||
```yaml
|
||
id: GH-DEC-2026-018
|
||
kind: decision
|
||
title: access-engine is a source of evidence for the decision record; custody is never
|
||
source, and section 4 must mark sources rather than leave the class to be inferred
|
||
status: resolved
|
||
owner: Bernd Worsch
|
||
repo: gate-house
|
||
standard: net-kingdom/canon/standards/security-layer-model_v0.8.md
|
||
source_note: access-engine docs/conformance/boundaries-review.md B3, held open as its
|
||
declared gap G2; audit-core holds the other half; GH-IN-0003
|
||
requested_dispositions:
|
||
- approved
|
||
- revised
|
||
- rejected
|
||
affects:
|
||
- gate-house
|
||
- net-kingdom
|
||
- access-engine
|
||
- audit-core
|
||
- approval-engine
|
||
- kings-guard
|
||
- informed-decision
|
||
decided_by: Bernd Worsch
|
||
rationale: 'Section 11 requires every repository catalogued in section 4 AS A SOURCE
|
||
OF EVIDENCE to declare class, cadence and detection surface, and says a source declaring
|
||
none is not conforming. access-engine produces the decision record, declares no emission
|
||
guarantee, and asked whether it is a section 4 source or only the producer of an artifact
|
||
audit-core is the source of. Ruled against access-engine on the substance and against
|
||
the check on the form. (1) A custodian is never the source of what it holds. audit-core
|
||
role is Evidence, which is custody; reading it as the source of records it did not emit
|
||
would make section 9.6 incoherent, because the archive that cannot prove a record was
|
||
never sent would be the same party as the one that would have sent it. (2) access-engine
|
||
is therefore a source, and the decision record is the clearest case in the estate: a
|
||
denial is the paradigm load-bearing event section 9.6 names, and a denial is exactly the
|
||
event an adversary most wants missing. It owes a declaration and does not have one, so it
|
||
is non-conforming on section 11 today. The correct state is a declared gap with owner,
|
||
blocker and review date, promptly; gate-house is not grading, it is naming which register
|
||
the fact belongs in. (3) The classification is per event class and is access-engine own to
|
||
publish. Section 11 forbids a conformance run to infer class from event name, payload or
|
||
observed rate, and that prohibition binds this ruling as much as a runner. (4) Section 11
|
||
names a section 4 property that does not exist: section 4 catalogues layers and roles and
|
||
marks no repository as a source of evidence, so the check requires a run to decide for
|
||
itself who is a source, which is the circularity section 11 forbids one level down.
|
||
Section 4 gains an evidence-source marking.'
|
||
created: '2026-09-21T00:00:00.000000Z'
|
||
updated: '2026-09-21T00:00:00.000000Z'
|
||
state_hub_decision_id: "ae77e47b-44bd-4007-bd4e-51bd3132d298"
|
||
```
|
||
|
||
## Context
|
||
|
||
`access-engine` put the question and declined the answer that favours it:
|
||
|
||
> The unclear boundary: are we a §4 source of evidence, or only the producer of an
|
||
> artifact `audit-core` is the source of? We are not answering that alone and we are not
|
||
> taking the flattering reading.
|
||
|
||
It recorded the gap as `G2` in its own conformance record and holds it open until this
|
||
repository rules *and* `audit-core` confirms its half. That is the second time this month
|
||
a repository has referred up a question whose convenient answer was available to it, and
|
||
it is the reason the question is answerable rather than settled by whoever moved first.
|
||
|
||
## Decision
|
||
|
||
### 1. A custodian is never the source of what it holds
|
||
|
||
**`audit-core` is not the source of the decision record.** Its §4 role is `Evidence`, and
|
||
§4 spells that role as *custody, retention, integrity verification, export*. Custody is
|
||
what you do with a record that arrived; a source is what makes one arrive.
|
||
|
||
The fork `access-engine` offered — *only the producer of an artifact `audit-core` is the
|
||
source of* — is not available, and the reason is §9.6's own load-bearing sentence. The
|
||
whole section rests on the fact that **an append-only archive cannot prove a record was
|
||
never sent**. That statement has content only because the archive and the emitter are
|
||
different parties. Collapse them and §9.6 is incoherent: the custodian would be the source
|
||
of records it never received, a suppressed record would have no one to attribute the
|
||
suppression to, and the residual the section exists to state — *adversarial omission at a
|
||
compromised source, prevented by nothing in this model* — would have no source to be
|
||
compromised.
|
||
|
||
So the rule generalises past this pair: **evidence custody and evidence emission are
|
||
disjoint obligations, and holding one never discharges the other.** No repository's
|
||
emission guarantee is satisfied by `audit-core` holding what it sent.
|
||
|
||
### 2. `access-engine` is a source of evidence, and the decision record is the clearest case in the estate
|
||
|
||
§17 moved the decision-record schema to `access-engine` on the ground that it is *"the one
|
||
thing in the estate only `access-engine` produces"* — an argument `access-engine` made
|
||
against its own interest, to take work on. The same fact answers this question, and this
|
||
time it costs rather than pays.
|
||
|
||
The decision record is not marginal evidence. **A denial is one of the three events §9.6
|
||
names as the paradigm load-bearing kind** — *"an approval revocation, a containment
|
||
action, a denial"* — and the section's own reasoning is that the negative event is exactly
|
||
what an adversary most wants missing, and that it is rare by nature, which is where rate
|
||
monitoring is the wrong instrument and the stakes are highest.
|
||
|
||
The estate has controls that read decision evidence. `GH-DEC-2026-010` requires a PEP to
|
||
be able to attribute a decision to `access-engine`. `kings-guard` evaluates streams and
|
||
raises silence findings. `informed-decision` declares its inherited gap against the
|
||
decision path. Every one of those reads a record `access-engine` emits, and none of them
|
||
can tell a quiet period from a suppressed one without a declared cadence.
|
||
|
||
**`access-engine` owes an emission guarantee, declares none, and is therefore not
|
||
conforming on §11 today.** Recorded in those words because it asked for the unflattering
|
||
reading and because softening it would make the register useless for the next repository.
|
||
|
||
### 3. The right register for that fact is a declared gap, and that is not a courtesy
|
||
|
||
§11's four states exist for this. An undeclared violation is *"anything else"* — the state
|
||
you are in when nobody has said. `access-engine` has said, publicly, in its own conformance
|
||
record, before anyone asked it to, and named the review that found it. **That is a declared
|
||
gap the moment it carries owner, blocker and review date**, and a declared gap is tracked
|
||
non-conformance, not a clean bill.
|
||
|
||
`G2` currently says *unruled*. It is now ruled, so `G2` closes as a question and reopens as
|
||
a gap of the ordinary kind, with a date. The distinction matters under A-17: this gap fails
|
||
closed on its distinguishing case — a stream with no declared cadence produces no silence
|
||
finding, so the failure is a **missed detection**, never a manufactured permission, which
|
||
is §9.6's §8-asymmetry payoff and the reason this is a gap a register can hold rather than
|
||
a permission.
|
||
|
||
### 4. The class inventory is `access-engine`'s to publish, and this ruling does not supply it
|
||
|
||
§11 is explicit: *"which class an event falls in, and whether it is rare, is the source's
|
||
published classification: a conformance run is supplied that inventory and MUST NOT infer
|
||
it from an event name, payload, or observed rate, or the check becomes circular."*
|
||
|
||
**That prohibition binds a ruling at least as hard as it binds a runner.** So this record
|
||
does not classify the decision record, and specifically does not rule that denials are rare
|
||
and allows are volume, however obvious that looks from here. What it rules is:
|
||
|
||
- the declaration is **per event class**, not per repository — a single repository-level
|
||
guarantee over a stream containing both a high-volume allow and a rare denial is not a
|
||
declaration, it is an average, and it will be satisfied by rate monitoring that cannot
|
||
see the denial go missing;
|
||
- `access-engine` publishes the inventory and the classification, under
|
||
`net-kingdom`'s `emission-cadence-security-profile_v0.1.md`;
|
||
- §11's consequences then follow mechanically: a **rare** load-bearing class MUST carry
|
||
heartbeat **and** reconciliation, not either alone, and MUST NOT be covered by rate
|
||
monitoring.
|
||
|
||
`approval-engine`'s `cadence.yaml` is the reference instance and the form is already
|
||
drafted in `gate-house/docs/contracts/approval-emission-detection.md`. `access-engine` is
|
||
not asked to invent a shape.
|
||
|
||
### 5. §11 names a §4 property that does not exist, and that is the finding under the finding
|
||
|
||
The check reads *"every repository catalogued in §4 as a source of evidence."* **§4
|
||
catalogues no such thing.** It has three columns — repository, layer, role — and the
|
||
`Evidence` role means custody, which §1 has just ruled is the opposite of source. So the
|
||
check, as written, requires a conformance run to decide for itself which repositories are
|
||
sources.
|
||
|
||
That is the same circularity §11 forbids two paragraphs later for event classes. §11 tells
|
||
a runner it MUST NOT infer an event's class, and in the same breath requires it to infer
|
||
the far larger fact of who is a source at all. `access-engine` could not answer the
|
||
question from the text because **the text does not contain the answer** — which is a
|
||
better account of B3 than *"the boundary is unclear."*
|
||
|
||
**§4 gains an evidence-source marking**, and each marked repository owns its class
|
||
inventory (A10). The alternative — restating the check in terms of *"any repository that
|
||
emits"* — was considered and refused: it moves the inference into the runner instead of
|
||
removing it, and it would make the source set something each runner computes rather than
|
||
something canon states. §11's own principle is that the classification is published, not
|
||
derived.
|
||
|
||
**This is the fifth time this standard has corrected the §9.1 defect in its own text**, and
|
||
§11 has now been the site of it twice. The count in §11 says four. It is wrong by one as of
|
||
this ruling, and A10 corrects it rather than leaving the number to drift — a derived count
|
||
inside a normative body is a derived artifact that names no source, which §11 also forbids.
|
||
|
||
## What this does not rule
|
||
|
||
- **Not ruled: `audit-core`'s half.** `access-engine` holds `G2` open until `audit-core`
|
||
confirms, and that is right. §1 tells `audit-core` what it is being asked to confirm — that
|
||
it is custodian and not source, and that it does not read its own custody as discharging any
|
||
emitter's guarantee — but a confirmation this repository writes on `audit-core`'s behalf is
|
||
exactly the §11 defect of a layer stated about a repository by another. Asked, not assumed.
|
||
- **Not ruled: which other §4 rows are sources.** `approval-engine` has declared;
|
||
`secrets-engine`, `user-engine`, `tenant-engine`, `zone-engine`, `maturity-engine`,
|
||
`ops-warden` and `ops-mason` have not been assessed here. The A10 marking is where that is
|
||
settled, repository by repository, and this ruling deliberately does not pre-empt it by
|
||
listing names — `access-engine` was ruled because it asked.
|
||
- **Not ruled: whether the decision record's emission must be atomic** with the decision.
|
||
§9.4 attaches that to load-bearing evidence and the class inventory is not published yet, so
|
||
the obligation is pending its own input rather than waived.
|
||
|
||
## Reversal condition
|
||
|
||
§2 reverses if a control is found that reads the decision record and would be unaffected by
|
||
its total absence — which would mean the record is attributive throughout, not that
|
||
`access-engine` is not a source. §1 does not reverse on that; it is structural.
|
||
|
||
§5's marking reverses if a §4 row turns out to be a source in one capacity and not another,
|
||
which a column cannot express. The repair would be a per-class marking, not a return to
|
||
inference.
|
||
|
||
## Provenance
|
||
|
||
Raised by `access-engine`, which produced the only artifact in the estate it is the sole
|
||
producer of, noticed that it had declared no guarantee for it, and refused the reading that
|
||
would have closed the question in its favour — then held the gap open in its own conformance
|
||
record rather than waiting to be asked. Every part of this ruling costs it something and none
|
||
of it was found by anyone else.
|
||
|
||
`audit-core` is the repository the §11 emission check exists because of, and is the one that
|
||
raised the general form so `GH-IN-0001` could not recur unnoticed. It is asked for its half
|
||
and has not yet been heard from on §11 at v0.8.
|
||
|
||
|
||
## GH-DEC-2026-019 — The v0.8 acceptance flip stays held, and the §11 declaration defects join the existing hold rather than a follow-on amendment
|
||
|
||
```yaml
|
||
id: GH-DEC-2026-019
|
||
kind: decision
|
||
title: The v0.8 acceptance flip stays held, and the section 11 declaration defects join
|
||
the existing hold rather than a follow-on amendment
|
||
status: resolved
|
||
owner: Bernd Worsch
|
||
repo: gate-house
|
||
standard: net-kingdom/canon/standards/security-layer-model_v0.8.md
|
||
source_note: the-custodian docs/assessments/2026-09-21-layer-declaration-boundaries.md,
|
||
reading offered and not pressed; gate-house docs/conformance/2026-09-06-v08-assent-round.md
|
||
round close; GH-DEC-2026-017, GH-DEC-2026-018
|
||
requested_dispositions:
|
||
- approved
|
||
- revised
|
||
- rejected
|
||
affects:
|
||
- gate-house
|
||
- net-kingdom
|
||
- audit-core
|
||
- kings-guard
|
||
- access-engine
|
||
- approval-engine
|
||
- ops-warden
|
||
- key-cape
|
||
- ops-mason
|
||
decided_by: Bernd Worsch
|
||
rationale: 'The v0.8 round closed with two circulated repositories not returning a text
|
||
review, and the section each was asked to attack therefore carrying no assent: kings-guard
|
||
on section 9.5, audit-core on whether section 11 emission wording lets a source imply
|
||
completeness. Publication and the acceptance flip were handed to net-kingdom on round
|
||
close and have not happened. Five section 11 defects have now been found from outside,
|
||
all of them in the text audit-core was asked to attack and did not. Held. The round own
|
||
closing finding was that every substantive finding against v0.8 was a correct rule a
|
||
careful implementer could satisfy without doing the thing it exists to require, and that
|
||
this repository is structurally prone to that failure. Section 11 is now that failure
|
||
pointed at section 11: a check calling itself mechanical that cannot make two conforming
|
||
runs agree, that names a section 4 property section 4 does not carry, and whose vocabulary
|
||
must be inferred from two tables that disagree. Accepting the version and amending it
|
||
immediately would make the accepted text the defective one, and would spend the one thing
|
||
the round produced. The hold is cheap because v0.7 is accepted and in force unpatched, so
|
||
nothing operational waits on it; that is stated as the reason it is affordable rather than
|
||
as an argument that holds are free. Bounded by three stated closing conditions so the hold
|
||
cannot become indefinite by inattention, and the conditions turn on returns and dated gaps
|
||
rather than on every repository being conformant, because a hold that waits for conformance
|
||
waits forever.'
|
||
created: '2026-09-21T00:00:00.000000Z'
|
||
updated: '2026-09-21T00:00:00.000000Z'
|
||
state_hub_decision_id: "b66ef2b9-3793-498d-8569-52b1b8e42edf"
|
||
```
|
||
|
||
## Context
|
||
|
||
The custodian offered a reading and said it was not pressing it:
|
||
|
||
> The round should not close while §11's own mechanical check is ambiguous. A standard that
|
||
> cannot make two conforming conformance runs agree is not yet mechanically checkable in the
|
||
> sense §11 claims for itself.
|
||
|
||
The restraint is noted and the reading is adopted, with reasons of this repository's own —
|
||
because a hold adopted on someone else's reasoning is a hold nobody can argue about later.
|
||
|
||
## Decision
|
||
|
||
### 1. Held, and these join the existing hold
|
||
|
||
`GH-DEC-2026-017` and `GH-DEC-2026-018` produce five amendments to §11, §4 and §3. They land
|
||
**in v0.8 before the acceptance flip**, not in a v0.9 amendment after it. v0.7 stays
|
||
`accepted` and in force, unpatched, as it has since the round closed.
|
||
|
||
### 2. The reason is the round's own closing finding, arriving again
|
||
|
||
The v0.8 round closed by saying something narrower and worse than it opened with:
|
||
|
||
> **Every substantive finding was about a rule that read as satisfied by a check that did not
|
||
> satisfy it.** … That is a failure mode this repository is structurally prone to, because
|
||
> doctrine is graded on whether it is *right* and consumed on whether it is *checkable*.
|
||
|
||
§11 is now the sixth instance, and the first one where the rule that reads as satisfied is
|
||
the rule *about checking*. Its declaration-form paragraph reads as making the layer question
|
||
mechanical; nine repositories satisfy it while giving two answers. Its emission check reads
|
||
as scoped by §4; §4 carries no such scope. Its vocabulary reads as closed; it is stated in
|
||
two tables that disagree, and the estate's only executable statement of it omits a layer.
|
||
|
||
**Accepting the version and amending it afterwards would make the accepted text the defective
|
||
one** — and would do it in the section whose subject is that defect. The round's finding was
|
||
that only implementers can tell *right* from *checkable*. Three of them just did, from
|
||
outside, after the round closed. Flipping now would spend that.
|
||
|
||
### 3. The hold's cost is the reason it is affordable, and the reason is stated rather than assumed
|
||
|
||
v0.7 is accepted and in force. Nothing in the estate waits on v0.8's status: every ruling
|
||
since has been issued against v0.8 as proposed and implemented by repositories that did not
|
||
wait, and the four undeclared repositories owe their declarations under v0.7's §11 as much as
|
||
v0.8's.
|
||
|
||
**So the hold costs documentation currency and nothing else.** That is said plainly because
|
||
the opposite case is the one to guard against — if a hold blocked implementation, the
|
||
calculus would change and the right answer might be to accept and amend. It does not, so it
|
||
does not.
|
||
|
||
### 4. Three closing conditions, because an unbounded hold is not a decision
|
||
|
||
The flip proceeds when all three are met:
|
||
|
||
1. **The five amendments are drafted, circulated, and dispositioned** —
|
||
`docs/amendments/v0.8-section-11-declaration-amendments.md`, A9–A13, carried by `GH-WP-0004`.
|
||
2. **`audit-core` returns its §11 review, or declines in writing.** It was asked to attack
|
||
whether §11's emission wording lets a source imply completeness; five §11 defects have since
|
||
been found by others in that text. A written decline closes this condition — §14 records
|
||
*not claimed* rather than counting silence as assent, and the point is that the record says
|
||
which, not that assent is extracted. `kings-guard`'s §9.5 review is wanted on the same terms
|
||
and is **not** a condition here, because no finding has landed against §9.5.
|
||
3. **The four undeclared §4 repositories have each either declared or recorded a dated gap** —
|
||
`gate-house` (done in `GH-DEC-2026-017` §6), `key-cape`, `ops-mason`, `net-kingdom`.
|
||
|
||
**Condition 3 asks for a declaration or a dated gap, not for conformance.** A hold that waits
|
||
for every repository to be conforming waits forever and hands any one repository a veto. What
|
||
the flip needs is that the §11 check, once amended, has been *run* and its results are in a
|
||
register — which a declared gap satisfies exactly as well as a declaration does. That is §11's
|
||
own position on blocked-clean, applied to the standard's own acceptance.
|
||
|
||
### 5. What is not held
|
||
|
||
- **The rulings are in force now.** `GH-DEC-2026-017` and `GH-DEC-2026-018` bind from today
|
||
and do not wait on the flip. Repositories correcting declarations, adding `Taxonomy` to a
|
||
validator, or opening a dated gap should do it now; nothing here is a reason to wait.
|
||
- **`net-kingdom` keeps publication and the flip.** They were handed over at round close and
|
||
are not taken back. This record states a condition on the flip, in the standard's authoring
|
||
voice, and `net-kingdom` executes it.
|
||
- **The v0.8 text stands** except in §3, §4 and §11 as amended. No finding has landed against
|
||
anything else.
|
||
|
||
## A candidate property, deliberately not numbered
|
||
|
||
B1 as corrected is an instance of something more general: **a conformance check that each
|
||
repository runs only against its own files cannot establish an estate property.** It
|
||
establishes self-consistency, and self-consistency is compatible with the estate disagreeing
|
||
with itself in every repository at once — which is precisely what nine of nine turned out to
|
||
be. §11 said as much in `access-engine`'s words — *"a mechanical check that cannot disagree
|
||
with anyone is not yet mechanical"* — but said it about a symptom.
|
||
|
||
It is **not** recorded as `A-18`. One instance is not a rule; `A-16` and `A-17` were derived
|
||
from shapes that kept arriving, and `INTENT.md` holds that neither has graduated to canon
|
||
because the bar is that a repository **bearing a cost under it** has argued it. This has one
|
||
instance and no such argument. `informed-decision`'s observation applies — the repository that
|
||
bears a rule at its weakest point sees the unstated precondition — and the repository that
|
||
would bear this one is whoever has to build the estate-wide runner. Recorded here so a second
|
||
instance is recognised rather than met fresh.
|
||
|
||
## Reversal condition
|
||
|
||
The hold reverses if v0.8 acquires operational load — if a ruling, a contract, or an engine's
|
||
implementation comes to depend on v0.8 being `accepted` rather than proposed. §3's whole
|
||
argument is that it does not today.
|
||
|
||
Condition 2 reverses to *waived* if `audit-core` is unable to return a review for reasons of
|
||
capacity rather than disagreement, and says so. The condition is for the record to say which,
|
||
not to compel a review.
|
||
|
||
## Provenance
|
||
|
||
Raised by `the-custodian`, which held the only view from which the six questions were visible
|
||
as one set, offered its reading explicitly as not pressed, and stated that none of it was its
|
||
to rule. The estate-wide sweep it volunteered is what turned a nine-repository finding into a
|
||
fourteen-repository one and produced two of the five amendments.
|
||
|
||
The hold itself rests on `access-engine`'s and `audit-core`'s work rather than on the
|
||
custodian's reading: the first found the defects, and the second is the repository whose
|
||
unreturned review is the reason the defects were still there to find.
|
||
|
||
## GH-DEC-2026-020 — What A12 reaches: every key of the declaration including a version-bearing path and the companion version, not stance or claims maps; and the version lives in the run, not in a record every repository must emit
|
||
|
||
```yaml
|
||
id: GH-DEC-2026-020
|
||
kind: decision
|
||
title: 'What A12 reaches: every key of the declaration including a version-bearing
|
||
path and the companion version, not stance or claims maps; and the version lives
|
||
in the run, not in a record every repository must emit'
|
||
status: resolved
|
||
owner: Bernd Worsch
|
||
repo: gate-house
|
||
standard: net-kingdom/canon/standards/security-layer-model_v0.8.md
|
||
source_note: the-custodian c19866c0 (three A12-reach questions, counts re-measured
|
||
here); approval-engine 98d337c4 (questions 1 and 2, with assent to A9-A13); ops-warden
|
||
4220413a (the conformance-record question); the-custodian docs/assessments/2026-09-21-layer-declaration-boundaries.md
|
||
requested_dispositions:
|
||
- approved
|
||
- revised
|
||
- rejected
|
||
affects:
|
||
- gate-house
|
||
- net-kingdom
|
||
- access-engine
|
||
- audit-core
|
||
- approval-engine
|
||
- user-engine
|
||
- whitehat-security
|
||
- ops-warden
|
||
- kings-guard
|
||
- secrets-engine
|
||
- tenant-engine
|
||
- maturity-engine
|
||
- zone-engine
|
||
- informed-decision
|
||
- railiance-master
|
||
- railiance-platform
|
||
created: '2026-09-21T06:27:08.536630Z'
|
||
updated: '2026-09-21T06:27:18.741684Z'
|
||
rationale: 'Four questions about the reach of GH-DEC-2026-017 section 5 (amendment
|
||
A12), raised independently by repositories applying it, plus a citation correction.
|
||
Ruled on the ground section 5 already gives: a version in a declaration is readable
|
||
as a validity condition, and that is a property of the content, not of a key name.
|
||
(1) A version-bearing standard: path counts. A12 reaches every key of the declaration,
|
||
which is the INTENT.md frontmatter and every key of a derived declaration file,
|
||
and forbids a standard version in any key or value. audit-core and user-engine de-version
|
||
the path; whitehat-security, never sent the ruling by gate-house, removes standard_version
|
||
and de-versions its path; the nine repositories that de-versioned made a required
|
||
change, not a voluntary one. Comments and schema_version are not reached. (2) companion_version
|
||
counts: the companion is a gate-house-owned standard-companion and its version in
|
||
a declaration is the same pin. approval-engine removes it; informed-decision removal
|
||
was required. (3) A12 does not reach stance maps, claims maps or evidence classifications:
|
||
they state positions on version-scoped clause text and their version is what makes
|
||
them re-readable when the text changes; nobody changes. (4) Section 11 does not
|
||
require every declaring repository to emit a durable conformance record, and section
|
||
5 was wrong to say that artifact exists. The version belongs to the run: a re-runnable
|
||
checker is sufficient, not merely for now, if every run states the version or commit
|
||
of the standard it checks against and its scope; kings-guard constant-and-print
|
||
pattern satisfies this. A run output that is retained or relied upon is a derived
|
||
artifact and the retaining party owes the record. Six copied checkers print no version
|
||
and must; all seven checkers key on field names and must widen to what (1) and (2)
|
||
rule. Citation: the body section numbering is canonical, GH-DEC-2026-017 section
|
||
5, statute A12; the rationale part numbers are a summary and are not cited. A12
|
||
is refined as A12 r2 and circulated for assent; nothing in net-kingdom canon is
|
||
edited here.'
|
||
decided_by: Bernd Worsch
|
||
decided_at: '2026-09-21T06:27:18.741684Z'
|
||
state_hub_decision_id: "89d7faed-398e-4b26-b20e-2e3b2c0c907f"
|
||
```
|
||
|
||
## Context
|
||
|
||
Thirteen repositories applied `GH-DEC-2026-017` within a day of it issuing: `ops-warden`,
|
||
`approval-engine`, `kings-guard`, `secrets-engine`, `audit-core`, `user-engine`,
|
||
`railiance-platform`, `tenant-engine`, `maturity-engine`, `zone-engine`,
|
||
`railiance-master`, `informed-decision`, `flex-auth`. In doing so, five of them hit the same
|
||
three questions about what §5 reaches, and split on two of them. `ops-warden` asked a fourth,
|
||
before applying anything, about where §5 had sent the version. The custodian collected the
|
||
three with counts; `approval-engine` raised the first two while assenting to A9–A13.
|
||
|
||
The split is the finding. §5 said *"a layer declaration MUST NOT carry a standard
|
||
version"*, and every checker in the estate implemented that as *"no key named
|
||
`standard_version`"*. Two careful implementers reading the same sentence reached different
|
||
files. That is a correct rule a careful implementer can satisfy without doing the thing it
|
||
exists to require — the v0.8 round's closing finding, again, and again in §11.
|
||
|
||
**The counts were re-measured here from the repositories' files**, not taken from the
|
||
custodian's message or this record's own request. They agree with the custodian's on every
|
||
row but one, and they add a repository the custodian's set did not contain:
|
||
|
||
| `standard:` in `INTENT.md` frontmatter | Repositories |
|
||
| --- | --- |
|
||
| versioned path (`…_v0.7.md`) | `audit-core`, `user-engine`, **`whitehat-security`** |
|
||
| unversioned name or path | `ops-warden`, `approval-engine`, `kings-guard`, `secrets-engine`, `tenant-engine`, `maturity-engine`, `zone-engine`, `railiance-master`, `informed-decision` |
|
||
| absent | `railiance-platform`, `flex-auth` (and `gate-house`, which carries `layer:` only) |
|
||
|
||
- **`informed-decision` is not absent.** Its key is present and points at the standards
|
||
directory, unversioned on purpose. Nine repositories are unversioned, not eight.
|
||
- **`whitehat-security` has not applied `GH-DEC-2026-017` at all.** Its `INTENT.md`
|
||
frontmatter still carries `standard_version: "0.7"` beside a versioned path. It is a §4
|
||
row (`Staff`) and is in `GH-DEC-2026-017`'s `affects` list, and **`gate-house` never sent
|
||
it the ruling**: the 2026-09-21 notices went to eleven recipients and it was not one of
|
||
them. The gap is `gate-house`'s, not `whitehat-security`'s, and is recorded as such.
|
||
- **`companion_version`** is carried only by `approval-engine`'s `layer.yaml` (`"0.2"`).
|
||
- **`standard_version` outside a declaration** is carried by `pep-stance.yaml` in
|
||
`ops-warden`, `secrets-engine`, `user-engine`, `tenant-engine` and `informed-decision`,
|
||
by `tenant-engine`'s `pip-claims.yaml`, and by `secrets-engine`'s
|
||
`evidence-classification.yaml` — seven files, not the two the question named.
|
||
- **Seven checkers, not six.** The custodian counts six copies of `ops-warden`'s
|
||
`check_layer_conformance.py` plus the original: `ops-warden`, `kings-guard`,
|
||
`tenant-engine`, `secrets-engine`, `user-engine`, `maturity-engine`, `zone-engine`
|
||
(`tools/`). `flex-auth` enforces absence in `internal/layer/conformance.go` by its own
|
||
code. **Only `kings-guard`'s prints the version it checks against.** Every one of them
|
||
detects a version by the key name `standard_version` and nothing else.
|
||
|
||
## Decision
|
||
|
||
### 1. A version in the `standard:` path is a standard version. A12 reaches the content, not a key name
|
||
|
||
**Counts.** §5's ground was never about a field. It was that a version in a declaration is
|
||
*readable as* a validity condition, and that a field kept "for information" will be branched
|
||
on. `standard: …/security-layer-model_v0.7.md` is read exactly that way — it is the more
|
||
likely of the two to be branched on, because a path is what a tool opens.
|
||
|
||
**What the declaration is, for A12's purpose:** every key of the `INTENT.md` frontmatter,
|
||
and every key of a derived declaration file. A12 forbids a standard version **in any key or
|
||
value** of either, including a version-bearing path or file name.
|
||
|
||
**Not reached,** stated so they do not later read as drift in either direction:
|
||
|
||
- **Comments.** Six sidecars keep a `# Framework: …_v0.7.md` header comment (`audit-core`,
|
||
`railiance-platform`, `tenant-engine`, `maturity-engine`, `zone-engine`,
|
||
`railiance-master`). A comment is not machine-readable and cannot be branched on. Leaving
|
||
it is conforming; removing it is harmless. Neither is required.
|
||
- **`schema_version`.** The version of the sidecar's own schema is not a version of the
|
||
standard. `ops-warden` bumped its schema to `0.2` for the removed key; `approval-engine`
|
||
left `0.1`. Both are fine: the sidecar schema is `ops-warden`'s (`GH-DEC-2026-017`, *What
|
||
this does not rule*), not doctrine's.
|
||
|
||
**Required changes:**
|
||
|
||
- **`audit-core`** — de-version `standard:` in `INTENT.md` frontmatter.
|
||
- **`user-engine`** — de-version `standard:` in `INTENT.md` frontmatter.
|
||
- **`whitehat-security`** — remove `standard_version: "0.7"` from `INTENT.md` frontmatter
|
||
(this is `GH-DEC-2026-017` §5 itself, owed since it issued) and de-version `standard:`.
|
||
|
||
De-versioning means pointing at the standard without a version — the name
|
||
`netkingdom-security-layer-model`, the unversioned path
|
||
`net-kingdom/canon/standards/security-layer-model`, or the directory, as the nine already
|
||
do — or removing the key. Which is the repository's.
|
||
|
||
**The nine that de-versioned made a required change, not an optional one.** `ops-warden`,
|
||
`approval-engine`, `kings-guard`, `secrets-engine`, `tenant-engine`, `maturity-engine`,
|
||
`zone-engine`, `railiance-master` and `informed-decision` acted on their own reading
|
||
of §5 before it was ruled, and the reading was right. **Nothing reverts.**
|
||
|
||
### 2. `companion_version` is a standard version
|
||
|
||
**Counts.** `SECURITY-COMPANION.md` is `type: standard-companion`, owned by `gate-house`,
|
||
`accepted`, and itself pinned `companion_to: …_v0.7.md`. A companion version in a declaration
|
||
makes every companion revision read as invalidating the declaration, which is §5's reason
|
||
without change. Nothing about the companion makes the layer less of a standing property.
|
||
|
||
- **`approval-engine`** — remove `companion_version: "0.2"` from `layer.yaml`. The
|
||
unversioned `companion:` path in `INTENT.md` may stay.
|
||
- **`informed-decision`** — its removal was **required**, not merely harmless. Nothing
|
||
reverts. Its question whether `ops-warden`'s reference form draws the line differently is
|
||
answered: the reference form carries no `companion_version` and does not need to.
|
||
|
||
### 3. A12 does not reach stance maps, claims maps, or evidence classifications
|
||
|
||
**Does not count.** `pep-stance.yaml`, `pip-claims.yaml` and `evidence-classification.yaml`
|
||
are not layer declarations. They state a repository's position on **clause text** — §6.4's
|
||
unreachable-engine stance, §9.3 and §9.7's freshness terms, §9.6's classes — and clause text
|
||
is version-scoped in a way a layer is not. A stance on §6.4 at v0.7 can be wrong at v0.8; a
|
||
layer cannot. The version in these files is what lets a reader know which text the position
|
||
answers, and therefore what to re-read when the text moves. It is the version-scoped state
|
||
§5 said belongs somewhere other than the declaration; these files are such a place.
|
||
|
||
`ops-warden`'s `standard_version` / `standard_version_reviewed` pair sits in the file
|
||
this repository already named as the shape to follow (`GH-DEC-2026-006`), and it is the right shape
|
||
for exactly this reason: it says what binds and what has been read.
|
||
|
||
**Nobody changes.** Every repository read A12 this way and left these files alone; the
|
||
reading is confirmed. A checker MUST NOT apply A12 to them.
|
||
|
||
### 4. §11 does not require every declaring repository to emit a conformance record. The version belongs to the run
|
||
|
||
**First, a correction to `GH-DEC-2026-017` §5.** It said version-scoped state belongs in
|
||
*"the derived conformance record, which under §11's derived-artifact rule already MUST name
|
||
what it derives from and carry the version… That artifact exists; the version has a home."*
|
||
The second half was wrong. §11's derived-artifact rule governs derived artifacts **where they
|
||
exist**; nothing in §11 obliges a declaring repository to produce one, and none of the seven
|
||
checkers writes anything durable. `ops-warden` saw that removing the field removed the only
|
||
place it stated what it conformed against, and asked rather than picked. §5 named a home that
|
||
was not built — the same shape as A10's §4 column, in the same decision family.
|
||
|
||
**Ruled: a re-runnable checker is sufficient — not "sufficient for now" — on one
|
||
condition.** Every run MUST state, in its output:
|
||
|
||
1. the **version or commit of the standard it checks against**, and
|
||
2. its **scope** (A11: §4, or every repository carrying a declaration).
|
||
|
||
The version is an input to the run, not a property of the repository, and a run is the
|
||
thing that has it. A durable record every repository emits would be a second copy of the
|
||
checker's answer that goes stale between runs — a derived artifact whose only property is
|
||
the ability to disagree with a re-run.
|
||
|
||
**Where durability is owed, the relying party owes it.** A run's output that is **retained
|
||
or relied upon** — by an assessment, a conformance report under
|
||
`docs/contracts/conformance-reporting.md`, a `maturity-engine` finding, or the v0.8
|
||
acceptance flip — is a derived artifact under §11's rule and MUST carry the version or
|
||
commit and scope. The party that retains it owes that, not the repository that was checked.
|
||
|
||
**`kings-guard`'s pattern is sufficient.** `VALIDATED_AGAINST`, a constant in the checker,
|
||
printed on every run, is condition 1 exactly. It also has a property the field never had:
|
||
when the canon moves, the constant goes visibly stale in every run's output, where the field
|
||
would have stayed quietly true of the file. It is adopted as the reference pattern. The
|
||
constant lives in the checker, which is not a declaration, and A12 does not reach it.
|
||
|
||
**Required changes to checkers:**
|
||
|
||
- **`ops-warden`, `secrets-engine`, `tenant-engine`, `user-engine`, `maturity-engine`,
|
||
`zone-engine`** — print the standard version or commit checked against, and the run's
|
||
scope, on every run. `kings-guard`'s constant is one way; the property is what is required.
|
||
- **`kings-guard`** — print the run's scope; its checker states the version and does not
|
||
yet state scope.
|
||
- **All seven checkers, and `flex-auth`'s `internal/layer/conformance.go`** — widen A12
|
||
enforcement from the key name `standard_version` to what §1 and §2 rule: no standard or
|
||
companion version in any key or value of the declaration, including a version-bearing
|
||
`standard:` or `companion:` path; comments and `schema_version` excluded; stance, claims
|
||
and classification files excluded. A checker that says it enforces A12 and enforces the
|
||
key name only is a derived artifact that does not agree with its source — §11's own
|
||
derived-artifact defect.
|
||
- **`ops-warden`** — as holder of the reference checker, the widened check is best landed
|
||
there first; the copies follow it. Sequencing is `ops-warden`'s.
|
||
|
||
**`ops-warden`'s held session.** `4220413a` held its change set for a session mandated to
|
||
verify the ruling in this repository rather than from a message. That bar is right, and this
|
||
record is written to be verified that way: the counts above are re-measured from files, and
|
||
each required change names its file.
|
||
|
||
### 5. The citation: `GH-DEC-2026-017` §5 is canonical, and after the flip, §11 as amended by A12
|
||
|
||
The **body's section numbering is canonical**. A decision is cited by its `### N.` sections.
|
||
The `rationale:` field summarises the ruling in parts `(1)`–`(4)` that do not map one-to-one
|
||
onto the six sections — rationale part (3) spans body §3 and §4 — and **is not cited**.
|
||
`ops-warden`'s playbook citation, *"§5"*, is correct. The two repositories that cited A12
|
||
instead were also correct: A12 is the statute text that carries §5. Before the v0.8 flip,
|
||
cite `GH-DEC-2026-017 §5`; after it, cite v0.8 `§11` (A12). Citing both is fine.
|
||
|
||
The rationale is left as written. It is a resolved record's summary, not its text, and
|
||
rewriting it would make the citation question harder to reconstruct, not easier.
|
||
|
||
### 6. A12 is refined as `A12 r2`, and circulated
|
||
|
||
The refinement is drafted in `docs/amendments/v0.8-section-11-declaration-amendments.md`
|
||
and goes to the `GH-WP-0004-T09` round list for assent. `A12` as first circulated already
|
||
had `approval-engine`'s assent; that assent is to the text it saw and is asked again for the
|
||
revision rather than carried over. Until the flip, this record governs implementers; the
|
||
amendment moves it into the statute and does not decide it again.
|
||
|
||
## What this does not rule
|
||
|
||
- **Not ruled: `whitehat-security`'s `conformance_state` and `declared_at` frontmatter
|
||
keys.** `conformance_state: blocked-clean` is state, in a declaration, and may be the same
|
||
shape as a version. It is not raised by any repository and is not ruled on inspection
|
||
alone; it goes to `whitehat-security` as a question.
|
||
- **Not ruled: `informed-decision`'s `INFD-IN-0007`** — how §3.4's definition of Staff
|
||
applies to a deterministic, agent-free repository holding evidence another layer depends
|
||
on. It is a real question and is carried separately; it is not an A12 question.
|
||
- **Not ruled: the sidecar schema's version policy.** `ops-warden`'s.
|
||
|
||
## Reversal condition
|
||
|
||
§1 and §2 reverse if a declaration is found whose layer genuinely depends on the version of
|
||
a document it names — which would mean the layer is not a standing property, and §5 itself
|
||
would fall with it.
|
||
|
||
§3 reverses if a stance or claims map is found being read as a layer declaration by a
|
||
conformance run; the remedy then is to fix the run, and only if that is impossible to extend
|
||
A12.
|
||
|
||
§4's sufficiency reverses if a conformance claim is found relied upon, at a version nobody
|
||
can recover, because nobody retained the run — which would show the relying-party duty does
|
||
not hold in practice.
|
||
|
||
## Provenance
|
||
|
||
Raised by `approval-engine`, which de-versioned its own path on a reading, left
|
||
`companion_version` in place on the same reading's uncertainty, and asked rather than
|
||
guessed on both — assenting to the amendments in the same message. Collected with counts by
|
||
`the-custodian`, which measured on disk rather than from reports and corrected its own
|
||
checker count before sending. `ops-warden` asked the conformance-record question while
|
||
holding its own change on a bar it set for itself, and the question turned out to be a defect
|
||
in `GH-DEC-2026-017` §5. `kings-guard` answered it for itself before it was asked, and that
|
||
answer is the ruling. `informed-decision` removed `companion_version` and said so, which is
|
||
the only reason question 2 had a split to report.
|
||
|
||
## GH-DEC-2026-021 — A12 reaches a pin, not a citation; the run names the text in force; one reference detector, converged by the flip commit
|
||
|
||
```yaml
|
||
id: GH-DEC-2026-021
|
||
kind: decision
|
||
title: A12 reaches a pin, not a citation; the run names the text in force; one reference
|
||
detector, converged by the flip commit
|
||
status: resolved
|
||
owner: Bernd Worsch
|
||
standard: net-kingdom/canon/standards/security-layer-model_v0.8.md
|
||
source_note: the-custodian 3d2775e2 and 45cd7bf9 (counts re-measured here); approval-engine
|
||
358143da; kings-guard 8f821b10 (KG-DEC-2026-005); tenant-engine 38efcca1; whitehat-security
|
||
986bac64; ops-warden acc25ebe (playbook 0f9ada0); the-custodian docs/assessments/2026-09-21-layer-declaration-boundaries.md
|
||
requested_dispositions:
|
||
- approved
|
||
- revised
|
||
- rejected
|
||
affects:
|
||
- gate-house
|
||
- net-kingdom
|
||
- kings-guard
|
||
- approval-engine
|
||
- maturity-engine
|
||
- zone-engine
|
||
- railiance-master
|
||
- railiance-platform
|
||
- informed-decision
|
||
- tenant-engine
|
||
- flex-auth
|
||
- secrets-engine
|
||
- user-engine
|
||
- ops-warden
|
||
- whitehat-security
|
||
- audit-core
|
||
created: '2026-09-21T10:38:31.327138Z'
|
||
updated: '2026-09-21T10:39:28.023577Z'
|
||
rationale: 'Five questions from the GH-DEC-2026-020 round, counts re-measured on disk.
|
||
(1) A12 reaches a pin, not a citation: a version in a key naming a standard or companion
|
||
version, in a path or file name, or in an identity-bearing standard:/companion:
|
||
value. A revision cited in prose is provenance and is not reached, because nothing
|
||
opens or branches on it. No declaration changes, including gate-house''s own INTENT.md.
|
||
The narrow reading benefits gate-house, so it goes to assent as A12 r3, and if that
|
||
is rejected gate-house rewords first. tenant-engine''s rewording is harmless and
|
||
stays. (2) VALIDATED_AGAINST names accepted v0.7 plus the gate-house decisions enforced
|
||
(017, 020, 021), with a gate-house commit recommended. tenant-engine and flex-auth
|
||
re-point now. (3) ops-warden''s playbook detector is the estate reference, with
|
||
one addition (a version token in a standard:/companion: value is a pin). Copies
|
||
converge when next edited and no later than the post-flip re-point commit. (4) The
|
||
re-point is not a 019 closing condition, because it is circular before acceptance.
|
||
It is a post-flip closing condition of GH-WP-0004 (T11). (5) whitehat-security''s
|
||
conformance_state moves to run/evidence records, concurring with its reading. kings-guard''s
|
||
single-repository scope is accepted as A11 r2. INFD-IN-0007 and GH-WP-0004-T06 are
|
||
left open and coupled. Nothing in net-kingdom canon is edited.'
|
||
decided_by: Bernd Worsch
|
||
decided_at: '2026-09-21T10:39:28.023577Z'
|
||
state_hub_decision_id: "f2e34b44-060c-4367-84bf-0d6d29bc4025"
|
||
```
|
||
|
||
## Context
|
||
|
||
`GH-DEC-2026-020` is applied in all eleven repositories it named. The round returned five
|
||
questions, collected by `the-custodian` (`3d2775e2`, corrected by `45cd7bf9`) and raised
|
||
directly by `approval-engine`, `kings-guard`, `tenant-engine`, `whitehat-security` and
|
||
`ops-warden`. Every count below was re-measured here on disk on 2026-09-21, parsing the
|
||
`INTENT.md` frontmatter of each repository that declares `layer:` and every `layer.yaml`,
|
||
comments excluded.
|
||
|
||
- **Prose citations.** Eight declarations carry a revision citation in a prose value, in ten
|
||
values: `kings-guard` 3; `approval-engine`, `maturity-engine`, `zone-engine`,
|
||
`railiance-master`, `informed-decision`, `railiance-platform` and `gate-house`'s own
|
||
`INTENT.md` 1 each. The custodian's "2" for `railiance-platform` is two citations
|
||
(`v0.8`, `v0.7`) in one value. Seven are the same sentence, *"Outside §5 by the v0.5 scope
|
||
rule"*. `tenant-engine` carried an eighth copy citing **v0.7**, which was the wrong
|
||
revision, and has reworded it.
|
||
- **`VALIDATED_AGAINST`.** Eight checkers: six name v0.7 (`kings-guard`, `user-engine`,
|
||
`zone-engine`, `secrets-engine`, `maturity-engine`, `ops-warden`), two name the proposed
|
||
v0.8 (`tenant-engine`, `flex-auth`). Only `ops-warden` names both a net-kingdom and a
|
||
gate-house commit. `kings-guard`, `user-engine` and `zone-engine` name v0.7 and nothing
|
||
else. The custodian's corrected count stands.
|
||
- **Detectors.** They diverge as reported. One more measured case: `informed-decision`'s
|
||
declaring frontmatter carries `intent_version: 0.1.0`, the version of its own `INTENT.md`.
|
||
A detector that flags any key containing or ending in `version` flags it. The reference
|
||
detector does not.
|
||
|
||
## Decision
|
||
|
||
### 1. A12 reaches a pin, not a citation. No declaration changes
|
||
|
||
**Ruled narrow.** A version is *reached* when it is carried **as a pin**: in a key that names
|
||
a version of this standard or its companion, in a path or file name, or in the value of an
|
||
identity-bearing key that names this standard or its companion (`standard:`, `companion:`).
|
||
A revision cited in a record's prose, to say where a rule came from, is **provenance** and
|
||
is not reached.
|
||
|
||
**Reason.** A12's ground, stated in `GH-DEC-2026-017` §5 and kept in `GH-DEC-2026-020` §1,
|
||
is that a version in a declaration *reads as a validity condition* and will be branched on,
|
||
and that a path is what a tool opens. No tool opens or branches on *"the v0.5 scope rule"*.
|
||
Striking the citation deletes provenance and reduces the pin risk by nothing. The
|
||
distinction can also be checked mechanically: a pin sits in a key name, in a path-shaped
|
||
token, or in an identity-bearing key. A reference detector built on that structure (§3)
|
||
separates pins from citations without an allowlist. `approval-engine`'s worry was that a
|
||
content-reading checker cannot tell the two apart by pattern. That is true of a bare `vN.N`
|
||
regex, and it is the reason §3 names one detector.
|
||
|
||
**Conflict of interest, stated.** `gate-house`'s own `INTENT.md` carries one of these
|
||
citations, so the narrow reading benefits the ruler, as it benefits `kings-guard`, which
|
||
proposed it. The reason above does not depend on `gate-house`'s line. The wording goes to
|
||
assent as A12 r3 and is not self-approved. If A12 r3 is rejected in favour of the literal
|
||
reading, `gate-house` rewords its own frontmatter **in the commit that records the
|
||
rejection**, before anyone else is asked to.
|
||
|
||
**Who changes under each outcome:**
|
||
|
||
- **Narrow (ruled):** no declaration changes. `gate-house`'s `INTENT.md` stands.
|
||
`approval-engine`'s single-line allowlist and `kings-guard`'s NOTE both become
|
||
unnecessary, and both are conforming until §3's convergence.
|
||
- **Literal (if A12 r3 is rejected):** ten values in eight declarations are reworded:
|
||
`kings-guard` (3), `approval-engine`, `maturity-engine`, `zone-engine`,
|
||
`railiance-master`, `railiance-platform`, `informed-decision` and `gate-house` (1 each).
|
||
In addition, `approval-engine` drops its allowlist, `kings-guard` turns its NOTE into a
|
||
failure, and the reference detector is widened to any `vN.N` in any value.
|
||
|
||
**`tenant-engine`'s rewording is harmless.** Its note now reads *"the standard's scope
|
||
rule"*, and that conforms under both readings. It also removed a citation that named the
|
||
wrong revision (v0.7, where the rule is v0.5's), so the change was an improvement for a
|
||
reason unrelated to A12. Leave it and do not revert it. The repair that *is* owed is in its
|
||
detector. It fails a bare `vN.N` in any value, which over-reaches this ruling, and it
|
||
converges under §3.
|
||
|
||
### 2. `VALIDATED_AGAINST` names the text in force. ops-warden's playbook is confirmed, with one tightening
|
||
|
||
**Confirmed.** While the v0.8 flip is held under `GH-DEC-2026-019`, a checker's
|
||
`VALIDATED_AGAINST` names the **accepted** `security-layer-model_v0.7.md` and the
|
||
gate-house decision records whose rulings the checker enforces beyond v0.7 (today
|
||
`GH-DEC-2026-017`, `GH-DEC-2026-020`, `GH-DEC-2026-021`). A run that names the proposed v0.8
|
||
claims a check against text that does not govern. That is the same defect `GH-DEC-2026-020`
|
||
§4 moved the version out of the declaration to prevent.
|
||
|
||
**Tightening.** Naming v0.7 alone understates the check. A checker that enforces A12's
|
||
content reach is enforcing `GH-DEC-2026-020`, not v0.7, and its run must say so. A
|
||
gate-house commit is **recommended** and not required. The accepted v0.7 text is frozen,
|
||
so its file name identifies it, while the decision set grows, so a commit pins what "the
|
||
decisions" meant at the time of the run. `ops-warden`'s constant is the reference form.
|
||
|
||
**Who changes:**
|
||
|
||
- **Now:** `tenant-engine` and `flex-auth` each re-point one constant from v0.8 to the v0.7
|
||
form. They claim non-governing text today.
|
||
- **At convergence (§3), not in a separate commit:** `kings-guard`, `user-engine` and
|
||
`zone-engine` add the decision ids. `maturity-engine` and `secrets-engine` add `021`.
|
||
`ops-warden` adds `021` when it next touches the constant.
|
||
|
||
### 3. ops-warden's detector is the estate reference, with one addition, and copies converge by the flip commit
|
||
|
||
**Ruled.** The detector quoted in `ops-warden`'s playbook
|
||
(`wiki/playbooks/netkingdom-layer-declaration.md`, `0f9ada0`) is the **estate reference**
|
||
that copies converge on. Its structure already implements §1. It flags keys that name a
|
||
standard or companion version, flags versions in path or file-name tokens, skips
|
||
`schema_version`, never reads comments, and does not flag a space-preceded `vN.N` in prose.
|
||
|
||
**One addition,** from `kings-guard`'s identity-bearing clause: any version token (`v?N.N`)
|
||
in the value of a `standard:` or `companion:` key is a pin. Without it,
|
||
`standard: security-layer-model v0.7` passes, and that form is the pin A12 exists to stop.
|
||
`ops-warden` adds it to the reference. The playbook's "pending" note on prose citations
|
||
becomes "not reached (`GH-DEC-2026-021` §1)".
|
||
|
||
**The reference errs on one side, deliberately.** Its path pattern flags a versioned path of
|
||
*any* document in a declaration, which is wider than A12's "this standard or its
|
||
companion". No declaration carries such a path today (measured). A repository that needs one
|
||
raises it, and it is not waived by allowlist.
|
||
|
||
**Timetable.** A copy converges **when it is next edited, and no later than the commit that
|
||
re-points its `VALIDATED_AGAINST` after the flip** (§4). That commit touches every checker
|
||
anyway, and a flip that leaves eight detectors disagreeing would accept §11 while its check
|
||
still cannot make two runs agree, which is the defect `GH-DEC-2026-019` holds on. Each
|
||
repository implements its own copy. `gate-house` does not edit them.
|
||
|
||
**Where each copy stands against the reference on today's declarations:** none produces a
|
||
wrong verdict on its own declaration today. `tenant-engine` (any bare `vN.N`) and
|
||
`maturity-engine` (any key containing `version`) over-reach. `flex-auth`'s estate survey is
|
||
the only copy run over peers, so it is the one whose divergence is visible to others.
|
||
|
||
### 4. The re-point is a consequence of the flip, not a condition on it. It is added to GH-WP-0004's closure instead
|
||
|
||
**Not added to `GH-DEC-2026-019`'s closing conditions.** Those conditions must hold *before*
|
||
the flip. A checker cannot name v0.8 as in force before v0.8 is accepted without becoming the
|
||
defect §2 corrects, so making the re-point a precondition would be circular.
|
||
|
||
**What is ruled instead.** The re-point and §3's convergence are a **post-flip closing
|
||
condition of `GH-WP-0004`**, carried as `GH-WP-0004-T11`. The workplan does not finish until
|
||
all eight checkers name v0.8 and run the reference detector, or a repository records a dated
|
||
reason in writing. The flip notice from T10 names the eight repositories, so nothing depends
|
||
on each of them noticing on its own. This keeps the custodian's point, which is that seven
|
||
hand edits need something to ensure they happen, and does not hold the flip on them.
|
||
|
||
### 5. `conformance_state` moves out of the declaration. A11 admits a single-repository run
|
||
|
||
**`whitehat-security`'s `conformance_state`: its reading is concurred with.** The key
|
||
carries no version, so A12 does not reach it and it is not a non-conformance. But it is
|
||
state judged against a particular §5 text, and it changes when WHITEHAT-WP-0008 gets an
|
||
engagement window. Under `GH-DEC-2026-020` §4 that belongs to a run's output or to the
|
||
record that retains it, not to a standing declaration. `whitehat-security` moves it to
|
||
WHITEHAT-WP-0008 or its evidence records, at its own next touch and no later than the flip.
|
||
`declared_at` stays: it dates the act of declaring and is not state.
|
||
|
||
**`kings-guard`'s A11 point: accepted.** A11's scope sentence names the two estate scopes
|
||
and is silent on the scope almost every copied checker actually runs, which is one
|
||
repository grading itself. Drafted as **A11 r2**. A single-repository run is a permitted
|
||
scope. It names the repository and says whether that repository is in §4. A run over a
|
||
repository outside §4 reports a voluntary result, not §4 conformance. On that sentence,
|
||
`informed-decision`'s self-check is well-scoped rather than over-scoped.
|
||
|
||
## What this does not rule
|
||
|
||
- **`INFD-IN-0007`**, how §3.4's Staff definition fits a repository that is deterministic by
|
||
test and holds evidence `audit-core` depends on. It is **left open, explicitly.** It is a
|
||
question about §3's primary cut, not about §11. A real answer amends §3.4 or states a
|
||
carried tension in the standard's voice, and neither belongs in a set whose hold is
|
||
scoped to §11 (`GH-DEC-2026-019` §5).
|
||
- **`GH-WP-0004-T06`, the §4 row `informed-decision` asked for.** It is **left open**, and it
|
||
is coupled to `INFD-IN-0007`. A catalogued Staff row is measured against §3.4 directly, and
|
||
drafting the row before that fit is answered would put a row into §4 that §3.4 prohibits
|
||
on its face. The answer is recorded as received and it is not declined.
|
||
- **The sidecar schema's version policy**, which remains `ops-warden`'s.
|
||
|
||
## Reversal condition
|
||
|
||
§1 reverses if a tool is found reading or branching on a prose revision citation in a
|
||
declaration. The remedy is then the literal reading, and `gate-house`'s own line goes first.
|
||
|
||
§3's reference reverses if a declaration is found that the reference passes and a reader
|
||
would take as pinned to a version. The detector is widened, and the ruling does not change.
|
||
|
||
§4 reverses if T11 is still open six months after the flip. That would show a workplan
|
||
closing condition is not enough, and the re-point becomes a precondition of the *next* flip.
|
||
|
||
## Provenance
|
||
|
||
Raised independently by `approval-engine`, which allowlisted its one line and asked instead
|
||
of rewording, and by `kings-guard`, which proposed the narrow wording and said plainly that
|
||
it benefits from it. `tenant-engine` reworded ahead of the ruling, offered to revert, and
|
||
turned out to have removed a wrong citation. `the-custodian` measured the eight declarations
|
||
and the checker split, and corrected its own count within a minute. `ops-warden` wrote the
|
||
reference detector as steward's practice, left the open question visibly pending rather than
|
||
deciding it in code, and the detector is adopted largely as written.
|
||
|
||
## GH-DEC-2026-022 — ops-mason's Kubernetes contact: no engine owns it, and founder plan approval is an accepted exception to §6.4
|
||
|
||
```yaml
|
||
id: GH-DEC-2026-022
|
||
kind: decision
|
||
title: 'ops-mason''s Kubernetes contact: no engine owns it, and founder plan approval
|
||
is an accepted exception to section 6.4'
|
||
status: resolved
|
||
owner: Bernd Worsch
|
||
repo: gate-house
|
||
standard: net-kingdom/canon/standards/security-layer-model_v0.7.md
|
||
source_note: the-custodian docs/kubernetes-change-gate-decision.md (the-custodian@e3d0d13);
|
||
the-custodian docs/ops-mason-plan-approval-gate-decision.md (the-custodian@4e58927,
|
||
terminology corrected at e3d0d13); ops-mason INTENT.md frontmatter (ops-mason@0ff263a);
|
||
ops-mason 696fa9e2; the-custodian 7a21dbfe and eba40030
|
||
requested_dispositions:
|
||
- approved
|
||
- revised
|
||
- rejected
|
||
affects:
|
||
- gate-house
|
||
- ops-mason
|
||
- net-kingdom
|
||
- railiance-platform
|
||
- railiance-master
|
||
- rapp-policy-nexus
|
||
- access-engine
|
||
created: '2026-09-21T12:30:00.000000Z'
|
||
updated: '2026-09-21T12:30:00.000000Z'
|
||
rationale: 'Records two founder decisions of 2026-09-21, both taken by Bernd Worsch
|
||
exercising GOVERN @ estate, against gate-house''s statute. (1) ops-mason''s section
|
||
5.3 gap kubernetes-plane-apply asked gate-house which engine, if any, should own
|
||
its contact with the Kubernetes API. None does. The gate on ADMINISTER @ realm:kubernetes
|
||
is a quality gate on a change, not an authorization decision, tiered by railiance-master
|
||
ADR-0006 readiness_state; no PDP belongs in the path. The gap stays declared with
|
||
intended_owner null by decision, which section 5.3 already accommodates as a permanent
|
||
operational necessity whose review keeps returning. (2) Founder plan approval (activation=APPROVED)
|
||
gating ops-mason''s phase-4 writes is a founder-accepted exception against section
|
||
6.4 obligation 1 and ops-mason''s section 13.1 row. It is not a change to section
|
||
6.4, ops-mason remains non-conformant there, and a conformance run reports the exception
|
||
as accepted, never as conformance. For kubectl apply, (1) narrows the exception
|
||
to targets below production-approved, the rapp-policy-nexus transition to 2026-12-21,
|
||
and BREAK_GLASS. No amendment is drafted. Nothing in net-kingdom canon is edited.'
|
||
decided_by: Bernd Worsch
|
||
decided_at: '2026-09-21T12:30:00.000000Z'
|
||
state_hub_decision_id: "9cff26fc-9213-4f46-b896-065c63886a19"
|
||
```
|
||
|
||
## Context
|
||
|
||
ops-mason declared its NetKingdom layer at `ops-mason@0ff263a`. Its `INTENT.md` frontmatter
|
||
lists every direct Tooling contact as a §5.3 declared engine gap. One of them,
|
||
`kubernetes-plane-apply` (`src/ops_mason/kubernetes_plane.py`: server dry-run then apply of
|
||
an allowlisted, digest-pinned bundle), carries `intended_owner: null`. Its `blocked_on` says
|
||
Kubernetes is not catalogued in §4, that ops-mason reads the cluster as Tooling by character
|
||
(§3.2), and that the question was *"raised with gate-house as a catalog question"*. Gate House
|
||
had not recorded that question anywhere. It is opened and closed as `GH-IN-0004`.
|
||
|
||
Separately, ops-mason answered gate-house's §6.4 obligation 3 note (`696fa9e2`): its stance is
|
||
undecided, not only unpublished, because phase-4 builds are gated by founder approval of a
|
||
construction plan (`plan.is_approved()`) and not by an `access-engine` decision. It recorded
|
||
`pep_stance: declared-gap`, review 2026-12-21.
|
||
|
||
The founder decided both on 2026-09-21. The records are the custodian's, and this entry reads
|
||
from them, not from the hub messages that announced them.
|
||
|
||
- `the-custodian/docs/ops-mason-plan-approval-gate-decision.md`: the plan-approval exception.
|
||
- `the-custodian/docs/kubernetes-change-gate-decision.md`: the Kubernetes change gate, which
|
||
answers the question the first record left open.
|
||
|
||
Section numbers are those of the accepted v0.7. They are unchanged in the held v0.8 text.
|
||
|
||
## Decision
|
||
|
||
### 1. No engine owns ops-mason's Kubernetes contact
|
||
|
||
**Answer to the §5.3 gap `kubernetes-plane-apply`: none.** Applying manifests to a running
|
||
cluster is `ADMINISTER @ realm:kubernetes/railiance01`. The gate on it is a **quality gate on a
|
||
change, not an authorization decision**. railiance-master ADR-0006 already keeps readiness and
|
||
permission on separate axes (`production-approved` "is not an authorization decision"), so no
|
||
policy decision point belongs in this path and `access-engine` is not its owner. The
|
||
Kubernetes API stays a Tooling contact, owned by `rail-kubernetes`.
|
||
|
||
The gate is tiered by the target's ADR-0006 `readiness_state`, not by `Environment`, because
|
||
railiance01 is one cluster and every workload on it shares one `Environment`:
|
||
|
||
| Readiness state of the target | Path for a change | `Activation` |
|
||
|---|---|---|
|
||
| `declared`, `installed`, `verified` | Direct `ADMINISTER @ realm:kubernetes` by ops-mason | `APPROVED`: founder approval of the construction plan |
|
||
| `production-approved` | `CONSTRUCT @ manifest repository`, reconciled by ArgoCD (`railiance-platform`) | `APPROVED` for the change; the merge is the gate |
|
||
| `production-approved`, emergency | Direct `ADMINISTER` | `BREAK_GLASS`, recorded, reconciled back into the repository afterwards |
|
||
|
||
Platform objects with no readiness state default to the production tier. Production goes
|
||
through git for an `EvidenceBoundary` reason: a direct apply is `target-audited`, and a change
|
||
through the manifest repository adds `external-audited` evidence. That is a statement about
|
||
evidence, not about trust in ops-mason.
|
||
|
||
**What this means for the gap, in §5.3's terms.** The contact stays a **declared gap**, and
|
||
`intended_owner: null` is now a decided value rather than an open one. §5.3 already names this
|
||
case: *"A permanent operational necessity is a declared gap whose review interval keeps
|
||
returning."* The gap is not converted into a standing allowance, and no fourth shape is
|
||
created, which §5.3 declines explicitly. ops-mason's `blocked_on` for this entry may now cite
|
||
the founder decision in place of the open catalog question. That edit is ops-mason's.
|
||
|
||
The decision relies on the limits ops-mason's executor has today: one expected namespace per
|
||
plan, no `Pod` or `Secret` kinds, no manifest carrying `data` or `stringData`. Widening them is
|
||
a new decision, and gate-house would expect the §5.3 entry to be re-reviewed with it.
|
||
|
||
### 2. Founder plan approval is an accepted exception to §6.4, not a change to it
|
||
|
||
Recorded against **§6.4 obligation 1** and against **ops-mason's §13.1 row**.
|
||
|
||
- **Covered:** ops-mason's phase-4 protected changes as declared at `ops-mason@0ff263a`:
|
||
writing OpenBao policies and auth roles on `auth/approle` and `auth/kubernetes`, creating
|
||
AppRole secret_ids, and `kubectl apply` of Kubernetes objects. For these, founder approval of
|
||
the construction plan (`activation=APPROVED`) is accepted as the gate, without an additional
|
||
`access-engine` decision.
|
||
- **Not a change to §6.4.** Obligation 1 still requires a PEP to act on a decision from
|
||
`access-engine` or on a recorded §9.3 stance. ops-mason meets neither, and this record does
|
||
not say it does. What changes is the status of the gap: undecided before, founder-accepted
|
||
now, with a reason and a review date.
|
||
- **§13.1.** ops-mason's row stays as written, not published and marked. Gate House reads it
|
||
with this exception beside it: the missing stance map is an **accepted** non-conformance
|
||
under §6.4 obligations 1 and 3, not an unexplained one. ops-mason's `pep_stance` stays
|
||
`declared-gap`. Nothing is added to the canon row.
|
||
- **Conditions:** the covered actions only; structure only, never secret values; the gaps stay
|
||
declared and a conformance run reports them as accepted exceptions, never as conformance;
|
||
review 2026-12-21, when the founder either renews the exception or asks for these writes to
|
||
route through `access-engine`.
|
||
|
||
### 3. How the two compose
|
||
|
||
For `kubectl apply`, decision 1 narrows the exception. Founder plan approval gates a direct
|
||
apply only where the target is below `production-approved`. A `production-approved` target, or
|
||
a platform object with no readiness state, takes the `CONSTRUCT` path through the manifest
|
||
repository, except under `BREAK_GLASS` and except for the `rapp-policy-nexus` transition.
|
||
`rapp-policy-nexus` is `production-approved` but not yet managed by ArgoCD. Until 2026-12-21 its
|
||
changes keep `activation=APPROVED` by founder plan approval, and each change records that its
|
||
target is production-tier, so the transition does not read as conformance.
|
||
|
||
The OpenBao writes in the exception are untouched by decision 1.
|
||
|
||
**A tension carried to the review.** At the 2026-12-21 review the exception offers a route
|
||
through `access-engine`. For the Kubernetes contact, decision 1 has already said no PDP belongs
|
||
in the path, so that route is closed there, and the review's real choice for `kubectl apply`
|
||
is to renew. The OpenBao writes keep both options. Gate House records this and rules nothing
|
||
on it now.
|
||
|
||
### 4. No amendment is drafted
|
||
|
||
Neither decision needs one to take effect.
|
||
|
||
- The exception is a founder-accepted exception by its own terms. An amendment recognising
|
||
plan approval as PDP-equivalent under §6.4 would be a canon change, and nobody has proposed
|
||
it. Gate House does not propose it here.
|
||
- The §5.3 answer fits the text as written, including a null `intended_owner` for a permanent
|
||
necessity.
|
||
|
||
One canon gap is noted and not drafted. Kubernetes is not catalogued in §4, yet decision 1
|
||
treats it as Tooling owned by `rail-kubernetes`, and ops-mason declares the contact as §5.3 by
|
||
character. §5's scope rule reads "Tooling-layer system" as "catalogued as Tooling in §4". So a
|
||
§4 row for the Kubernetes API is the way to bring the contact under §5 deliberately, and that
|
||
is the only point where the canon lags this decision. It is not drafted now, because the v0.8
|
||
hold is scoped to §11 (`GH-DEC-2026-019`) and ops-mason's declaration already closes the
|
||
practical gap. It is a candidate for the cut after v0.8.
|
||
|
||
## What this does not rule
|
||
|
||
- Whether ArgoCD is syncing on railiance01 today. The custodian could not check it, and
|
||
gate-house does not either.
|
||
- The ops-mason phase-4 readiness check, the ArgoCD onboarding of `rapp-policy-nexus`, and
|
||
ADR-0006's deploy-path consequence. They belong to ops-mason, railiance-platform,
|
||
rapp-policy-nexus and railiance-master.
|
||
- `GH-WP-0004-T08` (ops-mason's §11 declaration). It is related only because the same
|
||
frontmatter carries it.
|
||
|
||
## Reversal condition
|
||
|
||
Both decisions are the founder's, so gate-house does not reverse them. It returns decision 1
|
||
to the founder if the gate on `ADMINISTER @ realm:kubernetes` comes to carry an authorization
|
||
question, for example if ops-mason's executor is widened to `Secret` kinds or to arbitrary
|
||
namespaces. That would bring an owning engine back into question.
|
||
|
||
Decision 2 lapses at the 2026-12-21 review unless the founder renews it.
|
||
|
||
## Provenance
|
||
|
||
ops-mason declared the contact rather than treating it as out of scope, and named its own
|
||
open question in its `blocked_on` field instead of assigning an owner. The custodian recorded
|
||
both founder decisions and corrected its own first version's bare "operator" to the founder
|
||
exercising `GOVERN`.
|
||
|
||
## GH-DEC-2026-024 — The completeness non-claim binds load-bearing emission where it is not completeness; evidence source is yes, no, or unassessed; a failure-path release is refused
|
||
|
||
```yaml
|
||
id: GH-DEC-2026-024
|
||
kind: decision
|
||
title: The completeness non-claim binds load-bearing emission where it is not completeness;
|
||
evidence source is yes, no, or unassessed; a failure-path release is refused
|
||
status: resolved
|
||
owner: Bernd Worsch
|
||
repo: gate-house
|
||
standard: net-kingdom/canon/standards/security-layer-model_v0.8.md
|
||
source_note: audit-core history/2026-09-23-v0.8-section-11-review.md findings 1 and
|
||
2; AUDIT-IN-0005; AUDIT-IN-0006 / FLEX-DEC-2026-018; gate-house message 715cf1f2
|
||
(2026-10-03), a reading now ruled; GH-DEC-2026-018
|
||
requested_dispositions:
|
||
- approved
|
||
- revised
|
||
- rejected
|
||
affects:
|
||
- gate-house
|
||
- net-kingdom
|
||
- audit-core
|
||
- access-engine
|
||
created: '2026-10-04T23:42:32.322356Z'
|
||
updated: '2026-10-04T23:42:38.792330Z'
|
||
rationale: Accepts audit-core's 2026-09-23 section 11 review and rules the section
|
||
9.6 question AUDIT-IN-0006 referred, which gate-house message 715cf1f2 left as a
|
||
reading. (1) The completeness non-claim binds load-bearing emission guarantees as
|
||
well as attributive ones, where the declared guarantee is not itself completeness.
|
||
An outbox and a detection surface state the controls, not a proof that every event
|
||
was sent. A2 of the v0.8 amendment set is amended. The canon is not edited; publication
|
||
remains net-kingdom's. (2) The evidence-source column is yes, no, or unassessed.
|
||
audit-core is no, which GH-DEC-2026-018 and AUDIT-IN-0005 already decided; no new
|
||
status is invented. The binary yes-or-dash column is amended. (3) Section 9.6 admits
|
||
no exception that lets a load-bearing source declare a detectable, direction-limited
|
||
failure-path release and still count as conforming. A release that proceeds when
|
||
the required emission did not happen fails open. Rule 17 does not admit it. Section
|
||
11 gains no declaration for it. The conflict with fail-closed is resolved by refusal.
|
||
v0.8 is not flipped.
|
||
decided_by: Bernd Worsch
|
||
decided_at: '2026-10-04T23:42:38.792330Z'
|
||
state_hub_decision_id: "99fd5db2-2320-4285-ad48-f6254933afc3"
|
||
```
|
||
|
||
## Context
|
||
|
||
`audit-core` returned its §11 review on 2026-09-23
|
||
(`history/2026-09-23-v0.8-section-11-review.md`), not a decline. Two findings are
|
||
against the cut. Only the attributive arm of the emission-guarantee check must say
|
||
that completeness is not claimed, so a load-bearing declaration of an outbox, a
|
||
cadence and a detection surface reads as a completeness claim, and neither control
|
||
supports that reading. And A10's evidence-source column carries `yes` or `—`, while
|
||
an unassessed row also carries `—`, so a run cannot tell `audit-core` — assessed as
|
||
custodian, not source — from a row nobody has assessed.
|
||
|
||
Separately, on 2026-09-24 (`AUDIT-IN-0006`, from `FLEX-DEC-2026-018`), `audit-core`
|
||
asked whether §9.6 admits a declared, detectable, direction-limited failure-path
|
||
release for a load-bearing source, and whether §11 should read such a declaration.
|
||
The case is a deny, a redact, or a not-applicable that proceeds when the outbox
|
||
commit fails and is counted as `released_uncommitted`. Gate House replied on
|
||
2026-10-03 (message `715cf1f2`) with a reading of the current text and left the
|
||
ruling to this record. That reading stands. The conflict it named is no longer open.
|
||
|
||
Section numbers are those of the proposed v0.8 text. v0.7 stays accepted. Nothing
|
||
in `net-kingdom` canon is edited by this record.
|
||
|
||
## Decision
|
||
|
||
### 1. The completeness non-claim binds load-bearing sources where the guarantee is not completeness
|
||
|
||
**Accepted.** `audit-core`'s first finding is right, and it is the bound on rule 13
|
||
applied to the check that was written to make §9.6 observable.
|
||
|
||
§9.6 says an append-only archive proves records were not altered or truncated after
|
||
arrival. It cannot prove a record was never sent. INTENT states the same bound on
|
||
rule 13: completeness is the emitting system's obligation, discharged by making
|
||
emission atomic with the state change, and no archive can retrofit it. The §9.6
|
||
decomposition then assigns the controls:
|
||
|
||
- accidental omission is prevented by emission atomicity, the local outbox;
|
||
- adversarial omission is detected after the fact by cadence and reconciliation;
|
||
- adversarial omission at a compromised source, including a source that suppresses
|
||
an event and its own count together, is prevented by nothing in this model.
|
||
|
||
Heartbeat and reconciliation cover loss, outage, drain failure and accident. They
|
||
are not a completeness proof. The outbox gives atomicity at the source, not
|
||
completeness at the archive. A load-bearing declaration that names those controls
|
||
and stops has stated no bound, and a reader will take it as the claim the
|
||
attributive arm is forbidden to make. That reading has already been quoted as if it
|
||
were one.
|
||
|
||
**The non-claim is required on the load-bearing arm where the guarantee is not
|
||
actually completeness.** Atomic emission with the state change is the completeness
|
||
obligation, and the declaration may say that. Detection, and custody of what
|
||
arrived, are not that obligation. The declaration states the controls, not their
|
||
sufficiency. A load-bearing guarantee that omits the non-claim is not conforming,
|
||
for the same reason an attributive guarantee that implies completeness is not.
|
||
|
||
A2 of `docs/amendments/v0.8-amendment-set.md` is amended so the load-bearing arm
|
||
carries the explicit non-claim. The longer arm already assembled in the proposed
|
||
cut — volume versus rare, heartbeat and reconciliation — is otherwise unchanged;
|
||
the non-claim is added to that arm at publication. Publication remains
|
||
`net-kingdom`'s under `GH-WP-0004-T10`. This repository does not edit the canon.
|
||
v0.8 is not flipped.
|
||
|
||
### 2. The evidence-source column is `yes`, `no`, or `unassessed`, and `audit-core` is `no`
|
||
|
||
**Accepted.** This is `GH-DEC-2026-018` and `AUDIT-IN-0005`, recorded in the column
|
||
those records required. It is not a new classification of `audit-core`.
|
||
|
||
`GH-DEC-2026-018` §1: a custodian is never the source of what it holds, and
|
||
`audit-core`'s `Evidence` role is custody. `AUDIT-IN-0005`: `audit-core` is not the
|
||
§4 source of the decision record; the emitter is. The column A10 drafted could not
|
||
say that. `yes` or `—`, with `—` also meaning not yet assessed, makes the assessed
|
||
answer and the missing answer the same mark. That is the inference A10 exists to
|
||
remove.
|
||
|
||
**The column carries exactly three values: `yes`, `no`, `unassessed`.**
|
||
|
||
- `access-engine` stays `yes`, per `GH-DEC-2026-018` §2.
|
||
- `audit-core` is `no`. No other status is invented for it.
|
||
- A row not assessed in those two records carries `unassessed`. Silence is not
|
||
`no`. §11 reports `unassessed` as unassessed, not as conforming and not as
|
||
not-a-source.
|
||
|
||
`—` is not a value of this column. The binary text in
|
||
`docs/amendments/v0.8-section-11-declaration-amendments.md` A10 is amended.
|
||
Other §4 rows are not marked here.
|
||
|
||
### 3. No §9.6 exception for a failure-path release
|
||
|
||
**Refused.** A load-bearing source may not declare a detectable, direction-limited
|
||
failure-path release and still count as conforming. §11 does not gain a
|
||
declaration for it. The exception is not added to the standard.
|
||
|
||
The 2026-10-03 reading (message `715cf1f2`) stands as the reading of the current
|
||
text, and it is now the ruling:
|
||
|
||
1. §9.6 admits no such exception. Its table gives a load-bearing event one
|
||
obligation: emission MUST be atomic with the state change. A denial is one of
|
||
the examples. The declared trade — completeness MUST NOT be claimed — is
|
||
attached to attributive evidence only. It is not a licence to skip atomicity on
|
||
a load-bearing class and describe the skip.
|
||
2. §11's emission-guarantee check reads no such declaration. A load-bearing source
|
||
declares an outbox, a cadence and the governing detection surface. There is no
|
||
field for a failure-path release. Releasing deny, redact, or not-applicable
|
||
uncommitted is a §9.6 non-conformance for those classes, not a conformant
|
||
exception.
|
||
3. `audit-core` was right not to prefer withholding. Telling a decision point how
|
||
to release routes an authorization choice through the audit fabric. This record
|
||
does not do that either. It rules whether the release counts as conforming. It
|
||
does not.
|
||
|
||
**The conflict with fail-closed is resolved by refusal.** Message `715cf1f2` left
|
||
it open: the proposed failure direction is toward restriction, and a withheld deny
|
||
that an open-for-scope consumer reads as proceed would manufacture permission.
|
||
That conflict is real. It does not admit the exception.
|
||
|
||
The distinguishing case under rule 17 is the case that separates the proposal from
|
||
the conformant state. The conformant state is §9.6: the load-bearing emission
|
||
happens with the state change, or the change does not. The proposal is that the
|
||
release proceeds when the required emission did not happen, and that
|
||
`released_uncommitted` makes the miss detectable afterwards. **A release that
|
||
proceeds when the required emission did not happen fails open.** Detection after
|
||
the fact is not failing closed. Direction-limited is not failing closed. A promise
|
||
that fails open is a permission; a promise that fails closed is a gap; only the
|
||
second is a thing a register can hold. Rule 17 does not admit this one. Rule 14
|
||
is the same point from the other side: failure of a critical authorization
|
||
dependency fails closed, and an unavailable emission is not a permission to act
|
||
without the record.
|
||
|
||
Naming the classes, the failure condition and `released_uncommitted` as a §11
|
||
detection surface would make that permission look like a conforming trade.
|
||
`completeness_trade` keeps its attributive meaning. It is not extended to
|
||
load-bearing classes. `audit-core`'s registration claims no atomicity for those
|
||
classes until this ruling; the ruling is that they may not be released that way
|
||
and still conform. What `access-engine` does instead is its implementation, under
|
||
the obligation the text already states.
|
||
|
||
## What this does not rule
|
||
|
||
- **Not ruled: which other §4 rows are sources.** `access-engine` is `yes` and
|
||
`audit-core` is `no`. Every other row stays `unassessed` until it is assessed.
|
||
This record does not assign them.
|
||
- **Not ruled: `access-engine`'s class inventory.** `GH-DEC-2026-018` §4 still
|
||
holds. This record does not classify deny, redact, or not-applicable, and it
|
||
does not publish a cadence.
|
||
- **Not ruled: the registration mechanics of `AUDIT-IN-0006`.** Sender shape,
|
||
`may_read`, tenants, heartbeats, envelope and the token lane are `audit-core`'s.
|
||
They stay deferred on the outbox, as that intake already says. This record
|
||
registers nothing.
|
||
- **Not ruled: how `access-engine` withholds.** The statute says the load-bearing
|
||
release does not proceed without the emission. The mechanism is not specified
|
||
here, and it is not specified by `audit-core`.
|
||
- **Not ruled: v0.8 acceptance.** The hold under `GH-DEC-2026-019` stands. T09 and
|
||
T10 stay wait. v0.8 is not flipped.
|
||
- **Not ruled: `GH-DEC-2026-023`.** It remains a draft. This record does not move it.
|
||
|
||
## Reversal condition
|
||
|
||
§1 reverses if a load-bearing control is found whose soundness really is
|
||
completeness of the archive. §9.6 says no control in this model has that. The
|
||
non-claim would then be the false statement. It does not reverse because atomicity
|
||
prevents accidental omission: that obligation stays, and it is not what the
|
||
non-claim denies.
|
||
|
||
§2 reverses on the condition `GH-DEC-2026-018` §5 already names: a §4 row that is
|
||
a source in one capacity and not another. The repair is a per-class marking, not a
|
||
return to `yes` or `—`.
|
||
|
||
§3 reverses if the release is shown to fail closed on the distinguishing case —
|
||
the required emission did not happen, and the protected release did not proceed.
|
||
A release that proceeds is not that case. A later detection of `released_uncommitted`
|
||
is not that case.
|
||
|
||
## Provenance
|
||
|
||
`audit-core` returned the review it was asked for, against a cut whose emission
|
||
wording it had caused to exist, and the non-claim it asked for is one its own
|
||
declaration already states for both kinds. The column defect is the same line as
|
||
`AUDIT-IN-0005`, which it answered about itself rather than taking the source
|
||
role. The exception question came from `access-engine`'s `FLEX-DEC-2026-018`
|
||
through `AUDIT-IN-0006`. `audit-core` referred the statute question here instead
|
||
of deciding it in the registration, and said plainly that preferring withholding
|
||
was not its to say. The 2026-10-03 reply stated the reading and left the conflict
|
||
open. This record closes it by refusal.
|
||
|
||
|
||
## GH-DEC-2026-025 — Carry the deterministic presentation evidence tension explicitly and hand off the requested catalogue row
|
||
|
||
```yaml
|
||
id: GH-DEC-2026-025
|
||
kind: decision
|
||
title: Carry the deterministic presentation evidence tension explicitly and hand off the requested catalogue row
|
||
status: resolved
|
||
owner: Bernd Worsch
|
||
repo: gate-house
|
||
created: '2026-10-11'
|
||
updated: '2026-10-11'
|
||
decided_by: Bernd Worsch
|
||
source_note: GH-WP-0004-T06-r1; native human memo infd-20261011-staff-evidence-tension version 1
|
||
native_review_id: review-2e615985-54c9-40d8-8547-b8fdcb10b1d6
|
||
native_approval_id: d90c899b-f25c-4e66-a003-808ee5b1324f
|
||
native_disposition_id: disp-24e94200-ed93-4a18-900c-3128d26ba212
|
||
proposal_sha256: 08bc78a29c2b67cec0aafba993fb2d25312b629ecccb81458980baafe38e566a
|
||
submission_digest: sha256:d2224fb5f8e577b1dd45b73fb01bf6c8880f1e7e167945e3a186b23738742609
|
||
affects: [gate-house, informed-decision, net-kingdom, audit-core, policy-nexus]
|
||
rationale: >-
|
||
Confirmed native human ACCEPT of the exact bounded carried-tension proposal
|
||
for source-owner review and successor publication. Retain the ruled Staff /
|
||
PEP-shaped classification; propose the requested catalogue row with evidence
|
||
source yes, and keep the actual section 3.4 tension and owed per-event
|
||
load-bearing guarantees visible. This does not ratify a whole successor
|
||
standard, edit accepted v0.8, authorize deployment or certify runtime evidence.
|
||
state_hub_decision_id: "489be6ba-9aa8-4fea-87ed-4a2ee5fd29e7"
|
||
```
|
||
|
||
### Confirmed disposition and exact scope
|
||
|
||
The native outcome records a confirmed person `accept` at 2026-10-11T01:46:25Z,
|
||
actor `uid=platform-root,ou=people,dc=netkingdom,dc=local`, against memo version 1,
|
||
review `review-2e615985-54c9-40d8-8547-b8fdcb10b1d6`; the review is not stale.
|
||
The approval and disposition above identify the actual human act. The
|
||
[retained evidence receipt](../docs/evidence/2026-10-11-staff-evidence-human-disposition.json)
|
||
preserves the exact submitted packet and native outcome. Gate House records this
|
||
human disposition; it performs neither the human act nor a new NetKingdom review.
|
||
|
||
The approved instrument is the immutable
|
||
[GH-WP-0004-T06-r1 proposal](../docs/amendments/informed-decision-staff-evidence-disposition-proposal.md)
|
||
at its recorded digest, including its exact candidate §3.4 and §4 wording,
|
||
alternatives and recording limits. It approves **carrying** the incompatibility,
|
||
not claiming it solved: deterministic presentation evidence still does not fit the
|
||
absolute Staff wording. Catalogue membership identifies obligations; it is not
|
||
conformance. GH-DEC-2026-012/014/017/021/024 remain intact as prior decisions.
|
||
|
||
### Source-owner handoff and retained obligations
|
||
|
||
The [source-owner handoff](../docs/amendments/2026-10-11-staff-evidence-disposition-handoff.md)
|
||
extracts the approved wording for NetKingdom's proposed successor revision.
|
||
The prior distinct NetKingdom technical review in the native packet is not whole
|
||
revision ratification or serving publication. Accepted v0.8 SHA256
|
||
`3d8298560069ef471fba28d2b1245fb2309328f231dad1a667cdf0ce5a5a7c8b`
|
||
remains immutable. The permitted next work is source-owner follow-through and
|
||
proposed successor publication; later acceptance and delivery retain their own gates.
|
||
|
||
`INFD-IN-0007` remains open until the standard's accepted voice actually carries the
|
||
answer, as the approved packet says. The Staff/evidence fit remains a visible
|
||
unresolved finding even after that answer. `presentation` stays load-bearing/volume;
|
||
`disposition` and `stance-application` stay load-bearing/rare. Independent evidence,
|
||
per-class detection/reconciliation and existing fail-closed local evidence duties
|
||
are not waived. Source-owner implementation records, not this doctrine decision,
|
||
prove actual emission operation. Nothing here permits approval-current-state caches,
|
||
a second PDP, direct Tooling access, a blanket Staff state exemption or a new layer.
|
||
|
||
## GH-DEC-2026-026 — Decision classes C0-C3; ceremony is proportionate to reliance, and a decision relied on as authority for an act is at least C2
|
||
|
||
```yaml
|
||
id: GH-DEC-2026-026
|
||
kind: decision
|
||
title: Decision classes C0-C3; ceremony is proportionate to reliance, and a decision
|
||
relied on as authority for an act is at least C2
|
||
status: resolved
|
||
owner: Bernd Worsch
|
||
repo: gate-house
|
||
standard: net-kingdom/canon/standards/security-layer-model_v0.8.md
|
||
source_note: decisions/drafts/GH-DEC-2026-026-decision-classes.md (gate-house@a3d68c8);
|
||
net-kingdom docs/proposals/2026-10-31-decision-services-alignment-review.md (net-kingdom@b764561,
|
||
sections 4.3, 4.4, 6.1, slice S5); net-kingdom docs/proposals/2026-10-31-nk56-t17-founder-approval-path.md;
|
||
hub message 8f4ba4e2-5cb4-4965-9c5e-5aedf8fb6b5f (2026-10-31); founder ruling 2026-11-01
|
||
relayed in session by the net-kingdom coordinator
|
||
requested_dispositions:
|
||
- approved
|
||
- revised
|
||
- rejected
|
||
affects:
|
||
- gate-house
|
||
- informed-decision
|
||
- approval-engine
|
||
- state-hub
|
||
- net-kingdom
|
||
- access-engine
|
||
- audit-core
|
||
- ops-mason
|
||
- railiance-platform
|
||
created: '2026-10-31T23:31:56.581695Z'
|
||
updated: '2026-10-31T23:32:06.407351Z'
|
||
rationale: 'Approved as drafted. Founder ruling of 2026-11-01, relayed in session
|
||
by the net-kingdom coordinator: "Accept GH-DEC-2026-026 as drafted". The three open
|
||
points were accepted as drafted: reliance, not who executes, is the C2 trigger (Ruling
|
||
2); C3 is reserved, not usable (Ruling 1); the actor is never an approver of its
|
||
own approval (Ruling 6). Agents never approve at C1 or above. The ruling is itself
|
||
a C1 disposition taken in session and recorded as asserted under build-mode relaxation
|
||
B3; it is not C1 evidence. It sets doctrine only: no service mechanics, no canon
|
||
edit and no live change are authorized by it.'
|
||
decided_by: Bernd Worsch
|
||
decided_at: '2026-10-31T23:32:06.407351Z'
|
||
```
|
||
|
||
## Disposition
|
||
|
||
**Approved as drafted, 2026-11-01.** Founder ruling relayed in session by the
|
||
net-kingdom coordinator: "Accept GH-DEC-2026-026 as drafted". The open points
|
||
presented under GH-WP-0005-T01 were all accepted as drafted: reliance is the C2
|
||
trigger (Ruling 2), C3 is reserved (Ruling 1), the actor is not an approver of
|
||
its own approval (Ruling 6), and agents never approve at C1 or above.
|
||
|
||
By this record's own Ruling 4 the ruling is a C1 disposition. With no C1
|
||
surface yet, it is recorded as **asserted in session** under relaxation B3, not
|
||
as C1 evidence. The text below is the draft as ruled, unchanged.
|
||
|
||
## Question
|
||
|
||
The founder asked (review §6.1) whether four decision classes — **C0 note**,
|
||
**C1 confirm**, **C2 bound approval**, **C3 instrument** — and the rule
|
||
*"anything a service will execute on the strength of the decision is C2"* are
|
||
the right cut. `GH-DEC-2026-016` §5 left open which acts require human approval
|
||
at all and said that is Gate House's doctrine. This record answers that open
|
||
point as a floor rule, and sets how much ceremony each class carries.
|
||
|
||
## Position in one paragraph
|
||
|
||
**The cut is right, with one change to the rule.** The trigger is not *who
|
||
executes* but *what is relied on*: a decision is at least C2 when anything —
|
||
service, executor, PEP, agent or pipeline — relies on it as the authority for
|
||
an act that the relying actor's standing mandate does not already grant. That
|
||
is the review's rule made precise. It catches agents as well as services, and
|
||
it does not pull direction-setting decisions (a workplan, a choice of option)
|
||
into C2 merely because work follows them. Three guards make the cheap classes
|
||
safe: C1 evidence is never authority, the class floor comes from the act and
|
||
not from the requester, and every modifier — `risk_class`, posture — may only
|
||
raise.
|
||
|
||
## Ruling 1 — Four classes, distinguished by what may rely on the result
|
||
|
||
| | **C0 note** | **C1 confirm** | **C2 bound approval** | **C3 instrument** |
|
||
| --- | --- | --- | --- | --- |
|
||
| What it is | A record. No human disposition is claimed | A human disposition on a question. Sets direction; authorizes no act by itself | A human disposition bound to one exact act, which an actor will rely on | A multi-party or contractual commitment |
|
||
| May be relied on as authority for an act | No | **No** | Yes — for the bound act only, once, within its validity | Reserved |
|
||
| Surface | State Hub only | informed-decision single-screen confirm: question, the packet item(s) it rests on, at least one required highlight, the options | informed-decision full memo presenting an approval the actor created (review §4.2) | Not yet defined (informed-decision L4 direction) |
|
||
| Assurance | None | Authenticated human session, fresh at answer (the surface states its freshness bound) | `aal2`, fresh at answer | Per party; not yet defined |
|
||
| approval-engine object | No | No | Yes: created by the actor who will rely on it, `human_control: true` declared at issue (`GH-DEC-2026-016` §3) | Per party; not yet defined |
|
||
| Evidence | The hub record | informed-decision presentation (`view_hash`) and disposition, the authenticated subject, audit-core emission; resolves the hub decision by write-back | All of C1, plus the approval entry bound to the binding digest; the approval id joins the hub decision | Not yet defined |
|
||
| Who may decide | Anyone, including agents; nothing is decided | A human principal holding the decision scope (the founder for estate scope). Directory-asserted humanity only (`GH-DEC-2026-016` §5) | The human approvers listed for the action class, each a human principal, none of them the actor | Not yet defined |
|
||
|
||
Notes on the table:
|
||
|
||
- **C0 is not a lesser decision; it is not a decision.** A record that claims a
|
||
human answered something is at least C1. A hub item flagged `needs_human` is
|
||
never resolvable at C0.
|
||
- **"Who may decide" never includes an agent at C1 or above.** An owner agent's
|
||
review, assent or "delegated technical owner review" is input to a decision
|
||
and is labelled as such. It is not approval at any class. (Cognition proposes.)
|
||
- **C3 is reserved, not usable.** Until a C3 record rules it, a multi-party or
|
||
contractual commitment is not taken through this facility at all. It is not
|
||
quietly posed as C2 with extra approvers, because per-party assurance and
|
||
counter-signature are what C3 would add.
|
||
|
||
## Ruling 2 — The floor: relied-on means bound
|
||
|
||
**A decision MUST be at least C2 if any actor will rely on it as the authority
|
||
for an act that the actor's standing mandate does not already grant.** "Rely"
|
||
means the decision, or a record of it, is checked — by code or by an agent's
|
||
reading — as the reason an act is permitted. Typical acts: a privileged or
|
||
bounded execution run, a credential issue or rotation, a production deploy or
|
||
`kubectl apply`, an access-engine policy or pin change, any widening of an
|
||
authority ceiling.
|
||
|
||
Corollaries, each normative:
|
||
|
||
1. **C1 evidence is never authority.** No PEP, executor, lane or agent may
|
||
accept a C1 disposition, a hub resolution, or text in a workplan, CCR or
|
||
commit message as the approval of an act. If an act later needs a decision
|
||
that was taken at C1, the act is posed again at C2. C1 evidence is never
|
||
promoted.
|
||
2. **Direction does not carry authority downstream.** Approving a workplan or
|
||
choosing option A is C1. Each act inside that work that needs authority
|
||
carries its own C2 approval, or is run by the human principal personally (the
|
||
founder-run lane). The C1 decision is context for those acts, not their
|
||
permission.
|
||
3. **The founder running an act personally is not a delegation.** Where the
|
||
human principal is the one who executes, with their own authentication on
|
||
the lane, no approval object is needed, because nothing relies on someone
|
||
else's decision. The decision to do it may be C0 or C1. This is the existing
|
||
"live changes: founder runs" pattern, and it stays.
|
||
4. **Within the actor's standing mandate, no class is required.** An agent
|
||
editing its own repository within its mandate needs no approval. A decision
|
||
about *what* it should do (a workplan) is C1 at most.
|
||
5. **The test is applied to the act, not to the requester's choice.** Each
|
||
action class has a minimum class, set by doctrine (the examples in Ruling 4
|
||
are the first table). A requester may pose higher than the floor and never
|
||
lower. A presenting surface that is asked to present an act below its floor
|
||
refuses. An act whose class cannot be determined is treated as C2
|
||
(fail closed).
|
||
|
||
## Ruling 3 — Modifiers may only raise
|
||
|
||
`risk_class`, posture from King's Guard and any other adaptive input are
|
||
**restriction-only**, the same asymmetry as Blueprint §8 ("posture may only
|
||
restrict"):
|
||
|
||
- **Within C2** they may add required highlights, add required approvers (dual
|
||
control), shorten validity, require a fresh step-up, or narrow the bound
|
||
scope. They may not lower the class, drop `human_control`, relax `aal2`,
|
||
remove a listed approver or lengthen validity beyond the action class's
|
||
ceiling.
|
||
- **Within C1** they may add highlights, or raise the decision to C2.
|
||
- **Nothing lowers a class.** No `risk_class: low` turns an executed act into a
|
||
C1 confirm. A low-risk executed act gets a *lighter C2 memo* (fewer
|
||
highlights), not a different class. That is where "easy for simple cases"
|
||
lives inside C2.
|
||
|
||
## Ruling 4 — The estate's current cases
|
||
|
||
| Case | Class | Why | Today |
|
||
| --- | --- | --- | --- |
|
||
| Bounded Execution Admission (NK-WP-0056) | **C2** | The executor relies on it to run; the approval is created by `service:nk-bind-executor`, presented via informed-decision (review §4.2), approved at `aal2` | No path yet (NK-WP-0056-T17); review slices S1, S2 |
|
||
| Admission with high `risk_class` | **C2**, raised | Added highlights (scope ceiling, revert) and, where the action class says so, a second human approver | — |
|
||
| CCR credential lane (platform-owner and net-kingdom-owner approvals) | **C2** | The lane issues or rotates a credential on the strength of it; each required owner approval is a human entry on one approval object | Recorded as agent-written YAML comments; the second approval for CCR-2026-0058 was entered by hand. Not C2 evidence |
|
||
| Production deploy / `kubectl apply` by an agent or pipeline | **C2** | Executed on the decision | ops-mason's founder plan approval (`GH-DEC-2026-022`) sits at this floor. Its accepted §6.4 exception is not changed here, but the approval carrying it is C2 by this record |
|
||
| access-engine policy or pin change, any authority-ceiling change | **C2** | Executed by a pipeline; agents cannot edit their own ceiling | — |
|
||
| Founder runs a live step personally | none required (C0 or C1 for the decision) | Corollary 3 | The existing founder-run lanes |
|
||
| Workplan approval (`proposed` → `ready`/`active`) | **C1** | Direction; acts inside it carry their own C2 or are founder-run | "Approved by the founder in session" written by an agent: asserted, not evidenced |
|
||
| Adopting an owner proposal or doctrine record (including a GH-DEC ruling) | **C1** | Sets doctrine or direction; nothing executes on it | GH-DEC records cite founder in session; `GH-DEC-2026-025` already went through a full memo, which is allowed (higher than the floor) |
|
||
| Choosing between options A/B | **C1** | Direction; if the chosen option is then executed, that execution carries its own C2 | — |
|
||
| Acknowledging a report, recording a finding, coordination notes | **C0** | Nothing is decided | Hub records |
|
||
|
||
## Ruling 5 — The hub indexes; evidence resolves
|
||
|
||
Endorsed from review §4.4, as doctrine:
|
||
|
||
- A State Hub decision that needs C1 or C2 **MUST be resolved by the evidence**
|
||
(informed-decision write-back carrying the authenticated subject, memo
|
||
revision and `view_hash`, and for C2 the approval id), **never by an agent's
|
||
free text**. `decided_by` written by an agent is asserted provenance and stays
|
||
visibly asserted (ASM-M04, `GH-DEC-2026-023` C6).
|
||
- The hub record is the index of what is waiting. It is not evidence and holds
|
||
no binding.
|
||
|
||
## Ruling 6 — The present-existing contract is consistent with doctrine
|
||
|
||
The review's §4.2 contract (the actor creates, informed-decision presents and
|
||
adds the human entry, the actor consumes) is the shape doctrine asks for, and
|
||
nothing in Gate House required informed-decision to be the creator:
|
||
|
||
- Posing needs no human act (`GH-DEC-2026-023` Ruling 1). The actor creating
|
||
its own request is proposing.
|
||
- The human requirement attaches to the bind (`GH-DEC-2026-016`), and
|
||
`human_control: true` is declared at create by the actor.
|
||
- The surface's live read of the approval and the identity compare of
|
||
approval id and binding digest are the validation (`GH-DEC-2026-023` C1).
|
||
The surface must not accept the actor's memo as a statement of what the
|
||
approval binds.
|
||
- **The actor MUST NOT be an approver of its own approval.** approval-engine
|
||
already refuses non-human approvers under `human_control`, which covers a
|
||
service actor. This line covers a human actor too.
|
||
|
||
Owners decide the mechanics: informed-decision (profile or route), approval-engine
|
||
(`presentation_ref`, `aal2` floor, `actor_consumes`), State Hub (link columns).
|
||
|
||
## Build-mode relaxations this record names
|
||
|
||
Under the standing build-mode directive (2026-10-03) these are recorded for the
|
||
close-down list, not waived:
|
||
|
||
- **B1.** `aal2` is stored but not enforced by approval-engine
|
||
(APPROVAL-WP-0007-T01). Until it is, the C2 assurance is checked by the
|
||
surface and the executor. Re-arm: the object refuses an entry below the
|
||
class's assurance.
|
||
- **B2.** Consume does not check consumer = actor (APPROVAL-WP-0007-T02). Re-arm
|
||
as written there.
|
||
- **B3.** C1 does not exist as a surface yet (review slice S4) and hub write-back
|
||
is off (S3). Until both land, C1 decisions are taken in session and recorded
|
||
as **asserted** (`decided_by` names the founder, the record says "asserted in
|
||
session"). They are not C1 evidence, and corollary 1 already forbids relying
|
||
on them.
|
||
- **B4.** CCR approvals recorded as YAML comments are below the C2 floor. Until
|
||
the lanes move to approval objects, every CCR approval stays an asserted record
|
||
and the close-down list carries it.
|
||
|
||
Recording these in the-custodian close-down checklist is the-custodian's act;
|
||
this record asks for it and does not edit that file.
|
||
|
||
## What this does not rule
|
||
|
||
- The mechanics of any service (profile vs route, column vs `evidence_ref`,
|
||
validity defaults). Those belong to their owners.
|
||
- The list of action classes beyond Ruling 4's first table, or which classes
|
||
require dual control. Each new action class is assigned its floor by a Gate
|
||
House record or by the owning standard (e.g. the BEA standard), never by the
|
||
requester.
|
||
- C3. Reserved for a later record.
|
||
- Break-glass. It keeps its own path and is not a decision class.
|
||
|
||
## Reversal condition
|
||
|
||
Ruling 2 reverses if a case is found where relying on a C1 disposition for an act
|
||
is necessary and safe. That would show the floor was drawn at the wrong act, and
|
||
the repair is the action-class table, not a lower class. Ruling 1's C1 tier
|
||
lapses if the C1 surface is not built and C1 decisions remain asserted text
|
||
through the production close-down. The estate would then have three classes,
|
||
and C1 should be removed rather than left as a name for free text.
|