-
Notifications
You must be signed in to change notification settings - Fork 0
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.
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.
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.
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.
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.
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.
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.
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.
The page a player reads before pressing start. It is a required field, and forgetting it is the single most common first rejection.
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.
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.
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.
Exedra
Why
How it is built
What you write
Boundaries
For reviewers