Ir al contenido

Tu primer sistema compliant

🟡 Parcial — El arco corre sobre las fixtures del repo; el Anexo IV se ensambla luego en la nube y aún es parcial.

Este tutorial te guía por el golden path de la especialización git-nativa que Venturalítica hace del desarrollo guiado por riesgo (Risk-Driven Development, RDD): construyes loan —un clasificador de crédito de alto riesgo bajo el EU AI Act Anexo III §5— desde los ficheros de configuración hasta el bundle de evidencia firmado. Al terminar habrás completado un ciclo ISO 23894 §6.4–§6.5 completo con evidencia versionada y conformidad dual (prEN 18228 + ISO 23894). El Anexo IV (Art. 11) lo ensambla después la nube desde ese bundle firmado.

Los ficheros que usarás están en crates/seigarrena-cli/tests/resources/loan/. Es el mismo escenario que ejecuta el test de integración; aquí lo recorres a mano para comprender qué hace cada paso.

Lo que aprenderás:

  • Declarar riesgos, medidas y apetito en el programa de riesgos del Art. 9 (sección risk: de sei.yaml)
  • Compilar el programa a OSCAL y reproducir el pipeline con sei run
  • Leer el gate rojo/verde y entender qué significa SUBPODERADO
  • Commitear el tratamiento como acto normativo que cierra el bucle ISO 23894
  • Proyectar el bundle firmado a dos estándares con sei conformance
  • Registrar la aprobación de dirección y reconstruir el ciclo con sei reconstruct

loan es un clasificador logístico binario entrenado sobre el dataset German Credit (1 000 solicitantes) para aprobar o denegar préstamos al consumo. El sistema:

  • Es alto riesgo (EU AI Act Anexo III §5 — sistemas de puntuación crediticia)
  • Está operado por una entidad financiera, por lo que también aplica DORA (Reg. UE 2022/2554)
  • Tiene un AssuranceProgram (la sección risk: de sei.yaml) con 5 riesgos y 16 medidas → 10 controles ex-ante
  • Usa un pipeline DVC multi-stage (featurize → evaluate) con el evaluador agnóstico en compliance_eval.py

La medición de sesgo principal es el disparate impact por género (demographic_parity_diff). El modelo V1 (sin mitigación) falla el control bloqueante; el tratamiento V2 (fairlearn ExponentiatedGradient + DemographicParity) lo cierra.


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

    Terminal
    sei --help

    Deben aparecer los 16 subcomandos (init, run, status, verify, compile, reconstruct, assess, soa, conformance, impact, request, approve, review, reject, retire, pubkey). Si no es así, sigue la guía de instalación.

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

    Terminal
    mkdir /tmp/loan && cd /tmp/loan
    cp -r /ruta/a/seigarrena/crates/seigarrena-cli/tests/resources/loan/. .
  3. Inicializa el repositorio git y DVC:

    Terminal
    git init
    git add sei.yaml compliance_eval.py train.py \
    featurize.py evaluate.py dvc.yaml params.yaml
    dvc init
    dvc add data/german_credit.csv
    git add data/german_credit.csv.dvc .gitignore .dvc/
  4. Crea el entorno Python con uv:

    Terminal
    uv venv .venv
    uv pip install \
    "venturalitica==0.6.11" \
    "mlcroissant>=1.0" \
    "dvc>=3" \
    "pyarrow" \
    "scikit-learn==1.8.0" \
    "fairlearn==0.13.0"

    Las versiones de scikit-learn y fairlearn están ancladas: los valores de métrica deben ser deterministas porque sei.lock los ancla en la evidencia firmada.


Antes de ejecutar, observa la estructura que acabas de copiar:

loan/
├── sei.yaml # Manifiesto del sistema (incluye el programa de riesgos Art. 9)
├── compliance_eval.py # Evaluador agnóstico (venturalitica-sdk + Croissant)
├── train.py → train_unaware.py # Tratamiento activo (V1 al inicio)
├── featurize.py # Stage DVC: CSV → features.parquet
├── evaluate.py # Stage DVC: train + eval + model.pkl
├── dvc.yaml # Pipeline DAG featurize → evaluate
├── params.yaml # seed: 42
└── data/
├── german_credit.csv # Dataset German Credit (1 000 solicitantes)
└── german_credit.croissant.json # Gobernanza §2 (cómo se carga el dato)

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: loan-scoring
intended_purpose: "Scoring crediticio para aprobación de préstamos al consumo."
task:
modality: tabular
type: classification
eval: { script: train.py }
pipeline: { tool: dvc, metrics: metrics.json }
oscal: { assessment_plan: shared_data/policies/assessment_plan.oscal.yaml }
dataset: { croissant: data/german_credit.croissant.json }
artifacts:
model: { kind: logreg, seed: 42 }
risk:
appetite: { individual: MEDIUM, society: MEDIUM, organization: HIGH }
criteria: { scale: "5x5" }
overall_residual_criterion: HIGH
risks:
# 5 riesgos con sus medidas — ver extracto del control bloqueante abajo

Los campos clave: eval.script apunta al tratamiento activo (lo único que cambia V1↔V2); pipeline.tool: dvc declara el seam de reproducción; risk.appetite fija el apetito por-riesgo para la evaluación ISO 23894 §6.4.4. El bloque risk: es el programa de riesgos del Art. 9 (el AssuranceProgram): vive aquí, en sei.yaml, no en un fichero aparte.

Consulta la referencia de sei.yaml para el esquema completo.

La sección risk: — el programa de riesgos del Art. 9

Sección titulada «La sección risk: — el programa de riesgos del Art. 9»

El AssuranceProgram (la sección risk: de sei.yaml) declara 5 riesgos y 16 medidas (de las que sei compile deriva 10 controles ex-ante). El control bloqueante es:

sei.yaml — extracto del control bloqueante (risk.risks[].treat[].measures[])
- id: unfair-credit-exclusion
metric: demographic_parity_diff
constraint: "< 0.03"
severity: high
enforcement: gate
lifecycle: [validation]
article: "15"
frameworks: [eu/dora@2022#art-6]
standard_clauses: ["eu/pren-18228@2026#9.2", "eu/pren-18228@2026#7", "iso/23894@2023#6.5"]

enforcement: gate significa que si la métrica medida no cumple la restricción, sei run devuelve exit ≠ 0. El marco DORA Art. 6 se añade porque el modelo es un activo TIC de una entidad financiera.

Los demás riesgos —risk.data-governance (4 medidas de datos), risk.opacity (rendimiento + supervisión), risk.model-robustness-security (robustez + integridad) y risk.insufficient-human-oversight— aportan medidas enforcement: audit y de supervisión declarada: se miden y se reportan, pero no bloquean el gate como lo hace unfair-credit-exclusion.


Paso 3 — sei compile: AssuranceProgram → OSCAL

Sección titulada «Paso 3 — sei compile: AssuranceProgram → OSCAL»
Terminal
sei compile

sei compile lee la sección risk: de sei.yaml, arma el AssuranceProgram en memoria y genera el plan de evaluación OSCAL en la ruta declarada en sei.yaml (shared_data/policies/assessment_plan.oscal.yaml). Este fichero es la dep del stage evaluate en el DAG DVC; su digest entra en dvc.lock.

Haz el commit inicial:

Terminal
git add shared_data/policies/assessment_plan.oscal.yaml
git commit -m "init loan: AssuranceProgram compilado a OSCAL"

Consulta la referencia del CLI sei para los detalles de cada subcomando.


Terminal
sei run

sei run reproduce el pipeline DVC (dvc repro) sobre el DAG featurize → evaluate:

  1. featurize — carga el German Credit vía Croissant (§2), materializa data/features.parquet (out cacheado, content-addressed)
  2. evaluate — entrena el modelo V1 con compliance_eval.py (10 controles ex-ante vía vl.enforce) y vuelca metrics.json y model.pkl (out cacheado)

El motor juzga los resultados contra el assessment_plan OSCAL y aplica el gate.

Resultado esperado: sei run devuelve exit ≠ 0. El control bloqueante falla:

control: unfair-credit-exclusion
métrica: demographic_parity_diff
valor medido: ~0.06
umbral: 0.03
estado: FALLA (enforcement: gate)
frameworks: eu/dora@2022#art-6

El análisis de riesgo muestra:

  • risk.unfair-credit-exclusion: inherente HIGH, ciclo ABIERTO
  • El bundle .sei/bundle.json queda firmado y anclado igualmente (la evidencia del fallo es evidencia)

Verifica la firma y consulta el estado:

Terminal
sei verify # OK — la firma ECDSA-P256+DSSE+in-toto es válida
sei status # RED — gate fallando por unfair-credit-exclusion

Haz commit de la evidencia T0:

Terminal
git add sei.lock .sei/bundle.json .sei/bundle.json.sig metrics.json
git commit -m "T0: V1 evidencia (gate RED; dvc.lock + metrics.json anclados)"

Lee más sobre el bucle rojo/verde y la fiabilidad estadística en El bucle rojo/verde.


Paso 5 — Explorar el candidato de tratamiento con dvc exp

Sección titulada «Paso 5 — Explorar el candidato de tratamiento con dvc exp»

Antes de commitear el tratamiento, conviene confirmar que V2 cierra el gate. Copia el fichero mitigado sin commitear:

Terminal
cp train_mitigated.py train.py
dvc exp run
dvc exp show

dvc exp run ejecuta V2 como un experimento DVC (git-stashed, no entra al historial). dvc exp show compara la métrica unfair-credit-exclusion del candidato con el baseline V1:

Experimento unfair-credit-exclusion accuracy_score
baseline V1 0.060 0.82
candidato V2 0.015 0.80

El candidato lleva el disparate impact por debajo de 0.03 → cerraría el gate. Esta es la búsqueda del tratamiento, no el tratamiento: el experimento no está comprometido en git todavía.

Qué hace V2 (train_mitigated.py): aplica ExponentiatedGradient(DemographicParity(), eps=0.01) de fairlearn sobre la feature sensible gender. La reducción aprende un ensemble cuya tasa de selección es aproximadamente independiente del género (in-processing), produciendo un disparate impact residual realista de ~0.015.


Paso 6 — Commitear el tratamiento: el acto normativo

Sección titulada «Paso 6 — Commitear el tratamiento: el acto normativo»

La exploración confirmó que V2 cierra el gate. Ahora promovemos el candidato a tratamiento:

Terminal
git add train.py
git commit -m "T1: tratamiento — promueve V2 (train.py mitigado, candidato que cierra el gate)"

Este commit es el tratamiento ISO 23894 §6.5: un cambio versionado al que se puede atribuir el arco FALLA→PASA. sei reconstruct lo localizará por git log -S unfair-credit-exclusion y reconstruirá el ciclo desde él.

Solo train.py cambió. featurize.py, los datos y la clasificación del riesgo se reusan — es una deriva clase B (Art. 15): el modelo cambia, pero la finalidad y el dataset no. La staleness de DVC refleja exactamente eso.

Consulta Las tres modalidades de tratamiento (modalidad 1 = cambio de código) y git cierra el bucle.


Paso 7 — sei status: deriva tipada tras el tratamiento

Sección titulada «Paso 7 — sei status: deriva tipada tras el tratamiento»
Terminal
sei status

El motor detecta que train.py cambió respecto a la última ancla. Reporta deriva tipada:

SecciónEstadoPor qué
measurement-modelstale (clase B, Art. 15)train.py es dep de la fase modelo; su digest cambió
measurement-datareusadoLos datos y Croissant no cambiaron
data_governancereusadoEl Croissant (§2) es el mismo
classificationreusadoLa finalidad y el contexto son los mismos

sei status devuelve exit ≠ 0 porque la sección modelo está stale: el pipeline necesita recomputar.

Lee sobre la clasificación de derivas en Deriva tipada.


Paso 8 — T1: sei run con V2 → gate VERDE

Sección titulada «Paso 8 — T1: sei run con V2 → gate VERDE»
Terminal
sei run

dvc repro detecta que train.py (dep del stage evaluate) cambió y recomputa solo ese stage. El stage featurize queda en caché — no se re-ejecuta porque el dato no cambió. Esta es la staleness selectiva de DVC, que se corresponde exactamente con la deriva tipada del motor.

Resultado esperado: sei run devuelve exit 0. El control bloqueante pasa:

control: unfair-credit-exclusion
valor medido: ~0.015
umbral: 0.03
estado: PASA

El motor registra un evento de tratamiento anclado al commit: unfair-credit-exclusion FALLA→PASA. El análisis de riesgo muestra:

  • risk.unfair-credit-exclusion: inherente HIGH → residual MEDIUM, ciclo CERRADO

Paso 9 — sei conformance: proyección dual de estándares

Sección titulada «Paso 9 — sei conformance: proyección dual de estándares»

El bundle firmado de T1 se puede proyectar sobre dos estándares sin re-anotar el escenario. Venturalítica implementa conformidad por proyección: un AssuranceProgram → N informes.

Terminal
sei conformance --standard eu/pren-18228@2026 --out

Proyección sobre prEN 18228 (el estándar armonizado de gestión de riesgos, Art. 9 EU AI Act):

CláusulaResultadoPor qué
cl. 9.2 (medidas de control)Cubiertaunfair-credit-exclusion es una medida de control bloqueante alineada con cl. 9.2
cl. 10 (residual global)HuecoEl residual agregado CRITICAL excede el criterio HIGH; el riesgo opacity contribuye
Terminal
sei conformance --standard iso/23894@2023

Proyección sobre ISO 23894 (gestión del riesgo de IA):

CláusulaResultado
cl. 6.5 (tratamiento y residual)Cubierta — ciclo risk.unfair-credit-exclusion CERRADO con arco FALLA→PASA

El fichero --out escribe .sei/conformance/eu_pren-18228_2026.json + .sig en el repositorio. El mismo bundle firmado produce ambos informes sin ninguna anotación adicional.

Lee más sobre los dos gates (DORA / MDR) en Dos gates y sobre el CLI en Referencia del CLI sei.


Paso 10 — sei approve: aprobación de dirección

Sección titulada «Paso 10 — sei approve: aprobación de dirección»
Terminal
sei approve --by "Jane Roe <jane@acme.example>"

Crea un commit git vacío con el trailer Sei-Approved-by: Jane Roe <jane@acme.example>. Este acto satisface ISO/IEC 42001 §6.1.3 (aprobación de dirección del plan de tratamiento y aceptación del residual): es atribuible, fechado y separado del acto del evaluador.

sei reconstruct recoge este commit como la aprobación en la reconstrucción del ciclo.


Paso 11 — sei reconstruct: replay del ciclo ISO 23894

Sección titulada «Paso 11 — sei reconstruct: replay del ciclo ISO 23894»
Terminal
sei reconstruct --out

sei reconstruct recorre el historial git del bundle (.sei/bundle.json) y reconstruye el ciclo ISO 23894 por riesgo, determinista y sin LLM:

FaseQué reconstruye
① IdentificaciónEl commit que introdujo risk.unfair-credit-exclusion en el AssuranceProgram
② AnálisisLikelihood × impacto → nivel inherente HIGH (matriz 5×5 ISO 23894 §6.4.3)
③ EvaluaciónNivel inherente HIGH vs apetito MEDIUM → EXCEDE, requiere tratamiento
④ TratamientoEl commit de V2: train.py FALLA→PASA (arco empírico desde el bundle)
⑤ ResidualInherente HIGH → residual MEDIUM, ciclo CERRADO (§6.5)

La salida también muestra la aprobación de Jane Roe y el aviso SUBPODERADO con su IC:

unfair-credit-exclusion: 0.0151 < 0.03 PASA
IC bootstrap [0.001, 0.072] — n=1000 — SUBPODERADO
poder insuficiente, faltan muestras (Art. 10(5))

El artefacto .sei/reconstruct.json + .sig queda firmado. Consulta git cierra el bucle para la interpretación normativa.


Paso 12 — El Anexo IV (Art. 11) lo ensambla la nube

Sección titulada «Paso 12 — El Anexo IV (Art. 11) lo ensambla la nube»

El motor no emite el Anexo IV: solo deja la evidencia firmada (.sei/bundle.json y compañía). El Anexo IV (EU AI Act Art. 11) lo ensambla y renderiza la nube (plano de control) desde ese bundle.json firmado, con procedencia por campo, y lo entrega como PDF. No hay subcomando sei annex-iv ni artefacto annex-iv.json que commitear.

Cuando la nube lee el bundle firmado del repositorio, marca la procedencia de cada campo del Anexo IV:

  • Declarado — los campos de sei.yaml (nombre, finalidad, tipo de sistema)
  • Derivado del bundle — el digest del modelo, los resultados de los controles, el dvc.lock
  • Derivado de git — la historia de commits, la aprobación

Al completar este tutorial has ejecutado un ciclo RDD completo:

  1. Un AssuranceProgram (Art. 9) con 5 riesgos, 16 medidas (10 controles ex-ante) y un control bloqueante alineado con prEN 18228 cl. 9.2 e ISO 23894 §6.5
  2. Un pipeline DVC reproducible (featurize → evaluate) con staleness selectiva que refleja la deriva tipada
  3. Un bucle rojo/verde verificable: T0 gate RED → tratamiento V2 (commit) → T1 gate GREEN
  4. Un bundle de evidencia firmado (ECDSA-P256+DSSE+in-toto) que ancla código, modelo y datos
  5. Conformidad dual proyectada: prEN 18228 + ISO 23894 desde el mismo bundle, sin re-anotación
  6. Un ciclo ISO 23894 reconstruido por replay de git, determinista, con aprobación de dirección
  7. La evidencia firmada desde la que la nube ensambla el Anexo IV (parcial; en este escenario solo §3 y §9 quedan PENDIENTE — §7/§8 nunca) con procedencia por campo
HuecoPor qué importa
risk.opacity sin tratamiento efectivoEl residual global excede overall_residual_criterion: HIGH (prEN 18228 cl. 10)
Control unfair-credit-exclusion SUBPODERADOn=1 000 insuficiente; IC [0.001, 0.072] cruza el umbral (Art. 10(5))
Anexo IV §3/§9 PENDIENTE en este escenario§2/§3/§4/§9 pueden quedar pendientes si falta su insumo; aquí, con datos/controles presentes, solo §3 (sin medios Art.14 ni residuales en bundle) y §9 (sin medidas post-market); §7/§8 nunca pendientes
Anclaje de identidad keyless (Sigstore)La firma ECDSA-P256+DSSE está; la raíz de confianza externa, no

Consulta Estado e incompletitudes para el mapa completo de huecos y Qué es Risk-Driven Development para el marco normativo de fondo.