basquetWi + New ticket
movilba MOVILBA-308

Clase: JOIN a opciones sin calificar por catalogo - diez sitios, cinco de ellos vivos en PROD (rendiciones)

Done high unassigned

ALCANCE: la CLASE, no la linea. Se abrio por un sitio y la barrida de audit-mba-l-cc mostro que son DIEZ. Este item NO cierra arreglando rutap-historial.ts. EL DEFECTO: opciones guarda MUCHOS catalogos en una sola tabla (regla permanente de Elazar). Un JOIN por o.id = <columna>_id sin el par (grupo_nombre, campo_nombre) resuelve un id mal apuntado a una etiqueta AJENA, plausible y CONFIADA - sin error, sin NULL, sin nada que se note. Es el mismo defecto que coder03-mba-l-cc arreglo en v_export_estado_actual. SITIOS, verificados por mi con grep sobre origin/dev, no tomados del mensaje de audit: - src/repositories/rutap-historial.ts:100 (tramite_id) - ARREGLADO en v5.5.16, par ('vehiculo_historial','tramite') verificado contra cuatro usos independientes del repo. - src/repositories/rendiciones.ts 112 (tipo_correo_id), 120 (tipo_telefono_id), 202 (tipo_asociacion_id), 256 y 304 (estado_actual_id), 350 (un FROM opciones pelado). RENDICIONES ESTA VIVO EN PROD DESDE EL 09-02: son cinco lecturas en produccion. - src/repositories/parque-movil.ts 145 (estado_id), 479 (ambito_id), 542 (lic_clase). Estos tres llevan AND o.borrado_en IS NULL pero NINGUN par de catalogo, y esa combinacion es la que mas ensena: alguien penso en el predicado del join y puso la guarda equivocada. borrado_en no discrimina catalogos. - src/actions/audit.ts:74: SELECT id, nombre_mostrable FROM opciones WHERE id IN (...), sin catalogo ninguno. Es una superficie de AUDITORIA, o sea una etiqueta mal ahi es una etiqueta mal en la evidencia. Contraejemplo que prueba que el repo sabe hacerlo bien: actions/vehiculos.ts:802 califica con el par completo. COMO SE ARREGLA CADA UNO: el par (grupo_nombre, campo_nombre) de cada columna se ESTABLECE contra el catalogo y contra otros usos del repo, NUNCA se adivina del nombre de la columna. Gatear por la forma valida, no por las formas malas conocidas: con el par puesto, un id mal apuntado da celda VACIA en vez de una palabra de otro catalogo. MEDICION PENDIENTE, y es distinta del arreglo: "el arreglo hace imposible el modo" y "el modo nunca se dio" son dos afirmaciones y solo una esta medida. Por cada sitio, en DEV y en PROD: SELECT count(*) FROM <tabla> t LEFT JOIN opciones o ON o.id = t.<col> AND o.grupo_nombre='<g>' AND o.campo_nombre='<c>' WHERE t.<col> IS NOT NULL AND o.id IS NULL; Distinto de cero significa que hubo pantallas mostrando una palabra ajena; cero significa que el arreglo es profilactico. La misma cuenta sobre los diez sitios da el radio de la clase en una pasada.

Sub-tickets

No sub-tickets.
+ Add sub-ticket

Activity

  • wi-cli-venus created · 5w ago
  • wi-cli-venus titleChanged · 5w ago
    Clase: JOIN a opciones sin calificar por catalogo - diez sitios, cinco de ellos vivos en PROD (rendiciones)
  • wi-cli-venus descriptionChanged · 5w ago
    was: HALLAZGO de audit-mba-l-cc el 2026-09-07, en la revision nombrada de las tres rutas de historial contra 83673f42. Es el unico de sus cuatro hallazgos que es INCONDICIONAL: esta mal en el codigo sin importar que tenga cada ambiente, y estaba VIVO en PROD el dia del deploy. src/repositories/rutap-historial.ts:100, en getRutapHistorialByChain: LEFT JOIN opciones o ON o.id = h.tramite_id, sin predicado de catalogo, y o.nombre_mostrable sale como tramite_nombre en la ficha que mira una persona. POR QUE IMPORTA: opciones guarda MUCHOS catalogos en una sola tabla (regla permanente de Elazar). Un tramite_id que apunte a otro catalogo resuelve a una etiqueta ajena, plausible y CONFIADA - sin error, sin NULL, sin nada que se note. Es el mismo defecto que coder03-mba-l-cc arreglo unas horas antes en v_export_estado_actual, sobreviviendo en el camino de LECTURA. ARREGLO (v5.5.16): el JOIN va calificado con AND o.grupo_nombre = 'vehiculo_historial' AND o.campo_nombre = 'tramite'. Con eso un id mal apuntado da celda VACIA en vez de una palabra de otro catalogo - gatear por la forma valida, no por las formas malas conocidas. El par se verifico contra cuatro usos independientes del mismo repo (actions/vehiculos.ts:802, lib/reportes/liquidacion.ts:69, tools/rutap-reconcile-plan.sql, docs/migrations/2026-08-21-movilba-104). NO EJERCITADO: nadie conto cuantas filas de PROD o de DEV tienen hoy un tramite_id fuera del catalogo, o sea no se sabe si alguna ficha esta mostrando una etiqueta ajena AHORA mismo. El arreglo hace imposible el modo de falla; no mide cuanto se dio. Esa cuenta es una consulta de una linea y vale la pena antes de cerrar el tema. PENDIENTE: llega a PROD en el proximo deploy, con su GO fresco.
  • wi-cli-venus priorityChanged · 5w ago
    1
  • wi-cli-venus note · 5w ago
    Correccion de audit-mba-l-cc, 2026-09-07, sobre la medicion y sobre un sitio exento. 1) La cuenta del radio NO va como estaba escrita: 'o.id IS NULL' mezcla dos poblaciones - (a) el id pertenece a OTRO catalogo, o sea se rendereo una etiqueta ajena y eso es el radio, y (b) el id no esta en opciones para nada, o sea la celda estaba vacia antes y despues, que es un hueco de DATOS y no un defecto de pantalla. Se separan con dos FILTER contra un segundo LEFT JOIN sin par: count(*) FILTER (WHERE o2.id IS NOT NULL) AS resolvia_a_otro_catalogo y count(*) FILTER (WHERE o2.id IS NULL) AS id_inexistente. Solo la primera contesta 'mintieron las pantallas'. La segunda se reporta aparte, al dueno de los datos. 2) src/actions/audit.ts:74 queda EXENTO de la regla por sitio y va TEMPRANO en la cola, no ultimo. Resuelve una bolsa de ids que vienen de catalogos MEZCLADOS a proposito, asi que no existe un par (grupo_nombre, campo_nombre) unico con que calificarlo. El arreglo es de otra forma: llevar el catalogo al lado de cada id, o resolver por columna en vez de por bolsa. Y es el unico sitio donde una etiqueta mal es evidencia mal, no pantalla mal.
  • wi-cli-venus verified · 5w ago
    Sitio 1 de 10 medido por db02-mba-l-cc el 2026-09-07, par establecido ('vehiculo_historial','tramite'), los dos ambientes. RESULTADO: CERO en los dos. Aca el arreglo es PROFILACTICO, no una reparacion - a nadie le mostraron una palabra ajena por esta columna. PROD: 5388 filas, 5382 con tramite_id no nulo, 2 ids distintos, 0 sin resolver bajo el par correcto. DEV: 16126 filas, 16110 no nulos, 2 ids distintos, 0 sin resolver. Joineando SIN calificar, o sea lo que hace el codigo con el defecto: PROD 2890 MODIF / 2492 ALTA, DEV 8636 MODIF / 7474 ALTA, todos cayendo en vehiculo_historial/tramite. El join sin calificar devuelve la etiqueta correcta por SUERTE, no por construccion. CONTROL POSITIVO: la misma consulta con un par deliberadamente equivocado (vehiculo/estado) condena 5382 de 5382 en PROD. El instrumento ve la violacion cuando la hay, o sea el cero es medicion y no punto ciego. CORRECCION AL GATE, y aplica a los otros nueve: public.opciones.id es PRIMARY KEY (0 ids bajo mas de un par), asi que un join sin calificar siempre matchea exactamente una fila y la consulta solo puede disparar cuando el id es de OTRO catalogo o no existe. La consulta esta bien como esta, pero un cero solo significa algo al lado de su DENOMINADOR: hay que reportar con_<col>_no_nulo junto a cada cuenta, porque una columna toda NULL devuelve un cero limpio sin medir nada. Ese es el modo de falla esperable en actions/audit.ts:74, que no tiene catalogo ninguno. REGLA DE TRABAJO: db02 no corre una cuenta sobre un par ADIVINADO. coder03 manda cada par cuando lo ESTABLECE y db02 corre la forma de tres partes - denominador, gate, control positivo con un par equivocado.
  • wi-cli-venus progress · 4w ago
    Noveno sitio ARREGLADO y shipeado: parque-movil.ts clase_licencia_id, v5.5.239 (f039f83e). Los otros ocho ya estaban calificados en dev/dev antes de esta pasada (medido por coder02-mba-l-cc y re-verificado por coder03 con grep sobre el tip), y audit.ts queda EXENTO por la nota del propio item del 09-07, leida y acordada. EL NOVENO NO ERA UN PAR: clase_licencia_id apunta a DOS catalogos reales y vivos a la vez - ('personas','clase_licencia'), la clase general A..G, y ('licencia','clase_lnc'), la subclase de pasajeros D.1/D.3. Calificar con un par suelto habria VACIADO las filas del otro catalogo: el mismo defecto de la clase con la direccion invertida - en vez de una etiqueta ajena, una celda vacia donde habia un dato bueno. El JOIN acepta la UNION de los dos pares. Medido por coder03 en DEV (SELECT only) sobre la poblacion que el JOIN realmente ve (con lic.borrado_en IS NULL, que es lo que filtra la consulta): las dos clases resuelven, cero filas sin par. DEFECTO DE FORMA corregido antes de shipear, y es reusable: el comentario entregado traia backticks adentro de un template literal, que lo CIERRAN - eslint tiro 'Parsing error: , expected'. Ademas fijaba conteos en el comentario; se sacaron y quedo el mecanismo mas el nombre de la consulta para re-medir, que es la regla de Elazar del 09-18. SIGUE PENDIENTE, y es de db: la consulta de impacto por sitio de la MEDICION PENDIENTE, incluido este noveno, que nunca se midio en ninguna direccion. 'El arreglo hace imposible el modo' esta hecho; 'el modo nunca se dio' no esta medido en PROD.
  • wi-cli-venus progress · 4w ago
    db02 measurement, DEV+PROD, both coder03 tasks. Task 1 (per-site impact, remaining 5): A tipo_correo_id DEV 53/0/0 PROD 42/0/0. B tipo_telefono_id DEV 17/0/0 PROD 9/0/0. C tipo_asociacion_id DEV 2/0/0 PROD 0/0/0 (empty denom). D ambito_id DEV 1/0/0 PROD 0/0/0 (empty denom). E clase_licencia_id (UNION pair, the ninth site, never measured in any direction before) DEV 38/0/0 PROD 0/0/0 - clean. All zero impact, all fixes prophylactic (opciones.id is PK, discriminates by construction once qualified). Control positive (deliberately wrong pair) correctly zero false matches on every site. Task 2 (population spread): A/B/C/D single-catalog each: E splits personas.clase_licencia(35 DEV)+licencia.clase_lnc(2 DEV) - both live, confirms UNION was necessary not defensive. NEW finding, found via pg_get_viewdef not grep: public.v_vehiculo_historial has 3 of its own unqualified opciones joins (estado_id, motivo_id, tramite_id) inside v_vehiculos_detalle's historial sub-select - separate from the already-fixed rutap-historial.ts tramite site. estado_id DEV 1687/0/0 PROD 1600/0/0, tramite_id DEV 5578/0/0 PROD 5509/0/0 (both zero impact, PK-discriminated by luck same as the rest), motivo_id is 0 non-null both envs (dead column). Flagged to coder03 for scope call (10th/11th site vs new item).
  • wi-cli-venus completed · 4w ago
    CERRADO. Los NUEVE sitios de codigo quedan calificados: ocho ya lo estaban en dev/dev, el noveno (parque-movil.ts clase_licencia_id) shipeado en v5.5.239 (f039f83e). audit.ts exento por la nota del propio item del 09-07. Revisado por audit-mba-l-cc contra f039f83e, sin observaciones sobre el diff. MEDICION PENDIENTE, HECHA, y contesta la pregunta que el item se hacia: db02-mba-l-cc midio DEV y PROD con split de tres (con_id_no_nulo / resolvia_a_otro_catalogo / id_inexistente) y con control positivo -un par deliberadamente equivocado, que dio cero falsos matches en todos-. Resultado: CERO impacto en las dos puntas, en los cinco sitios que quedaban por medir, incluido el noveno que nunca se habia medido en ninguna direccion. O sea que el arreglo de la clase entera es PROFILACTICO: ninguna pantalla llego a mostrar una etiqueta ajena. Las dos afirmaciones que el item separaba a proposito -el arreglo hace imposible el modo, y el modo nunca se dio- estan las DOS medidas ahora, y no habia que asumir la segunda. APRENDIZAJE QUE SE LLEVA LA CLASE, del noveno sitio: la receta del item asume UN par por columna y eso no siempre es cierto. clase_licencia_id apunta a DOS catalogos vivos a la vez -('personas','clase_licencia') A..G y ('licencia','clase_lnc') D.1/D.3-, asi que un par suelto habria VACIADO las filas del otro en vez de mentir: el mismo defecto con la direccion invertida. Antes de calificar una columna hay que medir contra que pares resuelve DE VERDAD la poblacion, con los MISMOS filtros que aplica el consumidor. db02 lo midio para los nueve: solo el noveno es multi-catalogo. NO CIERRA ACA, ABIERTO EN MOVILBA-481: la misma clase adentro de la base. public.v_vehiculo_historial tiene tres joins a opciones sin calificar (estado_id, motivo_id, tramite_id), encontrados leyendo pg_get_viewdef y NO por grep - 308 se acoto al codigo por construccion. Y nadie barrio el resto de las vistas, asi que esos tres son una muestra, no un conteo.
bug
5w ago by wi-cli-venus
4w ago
2026-09-18 07:54