Add the additive "Create scenario" path (v0.31.0):
3 light era templates (ww2 1939 / present 2026 / near-future 2035) in presets/templates/
Two plain-chat() LLM steps: generate (draft WorldDraft + advisor checkpoint list) and finalize (constrained to the approved checkpoints) → saved playable GameState at #/game/
- server/scenario.ts: buildGeneratePrompt / buildRegeneratePrompt, defensive
parseGenerate / parseRegenerate (fence-strip + balanced-object + validate),
generateDraft (draft world + advisor checkpoints) and finalizeWorld (final
world constrained to approved checkpoints -> playable GameState), all over
the injectable LlmClient with a nudge re-send. SCENARIO_* markers for the
stub.
- server/stubScenario.ts: deterministic scenario stub transport (fixed 3-nation
world + checkpoint list; finalize refines stability per approved checkpoint)
+ makeScenarioStubLlmClient. Distinct from and never touching turn stub.ts.
- server/regions.ts: validCountryCodes() accessor (ISO_A3 parents) for draft
territory validation.
- shared/scenario.ts: worldDraftToGameState now guards a dangling playerNationId
(falls back to the first nation) so a finalize that drops it stays playable.
- server/scenario.test.ts: 16 tests (prompt builders, defensive parsing,
generateDraft/finalizeWorld over a fake client + the stub).
Fixes#52
- GET /api/scenarios/templates: the 3 era templates (templateStore from
presets/templates/).
- POST /api/scenarios/draft: generateDraft (template + description + year) ->
{ world, checkpoints } (502 on transport failure / unusable world).
- POST /api/scenarios/commit: finalizeWorld (constrained to approved
checkpoints, optionally based on the re-sent draft) -> saved GameState,
returns { id } (a normal game at #/game/<id>).
- scenarioLlm: the deterministic scenario stub under LLM_STUB=1 (distinct
from the untouched turn stub), the live client otherwise.
- jump route: synthesize a minimal Preset for dynamic games (presetId
'dynamic', no static file) so their turns run; genuinely-missing static
presets still 404.
Fixes#52
Additive 'Create scenario' path (v0.31): the home screen's create-scenario
card opens a ScenarioForm (pick one of 3 light era templates + a free-text
description + an editable, era-prefilled start year) whose 'Generate world'
posts the draft request; the CheckpointReview screen shows the generated
world (per-nation stats/territory/relations + backstory) and the advisor's
checkpoint list as an approve/remove checklist, then the player picks a
nation to lead and finalizes into a saved, playable game. Both LLM steps ride
the scenario client (deterministic stub under LLM_STUB=1); a failure toasts
and stays on the current screen. The turn stub and static presets are
untouched. New e2e covers the full deterministic flow (near-future 2035,
remove checkpoint 3, lead Boreas, finalize, one empty jump) and the 3-template
manifest.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Add the additive "Create scenario" path (v0.31.0):
Local gates: typecheck, lint, 307 unit tests (14 files), build all green.
Fixes #52
- GET /api/scenarios/templates: the 3 era templates (templateStore from presets/templates/). - POST /api/scenarios/draft: generateDraft (template + description + year) -> { world, checkpoints } (502 on transport failure / unusable world). - POST /api/scenarios/commit: finalizeWorld (constrained to approved checkpoints, optionally based on the re-sent draft) -> saved GameState, returns { id } (a normal game at #/game/<id>). - scenarioLlm: the deterministic scenario stub under LLM_STUB=1 (distinct from the untouched turn stub), the live client otherwise. - jump route: synthesize a minimal Preset for dynamic games (presetId 'dynamic', no static file) so their turns run; genuinely-missing static presets still 404. Fixes #52