Saltar a contenido

Matriz de evidencias

Responde: para cada objetivo comprometido, ¿qué lo implementa, qué decisión lo respalda y qué lo verifica?

Es el artefacto que busca un tribunal: la cadena que conecta lo que se prometió con lo que se puede mostrar. Cada fila es rastreable hasta un archivo de un repositorio, fijado por commit.

La cadena de trazabilidad está completa desde el 2026-10-14

La forma ideal de esta matriz es objetivo → caso de uso o historia → requisito → decisión → PR o release → prueba. Hasta el 2026-10-14 faltaban dos eslabones. Los dos se cerraron ese día:

Eslabón Cómo se cerró
Historias de usuario (US-0xx) El enunciado completo de las veinte apareció en el anexo del Informe de Avance 1, entregado el 2025-08-20. No son reconstrucciones derivadas del código: son el texto original con sus criterios de aceptación. Ver historias de usuario
Release Los cinco repositorios no tenían tags —no cuatro, como decía esta página—. Se fijó v1.0.0-rc1 sobre los commits que estaban efectivamente desplegados en producción. Ver releases

La matriz se construye entonces sobre la cadena completa. Donde una verificación no existe se dice, en lugar de inventarla: esa severidad no cambia.

Cómo leer el estado

Símbolo Significa
✅ Implementado y verificable
◑ Parcial: hay implementación, con una limitación declarada
✗ No implementado

La columna Verificación es la más severa a propósito: dice qué prueba automatizada cubre el objetivo, no qué se probó a mano alguna vez. Lo que se prueba fuera del CI, con fecha y versión, se registra en evidencias de pruebas integrales.


La matriz

Objetivo 1 — Modelo de arquitectura con conectividad Raspberry Pi ↔ nube

Estado ✅
Implementación Cuatro piezas en dos ubicaciones, con InfluxDB como desacople dentro de la Pi
Evidencia Contexto C4 · Contenedores C4 · Flujo de datos
Decisión SYS-ADR-001
Verificación Ninguna automatizada. Es un objetivo de diseño: su evidencia es documental

Objetivo 2 — Servicio en Raspberry Pi que reciba datos del PLC

Estado ✅
Implementación historian (Python, Modbus TCP de solo lectura) + Edge Pi Service (Go)
Evidencia src/historian/ del historian · internal/app/forwarder/ del Edge
Decisión SYS-ADR-001 · SYS-ADR-007 · EDGE-ADR-001 a 010
Verificación ✅ La mejor del sistema: el CI del historian levanta una InfluxDB real, corre el componente contra ella y verifica por consulta que los puntos llegaron. El CI del Edge compila para arm64 y corre sus tests unitarios
Limitación Nunca corrió en una Raspberry Pi real: el stack se verificó en amd64

Objetivo 3 — Almacenamiento local y remoto

Estado ✅
Implementación Local: InfluxDB (series) y SQLite (outbox). Remoto: Postgres (identidad y configuración) y MongoDB (mediciones)
Evidencia SYS-ADR-003 · migrations/ del Cloud
Decisión SYS-ADR-003, que reemplaza a CLOUD-ADR-003
Verificación ⚠️ Los tests de integración existen y el CI los saltea por no proveer bases
Limitación Ninguna de las bases tiene política de retención ni respaldos propios

Objetivo 4 — Dashboard con visualización en tiempo real e histórica

Estado ◑ parcial
Implementación 32 widgets definidos, con grilla y hasta 3 disposiciones por cliente. 14 consumen métricas reales; los otros 18 siguen con datos simulados
Evidencia src/lib/widget-registry.ts del frontend · catálogo de variables
Decisión FE-ADR-009: los datos simulados se conservan hasta que exista el backend que los reemplace
Verificación ⚠️ Tests del frontend; los E2E no bloquean el despliegue. Y la validación de aasPath tiene un defecto: ver abajo
Limitación 3 de los 32 widgets, los de alarma, están deshabilitados y no muestran datos: ver widgets

Objetivo 5 — Sistema de alertas automáticas

Estado ✗ no implementado
Implementación Existe el modelo de datos de reglas y notificaciones, su API y su interfaz. No existe código que evalúe las reglas
Evidencia internal/api/handler/alarm_rules/ e internal/app/alarm_rules/ del Cloud: son CRUD. No hay módulo de evaluación
Decisión FE-ADR-014 (2026-10-04, cátedra y equipo): el módulo no se expone en el MVP y el objetivo se declara no alcanzado. SYS-ADR-007 acota qué puede hacer una alarma —notificar, nunca actuar sobre la máquina—; FE-ADR-014 explica su ausencia
Verificación —
Limitación Es el único de los diez objetivos sin cumplir, y ahora está declarado como tal, no pendiente de decisión. La interfaz lo marca: ítem «Alertas» deshabilitado con cartel «Pendiente», campana oculta. Ver bitácora de alcance

Objetivo 6 — Estructurar los datos para análisis e inteligencia de negocio

Estado ✅
Implementación Semántica del estándar AAS de punta a punta: el aasPath identifica cada variable en los cuatro repositorios y se persiste con cada medición
Evidencia Catálogo de variables · Flujo de datos
Decisión SYS-ADR-004 · EDGE-ADR-007 · FE-ADR-010
Verificación ⚠️ Existe un control en el CI del frontend, y no detecta el defecto que debía detectar: ver abajo
Observación El AAS no estaba en el anteproyecto. Es la adición conceptual más grande del proyecto: ver bitácora

Objetivo 7 — Interfaces adaptadas a los perfiles fabricante y cliente

Estado ✅
Implementación Subsistema multi-tenant con 7 roles, catálogo de permisos en base, invitaciones y operadores de plataforma con acceso cruzado
Evidencia Seguridad · migrations/ del Cloud
Decisión CLOUD-ADR-015 · FE-ADR-001 · FE-ADR-007 · FE-ADR-008
Verificación ⚠️ El aislamiento entre clientes no tiene prueba automatizada contra una base real. Lo impone el código: el backend conecta con un rol que bypassea el control por fila
Observación Excede lo pedido: ver bitácora

Objetivo 8 — Trazabilidad por registros históricos y logs

Estado ◑ parcial
Implementación Servicio de logs con su API, y mediciones históricas con identificador de evento determinista e idempotencia por cliente
Evidencia internal/app/logs/ del Cloud · SYS-ADR-002
Decisión SYS-ADR-002
Verificación ⚠️ El índice único que sostiene toda la idempotencia no se verifica en CI
Limitación La calidad del dato no viaja: una lectura fallida es indistinguible de una máquina detenida. Y los logs de la Pi rotan, así que un incidente de ayer no se puede investigar

Objetivo 9 — Autenticación, cifrado y seguridad

Estado ◑ con deudas declaradas
Implementación Identidad delegada con verificación de firma contra claves públicas; patrón BFF; claves de dispositivo hasheadas con comparación en tiempo constante; permisos por rol desde la base
Evidencia Seguridad — el modelo completo y sus cinco debilidades verificadas
Decisión SYS-ADR-005 · CLOUD-ADR-002 y -015 · FE-ADR-002 a -004, -008
Verificación ⚠️ Tests unitarios. Nada verifica el aislamiento ni los controles contra una base real
Limitación Cinco debilidades sin corregir, de las cuales la más seria es que el aislamiento entre clientes depende del código. El cifrado en tránsito depende del despliegue, no del código

Objetivo 10 — Entorno visual interactivo de análisis y seguimiento

Estado ✅
Implementación Dashboard con disposiciones configurables y persistidas por cliente, catálogo de widgets y alta desde la interfaz
Evidencia src/lib/widget-registry.ts y la API de disposiciones del Cloud
Decisión FE-ADR-001
Verificación ⚠️ E2E con Playwright que no bloquean el despliegue
Limitación Los informes que el anteproyecto lista como componente del alcance no existen: no hay servicio de reportes

Lo que la matriz revela al mirarla entera

Tres cosas que no se ven fila por fila.

1 · Nueve de diez objetivos tienen implementación; casi ninguno tiene verificación automatizada

De los diez objetivos, uno solo tiene una prueba de integración real que lo respalde: el objetivo 2, gracias al CI del componente externo. Los demás se apoyan en tests unitarios, en pruebas que no bloquean el despliegue, o en nada.

Es la brecha más importante del proyecto desde el punto de vista de la defensa: "está implementado" y "está verificado" no son lo mismo, y la matriz lo hace visible.

2 · El control que debía proteger el objetivo 6 no detecta el defecto que existe

!!! danger "La validación de aasPath del frontend pasó una semana en verde sobre 3 literales rotos" Corregido el 2026-10-07 — el cierre está al final de esta admonición. El hallazgo se conserva porque es uno de los resultados del trabajo de reconciliación, y porque la forma del error es más instructiva que el error.

`FE-ADR-010` decidió, el 2026-09-30, validar cada `aasPath` del dashboard contra el catálogo
canónico del historian, fijado a un tag. El script existe y corre en el CI.

**Verificado ejecutándolo**: devuelve
`aaspath-check OK — 14 aasPath (10 distintos) existen en el catálogo canónico` y sale con
código 0.

Pero 3 de esos 14 literales **nunca van a devolver datos**, porque el Edge escribe
`Alarmas//paradaEmergencia` —con el segmento de colección vacío— y el dashboard pide
`Alarmas/paradaEmergencia`.

La causa está en cómo el script compone las rutas del catálogo: omite el segmento vacío,
que es la convención del **frontend**, no la del **Edge**. Su propio comentario lo dice:
*"la misma forma que usa widget-registry"*. Así que el control **compara el frontend contra
sí mismo**, y confirma que es internamente coherente — mientras que lo único que importa es
lo que el Edge efectivamente escribe, porque el Cloud compara por igualdad exacta.

No es un reproche al control: su diseño es correcto y su ADR descarta bien las
alternativas. Es un **error de un carácter en la composición**, y es justamente el tipo de
cosa que solo se ve mirando los dos repositorios a la vez.

**Cómo se cerró, el 2026-10-07.** Primero la decisión de sistema
([`SYS-ADR-009`](../arquitectura/decisiones/sys-adr-009.md)), que eligió colapsar el
segmento vacío; después el Edge, que lo aplicó (`EDGE-ADR-012`); después el frontend, que
dejó de implementar la regla por su cuenta y pasó a derivarla de un único módulo con test
propio, leyendo el YAML canónico (`FE-ADR-015`, que reemplaza a `FE-ADR-010`). El control
se volvió a ejecutar y pasa —ahora por la razón correcta—. Queda el paso 3: dejarlo
bloqueante en PR.

La decisión que fijó la forma canónica, con los dos caminos analizados y su costo, es
[`SYS-ADR-009`](../arquitectura/decisiones/sys-adr-009.md). Cambia el identificador de los
eventos de alarma ya almacenados, que quedan fuera del alcance de una consulta por la forma
nueva: ver [catálogo de variables](../integraciones/catalogo-variables.md).

3 · Los objetivos cumplidos lo están con una limitación declarada

Ninguna fila dice "✅" a secas. Seis tienen limitación explícita, y eso es deliberado: una matriz donde todo está verde no es creíble y no resiste una pregunta del tribunal. Cada limitación está documentada en la página que la analiza, no inventada acá.


Fuentes

  • Los diez objetivos específicos: el anteproyecto, hoy en docs/_process/pendiente-hub/embolsadora-4.0.md del frontend
  • Ausencia de motor de alarmas y de servicio de reportes: los árboles internal/api/handler/ e internal/app/ del Cloud
  • Validación de aasPath: scripts/check-aas-paths.mjs y scripts/lib/aas-path.mjs del frontend
  • Composición del aasPath: internal/domain/aas/catalog.go del Edge y su test en internal/app/forwarder/grouper_test.go
  • Integración real en el CI del historian: .github/workflows/ci.yml y ci_verify.py
  • Integración salteada en el CI del Cloud y E2E no bloqueantes en el del frontend: sus respectivos workflows

Relacionado