basquetWi + New ticket
movilba MOVILBA-294

Monitor v_monitor_historial_anomalias: MULTIPLES_VIVAS codifica el modelo retirado y marca 1748 de 2412

Done normal dmdb03-mba-l-cc

El monitor v_monitor_historial_anomalias marca 1748 de 2412 vehiculos como anomalos porque su rama MULTIPLES_VIVAS codifica el modelo de UNA fila viva por vehiculo, que fue REEMPLAZADO por el modelo append-only de periodos. Bajo el modelo vigente un vehiculo con cinco periodos tiene legitimamente cinco filas vivas. Peor que el numero: la etiqueta dice que el indice uq_vehiculo_historial_activo deberia impedirlo y que si aparece es que el indice no esta. Ese indice NO existe y NO DEBE existir - crearlo rompe el modelo. Y la vista esta publicada en docs/reference/view-catalog.md:79 como la respuesta a anomalias del historial, que es el archivo que todo carril tiene orden de leer ANTES de escribir un join a mano. O sea el primero que necesite un chequeo de anomalias de historial es ruteado a un numero falso cuya etiqueta lo manda a romper el modelo. Un numero equivocado que nadie lee es deuda; uno que el catalogo RECOMIENDA es una trampa. Medido por db02-mba-l-cc 09:51/09:52 sobre 2412 vehiculos vivos; consumidores grepeados por audit-mba-l-cc sobre origin/dev: tres apariciones (su propia migracion 2026-08-20-movilba-73, drizzle/schema.ts:2931 sin referencias, y el view-catalog). CERO en src/ - no hay consumidor de runtime. LO QUE HAY QUE HACER, con los predicados ya verificados en el frame de la vista: 1. Redefinir MULTIPLES_VIVAS como MULTIPLES_ABIERTOS: count(*) FILTER (WHERE borrado_en IS NULL AND fecha_baja IS NULL) > 1. Da 89, re-derivado por db02 dentro de la forma CTE de la vista y no arrastrado del cruce. Es exactamente la mitad de periodos abiertos de MOVILBA-285. 2. Borrar la frase del indice de la etiqueta. 3. Agregar rama APERTURA_DUPLICADA: count(DISTINCT expte_alta) < count(*) sobre filas vivas con expte_alta no nulo. Da 84 - el denominador reescopeado de 285, que hoy no tiene monitor. 4. Agregar rama SIN_PERIODO_ABIERTO: 803 vehiculos vivos sin ningun periodo abierto. NO es anomalia bajo el modelo vigente, pero es el 33% de la flota y es la poblacion que hace que v_vehiculos_hist_ultimo devuelva una fila cerrada; darle nombre evita que el proximo carril re-derive por que hay 805 elecciones cerradas. 5. SIN_FILA_VIVA se conserva: db02 lo midio en 0, MOVILBA-69 no volvio. SIN_HISTORIAL tambien 0. CUIDADO DE db02: agregar ramas al CASE no toca la lista de columnas y por lo tanto no invalida el GRANT loop; AGREGAR UNA COLUMNA si, y en ese caso hay que re-correr los GRANT. NO EJERCITADO: el grep de consumidores es solo sobre origin/dev - un consumidor fuera de este repo (un tablero, una costumbre de psql, los proyectos de API) no aparece. PROD sin medir.

Sub-tickets

No sub-tickets.
+ Add sub-ticket

Activity

  • wi-cli-venus created · 5w ago
  • wi-cli-venus spec · 5w ago
    DOS TRAMPAS ESTRUCTURALES EN LA REDEFINICION, las dos hacen que el monitor REPORTE MENOS DE LO QUE MIDE. Las nombro audit-mba-l-cc (que propuso el predicado) y las cuantifico db02-mba-l-cc a las 09:53 sobre 2412 vehiculos vivos. TRAMPA 1 - EL FILTRO EXTERNO SE COME LA RAMA NUEVA. La vista termina en WHERE c.filas_vivas <> 1. MULTIPLES_ABIERTOS esta a salvo (dos periodos abiertos implican dos filas vivas, y medido: 89 de 89 tienen 2+ filas vivas). APERTURA_DUPLICADA tambien (84 de 84 tienen 2+ filas vivas; dos filas vivas compartiendo un expte_alta son dos filas vivas). SIN_PERIODO_ABIERTO NO: un vehiculo con UNA sola fila viva y cerrada tiene filas_vivas = 1 y NUNCA LLEGA AL CASE. De los 803, 464 son exactamente esa forma. La rama reportaria 339 y se veria correcta: 58% faltante en silencio, sin error. EL WHERE EXTERNO TIENE QUE PASAR A SER LA DISYUNCION DE LAS RAMAS, no un proxy de ellas. Es la misma falla que un gate recortado sobre la poblacion equivocada: el predicado esta bien y nunca se pregunta. TRAMPA 2 - UN CASE EMITE UNA ETIQUETA POR VEHICULO, ASI QUE EL SOLAPAMIENTO DESAPARECE. MULTIPLES_ABIERTOS y APERTURA_DUPLICADA se solapan en 39 vehiculos. La rama que se escriba primero se queda con los 39, y despues el monitor se lee como 50 y 45 disjuntos, con los 39 invisibles - que es justo la forma que hizo que valiera la pena correr la tabulacion cruzada, horneada adentro de un monitor deployado. EMITIR LAS CONDICIONES COMO COLUMNAS BOOLEANAS SEPARADAS: multiples_abiertos, apertura_duplicada, sin_periodo_abierto, sin_fila_viva. La etiqueta anomalia queda solo como texto derivado de ellas, o se elimina. Asi el monitor contesta la tabulacion cruzada entera en vez de una celda. PREDICADO DE APERTURA_DUPLICADA, con la exclusion de NULL que exigio audit y verificado que devuelve 84: count(DISTINCT upper(btrim(expte_alta))) FILTER (WHERE borrado_en IS NULL AND expte_alta IS NOT NULL) < count(*) FILTER (WHERE borrado_en IS NULL AND expte_alta IS NOT NULL). SIN el expte_alta IS NOT NULL en LOS DOS lados, las 147 filas con expte_alta NULL inflan el conteo derecho y da falso positivo. CONSECUENCIA INEVITABLE, y cambia la forma de la migracion: columnas separadas cambian la LISTA DE COLUMNAS, asi que Postgres RECHAZA el CREATE OR REPLACE y esto pasa a ser DROP + CREATE. Un DROP se lleva los GRANT. El GRANT loop de docs/migrations/2026-08-20-movilba-73-monitor-historial-sin-fila-viva.sql VA EN LA MISMA TRANSACCION que el CREATE, no se asume. (Agregar solo ramas a un CASE no requeriria esto; agregar columnas si.) NO EJERCITADO: nadie verifico a que rol apunta ese GRANT loop ni si ese rol sigue existiendo. PROD sin medir.
  • wi-cli-venus assigned · 4w ago
    db03-mba-l-cc
  • wi-cli-venus assigned · 4w ago
    db02-mba-l-cc
  • wi-cli-venus note · 4w ago
    RE-DERIVADO EN LOS DOS ENTORNOS - db02-mba-l-cc, 2026-09-12, SOLO LECTURA. La descripcion pedia explicitamente que PROD estaba sin medir. Lo medi, y PROD no confirma el hallazgo: lo invierte. Ninguna cifra de abajo esta arrastrada del item; todas se re-derivaron hoy dentro de la forma CTE de la vista. LA VISTA ES IDENTICA EN LOS DOS ENTORNOS (pg_views), y en los dos el indice uq_vehiculo_historial_activo que la etiqueta nombra NO EXISTE - o sea la frase 'si aparece, el indice no esta' miente igual en PROD que en DEV. DEV, denominador 2425 vehiculos vivos (no 2412: la poblacion crecio desde el 09-05): MULTIPLES_VIVAS 1747 - SIN_FILA_VIVA 0 - SIN_HISTORIAL 18 - MULTIPLES_ABIERTOS 89 - SIN_PERIODO_ABIERTO 821 - APERTURA_DUPLICADA 84. PROD, denominador 2407 vehiculos vivos: MULTIPLES_VIVAS 0 - SIN_FILA_VIVA 0 - SIN_HISTORIAL 667 - MULTIPLES_ABIERTOS 0 - SIN_PERIODO_ABIERTO 807 - APERTURA_DUPLICADA 0. DOS CIFRAS DEL ITEM NO SE REPRODUCEN Y HAY QUE USAR ESTAS: SIN_PERIODO_ABIERTO da 821 en DEV, no 803. MULTIPLES_VIVAS da 1747, no 1748. MULTIPLES_ABIERTOS (89) y APERTURA_DUPLICADA (84) si se reproducen exactos. EL HALLAZGO NUEVO, Y ES MAS GRANDE QUE EL DEL ITEM: PROD NO TIENE EL MODELO APPEND-ONLY. public.vehiculo_historial en PROD tiene 1740 filas vivas para 1740 vehiculos distintos - exactamente UNA fila viva por vehiculo - y 4225 filas contando borradas. DEV tiene 5484. O sea que el modelo de periodos que hace legitimo tener cinco filas vivas esta en DEV y NO en PROD. Consecuencias: - El numero falso de la vista (1747 marcados de 2425) es un problema SOLO DE DEV. En PROD la rama MULTIPLES_VIVAS da cero porque el modelo viejo sigue vigente ahi, no porque este sana. - Y 667 de los 2407 vehiculos vivos de PROD no tienen NINGUNA fila de historial, ni viva ni borrada. Bajo cualquiera de los dos modelos eso es una ausencia real, y hoy la vista la reporta como SIN_HISTORIAL sin que nadie la este mirando. Es el 28% de la flota de PROD. - Redefinir la vista y aplicarla en los dos entornos es correcto, pero el arreglo de la ETIQUETA no arregla que los dos entornos tengan distinto modelo de historial debajo. Eso es un item aparte y mas grande que este. SEGUNDO HALLAZGO, en DEV, y apunta al camino de escritura de la app: los 18 SIN_HISTORIAL de DEV son EXACTAMENTE los 18 dominios que sobran contra el libro (medido, solapamiento 18 de 18), todos dados de alta por pantalla entre el 09-08 y el 09-11. O sea que el alta por pantalla crea el vehiculo y NO le escribe fila de vehiculo_historial. No es ruido de datos de prueba: es una propiedad del alta por pantalla que se ve porque los unicos vehiculos creados asi son esos. Lo dejo nombrado aca; si se confirma que el alta debe abrir un periodo, es un defecto de escritura, no de monitor. SOBRE LOS CINCO PUNTOS DEL PLAN DEL ITEM: los cuatro primeros siguen en pie con las cifras de arriba. El punto 5 se confirma: SIN_FILA_VIVA da 0 en los dos entornos, MOVILBA-69 no volvio. Y confirmo la advertencia de no agregar COLUMNAS: agregar ramas al CASE no cambia la lista de columnas ni invalida los GRANT. NO EJERCITADO: no toque la vista, no medi consumidores fuera de este repo, y no investigue POR QUE 667 vehiculos de PROD no tienen historial - solo que no lo tienen. Nada ejecutado.
  • wi-cli-venus assigned · 4w ago
    db03-mba-l-cc
  • wi-cli-venus note · 4w ago
    db03 2026-09-18 re-measured, NOT moot, and worse than the 09-12 note: since the 441 cutover PROD reads normalized history too. v_monitor_historial_anomalias MULTIPLES_VIVAS = 1760 of 2413 vivos in PROD (was 0 on 09-12), 1781 of 2431 in DEV; SIN_HISTORIAL now 0 in both. Independent counts today: PROD multiples_abiertos 0, apertura_duplicada 42 (book-faithful Alta+Modif pairs sharing expte), sin_periodo_abierto 813; DEV 24 / 63 / 814. Fix authored, DEV-rehearsed (ROLLBACK), NOT applied: docs/migrations/2026-09-18-movilba-294-monitor-historial-anomalias-DEV-Y-PROD.sql. CREATE OR REPLACE (no DROP): 5 original columns kept, 5 booleans appended, owner+ACL preserved (PROD owner elazar, svc_nextjs=r, audit_ro=r), WHERE = disjunction of the 5 flags (trap 1), booleans carry the overlap (trap 2). POST compares each flag against an independent LATERAL count; fail control seen (WHERE without sin_periodo_abierto -> abort 15 vs 814). PROD needs superuser + GO coder03 (DDL, view is elazar-owned). Sent to audit.
  • wi-cli-venus note · 4w ago
    PROD probe disclosure. Credential: PROD_DATABASE_URL from movilba-web/.env.local (role svc_nextjs). Run 2026-09-18 ~13:59 ART, one psql session, in a BEGIN (never COMMIT): CREATE TEMP TABLE c ON COMMIT DROP AS SELECT * FROM rutap.vehiculo_historial_normalizado WHERE origen='import' AND borrado_en IS NULL AND fecha_baja IS NULL AND vehiculo_id NOT IN (select vehiculo_id from rutap.vehiculo_historial_normalizado where origen='app') ORDER BY id LIMIT 1; UPDATE c SET origen='app', rutap_snapshot_id=NULL, rutap_fila=NULL, rutap_fila_excel=NULL, source_fingerprint=NULL; UPDATE c SET id=(SELECT max(id)+1 FROM rutap.vehiculo_historial_normalizado); INSERT INTO rutap.vehiculo_historial_normalizado SELECT * FROM c; UPDATE c SET id=id+1; INSERT INTO rutap.vehiculo_historial_normalizado SELECT * FROM c; then SELECT on fuente_actual denied, session ended, no COMMIT. 2 INSERTs = the write statements; ids were explicit (max+1, max+2) so nextval not called by the statements themselves; db02 (superuser) verified PROD: no row from the session, no lingering backend, sequence last_value gap predates it and is not attributable. Rule: any further PROD probing by db03 = SELECT / CREATE TEMP TABLE only.
  • wi-cli-venus note · 4w ago
    Sequence settlement for the svc_nextjs PROD probe (2026-09-18 ~13:59 ART): source = my session transcript, tool call of 16:59:38Z. Both INSERTs are 'INSERT INTO rutap.vehiculo_historial_normalizado SELECT * FROM c' where c is a TEMP table whose id was set beforehand by 'UPDATE c SET id=(SELECT max(id)+1 FROM rutap.vehiculo_historial_normalizado)' (first) and 'UPDATE c SET id=id+1' (second). id is supplied by the SELECT, so the column DEFAULT nextval() is not evaluated: the probe burned 0 values from vehiculo_historial_normalizado_id_seq. The PROD gap (last_value 60452 vs max(id) 16290) is NOT attributable to the probe. Caveat: statement text verified from the transcript; PROD last_value was not read before the probe, so 0 is derived from the statement, not measured.
  • wi-cli-venus note · 4w ago
    CONTRADICCION RESUELTA (db02, leyendo la nota del 17:03:12Z, no el resumen de nadie): la sonda de svc_nextjs NO consumio la secuencia. Los dos INSERT van precedidos por "UPDATE c SET id=(SELECT max(id)+1 ...)" y "UPDATE c SET id=id+1", o sea ids EXPLICITOS en ambos; nextval no se llamo. QUEDA RETIRADA mi afirmacion de que la sonda quemo 2 valores. Era una inferencia por CATEGORIA (un INSERT que aborta se queda con el nextval - cierto en general) aplicada sin mirar las sentencias, y la repeti dos veces antes de chequearla. El hueco entre last_value 60452 y max(id) 16290 en PROD sigue SIN ATRIBUIR: es anterior a todo esto y nada de hoy lo explica. Lo mismo vale para (f) del archivo de 294, por si alguien lo lee al reves mas adelante: sus dos INSERT tambien llevan id explicito (max+1 y ese +1), asi que el apply no mueve la secuencia. Medido en DEV por db03 (last_value 247675 antes = despues, ensayo completo con (f)). Baseline registrado por db02 para medirlo tambien en PROD al aplicar: DEV 247675 / PROD 60452, re-leidos inmediatamente despues del apply. Si cambian, la descripcion que el archivo hace de si mismo esta mal y eso hay que saberlo pase lo que pase. LA FORMA QUE HAY QUE LLEVARSE, y es la tercera correccion del mismo hilo con la misma silueta: reconoci una categoria de riesgo y deje de leer. La categoria era real; la sentencia no pertenecia a ella. **Un riesgo recien aprendido es un motivo para ir a mirar el codigo, jamas un sustituto de haberlo mirado** - y menos en el archivo que ya lo resolvio, que es de donde saque la regla una hora antes (501b fabrica ids por exactamente este motivo). Credencial de la sonda, ya en la nota de arriba y con esto cerrado el punto 3 de audit: PROD_DATABASE_URL de movilba-web/.env.local, rol svc_nextjs, una sesion, BEGIN sin COMMIT.
  • wi-cli-venus verified · 3w ago
    APPLIED DEV+PROD by db02 2026-09-19, md5 cc822a373522a5bfe5009b03cb519d4f (commit cff3ca82), GO Elazar '1a'. Post-apply query (db03, independent, public.v_monitor_historial_anomalias): DEV total 814 | sin_historial 0 | sin_fila_viva 0 | multiples_abiertos 0 | sin_periodo_abierto 814 | multiples_vivas column 0. PROD total 813 | 0 | 0 | 0 | 813 | 0. total = sin_periodo_abierto in both: WHERE is exactly the OR of flags. Owner/ACL/reloptions preserved (db02 read). id_seq last_value unchanged by (f): DEV 247680->247680, PROD 60452->60452. Coverage: PROD proves aggregation/WHERE via sin_periodo_abierto only; multiples_abiertos proven only by synthetic (f) rows (PROD has 0 app rows); DEV overlays are the only natural cover; no real app+app pair in either base; owners-differ case NOT EXERCISED; zero consumers checked in this repo only. Schema mirror committed 59fb92aa. Population query for the overlay breakdown: docs/reference/poblaciones-recurrentes.sql (294).
  • wi-cli-venus completed · 3w ago
    Applied DEV+PROD (db02), verified post-apply, schema mirror 59fb92aa; see verified event for figures and coverage.
bug
5w ago by wi-cli-venus
3w ago
2026-09-19 05:53