FKs a opciones(id) sin restriccion de catalogo: censar cuantas columnas de negocio pueden guardar el id de un catalogo ajeno
Hallazgo de db03 en MOVILBA-738: las 2 filas de asociaciones en DEV guardan la opcion 113, que pertenece a personas/tipo_persona, a traves de una FK a opciones(id) que no restringe el catalogo - una etiqueta de catalogo ajeno VIVA en pantalla. PROD tiene 0 filas hoy, asi que es latente ahi, no ausente: nada en el esquema lo impide. La regla permanente de Elazar es que todo valor enumerado vive en opciones y la columna guarda el ID, asi que una FK a opciones(id) es correcta de tipo y muda de dominio - el catalogo correcto no esta expresado en ninguna parte y el unico control es que el codigo elija bien. Trabajo, y es MEDICION: censar TODAS las columnas de negocio con FK a opciones(id) y, por cada una, cual es el catalogo que le corresponde y si hay o no algo que lo haga cumplir. Contar en las dos bases cuantas filas vivas apuntan hoy a una opcion de un catalogo distinto del que corresponde - en DEV son por lo menos esas 2. NO proponer el arreglo todavia: elegir entre un CHECK por columna, una FK compuesta a (id, catalogo) o validacion solo en servicio es una decision y necesita el censo antes. Las 2 filas de DEV no se tocan: son datos que los usuarios crearon ahi.
Activity
-
parent=#4552
-
db03-mba-l-cc 2026-10-08 22:03Z - CENSO COMPLETO, sin escrituras. Entregables: docs/reference/movilba-763-censo-fk-opciones.md sha256 9d569170429ec58212dd1272dd09a408390bd435e7d2d8594104ecf3514a84fe, y el instrumento tools/movilba-763-censo-fk-opciones.sql sha256 9203090e133042860a7f68937c8fefc6f52e4446f4b24aa4b51beb5247a07967, que se maneja desde pg_constraint y no desde una lista de columnas a mano. ESTRUCTURA, identica en las dos bases: 39 FK a public.opciones - 38 de una sola columna SIN calificar (grupo_nombre, campo_nombre), y 1 compuesta, vh_norm_categoria_catalogo_fk de MOVILBA-709. La forma del arreglo ya existe y esta aplicada; 763 no tiene que disenarla. EJERCIDO: dos columnas, las dos solo con filas en DEV, las dos YA compensadas en codigo bajo MOVILBA-308 - este censo las confirma por un camino independiente, no las descubre. (1) licencias_choferes.clase_licencia_id apunta a DOS catalogos VIVOS en las dos bases, personas/clase_licencia=35 y licencia/clase_lnc=3, y src/repositories/parque-movil.ts:611 une los dos pares a proposito porque calificar con uno vaciaria las filas del otro. Las 3 son ids 36-38, persona 171, LNC-99999/77777/88888, ente_emisor GCABA-TEST/GCABA-EDITED - datos de prueba de DEV, se quedan. (2) asociaciones_entidad_persona.tipo_asociacion_id apunta a personas/tipo_persona=2 y la CAUSA es permanente, no una escritura suelta: las tres opciones de entidades/tipo_asociacion (18,19,20) estan soft-deleted desde el 2025-12-11 EN LAS DOS BASES, asi que el catalogo que el nombre promete esta retirado entero y el formulario no tiene nada que ofrecer. src/repositories/rendiciones.ts:226 ya califica solo tipo_persona. PROD NO PUEDE ATESTIGUAR ESTO: 9 de las 38 columnas tienen 0 filas no nulas en PROD, y las dos del defecto estan entre ellas. En DEV 8 de esas 9 tienen filas. Medir la clase solo en PROD devuelve 0 violaciones con denominador vacio - linea verde, no control. Cualquier control futuro corre en las DOS bases. LIMITE DEL INSTRUMENTO, explicito en el doc: detecta MEZCLA (mas de un catalogo por columna), NO error consistente - una columna cuyas filas apunten TODAS al catalogo equivocado se ve como catalogos=1 y pasa limpia; asi se ve tipo_asociacion_id, que encontre por el nombre y no con el instrumento. De las 38, 2 estan MEDIDAS y 36 juzgadas por coincidencia de nombre, que no es medicion; las de si/no van a general/respuesta_binaria como manda la regla dura, pero para el resto no hay ninguna fuente de catalogo esperado por columna. Control positivo del censo: el split 35/3, que la misma corrida reporto. La deteccion de error consistente NO tiene control positivo y no se afirma cobertura sobre ella. SIN EJERCITAR: ninguna escritura, pantalla ni formulario; el vinculo con el codigo es lectura de fuente. licencias_choferes no tiene creado_por ni creado_en, asi que la provenance de sus 3 filas se derivo de la persona 171 y de la banda de ids, no de la fila.
-
researcher-mba-l-cc 2026-10-08 19:08 ART / 22:08 UTC - sub-nota estatica sobre los 36 FK juzgados por coincidencia de nombre (los 2 ya medidos por db03 quedan afuera). ALCANCE REAL: el censo de db03 no deja el listado de las 38 columnas en ningun artefacto - el instrumento se maneja desde pg_constraint, no de una lista escrita. El doc nombra 18 de las 38 (los 2 medidos, las 9 si/no, y 7 de las 9 con 0 filas en PROD). Las otras 20 NO estan nombradas en ningun lado que yo pueda leer sin consultar pg_constraint - no puedo clasificarlas ni por nombre ni por codigo. Esto queda SIN EJERCITAR, no resuelto. De las 16 nombradas que SI pude revisar (18 nombradas - 2 ya medidas): PROMOVIDAS a medido por lectura de codigo (el repositorio SI califica con un join a (grupo_nombre, campo_nombre) al leer la columna, mismo patron que los 2 casos ya medidos de db03): - personas_datos_chofer.ambito_id - src/repositories/parque-movil.ts:532, qualifica grupo_nombre='chofer' AND campo_nombre='ambito'. - validadoras.modalidad_id, validadoras.tipo_id, validadoras_historial.evento_tipo_id - src/repositories/validadoras.ts:107,153-157, qualifica grupo_nombre='validadoras' AND campo_nombre IN ('tipo_validadora','modalidad_validadora','evento_tipo'). Las 4 quedan MEDIDAS POR CODIGO, no por query - nadie corrio una consulta contra filas vivas para estas 4, solo se confirmo que el lector SI restringe el catalogo esperado. Sigue sin saberse si alguna fila viva viola esto hoy. SIGUEN NECESITANDO QUERY - sin join calificado en ningun lector encontrado: - direcciones_postales.tipo_direccion_id (src/repositories/direcciones-postales.ts) - recorridos.sentido_id (src/repositories/recorridos.ts) - rutap.vehiculo_historial_normalizado.motivo_id (src/services/vehiculos.ts) Ninguna fuente de catalogo esperado para estas 3 - igual que las 29 restantes que el doc de db03 ya marca sin fuente. LAS 9 SI/NO (adas_presente_id, wifi_id, mdvr_id, pantallas_id, conexiones_usb, identidad_id, cabina_antivandalica_id, aire_acondicionado_id, carroceria_aire_acondicionado_id): revisadas en src/repositories/vehiculos.ts - el catalogo esperado SI se conoce con certeza (general/respuesta_binaria, regla dura del proyecto), pero el lector las trae con SELECT directo, SIN ningun join calificado contra opciones. No se promueven a medido: la regla da el catalogo esperado, el codigo no lo verifica al leer, y ninguna query corrio sobre sus filas vivas. Quedan en una categoria intermedia: EXPECTED CONOCIDO, NI CODIGO NI QUERY LO VERIFICAN. EXTENSION del limite de db03 (no se repite, se extiende): el instrumento de db03 ve mezcla y no ve error consistente. Esta revision de codigo tiene el MISMO limite en espejo - un lector que SI califica (como los 4 promovidos) prueba que el codigo pide el catalogo correcto, pero no prueba que ninguna fila ya grabada antes de esa lectura, o escrita por otro camino (import, SQL directo, otra pantalla), cumpla la condicion. Medido por codigo no es medido por dato. Control positivo de esta sub-nota: ninguno corrido - esto es lectura de fuente, 0 queries.
-
db03-mba-l-cc 2026-10-08 22:13Z - AMPLIADO con las dos cosas que faltaban, las dos medidas en PROD y DEV, SELECT only. Nuevos pins: docs/reference/movilba-763-censo-fk-opciones.md sha256 ef86973d6eb979022ef17cb68f83ad3cc8bd173e83f94bc558d42f76a48e2c70, tools/movilba-763-censo-fk-opciones.sql sha256 e9441ed4677f6ca2a2e556a8c188ac4f630743b3d69302140b309e6e3a3d3005. Los pins anteriores (9d569170 / 9203090e) quedan RETIRADOS. 1. LAS 38 ENUMERADAS. El doc trae la tabla completa: tabla, columna, nombre de constraint, y el catalogo al que apuntan las filas que HAY en cada base por separado. Identicas en las dos bases - mismas tablas, mismas columnas, mismos nombres de constraint. El instrumento se reescribio para emitir la enumeracion en vez de un resumen, asi que la lista se re-deriva corriendo el archivo y no hay que confiar en la tabla. 2. LAS DE SI/NO SON 16, NO 9, Y ESTAN MEDIDAS. El conteo de 16 sale de la enumeracion: 8 en rutap.vehiculo_historial_normalizado (adas_presente_id, aire_acondicionado_id, cabina_antivandalica_id, conexiones_usb_id, identidad_id, mdvr_id, pantallas_id, wifi_id), 7 espejo en vehiculos_datos_colectivos (adas_presente_id, cabina_antivandalica_id, conexiones_usb, identidad_id, mdvr_id, pantallas_id, wifi_id) y carrocerias.carroceria_aire_acondicionado_id. RESULTADO: las 16 llevan unicamente 24 y 25, con 0 filas fuera de {24,25} en PROD y 0 en DEV. Repartos por columna y base en el doc. CONTROL POSITIVO CORRIDO Y VISTO DISPARAR, porque un 0 sin control es una linea verde: el mismo predicado not in (24,25) contra rutap.vehiculo_historial_normalizado.piso_id - que no es campo de si/no - marca 5695 filas en DEV, y contra wifi_id marca 0. El predicado puede fallar; el 0 de las 16 es medido. Asi que la parte del limite que corresponde se DISUELVE, no se repite: para las 16 de si/no el error consistente ES detectable porque la regla fija el catalogo de antemano, y esta medido en 0. El limite sobrevive solo para las otras 20: de las 38, 16 medidas contra una regla, 2 medidas por mezcla (clase_licencia_id, y tipo_asociacion_id encontrada por nombre), 20 juzgadas por coincidencia de nombre, que no es medicion, y sin tabla de catalogo esperado por columna que las convierta en medibles. 3. NADA PARA MOVILBA-738: ninguna columna de si/no lleva un id no binario en ninguna base. HALLAZGO LATERAL de la enumeracion, no es violacion de catalogo: vhn.unidad_propulsora_id y vehiculos.motor_unidad_propulsora_id llevan en DEV los ids 31 COMBUSTION_NAFTA y 33 COMBUSTION_BIODIESEL - 2+1 y 1+1 filas - ausentes en PROD. Son opciones vivas del catalogo correcto motor/unidad_propulsora, asi que es divergencia de filas de prueba de DEV, no deriva ni etiqueta ajena. SIN EJERCITAR, igual que antes: ninguna escritura, pantalla, formulario ni import; el vinculo con el codigo sigue siendo lectura de fuente.
-
db03-mba-l-cc / solo
-
db03 2026-10-08 ART, taking this item - it was inProgress with no assigned agent, so nobody owned it although its two artifacts were already in the shared checkout. Both are untracked, so they exist only as files in this working tree and nothing has verdicted them. Pinned and handed to audit with this note. PINS, taken with sha256sum against the shared checkout as the last step before writing this, not copied from an earlier note: - tools/movilba-763-censo-fk-opciones.sql e9441ed4677f6ca2a2e556a8c188ac4f630743b3d69302140b309e6e3a3d3005 - UNCHANGED from the sha I pinned at 22:13. - docs/reference/movilba-763-censo-fk-opciones.md ceb920eb5c9c3000f41f3e6ac445ea5e3504e0bf7ae1e26ac48663ab8aaf5734 - MOVED. At 22:13 I pinned it at ef86973d6eb979022ef17cb68f83ad3cc8bd173e83f94bc558d42f76a48e2c70, and that earlier pin is withdrawn rather than corrected: the file is untracked, there is no git object for ef86973d, so those bytes exist nowhere and no diff of the two revisions is possible on this host. I do not know what changed or who changed it, and I am not going to guess from the content - a plausible story about an edit is not evidence of one. This is the second artifact of mine tonight in that state; the other is the MOVILBA-371 doc, note of 01:58:49.085Z there. SO THE PIN IS NOT THE VERDICT-RELEVANT CLAIM, and the substitute is a re-measurement. What a verdict needs is whether the document as it stands is true of the two bases, and that I can test without the old bytes. Re-ran the figures the document rests on, SELECT-only, server clock 2026-10-08 23:0x-03 both bases. Every one reproduces: - STRUCTURE, the headline 39/38/1: FKs to public.opciones are 38 with one column and exactly 1 with three columns, identical in PROD and DEV. Same figure independently re-measured at 22:58 for MOVILBA-371, so two items now rest on the same re-verified number. - THE 16 SI/NO COLUMNS, the only subset the document claims is measured against a RULE: all 16 measured, 0 rows outside {24,25} in PROD and 0 in DEV. The distinct-value sets collapse to exactly two shapes, '24,25' and '24' alone - the latter being carrocerias.carroceria_aire_acondicionado_id, which the document already calls out as all-24 with no 25 in either base. The loop carries a coverage assert and it is not decorative: it raises unless it measured exactly 16 columns, and it printed 'COBERTURA si/no: 16 columnas medidas' in both bases. - THE POSITIVE CONTROL for that predicate: 'NOT IN (24,25)' against rutap.vehiculo_historial_normalizado.piso_id, which is not a yes/no field, marks 5695 of 5695 rows in DEV - the document's figure exactly - and 5558 of 5558 in PROD. The predicate fires; the 0 on the 16 is a measured 0. - THE MIXTURE CONTROL: licencias_choferes.clase_licencia_id still splits 35 rows personas/clase_licencia and 3 rows licencia/clase_lnc in DEV, and returns no rows at all in PROD. - THE EMPTY-IN-PROD SET: all 9 columns the document names count 0 non-null rows in PROD, and in DEV 8 of the 9 are populated - tipo_asociacion_id 2, tipo_direccion_id 6, clase_licencia_id 38, ambito_id 1, recorridos.sentido_id 1, validadoras.modalidad_id 46, validadoras.tipo_id 46, validadoras_historial.evento_tipo_id 59 - with motivo_id the only one empty in both. That is the document's claim reproduced column by column rather than as a count. WHAT THE RE-MEASUREMENT DOES NOT COVER, and it is the honest gap: it tests the document's FIGURES, not its PROSE. An edit between ef86973d and ceb920eb that changed wording, attribution or a conclusion while leaving every number alone is invisible to this instrument. Audit reviewing ceb920eb is reviewing bytes whose numbers I have just re-verified and whose edit history I cannot produce. CROSS-ITEM NOTE so nobody re-derives it: this document's own 'No medido aqui' already carries the retraction that matters - the census is driven from pg_constraint and therefore CANNOT see a column that stores an opciones id without declaring the FK, which is the other half of MOVILBA-738, so my earlier line that there was nothing here for 738 was the instrument and not the world. Those seven columns are measured in the MOVILBA-371 document and re-verified there at 22:58 today. NOT EXERCISED: the two revisions were not diffed, because that is not possible here; no screen, form, export or API was touched; the 20 columns the document marks as judged by name coincidence are still judged by name coincidence, with no expected-catalog source in existence; and no DDL was drafted or rehearsed for any of the 38.
-
db03 2026-10-08 ART. The park-return mechanism is real and I am not disputing it, but the ONE testable prediction it makes about this document FAILS, and the reason is a clock offset that makes every timestamp in this thread legible the wrong way round. Measured before writing. THE OFFSET FIRST, because nothing else here parses without it. bwi stamps createdAt in UTC; the lanes write ART in their note bodies; filesystem mtimes are ART. So my note "22:13" on this item is 22:13 UTC = 19:13 ART, and my MOVILBA-371 and MOVILBA-738 notes "22:33" are 19:33 ART. The 22:28:43 ART restore is therefore about three hours AFTER those notes, not fifteen minutes after. Read as same-zone, the sequence looks impossible - a document whose mtime is 22:28 citing a document I announced at 22:33 - and that apparent impossibility is the whole reason to check rather than accept the story. THE PREDICTION THAT FAILS. If the 22:28 return restored bytes from before my edit, the current document must be MISSING what my 19:13 note says I added. It is not. Every item of that amendment is present in ceb920eb: the full 38-row enumeration with constraint names and the per-base catalog column (:42-:83), the 16 yes/no columns named and measured with 0 outside {24,25} in both bases (:87-:91), the positive control on piso_id at 5695 in DEV (:93), the dissolved-limit framing of 16 measured against a rule / 2 by mixture / 20 by name coincidence (:95-:101), and the unidad_propulsora hallazgo lateral (:85). AND IT CARRIES CONTENT THAT POSTDATES THAT NOTE. Section "No medido aqui" at :105 cites docs/reference/movilba-371-unidad-propulsora-no-libro.md and the seven no-FK columns, and retracts my earlier line that there was nothing here for MOVILBA-738. That measurement is from 19:33 ART, twenty minutes after the 19:13 pin. So the restored bytes are NEWER than ef86973d, not older: what the return put back is an amendment of mine made after 19:13 that I never pinned in bwi. That is why ceb920eb differs from ef86973d while losing nothing the pin described. WHAT THAT CHANGES AND WHAT IT DOES NOT. It does not clear the mechanism - 45 files rewritten at 22:28:43 ART with sub-millisecond spacing is not a lane editing, and docs/reference/movilba-763-censo-fk-opciones.md at .117842588 shares its timestamp to the nanosecond with tools/movilba-371-censo-unidad-propulsora.sql, which no editing session produces. It does mean this document is not an instance of content loss, and that "my return put the pre-edit bytes back" is not what happened HERE. For the other two files the direction is different again: the MOVILBA-371 doc is 22:37:29 ART and tools/verification/movilba-738-censo-fk-opciones.sql is 22:38:16, both AFTER the restore, so those are live bytes and the pins I took tonight at 35c8f109 and c017c024 are post-restore and safe. STILL UNRESOLVED AND I CANNOT CLOSE IT: which revision ceb920eb actually is. It is a state between 19:13 and the park, and the unpinned amendment inside it was never hashed when written, so the gap between "contains everything I pinned, plus a later section" and "is byte-identical to what I last saved" cannot be closed from here. The figures are re-verified against both bases in my note of 02:05:42.068Z; the prose remains unverifiable, as stated there. ONE MORE FILE IN THAT CLUSTER THAT IS MINE: agents/db03-mba-l/MEMORY.md at 22:28:43.094842587. It is TRACKED and currently modified against HEAD, so unlike the two docs it has a pre-image and is recoverable if anything was reverted. I have not diffed it in this pass and am not claiming it is intact. NOT EXERCISED: no diff of any revision, because none exists for the untracked files; no attempt to recover ef86973d; git stash list and the stash reflog not inspected by me, so coder03's statement that a popped stash leaves no trace is taken as reported and not independently measured.
-
# MOVILBA-763 - audit verdict: PASS. Author db03-mba-l-cc. audit-mba-l-cc, 2026-10-08 tools/movilba-763-censo-fk-opciones.sql e9441ed4677f6ca2a2e556a8c188ac4f630743b3d69302140b309e6e3a3d3005 docs/reference/movilba-763-censo-fk-opciones.md ceb920eb5c9c3000f41f3e6ac445ea5e3504e0bf7ae1e26ac48663ab8aaf5734 Both untracked, pins exact against what db03's 02:05:42Z note names as current. I take db03's own position on the ef86973d/ceb920eb gap: the old pin is withdrawn, no git object exists for it, no diff is possible, and the figures - not the prose history - are what a verdict needs. I re-ran the instrument myself rather than trust db03's re-measurement. ## Instrument run fresh, both bases, SELECT only psql $DEV_DATABASE_URL -f tools/movilba-763-censo-fk-opciones.sql rc=0, 38 rows, 1 composite FK psql $SUPERUSER_ELAZAR_URL (PROD) -f same rc=0, 38 rows, 1 composite FK Structure matches the doc's 39/38/1 exactly in both bases. PROD's 9 zero-row columns, read straight off my own run's `<0 filas no nulas>` rows: asociaciones_entidad_persona.tipo_asociacion_id, direcciones_postales.tipo_direccion_id, licencias_choferes.clase_licencia_id, personas_datos_chofer.ambito_id, recorridos.sentido_id, rutap.vehiculo_historial_normalizado.motivo_id, validadoras.modalidad_id, validadoras.tipo_id, validadoras_historial.evento_tipo_id - matches the doc's list name for name, 9 for 9. DEV's clase_licencia_id reparto from my own run: 38-44=5 each (35, personas/clase_licencia) + 293=2,295=1 (3, licencia/clase_lnc) = the doc's 35/3 split exactly. tipo_asociacion_id: 113=2 [personas/tipo_persona], matches. ## The 16 si/no columns and the positive control, queried directly, both bases `NOT IN (24,25)` on all 16 named columns (8 in rutap.vehiculo_historial_normalizado, 7 mirrored in vehiculos_datos_colectivos, carrocerias.carroceria_aire_acondicionado_id): 0 in every column, PROD and DEV, 16 for 16. Positive control, same predicate against piso_id (not a si/no column): DEV 5695, PROD 5558 - matches the doc's two figures exactly. The predicate fires; the 16 zeroes are measured, not inert. ## Scope of what I did and did not re-verify I did not re-derive the 20-columns-judged-by-name-coincidence set, researcher's 4 code-qualified promotions, or db03's clock-offset reconciliation on the pin history - those are prose/code-reading claims, not figures this instrument re-tests, and db03's own notes already flag that gap. What I verified is every number the document states as measured: the structure count, the 9-empty-in-PROD list, the 35/3 and 113/2 reparto, and the 16/0 si/no result with its positive control. ## NOT EXERCISED No write of any kind. The 20 name-judged columns remain unmeasured by anyone pending a catalog-expectation table that does not exist. No DDL rehearsed for the composite-FK retrofit question, which the doc itself defers.
-
audit pass: Both pins (sql e9441ed4, md ceb920eb) verified; instrument re-run fresh against PROD and DEV by me, not trusted from db03's re-measurement; 38/1 structure, 9-empty-in-PROD list, 35/3 and 113/2 repartos, 16 si/no + piso_id control all re-queried directly.
payload
{"scope":"Both pins (sql e9441ed4, md ceb920eb) verified; instrument re-run fresh against PROD and DEV by me, not trusted from db03's re-measurement; 38/1 structure, 9-empty-in-PROD list, 35/3 and 113/2 repartos, 16 si/no + piso_id control all re-queried directly.","outcome":"pass","evidence":"rc=0 both bases, 38 rows/1 composite both. 9 empty-in-PROD column names match exactly. DEV clase_licencia_id 38-44=5x7=35 + 293=2/295=1=3 matches 35/3; tipo_asociacion_id 113=2 matches. 16 si/no NOT IN (24,25): 0 in all 16, both bases. Positive control piso_id: DEV 5695, PROD 5558, matches doc exactly. Did not re-derive the 20 name-judged columns or researcher's code-qualification promotions - prose/code claims, not instrument figures.","reportRef":null} -
Shipeado. dev d08f7376 patch 226, prod patch 226, health verde al primer intento en las dos patas. Los cinco pines re-hasheados por mi contra el arbol como ultimo paso antes del commit: 371 md 35c8f109 y sql 68f5a67c, 763 md ceb920eb y sql e9441ed4, 738 sql 6ad786d2 - este ultimo SIN VEREDICTO y nombrado PENDIENTE en el mensaje de commit, porque 738 esta cerrado como item pero su artefacto nunca se audito y el item instrumento MOVILBA-774 sigue en backlog. Entra igual porque sin commit no hay pre-imagen: ninguna enmienda a un archivo untracked se puede verificar despues como solo-prosa, el commit ES el control. El arbol de los otros carriles se parkeo para la pata de prod y volvio verificado POR ARCHIVO: diff de trackeados contra el stash vacio y los 21 blobs untracked restantes identicos. POD en 223 y pedido a proxy-mba-w-cc, asi que la paridad de flota sigue abierta. SIN EJERCITAR: son censos y SQL de solo lectura, ninguna consulta corrio desde estos bytes en este commit, ninguna pantalla ni ruta cambia, y el .sql de 738 no tiene camino de ship que lo ejecute.