Record the claim vs ActionAuthorization envelope divergence

secrets-engine reports its PIP join is implemented and blocked on
deployment rather than contract. Reviewing its
validate_action_authorization against what this engine actually serves
shows that is not the whole story: it expects a state-hub-authority
ActionAuthorization (id, status, superseded_by, request,
approvals.entries, policy pin) while GET /v1/approvals/{id}/claim serves
the governed approval-claim (approval_id, state/valid_now, binding,
freshness, reason_code, issuer approval-engine).

Both envelopes declare schema_version 0.1, so the version check passes
and the mismatch surfaces as a field or authority error that reads like
an approval-engine outage.

Document the field-by-field divergence and why the omissions are
deliberate: a claim is a fact about an approval object, not a decision,
so approver identities and policy pins are not republished. Reconciling
the envelopes is a GH-DEC-2026-003 cross-repo change, so the governed
claim schema is left unchanged here.

No code change; 84 tests still pass.

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

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 411227@bnt-lap001
Assistant-Session: d566f6d3-bcaf-43c3-bc5e-3ddd0f64b535
This commit is contained in:
tegwick 2026-09-06 01:09:23 +02:00
parent 2370f69927
commit 115f309e0a
2 changed files with 46 additions and 1 deletions

View file

@ -41,3 +41,36 @@ after consumption, the approval remains spent and a retry needs a new approval.
The response is mutation evidence, not a permission decision. It contains no
`effect`, `allow`, `deny`, or decision result.
## The claim response is not an `ActionAuthorization`
`GET /v1/approvals/{id}/claim` serves the **approval-claim** envelope defined in
[`approval-claim.md`](approval-claim.md). It is not the `ActionAuthorization`
object that secrets-engine's `validate_action_authorization` currently expects,
and a PEP that points that validator at this URL fails closed for the wrong
reason.
Both envelopes carry `schema_version: "0.1"`, so the version check passes and
the mismatch surfaces later as a missing-field or wrong-authority error. Do not
read that failure as an approval-engine outage.
| Validator expectation | What the claim actually serves |
| --- | --- |
| `id` (canonical UUID) | `approval_id` — the object id, same value, different key |
| `status == "approved"` | `state` (`approved`, `consumed`, `revoked`, `superseded`, `expired`, `requested`) plus the `valid_now` predicate |
| `superseded_by` | absent; supersession appears as `state: "superseded"` |
| `provenance.authority == "state-hub"` | `issuer: "approval-engine"` — this engine is the authority for the approval object; the State Hub is a read model and never issues one |
| `request` (full CheckRequest) | `binding` (`action`, `actor`, `principal`, `purpose`, `target`) plus `binding.digest`, and `binding.pdp_digest` when recorded at issue |
| `approvals.required_count` / `entries` | not exposed; the distinct-approver threshold is already folded into `valid_now`, with `reason_code: "insufficient_approvers"` when unmet |
| policy package/version pin | not carried; the policy pin belongs to the access-engine decision, not to the approval fact |
The omissions are deliberate. A claim is a *fact about an approval object*, not
a decision and not a permission; approver identities and policy pins are not
republished to consumers. The consumer checks in
[`approval-claim.md`](approval-claim.md) ("Required verification") are the
supported validation path.
Reconciling the two envelopes is a cross-repo contract change under
`GH-DEC-2026-003`, not a unilateral edit here. Until it is decided, this engine
keeps serving the approval-claim shape and does not emit a `state-hub`
authority it does not have.

View file

@ -8,7 +8,7 @@ status: active
owner: codex
topic_slug: netkingdom
created: "2026-09-01"
updated: "2026-09-02"
updated: "2026-09-06"
reviewed_at: "2026-09-01"
reviewed_against_commit: "ebce5abb276c01ab29ce2526f3b8abb332dc9e90"
reviewed_note: >-
@ -185,3 +185,15 @@ claim refusal, and unreachable-engine callback suppression. Waiting on live
closure: this service deployed (T03) and a durable consume binding served
(`SECRETS-WP-0007-T04` / `SECRETS-WP-0008-T02`). This repo does not claim the
OpenBao side effect.
2026-09-06 follow-up: secrets-engine reports its PIP join is implemented and
blocked on deployment, not contract (inbox `61ae1174`). Review of its
`validate_action_authorization` shows a real envelope divergence: it expects a
`state-hub`-authority `ActionAuthorization` (`id`, `status`, `superseded_by`,
`request`, `approvals.entries`, policy pin) while this engine serves the
governed approval-claim (`approval_id`, `state`/`valid_now`, `binding`,
`freshness`, `reason_code`, `issuer: approval-engine`). Both declare
`schema_version` `0.1`, so the mismatch surfaces as a field/authority error
rather than a version error. Recorded in `docs/approval-consumption.md`;
reconciling the envelopes is a `GH-DEC-2026-003` cross-repo change, not a
unilateral edit here. T05 stays `wait`: still no deployed base URL (T03).