The live StatefulSet now runs sha256:268cccf332b3f9f6b28085f26c8649f45d2a3bfd5779b6d7ff6c5ca3edfed7a2. A verified pre-v9 backup was migrated in isolation with unchanged counts before the sole pod was replaced. Readiness, integrity and a single writer were checked after the restart. Assistant: grok Assistant-Session: 01a1b5fd-0c33-7ba1-b383-53937d525595
179 lines
7.7 KiB
Markdown
179 lines
7.7 KiB
Markdown
---
|
|
id: APPROVAL-WP-0007
|
|
type: workplan
|
|
title: "Bounded-execution admission carrier: assurance floor, correspondence and revoker evidence"
|
|
domain: infotech
|
|
repo: approval-engine
|
|
status: blocked
|
|
flavor: implementation
|
|
owner: approval-engine
|
|
topic_slug: netkingdom
|
|
created: "2026-10-31"
|
|
updated: "2026-11-07"
|
|
depends_on: []
|
|
state_hub_workstream_id: "af365506-f451-50b5-a0a2-f0ba9a0a4d9c"
|
|
---
|
|
|
|
Demand: NetKingdom NK-WP-0056-T02 owner request (hub message
|
|
40344380-ea33-4670-9b27-dafca1699d36) to carry a Bounded Execution Admission
|
|
v0.1 (proposed) as an approval. Owner answer:
|
|
`docs/bounded-execution-admission-carrier.md`. The binding, consume and
|
|
revoke already work. This plan closes the engine-side gaps the answer found.
|
|
Every change is opt-in at issue, so existing approvals and consumers keep
|
|
their behavior. Native digest, CAS consumption and no-unconsume are unchanged.
|
|
|
|
2026-11-07: status is `blocked`. This plan is not current work. T01 through
|
|
T04 stay as recorded. T05 stays `wait` on KeyCape subject equality. T06 stays
|
|
`todo` for the later self-acceptance exception.
|
|
|
|
## Declared minimum approver assurance
|
|
|
|
```task
|
|
id: APPROVAL-WP-0007-T01
|
|
status: done
|
|
priority: high
|
|
state_hub_task_id: "9ce0aca8-7694-53c6-a76a-f78d395a9861"
|
|
```
|
|
|
|
Add an optional `required_assurance` (minimum `level`, ordered aal1 < aal2 <
|
|
aal3) to `POST /v1/approvals`. Store it and serve it in the object and the
|
|
claim, and inherit it on supersede. `add_entry` refuses an entry whose
|
|
verified token `assurance.level` is weaker or missing. `_evaluate` and
|
|
`consume` refuse when an existing entry does not meet it. Schema migration
|
|
leaves old rows NULL, meaning no floor. Tests cover aal1 refused, aal2
|
|
accepted, missing level refused, supersede inheritance and the claim
|
|
reason_code. Serves BEA-C4. Whether KeyCape emits `aal2` is KeyCape's
|
|
question, outside this plan.
|
|
|
|
Done 2026-10-31 in source (schema v7, `tests/test_required_assurance.py`,
|
|
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 consumer = actor (`actor_consumes`)
|
|
|
|
```task
|
|
id: APPROVAL-WP-0007-T02
|
|
status: done
|
|
priority: medium
|
|
state_hub_task_id: "9657820d-23f9-54d9-920c-8f2a72110ad0"
|
|
```
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
## Opt-in approver = principal (`principal_approves`)
|
|
|
|
```task
|
|
id: APPROVAL-WP-0007-T05
|
|
status: wait
|
|
priority: medium
|
|
state_hub_task_id: "b0b9398d-f9f9-507f-b8f7-91ed10c1a9b8"
|
|
```
|
|
|
|
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
|
|
|
|
```task
|
|
id: APPROVAL-WP-0007-T03
|
|
status: done
|
|
priority: medium
|
|
state_hub_task_id: "7ceb5ffd-3ba8-5e9d-96a2-5e89c38a5c43"
|
|
```
|
|
|
|
Record the verified revoker's subject, principal_type and assurance, plus an
|
|
optional bounded `reason`, in the `approval.revocation` outbox event. Persist
|
|
them on the object (the `revoked_by` fields) without changing the CAS or
|
|
terminal semantics. This is the evidence for the founder's pre-start kill
|
|
switch (NK-WP-0056-T07). Do not require the revoker to equal the principal:
|
|
revocation must stay possible without the holder.
|
|
|
|
Done 2026-11-07 in source (schema v9, `tests/test_revoker.py`, contract in
|
|
`docs/approval-claim.md`). `POST /revoke` accepts only an optional one-line
|
|
reason of at most 200 characters. The token supplies the revoker. GET and
|
|
`details.revoked_by` serve it. The claim omits it. An internal revoke with no
|
|
verified identity still revokes and omits the member, as do migrated rows.
|
|
Released and deployed 2026-11-07 as
|
|
`sha256:268cccf332b3f9f6b28085f26c8649f45d2a3bfd5779b6d7ff6c5ca3edfed7a2`.
|
|
Receipt: `docs/evidence/2026-11-07-schema-v9-rollout.json`.
|
|
|
|
## Synthetic bounded-execution carrier proof
|
|
|
|
```task
|
|
id: APPROVAL-WP-0007-T04
|
|
status: done
|
|
priority: medium
|
|
state_hub_task_id: "673890fe-3d49-5fe3-8ad7-c8c73e4d9376"
|
|
```
|
|
|
|
Add an in-process test and an example request covering the full path: the
|
|
executor (service) creates the request (`action: bounded-execution`,
|
|
`target: {admission_id, admission_digest}`, `human_control: true`,
|
|
`pdp_path: false`); a human aal2 entry approves it; GET binding comparison;
|
|
consume with `request_digest` = admission digest; idempotent retry; a
|
|
different digest returns 409; revoke before consume gives 409 on consume;
|
|
consumption outside the window is refused. Synthetic fixtures only, with no
|
|
live service.
|
|
|
|
Done 2026-11-07. Example `examples/bounded-execution-approval-request.json`.
|
|
Test `tests/test_bounded_execution_carrier.py` runs that request in process:
|
|
aal1 entry refused by the declared floor, human aal2 approves, GET matches
|
|
the binding, the actor consumes the admission digest, the same digest retries,
|
|
a different digest is 409, a founder who is not the principal revokes before
|
|
consume and consume is 409, and consume before the window and at expiry is
|
|
409. No live service.
|
|
|
|
## Founder decision 2026-10-31
|
|
|
|
Approved by the founder (`proposed` -> `ready`) after the NK-WP-0056-T02 owner answers (hub decision 19afd15e).
|
|
|
|
## Self-acceptance as an exception with handlers (backlog)
|
|
|
|
```task
|
|
id: APPROVAL-WP-0007-T06
|
|
status: todo
|
|
priority: low
|
|
state_hub_task_id: "db25c052-3c60-5328-9993-b51f87fc5ba6"
|
|
```
|
|
|
|
Founder direction, 2026-11-01 (gate-house GH-DEC-2026-026 addendum, relayed by the net-kingdom coordinator).
|
|
Today, under `human_control`, an entry whose subject equals `binding.actor` is refused (403, `5c45d3c`), and that
|
|
stays the default.
|
|
|
|
Later, self-acceptance may become a declared exception on the approval:
|
|
|
|
- explicitly accepted by the self-accepter;
|
|
- with exception handlers bound to it, such as eligibility exclusions (trainees) or a publication plus cooldown
|
|
window in which named others can veto before the approval becomes valid.
|
|
|
|
The engine would hold the exception and its window and refuse validity until the window closes without a veto.
|
|
Doctrine on which classes admit it comes from gate-house (GH-WP-0005-T07). Not to be implemented now.
|
|
|