Pre-Birth Admission Control — 06 Governance Second-Birth Handoff Design
06 — Governance "Second Birth" / Handoff Design
Goal: define how a finalized birth enters governance without coupling governance into the birth transaction. Reuse-first (0 new tables, per live SB-11). Design only; OSPA=0 ⇒ no activation.
0. Decoupling principle (Điều 45)
- Governance fault must NOT make birth fault unless policy explicitly says so. The handoff is post-commit and asynchronous.
- The 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. - Register-before-emit: a signal whose
event_typeis notactive=trueinevent_type_registryis captured toevent_pending, never emitted. - Executor boundary: GOV-SIV only detects/emits/proposes; any remediation is a governed DOT under an Điều 32 APR; a Mother (MOT/MOUT) is never the executor.
1. What governance reads (intake source) — LIVE-verified
Recommended: Option A — cursor-tail / CDC over durable append-only ledgers (matches doc 32 design and live state):
| source | live count | role |
|---|---|---|
birth_registry (born_at, id) keyset |
1,121,537 | the BORN tail — every finalized birth appears here |
registry_changelog (timestamp, id) |
70,313 | registry-level change tail (already populated) |
event_outbox |
181,712 | lifecycle bus (emit destination, not primary intake) |
event_pending |
0 | capture/retry/DLQ for unregistered/failed emits |
The handoff worker gov_handoff_intake (a gov_worker_cursor row reusing the iu_route_worker_cursor column shape — the proven precedent) tails birth_registry by (born_at, id) high-water mark. It does not read the permit table — the permit is birth-side; governance only cares about born objects. (A FINALIZED permit always implies a BORN row, so the BORN tail is sufficient and avoids permit/governance coupling.)
Why not Option B (observer trigger on birth_registry) or Option C (inline call in the birth gate)? Per doc 32: Option C is REJECTED (couples governance into the birth tx — violates the decoupling principle). Option B (additive fail-open observer trigger) is deferred to council item C-7. Cursor-tail is lossless, resumable, and adds zero load to the birth transaction.
2. Handoff per finalized birth
finalized birth (BORN row) → cursor tail picks it up
→ map to {object_type, object_ref, canonical_address, group_key, change_kind=object_born}
→ upsert governance_candidate_state (dirty=true) ← THIS is the handoff
→ emit-or-capture 'handoff.object_born'
· event_type active=true → event_outbox
· event_type active=false → event_pending (captured, retried later) ← TODAY's state
→ advance cursor AFTER the candidate-state upsert is durable (lossless)
handoff.object_bornis already registered (active=false) live → today every handoff would be captured toevent_pending, never lost, and flipped to emitting when OSPA opens the gate. This is register-before-emit working as designed.- Anti-rescan (doc 31 §4.3): candidate-state keyed by
(candidate_key, source_snapshot_ref, ruleset_version)— once written, not re-evaluated until dirty / ruleset bump / TTL.
3. Handoff states
| state | meaning | what it gates |
|---|---|---|
GOVERNANCE_PENDING |
born, handoff captured, not yet evaluated | nothing (birth stands) |
GOVERNANCE_CANDIDATE_CREATED |
candidate-state row written, ruleset to run | nothing |
GOVERNANCE_OWNER_GAP |
governed object with no owner (the live v_object_owner_gap=210 condition) |
production USE/ACTIVATION where policy requires an owner |
GOVERNANCE_COVERED |
owned + within an approved responsibility scope | unblocks governed use |
GOVERNANCE_BLOCKED |
policy violation / untrusted input / unregistered type | activation; raises finding |
4. What blocks what (the boundary)
| stage | blocked by governance? |
|---|---|
| object CREATION | NO — never (decoupling; birth must not depend on governance) |
| birth FINALIZE | NO — the permit/constraint is birth-side only |
| DOT EXECUTION | only via the existing fn_assert_safe_for_dot_action preflight (unchanged) |
| RP cleanup | only via the existing preflight (4 BLOCK dims) |
| production ACTIVATION / USE of a governed object | YES, where policy requires — a GOVERNANCE_OWNER_GAP/BLOCKED object may be created and born, but not activated for governed use until covered. This is the only place governance gates, and only for governed-role objects. |
This keeps birth-first and governance-coverage as two independent gates: "no permit → no birth" (birth-side, enforceable now for a clean family) and "no coverage → no governed activation" (governance-side, gated by OSPA). Neither blocks the other's creation step.
5. Heartbeat / silent-gap
- The worker ticks
queue_heartbeat(live, 3 rows) each poll and emits*.heartbeat/*_scan_completed; a missed tick →handoff_silent_gapfinding. A quiet system (no births) is distinguishable from a dead intake. Findings:handoff_lag,handoff_dlq,handoff_silent_gap,handoff_unregistered_type(doc 32 §8).
6. OSPA / human-approval boundary
- OSPA = 0 live ⇒ governance rollout NO-GO. No gate may be satisfied by self-approval. The handoff worker may be authored and the candidate-state upsert rehearsed (BEGIN..ROLLBACK), but the emit-flip (
active=true) and the live worker start require OSPA ≥ 1 (governance_build_authorization≥ 1) — a human act. - Until then: the handoff is design + register-only (the 5 governance event types already staged
active=false). The birth-side pilot (dot_toolspermit-first) does not depend on OSPA and can proceed independently; the handoff simply captures its births toevent_pendingand replays them when governance opens.
7. Net build for the handoff (reuse-first, live-confirmed)
0 new tables. Required: 1 gov_worker_cursor row (gov_handoff_intake), seed governance_ruleset (≥1), flip the 5 governance event types active=true (gated), start the worker via an external scheduler (pg_cron absent live), and OSPA≥1. Everything else (event_pending, governance_candidate_state, registry_changelog tail, queue_heartbeat) already exists and is live.