Tutorial: sistema médico (supervisión humana HOTL)
🟡 Parcial — El escenario medical.json ejecuta la evaluación ex-ante completa (11 controles, gate VERDE). El control de peor subgrupo (worst-subgroup-dice) es AUDIT: incumple en valor puntual pero NO bloquea el gate; el riesgo se trata con supervisión humana HOTL declarada (Art.14). La evaluación no corre en CI hermético (requiere GPU + caché TCIA).
Este tutorial recorre el escenario medical de Venturalítica: un dispositivo médico de software (SaMD) de alto riesgo bajo la MDR (Reg. UE 2017/745) y el EU AI Act Anexo III §6. El motor de segmentación vertebral es TotalSegmentator operando sobre la cohorte pública TCIA Spine-Mets-CT-SEG (≈55 casos CT reales). Los fragmentos de configuración que aparecen abajo son ejemplos ilustrativos: muestran cómo se escribe un sei.yaml para un sistema de imagen médica, no un volcado literal de fichero interno alguno.
Lo que aprenderás:
- Cómo el motor gestiona un sistema de imagen médica con métricas de segmentación (Dice,
es_dice) y de equidad (score_gap,worst_cell_score) - Por qué el gate puede quedar VERDE aun habiendo un control AUDIT incumplido (el peor subgrupo): un control AUDIT registra el residual pero no bloquea
- Cómo se trata ese residual con supervisión humana HOTL (Art.14, control
human-oversight-worst-case-review), no con un cambio de parámetro ni de código - Cómo se aplica el marco MDR vía
frameworksen el programa de riesgos (la secciónrisk:desei.yaml) - El contraste con
tutoriales/primer-sistema(loan = cambio de código): mismo motor, distinto marco regulatorio
Contexto del proyecto
Sección titulada «Contexto del proyecto»medical modela un dispositivo médico de software (SaMD) de segmentación vertebral para planificación quirúrgica raquídea:
- Alto riesgo bajo MDR Anexo I (dispositivo médico de software) y EU AI Act Anexo III §6
- Tarea: segmentación volumétrica de vértebras en TC
- Modelo: TotalSegmentator v2 (BYO, sin fine-tuning propio)
- Cohorte: TCIA Spine-Mets-CT-SEG — ~55 casos CT reales con metástasis espinales (cohorte efectiva ≈33 tras filtrado), multi-escáner, multi-protocolo
- Pipeline: DVC, un único stage
evaluate(segmenta en memoria, sin CSV intermedio — eliminado por ser PHI-shaped y fuente de staleness) - AssuranceProgram (la sección
risk:desei.yaml): 4 riesgos, 14 medidas → 11 controles ex-ante
La medición de exactitud es el Dice (coeficiente de similitud de Sørensen) por caso, con intervalo de confianza bootstrap por cluster de paciente. Las métricas de equidad son es_dice (Equity-Scaled Dice, FairSeg ICLR’24) y score_gap.
Paso 1 — Preparar el entorno
Sección titulada «Paso 1 — Preparar el entorno»-
Asegúrate de que
seiestá compilado:Terminal sei --helpDeben aparecer los 16 subcomandos. Si no, sigue la guía de instalación.
-
Crea un directorio de trabajo y copia los ficheros del escenario:
Terminal mkdir /tmp/medical && cd /tmp/medicalcp -r /ruta/a/seigarrena/crates/seigarrena-cli/tests/resources/medical/. . -
Inicializa git y DVC, y registra los metadatos de cohorte:
Terminal git initdvc initdvc add data/trusted_metadata.csvgit add sei.yaml dvc.yaml \data/trusted_metadata.csv.dvc data/cohort.croissant.json \eval/ .dvc/ .gitignore -
Crea el entorno Python con
uv:Terminal uv venv .venvuv pip install \"venturalitica[imaging]==0.6.12" \"dvc>=3" \"TotalSegmentator" \"monai" "nibabel" "pydicom" "pydicom-seg" \"SimpleITK" "pandas" "numpy" "pyyaml"venturalitica[imaging]incluye las métricas de segmentación nativas del registry (Dice, NSD,es_dice,score_gap), disponibles desde la versión 0.6.12.
Paso 2 — Los ficheros del proyecto
Sección titulada «Paso 2 — Los ficheros del proyecto»medical/├── sei.yaml # Manifiesto del sistema (incluye el programa de riesgos Art. 9 + MDR)├── shared_data/policies/ # destino del assessment_plan OSCAL que genera sei compile├── dvc.yaml # Pipeline: 1 stage `evaluate` (en memoria, sin CSV)├── data/│ ├── trusted_metadata.csv # Metadatos de adquisición reales (TCIA vía NBIA API)│ └── cohort.croissant.json # Gobernanza §2 (Croissant, EU AI Act Art. 10)└── eval/ ├── eval.py # Stage DVC: segmenta en memoria + audita con SDK ├── segment.py # segment_cohort() — TotalSegmentator/GPU └── dicom_utils.py # Utilidades DICOM/SEGsei.yaml — el manifiesto
Sección titulada «sei.yaml — el manifiesto»A continuación, una versión ilustrativa y abreviada del manifiesto (el bloque risks: se resume; el fichero del escenario lo trae completo). Sirve para entender la forma del sei.yaml:
apiVersion: seigarrena.dev/v1alpha1kind: AISystemsystem: name: spine-segmentation intended_purpose: "Segmentacion vertebral en TC sobre cohorte de validacion (eval-only)."task: modality: image type: segmentationeval: { script: eval/eval.py }pipeline: { tool: dvc, metrics: metrics.json }oscal: { assessment_plan: shared_data/policies/assessment_plan.oscal.yaml }dataset: { croissant: data/cohort.croissant.json }artifacts: model: { kind: totalsegmentator, seed: 0 }risk: appetite: { individual: HIGH, society: HIGH, organization: HIGH } criteria: { scale: "5x5" } risks: # 4 riesgos con sus medidas (cada una con frameworks MDR) — ver tabla abajoEl apetito se fija en HIGH para las tres dimensiones: el dispositivo opera en un entorno de alto riesgo (MDR) donde el apetito es mayor que en un sistema financiero. Los controles gate (Dice global, equidad por sexo/edad, robustez por escáner) deben superar el umbral clínico para que el gate quede VERDE; los controles audit (como el peor subgrupo) registran su valor pero no lo bloquean.
dvc.yaml — un único stage
Sección titulada «dvc.yaml — un único stage»El pipeline tiene un solo stage evaluate que segmenta la cohorte en memoria (no persiste un CSV intermedio) y audita los resultados contra el assessment_plan OSCAL:
stages: evaluate: cmd: .venv/bin/python eval/eval.py deps: - eval/eval.py - eval/segment.py - eval/dicom_utils.py - data/trusted_metadata.csv - shared_data/policies/assessment_plan.oscal.yaml metrics: - metrics.json: cache: falseEl handoff entre segmentación y auditoría es en memoria: segment_cohort() devuelve un DataFrame con una columna Dice por paciente, que el SDK evalúa como métricas de registry (mean_score, worst_cell_score, es_dice, etc.) con power-stats por cluster de paciente.
La sección risk: — 4 riesgos, regulación dual
Sección titulada «La sección risk: — 4 riesgos, regulación dual»El AssuranceProgram (la sección risk: de sei.yaml) declara 4 riesgos con 14 medidas. Cada medida lleva frameworks: [eu/mdr@2017#gspr-<n>] — el GSPR del Anexo I de la MDR que corresponde a ese control:
| Riesgo | Medidas clave | GSPR MDR |
|---|---|---|
risk.subgroup-segmentation-bias | worst-subgroup-dice (audit, crítico — no bloquea), human-oversight-worst-case-review (HOTL, Art.14) | GSPR-9 (control de riesgo) |
risk.segmentation-accuracy-failure | vertebra-segmentation-dice (gate), data-leakage-check (gate) | GSPR-17.1 (rendimiento del software) |
risk.data-governance-failure | fairness-sex-disparate-impact (es_dice, gate), privacy-k-anonymity (gate) | GSPR-17.1 (gobernanza del dato) |
risk.scanner-protocol-bias | robustness-scanner-bias, fairness-scanner-model (ambos gate) | GSPR-17.1 (rendimiento multi-escáner) |
worst-subgroup-dice tiene enforcement: audit (severity: critical pero no bloqueante): registra el peor subgrupo y superficia el residual honestamente, pero no tumba el gate. La cobertura gate de cl. 9.2 de prEN 18228 la aportan vertebra-segmentation-dice y fairness-sex-disparate-impact (ambos enforcement: gate).
Los dos controles post-market (postmarket-subgroup-drift, postmarket-dice-drift) y la supervisión HOTL (human-oversight-worst-case-review) tienen lifecycle: [monitoring]: sei compile los excluye de los 11 controles ex-ante del assessment_plan (14 medidas − 3 de monitoring = 11).
Consulta Las tres modalidades de tratamiento para el encuadre regulatorio completo de cada riesgo.
Paso 3 — sei compile: AssuranceProgram → OSCAL (11 controles ex-ante)
Sección titulada «Paso 3 — sei compile: AssuranceProgram → OSCAL (11 controles ex-ante)»sei compilesei compile lee la sección risk: de sei.yaml, arma el AssuranceProgram en memoria y genera shared_data/policies/assessment_plan.oscal.yaml con los 11 controles ex-ante (excluye los dos de lifecycle: [monitoring]). Este fichero es la dependencia del stage evaluate en DVC; su digest entra en dvc.lock y en el bundle firmado.
git add shared_data/policies/assessment_plan.oscal.yamlgit commit -m "init medical REAL (cohorte TCIA + TotalSegmentator en GPU; online, sin cohort_results.csv)"Consulta la referencia del CLI sei para los detalles del subcomando compile.
Paso 4 — sei run: evaluación ex-ante con gate VERDE y un control AUDIT incumplido
Sección titulada «Paso 4 — sei run: evaluación ex-ante con gate VERDE y un control AUDIT incumplido»sei runsei run dispara dvc repro, que ejecuta el stage evaluate:
segment_cohort()pasa todas las imágenes TCIA por TotalSegmentator/GPU y devuelve un DataFrame con el Dice real por caso- El SDK (
vl.enforce(data=df, cluster=PatientID, phase=validation)) evalúa los 11 controles del assessment_plan con power-stats por cluster de paciente - El motor aplica el gate y firma el bundle
Resultado real documentado: sei run devuelve exit 0 — gate VERDE. El modelo es apto globalmente (Dice global ≈0.90). Los resultados son:
| Control | Operador | Umbral | Resultado | Enforcement | Estado |
|---|---|---|---|---|---|
vertebra-segmentation-dice | > | 0.85 | ~0.90 (global) | gate | PASA |
data-leakage-check | < | 0.99 | (ningún Dice≈1.0) | gate | PASA |
fairness-sex-disparate-impact | > | 0.80 | apto (es_dice) | gate | PASA |
worst-subgroup-dice | > | 0.75 | por debajo (peor celda) | audit (no bloquea) | INCUMPLE (registrado) |
El gate queda VERDE porque todos los controles enforcement: gate pasan (Dice global, equidad por sexo/edad, robustez por escáner, k-anonimato). El control worst-subgroup-dice (GSPR-9 MDR, severity: critical) incumple en valor puntual —el peor subgrupo compuesto cae en casos atípicos— pero tiene enforcement: audit: registra el residual y lo superficia honestamente en el Anexo IV §4, sin tumbar el gate. El peor subgrupo en una cohorte pequeña con casos atípicos es una limitación del modelo BYO, no un defecto que se corrija con un gate; se trata con supervisión humana (HOTL), no gateando a verde.
Verifica la firma y el estado:
sei verify # OK — la firma ECDSA-P256+DSSE+in-toto es válidasei status # exit 0 — gate VERDE (imprime worst-subgroup-dice como control AUDIT incumplido)sei status devuelve exit 0 (gate verde) e imprime worst-subgroup-dice porque es un control AUDIT incumplido —para que quede visible el residual—, pero no pone el gate en rojo.
Paso 5 — El tratamiento del residual de subgrupo: supervisión humana HOTL (Art.14)
Sección titulada «Paso 5 — El tratamiento del residual de subgrupo: supervisión humana HOTL (Art.14)»El control worst-subgroup-dice incumple en valor puntual, pero es audit (no bloquea): el gate ya está VERDE. El residual de subgrupo no se trata con un cambio de parámetro ni de código —el modelo es BYO (TotalSegmentator), no se reentrena—, sino con un control organizativo declarado ex-ante: la supervisión humana en el bucle (HOTL, Art.14).
En la sección risk: del riesgo risk.subgroup-segmentation-bias, el tratamiento es method: REDUCE con controls: [eu/ai-act@2024#art-15, eu/ai-act@2024#art-14], y el control confirmante es:
- id: human-oversight-worst-case-review metric: hotl_worst_case_review_declared constraint: "> 0" severity: high enforcement: audit evaluation: manual lifecycle: [monitoring] article: "14" frameworks: [eu/mdr@2017#gspr-17.1] standard_clauses: ["eu/pren-18228@2026#14", "iso/42105@2026#intervention"]Un clínico valida la segmentación de los casos peor-subgrupo antes de su uso aguas abajo (planificación quirúrgica). El control se declara ex-ante en el manifiesto y opera post-market (Fase 2, lifecycle: [monitoring]): por eso sei compile lo excluye de los 11 controles ex-ante, pero queda registrado como medio de conformidad del Art.14.
Declarar esa supervisión es el tratamiento ISO 23894 §6.5: un cambio versionado en sei.yaml, con autoría y fecha, que documenta la respuesta proporcionada al residual de subgrupo.
git commit -m "treat(medical): declarar supervisión HOTL (Art.14) para los casos peor-subgrupo"Ver Las tres modalidades de tratamiento para el encuadre regulatorio de la modalidad de supervisión humana.
Paso 6 — Estado del escenario: gate VERDE, residual tratado
Sección titulada «Paso 6 — Estado del escenario: gate VERDE, residual tratado»sei verify # OK — bundle firmado, gate VERDEsei status # exit 0 — gate VERDE; worst-subgroup-dice listado como control AUDIT incumplidoEl escenario medical.json termina aquí: el gate es VERDE, el modelo es apto globalmente (Dice global ≈0.90) y el residual de subgrupo queda registrado (por el control audit worst-subgroup-dice) y tratado (por la supervisión HOTL declarada). No hay un arco FALLA→PASA por ajuste de parámetro: el gate nunca estuvo rojo. El ciclo ISO 23894 §6.5 del riesgo risk.subgroup-segmentation-bias queda cerrado por el tratamiento HOTL, no por re-medición.
Paso 7 — sei conformance: proyección MDR + EU AI Act
Sección titulada «Paso 7 — sei conformance: proyección MDR + EU AI Act»sei conformance --standard eu/pren-18228@2026 --outEl mismo bundle proyecta sobre prEN 18228 (el estándar armonizado de gestión de riesgos, Art. 9):
| Cláusula | Resultado | Por qué |
|---|---|---|
| cl. 9.2 (medidas de control) | Cubierta | La aportan los controles gate vertebra-segmentation-dice y fairness-sex-disparate-impact (enforcement: gate, alineados con cl. 9.2); worst-subgroup-dice es audit (confirmante, no aporta la cobertura gate) |
| cl. 10 (residual global) | Cubierta / Hueco | El motor agrega el residual global (evaluate_overall_residual()) y sei conformance cl.10 emite CUBIERTA o HUECO; solo es advisory en el gate de sei run |
sei conformance --standard iso/23894@2023Proyección ISO 23894: la cláusula §6.5 queda cubierta cuando el ciclo de risk.subgroup-segmentation-bias está cerrado (aquí, por el tratamiento HOTL declarado).
El campo frameworks: [eu/mdr@2017#gspr-9] en la sección risk: hace que el bundle incluya la trazabilidad MDR en los informes de conformidad sin anotación adicional.
El Anexo IV (Art. 11) no lo emite el motor: lo ensambla y renderiza la nube (plano de control) desde el bundle.json firmado, con procedencia por campo, y lo entrega como PDF. No hay subcomando sei annex-iv. La nube puede marcar PENDIENTE §2/§3/§4/§9 si falta su insumo (datos / misuse+residuales+Art.14 / resultados de control / medidas post-market); §7 y §8 nunca son pendientes. En este escenario, con datos y controles presentes, solo §3 y §9 quedarían pendientes. Ver Guía: Renderizar el Anexo IV.
Contraste con tutoriales/primer-sistema (loan)
Sección titulada «Contraste con tutoriales/primer-sistema (loan)»| Dimensión | loan (crédito) | medical (imagen médica) |
|---|---|---|
| Marco regulatorio | EU AI Act + DORA (ent. financiera) | EU AI Act + MDR (SaMD) |
| Modalidad de tratamiento | Cambio de código (train.py V1→V2, fairlearn) | Supervisión humana HOTL (Art.14, control organizativo declarado) |
| Modelo | LogReg, entrenado in-pipeline | TotalSegmentator v2, BYO (sin fine-tuning) |
| Métrica principal | demographic_parity_diff (tabla) | Dice volumétrico (imagen) |
| Equidad | disparate_impact (binaria, por género) | es_dice (ESSP, equidad sobre Dice continuo) |
| Power-stats | Bootstrap por muestra (n=1000) | Bootstrap por cluster de paciente (n≈33 efectivo) |
| Gate en T0 | ROJO — control global falla (equidad) | VERDE — todos los controles gate pasan; el peor subgrupo (audit) registra el residual |
| Respuesta al residual | Re-entrenar (Deriva B: modelo cambia) | Declarar supervisión HOTL (control organizativo, modelo y datos sin cambios) |
El motor es el mismo en los dos escenarios. El seam Reproducer despacha dvc repro en ambos casos. Lo que cambia es la modalidad de tratamiento y el marco regulatorio — que se declara en el AssuranceProgram vía frameworks y se proyecta en los informes de conformidad sin modificar el motor.
Lo que este tutorial demuestra
Sección titulada «Lo que este tutorial demuestra»- Un AssuranceProgram con regulación dual (EU AI Act + MDR) declarada por medida vía
frameworks - 11 controles ex-ante generados por
sei compiledesde 4 riesgos y 14 medidas (excluye 3 delifecycle: [monitoring]) - Un gate VERDE sobre una cohorte GPU real: todos los controles gate pasan (Dice global ≈0.90); el peor subgrupo (audit) registra el residual sin bloquear
- El tratamiento por supervisión humana HOTL (Art.14): un control organizativo declarado ex-ante, no un cambio de parámetro ni de código
- SUBPODERADO honesto: en cohorte efectiva ≈33 los ICs bootstrap son anchos; el peor subgrupo se modela como audit precisamente porque en n pequeño puede ser ruido
- Conformidad dual proyectada sobre el mismo bundle: prEN 18228 + ISO 23894
Huecos pendientes
Sección titulada «Huecos pendientes»| Hueco | Por qué importa |
|---|---|
| HOTL declarado ex-ante, operación post-market sin datos en vivo | El control human-oversight-worst-case-review documenta el plan; la evidencia de revisión clínica es runtime (Fase 2) |
| NSD / HD95 como cross-check | El caveat de sesgo-por-tamaño del Dice (arXiv 2509.19778) exige contrastar con métricas de borde; línea futura |
Controles post-market (postmarket-subgroup-drift) | Sólo ex-ante en v1; Art. 72 no modelado en el motor |
| Anexo IV §3/§9 PENDIENTE en este escenario | §2/§3/§4/§9 pueden quedar pendientes si falta su insumo; aquí solo §3 y §9 (dependen del entorno del deployer); §7 y §8 nunca son pendientes |
Consulta Estado e incompletitudes para el mapa completo de huecos.