Skip to content

game-board WC: sticky win state leaks across games on reused instances (splash) #49

Description

@cablehead

Summary

<game-board> tracks win state (hasWon, movesSinceWin) and lastAppliedJson as sticky per-instance fields with no game-identity key. When a single element instance is reused across different games, that state leaks between games and mislabels the endgame badge.

Where it bites

The splash is one <game-board id="splash-board"> whose splashState signal is overwritten with different games as it cycles/seeks through all_states (serve.nu /sse/splash/:tabId + seed at the page route). The same element instance receives snapshots from many distinct games over its lifetime.

  • Once any splashed game crosses 2048, hasWon latches true for every subsequent game on that element. A later game that never won still renders the win path — "game over" + "you win!" instead of "you lost" (#applyBadge: showWin = over ? this.hasWon : ..., showLost = over && !this.hasWon).
  • movesSinceWin ticks on every distinct snapshot, so across game boundaries the "hide the win badge after 3 post-win moves" rule is meaningless.

State only resets when a fresh element is created (page reload).

/play and the /my/games / /by/<id> cards are unaffected — there it's one element ↔ one game. /watch would be exposed if it ever swaps games on a single element.

Root cause

game-board.js dedupes purely on JSON equality (lastAppliedJson) and has no notion of "this is now a different game," so #apply can't know to reset hasWon / movesSinceWin.

Suggested fix

Carry a game identity in the wire state (e.g. gameId) and reset hasWon, movesSinceWin, and lastAppliedJson in #apply when it changes — or expose a game-id attribute the splash sets per seek and reset in attributeChangedCallback.

Secondary (minor)

movesSinceWin++ keys off "distinct JSON," not "a move." Any non-move re-render (e.g. a playedMs-only change) would tick it. Latent today because playedMs only changes on a move, but the counter is coupled to serialization rather than to game events.


File: examples/2048/static/game-board.js (#tickWinCounter, #applyBadge, attributeChangedCallback).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions