basquetWi + New ticket
movilba MOVILBA-182

Historical app-created vehicles still attribute creado_por to system_import despite audit_log CREATE

Blocked high dmdb03-mba-l-cc ⛔ db03 2026-10-09: prior GO (nqla 8a) cites public.vehiculo_historial + 'importer account', which doesn't match - that table doesn't exist, and the real candidate (rutap.vehiculo_historial_normalizado) already has 0 NULL creado_por in PROD. Actual defect: 17 vehiculos.creado_por='system_import' rows whose real historical actor doesn't resolve against public.users. Needs Elazar: what to write for an unresolvable historical actor, or correct GO target.

Medido 2026-09-01 por db02-mba-l-cc en PROD (10.78.42.168, SELECT). Origen: rastreando la procedencia de AH940VK para MOVILBA-181. HECHO: cruzando audit_log (accion CREATE sobre la tabla vehiculos) contra vehiculos.creado_por, de los 29 vehiculos que la aplicacion creo por pantalla, 24 tienen creado_por = 'system_import'. Solo 5 llevan el identificador de quien los creo. El audit_log SI tiene el user_id correcto en los 29 casos, o sea que el dato existe y la columna no lo refleja. POR QUE IMPORTA: es exactamente el proposito que Elazar le dio a las columnas de auditoria el 2026-08-31 - 'si un dia nos despertamos y donde decia Toyota dice Peter Loves Mary, necesitamos saber quien lo hizo'. Hoy, para 24 de 29 altas manuales, la respuesta que da la ficha es 'lo hizo el importador', y es falsa. Peor que un dato faltante: es un dato que exculpa al usuario y culpa al proceso automatico. CASO TESTIGO, el que lo destapo: AH940VK (vehiculo 5254) tiene numero_serie_chasis '18ABsfsfsfTA13113', que no esta en ningun libro (el vigente dice 'LA6C3K1G9TB101998'). Su fila dice creado_por='system_import'. El audit_log dice otra cosa: user 35 lo CREO el 2026-03-02 14:52 y lo EDITO 8 minutos despues cambiando numeroSerieChasis entre otros campos. Sin el audit_log, ese dato tipeado a mano queda atribuido al import para siempre. ALCANCE DE LA COLUMNA: 2238 de 2388 vehiculos vivos dicen 'system_import'. No se puede saber por la columna cuales son import de verdad y cuales son altas por pantalla mal estampadas - hay que cruzar con audit_log en los dos sentidos. audit_log tiene 573 filas y 16 usuarios distintos, o sea que cubre poco: NO sirve como censo, solo como testigo puntual. NO ES DUPLICADO: verificado que no hay dominios repetidos - 2388 filas vivas, 2388 dominios distintos. Los pares que aparecen en audit_log (AG045KB 5203/5204, AE971GV 5207/5208) tienen una de las dos filas soft-deleteada. QUE HACE FALTA: que el alta por pantalla estampe el usuario en creado_por, y decidir si las 24 filas existentes se corrigen desde audit_log (el dato esta) o se dejan. Corregirlas es escritura en PROD y necesita GO explicito de Elazar describiendo la escritura. No la estoy pidiendo. COBERTURA: solo PROD, solo la tabla vehiculos, solo la accion CREATE. NO ejercitado: DEV, las acciones UPDATE/DELETE, y las mismas columnas en vehiculos_datos_colectivos y vehiculo_historial.

Activity

  • wi-cli-venus created · 6w ago
  • wi-cli-venus verified · 6w ago
    CORRECCION DE LA PREMISA - NO ES UN BUG DEL CAMINO DE ESCRITURA (db02-mba-l-cc, 2026-09-01, verificado contra dev/dev y PROD). coder02-mba-l-cc lo ubico en el codigo y tiene razon: src/repositories/vehiculos.ts en dev/dev estampa el usuario en los DOS caminos de alta (create() y el de colectivo, ambos 'creadoPor: String(userId)'). No hay camino que lo omita. Mi titulo culpaba al alta por pantalla y eso queda retractado. ORIGEN REAL: docs/migrations/2026-08-12-copia-datos-dev-a-prod.md paso 2.4. Fue DELIBERADO y pedido por Elazar (requisito 5 de esa migracion): se creo la cuenta deshabilitada 'system_import' y en DEV, antes de copiar a PROD, se reemplazo todo creado_por que no fuera un id de usuario real - NULL entre ellos, 2195 filas - por 'system_import'. QUE SE PUEDE RECUPERAR, medido, y es menos de lo que el documento sugiere. El doc dice que el estado previo es 'recuperable solo desde' 2026-08-12-dev-{vehiculos,vh}-creadopor-before.tsv. Ese archivo NO esta en el repo ni en dev/dev ni en /data-lezama: vive en /home/rob/movilba-db-work/dev-to-prod-copy-20260812/, sin trackear, en una sola maquina. Y tiene 73 filas, no 2195, porque solo registro los valores previos NO NULOS: 37 'import-2026-06-29', 34 'import-2026-08-05', y los ids muertos '37' y '16' una vez cada uno. Ni un solo CUIT real. De los 24 vehiculos creados por la app que hoy dicen system_import, SOLO 2 aparecen en ese TSV, y su valor previo son los ids muertos 37 y 16. Los otros 22 estaban en NULL. O sea que la migracion no borro la autoria de un usuario: reemplazo una AUSENCIA por una AFIRMACION FALSA. La procedencia ya se habia perdido antes del 08-12, en el camino que escribio esas filas. LA UNICA FUENTE de la autoria real de los 24 es audit_log, que SI la tiene en los 29 casos. LO QUE QUEDA, y ninguna mitad es un fix de codigo: a) 24 filas historicas cuyo autor verdadero solo existe en audit_log. Backfillearlas es escritura en PROD y decision de Elazar. NO se pide GO. b) El camino actual es correcto POR LECTURA y NO EJERCITADO por medicion: ningun vehiculo se creo por la app desde 2026-06-17. coder02 hace el ensayo en DEV y reporta el valor. Riesgo aparte que sale de esto y no es de este item: el unico artefacto de recuperacion de una migracion que destruyo procedencia esta sin trackear, en un directorio local de una maquina. Si esa carpeta se pierde, se pierden los 73 valores previos y nadie se entera.
  • wi-cli-venus verified · 6w ago
    Probado end-to-end en DEV: Elazar creo ZAS549 por pantalla el 2026-09-02 07:41:15. creado_por = 20247094211 (su CUIT) en vehiculos, vehiculo_historial, vehiculos_datos_colectivos y audit_log, las cuatro con el mismo timestamp al microsegundo. El camino de alta estampa bien; las 24 filas con system_import son historicas (migracion 2026-08-12). Registro borrado despues a pedido. Doc: docs/reference/2026-09-02-prueba-alta-por-pantalla.md (dev v5.4.88).
  • wi-cli-venus note · 5w ago
    RE-SCOPE PEDIDO, medido por db02-mba-l-cc el 2026-09-08: el denominador de este item esta mal y hay que llevarlo de 29 a 94 con el split adentro. Discriminador contra MOVILBA-354: si el id del CREATE auditado todavia existe en public.vehiculos. CREATEs de vehiculo auditados y distintos: PROD 94, DEV 102. PROD parte en 65 con el id AUSENTE / 24 con el mismo id estampado system_import / 5 con el mismo id correcto. El '29 de los cuales 24' de este item es exactamente los 24+5 sobrevivientes: se midio solo sobre las filas que sobrevivieron y nunca vio los 65 cuyo id ya no esta. DEV: 44 ausentes / 42 estampados / 16 correctos. NO SON EL MISMO HALLAZGO y no se cierra ninguno: 182 es 'el escritor nunca estampo al usuario, la fila esta intacta, se puede reparar desde audit_log'; 354 es 'la fila fue REEMPLAZADA, el id se destruyo, no hay nada que reparar en su lugar y audit_log es el unico testigo'. De los 65 de PROD, 26 tienen el dominio vivo bajo OTRO id (el reemplazo). NO EJERCITADO: acciones UPDATE/DELETE, y los 39 ids de PROD cuyo dominio no esta vivo en otro lado.
  • wi-cli-venus note · 5w ago
    El NO de db02 contra MOVILBA-354 ahora esta sostenido por CAUSA y no solo por forma. La alternativa era que el UPSERT del import pisara creado_por en filas que la app habia estampado bien: FALSA para 22 de las 24, porque vehiculos.creado_en coincide al MICROSEGUNDO con el timestamp del CREATE auditado, o sea la fila es la original y nacio estampada system_import. Solo 2 de 24 tienen creado_en posterior a su CREATE. Las 5 correctas tambien coinciden exacto, y las dos clases se INTERCALAN en el tiempo (correctas 2026-03-11..04-30, estampadas 2025-12-26..06-29), asi que no hay corte antes/despues del import por el cual plegarlas. 182 = el escritor nunca estampo al usuario, fila intacta. 354 = fila reemplazada, id destruido. Dos items. El denominador de 182 sigue siendo 94, no 29.
  • wi-cli-venus assigned · 3w ago
    db04-mba-l-ca
  • db04-mba-l-ca progress · 3w ago
    db04-mba-l-ca 2026-09-24 04:05 -03 — Status sweep limitation: The creator-attribution mismatch for app-origin vehicles was not recomputed against current public.vehiculos and audit logs. BWI show and recent events were read; status unchanged and no DB write.
  • coder03-mba-l-cc note · 2w ago
    coder03-mba-l-cc 2026-10-01 16:50: recomputed in both bases, which nobody had done since the original 2026-09-01 measurement. It does not reproduce, and in PROD it can no longer even be asked. DEV: all 57 live vehicles tagged origen_ingreso='app_dev' carry a real person in creado_por and ZERO say system_import. Every one of the seven distinct values resolves to a row in public.users: 20349069890 Leandro Baez 21, 20425668650 Fabrici Dil 15, 20247094211 Elazar Pimentel 8, l2eptUQd81rhJSECul6Qe QA Editor DEV 7, 27302187695 Eugenia Grosclaude 3, 27331350864 Paula Beltran 2, 20341207038 Lautaro Perez 1. So the writer does stamp the acting user today and the column answers 'who did it' for every app-created row in DEV. PROD: there is no app-origin population to measure. Live vehicles break down as legacy_unknown/system_import 2257, legacy_unknown/import-movilba-19 131, ssot_import/system_import 12, legacy_unknown with a person's id 7 plus 4 plus 2 plus 1, and legacy_unknown/import-movilba-18 4. No row is tagged app_prod, so the original '24 of 29 app-created vehicles' cannot be re-derived there at all - and per Elazar's fourth ruling of 2026-09-24 origen_ingreso is not a PROD instrument and legacy_unknown is not a class there, so the attempt is not owed either. Worth keeping from this: creado_por holds two different KINDS of identity side by side - AD-derived national id numbers and a locally generated nanoid for the QA account - and both resolve, so a reader must not assume the column is numeric. That is a shape note, not a defect. Recommend closing as not reproducing. Leaving the status to db04-mba-l-ca, whose item it is; I only measured.
  • db04-mba-l-ca progress · 2w ago
    db04-mba-l-ca 2026-10-01 17:13 ART. SELECT-only correction to the proposed close. The item was defined by audit_log CREATE on table vehiculos joined on record_id to public.vehiculos, not by origen_ingreso='app_dev'/'app_prod'. Re-ran that original discriminator case-insensitively on action (CREATE and create), DISTINCT record_id, both bases. PROD movilba: 94 audited CREATE ids, 24 still present, 70 absent; of the 24 present, 19 STILL have vehiculos.creado_por='system_import' and 5 carry other values, 0 match the audit_log.user_id verbatim. Positive witness AH940VK id5254 is one of the 19: current creado_por=system_import, origen_ingreso=legacy_unknown, audit_log CREATE user_id=35. DEV movilba_dev: 130 audited CREATE ids, 60 present, 70 absent; 17 present rows still have creado_por=system_import (all ssot_import), 43 other, 38 verbatim matches to audit_log.user_id. The separate 57 current app_dev rows with person-valued creado_por do not test this historical cohort. Thus the defect DOES reproduce in retained historical rows; leave item open. No data or code write. A repair would require mapping historical audit_log user_id to current identity and separately deciding whether to update these source-governed PROD rows; this measurement does not authorize a backfill.
  • db04-mba-l-ca titleChanged · 2w ago
    Historical app-created vehicles still attribute creado_por to system_import despite audit_log CREATE
  • coder03-mba-l-cc note · 2w ago
    coder03-mba-l-cc 2026-10-01 17:12: CORRECTION of my 16:50 note on this item, which reached the wrong conclusion because my cohort key was too narrow. I keyed app-created rows on origen_ingreso, and that column is stamped on INSERT by the CURRENT writer, so it cannot see a row the app created before the tag existed - which is precisely this item's cohort, and which the project rule already says in those words. The rows the ticket is about carry origen_ingreso='legacy_unknown', so my query excluded every one of them and then I read the empty result as 'does not reproduce'. It does reproduce. db04-mba-l-ca's cohort is the right one: public.audit_log where table_name='vehiculos' and action='CREATE', joined to public.vehiculos by record_id, independent of origen_ingreso. I re-ran it myself SELECT-only in PROD and reproduce its live numbers exactly: 24 of those vehicles are still present and 19 of the 24 still say creado_por='system_import', the other 5 say something else. Witnesses by id: 5205 AH810HF, 5206 AH810HE, 5208 AE971GV, 5214 AH992CY, 5219 AI019EO, all created between 2026-01-08 and 2026-02-05, all origen_ingreso='legacy_unknown'. One number does NOT match and neither of us should quote it as settled: db04 counts 94 CREATE ids in PROD and my 'select distinct record_id' counts 72. The 24-present and 19-still-system_import figures agree, so the disagreement is in how the id population is counted - distinct record_id versus events, and whether soft-deleted vehicles are included - not in the finding. Whoever closes this reconciles those two denominators first. My earlier note stands only for what it actually measured: rows tagged app_dev TODAY are attributed correctly, which says the current writer stamps the acting user. It says nothing about the historical cohort. The item stays open, as db04 said, and no backfill is authorized - the historical audit_log user ids need an identity mapping first.
  • db04-mba-l-ca progress · 2w ago
    db04-mba-l-ca 2026-10-01 18:45 ART. Provenance-query control: public.audit_log.action is mixed case on BOTH bases. For table_name='vehiculos', PROD has 72 uppercase CREATE plus 22 lowercase create = 94 distinct audited CREATE record_id; DEV has 108 uppercase plus 22 lowercase = 130. Use upper(action)='CREATE' (or equivalent case-insensitive comparison) in every authorship/provenance cohort. Filtering only action='CREATE' silently undercounts PROD by 22/94 (23.4%) and can be misread as absence of evidence. This is why the 94 historical cohort, not the 72 uppercase-only cohort, governs MOVILBA-182. No DB write.
  • coder03-mba-l-cc assigned · 1w ago
    db03-mba-l-cc / db
  • db03-mba-l-cc note · 1w ago
    Re-confirmado PROD hoy (db03-mba-l-cc): 94 audited CREATE ids, 24 present, 19 still creado_por=system_import - identico a la medicion 2026-10-01 de db04/coder03, sin movimiento. Sigue bloqueado en lo mismo: (1) mapear historical audit_log.user_id a identidad actual, (2) decision de Elazar sobre si se actualizan estas 19 filas gobernadas por fuente en PROD. No hay nada nuevo que medir - es DECISION, no medicion. Dejo abierto.
  • coder03-mba-l-cc note · 1w ago
    Elazar GO 2026-10-08 12:55 ART (CLI, nqla 8a): backfill creado_por on the 19 NULL vehiculo_historial rows in PROD with the importer account used by every other row; rehearse ROLLBACK, apply PROD then DEV, audit. Executor: db03.
  • coder03-mba-l-cc assigned · 1w ago
    db03-mba-l-cc / db
  • db03-mba-l-cc note · 1w ago
    db03 2026-10-09T00:1xZ - RE-MEDIDO en las DOS bases. El defecto existe pero su POBLACION y su REMEDIO no son los que dice el item, y una parte de lo que pide es inconstestable con el dato que hay. Scoping, no cierro. CORRECCION DE INSTRUMENTO, primero, porque invalida una cifra que ya habia escrito en esta sesion: public.vehiculos_archive lleva UNA FILA POR CAMBIO (23.075 filas de archive_reason UPDATE solo en DEV), asi que cualquier JOIN a esa tabla se abre y un count(*) sobre el join no cuenta vehiculos. Mi primera corrida reporto '121 huerfanos' en DEV por eso; el numero real es 48 y lo da un EXISTS, no un join. Toda cifra de abajo que mire el archive usa EXISTS. LA POBLACION EN PROD, contra audit_log (table_name='vehiculos', action='CREATE'), 72 record_id distintos: - 24 apuntan a una fila VIVA de public.vehiculos: 19 con creado_por='system_import' y 5 con un identificador de usuario. Las 24 tienen origen_ingreso='legacy_unknown', NINGUNA tiene app_*. - 0 de 24 tienen creado_por igual al user_id que trae su propio evento. O sea los 5 que el item describe como 'llevan el identificador de quien los creo' llevan UN identificador, pero NO el del evento CREATE de esa fila. El item contaba 29/24 el 2026-09-01; hoy son 72/24/19. - 48 apuntan a un id que YA NO TIENE FILA en public.vehiculos. Eventos del 2025-12-16 al 2026-06-05, los 48 con dominio en details. LOS 48 SON EL HALLAZGO QUE EL ITEM NO TIENE, y cambia el remedio: - 31 de esos 48 dominios VIVEN HOY bajo OTRO id. O sea la fila que creo la app fue borrada y el dominio volvio a entrar como fila del import. Para esos 31 la fila viva fue creada por el import de verdad, asi que escribirle el usuario del audit_log seria una atribucion FALSA, no una correccion: son dos hechos distintos - quien tipeo el dominio por primera vez, y quien creo la fila que hoy existe. La columna creado_por responde el segundo. - 17 dominios no viven hoy bajo ningun id. - Solo 5 de los 48 tienen fila de archive con archive_reason='DELETE'; 43 no tienen NINGUNA fila de archive. O sea 43 filas de PROD desaparecieron sin que el trigger de archivo dejara rastro. No afirmo la causa: puede ser un borrado con el trigger deshabilitado, un borrado anterior a que el trigger existiera, o un record_id que no apunte a vehiculos. Hay que medirlo antes de llamarlo defecto, y va en item propio porque no es la atribucion. - NOTA ESTRUCTURAL, medida: public.vehiculos_archive NO tiene columna origen_ingreso (19 columnas, ninguna de procedencia), asi que el archive no puede responder con que procedencia entro una fila borrada. DEV dice que el CAMINO DE CODIGO DE HOY ESTA BIEN, y eso es lo que acota el arreglo a un backfill: 59 filas app_dev con evento CREATE, 54 de ellas YA tienen creado_por igual al user_id del evento. Las otras 17 con evento son ssot_import con creado_por='system_import'. Ninguna fila de DEV se creo antes ni despues de su evento por mas de un minuto, en las dos clases. No encontre nada que arreglar en el escritor; lo roto es historico y esta en PROD. ENTONCES EL ITEM SE PARTE EN TRES, y solo el primero es ejecutable hoy: 1) 19 filas vivas de PROD con creado_por='system_import' cuyo propio evento CREATE trae un user_id. Backfill posible y verificable fila por fila. Son 19 escrituras a PROD sobre una columna que NO es del libro, asi que NO las cubre la autorizacion de sync al SSOT de la regla 4 del 2026-09-24 - pido que se nombre antes de correrla. 2) 31 dominios cuya fila app fue reemplazada por una del import. NO se backfillea: la pregunta 'quien lo tipeo primero' no la contesta creado_por. Si hace falta responderla, es una superficie nueva sobre audit_log, no una columna. 3) 43 filas sin rastro de archive: medicion aparte, item propio. SIN EJERCITAR: SELECT solamente, no escribi nada. No medi la ficha ni ninguna superficie de la app, no verifique si los user_id del audit_log corresponden a cuentas vivas (public.usuarios no existe; hay que encontrar la tabla de usuarios antes de afirmarlo), y no medi la clase 3 mas alla del conteo.
  • db04-mba-l-ca note · 1w ago
    2026-10-08 db04 SELECT-only identity correction from MOVILBA-9 census: current PROD 19 system_import vehiculos join historical audit_log CREATE by record_id, but 2 (ids 5947,5951) have different current dominio and creado_en ~2 weeks after the audit event. Exact same-row match requires id+details.dominio+creado_en and yields 17, not 19. All 17 event user_id values (3 distinct) fail to join current public.users.id. Therefore 19 is NOT a safe backfill set, and even 17 lack a verified present-day identity mapping; no update authorized. See /data-lezama/movilba/evidencia/MOVILBA-9/2026-10-08-log-attribution-census.sql sha256 79df2c3e and sibling report bdfd70e9. DEV exact lost-creator cohort 17. No DB write.
  • db04-mba-l-ca note · 1w ago
    Preservation correction from MOVILBA-9 2026-10-08: of 17 exact current lost-creator rows in PROD, 5 have creation actor ID only in audit_log among measured live tables/logs; 12 also carry it in direct app_logs creation messages. A second audit_log event does not protect the 5 from table-wide purge. Historical actor IDs match current users 0/17. See corrected report sha256 93ba7579 and SQL 5bf5cd4f at /data-lezama/movilba/evidencia/MOVILBA-9/. No attribution write or purge.
  • db03-mba-l-cc note · 1w ago
    db03 2026-10-08 ART. CORRECTION of my own class-1 figure, independently re-measured in PROD, not taken from db04's handoff. Two defects in what I wrote earlier today. (1) PREDICATE TOO NARROW ON CASE: I counted CREATE events with action='CREATE' and got 72. Case-insensitive, upper(action)='CREATE' gives 94, of which 22 are the lowercase 'create' spelling. All 94 have distinct record_id, and exactly 24 point at a live vehiculos row in both spellings, so the live-row cohort of 24 does not move - the 22 lowercase events all point at ids with no live row. The 72 was still a wrong denominator and anything I derived from it as a rate is wrong. (2) CLASS 1 IS 17 ROWS, NOT 19, and it is not executable as a user attribution. Of the 24 live-row CREATE events, 19 sit on a row whose creado_por is 'system_import'. Two of those 19 are a false match: id 5947 is live as AI225QY while its CREATE event of 2026-06-16 10:23 carries details->>'dominio' = 'AA114VT', and id 5951 is live as AC343HC against an event of 2026-06-17 14:43 carrying 'DHU474'; both live rows were created 2026-06-29 14:10, so the event belongs to an earlier row that occupied the id. The id-only join I used could not see that - the control that does is matching the event's own details->>'dominio' against the live dominio, which neither my earlier note nor the item's remedy had. That leaves 17, which is the same cohort db04 reports for MOVILBA-9 reached by domain+time, so two instruments agree. (3) THE REMEDY STILL DOES NOT EXECUTE on those 17. Their three distinct event actors are d007a52d-4b5c-48d4-bd77-22b8bf10b3d0 (11 rows), f1e30001-bc25-4091-b8fc-8db77814f4af (5 rows) and the bare string '35' (id 5254, whose event dominio AH940VK does match the live row). ZERO of the three resolve in public.users, which holds 33 rows; positive control in the same query, an id taken from users itself, resolves 1. So writing creado_por from the audit event would replace 'system_import' with an identifier that names nobody in the current users table - not an attribution, a different unknown. No PROD write is proposed on this evidence and the 19-row backfill I asked to have named is withdrawn as specified; what is needed first is a decision on whether an unresolvable historical actor id is an acceptable value for creado_por, which is Elazar's call, not a measurement. NOT EXERCISED: no write, no DEV leg, the 48 non-live-row events and the 43 with no archive row are untouched by this note and keep their earlier classification, and I did not re-measure app_logs - db04 holds that surface for MOVILBA-9.
  • db03-mba-l-cc note · 1w ago
    db03 2026-10-08 ART, second correction of this date - the two gaps my previous note left, now closed by measurement, plus one defect in it. (A) THE DOMINIO CONTROL NOW COVERS THE WHOLE COHORT, not three spot checks. Matching details->>'dominio' against the live dominio across ALL 24 live-row CREATE events, with events whose details lack the key put in their own bucket so a missing key cannot pass as a match: 0 events lack the key, 17 match on rows whose creado_por is 'system_import', 5 match on rows whose creado_por is already a CUIT (ids 5265-5269), and exactly 2 differ - 5947 and 5951. So the 17 is measured over the full cohort and no longer rests on db04's handoff; two instruments reached it by different routes. (B) THE NON-LIVE CLASSES RE-RUN ON THE 94-EVENT POPULATION, which is what the case fix changed. 94 events, all with distinct record_id, 24 with a live row, 70 without. Routing those 70 by the event's own dominio: 31 have a dominio that lives today under a different id (all 31 are the uppercase spelling), and 39 have a dominio that exists nowhere today (17 uppercase plus all 22 lowercase). By archive instead: 65 of the 70 have no vehiculos_archive row at all and 5 have an archive row with archive_reason='DELETE'. So my earlier 31 survives and my earlier '17 nowhere / 43 no archive' do not - the correct figures are 39 nowhere and 65 with no archive row, and the earlier pair was the uppercase-only slice reported as if it were the population. (C) THE TWO SPELLINGS ARE ONE WRITER, NOT TWO, and that is the part worth keeping: on table_name='vehiculos' the lowercase 'create' runs 2025-10-06 to 2025-12-15 (22 rows, 3 actors) and the uppercase 'CREATE' runs 2025-12-16 to 2026-06-17 (72 rows, 13 actors), with no overlap, and 'update'/'UPDATE' split on the same date. The cause is in the code: src/lib/audit-wrapper.ts:103 writes action.toUpperCase() while every call site passes lowercase, so the normalization was added around 2025-12-16 and the older rows kept the raw string. CONSEQUENCE for any lane measuring audit_log: a predicate on action='CREATE' silently drops everything before 2025-12-16, which is 22 of 94 CREATE events here. (D) DEV's figure is unaffected by the case fix: re-run with upper(action), the app_dev cohort is 73 rows, 59 have a CREATE event and 54 of those match their own event's user_id - the same 54/59 as before. (E) The three actor ids of the 17 still resolve to nobody: 0 of 3 found among 33 rows of public.users, positive control in the same query resolves 1. NOT EXERCISED: bkp.users_groups_20260814_carlos could not be read at all - permission denied for schema bkp with my role, which is not evidence of absence, so whether those two UUIDs resolve there is UNMEASURED and someone with that grant has to answer it; no write in either base; no app_logs surface (db04 holds it for MOVILBA-9).
  • db03-mba-l-cc note · 1w ago
    db03 2026-10-08 ART. THE FORWARD HALF OF THIS ITEM IS CLOSED AND THE DEFECT IS NO LONGER BEING PRODUCED. Only the backfill decision on the 17 rows remains, and that one is Elazar's. (A) TODAY'S TREE, measured on the working checkout, not inferred from a commit: there is exactly ONE insert into public.vehiculos in all of src/ - src/repositories/vehiculos.ts:880 - and it carries creadoPor: String(userId) at :899. Enumerated every .insert( in that file (880 vehiculos, 925 vehiculos_datos_colectivos, and 972/1227/1600/1632 all into vehiculo_historial_normalizado) and grepped the whole tree for INSERT INTO vehiculos / insert(schema.vehiculos): no second writer. So an alta por pantalla stamps the user. (B) WHEN IT CLOSED: 9e928e7e, 2026-03-06 01:20:52 -0300, +23/-0 on src/repositories/vehiculos.ts. At that era the file had TWO insert(vehiculos) paths; 1 of 2 stamped creadoPor before the commit and 2 of 2 after. The last mis-stamped row is id 5262, creado_en 2026-03-04 - two days before. Date adjacency, not a causal proof: no alta was executed against either base for this note. (C) DEFECT IN MY OWN INSTRUMENT, reported because it reverses a count rather than softening it: a grep -n 'insert(vehiculos)' -A14 window returns 0 creadoPor matches on TODAY'S tree, where the truth is 1 - :880 to :899 is 19 lines. I first read that 0 as "the fix was refactored away". Positive control: the same grep at -A24 prints 1 on the same bytes. Any window count over this file needs >= 24 lines, and my first pre/post pair (reported as 0 then 2) was the same artifact; the correct pair is 1-of-2 then 2-of-2. (D) THE PREMISE OF THE ITEM HOLDS - the 17 are genuine app creations, not import rows that the app later touched. All 17 have creado_en equal to their audit_log CREATE timestamp TO THE MICROSECOND, i.e. row and event were written in the same transaction. Nothing in the import path can produce that: 'system_import' appears nowhere in src/ (control: grep -c origen_ingreso tools/rutap-snapshot-import.py = 10, so the instrument does find strings in that file), vehiculos.creado_por has no column default, and the literal is written by exactly two functions - rutap.proyectar_snapshot(bigint) and rutap.materializar_snapshot_raices(bigint) - the second inside an INSERT ... WHERE NOT EXISTS (SELECT 1 FROM public.vehiculos v ...) that cannot overwrite an existing row. (E) MONTHLY CROSS of upper(action)='CREATE' against the live row: every mis-stamp is in 2026-01 (4), 2026-02 (7) and 2026-03 (6), plus the 2 id-reuse cases of June already named (5947, 5951). April 2026 is 4 of 4 carrying a user. The distribution stops where (B) says it should. (F) WITHDRAWN, mine, same date: a figure of 2274 "app-origin rows in PROD". Its predicate was origen_ingreso <> 'rutap_import', and 'rutap_import' is not a value PROD holds - the column there carries only 'legacy_unknown' and 'ssot_import' - so the predicate matched rows it was meant to exclude. origen_ingreso cannot identify app-created rows in PROD at all, which is also why the cohort is built from audit_log and not from that column. (G) SEPARATE CLASS, needs its own item and is NOT part of this one: of the 94 CREATE events on table_name='vehiculos', 70 have no live row, 65 of those have no vehiculos_archive row either. That is a question about audit_log retention versus physical deletion, not about creado_por. NOT EXERCISED: no alta ran through any screen or HTTP call for this note, DEV was not measured at all, and nothing here was verified after a deploy. What is measured is the source tree of today, the commit's diff, and PROD rows/events SELECT-only.
  • db03-mba-l-cc note · 1w ago
    db03 2026-10-08 ART, correction of my note of 01:27:18.330Z on this item. Its part (C) is wrong in the direction that matters - it withdrew a figure that was correct and replaced it with one that is not - and the control it prescribed is the wrong control. The verdict of that note does not change. WHAT (C) GOT WRONG. It said the pre-image of 9e928e7e had 1 of its 2 insert(vehiculos) paths stamping creadoPor, and that my first reading of 0 was a window artifact. The 0 was right. Enumerating every .insert( site in the pre-image instead of counting inside a line window: insert(vehiculos) at :189 and :447, and the only creadoPor above :447 is at :229, which sits inside the insert(vehiculoHistorial) that opens at :225. A 40-line window from :189 reaches :229 and attributes a NEIGHBOURING insert's field to the vehiculos insert. So the pre-image was 0 of 2 and the post-image is 2 of 2 - creadoPor at :200 under the insert at :189, and at :459 under the insert at :448, each before the next .insert( site. The commit added both. THE CONTROL IS NOT A BIGGER WINDOW. I told coder03 in a DM that this file needs grep -A24; that prescription is wrong and I am withdrawing it. A window of ANY size is the defect here, because this file nests several .insert( calls inside one method and the fields of one are within line reach of another - widening the window is what produced the bad figure in the first place. The count has to be bounded to the .values({...}) block of the specific insert, i.e. between its own .insert( site and the next .insert( or .returning(. Both of today's figures and both of the pre/post figures above were re-derived that way. ONE CLAIM IN (A) THAT NEEDED A SECOND LOOK AND SURVIVES, with the reason corrected. The comment above :899 in today's tree says "create() (alta generica) si persiste asientos - el hueco era solo de este camino", which names a second alta path. There is no such path any more: class VehiculoRepository (:351) has no create() method - the alta methods are createColectivo (:823) and createHistorialRecord (:1131) - and src/services/vehiculos.ts calls only createColectivo (:559). No raw writer either: a case-insensitive sweep for INSERT INTO (public.)vehiculos across src/ returns nothing, and the same instrument finds five raw INSERT INTO sites in src/repositories/validadoras.ts, so it does detect raw SQL. The class is not a subclass and nothing does .insert(this.<table>). So "exactly one writer" stands, but it stands because the generic path was removed, not because it never existed - and that in-code comment is now stale and describes a method that is gone.
  • db03-mba-l-cc note · 1w ago
    db03 2026-10-08 ART, coverage statement on the sweep I ran after withdrawing the -A24 prescription, so nobody reads that sweep as wider than it was. WHAT I RAN: every bwi item assigned to me, dumping full events and grepping for a literal window flag - 'grep -A<n>', a bare '-A<n>', or the phrase 'windowed grep'. It returned exactly one item, this one, which is already corrected in the note of 01:32:05.054Z. The grep did fire on this item's own notes, so the instrument does find the string where the string exists. WHAT IT CANNOT SEE, and this is the part that matters: a figure I obtained with a line window but wrote up without naming the flag is INVISIBLE to that scan. The scan searches the prose of my notes, not the commands I ran, and nothing requires a note to state its grep. So the correct statement is 'no item of mine NAMES a windowed grep over repositories/vehiculos.ts other than this one', not 'no other item rests on one'. Any figure of mine over a file with several nested .insert( calls should be re-measured bounded to the insert's own .values({...}) block regardless of whether a note mentions a window. ALSO NOT COVERED: items assigned to other lanes, and my own notes on items that were closed and are no longer listed as mine.
  • db03-mba-l-cc note · 1w ago
    db03 2026-10-08 ART. La clase 3 de este item - los eventos CREATE cuyo vehiculo no existe - sale a su propio item, MOVILBA-780, medida en PROD con reloj de servidor 23:10 a 23:14-03. Aca quedan las dos trampas de instrumento que encontre midiendola, porque las dos afectan a CUALQUIER medicion sobre audit_log, incluidas las de este item. PRIMERA, y es la que importa: audit_log.action guarda el verbo en DOS GRAFIAS. Hay 'CREATE' 72 y 'create' 22, 'UPDATE' 224 y 'update' 13. Un filtro action='CREATE' devuelve 72 donde la poblacion es 94, y pierde 22 eventos del 2025-10-06 al 2025-12-15. Corri exactamente ese filtro en mi primera pasada de esta noche y dio 43 huerfanos; con upper(action) son 65. Toda medicion sobre esta tabla usa upper(action) o informa menos poblacion de la que dice. SEGUNDA: un LEFT JOIN a public.vehiculos_archive infla el recuento de eventos, porque el archive tiene hasta 4 filas por id - el reparto es 326 ids con 1 fila, 460 con 2, 196 con 3 y 5 con 4. Mi primera clasificacion dio 38+5+43=86 eventos sobre una poblacion de 72, que es la suma inflada. Las cifras de 780 estan hechas con EXISTS. TERCERA, de forma y no de recuento: public.vehiculos_archive NO es un archivo de borrados. Tiene 987 ids distintos y 977 de ellos SIGUEN VIVOS en public.vehiculos; solo 10 no. Es historia de UPDATE. Y no hay ningun evento DELETE en audit_log sobre vehiculos, ni una sola fila con borrado_en en public.vehiculos - 0 de 2424 -, asi que el borrado en esta tabla es FISICO y sin rastro. UNA ARITMETICA QUE CIERRA Y QUE NO VOY A AFIRMAR COMO CAUSA: la descripcion de este item habla de 29 vehiculos creados por pantalla, y mi clasificacion da 24 con fila viva mas 5 con fila solo en archive, que son 29. Si esa es la misma poblacion, entonces los 29 de este item son exactamente el subconjunto que TODAVIA tiene fila, y los 65 de 780 son el resto que nadie habia contado. Lo que lo decidiria es re-correr la medicion original de db02 con upper(action) y comparar los ids uno por uno; no lo hice, y hasta entonces es una coincidencia de dos numeros y no una identidad de poblaciones. SIN EJERCITAR aqui: DEV, ninguna pantalla ni export, y nada de esto toca la pregunta abierta de este item, que sigue siendo la decision A/B de Elazar sobre backfillear o no los creado_por desde audit_log.
  • db03-mba-l-cc blocked · 1w ago
    db03 2026-10-09 ART. El GO de coder03 (2026-10-08 15:19Z, nqla 8a) no describe el defecto de este item: nombra 'vehiculo_historial' con creado_por NULL y 'la cuenta del importador', y este item es rutap.vehiculo_historial_normalizado... no, es vehiculos.creado_por='system_import' en 17 filas (medido hoy, nota de 00:30). Medido ahora: public.vehiculo_historial NO EXISTE como tabla - solo hay rutap.vehiculo_historial_normalizado, bkp.vehiculo_historial_20260814_prebackfill_prod (nombre que indica un backfill YA CORRIDO el 2026-08-14) y vistas. rutap.vehiculo_historial_normalizado.creado_por tiene 0 NULLs hoy en PROD - si el GO se referia a esa tabla, ya esta hecho; si se referia a otra cosa, el nombre no existe. No ejecuto el GO tal como esta escrito porque no corresponde a ningun estado medible hoy. Ademas, aunque el GO aplicara, no resuelve los 17 de este item: 'la cuenta del importador' no es el actor real de esas filas (los tres actores historicos no resuelven contra public.users, 0 de 3, control positivo 1 de 1) - escribir el importador ahi seria la MISMA sustitucion que el item ya rechaza (system_import), solo con otro nombre. La decision pendiente sigue siendo de Elazar: si un id de actor historico sin resolver es un valor aceptable para creado_por, y que valor usar si no. No se escribio nada en ninguna base. Devuelvo a backlog con este bloqueo hasta que Elazar conteste la pregunta de arriba o aclare a que apunta el GO citado.
  • coder03-mba-l-cc blocked · 1w ago
    db03 2026-10-09: prior GO (nqla 8a) cites public.vehiculo_historial + 'importer account', which doesn't match - that table doesn't exist, and the real candidate (rutap.vehiculo_historial_normalizado) already has 0 NULL creado_por in PROD. Actual defect: 17 vehiculos.creado_por='system_import' rows whose real historical actor doesn't resolve against public.users. Needs Elazar: what to write for an unresolvable historical actor, or correct GO target.
bug
6w ago by wi-cli-venus
1w ago