BDP Model Gate 0.4.1
Pre-deployment ML governance

Every model gets a verdict before it ships.

Fairness, performance, compliance and security checks that run after training and before promotion — reduced to one status your pipeline can branch on. Built for decisions that answer to someone: credit scoring, underwriting, pricing and claims.

Get started Documentation $pip install "bdp-model-gate[structured]"
PASS exit 0

Deploy automatically

Nothing flagged. The pipeline promotes the model without a human in the loop.

NEEDS_REVIEW exit 2

Stop for sign-off

Only non-blocking flags. Fairness findings need judgement, so they route to a person rather than failing the build.

BLOCKED exit 1

Hard fail

A performance, compliance or security check failed. The build stops and the report says which.

What the reviewer gets

NEEDS_REVIEW hands the decision to a person.

So hand them a page, not a blob. report.to_html("gate-report.html") writes one self-contained file: the verdict in plain words, every finding with its evidence, and a chart beside each number whose shape is what has to be judged — a reliability curve, a threshold sweep showing whether the verdict survives a different cutoff, a loss-ratio scatter showing whether a margin gap is flat or grows with the risk.

No JavaScript, no stylesheet, no font, nothing fetched from anywhere. It opens offline years later and prints clean, because that is what a governance record has to do.

See what is in the report

Documentation

Where to go next

Sixteen checks, four categories

What gets checked

Optional inputs degrade rather than fail — omit protected attributes and the fairness checks report NOT_APPLICABLE instead of erroring. The gate grades what you give it.

Fairness

Needs review
  • proxy_correlation — features that encode a protected attribute
  • disparate_impact — demographic parity
  • shap_subgroup_gap — per-group contribution gaps
  • counterfactual_flip — prediction shift on attribute flip

Fairness, regression

Needs review
  • loss_ratio_parity — margin charged over each group's own expected loss
  • group_mean_gap — spread in mean prediction
  • error_parity — is the model worse for one group?
  • calibration_parity — systematic over- or under-prediction

Performance

Blocking
  • Score on a metric you choose — twelve built in, or your own callable
  • p95 latency against a benchmark run
  • Cost per inference

Compliance

Blocking
  • Model card completeness
  • DPIA required for a high-risk use case
  • Explainability documented where a decision affects a person

Security

Blocking
  • adversarial_robustness — gradient-directed or random perturbation
  • pii_leakage — raw identifiers in feature columns
  • prompt_injection — for any generative side-car

Yours

Your call
  • Subclass BaseCheck, implement run(context)
  • Declare blocking and supported_tasks
  • Ship checks from another package via an entry point
Coverage

Any task, any model

Nothing here imports a deep-learning framework. Pass an estimator with .predict(), or a plain fn(DataFrame) -> array — the boundary is deliberately narrow, so tensor conversion, batching and auth stay in your code.

TaskMetricsFairness
Binary
credit, fraud, lapse
roc_auc, average_precision, f1, … Demographic parity, proxy, SHAP, counterfactual
Multiclass & ordinal
underwriting decisions
quadratic_kappa, ordinal_mae, macro-averaged Parity against a favourable outcome you define
Regression
pricing, severity, frequency
rmse, mape, poisson_deviance, r2 Loss-ratio, mean gap, error parity, calibration
ModelWhat you pass
scikit-learn, LightGBM, XGBoost sklearn APImodel=estimator
Kerasmodel=, plus predict_proba_fn for the (n, 1) output
PyTorch nn.Modulepredict_fn, predict_proba_fn, gradient_fn
XGBoost native Boosterpredict_fn wrapping a DMatrix
Remote scoring endpointpredict_fn only — no model object at all
In your pipeline

Three lines, or one command

Build a context, run the gate, branch on the verdict. The same suite runs from Python or as a console script, and writes a JSON report your reviewers can read months later — it records which metric ran, which checks were skipped, and why.

Exit codes separate deploy from ask a human, which is the distinction most CI gates collapse.

from bdp_model_gate import ModelGate, StructuredGateContext

context = StructuredGateContext(
    model=pricing_model,
    X=X_val, y_true=realised_loss, y_pred=quoted_premium,
    protected_df=protected_val,
    expected_loss=technical_premium,  # margin parity
    task="regression",
)

report = ModelGate().run(context)
report.to_json("gate_report.json")

if report.gate_status == "BLOCKED":
    raise SystemExit(1)
Configurable to your regime

Out of the box the compliance and PII checks target NDPA/NDPR — patterns for NIN, BVN and Nigerian phone formats, with pricing, underwriting, credit scoring and claims decisioning as DPIA triggers. Every pattern, required field and high-risk use case is a plain list you replace, so the same suite runs against GDPR, CCPA or an internal standard. Defaults are a starting point, not regulatory advice.