ump_spec.rules.governance
module ump-spec
Materiality (G-MAT-01), maturity score and stages (§25.5), Benjamini-Hochberg (§10), conflict z (EMA §6.6), evidence ageing / use-by (§9, EMA §7).
Classes
Section titled “Classes”MaterialityResult
Section titled “MaterialityResult”class
class MaterialityResultFields
| Name | Type | Default | Description |
|---|---|---|---|
tier | str | ||
reasons | list[str] | ||
thresholds_proposed | bool | True | |
thresholds | dict[str, float] | field(default_factory=dict) |
Methods and properties (1)
init constructor
MaterialityResult( self, tier: str, reasons: list[str], thresholds_proposed: bool = True, thresholds: dict[str, float] = dict(),) -> NoneSource: packages/ump-spec/src/ump_spec/rules/governance.py, line 20
MaturityResult
Section titled “MaturityResult”class
class MaturityResultFields
| Name | Type | Default | Description |
|---|---|---|---|
score | float | ||
components | dict[str, float] | ||
stage | str | ||
stage_name | str | ||
flags | dict[str, bool] | ||
weights_proposed | bool | True |
Methods and properties (1)
init constructor
MaturityResult( self, score: float, components: dict[str, float], stage: str, stage_name: str, flags: dict[str, bool], weights_proposed: bool = True,) -> NoneSource: packages/ump-spec/src/ump_spec/rules/governance.py, line 81
CloseRerunResult
Section titled “CloseRerunResult”class
class CloseRerunResultSpec §13 close-rerun verdict. procedure is abs_z for one quantity, holm for more.
Fields
| Name | Type | Default | Description |
|---|---|---|---|
close | bool | ||
procedure | Literal['abs_z', 'holm'] | ||
z | list[float] | ||
p | list[float] | ||
rejected | list[bool] | ||
z_max | float | ||
alpha | float | ||
kpi_close | bool | None | None |
Methods and properties (1)
init constructor
CloseRerunResult( self, close: bool, procedure: Literal['abs_z', 'holm'], z: list[float], p: list[float], rejected: list[bool], z_max: float, alpha: float, kpi_close: bool | None = None,) -> NoneSource: packages/ump-spec/src/ump_spec/rules/governance.py, line 228
Functions
Section titled “Functions”materiality_tier
Section titled “materiality_tier”function
def materiality_tier( inputs: MaterialityInputs | dict[str, Any], thresholds: MaterialityThresholds | None = None,) -> MaterialityResultG-MAT-01 (computed). Thresholds are per account and proposed.
full if spend >= full threshold, or not reversible within a quarter, or a public claim, or EVOI > 10x the cost of a full review; standard if spend >= standard threshold or the decision feeds a client recommendation; else light. A decision below the standard threshold that takes more than a month to reverse is lifted to standard (light requires reversible within a month).
Source: packages/ump-spec/src/ump_spec/rules/governance.py, line 28
maturity_score
Section titled “maturity_score”function
def maturity_score( *, refit_age_days: float | None, tests_last_4q: int, share_channels_calibrated: float, share_spend_with_test_or_cal: float,) -> tuple[float, dict[str, float]]0..100 = 25 x freshness (1 if refit <= 90d, 0.5 if <= 180d, 0.2 if older, 0 if no model)
- 25 x min(tests/4, 1) + 30 x share of channels calibrated + 20 x causal share of spend.
Source: packages/ump-spec/src/ump_spec/rules/governance.py, line 91
maturity_stage
Section titled “maturity_stage”function
def maturity_stage(flags: dict[str, bool]) -> strStages are independent flags; the headline stage is the furthest one reached.
Source: packages/ump-spec/src/ump_spec/rules/governance.py, line 118
assess_maturity
Section titled “assess_maturity”function
def assess_maturity( *, foundations: bool, refit_age_days: float | None, quarters_with_test_last_4: int, tests_last_4q: int, share_channels_calibrated: float, share_spend_with_test_or_cal: float, reallocated_with_decision: bool,) -> MaturityResultSource: packages/ump-spec/src/ump_spec/rules/governance.py, line 124
benjamini_hochberg
Section titled “benjamini_hochberg”function
def benjamini_hochberg(pvalues: list[float], q: float = BH_Q_DEFAULT) -> list[bool]Return a reject/flag decision per p-value (same order) controlling FDR at q.
Source: packages/ump-spec/src/ump_spec/rules/governance.py, line 162
benjamini_yekutieli
Section titled “benjamini_yekutieli”function
def benjamini_yekutieli(pvalues: list[float], q: float = BH_Q_DEFAULT) -> list[bool]Benjamini-Yekutieli step-up (FDR under arbitrary dependence): BH at q / c(m), with
c(m) = 1 + 1/2 + … + 1/m. Spec §10 lets a calibration declare it when tests share geos or weeks.
Source: packages/ump-spec/src/ump_spec/rules/governance.py, line 179
function
def holm(pvalues: list[float], alpha: float = 0.05) -> list[bool]Holm step-down (family-wise error at alpha): reject the i-th smallest p while
p <= alpha / (m - i + 1); stop at the first that fails. Same order as the input.
Source: packages/ump-spec/src/ump_spec/rules/governance.py, line 189
threshold_set
Section titled “threshold_set”function
def threshold_set() -> dict[str, Any]The threshold set registry: {version, thresholds: {group: {name: {value, proposed, status, spec_ref}}}}` (`registries/threshold_set.yaml; every value proposed).
Source: packages/ump-spec/src/ump_spec/rules/governance.py, line 206
threshold_set_version
Section titled “threshold_set_version”function
def threshold_set_version() -> strVersion string to record as threshold_set_version (spec §14).
Source: packages/ump-spec/src/ump_spec/rules/governance.py, line 215
threshold_value
Section titled “threshold_value”function
def threshold_value(group: str, name: str) -> AnyOne threshold’s value; raises KeyError for an unknown group or name.
Source: packages/ump-spec/src/ump_spec/rules/governance.py, line 220
close_rerun
Section titled “close_rerun”function
def close_rerun( theta_1: Sequence[float], theta_2: Sequence[float], mcse_1: Sequence[float], mcse_2: Sequence[float], *, kpi_difference: float | None = None, materiality_threshold: float | None = None, z_max: float | None = None, alpha: float | None = None,) -> CloseRerunResultSpec §13: z = |theta_1 - theta_2| / sqrt(MCSE_1^2 + MCSE_2^2) per compared quantity, with MCSE
from Vehtari et al. (2021), method mean (the caller supplies it). One quantity: close when
z <= 2. Two or more: two-sided normal p-values through Holm at alpha 0.05; close unless Holm
rejects. With kpi_difference and materiality_threshold the recommended allocation’s
expected KPI must also differ by less than 1% of the threshold. Defaults come from the threshold
set (all proposed).
Source: packages/ump-spec/src/ump_spec/rules/governance.py, line 242
conflict_z
Section titled “conflict_z”function
def conflict_z( tau_hat: float, se_exp: float, mu0: float, sigma0: float,) -> tuple[float, float]EMA §6.6: z = |tau_hat - mu0| / sqrt(sigma0^2 + se_exp^2); returns (z, two-sided p).
Source: packages/ump-spec/src/ump_spec/rules/governance.py, line 289
precision_weighted_update
Section titled “precision_weighted_update”function
def precision_weighted_update( mu0: float, sigma0: float, y: float, sigma_e: float,) -> tuple[float, float]EMA Eq. 2 (G-CAL-05 fallback): posterior mean and sd of a normal-normal update.
Source: packages/ump-spec/src/ump_spec/rules/governance.py, line 296
variance_inflation
Section titled “variance_inflation”function
def variance_inflation(age_weeks: float, half_life_weeks: float) -> floatsigma_eff^2 / sigma_post^2 = exp(lambda t), lambda = ln 2 / h.
Source: packages/ump-spec/src/ump_spec/rules/governance.py, line 312
use_by_date
Section titled “use_by_date”function
def use_by_date( measured: date, half_life_weeks: float, k: float = USE_BY_K_DEFAULT,) -> dateDate at which variance inflation reaches k (t = h log2 k).
Source: packages/ump-spec/src/ump_spec/rules/governance.py, line 317
carryover_floor_weeks
Section titled “carryover_floor_weeks”function
def carryover_floor_weeks(alpha: float, threshold: float = 0.05) -> intEMA Eq. 17: k_min = ceil(ln(threshold)/ln(alpha)), clamped to [1, 26].
Source: packages/ump-spec/src/ump_spec/rules/governance.py, line 323
Constants
Section titled “Constants”| Name | Type | Value | Description |
|---|---|---|---|
MATURITY_WEIGHTS | dict[str, float] | {'fresh_model': 25, 'tests': 25, 'calibrated': 30, 'causal_share': 20} | §25.5 weights: placeholders for the measurement lead to set (treat as proposed). |
MATURITY_WEIGHTS_PROPOSED | True | ||
STAGE_NAMES | dict[str, str] | {'none': 'Not started', 'foundations': 'Foundations', 'model_live': 'Model li... | |
STAGE_ORDER | tuple[str, ...] | ('foundations', 'model_live', 'experimenting', 'calibrated', 'reallocating') | |
BH_Q_DEFAULT | 0.1 | §10 proposed. | |
USE_BY_K_DEFAULT | 2.0 | POC choice (proposed): use-by is when the effective variance reaches k x the posterior variance. | |
COLD_START_HALF_LIFE_WEEKS | dict[str, float] | {'digital': 39.0, 'broadcast': 91.0} | Cold-start ageing half-lives in weeks, chosen so use_by (k=2) lands at about 9 months for digital and 21 months for broadcast/OOH, the midpoints of the EMA defaults 6-12 and 18-24 months. |