Skip to content

fix(codemod): report retained hooks before component output - #2654

Merged
domgan-oai merged 5 commits into
octanejs:mainfrom
openai-oss-forks:codex/codemod-retained-hooks-local-output
Nov 14, 2026
Merged

domgan-oai merged 5 commits into
octanejs:mainfrom
openai-oss-forks:codex/codemod-retained-hooks-local-output

Conversation

@domgan-oai

@domgan-oai domgan-oai commented Nov 14, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Extend the retained React hook check from #2462 to native setup that returns another component or a fragment, and to calls after ordinary state setup. An unchanged local hook still executes under the enclosing renderer before the returned child runs.

In production, a small React caller rendered its label normally. The same caller compiled as clean Strong and then threw in the unchanged React useState under Octane SSR. The error now names the retained import. The existing path for generating a native external-store hook is unchanged for executable declarations.

Validation

  • pnpm format:check
  • pnpm typecheck
  • pnpm test
  • All 1,395 codemod and CLI tests passed. New tests reproduced the gap before the fix in both project type modes. Review regressions cover global undefined, signed numeric literals, a shadowed import, and an operand that calls user code.
  • Codemod package typecheck, targeted format, changeset validation, pnpm sync, and git diff --check.
  • Production React and Octane SSR comparison. Independent review exercised 21 caller forms with and without project types.
  • Performance review is inapplicable. This changes migration diagnostics only.
  • Concision review. Reuses existing local hook resolution, lexical argument checks, and native output ownership. No separate module or child-component resolver.

Risk / follow-ups

The diagnostic covers reachable setup. Earlier state initialization can still fail for particular inputs, and arbitrary control flow or lazy initializers remain outside the new check. The exact 7,902-file recipe-free replay on the signed revision, including the review fixes for named wrappers and co-declared state, reported 1,323 clean Strong files (16.74%), down from 1,361. The new errors identify retained React calls in 38 previously clean rows. Compiler Strong and Compat totals are unchanged.

Provenance

  • An agent produced this diff (agent-authored)

Codex task · host com-79386


Autofix with [code]smith
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.


Note

Low Risk
Migration-only diagnostic tightening in the codemod; no runtime compiler changes, though more files may fail Strong verification.

Overview
Extends the retained local hook diagnostic so codemod flags unchanged hooks (e.g. useLabel still calling React useState) when they run in component setup before the return value is a child component, fragment, or intrinsic—not only when setup ends with a lowercase native element and literal/useRef prefixes.

nativeSetupHook now treats prior ordinary useState declarations (safe literals, props, etc.) as valid setup, recognizes memo/forwardRef callers, and applies a separate diagnostic path when originalReact is enabled. transform.ts passes originalReact() into that checker; a changeset records a patch bump for @octanejs/codemod.

Adds a parameterized project test suite (21+ TSX shapes) asserting the expected error on safe callers and no erroneous rewrites.

Reviewed by Cursor Bugbot for commit fc54dde. Bugbot is set up for automated code reviews on this repo. Configure here.

@domgan-oai
domgan-oai marked this pull request as ready for review November 14, 2026 03:19
@github-actions github-actions Bot added agent-authored Diff or issue body substantially produced by an AI agent fix PR: bug fix labels Nov 14, 2026

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

@github-actions

github-actions Bot commented Nov 14, 2026 •

Copy link
Copy Markdown
Contributor

Benchmark report

🟢 No byte growth, no added work, and no timing changes beyond ±3%.

Compares 3c31a249a, the merge commit's first parent with 7e65adaee on the same runner. Any increase in a js-framework work counter fails this check; byte changes are a report. Wall time is a report: base and head samples alternate in one browser, and an operation is called slower or faster only when the 95% confidence interval of its ratio excludes ±3%. Workflow run

js-framework: 1k/10k row operations

target operation base ms head ms head/base 95% CI
octane-tsrx select_lots 0.005 0.005 −6.3% −8.3% … −5.7% 🟢 faster
All 20 timed operations (19 without a verdict)
target operation base ms head ms head/base 95% CI
octane-tsrx run 2.600 2.533 −0.0% −4.0% … +0.0% ⚪ within noise
octane-tsrx replace 6.908 7.017 −2.9% −12.7% … +2.9% ⚪ within noise
octane-tsrx add 2.292 2.092 −4.3% −9.1% … +0.0% ⚪ within noise
octane-tsrx update 0.084 0.085 +1.8% −1.0% … +2.6% ⚪ within noise
octane-tsrx select 0.005 0.005 +0.5% −0.5% … +4.7% ⚪ within noise
octane-tsrx swap 0.017 0.017 +2.2% +1.1% … +5.0% ⚪ within noise
octane-tsrx remove 0.014 0.015 +5.4% +1.6% … +9.3% ⚪ within noise
octane-tsrx runlots 19.758 20.417 +1.3% −1.0% … +4.7% ⚪ within noise
octane-tsrx select_lots 0.005 0.005 −6.3% −8.3% … −5.7% 🟢 faster
octane-tsrx clear 45.633 45.275 −0.0% −1.2% … +3.0% ⚪ within noise
octane-jsx run 3.292 3.283 +0.0% −3.0% … +7.3% ⚪ within noise
octane-jsx replace 6.775 7.575 +7.2% −1.3% … +12.9% ⚪ within noise
octane-jsx add 2.875 2.967 ±0.0% −6.5% … +7.1% ⚪ within noise
octane-jsx update 0.145 0.142 −0.8% −1.6% … +0.0% ⚪ within noise
octane-jsx select 0.071 0.069 −1.0% −1.5% … −1.0% ⚪ within noise
octane-jsx swap 0.109 0.109 −1.3% −1.9% … −0.6% ⚪ within noise
octane-jsx remove 0.098 0.097 −1.2% −3.3% … +0.9% ⚪ within noise
octane-jsx runlots 23.058 24.117 +0.8% −5.5% … +4.7% ⚪ within noise
octane-jsx select_lots 0.744 0.759 +2.1% +1.3% … +3.2% ⚪ within noise
octane-jsx clear 46.550 45.833 +0.0% −3.2% … +4.1% ⚪ within noise

All 64 work counters are unchanged.

Application bundle size (bytes)

No changes across 111 measured values.

Public-import reachability bundles (bytes)

No changes across 141 measured values.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is ON, but it could not run because the branch was deleted or merged before autofix could start.

Reviewed by Cursor Bugbot for commit 8c9c37f. Configure here.

@domgan-oai
domgan-oai merged commit 6099bf2 into octanejs:main Nov 14, 2026
31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent-authored Diff or issue body substantially produced by an AI agent fix PR: bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant