04 — +60 Birth Cascade Characterization (P-1 CLOSED)
04 — Branch D: Birth Cascade Characterization (P-1 CLOSED)
The prior campaign observed "+52" but did not decompose it. Measured precisely this campaign in BEGIN..ROLLBACK (birth_registry grouped by collection_name, before vs after): the deterministic cascade for the production 3-registry birth (with per-registry birth triggers) is +60 birth_registry rows.
Cascade map — measured delta by collection_name (3 registries)
| collection_name | total Δ | per registry | mechanism |
|---|---|---|---|
meta_catalog |
+3 | 1 | direct INSERT → fn_birth_registry_auto |
entity_species |
+3 | 1 | direct INSERT → birth |
species_collection_map |
+3 | 1 | direct INSERT → birth (synthetic entity_code species_collection_map::<id>) |
collection_registry |
+3 | 1 | direct INSERT → birth |
measurement_registry |
+3 | 1 | auto via fn_auto_create_measurement (fires: identity_class='managed' + registry_collection set + table exists) → that row is itself born |
entity_labels |
+42 | 14 | auto via fn_auto_label_assignment + fn_auto_label_provenance (AFTER INSERT on meta_catalog & collection_registry); each label row is born |
system_issues |
+3 | 1 | a DDL-detection event trigger logs each CREATE TRIGGER trg_birth_<reg> as a system_issue, which is itself born |
| TOTAL | +60 | 20 |
So 20 birth rows per registry × 3 = 60. entity_labels (the auto-label machinery) is the bulk (70%) and is exactly what the "+52" estimate had not pinned down.
Why +60 and not +52
The figure depends on two activation choices:
- WITH per-registry birth triggers (recommended, production-correct so future registry rows are counted) → the 3
CREATE TRIGGERs trip the DDL-detection event trigger →system_issues +3. Total +60. - WITHOUT per-registry birth triggers → no DDL logs → +57.
- The prior "+52" was a leaner/earlier path (no birth triggers + slightly fewer auto-labels for the stub column shapes). The number is now deterministic and reproducible for whichever path is chosen; the activation pack (doc 06) uses the +60 path and asserts that exact delta.
Physical-row footprint (snapshot delta, in-tx)
| Table | Δ | birth-tracked? |
|---|---|---|
| meta_catalog | +3 | yes |
| collection_registry | +3 | yes |
| entity_species | +3 | yes |
| species_collection_map | +3 | yes |
| measurement_registry | +3 | yes |
| v_registry_counts | +3 | no (no birth trigger on v_registry_counts) |
| entity_labels | +42 | yes |
| system_issues | +3 | yes |
| birth_registry | +60 | (the audit ledger itself) |
| governance_registry | 0 | (tier-ownership is an UPDATE, no new row) |
Note v_registry_counts +3 produces no birth row (consistent: it is absent from the birth-delta table), confirming fn_birth_registry_auto is not attached to it.
Determinism
fn_birth_registry_autois idempotent: EXISTS-guard on(entity_code, collection_name)+ON CONFLICT (entity_code) DO NOTHING. The duplicate birth triggers on meta_catalog/collection_registry/entity_species (birth_trigger_*+trg_birth_*) therefore do not double-count. Verified by the exact +1-per-table figures.- The cascade is fully a function of: identity_class='managed', registry_collection set (drives measurement), governance_role='governed' (drives auto-labels), and the presence of the per-registry birth trigger (drives the system_issues DDL log). All are fixed by the activation script → fully deterministic.
Rollback map
A. In-transaction (rehearsal): ROLLBACK → byte-identical. All 60 birth rows, 42 entity_labels, 3 system_issues, 3 measurement, 3 v_registry_counts and the 3 tables vanish. Zero risk. (Proven, doc 05.)
B. Committed → SOFT RETIRE (recommended reversal, Điều 30/31):
UPDATE collection_registry SET status='retired' WHERE code IN ('FIELD-001','FORM-001','TIER-001');
UPDATE entity_species SET status='retired' WHERE code IN ('SPC-FIELD-001','SPC-FORM-001','SPC-TIER-001');
UPDATE measurement_registry SET enabled=false WHERE measurement_id LIKE 'MSR-AUTO-CAT_101%';
UPDATE birth_registry SET status='retired' WHERE collection_name IN ('field_registry','input_form_registry','tier_registry'); -- registry-row births
-- tier ownership revert:
UPDATE governance_registry SET capability=NULL, output_target=NULL, primary_collection=NULL WHERE code='GOV-COUNCIL';
Tables and registration rows are preserved but inert. Lawful, low-risk, no guard fights.
C. Committed → HARD ROLLBACK (heavier; human-only):
DROP TABLE IF EXISTS public.field_registry, public.input_form_registry, public.tier_registry; -- drops their birth triggers too
-- meta_catalog deletes are GUARDED → must bypass:
SET LOCAL app.allow_meta_update='true';
DELETE FROM meta_catalog WHERE code IN ('CAT-1011','CAT-1012','CAT-1013'); -- fires fn_auto_cleanup_on_meta_delete (removes v_registry_counts rows, drops count triggers, refreshes CAT-ALL)
DELETE FROM collection_registry WHERE code IN ('FIELD-001','FORM-001','TIER-001');
DELETE FROM entity_species WHERE code IN ('SPC-FIELD-001','SPC-FORM-001','SPC-TIER-001');
DELETE FROM species_collection_map WHERE collection_name IN ('field_registry','input_form_registry','tier_registry');
DELETE FROM measurement_registry WHERE measurement_id IN ('MSR-AUTO-CAT_1011','MSR-AUTO-CAT_1012','MSR-AUTO-CAT_1013');
DELETE FROM birth_registry WHERE collection_name IN ('field_registry','input_form_registry','tier_registry')
OR entity_code IN ('CAT-1011','CAT-1012','CAT-1013','FIELD-001','FORM-001','TIER-001','SPC-FIELD-001','SPC-FORM-001','SPC-TIER-001');
DELETE FROM entity_labels WHERE <labels created for the above CAT/COL codes>; -- scope by entity ref captured at commit
DELETE FROM system_issues WHERE <the 3 CREATE TRIGGER DDL logs>;
UPDATE governance_registry SET capability=NULL, output_target=NULL, primary_collection=NULL WHERE code='GOV-COUNCIL';
Use a born_at window captured at commit to scope the entity_labels/system_issues/birth_registry deletes precisely.
Irreversible-risk map
| Element | Reversible? | Risk |
|---|---|---|
| 3 CREATE TABLE | Yes (DROP) | none |
| 60 birth_registry rows | Yes (retire or scoped DELETE) | low |
| 42 entity_labels | Yes (scoped DELETE) | low — must scope by entity ref/born_at window |
| 3 measurement_registry | Yes (disable or DELETE) | low |
| 3 v_registry_counts | Auto-removed by meta_catalog DELETE cleanup, or DELETE | low |
| 3 meta_catalog rows | Yes, but DELETE-guarded → needs app.allow_meta_update='true'; DELETE triggers auto-cleanup side effects |
moderate (guard + cascade) |
| GOV-COUNCIL ownership write | Yes (set fields NULL) | low |
| Pre-existing rows | untouched | none — no data loss |
No truly irreversible step exists (no enum drop, no destructive ALTER of existing tables, no loss of pre-existing data). The single elevated-caution item is the guarded meta_catalog DELETE — fully characterized and bypassable. Soft retire (path B) is strongly preferred over hard rollback.
Human activation warning
A committed birth writes to 9 tables (60 birth rows + 42 entity_labels + 3 system_issues + the core rows). This is the normal, lawful industrial-birth cascade — but it means a committed activation is not undone by a one-line DELETE. The human must accept the soft-retire reversal model (path B) as the default rollback, with hard-rollback (path C) reserved for emergencies and run under the same server-side-timeout discipline.