Overview and Workflow

Use the scenario planner when you want to compare whole plans rather than run a single low-level optimisation call.

The planner combines three things:

  • typed scenario specifications
  • a Python comparison service
  • a supported workspace app for fitted results directories

If you need the low-level optimiser instead, see Budget Optimisation.

For the supported beta entry points and current limits, see Supported Surface.

What the planner compares

The retained planner supports three scenario types:

Scenario type Purpose Public spec
Current Use observed history as a reference plan CurrentScenarioSpec
Manual allocation Simulate a user-defined future plan ManualAllocationScenarioSpec
Fixed-budget optimised Optimise a future plan at a fixed budget FixedBudgetOptimizedScenarioSpec

Planner units versus optimiser units

The most important distinction is budget units.

Surface Public budget contract
PanelBudgetOptimizerWrapper Per-period spend
ScenarioPlanner Total spend over the whole scenario horizon

For example, if a four-period scenario has a total budget of 900_000, the planner converts that to per-period units internally before it calls the wrapper or response sampler.

Requested and evaluated windows

Each scenario has a requested window from start_date to end_date.

For simulated scenarios, the evaluated window can be longer than the requested window when you set include_carryover=True. Abacus extends the synthetic future path so lagged adstock effects can continue after the requested end date.

The planner reports both windows in the metadata output.

Historical overlap for current scenarios

CurrentScenarioSpec is strict about history.

Its requested window must overlap observed data. Abacus does not reinterpret a future-only window as “use the latest history instead”.

Typical workflow

The common workflow is:

  1. Fit PanelMMM.
  2. Build one or more scenario specs.
  3. Either run ScenarioPlanner.compare(...) or launch the workspace app from the fitted run directory.
  4. Inspect the comparison tables, save workspaces, and export the planning outputs you need.

Minimal example

from abacus.scenario_planner import (
    CurrentScenarioSpec,
    ManualAllocationScenarioSpec,
    ScenarioPlanner,
)

planner = ScenarioPlanner(mmm)

comparison = planner.compare(
    [
        CurrentScenarioSpec(
            name="Current baseline",
            start_date="2025-01-06",
            end_date="2025-02-24",
        ),
        ManualAllocationScenarioSpec(
            name="Manual plan",
            start_date="2025-03-03",
            end_date="2025-03-24",
            noise_level=0.0,
            include_carryover=False,
            allocation={
                "channel_1": 420_000.0,
                "channel_2": 280_000.0,
                "channel_3": 200_000.0,
            },
        ),
    ]
)

For the full API, see Python API.

How the planner differs from post-model summaries

The scenario planner does not reuse mmm.summary tables directly. Instead, it builds comparison tables that are specific to planning:

  • totals
  • channels
  • contributions_over_time
  • allocations
  • metadata

See Comparison Outputs.

Common pitfalls

  • Mixing up total horizon spend and per-period spend
  • Using a future-only window in CurrentScenarioSpec
  • Forgetting that carryover can extend the evaluated window