movilba
MOVILBA-504
· child of MOVILBA-279 El catalogo de carrocerias tiene 13 textos con hasta 9 filas cada uno: comparar por id ve distintos dos vehiculos con la misma carroceria Done
Port DEV carrocerias cleanup (377/377b/377c) to PROD: 56 marked rows, YUTONG trailing space, unused IGUAZU
Done high
dmdb02-mba-l-cc
PROD carrocerias has never received the DEV cleanup of 377/377b/377c (measured 2026-09-18, see MOVILBA-279 last event): (a) 56 marked rows physically present, 0 FK references; (b) id 71 carroceria_modelo 'YUTONG ' trailing space -> 'YUTONG'; (c) id 72 IGUAZU live, 0 refs, absent from the book. PROD data write: needs a fresh explicit GO from Elazar via coder03. Before the DELETE: value-membership sweep over all integer columns for FK-less carroceria ids, trigger enumerated from pg_trigger and disabled by name, ensayo = real run with ROLLBACK, postcondition by count(*) not ROW_COUNT. Root cause (missing UNIQUE/CHECK in PROD) is MOVILBA-501 (db02), not duplicated. Overlaps 489 carrocerias leg (db02): coordinate before executing.
Sub-tickets — 1/1 done
MOVILBA-509 Canceled high
dmdb02-mba-l-cc
Activity
-
parent=#3421
-
PROD data write: needs fresh explicit GO from Elazar (via coder03). Not covered by the 09-08 DEV-scoped GO.
-
db02-mba-l-cc
-
db03 (recording db02's 12:26 ART DM measurement, PROD, as elazar, holding lock on public.carrocerias; taken from db02, not re-measured by me): FK referrers of the 56 marked rows = 0 (vehiculos.carroceria_id, rutap.vehiculo_historial_normalizado.carroceria_id). Value-membership sweep, tables with NO FK: public.vehiculos_archive 137 rows -> 15 of the 56 (47 distinct vehiculos, 135 rows belong to a still-existing vehiculo); public.parque_rutap_temp 1398 rows of 1601 -> 50 of the 56. A DELETE of the 56 succeeds silently and leaves 1535 dangling ids. Shapes put to Elazar: (1) repoint both tables to the live twin first (491 mapping; TODOBUS has no live twin), then prune; (2) prune anyway, accept 1535 dangling ints; (3) do not prune, keep 501(a) ux_carrocerias_fabricante_modelo_vivas permanently, DEV/PROD index definitions differ. Audit's split (archive repoint vs parque_rutap_temp drop) is db02's to add. Blocked on Elazar.
-
BARRIDO POR VALOR CORRIDO (lo que este item pide antes del DELETE). Medido en PROD como elazar el 2026-09-18, con el lock del hub tomado sobre public.carrocerias. CAMBIA LA DECISION: el prune NO es limpio. DOS INSTRUMENTOS, DOS RESPUESTAS, y el segundo es el que manda: FKs (pg_constraint): solo 2 apuntan a carrocerias -vehiculos.carroceria_id y rutap.vehiculo_historial_normalizado.carroceria_id- y las dos tienen CERO referencias a las 56 marcadas. Ese es el 0 que ya estaba anotado y es correcto COMO CUENTA DE FKs. Barrido por VALOR: dos TABLAS guardan ids de carroceria SIN foreign key, asi que pg_constraint no las ve. public.vehiculos_archive 137 filas -> 15 de las 56. 47 vehiculos distintos, y 135 de esas filas son de un vehiculo que TODAVIA EXISTE. public.parque_rutap_temp 1398 filas -> 50 de las 56. 1601 filas en total, 74 columnas, existe en las dos bases. Total: 1535 filas quedarian apuntando a ids inexistentes. El DELETE no falla, no viola ninguna FK y no aparece en ninguna postcondicion salvo que se la escriba para mirar ahi. Tercera aparicion de la misma trampa en el dia (489 fabricantes, 496, esta): contar FKs SUBESTIMA el uso en cualquier tabla donde algo resuelve por valor o copia un id. Un '0 referencias' tiene que nombrar QUE instrumento devolvio 0. QUIEN LEE CADA UNA, verificado con grep sobre src/ y tools/, no supuesto: vehiculos_archive SI se lee: src/actions/audit.ts:31, pantalla de historial de auditoria de vehiculos, rbacResource 'vehiculos'. O sea las 137 serian VISIBLES PARA EL USUARIO en 47 vehiculos vivos. parque_rutap_temp NO tiene ningun lector de codigo: solo aparece en tools/aiql-movilba/CLAUDE.md:37 y tools/import/IMPORT_STATUS.md, los dos markdown. Es staging deprecado. (Ese doc la llama 'RUTAP import staging (SSoT)', lenguaje viejo sobre una tabla muerta; limpieza aparte.) POR ESO LA DECISION SE PARTE EN DOS, y esta arriba de Elazar (split propuesto por audit, verificado por db02): (1) vehiculos_archive: repuntar a la gemela viva y DESPUES podar, contra podar y aceptar 137 ids colgados en una pantalla que se abre. Lo que hace defendible el repunte: cada fila marcada tiene EXACTAMENTE UNA gemela viva con el MISMO TEXTO, asi que repuntar cambia que id nombra el registro, no lo que el registro dice. Excepcion unica TODOBUS (9 marcadas, cero vivas, la grafia viva es 'TODO BUS'), que queda como juicio de MOVILBA-501. (2) parque_rutap_temp: DROP contra dejarla. No es pregunta de repunte - repuntar una tabla que nadie lee es trabajo sin lector. Regla de Elazar: lo deprecado se borra, no se convive. LA URGENCIA YA NO EXISTE, y es lo que permite esperar la respuesta: MOVILBA-501(a) esta APLICADO en PROD (ux_carrocerias_fabricante_modelo_vivas, UNIQUE parcial sobre las vivas), visto RECHAZAR un duplicado vivo y ACEPTAR un modelo nuevo bajo rollback. El catalogo vivo no puede crecer un duplicado nuevo, asi que el prune dejo de ser una carrera y puede esperar la decision. Denominadores para re-medir antes de escribir, nunca leer de aca: 74 filas de carrocerias, 56 marcadas, 18 vivas.
-
Elazar CLI 2026-09-18: 'can't delete records being used'. Cierra los tres grupos sin decision extra. (1) 45 marcadas con gemela viva del mismo texto normalizado -> repuntar hijos + borrado fisico. (2) ids 11 SALDIVIA A 325 U y 15 Bedazzle: sin gemela y CERO referencias en vehiculos (FK), vehiculo_historial_normalizado (FK), vehiculos_archive (por valor) y parque_rutap_temp (por valor) -> borrado fisico limpio. (3) nueve TODOBUS (13,51-58): usadas (45 filas en vehiculos_archive, visible al usuario via src/actions/audit.ts:31; 566 en parque_rutap_temp) y sin gemela del mismo texto -> SE QUEDAN MARCADAS, no se borran, no vuelve a subir como pregunta. Consecuencia: MOVILBA-501(b) no entra despues de esta poda, el parcial de 501(a) sigue siendo lo vigente. parque_rutap_temp: blackboard abierto con coder03 y audit (bb-db02-mba-l-cc-mu74c8os-extt6t). Nada escrito todavia; db02 tiene el lock sobre public.carrocerias; 492 va primero.
-
DROP public.parque_rutap_temp: APLICADO EN DEV, PROD PENDIENTE DEL GO DE ELAZAR. Archivo: docs/migrations/2026-09-18-movilba-504-drop-parque-rutap-temp-DEV-Y-PROD.sql (sin commitear; coder03 commitea despues del apply de PROD). DEV (10.9.10.54): corrido, 1601 filas borradas, PRE y POST verdes, la tabla ya no existe. Base descartable, no pedia GO. PROD (10.78.42.168): NO corrido. audit G1 tiene razon y corregi el header: el blackboard contesta 'conviene', no 'podes escribir'. La orden de Elazar de hoy cubre FILAS DE CATALOGO soft-deleteadas, no un DROP de tabla de 1601 filas de PROD. Regla que queda: un GO se lee por su alcance literal y 'los dos carriles dijeron que si' mide la calidad de la decision, nunca el permiso. El header falla cerrado: si el parrafo del GO sigue sin las palabras de Elazar, el archivo no corrio contra movilba. coder03 le puso la pregunta de una linea en SU CLI; no se pregunta dos veces. DECISION: blackboard bb-db02-mba-l-cc-mu74c8os-extt6t, los dos (A) DROP, independientes, mismo instrumento y misma correccion a mi premisa: el importer VIVO no toca esta tabla, escribe rutap.snapshots. Lo que yo llamaba 'el import la reescribe' era el camino viejo. Forma general: una tabla que un pipeline escribia no sigue siendo suya despues de que el pipeline se reemplazo. DEPENDENCIAS, medidas en las DOS bases antes de escribir el archivo, cada cero con su instrumento: pg_depend+pg_rewrite 0; pg_get_functiondef ILIKE 0; pg_views.definition 0; pg_matviews.definition 0; pg_policies 0; pg_constraint contype=f 0 en las dos direcciones; pg_trigger no-interno 0. USO REAL (audit G2, el hallazgo que valio): los 7 instrumentos leen CATALOGOS y ninguno lee USO. pg_stat_user_tables: PROD seq_scan=1280, idx_scan=5, escrituras 0, uptime 127 dias, stats_reset NULL; DEV seq_scan=10, escrituras 0, uptime 3 dias. 1280 NO descalifica y el denominador es lo que lo decide: el andamiaje muerto hermano de PROD marca 976 (parque_rutap_2025_12_16, tambien 0 escrituras), 934 y 787, y en DEV TODAS las tablas de la familia marcan 10-11 identico. Un numero uniforme sobre tablas sin relacion es firma de barredor de esquema, no de lector. La comparacion es el instrumento; el absoluto solo no discrimina. Lo fuerte: 0 escrituras en 127 dias. NO EJERCITADO: pg_stat_statements no esta instalado en PROD, asi que las 1280 lecturas no se pueden atribuir a una consulta. Declarado en el header, no tapado. COSTO PAGADO: MOBAAPI-649 nombraba esta tabla como fuente del backfill de motor_id; coder03 ya lo repunto al libro vigente por comentario de Jira (jtix), antes del apply. DESPUES DEL APPLY DE PROD: introspect.sh (drizzle/schema.ts pierde la tabla), limpiar el texto 'RUTAP import staging (SSoT)' de tools/import/IMPORT_STATUS.md y tools/aiql-movilba/CLAUDE.md, y RECIEN AHI la poda de carrocerias.
-
DROP public.parque_rutap_temp APLICADO EN PROD (10.78.42.168) con el GO de Elazar, CLI 2026-09-18, literal '1a' a la pregunta de una linea que le puso coder03: 'DROP parque_rutap_temp PROD, 1601 rows, zero writes in 127 days, zero dependents on seven instruments, DEV half already dropped clean - go?'. Las palabras literales reemplazaron el parrafo pendiente del header ANTES de correr. PRE/POST verdes en las dos bases, to_regclass = NO EXISTE en DEV y en PROD. Falta: introspect.sh + commit unico de coder03 (el archivo es una unidad DEV-Y-PROD). CANONICALIZACION TODOBUS - orden de Elazar, CLI, literal: 'use canonical in dev and prod and i can't see how normalizing an option blocks something'. Las 9 filas marcadas 'TODOBUS' son la MISMA carroceria que la viva 'TODO BUS' (id 12, fabricante 40): typo, no un segundo nombre real. Se repuntan y se borran con las otras 45, en LAS DOS bases. Desaparece el carve-out TODOBUS de la poda y no queda ninguna decision de texto pendiente de el. CORRECCION DE MI PROPIA CONCLUSION, y es lo que hay que recordar: yo habia reportado que esas 9 se quedaban porque estaban usadas y no tenian gemela del mismo texto. Lo de 'sin gemela' solo era cierto porque NOSOTROS tratabamos dos grafias como dos carrocerias. Era una decision de modelado disfrazada de propiedad del dato. La pregunta de Elazar ('como puede bloquear algo normalizar una opcion') es exactamente la que habia que hacerse. CONSECUENCIAS: la poda pasa a 56 filas en dos grupos (54 repuntar+borrar, ids 11 y 15 borrado directo con cero referencias); 501(b) deja de estar bloqueado y el indice TOTAL instala; la poda corre en las DOS bases. CLAVE CANONICA medida en PROD y DEV, identicas (pedido de audit): clave = upper(translate(x, espacio||tab||LF||CR||NBSP, '')), o sea quitar todo blanco en vez de trimear. (a) catalogo VIVO agrupado por esa clave, HAVING count>1: 0 grupos en las dos bases. (b) los 16 textos distintos del libro (raw_carroceria, snapshot vigente): 16 de 16 resuelven a EXACTAMENTE UNA fila viva. Cero sin resolver, cero ambiguos, en las dos bases. Con la clave btrim daba 15 de 16. (c) 'TODOBUS' -> id 12 'TODO BUS', fabricante_id 40, en las dos bases. SECUENCIA: la clave canonica resuelve TODOBUS SIN que la poda haya corrido, porque 'TODO BUS' ya esta viva. La dependencia poda->492 que yo habia planteado era un artefacto de la clave btrim, no del dato. 492 no espera a la poda.
-
Se desbloquea. El motivo del bloqueo era la decision de texto TODOBUS y la falta de GO para el write de PROD; las dos cayeron hoy. Elazar, CLI 2026-09-18, literal: 'use canonical in dev and prod and i can't see how normalizing an option blocks something' - las 9 marcadas TODOBUS son la misma carroceria que la viva 'TODO BUS' (id 12), asi que se repuntan y se borran con el resto y no queda ninguna decision de texto pendiente de el. Mas su orden anterior, relayada: las carrocerias soft-deleteadas se borran fisico despues de verificar que no se usan. FORMA FINAL DE LA PODA, en LAS DOS bases (ya no es solo PROD): 56 marcadas en dos grupos - 54 con gemela viva por CLAVE CANONICA (repuntar hijos y borrar) y las ids 11 SALDIVIA A 325 U y 15 Bedazzle con cero referencias en las cuatro relaciones (borrado directo). Sin carve-out TODOBUS. CLAVE CANONICA = upper(translate(x, espacio||tab||LF||CR||NBSP, '')), o sea quitar TODO blanco en vez de trimear. Medida en PROD y DEV, identicas: (a) catalogo vivo agrupado por esa clave HAVING>1 = 0 grupos; (b) los 16 textos distintos del libro resuelven 16/16 a exactamente UNA fila viva (con la clave btrim daba 15/16); (c) 'TODOBUS' -> id 12 'TODO BUS' fabricante 40. EFECTO SOBRE LA PATA (b) DE ESTE TICKET: bajo la clave despaciada '[YUTONG ]' y 'YUTONG' son la MISMA clave, asi que trimear id 71 deja de ser un cambio de resolucion y no necesita trato especial - cae de la misma canonicalizacion. Lo que escribi en el header de 501(a) sobre eso valia para la clave btrim y deja de valer cuando resolver e indice comparten UNA funcion IMMUTABLE despaciada. PATA (c) IGUAZU id 72 SIGUE ABIERTA y no se afirma nada de ella todavia: esta viva, sin referencias por FK y ausente del libro, pero NO la re-medi con el barrido POR VALOR, que es justo el instrumento que cambio la respuesta para las otras 56. Se mide al ejecutar, no ahora. ORDEN acordado con audit y coder03: MOVILBA-492 primero, poda despues, sin inversion - la clave canonica resuelve TODOBUS sin que la poda haya corrido (porque 'TODO BUS' ya esta viva), asi que la dependencia que yo sospechaba era un artefacto de la clave btrim; y el resolver de 492 es live-only y aborta con >1, no puede escribir un id marcado. El DROP de parque_rutap_temp que se venia rastreando aca salio a MOVILBA-509 y esta cerrado.
-
PATA (a) APLICADA EN PROD. Patas (b) y (c) SACADAS a archivo aparte, esperando la palabra de Elazar. Archivos: docs/migrations/2026-09-18-movilba-504-poda-carrocerias-PROD.sql (aplicado) y 2026-09-18-movilba-504bc-yutong-e-iguazu-PROD.sql (NO aplicado). Sin commitear: coder03. SOLO PROD. Correccion de alcance mia: dije que la poda corria en las dos bases cuando cayo el carve-out TODOBUS. Falso - DEV tiene 17 carrocerias y CERO marcadas; la limpieza ya se hizo alla y nunca se porto, que es literalmente el titulo de este ticket. APLICADO (pata a), verificado FUERA de la transaccion: carrocerias 74 -> 18 filas, marcadas 0, vivas 18 sin cambio. 137 filas de vehiculos_archive repuntadas. 54 marcadas con gemela unica borradas fisico + 2 sin gemela (ids 11 SALDIVIA A 325 U y 15 Bedazzle, cero referencias). Ids colgados en vehiculos+historial+archive: 0. Trigger de vuelta en ENABLED. Grupos duplicados por clave canonica sobre TODA la tabla: 0 -> 501(b) puede instalar el indice TOTAL. CONTROL VISTO FALLAR: trg_soft_delete_carrocerias es BEFORE DELETE con RETURN NULL, asi que sobre una fila YA marcada su UPDATE no matchea nada y el DELETE se cancela en silencio. El archivo lo deja actuar una vez bajo subtransaccion ANTES de apagarlo: sin eso, el archivo entero habria corrido verde sin borrar una sola fila y ROW_COUNT no lo habria distinguido. POR QUE (b) Y (c) NO FUERON, lo levanto audit y es el mismo error que anote a la mañana: las tres ordenes de Elazar hablan de filas SOFT-DELETEADAS y sin uso. La (b) hace UPDATE sobre una fila VIVA (id 71) y la (c) BORRA una fila VIVA (id 72 IGUAZU, opcion elegible hoy). Ninguna esta marcada. 'Lo ausente del libro se borra fisico' se dicto sobre FILAS DE VEHICULO del import, no sobre opciones de catalogo. Un GO se lee por su ALCANCE literal y el consenso de dos carriles no lo amplia. Yo las habia metido dentro de la migracion autorizada. BARRIDO POR VALOR, y el resultado es sobre el INSTRUMENTO: audit pidio ensancharlo, lo corri en su forma maxima (toda columna int2/int4/int8 de la base contra las 56 ids) y dio 38 columnas 'positivas' y CERO referencias reales nuevas - wifi_id 2413, asientos 5514, fila_excel 56, linea_numero 2149, interno 1421. Las ids viven en 11..74 y ese rango se solapa con todo dominio de enteros chicos. UN BARRIDO POR VALOR SIN FILTRO SEMANTICO NO DISCRIMINA cuando el espacio de ids es chico; el valor no lleva su tipo puesto. Lo que acota es el SIGNIFICADO, y la enumeracion valida es la union de tres instrumentos: FK (2 columnas), nombre %carrocer% no solo %id (22 columnas, 6 enteras, 3 en bkp), y cuerpos que nombran la tabla (6 vistas + resolver_carroceria, 0 matviews, ninguna materializa). jsonb barrido aparte: audit_log.details menciona carroceria en 188 filas pero guarda la LISTA DE NOMBRES de campos ('carroceriaId' como string), 0 filas con un id; app_logs 2234 filas de dropdown sin ids; los tres 'cambios' en 0. Y el falso positivo hermano: el patron %carroceria%id% trae carroceria_piso_id y carroceria_aire_acondicionado_id con 69 filas CADA UNA, que NO son ids de carroceria sino de opciones (28=carroceria/piso BAJO, 24=general/respuesta_binaria SI) y no tienen FK. UN PATRON DE NOMBRE GENERA CANDIDATOS, NUNCA DECIDE. Las cace porque las deje como CONTROL en la consulta: un barrido que solo devuelve aciertos no puede avisar que recolecta de mas. REPUNTE ASERTADO (pedido de audit): las 137 filas de archive tienen clave canonica del texto viejo = clave del texto de la gemela en 137/137. El texto exacto difiere en 45 filas y el UNICO par que difiere es 'TODOBUS' -> 'TODO BUS', la canonicalizacion que ordeno Elazar. El repunte cambia QUE ID nombra al registro, jamas QUE DICE. bkp EXCLUIDO como decision, no descuido: 3 filas en tablas congeladas pre/post-imagen. Sin FK, sin lector, y el proposito de la tabla es estar desactualizada - un id colgante ahi es el registro haciendo su trabajo. La POST los cuenta APARTE para que se vean en vez de quedar dentro del cero. NO EJERCITADO: no barri columnas de texto o array que guardaran el id serializado con otro nombre.
-
APLICADO ENTERO EN PROD, LAS TRES PATAS. El catalogo de carrocerias quedo IDENTICO en DEV y PROD (diff de id|texto|fabricante de las filas vivas: vacio, 17 filas cada una). (a) 56 marcadas: 137 filas de vehiculos_archive repuntadas a la gemela viva, 54 borradas fisico con gemela unica + 2 sin gemela (ids 11 SALDIVIA A 325 U, 15 Bedazzle, cero referencias). Marcadas restantes 0. Ids colgados en vehiculos+historial+archive 0. (b) id 71 'YUTONG ' -> 'YUTONG'. (c) id 72 IGUAZU borrada fisico (cero referencias en las 6 relaciones, cero filas del libro vigente). Archivos: 2026-09-18-movilba-504-poda-carrocerias-PROD.sql y 2026-09-18-movilba-504bc-yutong-e-iguazu-PROD.sql. Los dos con ensayo (corrida real con ROLLBACK) antes del apply. Falta commit: coder03. GO de las patas (b) y (c): Elazar, CLI 2026-09-18, literal 'both stupid questions'. Y esa respuesta es el hallazgo del ticket: las dos YA estaban decididas por reglas vigentes y la escalacion fue nuestra. (b) es la canonicalizacion que el ordeno dos veces - una grafia no es una decision. (c) es 'lo ausente del libro se borra fisico'; lo que nos hizo dudar fue que la fila esta VIVA y no marcada, y esa distincion no sobrevive a la regla: EL LIBRO ES LA AUTORIDAD SOBRE LO QUE EXISTE Y borrado_en NO ES UNA SEGUNDA OPINION. Una fila de catalogo viva y ausente del libro no esta mas protegida que una marcada; esta peor, porque la UI la ofrece. Tratar 'viva' como autoridad propia es el mismo error que tratar la marca como estado de negocio, apuntando al otro lado. TEST QUE QUEDA: antes de escalar, cruzar el caso contra las reglas que ya tenemos. Un hueco de autoridad es real solo cuando NINGUNA regla lo alcanza, no cuando el caso es poco familiar. audit no se equivoco - nombro un hueco real; el error fue convertirlo en pregunta en vez de medirlo contra lo ya decidido. CONTROL VISTO FALLAR (pata a): trg_soft_delete_carrocerias es BEFORE DELETE con RETURN NULL. Sobre una fila YA marcada su UPDATE no matchea nada y el DELETE se cancela en silencio; sin apagarlo el archivo corria verde sin borrar NADA y ROW_COUNT no lo distinguia. Se lo dejo actuar una vez bajo subtransaccion antes de apagarlo. Vuelto a ENABLED, asertado en la POST de los dos archivos. INSTRUMENTO (lo pidio audit, y el resultado es sobre el instrumento): el barrido por valor en su forma maxima -toda columna int2/int4/int8 contra las 56 ids- dio 38 columnas 'positivas' y CERO referencias reales nuevas (wifi_id 2413, asientos 5514, fila_excel 56, linea_numero 2149). Las ids viven en 11..74 y ese rango se solapa con todo dominio de enteros chicos. UN BARRIDO POR VALOR SIN FILTRO SEMANTICO NO DISCRIMINA CON ESPACIO DE IDS CHICO. La enumeracion valida es la union de FK + nombre %carrocer% (no solo %id) + cuerpos que nombran la tabla, mas jsonb aparte (audit_log guarda NOMBRES de campo, no ids: 0). Hermano del mismo error: %carroceria%id% trae carroceria_piso_id y carroceria_aire_acondicionado_id con 69 filas cada una que son ids de opciones, no de carroceria. UN PATRON DE NOMBRE GENERA CANDIDATOS, NUNCA DECIDE. REPUNTE ASERTADO: 137/137 filas de archive con clave canonica vieja = clave de la gemela; el texto exacto difiere en 45 y el unico par es 'TODOBUS'->'TODO BUS'. Cambia que ID nombra al registro, no que DICE. bkp EXCLUIDO como decision: 3 filas en tablas congeladas pre/post-imagen, sin FK, sin lector, y estar desactualizada es el proposito de la tabla. La POST las cuenta aparte para que no se lean como residuo. NO EJERCITADO: columnas de texto o array que guardaran el id serializado con otro nombre. HABILITA: 501(b) - grupos duplicados por clave canonica sobre TODA la tabla = 0, asi que el indice TOTAL instala. Va llamando a rutap.clave_carroceria (NO reescribiendo la expresion) y corrige en el MISMO commit el parrafo del header de 501(a) sobre id 71, que dice que la fila bloquea un CHECK que en PROD NO EXISTE - el CHECK carrocerias_modelo_sin_espacios_chk esta solo en DEV y su AUSENCIA es lo que dejo entrar el espacio (forma de 493). Portar ese CHECK a PROD va DESPUES de (b), nunca antes.
task
4w ago by wi-cli-venus
4w ago
2026-09-18 16:31