pytyche.generators.scenarios

V2 stress scenario catalog for BCF development.

Public API

Template-based API:

  • TEMPLATES: dict[str, Callable] — registered scenario templates. Keys: "constant", "reversal", "sparse_benefit", "nonlinear", "monotone_gradient", "interaction_only", "clustered". Each template callable has signature (metric_id, effect_scale, ...) -> (V2GeneratorConfig, dict).

  • build_catalog(...) returns list[ScenarioSpec] — a star-sweep catalog of (scenario_fn, kwargs) tuples for run_suite_parallel.

  • PROFILES: dict[str, dict] — preset catalog configurations. Keys: "validate", "standard", "thorough".

Design

  • Template callables accept seed and other knobs as kwargs so that (template_fn, kwargs) pairs are fully reproducible.

  • Metadata dicts carry at minimum "scenario_class" plus all control-knob keys so downstream benchmarking loops can group, filter, and compare runs.

  • Configs are ready to pass directly to generate_v2_core().

  • No imports from v1 generator internals.

Module Attributes

TEMPLATES

Registered scenario templates.

ScenarioSpec

Tuple of (scenario_fn, kwargs).

Functions

build_catalog(*[, templates, metric_ids, ...])

Build a star-sweep catalog of (scenario_fn, kwargs) tuples.

Classes

ClusterEffectProfile([conversion_delta, ...])

Treatment effect + prognostic specification for one cluster.

DriverInfo(name, kind[, mean, std, levels])

Resolved driver feature statistics from a sampler config.

SignalTerm(signal_type, drivers, amplitude)

One additive term in a within-cluster CATE surface.

class pytyche.generators.scenarios.DriverInfo(name, kind, mean=0.0, std=1.0, levels=None)[source]

Bases: object

Resolved driver feature statistics from a sampler config.

Two kinds: "continuous" or "categorical". Binary features (FeatureSpec kind=”binary”) map to categorical with levels=(True, False) or (False, True) depending on frequency.

name

Feature column name.

kind

"continuous" or "categorical" — no separate binary kind.

mean

Population-weighted mean (continuous only, 0.0 for categorical).

std

Population marginal std (continuous only, 1.0 for categorical).

levels

Actual level values sorted by (-prob, str(level)) for deterministic tie-breaking. None for continuous.

Parameters:
  • name (str)

  • kind (str)

  • mean (float)

  • std (float)

  • levels (tuple[Any, ...] | None)

class pytyche.generators.scenarios.SignalTerm(signal_type, drivers, amplitude, level_values=None)[source]

Bases: object

One additive term in a within-cluster CATE surface.

signal_type

One of "linear", "interaction", "quadratic", "step".

drivers

Feature name(s) for this term. Count is type-dependent.

amplitude

Signed weight for this term.

level_values

Per-level signal values for "step" type; None for others.

Parameters:
  • signal_type (str)

  • drivers (tuple[str, ...])

  • amplitude (float)

  • level_values (dict[str, float] | None)

class pytyche.generators.scenarios.ClusterEffectProfile(conversion_delta=0.0, severity_delta=0.0, conversion_signals=(), severity_signals=(), prognostic_conv_base=0.0, prognostic_sev_base=0.0, prognostic_conv_signals=(), prognostic_sev_signals=())[source]

Bases: object

Treatment effect + prognostic specification for one cluster.

The latent cluster type drives both prognostic outcomes (p0, m0) and treatment response (p1-p0, m1-m0). Observed features are noisy windows into the latent type — BCF only sees features, not cluster_id.

conversion_delta

Relative lift for conversion probability (e.g. +0.15 = +15%).

severity_delta

Relative lift for severity mean (e.g. -0.10 = -10%).

conversion_signals

Additive within-cluster signal terms for conversion HTE.

severity_signals

Additive within-cluster signal terms for severity HTE.

prognostic_conv_base

Logit-space shift from global baseline_rate for this cluster’s p0. Centered across clusters so weighted mean = 0.

prognostic_sev_base

Log-space shift from global m0_base for this cluster’s m0. Centered across clusters so weighted mean = 0.

prognostic_conv_signals

Within-cluster feature-driven p0 gradients.

prognostic_sev_signals

Within-cluster feature-driven m0 gradients.

Parameters:
  • conversion_delta (float)

  • severity_delta (float)

  • conversion_signals (tuple[SignalTerm, ...])

  • severity_signals (tuple[SignalTerm, ...])

  • prognostic_conv_base (float)

  • prognostic_sev_base (float)

  • prognostic_conv_signals (tuple[SignalTerm, ...])

  • prognostic_sev_signals (tuple[SignalTerm, ...])

pytyche.generators.scenarios.TEMPLATES: dict[str, Callable[[...], tuple[V2GeneratorConfig, dict]]] = {'clustered': <function _template_clustered>, 'clustered_complex': <function _template_clustered_complex>, 'clustered_realistic': <function _template_clustered_realistic>, 'constant': <function _template_constant>, 'interaction_only': <function _template_interaction_only>, 'monotone_gradient': <function _template_monotone_gradient>, 'nonlinear': <function _template_nonlinear>, 'reversal': <function _template_reversal>, 'sparse_benefit': <function _template_sparse_benefit>}

Registered scenario templates. Keys are template names; values are callables accepting (metric_id: str, effect_scale: float, **kwargs) and returning (V2GeneratorConfig, dict).

pytyche.generators.scenarios.ScenarioSpec

Tuple of (scenario_fn, kwargs). Each pair can be invoked as scenario_fn(seed=seed, **kwargs) to produce a (V2GeneratorConfig, dict) result. The kwargs dict MUST NOT include seed — seed is injected by run_suite_parallel.

alias of tuple[Callable[[…], tuple[V2GeneratorConfig, dict]], dict[str, Any]]

pytyche.generators.scenarios.build_catalog(*, templates=None, metric_ids=None, effect_scale_grid, severity_sigma_grid=None, n_nuisance_grid=None, n_visitors_grid=None, treatment_allocation_grid=None, benefit_prevalence_grid=None, baseline_rate_grid=None, revenue_model_grid=None, channel_mode_grid=None, default_effect_scale=1.0, default_n_visitors=1000, default_severity_sigma=0.5, default_n_nuisance=5, default_treatment_allocation=0.5, default_benefit_prevalence=0.15, default_baseline_rate=0.05, categorical_driver=None)[source]

Build a star-sweep catalog of (scenario_fn, kwargs) tuples.

Parameters:
  • templates (list[str] | None) – Template names to include. Defaults to all 7.

  • metric_ids (list[str] | None) – Metric IDs to include. Defaults to both "conversion_rate" and "revenue_per_visitor".

  • effect_scale_grid (list[float]) – Required. Core grid dimension — all templates × metrics are crossed with every value in this list.

  • severity_sigma_grid (list[float] | None) – Optional marginal sweep grid for severity_sigma.

  • n_nuisance_grid (list[int] | None) – Optional marginal sweep grid for n_nuisance.

  • n_visitors_grid (list[int] | None) – Optional marginal sweep grid for n_visitors.

  • treatment_allocation_grid (list[float] | None) – Optional marginal sweep grid for treatment_allocation.

  • benefit_prevalence_grid (list[float] | None) – Optional marginal sweep grid for benefit_prevalence.

  • baseline_rate_grid (list[float] | None) – Optional marginal sweep grid for baseline_rate.

  • revenue_model_grid (list[Any] | None) – Optional marginal sweep grid for revenue-model variants.

  • channel_mode_grid (list[str] | None) – For hurdle metrics, crosses channel_mode into the core grid. Defaults to ["mirror"] for backward compatibility.

  • default_effect_scale (float) – effect_scale used for marginal sweeps (default 1.0).

  • default_n_visitors (int) – Default visitor count for non-swept dimensions.

  • default_severity_sigma (float) – Default severity sigma for non-swept dimensions.

  • default_n_nuisance (int) – Default nuisance-feature count for non-swept dimensions.

  • default_treatment_allocation (float) – Default treatment allocation for non-swept dimensions.

  • default_benefit_prevalence (float) – Default benefit prevalence for non-swept dimensions.

  • default_baseline_rate (float) – Default baseline rate for non-swept dimensions.

  • categorical_driver (str | None) – When provided, one additional reversal spec with this driver is appended per metric family (binary and hurdle) before the coverage gate is validated. Must be a categorical or binary feature from the default schema (e.g. "is_returning"). Named profiles set this to "is_returning" so they satisfy the coverage gate by construction.

Returns:

List of (scenario_fn, kwargs) tuples consumable by run_suite_parallel. The kwargs dicts do NOT include seed.

Return type:

list[tuple[Callable[..., tuple[V2GeneratorConfig, dict]], dict[str, Any]]]

Raises:

ValueError – If the assembled spec list does not include at least one continuous-driver and one categorical-driver (binary counts as categorical) scenario per metric family.