El rebuild por import no tiene la mitad que CARGA: no existe un loader de libro completo para vehiculos, vehiculos_datos_colectivos y vehiculo_historial
BLOQUEA MOVILBA-155. Lo levanto db03-mba-l-ca en el preflight y lo verifique yo contra el arbol de dev; la afirmacion se sostiene. La directiva de Elazar del 2026-09-03 (truncar y reconstruir en cada import) tiene dos mitades. La de BORRAR quedo diseñada, probada en DEV con ROLLBACK y con gates: MOVILBA-226. LA DE CARGAR NO EXISTE. Correr la transaccion hoy deja el nucleo de DEV VACIO. QUE HAY, verificado: - tools/rutap-sync-prod.sql: solo actualiza estado/vigencia/expediente/interno y DELIBERADAMENTE reporta los vehiculos faltantes en vez de insertarlos. No carga atributos tecnicos. No sirve como loader y no fue escrito para eso. - docs/migrations/2026-08-14-movilba-{18,19,24}-*.sql y 2026-08-21-rutap-0624-faltantes-import-DEV.sql: INSERTs puntuales de lotes chicos, no un loader. - docs/migrations/2026-08-28-movilba59-rutap-snapshot7-operational-dev.sql: inserta 'las cuatro proyecciones canonicas de vehiculo' y actualiza ocho de VDC. Es una proyeccion operativa puntual de un snapshot, no una carga completa. EL PUNTO DE PARTIDA EXISTE Y NO HAY QUE EMPEZAR DE CERO: docs/migrations/2026-08-20-movilba-94-importer-template-corrected.sql se declara a si mismo 'el patron a usar en la PROXIMA importacion completa' - staging raw de una columna de texto por columna del libro, CTE _tramites, INSERT masivo. Nunca corrio y no tiene GO. Y ya trae resueltos DOS defectos que costaron caro: proyecta fecha_baja, expte_baja y tramite_id resuelto por JOIN contra opciones (nunca el texto crudo del tramite). Su ausencia en la corrida del 08-13 dejo 3963 filas con esas tres columnas vacias. EMPEZAR DE AHI, no de cero: reescribirlo desde el libro es re-pisar esos dos defectos. PERO CUBRE UNA SOLA TABLA. El template es de vehiculo_historial. El rebuild necesita tambien vehiculos y vehiculos_datos_colectivos, y para esas no hay ni template. REQUISITOS DEL LOADER: 1. Carga el libro ENTERO, periodos cerrados incluidos. Si lee solo filas abiertas, 798 dominios pierden su historia y las bajas desaparecen - y baja es un ESTADO, no un borrado. 2. Escribe las tres tablas centrales en una sola transaccion con el truncate de 226. 3. Respeta la regla T8: el 0 del libro se guarda como 0 en las cinco columnas, NULL solo para la celda VACIA (MOVILBA-191). 4. Nada de texto crudo donde hay catalogo: todo enumerado se resuelve a id de opciones. 5. Idempotente por construccion - despues del truncate no hay nada que mergear, que es justamente lo que abarata este loader respecto de todo lo anterior. 6. Lo que hoy 'se ajusta por corrida' en el template (nombre de la raw table, creado_por, _skip_vigente, fecha de cuarentena) tiene que dejar de ser manual o el rebuild-por-import no es repetible, que es el objetivo entero. RELACION CON 59: MOVILBA-59 ya dice que el pipeline de import no es reproducible - 3 conversores con semanticas incompatibles y handoffs manuales. Este item es la parte de 59 que el rebuild vuelve BLOQUEANTE en vez de deuda tecnica. NO EJERCITADO: no probe que el template de 94 corra; esta declarado como nunca ejecutado.
Activity
-
MEDICIONES DE db02 QUE CAMBIAN EL ALCANCE DE ESTE ITEM (2026-09-03, SELECT en PROD y DEV). Tres, y la segunda es una trampa dev/prod apuntada directo a este loader. === 1. PROD YA TIENE EL LIBRO VIGENTE CARGADO EN STAGING === PROD rutap.snapshots: 1 fila, id=9, archivo 2026-09-03-1049-parque-rutap.xlsx, filas=5368. PROD rutap.rutap_rows: 5368 filas. O sea 'PROD esta dos libros atras' es cierto de la PROYECCION a public, NO del staging. El libro del 09-03 ya esta adentro de PROD. Lo que falta es el paso rutap -> public, que es exactamente este item y nada mas. No hay que volver a importar el .xlsx a PROD. Las 5368 coinciden exacto con mi conteo independiente de filas del libro con Nro_dominio no vacio. === 2. EL ESQUEMA rutap DE PROD ES MAS FLACO QUE EL DE DEV. UN LOADER PROBADO EN DEV PUEDE FALLAR EN PROD. === DEV rutap: rutap_rows 5368, snapshots 1, vehiculo_historial_normalizado 5368, m95_cambios_backfill_dev 3787, chasis_resolver 9, unidad_propulsora_resolver 4 PROD rutap: rutap_rows 5368, snapshots 1. Y NADA MAS. PROD no tiene vehiculo_historial_normalizado, no tiene chasis_resolver y no tiene unidad_propulsora_resolver. Un loader que lea cualquiera de esas tres corre verde en DEV y revienta en PROD, o peor, no las encuentra y resuelve distinto. EL LOADER TIENE QUE LEER DE rutap.rutap_rows, que es lo unico que existe en los dos, o los resolvers tienen que crearse en PROD como parte de este item y quedar declarados como dependencia. === 3. SECUENCIA: la fuente de la recarga esta DENTRO del cierre del TRUNCATE === rutap.vehiculo_historial_normalizado tiene FK a vehiculos, asi que entra al TRUNCATE, Y es candidata a fuente del load. Truncarla en la misma transaccion borra el insumo. rutap.rutap_rows NO tiene FK y NO entra al cierre: sobrevive al truncate. Es el staging durable del que se puede regenerar todo, y otra razon para que el loader parta de ahi. === 4. G5 PASA A SER PRE-CONDICION === Ya lo anote en MOVILBA-226: el runbook no trunca hasta que exista un loader que DEMUESTRE recargar, probado contra una tabla de prueba y contado. Un gate posterior no sirve si el nucleo quedo vacio - es el caso 'el gate pasa por falta de entradas'. Y de acuerdo con coder02: mi Gate B no se puede ejercitar hasta que exista 227, asi que una corrida verde antes de eso NO es cobertura. NO EJERCITADO: no lei el cuerpo de rutap.rutap_rows columna por columna para decir si alcanza para poblar las tres tablas nucleo, ni compare su esquema entre DEV y PROD mas alla de la lista de tablas.
-
TRES MEDICIONES DE db02-mba-l-cc que achican este item por un lado y le meten una trampa dev-vs-prod por el otro. AUSENCIA CONFIRMADA CON DENOMINADOR: todos los archivos de dev/dev que INSERTAN en las tres tablas centrales viven en docs/migrations/ - 13 puntuales y fechados. Cero en tools/. Control positivo con el MISMO comando sobre el MISMO arbol: el patron de UPDATE devuelve 12+ archivos, asi que el cero de INSERT es el mundo y no el pathspec. rutap-sync-prod.sql: cero 'insert into', tres UPDATE. Y el grep de SQL no alcanza al importer de Python, asi que db02 lo LEYO: tools/rutap-snapshot-import.py, 1018 lineas, escribe SOLO rutap.snapshots, rutap.rutap_rows y rutap.rutap_expedientes, nunca toca public. Es un loader de STAGING, esta vivo y es actual. 1. PROD YA TIENE EL LIBRO VIGENTE STAGEADO, y eso achica este item. rutap.snapshots en PROD tiene UNA fila, id 9, 2026-09-03-1049-parque-rutap.xlsx, filas=5368, y rutap.rutap_rows tiene 5368. O sea 'PROD esta dos libros atras' es cierto de la PROYECCION a public, NO del staging: el libro ya esta adentro de PROD. **Este item es el paso rutap -> public y nada mas. Nadie tiene que volver a importar el xlsx a PROD.** 2. LA TRAMPA: el schema rutap de PROD es MAS FLACO que el de DEV, asi que un loader probado en DEV puede fallar en PROD. DEV rutap: rutap_rows 5368, snapshots 1, vehiculo_historial_normalizado 5368, m95_cambios_backfill_dev 3787, chasis_resolver 9, unidad_propulsora_resolver 4. PROD rutap: rutap_rows 5368, snapshots 1. Nada mas. PROD NO tiene vehiculo_historial_normalizado ni ninguno de los dos resolvers. Un loader que lea cualquiera de los tres corre verde en DEV y falla en PROD - o peor, no los encuentra y resuelve DISTINTO. O el loader lee rutap.rutap_rows, que es lo unico presente en los dos, o los resolvers se crean en PROD como parte de este item y quedan declarados como su dependencia. 3. CORRIGE EL RUNBOOK DE MOVILBA-226 QUE YA HABIAMOS ACORDADO: rutap.vehiculo_historial_normalizado TIENE FK a vehiculos, asi que esta DENTRO de la clausura del truncate, y es a la vez la fuente de recarga obvia. Truncarlo en la misma transaccion DESTRUYE EL INSUMO DE LA CARGA. rutap.rutap_rows no tiene FK, no esta en la clausura y sobrevive al truncate - tercer motivo para que el loader arranque de ahi. 4. G5 PASA A SER PRE-CONDICION, no post-check: no se trunca nada hasta que un loader demuestre que recarga, probado contra una tabla scratch y contado. Un gate que corre DESPUES no sirve si el nucleo quedo vacio - es exactamente el caso 'pasa por ausencia de input'. NO EJERCITADO (db02): no leyo rutap.rutap_rows columna por columna para decir si alcanza para poblar las tres tablas centrales, ni comparo su esquema entre DEV y PROD mas alla de la lista de tablas. **Eso es lo PRIMERO que tiene que medir este item.**
-
Read-only schema/source preflight (DEV, snapshot 9 = 5,368 rows): rutap.rutap_rows is the only durable common DEV+PROD source and has the full 39 book columns. public.vehiculo_historial cannot store a full SSOT row: it holds expediente/linea/entidad/tramite/dates/observaciones plus cambios jsonb, but no technical columns. public.vehiculos + public.vehiculos_datos_colectivos can hold only one current projection per domain. Therefore the loader must: (1) create exactly one current vehicle/VDC row per normalized dominio from an explicitly selected SINGLE current source row; (2) write all source periods to legacy VH only for its representable fields; (3) rebuild rutap.vehiculo_historial_normalizado from raw separately as the complete one-row-per-book-row history. It must never pick different source rows independently by field. Full historical technical fidelity remains MOVILBA-125/202 wide-layer scope, not a property legacy VH can deliver.
-
PRIMERA MEDICION DE 227, la que coder02 pidio para hoy: alcanza rutap.rutap_rows para poblar las tres tablas nucleo? (db02, 2026-09-03, SELECT en PROD y DEV.) RESPUESTA CORTA: como FUENTE DE DATOS si, es un espejo fiel del libro. Como fuente COMPLETA no: hay UNA columna NOT NULL que el libro no trae y que no se puede derivar sin equivocarse en 40 vehiculos. Necesita una cuarta tabla de parking que nadie habia nombrado. === ESQUEMAS: CERO DERIVA ENTRE ENTORNOS === rutap.rutap_rows es IDENTICA en DEV y PROD: 57 columnas, mismo tipo, mismo orden. 4 meta (snapshot_id, fila, fila_excel, cuit_norm) + 39 columnas del libro TODAS text + 14 col_39..col_52 vacias de relleno. O sea trae el libro entero en texto crudo. public.vehiculos, vehiculos_datos_colectivos y vehiculo_historial: las tres IDENTICAS entre PROD y DEV (columna, tipo y nullability). El riesgo de entorno es SOLO la falta de las tablas auxiliares de rutap en PROD, no deriva de esquema. === LOS NOT NULL SIN DEFAULT, que es lo que un INSERT no puede esquivar === vehiculos: dominio (libro: nro_dominio, OK), vehiculo_subtipo_transporte_id (NO ESTA EN EL LIBRO), id vehiculos_datos_colectivos: vehiculo_id, estado_id (derivable de Fecha_Baja: abierta->116 ALTA, todas cerradas->117 BAJA), id vehiculo_historial: vehiculo_id, observaciones (libro: Observaciones, pero NOT NULL - el loader tiene que escribir CADENA VACIA donde el libro no trae nada, no NULL, o el INSERT falla. Hoy 1065 de 4225 filas de PROD tienen '' y 3160 texto.) === EL BLOQUEO REAL: vehiculo_subtipo_transporte_id === Es NOT NULL, no tiene default, no es columna del libro, y NO ES FUNCION de ninguna combinacion de columnas del libro. Probe la mejor regla posible: (tipo_servicio, tipo, piso, unidad_propulsora) -> la moda del subtipo. Sobre los 2398 vehiculos de PROD, con 0 sin fila en el libro: ACIERTA 2358, FALLA 40. Se ve por que en el cruce: tipo=3 piso=Bajo va a 17 Largo 1537 veces, pero tambien a 18 Medio (8) y a 6 Corto (3); tipo=2 va a 18 Medio 751 veces y tambien a 9 Colectivo (2) y 6 Corto (1); tipo=1 va a 6 Corto (50) y a 1 Electrico (13). Y 1 Electrico, 3 Articulado y 4 Metrobus no salen del ancho del vehiculo. CONSECUENCIA: un rebuild desde el libro NO puede reconstruir esta columna. Adivinarla con la moda le pone el subtipo equivocado a 40 vehiculos EN SILENCIO, porque cualquier valor satisface el NOT NULL y la FK. POR LO TANTO: dominio -> vehiculo_subtipo_transporte_id se PARKEA antes del delete y se re-resuelve despues, exactamente como deudas_dominios y las dos tablas archive. Es la CUARTA tabla de parking del runbook y no estaba en la lista. Gate: cero vehiculos reconstruidos sin subtipo parkeado, y falla si el parking esta vacio. === LA OTRA MITAD DEL TRABAJO: 21 FK a resolver desde texto === Las tres tablas nucleo tienen 21 columnas FK que hay que resolver de texto del libro a id (sin contar vehiculo_id y borrado_por): 11 apuntan a opciones (estado, motivo, tramite, adas_presente, cabina_antivandalica, conexiones_usb, estandar_emisiones, identidad, mdvr, pantallas, wifi, motor_unidad_propulsora) y el resto a entidades, lineas, carrocerias, chasis, fabricantes, vehiculos_subtipos_transporte y regimen_servicio_modalidad. ESTO es lo que hacen chasis_resolver y unidad_propulsora_resolver en DEV, y es exactamente lo que PROD no tiene. Los resolvers son parte de 227, no un detalle de DEV. NO EJERCITADO: no verifique que cada una de las 21 resuelva hoy sin residuo para las 5368 filas del libro; eso es la medicion que sigue y es la que dice si 227 tiene una segunda mitad.
-
Canonical-source rule for the legacy current projection: per normalized dominio, select exactly one source row as current; every current attribute is projected from that same row. Provenance may be recorded per field, but per-field winner selection is prohibited. Any carry-forward exception requires a named business rule and stakeholder answer in rutap-transform-rules.md. Legacy vehiculo_historial receives every source period that is representable by its schema; no source row may be silently filtered or dropped. Its unavoidable fidelity boundary is named: historical technical/operational values (vehicle subtype/type, chassis/car body/motor/serials, model year, seats, propulsion, service modality, equipment/IDs, consumption, emissions, identity and operational current fields) have no columns in legacy VH; authoritative history for them is raw rutap.rutap_rows plus rutap.vehiculo_historial_normalizado. Consistency gates must assert raw=wide 1:1 by (snapshot_id,fila_excel), legacy VH period count=source period count unless a separately named exception is recorded, and current vehiculos+VDC values derive from the same selected source row.
-
Additional non-book-fact gate: vehiculos.vehiculo_subtipo_transporte_id is NOT NULL and the book does not reliably determine it (db02 measured 40 mismatches in a 2,398-row enumerated current-domain test). Before destructive reload, park dominio -> vehiculo_subtipo_transporte_id from live vehicles and restore it after source resolution; Gate B includes a zero-row anti-join. This is not a workaround: it preserves a load-bearing fact absent from SSOT. Loader maps NULL/blank SSOT observaciones to empty string because legacy VH.observaciones is NOT NULL. VDC estado_id is derived solely from fecha_baja (open=ALTA, closed=BAJA) and verified by the post-import SSOT-state gate.
-
RESIDUO DE LAS 21 FK, MEDIDO (db02, 2026-09-03, SELECT en PROD, denominador 5368 filas del libro con Nro_dominio no vacio). Respuesta a 'tiene 227 una segunda mitad': SI, pero no es la que parecia. Casi todo el residuo es CATALOGO SOFT-DELETEADO, no dato faltante. === EL HALLAZGO QUE MANDA: EL LOADER NO PUEDE FILTRAR borrado_en === chasis: catalogo 132 filas, 20 VIVAS, 112 borradas. filtrando borrado_en IS NULL -> 1722 filas del libro sin match, 78 modelos distintos SIN filtrar -> 61 filas sin match, 25 modelos distintos El 96% del residuo de chasis son filas de catalogo borradas. entidades: los 2 CUIT sin match EXISTEN, borrados. 30-54577578-2 M.O.D.O. S.A. (borrada 2026-08-14, 131 filas del libro, lineas 151 y 90) y 30-55665485-5 TRANSPORTES RIO GRANDE S.A.C.I.F. (borrada 2025-12-16, 9 filas, linea 23). regimen_servicio_modalidad: las 7 filas del catalogo estan borradas, LAS 7, y sin embargo 2395 de 2396 fichas de PROD apuntan adentro (2371 -> id 1 SP, 24 -> id 3 PP). Un loader que filtre borrado_en no resuelve NI UNA ficha. lineas: 175 filas sin match, valores 23, 90 y 99 - exactamente MOVILBA-220, y el 18+41+116 coincide con lo que medi alla. Y LAS TRES COSAS SON EL MISMO EVENTO: M.O.D.O. corre las lineas 90 y 151, Rio Grande la 23. Las entidades borradas y las lineas faltantes son la misma baja de operadores. REGLA QUE ESTO OBLIGA A ESCRIBIR: 'leer siempre por la vista que filtra borrado_en' es una regla del CAMINO DE LECTURA. Aplicarla al camino de IMPORT tira 1722 filas de chasis, 140 de entidad, 175 de linea y las 2395 referencias de modalidad. Es la tercera superficie del problema de MOVILBA-200 (lectura vs selector); el import necesita su propia respuesta y hay que decidirla por catalogo. PERO NO ES 'NUNCA FILTRAR' TAMPOCO, y este es el contraejemplo que lo prueba: opciones id 304 ELECTRICO-CABA esta borrada A PROPOSITO. .claude/rules/catalogos.md:40-43 dice que mapea a 37 ELECTRICO y 'Never recreate it, not even if an import reports it cannot find the value - that is the natural-key re-add trap'. O sea el loader necesita una TABLA DE ALIAS explicita, no una regla global de filtrado. (La regla dice 50 filas; en el libro vigente son 53. Re-derivar.) === RESIDUO CONTRA opciones: SOLO DOS VALORES EN 12 COLUMNAS === ADAS, MDVR, Wifi, Pantallas, ConexionesUSB, Cabina_Antivandalica, Aire_acondicionado, Piso, Tipo_Motor y Tramite: CERO sin match, cero vacias, sobre las 5368. Diez columnas limpias. Unidad_Propulsora: 53 filas con ELECTRICO-CABA -> alias conocido a 37. Tipo_Servicio: 24 filas con PP. opciones.tipo_servicio tiene UNA sola fila (125 SP). El PP vive en regimen_servicio_modalidad id 3, borrada como las otras 6. Carroceria -> carrocerias y Motor -> fabricantes: CERO residuo. Sirven de control positivo: el metodo de join encuentra match cuando lo hay. === LOS 25 MODELOS DE CHASIS QUE NO EXISTEN NI BORRADOS NO SON 25 MODELOS === Son ~6 modelos escritos de 25 formas. 'OH 1721/62' contra el catalogado 'OH 1721 L-SB/62'. '767 - 0 500 U', '767- 0 500 U', 'O-500 U', '897 - O 500 UA' son la misma familia con espacios inconsistentes y O-vs-cero. 'MT 17.0 GNV', '52-MT 17.0 GNV', '52-MT 17.0 GNV CA620', 'CA6200', 'CA 62' son un modelo con ruido de prefijo y sufijo. Y uno trae HOMOGLIFO: 'K280 В4X2 (GAS)' usa В cirilica (U+0412) en vez de B latina - convive con 'K280 B4X2 (GAS)' correcta, 8 filas. ESO ES NORMALIZACION, NO ALTA DE CATALOGO. Y se aprueba por filas que respaldan la grafia, nunca por parecido de texto. === ENTONCES, LA SEGUNDA MITAD DE 227 === No es 'construir resolvers para 21 columnas'. Es TRES decisiones de politica, y ninguna es de db03 sola: 1. Por cada catalogo, el import resuelve contra filas borradas o no. Hoy la respuesta tiene que ser SI para chasis, entidades, lineas y regimen_servicio_modalidad, o el loader no puede escribir. 2. Tabla de alias explicita, con ELECTRICO-CABA -> 37 como primera entrada y prohibicion de re-crear la 304. 3. Normalizacion conservadora de chasis_modelo + alias, para ~6 modelos en 25 grafias, homoglifo incluido. Lo que NO hace falta: dar de alta 78 modelos de chasis ni 2 entidades ni inventar categorias. NO EJERCITADO: no mire identidad_id, motivo_id ni estandar_emisiones contra sus valores del libro fila por fila mas alla del match de catalogo; no medi DEV; cero escrituras.
-
LA DECISION 1 ES NECESARIA PERO NO SUFICIENTE, Y LA MEDICION LO CUANTIFICA (db02, 2026-09-03, SELECT en PROD, denominador 5368 filas del libro). Verifique mi propia hipotesis de '~6 modelos en 25 grafias' como pidio coder02 - es una hipotesis hasta que cada colapso tenga filas que lo respalden - y al hacerlo aparecio algo mas grande que la normalizacion. === DEJAR DE FILTRAR borrado_en NO RESUELVE: CONVIERTE UN FALTANTE EN UNA AMBIGUEDAD === El catalogo chasis tiene GRAFIAS DUPLICADAS entre filas vivas y borradas. 24 cadenas de modelo tienen mas de una fila de catalogo, hasta CUATRO copias. Y la copia BORRADA suele tener MAS vehiculos que la viva: 'OH 1618 L-SB/55' -> id 41 (borrada, 149 vehiculos) + id 131 (VIVA, 33) + 2 borradas sin uso 'MT 17.0 LE' -> id 14 (borrada, 46) + id 127 (VIVA, 423) + 2 borradas sin uso 'K 250 UB 4x2' -> id 27 (borrada, 45) + id 121 (VIVA, 2) 'MT 15.0 LE' -> id 5 (borrada, 99) + id 130 (VIVA, 235) + 1 sin uso 'O 500 U 1826/59' -> id 4 (borrada, 23) + id 125 (VIVA, 198) MEDIDO sobre las 5368 filas del libro, resolviendo sin filtrar borrado_en: match UNICO = 581 match AMBIGUO = 4726 <-- el 88 por ciento SIN match = 61 O sea la regla tal cual quedo escrita cambia 1722 filas que no matchean por 4726 que matchean DE FORMA ARBITRARIA. Y elegir mal no da error: la FK es valida en las dos, asi que la mayoria de la flota se queda con un chasis_id equivocado y en silencio. === LA ESCALERA DE DESEMPATE, MEDIDA PASO A PASO === 1. PREFERIR LA FILA VIVA con esa grafia -> resuelve 3646 filas. Y el dato que hace que la regla sea segura: CERO filas ambiguas entre vivas. El catalogo VIVO no tiene ni una grafia duplicada; toda la duplicacion esta del lado borrado. 2. si no hay viva, y hay UNA sola borrada -> 577 filas. 3. si hay varias borradas, preferir la que TIENE vehiculos -> 942 filas. QUEDAN AMBIGUAS: 142 (ninguna borrada con uso, o mas de una). SIN match en ningun lado: 61. Total 3646+577+942+142+61 = 5368. Sin residuo. Entonces el desempate de dos pasos baja la ambiguedad de 4726 a 142, y el trabajo manual real de esta columna son 203 filas (142 ambiguas + 61 sin match), el 3,8 por ciento. Eso es lo que hay que decidir a mano, no 4726. === EFECTO LATERAL BUENO, VERIFICAR EN EL GATE: preferir la viva REPARA MOVILBA-200 === 200 reporta 574 vehiculos de PROD que muestran un chasis que ya no se puede volver a elegir porque su fila de catalogo esta borrada. Un rebuild que resuelva PREFIRIENDO LA VIVA los re-apunta a la fila viva y el selector deja de verse vacio. No es el objetivo del rebuild, es una consecuencia - y por eso hay que MEDIRLO despues, no asumirlo. === MI HIPOTESIS DE '6 MODELOS EN 25 GRAFIAS' QUEDA SIN PROBAR, y la retiro como afirmacion === Vale la regla de coder02: un alias se aprueba por FILAS VIVAS QUE YA USAN ESA GRAFIA, nunca por parecido de texto. Varios de los colapsos que propuse tienen respaldo DEBIL: '767-0 500U' (id 26) tiene 1 solo vehiculo; 'FL BMO 368 VERSION 1' (id 58, VIVA) tiene 1, y el libro escribe 'FU-BMO 368 VERSION 1', 'FU BMO-368 VERSION 1721 L62CA' y 'BMO 368 VESION 1618' (con la 'R' faltante). Son candidatos, no equivalencias. Para MOVILBA-199: la evidencia es la tabla de arriba, columna 'vehiculos que la usan', y hay que decidir de a una. EL HOMOGLIFO SIGUE SIENDO EL CASO QUE LIDERA: 'K280 В4X2 (GAS)' con В cirilica U+0412 contra la grafia latina de 8 filas. Es invisible en cualquier revision, vence a la igualdad y prueba que la normalizacion tiene que ser mecanica. NO EJERCITADO: no aplique la misma escalera a carrocerias ni a fabricantes (los dos dan cero residuo, pero no medi si tienen grafias duplicadas vivas/borradas, que es una pregunta distinta). Cero escrituras.
-
Catalog resolution policy for loader: resolve FK targets without filtering borrado_en; selector/validation views remain filtered. Historical source rows must retain retired entities/lineas/chassis/modalities. Explicit aliases are required: current first entry is unidad_propulsora ELECTRICO-CABA -> opciones id 37 (ELECTRICO); never recreate deleted opciones id 304. No undeletes or new entities/lineas/categories/chassis merely to satisfy import residue. Loader depends on MOVILBA-199 for conservative mechanical chasis normalization/aliases backed by existing rows, including the Cyrillic-B homoglyph case; no textual-similarity guesses. MOVILBA-220 finding: retired entities M.O.D.O. and Rio Grande and absent lineas 90/151/23 are one retirement event, not three lineas to recreate.
-
Read-only multiplicity audit, DEV snapshot 9, denominator 5,368: carrocerias resolved by carroceria_modelo has 5,368 exactly-one-live, 0 live-ambiguous, 0 deleted-only, 0 deleted-ambiguous, 0 unmatched, 0 blank. Motor fabricantes resolved by fabricante has exactly the same 5,368/0/0/0/0/0 result. Therefore no deleted fallback or alias is needed for either resolver today; the live-first ladder will nevertheless be implemented generically and gated to fail if a live ambiguity occurs.
-
db02 value-level check de identidad_id / motivo_id / estandar_emisiones contra el libro, en PROD, 2026-09-03. DENOMINADOR: 1586 dominios con fila ABIERTA en el libro Y ficha vdc VIVA en PROD (de 1602 con fila abierta; 2398 vehiculos en PROD). NO cubre el tercio cerrado del libro. 1. estandar_emisiones_id: 1585/1586. Una sola contradiccion (libro E3, prod EURO5). CERO fugas de catalogo. CORRIJO UNA MEDICION MIA DE HACE 20 MINUTOS: un primer pase sin filtrar borrado_en en la ficha reportaba 3 filas apuntando al campo tipo_motor (ids 153/154) en vez de estandar_emisiones. Las 3 estan en fichas BORRADAS. No es un defecto vivo. El error fue mio: junte vdc sin filtrar y publique la cifra. 2. identidad_id: 1577/1586. 9 contradicciones, todas en la misma direccion (libro SI, prod NO), todas estado ALTA: AG225BW AH152NT AH846SE AH846SJ AH846SL AI153BS AI153BV AI239RZ AI239SC AI282FA (10 dominios, uno sale del denominador por ficha borrada). Cero NULL. Antes de llamarlo defecto hay que correrle el test de ATRASO de MOVILBA-213 contra los libros archivados - no lo corri. Y NO ES UN CATALOGO 'identidad': identidad_id apunta a opciones campo respuesta_binaria (24 SI / 25 NO). El nombre de la columna no nombra su catalogo. 3. motivo_id: 0 de 4225 filas de vehiculo_historial lo tienen poblado. No hay nada que reconstruir ni fuente en el libro. Cerrado. RESTRICCION NUEVA PARA EL LOADER, y choca con la regla de no filtrar borrado_en: opciones tiene 192 valores distintos y 8 colisionan entre campos. Un lookup por valor_opcion SOLO es ambiguo para: SI y NO (respuesta_binaria 24/25 CONTRA aire_acondicionado 126/127, ambas BORRADAS), GNC (tipo_motor 156 / unidad_propulsora 158 / estandar_emisiones 173), ELECTRICO (unidad_propulsora 37 / estandar_emisiones 174), ALTA (estado 116 / tramite 317 / evento_tipo 323), BAJA (estado 117 / evento_tipo 327), OTRO, OFICINA. Como MOVILBA-227 resuelve catalogos SIN filtrar borrado_en, SI y NO pasan de 1 hit a 2. Toda busqueda del loader contra opciones tiene que ir por (campo_nombre, valor_opcion), nunca por valor_opcion solo. Elegir mal no da error: la FK es valida en las dos. HALLAZGO LATERAL, toca directo al rebuild: dominio NO es unico en vehiculos. 2388 dominios distintos en 2398 filas; 9 dominios duplicados (AE100DB AE100DF AE971GV AF928IF AG045KB AH152NT AI086GZ AI086HB PMH988; AG045KB con 3 filas). 10 vehiculos no tienen ficha viva, 2 no tienen ninguna. PERO al nivel de ficha VIVA dominio SI es llave: cero dominios con mas de una ficha viva. Entonces el parking por dominio (subtipo_transporte) se sostiene CON UNA CONDICION: parkear desde la ficha viva, no desde vehiculos. Parkear desde vehiculos colapsa 9 dominios en silencio. PMH988 es el caso feo: ficha borrada con estado BAJA en v.id 5072 y ficha viva con estado ALTA en v.id 6332. NO EJERCITADO: el tercio cerrado del libro; el test de atraso sobre las 9 de identidad; carrocerias y fabricantes contra la escalera de grafias duplicadas vivas/borradas; cero escrituras.
-
db02, PROD, 2026-09-03: cierro la segunda brecha que habia declarado sin ejercitar - carrocerias y fabricantes contra la misma escalera de grafias duplicadas vivas/borradas que rompio chasis. RESULTADO: chasis es la EXCEPCION, no el patron. Los tres catalogos tienen grafias duplicadas entre vivas y borradas (chasis 24, carrocerias 14, fabricantes 9) y los tres tienen CERO grafias duplicadas entre filas VIVAS. Pero el paso 1 de la escalera (preferir la viva) se comporta distinto: | catalogo | filas / vivas | sin filtrar borrado_en | despues de preferir la VIVA | |---|---|---|---| | fabricantes | 50 / 37 | unico 524, AMBIGUO 4844 | 5368 unico, 0 ambiguo, 0 sin match | | carrocerias | 74 / 18 | unico 2021, AMBIGUO 3347 | 5368 unico, 0 ambiguo, 0 sin match | | chasis | 132 / 20 | unico 581, AMBIGUO 4726 | 3646 unico, 142 siguen ambiguas, 61 sin match | Denominador 5368 filas del libro con Nro_dominio no vacio, las tres corridas. Y el 90% de ambiguedad de fabricantes NO era un hallazgo: colapsa entero en el paso 1. Cero residuo tampoco era prueba de que estuviera sano - las dos afirmaciones necesitaban la misma medicion. POR QUE chasis se porta distinto: en carrocerias las copias duplicadas son duplicados EXACTOS (mismo fabricante_id, piso, aire) borrados todos el 2026-06-30 en una sola pasada de deduplicacion, y quedo exactamente una viva por grafia. chasis no recibio esa pasada: tiene 132 filas y solo 20 vivas, con la copia borrada llevandose mas vehiculos que la viva. La deuda de catalogo de chasis es una limpieza que quedo a medias, no un problema de datos del libro. CONSECUENCIA PARA EL LOADER: la regla 'resolver contra borradas' se queda, pero el desempate 'preferir la VIVA' alcanza SOLO para carrocerias y fabricantes. chasis necesita ademas la tabla de alias (203 filas de superficie manual, 3,8%) - MOVILBA-199. NO EJERCITADO: no compare los ATRIBUTOS de la fila viva de carrocerias contra los de sus copias borradas mas alla de las 40 filas que mire (todas identicas salvo dos AUTOBUS con piso/ac NULL, ids 73 y 74, ambas borradas); no toque motores ni regimen_servicio_modalidad con esta escalera; cero escrituras.
-
Resolver invariants agreed 2026-09-03: opciones resolve by the composite key (campo_nombre, valor_opcion), then apply the ordered live-first ladder only within that campo; never resolve by valor_opcion alone. This prevents cross-field collisions (SI, NO, GNC, ELECTRICO, ALTA, BAJA, OTRO, OFICINA) while still retaining deleted historical catalog candidates where necessary. For parked vehicle-domain mapping, derive dominio from the live VDC ficha, never from vehiculos alone; gate asserts zero domains with more than one live ficha before parking/reload. Catalog readers filter active rows; catalog resolvers do not filter before applying their within-key live-first ladder.
-
DEV execution gates must state invariants, never frozen literals from another environment/run. Re-derive denominators at execution time and fail if a required denominator is zero. Parking selection: take entries from vehiculos, using the live VDC ficha to select one when a dominio repeats; if there is no live ficha and subtype values disagree, stop and classify. Assert zero dominios with multiple live fichas and, after reload, zero vehicles whose dominio is absent from the source book (which removes known historical import artifacts such as MOVILBA-152 rather than preserving them).
-
DEV full-book rebuild preflight found 28 current vehicles across 19 non-book dominios. Eleven are soft-deleted import artifacts; five have a live ficha and would be deleted by reload: AA111EE, DHU474, PAN219, ZZ001ZZ, ZZ002ZZ. Their human/demo origin is only a lead (creado_por is not provenance), so no rebuild may run until classified as disposable test data or explicitly parked/restored. Gate must capture non-book pre-state before truncate, fail if zero, assert post-state zero only for the classified deletion set, and enumerate any live-ficha records affected.
-
REQUISITO DEL LOADER (de MOVILBA-152, medido por db02 el 2026-09-03): en DEV, UNA sola corrida del import creo TRES filas para el dominio NEA182 el mismo dia con tres subtipos distintos, y el soft-delete lo tapo. El loader nuevo necesita una clave que haga imposible una segunda fila por dominio DENTRO de una corrida, ademas de entre corridas. Sin eso el rebuild borra la evidencia vieja y el defecto vuelve sin filas antiguas que lo delaten.
-
Required recoverable DEV pre-rebuild export completed and verified readable: docs/migrations/2026-09-03-2330-movilba-227-dev-nonbook-pre-rebuild-backup.tsv. It contains 71 TSV records (all 28 non-book vehiculos plus related VDC/history); SHA-256 0910dc1c78961e2b132e03569b0dbb76cebe9983fe7cbb59f32d850807449b9a. Explicit live-ficha records classified for deletion by PM: AA111EE, DHU474, PAN219, ZZ001ZZ, ZZ002ZZ. Export made; no core transaction executed.
-
Canonical DEV pre-rebuild row backup is NOT in the repository: /data-lezama/movilba/rebuild-dev/2026-09-03-2328-dev-dominios-fuera-del-libro-DUMP.json (MD5 9781bc397d8248ce2c2c5efe3b81ed98). It contains personal CUIT-like values in audit fields; row dumps must remain under /data-lezama, not docs/migrations/Git. The supplemental TSV is likewise outside the repo at /data-lezama/movilba/rebuild-dev/2026-09-03-2330-movilba-227-dev-nonbook-pre-rebuild-backup.tsv (SHA-256 0910dc1c78961e2b132e03569b0dbb76cebe9983fe7cbb59f32d850807449b9a).
-
PREGUNTA DE ELAZAR 2026-09-04: 'solucion?'. La forma, para que db03 no la derive de cero. El rebuild ya tiene probada la mitad que BORRA (transaccion, cierre de FK re-derivado, gates de MOVILBA-226 con control positivo). Falta la que CARGA. `tools/rutap-sync-prod.sql` solo actualiza y REPORTA los faltantes; no inserta. PUNTO DE PARTIDA QUE YA EXISTE, no arrancar en blanco: `docs/migrations/2026-08-20-movilba-94-importer-template-corrected.sql`. Nunca se corrio y no tiene GO, pero ya proyecta `fecha_baja`/`expte_baja` y resuelve `tramite_id` contra `opciones`. Cubre SOLO `vehiculo_historial`: faltan `vehiculos` y `vehiculos_datos_colectivos`. FUENTE: `rutap.rutap_rows`, que esta en los DOS entornos con las mismas 57 columnas. **PROD ya tiene el libro cargado** (`rutap.snapshots` id 9, 5368 filas): 'PROD esta dos libros atras' es cierto de la proyeccion a `public`, no del schema `rutap`. Este item ES el paso `rutap` -> `public`. OJO: `rutap.vehiculo_historial_normalizado` esta DENTRO del cierre del truncate y a la vez es la fuente obvia de recarga. Truncarla destruye la entrada. Ademas solo existe en DEV. REQUISITOS DEL LOADER, cada uno con su motivo: 1. **Clave por dominio DERIVADO del join**, nunca una columna `dominio` denormalizada. 2. **Una fila por dominio por corrida, imposible por construccion.** En DEV una SOLA corrida creo TRES filas para NEA182 el mismo dia con tres subtipos distintos, y el soft-delete lo tapo (MOVILBA-152). Sin clave que lo impida, el rebuild borra la evidencia vieja y el defecto vuelve sin filas antiguas que lo delaten. 3. **`creado_por = 'system_import'`**, el id que ya existe igual en DEV y PROD (MOVILBA-224). 4. **Derivar de la fila ABIERTA del libro, nunca de un evento cerrado** (MOVILBA-174, sin reparar). 5. **`vehiculos.vehiculo_subtipo_transporte_id` es NOT NULL y NO esta en el libro.** No es derivable: la mejor regla da 2358 bien / 40 mal. Se APARCA por dominio antes del truncate y se restituye. Es la cuarta tabla de aparcado y la razon por la que 'reconstruir todo desde el libro' no es literalmente alcanzable. 6. **Ninguna regla de seleccion sin su rama 'no resuelve' = PARAR Y CLASIFICAR.** Un valor arbitrario satisface el NOT NULL y el FK y no levanta nada. 7. Nombrar las tablas de aparcado a db02 para extender el gate F. No adivinarlas. CIERRE: los gates de 226 ya validan el resultado. El loader no necesita inventar verificacion, necesita pasar la que ya esta escrita y probada.
-
ANALISIS DEL TRACKER 2026-09-04-1100 (Eugenia contesto; el `Estado` casi no se movio, como siempre). **LOS CUATRO QUE LA HOJA `Bajas` SIGUE LISTANDO COMO 'SIN RESPUESTA' YA ESTAN CONTESTADOS** en la hoja `Para Eugenia`: AA914MC (5c), AE512KL (5d), AE352LC (5f), AH007QZ (5i). La hoja `Bajas` quedo vieja respecto de sus propias respuestas. Leer SIEMPRE `Tu respuesta`, nunca el `Estado`. **EL HALLAZGO QUE CAMBIA EL LOADER (MOVILBA-227) — respuesta 5d, AE512KL, palabras de ella:** 'SON EXPEDIENTES DE MODIFICCIONES (NO son BAJAS) por los cuales en un "periodo" estuvo con cierta info tecnica y luego se modifica.' **Un expediente que cierra un periodo NO es automaticamente una baja.** Una modificacion cierra el periodo tecnico anterior y abre uno nuevo EN LA MISMA LINEA. Si el loader lee 'periodo cerrado + expediente presente' como baja, inventa una baja por cada modificacion tecnica del libro. Da la misma forma para AA914MC, AE352LC, AH007QZ, AB674IP, AE618VI, AF106VS y AA935OF: cada uno tiene expediente POR BAJA y expedientes POR MODIFICACION, por separado, y son eventos distintos. Es el asunto de MOVILBA-97, que ya tiene clasificador puro commiteado en `movilba-97-modification-subtype` (a78225f8). **EL LIBRO YA NO ES EL QUE TENEMOS.** Respuesta 5f: 'Actualizado en el Excel de Parque el Expediente correspondiente.' Edito el workbook vivo despues de la descarga del 09-03. El archivo local mas nuevo sigue siendo `2026-09-03-1049-parque-rutap.xlsx`. Hay que bajar el vigente. **RESPUESTA 6, prefijos de resolucion:** 'Todas las Resoluciones son RS, Res o Resol, generalmente va el año y despues el Numero y el ente que la emite, en estos casos SECT.' O sea la familia Res NO tiene forma canonica, lo confirma la fuente. Ratifica la decision de MOVILBA-179: el write-gate acepta solo EX-, y Res/RS/Resol se siguen aceptando como instrumento en el camino de LECTURA (MOVILBA-184). **DOS PREGUNTAS MIAS ESTABAN MAL ESCRITAS: la 7 y la 8 las contesto 'NO entiendo'.** No es un problema de ella. La 7 preguntaba por que GRUPO EMPRESARIO repite la RAZON SOCIAL y la 8 por un instrumento calificado de 'experimental' — las dos pedian que INTERPRETARA una estructura nuestra en vez de pedir un dato. Se reescriben pidiendo el dato y nada mas, o se retiran. Ver feedback_una_pregunta_para_eugenia_no_evalua_su_trabajo. NO EJERCITADO: no compare las hojas `Datos` (127 filas) ni `Errores cronologia RUTAP` (254) contra la version anterior; solo `Para Eugenia` y `Bajas`.
-
MEDIDO EN EL LIBRO, no citado (db02, 2026-09-04, DEV snapshot 9). Confirma la respuesta de Eugenia y le pone denominador. **EX-2026-37226779 cubre 154 filas del libro sobre 77 DOMINIOS. Sus `tramite` son solo `Alta` y `Modif` — NO hay ninguna baja. Y los 77 de 77 CONSERVAN LA MISMA LINEA antes y despues. Cero cambian de linea.** Es exactamente la frase de ella - 'SON EXPEDIENTES DE MODIFICCIONES (NO son BAJAS)... en un periodo estuvo con cierta info tecnica y luego se modifica' - ahora medida. Un periodo se cierra el 2026-08-19 y otro se abre el mismo dia, misma linea, mismo operador, bajo un solo expediente. **TAMAÑO DE LA FALLA: un loader que lea 'periodo cerrado + expediente presente' como baja inventa 77 BAJAS con este unico expediente.** No es hipotetico: es el mismo expediente que esta en la fila abierta de AI239RS. AI239RS es el ejemplo trabajado de toda la forma: sus dos filas del libro dicen `Modif`, las dos traen linea 151, la cerrada termina el 2026-08-19 y la abierta empieza el 2026-08-19. **DEV guardo la fila abierta con `linea_id` NULL.** O sea la modificacion se leyo como algo que TIRA la linea en vez de como un cambio tecnico que la CONSERVA. Ahi nace la clase de MOVILBA-216 (170 filas abiertas vivas con linea_id NULL, 169 de las cuales SI tienen linea en la fila abierta del libro). GATE que se agrega: despues del reload, cero dominios de este lote cargan un evento con forma de baja, y los 77 conservan su linea. NO EJERCITADO (db02): no leyo el clasificador; no chequeo otros expedientes de lote, asi que 77/77 es DE ESTE LOTE y no una afirmacion sobre todo el libro; no toco PROD.
-
DEV raw SSOT snapshot 10 staged from 2026-09-04-1154-parque-rutap.xlsx: 5,370 rows / 2,406 dominios, md5 f7e9ead4ddcefecbc2350b726ae8d825. Official importer rehearsal passed first; committed only rutap staging. Loader must consume latest snapshot dynamically; no core tables changed.
-
AI239RS source has two Modif periods, both linea 151; current DEV open history loses linea. Loader will preserve book tramite and line per source row, never infer baja from fecha_baja/expediente and never use expediente as a vehicle key.
-
DECISION coder02 2026-09-05 06:58: el loader arranca desde docs/migrations/2026-08-20-movilba-94-importer-template-corrected.sql, no de cero - ya proyecta fecha_baja y expte_baja y resuelve tramite_id por JOIN contra opciones, los dos defectos que el 08-13 dejaron 3963 filas con esas columnas vacias. El gate de MOVILBA-224 tiene DOS ramas y para el 09-07 alcanza la B: la prohibicion escrita de correr el import de reemplazo con usuarios adentro, implementada DENTRO del loader como una negativa que DISPARA (el loader aborta si el destino tiene alguna fila cuya procedencia del libro no puede probar), nunca como comentario. La rama A, la marca de procedencia por fila que el import no puede escribir, queda abierta como el arreglo real. Ensayo con ROLLBACK y medicion ADENTRO de la transaccion. DEV ONLY. Asignado a db03-mba-l-ca.
-
Loader completo aplicado en DEV el 2026-09-05 07:47 por db03-mba-l-ca, GO de coder02, solo DEV. Ensayo re-corrido DESPUES de MOVILBA-255 y sin cambios: selected=5369, ya iguales al libro=5351, a actualizar=18, seleccionados soft-deleted=0. Commit: vehiculos 1 insert/15 updates; VDC 1 insert/19 updates; historial 19 inserts/18 updates. CERO deletes, CERO triggers deshabilitados. Post-commit vehiculo_historial total=6097, con borrado_en=608, activas=5489 - la aritmetica cierra contra el pre-estado de 255 (6078+19=6097, 608 sin cambio, 5470+19=5489). SHA-256 del loader 5240633a64b39e341f6c0e71c82af2523e27c9ac44c3018771018fa1ab18e774. LO QUE HIZO FALTA PARA LLEGAR, y es lo que hay que leer antes de tocarlo de nuevo: 1. La identidad (vehiculo_id, fecha_alta, fecha_baja, expte_alta, expte_baja, ordinal) NO sirve: incluye los campos que el libro CORRIGE, asi que una fila corregida nunca se reencuentra y el loader inserta una nueva dejando la vieja colgada. 2. Tampoco alcanza (vehiculo_id, fecha_alta, ordinal): 727 -> 709, no colapsa. El ordinal es lo unico de la identidad que NO es un hecho del libro, es una posicion que calculamos. 3. LA REGLA QUE FUNCIONA es de SUPERVIVIENTE por acuerdo de payload: puntuar los hechos que definen el periodo (fecha_baja, los dos expedientes, entidad, linea, tramite_id), despues el payload completo, desempate por id mas bajo (estable entre corridas y nadie lo confunde con una fecha), y RAMA DE ABORTO si ningun candidato acuerda o si dos filas de origen eligen la misma fila existente. El loader NUNCA borra a los perdedores: los deja y los reporta. 4. Las dos ramas de aborto se PROBARON forzandolas, cada una con su propio mensaje y exit 3. Un gate que solo paso esta sin probar. 5. La caida de 636 a 18 updates es la regla funcionando: el matching por ordinal reescribia filas que ya estaban bien. 5351 de 5369 ya coincidian con el libro. QUEDA AFUERA A PROPOSITO: las filas excedentes que el loader deja atras son MOVILBA-255 (aplicado), MOVILBA-260 y MOVILBA-271. El espejo ancho sigue en snapshot 10 y es MOVILBA-269.