KB-3780

RS3B-06 — Durable Failure-Audit Sink Selection — 2026-06-21

6 min read Revision 1
rs3baudit-sinkevent-outboxregistry-changeloggovernance-audit-logfail-closedno-new-ledger2026-06-21

RS3B-06 — Durable Failure-Audit Sink Selection — 2026-06-21

Macro: RS3B-REGISTRAR-HARDENING-DESIGN (read-only / KB-design) Deliverable: 06 of 10 · Durable failure-audit sink (Mục tiêu F) Date: 2026-06-21 · 0 mutations · NO_CODEX_LIVE_READ Deliverable status: SINK_CANDIDATE_SELECTED_FAIL_CLOSED_UNTIL_IMMUTABILITY_RETENTION_PROVENevent_outbox is the lead reuse candidate for the durable failure-audit sink, but no candidate proves enforced immutability/retention, so the sink stays fail-closed. No new ledger.


1. Why a durable failure-audit sink

RS3B-05 requires that a registration failure (esp. rolled-back Phase-1) leave a durable audit record outside the rolled-back transaction (RS2-PATCH1 Codex R3). The sink must be reused from existing surfaces (no new ledger until reuse is exhausted — must-not-do #13).

2. Candidate evidence (live, 2026-06-21; immutability via pg_trigger, not the privilege-blind information_schema.triggers)

Candidate Rows Schema fit Trigger facts (pg_catalog) Immutability Idempotency Post-rollback writable Payload safety
event_outbox 215,644 rich: event_domain/type/stream/lane/severity, subject_table/ref, canonical_address, actor_ref NN, source_system, correlation_id (nullable, non-unique), safe_payload jsonb, payload_classification, occurred_at, created_at trg_event_outbox_type_validate BEFORE INSERT (type validation) + safe_payload forbidden-key CHECK none (no UPDATE/DELETE block) none (only PK on id; no idempotency key) yes (normal heap table) yes (safe_payload guard, payload_classification)
registry_changelog 87,746 audit-log: entity_type/code/name, action, collection_name, changed_by, alert_level, resolved/resolved_by/resolved_at birth_trigger_registry_changelog AFTER INSERT, trg_label_assign_… AFTER INSERT, trg_count_… (DISABLED); none block UPDATE/DELETE none — explicitly mutable by design (resolve workflow) none yes weak (no classification guard)
governance_audit_log 1 narrow: relation_id, checked_at (nullable), checked_by NN, result, detail json no triggers none none yes weak
iu_route_attempt 68 retry ledger; wrong domain (IU routing) no triggers n/a UNIQUE(idempotency_key,attempt_no) (not single-use) yes n/a

3. Score table (0 = absent, 1 = partial, 2 = proven)

Criterion event_outbox registry_changelog governance_audit_log iu_route_attempt
schema fit (failure event) 2 1 1 0
writer authority (enumerable, restricted) 0 0 0 0
append-only / immutability (enforced) 0 0 0 0
retention (proven) 0 0 0 0
post-rollback write capability 2 2 2 2
replay/idempotency dedup 0 0 0 1
payload safety 2 1 1 0
consumer readback 1 1 1 1
no-new-ledger (already exists) 2 2 2 2
total 9 7 7 6

4. Selection

  • Selected lead candidate: event_outbox — highest schema fit, a safe_payload jsonb with a forbidden-key guard and payload_classification (payload-safety proven), normal heap table so it is writable after a Phase-1 rollback, and it already exists (no new ledger). RS3-PATCH2 classifies it consistently as "candidate failure-audit sink only."
  • Rejected as authority/replay surface: all four — none is an authority carrier; iu_route_attempt is wrong-domain and not single-use.
  • Why fail-closed despite selection: event_outbox (and every candidate) fails the immutability and retention criteria — there is no UPDATE/DELETE-blocking trigger or constraint on any of them (confirmed via pg_trigger), append-only is convention only, the writer role is not enumerable from the read-only role, and there is no idempotency dedup for failure records. registry_changelog is explicitly mutable (resolve columns). Therefore the sink is selected but fail-closed.

5. Required future surface (defined, not built)

To promote event_outbox to a proven durable failure-audit sink: (1) an enforced append-only mechanism (UPDATE/DELETE-blocking trigger or revoked grants) — none exists today; (2) an enumerable, restricted writer grant for the registrar; (3) a retention policy covering the replay horizon; (4) an idempotency/dedup key for failure records so retries do not duplicate audit rows; (5) consumer readback proven. These are reuse hardening of the existing table — no new ledger is authorized until these are evaluated and shown insufficient.

6. Status block

  • Deliverable status: SINK_CANDIDATE_SELECTED_FAIL_CLOSED_UNTIL_IMMUTABILITY_RETENTION_PROVEN
  • Selected lead: event_outbox (sink-only, not authority); no new ledger
  • Feeds RS3B-05 (durable failure audit outside rolled-back txn) and RS3B-09
  • Registration gate: REGISTRATION_HOLD · REGISTRATION_CAN_PROCEED = NO · 0 mutations