Skip to content

Invalidate current-phase resources on phase transitions - #1396

Merged
johnpooch merged 3 commits into
mainfrom
claude/sweet-bohr-yqpkn5
Sep 24, 2026
Merged

johnpooch merged 3 commits into
mainfrom
claude/sweet-bohr-yqpkn5

Conversation

@johnpooch

Copy link
Copy Markdown
Owner

What this PR does

/game/<id>/phase-states/ and /game/<id>/options/ are stable URLs that always represent the game's current phase. Their contents change when the server resolves a phase, but nothing told TanStack Query that. currentPhaseId is the signal to invalidate these resources, not part of their query identity. Generated query keys, generated clients and backend contracts are unchanged.

  • Transition observer (GameDetailLayout.tsx, alongside the existing polled useGameRetrieve): it watches currentPhaseId and status. When either changes for the same game, it invalidates phase states, options, the phase list, and the phase-retrieve and orders queries for the previous and current phase ids. Initial load and navigating between games are ignored. It never invalidates the polled game query and never calls a global invalidateQueries().
  • One shared predicate, canEnterOrdersForPhase(game, phase, selectedPhase) in src/utils/orderEntry.ts: the game is active, the phase is active, and the selected phase is the game's current phase. It is used in:
    • GameMap: order options are disabled, and ignored when already cached, so a historical, processing or completed phase cannot start the order wizard.
    • OrdersScreen: delete, confirm and sandbox resolve require it (this replaces the old isActivePhase && !isGameFinished).
    • MapScreen: the confirm button requires it.

No remount wrappers or query-owning component splits. The small phase-states resource is still fetched while viewing history and simply not used for order entry. useOrderWizard is untouched.

This supersedes #1386 and #1395, which this PR does not modify.

Tests: GameDetailLayout.test.tsx covers a phase advance, a status-only change, the game query staying untouched, initial load, and game-to-game navigation. Existing GameMap, OrdersScreen and MapScreen tests gain cases for stale, processing and completed phases. There are also unit tests for the predicate. Existing active-phase fixtures now set currentPhaseId.

Screenshots: no layout, styling or copy changes. The only visible effect is that delete and confirm controls stay hidden on a phase that is no longer current, which is the same appearance as today's historical-phase view.

Checklist

  • This PR does one thing — no unrelated fixes, refactors, or drive-by cleanups bundled in
  • For PRs of any significant complexity: I ran /review-pr against this PR in Claude Code and addressed (or responded to) its findings
  • Tests cover the change
  • Screenshots embedded in the PR description for any visual changes (see CLAUDE.md): not applicable, no visual change

🤖 Generated with Claude Code

https://claude.ai/code/session_01EUiNKjR45DXgsqFDw3EPks


Generated by Claude Code

/game/<id>/phase-states/ and /game/<id>/options/ are stable URLs whose
contents change when the server resolves a phase. GameDetailLayout now
watches the polled game's currentPhaseId and status and, when either
changes for the same game, invalidates phase states, options, the phase
list, and the previous/current phase and order queries. Generated query
keys are unchanged.

A shared canEnterOrdersForPhase predicate gates order entry on the map,
delete and confirm on the orders screen, and confirm on the map screen,
so a phase that is historical, processing, completed or no longer
current cannot create, delete or confirm orders.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EUiNKjR45DXgsqFDw3EPks
@github-actions

Copy link
Copy Markdown
Contributor

Warning

WIP limit exceeded. There are now 7 open pull requests — the project target is 5 or fewer.

Please close or merge an existing PR before continuing with this one.

createMemoryRouter's navigate builds a fetch Request, which Node 24's
undici rejects when given jsdom's AbortSignal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EUiNKjR45DXgsqFDw3EPks
@johnpooch
johnpooch merged commit f4c8acb into main Sep 24, 2026
22 checks passed
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