Conversation
id ?? React.useId() short-circuits, so useId only ran when no id prop was supplied — a hook called conditionally between renders, which violates react-hooks/rules-of-hooks and can hand one hook's state to another. Call useId unconditionally and choose the id after. Reproduces the exact diff already reviewed and verified in #109 (448->446 ESLint problems, react-hooks/rules-of-hooks 2->0, tsc clean on both files) rebased onto current main, since that PR went stale against a moved base. Superseding #109 with this branch. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011XdWmqAAcXnyBTQ6PVBhJb
|
CI status on this PR's head (
This PR's own description already measured the baseline: 222 lint errors on No fix ported here since none of these three failures are in code this PR touches or breaks, and I don't have a known existing fix to port for the FilterBar ref access, the prompt-books eslint config, or the claude-review action error. I don't have workflow re-run access from here, so I can't retry the flake-shaped Generated by Claude Code |
|
Triage correction: this PR is not the cause of its own red checks. An estate audit had this listed as REBASE. Looking at the actual CI logs, that's the wrong call — the fix is sound and the failures are pre-existing, repo-wide lint debt. Evidence from run
The gate lints the entire monorepo, so any PR against this repo goes red regardless of its content. Rebasing would not turn a single check green. What actually unblocks it — one of:
I'm not force-merging past a red gate on a repo I don't own the quality policy for. Option 1 is the cheap fix and I'm happy to do it on your word. 🤖 Generated with Claude Code |
|
Agreed — that matches what I found and posted here on 2026-09-07 (same two files, same pre-existing-debt conclusion). Option 1 is the right fix and it's precedented in this repo already: Generated by Claude Code |
Summary
id ?? React.useId()short-circuits, souseIdonly ran when noidprop was supplied. Rendering the same component once with anidand once without changes the number of hooks called between renders — the invariant React uses to match stored state to hook positions (react-hooks/rules-of-hooks).Why a new PR instead of updating #109
#109 (same fix, same author) went stale: opened 2026-08-20 against a base from before #108 merged, currently
unstable/needs rebase, no activity since 2026-08-25. The bug is still live on currentmain(confirmed by readingapps/web/components/ui/input.tsx:71andapps/web/components/ui/textarea.tsx:67at HEADfc1d1c0before making this change) and the fix has already been reviewed there with a measured before/after:react-hooks/rules-of-hooks: 2 → 0.tsc --noEmit: clean on both files. This branch reproduces that exact diff rebased onto currentmain, sincepnpm installwas not run in this environment to re-measure the lint delta — the diff is byte-for-byte what #109 already verified, just against a current base.Changes
apps/web/components/ui/input.tsx— calluseIdunconditionally, choose afterapps/web/components/ui/textarea.tsx— sameNo canon content touched; not a design/visual decision, so
web-release-gatedoes not apply (matches #109's own scope note).Closing #109 as superseded by this branch.
🤖 Generated with Claude Code
https://claude.ai/code/session_011XdWmqAAcXnyBTQ6PVBhJb
Generated by Claude Code