Skip to content

Fix fragile envSpecific gsub silently leaving lazy compilation on#4632

Merged
justin808 merged 10 commits into
mainfrom
4630-fragile-envspecific-gsub-lazy-compilation
Jul 18, 2026
Merged

Fix fragile envSpecific gsub silently leaving lazy compilation on#4632
justin808 merged 10 commits into
mainfrom
4630-fragile-envspecific-gsub-lazy-compilation

Conversation

@AbanoubGhadban

@AbanoubGhadban AbanoubGhadban commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes #4630

  • Made each gsub_file transform in update_server_client_or_both_for_rsc independently idempotent with its own guard, replacing the single overly-broad return if content.include?("rscWebpackConfig") early return that prevented re-runs from repairing partially transformed files
  • Made regex patterns flexible to tolerate missing semicolons (\s*;?) and extra whitespace (\s* around arguments) in envSpecific(...) calls, so the rewrite succeeds even after a linter reformats ServerClientOrBoth.js
  • Strengthened the check_rsc_scob_config verifier to check both the rscWebpackConfig import AND the envSpecific(clientConfig, serverConfig, rscConfig) call separately, so partial transforms are properly detected

Test plan

  • 6 new regression tests covering:
    • Missing trailing semicolons on envSpecific call
    • Extra whitespace around envSpecific arguments
    • Partial transform repair on re-run (import present, envSpecific not rewritten)
    • Verifier correctly detects partial transforms
    • Idempotency: fully configured file is a no-op on re-run
    • Partial default-bundle output repair (log message updated but result array not)
  • 2 existing tests strengthened with more specific assertions (require('./rscWebpackConfig') + envSpecific(clientConfig, serverConfig, rscConfig); instead of just rscWebpackConfig)
  • Full rsc_generator_spec.rb suite passes (exit code 0)
  • RuboCop clean on both modified files

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Improved React Server Components setup so reruns no longer abort when the rscWebpackConfig import is already present, and now applies only the missing RSC wiring steps.
    • Updated the default multi-bundle output to include rscConfig in the result array without duplicating prior work.
    • Strengthened RSC validation to independently detect and report missing wiring for the import, rscConfig declaration, envSpecific(..., rscConfig), RSC_BUNDLE_ONLY, and the RSC-aware default result array.
  • Tests

    • Added regression coverage for webpack and Rspack transforms, including formatting variations, partial transforms, correct insertion anchoring, verifier behavior, and idempotent reruns.

)

The rsc_setup generator's ServerClientOrBoth rewrite used rigid regex
patterns requiring exact semicolons and a single overly-broad idempotency
guard. When a linter reformatted the file (e.g. removed trailing
semicolons), the envSpecific gsub silently no-oped, leaving dev-server
lazy compilation enabled and producing an empty React Client Manifest.

- Make each gsub transform independently idempotent with its own guard
  so re-running the generator repairs partially transformed files
- Tolerate missing semicolons and extra whitespace in regex patterns
- Strengthen verifier to check both rscWebpackConfig import AND
  envSpecific(clientConfig, serverConfig, rscConfig) call separately

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@justin808, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 3 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b0685977-c3bf-4eb1-aaaa-95380c3899a6

📥 Commits

Reviewing files that changed from the base of the PR and between 590312f and 4d899df.

📒 Files selected for processing (2)
  • react_on_rails/lib/generators/react_on_rails/rsc_setup.rb
  • react_on_rails/spec/react_on_rails/generators/rsc_generator_spec.rb

Walkthrough

The RSC generator now repairs partial ServerClientOrBoth.js transformations, updates default multi-bundle output independently, validates required RSC wiring, and adds regression coverage for formatting variations, incomplete rewrites, verifier behavior, and idempotency.

Changes

RSC configuration rewrite

Layer / File(s) Summary
RSC rewrite and validation
react_on_rails/lib/generators/react_on_rails/rsc_setup.rb
RSC injection conditionally adds missing wiring, updates default bundle output separately, and verifies the import, invocation, three-argument envSpecific call, bundle-only branch, and RSC-aware result array.
Rewrite regression coverage
react_on_rails/spec/react_on_rails/generators/rsc_generator_spec.rb
Webpack and Rspack assertions verify the added wiring, while regression cases cover formatting differences, partial transformations, repair behavior, verifier detection, insertion anchoring, and idempotency.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Generator as RSC generator
  participant Config as ServerClientOrBoth.js
  participant Verifier as RSC configuration verifier
  Generator->>Config: apply missing RSC wiring
  Generator->>Config: update default bundle output
  Generator->>Verifier: check required RSC patterns
  Verifier-->>Generator: report missing or complete wiring
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main fix: making the RSC envSpecific rewrite less fragile.
Linked Issues check ✅ Passed The PR addresses #4630 by making the RSC transforms idempotent, tolerant of formatting differences, and verifier-aware of partial rewrites.
Out of Scope Changes check ✅ Passed The added helper logic and regression tests stay focused on the RSC generator fix and related SCOB rewrites.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 4630-fragile-envspecific-gsub-lazy-compilation

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jul 13, 2026

Copy link
Copy Markdown

Greptile Summary

This PR makes the RSC ServerClientOrBoth.js rewrite more resilient. The main changes are:

  • Independent guards for each generated SCOB edit.
  • More flexible regexes for semicolon and whitespace variations.
  • A stricter verifier for the RSC import and envSpecific call.
  • Regression tests for partial rewrites and idempotent reruns.

Confidence Score: 4/5

The changed verifier can still report success for an incomplete RSC bundle setup.

  • The rewrite path is better covered and handles the targeted formatting cases.
  • A partial SCOB file can still pass verification while missing generated lines needed for RSC builds.
  • The affected path can leave the default build without the RSC config or fail when rscConfig is referenced.

react_on_rails/lib/generators/react_on_rails/rsc_setup.rb

Important Files Changed

Filename Overview
react_on_rails/lib/generators/react_on_rails/rsc_setup.rb Updates the SCOB transform guards, regexes, and verifier; the verifier still misses several required generated markers.
react_on_rails/spec/react_on_rails/generators/rsc_generator_spec.rb Adds regression tests for formatted envSpecific calls, partial transform repair, and idempotent reruns.

Reviews (1): Last reviewed commit: "Fix fragile envSpecific gsub silently le..." | Re-trigger Greptile

Comment thread react_on_rails/lib/generators/react_on_rails/rsc_setup.rb

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f0dd247a5f

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread react_on_rails/lib/generators/react_on_rails/rsc_setup.rb Outdated
Comment thread react_on_rails/lib/generators/react_on_rails/rsc_setup.rb
Comment thread react_on_rails/lib/generators/react_on_rails/rsc_setup.rb Outdated
@claude

claude Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Review: Fix fragile envSpecific gsub (#4632)

Overview

This PR fixes #4630 by decomposing the single, overly-broad content.include?("rscWebpackConfig") -> return guard in update_server_client_or_both_for_rsc into four independent, per-transform guards. It also loosens the envSpecific(...) regexes to tolerate missing semicolons/extra whitespace, and strengthens check_rsc_scob_config to check the import and the envSpecific(...) call separately so partial transforms are actually detected. Solid, well-scoped fix for the reported bug, backed by 6 new regression tests plus 2 strengthened existing assertions.

Strengths

  • The four-guard decomposition directly addresses the root cause: previously a single rscWebpackConfig substring check masked partial/broken transforms and prevented repair on re-run.
  • check_rsc_scob_config returning granular messages (import vs. call) is a real improvement for diagnosability.
  • Good regression coverage: missing semicolons, extra whitespace, partial-transform repair, verifier detection, idempotency, and default-bundle-output repair are all exercised.
  • Extracting update_scob_default_bundle_output keeps update_server_client_or_both_for_rsc readable.

Issues found (posted inline)

  1. Medium - inconsistent semicolon/whitespace tolerance in update_scob_default_bundle_output (rsc_setup.rb:406-421): the console.log message gsub still requires an exact trailing ;, and the "already migrated" check for the result array uses an exact-spacing include? instead of a tolerant regex like the ones added above it. This reintroduces the same class of bug rails g react_on_rails:rsc: fragile envSpecific gsub silently leaves dev-server lazyCompilation on → empty client manifest (#4234) #4630 was about, just in the sibling method - if a linter strips the semicolon from this specific line, the transform will silently no-op on every future run.
  2. Low - broadened server_import_pattern regex (rsc_setup.rb:365): changed from anchoring on the specific const <name> = require(...) assignment shape to const\b.*require(...), which is looser than needed to tolerate a missing semicolon (could match commented-out lines or unrelated code between const and the require call). Low real-world risk, but tightening the shape back while keeping the semicolon/whitespace tolerance would be more precise.

Minor / non-blocking

  • In the new spec (rsc_generator_spec.rb), the "is a no-op when ServerClientOrBoth is already fully configured" test names its initial fixture full_content, but it's actually the unconfigured base template - the first generator run inside the test is what fully configure it. The test logic is correct, just the naming/comment is a bit confusing to a future reader.

Security / Performance

No security implications (dev-time Rails generator, no external input). Performance impact is negligible - a few extra string scans over small JS config files during code generation.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@react_on_rails/spec/react_on_rails/generators/rsc_generator_spec.rb`:
- Around line 5023-5039: Correct the spec named “is a no-op when
ServerClientOrBoth is already fully configured” so its fixture actually
represents fully configured RSC output, including the RSC-specific configuration
and imports expected by update_server_client_or_both_for_rsc. Capture the file
content before the first generator invocation and assert it is unchanged
afterward; retain the second-run assertion only if it remains relevant, and
align comments with the no-op behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fd501d3e-3ffc-4036-8032-70896dac108c

📥 Commits

Reviewing files that changed from the base of the PR and between 2ade196 and f0dd247.

📒 Files selected for processing (2)
  • react_on_rails/lib/generators/react_on_rails/rsc_setup.rb
  • react_on_rails/spec/react_on_rails/generators/rsc_generator_spec.rb

Comment thread react_on_rails/spec/react_on_rails/generators/rsc_generator_spec.rb Outdated
- Tighten server_import_pattern from overly-broad `const\b.*require(…)`
  to `const\s+(?:\{[^}]*\}|\w+)\s*=\s*require(…)` matching only the
  assignment shape (Claude review)
- Apply semicolon/whitespace tolerance to console.log and result-array
  patterns in update_scob_default_bundle_output for consistency (Claude)
- Add rscWebpackConfig() invocation check to verifier so partial
  transforms missing the rscConfig declaration are detected (Greptile)
- Fix misleading test name and comments for idempotency test (CodeRabbit)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@AbanoubGhadban

Copy link
Copy Markdown
Collaborator Author

All review feedback addressed in 331074b:

  1. Claude (line 365): Tightened server_import_pattern from const\b.*require(…) to const\s+(?:\{[^}]*\}|\w+)\s*=\s*require(…) — matches only the assignment shape
  2. Claude (line 421): Applied consistent \s*;? tolerance to console.log and result-array patterns in update_scob_default_bundle_output
  3. Greptile (line 637): Added rscWebpackConfig() invocation check to verifier (3 markers now)
  4. CodeRabbit (line 5039): Renamed test to "is idempotent across consecutive runs", fixed comments
  5. Codex (line 363): Not a real issue — the generator always produces require('./rscWebpackConfig') exactly

+ci-run-hosted

@github-actions github-actions Bot added the ready-for-hosted-ci Run optimized hosted GitHub CI for this PR label Jul 13, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Hosted CI Requested

Triggered 9 workflow(s) for 331074b1d800.
Mode: optimized hosted CI (path-selected by script/ci-changes-detector).
Added ready-for-hosted-ci, so future commits will keep running optimized hosted CI until +ci-stop-hosted is used.

View progress in the Actions tab.

@AbanoubGhadban

Copy link
Copy Markdown
Collaborator Author

+ci-run-hosted

@github-actions

Copy link
Copy Markdown
Contributor

Hosted CI Requested

Triggered 9 workflow(s) for 331074b1d800.
Mode: optimized hosted CI (path-selected by script/ci-changes-detector).
Added ready-for-hosted-ci, so future commits will keep running optimized hosted CI until +ci-stop-hosted is used.

View progress in the Actions tab.

@claude

claude Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Review

Overview: This PR fixes #4630, where a single overly-broad return if content.include?("rscWebpackConfig") guard in update_server_client_or_both_for_rsc caused the RSC webpack-config rewrite to silently no-op on re-runs (or fully skip) once any RSC string was present, even if the transform was only partially applied. The fix splits the rewrite into independently-guarded gsub_file calls, loosens a couple of regexes to tolerate missing semicolons/extra whitespace, and adds 6 regression tests. Overall this is a solid, well-tested fix for the reported issue.

Code quality

  • The per-transform unless content.include?(...) guards are a nice improvement over the single blanket early-return — each of the 4 steps in update_server_client_or_both_for_rsc (plus the 2 in the new update_scob_default_bundle_output) can now be independently repaired on re-run.
  • Splitting update_scob_default_bundle_output out keeps method length/complexity reasonable (useful since RuboCop's Metrics/MethodLength/AbcSize would otherwise likely flag the combined method).
  • Readability regression: the original code had a short # comment above every gsub_file call explaining what it does (e.g. # Add RSC import after serverWebpackConfig import, # Update envSpecific call to include rscConfig). All of these were dropped in the refactor and not replaced. Now that each block also carries an unless guard, a one-line comment per block would help future readers (and future contributors adding an 7th transform) understand what state each guard is checking.
  • Minor: all 6 guards read their "already applied?" state from the single content variable captured once at the top of update_server_client_or_both_for_rsc, before any of this run's own gsub_file calls execute (gsub_file itself operates on the live file each time). This happens to be safe today because none of the 6 transforms' guard conditions depend on an earlier transform completing within the same run — but that invariant isn't documented anywhere, and it's exactly the kind of subtlety that caused the original bug. Worth a comment noting why content is intentionally a pre-run snapshot.

Potential gap: verifier doesn't cover all 6 transforms

check_rsc_scob_config (rsc_setup.rb:625-641) was strengthened to check 3 conditions:

  • require('./rscWebpackConfig') import
  • rscWebpackConfig() invocation
  • envSpecific(clientConfig, serverConfig, rscConfig) call

However, update_server_client_or_both_for_rsc / update_scob_default_bundle_output actually perform 6 independent transforms — the other 3 being:

  • inserting the RSC_BUNDLE_ONLY else-if block
  • updating the console.log(...) text to "Creating client, server, and RSC bundles."
  • updating result = [clientConfig, serverConfig]result = [clientConfig, serverConfig, rscConfig]

These 3 remaining transforms use regexes that are still fairly exact-format-sensitive (e.g. /^(\s*const serverConfig = serverWebpackConfig\(\)\s*;?)$/ at line 376, and the %r{\n(\s*\} else \{\s*\n\s*// default is...)} anchor at line 398 — neither got the \s* whitespace tolerance that envSpecific(...) did). If one of these gsub_file calls silently fails to match (e.g. a linter reformats spacing around =, or reflows the } else { block), the file is left with a real gap (no RSC_BUNDLE_ONLY handling, or a default build that omits the RSC bundle from the result array) — but check_rsc_scob_config won't flag it, since it doesn't check for these 3 conditions. That reproduces the exact "masking" failure mode from #4630, just for a different subset of the transform.

Suggest extending check_rsc_scob_config with the missing 3 checks ("RSC_BUNDLE_ONLY", "client, server, and RSC bundles", result = [clientConfig, serverConfig, rscConfig]) for full parity between what's transformed and what's verified.

Tests

  • Good coverage of the specific scenarios called out in the PR description (missing semicolons, extra whitespace, partial-import repair, verifier detection, idempotency, partial default-bundle-output repair).
  • All new tests only exercise the envSpecific/import path; none exercise a reformatted RSC_BUNDLE_ONLY block or default-bundle-output line, which lines up with the verifier gap above — those code paths remain implicitly trusted rather than regression-tested.

Security / performance

No security or performance concerns — this is generator-time source rewriting of local files, not runtime code.

- Remove 4 redundant assertions from semicolon-tolerance test (already
  covered by the idempotency test)
- Add missing rscWebpackConfig() invocation assertion to verifier test
- Add complete-state verifier test (returns [] after full transform)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@claude

claude Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Review

Overview: Fixes #4630 by replacing the single return if content.include?("rscWebpackConfig") early-return guard in update_server_client_or_both_for_rsc with five independent, idempotent transform steps (import, invocation, envSpecific call, RSC_BUNDLE_ONLY branch, default-bundle output), each with its own presence check. Regexes for the import and envSpecific steps are loosened to tolerate missing semicolons/extra whitespace (e.g. after a linter reformat). check_rsc_scob_config now reports the three sub-components (import / invocation / envSpecific wiring) independently instead of collapsing them into one boolean check, so partial transforms are surfaced correctly instead of being masked by the old single include?("rscWebpackConfig") check.

Code quality

  • Good decomposition: each gsub_file step is now self-contained and independently testable, which is exactly what's needed to fix the "partial transform" masking bug from rails g react_on_rails:rsc: fragile envSpecific gsub silently leaves dev-server lazyCompilation on → empty client manifest (#4234) #4630.
  • Test coverage is strong: missing semicolons, extra whitespace, partial-import-only repair, verifier detection of partial state, full idempotency, and partial default-bundle-output repair are all covered.
  • Note that content is read once at the top of update_server_client_or_both_for_rsc and each unless content.include?(...) guard checks against that same stale snapshot rather than re-reading after each gsub_file. This is safe here because the five markers being checked are textually independent (none of the inserted strings satisfies another step's guard), but it's a subtle invariant — worth a short comment on the content = File.read(...) line noting that guards intentionally check pre-run state, not post-gsub state, so a future edit that adds an interdependent step doesn't silently break.

Minor / non-blocking

  • The RSC_BUNDLE_ONLY insertion point regex (matching the literal comment // default is the standard client and server build) wasn't loosened the way the envSpecific and import patterns were, so a linter/comment reformat could still silently no-op that step (mitigated by the strengthened verifier warning, but worth noting as residual fragility).
  • No CHANGELOG.md entry under [Unreleased] → Fixed — other recent bug-fix PRs in this repo (e.g. Pro: harden Node renderer multipart uploads #4623, Require graph-derived RSC client references in Doctor #4625) add one with the issue/PR links; might be worth adding for consistency, per .claude/docs/changelog-guidelines.md.

Security / performance: No concerns — this is generator-time code operating on local project files with no untrusted input, and the regex changes don't introduce any backtracking risk.

Overall: solid, well-tested bug fix. No blocking issues found.

Comment thread react_on_rails/lib/generators/react_on_rails/rsc_setup.rb
Comment thread react_on_rails/lib/generators/react_on_rails/rsc_setup.rb Outdated
Address remaining #4632 review threads on the SCOB transform:

- RSC_BUNDLE_ONLY insertion no longer depends on the literal
  `// default is the standard client and server build` comment. It now
  anchors on the bare `} else {` default-build branch (which never matches
  `} else if (...) {`), so a reflowed/reworded/removed comment can't silently
  no-op the insertion — the same fragility class #4630 fixed elsewhere.
- Document that update_server_client_or_both_for_rsc's guards intentionally
  check a single pre-run `content` snapshot; the five transforms are textually
  independent so no guard is flipped mid-run.

Adds specs: comment-removed and comment-reworded+reflowed RSC_BUNDLE_ONLY
insertion, and an explicit assertion that the transform yields the 3-arg
envSpecific(clientConfig, serverConfig, rscConfig) shape development.js relies
on to set clientWebpackConfig.lazyCompilation = false.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dfee073f39

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread react_on_rails/lib/generators/react_on_rails/rsc_setup.rb Outdated
Comment thread react_on_rails/lib/generators/react_on_rails/rsc_setup.rb Outdated
Comment thread react_on_rails/lib/generators/react_on_rails/rsc_setup.rb
@claude

claude Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Review

Overview

This PR replaces the single return if content.include?("rscWebpackConfig") early-return in update_server_client_or_both_for_rsc with five independently-guarded gsub_file transforms, loosens the envSpecific(...) regexes to tolerate missing semicolons/extra whitespace, and strengthens check_rsc_scob_config to check the import, invocation, and 3-arg call separately. It's well-motivated by #4630 (a linter-reformatted file could silently leave lazyCompilation on) and comes with 8 solid regression tests plus 2 strengthened existing assertions.

Strengths

  • The refactor to per-transform unless content.include?(...) guards is a real improvement over the old all-or-nothing early return — it lets a partially-transformed file be repaired on re-run.
  • Good in-code comment documenting the "stale snapshot content, five independent transforms" invariant — this is exactly the kind of non-obvious constraint worth calling out, and it does hold for the current set of transforms.
  • Regression tests are thoughtful: missing semicolons, extra whitespace, partial-transform repair, idempotency, and a targeted test for the "reworded/removed comment" scenario that motivated dropping the literal comment anchor.
  • check_rsc_scob_config's return type is unchanged (Array<String>), so this doesn't break verify_rsc_webpack_transforms's missing.concat(...) usage.

Issues found (posted as inline comments)

  1. Correctness risk — the new anchor for inserting the RSC_BUNDLE_ONLY branch, /\n(\s*\}\s*else\s*\{\s*\n)/, matches any bare } else { in the file, not just the intended default-build branch. Since gsub_file replaces all matches, a customized ServerClientOrBoth.js with an unrelated if/else elsewhere (plausible, since this generator is specifically designed to tolerate customized/reformatted files) would get the RSC_BUNDLE_ONLY block inserted at every match, silently producing broken JS.
  2. Verifier gapcheck_rsc_scob_config checks only 3 of the 5 things the transform writes (import, invocation, envSpecific args); it doesn't verify the RSC_BUNDLE_ONLY branch or the result = [clientConfig, serverConfig, rscConfig] default-bundle line. Given the PR's explicit goal of catching partial transforms, this leaves those two transforms unverified — including the one from issue TODO for first version #1 above.

Minor

  • All 8 new regression tests use destructured_import: true only; the non-destructured import path (const serverWebpackConfig = require(...)) isn't exercised by the new tests, though the regex change there is low-risk.

Overall the direction is good and clearly fixes the reported bug for the common case; the two issues above are about hardening the fix against the same class of "customized/reformatted file" scenarios the PR is designed to handle.

…ression)

The prior de-brittling used an unanchored `/\n(\s*\}\s*else\s*\{\s*\n)/` and
Thor's gsub_file replaces ALL matches, so a customized ServerClientOrBoth.js
with an earlier bare `} else {` (e.g. an else on the `if (envSpecific)` guard,
before `let result;`) got the RSC_BUNDLE_ONLY block spliced into the wrong
branch — placing `result = rscConfig` before `result` is declared and
corrupting the config. That traded literal-comment brittleness for
else-position brittleness (same #4630 fragility class).

Fix: extract insert_rsc_bundle_only_branch and anchor on the default-build
branch specifically — the bare `} else {` whose body assigns the default
`result = [clientConfig, serverConfig]`. `[^}]` cannot span an earlier else's
closing brace, so an unrelated earlier `} else {` is never matched; the anchor
keys off the default result assignment (not the comment), keeping comment
reflow/reword/removal tolerance; and it only splices when exactly one default
branch is identifiable (bails on 0 or 2+ to avoid multi-match insertion).

Adds a regression spec with an earlier bare `} else {`: asserts exactly one
RSC branch, the earlier else untouched, correct placement before the default
else, and no `result = rscConfig` before `let result;`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d800b9ef44

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread react_on_rails/lib/generators/react_on_rails/rsc_setup.rb Outdated
Comment thread react_on_rails/lib/generators/react_on_rails/rsc_setup.rb Outdated
@claude

claude Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Review

Overview

Fixes #4630 by making update_server_client_or_both_for_rsc idempotent per-transform (5 independent guards instead of one broad return if content.include?("rscWebpackConfig")), loosening the envSpecific(...) regexes to tolerate missing semicolons/extra whitespace, and strengthening check_rsc_scob_config to check the import, invocation, and 3-arg envSpecific call separately. Backed by 8 well-written regression tests.

Strengths

  • The core bug (2-arg envSpecific silently leaving lazyCompilation on) is fixed cleanly, with a dedicated test (rewrites envSpecific to the 3-arg form that enables lazyCompilation=false) that documents why the 3-arg call matters.
  • Replacing the single early-return with five independent guards is the right fix for the "partial transform can't be repaired on re-run" problem.
  • DEFAULT_BUILD_BRANCH_ANCHOR moving off the // default is the standard... comment (which a linter/formatter could reflow or remove) onto the actual result = [...] assignment is a good robustness improvement, and it's tested against an adversarial "earlier bare } else {" case.
  • The explanatory comments earn their keep here — this is genuinely subtle regex-over-source-code logic, and the invariants (transforms must be textually independent since content is a pre-run snapshot) are called out explicitly.

Issue found (left as inline comment)

insert_rsc_bundle_only_branch's bail-out (0 or 2+ matches of DEFAULT_BUILD_BRANCH_ANCHOR) claims in its own comment that a silent no-op here is "surfaced by check_rsc_scob_config / manual review instead" — but check_rsc_scob_config never checks for RSC_BUNDLE_ONLY or the 3-element result array, only the import/invocation/envSpecific pieces. So that failure mode currently produces no warning at all. Worth extending the verifier to close this gap, especially since this PR already touched it for the other three transforms. (This gap predates the PR — the old verifier didn't check it either — but the PR's new comment asserts a guarantee that isn't actually true, and the new bail-out logic is a new source of silent no-ops worth covering.)

Minor / lower-confidence notes

  • The [^}]*?-based brace-balance heuristic in DEFAULT_BUILD_BRANCH_ANCHOR is inherently fragile against JS string/regex literals containing a literal } (e.g. a console.log message with {...} in it) — a non-AST approach will always have this class of edge case. Not asking for an AST-based rewrite here, just flagging it as the most likely source of the 2+/0-match bail-out in practice, which reinforces the verifier gap above.
  • Hardcoded 2-space indentation in the inserted lines (e.g. "\\1\n\n const rscConfig = ...") won't match a differently-indented file, but this is pre-existing behavior carried over from the code being replaced, not a regression.

Security / Performance

No security concerns — this only rewrites local generator-managed files during a dev-time Rails generator run, no untrusted input involved. Performance is a non-issue given the small file sizes and linear (non-catastrophic) regex backtracking.

justin808 and others added 2 commits July 17, 2026 15:05
…aced

check_rsc_scob_config covered only the import, invocation, and 3-arg
envSpecific markers. The two default-branch transforms (RSC_BUNDLE_ONLY branch
and the RSC-aware `result = [clientConfig, serverConfig, rscConfig]` array)
share the `} else {` anchor, which insert_rsc_bundle_only_branch now
deliberately no-ops when a single default branch can't be identified. Their
success is therefore not implied by the invocation marker, so the verifier now
checks them too — a silent miss is reported instead of masked.

Adds a spec that degrades a fully-transformed file (strips the RSC_BUNDLE_ONLY
branch, reverts the result array) and asserts the verifier flags both while
leaving the three upstream markers unflagged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment thread react_on_rails/lib/generators/react_on_rails/rsc_setup.rb Outdated
@claude

claude Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Review: Fix fragile envSpecific gsub silently leaving lazy compilation on (#4630)

Overview

This PR reworks update_server_client_or_both_for_rsc in rsc_setup.rb so that each of the five gsub_file transforms applied to ServerClientOrBoth.js (RSC import, rscConfig invocation, envSpecific 3-arg call, RSC_BUNDLE_ONLY branch, default bundle output) has its own idempotency guard instead of one overly-broad return if content.include?("rscWebpackConfig") early return. It also loosens the regexes to tolerate missing semicolons/extra whitespace (so a linter reformat doesn't silently no-op the rewrite), and strengthens check_rsc_scob_config to check each piece of the transform independently so partial states are surfaced rather than masked.

Code quality / correctness

  • The core fix is sound. I traced the regex logic by hand against the actual ServerClientOrBoth.js.tt template and the spec fixtures in generator_spec_helper.rb#server_client_or_both_content — they match the real generated shape, so the new regression tests aren't tautological.
  • DEFAULT_BUILD_BRANCH_ANCHOR (introduced in the later commits) correctly avoids matching an earlier bare } else { (e.g. on a customized if (envSpecific) {...} else {...} guard) because [^}]*? can't cross that block's own closing brace before reaching result = [clientConfig, serverConfig]. This is a real fix for a real regression the PR's own commit history shows was caught mid-review (commit 5 fixes a bug commit 4 introduced) — good that it was caught and tested before merge.
  • The "stale pre-run content snapshot used for all guards, while gsub_file operates on the live file" design is a subtle invariant, but it's correctly reasoned and thoroughly documented (lines 361-368): none of the five transforms' inserted text can flip another transform's guard. I independently verified this claim for the two trickiest cases (import insertion vs. rscWebpackConfig() invocation guard) and it holds.
  • check_rsc_scob_config now verifies all 5 pieces of the transform independently (added incrementally across the commit history in direct response to review feedback), closing the exact gap that let the original bug (rails g react_on_rails:rsc: fragile envSpecific gsub silently leaves dev-server lazyCompilation on → empty client manifest (#4234) #4630) go undetected — a partially-transformed file that silently left lazyCompilation on.

Test coverage

Strong. 6 new regression tests cover: missing semicolons, extra whitespace, partial-transform repair on re-run, verifier detection of partial transforms, full idempotency, and default-bundle-output partial repair. Two more commits add coverage for the anchor-fragility regression (comment removed/reworded, and the "earlier bare } else {" corruption case) plus a direct assertion on the 3-arg envSpecific shape that development.js actually depends on for lazyCompilation = false. This is exactly the kind of test that pins the actual production bug, not just the refactor.

Minor finding (posted inline)

One narrow robustness gap: insert_rsc_bundle_only_branch's skip-guard and check_rsc_scob_config's presence-check both use a loose content.include?("RSC_BUNDLE_ONLY") substring test. Since both sides use the same loose check, a file where that substring exists without the branch being fully/correctly formed would silently no-op the transform and pass verification — the same "guard says configured, but it isn't" class of bug this PR eliminates for the other four transforms. Low severity/narrow edge case, but worth tightening for consistency given how carefully the rest of this PR closes that exact gap elsewhere. See inline comment for a concrete suggestion.

Security / performance

No security implications — this is generator-time (rails generate) file scaffolding over local template files, no user-controlled input or injection surface. Performance is a non-issue (one-time codegen, not a runtime hot path).

Verdict

Solid, well-tested fix that closes a real production bug (silently-stuck lazy compilation). The PR's own commit history shows it went through multiple rounds of self-review that caught and fixed a real regression (the anchor-position bug in commit 4/5) before landing — a good sign for the change's current correctness. Only the one minor nitpick above.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a73bc43eaf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread react_on_rails/lib/generators/react_on_rails/rsc_setup.rb Outdated
Comment thread react_on_rails/lib/generators/react_on_rails/rsc_setup.rb Outdated
@claude

claude Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Review: Fix fragile envSpecific gsub silently leaving lazy compilation on (#4632)

Overview

This PR fixes #4630, where the standalone RSC upgrade generator's rewrite of ServerClientOrBoth.js used a single broad return if content.include?("rscWebpackConfig") guard that (a) prevented re-runs from repairing partially-transformed files, and (b) used regexes that broke on linter-reformatted output (missing trailing semicolons, extra whitespace), silently leaving envSpecific(clientConfig, serverConfig) un-rewritten and thus lazy compilation left on for RSC.

The fix:

  • Splits the single early-return guard into five independent, per-transform guards (update_server_client_or_both_for_rsc, insert_rsc_bundle_only_branch, update_scob_default_bundle_output), each checking its own precondition so partial state gets repaired on re-run.
  • Loosens the envSpecific(...) regexes to tolerate missing semicolons and extra whitespace.
  • Replaces the comment-anchored RSC_BUNDLE_ONLY insertion point with a structural anchor (DEFAULT_BUILD_BRANCH_ANCHOR) keyed on the actual result = [clientConfig, serverConfig] assignment, so a reworded/removed/reflowed comment can't silently no-op the insertion.
  • Strengthens check_rsc_scob_config to check the import, the invocation, the 3-arg envSpecific call, the RSC_BUNDLE_ONLY branch, and the RSC-aware result array as five separate conditions instead of one coarse include?("rscWebpackConfig").
  • Adds 11 new regression tests plus tightens 2 existing assertions.

Code quality

  • The inline comments explaining the invariants (why content is read once as a pre-run snapshot, why the anchor regex can't cross a }, why the "exactly one match" guard exists) are genuinely useful — they document why, not what, and will save the next person from re-deriving these guarantees.
  • DEFAULT_BUILD_BRANCH_ANCHOR extracted to a shared constant is good practice given the regex's subtlety (non-greedy [^}]*? deliberately can't span a }, so it skips earlier bare } else { blocks and only matches the true default branch — verified this by hand against the "earlier bare } else {" regression test and it holds).
  • I traced through the content staleness invariant (all five guards in update_server_client_or_both_for_rsc check the same pre-transform snapshot, while the actual gsub_file calls always operate on the live file). The comment claims none of the inserted strings from earlier transforms can flip a later transform's guard — I checked all five pairwise and this holds for the current set of transforms. It's a bit of a maintenance trap for future contributors (a new transform must remember to preserve the invariant, as the comment notes), but that's already called out explicitly, so it's a reasonable tradeoff for avoiding repeated file reads.

Minor finding (posted inline)

  • The "already transformed" regexes for the default result array (update_scob_default_bundle_output, check_rsc_scob_config) don't have the same inner-bracket whitespace tolerance (\[\s*clientConfig...) that the envSpecific(...) regexes gained. Low real-world risk since default Prettier/ESLint configs don't add array-bracket spacing, but it's a slight inconsistency with the PR's own stated goal of tolerating reformatting drift. See inline comment for details.

Other observations (not blocking)

  • No CHANGELOG.md entry. Per .claude/docs/changelog-guidelines.md, bug fixes are supposed to get an entry (#### Fixed) since this is a user-visible fix (silently-broken RSC config repair). Worth adding before merge.
  • The envSpecific(...) 3-arg regex is duplicated verbatim in three places (update_server_client_or_both_for_rsc, check_rsc_scob_config, and referenced again in the spec). Not a bug, but given DEFAULT_BUILD_BRANCH_ANCHOR was already extracted to a constant for exactly this kind of subtle-regex-reuse reason, doing the same for the envSpecific pattern would reduce the risk of the two copies drifting out of sync in a future edit.

Test coverage

Strong — the new tests cover the actual failure modes from #4630 (missing semicolon, extra whitespace, partial-transform repair, verifier detection of partial transforms, idempotency, and default-bundle-output partial repair), plus edge cases around the new anchor regex (comment removed, comment reflowed/reworded, an earlier customized bare } else { that must not be matched). I traced through the regex behavior by hand for the trickiest case (the "earlier bare } else {" test) and confirmed the non-greedy [^}]*? correctly fails to match across the intervening }, so only the true default branch matches — the test's assumption is correct.

Security / performance

No concerns — this is local codegen tooling operating on generated config files during a Rails generator run; no user-controlled input reaches these regexes, and the file sizes are trivial.

…'t fool them

The ServerClientOrBoth skip-guards and their verifier counterparts used loose
substring checks, so a stray mention of an RSC marker in a comment or string
literal could either suppress a transform (leaving dangling rscConfig
references -> ReferenceError) or make the verifier report an incomplete setup
as complete -- the exact "guard says configured but isn't" class #4630 targets.

Introduce shared structural-matcher constants and use each in BOTH the
transform's skip-guard and its verifier check so the two can never disagree:

- RSC_WEBPACK_CONFIG_IMPORT / RSC_CONFIG_DECLARATION: match the real
  'const rscWebpackConfig = require(...)' import and
  'const rscConfig = rscWebpackConfig()' declaration, not a bare substring, so
  a comment mention no longer skips inserting the declaration.
- RSC_BUNDLE_ONLY_BRANCH: match process.env.RSC_BUNDLE_ONLY together with the
  'result = rscConfig' assignment, so a stray RSC_BUNDLE_ONLY comment neither
  suppresses the insertion nor fools the verifier.
- DEFAULT_RESULT_ARRAY / RSC_RESULT_ARRAY: add inner-bracket/comma whitespace
  tolerance so linter reflow ('[ clientConfig, serverConfig, rscConfig ]') is
  recognized as already-transformed, matching the envSpecific regexes.

DEFAULT_BUILD_BRANCH_ANCHOR is now composed from DEFAULT_RESULT_ARRAY (DRY).
Adds specs: comment-only rscWebpackConfig() still inserts the declaration;
comment-only RSC_BUNDLE_ONLY still inserts the branch; stray RSC_BUNDLE_ONLY
comment is flagged by the verifier; inner-bracket-spaced result array is
recognized as already RSC-aware.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8536ee2d5e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread react_on_rails/lib/generators/react_on_rails/rsc_setup.rb

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@react_on_rails/spec/react_on_rails/generators/rsc_generator_spec.rb`:
- Around line 5043-5047: Strengthen the assertions in the relevant RSC generator
spec so the valid envSpecific call is also confirmed absent from missing. Add a
negative expectation for the envSpecific marker alongside the existing
ServerClientOrBoth.js import and rscConfig declaration checks, preserving
coverage for all three upstream markers.
- Around line 5192-5196: The fixture rewrite in the test around
server_client_or_both_content is a no-op because the gsub search string has
incorrect indentation. Update the `gsub("      } else {", "      }else{")`
replacement to match the two-leading-space formatting emitted by
`server_client_or_both_content`, while preserving the intended compact `}else{`
output.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d5678805-17d3-46d8-9651-7d430466b63b

📥 Commits

Reviewing files that changed from the base of the PR and between a75a752 and 8536ee2.

📒 Files selected for processing (2)
  • react_on_rails/lib/generators/react_on_rails/rsc_setup.rb
  • react_on_rails/spec/react_on_rails/generators/rsc_generator_spec.rb
🚧 Files skipped from review as they are similar to previous changes (1)
  • react_on_rails/lib/generators/react_on_rails/rsc_setup.rb

Comment thread react_on_rails/spec/react_on_rails/generators/rsc_generator_spec.rb
Comment thread react_on_rails/spec/react_on_rails/generators/rsc_generator_spec.rb
Comment thread react_on_rails/lib/generators/react_on_rails/rsc_setup.rb Outdated
@claude

claude Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Review: Fix fragile envSpecific gsub (#4632)

Overall this is a solid hardening pass: replacing the single overly-broad return if content.include?("rscWebpackConfig") guard with five independently-idempotent, structurally-matched transforms is the right fix for the class of bug in #4630 (silent no-op on partial/reformatted files masking a broken lazy-compilation setup). The DEFAULT_BUILD_BRANCH_ANCHOR design (anchoring on the default result-array shape rather than a comment, bailing when 0 or 2+ default branches are found) is a well-reasoned way to avoid the previous comment-dependent fragility, and the regression test coverage for semicolon/whitespace tolerance, partial-transform repair, idempotency, and the "customized earlier } else {" case is thorough.

One consistency gap (left inline on rsc_setup.rb:458): update_scob_default_bundle_output's guard for the console.log message rewrite is still a bare content.include?(...) substring check, unlike its four sibling transforms which all moved to structural regex constants shared with the verifier. A stray mention of that string (e.g. in a comment) would silently no-op the log rewrite, and — unlike the other transforms — there's no corresponding check in check_rsc_scob_config, so the miss would not be surfaced. Impact is low (cosmetic log text, not a functional config value), but it's the one place that does not follow the PR's own stated invariant that guard and verifier share a matcher.

Minor / non-blocking:

  • RSC_WEBPACK_CONFIG_IMPORT, RSC_CONFIG_DECLARATION, and server_import_pattern still assume single-quoted require(...) calls. If a project's linter enforces double quotes, these structural matchers (like their pre-existing predecessors) would fail to recognize an already-transformed file. Not a regression from this PR, but since the goal here is linter-reformat tolerance, it may be worth a follow-up.
  • No CHANGELOG.md entry for what is a user-visible bug fix (previously: silently leaving lazy compilation on / producing an empty React Client Manifest). Per the project's changelog guidelines, user-visible bug fixes should get an entry.

No security concerns — this only rewrites local generator-created config files via Thor's gsub_file, all inputs are developer-controlled project files, not external/untrusted input.

… spec

Final quality pass on the ServerClientOrBoth transforms:

1. update_scob_default_bundle_output no longer guards the console.log rewrite
   with the loose substring "client, server, and RSC bundles". It now uses a
   new RSC_BUNDLES_LOG structural matcher (the whitespace-tolerant
   console.log('...') call shape), so a stray comment mention of the message
   text can't silently no-op the rewrite -- matching every sibling guard.

2. Fix a genuine test defect: the "reworded and reflowed" spec compacted
   `} else {` with SIX leading spaces, but the fixture emits the default branch
   with TWO, so the gsub was a no-op and the test passed vacuously without ever
   exercising compact `}else{` formatting. Correct the indentation and add a
   pre-run assertion that the fixture actually contains `}else{` (and no spaced
   `} else {`), so it can't silently no-op again. It still passes because
   DEFAULT_BUILD_BRANCH_ANCHOR is whitespace-tolerant.

3. Strengthen the "flags missing RSC_BUNDLE_ONLY" verifier spec to also assert
   the exact envSpecific marker string is NOT falsely reported (previously only
   import + declaration were checked).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment thread react_on_rails/lib/generators/react_on_rails/rsc_setup.rb
Comment thread react_on_rails/lib/generators/react_on_rails/rsc_setup.rb

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 590312feca

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread react_on_rails/lib/generators/react_on_rails/rsc_setup.rb Outdated
@claude

claude Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Review: Fix fragile envSpecific gsub silently leaving lazy compilation on (#4632)

Overview

This PR replaces a single overly-broad return if content.include?("rscWebpackConfig") early-return guard in the standalone RSC generator (update_server_client_or_both_for_rsc) with five independent, structurally-matched skip-guards, so a partially transformed ServerClientOrBoth.js can be repaired on re-run instead of being silently skipped. It also hardens envSpecific(...) matching to tolerate missing semicolons/extra whitespace, and splits the verifier (check_rsc_scob_config) into per-concern checks so partial transforms are individually surfaced. The change is well-motivated by #4630 (a real bug: a partial/reformatted transform could leave lazyCompilation silently on) and is backed by an extensive, well-targeted regression test suite (17 new test cases covering idempotency, partial-repair, comment-mention false-positives, and branch-disambiguation).

Strengths

  • The shared constants (RSC_WEBPACK_CONFIG_IMPORT, RSC_CONFIG_DECLARATION, ENVSPECIFIC_RSC_CALL, etc.) being reused by both the transform guards and the verifier is a good design choice — it structurally guarantees the two can't disagree about "already applied".
  • insert_rsc_bundle_only_branch's "bail unless exactly one anchor match" check is a thoughtful safety measure against corrupting an unintended branch in customized files.
  • Test coverage is thorough, including adversarial cases (stray comment mentions, reworded/removed comments, an earlier unrelated } else {) that specifically guard the new regexes' precision.

Issues found (see inline comments)

  1. Inconsistent ambiguity handling (update_scob_default_bundle_output, lines 461-477): unlike insert_rsc_bundle_only_branch, this method has no "exactly one match" guard before calling gsub_file with DEFAULT_RESULT_ARRAY / the log-message pattern — it will rewrite every textual match in the file. A customized file with a duplicated default-result-array shape would be silently mis-transformed everywhere, not just in the intended branch.
  2. Whitespace-tolerance inconsistency (update_server_client_or_both_for_rsc, lines 408-416): server_import_pattern (used to insert the rscWebpackConfig import) wasn't given the same \s* tolerance around require('./serverWebpackConfig') that the rest of this PR's patterns received, so a linter that adds space-in-parens could still make this specific transform silently no-op — the same class of bug this PR is fixing.

Minor / process note

  • Per .claude/docs/changelog-guidelines.md, user-visible bug fixes should get a CHANGELOG.md entry. This fixes a real user-facing bug (RSC standalone generator silently leaving lazy compilation on), but I don't see a changelog entry in this diff — worth adding before merge (unless the project intentionally batches generator-only fixes).

Security / Performance

No security concerns (build-time codegen over local config files, no external input). Performance impact is negligible — all patterns operate on small, one-off-read config files.

…le-match

Consolidated robustness pass over update_server_client_or_both_for_rsc,
insert_rsc_bundle_only_branch, and update_scob_default_bundle_output so every
gsub_file target is (a) structural, (b) whitespace/semicolon tolerant,
(c) anchored to a complete statement, and (d) guarded against unintended
multi-match.

- REAL BUG: the server-import rewrite pattern ended at the require(...) call, so
  for a customized `const serverWebpackConfig = require('./serverWebpackConfig').default;`
  it inserted the RSC import before the trailing `.default;`, producing invalid
  JS (`);.default;`). New SERVER_WEBPACK_CONFIG_IMPORT captures through an
  optional `.default` and the terminating `;`, so the RSC import always lands
  after the complete statement. (Canonical template uses the destructured
  `{ default: … }` or plain form, never trailing `.default`, so default output
  was unaffected; this only hit customized configs.)
- Added `\s*` tolerance around parens/quotes in the server-import and
  serverConfig-invocation patterns (`require( './serverWebpackConfig' )` etc.),
  consistent with the other matchers.
- New replace_single_match helper: applies a gsub_file rewrite only when the
  pattern matches exactly once in the pre-run snapshot (bails on 0 or 2+). All
  five SCOB rewrites now route through it, so an incidental extra match in a
  customized file can't be corrupted -- the miss is surfaced by
  check_rsc_scob_config instead. Previously only insert_rsc_bundle_only_branch
  had this guard.
- Promoted the remaining inline patterns to named constants
  (SERVER_WEBPACK_CONFIG_IMPORT, SERVER_CONFIG_INVOCATION, ENVSPECIFIC_DEFAULT_CALL,
  DEFAULT_BUNDLES_LOG) for a single consistent source of truth.

Adds specs: `.default` server import handled correctly (valid JS, RSC import
after the full statement); whitespace-spaced require recognized; incidental
second result-array match bails without corruption and is flagged by the
verifier.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@claude

claude Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Code Review

Overview

This PR fixes #4630, where the RSC generator's update_server_client_or_both_for_rsc used a single broad guard (return if content.include?("rscWebpackConfig")) gating five separate gsub_file rewrites. That made the whole transform an all-or-nothing operation and let a stray substring match (e.g. inside a comment) silently skip real work, sometimes leaving envSpecific(clientConfig, serverConfig) un-rewritten to its 3-arg form — which is what keeps lazyCompilation on for RSC builds (the actual symptom in #4630).

The fix:

  • Splits the single guard into five independent, structurally-anchored guards/transforms (RSC_WEBPACK_CONFIG_IMPORT, RSC_CONFIG_DECLARATION, ENVSPECIFIC_RSC_CALL, RSC_BUNDLE_ONLY_BRANCH, RSC_RESULT_ARRAY), each keyed off a real JS shape instead of a bare substring.
  • Adds replace_single_match, which only applies a gsub_file rewrite when the source pattern matches exactly once, so a customized file with an incidental extra match is never corrupted — the miss is surfaced by the verifier instead.
  • Reuses the same constants in check_rsc_scob_config, so the "already applied" check for a transform and its verifier check can never disagree.
  • Makes the source patterns tolerant of missing semicolons and extra whitespace, so a linter-reformatted ServerClientOrBoth.js doesn't break re-runs.

Code quality & design

  • Good use of shared constants between transform guards and verifier checks — this directly closes the loophole where the old verifier's content.include?("rscWebpackConfig") would report success even when only const rscConfig = rscWebpackConfig(); (the invocation, not the import) was present.
  • The "bail on 0 or 2+ matches" behavior in replace_single_match is a sound defensive default: better to no-op (and let the verifier flag it) than to gsub_file-corrupt a customized config across every match.
  • The large comment block above the constants (lines documenting the "stale snapshot" invariant) is doing real work here — it explains a genuinely non-obvious constraint (all guards check the pre-run content snapshot, not the file as progressively modified by earlier gsub_file calls within the same run) and states the invariant future edits must preserve. Worth keeping.
  • Splitting update_server_client_or_both_for_rsc into insert_rsc_bundle_only_branch / update_scob_default_bundle_output / replace_single_match improves readability over the previous monolithic method.

Potential risks (reviewed, not blocking)

  • The five transforms rely on being "textually independent" (an earlier transform's inserted text never satisfies or breaks a later transform's guard/source pattern). I traced through each pairing and this holds for the current constant set, but it's a soft invariant enforced only by code review/comments, not by a test that would catch a future violation directly (the idempotency/repair tests exercise the net effect, which is good, but wouldn't clearly pinpoint why if this invariant were ever broken by a future edit).
  • I verified the previously-existing indentation quirk in insert_rsc_bundle_only_branch (the spliced } else if (RSC_BUNDLE_ONLY) branch ends up at 2/4-space indent vs. the surrounding 6/8-space convention in generated output) is unchanged from the pre-PR code — not a regression introduced here, just noting it in case a future cleanup wants to address it.
  • No security concerns: all regex/gsub_file operations run against local, generator-controlled files during code generation (not user/network input), so there's no injection or ReDoS exposure here.

Test coverage

Very thorough — the 15 new/strengthened tests in rsc_generator_spec.rb cover missing semicolons, extra whitespace, partial-transform repair on re-run, verifier detection of partial state (including the "stray comment mention" false-positive case the old substring check was vulnerable to), idempotency, .default-suffixed imports, and the "bails without corrupting on an incidental second match" safety behavior. This gives good confidence in the fix.

Minor suggestion

Per this repo's changelog guidelines, user-visible bug fixes should get a CHANGELOG.md entry (#### Fixed, with a link to this PR). This PR only touches rsc_setup.rb and its spec — worth adding an entry before merge, since this fixes a real generator bug (silently-broken RSC lazy-compilation config) that's visible to app maintainers who ran the standalone RSC generator or a linter over their webpack config.

Overall: solid, well-reasoned fix with strong regression coverage. No blocking issues found.

@justin808
justin808 merged commit f894ca7 into main Jul 18, 2026
48 checks passed
@justin808
justin808 deleted the 4630-fragile-envspecific-gsub-lazy-compilation branch July 18, 2026 04:42
justin808 added a commit that referenced this pull request Jul 18, 2026
…t-policy

* origin/main: (30 commits)
  Fix SSR crash on unpaired UTF-16 surrogates from JS JSON output (#4710) (#4726)
  Remove false Doctor pack-tag pairing warnings (fixes #4619) (#4724)
  Fix Pro renderer artifact cache identity (#4701)
  [Pro] Skip stream caches for error-containing renders (fixes #4581) (#4722)
  docs: mark 16.2.0 immediate_hydration override note as historical (fixes #4639) (#4725)
  Redact RSC rendering error details from client DOM in production (#4631)
  Fix fragile envSpecific gsub silently leaving lazy compilation on (#4632)
  Docs: node-renderer default setup requires Node.js 20+ (Fastify 5) (#4733)
  [Pro] Harden loadable-stats success-cache test; route worker tests through formAutoContent shim (partially addresses #4506) (#4721)
  Add rsc-guardrails agent skill + payload-escaping regression test + advisory hook (#4599)
  Regenerate llms-full references (#4728)
  CI: make hosted dispatch exact-head idempotent (#4692)
  Docs: normalize version floors, release metadata, and branch links (#4709)
  Docs: fix node-renderer startup, versions, and missing config options (#4707)
  Docs: fix Shakapacker build & migration recipes (#4703) (#4708)
  Docs: document Pro ExecJS profiling prerequisites & missing cached helpers (#4706)
  docs: correct OSS helper & API-reference examples (broken/stale snippets) (#4637)
  Docs: correct immediate_hydration removal details (#4638) (#4640)
  CI: route gem generator specs by changed paths (#4691)
  Prevent oversized GitHub release failures (#4714)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-hosted-ci Run optimized hosted GitHub CI for this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

rails g react_on_rails:rsc: fragile envSpecific gsub silently leaves dev-server lazyCompilation on → empty client manifest (#4234)

2 participants