Use this section when you want to compare historical, manual, and optimised
future plans with abacus.scenarios.
The scenario planner is a higher-level planning surface than the low-level
optimisation wrapper. It works in total horizon spend units, returns
versioned structured comparison tables, and supports Python and CLI workflows.
abacus.scenario_planner remains the legacy compatibility namespace for
existing statistical imports and advisory dashboard facades. The experimental
abacus-dashboard application is deprecated. Its retained guide documents
historical behaviour; use abacus.scenarios for current workflows.
Pages
Supported Surface: The recommended scenario entry
points, compatibility facades, fitted-run contract, persisted workspace
state, and estimator limits.
Overview and Workflow: What the planner does,
how it differs from low-level optimisation, and how scenario windows work.
Scenario Specifications: The public scenario
spec classes, versioned YAML recipes, allocation shapes, bounds, and budget
distributions.
Python API: How to use ScenarioPlanner.evaluate(...) and
run retained recipes from Python, plus the compatibility workspace helpers.
Comparison Outputs: The structure and meaning of
ScenarioResult, ScenarioComparison, retained artefacts, and the dashboard
payload contract.
Historical reference
Deprecated Dash App: Retained documentation for the
experimental dashboard. It is not a recommended scenario workflow.
Subsections of Scenario Planning
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 typed scenario specifications, a Python comparison
service, and a CLI for retained YAML recipes. Use abacus.scenarios for
scenario workflows. The experimental abacus-dashboard application is
deprecated; its legacy import facades remain in this checkout.
For supported entry points and estimator 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
abacus.scenarios.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:
Fit PanelMMM.
Build one or more scenario specs.
Run abacus.scenarios.ScenarioPlanner.compare(...), or evaluate a YAML
recipe against a fitted run with python -m abacus.scenarios.
Inspect the comparison tables, save workspaces, and export the planning
outputs you need.
Mixing up total horizon spend and per-period spend
Using a future-only window in CurrentScenarioSpec
Forgetting that carryover can extend the evaluated window
Scenario Specifications
This page documents the public spec classes under abacus.scenarios.
abacus.scenario_planner still re-exports these classes for compatibility
with existing imports, but new code should use abacus.scenarios.
Most users create one of the three concrete scenario specs:
CurrentScenarioSpec
ManualAllocationScenarioSpec
FixedBudgetOptimizedScenarioSpec
Abacus also exposes shared base models such as
HistoricalReferenceScenarioSpec and SimulatedScenarioSpec, but you do not
normally instantiate those directly.
The named FE and CRE presets support historical and manual scenarios for the
complete set of fitted units; CRE also retains its frozen fitted summaries.
They do not support FixedBudgetOptimizedScenarioSpec. The RE preset remains
release-gated. Check the
estimator support matrix
before choosing a scenario type.
Shared fields
All public scenario specs inherit these core fields:
Field
Meaning
name
Display name for the scenario
start_date
Requested scenario start date
end_date
Requested scenario end date
scenario_id
Stable scenario key used in outputs
If you do not set scenario_id, Abacus derives one by slugifying name.
Scenario IDs must be unique within one ScenarioPlanner.compare(...) call.
CurrentScenarioSpec
Use CurrentScenarioSpec for a historical reference plan.
Abacus materialises DataArraySpec as an xarray.DataArray before it
validates dims and coordinates.
Versioned scenario recipes
Use ScenarioRecipe to retain several scenario specifications as one
versioned request. The recipe contract rejects unknown versions, empty
scenario lists, duplicate scenario IDs, and unknown top-level fields.
Abacus writes a new immutable evidence directory under
<fitted-run>/scenario_planner/recipes/. It does not refit the model or alter
the fitted run manifest.
Common pitfalls
Reusing the same scenario_id twice in one comparison
Using dict allocations or dict bounds for panel budgets
Passing an allocation or bounds object with missing coordinates
Providing a budget_distribution_over_period that does not sum to 1
Reusing an existing recipe output directory; retained evidence is never
overwritten
Python API
Use ScenarioPlanner when you want to evaluate one scenario or compare
multiple scenarios from Python.
The preferred public API lives under abacus.scenarios.
abacus.scenario_planner remains available for existing statistical
compatibility imports, but new statistical scenario code should use
abacus.scenarios. The experimental abacus-dashboard application is
deprecated; dashboard helpers below are historical reference only.
For the recommended entry points and current scope, see
Supported Surface.
Prerequisite
ScenarioPlanner requires a fitted PanelMMM with idata.
If you construct the planner before fitting, Abacus raises ValueError.
The named FE and CRE presets support historical and manual scenarios for the
complete set of fitted units; CRE also retains its frozen fitted summaries.
They do not support FixedBudgetOptimizedScenarioSpec. The RE preset remains
release-gated. Check the
estimator support matrix
before choosing a scenario type.
These helpers belong to the deprecated experimental dashboard. This section
records the former abacus_dashboard.app interface for existing integrations;
it is not a recommended workflow for new code.
Helper
What it returns
Use it when
load_workspace_bundle(...)
run_context, workspace_service, workspace
you want the fitted run context and active workspace without starting Dash
create_app_from_results_dir(...)
app, run_context, workspace_service, workspace
you want to launch or embed the dashboard app from Python
These helpers expect a fitted results directory with run_manifest.json and a
fit-stage idata artefact.
When available, the loader rebuilds the model from in-run metadata config
artifacts in this order:
00_run_metadata/config.resolved.yaml
00_run_metadata/config.original.yaml
the copied config file under 00_run_metadata/
run_manifest.json["config_path"] as fallback
The returned run_context records both config_path and
config_provenance_type so callers can tell which source was used.
Residual portability risk remains if the chosen config still points to dataset
files outside the saved run directory.
Legacy imports from abacus.scenario_planner still resolve for compatibility
and emit advisory DeprecationWarnings. No legacy dashboard app-layer facade
will be removed before Abacus 4.0.
Evaluate one scenario
Use evaluate(...) when you want one scenario result:
Unlike ScenarioResult, the combined object uses the plural
allocations.
Run a versioned recipe
Use ScenarioRecipe for an in-memory Python request. Use
load_scenario_recipe(...) for YAML and run_scenario_recipe(...) when the
model has already been retained by the pipeline.
The default output path is a new timestamped directory under
scenario_planner/recipes/ in the fitted run. Pass output_dir= only when you
need another new location. Abacus rejects an existing target directory so a
later evaluation cannot silently replace retained evidence.
Use evaluate_scenario_recipe(...) when you already have the fitted model in
memory:
This example creates the default workspace if it is absent. Use
load_workspace(...) instead when you require a specific existing workspace
ID.
WorkspaceService defaults to synchronous jobs when you instantiate it
directly. The dashboard app uses ThreadedScenarioPlannerJobRunner through
the dashboard compatibility layer.
Prepare data for a client UI
Use to_store_payload() when you want a JSON-friendly version of the
comparison tables:
payload=comparison.to_store_payload()
This method converts datetime columns to YYYY-MM-DD strings and returns a
dict with a scalar contract_version plus record lists for the comparison
tables. Compare contract_version with SCENARIO_CONTRACT_VERSION before a
dashboard or external client assumes a payload shape.
Background-job helpers
For custom integrations, WorkspaceService also exposes queue/apply methods:
submit_draft_evaluation(...)
apply_draft_evaluation_job(...)
submit_sensitivity_sweep(...)
apply_sensitivity_sweep_job(...)
Use these only when you need the same background-job pattern as the current
dashboard beta. For most scripted flows, the blocking methods are simpler.
Relationship to the low-level wrapper
ScenarioPlanner uses PanelBudgetOptimizerWrapper internally for simulated
scenarios, but its public contract is different:
you pass total horizon budgets and allocations
the planner converts them to per-period units internally
the planner returns comparison tables rather than raw optimiser objects
If you want direct access to optimize_budget(...) or
sample_response_distribution(...), use
Budget Optimisation instead.
Common pitfalls
Passing per-period spend into ManualAllocationScenarioSpec or
FixedBudgetOptimizedScenarioSpec
Expecting duplicate scenario_id values to be allowed in compare(...)
Forgetting that result.allocation and comparison.allocations use
different attribute names
Comparison Outputs
ScenarioPlanner returns structured planning tables rather than a single
optimiser object.
This page explains the output objects and the meaning of each table.
Import these objects from abacus.scenarios for new statistical scenario
code. abacus.scenario_planner remains a compatibility namespace for existing
statistical imports and legacy dashboard app-layer paths.
ScenarioComparison is a row-wise concatenation of the individual scenario
results, with scenario identifiers added to every table.
totals
totals has one row per scenario.
It includes:
scenario_id
scenario_name
scenario_type
total_spend
contribution_mean
contribution_median
contribution_hdi_94_lower
contribution_hdi_94_upper
efficiency_metric
efficiency_mean
efficiency_median
efficiency_hdi_94_lower
efficiency_hdi_94_upper
efficiency_metric is ROAS for revenue targets and CPA for conversion
targets.
channels
channels has one row per (scenario, channel).
It includes:
scenario identifiers
channel
spend
spend_share
spend_per_period
contribution summary columns
contribution-per-period columns
efficiency summary columns
efficiency_metric
The planner aggregates non-channel panel dims before it builds this table. For
example, a (geo, channel) model still returns one row per channel here.
contributions_over_time
contributions_over_time has one row per (scenario, date, channel).
It includes:
scenario identifiers
date
channel
contribution_mean
contribution_median
contribution_hdi_94_lower
contribution_hdi_94_upper
Like channels, this table aggregates non-channel panel dims before
summarising.
allocations
allocations keeps the original allocation grain.
It includes:
scenario identifiers
the allocation dims, such as channel, geo, or brand
allocation
realized_spend
For current scenarios, allocation is the summed historical spend over the
reference window. For simulated scenarios, allocation is the requested total
horizon allocation and realized_spend is the realised spend from the response
simulation.
metadata
metadata is the audit table for each scenario.
Shared fields include:
scenario_id
scenario_name
scenario_type
start_date
end_date
evaluated_start_date
evaluated_end_date
num_periods
target_type
efficiency_metric
Additional fields depend on scenario type.
Current scenario metadata
Current scenarios add:
reference_window_dates
Manual scenario metadata
Manual scenarios add:
requested_total_budget
total_budget
reference_window_dates
budget_unit
Fixed-budget optimised metadata
Optimised scenarios add:
requested_total_budget
total_budget
optimization_success
optimization_status
optimization_message
optimization_objective_value
reference_window_dates
budget_unit
Requested versus evaluated windows
The metadata table is the best place to check whether the evaluated window
matches the requested window.
When include_carryover=True, the evaluated end date can be later than the
requested end_date.
ScenarioComparison.to_store_payload() converts the comparison tables into a
JSON-friendly dict:
payload=comparison.to_store_payload()
The payload contains a scalar contract_version and record lists for
totals, channels, contributions_over_time, allocations, and
metadata. The current contract value is exported as
SCENARIO_CONTRACT_VERSION from abacus.scenarios, so downstream clients can
check whether they understand the result shape before rendering or importing
it.
The deprecated experimental abacus-dashboard application consumed this
payload format. The versioned contract remains available to machine consumers:
Abacus owns the statistical result shape; clients own rendering and interaction.
Retained recipe artefacts
run_scenario_recipe(...) and evaluate_scenario_recipe(...) persist the
comparison as an immutable bundle:
File
Purpose
scenario_recipe.resolved.yaml
versioned request after validation
scenario_validation.json
scenario IDs, estimator, fitted-unit scope, estimand, and pass state
estimator_manifest.yaml
fitted estimator contract copied with the scenario evidence
scenario_totals.csv
total spend, contribution, efficiency, and uncertainty by scenario
scenario_channels.csv
channel summaries and uncertainty
scenario_contributions_over_time.csv
date-channel contribution summaries and uncertainty
scenario_allocations.csv
requested allocation and realised spend at the original allocation grain
scenario_metadata.csv
scenario semantics, dates, history policy, scale, and estimand
scenario_payload.json
versioned five-table payload for machine consumers
scenario_artifact_manifest.json
source run ID, file sizes, and SHA-256 checksums
The target directory must not exist before evaluation. Abacus validates the
comparison before it creates the directory and never overwrites an earlier
bundle.
Common pitfalls
Reading channels as if it retained non-channel panel dims
Ignoring metadata when carryover is enabled
Comparing requested allocation with realised spend without checking the
allocations table
Supported Surface
Use abacus.scenarios for supported Python and CLI scenario workflows.
The experimental abacus-dashboard application is deprecated. It is not a
recommended entry point.
Legacy dashboard app-layer imports under abacus.scenario_planner remain as
advisory compatibility facades in this checkout. Their warnings identify
abacus_dashboard.* paths; those paths belong to the deprecated application.
Estimator prerequisites
The named FE and CRE presets support historical and manual scenarios for the
complete set of fitted units; CRE also retains its frozen fitted summaries.
They do not support FixedBudgetOptimizedScenarioSpec. The RE preset remains
release-gated. Check the
estimator support matrix
before choosing a scenario type.
Dashboard compatibility code does not add estimator support.
Recommended entry points
Use these entry points in preference order.
Entry point
Use it when you want to
Notes
abacus.scenarios.ScenarioPlanner
evaluate or compare scenarios from Python
Preferred statistical API for notebooks, scripts, and testable planning flows
python -m abacus.scenarios
evaluate a YAML recipe against a fitted run
Writes an immutable, checksummed evidence bundle under the fitted run
abacus.scenarios.run_scenario_recipe(...)
run the same retained recipe workflow from Python
Preferred scripted handoff when the fitted model is already saved
abacus.scenarios.WorkspaceService
work with saved workspaces programmatically
Library-facing surface for cloning, saving, evaluating, sweeping, and exporting
Advanced integration surfaces
Abacus exposes lower-level statistical orchestration objects such as:
ThreadedScenarioPlannerJobRunner
SynchronousScenarioPlannerJobRunner
WorkspaceStore
These are public, but they are more implementation-shaped than the recommended
entry points above. Use them only when you need to override job-runner or
storage behaviour.
Results directory contract
The dashboard-specific sections below record the deprecated prototype,
including its former compatibility plans. They do not recommend launching it
or establish a future release commitment. The statistical recipe and workspace
APIs remain available through abacus.scenarios.
The dashboard launcher and load_workspace_bundle(...) expect a fitted run
directory, not raw modelling inputs.
The run directory must include:
Requirement
Why it matters
run_manifest.json
Abacus uses it to locate the config and saved artefacts
a fit-stage idata artefact
Abacus attaches the saved posterior to the rebuilt model
When metadata-stage config artefacts are present, Abacus prefers those
in-run files when rebuilding the saved PanelMMM:
00_run_metadata/config.resolved.yaml
00_run_metadata/config.original.yaml
the copied config file under 00_run_metadata/
Only when those in-run config artefacts are absent does the planner fall back
to run_manifest.json["config_path"].
That makes the compatibility loader more portable when the original config
path is no longer available, but it does not guarantee full relocation across
machines. The chosen config can still reference dataset files outside the run
directory.
The planner can also load these optional optimisation artefacts when they are
present:
70_optimisation/budget_response_curves.csv
70_optimisation/budget_bounds_audit.csv
When these files are available, the app can show saved saturation-reference
response-curve and bounds-audit views.
Companion dashboard handoff contract
A retained recipe writes scenario_payload.json for machine consumers. The
companion abacus-dashboard package must:
reject a missing or unknown contract_version;
compare that value with SCENARIO_CONTRACT_VERSION before rendering;
preserve all five record collections: totals, channels,
contributions_over_time, allocations, and metadata;
use scenario_validation.json, estimator_manifest.yaml, and
scenario_artifact_manifest.json as provenance and integrity evidence; and
label the outputs as posterior media contributions, not total outcomes,
profits, causal effects, or model approval.
Abacus owns this statistical payload. The companion package owns rendering,
interaction, and any application persistence. This repository does not add or
change dashboard UI code as part of the recipe workflow.
The companion package also provides a read-only bundle viewer. It verifies the
manifest checksums for every declared artifact and requires agreement among
the payload, validation record, and estimator manifest before it renders the
five collections. It rejects tampered or incompatible bundles rather than
attempting a partial display.
What the app persists
The workspace app stores its own planning state under the fitted run
directory:
Deprecated experimental application. Use the abacus.scenariosPython API or recipe CLI for
current scenario workflows.
The rest of this page is a historical record of the abacus-dashboard
prototype. Installation commands, launch procedures, screenshots, beta limits
and compatibility plans below describe that prototype, not a current product
recommendation or release commitment.
The app does not fit PanelMMM. It loads an existing fitted run, reuses the
saved idata, and evaluates planner scenarios against that fitted model.
For the current statistical API and estimator limits, see
Supported Surface.
Interface version and screenshots
This guide describes the workspace interface in the companion source declaring
abacus-dashboard version 0.1.0a0, checked on 24 September 2026. The five-page
navigation and the Explain → Diagnostics and audit section were checked
against that source. This identifies the documented interface; it does not
certify an installed build or a published release.
The screenshots below show an earlier read-only demonstration interface with
four navigation entries. Their exact app version was not recorded. They are
historical illustrations, not screenshots of the documented five-page
workspace. Follow the page names and procedures in the text.
Legacy app-layer imports and launchers under abacus.scenario_planner still
work as advisory compatibility facades, but new dashboard code should use
abacus_dashboard.*.
This launcher is the workspace entry point for beta evaluation. It
loads the fitted run, opens or seeds a planner workspace, and starts the app
with the threaded job runner used by the UI.
To inspect a retained YAML-recipe result without opening or creating a
workspace, use the mutually exclusive read-only evidence-review mode:
Before the dashboard renders, this mode verifies every manifest checksum and
cross-checks the versioned payload, scenario validation evidence, and fitted
estimator manifest. It renders all five retained record collections. It does
not fit, refit, evaluate, optimise, mutate evidence, or infer total outcomes,
profits, causal effects, or model approval.
Useful flags:
--workspace-id to open one previously saved workspace
--workspace-name to control the seeded workspace name
--current-periods and --future-periods to change the default seeded windows
--budget-scale to scale the default future budget
--build-only to validate the run and print a summary without starting Dash
--host, --port, and --debug for the Dash server
--workspace-id, --workspace-name, --current-periods, --future-periods,
and --budget-scale apply only with --results-dir. The evidence-review mode
rejects them rather than silently ignoring them.
The dashboard package also exposes the lower-level
create_scenario_planner_dash_app(...) factory when you already have a
ScenarioComparison or ScenarioWorkspace.
New statistical scenario code should use abacus.scenarios. Legacy
abacus.scenario_planner app-layer imports remain available as advisory
compatibility facades and emit DeprecationWarnings that name the replacement
abacus_dashboard.* import.
What the launcher requires
The dashboard launcher expects a fitted results directory that contains:
run_manifest.json
a fit-stage idata artefact
When the metadata stage is present, the launcher prefers the in-run config
artefacts under 00_run_metadata/ and only falls back to
run_manifest.json["config_path"] if those files are absent.
In build-only mode, the launcher prints the selected config path and its
provenance so you can see whether the planner loaded:
resolved_in_run
original_in_run
copied_in_run
external_manifest_path
This makes the launcher more portable when the original config path no longer
exists, but the chosen config can still fail if it references dataset files
that are not present on the current machine.
When these optional files are present, the app also loads them for richer UI
views:
70_optimisation/budget_response_curves.csv
70_optimisation/budget_bounds_audit.csv
What the UI includes
The documented workspace interface has five pages:
Plan Setup for run context, workspace metadata, saved workspaces, draft inventory, and the launch path into Scenario Builder
Scenario Builder for editing one draft at a time and evaluating it back into the workspace
Review for cross-scenario totals, deltas, rankings, movers, and approval/export readiness
Explain for response curves, operating-region views, lift comparisons, and diagnostics/audit surfaces
Export for reproducible export bundles and deterministic sensitivity output selection
What the app saves
The workspace app persists planning state under the fitted run directory:
Path
What Abacus saves
scenario_planner/workspaces/
workspace JSON files and compact manifests
scenario_planner/cache/
cached evaluated scenarios and cache index
scenario_planner/exports/
export bundles and zipped archives
This means a planner session stays attached to one fitted run.
Plan Setup page
The Plan Setup page shows the loaded run context and the active planner
workspace. It also lets you:
open a different saved workspace for the same run
clone the current workspace into a new planning branch
edit workspace name, owner, tags, and notes
inspect revision history, job history, and evaluation-cache reuse
launch the current workspace into Scenario Builder
This page is the planner launch surface: planning context stays visible first,
while operational details remain available through collapsed secondary
sections.
Scenario Builder page
The Scenario Builder page is interactive. You can:
create current, manual_allocation, and fixed_budget_optimized drafts
duplicate or delete drafts
edit names, dates, carryover, budget, and manual allocations
capture scenario owner, workflow status, approvals, pinning, tags, and notes
evaluate and save the draft back into the workspace
When a draft has been evaluated, the page shows planned versus realised spend,
allocation detail, and scenario metadata. When a draft has changed but has not
yet been re-evaluated, the page shows a draft preview instead.
Historical illustration of allocation review:
Earlier demonstration interface; exact version unrecorded. This view compares
planned allocation with realised spend and shows requested and evaluated
windows. It does not illustrate the current draft-editing controls. Use the
workspace’s Scenario Builder procedure above for editing and evaluation.
Review page
The Review page focuses on scenario-to-scenario trade-offs and review
readiness. It includes:
scenario summary cards
overview and delta charts
channel comparison charts
scenario ranking and top-mover tables
contribution-over-time comparisons
Historical illustration of scenario comparison:
Earlier demonstration interface; exact version unrecorded. Its Compare
Scenarios page illustrates totals and differences relative to a baseline.
In the documented workspace, use Review for this task. These displayed
example values are not evidence that a proposed allocation improves outcomes.
Explain and Export pages
The remaining pages build on the same workspace state:
Explain overlays scenario reference points on the saved Stage 70 saturation-only response-curve artefact when available
the plotted marker position follows the saved reference curve at each scenario’s spend-per-period level
marker hover text also shows the actual evaluated average contribution so you can compare the scenario outcome with the reference-curve position
Explain also surfaces scenario warnings, optimiser status, bounds audit, allocation reconciliation, operating-region views, and lift comparisons
Export writes reproducible bundles under the run directory and exposes any saved sensitivity output selections
Background jobs
The dashboard app runs draft evaluation and sensitivity sweeps as background
jobs.
In this beta:
the app queues draft evaluation and sensitivity sweeps
the UI polls the active job and refreshes the workspace when the job completes
export runs synchronously, but Abacus still records it in job history
The UI currently tracks one active planner job at a time. Finish the current
evaluation or sweep before starting another one.
Practical guidance
Launch the app from a fitted results directory, not from raw input data.
Use separate cloned workspaces for competing planning narratives.
Re-evaluate a draft after changing dates, budget, or allocation values.
Check both requested and evaluated windows when carryover is enabled.
Open Explain → Diagnostics and audit before exporting or sharing a
scenario set. Diagnostics is a historical screenshot label, not a separate
page in the documented workspace.
Treat the dashboard launcher as a local beta workflow rather than a
production deployment surface.
Use abacus-dashboard as the dashboard app home; treat
abacus.scenario_planner dashboard paths as legacy compatibility.
Legacy compatibility window
Compatibility remains advisory with no removal before Abacus 4.0. Removal of
legacy dashboard app-layer facades under abacus.scenario_planner also
requires:
a documented abacus-dashboard release and install path
passing dashboard smoke checks against the supported Abacus scenario contract
zero known internal imports using legacy dashboard paths
Common pitfalls
Launching the app without installing the companion abacus-dashboard package
Pointing the launcher at a directory without run_manifest.json and fit artefacts
Expecting the app to fit a model from scratch
Interpreting a draft preview as evaluated output before clicking Evaluate and Save
Starting a second evaluation or sweep while another planner job is still running