Skip to content

Command line

Installing the package provides a bdp-model-gate console script, intended as a pre-deployment step — after training, before promotion. Not a per-PR check.

bdp-model-gate \
  --model model.joblib \
  --data validation.csv \
  --target-col label \
  --protected protected.csv \
  --model-card model_card.json \
  --task binary \
  --metric roc_auc --min-score 0.80 \
  --output gate_report.json

Exit codes

Code Status Pipeline should
0 PASS deploy
2 NEEDS_REVIEW pause for approval
1 BLOCKED hard fail

Three codes, not two, so a pipeline can tell deploy from ask a human.

Options

Model

Flag Notes
--model PATH a joblib-serialised model
--model-loader "pkg.mod:factory" a function returning a model or fn(DataFrame) -> array

Mutually exclusive. Use --model-loader for anything joblib cannot unpickle — PyTorch checkpoints, Keras SavedModel, ONNX, a remote endpoint. Your loader does the framework import, so this package needs no deep-learning dependency.

# mypkg/serving.py
def load_scorer():
    net = torch.load("model.pt")
    net.eval()
    return lambda df: net(torch.tensor(df.values).float()).detach().numpy()

Data

Flag Notes
--data PATH CSV of validation data — required
--target-col NAME ground-truth column — required
--protected PATH CSV of protected attributes, row-aligned
--train-data PATH CSV of the training features — unlocks split-overlap and drift
--expected-loss-col NAME column holding per-row expected loss
--exposure-col NAME column holding per-row exposure — weights the regression metrics and the pricing checks
--baseline-col NAME column holding the incumbent model's prediction — unlocks the dislocation check
--latencies PATH one latency in ms per line
--cost-per-inference FLOAT
--model-card PATH JSON model card
--generate-loader "pkg.mod:factory" a factory returning fn(str) -> str — the generative side-car, direct surface
--inject-loader "pkg.mod:factory" a factory returning fn(payload) -> str — the indirect surface, where retrieved content goes
--canaries-file PATH strings that must never appear in generated output, one per line

Champion

Flag Notes
--champion PATH the model this one would replace: .joblib/.pkl, .skops, .onnx or .keras/.h5
--champion-loader "pkg.mod:factory" a factory returning the champion — PyTorch, a SavedModel, a registry
--champion-col NAME column of --data holding the champion's predictions, in the same form as the challenger's; dropped from X
--champion-sha256 HEX pins the --champion file; checked before loading, and a mismatch exits 1
--champion-features a,b,c the columns the champion was fitted on, when the model does not record them
--champion-decision-threshold FLOAT the cut-off the champion is operated at, if it differs

The three sources are mutually exclusive. Any of them adds the comparison checks; without one they report NOT_APPLICABLE. --baseline-col is unchanged and is not an alias: it feeds only the dislocation check, so an existing pipeline that passes it does not suddenly start gating on a comparison it never asked for.

bdp-model-gate --model scorecard_v4.joblib \
  --champion scorecard_v3.joblib --champion-sha256 9f2c… \
  --data validation.csv --target-col label --output gate_report.json

The three column flags name columns of --data that are not features, and each is read out and then dropped from X. Leaving last quarter's premium in the feature frame would hand the model its own answer, which is the leak target_leakage exists to find.

--exposure-col belongs on a target expressed as a rate — claims per vehicle-year, loss cost per sum-insured-year. Leave it off when the target is a per-policy total, where the exposure is already inside the value. See Insurance pricing.

bdp-model-gate \
  --model premium_v4.joblib \
  --data motor_holdout.csv \
  --target-col realised_loss \
  --exposure-col earned_vehicle_years \
  --baseline-col premium_v3 \
  --expected-loss-col technical_premium \
  --task regression --metric lorenz_gini --min-score 0.15 \
  --config pricing_gate.yaml

There is no way to put a callable on a command line, so the three flags above follow --model-loader: your factory does the SDK import and the credential handling, so neither is a dependency of a governance gate.

bdp-model-gate \
  --model claims_model.joblib \
  --data validation.csv --target-col declined \
  --generate-loader "mypkg.sidecar:load_chat" \
  --inject-loader "mypkg.sidecar:load_claim_summariser" \
  --canaries-file canaries.txt \
  --config gate.yaml

--canaries-file is a file rather than a flag on purpose: a canary is usually a sentence from a system prompt, and putting that on a command line puts it in the shell history and the CI log of every run. One per line, # for a comment. Without canaries the leak probes can only be routed to a human — see Generative side-cars.

--train-data reads columns and distributions only, never labels: the target column is dropped if present, and the two frames need no row alignment. Give it and the validation checks can tell you whether the model has already seen the rows it is being graded on.

Task and scoring

Flag Notes
--task {auto,binary,multiclass,regression} default auto, which infers and logs
--class-order "a,b,c" ascending favourability; marks the problem ordinal
--favourable-classes "accept" defaults to the last of --class-order
--metric NAME see Configuration
--min-score FLOAT higher-is-better metrics
--max-error FLOAT error metrics — required when one is selected
--decision-threshold FLOAT default 0.5
--average {macro,micro,weighted} multiclass f1 / precision / recall

Other

Flag Notes
--config PATH JSON, YAML or TOML; CLI flags win
--output PATH default gate_report.json
-v, --verbose debug logging — per-check timing, what ran and why

In CI

- name: Model governance gate
  id: gate
  continue-on-error: true
  run: |
    bdp-model-gate --model model.joblib --data validation.csv \
      --target-col label --protected protected.csv \
      --model-card model_card.json --output gate_report.json

- name: Block on hard failure
  if: steps.gate.outcome == 'failure'
  run: exit 1

# exit 2 -> route to an environment with required reviewers

Ready-to-adapt GitHub Actions and Azure Pipelines examples ship in ci_examples/. Both structure it as three stages: run the gate, a manual approval gated behind exit code 2, and a deploy that runs only if the gate passed outright or was approved.