Un expediente del libro usa en-dash: todo predicado 'EX-' lo pierde en silencio (18 filas)
db02, 2026-09-05, snapshot 10 DEV. Un expediente del libro esta escrito con EN DASH (U+2013, codigo 8211) en lugar de guion: 'EX-2026-07797873- -GCABA-DGGSM' con el caracter 8211 en las posiciones 3 y 8. 18 filas, un solo valor distinto, cero em-dashes en ambas columnas de expediente. Hoy NO es una identidad partida: no existe gemelo escrito con guion. EL LOADER NO NORMALIZA - guardar verbatim es correcto y folding NFKC ya altero identidad de caracteres una vez en este proyecto. El riesgo es aguas abajo: cualquier predicado 'EX-%' o comparacion de expedientes pierde estas 18 filas EN SILENCIO (fue exactamente asi que escaparon del primer gate de db02). Trabajo: encontrar todo punto donde se compara o busca un expediente (UI de busqueda, joins de reconciliacion, gates, rutap-fidelidad.py) y decidir la regla de comparacion insensible a la grafia del guion SIN tocar lo almacenado. No cubierto: PROD, y si algun expediente aparece con las dos grafias en la tabla legacy.
Activity
-
Both-spellings check run (coder02, DEV, both tables: vehiculo_historial.expte_alta/baja + wide raw_expte_alta/baja, folding U+2010..U+2015 and U+2212): 39 rows with a non-hyphen dash, ONE distinct value after folding, ZERO split identities. No expediente exists in two spellings anywhere, legacy included -> stays PREVENTIVE, P2. The 39 is the same value counted in both tables (18 wide + 21 legacy), not a second population; zero em-dashes bounds it to one substitution. SCOPE (audit): the first consumer that breaks is SEARCH, not reconciliation - a hyphen typed by the user returns nothing and reads as missing data. FIX SHAPE: one shared expediente-comparison helper folding the whole dash class at comparison and SEARCH time, storage untouched; gate = the VALID form of an expediente reference accepts every dash spelling, never a list of known-bad ones ('EX-' is a list of one). Loader never normalizes.
-
SIZED. Census across every expediente-bearing base table (58 columns enumerated from information_schema; snapshot copies parque_* excluded as frozen and unread): non-hyphen dash rows = rutap.rutap_rows.expte_alta 18/9286, .expte_baja 18/6987, rutap wide 18 (snapshot 10), legacy vehiculo_historial 21/6078, vehiculos_datos_colectivos.expte_alta 8/2136; ZERO in vdc.expte_baja, chofer_historial, chofer_linea_asignaciones, linea_entidad_asignaciones, validadoras_historial, puestos_a_tierra. So it reaches the ficha's NON-history expediente field too (VDC), via a write path separate from the RUTAP loader. SPLIT IDENTITIES: folded-group check over VDC + legacy + wide together = 0; same query with one synthetic hyphen-spelled twin = 1, so the zero is measured, not silent (control by db02 independently: group at 2 spellings over 40 rows). Stays PREVENTIVE, P2. One substitution only (U+2013), zero em-dashes on every relation checked. Not exercised: PROD, parque_* copies.
-
SCOPING CLOSED, both lanes independently. ONE distinct value across four relations: 'EX-2026-07797873- -GCABA-DGGSM' with U+2013 at positions 3 and 8. Census: wide 18 (snapshot 10), legacy vehiculo_historial 21/6078, vehiculos_datos_colectivos.expte_alta 8/2136 (0 in expte_baja), rutap.rutap_rows 18+18 across retained snapshots. Zero em-dashes, zero split identities; db02's control seeded from a REAL vdc row fires at 2 spellings over 84 rows, so the zero is measured. PROVENANCE of the VDC 8: creado_por NULL, creado_en 2025-12-10, value present verbatim in rutap.rutap_rows -> arrived by import, NOT hand-entered, so the fix is ONE comparison/search helper with no input-path work. WORDING (audit, adopted): the SPLIT-IDENTITY risk is preventive, but the SEARCH MISS IS LIVE TODAY - a hyphen query on DEV returns none of those rows and vdc.expte_alta is a ficha field outside the history, on a write path separate from the loader. Exclusions are decisions, not omissions: PROD out of scope; parque_* snapshot copies frozen with no reader.
-
Census extended by db02: vehiculos_datos_colectivos_archive holds 47 en-dash rows, same single distinct value, same single creado_en microsecond (2025-12-10 00:59:02.544591) as the 8 VDC rows - a batch write, not hand entry. Archive is off every read path so severity is unchanged; it belongs on the census. Full census: rutap_rows 18+18, wide 18, legacy 21, VDC 8, vdc_archive 47. db02's caveat kept: creado_por is caller-supplied and proves nothing, the inference rests on the identical microsecond; and it establishes how these arrived HISTORICALLY, not that the app would reject a pasted en-dash tomorrow - that is a code question for whoever implements the helper.
-
coder03-mba-l-cc / coder
-
db03-mba-l-cc
-
db04-mba-l-ca
-
db03-mba-l-cc / db
-
db03-mba-l-cc 2026-10-05 15:26 ART - CLOSED: the comparison rule exists and the stored value is untouched. Measured SELECT only, PROD then DEV: one distinct value 'EX–2026–07797873- -GCABA-DGGSM', stored verbatim in vh_norm expte_alta 9 + expte_baja 9 (raw_* the same), rutap_rows 9+9, vdc.expte_alta 8 (26 dash cells in the comparison union, identical in both bases). Split identity: 0 keys where a dash-folded expediente has more than one spelling including a dash, in both bases. Comparison points: src/utils/expediente-validation.ts:37 normalizeExpediente folds [–—] to '-' (validation/comparison projection only, never persisted, used by services/vehiculos.ts and the alta/edit pages); src/lib/historial-vehiculo.ts:96 PATRON_EXPEDIENTE_ELECTRONICO /^ex[-–—]\d{4}[-–—]\d+/i; no DB function or view has an 'EX-' predicate (prosrc/viewdef scan public+rutap+agents, 0); no repository ILIKE on expediente. Residual: tools/rutap-snapshot-import.py:1461 sibling match uses exact equality - correct today (0 split keys), it would miss a sibling only if the book spelled one expediente two ways. NOT MEASURED: out-of-repo APIs.