Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a05e2e-805b-7042-a750-71f473bceea2
177 lines
8.5 KiB
Markdown
177 lines
8.5 KiB
Markdown
# SCOPE
|
|
|
|
> Implemented-and-first-cut boundary for agents and contributors. Aspirational
|
|
> direction belongs in `INTENT.md`; current work and operational gates belong in
|
|
> `workplans/`. Derived from INTENT after alignment to the accepted NetKingdom
|
|
> Security Layer Model v0.7 and its working companion.
|
|
|
|
## One-liner
|
|
|
|
approval-engine is the PIP for the approval object: a durable, authenticated,
|
|
consumable artifact that `access-engine` reads as an input claim and that this
|
|
engine alone mutates.
|
|
|
|
## Core Idea
|
|
|
|
An approval is current-state, not a log and not a decision. This repository
|
|
owns the object, the closed state machine, the local outbox that makes every
|
|
transition evidence, and the claim `access-engine` consumes. It does not decide
|
|
whether the action is permitted, does not author the policy that requires an
|
|
approval, and does not archive the trail.
|
|
|
|
The first cut is the spine that makes Canon `T-06 — Approval Replay` passable
|
|
and supplies the approval object and consumption mutation needed by protected
|
|
systems. Consumption follows the assented `GH-DEC-2026-003` contract.
|
|
|
|
## In Scope
|
|
|
|
- Durable approval objects with stable identifiers.
|
|
- Bindings captured at issue time: action, target, actor, principal, purpose,
|
|
validity window, identified approvers.
|
|
- Authenticated approval entries and distinct-approver counting.
|
|
- The closed state machine
|
|
`requested → approved → valid → consumed`, with
|
|
`superseded / revoked / expired` as terminal exits from `valid`.
|
|
- Atomic supersession and single consumption (compare-and-swap, never
|
|
read-then-write).
|
|
- A PEP-called consume mutation before the protected side effect, with
|
|
same-request idempotency, different-request conflict, and no unconsume.
|
|
- Revocation that does not require the holder's cooperation and is effective
|
|
at the next use.
|
|
- A local transactional outbox in this engine's own store; no synchronous
|
|
`audit-core` dependency inside a state-change transaction.
|
|
- An introspection API that returns an input claim: approval identifier,
|
|
canonical-binding digest, issuer, freshness.
|
|
- Emission-cadence declaration for load-bearing classes, as a heartbeat or as
|
|
reconciliation against `audit-core` event counts — not rate monitoring.
|
|
- Machine-readable layer declaration (`layer.yaml`) as Engine / PIP, with no
|
|
decision surface and no Tooling contact.
|
|
- Fail-closed when this engine's own store is unavailable. An `audit-core`
|
|
outage does not block a revocation.
|
|
|
|
## Out of Scope
|
|
|
|
- Authorization decisions — `access-engine` (statute §6).
|
|
- Approval policy: which actions require approval, how many approvers, which
|
|
separations of duty — `gate-house` doctrine, arriving as claims or versioned
|
|
policy rules.
|
|
- Identity and authentication of approvers — `key-cape`.
|
|
- The evidence archive — `audit-core`. This engine emits; it does not store
|
|
the trail or answer "is this approval valid?" from records.
|
|
- Stronger-than-shipped custody (WORM, object lock, transparency log) —
|
|
decided against (statute §16).
|
|
- Credentials materialized after a decision — `secrets-engine`.
|
|
- Graded progression, readiness, gap register — `maturity-engine`.
|
|
- Workflow, ticketing, inbox, notifications — the artifact, not the meeting.
|
|
- A general state-machine service for other concepts.
|
|
- PEP shape, unreachable-engine stance maps, Railiance `rail-*` / `rapp-*` /
|
|
`reef-*` axes. An approval is not a workload (statute §20.1).
|
|
- Any consumption protocol other than `GH-DEC-2026-003`, including PDP
|
|
mutation, action-before-consume, unconsume, reserve/release, or inferring use
|
|
from a decision record.
|
|
|
|
## Relevant When
|
|
|
|
- A protected action exceeds normal policy and needs a durable approval
|
|
object bound to the exact request.
|
|
- `access-engine` needs an input claim that distinguishes *approved* from
|
|
*approved for this exact action, target, actor, and purpose*.
|
|
- Distinct-approver requirements must be enforced rather than conventional.
|
|
- An approval must be revocable without the holder's cooperation.
|
|
- Canon `T-06 — Approval Replay` is the test, or `FLEX-WP-0017` T03/T05 is
|
|
blocked on the missing object.
|
|
- An event about an approval (especially a revocation) must not be separable
|
|
from the state change that made it true.
|
|
|
|
## Not Relevant When
|
|
|
|
- The question is "may this actor do X" — that is a decision.
|
|
- The work is policy authoring, runbooks, or credential issuance.
|
|
- The need is an audit query, a hash chain, or a WORM store.
|
|
- The need is a workflow inbox, a meeting, or a notification surface.
|
|
- The need is graded readiness or a maturity ladder.
|
|
- The work is mapping Railiance operational axes onto security objects.
|
|
- A caller wants to consume without presenting the PDP decision binding's
|
|
canonical request digest.
|
|
|
|
## Current State
|
|
|
|
- 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 public at `POST /v1/approvals/{id}/consume` under
|
|
`GH-DEC-2026-003`; the endpoint is a lifecycle mutation, never a decision.
|
|
- Taxonomy request-claim schema is still unassigned; the local claim yields.
|
|
- Work: `APPROVAL-WP-0001`. Tests: `make test`.
|
|
|
|
## How It Fits
|
|
|
|
```text
|
|
gate-house designs the approval contract (Staff, doctrine)
|
|
key-cape authenticates approvers (Tooling → claims)
|
|
approval-engine owns and mutates the object (Engine, PIP) ← this repo
|
|
access-engine consumes the claim; never mutates (Engine, PDP)
|
|
audit-core archives what this engine emitted (Engine, Evidence)
|
|
secrets-engine materializes credentials after a decision (Engine, Lifecycle)
|
|
```
|
|
|
|
Staff never holds this object. `access-engine` never owns it. `audit-core`
|
|
never answers whether it is still valid. Railiance consumes it as a claim;
|
|
it does not become a Railiance axis.
|
|
|
|
## Terminology
|
|
|
|
| Term | Meaning here |
|
|
| --- | --- |
|
|
| **Approval** | The durable object this engine owns. Not a decision, not a workflow item. |
|
|
| **Claim** | What `access-engine` reads. Identifier + binding digest + issuer + freshness. |
|
|
| **PIP** | Policy Information Point. Supplies facts; does not decide. |
|
|
| **PDP** | Policy Decision Point. `access-engine` only. |
|
|
| **Consumption** | A mutation in this engine. Never inferred from a decision record. |
|
|
| **Load-bearing** | A control's soundness depends on the event being present. Revocations are this. |
|
|
| **Local outbox** | Durable queue in this engine's own transactional store. |
|
|
| **Heartbeat** | Signed *nothing to report* for a quiet load-bearing class. |
|
|
|
|
## Related / Overlapping
|
|
|
|
| Other | Relation | Do not confuse with |
|
|
| --- | --- | --- |
|
|
| `access-engine` / `flex-auth` | Consumer of claims; owner of the decision. `FLEX-WP-0017` T03/T05 wait on this object. | This engine validating "may this actor do X". |
|
|
| `gate-house` | Doctrine; designs the contract. `GH-WP-0002` is the evidence-integrity work this spine must satisfy. | This engine authoring who may approve what. |
|
|
| `audit-core` | Evidence destination. `AUDIT-IN-0001` conditions the outbox. | This engine exposing an approval-validity query from records. |
|
|
| `maturity-engine` | Deliberate opposite: open graded ladder vs closed binary machine. | Levels as a substitute for valid/consumed. |
|
|
| `secrets-engine` | Downstream of a decision. | Approvals as credentials. |
|
|
| State Hub `/decisions/{uuid}` | Not this object. Free-form `decided_by` is what `FLEX-WP-0017` T03 rejected as a substitute. | Storing approvals in the hub. |
|
|
|
|
## Provided Capabilities
|
|
|
|
```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]
|
|
```
|
|
|
|
```capability
|
|
type: api
|
|
title: Approval object lifecycle
|
|
description: >
|
|
Create, collect authenticated entries with distinct-approver counting,
|
|
atomically supersede, consume with request-digest idempotency, and revoke
|
|
without holder cooperation.
|
|
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]
|
|
```
|