fix(save): back-fill state.resources and state.harvested on load - #381
Conversation
Saves that omit state.resources or state.harvested passed
validate_save_schema ("if present" checks) and then crashed the sim on
the first tick: ColonySim.apply_food_upkeep, gather_haul_tasks, and
do_gather read state.resources.get(...) / state.harvested[...] with no
guard.
Take the migration-first option from the issue:
- GameState.migrate_save back-fills both dictionaries (zeroed
wood/stone/food) before the version branching, so every valid load
path — desktop file and web localStorage — returns a save the sim can
tick. Existing values are preserved.
- ColonySim.ensure_defaults back-fills the same two keys so bootstrap
and direct state assignments are covered too.
- Main.is_save_compatible rejects a save without a well-typed
resources dictionary instead of letting one through.
Adds regression tests in tests/test_local_storage_load_validation.gd
covering the missing-resources and missing-harvested cases for both the
web (localStorage) and desktop (file) branches. Full suite passes
headless, including tests/test_local_storage_xss.gd.
Fixes #378
Signed-off-by: Saffron <263493777+itsmiso-ai@users.noreply.github.com>
There was a problem hiding this comment.
AI Automated Review
Full PR review.
Analysis engine: MiniMax-M2.7@https://litellm.jory.dev/v1 (anthropic) — primary route
Review: fix(save): back-fill state.resources and state.harvested on load
Recommendation: Approve.
Change-by-Change Findings
scripts/colony_sim.gd — ensure_defaults() now guards state.resources and state.harvested the same way it already guards reserved_resources, events, etc. The comment correctly explains why these two are special: they are read unconditionally on the first tick (by apply_food_upkeep, gather_haul_tasks, do_gather), while other fields are only accessed after workers exist. This is a belt-and-suspenders fallback for bootstrap and any direct state assignment.
scripts/game_state.gd — _backfill_required_state() is a small, well-scoped helper that sets {"wood": 0, "stone": 0, "food": 0} for whichever economy dictionary is missing or not a Dictionary. It is called at the top of migrate_save() before version branching, so every return path carries both fields. The get_or_set pattern (if not data.has(...) or not data["..."] is Dictionary) handles both the missing-key and the null/wrong-type cases.
scripts/main.gd — is_save_compatible() gains a resources check ahead of the geometry check. A save without a well-typed resources dict is incompatible even if the tile grid matches. This is a light gate; the real fix is in migrate_save.
tests/test_local_storage_load_validation.gd — Four new tests cover the web and desktop load paths for both missing resources and missing harvested. Each test verifies:
- The back-filled dict exists and is the correct type
- All three resource keys (
wood,stone,food) default to0 - Pre-existing values in the other economy dict are preserved
Standards Compliance
Repository conventions from AGENTS.md and CONTRIBUTING.md are satisfied:
- Branch name
foreman/wl-misospace-windowstead-378/issue-378follows thefix/issue-NN-shortpattern. - Commit message is descriptive:
fix(save): back-fill state.resources and state.harvested on load. - No source version bump required per the tag-driven release process.
- No export or rendering touches; headless test suite is the appropriate validation gate.
Linked Issue Fit
Issue PR 378's acceptance criteria reads:
"Either:
validate_save_schemarequiresstate.resources(andstate.harvested) to be present… ORmigrate_saveback-fills both on every load before the dictionary is returned toload_saved_game."
The PR implements the second option. migrate_save() calls _backfill_required_state() on every incoming save before returning it to load_saved_game, so a hand-edited, corrupted, or future-migrated save that omits either dictionary is healed automatically.
The issue's expected-files list named scripts/game_state.gd, scripts/colony_sim.gd, scripts/main.gd, and tests/test_local_storage_load_validation.gd — all four are in the diff. The issue also mentioned tests/test_local_storage_xss.gd should keep passing; CI confirms all checks succeeded including macOS validation.
Tool Harness Findings
No tool calls were issued; reviewing the corpus directly.
CI Results
All seven CI gates are green on the PR head commit:
| Check | Result |
|---|---|
| Script test suite | ✓ success |
| Headless smoke test | ✓ success |
| macOS validation | ✓ success |
| Export validation (macOS) | ✓ success |
| Export validation (Web) | ✓ success |
| Export validation (Linux) | ✓ success |
| Export validation (Windows) | ✓ success |
Implements migration and back-filling for missing
resourcesandharvesteddictionaries to prevent runtime crashes on save load.Fixes #378
Opened by foreman on review GO (workload wl-misospace-windowstead-378).