Skip to content

ump_spec.models.estimand

module ump-spec

Seven-field estimand (spec §5) and its scope (applies_to).

Every exchanged number carries one. Wire rules (spec §5, “Undeclared values”):

  • A field the source did not declare is written as the string "undeclared". In Python it reads as None; every dump writes "undeclared" for the seven fields and for a required sub-field (unit.per, unit.currency with per: spend, intervention.size_kind with a size, baseline_x with reduced_spend), so the absent and explicit forms hash the same.
  • JSON null is invalid anywhere in the estimand, on input. Optional members that are unset are left out of every dump.
  • Nothing has a default: no per, currency, schema_version or size_kind is filled in.
  • A member that is not one of the seven fields, their sub-fields or a registered optional member is rejected with ESTIMAND_UNKNOWN_FIELD (pydantic error type estimand_unknown_field).

G-EST-01 fills an undeclared field from the source-type default (ump_spec.rules.estimands.fill_undeclared), marks it assumed in field_status and widens the interval. normalise_legacy_estimand reads docs written before this contract (<ccy>_spend, nulls, weeks: null, the old defaults); it is read compatibility for one cycle and never a writer.

class

class Intervention(_EstimandPart)

Fields

NameTypeDefaultDescription
typeInterventionType
sizefloat | NoneNonee.g. -0.30 for a 30% cut, 0.10 for +10%.
size_kindSizeKind | NoneNoneHow to read size: relative (a fraction of current spend) or absolute (spend in unit.currency). Required when size is present; no default (spec §5).
armslist[str]list()
populationPopulation | NoneNone

Source: packages/ump-spec/src/ump_spec/models/estimand.py, line 163

class

class Horizon(_EstimandPart)

Time over which the effect is counted. {type: window, anchor: fit} is the model’s fit window: a template written before any fit (an adapter’s metadata) leaves weeks absent, and every quantity a fit produces states weeks (spec §5, “Fit-window horizon”). weeks is never null.

Fields

NameTypeDefaultDescription
typeHorizonType
weeksint | NoneNoneWeeks counted. Absent only on a fit-window template.
thresholdfloat | NoneNoneDecay threshold for total_to_decay.
anchorLiteral['fit'] | NoneNoneSpec §5: fit means the window is the model’s fit window. Absent means the window counts from the start of the intervention.

Source: packages/ump-spec/src/ump_spec/models/estimand.py, line 179

class

class Unit(_EstimandPart)

per is spend, impression or absolute. currency (ISO 4217) is required with per: spend and allowed with per: absolute (a money KPI); there its absence means the KPI is not money. Build a spend unit with spend_unit(currency).

Fields

NameTypeDefaultDescription
kpistr
perPer | NoneNoneDenominator: spend, impression or absolute (spec §5).
cost_basisCostBasis | NoneNone
currencystr | NoneNoneISO 4217 alpha-3; required with per: spend.

Source: packages/ump-spec/src/ump_spec/models/estimand.py, line 195

class

class PointRuleSpec(_EstimandPart)

{rule, scale} form of point_rule (spec §5): scale is identity or log.

Fields

NameTypeDefaultDescription
rulePointRule
scalePointScale

Source: packages/ump-spec/src/ump_spec/models/estimand.py, line 221

class

class IntervalSpec(_EstimandPart)

Fields

NameTypeDefaultDescription
methodIntervalMethod
levelfloat

Source: packages/ump-spec/src/ump_spec/models/estimand.py, line 230

class

class Period(_EstimandPart)

Calendar dates, half-open [start, end) (spec §4).

Fields

NameTypeDefaultDescription
startdate | NoneNone
enddate | NoneNone

Source: packages/ump-spec/src/ump_spec/models/estimand.py, line 237

class

class AppliesTo(_EstimandPart)

Scope beside the estimand: compared by G-EST-02 like the seven fields.

Fields

NameTypeDefaultDescription
media_idslist[str]list()
geo_idslist[str]list()
kpistr | NoneNone
periodPeriod | NoneNone
time_idstr | NoneNoneSpec §4 time registry entry ID.
client_idstr | NoneNone

Source: packages/ump-spec/src/ump_spec/models/estimand.py, line 246

class

class Estimand(_EstimandPart)

The seven fields plus applies_to and the registered optional members. None (written "undeclared") means undeclared.

Fields

NameTypeDefaultDescription
interventionIntervention | NoneNone
baselineBaselineKind | NoneNone
baseline_xfloat | NoneNonex of reduced_spend(x): spend at x times the current plan. Required with baseline reduced_spend; ignored otherwise (spec §5).
horizonHorizon | NoneNone
unitUnit | NoneNone
point_rulePointRule | PointRuleSpec | NoneNone
intervalIntervalSpec | NoneNone
schema_versionstr | NoneNone
applies_toAppliesToAppliesTo()
registry_idstr | NoneNoneRegistered estimand id, e.g. E-BM-AVG-ROI.
metric_familystr | NoneNonesales_return, brand_awareness, …
field_statusdict[str, FieldStatus]dict()
Methods and properties (3)

missing_fields method

def missing_fields(self) -> list[str]

Undeclared fields, then undeclared required sub-fields as dotted paths (unit.currency, unit.per, intervention.size_kind, baseline.baseline_x), in spec order.

assumed_fields method

def assumed_fields(self) -> list[str]

is_complete method

def is_complete(self) -> bool

Source: packages/ump-spec/src/ump_spec/models/estimand.py, line 287

function

def omit_when_none(value: Any) -> bool

exclude_if hook for members added after a shape was first published: an unset member is left out of every dump, so existing outputs and content hashes stay byte-identical.

Source: packages/ump-spec/src/ump_spec/models/estimand.py, line 75

function

def spend_unit(
currency: str,
kpi: str | None = None,
*,
cost_basis: CostBasis | None = None,
) -> dict[str, Any]

Members of a per-spend unit (spec §5): {"per": "spend", "currency": "USD", ...}. currency is an ISO 4217 code; lower case is upper-cased. Splat it into a unit dict or Unit(**...).

Source: packages/ump-spec/src/ump_spec/models/estimand.py, line 366

function

def normalise_legacy_unit(unit: dict[str, Any]) -> dict[str, Any]

Read compatibility for one cycle: per: "<ccy>_spend" becomes per: spend plus currency: "CCY", and null members are dropped. Other values pass through unchanged (a per-thousand unit such as usd_k_spend is rescaled by its adapter, never here).

Source: packages/ump-spec/src/ump_spec/models/estimand.py, line 381

function

def normalise_legacy_estimand(raw: dict[str, Any]) -> dict[str, Any]

Read a stored estimand written before the spec §5 wire rules (fixtures, old docs; never a writer).

It applies the defaults the old contract filled in (schema_version est-registry/1.2.0, size_kind: relative, per: usd_spend with currency: USD), rewrites <ccy>_spend, turns weeks: null into the fit-window anchor and drops every other null.

Source: packages/ump-spec/src/ump_spec/models/estimand.py, line 393

function

def without_unset(members: Any) -> Any

A producer’s own estimand dict with every None member dropped, at any depth, so optional state that is not known (no client id, no period) is left out instead of written as null. Use it only on dicts the producer builds; received input is validated as sent, where null is refused.

Source: packages/ump-spec/src/ump_spec/models/estimand.py, line 442

NameTypeValueDescription
ESTIMAND_FIELDStuple[str, ...]('intervention', 'baseline', 'horizon', 'unit', 'point_rule', 'interval', 'sc...The seven estimand fields, in spec order.
UNDECLARED'undeclared'The wire word for a field the source did not declare (spec §5).
InterventionTypeLiteral['remove_all', 'scale', 'add', 'marginal']
PopulationLiteral['itt', 'exposed', 'geo_set']
BaselineKindLiteral['zero_spend', 'current_plan', 'reduced_spend', 'control_counterfactual']
HorizonTypeLiteral['immediate', 'window', 'total_to_decay', 'total']
PointRuleLiteral['posterior_mean', 'posterior_median', 'map', 'estimator_point']
PointScaleLiteral['identity', 'log']
IntervalMethodLiteral['hdi', 'eti', 'confidence', 'bootstrap_pct', 'placebo', 'envelope', '...
CostBasisLiteral['net', 'gross']
FieldStatusLiteral['declared', 'undeclared', 'assumed']
PerLiteral['spend', 'impression', 'absolute']
SizeKindLiteral['absolute', 'relative']
PER_VALUEStuple[str, ...]('spend', 'impression', 'absolute')unit.per values (spec §5).
CURRENCY_RE'^[A-Z]{3}$'ISO 4217 alpha-3 code (spec §5 unit.currency).