basquetWi + New ticket
terra TERRA-131

Pieza-or-region DB invariant is live; behavior exercise and source provenance need reconciliation

Done normal dtdb02-terra-ca

DB-side status corrected 2026-09-10. Live catalog contains all three ENABLE ALWAYS deferred requireZona constraint triggers on terraPracticas, terraPracticasPiezasDentarias, and terraPracticasRegionesAnatomicas. The title claim that the invariant exists zero times in the DB, and the blocker saying terra_50 awaits apply, are stale.\n\nSource boundary: terra_50 remains under db/migrations/draft/ while untracked apply/provenance artifacts conflict with that location. Live catalog proves the objects exist; it does not itself exercise valid/invalid write behavior or establish tracked registration.\n\nNext: reconcile source/provenance and record independent behavioral exercise; do not re-apply.

Sub-tickets

No sub-tickets.
+ Add sub-ticket

Activity

  • wi-cli-venus created · 6w ago
  • wi-cli-venus verified · 6w ago
    THE STATE THE MISSING GUARD PERMITS ALREADY EXISTS IN THE DATA. db02-terra-cc, over all 5 live practicas, joining terraPracticas to terraPracticasPiezasDentarias and terraPracticasRegionesAnatomicas by EXISTS with deletedAt IS NULL on both children: 4 have a pieza dentaria, 2 have a region anatomica, and ONE HAS BOTH - practicaId bafe7b34-800c-4268-b90b-823b124b3684. All 5 carry at least one; none has neither. WHY THAT MATTERS MORE THAN THE COUNT SUGGESTS. This WI was filed on a source reading - createPractica does manual INSERTs and never calls createTerraPractica, which is where the cardinality check lives - and a source reading establishes only that the guard is ABSENT, never that the absence produced anything. It produced something. One practica in five, at N=5, with no DB layer able to refuse it. WHAT IS NOT YET ESTABLISHED, and I am not closing the gap by assumption: whether pieza AND region together is actually invalid. createTerraPractica's cardinality check is the only artifact in the system that asserts a rule, and NOTHING ON THE LIVE PATH CONSULTS IT - which is the decoy half of this WI. So the rule exists as code that nobody runs, and the data disagrees with it. Two readings survive: the rule is right and one practica is malformed, or the rule is wrong and the decoy has been asserting a constraint the catedra never had. Both are defects and they need opposite fixes. ESTABLISH WHICH BEFORE WRITING SQL - a DB constraint added on the wrong reading would refuse legitimate clinical records, which is worse than the current absence. RAISED TO PRIORITY 2 from 3: filed as a latent gap, now a measured occurrence. LANE NOTE: coder-terra-ca said it is taking this as a DB-layer fix. The constraint belongs to db-terra-ca to draft as a migration; coder specifies WHAT must hold and supplies the path-versus-decoy evidence. Do not let the migration be written by the lane that cannot apply it.
  • wi-cli-venus priorityChanged · 6w ago
    2
  • wi-cli-venus note · 6w ago
    CORRECTION TO MY OWN PREVIOUS EVENT, and it changes what this WI is asking for. I wrote that two readings survive - that pieza AND region together might be invalid, and that the decoy and the data disagree. THAT WAS WRONG AND IT WAS ANSWERABLE FROM THE SOURCE I ALREADY HAD. THE DECOY ASSERTS AT-LEAST-ONE, NOT EXCLUSIVITY. terra_6_boundary_functions.sql:319-320: `IF cardinality(piezasArg) = 0 AND cardinality(regionesArg) = 0 THEN RAISE 'at least one pieza or region is required'`. It is an AND over two zero-tests. Nothing in it forbids both being non-empty. AND THE APP DESIGN EXPLICITLY SUPPORTS BOTH. practica-zona-core.ts (TERRA-91) derives which axis renders from the cirugia's requierePieza/requiereRegion flags, and states that NULL is not false - every one of terra's 35 cirugias is NULL today, and a NULL row renders BOTH axes under the flat at-least-one rule. A three-option piezas/region/ambas selector was designed and rejected by all three fleet coders, so "ambas" is a supported clinical state that the catalog decides, not a mode the user picks. SO THE PRACTICA CARRYING BOTH IS NOT MALFORMED, and there is no disagreement between the rule and the data. I manufactured an open question by not reading the check I was describing, then recorded it as a reason to hold work. That is the more expensive kind of error here: it does not produce a wrong fix, it produces a stall. WHAT REMAINS TRUE AND IS STILL THE WHOLE WI: at-least-one is enforced NOWHERE on the live path. createTerraPractica holds the only assertion and createPractica does manual INSERTs without calling it. The decoy is real; my reading of what it asserts was not. DRAFT EXISTS: db/migrations/draft/terra_50_practica_zona_required.sql (coder-terra-ca, 1739d07, NOT applied). It requires at least one live pieza OR region via a DEFERRABLE INITIALLY DEFERRED constraint trigger on the parent and both child tables, so it evaluates the final transaction state rather than the transient parent-before-children moment, and it covers both writers rather than the one that exists today. That matches the boundary function's rule exactly. db02's census says all 5 practicas already satisfy it, so the preflight should report zero violations - which is a real check here rather than a vacuous one, because the constraint could have been written as exclusivity and would then have found one.
  • wi-cli-venus verified · 6w ago
    THE SOFT-DELETE CASE IS UNVERIFIED, NOT VERIFIED-ZERO, and db02-terra-cc said so rather than reporting the clean number it found. Asked whether any practica holds children that all exist but are all soft-deleted - a row that satisfies no live-child rule and would be refused the moment anything touched it - the answer is 0 of 5. It is an UNCONTROLLED zero: no row in terraPracticasPiezasDentarias or terraPracticasRegionesAnatomicas has deletedAt set ANYWHERE in the live data, not merely none in this population. piezaTotal equals piezaLive and regionTotal equals regionLive for all 5. WHY THAT MATTERS FOR terra_50 SPECIFICALLY. The proposed constraint is "at least one LIVE pieza or region", and live means deletedAt IS NULL. Every fact we hold about whether that constraint is satisfiable comes from data in which soft-deletion HAS NEVER HAPPENED. So the measurement cannot distinguish "the rule holds under deletion" from "deletion has never been exercised". The preflight will report zero violations and that report carries no information about the case the constraint is most likely to break on. THE ORDERING CASE IS THE SAME SHAPE AND IS THE ONE TO TEST: a practica whose last live child is soft-deleted LATER IN THE SAME TRANSACTION. A DEFERRABLE INITIALLY DEFERRED trigger evaluates at COMMIT, which is exactly why that shape was chosen, so it should refuse - but nothing in the live data has ever produced it and no arm asserts it. audit-terra-ca has independently named the same requirement for its eventual gate: parent/child insert order plus later same-transaction child soft-delete. SO THE APPLY IS NOT GATED ON A CENSUS. Counting rows cannot answer this; only a behavioural arm can. Whoever drafts the migration must ship that arm with it, and a preflight reporting zero violating practicas must NOT be presented as evidence the constraint is safe.
  • wi-cli-venus statusChanged · 6w ago
    Write-path census completed before implementation; only createPractica reaches the current application insert.
  • wi-cli-venus note · 6w ago
    CENSUS CONFIRMS THE DECOY. coder-terra-ca measured application source: exactly one practica writer, createPractica at practica-actions.ts:401, manual INSERT into terraPracticas, reached only through the /practicas/nueva flow, no API route and no other caller. createTerraPractica has ZERO invocation sites in application source - every reference to it is a definition, a history entry, schema documentation or a comment. So the cardinality check lives inside a function nothing calls, on a path nothing takes, while the live write goes around it. THIS IS WORSE THAN AN ABSENT CHECK AND THAT IS THE POINT OF THE ROW. An absent check gets noticed by whoever goes looking for it. A check that exists, is named correctly, and sits in the schema documentation reads as coverage to every reader who does not also run a call-site census - and nobody runs one, because the function being there is the answer to the question they were asking. DECISION, three parts, and I am taking it rather than routing it to Elazar. ONE, THE INVARIANT GOES IN THE DATABASE, on terraPracticas, covering every writer including ones that do not exist yet. That is the only placement where the decoy stops mattering, and it is the same reasoning terra_53 rests on for participantes. db-terra-ca owns the draft, AFTER terra_53 is applied - I am not running two membership-shaped drafts through the same lane at once. Measure the current population first and report it even if nothing violates the rule, and state explicitly what happens to any existing row that would fail. TWO, THE APP CHECK SHIPS FIRST AND IS LABELLED INTERIM IN THE SOURCE. Bad rows can be written today and the DB draft is at least a lane-cycle away. coder-terra-ca: put the cardinality rule in createPractica, extracted to a dependency-free core with the effects injected so it is testable, with a must-fail control. The comment must say it is interim pending the DB invariant and must NOT say the database enforces this, because it does not. TERRA-136 is already the same shape and this repeats it deliberately, not accidentally. THREE, createTerraPractica NEEDS A STATED FATE, and neither of us may guess it. It is a boundary function in a shared schema; zero app call sites does not prove zero callers. db-terra-ca: measure whether anything outside terra's application source invokes it. If nothing does, the choice is to retire it or to make it the real write path, and either way the answer gets written down - an uncalled function carrying a live-looking check is the exact artifact this row was filed against, and leaving it in place after fixing everything around it just relocates the decoy.
  • wi-cli-venus note · 6w ago
    Interim app half SHIPPED and independently verified. Commit 92e1b02ae2a6b13159aaed880c5ffe1809af33fa, production deployment READY, Agent trailer coder-terra-ca. I did not take the report as evidence: I read the call site, read the extracted core, and ran node --test src/lib/practica-zona-core.test.ts myself, 12 of 12 including arm 11, the non-empty-region control. What actually landed, stated precisely because the commit message could easily have overclaimed and does not. The pieza-or-region predicate ALREADY EXISTED as a pre-BEGIN pool read. What changed is that it now runs inside the write transaction through an injected effect, at practica-actions.ts:269 - after BEGIN and setArchiveContext, before every patient and practica write, so a refusal rolls back nothing already written. This is a transaction-bound refactor plus an extracted testable core, NOT a newly invented guard, and the commit says so. The INTERIM comment is the part that earns the approval. It names createTerraPractica as the decoy, says the database invariant is pending, and makes no claim that a constraint exists. That was the one thing I would have rejected the patch over, because the row is named after exactly that confusion: createTerraPractica carries the cardinality check and createPractica never calls it, so the function's existence reads as enforcement from a distance. One documented behaviour a later reader must not misread: loadRequirement returns null for an unread cirugia row and leaves an unknown or retired cirugia to the parent FK. The consequence is that such a practica falls back to the flat at-least-one rule rather than that cirugia's own flags. That is the safe direction and is deliberate, but the flags were NOT consulted in that path. Remaining work is the DB layer and it is db-terra-ca's, queued behind terra_53. Reassigned and set blocked on that, rather than left inProgress against a half that is already deployed - an inProgress row whose visible work is done is how the next reader concludes the whole row is done.
  • wi-cli-venus assigned · 6w ago
    db-terra-ca
  • wi-cli-venus blocked · 6w ago
  • wi-cli-venus verified · 6w ago
    Interim app-side guard is LIVE and I verified it independently of the lane that pushed it. coder-terra-ca reported 92e1b02; I did not take that on their word. Vercel production deployment dpl_BYwK4tiEyjv2YZioHYJkFjqYru6g carries githubCommitSha 92e1b02ae2a6b13159aaed880c5ffe1809af33fa on branch main, state READY, message "fix(TERRA-131): move zona check into write transaction". So the guard reached origin and reached production, which the reporting agent's word alone does not establish. What that guard is and what it is NOT. It reads the cirugia requirement through an injected effect on the TRANSACTION client, inside the same transaction as the practica write, before any INSERT. That closes the read-outside-the-write-txn window. It does NOT close this row. The row is about the absence of a DB layer and about createTerraPractica reading as one when createPractica never calls it, and an action-side check is exactly the layer this row says is insufficient - a second writer arriving at the table is not gated by it. This row therefore stays BLOCKED on the database invariant, which is db-terra-ca's and drafted as terra_50_practica_zona_required.sql. Do not read the shipped app guard as partial completion of the DB half.
  • wi-cli-venus note · 6w ago
    RE-VERIFIED AGAINST TODAY'S SOURCE, BECAUSE THE AUDIT LANE CANNOT AND A DECOY CLAIM IS EXACTLY THE KIND THAT DECAYS. audit-terra-ca has been holding at 14 percent context for several windows and correctly refuses to open a Class-A review from a truncated read, so this row's central claim was re-derived here rather than left to age. THE CLAIM HOLDS AND IS CURRENT. createTerraPractica appears in src exactly twice and both are COMMENTS - perfil-actions.ts:17 citing it as an example of the boundary-function rule, and practica-actions.ts:264 describing it. There is no call site. The live write is a manual INSERT INTO terraPracticas at practica-actions.ts:408. So the DB function that carries the cardinality check is not on the path that writes, and the row's decoy framing is accurate as of today. THE SOURCE IS HONEST ABOUT IT, WHICH IS WHY THIS SURVIVED, and that deserves recording as the reason rather than as a compliment. The interim guard at practica-actions.ts:262-268 states in the file that createPractica never calls createTerraPractica, that the function therefore cannot be treated as database enforcement for this path, and that the comment makes no claim a database constraint exists yet. A comment that refuses to overstate its own mechanism is what keeps a row like this checkable; the failure mode here is normally a guard whose name implies enforcement it does not perform. AND THE FIX FOR THIS CLASS IS ALREADY IN FLIGHT ON ANOTHER ROW, which is worth stating because the two look unrelated on a board. TERRA-136's terra_51 enforces its invariant with CONSTRAINT TRIGGERS ON THE TABLE, not inside a boundary function. Triggers fire for whatever writes the row, so they cover the manual INSERT at :408 that createTerraPractica does not. THAT IS THE SHAPE TERRA-131 NEEDS: a boundary function nothing calls enforces nothing, and moving the invariant from the function to the table is what makes the enforcement independent of which path happens to be in use. The pieza-or-region invariant should be specified the same way rather than as a second function the app would also have to remember to call. STATUS UNCHANGED, still blocked, no code and no DB touched. What this event adds is that the blocker is verified live rather than inherited, and that the DDL pattern to use when it unblocks is already demonstrated on terra_51 rather than needing to be invented.
  • wi-cli-venus verified · 6w ago
    RE-MEASURED AGAINST LIVE CATALOG AND SOURCE - the decoy half of this row is CONFIRMED, and the half a reader takes away from the title is WRONG. Measured by db02-terra-cc, then the load-bearing claims re-read by me in the source rather than accepted. CONFIRMED, DECOY: the function exists and its name is createTerraPractica, with no fn_ prefix - this row's own text had the naming wrong. 24 arguments, RETURNS TABLE(outcome, practicaId, practicaNumber, pacienteId, storedNombre, storedApellido). Its cardinality check is real, quoted from prosrc: a NULL-array refusal, and 'at least one pieza or region is required' when both cardinalities are zero, both P0001. And nothing calls it. grep over src/ returns two files and both hits are COMMENTS - perfil-actions.ts:17 and practica-actions.ts:332 - with zero call sites. createPractica at practica-actions.ts:266 INSERTs into terraPracticas, terraPracticasPiezasDentarias and terraPracticasRegionesAnatomicas directly. So the check exists, is correct, and guards nothing on the path that runs. WHAT THE TITLE GETS WRONG, AND IT IS THE HALF THAT CHANGES WHAT ANYONE DOES ABOUT IT. 'Pieza-or-region has no DB layer and a DECOY that reads as one' invites the reading that the running path is UNGUARDED. It is not. practica-actions.ts:330-336 carries a comment headed TERRA-131 INTERIM ACTION GUARD which states the decoy in its own words - the live path writes terraPracticas directly, createTerraPractica has a similar array check but is never called, therefore that function cannot be treated as database enforcement for this path - and explicitly disclaims making any claim that a database constraint exists yet. Line 337 then calls validateZonaForPractica inside the same transaction as the writes and before any INSERT. I VERIFIED THE FLOOR IS ACTUALLY UNIVERSAL RATHER THAN TAKING THE ONE QUOTED LINE. practica-zona-core.ts:141-159: validateZona returns the pieza-required message when that axis is required and piezas is empty, the region-required message on the same shape, and then at :158 an at-least-one floor when both arrays are empty. Those three exits are exhaustive for the both-empty case - whichever flags are set, an empty/empty submission is refused. So the app-side equivalent of the DB function's second RAISE is present, shipped, and covered by practica-zona-core.test.ts. SO THE ROW IS NEITHER 'absent entirely' NOR 'decoy with nothing behind it', and those are different findings with different fixes. The accurate statement is APP ENFORCEMENT SHIPPED, DATABASE INVARIANT STILL ABSENT: the constraint lives in application code inside the transaction, and a second writer - another app, a manual INSERT, a future service - meets no constraint at all. That is the real exposure and it is not what the title says. The row stays blocked on the DB invariant, which is genuinely missing. BOUNDS DECLARED BY THE MEASURING LANE AND KEPT RATHER THAN DROPPED: not checked whether validateZonaForPractica's catalogue read of vTerraCirugias requierePieza/requiereRegion can diverge from a per-cirugia DB-side rule beyond the flat both-empty floor; practica-zona-core.ts read only at :140-171, not in full; no check for a stricter CHECK constraint on the two child tables beyond the two RAISEs quoted; test suite not run; no history check on when the interim-guard comment landed relative to this row's filing. Nothing was written and nothing decided at the database.
  • wi-cli-venus titleChanged · 6w ago
    Pieza-or-region is enforced ONLY app-side: createTerraPractica holds the check but createPractica never calls it, so a second writer meets no constraint at all
  • wi-cli-venus blocked · 6w ago
    MEASURED 2026-09-01, re-check before accepting. The draft EXISTS and is substantive: db/migrations/draft/terra_50_practica_zona_required.sql defines fn_terraRequirePracticaZona plus three deferred constraint triggers on terraPracticas, terraPracticasPiezasDentarias and terraPracticasRegionesAnatomicas, covering both write paths at final transaction state. So this row is NOT blocked on design and never was. This blockedReason was EMPTY until now, which is its own defect - a row shut with no stated condition cannot be unblocked by anyone and cannot expire. TWO CONDITIONS REMAIN, and only two. (1) No dry-run transcript exists: agents/db-terra/evidence/ holds nothing matching terra_50, so there is no rollback evidence and nothing to audit. (2) No Class-A audit PASS is obtainable right now - audit-terra-ca is at 14 percent context, measured today. NARROWED, and this is new: NO db-enamel-cc GO IS REQUIRED. Every quoted identifier in the draft is terra-owned - terraPracticas, terraPracticasPiezasDentarias, terraPracticasRegionesAnatomicas, deletedAt, practicaId and the terra-prefixed function and triggers. Nothing shared is touched, and the gate boundary is shared-object TOUCH, not name prefix. BOUND on that claim: it comes from extracting quoted identifiers out of the draft text, not from executing it, so an unquoted or dynamically constructed reference would not appear. Verify before applying.
  • wi-cli-venus verified · 6w ago
    LA MITAD DE BASE DE ESTE ROW ESTA MEDIDA Y CONFIRMA EL RECLAMO. Pedida a db-terra-ca acotada a un censo SELECT-only, y verificada por mi contra eprpywqwzsvrjeaforei en vez de aceptada de su reporte - las dos lecturas coinciden. EL CHEQUE EXISTE Y VIVE SOLO EN LA FUNCION. createTerraPractica contiene, en su prosrc, IF cardinality(piezasArg) = 0 AND cardinality(regionesArg) = 0 THEN RAISE EXCEPTION 'at least one pieza or region is required' USING ERRCODE = 'P0001'. Lo confirme yo con position() sobre pg_proc.prosrc: devuelve 880, o sea que el texto esta en el cuerpo y no en un comentario adyacente ni en un nombre. Y NADA MAS LO EXIGE. Censo de triggers no internos sobre las dos tablas, leido por mi: terraPracticas tiene siete - archive, assignPracticaNumber, firstRowMilestone, forbidHardDelete, forbidTruncate, practicaNumberImmutable, setUpdatedAt. terraPracticasPiezasDentarias tiene seis - archive, archiveOnUpdate, archiveSoftDelete, forbidHardDelete, forbidTruncate, requireArchiveCtx. NINGUNO evalua cardinalidad cruzada entre practica, piezas y regiones. El censo de constraints que reporto el lane es de claves, FKs, identidad y chequeos de sesion; ninguno alcanza regiones ni exige un hijo. CONSECUENCIA, que es exactamente lo que el row afirmaba y ahora esta medido en vez de inferido: un INSERT directo sobre terraPracticas que no pase por createTerraPractica no encuentra NINGUN invariante de base. La regla pieza-o-region es hoy una propiedad de un camino de llamada, no del esquema, y createPractica es un segundo escritor que no toma ese camino. POR QUE ESTO NO CIERRA EL ROW. Lo medido es que la base no lo enforcea; no esta decidido que DEBA hacerlo ni con que forma. La opcion obvia - un trigger diferido sobre el parent, como el que terra_51 usa para complicaciones intraoperatorias en TERRA-136 - es plausible justamente porque es la misma clase de invariante de ausencia y no se puede hacer con un trigger de fila hija comun. Pero eso es diseno y no esta hecho, y TERRA-136 todavia esta blocked por falta de PASS de audit Clase A, asi que copiar su patron hereda su cola de gates. BOUND DE ESTA MEDICION: es del catalogo vivo de hoy, no del historial. Dice que nada enforcea la regla AHORA. No dice cuantas practicas existentes violarian el invariante si se aplicara, que es la cuenta que hace falta antes de escribir cualquier migracion - la poblacion protegida hay que contarla, no suponerla vacia.
  • wi-cli-venus verified · 6w ago
    POBLACION PROTEGIDA MEDIDA, y esto era lo que faltaba antes de que yo decida la forma de la migracion. Medida por db02-terra-cc y RE-MEDIDA por mi por otro transporte antes de usarla. RESULTADO: CERO. No existe hoy ninguna practica viva sin pieza dentaria ni region anatomica. Total de la tabla 6, vivas 6, archivadas 0. Consulta, textual, la misma de las dos corridas: count sobre terraPracticas con deletedAt IS NULL y NOT EXISTS de hijo vivo en terraPracticasPiezasDentarias y NOT EXISTS de hijo vivo en terraPracticasRegionesAnatomicas. db02 la corrio por MCP; yo la corri por psql contra el pooler. Los dos dan 0 de 6. EL ESTADO PROHIBIDO NO LO INTERPRETO NINGUNO DE LOS DOS, que era el riesgo real de este conteo: db02 lo tomo del preflight del propio borrador, terra_50_practica_zona_required.sql:82-85. Contar "lo que la regla nueva prohibiria" segun una lectura propia de la regla es como se produce un cero que no significa nada. GUARDA CONTRA EL CERO VACIO, y las dos mitades importan. db02 listo piezas y regiones vivas por practica y las 6 tienen al menos un hijo vivo, rango 0-4 piezas y 0-1 regiones, nunca las dos en cero. Yo ademas conte las tablas hijas enteras: 12 filas en terraPracticasPiezasDentarias y 3 en terraPracticasRegionesAnatomicas. O sea que el 0 no viene de tablas vacias ni de un join que no matchea nada - viene de que todas cumplen. QUE HABILITA. La migracion no tiene poblacion legacy que preservar, que es la diferencia CONCRETA contra terra_51: alla la excepcion legacy era el corazon del diseño y aca no hace falta ninguna. Con cero filas protegidas, un trigger diferido sin excepcion es aplicable sin reescribir ni romper nada existente. LA DECISION SIGUE SIENDO MIA Y TODAVIA NO ESTA TOMADA. Lo que cambia es que ahora se decide contra un numero medido y no contra una suposicion. Y el numero tiene fecha: 6 filas hoy es una poblacion chiquita, asi que este conteo se vuelve viejo rapido - cualquier borrador que se escriba tiene que traer su propio preflight que lo vuelva a contar en el momento de aplicar, no citar este evento. NO MEDIDO, dicho en vez de implicado: no hay archivadas, asi que no hay historico que revisar; y no se toco nada mas de las dos tablas hijas fuera de estos EXISTS.
  • wi-cli-venus decision · 6w ago
    DECISION DE DISEÑO TOMADA, contra el numero medido y no contra una suposicion: terra_50 NO lleva excepcion legacy. Poblacion protegida = 0 de 6 vivas, 0 archivadas, verificada por dos lanes y dos transportes. A diferencia de terra_51 - donde la excepcion legacy ERA el corazon del diseño porque habia practicas viejas con cero respuestas que preservar - aca no hay ninguna fila que exceptuar. El preflight que el borrador ya trae en :78-88 aborta si aparece una en violacion, y esa es la forma correcta: FALLA en vez de exceptuar, y se recuenta en el momento de aplicar en vez de confiar en el conteo de hoy. Con 6 filas totales, un numero medido esta noche envejece rapido; el preflight es lo que lo vuelve a preguntar. Y ENCONTRE EL MISMO DEFECTO QUE ACABABAMOS DE CORREGIR EN terra_51, sin corregir, en este archivo. Las lineas 3-4 dicen "A practica must retain at least one live pieza dentaria OR one live region anatomica" - una afirmacion sobre TODA practica viva - y trg_terraPracticas_requireZona esta atado a AFTER INSERT solamente (:57-58). Los dos triggers hijos si cubren INSERT, UPDATE OF deletedAt/practicaId y DELETE. Un UPDATE del parent no alcanza ningun arm. ESTO NO LO ENCONTRO UN AUDIT: lo encontre yo mirando el archivo de al lado inmediatamente despues de que el audit bloqueara terra_51 por exactamente esta redaccion. Un defecto se corrige en el archivo donde lo reportaron y sus hermanos quedan intactos, porque el reporte cita UNA ubicacion y el que arregla y el que revisa miran las mismas coordenadas. terra_50 y terra_51 son la misma forma escrita dos veces por la misma lane. DIFERENCIA REAL A FAVOR DE terra_50, y la escribo en vez de omitirla: su preflight GARANTIZA que al aplicar no exista ninguna fila en violacion, cosa que terra_51 no hacia porque preservaba legacy a proposito. O sea que el estado inicial queda limpio y la brecha es hacia adelante y por afuera de la app, no heredada. Hoy no hay practicas archivadas y no existe superficie de restauracion en src/ (unico "reactivar": cirugia-retire-core.ts:89, otra tabla). ASIGNADO a db-terra-ca: correccion de cabecera con la misma forma que terra_51, sin tocar DDL - la forma esta bien, incluido ENABLE ALWAYS y el UPDATE OF acotado a deletedAt y practicaId - mas los seis arms de fixture que el propio archivo pide en :104-107, en transaccion revertida y con NOTICEs autoverificantes, transcript en db/migrations/dryrun/ con nombre fechado. Verifico yo antes de que esto pida GO.
  • wi-cli-venus verified · 6w ago
    CABECERA DE terra_50 CORREGIDA Y VERIFICADA POR MI EN DISCO. La encontre por mtime, no por reporte: db-terra-ca la escribio a las 02:25:47 y quedo idle sin avisar, o sea que estuve a punto de reasignar un trabajo ya hecho. Un cambio que existe y nadie anuncia es indistinguible de uno que no se hizo. QUE QUEDO. Lineas 3-16: alcance acotado a INSERTs de practica nueva y cambios de hijos pieza/region, y - esta es la diferencia contra terra_51 y la escribio como diferencia - dice que el preflight GARANTIZA poblacion limpia al momento de aplicar EN VEZ de preservar una excepcion legacy. La brecha queda con fecha 2026-09-01, con los numeros (6 practicas, todas vivas, ninguna en violacion), con el unico "reactivar" de src/ nombrado como de otra tabla, y cerrando con "This is a forward measured gap, not not applicable". Linea 36, adentro de la funcion: el trigger del parent es AFTER INSERT only y no impone una condicion global. DDL INTACTO, verificado y no asumido: los tres triggers siguen igual, con el UPDATE OF acotado a deletedAt y practicaId en los dos hijos. El archivo paso de 107 a 118 lineas, o sea +11 lineas de comentario y ni una de SQL. sha b77ef36a982395cf89e002d393be8a4be61ccb7ee9751d1d6ec13abeed6ee011. LOS SEIS ARMS SE MUEVEN A db02-terra-cc por capacidad y no por calidad: db-terra-ca quedo al 29% de contexto y esa corrida en terra_51 produjo diez artefactos. Van con tres condiciones que no son detalle: los arms 3 y 5 son los unicos que PRUEBAN algo - si pasan sin fallar, el trigger no hace nada y el resultado es rojo aunque se vea verde; los triggers son DEFERRABLE INITIALLY DEFERRED, asi que hace falta SET CONSTRAINTS ALL IMMEDIATE para forzar la falla adentro de una transaccion que despues se revierte; y no se cuentan filas por lo que imprime el cliente, un UPDATE 1 de psql no es una asercion. UNA HONESTIDAD SOBRE LA SEGUNDA LECTURA, porque cuenta menos de lo que parece: le pedi a db-terra-ca que confirmara mi lectura de los dos "invariant" que sobreviven en terra_51 (:30 y :34) DESPUES de haberle dicho a que conclusion habia llegado yo. Coincidio y su razonamiento es correcto y propio - dice que :34 aplica cuando el cambio del HIJO si dispara la regla diferida, matiz que yo no habia escrito. Pero pedir confirmacion habiendo enunciado primero mi respuesta es exactamente la forma de fabricar corroboracion falsa que tengo anotada como regla: dos lanes que coinciden despues de que una vio la respuesta de la otra son UNA medicion con dos nombres. Lo registro como lectura de acuerdo, no como verificacion independiente.
  • wi-cli-venus verified · 6w ago
    ENSAYO COMPLETO CORRIDO Y EMPUJADO. db89624 en origin/main, v0.30.95, 87a5384..db89624: el .sql, el .result.md y la cabecera corregida del borrador, cuatro archivos, 404 inserciones. RESULTADO: seis arms, todos como se esperaba, en UNA transaccion revertida, transporte MCP execute_sql, proyecto eprpywqwzsvrjeaforei confirmado antes y despues de correr. LOS DOS QUE IMPORTAN SON LOS QUE TENIAN QUE FALLAR. arm3, practica sola sin hijos: P0001 con el texto "terra: practica <id> requires at least one live pieza dentaria or region anatomica". arm5, borrar en blando el ultimo hijo vivo: mismo P0001, misma plantilla. Los dos capturados con GET STACKED DIAGNOSTICS y comparados contra el mensaje esperado, no contra "hubo un error". Y cada uno tiene arriba un RAISE EXCEPTION que dice TRIGGER IS INERT si el check pasa - o sea que un verde no puede venir de un trigger que no hace nada, que es el modo de falla que este tipo de ensayo tiene por defecto. Los otros cuatro: arm1 practica con una pieza commitea, arm2 con una region commitea, arm4 con las dos commitea, arm6 borra en blando su unica pieza sobreviviendo la region y commitea - y ese conteo salio por GET DIAGNOSTICS, no por el "UPDATE 1" que imprime el cliente. Mas dos aserciones previas: aceptacion del DDL (preflight n=3, censo de triggers diferidos 3, EXECUTE de service_role) y ACL (ni anon ni authenticated ni PUBLIC tienen EXECUTE sobre fn_terraRequirePracticaZona). NO ACEPTE LA AFIRMACION DE QUE EL DDL DEL FIXTURE ES VERBATIM DEL BORRADOR - la diffee, ignorando comentarios y lineas vacias: identico, tres ENABLE ALWAYS en cada uno y el mismo GRANT a postgres y service_role. Era la unica afirmacion que, de ser falsa, habria hecho que los seis arms ensayaran un DDL distinto del que se va a aplicar, con todos los mensajes saliendo igual de verdes. RESIDUO PROBADO POR TERCERA LECTURA Y DESPUES DEL ROLLBACK, no en el medio. El transcript trae el conteo post-rollback en llamada separada, y ademas lo corri yo por psql, otro transporte: 6 practicas (igual al baseline), 0 de los seis ids que el script creo, 0 triggers zona y 0 funcion fn_terraRequirePracticaZona. El "5 fixture, 11 total" del log es de MITAD de transaccion y prueba que la fixture existio, no que se fue - por eso pedi el otro, y por eso este esta. LO QUE ESTO NO PRUEBA, dicho en vez de implicado: es un ensayo, no un estado aplicado. No hay nada vivo en la base. No se probo concurrencia, ni el comportamiento bajo replicacion, ni ningun camino de la aplicacion - los arms escriben SQL directo, no pasan por createPractica. Y el numero de poblacion tiene fecha: el preflight lo vuelve a contar al aplicar, que es lo que corresponde. SIGUIENTE Y ULTIMO GATE ANTES DE PEDIR GO: audit de adecuacion, igual que terra_51. Va a audit-terra-ca.
  • wi-cli-venus commit · 6w ago
    db89624 en origin/main, v0.30.95: db/migrations/dryrun/2026-09-01-terra_50-arms1-6-selfchecking.sql mas .result.md, mas la cabecera corregida de db/migrations/draft/terra_50_practica_zona_required.sql. Rango 87a5384..db89624.
  • wi-cli-venus audit-finding · 6w ago
    BLOCK DE audit-terra-ca SOBRE LA EVIDENCIA, no sobre el DDL, y el hallazgo central es una AFIRMACION FALSA EN UN ARTEFACTO QUE YO VERIFIQUE Y EMPUJE. Lo confirme en la fuente y tiene razon. EL NUMERO FALSO. El transcript dice "preflight n=3". Un run exitoso NO PUEDE tener preflight=3: el preflight cuenta practicas vivas sin pieza ni region y aborta si el numero no es CERO. Verificado en dryrun SQL :87-105: la variable n toma primero el conteo del preflight, se chequea contra 0, y despues se SOBREESCRIBE con el censo de triggers, que se chequea contra 3. La linea de log final hace format(..., n, n) - los dos huecos reciben el mismo valor, que a esa altura es 3. O sea que el numero del preflight nunca se imprimio; se imprimio el del censo dos veces. LO QUE SI ES CIERTO, y la distincion importa: la ASERCION corrio y paso. Si hubiera habido una practica en violacion, el IF n <> 0 habria abortado el script entero. Lo que fallo es el REPORTE de ese chequeo, no el chequeo. Pero un transcript es evidencia, y una evidencia que afirma un numero imposible se lee como corrupta entera - el que la audite dentro de un año no sabe cual mitad creer. Y ESTO PASO POR MI FILTRO. Yo verifique el diff del DDL contra el borrador, el residuo post-rollback por psql propio, y la forma de los arms de prueba. Lei "preflight n=3" como un RESULTADO y no rastree que lo producia. La linea de log de un script autoverificante es un ARTEFACTO DEL SCRIPT, no una medicion de la base: la genera un format() que puede estar mal escrito exactamente igual que cualquier otra linea. Verificar un transcript incluye leer el codigo que imprime cada numero, no solo el numero. SEGUNDO HALLAZGO, Y ES EL QUE MAS VALE: FALTA UN ARM MUST-FAIL. El DDL afirma en :39-45 que valida OLD y NEW practicaId, y los triggers hijos escuchan UPDATE OF practicaId en :73-81. NINGUN arm ejecuta una reasignacion. O sea que la rama de dos padres - la unica parte de la funcion que existe especificamente para ese caso - no se ejercito nunca, y los seis arms verdes no dicen nada sobre ella. El arm que falta: dos padres vivos validos, mover el unico hijo de uno al otro, SET CONSTRAINTS IMMEDIATE, y exigir P0001 nombrando al padre VIEJO. TERCERO: arm5 solo prueba UPDATE de deletedAt sobre PIEZAS. No prueba el trigger de REGIONES ni prueba DELETE fisico sobre ninguna de las dos. Son caminos declarados en el DDL y no ejercitados. Y UNA CORRECCION DE LECTURA QUE ME APLICO A MI TAMBIEN: arms 1, 2, 4 y 6 son caminos de aprobacion, no pruebas. Todos pasarian con un trigger inerte. Sus aserciones prueban que la fixture existe y que el UPDATE de arm6 afecto una fila - no prueban que algo se haya impuesto. Yo los conte como "seis arms todos como se esperaba", que es cierto y suena a mas de lo que es. Los que prueban son dos. VEREDICTO SOBRE EL DDL, separado del veredicto sobre la evidencia: PASS condicional. El alcance hacia adelante esta bien - el UPDATE OF acotado a deletedAt y practicaId no abre ningun bypass porque ninguna otra columna cambia la vitalidad del hijo ni su asociacion al padre; el camino real de la app es INSERT de padre y despues INSERTs de hijos (practica-actions.ts:476-506, :511-545) sin ningun writer de UPDATE, DELETE ni reasignacion de hijos; y el UPDATE postoperatorio solo toca columnas postop y predica deletedAt IS NULL (practica-postop-core.ts:87-98), asi que no puede resucitar un padre archivado sin hijos. TRUNCATE queda fuera de los tres triggers de fila y este ensayo no lo prueba. NO SE PIDE GO. Se rehace el ensayo: contadores separados con preflightN y triggerN por su cuenta, el arm de reasignacion, y arms de region y de DELETE fisico o el limite escrito explicitamente como no ejercitado. Va a db02-terra-cc.
  • wi-cli-venus verified · 6w ago
    Rerun verified and pushed as 8d3897b (db89624..8d3897b, v0.30.96). All three audit findings are closed in the artifact, and I verified each at a primary source rather than accepting the lane's report. FINDING 1, the impossible number. Separate v_preflight_n and v_trigger_n, each asserted then each printed from its own variable at the ddl-acceptance line; the transcript now reads preflight_n=0 (must be 0), trigger_census_n=3 (must be 3). I re-read every other format() in the file: v_affected in arm6 and v_fixture_n/v_total_n in the residue block are each asserted on the line immediately above the format() that prints them. No variable is reused across two assertions anywhere in the script. FINDING 2, the reassignment path. arm7-PROOF: parent A holds its only pieza, parent B is already valid via a region, the pieza is moved A to B by UPDATE practicaId rather than delete plus insert, SET CONSTRAINTS ALL IMMEDIATE forces the deferred check, and the refusal must equal the message naming OLD parent A. Naming B would raise the same P0001 with a different id and would be the wrong finding, so the arm compares the full formatted string against v_parent_a, not the sqlstate. It carries the inert guard: reassignment branch is INERT if the UPDATE succeeds. FINDING 3, the unexercised axes. arm5r-PROOF covers the region axis symmetrically to arm5. Physical DELETE is handled as EVIDENCE rather than as a proof or an omission: arm8 attempts a real DELETE and asserts twice, that the surfacing P0001 is forbidHardDelete's text AND that it is NOT requireZona's, so a precedence assumption failing announces itself instead of passing quietly. Relabelling accepted and applied in both files: arms 1, 2, 4 and 6 are -approval, they pass against a completely inert trigger. Four proofs now, arm3, arm5, arm5r, arm7. WHAT I CHECKED MYSELF, AND ON WHICH TRANSPORT. Executable DDL diffed line for line against the draft, identical, the only delta being seven comment lines the fixture omits. Post-rollback residue re-measured on my own psql pooler session rather than the MCP call that produced the run: 6 practicas, 0 synthetic, 0 of the eight logged fixture ids, 0 zona triggers, 0 zona function. Live preflight population re-counted independently and is still 0, so the draft's abort guard passes at apply time. ONE CLAIM CAME BACK STRONGER THAN REPORTED. The lane justified arm8's generalisation to the regiones table by pg_trigger census plus prosrc. Checked directly: both child tables carry forbidHardDelete at tgtype 11, BEFORE ROW DELETE, tgenabled A, and both point at ONE shared function, fn_terraDetailForbidHardDelete, whose entire body is a single unconditional RAISE with no branch. It is the same function, not merely the same shape, so the unreachability holds on both tables by construction rather than by resemblance. WHAT THIS STILL DOES NOT ESTABLISH, said rather than implied. The rehearsal executes the draft's SQL with comments stripped, so it proves the statements apply, not that the draft file as written applies. The verdict on the DDL was and remains PASS; this rerun was entirely about the evidence.
  • wi-cli-venus decision · 6w ago
    Rehearsal closed, row stays blocked but on a DIFFERENT thing and that distinction matters for whoever reads it next. It was blocked on audit-terra-ca's evidence BLOCK; that is resolved and pushed as 8d3897b. It is now blocked on eq 73, Elazar's GO to APPLY terra_50, filed under topic terra-db-invariant-apply-go alongside eq 72 for terra_51 so one answer can cascade to both. Nothing further is assignable on this row until that GO lands: the DDL verdict is PASS, the evidence is complete, and applying is not mine to do.
  • wi-cli-venus blocked · 6w ago
    REESCRITO 2026-09-01: las dos condiciones que este campo declaraba YA NO SON CIERTAS, y el row seguia diciendolas mientras sus propios eventos decian lo contrario. UNICA CONDICION VIVA: eq 73, el GO de Elazar para APLICAR terra_50. No falta evidencia ni auditoria. (1) EL TRANSCRIPT EXISTE: db/migrations/dryrun/2026-09-01-terra_50-arms1-6-selfchecking.result.md, 6354 bytes, nueve brazos, cuatro de ellos PROOF must-fail (arm3, arm5, arm5r, arm7), mas arm8 como evidencia explicita de que la clausula DELETE de requireZona es inalcanzable porque forbidHardDelete corre antes, y prueba de residuo DESPUES del ROLLBACK externo en llamada separada. Ademas es una REESCRITURA que corrigio tres defectos que encontro la propia auditoria, incluido un "preflight n=3" imposible por variable de reporte reusada, y relabelo arm1/2/4/6 como -approval porque pasarian con un trigger inerte. Por que la condicion se leia incumplida: el campo buscaba el transcript en agents/db-terra/evidence/ y quedo en db/migrations/dryrun/. Directorio distinto, nadie volvio a mirar. (2) EL BLOQUE DE AUDITORIA ESTA RESUELTO Y PUSHEADO como 8d3897b, y audit-terra-ca esta hoy al 52 por ciento de contexto, no al 14 con el que se escribio esta condicion. Un bloqueo cuya condicion es el contexto de otro agente caduca solo y sin aviso. LO QUE SIGUE SIN HACERSE, y es de otro carril: terra_50 sigue en draft, sin aplicar, y el GO de apply es de Elazar.
  • wi-cli-venus note · 6w ago
    MEDIDO POR db-terra-ca, SELECT solamente, 2026-09-01 08:35, con el predicado nombrado. CERO VIOLACIONES. Y YO LE AGREGO EL DENOMINADOR, QUE NO VINO Y QUE ES LO QUE DECIDE CUANTO VALE ESE CERO. EL RESULTADO: cero practicas vivas sin ninguna pieza vigente y sin ninguna region vigente. Tambien cero contando padres borrados. No hay primera ni ultima fecha porque no hay filas. Asi que esto es PREVENTIVO, no una limpieza. EL PREDICADO, explicito como lo pedi: padre terraPracticas vivo = deletedAt IS NULL, y no tiene isActive asi que no lo uso. Hijos terraPracticasPiezasDentarias y terraPracticasRegionesAnatomicas: asociacion vigente = deletedAt IS NULL, tampoco tienen isActive. Violacion = padre sin EXISTS de pieza vigente Y sin EXISTS de region vigente. EL DENOMINADOR, QUE MEDI YO Y QUE CAMBIA COMO HAY QUE LEER EL CERO: la base tiene SEIS practicas en total, ninguna borrada. Doce filas de piezas y tres de regiones. Cero violaciones sobre seis practicas no es lo mismo que cero sobre seis mil: es un corpus casi vacio, y una comprobacion que pasa sobre seis filas no dice casi nada sobre un escritor que apenas corrio. NO ESTOY DICIENDO QUE LA MEDICION ESTE MAL - esta bien hecha y el SQL es correcto. Digo que la frase "cero violaciones" citada sola se lee como "el invariante se sostiene en produccion", y lo que en realidad se sostiene es que casi nadie escribio todavia. Es la misma trampa del corpus vacio que en un test se ataja afirmando primero que el corpus no esta vacio. LO QUE ESO LE HACE A LA PRIORIDAD: no la baja, la sube. La fila dice que la regla vive SOLO del lado de la app, o sea que hoy la sostiene el unico escritor que existe. El costo de agregar el enforcement con seis practicas es cero - no hay nada que limpiar antes. Ese costo solo crece. DECISION DE DISEÑO, contestada y no asumida: NO se puede expresar como CHECK de una sola fila. La condicion depende de la ausencia o presencia de filas vigentes en DOS tablas hijas, asi que necesita enforcement entre tablas - un trigger o un constraint trigger, no un CHECK sobre terraPracticas. Lo pregunte explicitamente para que no se diera por sentado, y la respuesta cambia la forma del arreglo. NO SE ESCRIBIO NINGUNA MIGRACION. Lo pedi asi: el GO de terra_55 sigue pendiente en la eq 78 desde las 04:14 y no quiero dos migraciones sin aprobar en la cola. Cuando terra_55 se aplique, esta es la siguiente de la misma clase - una regla que hoy vive solo en el codigo de la app y que cualquier otro escritor no encuentra.
  • wi-cli-venus note · 6w ago
    ORDEN DE DISPARO ENTRE terra_50 Y terra_51: DECIDIDO, FUNDAMENTADO Y AHORA ESCRITO EN LOS DOS BORRADORES. 2026-09-01 09:38. Lo escribio db-terra-ca; lo verifique yo contra los archivos antes de darlo por bueno. DE DONDE SALIO: no lo estaba buscando. Pedi un censo de triggers de las seis tablas que tocan las cuatro migraciones medidas, para saber si CHOCAN al aplicarse. Cero colisiones de nombre sobre 29 triggers no internos, y cero cobertura duplicada - ningun trigger vivo impone hoy ni presencia de complicacion intra ni pieza-o-region, y el mas parecido, vocabGuard sobre complicaciones, solo valida que el value resuelva en vocabulario, no cardinalidad ni exclusividad. Pero de paso aparecio algo que ningun borrador comentaba: Postgres corre los triggers de un mismo evento POR ORDEN ALFABETICO DEL NOMBRE, asi que el orden entre los dos constraint triggers nuevos sobre terraPracticas ya estaba decidido - por los nombres, sin que nadie lo decidiera. EL ORDEN MEDIDO: trg_terraPracticas_firstRowMilestone es un AFTER ordinario y corre al statement. Al COMMIT corren los dos constraint triggers diferidos, primero trg_terraPracticas_requireIntraComplicacionAnswer (terra_51) y despues trg_terraPracticas_requireZona (terra_50), porque comparten el prefijo trg_terraPracticas_require y ahi I precede a Z. LA PREGUNTA QUE PEDI QUE CONTESTARA NO ERA CUAL ES EL ORDEN, ERA SI IMPORTA. Le dije explicitamente que si no podia determinarlo sin correr algo, me lo dijera y NO escribiera nada - un comentario que afirma indiferencia sin haberla comprobado es peor que no tener comentario, porque despues nadie lo vuelve a mirar. CONTESTO QUE ES INDIFERENTE, con el argumento: los dos leen el estado final, los dos retornan o hacen RAISE, y NINGUNO ESCRIBE. Invertirlos no puede convertir un rollback en commit ni al reves; si una practica viola los dos invariantes, lo unico que cambia es cual de los dos P0001 aparece primero. NO LO TOME DE PALABRA, PORQUE LA CLAVE DEL ARGUMENTO ES "NINGUNO ESCRIBE" Y ESO SE VERIFICA MIRANDO. Grepee los dos cuerpos por sentencias de escritura: en terra_50 y en terra_51 no hay un solo INSERT, UPDATE ni DELETE dentro de las funciones de trigger - son SELECT count(*), EXISTS y NOT EXISTS, y despues RAISE EXCEPTION o RETURN NULL. El unico INSERT de cualquiera de los dos archivos esta en los preflight y en los bloques de aceptacion, que corren una vez al aplicar y no en el camino del trigger. El argumento se sostiene sobre lo que los archivos realmente dicen. QUE QUEDO ESCRITO: un bloque de comentario identico y fundamentado antes de los CREATE CONSTRAINT TRIGGER de db/migrations/draft/terra_50_practica_zona_required.sql y de terra_51_practica_intra_complicacion_required.sql. Dice la regla de Postgres, el orden resultante con los nombres reales, y - lo unico que de verdad importa - que ese orden es indiferente y POR QUE, que es lo que evita que alguien lo "arregle" renombrando dentro de seis meses. SIN SQL EJECUTABLE TOCADO, sin aplicar y sin pushear: los borradores los pusheo yo. git diff --check pasa. UNA COSA ANOTADA PARA CUANDO YO PUSHEE, que db-terra-ca marco por su cuenta y esta bien que lo haya hecho: terra_51 YA TENIA en el arbol cambios de comentario ajenos a esta edicion. No los toco y no se los atribuye. Cuando pushee este borrador van a viajar en el mismo commit si no los reviso, asi que los miro en el patch antes de mandar en vez de descubrirlos despues.
  • wi-cli-venus note · 6w ago
    RE-MEDIDA CONTRA LA BASE VIVA, SIN DRIFT, 2026-09-01 09:52 UTC. Medido por db02-terra-cc y re-corrido por mi contra pg_constraint y pg_trigger - no acepte la descripcion. LA MITAD DE BASE SIGUE VACIA, y lo digo enumerando lo que SI hay para que el cero tenga denominador en vez de ser una afirmacion de ausencia a secas. Sobre terraPracticas, terraPracticasPiezasDentarias y terraPracticasRegionesAnatomicas, el UNICO CHECK que existe en las tres tablas es terraPracticas_syntheticSessionId_check, y su cuerpo no habla de piezas ni de regiones: CHECK ((isSynthetic AND syntheticSessionId IS NOT NULL) OR (NOT isSynthetic AND syntheticSessionId IS NULL)). Nada mas. Los triggers no-internos de esas tablas son los del patron de archivo mas los de numeracion: archive, archiveOnUpdate, archiveSoftDelete, forbidHardDelete, forbidTruncate, requireArchiveCtx, assignPracticaNumber, firstRowMilestone, practicaNumberImmutable, setUpdatedAt. NINGUNO COMPARA EXISTENCIA CRUZADA entre piezas y regiones, que es lo que la invariante necesitaria: la regla es "al menos una de las dos", o sea que ningun trigger que mire UNA SOLA de las dos tablas puede imponerla, y ninguno de estos mira a la otra. CONCLUSION SIN CAMBIO PARA TERRA-131: cero CHECK, cero trigger, cero constraint que imponga pieza-o-region. La regla sigue viviendo solo del lado de la app, y solo en createTerraPractica, que createPractica no llama - o sea que el segundo escritor no encuentra nada. Y LO MISMO PARA TERRA-136, medido aparte sobre terraPracticasComplicaciones: los constraints son el CHECK de fase - fase IN ('intra','post') -, la PK y la FK a terraPracticas. Hay un indice unico parcial sobre (practicaId, fase, value) WHERE deletedAt IS NULL, Y CONVIENE NO CONFUNDIRLO CON LA INVARIANTE: impide cargar DOS VECES EL MISMO value en la misma fase, que no es ni la obligatoriedad de responder ni la exclusividad de "Sin complicaciones". Un indice unico parcial ahi parece que restringe mas de lo que restringe. El unico trigger de contenido es vocabGuard, y db02 leyo el cuerpo de fn_terraComplicacionesVocabGuard en vez de fiarse del nombre - que es la disciplina correcta en esta base, donde ya tenemos dos casos de nombre que promete mas que su cuerpo. Valida UNICAMENTE que el value pertenezca al vocabulario de la categoria segun la fase. No exige que exista al menos una fila por fase, y no impide que "Sin complicaciones" conviva con otras complicaciones en la misma practica. O SEA QUE LAS DOS INVARIANTES DE TERRA-136 SIGUEN SIN EXISTIR EN LA BASE, las dos por separado: ni la respuesta obligatoria ni la exclusividad. NO SE ESCRIBIO NINGUNA MIGRACION POR ESTO Y ES DELIBERADO: terra_55 sigue sin GO en la eq 78, y las invariantes medidas de esta clase esperan a que ese GO las ordene en vez de competir entre si.
  • wi-cli-venus note · 6w ago
    EL TITULO DE ESTA FILA ES HOY FALSO EN SU SEGUNDA MITAD. Medido 2026-09-01 10:43 UTC: auditado por audit-terra-ca y VERIFICADO POR MI leyendo los tres archivos, no aceptando el reporte. LO QUE DICE LA FILA: "createTerraPractica holds the check but createPractica never calls it, so a second writer meets no constraint at all". La primera mitad sigue siendo cierta. LA SEGUNDA NO: createPractica no llama a createTerraPractica, pero NO ES CIERTO que no encuentre ninguna restriccion - REIMPLEMENTA la validacion. DONDE, con linea: src/lib/practica-actions.ts:336-357 llama validateZonaForPractica con input.piezasDentarias e input.regionesAnatomicas y lanza ActionError si devuelve mensaje. La regla real vive en src/lib/practica-zona-core.ts:141-160, y es un SUPERCONJUNTO de la de la funcion de base: exige pieza si el eje pieza es requerido, exige region si el eje region es requerido, y en la linea 158 tiene ademas el piso de AL MENOS UNA - "if (piezas.length === 0 && regiones.length === 0) return ZONA_AT_LEAST_ONE_MESSAGE". O sea que el camino vivo de la app si valida pieza-o-region, y ademas valida algo mas fino que la funcion de base no mira. Y NO ES UN DESCUBRIMIENTO ARQUEOLOGICO: el propio codigo se etiqueta "TERRA-131 INTERIM ACTION GUARD" en la linea 329 y dice que espera la invariante de base que db-terra-ca va a aplicar despues de terra_53. O sea que alguien ya actuo sobre esta fila y la fila no se entero. Eso es exactamente la deriva que estas revisiones existen para encontrar. LO QUE SIGUE VIVO Y ES EL NUCLEO REAL: NO HAY ENFORCEMENT EN LA BASE. Lo remedi este mismo dia contra pg_constraint y pg_trigger: cero CHECK, cero trigger, cero constraint que imponga pieza-o-region sobre terraPracticas, terraPracticasPiezasDentarias ni terraPracticasRegionesAnatomicas. El comentario del codigo lo dice el mismo y con todas las letras - "this comment makes no claim that a database constraint exists yet". La regla vive en DOS lugares de aplicacion y en NINGUNO de base. O SEA QUE EL RIESGO CAMBIA DE FORMA, NO DESAPARECE. Antes era "hay un escritor sin control". Ahora es "hay dos escritores con DOS COPIAS de la regla, escritas por separado, y nada las obliga a coincidir" - y de hecho ya no coinciden: la de la app es mas estricta. Un tercer escritor, o una divergencia entre las dos, no lo reporta nada. CENSO DE ESCRITORES, con el limite declarado: audit-terra-ca no encontro un tercer camino de INSERT no-test. Los dos son practica-actions.ts:474-506 (validado en 336-357) y el INSERT de createTerraPractica en terra_42:141-154 (validado en 95-102). DECLARA UNKNOWN, y lo dejo escrito en vez de redondearlo a cero: SQL directo contra produccion, llamadores externos, o un objeto de base que no este representado en las migraciones aplicadas quedan fuera de ese censo. Un censo de fuente no puede ver eso. QUE HAY QUE CORREGIR EN LA FILA: el titulo y la descripcion afirman en presente algo que dejo de ser cierto. Reescribir el nucleo como "la regla existe DOS VECES en la aplicacion y CERO veces en la base, y nada verifica que las dos copias digan lo mismo" - que es mas preciso y sigue justificando la migracion pendiente. terra_55 sigue sin GO en la eq 78; no se escribio migracion por esto.
  • wi-cli-venus titleChanged · 6w ago
    La regla pieza-o-region existe DOS VECES en la aplicacion y CERO veces en la base, y nada verifica que las dos copias coincidan - de hecho ya no coinciden
  • wi-cli-venus descriptionChanged · 6w ago
    was: "No deja guardar sin al menos una pieza dentaria o una region anatomica" is a promise we make to the client in writing, and it stands on ONE layer: the Node action. Measured by audit-terra-ca 2026-08-29. The form calls validateZona (practica-form.tsx:327-340) and the action independently re-reads requierePieza/requiereRegion per cirugia and calls the same shared validator (practica-actions.ts:221-242). So the browser is NOT the only guard - that part is sound. What is missing is the third: the base schema records the DB trigger for this rule as deliberately OMITTED, in its own text, at terra_1_initial_schema.sql:233-240. THE TRAP IS A FUNCTION THAT LOOKS LIKE COVERAGE AND IS NOT ON THE PATH. createTerraPractica carries its own array-cardinality check (terra_42:95-100). It is easy to read that as the DB-side guard. createPractica does NOT call it - it performs manual INSERTs at practica-actions.ts:356-466. So the check exists, is correct, and guards nothing that the app actually does. A future reader auditing this rule can find that function and conclude the invariant is enforced in the database. WHY THIS IS FILED AT ALL, given Node is genuinely authoritative: this is the specific rule item 10 of the client status document promises, and it is the one a docente would notice. One layer is defensible; one layer PLUS a decoy that reads as a second layer is not, because it stops the next person checking. Consequence today is bounded - no evidence of a bad row, and every real submit goes through the action. SCOPE, deliberately narrow: either put the invariant in the DB, or delete/annotate the createTerraPractica check so it cannot be mistaken for path coverage, and update terra_1's omission comment to say what DOES enforce it. Sibling items in the same class, all found in one pass: TERRA-127 (required campo, browser-only), TERRA-129 (antecedentes tree, browser-only), TERRA-130 (docente membership, Node-only).
  • wi-cli-venus decision · 6w ago
    GO GRANTED BY ELAZAR, 2026-09-02. Relayed to db-terra-ca as the applying lane, hub tag coder02-terra-cc-mtjublevyd7f. AUTHORIZATION AND ITS PROVENANCE, written here because the artifact does not exist anywhere else: Elazar gave the GO as a direct CLI message to coder02-terra-cc, answering a numbered/lettered question list. The chosen option was 1a, "GO for both, apply in order after fresh rehearsal", covering terra_50 (TERRA-131) and terra_51 (TERRA-136) in one answer. Elazar is CLI-only and cannot emit a hub tag or an eq answer, so no such artifact will ever exist for this GO. The hub tag above is the RELAY of the authorization, not the authorization. Any applied/ header citing it must say so in the same sentence, the way terra_55 does. CONDITION CARRIED BY THE GO ITSELF, not added by me: a FRESH REHEARSAL per migration before each apply. The earlier preflight (6/6 live practicas, zero violations) was measured against a state of the base that no longer exists - terra_55 has been applied since. A rehearsal whose population predates an intervening apply is not a rehearsal of what will actually run. ORDER, and why it is not cosmetic: terra_50 applies first, then terra_51, and terra_51's rehearsal happens AFTER terra_50 is applied. Rehearsing both up front and then applying both would measure terra_51 against a base without terra_50 - a state that never exists at apply time. WHAT MUST LAND IN THESE ROWS BEFORE THEY CLOSE: rehearsal output per migration, the registration number of each apply, and the post-apply catalog verification. I verify the catalog independently against the live base afterwards - two lanes, not distrust. STANDING INSTRUCTION TO THE APPLYING LANE: if the fresh rehearsal disagrees with the earlier one in any respect, stop and report. Two rehearsals of the same migration disagreeing is a finding, not a discrepancy to reconcile privately.
  • wi-cli-venus assigned · 5w ago
    db-terra-cc
  • wi-cli-venus assigned · 5w ago
    db02-terra-ca
  • wi-cli-venus assigned · 5w ago
    db-terra-cc
  • wi-cli-venus assigned · 5w ago
    db02-terra-ca / db
  • wi-cli-venus note · 5w ago
    HANDOFF db-terra-cc -> db02-terra-ca, orden directa de Elazar en CLI 2026-09-10. Marker HOFF-131-mtvfq. terra_50_practica_zona_required.sql sigue en db/migrations/draft/, confirmado en disco ahora. Unica condicion viva: GO de apply de Elazar, eq 73. EL TRANSCRIPT DEL DRY-RUN NO ESTA DONDE LO BUSCARIAS: db/migrations/dryrun/2026-09-01-terra_50-arms1-6-selfchecking.result.md, NO en agents/db-terra/evidence/. Esa discrepancia de directorio ya hizo que el bloqueo se leyera como incumplido una vez.
  • wi-cli-venus titleChanged · 5w ago
    Pieza-or-region DB invariant is live; behavior exercise and source provenance need reconciliation
  • wi-cli-venus descriptionChanged · 5w ago
    was: "No deja guardar sin al menos una pieza dentaria o una region anatomica" es una promesa que le hacemos al cliente por escrito, y hoy la sostienen DOS COPIAS DE LA REGLA ESCRITAS POR SEPARADO, ninguna de ellas en la base. DESCRIPCION REESCRITA 2026-09-01 10:50 UTC. La version anterior decia, en presente, que createPractica "no encuentra ninguna restriccion". ESO DEJO DE SER CIERTO y la fila lo siguio diciendo mientras el propio codigo se etiquetaba con el numero de esta fila. Queda el texto viejo en el evento descriptionChanged; lo que sigue es lo medido, verificado por mi leyendo los archivos y no aceptado de un reporte. LAS DOS COPIAS, con linea. Copia A, base: createTerraPractica lleva su propio chequeo de cardinalidad de arrays en terra_42:95-102, y createPractica NO la llama - inserta a mano en practica-actions.ts:474-506. Copia B, aplicacion: practica-actions.ts:336-357 llama validateZonaForPractica, y la regla real vive en practica-zona-core.ts:141-160. La copia B es un SUPERCONJUNTO de la A: exige pieza si el eje pieza es requerido, exige region si el eje region es requerido, y en la linea 158 tiene ademas el piso de AL MENOS UNA. El codigo se rotula a si mismo "TERRA-131 INTERIM ACTION GUARD" en la linea 329 y dice con todas las letras que no afirma que exista una restriccion de base. EL NUCLEO, QUE ES LO QUE JUSTIFICA LA MIGRACION PENDIENTE: la regla existe DOS VECES en la aplicacion y CERO veces en la base, y nada verifica que las dos copias digan lo mismo. De hecho YA NO DICEN LO MISMO - la de la app es mas estricta. Un tercer escritor no encuentra nada, y una divergencia entre las dos no la reporta nadie. LA MITAD DE BASE SIGUE VACIA Y ESTA MEDIDA, no inferida. Contra pg_constraint y pg_trigger sobre terraPracticas, terraPracticasPiezasDentarias y terraPracticasRegionesAnatomicas: cero CHECK, cero trigger, cero constraint que imponga pieza-o-region. El unico CHECK de las tres tablas es terraPracticas_syntheticSessionId_check, cuyo cuerpo no habla ni de piezas ni de regiones. Los triggers no internos son los del patron de archivo mas los de numeracion, y NINGUNO compara existencia cruzada entre las dos tablas hijas - que es lo que la invariante necesita, porque la regla es "al menos una de las dos" y ningun trigger que mire UNA sola tabla puede imponerla. FORMA DEL ARREGLO, contestada y no asumida: NO se puede expresar como CHECK de una sola fila. Depende de ausencia o presencia de filas vigentes en DOS tablas hijas, o sea que necesita un constraint trigger. DENOMINADOR DEL "CERO VIOLACIONES", porque citado solo se lee como que el invariante se sostiene en produccion: la base tiene SEIS practicas, ninguna borrada, doce filas de piezas y tres de regiones. Cero violaciones sobre seis practicas no dice que la regla se sostenga; dice que casi nadie escribio todavia. Eso SUBE la prioridad en vez de bajarla: el costo de agregar el enforcement hoy es cero porque no hay nada que limpiar antes, y solo crece. CENSO DE ESCRITORES CON SU LIMITE DECLARADO: audit-terra-ca no encontro un tercer camino de INSERT no-test. UNKNOWN, escrito en vez de redondeado a cero: SQL directo contra produccion, llamadores externos, y objetos de base no representados en las migraciones aplicadas quedan fuera de un censo de fuente. ALCANCE: poner la invariante en la base, y de paso anotar o borrar el chequeo de createTerraPractica para que no se lea como cobertura del camino real, y actualizar el comentario de omision de terra_1_initial_schema.sql:233-240 para que diga que la impone de verdad. Hermanas de la misma clase, halladas en la misma pasada: TERRA-127 (campo requerido, solo navegador), TERRA-129 (arbol de antecedentes, solo navegador), TERRA-130 (membresia de docente, solo Node).
  • wi-cli-venus unblocked · 5w ago
    Live trigger catalog invalidates the apply-GO blocker; source/provenance and behavior evidence remain.
  • wi-cli-venus completed · 5w ago
    DB invariant reconciled independently: live migration registry has 20260902084000 terra_50_practica_zona_required; all three requireZona constraint triggers are ENABLE ALWAYS, deferred, and initially deferred; live missing-both count is zero. A rollback-only replica-mode fixture with a valid intra answer and no pieza/region produced the expected P0001 require-at-least-one-live-pieza-or-region rejection; transaction rolled back. The local draft/applied-directory discrepancy is repository provenance hygiene, not grounds to re-apply an already registered live migration.
tech-debt
6w ago by wi-cli-venus
5w ago
2026-09-10 15:05