Skip to content

fix(query-mutation-missing-invalidation): recognize Zustand reconciliation as valid state sync - #1788

Draft
skoshx wants to merge 3 commits into
mainfrom
cursor/triage-1786-b9f4
Draft

skoshx wants to merge 3 commits into
mainfrom
cursor/triage-1786-b9f4

Conversation

@skoshx

@skoshx skoshx commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #1786

The query-mutation-missing-invalidation rule now correctly recognizes when a mutation explicitly fetches fresh data and updates a Zustand store as valid state synchronization, eliminating a false positive.

Root Cause

The rule was designed to detect when TanStack Query mutations don't invalidate cached query data, which can lead to stale UI. However, it flagged mutations that synchronize state through alternative state management (Zustand) even when they explicitly fetch fresh data and update the relevant store.

The Fix

Extended the cache-update detection to recognize a Zustand reconciliation pattern:

  1. Zustand store detection: Uses existing resolveZustandStoreFactoryCall to identify Zustand stores
  2. setState call detection: Identifies calls to .setState() on Zustand stores
  3. Data freshness check: Verifies an await expression precedes the setState (indicating fresh data fetch)
  4. Argument validation: Ensures setState uses dynamic data (identifiers/calls), not hardcoded literals

This prevents false negatives by still flagging:

  • UI state updates that don't prove data freshness (e.g., setState({ isOpen: false }))
  • setState calls without a preceding data fetch
  • Unrelated store updates

Scope

Conservative and narrow: Only suppresses the warning when all conditions are met. The pattern must show clear evidence of explicit data reconciliation.

Example from the issue:

async function reconcileMembership() {
  const membership = await getMembership();  // Fresh data fetch
  useMembership.setState(membership);        // Update the relevant store
}

This is now correctly recognized as valid synchronization.

Testing

  • ✅ Added 4 new unit tests covering the reconciliation pattern and edge cases
  • ✅ Added fuzz regression corpus entry
  • ✅ All existing tests pass (35 tests for this rule)
  • ✅ Linting and typecheck pass
  • ✅ Verified on the reported reproduction case

Notes

Full corpus parity scan was not run due to baseline data unavailability in the cloud environment. The fix is low-risk because:

  1. It only adds suppression conditions (can only reduce false positives)
  2. Detection is highly specific (4 required conditions)
  3. Comprehensive unit tests cover edge cases
  4. All existing tests pass
Open in Web Open in Cursor 

cursoragent and others added 2 commits September 10, 2026 07:21
…ation as valid state sync

Recognize when a mutation explicitly fetches fresh data and updates a
Zustand store as valid state synchronization, similar to query cache
invalidation.

Detection is conservative - only treats setState as synchronization when:
1. The setState argument uses dynamic data (identifiers/calls, not literals)
2. An await expression precedes the setState in the same function
3. The store binding is a Zustand store (create/createStore result)

This avoids false negatives from unrelated UI state updates while
correctly handling the reported pattern of explicit data reconciliation.

Closes #1786

Co-authored-by: Skosh <skoshx@users.noreply.github.com>
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
@pkg-pr-new

pkg-pr-new Bot commented Sep 10, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/eslint-plugin-react-doctor@1788
npm i https://pkg.pr.new/oxlint-plugin-react-doctor@1788
npm i https://pkg.pr.new/react-doctor@1788

commit: 20c5182

@github-actions

github-actions Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Interactive terminal E2E

Terminal Control verified the built CLI at 20c5182 in a real PTY:

  • selected a project interactively and observed Scanning... before the three-second Git delay completed
  • waited for the clean result and exercised the compact report
  • opened copy context and the GitHub Actions confirmation, then cancelled safely

Download the edited MP4 and PNG evidence

Co-authored-by: Skosh <skoshx@users.noreply.github.com>
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.

query-mutation-missing-invalidation: explicit Zustand reconciliation still reports stale data

2 participants