Skip to content

The Scenario Pack

Marty McEnroe edited this page Aug 6, 2026 · 2 revisions

The Scenario Pack

A scenario is one JSON file the platform loads. You do not write code, and you do not need this repository's toolchain to author one. A text editor and public data are enough.

The normative definition is schema/scenario-pack.v0.schema.json.

Required fields

pack_version  scenario_id  title  substrate  brief_md
step_minutes  turns  start_hour_local
site  grid  events  scoring

Optional: provenance, coach_md, difficulty_rank, requires_concepts.

The day's clock

turns, step_minutes, and start_hour_local define the day. The exact optimizer solves hourly turns only, so step_minutes must be 60 if you want stars. A pack with a different step is still playable and still publishable; it is published unstarred.

Nothing in the platform may assume a start hour. Three of the five shipped packs open at an hour other than eight.

grid

Required: price_usd_per_mwh and system_status, one entry per turn.

Optional: price_slope_usd_per_mwh_per_mw, which turns on grid response. A pack that declares a slope cannot be certified by the exact optimizer, because the solver is slope-free, and it is published unstarred.

site

Required: name, it_load_mw (one entry per turn), sla_usd_per_mwh_shed, battery, and diesel.

The battery declares power, energy, round-trip efficiency, and starting charge. The generator declares power, fuel cost, and permitted run-hours. The SLA price is what shedding a megawatt-hour of customer load costs you in refunds.

events

Conservation appeals and curtailment orders, each announced at a turn and active over listed turns.

Keep appeal and order windows disjoint. The engine pays no voluntary credit under an order, and the optimizer refuses a pack whose windows overlap. A pack that overlaps them is playable but cannot be starred.

scoring

Required: score_version, metrics, and baseline_cost_usd. Optional: optimal_cost_usd.

The baseline is the do-nothing day: buy everything from the grid, at nominal draw, every hour. It is the denominator every cost number is reported against.

provenance

Optional by schema, required in practice for any contributed pack. It carries authors with name and affiliation, cohort, source_url, source_license, and whatever notes make the derivation reproducible.

Your name rides in the pack and appears on the public library card.

brief_md

The page a player reads before pressing start. It is a required field, and forgetting it is the single most common first rejection.

Your optimum is discarded and recomputed

Whatever optimal_cost_usd you submit is stripped on ingest and recomputed by the platform's exact optimizer, then replayed through the real engine before anything reaches a player. Your number never becomes a published gold line.

Submit it anyway. The gate reports the difference back to you, and finding which constraint you dropped is the exercise.

In the worked example that ships here, the author's own optimum came in twenty-two thousand dollars below what the exact optimizer can prove reachable. The cause was a battery that starts empty and pays a toll on the way in.

Identifiers

Contributed scenarios take ids C-001 through C-999. The id is a citation handle and never changes. Names and affiliations live in provenance, where they can be corrected.

Contributed scenarios carry no difficulty rank and never join the catalogue's ladder.

Running the gate

One command, from the repository root:

poetry run python tools/verify_pack.py path/to/your.pack.json

Add --json for machine-readable output. Three verdicts are possible.

accept-with-stars. Schema, invariants, a certified optimum, and engine parity.

accept-unstarred. Valid and playable, but no optimum can be certified. The causes are a declared price slope, non-hourly turns, curtailment priced into the optimizer's objective, or overlapping appeal and order windows. Published with the absence stated, the way the platform's own price-response scenario is.

reject, with the reason. The gate is idempotent, so fix and rerun.

Clone this wiki locally