Close the binding-correspondence gap as GH-DEC-2026-008

access-engine raised, and declined to solve locally, a hole in the split
GH-DEC-2026-005 ruled on. approval-claim verification item 4 is a
disjunction and neither limb delivers "approved for THIS request" on the
PDP path: limb one requires translating between two engines' vocabularies
and no mapping is published, limb two (pdp_digest) is optional. Where the
digest is absent a consumer can hold valid_now true, receive an ALLOW,
consume and act with nothing establishing that approval and decision
concern the same action and target.

Ruled: the PDP digest is the correspondence and is required on that path;
a claim without one fails closed; the native limb survives only for
consumers already in approval-engine's vocabulary, including T-06. No
mapping is published — a translation can be wrong while still producing a
confident answer, it fails open, it would be owned by neither engine, and
recomputing another layer's binding is the re-derivation GH-DEC-2026-005
already forbids. The cost is stated: an approval issued without a bound
CheckRequest is unusable on this path, which is correct behaviour.

Also: adopted hub row b606e8ce as canonical for GH-DEC-2026-005 rather
than registering a duplicate; recorded approval-engine's narrowing of the
approver-threshold consequence (distinctness is a UNIQUE storage
invariant, so the PEP stopped checking that the engine applied its own
invariant, not whether dual control could be forged); and drafted A7/T08,
a §11 marking obligation and §12 consumer rule for derived summaries,
after four instances in one week across four repositories.

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

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 425128@bnt-lap001
Assistant-Session: f5944d8b-dac4-4e1a-87eb-8b3d8f314a63
This commit is contained in:
tegwick 2026-09-06 09:32:20 +02:00
parent 865bab3955
commit f0f888ca7e
4 changed files with 196 additions and 4 deletions

View file

@ -27,8 +27,9 @@ Assembly and circulation are `GH-WP-0003-T06`.
| A2 | §11 | `docs/contracts/approval-emission-detection.md` | T02 |
| A3 | §13, §13.1 | `GH-DEC-2026-006` | T03 |
| A4 | §9.5 | `GH-DEC-2026-007` | T04 |
| A5 | §6.4, §8 | `GH-DEC-2026-005` | T05 |
| A5 | §6.4, §8 | `GH-DEC-2026-005`, `GH-DEC-2026-008` | T05 |
| A6 | §17 | `GH-DEC-2026-004` | T07 |
| A7 | §11, §12 | four observed instances; proposed by `approval-engine` | T08 |
---
@ -230,8 +231,16 @@ join two artifacts will re-derive it or get it wrong.
> second check at the consumer. That is detection, not prevention, and it belongs
> in the same register as §9.6's other residual.
>
> Raised by `approval-engine`, and by `access-engine` against its own proposed
> artifact. Settled in `GH-DEC-2026-005`.
> **Correspondence is established by identity, not by translation.** Where two
> artifacts use different vocabularies for the same request, the consumer compares
> a digest one layer computed and the other recorded — it MUST NOT recompute one
> layer's binding from the other's vocabulary, and no cross-engine mapping is
> published for it to use. A mapping can be wrong in a way that still produces a
> confident answer, and it would be a third authority on what a request is.
>
> Raised by `approval-engine`, and by `access-engine` twice against its own
> interest — once on its proposed artifact and once on a gap it declined to close
> locally. Settled in `GH-DEC-2026-005` and `GH-DEC-2026-008`.
**Add to §8's demarcations:**
@ -274,6 +283,61 @@ statute is told the estate has not decided something it has.
---
## A7 — §11 and §12, derived summaries must be marked (T08)
**Why.** Four instances in one week, in four repositories, each caught only by another
repository reading the authoritative body:
- gate-house sourced a revisit trigger in `GH-DEC-2026-005` from a 2026-08-29
alignment record rather than from `flex-auth`'s current schema;
- gate-house read a change log for what §3.4 contained, which is the defect
`kings-guard` raised against v0.6 and the reason
`docs/conformance/2026-09-06-v06-findings-audit.md` checked the body instead;
- `access-engine` published a dual-control rule written against its own assumption of
the approval claim rather than `approval-engine`'s published schema — it required a
status field and an approver list that do not exist, and every live destroy would
have denied regardless of the approval (failed closed, fixed in `68ad039`);
- `secrets-engine` read a fixture for its contract's prose, and separately carried two
workplans asserting that remaining authorization work was external, which kept an
unimplemented local stub invisible.
Different artifact classes — change log, alignment record, fixture, workplan summary —
one shape. As `approval-engine` put it, at four instances this is not coincidence but
**a property of how this estate publishes**: authoritative bodies with derived
summaries and examples alongside them, and no staleness marker on the derivatives. A
reader cannot tell from the artifact whether it is current, so the diligent and the
careless read it the same way.
Three of the four were reported by the repository that had made the error, against its
own interest. That is the loop working, and it is also the argument for a check: a
control that depends on four repositories volunteering corrections is not a control.
**Add to §11's "Mechanically checkable" list:**
> - every derived artifact in an estate repository — change log, review record,
> alignment note, example, fixture, or summary that restates a normative body — is
> marked as derived, names the authoritative artifact it derives from, and carries
> the version or commit it was derived at.
**Add to §12, as a paragraph of the loop:**
> **A derived summary is not evidence of what the body says.** A repository acting on
> another repository's contract, schema, or standard MUST read the authoritative
> artifact, not a summary, example, or review record of it. This is not a counsel of
> care: the estate has produced four instances in a single week, in four repositories,
> each caught only because a second repository read the body. Diligence did not
> prevent any of them, and in three the erring repository reported itself.
>
> The obligation on the publishing side is §11's marking rule; this is its consumer
> half. Where a derivative is unmarked, treat it as stale.
**Note on scope.** This is the cheap half. It does not detect a derivative that is
marked and *still* wrong, and it should not claim to — the marking makes staleness
visible, it does not measure it. Naming that limit here so the check is not later read
as stronger than it is, which would be the same defect one layer up.
---
## Not in this set
Recorded so the omissions are deliberate rather than forgotten.

View file

@ -4,7 +4,8 @@
**PIP:** approval-engine
**PDP:** access-engine (currently flex-auth)
**Status:** normative for GH-WP-0002-T06; recorded as `GH-DEC-2026-003`,
amended by `GH-DEC-2026-005` (step-1 artifact and split validation)
amended by `GH-DEC-2026-005` (step-1 artifact and split validation) and
`GH-DEC-2026-008` (the PDP digest is the binding correspondence)
**Date:** 2026-09-06
**Statute:** `net-kingdom/canon/standards/security-layer-model_v0.7.md` §9.4, §9.7.34, §16
**Blocks:** `APPROVAL-WP-0001-T05`, `FLEX-WP-0017-T05`
@ -60,6 +61,20 @@ claim.
holds no runtime approval authority; the issuer to check is the engine that
served the claim.
**The correspondence is the PDP digest.** Amended by `GH-DEC-2026-008`. A consumer
on this path MUST verify that `claim.binding.pdp_digest` equals the decision's
`NewDecisionBinding.request_digest`, and MUST NOT use a claim that carries no
`pdp_digest`. Recomputing `approval-engine`'s native `binding.digest` from a
`CheckRequest` is **not** a permitted fallback here: it requires translating between
two engines' vocabularies, no mapping is published, and a wrong translation fails
open by silently accepting a claim approved for something else. The native limb
survives only for consumers already in `approval-engine`'s vocabulary, including the
`T-06` assurance case.
Without this, `valid_now: true` plus an ALLOW establishes *approved* and *permitted*
but never *approved for this request*, which is the property the binding exists to
carry.
## Why consume is before the side effect
§9.7.3 says consumption MUST NOT be inferred from a decision record. That