Portar a PROD el guard de catalogos sin resolver: vista + funcion + trigger que solo existen en DEV y no tienen migracion trackeada en ninguna rama
DECISION DELEGADA POR ELAZAR (CLI 2026-09-18, verbatim: 'not mine to make, you and other agents analize and decide'). Analizada y decidida por db02 con evidencia; coder03 y audit notificados para objetar con evidencia. QUE FALTA. No es una vista suelta: PROD no tiene NINGUNO de los tres objetos que DEV si tiene. (1) vista rutap.v_snapshot_catalog_preflight, (2) funcion rutap.vh_norm_reject_unresolved_catalogs, (3) el TRIGGER de esa funcion sobre rutap.vehiculo_historial_normalizado (tgenabled='O' en DEV). Medido: to_regclass/to_regproc devuelven NULL en PROD para (1) y (2), pg_trigger devuelve cero filas para (3). QUE HACE EL GUARD. RAISE 23514 sobre toda fila con origen='import' cuyo normalizacion_estado <> 'resuelto'. La vista NO se ejecuta: aparece solo en el texto del HINT, o sea es diagnostico y no dependencia de la funcion. Consecuencia hoy: PROD acepta en silencio una fila de import con catalogo sin resolver, DEV la rechaza. Es la misma forma que MOVILBA-493 - a PROD le faltan las protecciones, no los datos. ENTRA LIMPIO, MEDIDO ANTES DE DECIDIR. rutap.vehiculo_historial_normalizado agrupado por origen+normalizacion_estado: PROD 5514 import/'resuelto', 100%, cero filas en cualquier otro estado. DEV 5514 import + 95 app, todas 'resuelto'. O sea el trigger no rechazaria ni una fila existente en PROD; solo actua sobre importaciones futuras. No hay que limpiar nada antes. DIRECCION. Se porta DEV -> PROD. Sin ambiguedad: el objeto que falta es el que protege, y la base que no lo tiene es justamente la que tiene que igualar al libro. HALLAZGO QUE SALE DE BUSCAR EL ORIGEN, y es el que agrega trabajo: NINGUNO DE LOS DOS OBJETOS TIENE MIGRACION TRACKEADA, EN NINGUNA RAMA. git grep en dev los encuentra solo en docs/reference/movilba-479-dev-prod-schema-census.md (un censo, no una fuente) y en drizzle/schema.ts (introspeccion generada). Viven unicamente en la base de DEV. Entonces el primer paso NO es escribir la migracion de memoria: es capturar el cuerpo instalado con pg_get_viewdef / pg_get_functiondef y pg_get_triggerdef desde DEV y meter ESE texto en la migracion. Ojo con la trampa ya fichada: PG15 y PG17 imprimen el mismo cuerpo distinto, asi que el diff DEV/PROD posterior se normaliza con tools/movilba-479-normalize-viewdef.py y no a ojo. LO QUE NO ARREGLA, dicho para que no se lea como que si: el guard mira normalizacion_estado, no el resultado de cada resolver individual. El resolver muerto de carroceria (MOVILBA-492) proyecta NULL en 5514 de 5514 filas y esas filas estan marcadas 'resuelto' igual. Portar este guard NO cierra 492 ni lo detecta. PENDIENTE: coder03 escribe la migracion (tres objetos, mismo archivo DEV+PROD, idempotente: verifica si esta, crea si falta - como 493). db02 la ensaya en las dos bases y la aplica. Es DDL de PROD pero la decision de fondo ya la delego Elazar; el archivo lleva control negativo forzado, o sea hay que VER al trigger rechazar una fila no resuelta antes de aceptarlo.
Activity
-
Ensayo de b7e1a222 por db02: DEV pasa entero, PROD ABORTA. Tres hallazgos medidos. (1) LA VISTA SI SE PUEDE CREAR EN PROD - el 'solo-en-DEV' del censo 479 es falso. to_regclass('rutap.unidad_propulsora_resolver') y ('rutap.chasis_resolver') devuelven el nombre en PROD, y to_regproc('rutap.normalizar_clave_chasis') tambien. No se dedujo: se CREO la vista en PROD con el cuerpo capturado bajo BEGIN/ROLLBACK, CREATE VIEW sin error, y select count(*) sobre ella devuelve 0 filas (coherente con 5514/5514 resuelto). ORIGEN DEL ERROR: esas dos tablas son exactamente las que el censo de catalogos de db03 no pudo leer en PROD POR PERMISO DENEGADO con el rol de aplicacion, y quedaron anotadas como ausentes. Un read sin privilegio se lee igual que una ausencia; esta vez la confusion viajo dentro de un censo hasta convertirse en una decision de scope (sacar la vista del port). No hace falta item aparte para la vista: entra con los otros dos objetos. (2) PROD NO TIENE EL ROL movilba_user. El archivo aborta en la linea 153 con 'role "movilba_user" does not exist'. Defecto solo-en-ejecucion: leerlo no lo muestra porque el nombre es correcto en DEV. Medido: pg_roles en PROD no lo tiene, y las 14 relaciones y las 9 funciones del esquema rutap son TODAS de 'elazar'. (3) EL OWNER NO SE ESCRIBE, SE DERIVA. Un literal movilba_user ata el archivo a DEV igual que un id literal ataba la purga de ELECTRICO-CABA a una base. Regla que sobrevive a los dos entornos: el objeto nuevo toma el owner que ya tienen los objetos de rutap EN ESA MISMA BASE, resuelto por consulta, y se ABORTA si en esa base hay mas de un owner, porque entonces no hay respuesta unica y hace falta una decision escrita. Las aserciones de provolatile/prosecdef/proconfig IS NULL se quedan: esas son propiedades del objeto, no del entorno. DEV, para que conste que la pata 'verifica' no es una linea verde: sin_cambio x2, trigger identico a la captura y habilitado, owner/volatilidad/security/proconfig iguales, fixture revertido por subtransaccion y la fila re-leida en su estado original, 0 filas import sin resolver. Sin objecion al resto del diseno de coder03. Pendiente: coder03 corrige, db02 vuelve a ensayar.
-
APLICADO EN PROD, los TRES objetos, 2026-09-18 (db02). Orden de Elazar en CLI: 'i need this done now'. QUE SE CORRIGIO ANTES DE APLICAR. (a) El bloqueante 'la vista no se puede crear en PROD' era FALSO: las tres dependencias existen (to_regclass/to_regproc devuelven nombre) y la vista se creo en PROD con el cuerpo capturado bajo BEGIN/ROLLBACK antes de decidir nada. El censo 479 las daba DEV-only a partir de una lectura que el rol de aplicacion NO TENIA PERMISO de hacer. (b) El archivo abortaba con 'role movilba_user does not exist': se reemplazo el literal por una DERIVACION - el owner sale de los objetos que ya viven en el esquema rutap EN ESA MISMA BASE, y aborta si hay mas de uno. Resuelve movilba_user en DEV y elazar en PROD, sin fork. (c) Elazar rechazo crear el rol movilba_user en PROD solo para satisfacer el literal: seria un rol vacio inventado por un archivo. APLICADO: funcion rutap.vh_norm_reject_unresolved_catalogs (owner elazar), su trigger sobre rutap.vehiculo_historial_normalizado (BEFORE INSERT OR UPDATE OF origen, normalizacion_estado, conflictos; tgenabled='O', definicion comparada como TEXTO contra pg_get_triggerdef de DEV), y la vista rutap.v_snapshot_catalog_preflight (relkind='v', owner elazar, se LEE y devuelve 0 filas sin resolver). Denominador 5514 filas, 0 que el guard rechazaria antes y despues. El control de dos mitades corrio en PROD: el guard acepta con 'resuelto' y rechaza sin el, exigiendo su propio texto de error y no un 23514 pelado, revertido por subtransaccion con la fila re-leida en su estado original. Verificacion post-commit por consulta independiente al catalogo, no leyendo el reporte del archivo. Archivos (db02 los escribio/corrigio, coder03 los commitea): docs/migrations/2026-09-18-movilba-494-guard-catalogos-sin-resolver-DEV-Y-PROD.sql (corregido sobre b7e1a222) y docs/migrations/2026-09-18-movilba-494b-vista-preflight-DEV-Y-PROD.sql (nuevo). NO CIERRA MOVILBA-492: el guard mira normalizacion_estado, no el resultado de cada resolver. El resolver de carroceria proyecta NULL en 5514 de 5514 y esas filas estan marcadas 'resuelto' igual. DERIVADO: MOVILBA-497 (el owner 'elazar' es un rol personal con 122 objetos en PROD).
-
Guard de catalogos sin resolver APLICADO en PROD: rutap.vh_norm_reject_unresolved_catalogs, su trigger y rutap.v_snapshot_catalog_preflight. PROD ya no acepta en silencio una fila de import con un catalogo sin resolver. Owner derivado del esquema, no literal. NO cierra MOVILBA-492. Cerrado por coder03, que lo reporto aplicado en chat.
-
APLICADO en PROD 2026-09-18, los tres objetos. Verificado ahora contra el catalogo de PROD: vista rutap.v_snapshot_catalog_preflight presente, funcion rutap.vh_norm_reject_unresolved_catalogs presente, y 1 trigger de esa funcion sobre rutap.vehiculo_historial_normalizado. Cuerpos capturados con pg_get_viewdef/functiondef/triggerdef desde DEV, no escritos de memoria (no tenian migracion trackeada en ninguna rama). Dos defectos solo-en-ejecucion que ninguna lectura mostraba: el archivo hacia OWNER TO movilba_user, rol que NO EXISTE en PROD - se reemplazo por derivar el owner de los objetos que ya viven en el esquema y ABORTAR si hay mas de uno; y el 'la vista no existe en PROD' que justificaba dejarla afuera resulto ser una lectura sin permiso anotada como ausencia en el censo 479, desmentida CREANDO la vista en PROD bajo ROLLBACK.