v_vehiculos_detalle.historial: tres defectos en el mismo subquery JSON
Encontrados por db02-mba-l-cc el 2026-09-04 leyendo la definicion, DEV. **Ninguno lo arregla el reload**: son definicion de vista, no datos. Los tres estan en el mismo `jsonb_agg` de la columna `historial`. **1. LA VISTA NO EMITE NINGUNA FECHA DE PERIODO.** Las 13 claves que emite son: id, expediente, observaciones, estadoId, estadoNombre, entidadId, entidadNombre, lineaId, numeroLinea, cambios, creadoEn, motivoId, motivoNombre. **No hay `fecha_alta` ni `fecha_baja`.** La UNICA fecha es `creadoEn` = `vh.creado_en`, que es COLUMNA DE AUDITORIA. Una ficha que muestre un rango de periodo no lo puede sacar de aca, y si renderiza `creadoEn` como fecha del periodo esta mostrando auditoria como hecho de negocio - regla dura (reference_audit_columns_are_not_business_dates). Es la version fuerte del `COALESCE(fecha_baja, borrado_en::date)` de MOVILBA-225. ARREGLO: agregar `fechaAlta` = vh.fecha_alta y `fechaBaja` = vh.fecha_baja. **2. ORDENA POR `creado_en`.** `ORDER BY vh.creado_en DESC, vh.id DESC`. Commons 12: la fila actual es el evento de NEGOCIO mas reciente, nunca el escrito mas tarde, y ordenar historial por `creado_en` esta nombrado como lo que NO hay que hacer. Hoy lo que aparece primero en la ficha esta ordenado por hora de escritura. ARREGLO: `ORDER BY vh.fecha_alta DESC NULLS LAST, vh.id DESC`. **`DESC` implica `NULLS FIRST` en Postgres**, de ahi el `NULLS LAST` explicito. **3. NO FILTRA `borrado_en`.** El subquery es `WHERE vh.vehiculo_id = v.id` y nada mas. Comprobado: el elemento 4804 de AI239RS tiene `borrado_en` = 2026-08-19 y viene en el JSON igual. Es MOVILBA-170 reproduciendose por este camino tambien, y es el mecanismo general por el que un vehiculo muestra mas tarjetas que periodos vivos tiene. ARREGLO: `AND vh.borrado_en IS NULL`. **DEPENDENCIA DE ORDEN, no obviarla:** hoy `vehiculo_historial.borrado_en` esta SOBRECARGADO - 2309 filas guardan la Fecha Baja de RUTAP ahi, no un borrado (MOVILBA-83). Filtrar por `borrado_en IS NULL` ANTES del reload esconde periodos cerrados legitimos. **El punto 3 se aplica DESPUES del reload de MOVILBA-227**, cuando `borrado_en` vuelva a significar solo borrado. Los puntos 1 y 2 se pueden aplicar ya. CONTROL POSITIVO al aplicar: para un vehiculo con periodos cerrados, la cantidad de elementos del JSON tiene que BAJAR, y `fechaAlta` tiene que venir poblada. Si no baja, el filtro no esta haciendo nada. CUIDADO AL TOCAR: `creadoEn` lo consumen componentes vivos (InstalacionHistorial.tsx:178, LineaEntidadHistorial.tsx:167/195/217, EntidadAssignmentHistory.tsx). NO sacar la clave; agregar las de negocio y que la UI pase a usarlas.
Activity
-
coder-mba-l-ca
-
CUARTO DEFECTO del mismo subquery JSON (coder-mba-l-ca lo encontro; ese carril no tiene 'wi' en PATH, lo cargo yo). **`v_vehiculos_detalle.historial` emite `motivoNombre` desde un LEFT JOIN sobre `vehiculo_historial.motivo_id`, y esa columna esta 4341/4341 NULL** - medido por db02 en DEV, 2026-09-04. Nunca se poblo, ni una vez. Y el libro RUTAP no trae ninguna columna motivo de donde poblarla. O sea la UI presenta como dato un campo que es NULL en el 100% de las filas, en todos los elementos de todos los arrays de historial que renderiza. Es exactamente la misma clase que los defectos 1 y 2 de este ticket (la vista no emite fecha_alta/fecha_baja, y ordena por creado_en): **un campo que la pantalla muestra como si fuera informacion**. DECISION PARA EL LOADER (MOVILBA-227): `motivo_id` se deja NULL. No es un hueco del loader - no hay fuente. Si la columna se dropea o no es una decision aparte y NO es de este reload. Relacionado: la regla de vocabulario es `Expediente` + `motivo`, o sea el termino existe en el modelo; lo que no existe es el DATO.
-
coder02 09-05: the 'Historial de cambios' card image Elazar flagged (2026-08-20 14:45 ART, AG358KX) is a RETIRED build, dated from git: 'Tramite del:' was removed by 2d76d855 (MOVILBA-99) committed 2026-08-20 15:17:56, 32 minutes after the screenshot; 'Cambios:' became 'Cambios detectados por MovilBA:' in 86061e89 (2026-08-25 12:07). Neither old label exists anywhere on dev/dev - no third surface. Current render distinguishes a closed period from an open one: ExpedienteForm.tsx L282-290 prints 'Fecha de Alta: X - Fecha de Baja: Y' on every card, em dash when null, so the zero-length period of book row 1044 (opens and closes 2026-03-09) shows both dates rather than reading as open. PDF shares the same reader since aa6d6cb4. Not exercised: a render of AG358KX itself.
-
RENDERED, proxy on dev01 v5.4.181, AG358KX = /vehiculos/4453, text answers not image: 6 cards; dates 21/04-abierta, 09/03-21/04, 09/03-09/03, 12/12-18/02, 18/11-12/12, 08/07-18/11; the zero-length period shows an explicit Fecha de Baja and cannot read as open (the open card is the only one with a dash); 'Interno: De: 61 A: 23' present on it with Carroceria/Aire/Consumo/Cabina lines; NO duplicate date-pair cards; neither 'Cambios:' bare nor 'Tramite del:' anywhere. db02: the card's CONTENT was correct in snapshot 4 (row 975) and is identical in snapshot 10 (row 1044) - the image is a retired SKIN over correct data, not a wrong image. Split check requested by audit (ficha still takes Fecha de Alta from the legacy view via getFechaAltaMasReciente): wide vs legacy max(fecha_alta) over ALTA rows, 2280 vehicles comparable, 0 discrepancies, 0 one-sided - the two relations agree today, so step 3 removes the split without reconciling values.
-
Non-comparable population characterized (db02), closing audit's coverage line: of 2406 dominios in the wide table, 2280 have a dated ALTA row and BOTH relations hold exactly those same 2280, zero on either side alone. The excluded 126 = 121 dominios whose only tramite in the book is Modificacion + 5 with no tramite at all. The exclusion is a property of the book, not of the comparison.
-
unassigned
-
db03-mba-l-cc
-
Rehearsed PROD fix (ROLLBACK, SUPERUSER_ELAZAR_URL): all 3 applicable defects in v_vehiculos_detalle.historial's jsonb_agg fixed together - MOVILBA-227's reload (done 09-05) already replaced the legacy vehiculo_historial table; public.v_vehiculo_historial now sources rutap.v_vehiculo_historial_normalizado_fuente_actual, and the borrado_en/fecha_baja overload that blocked point 3 is gone (checked live 2026-09-28: 0/5545 PROD, 0/5587 DEV rows have borrado_en set). So the ticket's own stated dependency is cleared and points 1+2+3 ship in one migration instead of being split. Migration: docs/migrations/2026-09-28-movilba-232-vdetalle-historial-fechas-orden-borrado.sql. (1) adds fechaAlta/fechaBaja keys to the jsonb_build_object. (2) ORDER BY vh.fecha_alta DESC NULLS LAST, vh.id DESC (was creado_en DESC - business-event order per commons 12, not write-time). (3) adds AND vh.borrado_en IS NULL to the subquery WHERE. creadoEn and motivoId/motivoNombre keys left untouched per the ticket's own caution (creadoEn consumed by InstalacionHistorial.tsx, LineaEntidadHistorial.tsx, EntidadAssignmentHistory.tsx; motivoNombre's 100%-NULL state is this ticket's own point 4, already decided as no-source/not-a-defect, out of scope here). Rehearsed clean: 60 cols/2417 rows unchanged, fechaAlta now populated (sample vehiculo 3344/AA013AA). Honest gap: 0 vehicles currently have a borrado_en-marked historial row in PROD, so point 3's count-drop control has no live case to demonstrate today - the filter still ships (correctness fix independent of current data), noted rather than fabricated. Body md5-pinned to installed pre-change state (6a7a05bfb3397e1af588af8fb28cc7e2, post-MOVILBA-174's own change to this same view). Fixes something broken, no GO. Ready for audit PASS.
-
audit pass: md5 guard verified vs live PROD (matches). Adds fechaAlta/fechaBaja, reorders by fecha_alta DESC, filters borrado_en. Point-3 control gap disclosed not concealed. Point-2 ordering unexercised, low-risk. Row/col sanity present.
payload
{"scope":"md5 guard verified vs live PROD (matches). Adds fechaAlta/fechaBaja, reorders by fecha_alta DESC, filters borrado_en. Point-3 control gap disclosed not concealed. Point-2 ordering unexercised, low-risk. Row/col sanity present.","outcome":"pass","evidence":"file full read; own psql: PROD viewdef md5 matches pin; DEV md5 differs (pre-174), guard correctly self-gates DEV","reportRef":null} -
Applied to PROD, audit PASSed. v_vehiculos_detalle.historial now emits fechaAlta/fechaBaja, orders by fecha_alta DESC NULLS LAST/id DESC, filters vh.borrado_en IS NULL. 60 cols/2417 rows unchanged. Not yet ported to DEV - audit flagged DEV's viewdef md5 is still pre-MOVILBA-174, so 174 must land on DEV first (its md5 guard will self-abort otherwise).
-
db04-mba-l-ca
-
db03-mba-l-cc / db
-
Los 3 defectos ya fueron corregidos y APLICADOS a PROD (09-28, audit PASS): fechaAlta/fechaBaja en el jsonb, ORDER BY fecha_alta DESC NULLS LAST/id DESC, filtro borrado_en IS NULL. Unico pendiente que dejo abierto la nota del 09-28 era el port a DEV, bloqueado entonces porque el viewdef de DEV todavia era pre-174. Verificado hoy: DEV YA TIENE los tres cambios (pg_get_viewdef confirma 'fechaAlta'/'fechaBaja', mismo ORDER BY, mismo filtro borrado_en, identico a PROD byte a byte en el bloque del jsonb_agg) - el port aterrizo junto con el de 174 que tambien verifique esta sesion. Nada pendiente, cierra sin escritura.
-
audit pass: md5(viewdef) PROD vs DEV + key grep
payload
{"scope":"md5(viewdef) PROD vs DEV + key grep","outcome":"pass","evidence":"v_vehiculos_detalle viewdef md5 identical PROD/DEV (ef7570b7...); fechaAlta/fechaBaja keys present in both - byte-identical as claimed","reportRef":null} -
audit pass: docs/migrations/README.md hunk, DEV-convergence wording
payload
{"scope":"docs/migrations/README.md hunk, DEV-convergence wording","outcome":"pass","evidence":"already independently confirmed this session: viewdef md5 byte-identical PROD/DEV","reportRef":null}