basquetWi + New ticket

A named ayudante has no correction path: TERRA-140 lets one person assert another attended a surgery, and whether the named person can remove themselves is unanswered

Todo normal ctcoder-terra-cc

Raised out of TERRA-140 on 2026-08-31 and deliberately NOT answered by me. It is a question about a clinical record, not a design preference. TERRA-140 lets the operador name an ayudante so one practica load records the whole team quirurgico. The named person is written as a participante row referencing their user id - that is required, because a typed name credits nobody and defeats the point of the feature. THE CONSEQUENCE: SOMEBODY CAN BE NAMED WITHOUT THEIR KNOWLEDGE, and the record then asserts they were present at a surgery. That assertion appears in their own history, counts toward their practica totals, and is the sort of thing a catedra record exists to be authoritative about. THE QUESTION: may a named ayudante remove themselves from a practica they did not create? And if they can, what does the removal leave behind - a soft-deleted row that still shows the claim was made, or nothing at all? WHY IT IS NOT MINE: reversibility in the data is not reversibility in the record. A person disputing their presence at a surgery is a factual dispute between two catedra members, and whichever way it resolves the app is taking a side by default. Elazar or Puia decides; I should not pick by choosing an implementation. WHY IT DOES NOT BLOCK TERRA-140: today nobody can name anybody at all, so shipping the naming feature does not make the status quo worse. The gap is that it creates a claim with no correction path, which is a new state. DO NOT let TERRA-140 silently invent an answer to this by shipping a delete button or by shipping no delete button without saying which was chosen. Either is a decision.

Sub-tickets

No sub-tickets.
+ Add sub-ticket

Activity

  • wi-cli-venus created · 6w ago
  • wi-cli-venus blocked · 6w ago
    Needs Elazar or Puia: whether a named ayudante may remove themselves, and what a removal leaves behind
  • wi-cli-venus parentChanged · 6w ago
    parent=TERRA-140
  • wi-cli-venus note · 6w ago
    EL CASO NO ES HIPOTETICO: YA PASO. Medido por db02-terra-cc, SELECT solamente, con denominador, 2026-09-01 08:52. Es la primera de las filas medidas hoy que NO da cero. LA POBLACION: 2 filas vivas de participantes sobre SEIS practicas totales. Cinco practicas no tienen ninguno. La unica que tiene, tiene dos filas: el creador de la practica con rol operador, y OTRO usuario distinto con rol docente, las dos con el mismo createdAt exacto - alta conjunta en el mismo insert. O sea que practicas donde alguien fue nombrado por otro: UNA, no cero. La situacion que estas dos filas describen existe hoy en produccion, sobre una persona real. LA ESTRUCTURA, y aca hay una correccion a como yo venia escribiendo estas filas: la columna NO se llama rolPropio. Se llama rolEnPractica, es text NOT NULL, y esta en terraPracticasParticipantes. Yo venia arrastrando el nombre equivocado. La tabla tiene seis columnas: id, practicaId con FK a terraPracticas, userId con FK a users, rolEnPractica, createdAt y deletedAt. LO QUE NO EXISTE, Y ES LO QUE HACE QUE LA CORRECCION SEA INAUDITABLE AUNQUE SE CONSTRUYA: no hay ninguna columna que registre QUIEN agrego a cada participante. Nada tipo addedBy. createdBy vive en terraPracticas, no aca. Asi que una vez escrita la fila, la base NO PUEDE DECIR si la persona se puso sola o la puso otro. Y eso vale hacia atras tambien: la fila que ya existe, con dos participantes cargados en el mismo insert, no dice quien nombro a quien. La unica pista posible estaria fuera de esta tabla, en appEvents, si algun escritor guarda el actor real - db02 lo marco explicitamente como NO VERIFICADO porque no era parte de lo pedido, y yo lo dejo asi en vez de asumirlo. SACARSE A SI MISMO ES TECNICAMENTE POSIBLE HOY. deletedAt existe, o sea que sacar a alguien es un soft-delete y no un borrado - forbidHardDelete lo impide de todas formas. Y medido contra pg_trigger, no contra el nombre de las cosas: la tabla tiene OCHO triggers no internos - archivo en DELETE, archivo en UPDATE con rama de soft-delete, forbidHardDelete, forbidTruncate, requireArchiveCtx, requireTerraMembership y vocabGuard sobre rolEnPractica. NINGUNO registra ni restringe el ACTOR de la operacion. requireTerraMembership gatea que el userId sea miembro de terra, no quien hace la operacion. Asi que nada impide hoy que una fila se marque como borrada por cualquiera: ningun trigger compara userId contra el actor de la sesion. CONSTRAINTS: PK, las dos FK, y un indice unico parcial en (practicaId, userId, rolEnPractica) donde deletedAt IS NULL - evita repetir el mismo rol para la misma persona en la misma practica. No tiene nada que ver con la auto-remocion. LO QUE ESO LE HACE A LAS DOS FILAS. TERRA-149 pregunta QUIEN PUEDE atribuir un ayudante: sigue siendo una decision de politica y no cambia. TERRA-146 pregunta si la persona nombrada puede sacarse: la respuesta tecnica es que HOY PUEDE CUALQUIERA, porque no hay superficie construida pero tampoco hay nada en la base que distinga a la persona nombrada de cualquier otro actor. O sea que la pregunta no es "hay que permitirselo", es "cuando se construya la superficie, la base no va a poder ayudar a decidir quien tiene derecho, porque no guarda quien puso a quien". Y ESO ES UNA DECISION QUE HAY QUE TOMAR ANTES, NO DESPUES: si se quiere que la nombrada pueda sacarse y otros no, hay que empezar a guardar quien agrego a cada participante. Con DOS filas en la tabla, agregar esa columna es gratis. El dia que haya doscientas, las viejas no lo van a tener nunca.
  • wi-cli-venus note · 6w ago
    YO ESTABA LEYENDO MAL LA TABLA Y LO DIGO ACA PORQUE LA LECTURA EQUIVOCADA CASI ABRE UNA FILA QUE NO EXISTE. 2026-09-01 09:05. Hace un rato medi appEvents y encontre UN solo evento practica:create, con actorUserId en NULL, contra SEIS practicas. Lo escribi como "cinco practicas no dejaron evento de creacion" y me guarde de abrir fila hasta saber si era un escritor que falla, un escritor mas nuevo que las practicas, o yo contando mal. Era lo tercero. practica:create NO ES UN REGISTRO DE CREACION EXITOSA. Es el nombre de una ACCION, y en terra ese nombre solo llega a appEvents por dos escritores y los dos son de FALLA. Uno es el wrapper de server action: createPractica esta envuelto en withAction("practica:create") y el wrapper solo escribe cuando el cuerpo TIRA. El otro es el riel de friccion del cliente: el formulario le pasa el mismo actionName a useActionForm y el sink de friccion escribe action=input.actionName cuando la validacion del navegador rebota o la accion vuelve !ok. O sea que la fila unica que yo encontre no es una practica creada: es una practica que NO se creo, o un rebote de validacion antes de siquiera llamar a la accion. Seis practicas y un evento con ese nombre es exactamente lo que este codigo produce. LA PARTE QUE NO TOME DE PALABRA Y QUE CAMBIA EL POR QUE. audit escribio que el wrapper "devuelve exito sin loguear". El wrapper NO es asi: action-core.ts:69 dice if (deps.logSuccess) await deps.logSuccess({ action }), o sea que el gancho de exito EXISTE en el core. Si terra lo cableara, practica:create SI seria un ledger de creacion y cinco de seis faltando seria un defecto de verdad. Fui a ver quien lo provee: nadie. Todo el arbol src/ menciona logSuccess en tres lugares y uno solo es una decision - action.ts:72, "No logSuccess: success toasts / success rows are fleet-banned noise". Asi que la conclusion se sostiene, pero no por ausencia de camino: por una omision deliberada en el cableado, escrita y justificada. La diferencia importa porque un gancho opcional sin proveedor se cablea con una linea, y el dia que alguien la escriba el significado de todas las filas practica:create cambia de golpe hacia atras. NO ABRO FILA POR LOS CINCO EVENTOS FALTANTES. La condicion que yo mismo puse era saber cual de las tres, y ya se cual. LO QUE ESTO LE HACE A LA PREGUNTA DE ESTA FILA: la refuerza en vez de debilitarla. Yo habia escrito en la eq 82 que la columna addedBy no es una opcion entre dos porque el riel de eventos tiene el actor en NULL. La razon real es mas fuerte que esa: terra NO EMITE NINGUN evento de exito, por politica de flota, asi que no hay ni va a haber un evento de "se agrego un participante" del que sacar el actor. La atribucion no esta perdida en un campo vacio, no tiene donde vivir. Guardar quien agrego a quien en la tabla es la unica forma, y con dos filas es gratis. LO QUE SI SE MIDE DE PASADA Y NO SE SOBRE-LEE: existe UNA fila practica:create, o sea que alguna vez una creacion de practica fallo o rebotó en validacion. Una sola, sin actor y sin resourceId, y los dos escritores producen la misma forma - la fuente no puede decir cual de los dos la escribio. No es un incidente, es un dato: no lo convierto en fila.
  • wi-cli-venus note · 6w ago
    EL PRECIO DE LA COLUMNA, CONTESTADO EN VEZ DE PROMETIDO. 2026-09-01 09:14. Pregunte esto a proposito antes de recomendarle nada a Elazar: no queria ofrecerle el arreglo barato sin saber si era barato. Fuente leida por audit-terra-ca y verificada por mi linea por linea, no tomada de palabra. EL ACTOR YA ESTA AHI. createPractica resuelve al usuario que actua al principio, en practica-actions.ts:265-276, con requireAppUserAction(PRACTICA_ROLES). Ese mismo user.id llega vivo hasta el insert de participantes: linea 611. Osea que agregar addedBy NO necesita un parametro nuevo en la accion, ni una consulta de sesion, ni plomeria desde otra capa. El valor esta en el alcance lexico exacto donde se escribe la fila. Y HAY ALGO MAS FUERTE QUE ESO, QUE audit NO DIJO Y QUE VI AL LEER LA LINEA: user.id no entra como un dato suelto, entra como authorId - buildParticipantes({ authorId: user.id, rolPropio, docenteControladorId, ayudanteId }). Osea que el codigo YA SABE, en el momento de armar las filas, cual fila es la del autor y cuales son las de personas que el autor nombro. Esa distincion existe y se descarta al escribir. No estamos pidiendo que la app averigue algo que no sabe: estamos pidiendo que guarde algo que ya tiene en la mano. LO QUE SIGUE COSTANDO, y lo digo yo porque audit puso el limite y tiene razon: sigue haciendo falta la migracion de la columna y agregarla al INSERT. El INSERT vive en 671-679, es UNA sola sentencia con tres columnas - practicaId, userId, rolEnPractica - construida con unnest sobre dos arrays. Todas las filas de un mismo alta salen de esa unica sentencia y todas tendrian el mismo addedBy, asi que del lado del codigo es una columna mas en la lista y el mismo $1 que ya se usa para practicaId. No es "una linea", pero es lo mas barato que esta clase de cambio puede ser. LO QUE NO CUBRE ESTO, dicho antes de que alguien lo lea como cobertura: es el camino de la app. Si mañana alguien inserta participantes por psql o por una migracion, addedBy queda en NULL a menos que la columna sea NOT NULL o la sostenga un trigger. Es exactamente la misma clase que terra_55 y TERRA-131 - una regla que solo vive en el codigo Node se sostiene mientras la app sea el unico escritor. Si esta columna se aprueba, la decision de si la impone la base o solo la app hay que tomarla en el mismo momento, no despues. UN DATO DE FUENTE QUE CORRIGE UNA SUPOSICION MIA sobre las dos filas vivas: el comentario en 606-609 dice que la auto-asignacion es un caso REAL y no un bug - un docente que registra una practica que el mismo superviso produce DOS filas para UNA persona con dos roles distintos, y el rol es parte de la clave justamente para que eso siga siendo expresable. Yo venia leyendo "dos filas con el mismo createdAt" como "dos personas". db02 midio que son dos userId DISTINTOS, asi que en este caso concreto si son dos personas - pero la forma de la tabla admite las dos lecturas y yo no lo sabia cuando lo escribi la primera vez. CAPACIDAD DE LA LANE DE AUDITORIA, anotado porque afecta a que le pido despues: audit-terra-ca contesto esto con 20% de contexto restante. No le mando mas trabajo de lectura larga hasta que se recicle.
  • wi-cli-venus note · 6w ago
    MI AFIRMACION ERA DEMASIADO AMPLIA Y db02-terra-cc LA ACOTO. Pedi que la atacaran a proposito y funciono, asi que lo escribo entero en vez de solo el resultado. 2026-09-01 09:20. Medido por db02, re-verificado por mi contra la base por otro camino - no le tome la palabra. LO QUE YO HABIA ESCRITO, en la eq 82 y en la nota de arriba: que la atribucion de quien agrego a un participante "no tiene donde vivir". Eso es cierto para el camino que importa y FALSO como afirmacion sobre el esquema. LO QUE EXISTE, y no lo sabia cuando escribi la frase: terraPracticasArchive tiene una columna archivedBy, uuid, NOT NULL, que guarda el actor real de la operacion, y una archiveReason al lado. La llena fn_terraRequireArchiveContext a partir del contexto de sesion. Osea que terra YA TIENE un patron de atribucion de actor, construido, obligatorio y andando. Verifique las diez columnas contra information_schema: archiveSeq, archiveOp, archivedAt, archivedBy, archiveReason, rowId, rowBefore, rowAfter, sourceTable, rowIdInt. DONDE NO LLEGA, Y ESA ES LA PARTE QUE SE SOSTIENE: solo se escribe en DELETE y en el UPDATE de soft-delete. NUNCA en INSERT. Lo verifique por los bits de tgtype en pg_trigger y no por el nombre del trigger: requireArchiveCtx es tgtype 19, o sea BEFORE UPDATE ROW y nada mas. Agregar un participante no escribe ninguna fila de archivo y no exige ningun actor. Poblacion, con denominador: terraPracticasArchive tiene SEIS filas en total - cuatro de terraPracticas, una de terraCirugias, una de terraModulos - y CERO de terraPracticasParticipantes. LO QUE ESO LE HACE A LA RECOMENDACION: la mejora. Yo la estaba presentando como "hay que inventar un lugar para el actor". No hay que inventar nada: el esquema ya tiene su forma de guardar quien hizo que, con nombre propio y NOT NULL, y lo unico que pasa es que el camino de alta quedo afuera. Pedir addedBy no es introducir un mecanismo nuevo, es extender a INSERT el que ya rige en DELETE y en soft-delete. Es mas barato de justificar y mas dificil de discutir que como yo lo venia diciendo. Y HAY UN SEGUNDO HALLAZGO QUE db02 NO SEÑALO Y QUE SALE DE SU MISMA MEDICION: esta tabla YA TIENE dos triggers que corren BEFORE INSERT - requireTerraMembership y vocabGuard, los dos tgtype 23, o sea BEFORE INSERT OR UPDATE ROW. Osea que el punto de enganche en el alta no hay que crearlo tampoco: ya se corre codigo ahi. Ocho triggers no internos en total sobre la tabla, ninguno de los ocho mira el actor. LO QUE NO SE MIDIO, y lo marco en vez de dejarlo implicito: nadie miro si appEvents registra el actor en el momento del INSERT sobre esta tabla. db02 lo declaro fuera de alcance por su cuenta, correctamente, porque no se lo pedi. Igual esa puerta ya esta medio cerrada por otro lado - terra no emite eventos de exito por politica de flota, asi que un evento de "se agrego un participante" no existe. LA REGLA QUE ME LLEVO, y es la tercera vez esta semana que la misma clase de error me toca: una afirmacion de AUSENCIA es tan amplia como el alcance que le pongas, y yo la escribi sin alcance. "No hay donde guardar el actor" era falso; "el camino de alta no guarda el actor" es cierto y es lo que queria decir. La diferencia importa porque la version amplia habria hecho que Elazar aprobara una columna creyendo que no habia precedente, cuando el precedente existe y es lo que hace que la columna sea la decision obvia.
  • wi-cli-venus note · 6w ago
    MEDICION CONTRA LA BASE VIVA, 2026-09-01. Pedida a db-terra-ca y RE-CORRIDA POR MI contra information_schema, pg y las tablas - no acepte el resumen. Las cuatro cifras que reporto coinciden exactamente con las suyas. Pero dos de ellas SIGNIFICAN OTRA COSA de la que su redaccion sugiere, y esa diferencia es la que decide la fila. LO CONFIRMADO, con denominador. terraPracticasArchive tiene 6 filas en total. terraPracticasParticipantes tiene 2 filas, 2 vivas, 0 borradas, cubriendo 1 sola practica. terraPracticas sigue en 6 total, 6 vivas, 0 borradas. Las columnas reales de participantes son id, practicaId, userId, rolEnPractica, createdAt, deletedAt - ninguna registra QUIEN creo la atribucion. userId es la persona atribuida, no el autor. createdAt da tiempo, no actor. Eso corrige del todo mi propia afirmacion en blanco anterior, que era sobre la tabla equivocada. PRIMERA LECTURA QUE HAY QUE DESARMAR: "6/6 con archivedBy IS NOT NULL, 0 nulos" se lee como una medicion de disciplina y NO LO ES. archivedBy es uuid NOT NULL en el DDL. O sea que el 6/6 esta forzado por la estructura y habria salido 6/6 aunque nadie hubiese cuidado nada: una fila sin actor no puede existir ahi. La cifra es correcta y no es evidencia. Es el mismo genero de error que ya cometi yo en esta fila en la direccion contraria. SEGUNDA LECTURA, Y ES LA QUE CAMBIA EL DIAGNOSTICO: se reporto "0 filas de archivo con sourceTable=terraPracticasParticipantes", lo que se lee como un hueco PROPIO de participantes. Desglose por sourceTable y archiveOp de las 6 filas: terraCirugias UPDATE 1, terraModulos UPDATE 1, terraPracticas UPDATE 4. NO HAY NI UNA SOLA FILA INSERT EN TODO EL ARCHIVO, para ninguna tabla. O sea que el archivo no es un registro de altas y nunca lo fue: el cero de participantes es un caso particular de un cero universal, 0/6. Decirlo como propiedad de participantes invita a arreglar participantes y dejar el resto igual. CONSECUENCIA PARA LA DECISION DE addedBy, dicha sin inflar: el alta de un ayudante no deja actor NI en la fila NI en el archivo, y el archivo no puede aportarlo porque no archiva altas de ninguna tabla. Con 2 filas vivas hoy, la reconstruccion historica no es un problema de volumen: son dos atribuciones y su autor no esta almacenado en ningun lado que yo haya podido medir. NO SE ESCRIBIO NINGUNA MIGRACION Y ES DELIBERADO: terra_55 sigue sin GO en la eq 78. La eq 82 sigue abierta y es la que ordena esta fila.
  • wi-cli-venus note · 6w ago
    CENSO DEL PATRON DE ARCHIVO, 2026-09-01. Pedido a db-terra-ca, RE-CORRIDO POR MI con una definicion de poblacion distinta a proposito. La conclusion coincide y el denominador NO. LA CONCLUSION, que es lo que decide TERRA-146 y se sostiene en las dos mediciones: NINGUN trigger de archivo dispara en INSERT. Cero, en todas las tablas del patron. Los eventos declarados son UPDATE y DELETE, con los dos triggers de UPDATE particionados por WHEN - archiveSoftDelete para la transicion deletedAt NULL a NOT NULL, archiveOnUpdate para el complemento. O sea que el archivo de esta base NO ES UN REGISTRO DE ALTAS POR DISEÑO, y el cero de participantes que reporte antes es un caso particular de eso, no una omision de esa tabla. Y CONVIENE EL DENOMINADOR DE AL LADO, porque sin el "cero triggers de INSERT" se lee como que la base no usa INSERT triggers: hay 15 triggers no internos declarados sobre INSERT en public. Existen y se usan. Lo que ninguno de ellos hace es archivar. DONDE NO COINCIDIMOS, Y ES UN DEFECTO DE METODO QUE VALE MAS QUE LA CIFRA: db-terra-ca reporto 10 tablas y 24 triggers. Su consulta define la poblacion con una lista fija de cuatro nombres de funcion - proname IN (...) -, o sea que el censo solo puede encontrar lo que ya sabia que existia. Corri la misma pregunta definiendo la poblacion por el CUERPO de la funcion, cualquier funcion de trigger cuyo texto escriba en una tabla Archive, y me dio 12 tablas / 26 triggers con dos funciones mas: fn_terraArchiveAppendOnly y fn_terraPacienteImplantologiaArchive. DE ESAS DOS, UNA ES MIA Y LA DESCUENTO: fn_terraArchiveAppendOnly cuelga de terraPracticasArchive, que es la tabla de archivo protegiendose a si misma, no una tabla archivada. La otra NO: terraPacienteImplantologia lleva trg_terraPacienteImplantologia_archiveOnUpdate y quedo afuera del censo simplemente porque su funcion no estaba en la lista de cuatro nombres. O SEA QUE EL NUMERO CORRECTO ES 11 TABLAS CON EL PATRON, NO 10. La conclusion no cambia - las 11 tienen cero INSERT - pero el censo que la sostiene se equivoco por construccion, y un censo enumerado a mano falla en la direccion tranquilizadora: la tabla que falta es siempre la que nadie estaba mirando. terraPacienteImplantologia ademas ya tiene historia propia de hueco de archivo en esta base, o sea que es exactamente la fila que no convenia perder. REGLA QUE ME LLEVO: un censo cuya poblacion se define por una lista de nombres no es un censo, es una verificacion de la lista. Definir la poblacion por la PROPIEDAD - aca, el cuerpo que escribe en Archive - y recien despues contar. Sin DDL, sin migracion. terra_55 sigue sin GO en la eq 78.
  • wi-cli-venus note · 6w ago
    CONVERGENCIA DE TRES MEDICIONES INDEPENDIENTES, 2026-09-01. db02-terra-cc contesto la misma pregunta SIN VER la respuesta de db-terra-ca - se lo pedi explicitamente, porque dos carriles que coinciden despues de que uno leyo al otro son una sola medicion con dos nombres. COINCIDEN LAS TRES EN LO QUE DECIDE LA FILA: cero triggers de archivo sobre INSERT. db02 lo midio leyendo tgtype bit a bit en vez de fiarse del nombre del trigger, que es la disciplina correcta en esta base, y reporta 0/11 tablas fuente y 0/27 triggers de la familia. Y COINCIDEN CONMIGO EN EL DENOMINADOR QUE db-terra-ca ERRO: db02 lista las 11 tablas fuente una por una e incluye terraPacienteImplantologia, que es exactamente la que la lista de cuatro nombres habia dejado afuera. Tambien separa terraPracticasArchive como DESTINO y no como fuente, con el mismo criterio con el que yo la descarte. UN DETALLE SUYO QUE MEJORA MI LECTURA DEL appendOnly: tgtype 27 es BEFORE + UPDATE + DELETE, sin bit INSERT, o sea que ese trigger BLOQUEA update y delete sobre la tabla de archivo y deja el INSERT libre. Es coherente con append-only y no es un archivador de si mismo. Yo lo habia descontado por la tabla; el lo descuenta por el cuerpo, que es mejor razon. Y TRAJO EL CONTROL QUE YO HABIA PEDIDO Y CONVIENE DEJAR ESCRITO: los 15 triggers no internos con bit INSERT en public son de otra familia - assignPracticaNumber, firstRowMilestone, vocabGuard y companhia. O sea que el cero de INSERT esta LOCALIZADO EN LA FAMILIA ARCHIVE y no es un cero universal del schema. Sin ese control, "ningun trigger archiva altas" y "esta base no usa triggers de INSERT" se confunden, y son cosas distintas. NOTA DE METODO QUE NO PASO INADVERTIDA: db02 definio su poblacion con proname ILIKE '%archive%', que sigue siendo un filtro POR NOMBRE aunque mucho mas ancho que la lista de cuatro. Coincidio con mi consulta por cuerpo esta vez, pero se perderia un trigger de archivo cuya funcion no se llame archive. La definicion fuerte sigue siendo el cuerpo. ESTADO DE TERRA-146: la base esta medida y no hay nada mas que medir aca. El alta de un ayudante no deja actor en la fila ni en el archivo, y el archivo no puede aportarlo porque no archiva altas de ninguna tabla, por diseño. La fila espera la decision de addedBy en la eq 82. Sin DDL, sin migracion, terra_55 sigue sin GO en la eq 78.
  • wi-cli-venus assigned · 5w ago
    coder02-terra-ca
  • wi-cli-venus assigned · 5w ago
    coder02-terra-cc
  • wi-cli-venus decision · 5w ago
    DECIDED - DEFAULT SET, EXPLICITLY REVERSIBLE. Marker: T146-dec-mtwz05. Decided by the terra PM lane 2026-09-11 under Elazar's 09:27 ART standing delegation. Not Elazar's wording; this is the row most worth overruling if he disagrees. THE ROW IS RIGHT THAT BOTH ANSWERS ARE DECISIONS. "Ship no removal path" is not neutrality, it is a ruling that a person named in a clinical record cannot contest it. Leaving the row blocked while TERRA-140 ships IS that ruling, taken by default and unrecorded. That is the specific outcome the row asked us not to let happen, so not deciding is the one option that is unavailable. THE DECISION: a person named as ayudante on a practica they did not create MAY remove themselves. The removal is a SOFT delete - the participante row is marked withdrawn with who did it and when, and the fact that the claim was made remains in the record. Nothing is hard-deleted, and the practica itself is untouched. WHY THIS SHAPE AND NOT THE OTHER TWO: - A hard delete would let the named person erase the evidence that an assertion about them was ever made, which destroys the other side of a factual dispute. - No removal path at all means the app asserts, permanently and in someone's own history, that they attended a surgery they may not have attended, with no recourse inside the system. - The soft withdrawal takes NEITHER side. It records both the claim and the denial and leaves the catedra to resolve it as a human matter, which is what it is. The app stops being the thing that decides. CONSEQUENCE TO IMPLEMENT DELIBERATELY: a withdrawn participante must NOT count toward that person's practica totals, and must still be visible on the practica detail as withdrawn. A withdrawal that hides the row is a hard delete wearing a flag. CLIENT OVERRIDE: if Puia or Elazar wants the removal to require a docente instead of the named person, that is a change to who calls the action, not to the data shape - the soft-delete record is correct either way.
  • wi-cli-venus unblocked · 5w ago
    policy decided T146-dec-mtwz05: named ayudante may self-withdraw, soft delete preserving the claim, excluded from totals, visible as withdrawn
  • wi-cli-venus audit-finding · 5w ago
    THE QUESTION THIS ROW ASKS PRESUPPOSES A CORRECTION PATH THAT EXISTS FOR NOBODY. Marker: T146-nopath-mtwy9. MEASURED, not inferred. terraPracticasParticipantes has exactly ONE write in the whole application: an INSERT at src/lib/practica-actions.ts:887, inside createPractica. Coverage: command grep -r over src/**/*.ts and *.tsx, excluding tests. The other five hits are reads - mi-cursada/page.tsx:53, practica-postop-core.ts:60, practica-detail.ts:257 - plus two comments. There is no UPDATE, no DELETE, and no soft-delete column being set from anywhere. SO THE ROW'S FRAMING IS TOO NARROW. It asks whether the named ayudante may remove themselves. The answer today is that NOBODY can remove them: not the named person, not the author who named them, not a docente, not an administrator through any surface terra has. The row reads as a permissions question about one actor and it is actually the absence of the operation for every actor, which is a different thing to decide and a different thing to build. WHAT THAT MAKES IT: the participantes instance of TERRA-181, which says a practica cannot be corrected after creation and that the only exception is the postoperatorio. The clinical fields and the participant list are the same gap seen from two sides, and the postop exception proves the shape is buildable - postop already carries a vocabulary check, an access predicate and a live/soft-deleted distinction, so a correction path for participantes is not a new architecture, it is the second application of an existing one. WHY IT IS WORSE HERE THAN FOR A CLINICAL FIELD, and this is the part that should drive the decision rather than the permissions question. A wrong marca de implante is a wrong fact about a practica. A wrong ayudante is an assertion ABOUT ANOTHER PERSON, written by someone else, that the named person never confirmed and cannot retract - it says they attended a surgery. It renders on /mi-cursada, which is that person's own record of their cursada, so the first time they see it is on their own page, with no control next to it. TERRA-149 is the same defect at the moment of writing (any participant may assert another person attended); this row is the same defect afterwards. WHAT I AM NOT DOING: deciding it. Whether the named person may unilaterally remove themselves, whether removal needs the author or a docente, and whether a removed row is soft-deleted or erased are product calls for the terra lane, and per pmmaster-evolutiva-cc 2026-09-11 they belong to coder-terra-cc, not to Elazar. What I have removed is the false premise that some correction path exists and only the actor is in question. MY RECOMMENDATION, one line so the decision has a default to reject: soft-delete with the remover recorded, available to BOTH the named person and the author, because the two ways this row gets written wrong - a mistyped person and a disputed attendance - need different people to be able to undo it.
  • wi-cli-venus note · 5w ago
    READ BEFORE BUILDING THIS - THE DDL YOU ARE ABOUT TO ASK FOR ALREADY EXISTS. Marker: T146-noddl-mtwz3. I measured the schema for this row and then had to stop on an Elazar order pausing this agent until 14:00 ART, so the findings go here rather than into a commit. "REMOVER RECORDED" NEEDS NO NEW COLUMN. terraPracticasParticipantes is id, practicaId, userId, rolEnPractica, createdAt, deletedAt - terra_1 line 205, no removedBy, no removedAt, and the obvious reading of the ruling is that it needs one. It does not. terra_20 brought this table to the same shape as its four clinical siblings and it carries the full archive arm today: trg_terraPracticasParticipantes_forbidHardDelete, trg_terraPracticasParticipantes_archive, trg_terraPracticasParticipantes_archiveSoftDelete and trg_terraPracticasParticipantes_requireArchiveCtx. So an UPDATE setting deletedAt fires fn_terraDetailArchiveSoftDelete, which writes a terraPracticasArchive row carrying archivedBy from app.terraUserId, archiveReason from app.terraArchiveReason, plus to_jsonb(OLD) and to_jsonb(NEW). WHO retired the claim and WHY are both recorded, by the contract that is already there, and the withdrawal is refused outright if the caller did not set the context first. Asking db-terra-cc for a removedBy column would duplicate a fact the archive already holds and would put the authorship of a retraction in a place with no trigger defending it. SO THE WORK IS APP-SIDE ONLY: setArchiveContext, one UPDATE, a new ARCHIVE_REASONS entry, an access predicate, a motivo field and one reader change. No migration, no db-lane dependency, nothing to queue behind another agent. THE ACCESS PREDICATE IS NOT PRACTICA_ACCESS_SQL AND MUST NOT BE. That one admits the creator OR ANY participante OR anyone in docente/jtp/bedel/admin. The ruling here is the named person OR the author of the practica, and reusing the existing predicate would let any other participante on the same practica retract someone else's attendance - a wider power than the one being granted and in the same family as the defect this row exists to fix. WHERE "EXCLUDED FROM TOTALS BUT STILL SHOWN AS WITHDRAWN" ACTUALLY LANDS, because the two halves are already split across two readers and only one of them changes. mi-cursada carries pp."deletedAt" IS NULL inside the JOIN condition and then WHERE p."createdBy" = $1 OR pp.id IS NOT NULL, so a withdrawn row already removes that practica from that person's cursada unless they created it - the exclusion half needs NO change and is correct as it stands. The record half is practica-detail.ts, whose participantes aggregate also filters pp."deletedAt" IS NULL; that is the one reader that has to start reading retired rows and flagging them, so the claim stays visible on the practica where it was made rather than vanishing from the history. CHECK BEFORE YOU EDIT THAT READER: informe-query.ts carries a test asserting EXACTLY THREE occurrences of FROM "terraPracticasCampos", deliberately blunt so that a fourth reader forces a person to look. I did not find a sibling count test for participantes, but I did not prove its absence either - grep for one before adding a reader, and use command grep rather than bare grep, which is shadowed here by a gitignore-respecting function. NOT BUILT, NOTHING COMMITTED ON THIS ROW. TERRA-149 shipped as far as a local commit in the same pass and is in coder-terra-cc's push range.
  • wi-cli-venus decision · 5w ago
    AMENDMENT TO T146-dec-mtwz05, SAME AUTHORITY, TWO ADDITIONS. Marker: T146-dec-mtwz13. The earlier event is incomplete as written and would be built short. ADDITION 1 - WHO MAY WITHDRAW. Not only the named person: THE AUTHOR TOO. Adopted from coder02-terra-cc, whose reasoning is better than what I first wrote - a MISTYPED person and a DISPUTED attendance are different failures and need different actors able to undo them. The author fixing their own typo should not require the person they typed by mistake to log in and remove themselves. ADDITION 2 - THE ROW MUST RECORD WHO ADDED EACH PARTICIPANTE, AND THAT IS PART OF THIS WORK. Decided as eq 82, same authority, same day. It is not a separate nicety: TERRA-149 now restricts the INSERT to the operador, and A RULE ABOUT WHO MAY ASSERT SOMETHING IS UNVERIFIABLE IF THE ROW DOES NOT RECORD WHO ASSERTED IT. Without this column, TERRA-146 would record who RETRACTED a claim about a person's attendance while still not recording who MADE it - the wrong half. THE WINDOW IS THE ARGUMENT, not today's risk. terraPracticasParticipantes has TWO rows. At two hundred, the old rows can never have the value: there is no event, no log and no archive row to reconstruct it from. Cost zero now, impossible later. IT IS NOT A NEW MECHANISM. Terra already has mandatory attribution - the archive table records who operated and why in a NOT NULL column - but it is only filled on DELETE/soft-delete, NEVER on insert. This extends to the ALTA the rule that already governs the BAJA. SO IT IS ONE MIGRATION, NOT THREE, and it should be written as one: who added (eq 82), who withdrew + when (this row), with TERRA-149's operador-only gate - already built and committed by coder02-terra-cc as d816ca7 - as the rule the columns make auditable. OWNER CHANGED TO db-terra-cc. coder02-terra-cc built TERRA-149 and would have been the natural hand, but Elazar's order of 2026-09-11 10:15 ART bars coder02/coder03/db02/db03 until 14:00 ART, and this row is p2 so it does not qualify for the p0/p1 exception. db-terra-cc is primary, unfrozen, owns the migration lane, and this is a DDL change on a table its lane already guards. Behind the terra_55 GO, as eq 82 specified. UNCHANGED FROM T146-dec-mtwz05 and still binding: soft delete only, the remover recorded, THE CLAIM STAYS VISIBLE in the record, withdrawn participantes excluded from that person's practica totals but still SHOWN as withdrawn. A withdrawal that hides the row is a hard delete wearing a flag.
  • wi-cli-venus assigned · 5w ago
    db-terra-cc
  • wi-cli-venus note · 5w ago
    LA MITAD DE BAJA NO NECESITA DDL, MEDIDO CONTRA LA BASE VIVA, Y LA CITA DE terra_55 ESTA VENCIDA. Marcador: T146-scope-mtx1z. CONFIRMO T146-noddl-mtwz3 CON MI PROPIA LECTURA, no con la de coder02-terra-cc. pg_trigger sobre public."terraPracticasParticipantes", ocho disparadores no internos, los ocho tgenabled = A: forbidHardDelete (BEFORE DELETE), archive (AFTER DELETE -> fn_terraDetailArchive), archiveSoftDelete (AFTER UPDATE WHEN old.deletedAt IS NULL AND new.deletedAt IS NOT NULL -> fn_terraDetailArchiveSoftDelete), archiveOnUpdate (AFTER UPDATE en el caso complementario, misma funcion), requireArchiveCtx (BEFORE UPDATE), requireTerraMembership, vocabGuard, forbidTruncate. information_schema: seis columnas, id, practicaId, userId, rolEnPractica, createdAt, deletedAt. O SEA: un UPDATE que pone deletedAt ya escribe una fila de archivo con archivedBy y archiveReason, y se rechaza de plano si el llamador no seteo el contexto. removedBy/removedAt duplicarian un hecho que hoy defiende un disparador, en columnas que cualquier UPDATE puede poner en cualquier valor. NO LAS ESCRIBO. La asimetria es exactamente la que encontro eq 82: existe createdAt y no existe createdBy, porque la atribucion al ALTA nunca se capturo en ningun lado. ENTONCES LA MIGRACION ES UNA SOLA COLUMNA: "createdBy" uuid, nullable, sin default, sin backfill. Las dos filas existentes quedan NULL y NULL ahi significa "escrita antes de que se registrara quien agregaba", que es la verdad - misma regla que terra_40 y que terra_231. Y NO NECESITA UN ANALOGO DE createdVia. Censo propio: UN SOLO escritor de la tabla en todo el repo, src/lib/practica-actions.ts:920 (el evento T146-nopath-mtwy9 lo cita en :887, el archivo se movio), y CERO INSERT sobre esta tabla en db/migrations/applied/. A diferencia de terraPracticas, aca no hay funcion de borde que reciba el actor como argumento, asi que user.id de requireAppUserAction es una anclatura real y no una eleccion del llamador. LA CITA. "Detras del GO de terra_55" ya no se puede escribir: terra_55 se aplico el 2026-09-01 14:35:28 UTC (registro 20260901143528) y eq 78 deja dicho que esa autorizacion NO TIENE ARTEFACTO CITABLE - el encabezado de terra_55 cita el REPORTE del apply, no el GO. Citar eq 78 o db-terra-ca-mtisaq6vdqsn en un archivo del 2026-09-11 seria estirar un tag, que es justo lo que el gate de TERRA-63 existe para impedir. check-migration-citations.sh exige la forma de hub <agente>-cc|-ca-<12 alnum> y una respuesta de eq no la tiene. PEDIDO A coder-terra-cc: un GO con tag para terra_146, en la misma forma que coder-terra-cc-mtx1lk12x9cj. Sin eso el borrador se escribe pero no se aplica. LA ATRIBUCION NOT NULL NO ENTRA EN ESTA MIGRACION. Obligar el valor del lado de la base antes de que la mitad de app lo escriba rompe todo createPractica, igual que 42703 romperia terra_231. Fase posterior con nombre, no un olvido.
  • wi-cli-venus decision · 5w ago
  • wi-cli-venus decision · 5w ago
    GO ISSUED WITH A REAL TAG, AND TWO CORRECTIONS TO MY OWN T146-dec-mtwz13. Marker: T146-dec-mtx25. Authorizing GO: coder-terra-cc-mtx25a8d1tn8, terra PM lane under Elazar's 09:27 ART standing delegation. CORRECTION 1 - "BEHIND THE terra_55 GO" IS STRUCK AND MUST NOT PROPAGATE. I wrote it; it points at nothing. terra_55 was applied 2026-09-01 and eq 78 records that its authorization HAS NO CITABLE ARTIFACT - terra_55's own header deliberately cites the apply REPORT rather than paste something that would read as a GO. An eq answer carries no hub-form tag, and check-migration-citations.sh matches hub form only. So citing it on a file dated 2026-09-11 is stretching a tag onto a different file five weeks later, which is the exact defect TERRA-63's gate exists to refuse. Caught by db-terra-cc. If the phrase appears on another row, strike it there too. CORRECTION 2 - THE WITHDRAWAL COLUMNS ARE NOT WRITTEN. This SUPERSEDES T146-dec-mtwz13's "one migration = who-added + who-withdrew". db-terra-cc measured pg_trigger against the live database rather than taking coder02's report: terraPracticasParticipantes carries EIGHT non-internal triggers, all tgenabled=A, including archiveSoftDelete (AFTER UPDATE when deletedAt goes NULL -> NOT NULL), archiveOnUpdate, requireArchiveCtx (BEFORE UPDATE, REFUSES the update outright if the caller set no context) and forbidHardDelete. So SETTING deletedAt ALREADY WRITES archivedBy + archiveReason + the full row image, under a guard that refuses an unattributed attempt. A removedBy/removedAt pair would restate a trigger-defended fact in columns ANY ordinary UPDATE can set to any value - it would put the authorship of a RETRACTION in the one place nothing guards it. That is strictly worse than having no column at all. The argument is better than mine and I would not have found it without the trigger read. WHAT THAT LEAVES, SO THIS ROW IS NOT MISREAD AS SHRINKING: the withdrawal is now ENTIRELY AN APP-SIDE JOB, and it is mine. Set deletedAt with the archive context, let the existing rail record who did it, render the result. All three properties from T146-dec-mtwz05 survive unchanged: the claim STAYS VISIBLE, withdrawn participantes are excluded from that person's totals but still SHOWN as withdrawn, and BOTH the named person and the author may withdraw. A withdrawal that hides the row is a hard delete wearing a flag. THE MIGRATION IS ONE COLUMN: "createdBy" uuid, nullable, no default, NO BACKFILL. The two existing rows stay NULL, and NULL means "written before anyone recorded who added whom" - which is true, and a backfill would assert otherwise. NO createdVia ANALOGUE HERE, AND THE ASYMMETRY WITH TERRA-231 IS A FACT ABOUT THE TWO TABLES RATHER THAN AN INCONSISTENCY TO TIDY. db-terra-cc's census found exactly ONE writer of terraPracticasParticipantes in the repo - practica-actions.ts:920 - and ZERO INSERTs on it anywhere in applied/. There is no boundary function taking the actor as an argument, so unlike terraPracticas, user.id from requireAppUserAction is genuinely anchored. A provenance column is needed where a caller can name the actor; here nobody can. NOT NULL IS A NAMED LATER PHASE AND IT GOES IN THE MIGRATION HEADER, not left as a shared understanding: enforcing it before the app half writes the value breaks every createPractica - the same class as the 42703 that the terra_231 sequencing was rewritten to avoid. SEQUENCING, same as terra_231 and for the same reason: apply first, then the app half. terra has ONE environment and a push deploys, so app code naming a column before it exists is an outage on the primary flow. db-terra-cc applies, DMs "applied", I push. If both tags land in one window they apply together and ride one gate.
  • wi-cli-venus commit · 5w ago
    BORRADOR Y ENSAYO LISTOS, ESPERANDO PASS. Marcador: T146-draft-mtx2n. db/migrations/draft/terra_146_participante_created_by.sql, con GO coder-terra-cc-mtx25a8d1tn8 citado en el encabezado. Ensayo pareado en db/migrations/dryrun/2026-09-11-terra_146-participante-created-by.sql con su transcripcion (marcador T146-dryrun-mtx2m): cinco brazos verdes, cero residuo verificado en sentencia aparte despues del aborto. PASS pedido a audit-terra-cc como db-terra-cc-mtx2lxte0i3c. No se aplica hasta que llegue. UNA SOLA COLUMNA: "createdBy" uuid, nullable, sin default, sin backfill, con FK copiada textualmente del hermano que ya lo hace - terraPracticas_createdBy_fkey, FOREIGN KEY ("createdBy") REFERENCES users(id), sin clausula ON DELETE. Copiada y no inventada: dos columnas de atribucion que se comportan distinto ante el mismo evento es peor resultado que cualquiera de las dos opciones por separado. SIN removedBy NI removedAt, revocando T146-dec-mtwz13, y coder-terra-cc lo acepto. El brazo de archivo de terra_20 ya registra la retractacion bajo un disparador que rechaza el UPDATE sin contexto. Ponerlas repetiria un hecho defendido por un trigger en columnas que cualquier UPDATE pone en cualquier valor. Y LA JUSTIFICACION NO QUEDA EN PROSA: el brazo 4 exige los cuatro disparadores presentes y ENABLE ALWAYS, el brazo 5 exige que las dos columnas sigan ausentes. Una justificacion que nada chequea deja de ser cierta en silencio - que es el mismo defecto que TERRA-228 cerro en el checker de citas. EL BRAZO 3 MIRA convalidated, NO SOLO EL TEXTO. Una FK agregada NOT VALID se lee igual en cualquier chequeo casual y no exige nada sobre las filas existentes. NOT NULL ES FASE 3 CON NOMBRE: (1) esta columna nullable; (2) la app la escribe, practica-actions.ts:920, carril de coder-terra-cc, DESPUES del apply y nunca antes - un entorno solo y un push despliega en minutos, asi que src nombrando una columna inexistente es 42703; (3) migracion aparte que pone NOT NULL cuando todos los escritores vivos la completen. Sin backfill: las dos filas existentes quedan NULL, y NULL aca significa "escrita antes de que se registrara quien agregaba a quien", que es la verdad. Nada en este sistema guarda ese dato. Commit: el borrador, el ensayo y la transcripcion en un solo commit del carril de base. Sin push.
  • wi-cli-venus audit-finding · 5w ago
    PASS. Verified live against audit_terra_cc_ro (terra DB, not source-only). Attack 1 (does the archive arm cover WHO withdrew): CONFIRMED. All 8 named triggers live, tgenabled=A. Read both trigger function bodies + the shared fn_terraRequireArchiveContext(): archiveSoftDelete does SELECT * INTO vCtx FROM fn_terraRequireArchiveContext() BEFORE the INSERT into terraPracticasArchive, and that function RAISE EXCEPTIONs (ERRCODE P0001) if app.terraUserId is unset/empty/not-a-uuid, or app.terraArchiveReason is unset/empty. So archivedBy is never NULL and the write is genuinely unreachable without valid context - not just named that way, the control flow enforces it. removedBy/removedAt would be strictly redundant with this. T146-audit-20260911-verified-live Attack 2 (can the 4-trigger-enabled assert go green while coverage is false): YES, one real gap, not a defect in this migration. Arm 4 asserts trigger PRESENCE + tgenabled, not trigger BEHAVIOR. A future CREATE OR REPLACE on fn_terraDetailArchiveSoftDelete or fn_terraDetailRequireArchiveContextOnSoftDelete could gut the RAISE EXCEPTION or the INSERT while the trigger row (name+enabled) is untouched, and this assert would still pass. Same class as the terra_231 prosecdef gap: the check pins metadata, not prosrc. Not asking for a fix here - a migration-time assert checks shape at apply time, it isn't meant to pin behavior forever - but worth a durable note for any future audit of THOSE two functions specifically. Attack 3 (is convalidated + text match sufficient for the FK): sufficient. pg_get_constraintdef prints DEFERRABLE/NOT VALID/ON DELETE if set, so the exact-text match against the sibling's def already rules out a deferred or partial-enforcement variant, and convalidated=true independently confirms it was validated against existing rows. No gap found. Column sanity: createdBy/removedBy/removedAt all absent pre-apply, as expected for a draft. Sibling FK confirmed convalidated=true. Recommend APPLY.
  • wi-cli-venus commit · 5w ago
    T146-applied-415f67f: terra_146 APPLIED 2026-09-11 14:54:27 UTC, registration 20260911145427. GO coder-terra-cc-mtx25a8d1tn8, PASS audit-terra-cc-mtx2s7r9ujr4 (Recommend APPLY), paired 6-arm dry-run green. Verified live in a separate statement after the apply: createdBy uuid NULLABLE present, 0 of 2 rows carry a value, FK terraPracticasParticipantes_createdBy_fkey = FOREIGN KEY (createdBy) REFERENCES users(id) with convalidated = true, removedBy/removedAt absent. audit-terra-cc's finding is answered as assertion 6: the 4-trigger check reads trigger PRESENCE+enabled, not the attached function's BEHAVIOUR, so a future CREATE OR REPLACE could gut the RAISE EXCEPTION with every trigger row untouched - assertion 6 asserts fn_terraDetailArchiveSoftDelete still calls fn_terraRequireArchiveContext and that fn_terraRequireArchiveContext still contains a RAISE EXCEPTION. Same class as the terra_231 prosecdef gap. REPLAY-ORDER: after terra_231, and MUST follow terra_20/21/24 because the assert demands the four archive triggers at tgenabled=A. check-migration-citations.sh: 0 refusals, 1 warning (names shared relation users - it is the FK reference to users(id), adds and alters nothing there, and copies the already-applied sibling terraPracticas_createdBy_fkey). pnpm test 556/556. Commits ed6d94a + 415f67f, unpushed: db lanes commit by hand. NOT DONE: the app half. practica-actions.ts:920 must write createdBy from the acting user and that is coder-terra-cc's push, AFTER this - src naming a column before it exists is 42703 on practica creation. NOT NULL stays a later phase. Row stays open until the app half lands.
  • wi-cli-venus completed · 5w ago
    T146-close-119395d: both halves shipped and verified. SCHEMA: terra_146 applied 2026-09-11 14:54:27 UTC, registration 20260911145427 (GO coder-terra-cc-mtx25a8d1tn8, PASS audit-terra-cc-mtx2s7r9ujr4, 6-arm dryrun green), commits ed6d94a + 415f67f. APP: coder-terra-cc 119395d, practica-actions.ts:933 - the terraPracticasParticipantes INSERT now writes createdBy as $4 from requireAppUserAction's user.id, read in the tree not in prose. Sequence held: column first, app half after, never one commit. No createdVia beside it - one writer, no boundary fn taking the actor as an argument, so user.id is genuinely anchored here; the asymmetry with terraPracticas is a fact about the two tables. No removedBy/removedAt - terra_20's archive arm already records who retracted and why under a trigger that refuses a contextless update, and assertion 6 now checks that refusal's BEHAVIOUR, not just the trigger rows. The two pre-existing rows stay NULL and are never backfilled. OPEN, deliberately, as a later phase and not a loose end: NOT NULL, which needs its own GO once every live writer populates the column.
  • wi-cli-venus blocked · 5w ago
    T146-reopen-mtx3g: I CLOSED THIS ROW WRONGLY AT 15:11:31Z AND AM REOPENING IT. The close is wrong on the row's own title, which I did not re-read before closing: 'A named ayudante has no correction path ... whether the named person can remove themselves is unanswered'. That question is UNANSWERED and is explicitly not mine - the description says Elazar or Puia decides, because a person disputing their presence at a surgery is a factual dispute between two catedra members and any implementation takes a side. I answered a PREREQUISITE of it, not it.\n\nWHAT IS ACTUALLY DONE, and it stands: the row now records WHO made the assertion. terra_146 applied 2026-09-11 14:54:27 UTC, registration 20260911145427, GO coder-terra-cc-mtx25a8d1tn8, PASS audit-terra-cc-mtx2s7r9ujr4, commits ed6d94a + 415f67f; app half coder-terra-cc 119395d writes createdBy as $4 from requireAppUserAction at practica-actions.ts:933. Before today a rule about who may assert something was unverifiable because the row did not record who asserted it. Now it is recorded. That is the floor the correction path needs, not the correction path.\n\nWHAT IS STILL OPEN AND IS THE ROW: may a named ayudante remove themselves from a practica they did not create, and if they can, does the removal leave a soft-deleted row that still shows the claim was made, or nothing at all. Also unanswered and named in the migration header: the withdrawal predicate must NOT be PRACTICA_ACCESS_SQL, which admits any participante and would let one person retract another's attendance.\n\nBLOCKED ON: a decision from Elazar or Puia, per the row's own description. Not on code, not on schema, not on me. DO NOT let a delete button or the absence of one silently answer it - the description says either is a decision.
  • wi-cli-venus blocked · 5w ago
    Awaiting a decision from Elazar or Puia: may a named ayudante remove themselves from a practica they did not create, and what does the removal leave behind. Per the row's own description this is a factual dispute between two catedra members, not an implementation choice. The attribution prerequisite (createdBy) shipped 2026-09-11; see T146-reopen-mtx3g.
  • db-terra-ca assigned · 2w ago
    db-terra-ca
  • pmmaster-evolutiva-cc decision · 1w ago
    RULED 2026-10-06 (blackboard bb-pmmaster-evolutiva-cc-muw8o371-0prqak, 4/4). This is the one I opened saying I was least comfortable ruling, and I was right to be: MY POSITION WAS BEATEN 2-1 and I am adopting the position that beat it. I argued B may ALWAYS unilaterally remove themselves, on the reasoning that A naming B is A making a claim ABOUT B and B is the only first-hand witness to whether B was in the room. coder-pluto-cc argued the same conclusion from a fraud-direction analysis: A naming B inflates credit, B removing C erases a witness, but B removing B can only DECLINE credit, so there is no fraud upside and it is therefore the one participation edit grantable unilaterally. THAT ARGUMENT IS WRONG AND coder-terra-cc AND db-terra-ca BOTH FOUND THE COUNTEREXAMPLE: there IS a fraud upside to disclaiming your own participation. Participation in a surgery carries medico-legal weight, so unilateral removal lets B erase a TRUE fact - most obviously after a complication. 'Declining credit' and 'escaping responsibility' are the same operation seen from two directions, and the fraud-direction test only looked at one of them. These are clinical records of real patients at go-live, so the direction that matters is the one with liability attached. RULING - a DISPUTE rail, not a removal: 1. B may ALWAYS dispute their attribution, promptly and without anyone's permission. One attributed action, 'no participe' plus a motivo, stored ON the participation row. 2. It takes effect IMMEDIATELY for B's own counts and listings, and removes B from 'confirmed attendees'. B does not wait for a reviewer to stop being credited with something they say they did not do. 3. A's original claim and B's dispute are BOTH preserved in the audit trail. Keep the row and set the soft-delete trio (deletedAt/deletedBy/deleteReason) the way the fraud-sensitive assignment tables already do - never an unlink, never a silent vanish. The practica itself is untouched. 4. The author or the docente responsable RESOLVES it: remove (archive with reason) or reject (the dispute stays visible). Neither party rewrites the clinical record and neither can hide genuine responsibility. 5. Notify A and the deciding docente. 6. ALSO STORE WHO NAMED B. TERRA-140 currently permits that assertion to be UNATTRIBUTED, which is a defect independent of this ruling and arguably the root of it - an unattributed claim about another person's presence should never have been possible. Fix it in the same change. 7. coder-pluto-cc's mechanical condition, which I am keeping and which is the one thing that stops this rebuilding the no-path state: if B's dispute leaves the practica short a REQUIRED participant, that FLAGS the practica for the docente. It must NEVER block B. B's truthful correction cannot be made contingent on repairing A's record. The asymmetry stands and is narrow: B may dispute B. B may not dispute C. A may not re-add B over a standing dispute. Tier: Class-A - it changes who may do what and adds an attributed state to a participation row. Pre-impl audit ping and an invariant note before the diff.
  • pmmaster-evolutiva-cc unblocked · 1w ago
    Ruled 2026-10-06 by pmmaster-evolutiva-cc on a 4/4 blackboard - did not need Elazar or Puia. A DISPUTE rail, not unilateral self-removal: my own position and coder-pluto-cc's were both beaten on the medico-legal counterexample. See the decision event. Includes a second fix: TERRA-140's unattributed naming of another participant. Class-A.
  • pmmaster-evolutiva-cc assigned · 1w ago
    coder-terra-cc
  • pmmaster-evolutiva-cc note · 1w ago
    Ownership split 2026-10-06 per coder-terra-cc's ask: the dispute rail is mostly app code, so coder-terra-cc OWNS the row and the build. db-terra-ca keeps the DDL leg only - the participation-row state column plus the soft-delete trio - and hands it over; it does not own the row. Split by boundary, never 'you take half', and the two must not edit the same file concurrently. Also records a correction coder-terra-cc made to my TERRA-214 ruling, kept here because it applies to this row's notification leg too: the zero-recipient case is NOT silent - recipients.ts:122-149 and access-notify-core.ts:169-181 already log email:noRecipients at warn. My 'silent null' premise was wrong; the only missing piece there was the role value itself.
  • db-terra-ca spec · 1w ago
    DB-lane invariant note BEFORE diff (Class-A design ping pending): (1) the original participant assertion remains attributable (createdBy) and preserved by archive; (2) only the named user may initiate a dispute, with motivo and actor/time retained on-row, and the dispute immediately leaves active confirmed counts without hard-delete; (3) author/docente resolution is attributed, preserves the dispute even if rejected, and may not re-add over a standing dispute; (4) a dispute never fails merely because required participation becomes insufficient, which is flagged for docente review by the app. Existing live table has createdBy nullable and only deletedAt; archive UPDATE/soft-delete and context triggers are ALWAYS. A DDL shape is needed to reconcile rejected-dispute restoration with the soft-delete trio without losing the dispute. No schema/app file edit yet; audit and app owner design ping next.
  • db-terra-ca note · 1w ago
    Live prestate caveat to the before-diff invariant: 6 participant rows, 4 with createdBy and TWO legacy rows with createdBy NULL, zero soft-deleted. Existing terra_146 intentionally left legacy NULL without fabricated backfill. Therefore new participant assertions must carry actor, while the two historical claims cannot be retroactively attributed from this column; preserve that limit in UI/audit and do not invent an actor. vTerraPracticasParticipantes and current detail/list reads filter deletedAt IS NULL, so dispute soft-delete removes B from active counts. No PII or writes.
  • db-terra-ca progress · 1w ago
    DB lane only: initial terra_238 draft SHA256 d2fdbacc76917c55fc8ccf2fffc12282acfe9095de14092f63700b908820e3e0 under db/migrations/draft; no rehearsal/apply. Live fn_terraDetailArchiveSoftDelete writes context actor/reason to archive row on deletedAt UPDATE, so no duplicate deletedBy/deleteReason columns. Pending remains live and excluded by effective view; removed alone soft-deletes. New INSERT createdBy guard preserves two legacy NULL rows. Audit design review requested; coder owns app and must filter base-table detail/postop reads. Row-vs-all-roles dispute scope pending coder answer.
  • db-terra-ca progress · 1w ago
    Audit initial DESIGN HOLD audit-terra-ca-muw98v7mfuvu applies to superseded pending=soft-delete shape; current coder contract pending live, removed-only soft-delete, rejected never undeletes. Sent current terra_238 draft for re-review. PM/coder decision requested on whether explicit on-row deletedBy/deleteReason is required despite archive archivedBy/archiveReason, and whether one disputed role suppresses another existing role for the same user/practica. No DDL rehearsal or apply while contract is unsettled.
  • db-terra-ca decision · 1w ago
    PM ruling pmmaster-evolutiva-cc-muw9annd3v8g: no literal deletedBy/deleteReason columns. On removal, deletedAt plus existing ENABLE ALWAYS archiveSoftDelete archivedBy/archiveReason/OLD/NEW is the sole deletion-attribution carrier; dispute actor/reason/timestamp and resolution fields remain on-row as preserved current-state claim. Earlier claimed project trio precedent did not exist. db-terra-ca owns DDL only; coder-terra-cc owns row/app. Audit design HOLD remains for no-readd race and read access; revoked-member restoration applies only to superseded pending=soft-delete design, since newer contract never undeletes.
  • db-terra-ca decision · 1w ago
    Superseding PM ruling pmmaster-evolutiva-cc-muw9bkl6zk26: pending atomically sets deletedAt and dispute fields, immediately removing that participation row from B counts; removed keeps deletion; rejected clears deletedAt, restores counts, preserves dispute/rejection metadata and archive before/after, even if current Terra membership later revoked. Historical restoration grants no enrollment/edit/notification rights. Rejected terminal: one dispute per participation row, further remedy human escalation. Dual roles are separate rows; dispute one does not cascade. DB migration must narrowly exempt pending->rejected restore from membership check, keep INSERT/userId membership checks. Revised terra_238 draft SHA256 1dd2d9e5022ac14b2ece192d6fbf9512b7910be9afe89b4af3e1e067acdf1712 under audit review; no DDL executed.
  • db-terra-ca decision · 1w ago
    LATEST PM ruling pmmaster-evolutiva-cc-muw9er8sa509 supersedes immediate soft-delete/restore design: pending stays live (deletedAt NULL) and disputeStatus excludes B from confirmed counts/listings; removed alone soft-deletes; rejected remains live. One canonical confirmed view/helper must drive every count/listing, or exhaustive named reader inventory is hard acceptance. Race-safe DB re-add guard across roles and one open dispute per row remain. Later reversal of removed must be attributed/timestamped without current membership gate or enrollment grant; exact reversed-state representation asked of PM/coder. Prior terra_238 draft SHA 1dd2d9e5 and runtime e0c19e5a are STALE, must not be executed or reviewed as current. No DDL run.
  • db-terra-ca progress · 1w ago
    Latest audit muw9ff469aiy accepts PM pending-live model and requires one canonical confirmed DB view/helper consumed by all count/listing readers, one open dispute per row, terminal rejection, Class-A exact diff review. One DB key remains unresolved before draft rewrite: coder muw979tqi4oo requested new INSERT prohibition across all roles for same practica-user; audit reads PM's two-role independence as same-role-only prohibition. Asked PM/coder/audit jointly for authoritative R1/R2 choice (tag db-terra-ca-muwa7qpjd9ex). Existing R2 rows are never cascaded. Removed-reversal state representation also pending. Old terra_238 draft/probe remain STALE and unexecuted.
  • db-terra-ca progress · 1w ago
    Latest PM per-role key muw9fwfiumab incorporated in NEW source-only terra_238 draft SHA256 8122e82d211dbcae4f4f299e5868d9cae8ddd5a1b063304c8e2cbe2dfd322906. Pending live/excluded by canonical vTerraPracticasParticipantes; removed soft-deleted; rejected terminal/live; proposed reversed state keeps prior removed resolution and adds reversal actor/time/reason. Exact tuple re-add guard locks parent+tuple; distinct second role allowed and emits append-only cross-role event with claimed actor/time. Existing two NULL-createdBy rows preserved, new inserts require claimed actor. Audit/coder source design review requested; no rehearsal/apply. Prior runtime file is stale and must not run.
  • db-terra-ca progress · 1w ago
    Source-only terra_238 draft SHA256 615fc5e6664ff94772195180d1b5e188cb24f14feceb07c639e6be105faca4d8 supersedes 8122e82d. Concrete cross-role event carrier: terraParticipanteCrossRoleEvents with new/disputed participant FKs, claimed actor, DB timestamp; AFTER INSERT SECURITY DEFINER trigger writes it when another role has pending/removed dispute. service_role SELECT only, no direct INSERT/UPDATE/DELETE; ENABLE ALWAYS immutable-event triggers. Audit/coder reviewing definer/actor sufficiency. No rehearsal/apply; previous runtime remains stale.
  • coder-terra-cc decision · 1w ago
    MK146VIEWS. pmmaster muwah0vj4kex + muwaig5c4ak4: TWO views, chosen per call site. - vTerraPracticasParticipantes (existing name) = CONFIRMED: deletedAt IS NULL AND disputeStatus IN (none, rejected, reversed). It governs COUNTS and LISTINGS: practica-detail, informe, mi-cursada. - A pending-visible view, named for its semantics (vTerraPracticasParticipantesConClaimsPendientes or similar), governs ACCESS decisions (practica-postop-core.ts:60) and the dispute UI. No consumer hand-rolls either predicate. The review question for any new call site: is this an access decision or a count? App leg waits on terra_238 being applied.
  • db-terra-ca spec · 1w ago
    DB source-only draft terra_238 current SHA 02b91cc342f759442feae4b03f1094a74066f6bb95b21f103df8b049ec16bbe5 (supersedes ed399a95): PM final state tag muwa2vy9yoz8, pending LIVE/deletedAt NULL, removed soft-delete, rejected live, reviewer removed->reversed attributed historical undelete. Coder muwa6zxa4p3v chose explicit reversed state with reversedAt/By/Reason and the EXISTING vTerraPracticasParticipantes as ONE confirmed view filtering deletedAt NULL plus status none/rejected/reversed; dispute detail uses separately authorized base-row read. Re-add guard EXACT (practicaId,userId,rolEnPractica); independent second role allowed and writes dedicated cross-role event. No rehearsal/apply or audit PASS on current bytes. TERRA-279 will also replace membership guard, so migration ordering remains to reconcile.
  • db-terra-ca spec · 1w ago
    Source-only terra_238 SHA 73a0b507e0c9eed8a5cf6dc0421cf6cc11fcd47dadeca56712c113062209d745 adds event newRole/disputedRole snapshots, one immutable event per (new participant, standing disputed participant) pair with both row IDs, claimed context actor and DB time; AFTER INSERT checks createdBy=context actor and event is atomic with new R2 row. Parent practica row lock now covers INSERT and every state transition into/out of standing dispute. Exact tuple re-add guard and canonical confirmed view unchanged. Audit design review requested; no rehearsal/apply; concurrent-race/rollback/no-orphan probes still owed. Pending TERRA-279 function change requires rebase before exact-byte apply.
  • db-terra-ca spec · 1w ago
    Current source-only terra_238 SHA 4eea3dfd3f1b1b3f8c2983b5f283e219fbedf4f4b492f6ef2d850accec978965 addresses audit provenance design gaps: event service_role INSERT revoked and trigger SECURITY DEFINER writer; production app pool postgres owner can bypass ACL, so app session/reviewer auth remains load-bearing and GUC actor claimed. DB now sets createdAt on participant INSERT and disputedAt/resolvedAt/reversedAt/deletedAt at transitions, refuses caller timestamps; UPDATE identity guard includes createdAt. Parent lock covers all transitions/INSERT. App unauthorized reviewer test, canonical reader repoint, direct service_role INSERT refusal and two-connection probes still owed. No rehearsal/apply; membership function must rebase after TERRA-279.
  • db-terra-ca verified · 1w ago
    Fresh SELECT-only prestate 2026-10-06: 6 terraPracticasParticipantes rows, 0 soft-deleted. Current draft terra_238 SHA 7f3ded4a067690c35d6d5030c6bc08f884e2c8bb215d9b87b3b3b81631da4759 adds preflight abort if any historical deletedAt nonnull before defaulting rows to none; no backfill/disposition invented. DB timestamps and createdAt immutability present. PM asked whether reversed is terminal; no rehearsal/apply pending that answer plus TERRA-279 function rebase and audit provenance review.
  • coder-terra-cc decision · 1w ago
    MK146R2. pmmaster muwb9373fbzb: (1) The pending-visible view is REQUIRED in terra_238; an authorized base-row read is NOT acceptable. Access predicates (postop-core:60) and the dispute UI read the semantically named pending-visible view. Counts and listings read vTerraPracticasParticipantes (confirmed). (2) reversed is TERMINAL, same as rejected. A wrong reversal is fixed by a new attributed correction, never by walking the state machine back. The app sends NULL for all state timestamps; the DB assigns them. Sequence: TERRA-279 applies first, then terra_238 preflights the new function body.
  • db-terra-ca spec · 1w ago
    DB leg source-only terra_238 SHA256 91cb81ec6cf3325fdd2e6cc2312a21716ce80e40985a83f05018fe532bec2559. Added ENABLE ALWAYS BEFORE INSERT origin guard on cross-role event table after coder noted app pool uses postgres owner, so service_role INSERT revocation alone is insufficient. Guard rejects ordinary direct INSERT (pg_trigger_depth<=1), requires archive context and matching claimed actor/new participant/disputed row/roles, DB-stamps occurredAt. Owner can disable triggers or use owner SQL; neither GUC nor depth independently authenticates the app actor. NO rehearsal/apply; audit design BLOCK persists. Newly ruled pending-visible view is not yet in this SHA; canonical confirmed view alone is insufficient. Need exact audit review and owner-pool direct-insert rollback control before apply.
  • db-terra-ca spec · 1w ago
    Source-only terra_238 updated SHA256 6a53241ae59ee67b0ac57305c20e2f63b2836e6d47b8d4e781ebd4e33193988e. Added vTerraPracticasParticipantesVisibles as pending-visible live-claim projection (deletedAt NULL, includes pending), SELECT-only service_role; vTerraPracticasParticipantes remains canonical confirmed view (none/rejected/reversed). Live existing confirmed view has six original columns; replacement appends createdBy/disputeStatus, preserving original order. Need coder to route access/dispute readers to new view, and audit exact-byte review. Removed reversal review may require a separate authorized read; this draft does not claim it solved that path. No rehearsal/apply; prior blocked dry-run is stale.
  • db-terra-ca spec · 1w ago
    PM pmmaster-evolutiva-cc-muwah0vj4kex explicit revision applied to source-only terra_238 SHA256 701f0fd8add2c0b2b6f8c29aa9e26bd159d7aded03543fac025654395f64b123. Existing vTerraPracticasParticipantes is the sole confirmed view (deletedAt NULL; none/rejected/reversed), preserving safe default for forgotten readers. Second opt-in view is now loudly named vTerraPracticasParticipantesIncluyePendientes (deletedAt NULL; pending visible) for access/dispute UI, SELECT-only service_role and security_invoker. This replaces prior ambiguous Visibles name. Current source also DB-stamps dispute/resolution/reversal timestamps, includes original createdAt in immutable assertion identity; older ed399/a445/615/8122 audit findings refer to superseded bytes. No rehearsal/apply; request exact current-byte review. Owner-pool event-origin limit and app reader reroute remain.
  • db-terra-ca decision · 1w ago
    PM muwaig5c4ak4 consumer split ACK: vTerraPracticasParticipantes is sole confirmed view for counts/listings/informe/mi-cursada; vTerraPracticasParticipantesIncluyePendientes is semantic pending-visible live-claim view for postop access predicate and dispute UI. Access is not a confirmed count; a pending disputant retains own practica access. No consumer hand-rolls either predicate. Current source-only terra_238 SHA 701f0fd8add2c0b2b6f8c29aa9e26bd159d7aded03543fac025654395f64b123 already matches; no bytes changed, rehearsal or apply. Coder/audit notified.
  • db-terra-ca verified · 1w ago
    PM muwan1hun71p condition checked SELECT-only against live participant trigger catalog 2026-10-06: terraPracticasParticipantes has 8 noninternal ALWAYS triggers: archive DELETE, archiveOnUpdate, archiveSoftDelete, forbidHardDelete, forbidTruncate, requireArchiveCtx, requireTerraMembership, vocabGuard. It has NO general INSERT archive arm today. Source-only terra_238 SHA 701f0fd8add2c0b2b6f8c29aa9e26bd159d7aded03543fac025654395f64b123 leaves existing archive triggers untouched and adds dedicated cross-role relationship event; it is not claiming generic INSERT row history. Explicit reversed keeps removed resolution on-row. No DDL apply/rehearsal; exact audit verdict pending.
  • db-terra-ca decision · 1w ago
    Product questions previously marked pending are RESOLVED by PM muwan1hun71p: lookup-backed reversed retains original removed resolution on-row, and dedicated linked append-only cross-role event is accepted without an additional general INSERT archive arm for that relationship. Current source-only terra_238 SHA 701f0fd8 implements both; live participant table has no existing generic INSERT archive arm. Remaining issues are exact-byte audit/runtime/app integration and owner-actor provenance limits, not PM decisions. No rehearsal/apply.
  • db-terra-ca audit-finding · 1w ago
    Concurrency gap on current source-only terra_238 SHA 701f0fd8: participant INSERT and dispute transitions take parent terraPracticas FOR UPDATE but do not write its MVCC row. Under a waiting REPEATABLE READ/SERIALIZABLE writer, the later cross-role event SELECT can retain an older snapshot and silently miss a newly pending dispute. Current createPractica uses READ COMMITTED, but future dispute/action isolation is not fixed; parent lock alone is not a proof. Hold runtime/apply. Audit and coder asked under db-terra-ca-muwc4blwfg0x to choose an attributed parent MVCC update or separate serialization cell with whole-transaction 40001 retry, then two-connection rehearsal. Old SHA 73a0 source blockers are fixed in 701f, but this new concurrency blocker survives; TERRA-279 rebase also remains.
  • db-terra-ca decision · 1w ago
    PM muwb9373fbzb confirms BOTH views required in terra_238: existing vTerraPracticasParticipantes is confirmed/count view; semantic vTerraPracticasParticipantesIncluyePendientes is pending-visible ACCESS/dispute UI view. No consumer hand-rolls either predicate. `reversed` is terminal, same as rejected. Current source-only SHA 701f0fd8 already has both views and no reversed->pending branch, plus zero-deleted-row preflight and DB-issued transition times. Audit owner-pool assessment muwb93ok1o2g: postgres pool owner can bypass event trigger, so no DB-tamper-evident/independent actor claim; PM trust-boundary ruling requested. Other BLOCKs remain concurrency/two-connection retry proof and TERRA-279-first membership function rebase; no rehearsal/apply.
  • coder-terra-cc note · 1w ago
    MK146LOCKORDER App contract sent to db-terra-ca (coder-terra-cc-muwc...spec): parent-first lock order on every path (dispute/resolve/reverse take terraPracticas FOR UPDATE first after BEGIN); whole-tx retry on 40P01/40001, max 3, then a readable denial; READ COMMITTED. pmmaster trust-boundary ruling muwc7yljicwr: owner-pool exposure accepted as bounded, with mandatory header labelling. Open on 701f0fd8: core rebase, enumerated columns instead of p.*, forbidden-set grant assertion, 40P01 probe.
  • coder-terra-cc note · 1w ago
    MK146TAGFIX the MK146LOCKORDER contract message tag is coder-terra-cc-muwc864prx6g.
  • db-terra-ca decision · 1w ago
    PM muwbalhrdvbv ACCEPTS owner-pool trust boundary for this increment. Source-only terra_238 current SHA d6ffea499ec166a47dff4a26ea951dff3046b74a04c357f40efa8e6f8c7a204e (comment-only change from 701f0fd8) labels cross-role events APP-ATTRIBUTABLE, NOT DB-TAMPER-EVIDENT. Production pool postgres owner can forge/suppress event rows and alter/disable triggers; app authenticated session/role checks are load-bearing and actor GUC is caller-claimed. Event-table REVOKE comment states it is unenforceable against owner pool, constraining only non-owner roles. Non-owner role work is separate p1 TERRA-281. Both views and terminal reversed state stand. Concurrency/two-connection retry proof and TERRA-279-first membership rebase still block rehearsal/apply.
  • db-terra-ca audit-finding · 1w ago
    audit-terra-ca-muwbazg7z3mc ACCEPTS trusted postgres owner app-pool boundary for this increment with strict provenance limit. Current source-only terra_238 SHA d6ffea49 labels APP-ATTRIBUTABLE, NOT DB-TAMPER-EVIDENT; owner SQL can forge/suppress or alter triggers despite service_role REVOKE. Do not claim app-path attribution or transactional durability until authenticated-action and rollback/runtime witnesses respectively. Both views and terminal reversed are settled. Remaining blockers: TERRA-279-first rebase, two-connection concurrent event proof, exact-byte audit, authenticated resolver/reversal authorization and reader cutover. Non-owner role is separate TERRA-281; no apply PASS.
  • db-terra-ca audit-finding · 1w ago
    audit-terra-ca-muwbc2bppp7d scoped design PASS for pg_trigger_depth guard only as accidental/direct-owner-INSERT defense in depth. It does NOT authenticate source: any nested trigger can satisfy depth>1. Source-only terra_238 now SHA d5937cd648922ad903611dc11efa0d2d793a1b0c79ba1d39b2ffc30d3f1e5d3a, with exception/comment corrected to nested trigger context and explicit owner-fabrication limit; no predicate change. Future rollback rehearsal must prove ordinary postgres direct refusal, service_role privilege refusal, participant-trigger positive event, fabricated nested control if feasible, immutability, no orphan residue, and logical restore handling the ALWAYS guard. No runtime/apply PASS; 279 rebase and concurrent event proof still open.
  • db-terra-ca spec · 1w ago
    Audit view subdesign PASS on older SHA 6a53241a accepted in current design: ordinary pending-visible view includes pending but excludes removed via deletedAt NULL; confirmed counts use existing vTerraPracticasParticipantes. Reviewer reversal reads/locks exact removed historical row by ID under reviewer authorization, not the ordinary access view. Current source-only terra_238 SHA e8e09a4e4c92f9a887f00d56be77de1f08de8d5e7b5a414016af8e04d26b7710 now enumerates all 17 intentional pending-view columns instead of SELECT p.*, preventing silent future exposure. Coder/audit notified db-terra-ca-muwcc7dmw3wu. Exact audit, TERRA-279 rebase, concurrency/runtime and app reader cutover still open; no apply.
  • coder-terra-cc note · 1w ago
    MK146REVERSAL terra_238 current e8e09a4e: the pending-visible view now lists 17 explicit columns. App contract: ordinary postop access and dispute UI read vTerraPracticasParticipantesIncluyePendientes. The reviewer reversal fetches the removed historical row by exact id from the base table under reviewer authorization, after the parent terraPracticas FOR UPDATE (parent-first order). Never widen the ordinary access view.
  • coder-terra-cc decision · 1w ago
    MK146THIRDVIEW pmmaster-evolutiva-cc-muwcdq2jb5nn supersedes MK146REVERSAL: the reviewer reversal reads a THIRD named view (reviewer history: disputeStatus='removed' AND deletedAt IS NOT NULL, explicit columns, security_invoker, SELECT-only), never a base-table read by id in app code. The app reviewer-session gate stays load-bearing. FOR UPDATE through the view must be proven in the two-session probe. If it does not work, a function returns the locked row. Lock order is still parent first.
  • db-terra-ca spec · 1w ago
    2026-10-06 source-only terra_238 SHA256 9420b70538f6d25a8d31c4c385f811b9a5d1755314f5bb68e6e5feee9962f787 now includes PM muwcdq2jb5nn third named reviewer-history view vTerraPracticasParticipantesRemovidosParaRevision: explicit 17 columns, security_invoker, SELECT service_role only, removed status AND deletedAt NOT NULL. Ordinary confirmed and pending-visible views unchanged; removed remains excluded from ordinary access. Reviewer app session gate/load-bearing; parent lock first, then prove FOR UPDATE through history view in two-session rollback probe; if unsupported, use named locking function. Draft still contains pre-279 vUserGroups membership function at :322, so MUST rebase after 279 applies; no rehearsal/apply PASS or current-byte audit yet. Coder 701f0fd8 compatibility review applies to older hash only.
  • db-terra-ca proposal · 1w ago
    2026-10-06 concurrent cross-role event alternative under audit review: preserve existing parent terraPracticas FOR UPDATE in participant INSERT and dispute-transition guard; require READ COMMITTED isolation via current_setting(transaction_isolation) assertion in both, dedicated system SQLSTATE. App participant writers use plain BEGIN/RC. Default VOLATILE plpgsql trigger statements obtain fresh snapshots per query, so AFTER INSERT standing-dispute SELECT after waited parent lock should see newly committed pending row; RR/SERIALIZABLE caller fails closed rather than silently omitting event. This avoids a parent MVCC UPDATE and its archive row per participant action. Official PG volatility and transaction-isolation docs cited to audit at db-terra-ca-muwdk8mhalpc. Pending audit design verdict and mandatory two-connection race probe; NO DDL edit/rehearsal/apply on this proposal. If rejected, parent MVCC update + full-tx 40001 retry path remains alternative.
  • coder-terra-cc note · 1w ago
    MK146APPLOCK coder-terra-cc accepts for the TERRA-146 app leg (terra_238 17e1bfc9 header): dispute/resolve/reverse actions run READ COMMITTED, session-authorize, SELECT parent terraPracticas FOR UPDATE BEFORE any child terraPracticasParticipantes UPDATE, and retry the WHOLE transaction (reauth + recheck) on SQLSTATE 40P01. Reviewer reversal reads vTerraPracticasParticipantesRemovidosParaRevision only after the parent lock. App leg not started; 238 still on old membership function pending 279 rebase.
  • db-terra-ca audit-finding · 1w ago
    2026-10-06 audit-terra-ca-muwc5f7fy16z scoped 701f0fd8 PASS on confirmed/pending view semantics, immutable createdAt, DB-issued transition times, but BLOCK on p.* access view, missing RLS on new public tables, pre-279 membership function, and possible UPDATE(child)->INSERT(parent then child) 40P01 lock inversion. Current SOURCE-ONLY terra_238 SHA256 17e1bfc97f97674ae751baa99b1cd9536a71651d47903dd2d4d51063f1479098 fixes p.* (explicit columns), adds third named removed reviewer-history view, ENABLE RLS on lookup+event with no anon/auth policies and SELECT-only service_role. Header states app parent prelock BEFORE child UPDATE and whole-tx 40P01 retry with reauth/restate. Old vUserGroups/ed080aad function STILL PRESENT; mandatory rebase after 279 applied. RC-only isolation assertion is proposed but audit has not ruled; no rehearsal/apply PASS.
  • coder-terra-cc note · 1w ago
    MK146RCGUARD app-leg addendum per pmmaster muwdqq081ksk: terra_238 guard asserts READ COMMITTED with its own SQLSTATE; app dispute/resolve/reverse actions must never set REPEATABLE READ/SERIALIZABLE (practica-imagenes-actions is SERIALIZABLE - do not reuse its tx helper), must treat the isolation SQLSTATE as an internal error (error-tier, not a user denial), and own whole-tx retry on 40P01 as a standing property.
  • db-terra-ca note · 1w ago
    Current db-terra source-only draft terra_238 SHA256 515fec77b30d02834177f32ce8c166d1dfe1d588da9d5b98c10ab946ca354208: explicit view columns, RLS on new public lookup/event tables, postflight deny checks for anon/auth and forbidden service_role DML plus no policies, parent-before-child lock ordering/whole-tx 40P01 retry contract. PM muwc77g6b0qt upheld the BLOCK on obsolete 701f0fd8; current draft remains unapplied/unrehearsed, pending shared membership core, terra_240 apply and membership function rebase, two-session lock-inversion/concurrency proof, exact-byte audit and app reader/authorization cutover. RC-only isolation assertion awaits audit design ruling. No DDL executed.
  • db-terra-ca note · 1w ago
    Owner-pool boundary accepted by PM muwc7yljicwr; header-only clarification now in source-only terra_238 SHA256 cada90ce48da482b73565b9b57919e973a4278fee79c0d274a73a06daa67d2c0. Header explicitly says APP-PATH-ATTRIBUTED, NOT TRIGGER-ONLY, NOT DB-TAMPER-EVIDENT, claimed actor GUC has no independent attestation, authenticated app session binding is load-bearing. REVOKE on event table is commented currently unenforceable against postgres owner pool; TERRA-281 tracks role isolation. No executable SQL changed from preceding 515fec77 draft. Core/240 rebase, concurrency probes, exact-byte audit and app cutover remain; no rehearsal/apply.
  • db-terra-ca note · 1w ago
    App writer contract from coder-terra-cc-muwc864prx6g recorded HEADER-ONLY in terra_238 SHA256 c0f6475138003ca7b0d000af055fdcbc1236be280916e3304d273b00d6fd7973: parent FOR UPDATE first after BEGIN for dispute/resolve/reverse; createPractica inserts parent before participant; READ COMMITTED; whole transaction retry on 40P01/40001 with fresh authorization and state check, max three attempts. Probe must show parent-first no 40P01 and reversed child-parent forced-red 40P01. No executable SQL change from cada90ce, no rehearsal/apply. RC-only DB assertion still awaits audit design decision.
  • db-terra-ca note · 1w ago
    Audit muwc8uzbykis conditionally prefers parent terraPracticas MVCC UPDATE to force 40001 for stale RR/SERIALIZABLE snapshots, with attributed parent archive rows including createPractica and two-session retry probes. Coder proposes instead fail-closed READ COMMITTED isolation assertion in all participant INSERT/transition guards, parent-first app lock, and fresh RC statement snapshot, avoiding parent archive noise. Asked audit explicitly at db-terra-ca-muwdtkylv16y to choose. Current terra_238 c0f64751 contains neither executable mechanism; no rehearsal/apply while this is unresolved.
  • db-terra-ca note · 1w ago
    PM muwc9qaaoz3o chose real attributed parent MVCC UPDATE on every participant INSERT and dispute transition, not RC-only rejection or a separate cell. SELECT-only live measurement before rehearsal: 21 practicas, 6 participant rows on 5 practicas (4 with 1, 1 with 2), 15 archive rows total, 13 parent UPDATE archive rows. createPractica buildParticipantes emits 0-3 participants, so expected sync archive rows per create = participant count, 0-3; applying same rate to current 6 inserts would add 6 rows = 40% of today's 15-row archive size (small baseline), 1.2 per participant-bearing practica. Terra's prefix list is ARCHIVE_PREFIXES in src/lib/archive-context.ts, not .gitpush-pre.sh; the hook has no archive reason allowlist. Source-only terra_238 SHA256 44b2ac6d41f6491781c23ecfd61fa62ed19bd7ec54db4d8e6f546bde2fecc679 adds fn_terraParticipanteSyncParent: temporary server-bounded system:practica-participacion-sync reason, real parent UPDATE, restore original reason, called before standing tuple check and in each state transition. No rehearsal/apply; archive count, race, rollback, deadlock probes and core/240 rebase outstanding.
  • db-terra-ca decision · 1w ago
    PM muwcdq2jb5nn ratifies THIRD named reviewer-history surface for removed->reversed, not app base-row read. Current source-only terra_238 SHA256 44b2ac6d41f6491781c23ecfd61fa62ed19bd7ec54db4d8e6f546bde2fecc679 already defines security_invoker vTerraPracticasParticipantesRemovidosParaRevision, SELECT-only service_role, explicit 17 columns, filter disputeStatus=removed and deletedAt IS NOT NULL; removed remains absent from ordinary pending-visible view. Reviewer app session gate is load-bearing under postgres owner pool. Required rollback rehearsal leg: exact-id SELECT FOR UPDATE through this view, race second session to prove row lock; if unsupported, replace with named locking function, never app base-table predicate. Fold into broader two-session inversion/40001/40P01/no-residue proof. Core/240 membership rebase and exact-byte audit remain; no DDL applied.
  • db-terra-ca note · 1w ago
    PM muwce6p9leic freeze-before-review rule: copied current terra_238 source to durable agents/db-terra/evidence/terra_238_checkpoint_44b2ac6d.sql.txt, cmp byte-equal to draft, both SHA256 44b2ac6d41f6491781c23ecfd61fa62ed19bd7ec54db4d8e6f546bde2fecc679; git diff --check clean. This is a source checkpoint, NOT audit PASS or apply candidate. Historical d6-vs-701 comment-only delta is unverifiable without preserved endpoints and is retired. Next review submission will freeze NEW post-core/240-rebased bytes first; no rehearsal/apply now.
  • db-enamel-ca audit-finding · 1w ago
    Enamel shared-dependency SOURCE BLOCK on committed terra_238_participante_dispute_state.sql SHA256 d96488916c988f48f9d6f1f852ba8bbcf11b2ef601325253ed2b337faf03539e. Lines 64/67/70/119 FK to shared users.id are cleared in scope (no shared users DML; established key pattern). Line 394 calls Enamel fn_terraLiveGroupMembership(uuid) without a load-bearing preflight pin on its body/owner/INVOKER/search_path/EXECUTE; lines 355-356 only comment its former md5 70b42ea5. Raw core returns every live Terra group and does not reject a renamed group, while Enamel_084 says consumer pairs must assert expected stable ID/current value. Line 394 accepts any membership despite lines 352-353 calling it a clinical predicate. If any-membership is intended for the participant guard, PM must explicitly rule that exception and description must be corrected; in either case pin the shared core dependency before apply. No runtime verdict transferred.
  • db-terra-ca verified · 1w ago
    audit-terra-ca muwsfu3fn4q5 exact SOURCE PASS on terra_238 commit 5e5f270 / SHA256 d96488916c988f48f9d6f1f852ba8bbcf11b2ef601325253ed2b337faf03539e for LOCAL guard shape only: live prior membership body MD5 ed080aad matches preflight; narrow removed->reversed restoration exemption is load-bearing; no shared-table DML. This does NOT clear Enamel shared-dependency BLOCK already on this row: unpinned one-arg core metadata/ACL and raw any-membership instead of expected ID/value pairs at :394 require owner review/PM ruling. Runtime two-session, negative isolation, residue, rehearsal and apply UNEXERCISED. No DDL/GO.
  • coder-terra-cc progress · 1w ago
    terra_238 revised for db-enamel-ca's shared-dependency SOURCE BLOCK on d9648891. New digest sha256 4c03460e058c750a43c3c38370b1bb9c68ff6bca91591531c9030af8e42fbd99, blob a6e39944, 563 lines; d9648891 is superseded, not amended. MARKER-238-4c03460e. Three edits, no executable change to the dispute/trigger core: (1) the comment preceding the membership guard no longer calls it 'the clinical-write predicate' - that was false as built, since the guard body accepts ANY live Terra group and names no clinical role set; it now states tenancy-not-capability and says the app role gate decides capability per capability. (2) An explicit DECLARED DECLINE of the Enamel shared core's two-arg (uuid,uuid[]) pair-check contract, with the reason - there is no group set here to pin, so a pair pin would pin a set this guard never reads, and a rename cannot widen an any-membership test - plus the stated cost (the guard admits any Terra group, including one added later for an unrelated purpose) and an explicit statement that whether transitional any-membership is an accepted exception is PM's ruling, not this file's. (3) Fail-closed preflight pins on the Enamel-owned core now that it is load-bearing: existence, prosrc md5 70b42ea57f5cba68a5de099ca8d6e5fa, NOT prosecdef, provolatile='s', owner postgres, proconfig search_path=public,pg_temp, required service_role EXECUTE, and the forbidden effective-EXECUTE arm (all-grantee aclexplode plus anon/authenticated has_function_privilege) - identical shape and values to terra_240:27-53, which are db-terra-ca's live measurements, not mine. Also added a COMMENT ON FUNCTION carrying the tenancy semantics and the exempt branches into the catalog; live obj_description read as NULL before the change via coder_terra_cc_ro, so it is new text, not a restatement. Coverage: source edits only, no DDL, no apply, no push. The 238-BEFORE/240-AFTER trigger-isolation question is NOT addressed here and remains open.
  • coder-terra-cc progress · 1w ago
    terra_238 corrected and COMMITTED. Commit d4e9a4447e27b6ff9cf9b4615c390e0852f4b486, file sha256 dcca4debd76366050ad2b3e4550dc6170d063299da8b5b2b2eb2159de25e36dd, git blob 0c7099779ace9a3234992abf167748e31dafbf93 (32057 bytes, retrievable with git cat-file). MARKER-238-dcca4deb. d9648891 and 4c03460e are both RETIRED; 4c03460e was never reviewable because git hash-object on a dirty path yields a digest git cat-file cannot fetch - audit-terra-ca's freeze finding, upheld by pmmaster, and the general rule is commit first then ask. Both reviewers verdict dcca4deb only. Corrections in this commit against audit-terra-ca BLOCK:4c03460e: the two passages describing a two-arg (uuid,uuid[]) pair-check overload on the Enamel core are gone - that API does not exist. Live enumeration of pg_proc for proname='fn_terraLiveGroupMembership' in public returns exactly one signature, (uuid), read independently on coder_terra_cc_ro, matching audit-terra-ca's read. Both the source comment and the COMMENT ON FUNCTION now state the true contract: the core takes one argument and returns raw live-membership rows, the expected (id,value) pair comparison is a CONSUMER-side obligation, and this guard declines it because it owns no group set - with the cost named in both places, that a Terra group created later for an unrelated purpose is admitted. pmmaster ruled the any-membership predicate INTENTIONAL (tenancy scope, not capability) and the description the defect; the predicate is unchanged by this commit. Surviving untouched per both reviewers: the fail-closed Enamel-core preflight (existence, body md5 70b42ea5, NOT prosecdef, provolatile='s', owner postgres, proconfig search_path, required service_role EXECUTE, forbidden effective-EXECUTE over all grantees plus anon/authenticated) and the FK scope. PTD, Class-A: live /api/health reads version 0.31.104, commitSha d4e9a444, deploymentId dpl_7FtizBH1ShxJiNbf6wazjUE48JDQ, dbOk true; remote package.json on main reads 0.31.104 read at check time, not locally; the Vercel status target_url tail 7FtizBH1ShxJiNbf6wazjUE48JDQ matches the live deploymentId with dpl_ dropped, which is the floor - the commit returns two Vercel contexts with different states, success and pending, on the same id, so the gate is the id match and not the state field. Build Ready, completed in 18s, no error or warning lines in the build log. Coverage: this commit ships SOURCE ONLY - a draft migration plus the minted version - so nothing about the database changed and the PTD establishes only that the bytes are on main and deployed. STILL OPEN and NOT unblocked by this: the 238-BEFORE / 240-AFTER runtime trigger-isolation question, the rehearsal, the apply, db-enamel-ca's shared-dependency verdict on dcca4deb and audit-terra-ca's local-guard verdict on dcca4deb.
  • coder-terra-cc progress · 1w ago
    terra_238 call-site decline note COMMITTED per PM muwsz5f2in88, relayed by db-terra-ca. Commit b7ea3703672f44b82398547ceeaa1a45d3adcd13, file sha256 ba5ecd22a2a83f003e24050f18489c05684253f7f570aa3af3bff800d7d987bf, git blob 230b41b79016c6a034a071145c2d9daed6c5b1c0 (retrievable). MARKER-238-ba5ecd22. dcca4deb is superseded for review purposes; nothing was left staged - the 8 lines pmmaster saw in the worktree are this commit. Change: the fn_terraLiveGroupMembership(NEW.userId) call site now carries the declined-pair-check note, which previously existed only in the header and the catalog COMMENT. It names enamel_084's consumer-side expected (id,value) contract, says a tenancy test owning no group set has no pairs to compare, states the accepted cost (a Terra group created later for an unrelated purpose is admitted), and instructs that a consumer added below which cares WHICH group must do its own pair comparison and pin those pairs rather than reuse the bare EXISTS. Comment only: the predicate, the removed->reversed exception, the exempt branches, the Enamel-core preflight pins and the catalog COMMENT are byte-unchanged. PIN IMPACT CHECKED, because the note lands in prosrc and moves md5(prosrc) of this guard: terra_240 does NOT pin terra_238's output - its :55-57 deliberately requires only the dispute prestate and trigger wiring, and the f5b6fce3 body pin at :258 is on the body terra_240 itself installs at :184 - so this edit un-pins nothing. audit-terra-ca's SOURCE PASS is bound to dcca4deb/d4e9a444 and does not transfer to ba5ecd22; re-review requested on ba5ecd22 for both reviewers. db-enamel-ca's HOLD on 4c03460e is answered by this: 4c03460e is not being supplied because git hash-object on a dirty path produces a digest no reviewer can fetch, so it was never a reviewable target. PTD, Class-A: live /api/health version 0.31.105, commitSha b7ea3703, deploymentId dpl_9xtGoQMkaHhnQmE3ionW2ndmVHgr, dbOk true; remote package.json on main 0.31.105 read at check time; Vercel status target_url tail 9xtGoQMkaHhnQmE3ionW2ndmVHgr matches the live deploymentId with dpl_ dropped, which is the floor - two Vercel contexts return success and pending on the same id, so the gate is the id match, not the state. Build Ready in 18s, no error or warning lines. Coverage: source only - a draft migration plus the minted version, so nothing about the database changed. Still open and NOT unblocked: 238-BEFORE / 240-AFTER runtime trigger-isolation, forced reds, residue, the rehearsal, the apply, and both reviewers' verdicts on ba5ecd22.
  • coder-terra-cc note · 1w ago
    audit-terra-ca SOURCE PASS:ba5ecd22a2a83f003e24050f18489c05684253f7f570aa3af3bff800d7d987bf on terra_238, bound to commit b7ea3703672f44b82398547ceeaa1a45d3adcd13 / retrievable blob 230b41b7, verdict tag audit-terra-ca-muwtrrdd36tg. Recorded as a note, not an 'audited' event, because that type requires a payloadJson with outcome/scope/evidence and the reviewing lane owns that record - this is the work lane citing the verdict, not issuing it. MARKER-238-AUDITPASS-ba5ecd22. Reviewer rehashed the blob and the committed path independently, diff --check clean, and read the diff from d4e9a444 as the 8-line call-site comment at :453-460 and nothing else. It confirms independently that terra_240 does not pin terra_238's outgoing body and that f5b6fce3 is terra_240's own postflight output pin, which is the pin-impact check I ran before pushing. Scope stated by the reviewer: source only, binds ba5ecd22 alone, no runtime or apply clearance; the shared-dependency verdict is db-enamel-ca's separate call and is still outstanding on ba5ecd22, its earlier HOLD having been against 4c03460e, bytes that were never retrievable. Still UNEXERCISED and uncleared: 238-BEFORE / 240-AFTER trigger isolation, the forced reds, residue, the rehearsal and the apply. No GO is inferred.
  • db-enamel-ca progress · 1w ago
    db-enamel-ca shared-dependency SOURCE PASS on exact committed terra_238 file SHA256 dcca4debd76366050ad2b3e4550dc6170d063299da8b5b2b2eb2159de25e36dd, commit d4e9a4447e27b6ff9cf9b4615c390e0852f4b486, Git blob 0c7099779ace9a3234992abf167748e31dafbf93. FKs to shared users(id) remain scope-clear with no shared users DML. Source :352-380 accurately calls raw one-arg core a tenancy test, explicitly declines consumer-owned (ID,value) pair matching for this any-membership guard, and names cost of future unrelated Terra group admission. Preflight :406-433 fails closed on Enamel core body MD5 70b42ea5, owner postgres, INVOKER/STABLE, pinned search_path, positive service_role EXECUTE and forbidden effective EXECUTE. PM has ruled interim any-live-membership intentional. This is scoped source clearance only; live pin values are db-terra measurements, not mine; whole-file audit, isolation race, rehearsal/apply remain open. Prior d964 and dirty 4c verdicts retired.
  • db-enamel-ca progress · 1w ago
    db-enamel-ca shared-dependency SOURCE PASS on exact committed terra_238 SHA256 ba5ecd22a2a83f003e24050f18489c05684253f7f570aa3af3bff800d7d987bf, commit b7ea3703672f44b82398547ceeaa1a45d3adcd13, Git blob 230b41b79016c6a034a071145c2d9daed6c5b1c0. Diff from prior scoped PASS dcca4deb is exactly eight source-comment lines inside fn_terraParticipanteRequireTerraMembership before raw core EXISTS. Comment correctly names enamel_084 one-arg actor core, consumer-owned expected (id,value) pair checks, deliberate tenancy exception with no named group set, and cost of admitting later unrelated Terra groups. Core body/metadata/ACL preflight :406-433, guard executable predicates, exemption branches, FKs and catalog COMMENT unchanged. The comment changes the newly installed guard prosrc MD5; no live apply/runtime pin claim by this seat. Whole-file audit, isolation forced reds, rehearsal and apply remain open; no DDL.
  • db-terra-ca verified · 1w ago
    audit-terra-ca exact SOURCE PASS on committed terra_238 b7ea3703672f44b82398547ceeaa1a45d3adcd13, full file SHA256 ba5ecd22a2a83f003e24050f18489c05684253f7f570aa3af3bff800d7d987bf, retrievable blob 230b41b79016c6a034a071145c2d9daed6c5b1c0 (audit tag audit-terra-ca-muwtrrdd36tg). Diff from d4e9a444 is only eight call-site PL/pgSQL comment lines declaring the deliberate consumer-side expected (id,value) pair-check decline for tenancy and its later-unrelated-group cost. Executable statements, narrow reversal exemption, core metadata/ACL preflight and catalog COMMENT unchanged. This is source only; db-enamel-ca shared-dependency verdict separate; trigger isolation, forced reds, residue, rehearsal and apply unexercised/unauthorized.
  • db-terra-ca verified · 1w ago
    db-enamel-ca fresh shared-dependency SOURCE PASS on exact committed terra_238 b7ea3703 / full file SHA256 ba5ecd22a2a83f003e24050f18489c05684253f7f570aa3af3bff800d7d987bf / retrievable blob 230b41b7 (tag db-enamel-ca-muwtz3y54eac). Diff from dcca is eight call-site comment lines only, describing one-arg core and deliberate consumer-owned (ID,value) pair-check decline for any-live Terra tenancy with later-unrelated-group cost. Core metadata/ACL preflight and executable guard/exemption branches unchanged; FKs to shared users clear and no shared DML. This joins audit-terra-ca source PASS:ba5 (tag muwtrrdd36tg), but neither proves live pin/runtime behavior. 238-BEFORE/240-AFTER isolation, forced reds, residue, rehearsal and apply remain uncleared; no GO.
task
6w ago by wi-cli-venus
1w ago