Censo de cobertura de audit_log: que caminos de escritura emiten una fila y cuales no, porque con 1011 filas totales es el unico testigo de una edicion post-import y su cobertura no esta medida
Sale de MOVILBA-587, medido por db03-mba-l-cc el 2026-10-01. En DEV origen_ingreso protege entera la mitad CREADA (35 vehiculos app_dev, se estampa en el INSERT y no se re-estampa) pero no ve la mitad EDITADA. El unico testigo de una edicion post-import es audit_log: 243 de 2396 vehiculos ssot_import (10,1 por ciento) y 45 vdc tienen una entrada UPDATE posterior al import. Ese numero es un PISO, no la cuenta: audit_log tiene 1011 filas en total y nadie midio que caminos de escritura emiten una fila. vdc_archive ya fue descartado como segundo testigo -no tiene tag de origen y dispara tambien en las reescrituras del propio reconciliador, 36112 filas con motivo UPDATE, unas 15 por vehiculo-. Mientras la cobertura no este medida, cualquier arreglo del 592 que se apoye solo en origen_ingreso sub-protege, y una proteccion que se apoye en audit_log no se puede dimensionar. Entregable: por cada camino de escritura de vehiculo y de vdc -server action, ruta de API, importador, reconciliador, DDL a mano- decir si emite fila en audit_log, con el control positivo corrido, y nombrar lo que quedo SIN EJERCITAR.
Activity
-
db03-mba-l-cc 2026-10-01: Census of audit_log write-path coverage for vehiculo/vdc, measured DEV (movilba_dev). Code read in full for each path; one DB positive control run. Sole audit mechanism: `auditedOperation()`/`setTransactionActor()` in src/lib/audit-wrapper.ts. Inserts one audit_log row per operation, only if rows affected > 0. Documented caveat in the code itself: never route a soft-delete-rewritten DELETE through it, since a trigger-cancelled DELETE reports rowCount=0 and the row is wrongly suppressed as a no-op. AUDITED (audit_log row emitted): - vehiculoRepository.create() base vehiculos insert: UNAUDITED (no wrapper) - src/repositories/vehiculos.ts:615. Called only from services/vehiculos.ts:286 (plain alta, no vdc). - vehiculoRepository.createColectivo() vehiculos insert: AUDITED - repositories/vehiculos.ts:916-919. Called from services/vehiculos.ts:549. - vehiculoRepository.update() (plain vehiculo field edit, PUT /api/vehiculos/[id]): AUDITED - repositories/vehiculos.ts:741. - vehiculoRepository.softDelete() (DELETE /api/vehiculos/[id]): AUDITED - repositories/vehiculos.ts:817. This is an app-level UPDATE (sets borrado_en), not a physical DELETE, so the trigger-suppression caveat above does not apply here. - applyColectivoEditWithHistory() (colectivo edit form): AUDITED on both tables - repositories/vehiculos.ts:1497 (vehiculos), 1504-1505 (vehiculos_datos_colectivos), plus historial inserts 1519/1557/1587. NOT AUDITED (confirmed zero audit_log rows, DB-verified): - createHistorialRecord() - the shared write behind assignToEntidad (POST /api/vehiculos/[id]/entidad) and assignToLinea (POST /api/vehiculos/[id]/linea): plain db.transaction, repositories/vehiculos.ts:1178, no auditedOperation call anywhere in its body. Writes only to rutap.vehiculo_historial_normalizado. POSITIVE CONTROL run on DEV: 21 historial rows with normalizado_por='app-historial-record' (the literal this method writes) exist; 0 of them have any audit_log row referencing rutap.vehiculo_historial_normalizado. Contrast: 95 app-origin historial rows written via the audited createColectivo/applyColectivoEditWithHistory path (normalizado_por<>'app-historial-record') DO have matching audit_log rows - confirms audit_log itself is not silently failing; the gap is specific to this one write path. This explains MOVILBA-349: motivo_id is NULL on both the 21 endpoint-written rows and the 56 form-written rows, so it never distinguished the paths - but audit_log coverage does: the endpoint path has none, the form path is fully covered. - Importer (tools/rutap-snapshot-import.py): zero WRITES to audit_log anywhere. The two matches at lines 755/760 are READS, inside preparar_dev_sin_tocar_pruebas() (DEV-only predicate protecting rows a user later touched) - they query audit_log, they do not write it. - rutap.reconciliar_snapshot() (2026-09-19-movilba-516 migration, read in full, lines 1-897): zero audit_log INSERTs anywhere in the body. The only audit_log statement is a DELETE (line 717-721) that purges audit_log rows belonging to vehicles the function is about to physically delete - cleanup, not a write recording the reconciler's own action. - Manual DDL: by construction, any hand-run SQL against vehiculos/vdc outside the app's service layer has no audit_log emission - there is no DB-level trigger that writes audit_log (confirmed: the six triggers the reconciler disables are soft-delete/archive/append-only guards, none call an audit_log insert). API routes (src/app/api/vehiculos/**): all five vehiculo/vdc routes checked (route.ts, [id]/route.ts, [id]/entidad, [id]/linea, [id]/linea/current) call only vehiculoService/vehiculoRepository methods - no direct db write bypassing the service layer. So API-route coverage reduces to the repository-method coverage above; no separate gap at the route layer. UNEXERCISED / not measured this pass: - entidades/personas/choferes write paths - out of this ticket's vehiculo+vdc scope. - PROD audit_log coverage not independently re-measured; code is identical (one repo, one deploy), so the DEV-measured code-path gaps apply to PROD by construction, but PROD's actual row-level positive control (does PROD also show 0-coverage assignToEntidad/Linea rows) was not run - no PROD credential used this pass, SELECT-only would have sufficed but wasn't executed. - Whether any OTHER service method besides the ones named calls createHistorialRecord (grep showed only assignToEntidad/assignToLinea as service-level callers, but a second direct repository-level caller was not separately ruled out beyond that grep). - The validadoras_historial audit path (out of vehiculo/vdc scope, not checked). Bottom line for MOVILBA-587/592: audit_log is a reliable witness for vehicle field edits, soft-deletes, and colectivo-form edits, but is BLIND to entidad/linea reassignment (21 DEV rows with zero coverage) and to anything written outside the app (importer, reconciler, manual DDL - all zero audit_log write capability by construction). Any fix leaning on audit_log as "the" post-import edit witness must account for this gap or it will undercount edits the same way origen_ingreso undercounts them.
-
completed