A PROD le faltan el UNIQUE y el CHECK de carrocerias que DEV si tiene: es la causa de fondo de los duplicados que 279 y 491 vienen limpiando de a uno
MEDIDO por db02 el 2026-09-18 corriendo el diff de FUNCIONES/TRIGGERS/CONSTRAINTS/INDICES entre DEV y PROD, la mitad que el censo 479 y la convergencia de vistas del mismo dia NO habian comparado. Orden de Elazar en CLI para correrlo. A PROD LE FALTAN LAS DOS PROTECCIONES DE carrocerias QUE DEV SI TIENE. Misma forma que MOVILBA-493 con fabricantes: a PROD no le faltan datos, le faltan los objetos que impiden ensuciarlos. 1. ux_carrocerias_fabricante_modelo - UNIQUE (fabricante_id, upper(btrim(carroceria_modelo, espacios+NBSP))). SIN predicado parcial: cubre todas las filas, marcadas incluidas. 2. carrocerias_modelo_sin_espacios_chk - CHECK (carroceria_modelo = btrim(carroceria_modelo, chr(32)||chr(9)||chr(10)||chr(13)||chr(160))). ESTO EXPLICA LA CADENA, no es un hallazgo suelto: sin el UNIQUE, PROD viene acumulando carrocerias duplicadas por (fabricante, modelo) desde siempre. De ahi salen los 13 textos con hasta 9 filas de MOVILBA-279, la dedup del 2026-06-30 que marco perdedores sin repuntar hijos, y los 45 vehiculos vivos colgando de filas marcadas de MOVILBA-491. El defecto de fondo es la falta del indice; lo demas son sintomas que se vinieron arreglando de a uno. NINGUNA DE LAS DOS SE PUEDE INSTALAR HOY, y cada una por un motivo distinto: - El UNIQUE: 14 grupos / 67 filas lo violarian. CONSULTA SOMBRA, y es la que decide: contando SOLO filas vivas da 0 grupos / 0 filas. O sea las 67 son todas duplicados con alguna marcada; el catalogo VIVO ya cumple la unicidad. Se desbloquea podando fisico las 56 carrocerias marcadas de 74 - que es la pata que MOVILBA-489 dejo afuera y que MOVILBA-492 bloquea por el resolver muerto. Alternativa si 492 tarda: crear el indice con predicado WHERE borrado_en IS NULL, que protege el catalogo vivo YA, pero se aparta de la definicion de DEV y hay que decidirlo, no deslizarlo. - El CHECK: 1 fila de 74 lo viola, y NO esta marcada. id=71, fabricante_id=61, carroceria_modelo='YUTONG ' con espacio al final, con 4 vehiculos VIVOS apuntandole. Arreglarla es un btrim de una celda. NO SE ESCRIBIO: antes de tocarla hay que ver si algo la resuelve por texto exacto (el resolver de carrocerias no trimea el lado catalogo, misma asimetria medida en 493), porque un btrim puede ser justo lo que la hace resolver o dejar de resolver. ORDEN: 492 -> poda de carrocerias (489) -> UNIQUE. El CHECK va aparte y antes, si se decide el btrim de la 71. Denominadores: public.carrocerias 74 filas en PROD, 56 marcadas. Re-medir antes de escribir, nunca leer estos numeros de aca.
Activity
-
0
-
P0 por orden de Elazar (CLI 2026-09-18: 'bwi 501 seems important'). Subido de P1. POR QUE ES LA CAUSA Y NO UN SINTOMA MAS: cuatro items que se venian trabajando por separado son la misma ausencia. MOVILBA-279 (13 textos de carroceria repartidos en hasta 9 filas), la dedup del 2026-06-30 que marco perdedores sin repuntar hijos, MOVILBA-491 (45 vehiculos vivos colgando de filas marcadas, aplicado hoy) y la ambiguedad de resolucion que acaba de aparecer en MOVILBA-492. Sin el UNIQUE, PROD puede seguir creando duplicados por (fabricante, modelo) en cualquier momento, asi que cada uno de esos cuatro es limpieza que se vuelve a ensuciar. MEDIDO HOY EN PROD, re-medir antes de escribir: - ux_carrocerias_fabricante_modelo: UNIQUE (fabricante_id, upper(btrim(carroceria_modelo, espacios+NBSP))), SIN predicado parcial en DEV. En PROD lo violan 14 grupos / 67 filas. CONSULTA SOMBRA, y es la que decide: contando SOLO filas vivas da 0 grupos / 0 filas. El catalogo VIVO ya cumple la unicidad; las 67 violaciones son todas contra filas marcadas. - carrocerias_modelo_sin_espacios_chk: lo viola 1 fila de 74, y NO esta marcada: id=71, fabricante_id=61, modelo 'YUTONG ' con espacio al final, con 4 vehiculos VIVOS apuntandole. LO QUE SE PUEDE HACER YA, y es la decision que esta arriba de Elazar: crear el UNIQUE como PARCIAL, WHERE borrado_en IS NULL. Protege el catalogo vivo HOY (0 violaciones, instala limpio) sin esperar a que 492 arregle el resolver y 489 pode las 56 marcadas. El costo es que se aparta de la definicion de DEV, asi que DEV y PROD quedarian con indices distintos hasta la poda - hay que decidirlo explicitamente, no deslizarlo, y despues converger. URGENCIA CONCRETA: el backfill de 492 esta por apuntar 5514 filas de historial a este catalogo. Instalar el freno ANTES de esa escritura es barato; despues es limpieza otra vez. ORDEN SI SE ESPERA: 492 (resolver) -> poda de carrocerias de 489 -> UNIQUE total. El CHECK va aparte y antes, y pide decidir el btrim de la fila 71 - ojo que el resolver no trimea el lado catalogo (misma asimetria medida en MOVILBA-493), asi que ese btrim puede ser justo lo que la hace resolver o dejar de resolver.
-
CERRADO. 501(b) APLICADO EN LAS DOS BASES el 2026-09-18 (archivo docs/migrations/2026-09-18-movilba-501b-indice-total-clave-canonica-DEV-Y-PROD.sql; ensayo real con ROLLBACK verde en las dos antes del apply). Autorizacion: Elazar CLI literal "501 a now and b as soon as you can". ESTADO POST-APPLY, MEDIDO en las dos bases (no leer estos numeros para decidir manana): - ux_carrocerias_fabricante_modelo, UNIQUE TOTAL, definicion BYTE-IDENTICA en DEV(PG15) y PROD(PG17): (fabricante_id, rutap.clave_carroceria((carroceria_modelo)::text)). El parcial ux_carrocerias_fabricante_modelo_vivas de 501(a) ya no existe. - carrocerias_modelo_sin_espacios_chk presente en las dos; md5 del cuerpo normalizado igual en ambas. PROD lo recibio ahora, DEV ya lo tenia. - 17 filas cada una, 0 grupos duplicados por clave canonica, 0 filas con blancos en los bordes. LO QUE CAMBIO RESPECTO DEL TEXTO DE ARRIBA, y es el aporte del ticket: el indice NO quedo con la expresion btrim de DEV. Quedo llamando a rutap.clave_carroceria, la MISMA funcion que usa el resolver (MOVILBA-492). El defecto real no era que PROD no tuviera el indice de DEV: era que el indice de DEV normalizaba DISTINTO que el resolver (btrim saca blancos de los bordes, clave_carroceria saca TODOS), asi que aceptaba como distintos un par que el resolver manda a la misma fila. Forma de 493: dos copias de la misma idea de normalizar, en dos lugares, que derivan. Ahora hay una sola definicion y todos los llamadores la usan. El CHECK se dejo con btrim A PROPOSITO y no se canonicalizo: quitar TODO blanco prohibiria "TODO BUS", que es un nombre legitimo. El CHECK y el indice miden cosas distintas (texto sucio vs duplicado) y esta bien que normalicen distinto; lo que no puede pasar es que el INDICE y el RESOLVER normalicen distinto. CONTROLES VISTOS ACTUAR, los tres, en las dos bases: el indice RECHAZO un texto con un blanco en el medio que el btrim viejo habria aceptado; ACEPTO un modelo nuevo (no rechaza de mas); el CHECK RECHAZO un texto con espacio al final. HALLAZGOS DE AUDIT INCORPORADOS ANTES DEL APPLY: (1) el DROP barria por patron ux_% y podia borrar un tercer indice en silencio - ahora el PRE exige EXACTAMENTE UNO y que su definicion sea la forma btrim esperada, y se borra por identidad; (2) los 3 centinelas del POST consumian carrocerias_new_id_seq en cada corrida (un INSERT que aborta igual se queda con el nextval) - ahora fabrican id=max+1 y el PRE aborta si id fuera identity GENERATED ALWAYS; VERIFICADO: last_value quedo igual que antes del apply en las dos bases; (3) "el mismo CHECK en las dos bases" era una afirmacion - ahora el POST imprime pg_get_constraintdef y su md5 normalizado, y la comparacion se hizo con las dos salidas a la vista (iguales). Declarado en el header que la comparacion ENTRE bases queda fuera del alcance del archivo, porque cada corrida ve UNA sola base. PENDIENTE, DE CODER03 Y NO DE ESTE TICKET: commitear el archivo y en el MISMO commit corregir el header de 2026-09-18-movilba-501a-unique-carrocerias-vivas-PROD.sql, que tiene dos afirmaciones FALSAS mias sobre la fila id 71: (a) decia que bloqueaba carrocerias_modelo_sin_espacios_chk, cuando ese CHECK no existia en PROD - fue su AUSENCIA la que dejo entrar el espacio, no su presencia la que lo bloqueaba; (b) decia que trimearla era un cambio de RESOLUCION, cuando bajo clave_carroceria "YUTONG " y "YUTONG" son la MISMA clave y el trim fue cosmetico.