Lesson 61 of 170

Restore systems in a deliberate order

Martinez AI Studios Academy

Design, implement, and test a load sequence that validates source data, migrates without mutation, restores system-owned state, and resolves commit-time failures without leaving contradictory state.

890. Lesson identity

Module
2.13 — Save and load
Lesson
Restore systems in a deliberate order
Academic type
Debugging Lab
Schema type
Practical
Order
Lesson 2 in the module
Estimated time
40–50 minutes

891. Learning objective

After this lesson, you can write a load contract, implement a bounded restoration path, and validate an AI-assisted persistence change against explicit rules for source validation, migration, sequencing, commit-time failure, and final system state.

892. Why this matters

A parsed save file is not yet safe game state. Profile, Inventory, and Loadout may own different facts, while the HUD only presents their confirmed state. If one owner changes and a later owner rejects restoration, the game can contain a mixture of old and new data even though the loader reports an error.

AI can draft a loader, but it cannot decide the required ownership order or failure contract for you. Those decisions must be written before implementation and verified against the complete diff and observable final state.

893. Starter path

Use the instructor-provided runnable persistence harness when your project does not already expose a suitable load path. The harness contains:

  • bounded Profile, Inventory, Loadout, and HUD interfaces;
  • current-version and version-1 text fixtures;
  • malformed and cross-field-invalid fixtures;
  • a restoration fault switch selected by test input or configuration rather than a specific UI;
  • before-load and after-load state tables;
  • contract, changed-file review, and acceptance-result templates.

You may operate the harness through any accessible editor, test runner, command interface, or instructor-provided control surface. The required evidence is the same state transition and review record, not a particular input method.

894. Core concept: two validation levels before restoration

A migration must not consume an arbitrary parsed object, but an older payload also cannot be required to satisfy the current schema before migration. Use two validation levels:

  1. Parse and validate the source envelope. Parse without mutating game systems. Validate the version discriminator and the minimum schema required for that declared source version. Reject malformed data, unknown versions, or source fields that the migration cannot safely read.
  2. Migrate without mutation. Transform a supported older payload into a new in-memory value. Do not write into Profile, Inventory, Loadout, or HUD, and do not mutate the original parsed payload.
  3. Validate the normalized current payload. Validate all current required fields, types, ranges, and cross-field invariants. For example, every activeLoadout item must satisfy the contract's ownership rule.
  4. Plan, preflight, and commit restoration. Build an ordered restoration plan. Ask systems whether they can accept it where their interfaces support preflight checks. Then apply one explicit commit-time failure strategy.
  5. Rebuild and report. Rebuild the HUD only from the final confirmed gameplay state and report the outcome.

895. Restoration pipeline

Phase Gate question Evidence Failure response
Parse and source validation Is the version known, and does the payload satisfy the minimum schema for that version? Parsed version plus source-schema result Reject without mutation.
Non-mutating migration Can the supported source payload be transformed into a current candidate? New normalized candidate and migration result Reject without mutation.
Current validation Does the complete candidate satisfy the current schema and invariants? Field, range, required-value, and cross-field results Reject without mutation.
Plan and preflight Is the ordered change set coherent, and can each owner accept it where preflight is available? Restoration plan and preflight results Reject without mutation.
Commit Can all intended owners reach one consistent result? Commit trace plus final states Complete atomically, roll back, or enter the defined safe state.
Rebuild and report Does presentation reflect the final confirmed gameplay state? HUD projection and outcome Never display an unconfirmed mixture.

A validation failure and a commit-time failure are different:

  • Validation or preflight failure: no game system has changed, so rejection before mutation is sufficient.
  • Commit-time failure: at least one owner may already have changed. Merely returning an error is insufficient; the loader must restore consistency according to the contract.

896. Commit-time consistency strategies

Choose one strategy supported by the bounded implementation:

1. Atomic staged commit

Each owner prepares candidate state without publishing it. The loader publishes all prepared states as one commit. If preparation fails, nothing is published.

2. Snapshot and rollback

Before committing, capture the specific pre-load state needed to restore every owner that may change. Apply in order. If Inventory or Loadout fails, restore all previously changed owners from their snapshots, then rebuild the HUD from the restored pre-load state.

3. Defined safe-state transition

If atomic commit and reliable rollback are unavailable, define one complete safe state in the contract. On commit failure, transition every relevant owner to that state and rebuild the HUD from it. A safe state must specify the final values or reset rules for Profile, Inventory, and Loadout; “show an error” is not a state definition.

A repair policy for inconsistent save data is separate from commit recovery. Any repair must occur on the normalized in-memory candidate, be documented, and pass current-schema validation before restoration begins.

897. Concrete example

Current version 2 uses this shape:

{
  "version": 2,
  "profile": { "credits": 120, "rank": 3 },
  "ownedItems": ["scanner"],
  "activeLoadout": ["scanner"]
}

A safe version-1 path is:

  1. Parse the text.
  2. Confirm that version is present and equals the supported value 1.
  3. Validate only the documented version-1 fields and types required by the migration.
  4. Produce a separate version-2 candidate in memory.
  5. Validate the entire version-2 candidate and its cross-field invariants.
  6. Build and preflight the ordered plan for Profile, Inventory, and Loadout.
  7. Commit using the selected consistency strategy.
  8. Rebuild the HUD from the resulting confirmed state.

If the candidate contains "grappler" in activeLoadout but not in ownedItems, the loader must follow the written rule: reject the candidate or apply a documented repair before current validation completes. It must not silently grant ownership merely to make presentation look consistent.

898. Failure trace

Suppose the pre-load state is:

System Before load
Profile credits 20, rank 1
Inventory scanner owned
Loadout scanner active
HUD displays credits 20 and scanner

The candidate requests credits 120, scanner and grappler ownership, and grappler active. Profile commits, but the fault switch makes Loadout fail.

The test does not pass merely because the loader reports failure. It must assert the final state of all four systems:

  • Under rollback, Profile, Inventory, and Loadout match the complete pre-load state, and the HUD is rebuilt from that restored state.
  • Under a defined safe-state transition, all three gameplay systems match the safe-state contract, and the HUD reflects that state.
  • Under an atomic staged commit, none of the candidate state becomes visible.

A final mixture such as new Profile, old Loadout, and a refreshed HUD is contradictory and fails the contract.

899. AI-native workflow

  1. Complete the concise contract template: supported versions, source schemas, migration output, current invariants, owner order, consistency strategy, safe-state or rollback definition, and final-state assertions.
  2. Give the AI only the loader entry point, bounded system interfaces, fixtures, allowed files, and acceptance checks.
  3. Require a proposed changed-file list and assumptions before editing.
  4. Ask for a non-mutating migration and an explicit restoration plan. Do not accept field-by-field mutation during parsing or migration.
  5. Require the implementation to expose the provided configuration-driven fault switch for Inventory or Loadout restoration.
  6. Inspect the complete diff using the checklist: intended files only, no hidden ownership creation, no presentation data treated as durable state, no mutation before normalized validation, and no error path that leaves an unspecified partial state.
  7. Give every changed file a one-sentence rationale tied to the brief. Reject or revert unsupported changes.

900. Guided practice

Use the starter harness or an equivalent existing path.

  1. Fill in the load-contract template. Choose rollback, atomic staged commit, or a fully specified safe-state transition for commit-time failures.
  2. Define the minimum version-1 source schema and the complete version-2 schema. Write the non-mutating transformation between them.
  3. Define the ownership invariant for activeLoadout and ownedItems.
  4. Implement or review the sequence: parse, source validation, migration, current validation, plan, preflight where available, commit, HUD rebuild, and outcome report.
  5. Review the complete diff and record a rationale for every changed file.
  6. Run these acceptance cases using the supplied text fixtures:
    • valid current payload;
    • valid supported version-1 payload;
    • malformed text or missing version discriminator;
    • source-version payload that does not satisfy its minimum migration schema;
    • normalized payload with inconsistent ownership;
    • forced Inventory or Loadout commit failure.
  7. For every case, complete an expected-versus-observed table for Profile, Inventory, Loadout, HUD, and the reported outcome.
  8. Document one proposed change rejected for exceeding the brief.

901. Evidence

Submit the load contract, bounded AI brief, implementation artifact, complete diff review, changed-file rationales, and acceptance table. The evidence must show:

  • source-version validation before migration;
  • a non-mutating migration;
  • complete current-schema and invariant validation before restoration;
  • an ordered restoration plan and preflight where supported;
  • a concrete atomic, rollback, or safe-state mechanism for commit-time failure;
  • final-state assertions for Profile, Inventory, Loadout, and HUD after the forced failure;
  • HUD reconstruction from final confirmed gameplay state;
  • one rejected out-of-scope proposal.

902. Key takeaways

  • Validate the version discriminator and source-version shape before migration.
  • Migrate into a separate in-memory candidate, then validate the complete current contract.
  • Rejection before mutation handles validation failures, not failures after a system has committed.
  • Commit-time failures require atomic publication, rollback of every changed owner, or a fully defined safe-state transition.
  • Assert final system state, not only the reported error.
  • Presentation systems should observe restored, confirmed gameplay state rather than serialized presentation values; this same observer boundary leads into the next module on audio.

903. Next lesson

Continue to 2.14 — Audio.

904. Knowledge check

Answer these items for yourself before reading the answers.

A loader parses a payload declaring version 1. What must happen before its migration reads version-1 fields?

  • A. Apply the fields to Profile so the migration can inspect live state
  • B. Validate the version discriminator and the minimum version-1 schema required by the migration
  • C. Require the unmodified version-1 payload to satisfy the full version-2 schema
  • D. Rebuild the HUD to confirm that the source version is usable
Show answer and feedback

Answer: Validate the version discriminator and the minimum version-1 schema required by the migration

Why: The loader must establish a supported version and validate the minimum source shape that the migration will consume. It then migrates into a separate candidate and validates that candidate against the complete current schema.

Why should ownership normally be established before restoring a dependent loadout?

  • A. The loadout can verify each selection against the state confirmed by Inventory
  • B. It allows Loadout to grant any missing item automatically
  • C. It makes source-version validation unnecessary
  • D. It makes the HUD the owner of restored gameplay state
Show answer and feedback

Answer: The loadout can verify each selection against the state confirmed by Inventory

Why: Inventory provides the confirmed ownership state against which dependent selections can be checked. Loadout must not invent ownership to make its own data valid.

A normalized candidate contains an active item that is not owned. Which response respects the load contract?

  • A. Silently grant the item during Loadout restoration
  • B. Hide the item in the HUD while preserving the contradictory gameplay state
  • C. Apply the documented reject-or-repair rule before restoration and validate the resulting candidate
  • D. Commit Profile first and decide how to handle the contradiction afterward
Show answer and feedback

Answer: Apply the documented reject-or-repair rule before restoration and validate the resulting candidate

Why: The ownership rule belongs to normalized validation. A documented repair may transform the in-memory candidate, but the repaired candidate must pass validation before any owner is changed.

Trace: before loading, Profile has 20 credits, Inventory owns scanner, Loadout uses scanner, and the HUD shows both. During loading, Profile commits 120 credits and then Loadout fails. The contract requires rollback. Which evidence satisfies the contract?

  • A. The loader reports failure, regardless of the resulting system states
  • B. Profile remains at 120 credits, Loadout remains on scanner, and the HUD shows an error
  • C. Profile returns to 20 credits, Inventory and Loadout match their complete pre-load states, the HUD is rebuilt from those states, and failure is reported
  • D. The HUD keeps displaying the candidate values while rollback runs only for Profile
Show answer and feedback

Answer: Profile returns to 20 credits, Inventory and Loadout match their complete pre-load states, the HUD is rebuilt from those states, and failure is reported

Why: A rollback contract is satisfied by the final state of every affected owner and presentation system, not merely by an error result. All changed owners must return to the defined pre-load state, and the HUD must be rebuilt from that confirmed state.

Support