Hunt: hunt-false-positives over the 73-seed regression corpus + the
pinned 47-repo OSS sample, plus strict per-rule fuzz (500 iterations)
over every rule changed in the RB-COMP-FIX batch and the two new rules
— all fire under fuzz and pass the crash/slow/verdict oracles.
Fixes:
- exhaustive-deps: the effect-event dep message no longer fires on a
same-named useEffectEvent polyfill imported from a non-React package
or defined locally. The origin resolution that already guarded
rules-of-hooks and no-effect-event-in-deps is extracted into the
shared isNonReactEffectEventCallee util and applied to the dep check.
- no-direct-state-mutation: null-initialized state is no longer plain
React data when every observed setter call feeds it an opaque
instance (new X(), receiver.createGain()) — field writes there are
the instance's imperative API. Bare helper calls stay unclassified so
the wangeditor-class lost-update detection keeps firing.
- only-export-components: a default-exported unknown factory fed only
config objects/literals (defineFrontComponent({...})) is a library
definition counted as a plain non-component export, not an "unnamed
component"; known-HOC anonymous wrappers and curried HOCs keep their
reports.
Corpus: seed headers extended so the polyfill and disposed-resource
seeds also pin exhaustive-deps / no-direct-state-mutation; new
config-factory seed; the two no-array-index-as-key seeds trimmed to
their still-ground-truth shapes (split-output rows and same-item
composite keys were reclassified as true positives by the fn-hunt
sweep, so those sections contradicted the corpus contract). Hunt now
reports 0 regressions.
Fuzz: add the verdict-drop oracle — semantics-preserving source rewrites
(parenthesized/cast/non-null receivers, concise-arrow-to-block returns,
no-op prologues, optional-chain and computed-member spellings) applied to
firing programs; a rule that goes silent under one keys on incidental
token shape. Wired into fuzz-rule as an advisory finding kind, a strict
per-rule robustness suite over the audited liveness fixtures, a
registry-wide census script, and new regression-corpus entries.
Rules: add no-locale-format-in-render (locale/timezone-dependent
formatting during render in SSR-capable projects → hydration mismatch,
gated off client-only frameworks) and extend
prefer-use-sync-external-store to detect hand-rolled module-scope stores
(let + listener set + subscribe fn consumed via useState snapshot +
useEffect subscription).
Robustness sweep: shared is-no-op-statement / is-global-method-call /
executes-during-render utilities and cast-wrapper unwrapping across the
rule registry so detection survives the rewrites above; census is 0
drops across all fixture-covered rules.