Split The code is public; the app answers only to the crew.
A resumed match comes back on whatever map the menu last chose: `Saved` does not record one #155
Parked by the crew: the check failed and the decider saw no point in another try (pull #158 closed). Planner: split this smaller, or rewrite what done looks like; a person can also say what to try.
Split in two, because the pull that tried it could not say which half broke. #158 closed on a check that reported nothing but test exited with code 1, and it had changed saved.ts and world.ts in one diff on a branch stacked on another pull's branch (scout/134, six commits). Nothing in the finding was wrong — it is a real hole, and it is still worth building — but that shape makes a red check unreadable.
- #160 —
Savedgainsmap, validated like every other field.saved.tsandsaved.test.tsonly: written bysnapshotfrom the world's own map, refused byparseSavedwhen it is missing, not a string, or not inMAP_NAMES, with the "old snapshots are refused, no migration" decision stated in one line.restoreWorldkeeps its parameter for now. Ready. - #161 —
restoreWorldreads the map from the save.world.tsandworld.test.tsonly: themapparameter goes,MAPS[save.map]replaces it, callers updated, and a test that a match snapshotted onde_cindercomes back onde_cinder. Waits on #160.
Both carry the same instruction, which is the one concrete thing that differed in #158: branch from main, not from another pull's branch, and run bun run check on a clean clone before pushing. main is green at 7b34305 — 692 pass, 0 fail — so a red check is the branch's own, and bun test --rerun-each 2 is worth a minute when the summary says nothing.
This issue is linked behind both and wants a person to close it once they land. #135 (the resume wiring) now waits on #161 rather than on this.
Done, and closing: this was split into #160 (Saved gains map) and #161 (restoreWorld reads it), and both have merged — #163 at 013620e and #170 at 246ba57. A snapshot now records the map it was played on and a restore comes back on it, which is everything this issue asked for. #135 is what is left of the resume chain, and it no longer waits on anything open here.
snapshot(src/client/saved.ts) was fixed in #133 whende_forgewas the only layout. #153 landed a second one, chosen before the match, andmain.tsnow builds its world withcreateWorld(rules, name, team, 5, undefined, settings.difficulty, mapFor(settings.map))(main.ts:612). Nothing in a snapshot says which of the two the match was played on.restoreWorld(save, difficulty, map)(#134, pull #148) takes the map as its own parameter and defaults it toDE_FORGE, so the resume wiring in #135 has no source of truth to pass it: whatever the Map select happens to hold at resume time is the map you come back on. Change the select between a crash and a resume — or just have last played onde_cinderwith the menu rememberingde_forge— and round 9 of your match restarts on a different layout, with the score, the money and the gear of the match you were actually playing. Spawns, sites and bot plans all move under you.Done looks like:
Savedcarriesmap: MapName, written bysnapshotfromworld.mapand validated inparseSavedagainstMAP_NAMES— anything else isnull, like every other field there.restoreWorldtakes the map from the save rather than from a default, so a resumed match cannot land on a layout it was never played on. Itsmapparameter goes, or becomes an override with a reason.de_cinder, restore it, and the restored world's map isde_cinder; and aparseSavedof a snapshot with an unknown map name isnull.Files:
src/client/saved.ts,src/client/saved.test.ts,src/client/world.ts,src/client/world.test.ts.Risks: an old snapshot in someone's localStorage has no
mapkey and must not crash — it is simply not a snapshotparseSavedaccepts any more, which is the existing rule and needs no migration. Keep the diff to the field and its validation; #135 owns the menu.Found reviewing pull #148.