APPROVAL-WP-0007-T02 done: actor_consumes; T05 principal_approves split out

Founder decision 2026-11-01, relayed by the net-kingdom coordinator: "Agree to
split APPROVAL-WP-0007-T02: build actor_consumes now (opt-in at issue; the
bounded executor will set it); principal_approves keeps waiting for the KeyCape
subject mapping."

- Optional actor_consumes (boolean) at issue, schema v8. Consume refuses with
  403 unless the consuming subject equals binding.actor, also on idempotent
  retries; internal calls without a consumer fail closed. Inherited on
  supersession (existing-successor mismatch 409), in audit details, served in
  GET/claim only when declared so undeclared claims keep exact bytes. Legacy
  rows migrate without the flag.
- GH-DEC-2026-026 Ruling 6: under human_control, add_entry refuses (403) the
  binding actor as approver. human_control already covered a service actor;
  this covers a human actor.
- Workplan: T02 done (actor_consumes); new T05 principal_approves (wait).
- Not released or deployed: needs a v8 image and founder-run rollout.

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
This commit is contained in:
tegwick 2026-11-01 00:39:34 +01:00
parent e9e9f93317
commit 5c45d3c157
11 changed files with 344 additions and 36 deletions

View file

@ -9,7 +9,7 @@ flavor: implementation
owner: approval-engine
topic_slug: netkingdom
created: "2026-10-31"
updated: "2026-10-31"
updated: "2026-11-01"
depends_on: []
state_hub_workstream_id: "af365506-f451-50b5-a0a2-f0ba9a0a4d9c"
---
@ -46,30 +46,54 @@ contract in `docs/approval-claim.md`). The member is present only when
declared, so undeclared claims keep their exact bytes for strict readers.
Not released or deployed: a v7 image and a founder-run rollout are still needed.
## Opt-in approver and consumer correspondence
## Opt-in consumer = actor (`actor_consumes`)
```task
id: APPROVAL-WP-0007-T02
status: wait
status: done
priority: medium
state_hub_task_id: "9657820d-23f9-54d9-920c-8f2a72110ad0"
```
Proposal for owner and Gate House agreement before implementation, because
it gives `principal` and `actor` an enforced meaning. Two optional issue
flags:
Optional issue flag `actor_consumes: true` on `POST /v1/approvals`: the
consuming subject must equal `binding.actor`. Closes the denial-of-run gap
(today any tenant service with `approval:consume` can spend the object). Adds
no identity mapping, because the actor is already pinned to the creator's
token subject. Serves GH-DEC-2026-026 build-mode relaxation B2.
- `principal_approves`: every entry subject must equal `binding.principal`.
- `actor_consumes`: the consuming subject must equal `binding.actor`.
Split from the original T02 by founder decision 2026-11-01, relayed by the
net-kingdom coordinator: "Agree to split APPROVAL-WP-0007-T02: build
actor_consumes now (opt-in at issue; the bounded executor will set it);
principal_approves keeps waiting for the KeyCape subject mapping."
`principal_approves` moved to T05.
Owner position 2026-10-31 (`docs/decision-services-alignment-answer.md`):
split it. `actor_consumes` is ready to implement once agreed. `principal_approves`
keeps waiting for the subject mapping and the S5 doctrine.
Done 2026-11-01 in source (schema v8, `tests/test_actor_consumes.py`,
contract in `docs/approval-claim.md`). Stored on the object, served in GET and
the claim only when declared (undeclared claims keep their exact bytes),
carried in audit `details`, inherited on supersession (existing-successor
mismatch is 409). Consume refuses with 403 when the consuming subject differs,
also on idempotent retries; an internal call without a consumer fails closed.
Legacy rows migrate without the flag. Same commit: under `human_control`,
`add_entry` refuses (403) the binding actor as approver (GH-DEC-2026-026
Ruling 6); human_control alone already covered a service actor, this covers a
human actor. Not released or deployed: a v8 image and a founder-run rollout
are still needed.
Today any human with `approval:approve` can approve, and any tenant service
with `approval:consume` can spend the object (a denial-of-run risk). Wait
reason: semantic decision. NetKingdom's actor and principal strings must also
match KeyCape subjects exactly.
## Opt-in approver = principal (`principal_approves`)
```task
id: APPROVAL-WP-0007-T05
status: wait
priority: medium
```
Optional issue flag `principal_approves: true`: every entry subject must equal
`binding.principal`. It gives `principal` an enforced meaning, so it waits.
Wait reasons: the KeyCape subject mapping (NetKingdom's principal strings must
equal KeyCape subjects exactly) and the S5 doctrine. Split from T02 by the
founder decision of 2026-11-01 quoted under T02. Until it lands, any human
holding `approval:approve` for the tenant can approve, and the executor checks
the entry subject itself (`docs/bounded-execution-admission-carrier.md` §3).
## Revoker identity in revocation evidence