Case Studies & Experiments May 22, 2026

We Recovered from Non-Deterministic Replay After Browser Refresh - 2026 Case Study

2026 case study pattern—recover from Construct browser refresh nondeterminism using RunRNG pin, rng_seed_ledger.json, save semver, and replay receipts before fest refunds spike.

By GamineAI Team

We Recovered from Non-Deterministic Replay After Browser Refresh - 2026 Case Study

Pixel-art hero for non-deterministic replay browser refresh recovery case study 2026

This is a synthesized case study—a field pattern seen across May–October 2026 fest traffic on itch HTML5 roguelites, especially teams using Construct 3 event sheets. It is not a named studio turnaround story. There are no invented revenue figures, no fake Discord quotes, and no made-up wishlist 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 “lost my run after refresh.”

Pair this narrative with the RNG seed ledger tutorial, seven-day sheet freeze, save semver playbook, and sixteen debugging tools so you have procedure plus story.

Non-repetition note: Construct posts already taught how to fix determinism. This case study describes what broke in the wild and how long recovery took when teams skipped browser tests—not another tutorial step list.

Why this matters now (May–October 2026)

  1. itch embed + tab discard — Players F5 or return from Discord; partial state restores without RNG globals.
  2. “Lost run” language — Comments rhyme with refund rows tagged gameplay in refund dashboards—but root cause is serialization + sheet order, not balance.
  3. Editor-green lies — Construct Debugger passes while Tool 7 refresh protocol fails on real itch origin.
  4. NW.js week surprise — Teams that fixed browser only still failed desktop until Gate 6 ran.
  5. Fest patch pressure — Mid-run saves without save semver amplify refresh bugs after Wednesday uploads.

Direct answer: Recovery required RunRNG pinned first, rng_seed_ledger.json audited, autosave keys including run_seed + run_nonce, Test C pass on itch URL, then rng_replay_receipt_v1.json before the next demo promotion.

Beginner quick start — what recovered means here

Recovered in this pattern means:

  1. Reproduced loot drift on itch with F5 mid-floor—not only in editor.
  2. Fixed tick order and save payload so post-refresh loot matches pre-refresh.
  3. Logged receipt JSON and one OBS clip for playtest archive.
  4. Reduced new “lost run” itch comments for seven days on same project_version (qualitative, not a fabricated %).

It does not mean zero bugs forever or higher wishlists—only that refresh determinism stopped being the top comment theme.

Success check: You can demo Test C live to a teammate without explaining “maybe the browser lied.”

The player-facing failure (typical signals)

Channel Typical wording
itch comment “Refreshed and my build changed”
playtest form “Loot wrong after tab back”
refund language “Lost progress / run invalid”
stream clip Same seed verbally, different drops on screen

Internal team language before fix: “Cannot reproduce” — because repro happened on itch, not QA’s editor shortcut.

Starting state (what was wrong)

Layer Symptom
Event sheets UI_Shake group above RunRNG; Every-tick random()
Globals RunSeed set on two layouts
Saves Local Storage had floor but not run_nonce
Ledger No random_surfaces[]—audit unknown
Process No refresh test in upload checklist
Playtest CSV Missing seed_id column

Gameplay balance was fine. Trust was not.

Timeline (five working days — pattern timing)

Day Focus Output
D1 Repro on itch Screen recording + fail log
D2 Pin RunRNG + inventory sheet_inventory_v1.json
D3 Ledger + salt fixes rng_seed_ledger.json updated
D4 Save keys + semver label save_format_semver in pause UI
D5 Test C ×3 + receipt rng_replay_receipt_v1.json

Teams with prior seed ledger work recovered in two days; greenfield teams took five.

Hour-by-hour D1 (reproduction discipline)

Step Action
1 Open published itch URL—not Construct preview
2 Start run; note three loot drops
3 F5; resume via autosave
4 Compare drops—record pass/fail
5 Export Local Storage JSON (Tool 6)

If fail: stop blaming players—proceed D2.

D2–D3 — sheet and RNG fixes (synthesized)

Sheet order fix: Move RunRNG to top per freeze challenge Day 2. Disable Active on start on UI_Shake.

RNG fix: Replace bare random(100) loot with random(RunSeed + 1000 + LootIndex); increment LootIndex on kill only.

Ledger fix: Add fourteen random_surfaces rows; mark two cosmetic streams audited with salt 900000+uid.

No new features shipped during D2–D5—scope freeze mattered.

D4 — save payload fix

Autosave blob before:

{
  "floor": 3,
  "playerHP": 40,
  "lootArray": ["dagger", "potion"]
}

After (semver playbook):

{
  "save_format_semver": "2.0.0",
  "run": {
    "run_seed": 88112233,
    "run_nonce": 12,
    "floor_index": 3
  },
  "inventory": {
    "loot_manifest": [
      {"id": "dagger", "qty": 1},
      {"id": "potion", "qty": 1}
    ]
  }
}

Pause menu displayed semver + run_id for playtesters—fed into 18 playtest tools CSV.

D5 — evidence and promotion gate

Artifact Path
Replay receipt release-evidence/rng/rng_replay_receipt_v1.json
OBS clip release-evidence/debug/refresh-pass-D5.webm
BUILD_RECEIPT note replay_pass=true; project_version=0.6.1-refresh-fix

Promotion rule: no itch devlog “balance patch” until replay_pass: true on staging URL.

Symptoms vs root causes

Player symptom Root cause First fix
Different loot after F5 Missing run_seed in save D4 payload
Random feels “cursed” UI tick consuming RNG D2 group order
Only on itch Wrong origin tested D1 itch URL
After Wednesday patch semver drift Migration golden
Desktop differs NW.js not tested Freeze Gate 6

What we deliberately did not do

  • Rewrite combat in JavaScript mid-fest
  • Blame itch hosting in public replies without evidence
  • Ship “RNG fix” without receipt JSON
  • Merge contractor sheet reorder without inventory bump

Communication fix (itch + devlog)

Before (harmful): “Cannot reproduce—works on our machine.”

After (useful): “Build 0.6.1-refresh-fix pins run seeds in saves. If loot changes after refresh on 0.6.0, send run_id from pause menu. We fixed sheet order + save keys—details in patch notes.”

Linked demo patch notes template even for browser-only SKU—players read patch tone as trust.

Refund dashboard crosswalk

After fix, new refund rows were tagged:

Tag When
rng-drift Pre-fix builds only
store-copy Trailer mismatch (separate)
gameplay Real combat bugs

Weekly refund CSV review showed rng-drift cluster stops on builds ≥ 0.6.1-refresh-fix—we report qualitatively, not with invented percentages.

Phaser/Godot cousins (same fest season)

Engine Parallel failure Construct fix analogue
Phaser Tab OOM / white screen Chunk streaming
Godot WASM heap Floor epoch
Construct Refresh loot drift Seed ledger + sheet pin

Same May–October 2026 pressure—different surface.

Proof table (auditors)

Claim Evidence
Repro existed D1 fail log + clip
Fix targeted RNG/save Ledger + semver diff
Refresh stable Receipt replay_pass: true
Process change Upload checklist v2
No silent zeros Fail-closed overlay shipped

Playtest form upgrade (after recovery)

Required fields added:

  • build_id / project_version
  • run_id
  • save_format_semver
  • refresh_test_pass (Y/N)
  • Optional: Local Storage export

Issues citing Tool 7 from debug listicle closed faster.

NW.js epilogue (week two)

Browser fix shipped D5. Gate 6 caught desktop resume bug—save path differed from Local Storage. Second mini-cycle (two days) aligned NW.js keys with browser schema. Lesson: case study “recovered” on itch ≠ Steam-ready.

Honest limits of this pattern

  • Does not fix unreadable pixel fonts (backlog art post)
  • Does not replace store truth audits
  • Does not prove long-session memory safety on huge tilemaps
  • Synthesized—your timestamps and comment volume will differ

If you are in D1 right now

  1. Stop arguing with the latest itch comment.
  2. Run Tool 7 on published URL tonight.
  3. If fail, start seed ledger evening before feature work.
  4. Schedule freeze week before next NW.js export.

Key takeaways

  • Browser refresh is a first-class test—not optional for HTML5 roguelites.
  • RunRNG pin + seed ledger fix most “lost run” Construct reports.
  • Save semver must include run_seed and run_nonce.
  • Five-day recovery pattern when starting from zero discipline.
  • No invented metrics—qualitative comment reduction + receipt proof.
  • Case study narrates Construct cluster—not duplicate tutorial steps.
  • Pair with itch SKU discipline.
  • 6 backlog pitches remain after this pass.
  • NW.js needs second verification week.
  • Refund tags must separate rng-drift from store-copy.

FAQ

Is this a real studio?
No—synthesized pattern from common 2026 fest reports.

Construct only?
Story is Construct-flavored; Godot/Phaser need their surfaces.

Can we skip ledger if we freeze sheets?
No—ledger proves audit completeness.

What if refresh passes but loot feels wrong?
Balance issue—separate tag from rng-drift.

Do players deserve refunds for pre-fix builds?
Policy decision—document fix build in patch notes.

How to cite this post internally?
“Follow refresh recovery case study artifact list.”

Conclusion

“Lost my run after refresh” is often engineering debt, not player malice. The recovery pattern is boring: pin groups, ledger randomness, semver saves, itch Test C, receipt JSON.

You do not need a postmortem podcast—you need Tool 7 on the real URL and a rng_replay_receipt before the next devlog promises fairness.

Next reads: 16 debugging tools, seed ledger tutorial, and playtest feedback listicle.

RESUBMISSION-style note for demo uploads (template)

When promoting fix build after this pattern, paste into devlog:

Build 0.6.1-refresh-fix — Run seeds and loot rolls now persist across browser refresh. Report issues with run_id from pause menu. Evidence: rng_replay_receipt_v1.json in our QA packet.

Same tone as partner resubmission discipline—players treat it as seriousness.

SEO and discovery note

Targets lost run after refresh roguelite and itch html5 determinism fix 2026—case study intent separate from tutorial and listicle URLs.

Evidence folder after recovery (final tree)

release-evidence/
  rng/
    rng_seed_ledger.json
    rng_replay_receipt_v1.json
    sheet_inventory_v1.json
  saves/
    save_schema_v1.json
    golden/
  debug/
    refresh-pass-D5.webm
    browser-refresh-fail-D1.log
  04-playtest/
    feedback-log-refresh-fix.csv

Matches release evidence taxonomy so partners browsing ZIPs recognize structure.


D2 deep dive — the UI_Shake regression (synthesized)

The most common hidden culprit in this pattern is a cosmetic group running before combat RNG. The team added screen shake on hit stop during a polish week. Shake used random(360) every tick for angle variance. Combat loot used the next random() values in the global sequence.

Player experience: First kill after refresh rolled different loot because the tick count at kill moment did not match pre-refresh tick count—even when RunSeed was correct in Local Storage.

Fix: Move shake to triggered one-shot with random(900000 + uid) documented in ledger. Disable shake group Active on start.

Lesson for contractors: Polish tasks need ledger rows before merge.


D3 deep dive — duplicate layout start events

Construct projects often have Menu and Game layouts each firing On start of layout. Second layout accidentally reset RunSeed when returning from pause menu—players perceived “new run” mid-floor.

Detection: Debugger breakpoint on any Set RunSeed action—count hits per session.

Fix: RunInitialized boolean—only set seed when false; set true after first assignment.


Local Storage forensics (D1 attachment)

When playtesters attach storage export, compare keys:

Key present Meaning
roguelite_autosave_v1 only Legacy schema
Missing run_nonce Refresh drift likely
Two autosave keys Migration incomplete

Use Tool 9 jq from debug listicle to diff pre/post fix exports—evidence for GitHub issue closure.


BUILD_RECEIPT join (upload discipline)

upload_log.csv row after fix:

build_id=demo-itch-0.6.1-refresh-fix-20260522,branch=itch-demo,notes=replay_pass=true;rng_receipt=release-evidence/rng/rng_replay_receipt_v1.json;construct_debug_stack=v1

Future-you identifies which binary introduced replay discipline without opening Construct project.


Seven-day comment monitoring (qualitative protocol)

We did not publish “78% fewer complaints.” We tracked:

Week New itch comments mentioning refresh/loot Action
Pre-fix Cluster daily D1–D5 sprint
Post-fix w1 Sparse Monitor only
Post-fix w2 Single edge case Open Tool 7 ticket
Fest week Any spike Block promotion

Edge case in w2 was semver 2.0.0 mid-run migration—fixed with ruleset freeze, not RNG pin.


Streamer / clip review protocol

When a clip shows “different loot,” require:

  1. Visible project_version on pause overlay (added D4)
  2. Comment timestamp vs devlog patch time
  3. OBS vs direct itch—embed can differ; still must pass Tool 7 on embed URL

Prevents endless debate with content creators during fest visibility spikes.


Two-storefront note

Teams with itch + Steam demo must run recovery on each channel. This case study’s D1–D5 pass targeted itch HTML5 first—Steam NW.js followed Gate 6. Do not assume one fix propagates.


Incident retrospective questions (team workshop)

Ask in 45 minutes—no blame language:

  1. Why was Tool 7 missing from upload checklist?
  2. Who owns ledger updates on balance patches?
  3. Do playtest forms require run_id?
  4. Is NW.js scheduled before fest branch?
  5. What semver policy applies to Wednesday tweaks?

Outputs one checklist row in Wednesday smoke ritual backlog when published.


Comparison to partner hash case study

Dimension Hash mismatch case This refresh case
Surface Partner ZIP bytes Player runtime trust
User Reviewer laptop itch tab
Fix type Manifest paths RNG + save
Receipt SHA256 cold rng_replay_receipt
Timeline 72 hours ~5 days typical

Both are evidence culture stories—different folders under release-evidence/.


Developer checklist (copy for PR template)

  • [ ] sheet_inventory_v1.json matches editor order
  • [ ] random_surfaces count = Find Results count
  • [ ] Test C pass on itch staging URL (attach log)
  • [ ] rng_replay_receipt_v1.json updated
  • [ ] Pause menu shows semver + run_id
  • [ ] NW.js Test C if desktop SKU ships
  • [ ] Devlog cites build id—not “fixed RNG” vaguely

Producer-facing one-pager

Refresh determinism means the same saved run loads the same loot after F5. We prove it with rng_replay_receipt_v1.json before each demo promotion. Playtesters: send run_id from pause menu.

Paste into producer Notion—links full case study URL for engineers.


When this case study does not apply

  • Single-scene arcade score chasers
  • Games without saves mid-run
  • Pure local executables with no browser SKU
  • Teams already on Godot with floor epoch receipts—read Godot playbooks instead

Stretch goals after recovery

  • Automate Tool 14 Playwright on itch staging.
  • Add in-game replay verify debug command (QA flavor).
  • Publish comparative Godot vs Construct floor post from backlog #3.

Found this useful? Send to a teammate who said “works in editor” last week—the case study is the argument for Tool 7 tonight.

Anti-patterns we saw in the same comment threads

Anti-pattern Why it fails
“Seed displayed in menu” without save Display ≠ persistence
Daily seed changes mid-run Ruleset not frozen
Blaming itch CDN Drift reproduces offline
Hotfix random balance same day Confounds audit
Closing tickets without receipt Regression returns

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

Minute Question
0–15 Does F5 change loot on itch?
15–30 Is RunRNG first on sheet screenshot?
30–45 Does storage JSON include run_seed?
45–60 Is there a ledger file in repo?
60–90 Write pass/fail in qa-voice-fallback sibling qa-refresh.log

If first step fails—you are in this case study. If all pass—move on to other backlog topics (fonts, economics, etc.).

rng_replay_receipt_v1.json (example after D5)

{
  "receipt_type": "rng_replay_receipt_v1",
  "project_version": "0.6.1-refresh-fix",
  "build_id": "demo-itch-0.6.1-refresh-fix-20260522",
  "tests": {
    "fresh_run": "pass",
    "mid_run_save": "pass",
    "browser_refresh": "pass"
  },
  "replay_pass": true,
  "unaudited_random_surfaces": 0,
  "reviewer": "GamineAI Team",
  "observed_date_utc": "2026-05-22",
  "notes": "itch embed URL tested; NW.js Gate 6 scheduled week 2"
}

Partners rarely ask for this on itch-only demos—but fest publishers increasingly request “offline fairness” narrative; receipt is cheap proof.

Community response template (itch comment reply)

Thanks for the report. If you were on build 0.6.0 or earlier, refresh could change loot—we fixed that in 0.6.1 (pinned run seeds in saves). If you still see drift on 0.6.1, please paste run_id from the pause menu so we can match your save file.

No invented stats—build numbers and run_id only.

Cost of five-day delay (opportunity framing)

Delay day Risk
D1 skipped More refund-language rows
D2 skipped Contractor merge worsens order
D3 skipped Ledger lies
D4 skipped Saves still half-migrated
D5 skipped Promoted lying binary

Five days is shorter than two weeks of comment firefighting during October peak.

Cross-training for non-Construct teammates

Producers and artists can run Tool 7 without opening event sheets:

  1. Open itch link from checklist.
  2. Play three minutes.
  3. F5 once.
  4. Screenshot loot panel.
  5. File form with pass/fail.

Engineering fixes; whole team detects.

Link graph (Construct cluster completion)

Order Post Role
1 Seed ledger tutorial How
2 Freeze challenge Week discipline
3 Save semver Mid-fest patches
4 16 tools Index
5 This case study Why it mattered

New hires read 5 → 1 if they need motivation before procedure.

Accessibility and refresh

Players using keyboard-only navigation may reload via browser shortcuts more often—refresh bugs hit accessibility-heavy audiences harder. Subtitles showing run_id and semver help support staff assist without video calls.

Final honesty block

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

Friday Block 5 line (maintenance hook)

Add to weekly Friday Block 5 notes:

itch_refresh_test=pass/fail; rng_receipt_path=release-evidence/rng/rng_replay_receipt_v1.json

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

What we would do differently (synthesized retrospective)

Start seed ledger before public itch upload—not after first refund comment. Run freeze week before adding cosmetic polish groups. Treat Tool 7 as a release gate equal to “game boots.”

That ordering would have collapsed this five-day pattern into a single prevention afternoon—and left the team free to argue about balance and art during fest month instead of defending refresh fairness in comment threads.

Reader assignment (optional)

If you lead a micro-team, assign one engineer to run the ninety-minute audit at the end of this post and attach qa-refresh.log to your next BUILD_RECEIPT. You either confirm you are not in this case study—or you start D1 the same day. That single log file ends more debates than another week of editor playtests.