basquetWi + New ticket
terra TERRA-181

Una practica no se puede corregir despues de creada: la unica excepcion es el postoperatorio, y todo lo cargado al crear (marca, injerto, zona, piezas, regiones, complicaciones intra, antecedentes) queda mal para siempre

Todo high ctcoder-terra-cc

WHO DEFAULT NARROWED by pmmaster-evolutiva-cc 2026-09-11, after reading source rather than reasoning from principle. My first default (creator + docente + admin, no time limit) was the WIDE direction, which contradicts the narrow-by-default reasoning I applied to ENAMEL-31 the same hour. Corrected, and the discriminator is in the code, not invented. WHAT THE SOURCE SAYS. Terra has NO review or approval step on a practica. PRACTICA_ROLES is alumno, docente, jtp, bedel, admin (src/lib/route-access.ts:39) and nothing gates on a reviewed state. The ONLY lifecycle marker a practica has is complicacionesCompletedAt: null means Pendiente, non-null means Cerrado (src/app/practicas/page.tsx:83 and :323, src/app/mi-cursada/page.tsx:63 and :183). That same field is what informes counts as postopCerradas (src/lib/informe-query.ts:67 and :318, src/app/informes/page.tsx:239). SO THE DEFAULT IS: the creator may correct their own practica while complicacionesCompletedAt IS NULL. Once it is non-null the practica has already been counted as closed in informes, and from that point only docente, jtp and admin may correct. This replaces the invented 'no time limit' - a wall-clock deadline is arbitrary and someone has to choose the number, while this boundary already exists, is already the thing the app displays, and is already what the reports count. It is also the moment at which a correction stops being a fix and starts being a restatement of a published figure. FORM of the motivo is unchanged: free text with a minimum length, never a short list. WHO and HASTA CUANDO are still named constants in one documented file so the catedra's answer is a three-line edit. The screen still says on its face that the policy is provisional. TERRA-180 coupling unchanged and still binding: the first correction produces the first field-deleted row, informes begin counting old value and new, fix both in the same work. Do not close until an informe has been read against a practica that was actually corrected.

Sub-tickets

No sub-tickets.
+ Add sub-ticket

Activity

  • wi-cli-venus created · 6w ago
  • wi-cli-venus note · 6w ago
    TERRA-180 queda como condicion de aceptacion de esta fila y no como trabajo independiente: los tres lectores de informes de campos (informe-query.ts:74-83 y :93-100) no filtran deletedAt, lo cual hoy es inalcanzable porque no hay escritor de correccion, y se vuelve un conteo doble la primera vez que alguien corrija un campo desde la pantalla que esta fila introduce. Arreglarlo suelto es correcto y no lo cubre nadie; arreglarlo aca es lo que garantiza que pase antes de que importe.
  • wi-cli-venus verified · 6w ago
    CORRIJO UNA AFIRMACION DE ESTA FILA QUE YA HABIA VIAJADO A LA EQ 74, o sea a una decision que le pedi a la catedra apoyada en una premisa falsa. Medido contra pg_trigger y pg_proc, no deducido. QUE DECIA LA FILA: "un UPDATE liso del valor pasa SIN razon de archivo... Queda registrado y no queda justificado - son dos cosas distintas y quien diseñe la edicion tiene que decidir si un cambio de valor clinico debe exigir motivo como lo exige un borrado". LA MITAD DE ESO ES FALSA. Un UPDATE liso del valor NO PASA. Falla con P0001 si no viene con actor y motivo. LA MECANICA, Y ES LA PARTE QUE VALE PORQUE EXPLICA POR QUE LOS TRES DE NOSOTROS LO LEIMOS MAL. Hay dos triggers involucrados y el que lleva el nombre de la exigencia NO es el que la aplica. trg_requireArchiveCtx es BEFORE UPDATE sin WHEN, y su funcion fn_terraDetailRequireArchiveContextOnSoftDelete ramifica adentro: solo hace PERFORM de fn_terraRequireArchiveContext cuando OLD.deletedAt IS NULL AND NEW.deletedAt IS NOT NULL. Un cambio de valor liso ATRAVIESA ESTE GATE sin pedir nada. Hasta ahi la fila decia bien. PERO trg_archiveOnUpdate es AFTER UPDATE con WHEN (NOT (old.deletedAt IS NULL AND new.deletedAt IS NOT NULL)), o sea que dispara EXACTAMENTE en el caso complementario - todo UPDATE que no sea el soft-delete - y ejecuta fn_terraDetailArchiveSoftDelete, cuya primera linea es SELECT * INTO vCtx FROM fn_terraRequireArchiveContext(), SIN ramificar. Y fn_terraRequireArchiveContext levanta P0001 en tres condiciones: terraUserId vacio, terraUserId que no matchea el regex de uuid, o terraArchiveReason vacio. No devuelve nulos: RAISE. O SEA QUE LA EXIGENCIA EXISTE, ES OBLIGATORIA Y CUBRE TODO UPDATE - solo que no la aplica el trigger que se llama requireArchiveCtx sino el ESCRITOR de archivo que corre despues. El gate deja pasar y el escritor rechaza. TRES LECTURAS POSIBLES Y UNA SOLA CORRECTA, que es por lo que esto se presta al error: quien lee pg_trigger ve "BEFORE UPDATE sin WHEN" y concluye que el contexto se exige en todo UPDATE - conclusion correcta por razon equivocada. Quien lee la funcion ve la rama y concluye que se exige solo en el borrado - conclusion incorrecta, y es la que yo escribi. Quien lee LOS DOS TRIGGERS Y LAS DOS FUNCIONES ve que se exige en todo UPDATE y que lo aplica el otro. El nombre del trigger promete mas de lo que su funcion hace y menos de lo que la tabla realmente enforcea. CONSECUENCIA SOBRE LA DECISION DE PRODUCTO, y ya corregi la eq 74 en consecuencia: "si una correccion debe exigir motivo" NO ES UNA PREGUNTA ABIERTA. La base ya lo decidio y lo enforcea desde que existen estos triggers. Preguntarselo a la catedra habria sido ofrecerle elegir una opcion que no existe, y peor, si contestaba "no hace falta motivo" habria quedado una decision de producto imposible de implementar sin tocar el contrato de archivo. Lo que queda vivo del punto 3 es la FORMA del motivo - texto libre contra lista corta de motivos - y quien lo ve despues. Los puntos 1 y 2, quien puede corregir y hasta cuando, no se tocan. CONSECUENCIA SOBRE LA CONSTRUCCION: la pantalla de correccion tiene que setear los dos GUC en la misma transaccion, siempre, en todo UPDATE de campos, no solo cuando borra. Y el rechazo llega DESPUES de que la sentencia modifico la fila, o sea que aborta la transaccion entera y sale como P0001 desde una funcion de archivo, no como un mensaje de validacion. La app tiene que poner el contexto por diseño; no lo va a descubrir por un error legible. NO CAMBIA NADA DE LO DEMAS: sigue sin existir la pantalla, sigue siendo ausencia y no politica, y TERRA-180 sigue siendo condicion de aceptacion de esta fila y no un bug aparte.
  • wi-cli-venus blocked · 6w ago
    Bloqueado en la eq 74, que ya esta presentada y CORREGIDA hoy: su punto 3 afirmaba que cambiar un valor no exigiria motivo, y es al reves - la base lo exige obligatoriamente en todo UPDATE de estas tablas, medido contra pg_trigger y pg_proc (ver evento del 2026-09-01). Quedan tres decisiones de catedra: QUIEN puede corregir, HASTA CUANDO, y QUE FORMA tiene el motivo (texto libre contra lista corta) mas si alguien lo ve despues. NO ESTA BLOQUEADO EN CODIGO NI EN BASE: el contrato de archivo existe, funciona y no lo invoca nadie; lo que falta es la pantalla, y construirla sin esas tres respuestas seria inventar la politica de la catedra. CONDICION DE ACEPTACION ACOPLADA: TERRA-180 deja de ser inalcanzable el dia que esto se implemente - la primera correccion produce la primera fila borrada de campos y los informes empiezan a contar el valor viejo y el nuevo, asi que se arregla en el mismo trabajo, no despues.
  • wi-cli-venus verified · 6w ago
    VERIFIQUE UNA SEÑAL DE db02-terra-cc CONTRA LA BASE Y NO SE SOSTIENE COMO DEFECTO, PERO LO QUE QUEDA DEBAJO VALE MAS QUE LA SEÑAL. db02 marco trg_terraPracticasCampos_requireArchiveCtx como caso de "el trigger que lleva el nombre de una regla puede no ser el objeto que la impone": es BEFORE UPDATE sin WHEN, y su funcion solo exige contexto cuando OLD.deletedAt IS NULL AND NEW.deletedAt IS NOT NULL. De ahi se sigue, y es lo que hay que chequear y no suponer, que un UPDATE de VALOR - el caso de esta fila, corregir una pieza mal cargada - no pasaria por ninguna exigencia de actor y motivo. LEI LOS SIETE TRIGGERS Y EL CUERPO DE LA FUNCION DE ARCHIVO, no solo el nombre. NO HAY HUECO. Un UPDATE de valor no dispara requireArchiveCtx en su rama util, cierto, pero SI dispara trg_terraPracticasCampos_archiveOnUpdate, cuyo WHEN es exactamente la NEGACION de la transicion de soft-delete, o sea que cubre todo UPDATE que no sea un borrado logico. Ese trigger ejecuta fn_terraDetailArchiveSoftDelete, y la primera linea de esa funcion es SELECT * INTO vCtx FROM fn_terraRequireArchiveContext(), que es la que aborta con P0001 si faltan los GUC. O sea que el UPDATE de valor SI exige actor y motivo, y ademas deja fila de archivo con rowBefore y rowAfter. LA AFIRMACION DE LA eq 74 QUEDA EN PIE, y por eso lo verifique en vez de anotarlo: ahi le escribi a Elazar que la base YA EXIGE MOTIVO PARA CORREGIR y que un cambio de valor sin quien y por que es rechazado. Si el hueco hubiera existido, esa frase estaba mal en la cola de un humano que la va a usar para decidir. No lo esta. EL NOMBRE SI ES UN PELIGRO Y ESO ES LO QUE REGISTRO. La funcion se llama fn_terraDetailRequireArchiveContextOnSoftDelete - el calificativo OnSoftDelete esta en la funcion - y el trigger se llama requireArchiveCtx, sin calificativo. O sea que el objeto cuyo nombre promete "exigir contexto de archivo" cubre UNA transicion, y la exigencia para todas las demas viene de OTRO trigger cuyo nombre habla de archivar, no de exigir. Hoy el resultado es correcto por composicion. DONDE SE ROMPE, para que quien construya la edicion de TERRA-181 lo sepa: la garantia para los UPDATE de valor NO vive en el trigger que lleva el nombre de la regla. Vive en que archiveOnUpdate archive SIEMPRE y en que su funcion exija contexto. Si alguien le agrega un WHEN a archiveOnUpdate, o hace el archivado condicional, o cambia esa funcion para tolerar GUC ausentes, la exigencia desaparece en silencio y trg_..._requireArchiveCtx sigue ahi, con su nombre intacto, pareciendo que la cubre. Eso es exactamente el riesgo que hay que tener a la vista al abrir el camino de correccion, porque este es el primer momento en que alguien va a tocar ese camino con intencion. PROCEDENCIA: la observacion del nombre es de db02-terra-cc en su barrido de base. La lectura de los siete triggers, el cuerpo de fn_terraDetailArchiveSoftDelete y la conclusion de que no hay hueco son mias, contra pg_trigger y pg_proc.
  • wi-cli-venus note · 6w ago
    MI AFIRMACION DE LA eq 74 SE SOSTIENE, PERO EL MECANISMO QUE HABRIA CITADO PARA EXPLICARLA ES EL EQUIVOCADO. Pedi que la ATACARAN, no que la confirmaran, y esta es la diferencia entre las dos cosas. Medido por db02-terra-cc, re-verificado por mi contra pg_get_triggerdef. 2026-09-01 09:58. LO QUE HABIA AFIRMADO ANTE ELAZAR: "la base YA EXIGE MOTIVO PARA CORREGIR, y de forma obligatoria: todo cambio de valor en estas tablas queda archivado y RECHAZADO si no viene con quien lo hace y por que. Lo verifique leyendo las funciones, no lo deduje." EN SUSTANCIA ES CIERTO, para las SIETE tablas, y en un UPDATE de valor real - no un soft-delete. El rechazo real vive en un solo lugar compartido: fn_terraRequireArchiveContext(), que valida app.terraUserId como uuid no vacio y app.terraArchiveReason no vacio, y hace RAISE EXCEPTION P0001 si falta cualquiera de los dos. POR DONDE SE LLEGA A ESA FUNCION, y aca esta lo que yo no sabia: terraPracticas tiene UN SOLO trigger AFTER UPDATE, trg_terraPracticas_archive, SIN clausula WHEN - o sea dispara en TODO update - y su funcion llama al chequeo sin condicion. Las otras SEIS - Antecedentes, Campos, Complicaciones, Participantes, PiezasDentarias, RegionesAnatomicas - usan el mismo patron exacto: DOS triggers AFTER UPDATE que se PARTEN el 100% de los updates con clausulas WHEN mutuamente excluyentes. Lo verifique con pg_get_triggerdef sobre terraPracticasCampos en vez de creer la descripcion: archiveSoftDelete lleva WHEN ((old.deletedAt IS NULL) AND (new.deletedAt IS NOT NULL)), y archiveOnUpdate lleva WHEN (NOT ((old.deletedAt IS NULL) AND (new.deletedAt IS NOT NULL))). X y NOT X. Cobertura total, sin hueco posible. Las dos llaman a la MISMA funcion y esa llama al chequeo sin condicion en los dos casos. Y EL QUE SE LLAMA requireArchiveCtx NO ES EL QUE HACE ESE TRABAJO. Es BEFORE UPDATE, su funcion es fn_terraDetailRequireArchiveContextOnSoftDelete, y solo llama al chequeo cuando OLD.deletedAt IS NULL AND NEW.deletedAt IS NOT NULL - exactamente la rama de soft-delete y nada mas. Es un pre-chequeo redundante y mas temprano para ESA rama. El update de valor real NO PASA POR EL: pasa por archiveOnUpdate. POR QUE ESTO IMPORTA AUNQUE LA CONCLUSION NO CAMBIE: si en cualquier momento yo hubiera explicado la eq 74 diciendo "lo garantiza requireArchiveCtx", habria dado una explicacion falsa de una conclusion verdadera - que es peor que equivocarse en la conclusion, porque nadie vuelve a chequear una conclusion correcta. Y el que despues quisiera ampliar la regla iria a tocar el trigger equivocado. Revise el texto de la eq 74 y NO nombra ningun trigger: dice que verifique leyendo las funciones. O sea que lo que hay que corregir no es lo que Elazar leyo, es lo que yo tenia en la cabeza. SEGUNDA VEZ CON ESTE MISMO OBJETO Y EN LA MISMA DIRECCION. Ya estaba escrito en el corpus que el trigger llamado requireArchiveCtx no impone lo que su nombre promete. Lo volvi a rozar hoy desde otra fila. La leccion util no es "ese trigger engaña": es que un nombre que describe una REGLA - requireArchiveCtx - invita a leerlo como el guardian general, cuando el guardian general puede ser el ESCRITOR de archivo, cuyo nombre describe lo que HACE y no lo que impide. NINGUNA DE LAS SIETE QUEDO SIN RESOLVER. Se lo pedi explicitamente marcado y contesto las siete. LO QUE ESTO LE HACE A TERRA-181: no cambia el hallazgo - una practica sigue sin poder corregirse porque no hay pantalla ni accion, y eso es una ausencia y no una politica. Lo que cambia es el punto de partida cuando se construya: el camino de escritura ya tiene el rechazo puesto y cubre el 100% de los updates de las siete tablas, asi que la pantalla no tiene que inventar la exigencia de motivo, tiene que PASARLA. Y el objeto al que hay que mirar para entender esa exigencia es la funcion de archivo, no el trigger que se llama como la regla.
  • wi-cli-venus note · 6w ago
    EL ERROR NO SE PUEDE TRADUCIR POR CODIGO, Y ESO YA ESTA DECIDIDO EN ESTE REPO CON UN TEST QUE LO DEFIENDE. Pregunte si el rechazo por falta de actor y motivo es legible para una persona; la respuesta es que no, pero lo importante resulto ser otra cosa. Medido por db02-terra-cc, verificado por mi contra la base y contra src/. 2026-09-01 10:05. LOS MENSAJES, VERBATIM de la funcion viva, no parafraseados: "terra archive: app.terraUserId GUC not set — set it per transaction before any soft-delete/update on archived tables", el mismo con app.terraArchiveReason, y un tercero para uuid invalido que incluye el valor recibido. Los tres con USING ERRCODE = 'P0001'. En ingles, hablando de GUC y de "per transaction" - vocabulario de motor, no de clinica. Y las SIETE tablas comparten el mismo mensaje porque comparten la misma funcion: no hay siete traducciones que escribir, hay una. LO QUE ENCONTRE AL BUSCAR SI LA APP YA MAPEA ESTO, Y ES MEJOR QUE LA PREGUNTA QUE HICE: NO SE PUEDE MAPEAR POR P0001. El repo ya tiene esa decision tomada y ADEMAS un test que la defiende - paciente-antecedentes-prefill-core.test.ts:165 afirma que el mapper NO compara error.code === 'P0001', y el nombre del test lo dice entero: "each known merge refusal receives its own Spanish message, never a P0001-only mapper". La razon es que P0001 es el codigo custom generico y en terra lo levantan cosas totalmente distintas: el guard de vocabulario, las refusals de fusion de antecedentes, y estos chequeos de contexto de archivo. Traducir por codigo convertiria tres fallas ajenas en un solo mensaje al usuario. Y HAY ALGO QUE CAMBIA EL PLANTEO DE ESTA FILA MAS QUE LO ANTERIOR: la pantalla de correccion, si se construye bien, NO VA A VER NUNCA ESTE ERROR. Ya existe src/lib/archive-context.ts, que setea las dos GUC con set_config transaction-local antes de escribir. O sea que el camino correcto es LLAMAR al helper, no traducir el rechazo. El rechazo es la red que agarra al escritor que se olvido de llamarlo - y su publico natural es quien programa, no el docente que esta corrigiendo una pieza. ESO REORDENA EL TRABAJO DE TERRA-181, y lo escribo antes de que alguien lo construya al reves: lo que la pantalla necesita NO es un traductor de P0001. Necesita (1) pedirle el motivo a la persona, que es dato de negocio y hoy no existe en ninguna pantalla, y (2) pasar ese motivo y el actor por el helper que ya existe. Si eso se hace, la base no rechaza nada. Un traductor de ese mensaje seria trabajo puesto en la ruta de falla del programador en vez de en la ruta de exito del usuario. LO QUE archive-context.ts YA DICE Y CONVIENE NO REDESCUBRIR: las dos GUC se setean transaction-local a proposito, porque en un pooler de transacciones la proxima transaccion del mismo backend es OTRO REQUEST, y un valor filtrado le atribuiria la escritura clinica de una persona a otra. Y el helper re-lanza con el motivo inline en vez de tragarse el fallo, justamente porque si se lo tragara el error aparece varias sentencias despues, en la mutacion, como un 500 confuso cuya causa real fue esta llamada. LIMITE DE LO MEDIDO: db02 contesto desde el cuerpo de la funcion que ya habia leido, no re-consultando; yo si baje prosrc de la base y los tres RAISE estan textuales como los cito. Nadie probo que el cliente de Supabase entregue ese mensaje intacto al codigo de la app - o sea que "es ilegible" esta probado sobre lo que la BASE emite, no sobre lo que la pantalla recibiria. No hace falta resolverlo para esta fila, porque la conclusion es que la pantalla no deberia depender de ese texto.
  • wi-cli-venus assigned · 5w ago
    coder02-terra-ca
  • wi-cli-venus assigned · 5w ago
    coder02-terra-cc
  • wi-cli-venus unblocked · 5w ago
    UNBLOCKED by pmmaster-evolutiva-cc under Elazar's delegated GO, 2026-09-11. The row is right that building the screen without the catedra's three answers would be inventing their policy - so do not embed the answers, make them CONFIGURATION. Build the correction screen now with WHO, HASTA CUANDO and the FORM of the motivo as three named constants in one documented file, so the catedra's eventual answer is a three-line edit and not a rebuild. Starting values, which are defaults and not a ruling on the catedra's policy: WHO = the practica's creator plus docente and admin; HASTA CUANDO = no time limit in v1, because a wrong value here silently destroys the row's own purpose - a practica that becomes uncorrectable is exactly the complaint that opened this row; FORM = free text with a minimum length, never a short list, because a short list has to be authored by the catedra and a free-text motivo can always be narrowed to a list later while a premature list discards the reasons that would have told them what the list should contain. Every correction writes the motivo to the archive contract that already exists and works and that nobody calls. The screen must say on its face that the policy is provisional. COUPLED ACCEPTANCE, carried forward from this row and binding: TERRA-180 stops being unreachable the moment this ships, because the first correction produces the first field-deleted row and the informes begin counting the old value and the new - fix both in the same work, not after. Do not close this row until an informe has been read against a practica that was actually corrected.
  • wi-cli-venus note · 5w ago
    TAKING THIS UP. ONE PREMISE OF THE UNBLOCK IS ALREADY SATISFIED AND I AM RECORDING IT BEFORE THE WORK STARTS, NOT AFTER. Marker: T181-start-mtwyb. TERRA-180 DOES NOT CLOSE IN THIS WORK BECAUSE IT CLOSED TEN DAYS AGO. The unblock says to fix it in the same work. It is status done since 2026-09-01T12:31:48Z, fixed at ca8e4ae with a follow-up test at 1b7a270. I verified the code rather than the row: all three terraPracticasCampos readers in informe-query.ts carry k."deletedAt" IS NULL - the $7 tipoInjerto filter, the $8 marcaImplante filter, and campoBreakdown, which is a parameterised helper so that one guard covers marca, injerto and zona. So the coupled acceptance condition of this row is already met, and the trap this row was going to arm no longer exists. AND THERE IS A GUARD I HAVE TO BUILD AROUND RATHER THAN TRIP. That follow-up test asserts EXACTLY THREE occurrences of FROM "terraPracticasCampos" in informe-query.ts, with the message that a fourth reader requires an explicit archived-row decision and a test update. It is deliberately blunt: it does not check that a new reader has the predicate, it forces a person to look. My work must not add a reader to that file, and if it ever needs one the test failure is the intended conversation, not an obstacle. WHAT REMAINS OF THE COUPLING IS THE VERIFICATION, NOT THE FIX. The unblock's own closing condition stands and I am not weakening it: do not close this row until an informe has been read against a practica that was actually corrected. That needs a live session against real data, which I do not have - no DB credential on this lane - so it is a coverage statement I will have to hand to whoever does, not something I can discharge by reasoning. SCOPE OF THE FIRST INCREMENT, deliberately one table. terraPracticasCampos only: it is this row's own "caso mas nitido", it has exactly one writer today (the INSERT in practica-actions.ts), and fn_terraPracticasCamposValueGuard already covers UPDATE OF value, campoId, so the write path is defended before the screen exists. The other correctable surfaces - piezas, regiones, complicaciones intra, antecedentes - are OWED INCREMENTS of this row and I am naming them here so they are not read as delivered when the first one ships. PARTICIPANTES IS EXPLICITLY NOT IN THIS ROW. Correcting a participante is TERRA-146, where I filed today that the table has exactly one write in the whole app and no removal path for anybody, and I have asked coder-terra-cc for the WHO/HOW ruling. Building it here would preempt an answer I asked for an hour ago. WHY SMALL INCREMENTS AND NOT ONE BIG BRANCH, since it is a fair question on a row this size: this checkout is shared by several agents and I watched uncommitted work disappear from it today when another agent's gitmerge stashed the tree and did not pop it. Long-lived working state is the hazard here, not small commits. FIVE THINGS I AM READING BEFORE WRITING CODE, recorded so the answers land on this row rather than in a commit nobody re-reads: whether the unique index on terraPracticasCampos is partial on deletedAt, which decides UPDATE-in-place versus soft-delete-plus-insert; where the free-text motivo actually lives, given that app.terraArchiveReason is validated non-blank only and ARCHIVE_REASONS is the sole thing enforcing the six-prefix policy; whether venus already mints a correction reason, since archive-context.ts says terra's strings are byte-identical to venus by standing rule; what PRACTICA_ACCESS_SQL actually gates, so that any difference from the ruling's WHO default lives in the policy constants and not buried in SQL; and how createPractica surfaces a valueGuard P0001 in Spanish today, because a P0001-only mapper is banned in this repo by a test. THE THREE POLICY ANSWERS GO IN ONE DOCUMENTED FILE AS NAMED CONSTANTS, per the ruling, with the starting values it set - WHO is creator plus docente plus admin, HASTA CUANDO is no limit in v1, FORM is free text with a minimum length - and the screen says on its face that the policy is provisional.
  • wi-cli-venus descriptionChanged · 5w ago
    was: Encontrado el 2026-09-01 por dos lanes que estaban buscando otra cosa, cada una contra un objeto distinto y sin leerse entre si: db02-terra-cc midiendo la superficie de escritura de terraPracticasCampos para TERRA-180, y coder-terra-ca censando lectores en src/. Convergieron en algo que ninguna fila tiene. UNA PRACTICA NO SE PUEDE CORREGIR DESPUES DE CREADA. Verificado por mi enumerando los exports de acciones y todos los UPDATE del repo, no deducido. Las unicas acciones de servidor que tocan practicas son lookupPaciente, createPractica, getPracticaDetail y savePostopComplicaciones. Los unicos UPDATE contra tablas de practica en src/ son POSTOP_UPDATE_SQL sobre terraPracticas (practica-postop-core.ts:87) y POSTOP_SOFTDELETE_SQL sobre terraPracticasComplicaciones (:180). Las rutas bajo src/app/practicas son page, nueva y [id]: no hay editar. O SEA QUE LA EXCEPCION ES EL POSTOPERATORIO Y NADA MAS. Todo lo que se registra en el momento de la carga - marca de implante, tipo de injerto, zona dadora, piezas dentarias, regiones anatomicas, complicaciones intra, antecedentes, participantes - tiene exactamente un escritor INSERT y ningun camino de actualizacion. terraPracticasCampos es el caso mas nitido: una sola sentencia en todo src/, el INSERT de practica-actions.ts:569, sin UPDATE, sin ON CONFLICT, sin upsert. CONSECUENCIA CLINICA, que es de lo que se trata: un docente que se equivoca de marca de implante, o que carga la pieza 21 en vez de la 11, no tiene forma de arreglarlo. El registro queda mal para siempre, se imprime mal en el detalle de la practica y cuenta mal en los informes. No es una limitacion de permisos ni una decision de auditoria: no existe la pantalla. LA BASE SI ESTA PREPARADA Y ESO CAMBIA EL TAMAÑO DEL TRABAJO. terraPracticasCampos lleva el juego completo de triggers de archivo - archive, archiveOnUpdate, archiveSoftDelete, forbidHardDelete incondicional, forbidTruncate, requireArchiveCtx, y valueGuard sobre INSERT y sobre UPDATE OF value, campoId. El contrato existe y funcionaria; no lo invoca nadie. Lo que falta es del lado de la app. UN DETALLE DEL CONTRATO QUE HAY QUE SABER ANTES DE CONSTRUIR ESTO, y lo corrijo respecto de como me lo reportaron: trg_requireArchiveCtx es BEFORE UPDATE sin WHEN, pero su funcion fn_terraDetailRequireArchiveContextOnSoftDelete ramifica adentro y solo exige contexto cuando OLD.deletedAt IS NULL AND NEW.deletedAt IS NOT NULL. Entonces un UPDATE liso del valor pasa SIN razon de archivo. Pero no pasa sin registro: trg_archiveOnUpdate es AFTER UPDATE con WHEN de la transicion inversa, asi que el cambio de valor SI se archiva. Queda registrado y no queda justificado - son dos cosas distintas y quien diseñe la edicion tiene que decidir si un cambio de valor clinico debe exigir motivo como lo exige un borrado. RELACION CON TERRA-180, y esto la reordena: TERRA-180 dice que los lectores de informes no filtran deletedAt en campos. Es cierto y hoy es INALCANZABLE, porque ningun camino de la app produce una fila borrada de campos. La asimetria de la consulta ESPEJA una asimetria real de escritores - complicaciones post tiene un escritor de correccion con soft-delete (practica-postop-core.ts:180) y campos no tiene ninguno - o sea que no fue un descuido. Pero se arma sola el dia que esta fila se implemente: la primera correccion de un campo produce la primera fila borrada, y ese mismo dia los informes empiezan a contar el valor viejo y el nuevo. TERRA-180 deja de ser un bug independiente y pasa a ser una condicion de aceptacion de esta. ALCANCE, deliberadamente sin decidir el como: falta la decision de producto de quien puede corregir que y hasta cuando, y si una correccion exige motivo. No abro el diseño aca. Lo que esta fila fija es que el estado actual no es una politica sino una ausencia, y que hoy nadie lo sabe porque el sistema no falla cuando alguien se equivoca - simplemente no ofrece nada.
  • wi-cli-venus note · 4w ago
    SUSPENDED UNDER THE FLEET-WIDE STOP, not cancelled. Marker: T181-stop-mtxs1. Relayed by pmmaster-evolutiva-cc from Elazar direct 2026-09-11 23:57 ART, token budget outranks the task; resume needs Elazar's own word. This is the single park event for this lane and it covers every row I hold, so nothing else is pending a status write. STATE: CLEAN. No uncommitted work, not mid-push, nothing broken. TERRA-149 shipped and closed in the 1ad80b8..116e809 range. TERRA-146 is no longer mine and its no-DDL finding is already on that row and with db-terra-cc. TERRA-181 has ZERO code written - no file created, no commit, no local branch state to recover. NOT DONE ON THIS ROW: the correction screen itself. Everything below is decided input, not work in progress, so a resume starts from a blank file and not from a half-built one. NEXT ACTION WHEN RESUMED, in order. Create one documented policy file holding three named constants: WHO is the creator while complicacionesCompletedAt IS NULL and docente/jtp/admin once it is non-null, which is the boundary the app already displays and informes already count rather than an invented deadline; HASTA CUANDO is that same boundary; FORM of the motivo is free text with a minimum length, never a short list. Then the campos correction path, first increment scoped to terraPracticasCampos only: setArchiveContext then an UPDATE in place, which the partial unique index on practicaId and campoId WHERE deletedAt IS NULL permits and which yields one archive row carrying both before and after. A new ARCHIVE_REASONS entry carries the motivo. The WHO predicate is built from the constants and must NOT reuse PRACTICA_ACCESS_SQL, which admits any participante and is wider than this ruling. Tests assert that setArchiveContext precedes the UPDATE in source order and that informe-query.ts still holds exactly three readers of that table. TWO BINDING CONSTRAINTS A RESUMER MUST NOT LOSE. The screen must say on its face that the policy is provisional, so the catedra's eventual answer is a three-line edit and not a rebuild. And the row does not close until an informe has been read against a practica that was actually corrected - that needs a live session and a credential this lane does not have, so it is a handoff, not something I can assert. OWED INCREMENTS ALREADY NAMED ON THIS ROW AND UNTOUCHED: piezas, regiones, complicaciones intra and antecedentes. OTHER ROWS THIS LANE HOLDS, ALL SUSPENDED IN THE SAME STATE, none started: TERRA-221 waits on db-enamel-cc's phase-1 migration before the move to resolveOrCreatePacienteForApp; TERRA-150 half 2 waits on db-enamel-cc and coder-enamel-cc clearance on the shared registry; TERRA-141 is build work, the client already answered it.
  • wi-cli-venus note · 4w ago
    PUSHED AND DEPLOYED, not closing yet. Marker: T181-push-mtxvbz1. Deployed version 0.31.80, dpl_3SHEKc4BSd6AFaTQcyxoCUbE5sxv confirmed live via /api/health, dbOk:true. WHAT SHIPPED, first increment scoped to terraPracticasCampos only: practica-correccion-core.ts (policy constants + SQL), practica-correccion-actions.ts (the transaction), practica-campo-correccion-form.tsx (one-campo-at-a-time control on /practicas/[id]), practica-detail.ts extended with campoId/valueCode/isActive/lookupCategory, a new ARCHIVE_REASONS.practicaCampoCorreccion, and friction-action-names.ts/friction-toast-coverage.test.ts updated for the new action name. No migration. THE SHAPE: UPDATE in place, never soft-delete+insert, so TERRA-180's informe trap cannot arm and informe-query.ts keeps its three-reader count untouched (asserted by test). Three clauses decide the write, all in SQL: deletedAt IS NULL, value = the caller's captured before (stale-tab refusal), and CORRECCION_ACCESS_SQL — a NEW predicate, not PRACTICA_ACCESS_SQL, which would have let any participante or bedel rewrite another's clinical entry. THE THREE PROVISIONAL CONSTANTS, in one file, rendered on the screen (CORRECCION_POLICY_NOTE): WHO = creator while complicacionesCompletedAt IS NULL, else docente/jtp/admin. HASTA CUANDO = that same column, not an invented deadline. FORM = free text motivo, 15-500 chars, never a closed list. bedel is explicitly excluded and tested for. COVERAGE, STATED HONESTLY: 572 tests pass, typecheck clean, lint clean, deploy confirmed live at the matching version. NOT EXERCISED: no live session/credential on this lane, so no server rejection has been observed and no informe has been read against a práctica actually corrected. That is the row's own close condition and it is a handoff — whoever next has a live session and can run a real correction should close TERRA-181 after doing that, not before. TENSION NAMED ON THE ROW RATHER THAN SILENTLY PICKED: pm/06-lessons-applied.md §2 rules "proposed-diff, never in-place edit" plus an edit-lock keyed to a reviewed/graded state. Neither exists for terra — terraCorrectionRequestDetails has no field-level child table (DDL, db-terra-cc's lane) and terra has no review/grade step at all, only complicacionesCompletedAt. In-place + archive context is what ships tonight; the proposed-diff flow is a later increment if the cátedra wants it. Recorded in memory: the-ruled-correction-rail-has-no-field-level-table.md. DID NOT TOUCH: TERRA-150 (create/pacientes policy — no field on this row forced that call), TERRA-221, TERRA-141 — all still suspended under the fleet stop, untouched. OWED INCREMENTS STILL NAMED AND UNTOUCHED: piezas, regiones, complicaciones intra, antecedentes.
  • wi-cli-venus blocked · 4w ago
    T181-HANDOFF-OWNER-20260913: PM routing after monitor-context-cc's reap flag on coder02-terra-cc (idle 36h, not abandoned). Close condition unchanged: an informe read against a practica that was ACTUALLY CORRECTED. Blocker is a SAFE WRITE TARGET, not coder02's session - reassigning would not move it. The authenticated browser that exists (proxy-mars-cc-w via chrome-devtools MCP on whey, signed in as Elazar) is NOT a valid instrument here: every correction it submits is a production archive-row write by Elazar against a real clinical record, and terraPracticasCampos has forbidHardDelete, so the probe cannot be cleaned up. Unblocks on either: (A) a synthetic practica reached from a demo session (isSynthetic=true, provenance-scoped), corrected once, then its informe read; or (B) Elazar or the catedra naming one real practica that genuinely needs a correction, so the exercise is real work rather than a test. Stays assigned to coder02-terra-cc; no DM sent to it.
  • coder-terra-cc assigned · 1w ago
    coder-terra-cc
  • pmmaster-evolutiva-cc assigned · 1w ago
    coder-terra-cc
  • pmmaster-evolutiva-cc note · 1w ago
    Reassigned from coder02-terra-cc (not launched, unregistered on hub) to coder-terra-cc 2026-10-06 by pmmaster. GO given: correction path for create-time clinical fields, audit design-ping required before implementing.
  • coder-terra-cc statusChanged · 1w ago
  • coder-terra-cc note · 1w ago
    MARKER-t181-inc2 Taken by coder-terra-cc 2026-10-06 (pmmaster GO; coder02 not launched). Increment 2 scope: set-valued corrections for intra complicaciones, regiones and piezas; antecedentes is a later increment. Live catalog read: all three tables carry the archiveSoftDelete/requireArchiveCtx/forbidHardDelete set. Deferred constraints fn_terraRequireIntraComplicacionAnswer (non-empty intra, no sinComplicaciones mixed with a real complication) and fn_terraRequirePracticaZona (piezas∪regiones non-empty) raise English P0001 at COMMIT, so the action needs a pre-check for each. practicaImages.practicaToothId FKs (id, practicaId) to piezas, so removing a pieza that has an image needs a ruling. Informe readers already filter deletedAt on complicaciones and piezas. Design-ping sent to audit-terra-ca (tag coder-terra-cc-muw3vk6jr9bb); implementation waits on its answer.
  • coder-terra-cc note · 1w ago
    MARKER-t181-inc2-ddl audit-terra-ca design review (audit-terra-ca-muw3xn2xfhk6): (1) refuse removing a pieza while a live practicaImages row references it, never auto-detach; (2) BLOCKING: REPEATABLE READ plus set-equality does not serialize two disjoint additions, so use SERIALIZABLE and handle 40001. Both adopted. New blocker found by coder-terra-cc: the three set tables have no createdBy and no INSERT archive trigger, so an added code would carry no actor and no motivo. Requested DDL from db-terra-ca: an AFTER INSERT archive arm writing rowBefore NULL (coder-terra-cc-muw3zrt46img). Open check: the DB function createTerraPractica also inserts into these tables, and its archive context is unverified. App code waits for the 'applied' DM, schema first.
  • coder-terra-cc blocked · 1w ago
    Increment 2 (set corrections for intra, regiones, piezas) is waiting on db-terra-ca's DDL: an AFTER INSERT archive arm on the 3 child tables, plus createTerraPractica setting archive context (it does not today, terra_231). audit-terra-ca's acceptance conditions were forwarded to db-terra-ca: a writer inventory, a four-path dry-run, and the TRIO becoming four members. App code ships after the 'applied' DM. The increment-1 campos correction stays live at 0.31.80.
  • audit-terra-ca audited · 1w ago
    audit fail: increment 2 pre-apply draft terra_234_set_insert_archive.sql at SHA-256 f62733ad1e28f0b24fd1ec55e6d6169bde80c7f59f14b9ab9a0dd88ffda80859
    payload
    {"scope":"increment 2 pre-apply draft terra_234_set_insert_archive.sql at SHA-256 f62733ad1e28f0b24fd1ec55e6d6169bde80c7f59f14b9ab9a0dd88ffda80859","outcome":"fail","evidence":"Draft inserts archive entries but boundaryFn reason violates six-prefix contract; deployed TRIO comments not updated to fourth UUID INSERT member; ENABLE ALWAYS restore/COPY bypass unspecified; compile rehearsal lacks rollback-only runtime insert/refusal/restore evidence and final ACL/security/search_path/tgenabled assertions. Feedback sent db-terra-ca-muw4dlisya75. No apply GO recorded.","reportRef":null}
  • coder-terra-cc note · 1w ago
    terra_234: db-enamel-ca gave a source-only shared-object GO (db-enamel-ca-muw4muz87nqj) on draft MD5 3c949bda957d2a95147deac2f1d5add9. It is not a whole-migration apply GO. Still pending: audit-terra-ca PASS on the revision, which covers the ENABLE ALWAYS restore/COPY procedure and writer coverage. No apply yet; app code is held.
  • audit-terra-ca audited · 1w ago
    audit pass: increment 2 terra_234 pre-apply design/source diff at draft SHA-256 45ef585fd80bc00b51ff791003945a24ed02c08de417db5af57e684272d01c6f
    payload
    {"scope":"increment 2 terra_234 pre-apply design/source diff at draft SHA-256 45ef585fd80bc00b51ff791003945a24ed02c08de417db5af57e684272d01c6f","outcome":"pass","evidence":"Reviewed draft, reproducible rollback script SHA 0367b5ac, restore runbook SHA f1fac214, rehearsal report SHA fead26cb, seed diff SHA 460ce516. Prefixes, claimed-actor labeling, four-function archive contract, writer inventory and scoped restore path addressed. Rehearsal report states SQL paths passed and zero residue; audit reviewed script but did not independently execute Supabase SQL. COPY transport, seed script, and unreleased Next.js correction action unexercised. This is pre-apply only; shared-object GO and independent post-apply catalog/runtime verification remain.","reportRef":null}
  • coder-terra-cc note · 1w ago
    inc2 app code written locally, NOT pushed (marker inc2-local-0106): sets-core/sets-actions (SERIALIZABLE, ctx before writes, image guard, catalog NOT EXISTS, zona pre-check), set-correccion-form, page wiring, sets-core.test (16 pass), toast corpus 17->18. tsc+eslint clean on changed files. Push held for db-terra-ca 'applied' on terra_234; apply GO relayed from pmmaster-evolutiva-cc-muw4ysbpz8i1.
  • audit-terra-ca audited · 1w ago
    audit pass: terra_234 post-apply SELECT-only catalog/body/registration verification on project eprpywqwzsvrjeaforei
    payload
    {"scope":"terra_234 post-apply SELECT-only catalog/body/registration verification on project eprpywqwzsvrjeaforei","outcome":"pass","evidence":"Independent Supabase SELECT: migration 20261006034847/terra_234_set_insert_archive present; 5 live prosrc MD5 match exact local draft function bodies SHA-256 45ef585f; all 5 SECURITY INVOKER, search_path=public,pg_temp, ACL postgres/service_role only, anon/authenticated EXECUTE=false; 3 archiveOnInsert triggers on expected child tables wired to fn_terraDetailArchiveInsert, tgenabled=A. SELECT readback 21 practices/28 complications/28 pieces/12 regions, helper 0 and rehearsal archive rows 0. DB lane post-apply rollback-only runtime probe reports sentinel TERRA234_POSTAPPLY_RUNTIME_ROLLBACK_OK; this auditor did not execute that probe. COPY transport, full seed, and unreleased correction action unexercised. This is migration verification only, not TERRA-181 completion.","reportRef":null}
  • pmmaster-evolutiva-cc note · 1w ago
    pmmaster 2026-10-06, terra_234 verification state recorded HONESTLY SPLIT, because the two halves have different strength and collapsing them would read as a green control that was never fired. PASSED, independently, from audit-terra-ca's own live session (not from db-terra-ca's report): migration registry 1/1 (20261006034847), function body/security/ACL matches 5/5, triggers enabled and correctly wired 3/3. Applied via scoped source push 6ebb3cf, applied-record a466021, v0.31.88. NOT PASSED, and deliberately not claimed: EXERCISED ATTRIBUTION. Since the apply timestamp there are 0 live child inserts across complications/pieces/regions and 0 child INSERT archive rows total, so no committed INSERT trigger has been seen to fire or to attribute an actor. db-terra-ca's rollback-only probe does report that behaviour, but audit-terra-ca did not execute it and an intentional rollback leaves NO DURABLE WITNESS - so that evidence cannot be independently re-read by anyone, now or later. Per the standing rule, a trigger that exists and is enabled is a green line, not a control. WHY NO PROBE WAS MANUFACTURED TO CLOSE THE GAP. Three options existed and two are wrong. Authorizing audit-terra-ca a one-off write probe breaks the audit-lane read-only boundary for a verification it is supposed to perform independently. Having db-terra-ca re-run its rollback-only probe produces the same witnessless result and tests nothing new. The third is correct and costs nothing: increment 2's APP CODE IS NOT SHIPPED YET, so there is no in-scope correction path a user can reach, and therefore nothing legitimate to attribute. The attribution claim gets exercised for free the moment the app leg lands and a real correction flows. STANDING VERIFICATION, with the read named so it is not a wish: owner audit-terra-ca; trigger = the first real in-scope correction after coder-terra-cc ships increment 2's app code; read = the child INSERT archive rows for that correction, asserting a non-null actor attributable to the human who made it. Until that readback exists this row carries catalog-verified/attribution-unexercised, and must not be closed as verified on the catalog half alone.
  • coder-terra-cc note · 1w ago
    TEST-EXERCISE RESIDUE PRE-DECLARATION (marker inc2-residue-0106), per evolutiva-commons Test-exercise residue. Exercise: one set correction via /practicas/[id] after inc2 deploy. Named consenting actor: Elazar, on the designated fleet test account, acting as docente (pmmaster-evolutiva-cc-muw5e4xy6ban). Práctica: a TEST práctica Elazar picks; its number is recorded here before readback. Archive context: app.terraUserId = that account's users.id, app.terraArchiveReason = 'user:practica-set-correccion: <motivo>'. Rows created: 1+ child rows (inserted codes) and 1+ terraPracticasArchive rows; removed codes are soft-deleted (deletedAt set). Recovery: archive rows WHERE archiveReason LIKE 'user:practica-set-correccion:%' AND archivedBy = actor AND archivedAt in the exercise window, keyed on the práctica id. Revert: a second correction restoring the prior set, itself archived. terraPracticasArchive rows are APPEND-ONLY and persist by design, so they are not removed. Verify removal: the live set equals the pre-exercise set, and the informe for that práctica shows the original piezas/complicaciones. Readback asserts a non-null archivedBy equal to the actor and the reason prefix, for both INSERT and soft-delete arms.
  • coder-terra-cc note · 1w ago
    inc2 SHIPPED (marker inc2-ptd-0106): a2e37d1, live /api/health version 0.31.89 commitSha a2e37d1d4e5b deploymentId dpl_Dugdn3U9tYpuM1tUXReWKNrJC8dJ dbOk true; matches remote main 0.31.89. Build log compiled with no error/warn lines; runtime log 40s window, no error lines (low traffic). Pre-push diff PASS audit-terra-ca-muw5fki4yrop on the same bytes. COVERAGE: no authenticated correction run; durable INSERT/soft-delete attribution is UNEXERCISED until Elazar's test correction (residue pre-declared, inc2-residue-0106); audit-terra-ca owns the readback. Row stays open for that readback, the informe check and increment 3 (antecedentes).
  • coder-terra-cc note · 1w ago
    inc3 RULING A (marker inc3-ruling-a-0106, pmmaster-evolutiva-cc-muw5jtq78tbh): an antecedentes correction changes ONLY the práctica's own terraPracticasAntecedentes rows. The shared pacienteAntecedentes ficha is NOT touched. A ficha value retained after a práctica correction is BY DESIGN (MERGE-AND-RETAIN), not a bug. A genuinely wrong ficha antecedente goes through the existing correction rail with its own attestation. DDL prerequisite: terra_235 (INSERT archive arm on terraPracticasAntecedentes), requested from db-terra-ca; app code ships only after its 'applied' DM.
  • coder-terra-cc note · 1w ago
    inc3-local-0106: antecedentes correction app code complete LOCALLY, unpushed. Files: src/lib/practica-correccion-antecedentes-{core,actions}.ts, src/components/practica-antecedentes-correccion-form.tsx, src/app/practicas/[id]/page.tsx, src/lib/practica-detail.ts (antecedenteId in detail), archive-context.ts (user:practica-antecedentes-correccion), friction-action-names.ts, friction-toast-coverage.test.ts (18->19), new practica-correccion-antecedentes-core.test.ts. Ruling A enforced: no ficha write, asserted with a must-fail control. Coverage: tsc+eslint clean on changed files, full node suite 667/667; SQL text/source order/pure functions only - no live statement, no authenticated browser. Push gated on terra_235 applied DM + audit pre-push diff PASS.
  • coder-terra-cc note · 1w ago
    inc3-prepush-0123: audit pre-push source PASS audit-terra-ca-muw6b4286q6m on base 5023907. Push attempt failed in pre-push hook: migration-replay-order draft/applied overlap on terra_235 (db-terra-ca applied-record push held). Nothing committed; waiting on db-terra-ca record SHA. DB-lane follow-up raised: requireDetail BEFORE UPDATE would reject soft-delete of a NULL-detail row if its catalogue entry later flips to requiresDetail=true (0 such rows live). UI note: retired recorded child is promoted to root, so unchecking its parent leaves it checked and the server returns falta-principal; user recovers by unchecking the child.
  • pmmaster-evolutiva-cc note · 1w ago
    terra_235 applied + independently catalog-audited (audit-terra-ca-muw68ijaz8a4: registry/catalog/wiring/ACL match, child count 16). Applied SOURCE-RECORD push is held, not the migration: TERRA-160 pre-push test rejects a draft/applied stem overlap while REPLAY-ORDER requires a schema export before the reviewed draft is removed - mutually unsatisfiable without the export. Export needs TERRA_DSN + psql (db/export-schema.sh hard-requires it). Documented exporter db-terra-cc is hub-unregistered; db-terra-ca holds no TERRA_DSN; db-enamel-ca's terra reach is Supabase MCP only and it correctly refused to borrow another seat's credential. No live seat can export -> Elazar seat/credential decision, consolidated with the Mars DDL seat and lezama gaps as ONE unregistered-owner-seat ask. Nothing unsafe done: reviewed draft preserved in pushed 5023907, applied executable bytes match, no hook bypass. Split state named explicitly: executable bytes live and verified, provenance not yet committed. PM decision - this does NOT gate the inc3 app leg, which depends on the applied DM (sent), so coder-terra-cc is cleared to push. Durable INSERT attribution remains UNOBSERVED pending Elazar's one-code-added/one-code-removed test correction as docente.
  • db-terra-ca note · 1w ago
    terra_235 applied source-file preservation before reversible move: db/migrations/applied/terra_235_antecedentes_archive_on_insert.sql full-file SHA256 434f6f3ac730377dece6ea40dd357b4c71146a7bd879f41a71f05338d5678e32; reviewed draft SHA256 0603a9c7d987b8ca7470c1745d5d05440626dad92ad5ae9c927b75de73d973f5 in pushed 5023907; executable-only SHA256 6716541c1b723a3fde50ceb7f02ccc1d74f31c26379db0dc772112948ff11d87. The first local move preceded this full-file-hash event; I restored the file to applied/ and am redoing the move in the required hash-first order. DB executable bytes live and catalog-verified, provenance source not committed, durable INSERT attribution UNOBSERVED. Export still Elazar-only.
  • db-terra-ca note · 1w ago
    terra_235 reversible move completed after hash-first event: agents/db-terra/evidence/terra_235_antecedentes_archive_on_insert.applied.pending.sql full-file SHA256 434f6f3ac730377dece6ea40dd357b4c71146a7bd879f41a71f05338d5678e32, exact match to pre-move applied/ file hash. The pending REPLAY-ORDER line is preserved verbatim in agents/db-terra/evidence/terra235-replay-order.pending.txt. Reviewed draft untouched in 5023907; no hook bypass, no draft deletion. Applied provenance commit awaits Elazar-only schema export; durable INSERT attribution UNOBSERVED.
  • coder-terra-cc note · 1w ago
    inc3-ptd-0133: inc3 PUSHED 43b23c6 v0.31.90. PTD: deploy dpl_XGKY9WnFwjpTLHUMcdLhCbvWNfrU Ready, production, alias terra-enamel.pensanta.com; /api/health version 0.31.90 == remote main package.json, commitSha 43b23c6, dbOk true. Split state: terra_235 executable bytes live and verified; provenance record not committed (export Elazar-only, applied SQL held at agents/db-terra/evidence/*.applied.pending.sql); durable INSERT attribution UNOBSERVED. Not exercised: the action itself, authenticated browser, committed archive row. Remaining: Elazar test correction covering inc2+inc3, audit readback, terra_236 soft-delete exemption (db lane).
  • db-terra-ca verified · 1w ago
    434f6f3ac730377dece6ea40dd357b4c71146a7bd879f41a71f05338d5678e32 path=agents/db-terra/evidence/terra_235_antecedentes_archive_on_insert.applied.pending.sql full-file SHA256 re-read after move; matches the full-file hash recorded on the row before the repeated move. Executable-only SHA256=6716541c1b723a3fde50ceb7f02ccc1d74f31c26379db0dc772112948ff11d87 matches reviewed draft/applied strip-diff. DB-side supabase_migrations.schema_migrations version=20261006041924, name=terra_235_antecedentes_archive_on_insert, statements[1] SHA256=0603a9c7d987b8ca7470c1745d5d05440626dad92ad5ae9c927b75de73d973f5 and length=3245, exactly matching pushed reviewed draft. Live trigger/function catalog independently passed audit-terra-ca-muw68ijaz8a4. Source provenance commit pending export; durable INSERT attribution UNOBSERVED. 6491b0161dcc4231e386b13b712ed6bad4bbc4d25e9481178b342ee6449f00a8 path=agents/db-terra/evidence/terra235-replay-order.pending.txt; pending replay line bytes only, to restore after export. requireDetail follow-up is separate terra_236 function-only draft; it does not alter terra_235 AFTER INSERT archive trigger behavior. A later catalog requiresDetail=true could trap historical NULL-detail soft-delete; pure-delete exemption is separately reviewed, not yet applied.
  • db-terra-ca verified · 1w ago
    DB-to-file chain for terra_235: pending applied file full SHA256 434f6f3ac730377dece6ea40dd357b4c71146a7bd879f41a71f05338d5678e32; executable-only SHA256 6716541c1b723a3fde50ceb7f02ccc1d74f31c26379db0dc772112948ff11d87 equals reviewed draft/applied strip-diff. Live supabase_migrations.schema_migrations row 20261006041924 stores statements[1] SHA256 0603a9c7d987b8ca7470c1745d5d05440626dad92ad5ae9c927b75de73d973f5, length 3245, exactly equal to pushed reviewed draft 5023907. Independent live catalog PASS audit-terra-ca-muw68ijaz8a4: antecedente AFTER INSERT archiveOnInsert A wired to fn_terraDetailArchiveInsert; live generic function prosrc MD5 8bddc6a40b1111fe9cbc6afbe7c38828, INVOKER/pinned/ACL, requireDetail O unchanged. This proves stored SQL identity and resulting catalog state; no committed INSERT attribution witness yet (UNOBSERVED). Separate requireDetail soft-delete follow-up is TERRA-272, not a terra_235 trigger-behaviour change.
  • db-terra-ca verified · 1w ago
    terra_236 PRE-REPLACE live catalog preimage of public.fn_terraAntecedenteRequireDetail(): prosrc SHA256 6720438b9169ad92f229c5ae80549e902e7e383eece5f1965c192df8a389cc4b; prosrc MD5 6313c53096916021fcba3f6172074de6; length 411. Read directly from pg_proc on shared project eprpywqwzsvrjeaforei before CREATE OR REPLACE. SECURITY INVOKER, search_path=public,pg_temp, ACL postgres/service_role; trigger requireDetail O. Exact pg_get_functiondef preimage is preserved at agents/db-terra/evidence/2026-10-06-terra-236-preimage-function.sql in pushed commit 914d20c. PM GO pmmaster-evolutiva-cc-muw6pv44ns6d requires post-apply body hash in this same event thread; draft SHA256 6c515a5ed96b750a8705cbd3ac3e939ebb7ee297730f3f9ce4a6eb1a69ca7120.
  • db-terra-ca verified · 1w ago
    terra_236 CREATE OR REPLACE body-hash pair from LIVE pg_proc, shared project eprpywqwzsvrjeaforei: PRE-image fn_terraAntecedenteRequireDetail prosrc SHA256 6720438b9169ad92f229c5ae80549e902e7e383eece5f1965c192df8a389cc4b (MD5 6313c53096916021fcba3f6172074de6, length 411); POST-apply prosrc SHA256 d7c00550a64a191dfd70dbefc75f881f3ef248ead7696c2e4204993fa2ab56b4 (MD5 922c598149dfa59a617489933b1ea96b, length 916). Preimage pg_get_functiondef preserved in pushed 914d20c at agents/db-terra/evidence/2026-10-06-terra-236-preimage-function.sql. Registry version 20261006043931/name terra_236_antecedente_pure_softdelete_detail_exemption stores exact reviewed draft SQL SHA256 6c515a5ed96b750a8705cbd3ac3e939ebb7ee297730f3f9ce4a6eb1a69ca7120. Function remains INVOKER, search_path=public,pg_temp, ACL postgres/service_role only; requireDetail trigger O, archiveSoftDelete A, archiveOnInsert A. Child count 16 and committed antecedente UPDATE archive rows 0: durable pure-delete actor attribution UNOBSERVED. This is separate TERRA-272 work; terra_235 INSERT archive trigger unchanged.
  • db-terra-ca verified · 1w ago
    terra_236 applied-record hold PRE-MOVE: untracked path db/migrations/applied/terra_236_antecedente_pure_softdelete_detail_exemption.sql; full SHA256 ad77a7b4ad59dd2beff769466a803dcd410582972a9c47367f426f4382afa76e. Executable-only SHA256 a0be72d3a6b7408ec3b6ce42fb8fcee5a9ddf3d8cdd7f18f74ba02db96a1545a; live supabase_migrations version 20261006043931 statements[1] SHA256 6c515a5ed96b750a8705cbd3ac3e939ebb7ee297730f3f9ce4a6eb1a69ca7120, identical to reviewed draft executable migration.
  • db-terra-ca verified · 1w ago
    terra_236 applied-record hold POST-MOVE: source db/migrations/applied/terra_236_antecedente_pure_softdelete_detail_exemption.sql (untracked); destination agents/db-terra/evidence/terra_236_antecedente_pure_softdelete_detail_exemption.applied.pending.sql. Pre-move and post-move full SHA256 both ad77a7b4ad59dd2beff769466a803dcd410582972a9c47367f426f4382afa76e. Executable-only SHA256 a0be72d3a6b7408ec3b6ce42fb8fcee5a9ddf3d8cdd7f18f74ba02db96a1545a; live supabase_migrations version 20261006043931 statements[1] SHA256 6c515a5ed96b750a8705cbd3ac3e939ebb7ee297730f3f9ce4a6eb1a69ca7120 matches reviewed draft SQL; executable-only draft/applied diff empty. Held files pending export, restore in migration order: terra_235 applied SQL SHA256 434f6f3ac730377dece6ea40dd357b4c71146a7bd879f41a71f05338d5678e32 and replay-order pending text SHA256 6491b0161dcc4231e386b13b712ed6bad4bbc4d25e9481178b342ee6449f00a8; terra_236 applied SQL SHA256 ad77a7b4ad59dd2beff769466a803dcd410582972a9c47367f426f4382afa76e. Split state: executable bytes live and verified; provenance not committed. Durable terra_234/235 INSERT and terra_236 pure-delete actor attribution UNOBSERVED.
  • db-terra-ca verified · 1w ago
    terra_236 independent post-apply catalog PASS (audit-terra-ca-muw6z1nm5hdv): live registry version 20261006043931, function prosrc SHA256 d7c00550a64a191dfd70dbefc75f881f3ef248ead7696c2e4204993fa2ab56b4, expected trigger modes and ACL, fixture residue 0/0. Committed antecedente UPDATE archive rows 0; durable pure-delete actor attribution UNOBSERVED. Applied executable bytes live/verified; applied source provenance not committed pending schema export.
  • coder-terra-cc note · 1w ago
    export-0455: db/schema-live.md re-exported under coder_terra_cc_ro (own env file, PGURI only) and pushed 045a5a9 v0.31.93 with db/export-schema.sh grants query rewritten to pg_class.relacl+aclexplode. Role-invariance witness same session pid 2953896: information_schema 0 rows vs aclexplode 5 grantees (audit_terra_cc_ro 17, db02_terra_cc_ro 3, db_terra_cc_ro 3, postgres 18, service_role 17); 0 anon/authenticated/PUBLIC on terra objects. Audit PASS audit-terra-ca-muw7ddlsbjvd. PTD: health 0.31.93 == remote main, commitSha 045a5a9, dpl_GLvtHpuepJVAr8tzrAV89Vrj9gRv. Held terra_235/236 restore now with db-terra-ca. Attribution for terra_234/235 INSERT arms and terra_236 pure-delete actor still UNOBSERVED.
  • db-terra-ca verified · 1w ago
    terra_235 held applied record RESTORED and provenance COMMITTED in 4b09f2a91cca23e9a229656cbebc0e971c1c4a0b (remote main readback). db/migrations/applied/terra_235_antecedentes_archive_on_insert.sql full SHA256 434f6f3ac730377dece6ea40dd357b4c71146a7bd879f41a71f05338d5678e32 matches pre/post-hold hash; executable-only SHA256 6716541c1b723a3fde50ceb7f02ccc1d74f31c26379db0dc772112948ff11d87, empty executable diff against reviewed draft SHA256 0603a9c7d987b8ca7470c1745d5d05440626dad92ad5ae9c927b75de73d973f5, live registry 20261006041924 statements[1] SHA256 same as draft. Cleared terra_235 from held list. terra_236 restoration recorded separately in the same source commit. Durable committed antecedente INSERT actor attribution remains UNOBSERVED.
  • db-terra-ca verified · 1w ago
    terra_236 held applied record RESTORED and provenance COMMITTED in 4b09f2a91cca23e9a229656cbebc0e971c1c4a0b (remote main readback). db/migrations/applied/terra_236_antecedente_pure_softdelete_detail_exemption.sql full SHA256 ad77a7b4ad59dd2beff769466a803dcd410582972a9c47367f426f4382afa76e matches pre/post-hold hash; executable-only SHA256 a0be72d3a6b7408ec3b6ce42fb8fcee5a9ddf3d8cdd7f18f74ba02db96a1545a, empty executable diff against reviewed draft SHA256 6c515a5ed96b750a8705cbd3ac3e939ebb7ee297730f3f9ce4a6eb1a69ca7120, live registry 20261006043931 statements[1] SHA256 same as draft. Cleared terra_236 from held list; no held applied files remain. Schema export landed at 045a5a9 before this push; standing hold expired. Executable bytes live/verified and provenance committed. Durable terra_234/235 INSERT arms and terra_236 pure-delete actor attribution remain UNOBSERVED.
  • db-terra-ca verified · 1w ago
    Apply/restore evidence for terra_235 and terra_236 preserved on remote main in 240cce93fd48 (two scoped evidence docs). Source-record commit remains 4b09f2a91cca. No held applied files remain. Durable committed terra_234/235 INSERT and terra_236 pure-delete actor attribution UNOBSERVED.
  • coder-terra-cc note · 1w ago
    MKR-181-inc2-stale coder-terra-cc 2026-10-06: the blockedReason is STALE ON BOTH PREMISES. Measured, not inferred. (1) 'App code ships after the applied DM' - the app code ALREADY SHIPPED. a2e37d1 'TERRA-181 correct piezas, regiones and intra complicaciones sets' is on origin/main (git branch -r --contains), 10 files, 783 insertions: practica-correccion-sets-core.ts (240), -actions.ts (135), -core.test.ts (163), practica-set-correccion-form.tsx (169), plus practicas/[id]/page.tsx, archive-context.ts, friction-action-names.ts, practica-detail.ts. Working tree clean on all three lib paths. (2) 'Waiting on db-terra-ca DDL: an AFTER INSERT archive arm on the 3 child tables' - the arm EXISTS AND IS ENABLED on all three. pg_trigger read under coder_terra_cc_ro (catalogs are still readable; every app TABLE is refused, see TERRA-285): terraPracticasComplicaciones trg_..._archiveOnInsert AFTER INSERT tgenabled=A fn_terraDetailArchiveInsert terraPracticasPiezasDentarias trg_..._archiveOnInsert AFTER INSERT tgenabled=A fn_terraDetailArchiveInsert terraPracticasRegionesAnatomicas trg_..._archiveOnInsert AFTER INSERT tgenabled=A fn_terraDetailArchiveInsert tgenabled=A is ENABLE ALWAYS, so it fires for a replica session too. Each table also carries requireArchiveCtx (BEFORE), forbidHardDelete, archiveSoftDelete and archive. Trigger event bits decoded as 4=INSERT/8=DELETE/16=UPDATE; an earlier decode in this session had 8 and 16 swapped and is not what is reported here. WHAT IS GENUINELY LEFT, and it is the only thing: nobody has watched a real set correction write its archive rows. The control exists and has never been seen to fire OR fail, which is a green line, not a control. Still unexercised: that fn_terraDetailArchiveInsert writes an attributed row on a correction-path INSERT, with the app-set archive context resolving to the acting user rather than NULL; and audit-terra-ca's acceptance conditions (writer inventory, four-path dry-run, the TRIO becoming four members) are db-terra-ca's evidence and I hold none of it. NOT CHANGING STATUS: the remaining gate is another lane's evidence. Routed to db-terra-ca.
  • coder-terra-cc unblocked · 1w ago
    MKR-181-unblock pmmaster GO pmmaster-evolutiva-cc-muwpexczq591. Both stale premises cleared by measurement (MKR-181-inc2-stale): app code a2e37d1 on origin/main, and trg_*_archiveOnInsert AFTER INSERT tgenabled=A calling fn_terraDetailArchiveInsert on all three child tables per pg_trigger. pmmaster ruling: a catalog read of the applied trigger outranks an acceptance-conditions list written before the trigger existed, so no acceptance restatement is awaited; audit-terra-ca speaks only if those three tables fall outside its scope, silence is agreement. REMAINING, assigned to db-terra-ca, not to me: fn_terraDetailArchiveInsert has never been seen to write an attributed row. Exercise under ROLLBACK, never against the live app - set archive context as the app sets it, INSERT one row into each of the three child tables in a transaction, read the archive row back and assert the actor resolved to the acting user not NULL, ROLLBACK, verify zero residue; then force RED with context unset and show NULL attribution or a refusal, whichever the function does. No domain rows are created, so no ID manifest, no consenting actor and no removal plan are required. If attribution depends on something only a real request sets (a per-transaction pooler-scoped GUC), STOP and say so rather than simulating it - the rollback would then prove the wrong thing.
  • db-terra-ca verified · 1w ago
    TERRA-181 inc2 evidence reconciliation 2026-10-06: agents/db-terra/evidence/2026-10-06-terra-234-apply.md records reviewed terra_234 SHA 45ef585f, PM GO, registry 20261006034847, fn_terraDetailArchiveInsert MD5 8bddc6a4 and three AFTER INSERT ENABLE ALWAYS child triggers. The saved rollback runtime SQL exercised createTerraPractica, app-style create, postop insert and correction-style additions into complicaciones/piezas/regiones. For the correction-style three INSERTs, fn_terra234_assert_insert_archive asserted rowAfter=to_jsonb(child), archiveOp INSERT, rowBefore NULL, archiveReason user:practica-set-correction: motivo de prueba, archivedBy=p.createdBy, with zero post-rollback residue. Thus DB-trigger attribution fired and was observed transiently. Still UNEXERCISED: actual shipped Next.js correction action, real request/session actor binding, and durable first committed correction archive readback. Repeating the same set_config SQL would not close those gaps.
  • db-terra-ca verified · 1w ago
    TERRA-181 inc2 forced-red clarification: existing post-apply terra_234 rollback runtime also set app.terraUserId and app.terraArchiveReason to empty, attempted a valid child INSERT, and required P0001 refusal from requireArchiveCtx with no child/archive residue. Positive correction-style context+3 attributed archive rows and negative unset-context refusal are BOTH already exercised DB-only. The only remaining coverage is an actual authenticated Next.js correction action and first committed archive readback; no duplicate SQL probe needed.
  • coder-terra-cc note · 1w ago
    MKR-181-standing TERRA-181 inc2 is DONE PENDING FIRST REAL USE, not blocked and not awaiting an exercise. pmmaster WITHDREW the rollback-exercise order (muwpsktlh4au) on db-terra-ca's correction: terra_234's apply record already observed four writer shapes plus a correction-style INSERT into all three child tables, exact rowAfter, reason `user:practica-set-correction: motivo de prueba`, archivedBy=p.createdBy, zero residue, tied to reviewed SHA 45ef585f and registry 20261006034847. The trigger HAS fired under rollback with non-NULL actor attribution. WHAT IS UNEXERCISED is narrower than 'the trigger never fired': the SHIPPED Next.js correction action has never been invoked, and no COMMITTED first-correction archive row has been read. One event satisfies both - the first real correction a user performs. STANDING QUERY WRITTEN: db/standing-queries/terra_181-first-real-correction.sql. Validated against pg_attribute - all ten terraPracticasArchive columns exist with the types the query assumes (archiveSeq bigint, archiveOp/archiveReason/sourceTable text, archivedAt timestamptz, archivedBy uuid, rowId uuid, rowIdInt bigint, rowBefore/rowAfter jsonb). IT EXCLUDES `system:practica-create-boundaryFn`. terra_234's child INSERT arms stamp two prefixes and only `user:practica-set-correction%` is a user correction; without the exclusion every created practica reads as one and the query answers nothing. NOT RUN. pmmaster asked for it to be run now so it is known to work; coder_terra_cc_ro has no SELECT on "terraPracticasArchive" (has_table_privilege=f, probed 2026-10-06). Reassigned to the db lane - stating this rather than reporting the write as the deliverable. Put the returned row on this row when it first returns one, then close. No test rows, no id manifest, no consenting-actor declaration, nothing for Elazar to rule on - the whole point of a standing read over a manufactured exercise.
  • db-terra-ca verified · 1w ago
    TERRA-181 inc2 standing read executed SELECT-only on live project eprpywqwzsvrjeaforei, 2026-10-06. Committed query db/standing-queries/terra_181-first-real-correction.sql at origin/main 83c0b55, SHA256 d06b513f8d09094f8976cc76e65123aaedf49016124aa2445fce23d434ae7ce8. Exact file execution returned [] (zero committed correction-prefixed INSERT archive groups); a separate count control returned matchingArchiveRows=0, attributedRows=0, firstArchivedAt=NULL. Query output is aggregate only: source table, row/attributed counts, first archive sequence/time/attribution flag; no motivo, actor or child UUID, or row JSON. No DML, manufactured actor, or rollback exercise. Existing terra_234 rollback probe already proved trigger attribution; first real Next.js correction and durable archive row remain UNOBSERVED. The reason prefix is app-path attribution, not independent human attestation.
  • db-terra-ca note · 1w ago
    Standing-query positive control, SELECT-only live on eprpywqwzsvrjeaforei, 2026-10-06: re-ran the exact committed query with ONLY archiveReason LIKE user:practica-set-correction% removed. Result was also [] (zero rows). A second aggregate proves table reach is real: terraPracticasArchive has 15 committed rows, all UPDATE (terraPracticas 13, terraCirugias 1, terraModulos 1), and zero committed child-table INSERT archive rows of any reason. Therefore the correction-prefix-only negative is NOT independently discriminated by committed data today; no in-domain positive control exists yet. This does not imply SELECT permission failure. The earlier terra_234 rollback probe remains the only observed child INSERT archive firing; no new DML or fixture made. Keep first committed correction observation UNEXERCISED and the standing query as an unvalidated live watch until an ordinary child INSERT archive appears.
task
6w ago by wi-cli-venus
1w ago