Quickstart¶
This walks through the whole lifecycle once: track a training run, ask which models a subject's data reached, hand over a dossier, and check that the audit trail backing it hasn't been tampered with. Every command below is one you can run yourself, in order, in an empty directory.
Prefer a notebook?
consentml_demo.ipynb
is this same end-to-end workflow as a runnable notebook — train with
lineage, revoke, verify, and export a dossier — on a synthetic in-memory
dataset. It renders on GitHub without running anything.
Install¶
Requires Python 3.10 or later.
Data sources and export formats beyond the basics are behind optional
extras — consentml[postgres] and consentml[pdf] — introduced as they come
up below.
Track a training run¶
@track wraps a training function and hands it data from a Source you
declare. For data already in memory, DataFrameSource reads subject IDs out
of a column you name. Save this as train.py:
import pandas as pd
from sklearn.linear_model import LogisticRegression
from consentml import track
from consentml.sources import DataFrameSource
df = pd.DataFrame({
"patient_id": ["p1", "p2", "p3", "p4", "p5", "p6"],
"age": [52, 61, 45, 70, 39, 58],
"ldl": [130, 145, 110, 160, 95, 150],
"outcome": [0, 1, 0, 1, 0, 1],
})
@track(
model_name="readmission-risk",
source=DataFrameSource(df, subject_id_col="patient_id", label="clinic.patients"),
db_path="lineage.db",
)
def train(df):
return LogisticRegression().fit(df[["age", "ldl"]], df["outcome"])
model = train()
print(f"Trained {type(model).__name__} on {len(df)} rows.")
That call trained the model and, in the same step, recorded a training run
in lineage.db: which subjects (as SHA-256 digests, not raw IDs), what
query or frame produced the data, and a hash of the trained model itself.
Ask who was affected¶
revoke looks up a subject and reports which recorded runs their data
covers, with a per-model recommendation. --dry-run reports without writing
anything back to the log:
1 affected model for subject 3946ca64ff78…
- readmission-risk run=e8240888 trained=2026-08-14T04:00:04.211248+00:00 recommendation=retrain
Dry run: nothing recorded.
readmission-risk is flagged retrain because patient p2's data is in
this run and no later run supersedes it.
Double-check --db before you rely on a 0 affected models result: if the
path is wrong, revoke doesn't error — it creates an empty database at that
path and reports 0 affected models against it, --dry-run included. See
the CLI reference for what that means in
practice.
Produce a dossier¶
export turns that same lookup into the document you'd hand to whoever is
asking — audit-log integrity, affected models, and any revocation already on
record, all in one file:
The printed path is absolute and will point into your own working directory;
3946ca64ff78 is the same subject-key prefix revoke printed above, not the
raw subject ID — see Your first dossier for what the
document contains and why the filename is hashed.
Verify the trail¶
verify checks the audit log independently of any one subject — that every
entry still hashes to its recorded value, that the chain links correctly,
and that the log agrees with the live tables:
Audit log OK: 1 entries, chain intact.
head: 85d36e6f5c1ff020f9bd0221e1069294c983baa51b080d20f1a1ba101e747eff
Record that head hash somewhere outside the database if you want to be
able to detect a wholesale rewrite of the log later — see
the anchoring guide for how --expected-head uses
it.
From here: Tracking a run covers the decorator and data sources in more depth, and Your first dossier covers what the exported document says and doesn't say.