Barrido completo de .py trackeados en git con 60+ días sin commit, cruzados contra los 5 entry points de producción, los workflows de CI, y duplicados por nombre de archivo en todo el repo.
El clon estaba superficial (52 commits, todo dentro de la última semana) — se hizo git fetch --unshallow
antes de fechar nada, porque con historia truncada cada archivo aparece falsamente "reciente". Con historia completa
(hasta abril), el corte real de 60+ días dio 112 archivos, no los ~30 esperados. El hallazgo central
no es un fósil aislado como el de ayer: es un patrón sistémico. 31 archivos implementan lógica que,
por nombre, docstring o cita directa en CLAUDE.md, debería estar en el camino de decisión — y no lo está.
signal_quality_gate.py de ayerEse caso no era una excepción — es la firma de un patrón que se repite en al menos ocho subsistemas: el gate de
Causal Closure Score completo (4 archivos, con test unitario propio que nunca se conecta al scorer), el trío
Ockham/dissent/planner-acotado, todo vigia/abduction/ (93KB, el núcleo teórico peirceano), el pilar
geopolítico de falsa bandera (dos versiones, ambas muertas), y el propio vigia_core_semiotic_detector.py
— un stub de 4 líneas que siempre retorna "NORMAL" si algo lo llegara a cablear por error.
Cuatro hallazgos individuales antes que los clusters temáticos, porque no son "código sin usar" — son riesgos activos o casos con evidencia de daño ya ocurrido.
vigia/governance/risk_bounded_layer_v2.py
pre_release_check.py afirma que v2 es la versión activa en producción. No lo es:
vigia/pipeline/pipeline.py importa vigia.core.risk_bounded_layer (sin _v2) directamente.
Peor — las dos definen posterior con semántica opuesta: la versión viva usa
P = P(fabricación | evidencia); la huérfana v2 tiene un fix P0-001 documentado que usa
P = P(autenticidad | evidencia), con una advertencia explícita en el propio código:
"si algún desarrollador futuro interpreta P como P(fabricación), TODOS los veredictos se invertirán."
El archivo vivo no tiene ese guard.
Esto es la capa de governance del veredicto en sí misma. Necesita revisión de ingeniería antes que cualquier otro ítem de esta lista.
vigia/core/signal_contract.py
No es hipotético: tests/test_eml_import_regression.py documenta que este archivo —un re-export de una
línea que colisiona de nombre con el SignalBuilder real en vigia/tools/signal_contract.py—
ya causó que tres módulos vivos (eml_symbolic.py, eml_gci.py, signal_adapter.py)
importaran desde el lugar equivocado, recibieran ImportError, y quedaran silenciosamente al 0% de
cobertura hasta que alguien lo notó.
Prueba directa de que un huérfano por colisión de nombre no es "inerte" — ya rompió producción una vez.
vigia/core/vigia_core_semiotic_detector.py
Cuatro líneas: analyze() retorna incondicionalmente {"alert_level": "NORMAL", ...} —
un no-op hardcodeado. Está deprecado según pre_release_check.py, pero si alguna vez se cablea por
accidente en lugar del detector real, no falla con error: deshabilita la detección semiótica en completo silencio.
El peor tipo de fósil — uno que falla cerrado hacia "todo normal" en vez de fallar ruidosamente.
vigia/cli.py
Implementa su propio verificador de cadena de hash (verify_manifest, verify_ledger)
con un esquema simple, sin HMAC — exactamente el patrón "legacy v1" que CLAUDE.md
dice que no debe usarse para investigaciones nuevas. No es forensics/verify_ebs_v1.py ni
verify_tool_log.py (los canónicos). Alguien podría correrlo esperando protección HMAC equivalente
y obtener un falso "verificado" sobre un bundle alterado.
Ninguno es un archivo aislado — cada cluster representa una capacidad completa, con frecuencia testeada de forma aislada, que nunca llegó a conectarse al scorer o al bridge vivos.
El gate matemático que CLAUDE.md describe como "cap en ABSTAIN por debajo del 50% de cierre causal" — construido, testeado, nunca invocado por el scorer real.
Penalidad Ockham anti-SolarWinds, escalación por disenso minoritario, límite de Miller para abducción, detección de tampering de config — todos invariantes que CLAUDE.md describe como parte de la arquitectura viva.
normalization_layer.py se autodocumenta como "el único checkpoint obligatorio" — calco textual del patrón signal_quality_gate.
Detección de anacronismo/falsificación de fecha, comparación dual fitz/pypdf para evasión de PDF, timestamping RFC 3161 independiente, entropía espacial para esteganografía. Ninguno es un duplicado — cada uno es una capacidad ausente del pipeline vivo.
Ambas cuelgan de vigia/vigia_core.py, un monolito legacy con cero importadores en todo el repo — el "Quinto Pilar" de atribución APT/falsa-bandera está completamente fuera de producción.
semiotic_detector.py es duplicado de semiotic_detector_v2.py, pero el estado "vivo" de v2 mismo depende solo de dev tooling y tests, no confirmado alcanzable desde vigia_scorer.py — vale una verificación adicional de ingeniería.
La cadena generate_calibration.py → fit_calibration.py → calibrated_lr_models.pkl no es alcanzable desde ningún entry point ni CI. Vale confirmar si los .pkl que carga el LikelihoodEngine en producción realmente salieron de este código.
Cero importadores del namespace vigia.abduction en todo el repo. Es la maquinaria de linaje de hipótesis y contrafactuales — el corazón teórico peirceano del proyecto — completamente aislado.
Su propio docstring ordena "importar desde vigia_sift_bridge.py; no dispersar lógica de seguridad" — el bridge nunca lo hace. Implementa una whitelist de subprocess sin equivalente confirmado en el sandbox vivo.
Filtrable por categoría y buscable por ruta. Ordenada por prioridad de categoría y luego por antigüedad.
| Archivo | Última modificación | Días | Categoría | Cluster | Justificación |
|---|
El repo llegó con git rev-parse --is-shallow-repository → true (52 commits, todos de la última semana).
Con esa historia, git log -1 sobre cualquier archivo sin cambios desde antes del límite del shallow-clone
devuelve la fecha del commit límite, no la fecha real — ocultando exactamente los fósiles que este barrido busca.
Se corrió git fetch --unshallow antes de fechar nada; la historia completa retrocede hasta el 21 de abril.
Se parseó con AST cada uno de los 402 .py trackeados, se construyó un grafo dirigido de imports
(incluyendo imports relativos resueltos por paquete), y se calculó BFS desde los 5 entry points reales:
vigia_agent.py, vigia/core/vigia_scorer.py, vigia/vigia_sift_bridge.py,
vigia/tools/vigia_planner.py, vigia/pipeline/pipeline.py. Se corrigió un falso negativo:
un __init__.py es cargado implícitamente por Python en cuanto cualquier submódulo del paquete se importa,
así que se propagó alcanzabilidad a los __init__.py ancestros de todo módulo alcanzado.
Se leyeron los 3 workflows (pytest.yml, vigia-forensic-ci.yml, docker-publish.yml).
pytest.yml corre pytest tests/ vigia/tests/ sin --ignore, así que todo
test_*.py bajo esos árboles se considera "conectado" por auto-discovery, incluso sin importador directo.
Se detectó una referencia rota: vigia-forensic-ci.yml invoca tests/test_integration_end_to_end.py
(ruta que no existe — el archivo real vive en tests/e2e/), con el fallo silenciado por || true.
Se agrupó cada basename no-__init__.py del repo; donde ≥2 rutas comparten nombre y al menos una
está en el corte de 60 días, se verificó con diff -q si eran idénticas byte a byte, y se leyó el
contenido de cada una para distinguir shim deliberado (p. ej. la capa engine/·forensics/·
governance/·models/ en la raíz, confirmada como re-exports de una línea usados por el
verificador EBS v1 independiente y aislados a propósito de vigia/) de duplicado muerto por deriva de código.
Los 68 archivos sin señal mecánica clara de "vivo" se repartieron en lotes de 17 para lectura de contenido —
docstrings, imports internos, y cruce contra pre_release_check.py / BANNED_MODULES /
docs/AUDITORIA_FUGA_INDIRECTA.md donde el propio repo ya documentaba el estado de un archivo.
Un caso se reconciliyó entre lotes: vigia/memory/__init__.py se había marcado ALTO RIESGO
independientemente hasta cruzar con el hallazgo de que su único contenido, case_pattern_library.py,
es un duplicado superado confirmado — se reclasificó a BAJO RIESGO.
importlib.import_module
con nombre construido en runtime no se detectan (se buscó ese patrón específicamente en los entry points y no apareció).