basquetWi + New ticket
movilba MOVILBA-730

v_vehiculos_export_periodo_actual proyecta el texto crudo de carroceria_categoria en vez de la etiqueta del catalogo

Canceled high dmdb03-mba-l-cc

Hallado por db03 el 2026-10-08 haciendo el censo de MOVILBA-123, medido sobre PROD instalado (no el espejo de Drizzle). La vista v_vehiculos_export_periodo_actual proyecta h.carroceria_categoria, el TEXTO CRUDO del libro, en vez de resolver la etiqueta del catalogo por el id nuevo (vehiculo_historial_normalizado.carroceria_categoria_id, agregado por MOVILBA-709). Es la regla 2 del 2026-09-24 incumplida en una superficie de export: ninguna superficie muestra texto crudo de un campo que tiene catalogo detras. Es exactamente el defecto al que apuntaba la opcion 72 soft-deleteada. Arreglo: resolver por el id contra el catalogo, CREATE OR REPLACE preservando toda la lista de columnas proyectadas (sin DROP VIEW, relacl de PROD no es NULL), PROD primero y despues DEV. Verificar antes si /api/v1 publica esa columna, es contrato externo.

Sub-tickets

No sub-tickets.
+ Add sub-ticket

Activity

  • coder03-mba-l-cc created · 1w ago
  • db03-mba-l-cc note · 1w ago
    db03-mba-l-cc 2026-10-08. MOVILBA-730 is NOT A DEFECT. No DDL. I filed this item and the finding behind it was my own instrument error; retracting it. HOW I GOT IT WRONG. During the MOVILBA-123 census I concluded "v_vehiculos_export_periodo_actual projects h.carroceria_categoria raw text" by regexp-matching the TEXT of pg_get_viewdef. That line sits in an INNER block of the view, not in its outer projection. Measured against output columns instead (pg_attribute, PROD): v_vehiculos_ciclo_actual 12 output columns, NONE named carroceria* v_vehiculos_export_periodo_actual 8 output columns, NONE named carroceria* Neither view exposes the column at all, so neither can be displaying anything. The viewdef text is not the output column list - same instrument-vs-object gap I have been cataloguing, this time in my own evidence. WHERE THE COLUMN IS ACTUALLY EXPOSED: nine views, all rutap.*, identical in PROD and DEV, output column carroceria_categoria (text): v_export_estado_actual, v_export_libro, v_rutap_latest, v_rutap_latest_norm, v_rutap_latest_projection_eligible, v_rutap_rows_norm, v_rutap_ultima_alta_por_dominio, v_vehiculo_historial_actual, v_vehiculo_historial_normalizado_fuente_actual (this one also exposes raw_carroceria_categoria). THE TWO USER-REACHABLE SURFACES, AND BOTH ARE ALREADY CORRECT. 1. The historical report (/reportes, MOVILBA-441) ALREADY resolves through the 709 id. src/app/api/reportes/vehiculos-historico/route.ts:47 emits op_categoria_regulatoria.valor_opcion AS "carroceriaCategoria" joining base public.opciones on h.carroceria_categoria_id with the app-origin fallback (route.ts:102-107), and it is test-guarded at src/lib/rutap-history-values.test.ts:147,167. Ruling 2 satisfied: the catalog label, not book text. 2. The book-mirror download emits the raw book text BY DESIGN, and that is ruling 3, not a defect. rutap.v_export_libro.carroceria_categoria is fed by rutap.vehiculo_historial_normalizado. raw_carroceria_categoria - measured via pg_depend on the view's referenced base columns, NOT from the view name. src/lib/exports/rutap-historico.ts:1-3 states the split in-code: "This report remains a separate /reportes product... unlike the internal latest-snapshot book export", and the libro path (src/repositories/rutap-libro.ts:35 -> src/lib/exports/rutap-libro.ts) is that internal mirror. tools/rutap-export-roundtrip.py:35 round-trips carroceria_categoria against the book, so putting a catalog label in that column would break the fidelity instrument. The same file's contract says callers supply catalog-resolved labels; the historico route does. 3. /api/v1 does not publish the column at all: /api/v1/exports/vehiculos reads v_vehiculos_export, which does not project carroceria_categoria (count 0). No external-contract exposure. 4. The ficha already resolves it too: src/repositories/vehiculos.ts:515 emits o.valor_opcion. WOULD-BE BLAST RADIUS, had I shipped the filed fix: PROD has 5558 rows, all origen='import', carroceria_categoria = raw_carroceria_categoria = 'M3', carroceria_categoria_id = 72, and option 72 is valor_opcion 'M3' / nombre_mostrable 'M3 - Colectivos'. So on today's data a catalog join changes 0 bytes - and in v_export_libro it would have silently converted a book-fidelity column into a derived one, which the roundtrip tool is there to catch and which no row count would have shown. TWO FINDINGS THAT DO SURVIVE, neither one 730's. A. MOVILBA-123 truncation, measured: ' (borrado)' is 10 chars; max(length(nombre_mostrable)) over public.opciones is 41, so the suffixed value reaches 51 and opciones.nombre_mostrable is character varying(50). valor_opcion is varchar(255), max length 28. Before any 123 DDL I still owe the OUTPUT-column typmods of the target view columns and of the 11 existing CASE sites - varchar(50) || text yields text, so the hazard is CREATE OR REPLACE rejecting a type change, plus silent truncation only where a cast back to varchar(N) is written explicitly. Not yet measured; not claiming a verdict. B. MOVILBA-123 scope, consequence worth deciding before it ships: all ten options of vehiculo/categoria_regulatoria carry borrado_en = 2026-07-02 04:06:53.288668 in BOTH bases, and this is a KNOWN, deliberate state, already documented in-code - src/repositories/opciones.ts:88-93 (MOVILBA-209) and src/app/api/dropdowns/route.ts:190-199 (MOVILBA-546: "this historical catalog is retired but remains the authoritative source for values captured on new app-created periods"). 4 of 34 catalogs are 100% soft-deleted; 33 of 200 opciones rows overall. Nothing is broken today: the dropdown (dropdowns/route.ts:192-199), the write-path validation (src/services/vehiculos.ts:411-418) and categoriaCarroceriaIdParaPeriodo (src/repositories/vehiculos.ts:311-318) all read BASE public.opciones with no borrado_en filter, so the field is selectable and writable despite the soft-delete. I verified that rather than assuming it. But MOVILBA-123 appends ' (borrado)' to catalog labels, and this catalog is retired-but- authoritative, so the dropdown at dropdowns/route.ts:194 - which emits opciones.nombreMostrable - would offer "M3 - Colectivos (borrado)" as the only selectable categories, 10 of 10. The historical report is unaffected because it emits valor_opcion. That is a decision for 123's scope, not something I should settle inside a view body. ALSO OWED, and this is the part that matters beyond 730: my MOVILBA-123 census counted join sites by parsing pg_get_viewdef TEXT. The error above came from exactly that method, so every "view X projects Y" line in that census is a candidate, not a measurement. I am re-deriving the 42 targets from pg_attribute output columns before writing any 123 DDL, and the earlier "67 join sites / 42 targets" figures should not be cited until I do. COVERAGE / SIN EJERCITAR: all of the above is read-only measurement of PROD and DEV plus repo reads. No DDL ran, no rehearsal was needed. Not exercised: any import, and the behaviour of the nine rutap views under a book value whose spelling differs from its catalog valor_opcion - today every live row is 'M3' on both sides, so the divergent case is reasoned from the column lineage, not observed. DEV additionally holds 167 origen='app' rows with carroceria_categoria_id NULL (154 with NULL text, 12 'M3', 1 'L1'); an id-only join would blank the 13 that carry text, which is why the app-origin fallback in the historico route and the ficha is load-bearing rather than defensive.
  • db03-mba-l-cc canceled · 1w ago
    NOT A DEFECT. The named view exposes no carroceria_categoria output column at all - my finding came from regexp-matching pg_get_viewdef TEXT, which matched an inner block, not the outer projection. Both user-reachable surfaces are already correct: the historical report resolves through the 709 id and emits valor_opcion (src/app/api/reportes/vehiculos-historico/route.ts:47, test-guarded), and the book-mirror download emits raw book text by design (v_export_libro.carroceria_categoria is fed by raw_carroceria_categoria per pg_depend, and tools/rutap-export-roundtrip.py:35 round-trips it), which is ruling 3. /api/v1 does not publish the column. No DDL. Full measurement in the preceding note, including two surviving MOVILBA-123 findings and the re-derivation I owe on the 123 census.
  • db03-mba-l-cc note · 1w ago
    db03-mba-l-cc 2026-10-08, CORRECTION to my own note on this item. Finding B is WITHDRAWN. What I wrote: that the carroceriaCategorias dropdown "would offer 'M3 - Colectivos (borrado)'". That rests on the same defective instrument as the rest of 730 - I inferred a projection from a pg_get_viewdef text match - and it is false. Nothing in the dropdown path reaches a view at all, so no suffix CASE applies to it, and MOVILBA-123's suffix cannot reach it either. The dropdown must be left exactly as it is, and the reason is in code, not in the view layer: - src/app/api/dropdowns/route.ts:190-199 reads BASE public.opciones with no borrado_en filter and emits nombreMostrable. MOVILBA-546 did that on purpose: "this historical catalog is retired but remains the authoritative source for values captured on new app-created periods". - All 10 options of vehiculo/categoria_regulatoria are soft-deleted (borrado_en 2026-07-02 04:06:53.288668, both bases). Filtering soft-deleted rows would leave the dropdown with ZERO options. - The write path REQUIRES one: src/services/vehiculos.ts:407-410 rejects a non-positive-integer carroceriaCategoriaId and :411-420 rejects an id absent from that catalog. An empty dropdown makes the field unsatisfiable and the form unsubmittable. - src/repositories/vehiculos.ts:311-318 (categoriaCarroceriaIdParaPeriodo) also reads base opciones and throws 'Categoria de carroceria sin vinculo unico en el catalogo' when it finds no row. So "do not offer those rows at all" would break vehicle create and edit. There is no change owed here and nothing to escalate: the premise was mine and it was wrong. 730 stays canceled. Coverage: measured the four code paths above and the borrado_en state of that catalog in both bases. NOT exercised: whether any OTHER dropdown type in that route depends on soft-deleted rows the same way - I checked only carroceriaCategorias.
bug
1w ago by coder03-mba-l-cc
1w ago
2026-10-08 16:08