Saltar a contenido

Referencia de la API

Superficie pública de Nikodym RiskLib, organizada por dominio. Cada símbolo se genera automáticamente desde sus docstrings con mkdocstrings; las firmas y campos son los del código publicado (1.12.0).

Estabilidad (SemVer 1.x)

El pipeline de validación de scorecard (F1) —el trío runStudyNikodymConfig y los dominios data, eda, binning, selection, model, scorecard, calibration, performance y stability— es API estable: no rompe hasta un 2.0. También lo son el informe (report) y el trail de auditoría (audit), porque ya son superficie de integración. Las superficies que aún crecen (modelado ML, provisiones, survival, forward-looking, stress, validación, gobernanza y tracking) están marcadas como experimentales en su docstring, fuera de la garantía SemVer 1.x.

Esa lista no se escribe a mano en tres sitios: la fija nikodym.testing.stability y la verifican los gates del repositorio contra el docstring de cada paquete y contra esta página.

Núcleo liviano e import perezoso

import nikodym no arrastra el stack ML. nikodym.run se re-exporta de forma perezosa (PEP 562) desde nikodym.api, y los backends pesados de cada dominio (pandas, sklearn, statsmodels, optbinning, XGBoost, …) se cargan solo al ejecutar el paso correspondiente, tras sus extras opcionales.

Ejecución y estado de la corrida

Punto de entrada único (run) y las estructuras stateful que produce: el Study contenedor, su ArtifactStore namespaced, el RunContext (estado + lineage) y el LineageBundle reproducible. check_pipeline responde si un config se puede ejecutar, sin ejecutarlo.

run

run(config, *, artifacts=None, run_dir=None)

Ejecuta una corrida completa de extremo a extremo y devuelve el Study.

Superficie pública única de ejecución (CT-4): ensambla el AuditSink y el ModelInventory (assemble_run), corre el Study, y —solo en éxito y solo si governance.publish_to_inventory— publica la ModelCard en el inventario.

Semántica de fallo (D-UI-2, decidida). Study.run() es el primitivo fail-loud: ante un fallo marca status="failed", conserva el lineage y re-levanta. Esta función es el envoltorio de producto: captura el NikodymError y devuelve el Study parcial en vez de propagarlo. El fallo no se silencia pero tampoco explota. Por eso, el consumidor por código debe chequear study.run_context.status ("done" vs "failed") antes de leer los resultados.

Dónde quedan los resultados: en study.artifacts, indexado por (dominio, clave)::

study = nikodym.run(config)
assert study.run_context.status == "done"
study.artifacts.get("performance", "result")     # métricas de discriminación
study.artifacts.get("model", "coefficients")     # los betas del modelo
study.artifacts.keys()                           # todo lo que dejó la corrida

study.results es el resumen firmable de la corrida, no un duplicado del store: trae metrics —plano, "<dominio>.<metrica>", float finito— y metric_sections por dominio (D-GOB-1…3). Es lo que leen el model card y MLflow. Una métrica que el dominio no pudo evaluar no aparece; ausencia y cero no son lo mismo.

Dónde queda la evidencia en disco: en run_dir, y sólo si se pide (D-GOB-6). Con el default None la corrida no escribe nada, que es el comportamiento histórico: una librería que empieza a dejar archivos en el cwd de quien la importa es una regresión, no una mejora. Con un run_dir se escribe allí el layout de SDD-03 §6::

<run_dir>/audit_trail.jsonl   # si `audit` está activo (su nombre lo fija AuditConfig)
<run_dir>/environment.json    # si `audit` está activo y captura entorno
<run_dir>/model_card.json     # si `governance` está activa
<run_dir>/model_card.md       # idem
<run_dir>/study/              # lo que produce `Study.save`: config, lineage y artefactos

Cada archivo aparece sólo si su sección está activa: audit sin governance deja trail y entorno, y no card. scenario_log.jsonl del layout de SDD-03 §6 no se escribe: hoy no tiene ningún productor, y crear un archivo vacío para cumplir el layout sería teatro.

Entrar por la mitad. artifacts= permite traer resultados ya calculados. Las claves son las parejas (dominio, clave) declaradas en Step.requires/Step.provides; hay que apagar en el config la sección que produciría cualquiera de las claves inyectadas. El tipo lo valida el paso consumidor, no esta puerta. Toda corrida que recibe artefactos externos los enumera en lineage.injected_artifacts y declara que no es reconstruible sólo desde config y datos. Esta puerta es de código: la UI/HTTP no deserializa artefactos externos.

Dónde queda el diagnóstico. En study.run_context.error (:class:~nikodym.core.lineage.RunError): tipo de la excepción, mensaje del motor y paso que falló, sin que haya que configurar nada. El audit-trail lo repite en el evento run_end, pero sólo si el config declara un sink: los presets lo declaran desde D-GOB-8, pero un config escrito a mano puede traer audit: null, así que no dependa de él; y el lineage no guarda el error nunca (enmienda RUN-ERROR).

check_pipeline

check_pipeline(config, *, artifacts=None)

Responde si config es ejecutable, sin ejecutarlo, y con qué pasos.

Envoltorio de producto de :meth:~nikodym.core.study.Study.check_pipeline: donde el primitivo del núcleo re-levanta, esta función captura y devuelve el veredicto, igual que :func:run frente a Study.run (D-UI-2). Sirve para avisar mientras se edita —el usuario sabe que le falta encender una sección antes de apretar Ejecutar— y es la misma respuesta por código y por interfaz (D-PIPE-3).

No ejecuta pasos, no lee el dataset, no monta sinks ni inventario y no deja rastro de corrida: comprobar no es correr.

Captura Exception, no sólo NikodymError. Es deliberado y más amplio que :func:run: una comprobación existe para informar, así que tumbar a quien la llama —el formulario la invoca en cada tecleo— sería peor que cualquier fallo que quiera reportar. Un from_config de dominio puede levantar algo que no es de la familia del motor; is_domain_error lo declara en vez de disfrazarlo (D-PIPE-6).

Parameters:

Name Type Description Default
config NikodymConfig

Config ya reconstruido. Que reconstruya es precondición, no resultado: la validez del modelo Pydantic y la ejecutabilidad del pipeline son dos preguntas distintas (D-PIPE-1).

required
artifacts Iterable[ArtifactKey] | Mapping[ArtifactKey, Any] | None

Claves de artefactos que estarán disponibles al correr. Si se entrega un mapping, sus valores se ignoran: comprobar sólo necesita las claves. Una clave válida que ningún paso activo consume se publica en PipelineCheck.inert_artifacts en vez de bloquear.

None

Returns:

Type Description
PipelineCheck

executable=True + steps en orden, o executable=False + el diagnóstico del motor.

PipelineCheck dataclass

Veredicto de ejecutabilidad de un config, sin correr nada (D-PIPE-2/D-PIPE-3).

steps trae los pasos en el orden en que correrían —útil por sí solo: es lo que el usuario va a ejecutar—, y queda vacío si el config no es ejecutable, porque en ese caso no hay pipeline que anunciar.

message guarda str(exc) íntegro, con el código de marca si el motor lo trae al frente: esta es superficie de código, donde el código es el dato, igual que en :class:~nikodym.core.lineage.RunError. El copy público lo sanea al publicarlo (:func:~nikodym.core.markers.strip_declared_codes, D-ERR-4).

is_domain_error distingue el diagnóstico accionable por quien configura de una excepción inesperada, cuyo texto puede ser detalle interno sin valor para quien usa el formulario (mismo criterio que D-ERR-5).

inert_artifacts enumera, en orden canónico, las claves externas que ningún paso activo ni el cierre transversal del lineage consumirá. No vuelven el config inejecutable: son un aviso contra typos o material preparado para una sección todavía apagada.

Cubre dos familias, y el ValidationError no es un añadido cosmético: las secciones de dominio son Any en el schema raíz, así que un valor fuera de rango dentro de ellas no lo caza NikodymConfig.model_validate — lo caza la coacción que hace la resolución, y llega aquí como ValidationError de Pydantic. Es el diagnóstico más accionable que produce esta función (nombra el campo y la restricción); clasificarlo como «inesperado» lo habría ocultado justo en el caso más común.

assemble_run

assemble_run(config, *, run_dir=None)

Construye el AuditSink compuesto y el inventario real/no-op de una corrida.

core recibe ambos objetos ya resueltos: no importa audit, governance, tracking ni MLflow. Si governance.publish_to_inventory=True y falta el extra tracking, esta capa falla ruidoso con MissingDependencyError porque la publicación fue una petición explícita.

run_dir es el directorio de la corrida (D-GOB-6): contra él se resuelve el nombre relativo del audit-trail. Sin él, un trail_filename relativo es un error explícito (D-GOB-7).

Study

Estado del experimento y orquestador de la corrida (SDD-01 §4/§7).

Un Study recién construido arranca en status="created" y serializa sin valores ficticios (DoD F0). :meth:run lo transiciona a runningdone/failed y congela el lineage. El config es inmutable: su identidad se ancla al config_hash.

inert_injected_artifacts property

inert_injected_artifacts

Expone a la API las claves externas que ningún paso activo consume.

set_audit_sink

set_audit_sink(sink)

Inyecta el AuditSink (ya compuesto por api/runner) y lo propaga al ArtifactStore.

Debe llamarse antes de :meth:run. core no compone FanOutSink ni resuelve el inventario (CT-4): toma un sink ya resuelto.

lineage_bundle

lineage_bundle()

Devuelve el :class:LineageBundle congelado en :meth:run; levanta si no se corrió.

run

run(steps=None)

Ejecuta el pipeline y devuelve self (encadenable).

El argumento steps tiene prioridad sobre config.run.steps. fail_fast=False no se soporta en v1: se emite un warning ruidoso (no un no-op silencioso) y se procede como True. Una excepción en un paso (con fail_fast=True) deja status="failed" pero conserva el lineage (evidencia de trazabilidad, SR 11-7), escribe el rastro del fallo en run_context.error (:class:~nikodym.core.lineage.RunError: tipo, mensaje y paso), sella finished_at, emite run_end y se re-levanta; el Study parcial sigue siendo guardable.

check_pipeline

check_pipeline(steps=None)

Resuelve y valida el pipeline sin ejecutar nada; devuelve los pasos en orden.

Responde la pregunta «¿este config se puede correr?» antes de correrlo, que es lo que permite avisarlo mientras se edita en vez de al apretar Ejecutar (enmienda VALIDACION-PIPELINE, D-PIPE-3). La capacidad vive aquí, en el núcleo, y no en la capa UI: quien trabaja por código tiene la misma respuesta que quien usa el formulario, que es el requisito de paridad.

Es fail-loud como :meth:run: un config inejecutable levanta el ConfigError del motor con su diagnóstico. El envoltorio de producto que lo captura y devuelve un veredicto inspeccionable es :func:nikodym.check_pipeline, igual que :func:nikodym.run frente a :meth:run (D-UI-2).

No toca el run_context: no asigna run_id, no cambia status ni sella finished_at. Comprobar no es correr, y una comprobación no debe dejar rastro de corrida en el audit-trail. No lee el dataset ni escribe en disco, y cuesta ≤0,1 ms con los dominios ya importados (la primera llamada del proceso paga sus imports perezosos, ~1-3 s).

Sí tiene un efecto, y no es cosmético: :meth:_resolve_steps coacciona los sub-configs opacos a su clase real, exactamente como haría :meth:run, y esa coacción materializa los defaults que un config cargado de YAML no traía — con lo que el config_hash de este Study puede cambiar. Es convergente (coaccionar dos veces da lo mismo) y deja el config en el estado que tendría al correr, así que una corrida posterior sobre el mismo Study es consistente; pero quien compare hashes alrededor de esta llamada debe saberlo.

Lo que no hace es sembrar los RNG del proceso cuando el Study se construyó con apply_global_seed=False, que es como lo hace :func:nikodym.check_pipeline.

run_step

run_step(name)

Ejecuta un paso aislado y devuelve su resultado; no altera run_context.status.

Emite sólo los eventos del paso (no run_start/run_end) y exige sus prerequisitos presentes. En F0 NikodymConfig no expone secciones de dominio, así que la resolución levanta ConfigError (la orquestación de dominios llega en T2).

Se resuelve SIN contexto de dominios activos, a propósito (D-FX-1). [name] no es «el pipeline de esta invocación»: es un paso suelto sobre artefactos que ya deben estar en el store. Pasar {name} como conjunto activo convertiría la comprobación CT-1 de este método en vacua para cualquier paso cuyo requires se derive del contexto —run_step ('report') dejaría de exigir sus cards—, y la precedencia que D-FX-1 fija (steps=config.run.steps → secciones no nulas) describe una corrida, no este atajo.

save

save(path)

Serializa el Study a un directorio de forma atómica (escribe-a-temporal-y-renombra).

Layout: config.yaml + run_metadata.json + lineage.json (si hay lineage) + artifacts/<domain>/<key>.joblib. Al sobrescribir, el directorio previo se aparta a un respaldo lateral antes de colocar el nuevo y se restaura si el swap falla. En el doble-fallo (falla el swap y también la restauración), el estudio previo queda preservado en el respaldo lateral .old.* y path podría quedar transitoriamente sin directorio válido; se prioriza no perder datos. El azar (seed_manager) no se guarda: se reconstruye en :meth:load. Devuelve el Path del directorio final.

load classmethod

load(path, *, trust=False)

Recarga un Study desde un directorio; reconstruye el azar y verifica el config_hash.

trust=False (default) rechaza un Study con artefactos pickle (vector de ejecución de código). Un config_hash que no coincide con el del lineage levanta :class:~nikodym.core.exceptions.ReproducibilityError; una divergencia de versiones de librerías sólo advierte. El SeedManager se reconstruye desde config.repro.seed.

Nota: el chequeo de config_hash detecta divergencia accidental entre config.yaml y el lineage, no manipulación maliciosa (el hash de referencia vive en el mismo directorio editable). La integridad fuerte recae en trust=True + control del origen del directorio.

ArtifactStore

Contenedor namespaced (domain, key) → valor con traza de auditoría por escritura.

El Study inyecta el sink de auditoría; si no se pasa, cae a NullAuditSink (nunca None), de modo que emitir es siempre seguro. get devuelve el mismo objeto guardado (identidad, sin copia defensiva).

set

set(domain, key, value, *, overwrite=False)

Escribe value bajo (domain, key) y emite un AuditEvent "artifact".

Si la clave ya existe y overwrite=False, levanta :class:~nikodym.core.exceptions.ArtifactExistsError. El payload del evento distingue creación de sobrescritura con el campo overwrite (trazabilidad SR 11-7). Convención del evento "artifact": step lleva el domain del artefacto (no el paso que lo escribió) y payload el (domain, key) completo; SDD-03 lo consume sin adivinar.

get

get(domain, key)

Devuelve el artefacto (domain, key) (el mismo objeto); ausente → error.

has

has(domain, key)

Indica si la clave (domain, key) está presente.

keys

keys()

Lista las claves (domain, key) presentes, en orden de inserción.

RunContext

Bases: BaseModel

Estado de vida de una corrida del Study.

Arranca en "created" (Study recién construido, serializable sin correr); run() lo transiciona created → running → done|failed y le cuelga el :class:LineageBundle congelado. No es frozen (run() muta su estado); extra="forbid" rechaza un campo intruso al recargar run_metadata.json.

LineageBundle

Bases: BaseModel

Bundle de trazabilidad de una corrida (gobernanza en el núcleo, §4 principio 3, SR 11-7).

Se construye al cierre del run (§7 paso 4); git_sha/data_hash/uv_lock_hash son | None por ausencia legítima (repo ausente, datos sin cargar, uv.lock ausente). data_hash es el hash del contenido lógico por bloques (no los bytes del Parquet, decisión D2); su cálculo vive en data/ (SDD-02), aquí sólo se declara el campo. extra="forbid" rechaza un campo intruso al revalidar el bundle desde disco (Study.load).

injected_artifacts enumera las claves que entraron desde fuera de la corrida. Su default vacío mantiene compatibles los bundles escritos antes de la puerta D-ART-7.

Step

Bases: Protocol

Lo que un dominio implementa para ser orquestable (SDD-01 §7).

@runtime_checkable permite isinstance(obj, Step) en el despacho del motor; sólo verifica la presencia de name/requires/provides/execute, no sus tipos ni firmas.

execute

execute(study, rng)

Ejecuta el paso: lee de study.artifacts, calcula y escribe su salida.

Configuración declarativa

NikodymConfig es la raíz del experimento (Pydantic v2): agrupa las secciones de reproducibilidad, orquestación y todos los dominios. Se acompaña de utilidades de identidad (config_hash), carga/volcado YAML y migración de esquema.

NikodymConfig

Bases: NikodymBaseConfig

Configuración completa del estudio: todas las secciones del pipeline en un solo objeto.

Cada sección es opcional: la que se deja vacía no se ejecuta, y NikodymConfig() sin argumentos construye un estudio con todas las secciones vacías. El orden de ejecución lo fija el motor, no el orden de los campos; audit, governance y tracking documentan y registran la corrida, pero no son pasos del pipeline.

RunConfig

Bases: NikodymBaseConfig

Parámetros de orquestación de la corrida.

ReproConfig

Bases: NikodymBaseConfig

Parámetros de reproducibilidad del experimento.

config_hash

config_hash(cfg)

Devuelve el SHA-256 hex (64 chars) del JSON canónico de las secciones computacionales.

Las secciones de dominio que lleguen opacas (un dict, porque el proceso aún no importó esa capa) se coaccionan antes de canonicalizar, de modo que el digest no dependa del orden de los import. Ver :func:_coaccionar_secciones_opacas y D-HASH-1.

Parameters:

Name Type Description Default
cfg NikodymConfig

Config ya validado del que derivar la identidad.

required

Returns:

Type Description
str

Digest hexadecimal SHA-256 del config sin las :data:INFRA_SECTIONS ni la ruta data.load.source (la identidad depende del CONTENIDO del dato, vía data_hash, no de su ubicación en disco).

load_config

load_config(path)

Carga un :class:NikodymConfig desde un fichero YAML.

Parameters:

Name Type Description Default
path str or PathLike

Ruta del fichero YAML del config.

required

Returns:

Type Description
NikodymConfig

Config validado e inmutable.

Raises:

Type Description
ConfigError

Si el YAML no cumple el schema (campo desconocido, tipo/rango erróneo).

loads_config

loads_config(text)

Carga un :class:NikodymConfig desde un string YAML.

Parameters:

Name Type Description Default
text str

Contenido YAML del config (un mapeo en la raíz).

required

Returns:

Type Description
NikodymConfig

Config validado e inmutable.

Raises:

Type Description
ConfigError

Si el YAML no es un mapeo o no cumple el schema.

dump_config

dump_config(cfg, *, exclude_unset=False)

Serializa un :class:NikodymConfig a YAML legible (orden de declaración).

Parameters:

Name Type Description Default
cfg NikodymConfig

Config a volcar.

required
exclude_unset bool

Si es True, omite los campos que no fueron provistos explícitamente (toman su default al recargar). Hace el volcado determinista frente al estado de imports para las secciones de capa diferida (report/audit/governance/validation): un dict de entrada sin, p. ej., report.document produce el MISMO YAML se haya importado o no la capa que coacciona a ReportConfig (que materializaría document por default_factory). El default False conserva el volcado completo (lineage auditable de una corrida).

False

Returns:

Type Description
str

YAML con las claves en orden de declaración y las tildes sin escapar.

migrate

migrate(raw)

Aplica el version-gate y la cadena de migradores a un config crudo.

Parameters:

Name Type Description Default
raw dict[str, Any]

Config recién deserializado del YAML, antes de validar. Un dict sin schema_version asume la versión base del paquete.

required

Returns:

Type Description
dict[str, Any]

El config listo para NikodymConfig.model_validate (migrado si hacía falta).

Raises:

Type Description
ConfigError

Si schema_version no es una cadena SemVer válida.

ConfigVersionError

Si schema_version es mayor que la del paquete (config "del futuro").

MigrationNotFoundError

Si falta un migrador para completar algún salto de versión necesario.

migration

migration(from_version, to_version)

Registra un migrador puro dict -> dict para el salto from_version -> to_version.

Valida en import time la linealidad de la cadena: el destino avanza estrictamente sobre el origen y no existe ya otro migrador con el mismo origen (evita ciclos, pasos que no progresan y bifurcaciones que colgarían o desviarían :func:migrate).

Parameters:

Name Type Description Default
from_version str

Versiones SemVer de origen y destino del migrador.

required
to_version str

Versiones SemVer de origen y destino del migrador.

required

Returns:

Type Description
Callable[[Migrator], Migrator]

Decorador que registra la función en :data:_MIGRATORS y la devuelve intacta.

Raises:

Type Description
ConfigError

Si el destino no avanza sobre el origen, o si ya hay un migrador con ese origen.

Datos

Carga, validación de esquema, definición del target, particionado y hashing lógico del dataset (data_hash) que alimenta el lineage.

DataConfig

Bases: NikodymBaseConfig

Carga el dataset, valida su esquema, define el target y arma las particiones.

columnas_que_produce

columnas_que_produce()

Columnas que este paso añade al frame, y que las secciones de abajo pueden nombrar.

Las cuatro se escriben sin condiciónDataStep.execute llama a TargetDefinition.apply y a Partitioner.split siempre (data/step.py:77-80)—, o sea que no hay rama que consultar: si esta sección corre, están.

🔴 Existen aquí porque el preflight compara contra el ARCHIVO y las secciones de abajo consumen la SALIDA de este paso. Medido: survival.input.event_col = "target" llega a done —el indicador de evento es el flag de malo, que es lo natural— y sin esta declaración el preflight lo acusaría de columna faltante. stability.temporal_column ya sufría lo mismo con tres valores alcanzables (D-RAM-6).

El import es perezoso por el ciclo: data/target.py y data/partition.py importan este módulo. Las constantes se toman de ellos y no se redeclaran: una constante duplicada que se mueva por un lado deja el preflight mintiendo por el otro, y este repo ya pagó una triplicada.

DataLoader

Carga el dataset crudo a pandas.DataFrame con copias defensivas.

from_config classmethod

from_config(cfg)

Construye un cargador desde DataConfig.load / LoadingConfig.

load

load(source=None, *, audit=None)

Carga source como DataFrame y devuelve una copia defensiva.

Parameters:

Name Type Description Default
source (str, Path, DataFrame or None)

Ruta CSV/Parquet/Excel (.xlsx) o DataFrame en memoria. Si es None, usa self.config.source; si ambos faltan, levanta DataValidationError. Excel solo se admite con backend='pandas'.

None
audit AuditSink or None

Reservado para la orquestación de DataStep; la carga no emite decisiones todavía.

None

Returns:

Type Description
DataFrame

Dataset cargado. Siempre es una copia nueva respecto de la fuente interna.

SchemaValidator

Valida columnas, tipos y reglas simples mediante pandera.

index_col se interpreta como el nombre del índice pandas ya existente: el validador no ejecuta set_index ni consume una columna ordinaria con ese nombre. Si el identificador vive como columna, debe declararse como ColumnSpec o en unique_keys; si vive en el índice, index_col exige que el índice tenga ese nombre y sea único.

from_config classmethod

from_config(cfg)

Construye un validador desde DataConfig.schema_ / SchemaConfig.

build_schema

build_schema()

Traduce SchemaConfig al contrato imperativo de pandera.

Returns:

Type Description
DataFrameSchema

Esquema listo para validar un DataFrame con backend pandas. El mapeo de tipos lógico→pandera es explícito: intint64, floatfloat64, strstr, boolbool, categorycategory y datetimedatetime64[ns].

validate

validate(df, *, audit=None)

Valida df y devuelve el DataFrame resultante de pandera.

Parameters:

Name Type Description Default
df DataFrame

Dataset a validar. No se muta in-place; si coerce=True pandera devuelve una copia con los tipos coaccionados.

required
audit AuditSink or None

Reservado para la orquestación de DataStep; la validación de esquema no emite decisiones todavía.

None

Returns:

Type Description
DataFrame

DataFrame validado, posiblemente coaccionado según ColumnSpec.coerce.

Raises:

Type Description
DataValidationError

Si pandera detecta incumplimientos. El mensaje agrega todos los fallos de failure_cases explicados en español: qué columna falta, qué tipo se esperaba o qué regla se incumplió. Es copy público, así que no transporta los literales de pandera (column_in_dataframe, not_nullable, in_range) ni el vocabulario de su volcado — los lee un usuario, no quien desarrolla la librería.

TargetDefinition

Deriva la etiqueta binaria desde reglas declarativas con precedencia explícita.

from_config classmethod

from_config(cfg)

Construye una definición desde DataConfig.target / TargetConfig.

apply

apply(df, *, audit=None)

Etiqueta df en una copia defensiva y devuelve el contenedor auditable.

Parameters:

Name Type Description Default
df DataFrame

Dataset validado sobre el que se evalúan las reglas de target. No se muta in-place.

required
audit AuditSink or None

Sumidero opcional para emitir eventos decision por exclusiones y ambigüedades.

None

Returns:

Type Description
LabeledFrame

Copia de df con target y label_status agregados, más resumen de clases.

Raises:

Type Description
ConfigError

Si una regla está vacía, referencia columnas inexistentes, usa un operador fuera de la allowlist o compara valores incompatibles con el dtype de la columna.

DataValidationError

Si la ventana declara fechas no datetime, si las columnas de salida colisionan con el input, o si el resultado queda sin buenos o sin malos.

Partitioner

Asigna particiones Dev/HO/OOT de forma estable por observación.

from_config classmethod

from_config(cfg)

Construye un particionador desde PartitionConfig.

split

split(lf, *, root_seed, rng, audit=None)

Particiona un LabeledFrame sin mutar el frame de entrada.

Parameters:

Name Type Description Default
lf LabeledFrame

Resultado de TargetDefinition.apply con columnas target y label_status.

required
root_seed int

Semilla raíz cruda: ancla la identidad estable por observación.

required
rng Generator

Generador derivado por core; reservado para sorteos auxiliares deterministas.

required
audit AuditSink or None

Sumidero opcional para emitir decisiones de estrategia y resumen.

None

Returns:

Type Description
PartitionResult

Copia del frame con partition categórico y ttd booleano.

Raises:

Type Description
ConfigError

Si la estrategia no existe en el factory local o su config es inconsistente.

DataValidationError

Si faltan columnas, hay particiones vacías o se viola el piso de malos.

suggest

suggest(lf)

Sugiere una PartitionConfig editable según señales temporales simples.

DataStep

Bases: AuditableMixin

Orquesta la secuencia canónica de datos y publica artefactos domain='data'.

from_config classmethod

from_config(cfg)

Construye DataStep desde NikodymConfig.data.

execute

execute(study, rng)

Ejecuta load → schema → special → target → partition → hash → artefactos.

metrics

metrics(study)

Publica el resumen métrico del dominio al namespace canónico (D-GOB-4).

Proyección directa de la card: los tres son escalares que DataCardSection ya declara, así que aquí no hay reducción que decidir. Sin metric_sections: data no tiene hoy payload estructurado CT-2, y fabricar uno para llenar el hueco sería inventar (D-GOB-5).

Análisis exploratorio (EDA)

Perfilado univariado, calidad de datos, tasa de default y estabilidad temporal previa al modelado.

EdaConfig

Bases: NikodymBaseConfig

Perfila la cartera antes de modelar: variables, calidad de datos y tasa de default.

UnivariateProfiler

Calcula perfiles descriptivos de features candidatas frente al target.

from_config classmethod

from_config(cfg)

Construye un profiler desde UnivariateConfig.

profile

profile(frame, *, target_col, columns, audit=None)

Calcula perfiles univariados sobre filas con target elegible.

Parameters:

Name Type Description Default
frame DataFrame

Dataset etiquetado por data o equivalente standalone.

required
target_col str

Columna binaria nullable: 1 malo, 0 bueno, <NA> no elegible.

required
columns tuple[str, ...]

Columnas candidatas a perfilar. Una tupla vacía produce resultado vacío.

required
audit AuditSink or None

Reservado para compatibilidad con la orquestación; este profiler puro no emite eventos auditables y no aplica muestreo.

None

Returns:

Type Description
UnivariateResult

Diccionario columna-tabla y, si se pidió, IV descriptivo pre-binning.

Raises:

Type Description
EdaError

Si faltan columnas requeridas, el frame está vacío o el índice no es único.

DataQualityProfiler

Calcula missing, cardinalidad y flags descriptivos por columna.

from_config classmethod

from_config(cfg)

Construye un profiler desde QualityConfig.

profile

profile(frame, *, audit=None)

Calcula el diagnóstico de calidad sin mutar el DataFrame de entrada.

Parameters:

Name Type Description Default
frame DataFrame

Dataset validado por data o equivalente standalone. Se diagnostican todas sus columnas.

required
audit AuditSink or None

Reservado para compatibilidad con la orquestación; este profiler puro no emite eventos auditables.

None

Returns:

Type Description
QualityResult

Tabla con una fila por columna y flags descriptivos de calidad.

Raises:

Type Description
EdaError

Si el frame está vacío o el índice no identifica observaciones de forma única.

DefaultRateAnalyzer

Calcula la tasa de default sobre la población elegible del target.

from_config classmethod

from_config(cfg)

Construye un analizador desde DefaultRateConfig.

compute

compute(frame, *, target_col, audit=None)

Calcula la tasa de default por período/cohorte sin mutar el input.

Parameters:

Name Type Description Default
frame DataFrame

Dataset etiquetado por data o equivalente standalone.

required
target_col str

Columna binaria nullable: 1 malo, 0 bueno, <NA> no elegible.

required
audit AuditSink or None

Reservado para compatibilidad con la orquestación; este analizador puro no emite eventos auditables.

None

Returns:

Type Description
DefaultRateResult

Tabla agregada ordenada y tasa global ponderada por elegibles.

Raises:

Type Description
EdaError

Si faltan columnas requeridas, el eje temporal es ambiguo/no datetime o no hay filas que describir.

TemporalStabilityAnalyzer

Bases: AuditableMixin

Evalúa la estabilidad temporal descriptiva de la tasa de default cruda.

from_config classmethod

from_config(cfg)

Construye un analizador desde TemporalStabilityConfig.

assess

assess(default_rate, *, audit=None)

Calcula CV, drift relativo extremo y pendiente OLS de la tasa de default.

Parameters:

Name Type Description Default
default_rate DefaultRateResult

Resultado de DefaultRateAnalyzer.compute con axis='period' y la tabla by_period ordenable temporalmente.

required
audit AuditSink or None

Sumidero opcional para registrar la decisión auditable de redesarrollo o no evaluabilidad.

None

Returns:

Type Description
StabilityResult

Indicadores descriptivos, métrica configurada, umbral y bandera de señal.

Raises:

Type Description
EdaError

Si el resultado no usa eje temporal o si by_period no contiene las columnas mínimas del contrato de B5.2.

EdaStep

Bases: AuditableMixin

Orquesta EDA y publica artefactos domain='eda' sin mutar data.

from_config classmethod

from_config(cfg)

Construye EdaStep desde NikodymConfig.eda.

execute

execute(study, rng)

Ejecuta default_rate → stability → univariate → quality → figures.

EdaStep sólo lee el dominio data y sólo escribe el dominio eda. Para particiones, lee ("data", "splits") de forma condicional cuando analysis_partition no es "todas"; esa clave no entra en requires por decisión de frontera documentada en el módulo.

Binning y WoE

Discretización supervisada con Weight of Evidence (WoE), monotonía controlada e IV (motor OptBinning tras el extra scoring).

BinningConfig

Bases: NikodymBaseConfig

Agrupa cada variable en tramos WoE y mide su poder predictivo con el IV.

requisitos_incumplidos_por_perfil

requisitos_incumplidos_por_perfil(perfil)

Invariantes que exigen mirar los DATOS, no sólo los nombres (D-PERF-3/4).

La invariante la declara aquí el dominio que la impone, igual que las de D-INV-1: es binning quien sabe que una columna de texto con casi un valor por fila no es un predictor.

El caso real que la motiva, medido con un CSV de cartera corriente: una columna id_operacion con un valor por fila entra por el comodín, OptBinning manda todas sus categorías al bin «otros», se queda sin ninguna y mata la corrida con un mensaje suyo, en inglés, que no nombra la columna. El paquete C ya dejó la salida —declararla en la llave de unicidad—; lo que faltaba era señalarla antes de pagar la corrida.

WoEBinner

Bases: TransformerMixin, BaseEstimator, NikodymTransformer

Wrapper sklearn-like sobre optbinning.BinningProcess para scorecard.

from_config classmethod

from_config(cfg)

Construye WoEBinner desde BinningConfig excluyendo el discriminador type.

fit

fit(X, y, *, special=None, sample_weight=None)

Ajusta bins supervisados WoE/IV sin mutar X, y ni special.

Raises:

Type Description
BinningFitError

Si el target no es binario con ambas clases, si todas las variables son no binneables, si OptBinning no alcanza un estado aceptable o si alguna tabla publica WoE infinito.

transform

transform(X)

Transforma variables crudas a columnas WoE usando bins fiteados previamente.

transform_bins

transform_bins(X)

Publica la etiqueta congelada de cada bin sin recalcular cortes ni WoE.

fit_transform

fit_transform(X, y, **kwargs)

Ajusta el binner y devuelve el woe_frame para el mismo X.

BinningResult

Bases: BaseModel

Contenedor agregado de las salidas principales de binning.

BinningStep

Bases: AuditableMixin

Orquesta binning supervisado WoE/IV y publica artefactos domain='binning'.

from_config classmethod

from_config(cfg)

Construye BinningStep desde NikodymConfig.binning.

execute

execute(study, rng)

Ejecuta fit en Desarrollo y transform determinista sin consumir rng.

rng se recibe por el protocolo homogéneo de Step; binning v1 no introduce muestreo ni azar propio. La reproducibilidad depende de la matriz fija de datos/config/OptBinning.

metrics

metrics(study)

Publica el resumen métrico del dominio al namespace canónico (D-GOB-4).

Los dos conteos que describen qué pudo binnearse. El IV por variable NO entra: es un mapa por variable, no un escalar del modelo, y aplanarlo publicaría una clave por columna en cada model card. Sin metric_sections (D-GOB-5).

Selección de variables

Filtrado pre-modelo por IV, correlación, VIF y estabilidad.

SelectionConfig

Bases: NikodymBaseConfig

Filtra las variables WoE candidatas por IV, correlación, VIF y estabilidad PSI/CSI.

FeatureSelector

Bases: TransformerMixin, BaseEstimator, NikodymTransformer

Selector sklearn-like de columnas WoE para scorecard.

from_config classmethod

from_config(cfg)

Construye FeatureSelector desde SelectionConfig y sus sub-configs.

fit

fit(
    woe_frame,
    *,
    target_col,
    partition_col,
    binning_summary,
    woe_column_map,
    audit=None,
)

Ajusta filtros de selección sobre Desarrollo sin mutar artefactos de entrada.

transform

transform(woe_frame)

Filtra el frame WoE a columnas estructurales y variables seleccionadas.

fit_transform

fit_transform(woe_frame, **kwargs)

Ajusta la selección y devuelve el frame WoE filtrado para el mismo input.

SelectionResult

Bases: BaseModel

Contenedor agregado de las salidas principales de selection.

SelectionStep

Bases: AuditableMixin

Orquesta selección pre-modelo y publica artefactos domain='selection'.

from_config classmethod

from_config(cfg)

Construye SelectionStep desde NikodymConfig.selection.

execute

execute(study, rng)

Ejecuta fit en Desarrollo y transform determinista sin consumir rng.

rng se recibe por el protocolo homogéneo de Step; selection v1 no introduce muestreo ni azar propio. La reproducibilidad depende de datos, config y versiones instaladas.

metrics

metrics(study)

Publica el resumen métrico del dominio al namespace canónico (D-GOB-4).

max_abs_correlation_after_selection es opcional en la card —sin pares que comparar no hay máximo— y se publica None para que el núcleo lo OMITA en vez de rellenarlo con 0.0, que leería como «cero correlación» cuando lo cierto es «no se pudo evaluar». Sin metric_sections (D-GOB-5).

Modelo (regresión logística PD)

Regresión logística sobre variables WoE con stepwise, política de signos e inferencia (statsmodels).

ModelConfig

Bases: NikodymBaseConfig

Ajusta la regresión logística de PD sobre las variables WoE seleccionadas.

LogisticPDModel

Bases: ClassifierMixin, BaseEstimator, NikodymClassifier

Modelo logístico PD sobre columnas WoE seleccionadas.

from_config classmethod

from_config(cfg)

Construye LogisticPDModel desde ModelConfig y sus sub-configs.

fit

fit(
    X,
    y,
    *,
    feature_names,
    woe_columns,
    iv_by_feature,
    audit=None,
    sample_weight=None,
)

Ajusta la logística PD y el stepwise usando sólo filas de Desarrollo.

decision_function

decision_function(X)

Devuelve el predictor lineal preservando índice y orden de entrada.

predict_pd

predict_pd(X)

Devuelve PD cruda P(target=1) preservando el índice original.

predict_proba

predict_proba(X)

Devuelve probabilidades [P(good), P(bad)] con el orden de entrada.

predict

predict(X)

Clasifica con umbral fijo 0.5; la calibración formal vive en SDD-10.

ModelResult

Bases: BaseModel

Contenedor agregado de artefactos publicados por la capa model.

ModelStep

Bases: AuditableMixin

Orquesta ajuste logístico PD y publica artefactos domain='model'.

from_config classmethod

from_config(cfg)

Construye ModelStep desde NikodymConfig.model.

execute

execute(study, rng)

Ejecuta fit en Desarrollo y predicción PD determinista sin consumir rng.

rng se recibe por el protocolo homogéneo de Step; model v1 no introduce muestreo ni azar propio. La reproducibilidad depende de datos, config y versiones instaladas.

metrics

metrics(study)

Publica el resumen métrico del dominio al namespace canónico (D-GOB-4).

Sólo el tamaño del modelo final. Los estadísticos de ajuste viven en ModelFitStatistics y son un DTO, no escalares del namespace: su lugar es metric_sections cuando SDD-08 declare qué va dentro.

metric_sections

metric_sections(study)

Publica el payload estructurado CT-2 de la card, sin aplanar (D-GOB-3).

Scorecard

Traducción de coeficientes a puntajes enteros (escala PDO / target odds), con overrides y redondeo controlado.

ScorecardConfig

Bases: NikodymBaseConfig

Traduce el log-odds del modelo a puntos de scorecard.

direccion_del_score_declarada

direccion_del_score_declarada()

Declara con qué orientación esta sección construye el puntaje (D-DIR-5).

Es el protocolo METODO_CONVENCION_SCORE del preflight, por convención de nombre y no por herencia, igual que requisitos_incumplidos. Existe para que el núcleo no tenga que leer config.scorecard.score_direction: con la sección opaca —el estado por defecto— ese atributo sería una clave de dict, y el núcleo pasaría a conocer el vocabulario de un dominio, que es justo lo que D-INV-1 rechazó.

Quien la construye es quien la declara: scorecard es la única sección que fabrica el puntaje (scaler.py:536-553 decide el signo de cada punto con este valor). performance y stability sólo lo miden, y por eso preguntan en vez de declarar.

PointsScaler

Bases: NikodymTransformer

Escala componentes log-odds de una logística WoE a puntos de scorecard.

from_config classmethod

from_config(cfg)

Construye PointsScaler desde ScorecardConfig excluyendo type.

fit

fit(
    *,
    coefficients,
    final_features,
    final_woe_columns,
    binning_tables,
    woe_column_map,
    audit=None,
)

Deriva puntos por bin desde coeficientes y tablas WoE sin mutar entradas.

transform

transform(woe_frame)

Publica columnas de puntos y score total desde un frame WoE ya validado.

Scorecard

Bases: PointsScaler, TransformerMixin, BaseEstimator

Transformer sklearn-like que publica puntos por variable y score total.

fit_from_artifacts

fit_from_artifacts(
    *,
    model_result=None,
    binning_result=None,
    coefficients=None,
    final_features=None,
    final_woe_columns=None,
    binning_tables=None,
    woe_column_map=None,
    audit=None,
)

Ajusta el scorecard desde DTOs de model/binning o artefactos explícitos.

ScorecardResult

Bases: BaseModel

Contenedor agregado de artefactos publicados por la capa scorecard.

ScorecardStep

Bases: AuditableMixin

Orquesta el escalamiento log-odds a puntos y publica domain='scorecard'.

from_config classmethod

from_config(cfg)

Construye ScorecardStep desde NikodymConfig.scorecard.

emit

emit(event)

Permite pasar el step como AuditSink a PointsScaler.

execute

execute(study, rng)

Ejecuta scorecard determinista sin consumir rng y publica cuatro artefactos.

metrics

metrics(study)

Publica el resumen métrico del dominio al namespace canónico (D-GOB-4).

Sólo el tamaño de la tarjeta. pdo, target_score, factor y offset son PARÁMETROS de escalamiento elegidos por la institución, no resultados medidos: publicarlos como «métricas del modelo» es justamente el error que D-GOB-4 evita.

metric_sections

metric_sections(study)

Publica el payload estructurado CT-2 de la card, sin aplanar (D-GOB-3).

Calibración

Ajuste de la PD cruda a un ancla de negocio (through-the-cycle), con tope de offset auditable.

CalibrationConfig

Bases: NikodymBaseConfig

Ajusta la PD cruda del modelo a una tasa central de anclaje aprobada.

PDCalibrator

Bases: NikodymTransformer

Calibra PD cruda de una logística a una tasa central.

from_config classmethod

from_config(cfg)

Construye PDCalibrator desde CalibrationConfig excluyendo type.

fit

fit(raw_pd_frame, *, audit=None)

Ajusta parámetros de calibración usando sólo filas de Desarrollo.

transform

transform(raw_pd_frame)

Aplica la calibración fiteada y publica las ocho columnas canónicas.

fit_transform

fit_transform(raw_pd_frame, *, audit=None)

Ajusta el calibrador y devuelve el frame calibrado para la misma entrada.

CalibrationResult

Bases: BaseModel

Contenedor agregado de artefactos publicados por la capa calibration.

CalibrationStep

Bases: AuditableMixin

Orquesta la calibración de PD cruda y publica domain='calibration'.

from_config classmethod

from_config(cfg)

Construye CalibrationStep desde NikodymConfig.calibration.

emit

emit(event)

Permite pasar el step como AuditSink si un motor futuro lo requiere.

execute

execute(study, rng)

Ejecuta calibration determinista sin consumir rng y publica cuatro artefactos.

metrics

metrics(study)

Publica el resumen métrico del dominio al namespace canónico (D-GOB-4).

El ancla objetivo y las dos tasas que permiten juzgar si la calibración la alcanzó. Sin las tres juntas, calibrated_mean_pd_dev no dice nada por sí sola.

metric_sections

metric_sections(study)

Publica el payload estructurado CT-2 de la card, sin aplanar (D-GOB-3).

Desempeño

Métricas de discriminación (AUC/KS/Gini) y desempeño por decil, por partición.

PerformanceConfig

Bases: NikodymBaseConfig

Mide el desempeño del modelo ya ajustado: AUC, Gini, KS y tablas de gains por partición.

requisitos_incumplidos

requisitos_incumplidos(columnas)

Invariantes que el evaluador exige y que sólo se descubrían corriendo (D-INV-1).

No dependen del dataset —columnas va sin usar—, pero el protocolo la recibe igual porque el comprobador no sabe de antemano qué necesita cada dominio.

requisitos_incumplidos_por_contexto

requisitos_incumplidos_por_contexto(contexto)

Avisa si esta sección mide el puntaje al revés de como se construyó (D-DIR-5).

🔴 Es el defecto más caro que este repo ha medido, y no fallaba: publicaba. Con la tarjeta construida en un sentido y el desempeño midiendo en el otro, la corrida llega a done y el informe publica Gini -0,424 —un modelo con la discriminación invertida— con el validador, check_pipeline, check_dataset y la corrida los cuatro en verde y cero avisos.

Se avisa aunque hoy el valor sea inerte. Medido: la orientación sólo entra al cálculo con evaluation_source='score'; con la fuente por defecto no cambia ningún número. Callar en ese caso dejaría la contradicción escrita, publicada en la ficha del informe y lista para volverse mortal en cuanto alguien cambie la fuente con dos clicks — que es exactamente el camino por el que se llegó al Gini invertido.

PerformanceEvaluator

Bases: AuditableMixin, BaseNikodymEstimator

Calcula métricas discriminantes y deciles/gains para score o PD calibrada.

from_config classmethod

from_config(cfg)

Construye el evaluador desde PerformanceConfig excluyendo metadatos de schema.

evaluate

evaluate(
    frame,
    *,
    score_column,
    pd_column,
    target_column,
    partition_column,
)

Evalúa AUC/Gini/KS y tabla de deciles por partición.

Parameters:

Name Type Description Default
frame DataFrame

Frame analítico post-modelo con score, PD calibrada, target y partición.

required
score_column str

Columna del score operacional.

required
pd_column str

Columna de PD calibrada post-modelo.

required
target_column str

Columna target binaria, con 1 como default.

required
partition_column str

Columna que identifica desarrollo, holdout y oot.

required

Returns:

Type Description
PerformanceResult

DTO agregado con performance_table, discriminant_metrics, records y card.

PerformanceResult

Bases: BaseModel

Contenedor agregado de artefactos publicados por la capa performance.

PerformanceStep

Bases: AuditableMixin

Orquesta desempeño post-modelo y publica domain='performance'.

from_config classmethod

from_config(cfg)

Construye PerformanceStep desde NikodymConfig.performance.

emit

emit(event)

Permite pasar el step como AuditSink si un motor futuro lo requiere.

execute

execute(study, rng)

Ejecuta performance determinista sin consumir rng y publica cuatro artefactos.

metrics

metrics(study)

Publica el resumen métrico del dominio al namespace canónico (D-GOB-4).

🔴 Aquí hay REDUCCIÓN, no proyección: AUC, Gini y KS no son campos escalares de PerformanceCardSection —el único escalar declarado es n_deciles—, sino que viven en max_metrics_by_partition, un dict por partición. Se publica una clave por partición y métrica, auc_<partición>, porque colapsar las particiones a un número exigiría elegir cuál manda y esa elección es institucional, no del motor.

Una partición not_evaluable —cartera corta, sin ambas clases— trae None y el núcleo la OMITE. Es el caso real de una cartera pequeña, y publicar 0.0 ahí diría «AUC de 0.0», que es peor que no decir nada.

metric_sections

metric_sections(study)

Publica el payload estructurado CT-2 de la card, sin aplanar (D-GOB-3).

Estabilidad

PSI/CSI y estabilidad temporal del puntaje y de las características.

StabilityConfig

Bases: NikodymBaseConfig

Mide la estabilidad del score y de la PD calibrada con PSI y CSI.

requisitos_incumplidos

requisitos_incumplidos(columnas)

Invariantes que esta sección impone y que la corrida rechazaría (D-INV-1).

No son validaciones de forma —de eso se encarga _check_invariantes— sino exigencias sobre la combinación de campos y sobre el dataset, que hasta ahora sólo se descubrían pagando la corrida entera: el caso de origen de la enmienda moría en el paso 8 de 10 con el preflight y check_pipeline en verde.

requisitos_incumplidos_por_contexto

requisitos_incumplidos_por_contexto(contexto)

Avisa si esta sección describe el puntaje al revés de como se construyó (D-DIR-5).

⚠️ Aquí la consecuencia no es un número invertido: es un documento que se contradice. Medido, el motor de estabilidad no lee este campo en ningún cálculo —PSI y CSI comparan distribuciones binadas y son invariantes al signo—; el valor viaja del config a la ficha y de ahí al informe. Con la respuesta contraria a la de la tarjeta, el mismo documento afirma dos orientaciones distintas del mismo puntaje, y el lector no tiene cómo saber cuál rige.

StabilityEvaluator

Bases: AuditableMixin, BaseNikodymEstimator

Calcula PSI del score/PD, CSI por característica y estabilidad temporal post-modelo.

from_config classmethod

from_config(cfg)

Construye el evaluador desde StabilityConfig excluyendo metadatos de schema.

evaluate

evaluate(
    frame,
    *,
    score_column,
    pd_column,
    partition_column,
    feature_point_columns,
)

Evalúa PSI del score/PD, CSI por característica y estabilidad temporal por partición.

Parameters:

Name Type Description Default
frame DataFrame

Frame analítico post-modelo con score, PD calibrada, partición, columnas <feature>__points y, si aplica, la columna de período/cohorte.

required
score_column str

Columna del score operacional.

required
pd_column str

Columna de PD calibrada post-modelo, estrictamente en (0, 1).

required
partition_column str

Columna que identifica desarrollo, holdout y oot.

required
feature_point_columns Sequence[str]

Columnas <feature>__points cuya distribución de puntos alimenta el CSI.

required

Returns:

Type Description
StabilityResult

DTO agregado con psi_table, stability_metrics, records y card.

StabilityResult

Bases: BaseModel

Contenedor agregado de artefactos publicados por la capa stability.

StabilityStep

Bases: AuditableMixin

Orquesta estabilidad post-modelo y publica domain='stability'.

from_config classmethod

from_config(cfg)

Construye StabilityStep desde NikodymConfig.stability.

emit

emit(event)

Permite pasar el step como AuditSink si un motor futuro lo requiere.

execute

execute(study, rng)

Ejecuta stability determinista sin consumir rng y publica cuatro artefactos.

metrics

metrics(study)

Publica el resumen métrico del dominio al namespace canónico (D-GOB-4).

worst_psi es una REDUCCIÓN de max_psi_by_comparison (un dict por comparación): el peor caso es lo que gobierna la conclusión de estabilidad, y es la única forma de publicar un escalar sin elegir por la institución qué comparación importa. Sin ninguna comparación evaluable no hay peor caso, y la clave se omite en vez de valer 0.0 —que leería como «estabilidad perfecta», la lectura exactamente opuesta a la verdadera—.

metric_sections

metric_sections(study)

Publica el payload estructurado CT-2 de la card, sin aplanar (D-GOB-3).

Validación

Backtesting y pruebas regulatorias de discriminación, calibración y estabilidad (familias de tests).

ValidationConfig

Bases: NikodymBaseConfig

Valida el modelo con calibración y backtesting, y lo resume en un semáforo.

requisitos_incumplidos

requisitos_incumplidos(columnas)

Invariantes que el evaluador exige y que sólo se descubrían corriendo (D-INV-1).

families vacío es el caso caro: el campo no tiene min_length, _check_validation sólo mira la coherencia backtesting↔enabled, y validation corre penúltimo en el F1 — así que un if de una línea tumbaba la corrida con todo el cómputo ya pagado.

ValidationEvaluator

Orquesta las familias de validación activas y consolida un :class:ValidationResult (§4).

from_config classmethod

from_config(cfg)

Construye ValidationEvaluator desde NikodymConfig.validation.

validate

validate(
    *,
    calibrated_pd=None,
    performance_metrics=None,
    stability_metrics=None,
    stability_frame=None,
    ifrs9_detail=None,
    realised=None,
    model_ref="validation",
)

Ejecuta las familias activas en la secuencia canónica §7 y publica el resultado tidy.

calibrated_pd es el frame analítico común (§6): partition/target/ pd_calibrated/grade (nombres por config.calibration). Los artefactos consumidos (performance_metrics/stability_metrics) y los insumos de backtesting (ifrs9_detail/realised) se pasan tal cual; el evaluador copia todo en profundidad. model_ref identifica el modelo validado en la card. Levanta un :class:~nikodym.validation.exceptions.ValidationConfigError si no hay familias activas o si una brecha crítica gatilla con fail_on_falta_dato=True.

ValidationResult

Bases: BaseModel

Contenedor agregado de los artefactos publicados por la capa validation (§4/§6).

ValidationStep

Bases: AuditableMixin

Orquesta la validación avanzada y publica domain='validation'.

from_config classmethod

from_config(cfg)

Construye ValidationStep desde NikodymConfig.validation.

emit

emit(event)

Permite pasar el step como AuditSink si un motor futuro lo requiere.

execute

execute(study, rng)

Ejecuta la validación determinista sin consumir rng y publica seis artefactos.

Backends ML

Modelos GBDT (XGBoost, LightGBM, CatBoost), random forest y SVM como extras selectivos, con monotonía y comparación challenger frente al scorecard.

MLConfig

Bases: NikodymBaseConfig

Entrena un challenger de machine learning que reta al scorecard campeón.

Compite sobre los mismos datos que el campeón.

contrato_de_variables_declarado

contrato_de_variables_declarado()

Publica de dónde salen las variables del challenger en ESTA corrida (D-REQ-3).

Lo consume el resolver del núcleo por convención de nombre (core.steps.METODO_CONTRATO_VARIABLES) para armar el contexto con que tuning y explain calculan su requires. Los dos pasos ajustan el mismo modelo que esta sección describe, así que leen artefactos distintos según lo que aquí se decida: con feature_source='selection_woe' el WoE lo publica selection, no binning.

🔴 Existe para que el núcleo no tenga que conocer estos dos campos. Podría leer config.ml.feature_source en dos líneas, y sería el acoplamiento que D-INV-1 rechazó: con la sección opaca —el estado por DEFECTO— eso es una clave de dict y el núcleo pasaría a depender del vocabulario de este dominio. Aquí el núcleo transporta un mapa de str cuyas claves no interpreta; quien las lee es quien las necesita.

⚠️ Son dos campos y no uno: hasta D-REQ-3, tuning declaraba binning.tables/binning.result, que sólo consume con monotonic.mode 'from_binning': con 'off' exigía dos artefactos que nunca lee.

🔴 data_raw NO se publica, y salió al implementar. Es una fuente diferida: el motor la rechaza siempre con FALTA-DATO-ML-1, nombrando la carencia y las dos salidas. Publicarla hacía que el paso declarase ('data','frame') como prerequisito duro, y entonces el DAG cortaba antes con «necesita 'frame', que produce 'data'» — un mensaje cierto y mucho peor, sobre un config que el motor iba a rechazar de todos modos. Omitirla no es declarar de menos: un paso con data_raw no llega a correr nunca, así que sus requisitos son irrelevantes y lo único que importa es cuál de los dos errores se lee.

MLResult

Bases: BaseModel

Contenedor agregado de los artefactos publicados por la capa ml (SDD-12 §4/§6).

term_structure

term_structure()

Retorna None: el challenger ML no publica estructura temporal (CT-2, SDD-12 §9).

A diferencia de IFRS 9/forward, ml produce una PD escalar por observación, no una curva multi-período; alimenta a report/governance por card + metric_sections.

comparison_frame

comparison_frame()

Materializa el tidy de :class:MLComparisonRecord (SDD-12 §6).

Preserva el orden de los registros (el MLStep los produce en el orden de config de particiones y métricas). Importa pandas de forma perezosa para no romper el import liviano de nikodym.ml.

MLStep

Bases: AuditableMixin

Orquesta el challenger ML y publica domain='ml' (SDD-12 §4/§7).

from_config classmethod

from_config(cfg)

Construye MLStep desde NikodymConfig.ml.

emit

emit(event)

Permite pasar el step como AuditSink si un motor futuro lo requiere.

execute

execute(study, rng)

Entrena, predice, compara, (opcional) calibra, audita y publica siete artefactos (§7).

Tuning de hiperparámetros

Optimización del espacio de búsqueda (Optuna) con muestreadores/pruners deterministas.

TuningConfig

Bases: NikodymBaseConfig

Busca con Optuna los hiperparámetros del challenger definido en ml.

resolve_search_space

resolve_search_space(ml_config)

Resuelve el espacio de búsqueda efectivo contra el backend de ml (SDD-13 §5).

tuning hereda el backend de ml (no lo duplica): un ml ausente impide tunear (:class:~nikodym.tuning.exceptions.TuningConfigError). Con search_space vacío devuelve default_search_space(ml.backend); si el usuario declaró claves, cada una debe ser un hiperparámetro del params-model del backend y su kind debe casar con el tipo del campo (:class:~nikodym.tuning.exceptions.TuningSearchSpaceError).

TuningResult

Bases: BaseModel

Contenedor agregado de los artefactos publicados por la capa tuning (SDD-13 §4/§6).

term_structure

term_structure()

Retorna None: el tuning no publica estructura temporal (CT-2, SDD-13 §9).

A diferencia de IFRS 9/forward, tuning produce hiperparámetros escalares y una curva de optimización, no una curva multi-período; alimenta a report/governance por card + metric_sections.

trials_frame

trials_frame()

Materializa el tidy de :class:TuningTrialRecord (SDD-13 §6).

Columnas number, param_<hiperparámetro> (unión estable en orden de aparición), value y state, en el orden de ejecución de los trials. Importa pandas de forma perezosa para no romper el import liviano de nikodym.tuning.

TuningStep

Bases: AuditableMixin

Orquesta la búsqueda de hiperparámetros y publica domain='tuning' (SDD-13 §4/§7).

from_config classmethod

from_config(cfg)

Construye TuningStep desde NikodymConfig.tuning (firma histórica, standalone).

from_config_with_context classmethod

from_config_with_context(cfg, *, contexto)

Fábrica contextual del resolver (D-FX-2): declara el requires de ESTA invocación.

Segundo implementador del hook, y la razón de que su contexto dejara de ser un frozenset[str]: saber que selection corre no basta —lo que decide qué artefactos lee este paso es qué eligió ml, no qué secciones existen— (D-REQ-2).

emit

emit(event)

Permite pasar el step como AuditSink si un motor futuro lo requiere.

execute

execute(study, rng)

Busca θ* con Optuna, valida invariantes, audita y publica siete artefactos (§7).

Explicabilidad

Explicaciones globales/locales (SHAP opcional) y reason codes para scorecard y modelos ML.

ExplainConfig

Bases: NikodymBaseConfig

Explica cada decisión con el aporte del scorecard, valores SHAP y reason codes.

ExplainResult

Bases: BaseModel

Contenedor agregado de los artefactos publicados por explain (SDD-14 §4/§6).

term_structure

term_structure()

Retorna None: la explicación no publica estructura temporal (CT-2, SDD-14 §9).

A diferencia de IFRS 9/forward, explain atribuye una predicción escalar por observación, no una curva multi-período; alimenta a report/governance por card + metric_sections.

global_frame

global_frame()

Materializa el tidy de :class:ShapGlobalRecord (SDD-14 §6).

Preserva el orden de los registros (el step los produce descendente por mean_abs_contribution con desempate lexicográfico). Importa pandas de forma perezosa para no romper el import liviano de nikodym.explain.

reason_codes_frame

reason_codes_frame()

Explota los reason codes a un tidy (observación · factor) (SDD-14 §6).

Recorre reason_codes (la vista top-N de shap_local) preservando el orden de las observaciones y, dentro de cada una, el orden por rank. Importa pandas de forma perezosa.

ExplainStep

Bases: AuditableMixin

Orquesta la explicabilidad unificada y publica domain='explain' (SDD-14 §4/§7).

from_config classmethod

from_config(cfg)

Construye ExplainStep desde NikodymConfig.explain (histórica, standalone).

from_config_with_context classmethod

from_config_with_context(cfg, *, contexto)

Fábrica contextual del resolver (D-FX-2): declara el requires de ESTA invocación.

emit

emit(event)

Permite pasar el step como AuditSink si un motor futuro lo requiere.

execute

execute(study, rng)

Explica ML (SHAP) y/o scorecard (analítico), audita y publica siete artefactos (§7).

Survival

Modelos de tiempo-a-evento: Kaplan-Meier, hazard discreto y Cox/AFT (algunos tras extra).

SurvivalConfig

Bases: NikodymBaseConfig

Modela el tiempo hasta el incumplimiento y obtiene de ahí la PD lifetime.

requisitos_incumplidos

requisitos_incumplidos(columnas)

Lo que esta sección se exige a sí misma y detiene la corrida al final (D-INV-1).

🔴 El caso es caro y era invisible: con los dos campos de la grilla en su default, el motor cae a los tiempos observados, emite DATO-INSTITUCIONAL-SUR-1 y —como fail_on_falta_dato viene en Trueaborta en step.py:637-643, después de cargar el archivo, ajustar el modelo y calcular la term-structure. Medido con corridas reales: los cuatro métodos abortan, porque el fallback lo resuelve el paso y no cada motor.

Va en esta clase y no en las sub-secciones porque la condición necesita fail_on_falta_dato y method, que viven aquí. Es el mismo criterio por el que el gate del motor está en _card_from_model y no dentro de un motor.

⚠️ fail_on_falta_dato es parte de la condición, no un detalle: con él apagado la corrida llega a done y registra el aviso, así que avisar ahí sería un falso positivo —y el mensaje, que dice que la corrida se detendrá, sería literalmente falso—.

SUR-2 queda fuera con su razón medida: depende del CONTENIDO (todos censurados), no del config, y este protocolo sólo recibe nombres de columna.

SurvivalStep

Bases: AuditableMixin

Orquesta modelos survival y publica domain='survival'.

from_config classmethod

from_config(cfg)

Construye SurvivalStep desde NikodymConfig.survival.

emit

emit(event)

Permite pasar el step como AuditSink a los modelos survival.

execute

execute(study, rng)

Ejecuta survival determinista sin consumir rng y publica siete artefactos.

Cadenas de Markov

Estimación de matrices de transición y estructura temporal de PD por estados.

MarkovConfig

Bases: NikodymBaseConfig

Estima matrices de transición y la curva de PD lifetime desde un panel de migraciones.

MarkovStep

Bases: AuditableMixin

Orquesta matrices Markov y publica domain='markov'.

from_config classmethod

from_config(cfg)

Construye MarkovStep desde NikodymConfig.markov.

emit

emit(event)

Permite pasar el step como AuditSink sin exponer el sink interno.

execute

execute(study, rng)

Ejecuta Markov determinista sin consumir rng y publica siete artefactos.

Forward-looking

Proyección macroeconómica, modelos satélite y escenarios ponderados para PD point-in-time.

ForwardConfig

Bases: NikodymBaseConfig

Proyecta la PD con variables macroeconómicas y convierte entre PD PIT y PD TTC.

ForwardResult

Bases: BaseModel

Contenedor agregado de artefactos publicados por la capa forward.

term_structure

term_structure()

Retorna la term-structure forward-looking tidy o None si no existe.

Cumple CT-2: SDD-16 puede consumir esta salida sin que forward importe ni instancie el motor ECL. pandas se importa perezosamente aquí para mantener liviano import nikodym.forward.results.

ForwardStep

Bases: AuditableMixin

Orquesta forward-looking y publica domain='forward'.

from_config classmethod

from_config(cfg)

Construye ForwardStep desde NikodymConfig.forward.

emit

emit(event)

Permite pasar el step como AuditSink sin exponer el sink interno.

execute

execute(study, rng)

Ejecuta el flujo forward determinista y publica las diez claves del dominio.

Stress testing

Escenarios de shock, barridos de sensibilidad y reverse stress sobre las métricas de provisión.

StressConfig

Bases: NikodymBaseConfig

Aplica escenarios de stress, sensibilidad y reverse stress sobre la cartera.

StressResult

Bases: BaseModel

Contenedor agregado de artefactos publicados por la capa stress.

term_structure

term_structure()

Retorna la term-structure estresada tidy o None si no fue publicada.

Cumple CT-2: SDD-16/17 y reportes pueden consumir esta salida cuando existe. pandas se importa perezosamente aquí para mantener liviano import nikodym.stress.results.

scenarios

scenarios()

Retorna una copia de la tabla pública de escenarios/shocks aplicados.

tidy

tidy()

Retorna una copia de la tabla de impactos de stress.

StressStep

Bases: AuditableMixin

Orquesta stress testing severo y publica domain='stress'.

from_config classmethod

from_config(cfg)

Construye StressStep desde NikodymConfig.stress.

emit

emit(event)

Permite pasar el step como AuditSink sin exponer el sink interno.

execute

execute(study, rng)

Ejecuta el stress determinista y publica las nueve claves del dominio.

Provisiones

Dos marcos de provisión —IFRS 9/ECL y método interno (exposición por la tasa de pérdida del grupo, descompuesta en PD · LGD o provista directamente; jurisdiccionalmente neutro)— más una capa fina de orquestación que compara dos metodologías y aplica la regla declarada. El motor CMF (Chile) documentado más abajo es el caso de referencia de cómo se aterriza una norma local sobre esa base; su alcance y su fecha de verificación están en Aterrizar una norma local.

Sobre la regla del máximo

La regla del máximo del Capítulo B-1 (Circular N° 2.346 / 06.03.2024) es entre el método estándar de la CMF y el método interno del banco, y se aplica "para cada institución en Chile que consolida con el banco". No es un máximo entre la provisión CMF y el ECL de IFRS 9: el Compendio (Cap. A-2, num. 5) excluye el modelo de deterioro de NIIF 9 sobre las colocaciones y los créditos contingentes, porque esos criterios los define la propia CMF en B-1 a B-3. El comparativo CMF↔IFRS 9 que expone esta capa es un comparativo entre marcos contables (útil, por ejemplo, para reportar a una matriz extranjera), no una exigencia de la CMF.

ProvisioningConfig

Bases: NikodymBaseConfig

Compara dos fuentes de provisión configurables y aplica la regla declarada.

La regla del máximo del Cap. B-1 (Circular N° 2.346) es entre el método estándar de la CMF y el método interno del banco, por institución; comparar contra IFRS 9 es un contraste entre marcos contables, no la exigencia local.

sources property

sources

Par ordenado de dominios comparados (source_a, source_b).

consume_source_a property

consume_source_a

Consumo efectivo de la fuente A (el flag deprecado de su dominio manda si se informó).

consume_source_b property

consume_source_b

Consumo efectivo de la fuente B (el flag deprecado de su dominio manda si se informó).

portfolio_col_for

portfolio_col_for(source)

Columna de cartera declarada para el detail de la fuente indicada.

ProvisioningOrchestrator

Compara dos fuentes de provisión y aplica la regla declarada por celda (SDD-17 §6/§7).

from_config classmethod

from_config(cfg)

Construye el orquestador desde NikodymConfig.provisioning (revalida si aplica).

compare

compare(*, result_a, result_b, as_of_date, audit=None)

Aplica la regla (max / use_internal) por celda, determinista.

result_a y result_b son los resultados publicados por cfg.source_a y cfg.source_b respectivamente (posicionales por ranura, no por motor).

ProvisionOrchestrationResult

Bases: BaseModel

Contenedor agregado del comparativo de dos fuentes de provisión (SDD-17 §4/§6).

term_structure

term_structure()

Retorna la curva ECL de IFRS 9 (CT-2) o None si IFRS 9 no es fuente (SDD-17 §4).

Delega en la curva larga que IfrsProvisionResult.term_structure() publicó y que el orchestrator guardó en ifrs9_term_structure; la expone como copia defensiva. No fabrica una term-structure de la provisión reportada (que es escalar por celda): si IFRS 9 no participa retorna None — ni el CMF ni el método interno publican curva (D-CORE-7).

ProvisioningStep

Bases: AuditableMixin

Orquesta dos fuentes de provisión bajo la regla declarada (domain='provisioning').

from_config classmethod

from_config(cfg)

Construye ProvisioningStep desde NikodymConfig.provisioning.

emit

emit(event)

Permite pasar el step como AuditSink al orquestador (SDD-17 §9).

execute

execute(study, rng)

Aplica la regla a las dos fuentes sin usar rng y publica cuatro artefactos.

Motor CMF

CmfProvisioningConfig

Bases: NikodymBaseConfig

Calcula la provisión regulatoria CMF (Cap. B-1 y B-3) con el bundle de matrices versionado.

El bundle activo se elige en matrices.active_version.

Motor experimental: fuera de la garantía SemVer 1.x.

CmfProvisioningEngine

Calcula provisiones CMF B-1/B-3 con garantías verificadas o fail-fast.

from_config classmethod
from_config(cfg)

Construye el motor y carga las matrices CMF activas por config.

calculate
calculate(frame, *, pd_frame=None, as_of_date, audit=None)

Calcula detalle, resumen y card CMF preservando orden e índice del input.

CmfProvisionResult

Bases: BaseModel

Contenedor agregado de artefactos publicados por provisioning.cmf.

term_structure
term_structure()

Retorna None en CMF B-1 agregado, cumpliendo CT-2/D-CORE-7.

El modelo estándar CMF B-1 publica provisión agregada y por operación, no una curva lifetime ni una estructura multi-período. SDD-17 usa summary/card para comparar el método estándar con la fuente configurada; no fabrica una curva para CMF.

Motor IFRS 9 / ECL

IfrsProvisioningConfig

Bases: NikodymBaseConfig

Calcula las provisiones contables IFRS 9: staging y pérdida esperada (ECL).

Motor experimental: fuera de la garantía SemVer 1.x.

requisitos_incumplidos
requisitos_incumplidos(columnas)

Lo que esta sección se exige a sí misma y la corrida rechazará (D-INV-1).

🔴 El caso es el config DE FÁBRICA, y por eso importa tanto. Medido: los tres defaults —curva de survival, modo «ya viene a condiciones actuales» y escenarios de forwardconstruyen sin un solo error y revientan al calcular, porque las dos columnas que esas dos elecciones exigen —la marca de curva ajustada al momento y el peso de escenario— las publica únicamente forward: cero apariciones en survival/ y en markov/. Quien entra por el trabajo «Provisiones IFRS 9» recibe ese esqueleto; el preset F4 no lo sufre porque fija los tres a mano, o sea que el árbol ya sabía que los defaults no corren.

Va aquí y no en cada sub-sección porque la condición cruza dos de ellas: scenarios.source no puede juzgarse sin mirar pd.term_structure_source, que vive en su hermana. Es el mismo criterio con que la invariante de survival vive en la clase que ve method y el flag.

⚠️ No es un model_validator, y es deliberado. Las tres combinaciones son alcanzables y legítimas para quien inyecta su propia curva por código con esas columnas puestas; cerrarlas al construir mataría ese uso. Aquí se avisa (D-PRE-5, D-INV-3) y el motor sigue siendo la autoridad sobre sí mismo.

columnas no se usa: la exigencia es entre campos del config, no sobre el dataset.

IfrsProvisioningEngine

Motor económico IFRS 9 que orquesta la secuencia canónica de la ECL (SDD-16 §7).

from_config classmethod
from_config(cfg)

Construye el motor desde IfrsProvisioningConfig (molde hermano from_config).

calculate
calculate(
    frame,
    *,
    term_structure,
    calibrated_pd=None,
    as_of_date,
    audit=None,
)

Calcula la ECL IFRS 9 por operación y ensambla el :class:IfrsProvisionResult.

Parameters:

Name Type Description Default
frame DataFrame

DataFrame económico (exposición/drawn/límite, dpd, EIR, rating, LGD/recovery, flags). No se muta (copia defensiva).

required
term_structure DataFrame

Term-structure tidy lifetime PD del proveedor configurado (survival/markov/forward), con al menos row_id/period/time_value/pd_marginal. No se muta.

required
calibrated_pd DataFrame | None

PD 12m anclada por SDD-10 (columna pd_calibrated); obligatoria sólo cuando pd.base_pd_source='calibration'.

None
as_of_date str

Fecha de cálculo/cierre contable de la provisión (texto no vacío).

required
audit AuditSink | None

Sink de auditoría opcional (el step orquestador registra las decisiones de §9).

None

Returns:

Type Description
IfrsProvisionResult

Contenedor con staging/detail/ecl_term_structure/summary, los registros por operación y la card CT-2.

Raises:

Type Description
IfrsTermStructureError

Si la term-structure incumple el contrato tidy o sus invariantes.

IfrsConfigError

Si el modo PIT, la fuente de PD base o la fuente de escenarios exige insumos ausentes.

IfrsInputError

Si faltan columnas raíz del frame o los identificadores no son únicos/alineables.

MissingDependencyError

Si falta numpy o pandas.

IfrsProvisionResult

Bases: BaseModel

Contenedor agregado de artefactos publicados por provisioning.ifrs9 (SDD-16 §4).

term_structure
term_structure()

Retorna la term-structure de ECL en forma larga CT-2; nunca es None en IFRS 9.

Apila ecl_term_structure (ancho por componente) en la forma larga [row_id, scenario, period, time_value, component, value] que consumen SDD-17 y los reportes. Los componentes se preservan en orden canónico dentro de cada (row_id, scenario, period) y -0.0 se normaliza a 0.0.

Gobernanza

Model card (SR 11-7), inventario de modelos y registro de escenarios/overlays. Es la superficie de trazabilidad que run ensambla y (opcionalmente) publica al inventario.

GovernanceConfig

Bases: NikodymBaseConfig

Documenta el modelo para su gobierno: model card, inventario y diario de overlays.

Cambiar el propósito, los metadatos de inventario o la política de publicación no altera los resultados de la corrida ni su config_hash; el cambio queda registrado en el model card y en el audit-trail.

ModelCard

Bases: BaseModel

Ficha auditable del modelo, serializable a JSON canónico y markdown.

to_json

to_json()

Serializa el model card a JSON canónico para diff/auditoría.

to_markdown

to_markdown()

Renderiza una versión markdown estable del model card.

ModelCardBuilder

Ensambla un :class:ModelCard desde un Study finalizado y su trail.

build

build(study, *, trail_path=None)

Construye el model card desde lineage, resultados, artefactos y audit-trail.

ModelInventory

Bases: Protocol

Protocol SR 11-7 que SDD-04 implementa sobre MLflow Registry.

register debe ser idempotente por la ancla (model_name, nikodym.config_hash). Si el backend no soporta Registry, la implementación levanta RegistryUnavailableError.

register

register(entry)

Registra una entrada y devuelve el identificador de versión.

get_active

get_active(model_name)

Devuelve la versión activa del modelo, si existe.

list_versions

list_versions(model_name)

Lista las versiones conocidas del modelo.

NullInventory

Inventario no-operativo para publish_to_inventory=False.

register

register(entry)

No registra nada y devuelve cadena vacía por no-op consciente.

get_active

get_active(model_name)

Sin backend, no hay versión activa.

list_versions

list_versions(model_name)

Sin backend, no hay versiones.

InventoryEntry

Bases: BaseModel

Entrada completa que una implementación de inventario debe registrar.

publish_inventory

publish_inventory(entry, *, inventory=None)

Publica una entrada usando el inventario inyectado o NullInventory.

La resolución publish_to_inventory=True + extra tracking vive fuera de este módulo (B3.1c, assemble_run). Aquí solo se aplica el no-op explícito cuando el llamador entrega inventory=None.

ScenarioLog

Diario append-only de escenarios y overlays en JSONL canónico.

log_scenario

log_scenario(rec)

Añade un escenario al JSONL append-only.

log_overlay

log_overlay(rec)

Añade un overlay al JSONL, rechazando justificación vacía si fue manipulada.

read

read()

Lee y revalida todo el scenario_log en orden de escritura.

Auditoría, lineage y reproducibilidad

Audit sink JSONL, captura del entorno y hashing determinista de datos/archivos, más la relectura del trail para reconstruir la corrida.

AuditConfig

Bases: NikodymBaseConfig

Controla el audit-trail de la corrida y el snapshot del entorno de ejecución.

JsonlAuditSink

Sink que persiste el audit-trail a un archivo JSONL append-only.

emit

emit(event)

Serializa event como una línea JSON canónica y la añade al trail.

close

close()

Cierra el archivo de forma idempotente.

EnvironmentSnapshot

Bases: BaseModel

Registro serializable del entorno que acompaña a una corrida.

capture_environment

capture_environment(
    *,
    packages=None,
    uv_lock_path=None,
    now=None,
    version_provider=None,
    python_version_provider=None,
    platform_provider=None,
)

Captura versiones, plataforma, Python y hash de uv.lock.

Los proveedores son inyectables para que los tests fijen golden values exactos sin depender del entorno real del desarrollador.

hash_dataframe

hash_dataframe(df, *, algo='sha256')

Delegación perezosa al data_hash canónico de SDD-02.

hash_file

hash_file(path, *, algo='sha256')

Calcula el hash hexadecimal de un fichero leído por bloques.

read_trail

read_trail(path)

Lee todo el trail JSONL y devuelve una lista de AuditEvent revalidados.

iter_trail

iter_trail(path)

Itera eventos del trail, descartando líneas finales corruptas por crash.

Tracking (MLflow)

Registro opcional de corridas y modelos en un backend externo (MLflow), tras el extra correspondiente.

TrackingConfig

Bases: NikodymBaseConfig

Registra la corrida en MLflow y publica el modelo en el Model Registry.

Cambiar la URI, el experimento o la política de logging no altera los resultados de la corrida ni su config_hash, así que apuntar a otro destino no duplica versiones en el inventario.

TrackingRecorder

Frontera MLflow: traduce un Study ejecutado a un run auditable.

start_run

start_run(study, *, run_name=None)

Abre un run MLflow y devuelve un handle con sus identificadores.

ensure_run

ensure_run(*, run_name=None)

Abre un run si aún no existe; lo usa TrackingSink con eventos de core.

end_run

end_run(*, status='FINISHED')

Cierra el run activo si existe; doble cierre es no-op.

log_config

log_config(config)

Loguea params computacionales y tags de identidad del config.

log_metrics

log_metrics(results, *, step=None)

Loguea métricas finitas como metrics y el resto como results.json.

log_lineage

log_lineage(bundle)

Loguea lineage como tags de búsqueda y artefacto JSON.

log_study_dir

log_study_dir(path)

Adjunta el directorio serializado del Study bajo study/.

log_artifact_file

log_artifact_file(path, *, artifact_path=None)

Adjunta un fichero de artefacto al run activo.

register_model

register_model(model_uri, *, name=None, tags=None)

Registra un modelo vía el atajo MLflow de bajo nivel.

Con un Registry no respaldado por DB devuelve None + warning; el contrato regulatorio ruidoso vive en MLflowInventory.register.

snapshot_study

snapshot_study(study)

Guarda temporalmente el Study y adjunta su directorio si la config lo permite.

TrackingSink

Implementa AuditSink enrutando eventos del Study hacia TrackingRecorder.

emit

emit(event)

Procesa un evento de auditoría sin levantar hacia core por defecto.

MLflowInventory

Inventario SR 11-7 respaldado por MLflow Model Registry.

register

register(entry)

Registra entry idempotentemente por (model_name, config_hash).

get_active

get_active(model_name)

Devuelve la versión apuntada por el alias champion, si existe.

list_versions

list_versions(model_name)

Lista versiones rehidratadas desde tags del Registry.

list_models

list_models()

Lista modelos registrados con conteo y última versión.

get_version

get_version(name, version)

Lee una versión exacta; ausente levanta ModelNotFoundError.

latest_version

latest_version(name, *, alias=None)

Devuelve versión por alias o la última numérica; None si no existe.

Reportería

Reporte auditable del scorecard: ensamblado del bundle, render HTML/PDF y narración opcional (regla o IA).

ReportConfig

Bases: NikodymBaseConfig

Genera el informe auditable de la corrida y elige sus formatos de salida en formats.

ReportBuilder

Ensambla el documento lógico desde cards/results; no renderiza.

from_config classmethod

from_config(cfg)

Construye ReportBuilder desde NikodymConfig.report.

collect

collect(study)

Recolecta cards, tablas, figuras, parámetros y lineage en un snapshot defensivo.

build_sections

build_sections(bundle)

Construye el documento: capítulos, subsecciones de dominio y anexos.

El orden y los títulos salen de :data:~nikodym.report.document.CHAPTER_SPECS; la numeración (1-6 para capítulos, A/B/C para anexos) se deriva aquí, de modo que omitir un dominio no deja huecos en el índice.

Un capítulo con requires_domain informado es condicional: se omite entero si ese dominio no publicó card. La numeración se reajusta sola, porque se deriva de los capítulos efectivamente emitidos y no de la posición en CHAPTER_SPECS.

build_manifest

build_manifest(bundle, *, path)

Ensambla metadatos pre-render; el renderer completa el sha256 real.

HtmlReportRenderer

Render HTML standalone determinístico con Jinja2.

from_config classmethod

from_config(cfg)

Construye HtmlReportRenderer desde NikodymConfig.report.

render

render(bundle, *, ai_blocks=())

Renderiza HTML standalone byte-determinístico desde el bundle lógico.

build_manifest

build_manifest(html)

Construye el manifiesto HTML canónico sin escribir archivos.

write

write(html, *, output_dir)

Escribe el HTML en disco y devuelve un manifiesto reproducible.

PdfReportRenderer

Render opcional a PDF vía WeasyPrint sobre el HTML básico primario.

from_config classmethod

from_config(cfg)

Construye PdfReportRenderer desde NikodymConfig.report.

render

render(bundle, *, output_dir)

Renderiza y escribe el HTML básico y, si procede, un PDF opcional en disco.

El HTML determinístico es el artefacto primario: se escribe siempre y su manifest es el valor de retorno (igual que hoy con la ruta HTML). Con pdf.enabled se genera además un PDF con WeasyPrint (import perezoso) que se escribe como efecto secundario en {basename}.pdf y NO se refleja en el manifest. Si WeasyPrint no está disponible degrada a HTML (fail_if_unavailable=False) o re-lanza la dependencia ausente (True).

write_pdf_from_html

write_pdf_from_html(html, *, output_dir)

Escribe el PDF desde un HTML ya renderizado; devuelve su Path o None al degradar.

Recibe el HTML primario (que puede incluir la narrativa IA) y produce el PDF con WeasyPrint (import perezoso), sin re-renderizar el HTML. Degrada con gracia según pdf.fail_if_unavailable: en ausencia de WeasyPrint re-lanza la dependencia (True) o emite RuntimeWarning y devuelve None (False). En éxito escribe {basename}.pdf y devuelve el Path real en disco.

El warning propaga el diagnóstico de :func:~nikodym.report.pdf.render_pdf, que distingue "falta el paquete" de "el paquete está pero no encuentra sus nativas". Un texto genérico ("WeasyPrint no está disponible") describía mal el segundo caso —el más común en macOS y Windows, donde pip install nikodym[pdf] sí instaló WeasyPrint— y dejaba al usuario reinstalando un paquete que ya tenía.

ReportResult

Bases: _ReportBaseModel

Contenedor agregado publicado como salida final de la capa report.

md_path class-attribute instance-attribute

md_path = None

Ruta del .qmd (Quarto/Markdown): la fuente editable del informe, no un artefacto terminal. El analista escribe su contexto y sus conclusiones encima y compila su documento.

data_exports class-attribute instance-attribute

data_exports = Field(default_factory=dict)

{nombre de archivo: ruta real} de los adjuntos de datos (tablas por observación completas, ver :mod:nikodym.report.exports). Vacío si no se pidió csv ni xlsx.

ReportStep

Bases: AuditableMixin

Orquesta el reporte canónico F1 y publica domain='report'.

from_config classmethod

from_config(cfg)

Construye ReportStep desde NikodymConfig.report (firma histórica, standalone).

from_config_with_context classmethod

from_config_with_context(cfg, *, contexto)

Fábrica contextual del resolver (D-FX-2): recibe el contexto de ESTA invocación.

Study._resolve_step la prefiere sobre :meth:from_config cuando existe. Es la extensión genérica del resolver, no un caso especial de report: cualquier dominio cuyo contrato dependa de la invocación puede exponerla, y el que no la exponga no cambia.

⚠️ report sólo usa dominios_activos, que es lo que el contexto ya traía cuando era un frozenset a secas (D-REQ-2). Lo que cambió es la forma: el DTO permitió que otro paso necesitara más sin obligar a éste a enterarse.

emit

emit(event)

Permite pasar el step como AuditSink si un motor futuro lo requiere.

execute

execute(study, rng)

Ejecuta report determinístico sin consumir rng y publica tres artefactos.

Datasets y presets (helpers)

Utilidades para el quickstart y la UI: materialización determinista de datasets sintéticos, ingesta de uploads y el config F1 curado (standard_preset).

materialize

materialize(dataset_id, *, workdir)

Materializa un dataset a parquet determinista bajo workdir y lo cachea.

Deja además su perfil de columnas al lado (D-PERF-1), igual que :func:ingest_upload con un archivo subido: los datasets del catálogo no tienen por qué ser los únicos sobre los que el preflight no puede avisar de una columna identificador. Aquí también sale gratis —el generador ya devuelve el DataFrame—, y en la rama de caché lo repone :func:_asegurar_perfil.

Parameters:

Name Type Description Default
dataset_id str

Identificador del dataset. Un id uploaded_<token> resuelve el parquet ya materializado por :func:ingest_upload; en otro caso es la clave del registro sintético. Uno desconocido (o un upload no encontrado) levanta UiDatasetError.

required
workdir Path

Directorio de trabajo local; el parquet vive en workdir/datasets/<id>.parquet.

required

Returns:

Type Description
Path

Ruta del parquet materializado (o el cacheado si ya existía).

Raises:

Type Description
UiDatasetError

Si el dataset_id es desconocido, un upload no está materializado, o la ruta escaparía del workdir (path traversal).

list_datasets

list_datasets()

Devuelve el catálogo estable de datasets sintéticos.

Returns:

Type Description
list of dict

Un descriptor por dataset con id/name/description/columns/ index_columns/n_rows. Cada entrada de las dos listas trae name/dtype/ role y, desde D-COL-7, values con sus valores ofrecibles. El orden es estable (orden de inserción del registro), de modo que el listado no cambia entre corridas.

``index_columns`` va **aparte** desde D-PRO-1: el índice no es una columna, y publicarlo dentro
de ``columns`` hacía que la interfaz lo ofreciera donde el motor no puede leerlo. Un campo con
``column_role: "index"`` ofrece esta lista; uno con ``"input"``, la otra.
No depende del ``workdir``: estos datasets son sintéticos deterministas, así que sus valores
son una propiedad del catálogo y no de una materialización concreta.

ingest_upload

ingest_upload(
    content, filename, *, workdir, max_bytes=None
)

Ingesta un dataset propio subido y lo materializa a parquet canónico bajo workdir.

Valida tamaño/formato, lee el archivo con pandas según su extensión (.csv/.xlsx/ .parquet) y lo materializa en workdir/datasets/uploaded_<token>.parquet (token = sha256 del contenido: determinista ⇒ el mismo archivo reusa su parquet cacheado). Devuelve el dataset_id más un preview de columnas. Es domain-agnostic: no importa nikodym.data; el cableado de data.load.source ocurre luego en :func:nikodym.ui.routes.run_pipeline, dejando intacta la byte-identidad del config canónico (SDD-23 §9, §11).

Parameters:

Name Type Description Default
content bytes

Bytes crudos del archivo subido.

required
filename str

Nombre original; su sufijo (.csv/.xlsx/.parquet) determina el lector pandas.

required
workdir Path

Directorio de trabajo local; el parquet vive en workdir/datasets/uploaded_<token>.

required

Returns:

Type Description
dict

{dataset_id, name, n_rows, columns} con columns = lista de {name, dtype}.

Raises:

Type Description
UiDatasetError

Si el archivo está vacío, supera max_bytes, su formato no está admitido, no se puede leer con pandas o no contiene filas/columnas de datos.

standard_preset

standard_preset()

Devuelve el descriptor del preset estándar F1 (config curado + dataset recomendado).

Returns:

Type Description
dict

{id, name, description, config, dataset_id}: un config F1 completo y JSON-able (copia defensiva, no el literal compartido) alineado a las columnas del dataset sintético consumo_comportamiento. El config valida con NikodymConfig.model_validate y corre end-to-end produciendo un scorecard; dataset_id es el dataset recomendado para materializar y ejecutar la corrida (SDD-23 §3.2/§5).

Extras opcionales

Introspección de extras instalados e imports perezosos con error accionable cuando falta una dependencia opcional.

has_extra

has_extra(extra, *modules)

Devuelve True si todos los modules del extra están importables (sin levantar).

require_extra

require_extra(extra, *modules)

Importa y devuelve los módulos de un extra; si falta uno, levanta MissingDependencyError.

Parameters:

Name Type Description Default
extra str

Nombre del extra (clave de [project.optional-dependencies]), usado en el mensaje de instalación.

required
*modules str

Nombres de módulos importables a resolver (p. ej. "xgboost").

()

Returns:

Type Description
tuple of module

Los módulos importados, en el mismo orden.

Raises:

Type Description
MissingDependencyError

Si alguno de los módulos no se puede importar.

Examples:

>>> xgb, = require_extra("xgboost", "xgboost")