Contracts first (T02–T04): approval claim schema with issuer, freshness,
and binding digest; local transactional outbox wire; load-bearing cadence
as heartbeat or reconciliation (layer.yaml declared).
Then the object (T06–T08): SQLite closed state machine, CAS supersession,
distinct-approver fail-closed, revocation without holder cooperation,
outbox insert in the same transaction. Tests fail the mutation when
emission fails, and revoke while the drain sink is down.
Introspection GET /v1/approvals/{id}/claim is a PIP fact, not a decision.
No public consume (T05 waits on GH-WP-0002-T06). Canon T-06 coverage for
wrong binding, expiry, revoke, and supersede.
FLEX-WP-0017 T03 is unblocked on this object; T05 remains blocked only on
consumption ordering.
Assistant: grok
Assistant-Session: 01a04ceb-2057-7e20-b0f9-c282964d5dd9
9 KiB
| id | type | title | domain | repo | status | owner | topic_slug | created | updated | state_hub_workstream_id |
|---|---|---|---|---|---|---|---|---|---|---|
| APPROVAL-WP-0001 | workplan | v0.7 alignment and the engine spine | infotech | approval-engine | active | grok | netkingdom | 2026-08-29 | 2026-08-29 | 546f2fae-c53e-5ea5-8c63-320118d8ee1e |
APPROVAL-WP-0001 — v0.7 alignment and the engine spine
Evolve this repository from a v0.5 seed INTENT into a v0.7-aligned PIP with
the contracts and first implementation that make Canon T-06 passable and
unblock FLEX-WP-0017 T03/T05.
Source:
net-kingdom/canon/standards/security-layer-model_v0.7.md(accepted)net-kingdom/SECURITY-COMPANION.mdv0.2history/2026-08-29-security-layer-model-v0.7-scope-intent-review.mdINTENT.md,SCOPE.md,layer.yaml
Rule of the workplan. Contracts before code. Consumption is not
implemented until GH-WP-0002-T06 settles it. A reachable mutation that
guesses the three races is a defect, not a prototype.
Peer work this does not own and must not duplicate: GH-WP-0002 (T02 outbox
wire, T03 revocation failure mode, T04 detection surface, T06 consumption
ordering), FLEX-WP-0017 T03/T05, AUDIT-IN-0001.
T01 — Align declaration to the accepted statute
id: APPROVAL-WP-0001-T01
status: done
priority: high
state_hub_task_id: "090ab9d5-1467-5a82-b3cd-ac4215bec0f0"
2026-08-29: INTENT frontmatter layer: Engine / role: PIP; aligned to
v0.7 (PIP typing, threat decomposition, load-bearing cadence, custody
closed, consumption as mutation, issuer/freshness, Railiance non-axis).
SCOPE.md written as first-cut boundary with standard sections. layer.yaml
declared in this repository's own voice. Review filed under history/.
Registered with State Hub (infotech, topic custodian). Register's
bootstrap workplan was discarded: it collided on APPROVAL-WP-0001 and
its three tasks are already discharged by this file, AGENTS.md, and
SCOPE.md.
T02 — Publish the approval claim contract
id: APPROVAL-WP-0001-T02
status: done
priority: high
state_hub_task_id: "ca2ec789-b760-525a-9960-95d15760191e"
2026-08-29: schemas/approval_claim.schema.json, docs/approval-claim.md,
examples. Native digest is sorted-key JSON of action/actor/principal/purpose/target;
optional pdp_digest records NewDecisionBinding.request_digest at issue.
Yields to Taxonomy §17.
Specify the input claim access-engine consumes: approval identifier,
canonical-binding digest over the same binding the PDP already computes,
issuer (this engine), and freshness. Schema and examples in-repo.
Until Taxonomy's request-claim schema exists (statute §17, ownership proposed not assigned), this is the boundary contract. Mark it as yielding to Taxonomy; do not treat a local shape as permanent.
Acceptance: a document access-engine can implement a consumer against
without reading this engine's source; wrong-action / wrong-target /
wrong-scope are distinguishable; a PDP can state a deadline for this input
class.
T03 — Specify the local transactional-outbox contract
id: APPROVAL-WP-0001-T03
status: done
priority: high
state_hub_task_id: "a2eb2e8f-9b49-598e-b4a1-fb93e65f1bf3"
2026-08-29: docs/outbox-contract.md. Classes issuance/use/supersession/revocation/heartbeat.
Payload is audit-core.event.v1alpha1. Synchronous audit-core inside the
mutation transaction is named forbidden.
Event classes (issuance, use, supersession, revocation, and the heartbeat
class T04 needs), same transaction as the object mutation, queue local to
this engine, at-least-once into the outbox (audit-core dedupes on event
id). No synchronous audit-core call inside the state-change transaction.
Coordinate with GH-WP-0002-T02; do not author doctrine this engine does
not own. INTENT already states the boundary and the locality.
Acceptance: a wire contract another repository can review; an implementer
cannot satisfy it by emitting synchronously to audit-core.
T04 — Declare load-bearing cadence as heartbeat or reconciliation
id: APPROVAL-WP-0001-T04
status: done
priority: high
state_hub_task_id: "fce0df25-0106-5c0a-8187-87b956ca6220"
2026-08-29: cadence.yaml + docs/emission-cadence.md. layer.yaml
evidence.cadence_status: declared. Missing heartbeat and count divergence
are findings. Rate monitoring forbidden.
Approval evidence is load-bearing and low-volume. Rate monitoring is the
wrong form (statute §9.6). Publish the source-side declaration: expected
classes, the heartbeat (nothing to report, signed, itself able to go
missing) and/or reconciliation of this engine's transitions against
audit-core event counts per class.
Coordinate with GH-WP-0002-T04, which is the detection surface. This
task is the source that surface reads.
Acceptance: layer.yaml evidence.cadence_status is no longer
undeclared; a missing heartbeat or a count divergence is specified as a
finding, not as a log line.
T05 — Wait on consumption ordering; do not implement it
id: APPROVAL-WP-0001-T05
status: wait
priority: high
state_hub_task_id: "204bdfeb-a669-569e-a654-10c1a9fcacbc"
Blocked on GH-WP-0002-T06 / access-engine. The three races (allow never
consumed; double consumption; consume after failed action) are named in
statute §9.7.4 and §16. This engine performs the mutation; it does not
choose the signal, the point relative to the decision, or the handling of
the three states.
Acceptance: a written contract both engines have assented to, recorded
here, then a consume path. Until then, no consume endpoint, no inferred
consumption from a decision record, no demo that "just consumes on allow".
T06 — Durable object, closed state machine, authenticated entries
id: APPROVAL-WP-0001-T06
status: done
priority: high
state_hub_task_id: "44c4997b-6833-5540-a554-0e24210809f2"
2026-08-29: SQLite object + closed machine in approval_engine/store.py.
CAS supersession (concurrent test), distinct-approver fail-closed, revocation
without holder cooperation. _cas_consume is unexported.
Depends on T02 and T03. Implement the object and the machine in SCOPE: identifiers; bindings (action, target, actor, principal, purpose, validity window, approvers); authenticated entries; distinct-approver counting; CAS supersession; validity/expiry; revocation without holder cooperation.
Do not ship a public consume until T05 is unblocked. Internal CAS
consumption may exist behind an unexported seam so T08 can be tested
without guessing the ordering contract.
Acceptance: state transitions are total and reconstructable; two concurrent supersessions cannot both succeed; distinct-approver requirements fail closed on duplicates; revocation is effective at the next introspection.
T07 — Introspection API as input claims
id: APPROVAL-WP-0001-T07
status: done
priority: high
state_hub_task_id: "ea51499d-ced5-50fa-b852-396719a8c0f4"
2026-08-29: GET /v1/approvals/{id}/claim. Tests forbid decision-shaped
keys and /v1/check / /authorize / /consume. Store unavailable → 503.
Depends on T02 and T06. An API that answers INTENT's question and returns the T02 claim. No endpoint answers "may this actor do X". Fail-closed when this engine's own store is unavailable.
Acceptance: access-engine can fetch a claim; a decision rendered against
approval A for request R cannot be replayed for R' on the digest; tests
forbid a decision-shaped response.
T08 — Local outbox in the mutation transaction
id: APPROVAL-WP-0001-T08
status: done
priority: high
state_hub_task_id: "b9267011-71b3-5138-a3f9-5256374a6b3b"
2026-08-29: Outbox insert in the same IMMEDIATE transaction. Test fails the transaction when emission fails (no leftover mutation). Revoke succeeds while the drain sink is down; the revocation row stays undrained.
Depends on T03 and T06. Every issuance, use, supersession, and revocation
inserts the outbox row in the same transaction. Drain is asynchronous.
audit-core outage does not block a revocation.
Acceptance: a test that fails the transaction when emission fails, not an inspection of the code; a test that revokes while the evidence engine is unreachable; no path where the state change commits and the outbox row does not.
T09 — Canon T-06 and the FLEX-WP-0017 handoff
id: APPROVAL-WP-0001-T09
status: done
priority: medium
state_hub_task_id: "b4946568-5dda-5bd7-9941-83a5f0137700"
2026-08-29: tests/test_t06_replay.py encodes Canon T-06 for wrong target,
wrong action, later time, revoked, superseded. Consume-side replay stays out.
Handoff: docs/flex-auth-handoff.md. FLEX-WP-0017 T03 is unblocked on this
object; T05 remains blocked only on consumption ordering.
Depends on T07, T08, and T05 (the last only for the consume-side replay
cases). Point Canon T-06 — Approval Replay at a live implementation.
Hand access-engine / secrets-engine a claim they can validate before
privileged production actions (FLEX-WP-0017 T03/T05).
Acceptance: T-06 passes; T03 is unblocked on the object (not on a hub
substitute); T05 remains blocked only on consumption ordering if T05 of
this workplan is still wait, never on a missing object or a missing
digest.