Ir al contenido

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 frameworks en el programa de riesgos (la sección risk: de sei.yaml)
  • El contraste con tutoriales/primer-sistema (loan = cambio de código): mismo motor, distinto marco regulatorio

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: de sei.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.


  1. Asegúrate de que sei está compilado:

    Terminal
    sei --help

    Deben aparecer los 16 subcomandos. Si no, sigue la guía de instalación.

  2. Crea un directorio de trabajo y copia los ficheros del escenario:

    Terminal
    mkdir /tmp/medical && cd /tmp/medical
    cp -r /ruta/a/seigarrena/crates/seigarrena-cli/tests/resources/medical/. .
  3. Inicializa git y DVC, y registra los metadatos de cohorte:

    Terminal
    git init
    dvc init
    dvc add data/trusted_metadata.csv
    git add sei.yaml dvc.yaml \
    data/trusted_metadata.csv.dvc data/cohort.croissant.json \
    eval/ .dvc/ .gitignore
  4. Crea el entorno Python con uv:

    Terminal
    uv venv .venv
    uv 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.


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/SEG

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:

sei.yaml (abreviado, ilustrativo)
apiVersion: seigarrena.dev/v1alpha1
kind: AISystem
system:
name: spine-segmentation
intended_purpose: "Segmentacion vertebral en TC sobre cohorte de validacion (eval-only)."
task:
modality: image
type: segmentation
eval: { 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 abajo

El 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.

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:

dvc.yaml (extracto)
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: false

El 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:

RiesgoMedidas claveGSPR MDR
risk.subgroup-segmentation-biasworst-subgroup-dice (audit, crítico — no bloquea), human-oversight-worst-case-review (HOTL, Art.14)GSPR-9 (control de riesgo)
risk.segmentation-accuracy-failurevertebra-segmentation-dice (gate), data-leakage-check (gate)GSPR-17.1 (rendimiento del software)
risk.data-governance-failurefairness-sex-disparate-impact (es_dice, gate), privacy-k-anonymity (gate)GSPR-17.1 (gobernanza del dato)
risk.scanner-protocol-biasrobustness-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)»
Terminal
sei compile

sei 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.

Terminal
git add shared_data/policies/assessment_plan.oscal.yaml
git 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»
Terminal
sei run

sei run dispara dvc repro, que ejecuta el stage evaluate:

  1. segment_cohort() pasa todas las imágenes TCIA por TotalSegmentator/GPU y devuelve un DataFrame con el Dice real por caso
  2. 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
  3. 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:

ControlOperadorUmbralResultadoEnforcementEstado
vertebra-segmentation-dice>0.85~0.90 (global)gatePASA
data-leakage-check<0.99(ningún Dice≈1.0)gatePASA
fairness-sex-disparate-impact>0.80apto (es_dice)gatePASA
worst-subgroup-dice>0.75por 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:

Terminal
sei verify # OK — la firma ECDSA-P256+DSSE+in-toto es válida
sei 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:

sei.yaml (extracto del riesgo de subgrupo)
- 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.

Terminal
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»
Terminal
sei verify # OK — bundle firmado, gate VERDE
sei status # exit 0 — gate VERDE; worst-subgroup-dice listado como control AUDIT incumplido

El 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»
Terminal
sei conformance --standard eu/pren-18228@2026 --out

El mismo bundle proyecta sobre prEN 18228 (el estándar armonizado de gestión de riesgos, Art. 9):

CláusulaResultadoPor qué
cl. 9.2 (medidas de control)CubiertaLa 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 / HuecoEl 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
Terminal
sei conformance --standard iso/23894@2023

Proyecció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ónloan (crédito)medical (imagen médica)
Marco regulatorioEU AI Act + DORA (ent. financiera)EU AI Act + MDR (SaMD)
Modalidad de tratamientoCambio de código (train.py V1→V2, fairlearn)Supervisión humana HOTL (Art.14, control organizativo declarado)
ModeloLogReg, entrenado in-pipelineTotalSegmentator v2, BYO (sin fine-tuning)
Métrica principaldemographic_parity_diff (tabla)Dice volumétrico (imagen)
Equidaddisparate_impact (binaria, por género)es_dice (ESSP, equidad sobre Dice continuo)
Power-statsBootstrap por muestra (n=1000)Bootstrap por cluster de paciente (n≈33 efectivo)
Gate en T0ROJO — control global falla (equidad)VERDE — todos los controles gate pasan; el peor subgrupo (audit) registra el residual
Respuesta al residualRe-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.


  1. Un AssuranceProgram con regulación dual (EU AI Act + MDR) declarada por medida vía frameworks
  2. 11 controles ex-ante generados por sei compile desde 4 riesgos y 14 medidas (excluye 3 de lifecycle: [monitoring])
  3. 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
  4. 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
  5. 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
  6. Conformidad dual proyectada sobre el mismo bundle: prEN 18228 + ISO 23894
HuecoPor qué importa
HOTL declarado ex-ante, operación post-market sin datos en vivoEl control human-oversight-worst-case-review documenta el plan; la evidencia de revisión clínica es runtime (Fase 2)
NSD / HD95 como cross-checkEl 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.