Policies

class sim_panel.policies.base.PolicyConfig(name, evals_per_period=1, random_mode='balanced_quota', product_probs=None, choice_set_size=None, allow_empty_selection=True, manual_assignment_fn=None)[source]

Bases: object

YAML-governed policy config.

Note

  • policies are PURE exposure logic (no LLM calls, no IO, no schema row creation)

  • generator owns orchestration, validation, and execution budgets

Parameters:
  • name (Literal['random', 'manual', 'self_selection'])

  • evals_per_period (int)

  • random_mode (Literal['balanced_quota', 'iid_probs'])

  • product_probs (Dict[str, float] | None)

  • choice_set_size (int | None)

  • allow_empty_selection (bool)

  • manual_assignment_fn (ManualAssignmentFn | None)

name: Literal['random', 'manual', 'self_selection']
evals_per_period: int = 1
random_mode: Literal['balanced_quota', 'iid_probs'] = 'balanced_quota'
product_probs: Dict[str, float] | None = None
choice_set_size: int | None = None
allow_empty_selection: bool = True
manual_assignment_fn: ManualAssignmentFn | None = None
class sim_panel.policies.base.Policy(cfg)[source]

Bases: object

Pure exposure logic: decides what the panelist is exposed to.

  • random/manual -> list of product_ids to evaluate

  • self_selection -> choice_set of product_ids shown

Parameters:

cfg (PolicyConfig)

property name: Literal['random', 'manual', 'self_selection']
decide(*, rng, panelist_id, t, product_ids)[source]
Return type:

ExposureDecision

Parameters:
  • rng (Generator)

  • panelist_id (str)

  • t (int)

  • product_ids (Sequence[str])

class sim_panel.policies.types.SelectionSpec(choice_set, allow_empty=True)[source]

Bases: object

Self-selection exposure spec.

Policy controls what is SHOWN (choice_set). Panelist returns what they WANT (requested_product_ids) later. Generator may apply operational rules (budget caps, filtering) later.

Parameters:
  • choice_set (List[str])

  • allow_empty (bool)

choice_set: List[str]
allow_empty: bool = True
class sim_panel.policies.types.ExposureDecision(panelist_id, t, policy, evaluate_product_ids=None, selection=None, meta=None)[source]

Bases: object

Policy decision for one (panelist_id, t).

Exactly one of the following fields should be populated:

  • evaluate_product_ids for random/manual exposure.

  • selection for self-selection exposure.

Parameters:
  • panelist_id (str)

  • t (int)

  • policy (Literal['random', 'manual', 'self_selection'])

  • evaluate_product_ids (List[str] | None)

  • selection (SelectionSpec | None)

  • meta (Dict[str, Any] | None)

panelist_id: str
t: int
policy: Literal['random', 'manual', 'self_selection']
evaluate_product_ids: List[str] | None = None
selection: SelectionSpec | None = None
meta: Dict[str, Any] | None = None
class sim_panel.policies.types.ManualAssignmentFn(*args, **kwargs)[source]

Bases: Protocol

Manual assignment hook. Expected to be deterministic conditional on inputs.

Returns either a single product_id or a list of product_ids to evaluate.

class sim_panel.policies.random.RandomAssignmentPolicy(cfg)[source]

Bases: Policy

Randomized exposure, with RCT-like balanced allocation by default.

Modes:
  • balanced_quota: equal/near-equal panelist counts per product (per period)

  • iid_probs: per-panelist independent draws using a product probability distribution

prepare_for_period(*, rng, product_ids)[source]

Optional hook: generator may call this once per run (or per period) to prime schedulers. (Kept optional so Policy API stays minimal.)

Return type:

None

Parameters:
  • rng (Generator)

  • product_ids (Sequence[str])

decide_batch(*, rng, panelist_ids, t, product_ids)[source]

Batch decision method for balanced_quota (preferred) to guarantee balance.

Generator can call this for each t to get all decisions in one shot.

Return type:

List[ExposureDecision]

Parameters:
  • rng (Generator)

  • panelist_ids (Sequence[str])

  • t (int)

  • product_ids (Sequence[str])

decide(*, rng, panelist_id, t, product_ids)[source]
Return type:

ExposureDecision

Parameters:
  • rng (Generator)

  • panelist_id (str)

  • t (int)

  • product_ids (Sequence[str])

class sim_panel.policies.manual.ManualAssignmentPolicy(cfg)[source]

Bases: Policy

Manual exposure from a user-provided mapping function. Loader/wiring from file happens elsewhere; policy stays pure.

The function takes (panelist_id, t, product_ids) and returns:
  • product_id (str), or

  • list[str]

Parameters:

cfg (PolicyConfig)

decide(*, rng, panelist_id, t, product_ids)[source]
Return type:

ExposureDecision

Parameters:
  • rng (Generator)

  • panelist_id (str)

  • t (int)

  • product_ids (Sequence[str])

class sim_panel.policies.self_selection.SelfSelectionPolicy(cfg)[source]

Bases: Policy

Self-selection exposure.

Default behavior (choice_set_size is None):
  • show ALL products

If choice_set_size is provided:
  • show a shortlist sampled uniformly without replacement

Parameters:

cfg (PolicyConfig)

decide(*, rng, panelist_id, t, product_ids)[source]
Return type:

ExposureDecision

Parameters:
  • rng (Generator)

  • panelist_id (str)

  • t (int)

  • product_ids (Sequence[str])

sim_panel.policies.registry.build_policy(cfg)[source]
Return type:

Policy

Parameters:

cfg (PolicyConfig)