Skip to content

docs: refresh save-format section against current validation/migration behavior - #426

Merged
joryirving merged 1 commit into
mainfrom
courier/misospace/windowstead/issue-416
Oct 13, 2026
Merged

joryirving merged 1 commit into
mainfrom
courier/misospace/windowstead/issue-416

Conversation

@itsmiso-ai

Copy link
Copy Markdown
Contributor

What

Docs-only fix for #416. Updates the stale save-format material in docs/DESIGN.md:

  • Persistence key list (docs/DESIGN.md "Persistence"): now lists every persisted key (colony_stance, reserved_resources, active_rewards, current_milestone_id, completed_milestone_ids, and migration_log on upgraded saves) and names validate_save_schema() in scripts/game_state.gd as the source of truth.
  • Data-model state dictionary: adds the same missing fields (colony_stance, active_rewards with entry shape, milestone ids, reserved_resources, migration_log), marks spawn_tick optional (set on recruit, backfilled by migration), and notes resource on reward entries is trickle-only.
  • "Save format" section: replaces "version mismatch triggers a colony reset" with the actual lifecycle — v1 saves are migrated in place by migrate_v1_to_v2() and load normally; future versions and version 0 are rejected (load fails, running colony untouched, no reset on any load path); a missing save_version is treated as current; the migration bullet lists what migrate_v1_to_v2() actually writes (migration_log, spawn_tick), with the other newer fields attributed to ColonySim.ensure_defaults().

Invariants this change must keep, and the code paths that enforce each

This is a documentation change: the invariant is that the doc describes what the code actually does. Each rule below was checked against the named enforcer on main:

  1. v1 saves migrate, nothing resets. Enforced by GameState.migrate_save() / migrate_v1_to_v2() (scripts/game_state.gd); the doc now states this. clear_game() is only invoked from New Game (which backs up first), never from a load path — doc makes no reset claim.
  2. Future/unknown versions and version 0 fail the load without touching state. Enforced by migrate_save() returning {} and main.gd:load_saved_game() bailing via _load_failed() before assigning state. Doc matches.
  3. Desktop and web loads share one validation/migration pipeline. Enforced by _validate_and_apply_save() (issue [P2] Web localStorage load path skips save-schema validation and migration #313); the doc's wording ("shared by the desktop and web paths") reflects that single implementation.
  4. The persisted key set is exactly what bootstrap_state() + ColonySim.ensure_defaults() + persist() write. Verified all three (scripts/main.gd:636-652, scripts/colony_sim.gd:48-75, scripts/main.gd:1842-1855); the doc key list matches, and defers to validate_save_schema() for validated shapes.
  5. Only migrate_v1_to_v2() writes migration_log/spawn_tick; every other newer field is an ensure_defaults() backfill. Enforced in scripts/game_state.gd:700-709 and scripts/colony_sim.gd:57-73; the doc attributes each field to the right mechanism.

Validation

  • Independent review pass (separate agent) verified every new doc claim against scripts/game_state.gd (validate_save_schema, migrate_save, migrate_v1_to_v2, load_game), scripts/colony_sim.gd (ensure_defaults, recruit_worker), scripts/main.gd (bootstrap_state, persist, load_saved_game), and scripts/goal_reward.gd reward shapes; both findings from that review (optional resource on reward entries, optional spawn_tick) are included in the diff.
  • No Godot binary is available in this run environment (.tools/ absent), so the headless test suite was not run; the change is markdown-only and touches no script or test file. CI (test.yml) remains the external gate.

Closes #416.

…n behavior (issue #416)

- v1 saves are migrated in place, not reset; future/0 versions fail the load
- migration bullet lists what migrate_v1_to_v2() actually writes
- persisted key list now includes colony_stance, reserved_resources,
  active_rewards, milestone fields, and migration_log, and points to
  validate_save_schema() as the source of truth

@its-saffron its-saffron Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI Automated Review

Full PR review.

Analysis engine: MiniMax-M3 (anthropic) — primary route · pr-reviewer-action v3.4.1

Recommendation: Approve

This is a documentation-only change that updates docs/DESIGN.md to match the current save/load validation and migration behavior. The diff is consistent with the actual code paths and addresses every acceptance criterion in linked issue PR 416.

Change-by-change findings

docs/DESIGN.md

  1. Persistence key list (line 49) — Now lists colony_stance, reserved_resources, active_rewards, current_milestone_id, completed_milestone_ids, and migration_log in addition to the previously documented keys, and names validate_save_schema() in scripts/game_state.gd as the source of truth. Cross-checked against scripts/main.gd:636-652 (bootstrap_state), scripts/colony_sim.gd:48-75 (ensure_defaults), and scripts/main.gd:1842-1855 (persist) — all keys listed are written by these three code paths.

  2. Data-model state dictionary — Adds the missing fields colony_stance (line 76), active_rewards (line 107), milestone ids (line 109), reserved_resources (line 113), and migration_log (line 114). Marks spawn_tick as optional with a comment that it is set on recruit (scripts/colony_sim.gd:325) and backfilled by migration (scripts/game_state.gd:707-708). Notes that resource on reward entries is trickle-only, which matches the apply_reward logic in scripts/goal_reward.gd where resource is only assigned when the entry has it (trickle-type rewards).

  3. Save format section (lines 140-147) — Replaces "version mismatch triggers a colony reset" with the actual lifecycle: v1 saves are migrated in place by migrate_v1_to_v2() (scripts/game_state.gd:700-709); future versions and version 0 are rejected via migrate_save() returning {} (scripts/game_state.gd:661-698) and main.gd:load_saved_game() bailing via _load_failed() before assigning state (scripts/main.gd:767-774); a missing save_version is treated as current (scripts/game_state.gd:667-670); the migration bullet correctly attributes migration_log and spawn_tick to migrate_v1_to_v2() and the other newer fields to ColonySim.ensure_defaults() (scripts/colony_sim.gd:57-73).

Claim verification

  • Claim 1 (persistence key list): Held. 9/9 items verified. The key list at docs/DESIGN.md:49 matches what bootstrap_state(), ColonySim.ensure_defaults(), and persist() write, and defers to validate_save_schema() for validated shapes.
  • Claim 2 (data-model state dictionary): Held. 8/8 items verified. All newly documented fields match the code that produces them. The spawn_tick optionality and resource trickle-only notes are accurate.
  • Claim 3 (invariants checked on main): Held. The doc text at line 108 accurately describes the v1→v2 migration behavior.
  • Claim 4 (clear_game() not on load path): Held. 3/3 items verified. clear_game() is only called from the New Game flow (scripts/main.gd:285-287 backs up before reset), not from any load path. migrate_save() returns {} on version 0 or future versions, and load_saved_game() calls _load_failed() before assigning state.
  • Claim 5 (desktop/web share one pipeline; persisted key set exact): Held. 6/6 items verified. _validate_and_apply_save() (scripts/game_state.gd:256-265) is the single entry point used by both desktop and web load paths (issue PR 313). The persisted key set matches bootstrap_state() + ColonySim.ensure_defaults() + persist().

Sources

  • docs/DESIGN.md (the modified file)
  • scripts/game_state.gd:256-265 (_validate_and_apply_save)
  • scripts/game_state.gd:284-660 (validate_save_schema)
  • scripts/game_state.gd:661-698 (migrate_save)
  • scripts/game_state.gd:700-709 (migrate_v1_to_v2)
  • scripts/colony_sim.gd:48-75 (ensure_defaults)
  • scripts/colony_sim.gd:325 (recruit sets spawn_tick)
  • scripts/main.gd:285-290 (New Game backs up before reset)
  • scripts/main.gd:630-660 (bootstrap_state)
  • scripts/main.gd:761-774 (_load_failed, load_saved_game)
  • scripts/main.gd:1842-1855 (persist)
  • scripts/goal_reward.gd (reward entry shape, resource only on trickle)

Standards Compliance

The repository standards file (AGENTS.md) notes that "Save/version migration should be migration-first because the game auto-loads the latest save on startup." This PR documents exactly that behavior — the doc now states v1 saves are migrated in place, which is consistent with the migration-first principle. No standards violations.

Linked Issue Fit

The PR closes PR 416. All three acceptance criteria from the issue are met:

  1. ✅ The Save format section states that v1 saves are migrated (not reset) and that future versions are rejected with a load failure.
  2. ✅ The migration bullet lists what migrate_v1_to_v2() actually writes (migration_log, spawn_tick).
  3. ✅ The key list includes all schema-validated fields and links to validate_save_schema() as the source of truth.

Tool Harness Findings

15 tool calls were executed across 9 rounds. Key findings:

  • validate_save_schema() in scripts/game_state.gd:284 is the single validation entry point used by both desktop and web load paths via _validate_and_apply_save() (line 256).
  • migrate_save() (line 661) returns {} for version 0 and future versions (> SAVE_VERSION).
  • migrate_v1_to_v2() (line 700) writes migration_log and backfills spawn_tick on workers — it does NOT write active_goal, completed_goal_ids, active_rewards, milestone ids, colony_stance, or reserved_resources.
  • ColonySim.ensure_defaults() (line 48) backfills reserved_resources, events, completed_goal_ids, active_rewards, active_goal, colony_stance, and milestone state.
  • clear_game() is only invoked from the New Game startup path (scripts/main.gd:285-287), which backs up first. No load path calls it.
  • load_saved_game() (line 767) bails via _load_failed() before assigning state when the load result is empty.
  • The resource field on reward entries is only set for REWARD_RESOURCE_TRICKLE type rewards in scripts/goal_reward.gd:78-79.

CI Status

All CI checks (Script test suite, Headless smoke test, Export validation for macOS/Linux/Windows/Web, Release tag validation, macOS validation) are reported as success. The PR is markdown-only and touches no script or test file, so the test suite is not directly exercised by this diff but provides context that the surrounding code compiles and passes.

@joryirving
joryirving merged commit 9ee2598 into main Oct 13, 2026
9 checks passed
@joryirving
joryirving deleted the courier/misospace/windowstead/issue-416 branch October 13, 2026 16:19
@its-saffron its-saffron Bot mentioned this pull request Oct 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[P3] docs/DESIGN.md save-format section is stale — v1 saves are migrated not reset, key list omits validated fields

2 participants