ump-spec
Contract import ump_spec
Ump-spec is the contract in code. Every shape the tools exchange, every rule that decides how numbers combine, and every gate lives here.
It is pure: no I/O beyond reading its own packaged registry files, and no numpy or modelling library. The other packages build on it. Analysts usually meet it through babelfin, which keeps the ump-spec object on .spec.
Quick path
Section titled “Quick path”- Install:
pip install -e 'packages/ump-spec'from a checkout. - Start an estimand from the registry and build a shown number.
from ump_spec.registries import registered_estimandfrom ump_spec.rules import shown_number
roi = registered_estimand("E-MMM-ROI")tv = shown_number(1.37, 1.26, 1.50, roi, label="TV ROI")tv.interval.level, tv.plain_words# (0.9, 'revenue per dollar, net from removing all spend, geo_set, versus zero spend,# total including carryover, posterior median, 90% eti')Main entry points
Section titled “Main entry points”| Module | What it holds |
|---|---|
ump_spec.models | Every exchanged shape: Estimand, ShownNumber, ModelManifest, TestResult, Calibration, DecisionRecord and more. validate_doc(kind, doc) checks a document against its kind. |
ump_spec.rules | Pure rule functions: shown_number, compare_estimands, align (gate G-EST-02), dependence_envelope (G-DEP-01), choose_ladder_step. |
ump_spec.gates | The gate catalogue and an evaluator that stands in for OPA/Rego: evaluate, summarize, raise_for_stops. |
ump_spec.integrity | Canonical JSON, content hashes, an RFC 9162 Merkle log with inclusion and consistency proofs, Ed25519 checkpoints. |
ump_spec.events / ump_spec.errors | CloudEvents 1.0.2 envelopes, Standard Webhooks signing, and UmpError with RFC 9457 problem details. |
ump_spec.adapter | Request and response models of the engine adapter contract. |
Compare estimands before combining
Section titled “Compare estimands before combining”from ump_spec.rules import compare_estimands
cmp = compare_estimands(registered_estimand("E-MMM-ROI"), registered_estimand("E-GEO-IROAS"))cmp.combinable # Falsecmp.mismatched # ['intervention', 'baseline', 'horizon', 'point_rule', 'interval']combinable is true only when all seven fields and the scope are declared and equal. Undeclared fields count as mismatched.
Walk the fallback ladder
Section titled “Walk the fallback ladder”from ump_spec.rules import choose_ladder_step
choose_ladder_step(["C", "D"]).step # 'spend_table'step = choose_ladder_step(["A"], excluded=["full_model"]) # a model that failed the acceptance barstep.step, step.warned, step.notes[0].gate # ('benchmarks', True, 'G-SCN-02')Validate and record
Section titled “Validate and record”from ump_spec import UmpError, validate_docfrom ump_spec.integrity import MerkleLog
try: validate_doc("model_manifest", doc)except UmpError as err: err.code # 'SCHEMA_INVALID', every issue listed with its pointer
log = MerkleLog()index, leaf = log.append_record("ump/decision/v1", {"q": "shift 10% to search"})log.root(), log.inclusion_proof(index)Command line
python -m ump_spec gates # list the gate cataloguepython -m ump_spec export-schemas schemas # regenerate the JSON Schemaspython -m ump_spec check model_manifest doc.json --strict # validate a document and run its gatesThe committed JSON Schemas are generated from the models. A test fails when they drift.
Conventions
- Value objects reject unknown fields. Artifact bodies keep them, so documents from other tools still load.
- Thresholds that wait on the pre-rollout studies are typed
Proposed, carrying their value and source, so a proposed number never reads as settled. - In an estimand,
Noneor the string"undeclared"means the source did not say. GateG-EST-01fills it from the source-type default, marks it assumed and widens the interval.
Conformance
Section titled “Conformance”The conformance suite is not yet published. The tests in this package are reference tests of this implementation only: passing them does not make a tool conformant, and they are not the suite that section 21 describes. Where the package and the spec disagree, the spec wins and the package has a bug.