APPROVAL-WP-0007: record the verified revoker and park the inactive plans

Schema v9 stores who revoked an approval and an optional bounded reason.
The bounded-execution carrier example is proven in process. APPROVAL-WP-0005,
0006, and 0007 are blocked because they are not current work. Task statuses
stay as they were, apart from T03 and T04, which are done in source.

Assistant: grok
Assistant-Session: 01a1b5fd-0c33-7ba1-b383-53937d525595
This commit is contained in:
tegwick 2026-11-07 14:10:01 +01:00
parent f41a9ca82c
commit 4aa0b75449
17 changed files with 599 additions and 36 deletions

View file

@ -448,6 +448,22 @@ call with no authenticated consumer fails closed. The check does not change
Migration leaves existing rows without the flag. The declaration is separate
from the five-field act digest.
### Revoker evidence — `revoked_by`
APPROVAL-WP-0007-T03, schema v9 store. `POST /v1/approvals/{id}/revoke` still
moves `requested` or `approved` to terminal `revoked` by the same
compare-and-swap. The body accepts only an optional `reason`: one line, at
most 200 characters. The verified token supplies `subject`, `principal_type`
and `assurance`. A body cannot name the revoker. The revoker is not required
to equal `binding.principal`.
When a verified revoker is present, `GET` serves `revoked_by` and the
`approval.revocation` outbox event carries the same object in
`details.revoked_by`. The event `actor` stays the bound actor. The claim does
not gain `revoked_by`: it stays a validity fact, and undeclared claim bytes
stay exact. An internal revoke with no verified revoker still revokes and
omits the member, which is also how legacy rows read after migration.
### Actor is never an approver under `human_control`
GH-DEC-2026-026 Ruling 6. Under `human_control: true`, `POST /entries` refuses

View file

@ -18,7 +18,7 @@ Inputs: NetKingdom `canon/standards/bounded-execution-admission_v0.1.md`
| 1. Binding | **Supported today**, with one consequence: the executor (the `actor`) must create the request itself |
| 2. aal2 | **Recorded today, not enforced.** Enforcement at issue/entry/consume needs a change (APPROVAL-WP-0007-T01) |
| 3. Consume | **Supported today.** Scope `approval:consume`, service principal; proposed `request_digest` = the admission digest. The independent GET comparison is the intended reading |
| 4. Revoke | **Supported today** for unconsumed approvals. The revoker's identity is not yet recorded in evidence (APPROVAL-WP-0007-T03) |
| 4. Revoke | **Supported.** Unconsumed approvals revoke by CAS. Schema v9 records the verified revoker (APPROVAL-WP-0007-T03, in source, not deployed) |
## 1. Binding
@ -207,11 +207,13 @@ Limits:
after the executor's first-step consume, stopping it mid-run is the
executor's own kill switch (T07, NetKingdom runtime). This engine has no
"stop after start".
- **The engine does not record who revoked.** The event carries the bound
`actor` and the binding digest, not the revoker's subject or assurance, and
the engine does not check that the revoker is the approver or principal.
APPROVAL-WP-0007-T03 records the verified revoker identity, assurance and an
optional reason in the revocation event.
- **The verified revoker is recorded** (APPROVAL-WP-0007-T03, schema v9, in
source, not yet deployed). `GET` serves `revoked_by` with the token's
subject, principal type and assurance, plus an optional one-line `reason`
of at most 200 characters. The same object is on the `approval.revocation`
event. The event `actor` stays the bound actor. The revoker is not required
to be the principal or the approver. The claim does not carry `revoked_by`.
Legacy rows and an internal revoke with no verified identity omit it.
- Supersession (`approval:supersede`) also stops an unconsumed approval and
links a successor. For the pilot, revoke is the right kill switch.

View file

@ -94,3 +94,16 @@ Publish/scan and pin the same v6 artifact for both containers, take and verify
the pre-migration backup, and obtain per-change rollout approval. An old v5
server refuses a v6 store; rollback uses the verified pre-migration backup with
the matching release and the stopped single-writer restore procedure above.
## Schema v7–v9 — assurance floor, actor consumption, revoker evidence
v7 adds nullable `approvals.required_assurance`. v8 adds `approvals.actor_consumes`
(0 or 1, default 0). v9 adds nullable `revoked_by_subject`,
`revoked_by_principal_type`, `revoked_by_assurance`, and `revocation_reason`.
Migration is additive. Legacy rows stay NULL, and `actor_consumes` stays 0.
Nothing is inferred for old approvals, entries, or revocations.
A v6 server refuses a v9 store. Rollback uses the verified pre-v9 backup with
the matching v6 release and the stopped single-writer restore procedure above.
Take and verify that backup, and open an isolated copy with the new image,
before the sole pod is replaced.