Nada garantiza una sola fila abierta por chasis en el libro RUTAP: los gates usan max() y elegirian un ganador en silencio
Current defect (2026-10-02): the imported book has exactly one open row per normalized chassis today (PROD snapshot 8 and DEV snapshot 20: 1,602 open rows, 1,602 chassis keys, zero duplicates), but the importer does not enforce that at the chassis level. The installed rutap.proyectar_snapshot W4 marks multiple open rows by (vehiculo_id, dominio), not by chassis identity. The standalone 2026-08-26 MOVILBA-89 SQL detects duplicate-open chassis but is not invoked by tools/rutap-snapshot-import.py. A read-only duplicated-row witness changes the duplicate-group count 0 to 1. Implement a per-chassis current-projection eligibility/conflict check and an old-versus-new negative control: a second open source row for one chassis must never be resolved by max() or another silent winner. Preserve every raw workbook row and report the conflict under docs/reference/rutap-transform-rules.md; do not wire a global abort that rolls back raw ingestion, because the importer currently stages and projects in one transaction. Retain the existing exactly-one-open-domain and terminal-date controls where applicable. Acceptance: normal source population passes with positive count, the duplicate witness is detected and withheld from current projection without discarding source history, and the gate is exercised on both bases before a subsequent import. Related: MOVILBA-125, MOVILBA-42, MOVILBA-76.
Activity
-
STILL OPEN y sigue siendo verde POR SUERTE, medido por db02-mba-l-cc 2026-08-21 08:12. Prod: los 1600 vehiculos en ALTA tienen exactamente una fila de historial abierta, los 137 en BAJA tienen cero, maximo abierto por vehiculo = 1. Lado libro, rutap.v_rutap_latest: 2252 chasis distintos, maximo de filas abiertas por chasis = 1, ninguno con dos. O sea que el invariante se cumple hoy en los dos lados y NADA lo asegura en ningun lado. Mas filoso que cuando se filo: 130 seriales de chasis estan compartidos por mas de un vehiculo vivo en prod, asi que la agregacion por chasis YA es multi-fila de verdad; lo unico que salva a los max() es que la cantidad de filas ABIERTAS sea uno. El dia que deje de serlo, los gates eligen un ganador en silencio.
-
AUDIT 2026-08-25: hoy snapshot5-equipo-terminal5 (DEV+PROD) aplico exactamente el fix que este item pide, en miniatura - re-deriva tie_count de rutap.v_rutap_latest LIVE al momento del write (no confia en el worklist pre-armado) y aborta si el libro cambio y aparecio un empate nuevo desde que se armo el worklist. 4 dominios con empate genuino (AF821DV/AF875JB/AF875JQ/AF899TF) quedan explicitamente excluidos, nunca desempatados en silencio. Precedente puntual, no cierra el item - el patron todavia falta generalizarse a los demas gates que usan max().
-
db02-mba-l-ca / db
-
Implementando preflight reutilizable: conserva siempre rutap_rows crudo y bloquea solamente la mutación de proyección actual ante más de una abierta o empate terminal.
-
Audit-PASS preflight SQL is ready in docs/migrations/2026-08-26-movilba-89-rutap-current-projection-gate.sql; coder integration/commit requested during completion sweep.
-
Audit-PASS reusable projection gate committed and deployed to Dev branch as v5.4.49 / 77241f62. It preserves raw rows and blocks only ambiguous current projections.
-
MOVILBA-89 current-projection preconditions are included in docs/migrations/2026-08-26-movilba-112-89-history-import-gates.sql for DB03’s coordinated MOVILBA-42 migration; DEV rehearsal passed.
-
Reopened: the shipped workbook-wide abort gate does not satisfy the agreed per-chain quarantine-and-continuation protocol. Design and DEV measurement are ready; persistent worklist/eligible-view implementation is pending MOVILBA-89/125.
-
Audit PASS: persistent per-chain quarantine design and reproducible Snapshot-6 read-only measurement documented. Pending MOVILBA-89/125 DDL and projection-writer integration; no global-abort gate may be used.
-
DEV MOVILBA-42 prerequisite is applied/audit-PASS, but the persistent per-chain quarantine worklist and projection-eligible views remain deferred to MOVILBA-89/125. The prior workbook-wide abort gate is still prohibited; raw import and unambiguous chains must continue when that work lands.
-
DEV MOVILBA-42 prerequisite is applied/audit-PASS, but the persistent per-chain quarantine worklist and projection-eligible views remain deferred to MOVILBA-89/125. The prior workbook-wide abort gate is still prohibited; raw import and unambiguous chains must continue when that work lands.
-
Reviewed MOVILBA-112/89 TEMP import-gate worklist artifact committed to Dev branch as v5.4.52 / 41a11677. It documents provenance, scoped coverage and quarantine worklist only; persistent quarantine/views remain pending the coordinated MOVILBA-42/125 DB migration.
-
MOVILBA-42 foundation is now live/audit-PASS in DEV and PROD. Persistent per-chain quarantine tables and projection-eligible views remain outstanding under MOVILBA-89/125; the global-abort prototype remains noncanonical.
-
Snapshot-6 source-only recheck of AE922FX/AE971FE/AE971FF: each has a NUDO zero-day interval (fecha_alta=fecha_baja=2025-07-08) and a parallel C.U.S.A. valid interval from 2025-07-08 to 2025-10-22; every later event remains C.U.S.A. Therefore NUDO rows are retained raw invalid_business_interval evidence, while C.U.S.A. supplies the valid entity/current chronology. No creado_en, DB id, or workbook-order tie-break used. Protocol doc updated; no writes.
-
DB02-reviewed SSOT chronology handoff deployed docs-only to DEV 8eefca48/v5.4.56 (live serviceId 8583; dev/origin refs agree; typecheck PASS). Document hash e24b64c2 matches reviewed handoff. It records AE922FX/AE971FE/AE971FF source-evidence resolution: retain/quarantine invalid zero-day NUDO rows; use valid C.U.S.A. continuity; never order by creado_en, DB id, or workbook row. PROD untouched; final docs-only audit pending.
-
AE922FX/AE971FE/AE971FF source-chronology protocol update deployed canonically to DEV as 8eefca48/v5.4.56; document hash e24b64c2 matches reviewed handoff, typecheck PASS, live serviceId 8583. PROD untouched; docs-only deployed-diff audit pending.
-
Independent audit PASS for docs-only DEV 8eefca48/v5.4.56. Exact scope doc+package only; committed sha256 e24b64c2186e4621978f3773282adc49ecf7ab00a4456b5179376821f013a8a9. Audit independently matched AE922FX, AE971FE and AE971FF raw SSOT chains: invalid NUDO zero-day row followed by uninterrupted C.U.S.A. chronology, resolved by business date/expediente continuity with no creado_en/id/order tie-break. PROD untouched.
-
Reviewed/audit-PASS SSOT chronology documentation promoted with canonical PROD merge 5d73e70a/v5.4.57; no database or application-logic change from the doc. Independent PROD deployed-diff audit pending.
-
Source-chronology protocol docs promoted to PROD in SHA 5d73e70a / v5.4.57 / serviceId 8720 alongside M137 runtime fix. Validadoras remained fail-closed 404; no DB action or M42 reapply.
-
db02-mba-l-cc / db
-
parent=MOVILBA-125
-
Absorbido por MOVILBA-125 como dependencia de disenio. No estaba activo: inProgress heredado de un carril retirado. db02-mba-l-ca confirmo CERO escrituras y CERO DDL suyo; solo existieron worklists temporales de ensayo, ninguna implementacion persistente. Disenio en docs/design/movilba-89-per-chain-quarantine-design.md. CONDICION DURA para 125: tiene que CREAR las tablas de cuarentena persistentes ANTES de usar cualquier resultado de cuarentena - hoy no existen. La cuarentena retiene origen e historial y solo retira la proyeccion.
-
Corroboracion medida 2026-08-31 03:57 (db02-mba-l-cc, DEV 10.9.10.54/movilba_dev): rutap.v_rutap_latest devuelve DOS filas para un mismo nro_dominio en el snapshot 7 - AI086FZ, AI086HA, AI086HC, AI086HJ, cada uno con count=2, hallados de paso mirando la familia AI086 por MOVILBA-152. Es exactamente la forma que describe este item: la vista 'latest' no garantiza una sola fila abierta, y un gate con max() elegiria ganador en silencio sobre estos 4. No es una medicion exhaustiva - salio de un filtro nro_dominio like 'AI08%', asi que 4 es un piso, no el total. Falta correr el conteo completo de dominios con >1 fila en v_rutap_latest.
-
CORRECCION de la nota anterior de las 03:57, misma sesion. Lei el viewdef antes de dejar la cifra en pie: rutap.v_rutap_latest NO es 'la ultima fila por vehiculo', es 'todas las filas del ultimo SNAPSHOT' (WHERE snapshot_id = (select id from rutap.snapshots order by fecha_descarga desc, id desc limit 1)). Por lo tanto varias filas por nro_dominio es la historia del libro y es lo esperado, no un defecto: medido completo en DEV, 1723 de 2390 dominios tienen mas de una fila, max 7, 4590 filas involucradas. Los 4 dominios AI086* que cite como 'la forma del problema' no son nada por si mismos. Lo que SIGUE en pie de este item es lo que decia el titulo: elegir la fila ABIERTA dentro de ese conjunto no esta garantizado por nada, y con 1723 dominios multi-fila la superficie donde un max() elige ganador en silencio es la mayoria del libro, no un caso borde. La trampa a registrar es de nombre: 'latest' aca califica al snapshot, no a la fila.
-
Corroboracion medida 2026-08-31 (db02-mba-l-cc): la forma 'dos filas Modif con fechas identicas y una con el expediente del Alta' tiene poblacion EXACTA de 4 dominios en snapshot 6 y 1 en snapshot 7 (AF875JB). No es una muestra. Detalle y el caso abierto en MOVILBA-154. Relevante para este item porque AF875JB es justo el dominio que 2026-08-28-movilba59-rutap-snapshot7-operational-dev.sql excluye a proposito: es el caso real donde un gate con max() elegiria ganador en silencio entre dos filas abiertas indistinguibles por fecha.
-
coder02 22:40 (from the 204 badge measurement, snapshot 10): grouping the wide table by raw_chasis_nro gives 3108 non-first events; upper+btrim (the v_vehiculo_cadena expression) 3109; upper + ALL whitespace stripped 3113. So 1 chassis string differs from another only by case/edge whitespace and 4 only by INTERNAL whitespace. The production chain key (upper(btrim(numero_serie_chasis))) merges the first and keeps the 4 apart. Whether those 4 are one chassis written two ways is a book question for the chain-identity work here; not touched tonight.
-
db02 2026-09-05, DEV: este item dice que nada garantiza una sola fila abierta por chasis EN EL LIBRO. Medido del lado de MovilBA, la condicion ya existe adentro de nuestra base: 86 grupos (vehiculo_id, fecha_alta) tienen MAS DE UNA fila ACTIVA Y ABIERTA de public.vehiculo_historial, 172 filas. Filed como MOVILBA-260 junto con las otras dos clases que MOVILBA-255 no repara (14 sin ninguna abierta, 5 fuera de forma). Por que le importa a 89: el riesgo que 89 describe - un max() eligiendo un ganador en silencio - ya no es hipotetico ni exclusivo del libro. Un lector que resuelva 'la fila abierta' de esos 86 vehiculos por max(id) o max(creado_en) elige uno de dos sin decirlo. El gate de tools/rutap-sync-prod.sql es el unico que hoy se planta en vez de desempatar, y su mensaje ('no id-order tie-break is applied') es exactamente la politica que 89 pide. NO EJERCITADO: no revise ningun consumidor para ver cual de ellos aplica un max() sobre esa poblacion. Eso es lo que le falta a 89 para dimensionarse.
-
AUDIT 2026-09-18 (audit-mba-l-cc): verificado contra dev/dev tip. Confirmado que rutap.projection_quarantines/projection_quarantine_rows y las dos vistas NO existen en DEV (query directa, 0 filas) - la condicion dura del blockedReason sigue vigente. Los dos .sql (2026-08-26-movilba-89-rutap-current-projection-gate.sql, 2026-08-26-movilba-112-89-history-import-gates.sql) y docs/design/movilba-89-per-chain-quarantine-design.md estan committeados en dev/dev. CORRECCION a la nota del 09-05 (event de wi-cli-venus, '86 grupos / 172 filas'): esa cifra es contra public.vehiculo_historial, tabla que ya no existe (renombrada, ahora rutap.vehiculo_historial_normalizado - confirmado via information_schema.tables). La misma forma de query contra la tabla VIGENTE hoy da 22 grupos / 44 filas - orden de magnitud distinto. No usar 86/172 para dimensionar trabajo nuevo; re-medir contra rutap.vehiculo_historial_normalizado antes de asignar a coder02. NO CIERRO: la condicion que blockea (tablas de cuarentena persistentes creadas ANTES de que 125 use resultados de cuarentena) sigue sin cumplirse. Routing de asignacion (coder02 salvo objecion) va a coder03 por DM separado, no es decision de audit.
-
Found docs/migrations/2026-09-18-movilba-89-projection-quarantine-DEV.sql on disk, untracked, already APPLIED live on DEV (verified: rutap.projection_quarantines, rutap.projection_quarantine_rows both empty base tables; rutap.v_rutap_latest_quarantined_chains, rutap.v_rutap_latest_projection_eligible both resolve). Matches design doc exactly: schema rutap only, FK prerequisite unique(snapshot_id,fila_excel) on rutap.rutap_rows confirmed already present (not re-added), reason_code CHECK enumerates all 6 doc values, chain_key_kind restricted to domain_provisional/physical_chain, quarantine_rows FK is MATCH FULL to rutap.rutap_rows(snapshot_id,fila_excel). One open flag in the file's own header: physical_chain_key format 'domain:' || dominio_norm is this file's literal choice, not stated as literal SQL in the design doc - needs audit/coder03 sign-off, one-view fix if wrong (no data yet). File has DEV env guard, pre/post gates, ensayo-by-default (-v apply=true). Shipped, not committed - drizzle/schema.ts not regenerated. Blocking condition for 125 (quarantine tables must exist before 125 uses quarantine results) is now satisfied on DEV. Handing to coder03 for introspect+commit; not closing 89 myself (db lane doesn't commit).
-
CORRECCION a la nota de db02 de 07:32, medida contra el checkout COMPARTIDO: el .sql SI esta committeado y el introspect SI corrio. dfc7a29d en dev/dev, v5.5.232, 2026-09-18 03:44 - trae la migracion, drizzle/schema.ts (projectionQuarantinesInRutap + projectionQuarantineRowsInRutap, ambas con sus CHECK y la unique(snapshot_id,physical_chain_key,reason_code)) y drizzle/relations.ts. El archivo se ve untracked SOLO en /home/rob/Documents/work/gcaba/movilba-web, que es el checkout compartido y esta atrasado; en el worktree dev el arbol esta limpio. Es la trampa ya registrada: un checkout atrasado miente en status/log. No hay nada que landear. Lo que esto NO cierra: 89 pide que los gates ASEVEREN 'una sola fila abierta por chasis' y aborten si el conteo no da 1. Eso sigue sin hacerse. Lo que quedo hecho es el ALMACEN de cuarentena, que es la condicion dura de MOVILBA-125, no el pedido del titulo de 89. 89 sigue blocked por su propio motivo, no por falta de commit. KEY-FORMAT: db02 levanto la objecion - physical_chain_key = 'domain:' || dominio_norm coincide con la prosa del disenio y el writer de 125 no existe todavia, asi que nada aguas abajo depende de el hoy. Queda como esta.
-
db04-mba-l-ca
-
db04-mba-l-ca 2026-09-24 04:05 -03 — SELECT-only installed-object check: DEV movilba_dev and PROD movilba both have rutap.projection_quarantines, projection_quarantine_rows, v_rutap_latest_quarantined_chains and v_rutap_latest_projection_eligible. The old blocked reason claiming these tables do not exist is obsolete. The one-open-period-per-chassis assertion and negative failure gate requested by this ticket were not exercised; remain blocked on MOVILBA-125 implementing and testing that gate, not on quarantine table creation. No DB write.
-
db04-mba-l-ca 2026-10-01 21:31 ART — Ya no hay dependencia externa: MOVILBA-125 es mi propio epic y las tablas/vistas de cuarentena existen en PROD y DEV según la medición instalada del 24/09. Tomo aquí el gate faltante: en el camino de ingesta/comparación del libro vigente, afirmar exactamente una fila abierta por chasis antes de todo max() que pueda elegir un ganador; probar con un caso mutado de dos filas abiertas que el comportamiento actual acepta o silencia y que el gate nuevo aborta. Se implementa antes del próximo import, bajo 125/89; no declarar control terminado con una corrida sólo verde. Sin escritura de DB en este cambio de estado.
-
2026-10-02 SELECT-only census: PROD snapshot 8 (2026-09-30-1305-parque-rutap.xlsx, md5 8512833be84d1568743d61b601179c6b) and DEV each have 1,602 open source rows with nonblank normalized chassis key, 1,602 distinct keys, zero duplicate-open chassis groups. A read-only mutant duplicating PROD source fila_excel 3939 (key 8AB368185LA149709) changes the duplicate-group count from 0 to 1, so the count predicate is discriminating. Installed rutap.proyectar_snapshot W4 detects >1 open row only by (vehiculo_id,dominio), marks those rows conflicto/elegible_actual=false, and contains no chassis-key branch. The archived 89 gate SQL checks chassis duplicates but tools/rutap-snapshot-import.py does not invoke it. Implementation requires preserving the later source rule in docs/reference/rutap-transform-rules.md: import every raw row and report source conflict, never reject the entire workbook. The current importer stages and projects in one transaction, so wiring a global RAISE there would roll back raw rows too. No DB/code writes made; next implementation must put a per-chassis eligibility/conflict check into projection without silently choosing a max() winner, and exercise old/new behavior on the duplicated-row witness.
-
was: Flaggeado por db02-mba-l-cc el 2026-08-20 08:10 midiendo prod, y por db03-mba-l-ca desde el otro lado. HOY se cumple: de los 1599 chasis vivos, los 1599 tienen exactamente UNA fila abierta (fecha_baja IS NULL) y un solo valor de Consumo en ella. Los 24 chasis que db03 marco con dos valores distintos los tienen en filas DISTINTAS EN EL TIEMPO - una cerrada y una abierta - que es exactamente para lo que sirve una fila cerrada. No hay conflicto. EL PROBLEMA ES QUE NADA LO GARANTIZA. Los gates de comparacion libro-vs-prod agregan con max() sobre las filas del chasis. Mientras haya una sola fila abierta, max() agrega un solo elemento y no elige nada. Si alguna vez aparece una SEGUNDA fila abierta para el mismo chasis, max() elige un ganador en silencio y el gate reporta verde igual: no existe ninguna asercion que diga cuantas filas abiertas hay. Es la misma forma que hizo que fecha_alta pareciera tener cuatro definiciones: el libro es un log append-only y 'el valor de este colectivo' no significa nada hasta que decis QUE FILA. QUE HACER: declarar la invariante del lado de la ingesta - una fila abierta por chasis - y hacer que los gates la ASEVEREN en vez de asumirla, abortando si el conteo de filas abiertas por chasis es distinto de 1. No es urgente: hoy se cumple en las 1599. Es un gate que reporta verde por suerte y no por medicion. Relacionado con MOVILBA-42 y MOVILBA-76.
-
2026-10-05 installed-path measurement (PROD snapshot8; SELECT-only): rutap.v_rutap_latest_norm has 1602 open rows with nonblank normalized chassis keys, 1602 distinct keys, 0 duplicate-key groups; projection_quarantines has 0 rows for snapshot8. Installed rutap.proyectar_snapshot W4 (prosrc lines 353-367) marks duplicates only by (vehiculo_id,dominio), not chasis_nro_norm. Installed rutap.reconciliar_snapshot creates rutap_reconcile_source via row_number PARTITION BY (vehiculo_id,dominio) at lines 55-72 and does not reference elegible_actual anywhere. tools/rutap-snapshot-import.py build_postgres is one transaction (docstring line 1018; materializer then projector then reconciler, commit line 1338). materializar_snapshot_raices writes public.vehiculos roots before W4. Therefore a W4-only chasis flag would NOT withhold current projection; all three writers and the importer transaction boundary need coordinated change for the per-chain quarantine contract. Required negative control: two open source rows with same normalized chassis but different dominio/vehiculo_id must leave both raw rows, emit a quarantine reason, create/update no derived current state for either, and not be silently ranked or physically deleted; unaffected chains still reconcile. No DB/code write. Do not install a global RAISE that rolls back raw ingestion.
-
Installed PROD body read 2026-10-05: materializar_snapshot_raices has two workbook-wide RAISE gates before writes (prosrc lines 110-120: >1 open event per normalized dominio; tied effective-current rank), while its root/VDC inserts consume all rutap_materializer_source rows (lines 154-189). The importer asserts filas_materializadas = len(data) at tools/rutap-snapshot-import.py:1211-1216. Therefore simply switching the materializer to v_rutap_latest_projection_eligible would make the importer abort on a quarantined row; quarantine requires a separate raw-row count vs eligible-root count and must not bypass raw-history projection. This is the concrete first writer/contract change for 89/125, not a standalone SQL duplicate check. No code/DDL write yet.
-
2026-10-05 writer-path check against installed PROD bodies (read-only): materializar_snapshot_raices prosrc md5 d11f9ae5f85e7a25b86f5d4fdf958a0e reads all raw rows, gates >1 open per dominio but not per normalized chassis, then DISTINCT ON(dominio_n) creates roots. proyectar_snapshot W4 only marks >1 open per (vehiculo_id,dominio) in normalized history. reconciliar_snapshot md5 6dbab81ec78cbdf13824cd5df6d3bebf builds rutap_reconcile_source with row_number partitioned by (vehiculo_id,dominio), independent of elegible_actual/quarantine, then deletes/updates from that selected source. Thus adding a chassis check only to W4 or to materializer without changing the downstream selected-source/count contract cannot implement the requested quarantine: one path silently picks a winner and the other aborts/rolls back raw staging. Required coordinated writer change: count all raw rows separately from eligible roots; persist/report per-chassis ambiguity; exclude its chains from root current projection AND reconcile source without deleting existing current data for those chains; keep all raw/normalized history; negative control with a duplicated open chassis must fail old behavior and show new quarantine. No code/DDL write or apply yet.
-
2026-10-06 PROD SELECT-only discriminating mutant on snapshot 8: copied one currently open AG451NP normalized row to synthetic AG451NPX with different vehiculo_id but identical normalized chassis, then applied installed reconciler row_number ordering per (vehiculo_id,dominio). Old rank selects 2 current rows; chassis-open group gate excludes both (0). This proves the existing per-domain ranking cannot detect a cross-domain same-chassis conflict. No persistent row/DDL changed. Additional writer trace: vehiculo_historial_normalizado.vehiculo_id IS NULLABLE, so all book rows can be projected even if root materialization withholds a quarantined domain. Materializer currently creates every root/VDC before projector, so quarantine detection must run before it and materializer must skip only current-root creation while still reporting all raw rows. Final MOVILBA-174 open-period/export gate must exclude quarantined chains or it will abort the import.
-
2026-10-06 implementation step, DRAFT ONLY / not installed: /data-lezama/movilba/migration-evidence/2026-10-06-movilba-89-quarantine-detector-DRAFT.sql SHA256 494e2fd7244552f29b608f84a324df460067db18cada1666c2c2508e9cb488ec. Function detectar_chasis_abierto_ambiguo detects duplicate open normalized chassis across domains, writes one domain-provisional header per affected domain and links ALL raw periods of each domain; competing JSON includes both sides. PROD rehearsal entirely under ROLLBACK: baseline snapshot8 -> 0 domains; synthetic duplicate of AE192MZ row3939 as ZZ999ZZ row999999 -> 2 quarantined domains, 2 conflicting open rows, 3 linked raw rows, 2 competitors in each header. Post-ROLLBACK verification: detector not installed, mutant raw row 0, quarantine headers 0. IMPORTANT: this function alone is not a fix and MUST NOT apply until materializer/projector/current reader/reconciler/importer gates consume the quarantine atomically. No PROD/DEV persistent write or shared-checkout edit.
-
2026-10-06 DEV leg after dbcaba restoration: same detector DRAFT SHA256 494e2fd7 rehearsed on movilba_dev snapshot20 under one ROLLBACK. Synthetic duplicate of AE192MZ Excel row3939 as ZZ999ZZ row999999 yields 2 quarantined domains, 2 conflicting open rows, 3 linked raw periods; each header names both competitors. Post-rollback verification: detector function absent, synthetic raw row absent, quarantine headers 0. PROD leg showed identical 2/2/3 earlier. This is still only the producer; materializer/projector/current reader/reconciler/importer consumption must be completed atomically before apply or audit-for-ship. No persistent DB write.
-
2026-10-06: coordinated DDL draft rehearsed ROLLBACK on PROD and DEV with a synthetic cross-domain duplicate-open VIN (AE192MZ/AH475BE). Detector: 2 quarantined domains, 2 conflicting open rows, 3 linked raw periods. Patched materializer preserved 5548 raw count, created 0 roots for the two domains; projector preserved 5548 normalized rows, marked all 3 witness periods ineligible; current-history view exposed 0 witness rows. Strict catalog trigger initially rejected the quarantine marker, so draft now permits only the exact linked chasis_abierto_ambiguo marker; all other unresolved catalogs remain rejected. Both rehearsals rolled back. Not applied; importer integration and old-body negative control remain.
-
2026-10-06 discriminating control completed in BOTH bases under ROLLBACK. Fixture: mutate existing open AH475BE row4052 to AE192MZ row3939 VIN (same model/propulsion, valid catalog/root). Old installed projector reports 0 conflicts and current reader exposes BOTH rows (2). Coordinated detector/writer draft: 2 quarantined domains, 2 conflicting opens, 3 linked raw rows; materializer still counts 5548 raw, projector writes 5548 normalized and marks all 3 witness periods ineligible; current reader exposes 0 witness rows; reconciler with apply=true retains both pre-existing roots and has 0 delete candidates. PROD+DEV each rollback; no persistent DB change. The strict catalog trigger needed a narrowly evidenced exception for exactly [chasis_abierto_ambiguo], discovered by a failed rehearsal, now included. Importer diff invokes detector before materializer and excludes quarantined opens from 174 export gate. Drafts: /data-lezama/movilba/migration-evidence/2026-10-06-movilba-89-coordinated-writer-DRAFT.sql plus quarantine-detector-DRAFT.sql; controls in evidencia/MOVILBA-89. This is still pending audit and coordinated apply/ship.
-
2026-10-06 additional rollback control after audit handoff: captured full to_jsonb preimages of both ambiguous public.vehiculos rows and VDC rows, ran patched reconciliar_snapshot(snapshot,true), checked both roots still present and 0 full-row-image differences. PROD and DEV both: retained_roots=2, changed_witness_roots=0, DO assertion PASS, ROLLBACK. This narrows the earlier retained-roots control: quarantine not only avoids DELETE, it avoids any update to either ficha.
-
2026-10-06 publication-scope trace: public.v_vehiculos_export reads public.v_vehiculos_hist_ultimo -> public.v_vehiculo_historial_normalizado_actual -> rutap.v_vehiculo_historial_actual. Thus the patched eligibility filter removes the quarantined imported CURRENT PERIOD from export/ficha period fields. The pre-existing public.vehiculos/VDC root itself intentionally remains unchanged and can still appear in one-row-per-vehicle exports; quarantine is not a physical vehicle deletion. DEV app-origin current rows remain eligible under the 09-24 user-data protection. This distinction is explicit so a missing period is not mistaken for a missing vehicle.
-
audit pass: Coordinated-writer DRAFT (drift guards, exact-anchor patches), detector DRAFT (final SHA 2765693a, re-diffed vs prior: only DROP TABLE->pg_temp.* changed), both negative controls, importer+docs diffs, all read in full
payload
{"scope":"Coordinated-writer DRAFT (drift guards, exact-anchor patches), detector DRAFT (final SHA 2765693a, re-diffed vs prior: only DROP TABLE->pg_temp.* changed), both negative controls, importer+docs diffs, all read in full","outcome":"pass","evidence":"Old-order ctrl: 2 current rows (defect reproduced). Coordinated ctrl: 2 quarantines, 3 rows retained+labeled, 0 current witnesses, 2 roots retained, strict-gate rejects unrelated conflict, 0 image drift. Importer gates on detector existing. ROLLBACK-only.","reportRef":null} -
2026-10-06 strict-gate negative control added and run under ROLLBACK in PROD+DEV: after the linked chasis_abierto_ambiguo marker is accepted, an UPDATE of the same normalized witness to conflictos=[not_quarantine] raises SQLSTATE 23514 (strict catalog trigger), caught only by the test subtransaction. This proves the new quarantine exception cannot silently admit arbitrary unresolved-catalog conflicts. Full-row root/VDC preimage control remains 0 differences in both bases.
-
audit pass: Post-apply repo copies: coordinated-writer-PROD-Y-DEV.sql + quarantine-detector.sql, diffed against the audited DRAFTs I already reviewed
payload
{"scope":"Post-apply repo copies: coordinated-writer-PROD-Y-DEV.sql + quarantine-detector.sql, diffed against the audited DRAFTs I already reviewed","outcome":"pass","evidence":"diff -u: only header comments (draft->applied wording) and \\i absolute-path -> \\ir relative-path changed. No logic/anchor/guard changes. Detector SHA 1a6f65a5dd38962bcac53cbb75b052bb98b17dbd82b96c70d2c538bca8d3d57d. Importer/docs diffs unchanged from prior PASS. No DB execution needed, applied+verified by db04 (1602 open chassis, 5548 normalized, q=0 post-apply).","reportRef":null} -
2026-10-06 APPLY after audit PASS: coordinated DDL draft SHA256 b0fb0e9c... including detector SHA 2765693a... committed to DB PROD movilba first, then DEV movilba_dev. Both postchecks: detector installed; materializer/projector/strict gate/current view/reconciler changed from pinned prior bodies; 1602 open rows = 1602 distinct chassis, 0 duplicate keys, 0 quarantine headers, 5548 normalized rows. PROD current-view owner movilba_owner, relacl {movilba_owner=arwdDxtm,svc_nextjs=r}; DEV owner movilba_user, relacl preserved. No source-data import or row update was part of this apply. Importer code/docs + repo migration copies and generated Drizzle mirror still await post-apply audit/SHIP. db03 informed to rerun import rehearsal only, no real import until code ships/gates pass.
-
audit pass: drizzle/schema.ts diff (1 line) added to post-apply verdict
payload
{"scope":"drizzle/schema.ts diff (1 line) added to post-apply verdict","outcome":"pass","evidence":"git diff confirms sole change: v_vehiculo_historial_actual view body gains AND (h.origen='app' OR h.elegible_actual IS TRUE), exact text of the m89_once patch applied to the installed view. relations.ts unchanged. Included in SHIP set.","reportRef":null} -
audit pass: docs/migrations/README.md new 2026-10-06 row: applied-order, SHA, count wording
payload
{"scope":"docs/migrations/README.md new 2026-10-06 row: applied-order, SHA, count wording","outcome":"pass","evidence":"SHAs match verified drafts: coordinated-writer b0fb0e9c (confirmed via sha256sum), detector 2765693a (confirmed earlier). Counts match db04's reported post-apply (1602 open chassis, 0 quarantines, 5548 rows) and my reviewed negative-control numbers (2 quarantines/3 periods/0 current pre-apply under ROLLBACK). PROD-first wording correct. Six-file SHIP set cleared.","reportRef":null} -
2026-10-06 SHIP sent to coder03 after scoped audit PASS on all six repo paths: two applied SQL artifacts, docs/migrations/README.md, docs/reference/rutap-transform-rules.md, drizzle/schema.ts, tools/rutap-snapshot-import.py. DDL is already live PROD+DEV; no new import was run by db04. Await exact-path commit/deploy PROD/DEV/pod before closing 89 or allowing db03 real import.
-
2026-10-06 DoD verified: DDL applied PROD then DEV with old/new discriminating duplicate-open-chassis witness (old selected two false current rows; new quarantines both and preserves every raw/history row and prior vehicle image). Six-path importer/SQL/docs/schema set committed ec2a5904 v5.6.177; independent /api/health read returns serviceId 25160 (=177) on PROD, DEV and OpenShift pod. Current 1140-book PROD rehearsal by db03: 5558/5558 projected, quarantine 0/0/0, conflicts 0, gate_not_null 0, ROLLBACK. Routine PROD import is db03's separate next step, not part of this closure.