Skip to content

fix: call ColumnCard hooks unconditionally, enforce lint in CI#116

Merged
aaronjmars merged 1 commit into
mainfrom
fix/hooks-order-and-ci-lint
Jul 20, 2026
Merged

fix: call ColumnCard hooks unconditionally, enforce lint in CI#116
aaronjmars merged 1 commit into
mainfrom
fix/hooks-order-and-ci-lint

Conversation

@aaronjmars

Copy link
Copy Markdown
Collaborator

What

npm run lint was reporting 26 errors and 7 warnings on main. ESLint was already configured — CI just never ran it, so the tree drifted. This gets it to zero and wires it into CI so it stays there.

The bug worth reviewing

ColumnCard returned its "Unknown column type" card at column-card.tsx:106, above ~10 useMemo/useRef/useEffect calls. A column's type resolves through the plugin registry, so type can flip between renders — which changes hook order and crashes the component. Moving the bail-out below the hooks clears all 14 rules-of-hooks errors at once. The hooks above already tolerate a missing type (paginated optional-chains; the refresh effect has its own guard).

Three refs were also assigned during render. That's unsafe under concurrent rendering — a render that never commits would still have written. Now synced in effects; the useRef seeds cover the first frame and both consumers only dereference asynchronously.

Suppressed, not fixed

Three set-state-in-effect reports are disabled with inline rationale, because a mechanical rewrite would change behavior:

  • sticky search-open — deriving searchOpen || searchActive would auto-close the row when the query is cleared mid-type, which is exactly what the existing comment rules out
  • / shortcut routed through the store — an external signal, no render-time value to derive from
  • snapshot fetch-on-open — properly removing the cascade means moving it behind Suspense

Happy to do the Suspense refactor separately if preferred.

Cosmetic

6 unescaped entities → HTML entities. Removed MODE_LABELS from producthunt/client.tsx — verified dead, every other plugin references its own.

Config

Added argsIgnorePattern: "^_" to no-unused-vars. The six plugin ConfigForm(_: ConfigFormProps<…>) params are deliberately unused and already say so with _ — a convention gap, not six bugs.

CI

New Lint & Test job (eslint --max-warnings=0 + vitest), parallel to Build so lint failures report without waiting on the production bundle. --max-warnings=0 holds the line now that the tree is clean. The build job id is unchanged in case any required check references it.

Verification

npm run lint clean · 279/279 tests pass · TypeScript + npm run build succeed. No behavior changes intended — the hook reordering is the only semantic change, and it strictly widens when hooks run.

ColumnCard returned its "Unknown column type" card before ~10 hooks. A
column's type resolves through the plugin registry and can flip between
renders, so that early return could change hook order and crash the
component. Move the bail-out below every hook; the hooks above already
tolerate a missing type (`paginated` optional-chains, the refresh effect
guards itself).

Three refs were also mutated during render, which is unsafe under
concurrent rendering — a render that never commits would still have
written. Sync them in effects instead; the useRef seeds cover the first
frame and both consumers only dereference asynchronously.

The remaining set-state-in-effect reports are suppressed with rationale
rather than restructured: sticky search-open cannot be derived without
auto-closing mid-type, and the other two sync from outside React.

Also fix 6 unescaped entities, drop the unused MODE_LABELS in the
producthunt client, and treat a leading underscore as deliberately-unused
so plugin ConfigForms can keep documenting the props contract they satisfy.

The tree was at 26 errors and 7 warnings because CI only ran `next build`
and never invoked the lint script that already existed. Add a Lint & Test
job running eslint --max-warnings=0 and vitest, split from Build so
failures report without waiting on the production bundle.
@aaronjmars
aaronjmars merged commit 147c148 into main Jul 20, 2026
2 checks passed
@aaronjmars
aaronjmars deleted the fix/hooks-order-and-ci-lint branch July 20, 2026 16:48
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.

1 participant