Closes#221 (adversarial-reviewer#18 MUST-FIX gate for #91 phase b).
Param-keyed success state in SearchScreen + MediaBrowseScreen: refreshing derived when visible results no longer match current query/kind/page; visible cue (spinner + grid dim), all mutation surfaces disabled (per-card AddToMenu, select mode, selection bar, Add All, Save As Smart Collection); card navigation stays live.
addAll completion now discards resolutions whose snapshotted query is no longer current (was: only mount check — could open a bulk-add dialog for a previous query's full result set).
3 new deferred-promise race tests; full web suite 480 green.
Closes #221 (adversarial-reviewer#18 MUST-FIX gate for #91 phase b).
- Param-keyed success state in SearchScreen + MediaBrowseScreen: `refreshing` derived when visible results no longer match current query/kind/page; visible cue (spinner + grid dim), all mutation surfaces disabled (per-card AddToMenu, select mode, selection bar, Add All, Save As Smart Collection); card navigation stays live.
- `addAll` completion now discards resolutions whose snapshotted query is no longer current (was: only mount check — could open a bulk-add dialog for a previous query's full result set).
- 3 new deferred-promise race tests; full web suite 480 green.
- docs: spa-conventions §3a refreshing/gating pattern + §8 temporal-semantics review checklist (adversarial-reviewer#18 process finding); blazor-route-parity search/media verdict notes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Search and Media browse keep the previous successful result set rendered
during a refetch (query on Search; kind/query/page on Media browse) with no
gating, so per-card Add-to, Select/select-mode, the selection action bar, Add
all, and Save-as-smart-collection stayed live over stale, about-to-be-replaced
items. Worst path: SearchScreen.addAll only checked activeRef, so a late
GET /api/search/all-items could open a bulk-add dialog scoped to the previous
query's entire result set.
Key the success state to the request params that produced it and derive a
`refreshing` flag; while refreshing, keep cards visible but disable every
mutation surface, show a "Refreshing…" cue, and dim the grid. Card navigation
stays live. Bind addAll's completion to its query via lastQueryRef so a stale
all-items result is discarded. Same pattern applied to both screens.
Docs: spa-conventions §3a (refreshing/gating pattern) + §8 (temporal-semantics
review checklist); blazor-route-parity search/media-browse verdicts.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Three PR #222 adversarial-review findings fixed:
1. SearchScreen's `refreshing` derivation compared the last success `state.query`
against the current query even when the query was cleared to empty — `load()`
early-returns on a blank query, so `state` never updates and the "Refreshing…"
cue got stuck forever over the empty-query card. Gate on `hasQuery`.
2. `MediaPosterCard` falls back to `onOpen` whenever `onToggleSelect` is
undefined, so `selectMode && refreshing` (onToggleSelect withheld but onOpen
still derived from `!canSelect`) made a mid-select click navigate away
instead of no-op'ing. Both screens now withhold `onOpen` for the whole of
select mode, not just the "live" part of it.
3. The Select/Done toggle was `disabled={refreshing}`, which also blocked
*exiting* select mode — but exiting only clears selection, it isn't a
mutation against the stale result set. Disable only when entering
(`refreshing && !selectMode`).
Also corrected the "can never get stuck" over-claim in docs/spa-conventions.md
§3a: the param-keyed refreshing derivation is only self-correcting when every
param value actually triggers a fetch; params that suppress fetching (like an
empty search query) must be excluded from the comparison or the whole flag
gated on the same condition.
Tests added: query-cleared-to-empty shows no refreshing cue (both screens'
existing 3 race tests still green); select-mode+refreshing card click neither
selects nor navigates; select toggle disabled only while entering, not exiting.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #221 (adversarial-reviewer#18 MUST-FIX gate for #91 phase b).
refreshingderived when visible results no longer match current query/kind/page; visible cue (spinner + grid dim), all mutation surfaces disabled (per-card AddToMenu, select mode, selection bar, Add All, Save As Smart Collection); card navigation stays live.addAllcompletion now discards resolutions whose snapshotted query is no longer current (was: only mount check — could open a bulk-add dialog for a previous query's full result set).🤖 Generated with Claude Code