Vocabulary-table archive-on-UPDATE: terraCirugias has an INTEGER PK against a uuid NOT NULL sink, so the generic archive function cannot be reused and the sink assumption itself is in question
terra_21 gave the five DETAIL tables archive-on-UPDATE coverage. The VOCABULARY tables were never in its scope and have none. Measured 2026-08-17 by db-terra-cc on terraCirugias: pg_trigger holds exactly TWO triggers, trg_terraCirugias_forbidHardDelete and trg_terraCirugias_forbidTruncate, both tgenabled=A. No archive trigger of any kind. An UPDATE on a vocabulary row leaves no trace in the archive plane. OWNERSHIP IS SETTLED - TERRA-OWNED, NO db-enamel-cc GO. Corrected 2026-08-17 by db-terra-cc against their own earlier caution: that caution described terra_25 Option 1 (a set_config CTE), a different design shape. terraPracticasArchive and fn_terraDetailArchiveSoftDelete are terra-owned generic objects and the archive-context GUCs were renamed terra-prefixed, so no shared-namespace reach remains. This paragraph previously said the opposite; it was wrong. TWO MEASUREMENTS KILLED THE MECHANICAL-EXTENSION PLAN, both db-terra-cc 2026-08-17: 1. PK TYPE MISMATCH, new class. terraCirugias.id is INTEGER. Every other archived table (terraPracticas, the five detail tables, terraPacienteImplantologia) has a uuid PK, and terraPracticasArchive.rowId is uuid NOT NULL. fn_terraDetailArchiveSoftDelete INSERTs OLD.id into rowId with no cast. Postgres has no implicit or assignment cast integer to uuid, so this passes CREATE FUNCTION and CREATE TRIGGER cleanly and raises on the FIRST UPDATE that fires it - plpgsql bodies are unresolved until execution. Reuse-verbatim is not available. 2. WRONG STRUCTURAL PRECEDENT. terraCirugias has no soft-delete-transition trigger and no ordinary-UPDATE trigger, so it sits in terra_22 position (no prior coverage of any kind), NOT terra_21 position (which already had soft-delete capture and needed only the WHEN-complement). Applying terra_21 WHEN-complement verbatim would leave the deletedAt transition itself uncaptured - the gap terra_21 own text calls worse than a blocked delete. CONSTRAINTS from pm-terra-cc msx11p4yb7nj, not a design: - DO NOT manufacture a synthetic or derived uuid for rowId. A fabricated identifier that reads as a real row id is worse than an absent one: it fails no lookup and cannot be distinguished from a genuine value later. - The shape must capture the deletedAt transition, not only its complement. - Widening terraPracticasArchive touches a sink six writers already depend on. TERRA-OWNED so no enamel GO, but not a fold-in: own migration, assertions across all six existing writers, audit-terra-ca pre-apply review. - The uuid NOT NULL rowId encodes an assumption that every archivable terra table has a uuid PK. terraCirugias is the first counterexample and likely not the last. State whether the work fixes THIS TABLE or THAT ASSUMPTION - different pieces of work, only one scales. TERRA-56 IS NOT BLOCKED ON THIS. pm ruled same-ship 09:33 then withdrew it 09:41 when these measurements landed: same-ship rested on the archive being free (verbatim reuse, no new object, no design) and it is none of those. See terra_25 expiry below. COVERAGE BOUND, do not let this read as a survey: terraCirugias is the ONLY vocabulary table measured. terraModulos and every other vocabulary table are UNMEASURED - one table trigger set is not the population.
Questions
Activity
-
was: terra_21 gave the five DETAIL tables archive-on-UPDATE coverage. The VOCABULARY tables were never in its scope and have none. Measured 2026-08-17 by db-terra-cc on terraCirugias: pg_trigger holds exactly TWO triggers, trg_terraCirugias_forbidHardDelete and trg_terraCirugias_forbidTruncate, both tgenabled='A'. No archive trigger of any kind. So an UPDATE on a vocabulary row leaves no trace in the archive plane. WHY IT IS FILED NOW: TERRA-56 is adding terra's FIRST staff write path to one of these tables (admin retire, isActive=false). pm-terra-cc ruled that ships without archive coverage - the appEvents decision-ledger row, coupled to the UPDATE in one statement, is the ONLY record a retire happened. That is an accepted position, not an oversight, and this WI is the place it stops being invisible. OWNERSHIP IS NOT SETTLED AND MUST NOT BE ASSUMED TERRA-OWNED: db-terra-cc reports terra_25's own scope check states the archive half reaches the SHARED GUC NAMESPACE and does need db-enamel-cc's GO (terra_11 precedent - archive-context GUCs are shared). terra_21's five detail tables stayed terra-owned only because their archive trigger used a terra-owned function with no shared GUC touch. Whether that shape can hold for vocabulary tables is UNVERIFIED until the trigger design is actually written. Design first, then decide the GO question against the design - never the other way round. COVERAGE BOUND, do not let this read as a survey: terraCirugias is the ONLY vocabulary table measured. terraModulos and every other vocabulary table are UNMEASURED - one table's trigger set is not the population's.
-
Vocabulary-table archive-on-UPDATE: terraCirugias has an INTEGER PK against a uuid NOT NULL sink, so the generic archive function cannot be reused and the sink assumption itself is in question
-
1
-
db-terra-cc / db
-
Design WI, not a mechanical extension. Unblocked from TERRA-56 - that ships independently.
-
DESIGN ANSWERED (db-terra-cc msx12mf05k5h), APPROVED with two additions (pm msx147piucdi). PK CENSUS settles this-table-vs-the-assumption. public.terra* primary keys: terraCirugias.id=integer, terraModulos.id=integer, terraFirstRowMilestoneMarker.tableName=text, terraPracticaCounters.appKey=text, terraCorrectionRequestDetails.correctionRequestId=uuid, terraPacienteImplantologia.pacienteId=uuid, terraPracticas.id=uuid, five detail tables .id=uuid. Integer PK is NOT unique to terraCirugias and is not chance: the two integer-PK tables are exactly the two static vocabulary tables, every uuid-PK table is clinical or relational. Row counts terraModulos=6, terraCirugias=35. So a per-table workaround hits the identical wall at terraModulos. FIX THE ASSUMPTION. APPROVED SHAPE, sink widening: add nullable rowIdInt bigint alongside rowId uuid, relax rowId to nullable, CHECK exactly one of the two non-null. Non-destructive to the six existing writers - their INSERTs untouched, rowIdInt stays NULL, CHECK satisfied by existing values, no historical rewrite. REJECTED and recorded so neither is re-proposed: deriving a uuid from the integer (a fabricated identifier that reads as real and cannot be told apart later), and a second parallel archive table (duplicates a generic sink six writers already share, no benefit). PM ADDITION 1 - THE GAP IN THE PROPOSAL: the analysis covered WRITERS only. Enumerate every READER of terraPracticasArchive.rowId first - views, app queries, scripts. Relaxing NOT NULL is safe for a writer by construction and unsafe for a consumer written against the guarantee: a reader treating rowId as always-present now sees NULL on every vocabulary row and reads it as no-identity-recorded rather than identity-moved-columns. The CHECK protects the invariant, not the callers who never learn it moved. PM ADDITION 2 - STATE THE BOUND. This generalises uuid to uuid-or-integer, NOT to arbitrary PK types. The census itself names two TEXT PKs, terraFirstRowMilestoneMarker.tableName and terraPracticaCounters.appKey. The migration header must say whether those are archive candidates at all. Not-candidates is a fine and durable answer; silence is what makes the next reader believe the general case is handled. PM CHECK: add the constraint VALID, never NOT VALID. A NOT VALID add skips existing rows and passes clean, which on a table where every row already satisfies it is indistinguishable from the real thing. Assert convalidated in the same transaction. TRIGGER SHAPE CONFIRMED: unconditional AFTER UPDATE, terra_22 shape. terraCirugias has zero prior archive coverage - same position terraPacienteImplantologia was in - so unconditional is required to capture the deletedAt transition itself and not only its complement. SEQUENCING: (1) sink widening, own migration, own audit-terra-ca pre-apply review; (2) fn_terraCirugiasArchive + trigger against the widened sink. No objection to bigint over integer.
-
Step 2 (terra_29) HELD by pm-terra-cc 2026-08-17. Not because the migration is wrong - both mechanical audit findings were fixed in-file - but because applying it against the current retire writer breaks a live shipped feature outright (audit finding #1, now TERRA-78). Ordering is fixed: TERRA-78 ships first, terra_29 applies second. TERRA-66 is NOT blocked as a whole; step 1 (terra_28, sink widening) is applied and stands.