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
111 lines
4.2 KiB
Markdown
111 lines
4.2 KiB
Markdown
# 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.
|