Skip to content

Fix startup when upgrading a saved v0.0.12 loadout - #275

Merged
Hona merged 1 commit into
mainfrom
work/tf2-v010-storage-upgrade
Sep 1, 2026
Merged

Fix startup when upgrading a saved v0.0.12 loadout#275
Hona merged 1 commit into
mainfrom
work/tf2-v010-storage-upgrade

Conversation

@Hona

@Hona Hona commented Sep 1, 2026

Copy link
Copy Markdown
Owner

Root cause

Reproduced the exact Unable to start TF2 / TransitionFailed screen 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.#ensureResourceRuntime initializes the worker and restores playsrc.tf2.local-equipment.v1 before resource decoding. The 693-byte equipment restore request reaches Rust Equipment::restore. Old Demoman primary/secondary entries are 0xffffffff; equip correctly resolves these to newly available stock definitions 19/20, but the final persistence equality check compared against unnormalized empty entries and returned InvalidPersistence. The WASM update returns 0; the worker emits TransitionFailed with protocol detail 0 and no reason (the UI displays only TransitionFailed). 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::GetItemInLoadout likewise resolves absent loadout items to their class base item.

Verification

  • Rust regression failed before the fix with InvalidPersistence; all 11 equipment tests pass afterward.
  • 46 focused browser equipment/storage/worker-pipeline tests pass (1,655 assertions).
  • Threaded WASM and static application build pass.
  • Headed Edge, same origin: authentic old-worker save → old application reload succeeds → retained v0.1.0 fails → fixed application reaches MainMenu. Exactly bytes 236–243 change to definitions 19 and 20; Scout item 45 and all other 684 bytes remain unchanged. No persisted cache is cleared.
  • Browser tests verify unrelated settings/storage values are untouched, unchanged profiles are not rewritten, and restore failures propagate without writing.

Before:

After:

No deployment or release is included.

Copilot AI lite review requested due to automatic review settings September 1, 2026 02:34
@Hona
Hona force-pushed the work/tf2-v010-storage-upgrade branch from 2fad112 to fbf4457 Compare September 1, 2026 02:34
@Hona

Hona commented Sep 1, 2026

Copy link
Copy Markdown
Owner Author

Storage-boundary trace: authenticated configuration/WASM generation initialization completes before Tf2EquipmentProfile.initialize() is called (apps/web/tf2/src/runtime.ts, #ensureResourceRuntime). That call is the reproduced failure: generation 0 equipment restore, before resource decoding/finalization and map/presentation cache admission. Browser settings have a separate owner and are read later during UI initialization through TF2_BROWSER_SETTINGS_STORAGE_KEY; neither their parser nor persistence format is changed. Immutable object/cache integrity checks remain unchanged. The successful fixed startup retained the same browser origin and old persisted caches; no reset or deletion was used.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 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::restore so 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.

Comment on lines +36 to +39
if (saved !== null && saved !== undefined) {
const normalized = btoa(String.fromCharCode(...state.persistence))
if (normalized !== saved) this.storage?.setItem(STORAGE_KEY, normalized)
}
@Hona

Hona commented Sep 1, 2026

Copy link
Copy Markdown
Owner Author

Rebased onto current main (db3a0cac). Final local checks: 11/11 Rust equipment tests; 46/46 focused browser tests; full Bun suite 1,434 passed, 21 skipped, zero failures (38,163 assertions). Required GitHub Checks is still running; merge remains gated on its success.

@Hona
Hona force-pushed the work/tf2-v010-storage-upgrade branch from fbf4457 to c944f8e Compare September 1, 2026 02:44
@Hona
Hona merged commit dbdc45c into main Sep 1, 2026
1 check passed
@Hona
Hona deleted the work/tf2-v010-storage-upgrade branch September 1, 2026 02:51
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.

2 participants