Case Studies & Experiments May 24, 2026

We Recovered Mismatched Save Slot Labels After Steam Branch Promotion - 2026 Case Study

2026 case study—recover from mismatched save slot labels after Steam branch promotion using save_slot_label_map_v1.json and save_slot_recovery_receipt_v1.json before fest refund spikes.

By GamineAI Team

We Recovered Mismatched Save Slot Labels After Steam Branch Promotion - 2026 Case Study

Pixel-art hero for mismatched save slot labels after Steam branch promotion recovery case study 2026

This is a synthesized case study—a field pattern seen across May–October 2026 fest demos on Steam Windows builds, especially teams that promoted a playtest or internal branch to a public fest depot without updating save slot label maps. It is not a named studio turnaround story. There are no invented revenue figures, no fake Discord quotes, and no made-up refund percentages.

What follows is the failure signature, the isolation order that worked, the artifacts that proved recovery, and how the same pattern maps to your project if players say “I saved in Slot 1 and it loaded empty.”

Pair this narrative with GDevelop save-path freeze, GameMaker export sanity, Ren'Py label freeze, and BUILD_RECEIPT so you have procedure plus story.

Non-repetition note: Freeze-week posts teach prevention. This case study describes what broke after promotion when slot UI and persistence keys diverged—not another seven-day gate list.

Why this matters now (May–October 2026)

  1. Weekly fest promotions — Producers merge playtest into fest_public without a slot-label diff.
  2. “Lost progress” threads — Comments rhyme with gameplay / save tags in refund dashboards—but root cause is label map drift, not cloud outages.
  3. Multi-slot UI debt — Menu shows Slot 1 while code writes save_slot_b after a refactor.
  4. Cross-engine blind spots — GDevelop Storage keys, GameMaker ini sections, and Ren'Py persistent fields each fail differently; the symptom is identical.
  5. Evidence gap — Teams ran Wednesday smoke on boot path only, not save/load matrix.

Direct answer: Recovery required save_slot_label_map_v1.json, a promotion-day slot round-trip on installed Steam build, save_slot_recovery_receipt_v1.json, and a BUILD_RECEIPT row tying build_label to the map hash before the next branch merge.

Beginner quick start — what recovered means here

Recovered in this pattern means:

  1. Reproduced wrong slot load on installed Steam build—not editor only.
  2. Mapped every UI label to exactly one persistence key per build_label.
  3. Logged receipt JSON and one screen recording of save → quit → load.
  4. Reduced new “lost save” comments for seven days on the same build_label (qualitative, not a fabricated %).

It does not mean cloud saves work globally or that Steam Cloud was enabled—many fest demos are local-only with honest FAQ copy.

Success check: A producer can load Slot 2, quit, relaunch, and Slot 2 still shows the same chapter or floor—without engineer jargon.

The player-facing failure (typical signals)

Channel Typical wording
Steam discussion “Slot 1 empty but I saved”
playtest form “Wrong chapter after update”
refund language “Lost all progress after patch”
stream clip Clicks Slot 1; loads different timestamp

Internal team language before fix: “Saves work on my machine” — because QA used one slot and local dist folder, not installed client with three labeled slots.

Starting state (what was wrong)

Layer Symptom
UI Menu: Slot 1, Slot 2, Slot 3
Code Writes file_a, file_b, quicksave
Promotion build_label bumped; map not updated
FAQ “Three save slots” — true in UI, false in keys
Process No slot matrix in promotion checklist
Playtest CSV Missing slot_ui and persistence_key columns

Gameplay was fine. Trust in saves was not.

Root cause pattern (synthesized)

Three recurring mechanics—often combined:

Mechanic What drifted
Index off-by-one UI Slot 1 → slot_index=0 in old build, slot_index=1 after merge
Renamed keys Refactor save1demo_save_v2 without UI migration
Branch scope mix Playtest branch wrote full_game_slot_1; fest demo UI still shows three demo slots

None require malice—only missing map file at promotion time.

Timeline (five working days — pattern timing)

Day Focus Output
D1 Repro on installed Steam Recording + fail log
D2 Inventory UI strings + keys save_slot_label_map_v1.json draft
D3 Fix mapping + migration message Code or script patch
D4 Three-slot round-trip matrix gate_slot_matrix.log
D5 Receipt + BUILD_RECEIPT row save_slot_recovery_receipt_v1.json

Teams with existing GDevelop freeze save_path_map.json recovered in two days; teams without any map took five.

Hour-by-hour D1 (reproduction discipline)

Step Action
1 Install from Steam client (or playtest branch players use)
2 Note build_label on title screen
3 Save mid-demo in Slot 1; note chapter/floor shown
4 Quit fully
5 Relaunch; load Slot 1 — record pass/fail
6 Repeat for Slot 2 and Slot 3

If Slot 1 loads empty but Slot 2 shows Slot 1’s progress—you are in this case study.

D2 — save_slot_label_map_v1.json (inventory)

Create release-evidence/saves/save_slot_label_map_v1.json:

{
  "schema": "save_slot_label_map_v1",
  "build_label": "fest-demo-2026-05-24-rc2",
  "slots": [
    {
      "ui_label": "Slot 1",
      "ui_index": 1,
      "persistence_key": "demo_save_slot_a",
      "storage_surface": "local_file",
      "expected_path_hint": "%APPDATA%/Studio/Game/saves/"
    },
    {
      "ui_label": "Slot 2",
      "ui_index": 2,
      "persistence_key": "demo_save_slot_b",
      "storage_surface": "local_file",
      "expected_path_hint": "%APPDATA%/Studio/Game/saves/"
    },
    {
      "ui_label": "Quicksave",
      "ui_index": 0,
      "persistence_key": "quicksave",
      "storage_surface": "local_file",
      "notes": "Hidden from fest UI—must not steal Slot 1 key"
    }
  ],
  "faq_claim": "three manual slots local only",
  "cloud_enabled": false
}

Pass: Every visible UI slot has exactly one persistence_key; no duplicate keys.

Engine-specific inventory notes

Engine Where keys hide
GDevelop Storage action keys in save_path_map
GameMaker ini section names + slot functions
Ren'Py FileSave / FileLoad slots + persistent
Construct Local Storage keys per save semver
Godot user://save_%d.save pattern

One map file per SKU—do not merge demo and full-game maps without a sku_id column.

D2 deep dive — grep and screenshot discipline

Programmers export evidence—not opinions:

Artifact Contents
UI screenshot All slot strings visible on load menu
grep log Every save, Storage, FileSave, ini key
BUILD_RECEIPT prior row Previous build_label for diff
Disk listing Filenames under save root (redact usernames)

Pass: Screenshot string Slot 1 appears on same line in map JSON as ui_label, and persistence_key appears in grep log exactly once.

Studios using validate-packet added a optional check: save_slot_label_map_v1.json must exist when demo_has_save_slots=true in packet manifest.

D3 — fix mapping and migration

Minimum fix set:

  1. Align ui_index to persistence_key in code or rename keys to match shipped UI.
  2. On load, if old key exists under legacy name, migrate once with logged message.
  3. Show save_incompatible label instead of silent empty slot when migration impossible.

Example migration block (conceptual—adapt to engine):

IF legacy_key "save1" exists AND "demo_save_slot_a" empty
  COPY legacy → demo_save_slot_a
  DELETE legacy
  LOG "migrated save1 → demo_save_slot_a for build_label rc2"

Scope rule: No new features during D3—mapping fixes only.

Align FAQ save lines with faq_claim row in map.

D4 — slot round-trip matrix

Log gate_slot_matrix.log:

UI slot Save OK Load OK Timestamp matches Pass
Slot 1 Y Y Y Y
Slot 2 Y Y Y Y
Slot 3 Y N N N

Run matrix on:

  • Fresh install (no prior saves)
  • Install after one promotion (simulates fest player updating mid-week)

Pair with metadata diff on same promotion day—store copy and slot behavior ship together.

D5 — save_slot_recovery_receipt_v1.json

{
  "schema": "save_slot_recovery_receipt_v1",
  "build_label": "fest-demo-2026-05-24-rc2",
  "map_path": "release-evidence/saves/save_slot_label_map_v1.json",
  "map_sha256": "sha256:example…",
  "matrix_log": "release-evidence/saves/gate_slot_matrix.log",
  "slots_tested": 3,
  "matrix_pass": true,
  "migration_applied": true,
  "recovery_pass": true,
  "promotion_allowed": true,
  "signed_at": "2026-05-28T17:00:00Z",
  "reviewer": "GamineAI Team",
  "notes": "Installed Steam build; cloud off; pairs GDevelop freeze week 2026-W21"
}

Attach to BUILD_RECEIPT upload row:

Field Value
save_slot_recovery_pass true
save_slot_map_sha256 (from receipt)

What promotion day should have caught

Check Owner Time
Slot matrix on installed build QA 15 min
Map file diff vs previous build_label Programmer 5 min
FAQ vs faq_claim Producer 5 min
BUILD_RECEIPT hash Producer 2 min

Total ~27 minutes—cheaper than five-day recovery.

Add row to Wednesday smoke optional S9: “Slot 1 round-trip pass.”

Refund tag crosswalk (qualitative)

In refund dashboard spreadsheets, teams reported clusters of:

Tag Often actually
save / progress Slot label mismatch
cloud Local-only demo; player expected sync
update broke game Migration missing after key rename

After receipt shipped, new rows on same build_label with save language dropped in several teams’ qualitative notes—not a guaranteed metric for your studio.

Playtest form fields (D2 add-on)

Field Why
build_label Correlate map version
ui_slot What player clicked
last_chapter_or_floor Detect wrong load
installed_from_steam Y/N

Use 18 playtest tools for intake—require these four fields on save-related tickets.

Branch promotion failure modes

Failure Symptom
Merged playtest saves into fest depot Slot 3 shows dev data
Promoted without wiping QA saves Players inherit tester slots
build_label changed; map did not Empty Slot 1
Hotfixed UI strings only Keys still wrong

Rule: Promotion checklist includes map hash diff, not only binary smoke.

Comparison to replay refresh case study

Dimension Browser refresh replay case This slot-label case
Surface itch F5 / RNG Steam slot UI
User action Refresh tab Load save menu
Fix type Sheet order + seed Label map + migration
Receipt rng_replay_receipt save_slot_recovery_receipt
Timeline ~5 days ~5 days typical

Both live under release-evidence/—different subfolders.

Comparison to Ren'Py persistent drift

Ren'Py freeze week prevents label renames mid-fest. This case study covers UI slot numbers vs persistence keys after branch promotion—VN teams hit both; run freeze week before promotion, slot map on promotion day.

Developer checklist (PR template)

  • [ ] save_slot_label_map_v1.json matches UI screenshot
  • [ ] No duplicate persistence_key values
  • [ ] Slot matrix pass on installed Steam build
  • [ ] save_slot_recovery_receipt_v1.json updated
  • [ ] FAQ save claims match faq_claim
  • [ ] BUILD_RECEIPT row includes map hash
  • [ ] Migration log attached if keys renamed

Producer one-pager

Save slot honesty means Slot 1 on screen writes to the key players expect after every promotion. We prove it with save_slot_recovery_receipt_v1.json before fest branch merge. Playtesters: send build_label and which slot you used.

Anti-patterns in the same threads

Anti-pattern Why it fails
“Works in editor” Wrong install surface
Testing only Slot 1 Slot 2 drift hidden
UI rename without key map Silent empty load
Blaming Steam Cloud Cloud was off in FAQ
Closing tickets without receipt Regression on next merge

Ninety-minute “are we in this case study?” audit

Minute Question
0–15 Does Slot 1 round-trip on installed Steam?
15–30 Does map file exist in repo?
30–45 Do UI labels match map JSON?
45–60 Does FAQ match faq_claim?
60–90 Write pass/fail in qa-slot-label.log

If first step fails—you are in this case study.

Incident retrospective (45-minute workshop)

  1. Why was slot matrix missing from promotion checklist?
  2. Who owns map updates when UI strings change?
  3. Do playtest forms capture ui_slot?
  4. Is playtest branch isolated from public fest depot?
  5. Does Wednesday smoke include save round-trip?

Forward-link: playtest invite isolation playbook when backlogged—separate scopes need separate maps.

When this case study does not apply

  • Single-slot arcade games with no load menu
  • Roguelites with one run autosave only (see replay case study instead)
  • Games with no Steam branch promotions this quarter
  • Teams that only ship itch HTML5 without labeled slots

Community response template (Steam discussion)

Thanks for the report. Build fest-demo-2026-05-24-rc2 fixed a slot-label mismatch from the previous branch—please update. If you are on rc2 and Slot 1 still loads empty, reply with build_label from the title screen and which slot you used so we can match your save file.

No invented stats—build label and slot only.

Cost of five-day delay (opportunity framing)

Delay day Risk
D1 skipped More “lost save” posts
D2 skipped Map lies
D3 skipped Wrong migration
D4 skipped Slot 3 still broken
D5 skipped Promoted lying binary

Five days beats two weeks of fest-week comment firefighting.

Cross-training for non-programmers

Producers can run D1 matrix without opening engine:

  1. Install Steam build from checklist.
  2. Play to mid-demo.
  3. Save each slot; quit; reload each.
  4. Screenshot pass/fail table.
  5. File form.

Engineering fixes maps; whole team detects.

Link graph (save discipline family)

Order Post Role
1 GDevelop freeze Path prevention
2 Ren'Py freeze VN prevention
3 GameMaker export Export sanity
4 Construct save semver Mid-fest patches
5 This case study Post-promotion recovery

New hires read 5 → 1 for motivation before procedure.

Cloud saves caveat

If cloud saves parity applies, extend map with cloud_enabled: true and Steam Cloud API row per slot. This synthesized pattern often involved local-only fest demos where players assumed cloud sync—fix FAQ before enabling cloud.

Defold and collection saves

Defold collection audit addresses save root discovery. Slot-label mismatch can still occur if UI uses slot numbers but collections write to a single game.state file—add collection_slot column to map JSON.

Audio and trust (tangential)

Players who mute after save frustration still leave bad reviews—optional menu loop check via LUFS listicle does not fix slots but reduces compound negative first impressions after a save scare.

Friday Block 5 line

Add to Friday Block 5:

slot_matrix=pass/fail; save_slot_receipt_path=release-evidence/saves/save_slot_recovery_receipt_v1.json

Fifteen seconds prevents promoting a build that only passed boot smoke.

What we would do differently (retrospective)

Ship save_slot_label_map_v1.json before first public fest promotion—not after the first “lost progress” thread. Run slot matrix on installed Steam the same hour as BUILD_RECEIPT upload. Treat map hash diff as a merge blocker equal to broken exe.

That ordering collapses this five-day pattern into one promotion afternoon—and leaves the team arguing about story and art during fest month instead of defending slot numbering in discussion threads.

Key takeaways

  • Synthesized pattern—no invented studio metrics; portable artifact list.
  • UI slot labels must map 1:1 to persistence keys per build_label.
  • save_slot_label_map_v1.json is the inventory heart.
  • save_slot_recovery_receipt_v1.json proves recovery before next promotion.
  • Reproduce on installed Steam, not editor or dist folder only.
  • Five-day timeline is indicative; prevention takes one promotion checklist.
  • Pairs with GDevelop, Ren'Py, GameMaker, and Construct save discipline posts.
  • Refund dashboard tags often mislabel slot bugs as cloud issues.
  • Add S9 slot round-trip to Wednesday smoke optional gates.
  • Migration messages beat silent empty slots.
  • Playtest forms need ui_slot and build_label.
  • Branch promotion without map diff is the usual trigger.
  • Producers can run the ninety-minute audit without engine access.
  • FAQ faq_claim row must match real slot count and cloud state.

FAQ

Is this the same as corrupt save files?
No—files may exist under a different key than the UI slot the player chose.

Do we need Steam Cloud?
Not for local-only demos—honest FAQ matters more than enabling cloud.

Does this replace GDevelop freeze week?
No—freeze prevents path bugs; this case study covers post-promotion label drift.

Can one slot work and two fail?
Yes—matrix testing all visible slots is mandatory.

Should quicksave share Slot 1’s key?
No—give quicksave its own persistence_key in the map unless FAQ says they are the same slot.

Post-recovery monitoring (seven-day qualitative window)

Signal Healthy after fix
New save-language comments Flat or down vs prior build_label
Playtest forms citing wrong slot Stop after map ships
Refund rows tagged save Fewer new rows on fixed label
Internal chat Fewer “cannot repro” threads

No target percentages—track direction only.

Partner diligence attachment

Q3 diligence reviewers ask what happens to player progress when branches merge. Attach save_slot_label_map_v1.json, save_slot_recovery_receipt_v1.json, and optional 60s three-slot matrix capture—answers slot honesty without inventing retention stats.

Store-demo mismatch crosslink

When saves fail, players also report store-demo mismatch symptoms—treat slot map as binary truth beside metadata diff, not a separate crisis narrative.

Final honesty block

GamineAI Team publishes synthesized patterns to reduce repeated support questions across indie teams. Your comment volume, refund rate, and engine will differ. The artifact list is the portable part—timelines are indicative, not guarantees.

Reader assignment (optional)

Assign one person to run the ninety-minute audit and attach qa-slot-label.log to your next BUILD_RECEIPT. You either confirm you are not in this case study—or you start D1 the same day. Share the log in your next producer standup so art and narrative leads know saves are unblocked before trailer week.

Conclusion

Fest promotion without a slot-label receipt recreates “lost progress” threads even when saves exist on disk.

Map the slots. Test the matrix. File the receipt. Then merge the branch. Players forgive hard games faster than saves that lie about which file they touched.

Next reads: GDevelop save-path freeze, Wednesday demo smoke, BUILD_RECEIPT pipeline.