KB-6CAC

32 — Birth/Registry → Governance Handoff Ledger Design (Branch B, Điều 45, no Birth modification, design-only, read-only zero mutation, 2026-06-01)

19 min read Revision 1
one-roof-governanceimplementation-indexhandoff-ledgerbranch-bdieu45queue-carries-signalevent-vs-jobexecutor-boundarymot-not-executorsilent-gap-heartbeatevent-outboxevent-pendingregistry-changelogiu-route-worker-cursorcdc-tail-no-birth-touchreplayidempotencyretry-dlqcoalesceprovenanceno-lost-handoffno-islanddesign-only2026-06-01

32 — Birth/Registry → Governance Handoff Ledger Design (Branch B)

Path: knowledge/dev/reports/architecture/one-roof-governance-technical-addendum-and-implementation-index-2026-06-01/ Doc: 32. Track: Branch B of the Backfill / Handoff / Input-Control addendum. Builds on doc 31 (backfill), docs 24/25 (T7/T6), concept canon 01–02, mission §4K / Điều 45 Queue Law, GPT direction (backfill+handoff+input-control). Status: DESIGN ONLY. No PG/Directus/Qdrant/Nuxt mutation. No table/view/function/trigger created. No event domain registered. No event/job/notification emitted. Birth process is NOT modified (proof in §4). Register-before-emit means the governance event domain is registered later (T7 build); this doc specifies the durable handoff contract, not its activation. Owner (proposed): GOV-SIV runs the handoff intake (read/capture/enqueue); it never executes remediation. Producers are the existing Birth/Registry substrate; the executor of any governance work is a GOV-DOT under an approved APR (Điều 35). A Mother (MOT/MOUT) is never the executor. Evidence base: live read-only re-verified 2026-06-01 (counts inline); Điều 45 v1.0 enacted 2026-05-26.


0. §0-GOV declaration

§0-GOV Governance Coverage Declaration — Branch B (Handoff Ledger)
  governed_objects:   [ handoff_signal, handoff_intake_worker, handoff_cursor ] (Class-2 process records)
  owner_per_scope:    { policy: GOV-COUNCIL, health: GOV-SIV, execution: GOV-DOT,
                        render: GOV-MOUT(TTL→C-5), approval: Điều32, audit: GOV-SIV }
  coverage_profile:   [ queue/worker profile — owner, audit, rollback, heartbeat, issue-event ]
  axes_introduced:    [ none ]
  detection_path:     birth_registry tail + registry_changelog tail + event_outbox/event_pending
  issue_event_types:  [ handoff_lag, handoff_dlq, handoff_silent_gap, handoff_unregistered_type ]
                      (register-before-emit, Điều 45 — NOT registered here)
  exceptions:         [ none minted ]

1. Goal and the Điều 45 frame

Backfill (doc 31) onboards the existing 1.04M-object backlog once. Branch B answers the future: every new birth/registry/change must be handed off to the governance candidate/coverage pipeline durably, replayably, and auditably — with no lost handoff and no dependence on memory or prompt discipline (GPT direction). The handoff layer is bound by the Điều 45 Queue Law (mission §4K), whose five boundaries this design preserves verbatim:

  1. Queue carries signal, not data. A handoff carries {object_type, object_ref, canonical_address, group_key, change_kind, source, occurred_at} — the address to find the truth, never the object's contents.
  2. Event vs job. A handoff is a signal ("object X was born / changed"). Classifying it (candidate scan) and remediating it (assign owner) are jobs — the classify job runs read-only under GOV-SIV; any remediation job routes through the Điều 32 APR spine. The signal never carries an executable instruction.
  3. Executor boundary. The intake worker only captures and enqueues a dirty-group mark (doc 34); it does not classify or remediate. The executor of governance work is a governed DOT under an approved APR.
  4. MOT is not the executor. No Mother consumes the handoff to mutate governed state. MOUT/MOT may render coverage, never execute remediation.
  5. Silent-gap / heartbeat. The intake worker emits a periodic heartbeat; a missed heartbeat is itself a finding (handoff_silent_gap). Absence of handoffs (quiet system) is distinguishable from intake-not-running.

2. The durable substrate already exists — reuse map (no new bus, no new ledger)

Discover-first: the live system already has every primitive a durable handoff needs. Branch B wires them, it does not mint a parallel ledger:

Handoff need Reused live object Live evidence (2026-06-01) How
Durable born/registered ledger birth_registry 1,037,716 rows, append-only, (born_at, id) monotone the source-of-truth tail for births (object born / registered)
Durable change ledger registry_changelog 68,323 rows; (entity_type, entity_code, action, timestamp, alert_level, resolved) the source-of-truth tail for registry/collection/count/source/policy/owner changes
Registered-signal emit (Đ45) event_outbox Đ45 signal-not-data shape; payload_classification='safe_metadata', safe_payload jsonb the emission path once a governance domain is registered
Pre-registration capture / retry staging event_pending 0 rows (structure present, unused) — event_type_hint, entity_table, entity_ref, capture_payload, processed_at, error_count, last_error durable capture of a handoff before its type is registered+active; retry ledger
Type registry (register-before-emit) event_type_registry 40 rows; domains iu(16)/mother(9,0 active)/piece(6)/staging(5)/system(4); no governance domain (SB-4) the governance domain is defined (T7 doc 24) and registered later
Consumer cursor + DLQ counters iu_route_worker_cursor 1 active (iu_outbound_default, events_seen 68, dead_lettered 0) the exact durable-cursor + replay + DLQ precedent the intake worker reuses
Audit registry_changelog (+ event_outbox heartbeat) one row per intake batch / DLQ event

Decision (reuse vs new vs hybrid): HYBRID, reuse-first.

  • Default = tail existing ledgers via a cursor (CDC-style), reusing iu_route_worker_cursor — no new ledger table, no Birth modification, no trigger (§4).
  • Capture via event_pending when a handoff must be staged before its governance event type is registered+active (register-before-emit), reusing event_pending's error_count/last_error/processed_at for retry/DLQ.
  • Emit via event_outbox under the governance domain once registered (T7 build) for downstream subscribers.
  • A dedicated governance handoff ledger is NOT created now. It is recorded as a future option only if the handoff signal taxonomy outgrows event_pending + the tailed ledgers (see §10). Minting one now would be a second roof and is forbidden.

3. The ten handoff signal kinds → source tail → registered event type

Each mission-mandated handoff kind maps to a tail source (where the truth already lands durably) and a registered governance event type (the Đ45 signal). On consume, each marks the affected group_key dirty in the candidate-state store (doc 34) — that dirty-mark is the handoff into the candidate layer.

# Handoff kind Tail source (durable) Registered event type (domain=governance) Dirties group_key dimension
1 object born birth_registry (born_at tail) governance.handoff.object_born object_class + source_registry
2 object registered birth_registry / per-class registry governance.handoff.object_registered object_class + source_registry
3 collection changed registry_changelog (entity_type='collection') + collection_registry governance.handoff.collection_changed source_registry + scope
4 registry count changed registry_changelog / v_registry_counts governance.handoff.count_changed source_registry (count>1 candidacy, M-DEF-10)
5 object retired registry_changelog (action=retire/supersede) + status cols governance.handoff.object_retired object_class + lifecycle/status
6 source changed registry_changelog (source_kind/migration_state) governance.handoff.source_changed source_registry
7 axis introduced Axis Registry (when live) / pivot_definitions / law_jurisdiction classification pivot governance.handoff.axis_introduced
8 policy changed normative_registry / law_jurisdiction / measurement_registry governance.handoff.policy_changed scope (rule scope) → bumps ruleset_version (doc 31 §5)
9 owner / approval / exception changed governance_object_ownership (SB-2, when live) / approval_requests / exception register governance.handoff.authority_changed owner scope + scope
10 ruleset changed governance_ruleset registry row (proposed) / enabled measurement_registry set governance.handoff.ruleset_changed ALL groups in the changed rule's scope

No-hardcode: the kinds are config conventions tied to the registered event taxonomy, not code literals; the tail source for each is resolved from the registry, and the group_key dimensions are computed (doc 34 §group_key), not embedded.


4. Birth is NOT modified — proof (mission §5 hard constraint)

The mission forbids modifying Birth "unless proven unavoidable." It is avoidable. Three options were evaluated; the default touches Birth zero ways:

Option Touches Birth? Latency Verdict
(A) Cursor-tail / CDC (DEFAULT) No — the intake worker polls birth_registry and registry_changelog by (born_at,id) / (timestamp,id) high-water mark, exactly as iu_outbound_default already tails IU events seconds–minutes (poll interval) RECOMMENDED. Zero Birth change, zero trigger, fully reuse iu_route_worker_cursor. Birth keeps its single responsibility (existence/ID/registry visibility).
(B) Additive observer trigger on birth_registry/registries that writes a capture row to event_pending Adds a trigger to a Birth table near-real-time Optional latency optimization only. It is additive and fail-open — it can never alter or block a birth row (an AFTER INSERT that only writes a capture row); if it errors it must not fail the birth. Even so it is a new trigger ⇒ build NO-GO and a council/decision point (does an observer-only, fail-open trigger count as "modifying Birth"? Recommended ruling: NO — it observes, never gates — but it is deferred to C-7).
(C) Modify the Birth gate to call governance inline Yes inline REJECTED. Couples Birth to governance, violates "keep Birth stable," and makes a governance fault a birth fault. Forbidden.

Default = Option A. Because births are append-only and ordered by (born_at, id), a cursor tail is lossless: every new birth has born_at ≥ cursor.last_created_at and is captured on the next poll. The same holds for registry_changelog (timestamp monotone). Birth remains responsible for existence/ID/registry visibility; governance processing begins after birth/registry visibility (GPT principle), reading the same durable ledgers the birth process already writes.


5. The intake worker (reuse iu_route_worker_cursor)

gov_worker_cursor  (proposed; reuses iu_route_worker_cursor columns 1:1)
  worker_name      = 'gov_handoff_intake'
  event_domain     = 'governance'
  last_created_at  = max processed (born_at | changelog.timestamp) low-water mark per tailed source
  last_event_id    = tie-breaker id per source        (one cursor row per tailed source, or composite in metadata)
  events_seen, attempts_written, dead_lettered (bigint)
  last_run_at, last_run_summary(jsonb), metadata(jsonb = { sources, poll_interval, coalesce_window })

Per-poll algorithm (read-only design):

  1. For each tail source, read rows WHERE (order_key) > (:low_water) ORDER BY order_key LIMIT :batch (keyset; no OFFSET; under the 5 s read timeout).
  2. Map each row → (change_kind, group_key, object_ref, canonical_address) (§3).
  3. Coalesce within the poll window: many changes to the same group_key collapse to one dirty-mark (anti-storm; reuse the T7 coalesce_key discipline).
  4. Enqueue the dirty-mark by upserting the candidate-state row's dirty=true, dirty_reason, dirtied_at (doc 34) — this is the handoff; the signal carries address-only.
  5. Emit a governance.handoff.<kind> signal to event_outbox (Đ45) iff the type is registered+active; otherwise capture to event_pending (register-before-emit) and raise handoff_unregistered_type once.
  6. Advance the cursor only after the dirty-marks are durable (happens-after) → resumable, no loss.
  7. Emit governance.handoff.heartbeat with {seen, coalesced, enqueued, dlq}.

6. Replay, idempotency, ordering, retry, DLQ, coalesce (mission §5 musts)

  • Durable storage — the truth already lives in birth_registry / registry_changelog (append-only) and event_pending/event_outbox; the cursor is the only added state. Nothing is held in memory or prompt.
  • Replay — reset the cursor's last_created_at/last_event_id to any past watermark and re-tail; because dirty-marks are idempotent upserts (§idempotency) and signals are keyed, replay is safe and produces no duplicate work.
  • Idempotency — a handoff is keyed by (source, order_key) for consume-once, and the resulting dirty-mark is keyed by group_key (upsert) — re-delivering the same change re-sets the same dirty flag (no-op) rather than enqueuing twice. Downstream system_issues dedup via coalesce_key/occurrence_count (T7).
  • Ordering where needed — within a group_key, the latest occurred_at wins (last-writer dirty state); cross-group ordering is irrelevant (groups are independent). Causal ordering (born → registered → owner-assigned) is preserved by occurred_at on the tailed rows.
  • Retry — transient consume errors increment event_pending.error_count / last_error and retry with backoff.
  • DLQ — after N attempts, dead-letter (dead_lettered counter; event_pending flagged) and raise handoff_dlq; intake continues. A growing DLQ raises severity.
  • Coalesce — §5 step 3; plus a digest for high-churn groups (Đ45 + T7 §6).
  • No lost handoff — the lossless cursor tail (§4) + register-before-emit capture (event_pending) + DLQ-instead-of-drop together guarantee a change is never silently lost; the worst case is delayed (in DLQ) and visible (a finding), never missing.

7. Provenance & source trust (handoff side of Branch C)

Each handoff carries provenance the input-quality gate (doc 33) consumes:

  • source = the tail source (birth_registry / registry_changelog / approval_requests / Axis Registry / governance_ruleset).
  • source_system + actor_ref (reuse event_outbox/birth_registry columns) = who/what produced the change.
  • payload_classification='safe_metadata' enforced (Đ45) — a handoff that tries to carry object contents is rejected and raises an input-quality finding (doc 33), never enqueued.
  • A handoff from an untrusted/unknown source is captured but flagged untrusted_source (doc 33) and not promoted to a candidate-relevant verdict until trust is established — it cannot silently inject governance work.

8. Handoff issue types (proposed, register-before-emit — NOT registered)

issue_type bucket severity detection event route
handoff_lag sai_lệch_dữ_liệu medium→high governance.handoff.lag GOV-SIV (cursor behind by > threshold)
handoff_dlq silent_fail high governance.handoff.dlq GOV-SIV
handoff_silent_gap silent_fail high→critical governance.handoff.silent_gap GOV-SIV (missed heartbeat)
handoff_unregistered_type thiếu_quan_hệ low→medium governance.handoff.unregistered_type GOV-SIV (register-before-emit: type not yet in registry)

These ride system_issues + the governance event domain; anti-spam reused from T7.


9. Relation to backfill (doc 31) and candidate scan (doc 34)

  • Backfill seeds; handoff sustains. The backfill (doc 31) is the one-time sweep that creates the initial candidate-state rows for the 1.04M backlog; the handoff intake keeps that store current by dirtying groups as births/changes arrive. Together they guarantee complete then continuously-correct coverage with no perpetual full scan.
  • Boundary handshake. New births that arrive during the backfill sweep are caught by whichever runs first (the sweep's keyset will reach them, or the handoff tail will dirty them); the idempotent candidate key (doc 31 §6) makes the overlap harmless.
  • The handoff is the dirty-source for Branch D. Every consumed handoff = a dirty-mark; Branch D (doc 34) decides re-evaluation from the dirty + stale set.

10. Future option (recorded, not built): a dedicated governance handoff ledger

If the handoff signal taxonomy outgrows event_pending + the tailed ledgers (e.g. needs per-signal SLA, multi-consumer fan-out with independent cursors, or a signal shape the existing columns cannot carry), a dedicated additive governance_handoff_ledger (modeled on event_pending + event_outbox, Đ45-shaped) may be designed in a later macro. Not now — reuse-first; minting it now is an unjustified second roof. This is flagged as part of new blocker SB-11 (doc 35 §2).


11. Dependencies, gates, NO-GO

Capability Needs Status
Cursor-tail design (read-only) nothing live designable now
Register governance event domain + handoff types T7 build + register-before-emit (Đ45) + GOV-SIV ownership ruled (SB-11/SB-4) NO-GO
Run the intake worker / emit signals governance domain active + worker cursor family (SB-13) NO-GO
Capture to event_pending under governance domain event types defined (no registration to capture-stage, but worker build) NO-GO (design only)
Observer trigger on Birth (Option B) C-7 ruling + build authorization NO-GO (default is Option A, no trigger)
Dirty-mark target (candidate-state store) SB-10 (doc 34) NO-GO

No gate may be satisfied by self-approval.


12. Verdict

Branch B handoff-ledger design: COMPLETE. A durable, replayable, idempotent, auditable, no-lost-handoff path from Birth/Registry into the governance candidate layer is specified, fully Điều 45-compliant (signal-not-data, event≠job, executor boundary, MOT-not-executor, silent-gap/heartbeat). Birth is not modified — the default (Option A) is a lossless cursor-tail over the already-durable birth_registry/registry_changelog, reusing the live iu_route_worker_cursor precedent; capture/retry/DLQ reuse event_pending; emission reuses event_outbox. The reuse-vs-new decision is hybrid, reuse-first — no new ledger now, a dedicated ledger flagged as a future option only. All ten handoff kinds, provenance/trust, and the four handoff issue types are specified. Nothing registered, emitted, or mutated; no trigger created. Next: doc 33 (input-quality gate that validates each handoff/candidate before classification).

Back to Knowledge Hub knowledge/dev/reports/architecture/one-roof-governance-technical-addendum-and-implementation-index-2026-06-01/32-birth-registry-to-governance-handoff-ledger-design.md