Fix startup when upgrading a saved v0.0.12 loadout - #275
Conversation
2fad112 to
fbf4457
Compare
|
Storage-boundary trace: authenticated configuration/WASM generation initialization completes before |
There was a problem hiding this comment.
🟡 Changes recommended
The new startup-path storage rewrite can throw on Storage#setItem, potentially failing initialization even when restore succeeds, so it should be made best-effort.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR fixes a TF2 equipment loadout migration bug when upgrading from a saved v0.0.12 profile by normalizing “empty” (0xffffffff) slots through the stock-item equip authority before performing strict persistence equality checks, and by persisting only when Rust normalization actually changes the canonical bytes.
Changes:
- Normalize empty persisted entries during Rust
Equipment::restoreso older profiles restore successfully against newer stock definitions. - Add a Rust regression test covering the v0.0.12 empty Demoman primary/secondary slot upgrade scenario.
- Add browser tests and update profile initialization to rewrite local storage only when the restored persistence bytes differ.
File summaries
| File | Description |
|---|---|
| games/tf2/rust/src/equipment.rs | Normalizes empty persisted slots during restore and adds a regression test for legacy profile upgrades. |
| games/tf2/browser/tests/equipment-storage.test.ts | Adds focused tests to verify only changed equipment persistence is rewritten and failures do not write. |
| games/tf2/browser/src/equipment/profile.ts | Writes back normalized persistence only when restoration changes the stored bytes. |
Review details
- Files reviewed: 3/3 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| if (saved !== null && saved !== undefined) { | ||
| const normalized = btoa(String.fromCharCode(...state.persistence)) | ||
| if (normalized !== saved) this.storage?.setItem(STORAGE_KEY, normalized) | ||
| } |
|
Rebased onto current main ( |
fbf4457 to
c944f8e
Compare
Root cause
Reproduced the exact
Unable to start TF2 / TransitionFailedscreen with genuine v0.0.12 equipment output, not current-version cache under old HTML. The archived v0.0.12 worker equipped Scout item 45 and persisted its 692-byte TFEQ v1 profile; the archived application successfully restored it on reload. Navigating the same browser origin to the retained v0.1.0 package then failed.runtime.#ensureResourceRuntimeinitializes the worker and restoresplaysrc.tf2.local-equipment.v1before resource decoding. The 693-byte equipment restore request reaches RustEquipment::restore. Old Demoman primary/secondary entries are0xffffffff; equip correctly resolves these to newly available stock definitions 19/20, but the final persistence equality check compared against unnormalized empty entries and returnedInvalidPersistence. The WASM update returns 0; the worker emitsTransitionFailedwith protocol detail 0 and no reason (the UI displays onlyTransitionFailed). This is a loadout migration issue, not an IndexedDB/native cache or stale configuration issue.Fix
Normalize empty entries through the existing stock-item equip authority before the strict persistence comparison. The browser writes back only a successfully restored profile whose canonical bytes changed. No cache eviction, database deletion, settings reset, error suppression, or storage-key version bump. Unknown items, invalid slots, malformed profiles and duplicate conflicts retain their validation. Official SDK
CTFPlayerInventory::GetItemInLoadoutlikewise resolves absent loadout items to their class base item.Verification
InvalidPersistence; all 11 equipment tests pass afterward.Before:
After:
No deployment or release is included.