Commit Graph

129 Commits

Author SHA1 Message Date
Aiden Bai 2b0f06ec70 perf: profile and optimize rule execution (#1663) 2026-08-20 22:05:20 -07:00
Aiden Bai bea01b8cf5 feat(r3f): add material rendering diagnostics (#1633) 2026-08-12 15:40:07 -07:00
Aiden Bai 8dfb013067 Add comprehensive Three.js and R3F diagnostics (#1629) 2026-08-11 15:40:53 -07:00
Aiden Bai 27a39dede7 fix(rules): recognize retained cleanup ownership (#1615)
* fix(rules): recognize retained cleanup ownership

* fix(types): normalize optional AST parents

* test: store imported corpus as source text fixtures
2026-08-08 21:50:44 -07:00
Aiden Bai 6a546c2a4c test(fuzz): pin exhaustive React Bench audit corpus (#1603)
* test(fuzz): pin exhaustive React Bench audit corpus

* fix(fuzz): normalize corpus paths

* test(fuzz): normalize corpus expectations

* fix(fuzz): skip TypeScript declarations
2026-08-07 17:38:28 -07:00
Aiden Bai d62caa575f fix(rule): harden effect cleanup regressions (#1596)
* fix(rule): harden effect cleanup regressions

* fix(fuzz): preserve cleanup-local scope
2026-08-06 17:43:18 -07:00
Skosh afd60dbe69 fix(effect-needs-cleanup): prove effect-owned cleanup (#1559)
* fix(effect-needs-cleanup): handle returned identifiers for addEventListener/addListener

Fixes #1558 - Part 1

- Allow returning identifiers bound to addEventListener/addListener results as valid cleanup
- Recognize calling such identifiers (e.g., ) as cleanup
- This fixes false positives for React Native's NetInfo.addEventListener and similar APIs

Remaining work: helper function cleanup and array collection cleanup

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

* docs: add changeset for addEventListener cleanup fix

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

* fix(effect-needs-cleanup): prove resource ownership

* fix(effect-needs-cleanup): harden ownership proofs

* fix(effect-needs-cleanup): isolate deferred ownership

* fix(effect-needs-cleanup): prove deferred timer ownership

* fix(effect-needs-cleanup): narrow invocation owners

* fix(effect-needs-cleanup): track helper collection mutations

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
Co-authored-by: Aiden Bai <aiden@million.dev>
2026-08-03 13:29:06 -07:00
Aiden Bai 49c5c1e837 fix: improve effect provenance diagnostics (#1452) 2026-07-25 16:43:28 -07:00
Aiden Bai 9b532015f0 perf(fuzz): reuse parsed rule fixtures (#1435) 2026-07-23 01:35:47 -07:00
Aiden Bai 8c4959bb74 fix(rules): harden parity diagnostics (#1419)
* fix(rules): harden parity diagnostics

* fix(evals): keep parity artifacts parseable

* fix(evals): support Windows harness tests

* fix(fuzz): parse CRLF corpus directives
2026-07-20 22:28:25 -07:00
Aiden Bai f5f13b877a feat(rules): add version-aware React Router diagnostics (#1411) 2026-07-20 13:43:35 -07:00
Aiden Bai 5b468f8a92 feat(rules): add React Three Fiber diagnostics (#1371) 2026-07-20 09:22:48 -07:00
Aiden Bai 0b0b5ac523 feat(rules): add deterministic UI, accessibility, and animation diagnostics (#1337)
* feat(rules): add 10 motion, accessibility, and design lint rules

Derived from a cross-resource design reference (every principle from the
design knowledge base), deduped against the full existing rule inventory.

Motion: extend no-transition-all to the Tailwind `transition-all` class
(was inline-only) and add no-tailwind-layout-transition for arbitrary
`transition-[<layout-prop>]`.

Accessibility: no-autoplay-without-muted, no-uninformative-aria-label,
no-target-blank-without-rel, and no-low-contrast-inline-style (computes the
real WCAG 2.1 ratio from co-located inline color + backgroundColor).

Design/Tailwind hygiene: no-redundant-display-class, prefer-truncate-shorthand,
no-full-viewport-width, and no-svg-currentcolor-with-fill-class.

All register via codegen (388 rules); 77 co-located tests pass; typecheck,
lint, and format clean.

* fix(rules): correct two false positives found in rule-validate

- no-low-contrast-inline-style: when the inline style has no `fontSize`,
  the text may be sized large via a class (`text-5xl`), so fall back to the
  lenient 3:1 large-text threshold instead of 4.5:1 to avoid flagging large
  text that only needs 3:1. Stricter 4.5:1 applies only when the size is a
  visible normal size.
- no-redundant-display-class: `<li>` defaults to `display: list-item`, not
  `block`, so `block` on an `<li>` is meaningful — removed `li` from the
  block-default set.

Adds regression tests for both.

* fix(rules): resolve Cursor Bugbot findings

- no-low-contrast-inline-style: use a solid `background` shorthand color as
  the background (was skipped entirely, missing low-contrast pairs); skip only
  gradients/images/ambiguous (both backgroundColor + background). Also treat a
  string `fontWeight: "700"` as bold for the large-text threshold.
- no-transition-all: match `transition-all` as a whole Tailwind token (segment
  after variant prefixes) so compound classes like `transition-all-custom` are
  not falsely flagged.
- no-svg-currentcolor-with-fill-class: exclude stroke-WIDTH utilities
  (`stroke-2`, `stroke-[1.5]`) — they set thickness, not color — so they no
  longer false-conflict with `stroke="currentColor"`.

Adds regression tests for each.

* feat(rules): add 3 Tailwind-canonicalization rules from ui.sh guidance

- no-deprecated-tailwind-class: flag Tailwind v4 renames (bg-gradient-* →
  bg-linear-*, flex-shrink-* → shrink-*, flex-grow-* → grow-*,
  overflow-ellipsis → text-ellipsis). Gated on a new `tailwind:4` capability.
- no-arbitrary-px-font-size: `text-[13px]` → rem so text scales with the
  user's root font size (px stays fine for border-*/outline-*).
- prefer-dvh-over-vh: `h-screen`/`min-h-screen`/`h-[100vh]` → dvh (tailwind:3.4).

Adds `tailwind:4` capability to @react-doctor/core and extracts a shared
`get-class-name-tokens` util (variant-aware token splitting), reused by
no-transition-all and no-svg-currentcolor-with-fill-class.

* fix(rules): adversarial-review false positives in the new design rules

- no-tailwind-layout-transition: match transition-[…] property names exactly
  (comma-split + set) so SVG `stroke-width` / `border-width` — which merely
  contain "width" — are no longer flagged as HTML layout thrash.
- no-full-viewport-width: drop `max-w-*` / `maxWidth` (a defensive cap, not the
  overflow footgun); keep `w-screen`/`w-[100vw]`/`width`/`minWidth`.
- prefer-dvh-over-vh: drop `max-h-*` / `maxHeight` (a valid height cap, e.g. a
  scrollable modal); keep `h-screen`/`min-h-screen`/`height`/`minHeight`.
- no-deprecated-tailwind-class: only rename `bg-gradient-to-*` → `bg-linear-to-*`
  (v4 radial/conic are `bg-radial`/`bg-conic`, not `bg-linear-radial`).

Adds regression tests for each false positive.

* fix(rules): resolve thermo-review false positives

- no-svg-currentcolor-with-fill-class: only treat UNPREFIXED `fill-*`/`stroke-*`
  color classes as conflicts; `hover:fill-blue-600` / `dark:fill-white` (state-
  gated, no static conflict with the base `fill="currentColor"`) are no longer
  flagged — a very common icon pattern.
- no-low-contrast-inline-style: reject 4-arg `rgb(0,0,0,0.5)` / slash-form alpha
  (was judged opaque), and bail when the style object contains a `{...spread}`
  that could override the colors. Tag `test-noise` to match sibling no-tiny-text.
- no-full-viewport-width: drop the redundant `category: "Architecture"` override
  (it's the design-bucket default).
- Extract `has-jsx-spread-attribute` util; use it in the two a11y rules.

Adds regression tests for the variant-prefixed svg classes, rgb-alpha, opaque
rgb, and the style-spread bail.

* refactor(rules): deslop the design/motion/a11y rule additions

Consolidate duplication surfaced by an adversarial deslop pass; no behavior
change (the same diagnostics fire for the same inputs):

- no-autoplay-without-muted: fold isStaticallyTrue/isStaticallyFalse into one
  tri-state resolveStaticBoolean, mirroring the existing parseJsxValue idiom
- no-svg-currentcolor-with-fill-class: collapse the duplicated fill/stroke
  branches into a single loop over the two paint attributes
- no-low-contrast-inline-style: hoist the repeated `properties` fallback
- no-uncontrolled-input: drop the local hasJsxSpreadAttribute copy in favor of
  the branch's new shared utils/has-jsx-spread-attribute, completing the extraction

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(rules): no-deprecated-tailwind-class stops flagging overflow-clip

`overflow-clip` is a current Tailwind utility for `overflow: clip` (v3.1+,
still present in v4) — it was never renamed to `text-clip`, which sets the
unrelated `text-overflow: clip`. The stray mapping produced an incorrect
"renamed in v4" suggestion (Cursor Bugbot). Only `overflow-ellipsis ->
text-ellipsis` is a real rename; keep that. Adds a regression test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(capabilities): require a confirmed Tailwind major for the tailwind:4 gate

`tailwind:4` gates no-deprecated-tailwind-class, which tells users a class was
renamed/removed in v4. The optimistic-on-null policy (assume latest for an
unparseable spec like `workspace:*`) is right for the suggestion rule behind
`tailwind:3.4`, but for a deprecation rule it surfaces confidently-wrong
"renamed in v4" warnings on a v3 project. Require a CONFIRMED parsed major >= 4
for tailwind:4 — favor a false negative over a false positive (Cursor Bugbot).
`tailwind:3.4` stays optimistic. Adds an unparseable-version regression test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(rules): resolve Bugbot/Devin review findings on design/a11y rules

- no-full-viewport-width: match variant-prefixed `md:w-screen` / `lg:min-w-screen`, mirroring the sibling `prefer-dvh-over-vh` regex (overflow happens at every breakpoint).
- no-target-blank-without-rel: resolve `rel={'noopener'}` expression-container literals instead of treating them as dynamic, so reverse-tabnabbing isn't silently missed; share one literal resolver with the `target` check.
- Extract the bare `16` root-font-size divisor into `ROOT_FONT_SIZE_PX` per the magic-number convention.

* fix(rules): no-uninformative-aria-label resolves braced string literals

Extracts no-target-blank-without-rel's inline getStringLiteralAttributeValue
into a shared util and uses it in no-uninformative-aria-label, so a static
braced literal like aria-label={'icon'} is judged instead of silently skipped
(getJsxPropStringValue only handles plain string literals). Adds regression
tests for the braced uninformative and braced descriptive cases.

Addresses Bugbot review on #850.

* test(rules): add liveness fixtures after rebase

* fix(rules): address automated review findings

* fix(rules): handle leading-dot stroke widths

* fix(rules): skip dynamic background overrides

* fix(rules): address target blank and transition reviews

* fix(rules): skip svg layout transitions

* fix(rules): preserve font line height suggestion

* fix(rules): match complete transition utilities

* fix(rules): share layout transition properties

* fix(rules): bound deprecated utility prefixes

* fix(rules): clear dynamically overridden colors

* fix(rules): tighten style and svg precision

* fix(rules): preserve competing display utilities

* fix(rules): preserve animation property scopes

* feat(rules): expand deterministic design checks

* feat(rules): add structural design diagnostics

* feat(rules): complete source-auditable design checks

* fix(rules): skip unresolved input types

* fix(rules): tighten layout and boundary detection

* fix(rules): close motion and padding gaps

* fix(rules): tighten surface and line-height proofs

* fix(rules): evaluate opaque hsl contrast

* fix(rules): honor effective static values

* fix(rules): honor final inline style declarations

* fix(rules): respect variants and share surface checks

* fix(rules): traverse fragments and preserve variant scope

* feat(rules): deepen UI quality diagnostics

* feat(rules): add deterministic animation diagnostics

* fix(rules): retain in-house accessibility checks

* feat(rules): expand deterministic UI diagnostics

* feat(rules): detect generated interface patterns

* fix(rules): respect dynamic style overrides

* feat(rules): expand deterministic design diagnostics

* fix(rules): close design precision gaps

* feat(rules): expand deterministic design and accessibility checks

* feat(rules): detect unsafe Motion API usage

* test(fuzz): remove duplicate module snippets

* feat(cli): add focused design command

* fix(design): include the complete rule bucket

* fix(core): align opt-in rule gates

* feat(rules): expand deterministic motion and interaction checks

* feat(rules): harden deterministic design diagnostics

* fix(rules): harden design expansion diagnostics

* fix(rules): apply large-corpus precision review

* fix(rules): suppress large-corpus accessibility noise

* fix(core): detect compiler in rstack configs

* fix(a11y): avoid responsive navigation false positives

* fix(rules): reduce design corpus false positives

* fix(rules): restore will-change build after rebase

* fix(rules): harden all-rules corpus precision

---------

Co-authored-by: Rayhan Noufal Arayilakath <me@rayhanadev.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 01:09:01 -07:00
Aiden Bai cd9ca68faa NEW_RULES: Add rule analysis foundation and 56 rules (#1402)
* NEW_RULES: Reapply rule analysis foundation

Reapply the complete reviewed NEW_RULES stack on top of current main after the rollback.

* fix(rules): harden new diagnostics against false positives

* fix(rules): preserve dynamic context providers

* fix(core): resolve styled-components workspace versions

* fix(rules): harden new diagnostics after deep audit
2026-07-20 00:54:55 -07:00
Aiden Bai 6fcd9c9576 feat(plugin): detect eager Zustand get calls (#1407)
* feat(plugin): detect eager Zustand get calls

* fix(rule): cover eager async Zustand reads

* fix(rule): model Zustand async suspension paths

* fix(rule): follow eager Zustand helper calls
2026-07-19 23:51:17 -07:00
Aiden Bai 7eca0eebf9 feat(rule): detect whole Zustand store subscriptions (#1398)
* feat(plugin): detect whole Zustand subscriptions

* fix(rule): cover traditional Zustand stores

* fix(rule): detect imported Zustand store creators
2026-07-19 23:47:57 -07:00
Aiden Bai 8e5ae45dd3 feat(rules): detect unstable Zustand selector results (#1395)
* feat(rules): detect unstable Zustand selector results

* fix(rules): tighten Zustand selector provenance

* fix(rules): gate fresh Zustand selectors to v5

* fix(rules): harden Zustand selector gating

* fix(rule): respect Zustand v5 equality APIs

* fix(rule): harden Zustand selector analysis

* fix(rule): prove Zustand selector collection shapes

* test(rule): cover split curried Zustand stores

* fix(rule): classify Object collection helpers
2026-07-19 23:44:55 -07:00
Aiden Bai 61bf03eedc feat(rules): add MobX diagnostics foundation (#1405) 2026-07-19 21:30:10 -07:00
Aiden Bai 5774353907 feat(rules): detect Valtio snapshot reads in callbacks (#1397)
* feat(rules): detect Valtio snapshot reads in callbacks

* fix(rules): gate Valtio callback checks by dependency

* fix(rules): follow deferred Valtio callback aliases

* fix(rules): require supported Valtio version
2026-07-19 07:01:38 -07:00
Aiden Bai a4eaeddefe feat(rules): detect Valtio proxy reads during render (#1396) 2026-07-19 06:44:56 -07:00
Aiden Bai 3598138c7b Scale eval corpus and tighten diagnostics (#1403)
* scale eval corpus and tighten diagnostics

* fix review and Windows eval failures
2026-07-19 04:13:13 -07:00
Aiden Bai 88114a2332 Revert "NEW_RULES: Add rule analysis foundation" (#1401)
Reverts #1338 in full.
2026-07-19 03:16:55 -07:00
Aiden Bai 3018538b7c NEW_RULES: Add rule analysis foundation (#1338)
Replace aggregate PR #1000 with the reviewed NEW_RULES stack, including workspace capability aggregation and stable performance regression coverage.
2026-07-19 02:56:31 -07:00
Aiden Bai a667b45907 fix: preserve external subscription hook provenance (#1323)
* fix(rule): preserve external hook result provenance

* fix(rule): harden external hook result provenance

* fix(rule): address external hook alias edge cases

* fix(effects): recognize external visibility signals

* fix: align local external store provenance

* fix: preserve external state provenance boundaries

* fix: gate local external store provenance
2026-07-18 03:15:59 -07:00
Aiden Bai b8529619bd fix(rule): preserve external location invalidation state (#1311)
* test(rule): capture external location invalidation

* fix(rule): preserve external location invalidators

* fix(rule): prove external location invalidation

* fix(rule): require definite listener removal

* fix(rule): unwrap location listener options

* fix(rule): avoid caching cyclic mutation misses

* fix(rule): preserve listeners with unknown capture

* fix(rule): preserve listeners across suspension

* fix(rule): harden deferred invalidation provenance

* fix: batch effect location invalidation
2026-07-18 03:06:57 -07:00
Aiden Bai fe241a9723 fix(no-effect-chain): preserve stable callback precision (#1322)
* fix(no-effect-chain): follow stable local callbacks

* fix(no-effect-chain): harden stable callback analysis

* fix(no-effect-chain): preserve returned callback chains

* fix(no-effect-chain): unwrap optional cleanup returns

* fix(no-effect-chain): follow concise cleanup returns

* fix(no-effect-chain): preserve stable callback precision

* test(no-effect-chain): avoid wall-clock CI gate

* fix: reject defaulted global namespace aliases
2026-07-18 02:55:07 -07:00
Aiden Bai 82c4a125c5 fix(rule): match legacy media query listener cleanup (#1327) 2026-07-18 02:36:55 -07:00
Aiden Bai 26b4a0ceb1 fix(no-effect-chain): recognize lazy DOM ref Maps (#1325)
* test(no-effect-chain): capture lazy DOM ref maps

* fix(no-effect-chain): prove lazy DOM ref maps
2026-07-18 02:32:49 -07:00
Aiden Bai a2f9bf42c0 fix(a11y): compose global ARIA role properties (#1329) 2026-07-18 02:31:57 -07:00
Aiden Bai d9700556d1 fix(rules): guideline audit — compiler gates, capability fixes, message honesty across 15 rules (#1369)
Co-authored-by: Aiden Bai <aiden.bai05@gmail.com>
2026-07-18 01:03:13 -07:00
Aiden Bai 4f3848b001 fix(rules): resolve state and effect aliases semantically (#1358)
* fix(rules): resolve state effect aliases semantically

* fix(rules): tighten setter alias identity
2026-07-17 09:03:50 -07:00
Aiden Bai 21043e024e feat: flag React 19-only ref cleanups on React 18 (#1356)
* feat: flag React 19-only ref cleanups on React 18

* fix: skip unreachable ref callback branches

* fix: resolve declared ref callbacks
2026-07-17 07:24:46 -07:00
Aiden Bai bd3655c13d fix(rendering-hydration-no-flicker): detect immediate viewport adoption (#1328)
* fix(rendering-hydration-no-flicker): detect viewport adoption

* fix(rendering-hydration-no-flicker): handle block returns
2026-07-17 06:11:31 -07:00
Aiden Bai 2ba83c3201 fix(rules): recognize callback ref convergence (#1335)
* fix(rules): recognize callback ref convergence

* fix(rules): tighten did-update transition guards

* fix(rules): invalidate reassigned callback refs

* fix(rules): reject disjunctive convergence guards

* fix(rules): follow logical callback refs

* fix(rules): respect logical ref selection

* fix: make did-update guards branch-aware

* fix(rules): resolve destructured previous props

* fix(rules): ignore static ref handler names

* fix(rules): handle private callback refs

* fix(rules): distinguish private member identities

* fix(rules): cover callback ref guard edges

* fix(rules): preserve branch-sensitive convergence

* fix(rules): invalidate overwritten callback refs

* fix(rules): track callback ref writes in IIFEs
2026-07-17 06:10:47 -07:00
Aiden Bai b51022f8e0 fix(rules): detect API keys through storage helpers (#1334)
* fix(rules): detect API keys through storage helpers

* fix(rules): follow aliased storage helpers

* fix(rules): cover storage fallback sinks

* fix(rules): cover wrapped storage helpers

* fix(rules): preserve storage parameter identity

* refactor(rules): reuse function return walker

* fix(rules): unwrap typed serialized parameters

* fix(rules): handle this parameters in storage helpers

* test(fuzz): exercise render argument rules
2026-07-17 05:51:53 -07:00
Skosh b3920938da fix: don't treat TypeScript source files as browser artifacts (#1320)
* fix: don't treat TypeScript source files as browser artifacts (#1318)

Fixes a false positive where artifact-env-leak fired on Prisma 7
generated TypeScript client files. TypeScript source files cannot be
browser artifacts because browsers don't execute TypeScript directly.

The fix exempts .ts/.tsx files from browser artifact classification,
even if they look minified (have long lines from inlined data).

Regression tests added to prevent recurrence.

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

* chore: format is-browser-artifact-path.ts

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

* fix(security): ignore env examples in comments

* fix(artifact-env-leak): preserve scan fast path

* fix(artifact-env-leak): avoid comment-analysis regressions

* fix(artifact-env-leak): preserve Unicode line terminators

* fix(artifact-env-leak): harden comment masking

* fix(artifact-env-leak): avoid HTML regex ambiguity

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
Co-authored-by: Aiden Bai <aiden@million.dev>
Co-authored-by: Aiden Bai <aiden.bai05@gmail.com>
2026-07-17 01:43:58 -07:00
Skosh 6c5c91b68c fix: server-after-nonblocking false positive for calls wrapped in after() (#1317)
* fix(server-after-nonblocking): skip diagnostics for calls already wrapped in after()

Fixes #1313

The server-after-nonblocking rule was flagging console.* and analytics
calls that were already wrapped in after() from next/server, which is
the exact fix the rule prescribes.

The rule now tracks imports of after/unstable_after from next/server
and traverses the AST parent chain to detect when a deferrable side
effect is inside a function passed as an argument to after().

Changes:
- Track after imports from next/server in ImportDeclaration visitor
- Add isInsideAfterCallback helper to check if a call is inside an
  after() callback by walking up the parent chain
- Skip reporting when the call is already inside after()
- Add comprehensive unit tests for the fix including aliased imports,
  unstable_after, and edge cases

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

* chore: add changeset for server-after-nonblocking fix

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

* chore: format files

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

* fix(server-after-nonblocking): prove next after callbacks

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
Co-authored-by: Aiden Bai <aiden@million.dev>
Co-authored-by: Aiden Bai <aiden.bai05@gmail.com>
2026-07-17 01:33:27 -07:00
Skosh c8a29185a0 fix: skip supabase-client-owned-authz-field on 'use server' files (#1316)
* fix: skip supabase-client-owned-authz-field on 'use server' files

Detect files with top-level 'use server' directives and treat them as
server-only code. The supabase-client-owned-authz-field rule's threat
model (browser forging authz fields) does not apply to server actions.

Adds hasUseServerDirectiveInContent utility that checks file content
for 'use server' directives at the module level.

Fixes #1312

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

* chore: add changeset for use server directive fix

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

* chore: format code

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

* fix(security): parse use server directives precisely

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
Co-authored-by: Aiden Bai <aiden@million.dev>
2026-07-17 01:23:06 -07:00
Aiden Bai 1a30f2caac fix(security): prove safe KaTeX HTML provenance (#1324) 2026-07-16 01:22:32 -07:00
Skosh 3e6dcfc217 fix: control-has-associated-label recognizes component-wrapped labels with htmlFor (#1315)
* fix(control-has-associated-label): recognize component-wrapped labels with htmlFor

Fixes #1314

The rule now recognizes form controls associated through component-wrapped
labels like shadcn/ui's <Label htmlFor> (Radix LabelPrimitive.Root), not just
native <label> elements.

Previously, the rule only collected htmlFor associations from native <label>
elements. Now it collects them from ANY element (native or component) that has
both an htmlFor attribute and accessible text content. This handles:
- <Label htmlFor="id">Text</Label> (shadcn/Radix pattern)
- <FormLabel htmlFor="id">Text</FormLabel>
- <InputLabel htmlFor="id">Text</InputLabel>
- Any other capitalized component carrying htmlFor

The fix is intentionally broad: a component with htmlFor + text is a strong
association signal even when the rendered tag can't be resolved statically.

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

* chore: add changeset for #1314 fix

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

* fix(rule): preserve label association precision

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Skosh <skoshx@users.noreply.github.com>
Co-authored-by: Aiden Bai <aiden@million.dev>
2026-07-15 05:18:39 -07:00
Aiden Bai 64ae10dce6 test(no-initialize-state): preserve async gating provenance (#1310)
* test(no-initialize-state): preserve async gating provenance

* test(no-initialize-state): fuzz async gating boundaries
2026-07-15 04:10:35 -07:00
Aiden Bai f59ec540c7 fix(rule): preserve createRef stored in state (#1309)
* chore: start stable createRef state fix

* fix(rule): preserve createRef stored in state

* fix(rule): handle named lazy ref initializers
2026-07-15 03:20:55 -07:00
Aiden Bai 174955c255 fix(rule): allow proven one-shot RTL createRef components (#1303)
* test(no-create-ref): cover one-shot RTL mounts

* fix(no-create-ref): prove one-shot RTL mounts

* chore: add one-shot RTL mount changeset

* fix(rule): harden one-shot RTL proof

* fix(rule): accept transparent one-shot render wrappers
2026-07-15 02:31:31 -07:00
Aiden Bai b2f3c9c463 fix(effect-needs-cleanup): follow ref callback chains (#1308) 2026-07-15 01:39:41 -07:00
Aiden Bai b76aef7163 fix(no-scale-from-zero): require motion component provenance (#1290)
* test(no-scale-from-zero): reproduce ordinary initial prop false positive

* fix(no-scale-from-zero): require motion provenance

* test(no-scale-from-zero): use genuine motion fixture

* fix(no-scale-from-zero): exclude animation-only mini entries

Restrict component provenance to Motion entrypoints that actually export JSX tag components.

* fix(no-scale-from-zero): preserve intrinsic lowercase tags

* fix(no-scale-from-zero): reuse authoritative attribute helper
2026-07-15 00:54:42 -07:00
Aiden Bai cf7ada5839 fix(rule): detect cleanup leaks in invoked ref callbacks (#1269)
* test(rule): reproduce ref callback cleanup FN

* fix(rule): analyze effect-invoked ref callbacks

* fix(effect-needs-cleanup): honor effect ref overwrites

* fix(effect-needs-cleanup): follow returned disposer bindings

* fix(effect-needs-cleanup): enforce disposer ownership paths

* fix(effect-needs-cleanup): require returned disposer ownership

* fix(effect-needs-cleanup): follow effect cleanup bindings

* fix(effect-needs-cleanup): retain ref socket ownership

* fix(effect-needs-cleanup): follow wrapped cleanup ownership

* fix(effect-needs-cleanup): prove ref overwrite dominance
2026-07-15 00:15:00 -07:00
Aiden Bai 5f3ba37628 fix(a11y): scope local test harness diagnostics (#1304)
* test(a11y): reproduce local harness diagnostics

* fix(a11y): ignore proven local test scaffolds

* fix(a11y): tighten local test scaffold proof

* fix(a11y): preserve direct provider diagnostics

* fix(a11y): handle tagged test tables

* fix(a11y): preserve direct children diagnostics
2026-07-15 00:14:54 -07:00
Aiden Bai 1b86dae52c fix(prefer-module-scope-static-value): follow nested mutations (#1306)
* test(prefer-module-scope-static-value): reproduce nested mutation

* fix(prefer-module-scope-static-value): follow nested mutations

* fix(prefer-module-scope-static-value): unwrap mutator callees
2026-07-14 23:50:23 -07:00
Aiden Bai 544356cb0e fix(prefer-use-effect-event): respect mixed helper execution (#1291)
* test(prefer-use-effect-event): cover mixed helper execution

* fix(prefer-use-effect-event): respect mixed helper execution

* fix(prefer-use-effect-event): resolve dependency reads by symbol

Prevent shadowed callback names from satisfying the deferred-use proof for an unrelated dependency.

* fix(prefer-use-effect-event): resolve nested declarations
2026-07-14 23:49:05 -07:00
Aiden Bai c7f61cd4f5 fix(no-effect-chain): preserve committed DOM synchronization (#1296)
* test(no-effect-chain): cover committed DOM synchronization

* fix(no-effect-chain): preserve committed DOM sync

* fix(no-effect-chain): require DOM receiver provenance

Keep generic method calls and mixed local-state updates reportable while preserving proven committed DOM synchronization.

* fix(no-effect-chain): require DOM evidence for ref methods

* fix(no-effect-chain): preserve proven host ref synchronization

* fix(no-effect-chain): allow read-only DOM ref map access

* fix(no-effect-chain): resolve defaulted ref parameters
2026-07-14 23:32:58 -07:00