MLOps Data Contracts
ivyx✓
Adds data contracts to the MLOps extension, stopping the pipeline when your data stops matching
MLOps Data Contracts
The pandera engine for the MLOps hub: draft a data contract from a dataset you already have, then stop the pipeline when the data stops matching it.
pandera is the real upstream tool — this extension manages it, it does not imitate it. The contract is a pandera schema in your repository, it is code you edit, and git is its history.
What you can do
- Draft a data contract from a dataset you already have, instead of writing one from a blank file
- Keep that contract as code in your repository, edited by you and versioned in git
- Stop an MLOps pipeline the moment your data stops matching the contract, with the offending column named
- Check a dataset against its contract before anything downstream sees it
Requirements
The MLOps extension, the desktop app, and pandera in the Python environment your workspace already uses.
Getting started
This is step 5 of the walkthrough in the MLOps extension's README, which starts from an empty folder and ends with a run that this gate stops. Install this alongside MLOps and draft a contract from one of your datasets.
What a contract is here
A file the pipeline points at. Either a Python module that exports schema
(a DataFrameSchema) or defines a DataFrameModel class, or a pandera YAML
schema:
import pandera.pandas as pa
schema = pa.DataFrameSchema(
{
"id": pa.Column("int64", nullable=False),
"age": pa.Column("float64", nullable=True, checks=[pa.Check.in_range(18, 92)]),
"city": pa.Column(nullable=False, checks=[pa.Check.isin(["ankara", "izmir"])]),
},
strict=False,
coerce=False,
)
Wire it into .punica/mlops.yaml as a gate and the hub runs it in order:
stages:
- id: data-contract
kind: gate
capability: mlops.pandera.validate
input:
contract: contracts/data_contract.py
data: data/prepared.csv
onFailure: stop
- id: train
kind: pipeline
onFailure: stop
A failing gate marked stop ends the run, and train is recorded as skipped.
Drafting one from a dataset
mlops.pandera.contractFromProfile profiles a file through
Data Profiler and writes a contract from what the profile measured. The
draft is conservative on purpose — a generated contract that fails on the next
perfectly good file teaches people to ignore the gate:
- Column presence and nullability, from the observed null ratio.
- Numeric dtype, and the observed numeric range (turn this off with
ranges: false). - An
isinlist only when the profile proves the list is complete — top-K carries an(other)remainder whenever it does not cover every row, so its absence is exact evidence. - No
coerce, because coercion turns one missing value into three failures and hides real type drift. - No dtype on text or dates. Measured: pandas 2.3.3 reads a string column as
objectand pandas 3.0.5 reads it asstr, so a hardcoded string dtype breaks on whichever version the profile did not come from. - No
unique, because the profiler's distinct count is approximate and an approximation must not mint a hard constraint.
Everything it could not prove is written into the file's docstring rather than guessed.
How it runs
The interpreter comes from Python Environments (python.env.resolve) and
the validation driver is handed to it with -c. There is deliberately no bare
python3, no PATH lookup, and no scratch file written into your workspace to
run a gate.
The range this provider is written against is pandera[pandas]>=0.32,<0.34,
measured on pandera 0.32.1 with pandas 3.0.5. The pandas extra is not
optional: pandera installs without pandas, and the panel reports that state
separately because the fix is different.
Capabilities
| Capability | Policy | What it does |
|---|---|---|
mlops.pandera.validate |
low / none | Checks a dataset against a contract; reports which column failed which check, how often, and with what values |
mlops.pandera.contractFromProfile |
medium / none | Drafts a contract from a dataset profile and writes it into the workspace |
mlops.pandera.engine |
low / none | The installed pandera and pandas versions |
mlops.pandera.reveal |
low / none | Reveal the Data Contracts panel |
mlops.pandera.validate answers pass: false with a reason when the data
violates the contract — that is the verdict the MLOps hub records as a failed
stage. An unusable environment (no interpreter, no pandera, no pandas, a
contract that does not import) throws instead, with a different sentence for
each, because each has a different fix.
Limits worth knowing
- Electron-only: running processes is not something a browser host does.
- Whole-file validation. A dataset larger than memory needs a
limit, and the gate then states what it checked. - The panel reads its gate list from the hub's
mlops.pipeline.describe. With no MLOps hub installed it says so rather than showing an empty list.
Verification
npm run check:panderareplays measured driver envelopes (pandera 0.32.1 / pandas 3.0.5, plus two deliberately broken environments) through the shipped parsers, generator and panel logic. 78 checks.npm run probe:pandera -- /path/to/pythonbuilds a throwaway dataset, drafts a contract with the shipped generator, and drives the shipped engine against a live pandera: the draft accepts the data it came from, a raised null ratio fails the gate and names the column, every generated check fires, and a missing column is named. Re-run this after a pandera or pandas upgrade — a renamed check passes the harness and fails in the app.