# approval-engine source registration `AUDIT-WP-0009-T09` · intake `AUDIT-IN-0001` · statute §9.4, §9.6 The registration inputs for `approval-engine` as a distinct audit source, onboarded under `INTENT.md` principle 4 — declared ownership, retention, access, export and evidence policy, not merely events arriving. This file is the owner-side record. Everything in it is non-secret. No sender token appears here, in Git, in State Hub, or in a workplan. ## Declaration | Field | Value | | --- | --- | | Sender name | `approval-engine` | | Permitted `source` | `approval-engine` (exact; no wildcard) | | `evidence_kind` | **`load-bearing`** (§9.4 — a control's soundness depends on the revocation event being present) | | `completeness_trade` | none, and none is permitted — §9.6 requires emission atomicity of a load-bearing source | | `may_write` | true | | `may_read` | false — a source does not gain a read surface by emitting | | `secret_policy` | `redact` (estate default; see below) | | `tenants` | `["*"]` — **proposed, needs approval-engine's confirmation** | | Retention | no expiry set; recoverable history is the platform `data.backup` window, 30 days, `measured` | | Custody class | `operational` — never `archive`, never WORM | ### Event classes The four §9.4 classes, carried as distinct actions on one source: | Class | Why it matters | | --- | --- | | issuance | the approval came into being | | use | single consumption, a state change owned by `approval-engine` | | supersession | the prior approval stopped being current | | revocation | **the acute one** — the most valuable event to suppress | Audit Core stores all four and derives nothing from them. It renders no verdict on whether an approval is still valid (§9.4), asserted by test in `tests/test_approval_validity_prohibition.py`. ### The `tenants` value is the one input still owed `["*"]` is proposed because approval issuance is not obviously tenant- partitioned, and the alternative — an explicit tenant list — cannot be invented here. `audit_core/senders.py` states that omitting a tenant restriction "should be justified per sender, not adopted by default", so this needs `approval-engine` to either confirm the wildcard with its reasoning or supply the list. Tenant identifiers are opaque to Audit Core; their shape is owned by the IAM Profile and `tenant-engine`. ### `secret_policy` `redact` accepts the event and redacts a secret-shaped field, so a legitimate event is not lost over one field. For a load-bearing source that trade is worth re-examining: `reject` refuses the event instead, which for approvals converts a redactable field into a delivery failure the source must retry. `redact` is the recommendation — losing a revocation record is worse than storing it with one field redacted — but it is `approval-engine`'s call to make explicitly rather than inherit. ## Applied in this repository | Input | Where | | --- | --- | | Non-secret scope | `deploy/senders-scope.json` + `deploy/senders-scope.yaml` (lockstep) | | Receiver ingress | `deploy/networkpolicies.yaml`, `audit-core-approval-engine-ingress` | | Evidence kind in the model | `audit_core/senders.py`, `SenderIdentity.evidence_kind` | The scope overlay only applies to a sender the Secret already carries, so this entry is **inert until the token exists**. That is what makes it safe to land ahead of the credential rather than in the same change. The ingress rule is narrower than `user-engine`'s: namespace **and** pod label in a single `from` peer, so both are ANDed. A new sender should not inherit an older rule's breadth. `user-engine`'s sender and its policy are unchanged. ## Still owed by others | Input | Owner | Note | | --- | --- | --- | | Token at `approval-engine/approval-engine-audit`, key `audit-token` | OpenBao (`railiance-platform`), routed via `warden route` | Audit Core never holds or transports it | | `tenants` confirmation | `approval-engine` | see above | | `secret_policy` confirmation | `approval-engine` | see above | | Applying the manifests to `railiance01` | operator | Audit Core does not apply cluster changes unprompted | ## What Audit Core will and will not claim about this stream Stated here because §9.6 requires the bound to travel with the trail, and because a load-bearing source will otherwise be told less than it needs. **Will:** every event it accepted is stored append-only, and the hash chain detects alteration or truncation of what it received. **Will not:** that the archive proves an approval event occurred, or that the absence of one proves it did not. Completeness at the boundary is `approval-engine`'s obligation and an archive cannot retrofit it. ### Open gates, and which of them block what | Gate | Blocks admission? | What it actually bounds | | --- | --- | --- | | `T02` attestation scheduling | **No** | Evidence *quality*, not custody. See below. | | `T04` heartbeat / missing-heartbeat findings | No | Detection of adversarial omission for rare classes — the one that matters most for revocation | | `T06` reconciliation counts | No | The source's own ability to detect divergence | | `T05` declared cadence | No | Held deliberately on the §17 Taxonomy schema | **T02 is an evidence-quality gate, not an admission or deployment blocker.** Admission depends on identity, scope, ingress and a token. Attestation freshness governs what Audit Core may *claim*, not whether it accepts and durably stores. The append-only trigger and hash chain operate regardless; what a stale attestation removes is detection of a suffix rewrite by someone who owns the database. Since `AUDIT-WP-0009-T01`, `/readyz` reports `tamper_evidence: false` rather than overclaiming, and will keep doing so until T02 mounts a renewed attestation. It also is not the gate that matters most here. §9.6 is explicit that the acute risk for approvals is **omission**, and tamper evidence does not address omission at all — T04 does. So a consumer waiting on T02 before trusting approval evidence would be waiting on the wrong control. Until T04 and T06 land, Audit Core cannot detect a suppressed revocation, and no reading of the chain, attested or not, changes that.