basquetWi + New ticket
movilba MOVILBA-335

Editar solo observaciones abre un periodo de negocio en el historial

Done normal dmdb03-mba-l-cc

Hallazgo de db02-mba-l-cc el 2026-09-07 23:00, leido de `git show dev:src/repositories/vehiculos.ts`, mientras verificaba el diseño de un control para MOVILBA-331. No es un bug demostrado: es una DECISION que nadie registro haber tomado. QUE PASA: `changes` trata por igual a todos los campos de `colectivoValues` (el loop de `:1019-1021`), y `observaciones` es uno de ellos (`:976`). Entonces editar UNICAMENTE una nota cosmetica pasa el gate de `:1026`, cierra el periodo abierto con una `fecha_baja` y abre un sucesor con `fecha_alta` nueva en `rutap.vehiculo_historial_normalizado`. POR QUE IMPORTA: el historial pasa a decir "algo cambio el 07/09" cuando no cambio nada de entidad, linea, estado ni expediente. Contra el estandar de custodio fiel -que es por lo que se nos juzga- **un periodo es un hecho de NEGOCIO; una nota no lo es**. El libro RUTAP no registra un tramite porque alguien corrigio una falta de ortografia en una observacion. CONSECUENCIA MEDIBLE, no hipotetica: cualquier auditoria que cuente periodos, o que derive "cuando se modifico este vehiculo" del historial, cuenta ediciones de texto libre como si fueran tramites. Y como `normalizado_por` nombra al que ABRIO el periodo y no al que lo cerro (ver reference_normalizado_por_nombra_al_que_abrio_el_periodo_nunca_al_que_lo_cerro), tampoco se distingue despues cual periodo nacio de un cambio real. QUE HAY QUE DECIDIR, y no lo decido yo solo: - Que subconjunto de campos ABRE periodo. Candidatos a NO abrirlo: `observaciones` y cualquier otro campo puramente descriptivo. - Si el cambio de un campo que no abre periodo igual tiene que quedar registrado en algun lado (audit_log si, historial no). - Ojo con el reverso: sacar campos del disparador es exactamente la forma de "una regla relajada porque los campos igual llegan" - hay que MEDIR desde el llamador real que campos manda cada pantalla antes de excluir ninguno, no deducirlo. CONTEXTO DE COMO APARECIO: se necesitaba un cambio minimo y no destructivo para que el control de MOVILBA-331 pudiera disparar, porque un guardar-sin-cambios retorna temprano en `:1026` y no escribe nada (correcto). Se eligio `observaciones` justamente porque parecia el campo mas inocuo, y resulto abrir un periodo igual que cualquier otro. El control de 331 se corre igual - el texto queda auto-identificable en la columna - pero el hallazgo sobrevive al control. NO CONFUNDIR CON MOVILBA-331: 331 es que el sucesor nace sin `estado_id`. Esto es que el sucesor no deberia existir.

Sub-tickets

No sub-tickets.
+ Add sub-ticket

Activity

  • wi-cli-venus created · 5w ago
  • wi-cli-venus progress · 5w ago
    2026-09-07 23:03 - EL MECANISMO ES MAS ANCHO DE LO QUE DECIA EL ITEM. Confirmado por audit-mba-l-cc sobre origin/dev, independientemente de la lectura de db02. El cierre-y-apertura es INCONDICIONAL. En :1107 se cierra currentHistorial y en :1119 se inserta el sucesor SIEMPRE que !esBaja, sin ningun test de que campos cambiaron. colectivoValues gatea unicamente el UPDATE de la ficha en :1094, JAMAS el periodo. O sea: no es que 'observaciones cuente como cambio'. Es que **nada del periodo depende de que cambio**. El unico gate que mira los campos es el de :1026, que solo decide si la operacion sigue o retorna temprano; una vez que sigue, el periodo se abre igual cualquiera sea el campo que la disparo. ESO CAMBIA LA FORMA DEL ARREGLO. La version que yo habia escrito -'sacar observaciones del disparador', o sea excluir campos de changes- no alcanza: mientras la operacion no retorne temprano, el periodo se abre. El arreglo tiene que decidir la apertura del periodo por su propio criterio, separado del gate de continuidad. Sigue en pie la advertencia inversa: antes de excluir cualquier campo hay que MEDIR desde el llamador real que manda cada pantalla, no deducirlo. DATO RELACIONADO, del mismo par de lineas (audit): las dos 'observaciones' son COLUMNAS DISTINTAS. La de la ficha es vehiculos_datos_colectivos.observaciones; la de la fila de historial es data.motivoTramite || 'Actualizacion desde edicion de colectivo' en :1132. Como la pantalla no manda motivoTramite, todo periodo abierto por esta pantalla lleva la misma cadena generica.
  • wi-cli-venus assigned · 4w ago
    coder03-mba-l-cc / coder
  • coder03assistant-mba-l-ca progress · 3w ago
    coder03assistant-mba-l-ca | 2026-09-24 04:11:27 ART | dev 7d299b6a / main 721b9eb8: edit writer returns unchanged only when no field changes and no expediente; otherwise it reaches close/open period. Observaciones appears among collective fields, while motivoTramite has a note-only guard. Business-field subset decision and note-only integration behavior remain unverified; do not close.
  • coder03-mba-l-cc assigned · 2w ago
    db03-mba-l-cc
  • coder03-mba-l-cc assigned · 2w ago
    db04-mba-l-ca
  • coder03-mba-l-cc assigned · 1w ago
    db03-mba-l-cc / db
  • db03-mba-l-cc note · 1w ago
    db03 2026-10-08: premise superseded, closing. The 09-24/09-28 progress notes ("do not close", "unverified") predate the fix - commit 1009e223 (2026-09-23-1530, "MOVILBA-335 + MOVILBA-560b: dos arreglos al mismo escritor de historial") already shipped it one day earlier and those later notes never re-measured against it. MEASURED in current src/repositories/vehiculos.ts (dev+main, unchanged since 1009e223): - colectivoValues (:1278-1292, the field set gating `changes`) does NOT include observaciones/motivoTramite - only interno, consumo, camarasAdas*, ip*, conexionesUsb, cabinaAntivandalica, mdvr, pantallas, wifi, estandarEmisiones, regimenServicioModalidad, estadoId, identidadId. This IS the "subset of fields that opens a period" the ticket asked for. - Guard at :1347: `hasBusinessReason = Boolean(expedienteParaValidacion)`; :1347 comment names MOVILBA-335 directly: "A note describes a real change but is not one by itself; without a changed field or expediente there is no business event whose period can be opened." - :1348: `if (Object.keys(changes).length === 0 && !hasBusinessReason) return 'unchanged' as const` - an edit touching only observaciones, with no expediente, returns unchanged and writes nothing: no new period, no closed/reopened row. - motivoTramite's only live use is as free text inside an ALREADY-opening period's observaciones column (:1535 baja-por-transferencia, :1566 generic edit) - it never gates whether a period opens, confirming the 2026-09-08 finding's "motivoTramite only gates colectivoValues ficha UPDATE, never the period" is now exactly reversed: it no longer gates anything AND doesn't need to, since observaciones/motivoTramite was removed from the field set entirely rather than kept as a second gate. ANSWERS to the ticket's own 3 open questions: 1. Field subset that should NOT open a period: observaciones/motivoTramite is excluded (not in colectivoValues) - delivered. 2. Should a non-opening edit still be recorded somewhere: not done (no audit_log row written for the unchanged-path return) - NOT closing this as out of scope, just noting it was not part of the shipped fix and no separate ticket exists for it today. 3. Warning against the reverse failure (fields excluded from trigger but still arrive from the caller, deducing instead of measuring): not applicable here - colectivoValues was built as an explicit allowlist (each field individually gated by `!== undefined`), not a blocklist that excluded observaciones after the fact, so there's no silent-arrival risk from this specific screen. NOT RE-VERIFIED: whether any OTHER edit screen besides src/app/.../editar/colectivo sends a field outside this known set that could still open a period unexpectedly - out of scope for 335, which was specifically about the colectivo edit form's observaciones field. Open residual (point 2 above, note-only audit trail) can become its own ticket if Elazar wants it; not filing one unprompted.
  • db03-mba-l-cc completed · 1w ago
    db03: fix already shipped 1009e223 (2026-09-23), predates stale open-questions notes. See note for field-level proof.
  • audit-mba-l-cc audited · 1w ago
    audit pass: re-read commit 1009e223 + current repo field-exclusion/guard logic
    payload
    {"scope":"re-read commit 1009e223 + current repo field-exclusion/guard logic","outcome":"pass","evidence":"commit exists, message matches claim; colectivoValues (vehiculos.ts:1283-1292) excludes observaciones/motivoTramite; hasBusinessReason=Boolean(expedienteParaValidacion) only, unchanged-return at line 1352 when no changes and no expediente - matches claim exactly","reportRef":null}
question
5w ago by wi-cli-venus
1w ago
2026-10-08 14:48