186 lines
11 KiB
Markdown
186 lines
11 KiB
Markdown
|
|
# Security layer model v0.7 — approval-engine scope vs intent review
|
||
|
|
|
||
|
|
**Date:** 2026-08-29
|
||
|
|
**Statute:** `net-kingdom/canon/standards/security-layer-model_v0.7.md` (accepted)
|
||
|
|
**Companion:** `net-kingdom/SECURITY-COMPANION.md` v0.2
|
||
|
|
**Reviewed against:** this repository's v0.5-aligned `INTENT.md` (commits
|
||
|
|
`0c481de`, `35fee0e`, `ab5d69e`), the empty implementation, and the first-cut
|
||
|
|
`SCOPE.md` written from the aligned intent
|
||
|
|
**Outcome:** INTENT aligned to v0.7; SCOPE created as a first-cut boundary;
|
||
|
|
implementation is seed-only. The work to evolve the repo is
|
||
|
|
`APPROVAL-WP-0001`.
|
||
|
|
|
||
|
|
Hub MCP tools were not exposed in this session. Orientation and the inbox
|
||
|
|
read used the State Hub HTTP API at `http://127.0.0.1:8000`. The gate-house
|
||
|
|
broadcast `ACCEPTED: security layer model v0.7 — and start here:
|
||
|
|
net-kingdom/SECURITY-COMPANION.md` is the trigger.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## What v0.5 already had right
|
||
|
|
|
||
|
|
The seed INTENT, written against v0.5, already carried the properties that
|
||
|
|
make this engine an engine:
|
||
|
|
|
||
|
|
- the object, not the decision;
|
||
|
|
- atomic supersession and single consumption;
|
||
|
|
- local transactional outbox, no synchronous `audit-core` in the mutation
|
||
|
|
path;
|
||
|
|
- claim shape with identifier and canonical-binding digest;
|
||
|
|
- consumption ordering recorded as unresolved rather than guessed;
|
||
|
|
- the "what would make this repository wrong" list.
|
||
|
|
|
||
|
|
Those survive. v0.7 does not reopen them. It types them, bounds them, and
|
||
|
|
adds obligations the v0.5 text did not know it owed.
|
||
|
|
|
||
|
|
## What v0.6/v0.7 changed that this engine must carry
|
||
|
|
|
||
|
|
| Change | Where | Effect on this repo |
|
||
|
|
| --- | --- | --- |
|
||
|
|
| Engines are typed. This one is **PIP**. | §3.3, §4 | INTENT frontmatter `layer: Engine` / `role: PIP`. A new engine is a PIP unless the statute is amended; it can never be a second PDP. |
|
||
|
|
| Machine-readable declaration | §11, companion §2 | `layer.yaml` in this engine's own voice. A layer stated *about* this repo is not a declaration. |
|
||
|
|
| Statute accepted; companion is the operative form | §14, companion | Cite v0.7 as accepted. Disagreement with the companion is a finding, not a workaround. |
|
||
|
|
| Threat decomposition on §9.6 | §9.6, v0.7 change 5 | Local outbox **prevents accidental omission**. It does **not** prevent a compromised source. Cadence/reconciliation **detects** the adversarial case after the fact. The residual is stated. |
|
||
|
|
| Cadence is MUST for load-bearing, and rate monitoring is the wrong form | §9.6 | Revocations are rare. Required form: heartbeat or positive reconciliation against `audit-core` (`GH-WP-0002-T04`). |
|
||
|
|
| Stronger custody decided: no | §13, §16 | v0.5 INTENT treated this as an open gap this engine must not assume closed. v0.7 closes it: same bound as every other source. Archival custody does not address omission. |
|
||
|
|
| Time in the model | §9.7 | Every allow has a lifetime (the object's validity window). Consumption is a mutation, never an inference from a decision record. Three races named, each needing an owner. |
|
||
|
|
| Claim schema includes issuer and freshness | §17, §9.7.2 | The v0.5 claim (id + binding digest) is necessary and not sufficient. PDP deadlines are per input class; this PIP must publish freshness. |
|
||
|
|
| Approval objects are not Railiance workloads | §20.1 | Do not grow a `rail-*` / `rapp-*` mapping. How the axes meet the model is unwritten. |
|
||
|
|
| Observation and actuation at zero | companion §10, §9.2, §12 | Do not cite "observed in operation". Do not plan on automatic containment. |
|
||
|
|
| Evidence outage rule is a trade, not a property | §3.3 | `audit-core` MUST NOT block the recorded operation *by default*. Independent-recording-before-effect remains raisable. This engine's local-outbox rule is how availability and atomicity coexist. |
|
||
|
|
|
||
|
|
## Scope vs intent
|
||
|
|
|
||
|
|
`INTENT.md` is the kind of system this repository is meant to become.
|
||
|
|
`SCOPE.md` is the first-cut boundary: what the first workplan is allowed to
|
||
|
|
build, and what it is forbidden to guess.
|
||
|
|
|
||
|
|
There is no contradiction of ownership. Every in-scope item is an INTENT
|
||
|
|
item. The gaps are maturity, missing contracts, and a missing runtime.
|
||
|
|
|
||
|
|
### Intent scorecard
|
||
|
|
|
||
|
|
| Intent area | SCOPE | Implementation | Material gap |
|
||
|
|
| --- | --- | --- | --- |
|
||
|
|
| PIP, never PDP | In scope as a prohibition | No endpoints exist, so no decision surface exists either | Vacuous. The failure mode is the first endpoint that answers "may". Guard with `layer.yaml` `decision_surfaces_exposed: none` and a test once code exists. |
|
||
|
|
| Durable object + closed state machine | In scope | None | Entire store and machine. First implementation slice. |
|
||
|
|
| Atomic supersession and single consumption | In scope as CAS | None | Must be in the first mutation API. Read-then-write is a defect, not a stepping stone. |
|
||
|
|
| Authenticated entries, distinct-approver counting | In scope | None | Depends on `key-cape` claims for identity; this engine counts and binds, it does not authenticate. |
|
||
|
|
| Validity window / expiry | In scope | None | The object's lifetime is how §9.7.1 lands here. |
|
||
|
|
| Revocation without holder cooperation | In scope | None | Load-bearing event. Must hit the local outbox in the same transaction. |
|
||
|
|
| Claim: id + binding digest | In scope | None | Needed for `FLEX-WP-0017` T05. |
|
||
|
|
| Claim: issuer + freshness | In scope | None | v0.7 addition. Until Taxonomy's request-claim schema exists, publish a local contract and yield later. |
|
||
|
|
| Local outbox, no sync `audit-core` in the mutation txn | In scope | None | Prose contract in INTENT; wire contract not written (`GH-WP-0002-T02`). |
|
||
|
|
| Fail-the-transaction-if-emission-fails test | Success criterion; in scope | None | Demonstrable, not inspectable. |
|
||
|
|
| Cadence / heartbeat / reconciliation | In scope as declaration + design | None | MUST for load-bearing. `GH-WP-0002-T04` is the detection surface; this engine owes the source side. |
|
||
|
|
| Consumption ordering | **Explicitly out of first-cut** | Must stay unimplemented | Unresolved in §16 / `GH-WP-0002-T06`. Implementing it is the failure INTENT names. |
|
||
|
|
| Stronger custody | Out of scope (decided no) | n/a | Closed. Do not reopen in this repo. |
|
||
|
|
| Policy, identity, archive, maturity, inbox | Out of scope | n/a | Unchanged from v0.5. |
|
||
|
|
| PEP stance / Railiance axes | Out of scope | n/a | v0.7 clarification. |
|
||
|
|
| Canon `T-06` | Success criterion | Unrunnable | No implementation to point the test at. |
|
||
|
|
| `FLEX-WP-0017` T03 / T05 | Success criterion | Blocked | T03 waits on the object; T05 waits on T03 and on consumption ordering. |
|
||
|
|
|
||
|
|
### Where SCOPE is narrower than INTENT on purpose
|
||
|
|
|
||
|
|
1. **Consumption signaling.** INTENT owns the mutation. SCOPE forbids
|
||
|
|
implementing *when* it fires until the other engine assents. This is not
|
||
|
|
a missing SCOPE item; it is a named wait.
|
||
|
|
2. **Shipped capabilities.** INTENT describes a live PIP. SCOPE currently
|
||
|
|
provides **none**. Advertising a capability block would claim a surface
|
||
|
|
that does not exist.
|
||
|
|
3. **Taxonomy claim schema.** INTENT will yield to it. SCOPE publishes a
|
||
|
|
local contract in the meantime rather than waiting on an unassigned
|
||
|
|
owner.
|
||
|
|
|
||
|
|
### Where SCOPE would be wrong if it grew
|
||
|
|
|
||
|
|
- A "may this actor do X" helper for local tests.
|
||
|
|
- Storing approvals in the State Hub as a substitute object
|
||
|
|
(`FLEX-WP-0017` T03 already rejected that shape).
|
||
|
|
- Emitting synchronously to `audit-core` "for now" to skip the outbox.
|
||
|
|
- Inferring consumption from a decision record, because it is easier than
|
||
|
|
a mutation.
|
||
|
|
- A workflow inbox, because operators will ask for one.
|
||
|
|
- A Railiance mapping, because §20 looks adjacent.
|
||
|
|
|
||
|
|
## Implementation necessities
|
||
|
|
|
||
|
|
The repository at review time contains documentation and git history. There
|
||
|
|
is no language runtime, schema, store, or test. Everything in SCOPE is
|
||
|
|
therefore a necessity, sequenced so that contracts precede code, and so that
|
||
|
|
the one unowned contract is not filled in from this side.
|
||
|
|
|
||
|
|
### P0 — must exist before any mutation API is reachable
|
||
|
|
|
||
|
|
1. **Claim contract** — identifier, canonical-binding digest, issuer,
|
||
|
|
freshness. `access-engine` cannot consume what is not specified.
|
||
|
|
2. **Local outbox wire contract** — event classes, at-least-once into the
|
||
|
|
outbox, `audit-core` dedupes on event id. Boundary is in INTENT; the
|
||
|
|
wire is `GH-WP-0002-T02`.
|
||
|
|
3. **Keep consumption unimplemented** until `GH-WP-0002-T06`. A reachable
|
||
|
|
`consume` that guesses the races is worse than no `consume`.
|
||
|
|
|
||
|
|
### P0 — first implementation slice, after the contracts
|
||
|
|
|
||
|
|
4. **Durable object and closed state machine** with CAS supersession and
|
||
|
|
CAS consumption *once T06 has settled the latter*.
|
||
|
|
5. **Authenticated entries and distinct-approver counting.**
|
||
|
|
6. **Introspection API** that returns the claim and never a decision.
|
||
|
|
7. **Revocation** without holder cooperation, outbox-atomic, effective at
|
||
|
|
next use.
|
||
|
|
8. **Fail-closed on this store's outage; never on `audit-core`'s.** Proven
|
||
|
|
by a test that fails the transaction when emission fails, and by a test
|
||
|
|
that revokes while the evidence engine is down.
|
||
|
|
|
||
|
|
### P1 — load-bearing evidence residual
|
||
|
|
|
||
|
|
9. **Heartbeat or reconciliation** for issuance / use / supersession /
|
||
|
|
revocation classes. Rate monitoring is not an acceptable substitute.
|
||
|
|
Source side of `GH-WP-0002-T04`.
|
||
|
|
10. **Layer conformance test** once code exists: no decision surface, no
|
||
|
|
undeclared Tooling contact, outbox remains local.
|
||
|
|
|
||
|
|
### P2 — yield, do not invent forever
|
||
|
|
|
||
|
|
11. Replace the local claim contract with Taxonomy's request-claim schema
|
||
|
|
when that artifact exists and is assented.
|
||
|
|
12. Do not cite production observation or automatic containment. Both are
|
||
|
|
at zero estate-wide.
|
||
|
|
|
||
|
|
## Dependencies this repo does not own
|
||
|
|
|
||
|
|
| Work | Owner | What we owe |
|
||
|
|
| --- | --- | --- |
|
||
|
|
| `GH-WP-0002-T02` outbox wire | `gate-house` | Satisfy the contract; do not author doctrine |
|
||
|
|
| `GH-WP-0002-T03` revocation failure mode | `gate-house` | Local-outbox already narrows it; ship the engine to the ruling |
|
||
|
|
| `GH-WP-0002-T04` detection surface | `gate-house` | Heartbeat / counts from this side |
|
||
|
|
| `GH-WP-0002-T06` consumption ordering | `gate-house` + `access-engine` | Mutation API after assent, not before |
|
||
|
|
| `FLEX-WP-0017` T03 / T05 | `access-engine` / `flex-auth` | The object and the claim; not a hub substitute |
|
||
|
|
| `AUDIT-IN-0001` | `audit-core` | Local outbox, no validity query from records |
|
||
|
|
| Taxonomy request-claim schema | unassigned | Local contract, then yield |
|
||
|
|
| Canon `T-06` | `whitehat-security` / canon | A live implementation to aim at |
|
||
|
|
|
||
|
|
## Conformance snapshot
|
||
|
|
|
||
|
|
| §11 state | Now | Notes |
|
||
|
|
| --- | --- | --- |
|
||
|
|
| Layer declared in own voice | yes | INTENT frontmatter + `layer.yaml` |
|
||
|
|
| Claims inside layer permissions | yes, as prose | Reviewable, not compileable, until there is code |
|
||
|
|
| Tooling contacts | none | Vacuously conforming. Intended non-Tooling clients listed so they cannot appear as silence. |
|
||
|
|
| Decision surface | none | Required to stay none |
|
||
|
|
| Blocked-clean items | none of ours | Consumption wait is an unsettled contract, not a missing engine surface |
|
||
|
|
|
||
|
|
## Position
|
||
|
|
|
||
|
|
approval-engine assents to v0.7 as the statute it already declared under at
|
||
|
|
v0.5, typed and bounded. The PIP role is correct. The local-outbox rule is
|
||
|
|
already in the seed INTENT. The new obligations that bite are the heartbeat
|
||
|
|
for load-bearing classes, issuer and freshness on the claim, the explicit
|
||
|
|
ban on inferring consumption, and the custody question being closed rather
|
||
|
|
than held open.
|
||
|
|
|
||
|
|
The implementation gap is total. The dangerous gap is not the missing code;
|
||
|
|
it is the temptation to fill `GH-WP-0002-T06` from this side so that a
|
||
|
|
demo `consume` exists. SCOPE forbids that. `APPROVAL-WP-0001` is the work
|
||
|
|
that remains.
|