Implement the engine spine: claim, outbox, machine, API

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
This commit is contained in:
tegwick 2026-08-29 12:52:49 +02:00
parent 624e43f554
commit 9c9528f5b2
29 changed files with 2121 additions and 26 deletions

View file

@ -93,14 +93,14 @@ the other side has not assented to.
## Current State
- Status: **seed**. The repository holds `INTENT.md`, this file, `layer.yaml`,
and a README. There is no store, no API, no outbox, no tests, no runtime.
- Layer declaration exists in this engine's own voice (INTENT frontmatter +
`layer.yaml`). Conformance checks against Tooling contact are vacuously
clean: there is no code to contact anything.
- Consumption ordering remains unresolved estate-wide (`GH-WP-0002-T06`).
- Taxonomy request-claim schema is proposed, not assigned (statute §17).
- Work: `APPROVAL-WP-0001`.
- Status: **first-cut spine**. SQLite-backed object, closed machine, local
outbox, WSGI introspection API, claim contract. Not a production deploy.
- Layer declaration: INTENT frontmatter + `layer.yaml`. Cadence declared in
`cadence.yaml`. No Tooling contacts.
- Consumption is not a public API (`APPROVAL-WP-0001-T05` waits on
`GH-WP-0002-T06`).
- Taxonomy request-claim schema is still unassigned; the local claim yields.
- Work: `APPROVAL-WP-0001`. Tests: `make test`.
## How It Fits
@ -143,9 +143,32 @@ it does not become a Railiance axis.
## Provided Capabilities
None. The spine described above is INTENT and first-cut SCOPE, not a shipped
surface. No store, no API, no claim, no outbox.
```capability
type: api
title: Approval introspection claim
description: >
GET /v1/approvals/{id}/claim returns an input claim with identifier,
canonical-binding digest, optional PDP digest, issuer, and freshness.
It does not decide whether an action is permitted.
keywords: [approval, claim, pip, digest, freshness]
```
When the first surface ships, this section gains `capability` blocks for the
introspection API, the mutation API, and the outbox. Until then, declaring
capabilities would advertise a PIP that does not exist.
```capability
type: api
title: Approval object lifecycle
description: >
Create, collect authenticated entries with distinct-approver counting,
atomically supersede, and revoke without holder cooperation. No public
consume until consumption ordering is settled.
keywords: [approval, state-machine, cas, revocation, supersession]
```
```capability
type: infrastructure
title: Local transactional outbox
description: >
Issuance, use, supersession, revocation, and heartbeat rows are inserted
in the same SQLite transaction as the mutation. Drain is asynchronous;
an audit-core outage does not block revocation.
keywords: [outbox, audit-core, emission-atomicity, heartbeat]
```