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:desei.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
Contexto del proyecto
Sección titulada «Contexto del proyecto»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:desei.yaml) con 5 riesgos y 16 medidas → 10 controles ex-ante - Usa un pipeline DVC multi-stage (
featurize → evaluate) con el evaluador agnóstico encompliance_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.
Paso 1 — Preparar el entorno
Sección titulada «Paso 1 — Preparar el entorno»-
Asegúrate de que
seiestá compilado e instalado:Terminal sei --helpDeben 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. -
Crea un directorio de trabajo temporal y copia los ficheros del escenario:
Terminal mkdir /tmp/loan && cd /tmp/loancp -r /ruta/a/seigarrena/crates/seigarrena-cli/tests/resources/loan/. . -
Inicializa el repositorio git y DVC:
Terminal git initgit add sei.yaml compliance_eval.py train.py \featurize.py evaluate.py dvc.yaml params.yamldvc initdvc add data/german_credit.csvgit add data/german_credit.csv.dvc .gitignore .dvc/ -
Crea el entorno Python con
uv:Terminal uv venv .venvuv 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-learnyfairlearnestán ancladas: los valores de métrica deben ser deterministas porquesei.locklos ancla en la evidencia firmada.
Paso 2 — Los ficheros del proyecto
Sección titulada «Paso 2 — Los ficheros del proyecto»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)sei.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: loan-scoring intended_purpose: "Scoring crediticio para aprobación de préstamos al consumo."task: modality: tabular type: classificationeval: { 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 abajoLos 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:
- 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»sei compilesei 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:
git add shared_data/policies/assessment_plan.oscal.yamlgit commit -m "init loan: AssuranceProgram compilado a OSCAL"Consulta la referencia del CLI sei para los detalles de cada subcomando.
Paso 4 — T0: sei run con V1 → gate ROJO
Sección titulada «Paso 4 — T0: sei run con V1 → gate ROJO»sei runsei run reproduce el pipeline DVC (dvc repro) sobre el DAG featurize → evaluate:
featurize— carga el German Credit vía Croissant (§2), materializadata/features.parquet(out cacheado, content-addressed)evaluate— entrena el modelo V1 concompliance_eval.py(10 controles ex-ante víavl.enforce) y vuelcametrics.jsonymodel.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-6El análisis de riesgo muestra:
risk.unfair-credit-exclusion: inherente HIGH, ciclo ABIERTO- El bundle
.sei/bundle.jsonqueda firmado y anclado igualmente (la evidencia del fallo es evidencia)
Verifica la firma y consulta el estado:
sei verify # OK — la firma ECDSA-P256+DSSE+in-toto es válidasei status # RED — gate fallando por unfair-credit-exclusionHaz commit de la evidencia T0:
git add sei.lock .sei/bundle.json .sei/bundle.json.sig metrics.jsongit 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:
cp train_mitigated.py train.pydvc exp rundvc exp showdvc 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_scorebaseline V1 0.060 0.82candidato V2 0.015 0.80El 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:
git add train.pygit 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»sei statusEl motor detecta que train.py cambió respecto a la última ancla. Reporta deriva tipada:
| Sección | Estado | Por qué |
|---|---|---|
| measurement-model | stale (clase B, Art. 15) | train.py es dep de la fase modelo; su digest cambió |
| measurement-data | reusado | Los datos y Croissant no cambiaron |
| data_governance | reusado | El Croissant (§2) es el mismo |
| classification | reusado | La 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»sei rundvc 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: PASAEl 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.
sei conformance --standard eu/pren-18228@2026 --outProyección sobre prEN 18228 (el estándar armonizado de gestión de riesgos, Art. 9 EU AI Act):
| Cláusula | Resultado | Por qué |
|---|---|---|
| cl. 9.2 (medidas de control) | Cubierta | unfair-credit-exclusion es una medida de control bloqueante alineada con cl. 9.2 |
| cl. 10 (residual global) | Hueco | El residual agregado CRITICAL excede el criterio HIGH; el riesgo opacity contribuye |
sei conformance --standard iso/23894@2023Proyección sobre ISO 23894 (gestión del riesgo de IA):
| Cláusula | Resultado |
|---|---|
| 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»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»sei reconstruct --outsei reconstruct recorre el historial git del bundle (.sei/bundle.json) y reconstruye el ciclo ISO 23894 por riesgo, determinista y sin LLM:
| Fase | Qué reconstruye |
|---|---|
| ① Identificación | El commit que introdujo risk.unfair-credit-exclusion en el AssuranceProgram |
| ② Análisis | Likelihood × impacto → nivel inherente HIGH (matriz 5×5 ISO 23894 §6.4.3) |
| ③ Evaluación | Nivel inherente HIGH vs apetito MEDIUM → EXCEDE, requiere tratamiento |
| ④ Tratamiento | El commit de V2: train.py FALLA→PASA (arco empírico desde el bundle) |
| ⑤ Residual | Inherente 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
Qué has construido
Sección titulada «Qué has construido»Al completar este tutorial has ejecutado un ciclo RDD completo:
- 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
- Un pipeline DVC reproducible (
featurize → evaluate) con staleness selectiva que refleja la deriva tipada - Un bucle rojo/verde verificable: T0 gate RED → tratamiento V2 (commit) → T1 gate GREEN
- Un bundle de evidencia firmado (ECDSA-P256+DSSE+in-toto) que ancla código, modelo y datos
- Conformidad dual proyectada: prEN 18228 + ISO 23894 desde el mismo bundle, sin re-anotación
- Un ciclo ISO 23894 reconstruido por replay de git, determinista, con aprobación de dirección
- 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
Lo que queda pendiente
Sección titulada «Lo que queda pendiente»| Hueco | Por qué importa |
|---|---|
risk.opacity sin tratamiento efectivo | El residual global excede overall_residual_criterion: HIGH (prEN 18228 cl. 10) |
Control unfair-credit-exclusion SUBPODERADO | n=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.