Nivel 4 · El arco, por traspasos
This content is not available in your language yet.
El arco, por traspasos
Sección titulada «El arco, por traspasos»Seis 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 ÁMBAR → VERDE —una falta de conclusión real y honesta que SÍ se resuelve en cuanto se mide con potencia real (OUT-OF-FOLD sobre las 1.000 filas, no un held-out de 200)— con un riesgo de proxy que aflora al revisar el modelo y se deja sin tratar, cerrando con una aprobación legítima que acepta conscientemente ese residual. Y un sexto hito nuevo: la revisión periódica que reabre esa aprobación y forma una cadena de aprobaciones con un aprobador efectivo — el último responsable del expediente.
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.
Nerea es la responsable de producto en NovaCredit, una entidad de crédito que despliega un modelo de puntuación. Abre el portal y ejecuta las misiones de autoría que generan el manifiesto de gobernanza froga.yaml. Tres cosas importan:
- El nivel es
high, declarado por un humano, vía la ruta del uso. La misiónclassify-systemrellena el bloqueclassificationcon la base: «Ley de IA de la UE Anexo III §5(b) (evaluación de solvencia crediticia / puntuación de crédito)» — más «DORA Art. 6 (riesgo TIC de la entidad financiera)». La activación de alto riesgo aquí es el Anexo III §5(b), no el Art. 6(1). El motor no lo infiere; Nerea lo declara y lo asume. - Se declaran dos regímenes, y uno es la superposición. La misión
declare-standardsescribeapplicable_standardscon la columna vertebral (eu/ai-act@2024,eu/pren-18228@2026,iso/23894@2023) máseu/dora@2022— la superposición DORA — con un bloquedora.entity(el LEI, el tipo de entidadcredit_institution). Declarareu/dora@2022es lo que hace que el motor ensamble el Registro DORA más adelante. - El riesgo es la exclusión crediticia injusta. La misión
identify-risksañaderisk.unfair-credit-exclusion— «el modelo puede excluir injustamente a grupos protegidos al heredar patrones históricos de discriminación.» El control que confirmará el residual es la diferencia de paridad demográfica — una barrera de equidad bloqueante (< 0,092).
Las 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 los riesgos con sus barreras numéricas fijadas antes de que exista modelo:
Diego recibe el PR que abrieron las misiones de Nerea, revisa que el manifiesto sea correcto — nivel high por Anexo III §5(b) (evaluación de solvencia) más DORA Art. 6 (riesgo TIC), normas eu/ai-act@2024 + eu/pren-18228@2026 + iso/23894@2023 + eu/dora@2022 con bloque dora.entity, riesgo de exclusión crediticia injusta con vocabulario completo — e integra el PR. El froga.yaml declarado queda en el repositorio.
Todavía no hay nada que medir, pero Marta deja el reproductor listo en git: el proyecto uv + DVC, el dataset real Statlog German Credit (UCI #144, CC-BY-4.0) con su manifiesto Croissant y el paso de rasgos ya son commits del guion:
15
git init -q -b maingit config user.email marta@demo.seigarrena.devgit config user.name "Marta Demo"uv init --bare --name vldemo-loan-scoring --python 3.12patch: pyproject-index.patchuv add "dvc>=3" pyyaml froga "venturalitica==0.6.11" "mlcroissant>=1.0" pyarrow "scikit-learn==1.8.0" fairlearn pandas joblibpatch: gitignore.patchpatch: gitattributes.patchpatch: readme.patchuv syncuv run dvc init --no-scm -quv run dvc config core.analytics falsefroga pubkey --out .froga/PUBKEY.txtgit add -Agit commit -m "init: repo, proyecto uv (deps reales) y README del reproductor"
Con el manifiesto declarado y el andamiaje en git, el turno pasa a medir (hito 2).
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 la evidencia demuestra el residual o solo lo estima.
Marta mide el sistema tal como está — el riesgo inherente, sin tratar. Primero compila el contrato de la barrera —qué controles se van a medir y con qué umbral—:
froga compilegit add -Agit commit -m "compile: assessment plan OSCAL (contrato del gate, antes del modelo)"
Ahora añade el modelo base —una regresión logística simple, sin mitigación de equidad— y corre la evidencia:
patch: params.patchpatch: dvc-evaluate.patchpatch: train.patchpatch: evaluate.patchpatch: compliance-eval.patchfroga runmay failgit add -Agit commit -m "modelo: logreg base V1 sin mitigación (train/evaluate + dvc.yaml) — run: V1 evidencia base (gate ÁMBAR infrapotenciado; seed=42)"
El control unfair-credit-exclusion vuelve ÁMBAR, y por qué es ámbar es toda la cuestión:
actual_value = 0,1050, barrera< 0,092→ la estimación puntual NO pasa (passed: false): el modelo sin tratar discrimina de verdad, medido con potencia real.- El bloque de potencia informa de un IC 95% bootstrap de
[0,0425, 0,1702], medido OUT-OF-FOLD sobre las 1.000 filas (690 hombres, 310 mujeres; 5-foldStratifiedKFold— ninguna fila la predice un modelo que la vio entrenar). El extremo inferior, 0,0425, cae por debajo de la línea 0,092.
Así que el intervalo cruza el umbral (por debajo en un extremo, por encima en el otro): el motor no puede demostrar con certeza que la disparidad viole el límite, así que activa inconclusive() → ÁMBAR, no un rojo concluyente. Esto es honesto en un sentido distinto al de un dato pequeño: con 1.000 filas la potencia ya es real — el intervalo cruza porque el residual está genuinamente indeciso en ese punto, no porque falten datos. El paquete se firma y ancla de todos modos — un resultado ÁMBAR es evidencia, registrada honestamente.
El riesgo es real y la evidencia inconclusa. Pero antes de tratar, Nerea vuelve a mirar el modelo — y encuentra algo que la barrera no vio.
Al revisar la evidencia V1, Nerea no mira solo el color de la barrera: mira el modelo. Y ve algo que la barrera de equidad no capturó — el código postal entra como variable. En zonas con segregación residencial, el código postal correlaciona con el origen étnico: el modelo puede aprender a discriminar por un atributo protegido sin usarlo explícitamente. Es el beat A.1.c del proceso ISO 23894 (§6.4.2, análisis del riesgo): un riesgo que aflora al examinar el sistema, no al declararlo de antemano.
Nerea lo declara en el froga.yaml como risk.proxy-discrimination — impacto individual ALTO, probabilidad PROBABLE —, y toma una decisión deliberada: no lo trata todavía. Retirar el código postal degradaría el modelo y hace falta más análisis antes de actuar; así que el riesgo queda identificado pero sin tratar, por encima del apetito individual (above-appetite):
Fíjate en lo que no cambia: sin un bloque treat: ni una medida, el riesgo no aporta ningún control_result, así que el color de la barrera no se mueve — sigue ÁMBAR. Un riesgo above-appetite sin tratar no pinta la barrera de rojo por sí mismo; lo que hace es abrir una puerta en la aprobación: alguien tendrá que aceptarlo conscientemente, con motivo, o el sistema no se aprueba. Ese es el segundo residual que viajará hasta el hito de gobernanza.
Esperando. La identificación del riesgo es un acto de gobernanza de la responsable de producto; Marta lo verá reflejado en el manifiesto y sabrá que la aprobación llevará una condición añadida. Su siguiente paso sigue siendo el tratamiento de la equidad.
Esperando. Diego ha visto el ÁMBAR — la barrera es inconclusa, medida OOF sobre las 1.000 filas. No toca git; espera la evidencia vuelta a medir, donde leerá si el tratamiento resuelve la falta de conclusión.
Este es el tratamiento (ISO 23894 §6.5). Como en el Nivel 2, el tratamiento reemplaza train.py: el estimador pasa de una regresión logística plana a un aprendizaje justo con la restricción DemographicParity de fairlearn (ExponentiatedGradient), un cambio de código versionado en git que el motor atribuye al tratamiento del riesgo. El diff es el tratamiento, y en el mismo paso Marta vuelve a correr la barrera:
git checkout -b tratamiento/mitiga-paridadpatch: train.patchfroga runmay failgit add -Agit commit -m "treatment: aplica mitigación de paridad demográfica (fairlearn DemographicParity) sobre el sexo — ISO 23894 §6.5"
Y esta vez la barrera pasa a VERDE, y la razón es el hallazgo honesto del nivel:
actual_value = 0,0065— la estimación puntual cae muy por debajo del 0,1050 de V1, y muy por debajo de la barrera< 0,092.- El bloque de potencia: IC 95% bootstrap
[0,0010, 0,0645]— el extremo superior queda por debajo del umbral 0,092.
El IC ya no cruza la línea: queda enteramente por debajo. El motor activa adequate() → VERDE concluyente. Léelo con precisión: el tratamiento es una intervención real y versionada, y sobre las mismas 1.000 filas medidas OOF, el número baja Y la potencia lo demuestra. No hace falta más dato — el mismo tamaño de muestra que dejó V1 en ÁMBAR certifica V2 en VERDE, porque el residual tratado está genuinamente lejos del umbral.
Tratado, firmado, VERDE concluyente — y el riesgo de proxy sin tratar del hito 3 es lo único que queda para la decisión.
Este es el cierre — y el contraste con la retina es la clave. La evidencia VERDE tratada y firmada de Marta está en el repositorio, con la solicitud ya emitida (columna de Marta). Diego revisa el paquete, verifica la firma de Marta y ve la equidad resuelta: el tratamiento demostró el residual, medido OOF sobre las 1.000 filas — ya no hay ámbar que aceptar. Pero quedan las dos condiciones de gobernanza que la barrera nunca mide: proxy-discrimination sigue above-appetite, sin tratar, y el residual de opacidad excede el apetito sin control técnico que lo acote.
Diego aprueba — la aprobación acepta esos dos residuales de gobernanza a la vez: el riesgo de proxy sin tratar y el residual de opacidad. La aprobación es un acto git-nativo y firmado: un acto DSSE .froga/acts/NNNN-approve.json —firmado ECDSA-P256 y verificado contra la clave de Diego declarada en signers:— registra quién aprobó; el commit que lo añade es texto plano, sin firma GPG (no esperes la insignia «Verified» al pincharlo en GitHub), pero el acto sí va criptográficamente firmado; el motivo que acepta ambos residuales queda en el acta del portal (la CLI no admite --reason y lo omite con aviso); y junto al acto va firmada la evidencia (bundle.json.sig y las conformidades). Con la aprobación en la historia, la conformidad se re-emite y la cláusula 11 de prEN 18228 (revisión de gestión de riesgo) pasa de Gap a Cubierta al leer el acto de aprobación:
Reason: «Aceptación consciente del riesgo residual: proxy-discrimination sigue above-appetite sin tratar (se acepta con motivo) y el residual de opacidad excede el apetito; la equidad medida OUT-OF-FOLD (n=1000) cierra VERDE tras el tratamiento fairlearn. Revisión P6M.»
El motor no borra ninguno de los dos residuales: los ancla en la aprobación, atribuibles y verificables. Esa es la diferencia entre aceptar conscientemente un residual y ocultarlo.
Marta cierra su parte del ciclo desde la CLI. Con la V2 en VERDE firmada, emite la conformidad y el reconstruct sobre las normas aplicables y solicita la aprobación:
patch: entitlement.patchfroga conformance --standard eu/pren-18228@2026 --outmay failfroga conformance --standard iso/23894@2023 --outmay failfroga conformance --standard eu/ai-act@2024 --outmay failfroga conformance --standard eu/dora@2022 --outmay failfroga conformance --standard eu/pren-18283@2026 --outmay failfroga conformance --standard eu/pren-18282@2026 --outmay failfroga reconstruct --outmay failgit add -Agit commit -m ".froga: conformance + reconstruct firmados"
solicitud de aprobación (el acto lo commitea froga request)La aprobación es de Diego (arriba): Marta la solicitó con el acto anterior, no puede concederla ella misma. Cuando el acto firmado .froga/acts/NNNN-approve.json de Diego aterriza —con los dos residuales de gobernanza aceptados conscientemente—, Marta re-emite la conformidad para que froga derive el ciclo de la historia git, ahora con la aprobación real:
froga conformance --standard eu/pren-18228@2026 --outmay failfroga conformance --standard iso/23894@2023 --outmay failfroga conformance --standard eu/ai-act@2024 --outmay failfroga conformance --standard eu/dora@2022 --outmay failfroga conformance --standard eu/pren-18283@2026 --outmay failfroga conformance --standard eu/pren-18282@2026 --outmay failfroga reconstruct --outmay failgit add -Agit commit -m ".froga: re-emisión de conformance + reconstruct tras aprobar (cl.11 = Approved)"
El sistema queda declarado, tratado, VERDE, solicitado y aprobado con el doble residual de gobernanza (proxy + opacidad) en acta: el final del arco, con la aprobación de Diego anclada en la etiqueta loan-v2.0.0-approved de arriba.
Aprobar con el doble residual en acta
Equidad ya VERDE (tratamiento demostrado, OOF sobre las 1.000 filas) — quedan dos residuales de gobernanza: proxy-discrimination above-appetite sin tratar + opacidad por encima del apetito. Diego acepta ambos de forma consciente, con motivo (autodeclaración Anexo III §5(b)).El froga.yaml de crédito declaró review_interval: P6M: una revisión semestral (ISO 23894 §6.6, la supervisión continua del Art. 14). Pasados los seis meses, el portal ofrece la revisión y Diego la ejecuta — y, como en cualquier revisión, reabre el ciclo:
El motor deriva «en revisión periódica» (froga status: «Sistema en revisión periódica (ISO 23894 §6.6). Compliance debe re-aprobar el sistema.»): la aprobación de arriba queda suspendida. Pero aquí el arco es distinto al del Nivel 2: la evidencia no cambia. No hay nada que re-medir —el doble residual (proxy sin tratar + opacidad) es una decisión de gobernanza, no un número que re-correr—, así que no hay froga run entre medias. Diego revisa el mismo bundle V2 y lo re-aprueba tal cual:
Reason: «Re-aprobación tras la revisión periódica (P6M) sobre la MISMA evidencia vigente: se re-confirma la aceptación consciente del doble residual (proxy-discrimination above-appetite sin tratar + opacidad por encima del apetito). El aprobador efectivo del expediente pasa a ser esta re-aprobación (cadena aprobar→revisar→re-aprobar).»
El sistema vuelve a «aprobado», ahora con la cadena completa en el expediente y el aprobador efectivo anclado en la etiqueta loan-v2.0.0-reapproved de arriba.
Esperando — y esta vez el turno de Marta es no actuar. La revisión de un residual de gobernanza (el proxy sin tratar, la opacidad) no exige re-medir: no hay parámetro que cambiar ni barrera que re-correr, la evidencia V2 sigue siendo la vigente. Toda la acción del hito vive en el portal, entre la revisión y la re-aprobación de Diego. Marta lo verá reflejado en la cadena de aprobaciones del expediente, sin un commit suyo de por medio — el contraste exacto con el Nivel 2, donde la revisión sí devolvió a medir.