Ir al contenido

Nivel 3 · El arco, por traspasos

Cuatro hitos. Como en los niveles anteriores, los tres roles están presentes desde el primero: 🧭 Nerea arriba (portal · producto), 🛡️ Diego en medio (portal · calidad), 🧑‍💻 Marta a la derecha (CLI + git). La lección de este arco es el VERDE que no basta: la barrera de sensibilidad pasa de ROJO a VERDE limpio (no un ámbar honesto, un verde de verdad) — y aun así el ciclo se pausa en «solicitado», porque un dispositivo médico MDR clase IIa no puede cerrar su conformidad sobre su propia atestación. El motor firma evidencia; no es un organismo notificado.

Los datos duros de cada hito —los comandos, el mensaje de commit, el diff y el color de la barrera— no están escritos a mano: cada bloque GuionStep los lee del guion steps/ del repositorio publicado. Si un paso no existiera, el build fallaría; lo que lees aquí es exactamente lo que el repositorio hace.

1Declarar el SaMD (Art. 6(1) + MDR) y el riesgo de infradiagnóstico
🧭 Nerea

Nerea es la responsable de producto en la clínica que despliega el sistema de cribado de retinopatía diabética. Abre el portal y ejecuta las misiones de autoría que generan el manifiesto de gobernanza froga.yaml. Tres cosas importan, y la segunda es nueva:

  1. El nivel es high, declarado por un humano, vía la ruta de seguridad de productos. La misión classify-system rellena el bloque classification con la justificación: «Art. 6(1) (componente de seguridad de un dispositivo médico — SaMD MDR clase IIa)». La activación de alto riesgo aquí es Art. 6(1) + Anexo I, no el Anexo III. El motor no lo infiere; Nerea lo declara y lo asume.
  2. Se declaran dos regímenes, y uno es la superposición. La misión declare-standards escribe applicable_standards con la columna vertebral (eu/ai-act@2024, eu/pren-18228@2026, iso/23894@2023) más eu/mdr@2017 — la superposición MDR. Sin DORA (no es una entidad financiera). Declarar eu/mdr@2017 es lo que hace que el motor emita el cruce documental MDR más adelante.
  3. El riesgo es la seguridad del paciente. La misión identify-risks añade risk.dr-underdiagnosis«un falso negativo priva al paciente del tratamiento a tiempo, con riesgo de pérdida visual irreversible.» Inherente: PROBABLE × CRÍTICO (individual). Supera el apetito y exige tratamiento. El control que confirmará el residual es la sensibilidad en retinopatía diabética (recall) — una barrera clínica bloqueante, model-dr-sensitivity > 0,80.

Las tres misiones abren un PR en el repositorio del sistema. El turno pasa a Diego, que lo revisa e integra. En el guion, la identidad, el encuadre y el programa de riesgos quedan como tres commits del manifiesto froga.yaml —el diff del último muestra el riesgo de seguridad del paciente con su barrera numérica fijada antes de que exista modelo:

Identidad del sistema (froga init + patch) Nerea
Contexto y estándares aplicables (SaMD MDR Clase IIa, Art.6(1)) Nerea
Programa de riesgos con gates numéricos (antes del modelo) Nerea
🛡️ Diego

Diego recibe el PR que abrieron las misiones de Nerea, revisa que el manifiesto sea correcto — nivel high por Art. 6(1) + Anexo I (SaMD MDR clase IIa), normas eu/ai-act@2024 + eu/pren-18228@2026 + iso/23894@2023 + eu/mdr@2017, riesgo de seguridad del paciente con vocabulario completo — e integra el PR. El froga.yaml declarado queda en el repositorio.

🧑‍💻 Marta

Todavía no hay nada que medir, pero Marta deja el reproductor listo en git: el proyecto uv + DVC y el dataset real ODIR-5K (etiquetas y metadatos versionados; las imágenes ~2 GB se leen de la caché en build) con su manifiesto Croissant ya son commits del guion:

Repo, identidad, proyecto uv (uv init + deps resnet18/LogReg), DVC, pubkey y README del reproductor Marta
Comandos
15
  • git init -q -b main
  • git config user.email marta@demo.seigarrena.dev
  • git config user.name "Marta Demo"
  • uv init --bare --name vldemo-retina-screening --python 3.12
  • patch: pyproject-index.patch
  • uv add "dvc>=3" pyyaml froga "venturalitica==0.6.11" "torch==2.12.0" "torchvision==0.27.0" "scikit-learn>=1.4" "pandas>=2.1" pyarrow "pillow>=10.0" "numpy>=1.26" "mlcroissant>=1.0" joblib
  • patch: gitignore.patch
  • patch: gitattributes.patch
  • patch: readme.patch
  • uv sync
  • uv run dvc init --no-scm -q
  • uv run dvc config core.analytics false
  • froga pubkey --out .froga/PUBKEY.txt
  • git add -A
  • git commit -m "init: repo, proyecto uv (deps reales) y README del reproductor"
Dataset ODIR-5K + manifiesto Croissant + versionado DVC Marta

Con el manifiesto declarado y el andamiaje en git, el turno pasa a medir (hito 2).

Venturalíticademo.venturalitica.ai
DeclaradoSiguiente: ejecutar y medir
Venturalíticademo.venturalitica.ai
¿Qué categoría del Anexo III aplica?
¿Qué clase MDR aplica al dispositivo?
¿Algún régimen adicional?
Venturalíticademo.venturalitica.ai
Riesgos significativos
IDTítuloProbabilidadImpacto individualImpacto socialImpacto organizaciónAsignar tratamiento a (opcional)
1
2
3
4
5
6
2Medir la V1: la sensibilidad DR (recall) sale en rojo
🛡️ Diego

Esperando. Nerea ha declarado el sistema y Diego lo ha integrado; ahora Diego espera la primera medición de Marta. No toca la CLI: cuando Marta informe del color de la barrera, verá si el riesgo de seguridad del paciente es real y cuánto supera el apetito.

🧑‍💻 Marta

Marta mide el sistema tal como está — el riesgo inherente, sin tratar. Primero compila el contrato de la barrera desde froga.yaml —qué controles se van a medir y con qué umbral—:

Compilar el plan de evaluación OSCAL (antes del modelo) Marta
Comandos
  • froga compile
  • git add -A
  • git commit -m "compile: assessment plan OSCAL (contrato del gate, antes del modelo)"

Ahora añade el modelo base —un cribador resnet18 + LogReg en el umbral por defecto y con desequilibrio de clases— y corre la evidencia. froga run reproduce el pipeline, mide los controles y aplica la barrera:

Modelo resnet18+LogReg base V1 — escribe Y corre (gate RED esperado) MartaVeredicto esperadoROJO
📍 reproducir retina-v1.0.0-red
git clone https://github.com/Venturalitica/vldemo-retina-screening
cd vldemo-retina-screening
git switch -c try retina-v1.0.0-red
Comandos
  • patch: params.patch
  • patch: dvc.patch
  • patch: train.patch
  • patch: evaluate.patch
  • patch: compliance-eval.patch
  • froga runpuede fallar
  • git add -A
  • git commit -m "modelo: resnet18+LogReg V1 (train/evaluate + dvc.yaml) — run: V1 evidencia base (gate RED esperado; seed=42)"

El control model-dr-sensitivity vuelve ROJO, y por qué es el punto:

  • recall_score = 0,4165, barrera > 0,80, gravedad crítica, aplicación bloqueopassed: false.

Un recall de 0,4165 significa que el cribador pierde bastante más de la mitad de los casos verdaderos de retinopatía diabética. El comando sale con un código de error distinto de cero —de ahí el aviso «puede fallar» sobre froga run— pero el paquete sigue firmado y anclado: un resultado ROJO es evidencia, registrada honestamente.

El riesgo es real y supera el apetito; necesita tratamiento. Esta confirmación de evidencia V1 queda congelada en el checkpoint de arriba, retina-v1.0.0-red.

Venturalíticademo.venturalitica.ai
Evaluado · ROJO
3Tratar el riesgo: reentrenar balanceado + umbral 0,30 → verde limpio
🛡️ Diego

Esperando. Diego ha visto el ROJO — el cribador pierde demasiados casos. No toca git; espera la evidencia vuelta a medir, donde leerá el residual y el color de la barrera. Verá no solo un color, sino por qué: el motor informa del intervalo de confianza, no solo de la estimación puntual.

🧑‍💻 Marta

Este es el tratamiento (ISO 23894 §6.5, «tratamiento del riesgo»). Como en cada nivel, el cambio versionado es el reemplazo de train.py; el diff es el tratamiento, y en un mismo paso Marta trata y vuelve a medir.

El nuevo train.py trae la mecánica propia de este nivel: Marta reentrena el cribador con ponderación equilibrada de clases para que la clase minoritaria de retinopatía diabética no quede ahogada, y baja el umbral de decisión a 0,30 para que un ojo dudoso sea derivado en lugar de pasado por alto. Ambas medidas cambian un poco de precisión por bastante sensibilidad — la decisión correcta para una herramienta de cribado, donde un fallo de detección es mucho peor que una sobrederivación. (En el N1 el tratamiento añade las características del pétalo; en el N2 intercambia el aprendiz por fairlearn. El git diff tiene la misma forma —un cambio de código versionado en train.py—; lo que cambia es su naturaleza.) El modelo tratado deja obsoleta la evaluación, así que el mismo paso reentrena y vuelve a medir — el paso de GPU que observas en lugar de ejecutar:

Tratamiento: reentrena balanceado + umbral 0.30 (§6.5) — escribe Y corre (gate VERDE) MartaVeredicto esperadoVERDE
📍 reproducir retina-v2.0.0-green
git clone https://github.com/Venturalitica/vldemo-retina-screening
cd vldemo-retina-screening
git switch -c try retina-v2.0.0-green
Comandos
  • patch: train-treatment.patch
  • froga run
  • git add -A
  • git commit -m "treatment: reentrena el cribador DR con clase balanceada + umbral 0.30 (recupera la sensibilidad recall > 0.80) — ISO 23894 §6.5"

La barrera se vuelve VERDE — y esta vez, limpiamente:

  • recall_score = 0,8847, barrera > 0,80, aplicación bloqueopassed: true.
  • Bloque de potencia: bootstrap IC 95 % [0,8516, 0,9127], bootstrap por clúster de paciente (n = 1279 ojos, 1160 clústeres de paciente, semilla 42).

Lee el IC honestamente, como enseñó el Nivel 2: el borde inferior es 0,8516, cómodamente por encima de la línea 0,80. El intervalo completo supera la barrera, así que el motor no activa inconclusive(). Este es un VERDE limpio, no un ámbar.

Verde limpio, firmado, en git — congelado en el checkpoint de arriba, retina-v2.0.0-green. Y sin embargo — como muestra el siguiente hito — eso todavía no es suficiente para cerrar el ciclo.

Venturalíticademo.venturalitica.ai
Tratado · VERDE
4Gobernanza en pausa: conformidad, solicitud y sin aprobación (falta el organismo notificado)
🛡️ Diego

La evidencia firmada y VERDE limpio de Marta está en el repositorio, con la conformidad ya emitida (columna de Marta). En el Nivel 1 un verde limpio significaba una aprobación limpia; en el Nivel 2 un ámbar honesto se aprobó con la brecha en el registro. Aquí ocurre algo diferente — y ahí está la clave de todo el nivel.

Diego revisa el paquete, verifica la firma de Marta, ve la barrera de seguridad del paciente en verde y el residual dentro del apetito — y no aprueba. No hay froga approve. El estado del ciclo de vida queda en draft; approval es null. El ciclo se detiene en «solicitado».

🧑‍💻 Marta

Marta cierra su parte del ciclo desde la CLI. Con la V2 en VERDE limpio, emite la conformidad y el reconstruct firmados sobre las normas aplicables (incluido el cruce documental eu/mdr@2017), y solicita la aprobación:

Conformance + reconstruct firmados (entitlement + 6 normas) Marta
Comandos
  • patch: entitlement.patch
  • froga conformance --standard eu/pren-18228@2026 --outpuede fallar
  • froga conformance --standard iso/23894@2023 --outpuede fallar
  • froga conformance --standard eu/ai-act@2024 --outpuede fallar
  • froga conformance --standard eu/mdr@2017 --outpuede fallar
  • froga conformance --standard eu/pren-18283@2026 --outpuede fallar
  • froga conformance --standard eu/pren-18282@2026 --outpuede fallar
  • froga reconstruct --outpuede fallar
  • git add -A
  • git commit -m ".froga: conformance + reconstruct firmados"
Solicitar aprobación (froga request) — verde firmado, ciclo en pausa: sin organismo notificado Marta
📍 reproducir retina-v2.0.0-request
git clone https://github.com/Venturalitica/vldemo-retina-screening
cd vldemo-retina-screening
git switch -c try retina-v2.0.0-request
git commitsolicitud de aprobación (el acto lo commitea froga request)

Y ahí termina el guion. No hay paso de aprobación, y no lo hay a propósito: el ciclo de un dispositivo clase IIa no puede cerrarse por el fabricante en absoluto, así que no hay conformidad que re-emitir sobre un estado Aprobado que nunca llega. Marta produjo y firmó la evidencia VERDE limpio; el resto no le corresponde a ella otorgar, ni a Diego conceder. El sistema queda declarado, tratado, firmado y solicitado — anclado en la etiqueta retina-v2.0.0-request del checkpoint de arriba —, honestamente pendiente del organismo notificado. Ese es el final del arco: un borrador, solicitado, nunca aprobado.

Venturalíticademo.venturalitica.ai
El ciclo queda en «solicitado»
Pendiente: evaluación por organismo notificado (MDR Art. 52)Un dispositivo médico de Clase IIa no puede cerrarse por autodeclaración.