Publish approval evidence-integrity contracts for GH-WP-0002
Adopt approval-engine's outbox wire as Gate House doctrine, specify the heartbeat-and-reconciliation detection surface, and settle consumption ordering: the PEP consumes by CAS before the side effect. T05's §11 check is written here and queued for statute v0.8. Assistant: grok Assistant-Session: 01a04d89-aaa5-7443-945e-b3055cd4b7e4
This commit is contained in:
parent
2ae611d2ad
commit
7408ff9234
5 changed files with 441 additions and 10 deletions
111
docs/contracts/approval-emission-detection.md
Normal file
111
docs/contracts/approval-emission-detection.md
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
# Approval emission detection surface
|
||||
|
||||
**Owner:** gate-house
|
||||
**Source:** approval-engine
|
||||
**Archive:** audit-core
|
||||
**Observer:** kings-guard (silence-as-signal; offered)
|
||||
**Status:** normative for GH-WP-0002-T04
|
||||
**Date:** 2026-08-29
|
||||
**Statute:** `net-kingdom/canon/standards/security-layer-model_v0.7.md` §9.6
|
||||
**Source declaration:** `approval-engine/cadence.yaml`
|
||||
|
||||
A hash chain proves accepted records were not altered or truncated. It proves
|
||||
nothing about an event never emitted. Atomicity (the outbox contract) prevents
|
||||
accidental omission. This surface is what makes a *silent* loss visible.
|
||||
|
||||
It does not prevent a compromised source from suppressing. That residual is
|
||||
stated in §9.6 and is not closed here.
|
||||
|
||||
## Form
|
||||
|
||||
Approval evidence is **load-bearing** and **low-volume**. Rate monitoring is
|
||||
forbidden: a handful of revocations a month has no rate to drop below, and
|
||||
suppression is indistinguishable from a quiet month.
|
||||
|
||||
The required form is **heartbeat plus reconciliation**. Reference instance:
|
||||
`approval-engine/cadence.yaml` and `approval-engine/docs/emission-cadence.md`.
|
||||
|
||||
### Heartbeat
|
||||
|
||||
A signed positive claim: *nothing to report*, together with per-class
|
||||
transition counts since the previous heartbeat (or since process start on
|
||||
the first). The claim can itself go missing, which is the point.
|
||||
|
||||
| Field | Value |
|
||||
| --- | --- |
|
||||
| Class | `heartbeat` |
|
||||
| Interval | 24 hours (SHOULD also be emittable on demand) |
|
||||
| Assertion | `nothing-to-report` |
|
||||
| Counts | `{issuance, use, supersession, revocation}` of committed outbox rows |
|
||||
| Missing heartbeat | **finding** |
|
||||
|
||||
Heartbeat rows use the outbox table and the same at-least-once drain. They are
|
||||
not coupled to an object mutation.
|
||||
|
||||
### Reconciliation
|
||||
|
||||
Compare `approval-engine`'s committed outbox counts per class to `audit-core`'s
|
||||
accepted event counts for `source=approval-engine` and the corresponding
|
||||
`action`. Divergence is a **finding**, not a log line.
|
||||
|
||||
| Source class | `audit-core` `action` |
|
||||
| --- | --- |
|
||||
| `issuance` | `approval.issuance` |
|
||||
| `use` | `approval.use` |
|
||||
| `supersession` | `approval.supersession` |
|
||||
| `revocation` | `approval.revocation` |
|
||||
| `heartbeat` | `approval.heartbeat` |
|
||||
|
||||
Undrained local rows are lag, not yet a divergence. A row with `drained_at` set
|
||||
that `audit-core` does not hold is the omission case §9.6 names.
|
||||
|
||||
### Lag bound
|
||||
|
||||
| Bound | Default (reference) | Exceed |
|
||||
| --- | --- | --- |
|
||||
| Outbox depth | 100 undrained rows | **finding** |
|
||||
| Outbox age | 1 hour for the oldest undrained row | **finding** |
|
||||
|
||||
These detect a stuck drain. They are not a completeness proof.
|
||||
|
||||
## What is a finding
|
||||
|
||||
- No heartbeat arrives for more than one interval.
|
||||
- `audit-core` count for a class is less than the source's drained count for
|
||||
that class.
|
||||
- Outbox depth or age exceeds the lag bound.
|
||||
|
||||
None of these are rate drops. None of these are informational logs.
|
||||
|
||||
`kings-guard` consumes the finding as observation of the stream, not of its
|
||||
contents. Until it reports that it is watching in production, no argument may
|
||||
assume this surface is live (§12). The source MUST still publish the
|
||||
declaration; a detector that is not yet watching does not excuse an undeclared
|
||||
source.
|
||||
|
||||
## Who owns which half
|
||||
|
||||
| Half | Owner |
|
||||
| --- | --- |
|
||||
| Publish cadence and expose committed counts / lag | approval-engine |
|
||||
| Hold accepted events and answer per-source per-class counts | audit-core |
|
||||
| Raise silence, divergence, and lag as findings | kings-guard |
|
||||
| Name the form and the residual | gate-house |
|
||||
|
||||
## Conformance check (queued for statute v0.8 §11)
|
||||
|
||||
GH-WP-0002-T05. Mechanically checkable, in the same list as the existing §11
|
||||
bullets:
|
||||
|
||||
- every repository catalogued as an evidence source, or that emits
|
||||
**load-bearing** evidence, declares its emission guarantee in a
|
||||
machine-readable form at a path named in its layer declaration:
|
||||
- **load-bearing:** local transactional outbox (this contract's shape) **and**
|
||||
a heartbeat-or-reconciliation cadence declaration;
|
||||
- **attributive, deliberately non-atomic:** the named trade, and a statement
|
||||
that completeness is not claimed.
|
||||
|
||||
A new engine catalogued under §9.4 / §4 as an evidence source that ships
|
||||
without this declaration reintroduces the approval omission gap silently.
|
||||
Until v0.8 lands, this paragraph is doctrine; `approval-engine`'s
|
||||
`cadence.yaml` plus `layer.yaml` is the reference form.
|
||||
Loading…
Add table
Add a link
Reference in a new issue