Skip to content

fix(installed-apps): prefer Steam client icon and honour the store fallback - #167

Open
divya0795 wants to merge 1 commit into
k1tbyte:masterfrom
divya0795:fix/installed-apps-artwork-and-store-fallback
Open

fix(installed-apps): prefer Steam client icon and honour the store fallback#167
divya0795 wants to merge 1 commit into
k1tbyte:masterfrom
divya0795:fix/installed-apps-artwork-and-store-fallback

Conversation

@divya0795

@divya0795 divya0795 commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Fixes #166

Two defects in installed-data.js, both affecting the My Games snapshot. They share a file, so they share a PR — no other open PR of mine touches it.

1. Steam client_icon was unreachable

pickImageUrl returns the first non-null candidate in argument order, and getSteamClientIconUrl(...) sat at argument 7, behind six title.* image fields. Any title carrying flat artwork won, so the client icon CDN shape was never selected — the inverse of the rule in AGENTS.md:20 ("must prefer … whenever the matched title/game/version metadata contains a Steam AppID, regardless of install platform").

Moved it to the front. It returns null when no AppID resolves, so non-Steam titles keep falling through to their own metadata with identical results.

The sidebar candidate moved the other way — argument 8 → last. AGENTS.md describes the rendered sidebar DOM as the fallback used only when metadata does not expose the icon, but it was overriding every game.* field.

2. Empty service slice bypassed the store fallback

isRecord({}) is true, so an installedAppsService.installedApps of {} (its state before refreshApps fills it) took the service branch with nothing to match and skipped the store branch below. Now that branch requires a non-empty record. catalog and installedGameVersions are untouched — they already chain their own store fallbacks.

Tests

Three tests added, all driven through the public buildSnapshot / resolveInstalledData contracts. Per web-panel/CLAUDE.md ("test product behavior and public contracts", "keep implementation-only helpers private") I did not export pickImageUrlForTitle to test it directly — the fixtures go through the real snapshot path instead.

Both bug-specific tests were confirmed to fail against the unfixed source before the fix was applied:

× prefers the Steam client icon over the title's own artwork fields
  Expected: "https://api-cdn.wemod.com/steam_community/1245620/client_icon/96.webp"
  Received: "https://cdn.example/subnautica-cover.webp"

× reads installed apps from the store while the service slice is still empty
  Expected: "store"
  Received: "service"

The third test pins the non-Steam path (epic: correlation → title artwork still wins) so the reorder cannot over-correct.

Verification

Run locally on Node 22.23.1 / pnpm 10.17.0, the versions .github/workflows/build.yml pins:

  • pnpm test37 passed (12 files), up from 34 on master
  • pnpm lint — clean at --max-warnings=0
  • pnpm typecheck — clean (both typecheck:web and typecheck:bridge)

Note on visible behaviour

This intentionally changes what users see: Steam titles that previously showed a wide catalog cover will now show the 96px client_icon. That is what AGENTS.md mandates, but it is a visual change rather than a silent correctness fix, so flagging it explicitly in case the documented rule no longer reflects your intent — happy to drop that half and keep only the store-fallback fix if so.

I do not have a licensed WeMod install, so I have not exercised this against a live Wand renderer; the evidence above is the unit suite plus the documented invariant.

…allback

Two defects in the My Games snapshot pipeline, both in installed-data.js.

1. The Steam client icon was never selected. pickImageUrl returns the first
   non-null candidate in argument order, and getSteamClientIconUrl sat at
   argument 7, behind title.imageUrl/iconUrl/coverUrl/thumbnailUrl/logoUrl/
   headerImageUrl. Any title carrying a flat image field won, so the
   client_icon CDN shape was unreachable whenever catalog metadata had
   artwork -- the inverse of the rule in AGENTS.md, which requires preferring
   it whenever a Steam AppID is present, on any install platform.

   Move the client icon to the front. It yields null when no AppID resolves,
   so non-Steam titles keep falling through to their own metadata unchanged.

   The sidebar candidate moves in the other direction, from argument 8 to
   last. AGENTS.md describes the rendered sidebar DOM as the fallback used
   only when metadata does not expose the icon, but it was overriding every
   game.* field.

2. resolveInstalledData treated an empty-but-present service slice as
   populated. isRecord({}) is true, so when installedAppsService.installedApps
   existed but was still {} -- the state before refreshApps fills it -- the
   service branch was taken with nothing to match and the store branch below
   was never consulted, leaving My Games empty until refreshApps fired.

   Require a non-empty record for that branch. The catalog and
   installedGameVersions branches are untouched; they already chain their own
   store fallbacks.

Covered by three tests driven through the public buildSnapshot and
resolveInstalledData contracts. Both bug-specific tests were confirmed to fail
against the unfixed source; the third pins the non-Steam path so the icon
reorder cannot over-correct.
@divya0795
divya0795 force-pushed the fix/installed-apps-artwork-and-store-fallback branch from c3db32c to e4d374b Compare July 26, 2026 14:32
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.

installed-apps-sync: Steam client_icon never preferred, and empty service slice bypasses the store fallback

1 participant