fix(rule): preserve lifecycle synchronization semantics - #1579
Merged
Conversation
commit: |
Contributor
Interactive terminal E2ERecorded from the built CLI at |
Contributor
|
React Doctor found no new issues. 🎉 Reviewed by React Doctor for commit |
Contributor
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit db0807e. Configure here.
This was referenced Aug 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Why
React Bench PR #488 excluded six React Doctor rules after 193 of 198 adjudicated occurrences proved to be false positives. The remaining detector gaps still reported valid controlled-state fallbacks, owned-resource transitions, and prop-originated lifecycle synchronization; five genuine reset-state findings must remain reportable.
Before, 54 confirmed false-positive occurrences still reported. After, all 193 confirmed false positives are silent and the five named true positives still report at their exact locations.
What changed
Eval results
The self-contained React Bench PR #488 runner processed 166 full-source examples and 198 diagnostic occurrences with zero parse failures. It matched all intended outcomes: 193 confirmed false positives are silent and only the five required true-positive suffixes report.
Exact-SHA parity compared da0647e with 1b8c62b across all 2,000 pinned projects: 2,000 compared, zero skipped, +0 additions, -24 removals, and 10,364 unchanged diagnostics. The removals are 19 no-pass-data-to-parent, four no-prop-callback-in-effect, and one no-reset-all-state-on-prop-change finding; all 24 identities match the source-audited false-positive set.
Paired sequential performance found zero project regressions. Candidate aggregate time was 539,632.191 ms versus 541,731.395 ms for base (0.996x); median project ratio was 0.994 and p95 was 1.113.
The exact-head full-rule shadow completed 2,000/2,000 with zero failures. Projecting its reports onto the five-rule impact scope matched the scoped candidate exactly: +0/-0 with all 10,364 diagnostics unchanged and zero skipped projects.
Local RDE could not start because the sibling eval environment is missing AXIOM_DATASET and AXIOM_TOKEN; the complete Daytona evidence above used the copied DAYTONA_API_KEY.
Test plan
Note
Medium Risk
Broad changes to static-analysis heuristics across six related rules could miss edge-case violations or over-suppress, though extensive regression and fuzz corpus coverage mitigates that.
Overview
React Doctor / ESLint plugin: several state-and-effects rules get smarter provenance and lifecycle analysis so React Bench–style patterns stop false-alarming without weakening real findings.
exhaustive-depsnow treats classic controlled/uncontrolled?? []selections as stable when the uncontrolled branch is provably non-nullish and the controlled prop type excludes null (including globalArray/ReadonlyArray), while still reporting reachable fresh fallbacks and imported types that shadowArray.no-reset-all-state-on-prop-changeskips “reset all state on prop change” when the same effect synchronously invalidates or releases owned resources (abort, ref epoch bumps, collection clears, memoized cleanup helpers, etc.) via newhasSynchronousResourceLifecycleTransition.Parent-sync rules (
no-pass-data-to-parent,no-pass-live-state-to-parent,no-prop-callback-in-effect) allow arguments that only echo props through transparent paths (deep-compare memoizers,useMemo/JSONtransforms, ref-stabilized values) and require equivalent local state writes before flagging lifecycle prop callbacks; memoizer-named custom hooks that actually calluseState/useReducerstill count as child-owned state.Fuzz harness corpus directives can list multiple comma-separated rules; new regression/true-positive fixtures and a large
react-bench-pr-488regression suite lock behavior. Patch changeset for bothoxlint-plugin-react-doctorandeslint-plugin-react-doctor.Reviewed by Cursor Bugbot for commit 1b8c62b. Bugbot is set up for automated code reviews on this repo. Configure here.