feat: add REACT_ON_RAILS_BASE_PORT for concurrent worktree port management#3142
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds deterministic base-port support via Changes
Sequence Diagram(s)sequenceDiagram
participant Dev as bin/dev
participant PS as ReactOnRails::Dev::PortSelector
participant SM as ReactOnRails::Dev::ServerManager
participant Svc as Services (Rails, Webpack, Node-Renderer)
Dev->>PS: select_ports()
alt REACT_ON_RAILS_BASE_PORT detected
PS->>PS: validate base_port (1..MAX_BASE_PORT)
PS->>PS: derive rails=base+0, webpack=base+1, renderer=base+2
PS-->>Dev: {rails, webpack, renderer}
else CONDUCTOR_PORT detected
PS->>PS: parse conductor as base
PS->>PS: derive rails=base+0, webpack=base+1, renderer=base+2
PS-->>Dev: {rails, webpack, renderer}
else
PS->>PS: use explicit envs or probe free ports
PS-->>Dev: {rails, webpack, nil}
end
Dev->>SM: configure_ports(selected)
alt selected.renderer present
SM->>SM: set ENV["PORT"], ENV["SHAKAPACKER_DEV_SERVER_PORT"] (overwrite)
SM->>SM: set ENV["RENDERER_PORT"], ENV["REACT_RENDERER_URL"]
SM-->>Svc: processes inherit envs
else
SM->>SM: apply explicit/env-default PORT and dev-server using ||=
SM->>SM: set REACT_RENDERER_URL only if RENDERER_PORT present and URL unset
SM-->>Svc: processes inherit envs (no renderer)
end
Svc->>Svc: bind services to assigned ports
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
Code ReviewOverviewThis PR adds a What Works Well
IssuesBug (medium) — derived ports can overflow 65535. Misleading log when Minor — Nice-to-have — Test Coverage GapThere's no test for the scenario where DocsThe new process-managers.md section and SummaryThe approach is sound and the feature is useful. The port-overflow bug is the one concrete correctness issue to fix before merging. The log/priority conflict is worth at least a decision: either document that base port always wins (and change 🤖 Generated with Claude Code |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 37a9ae17d4
ℹ️ 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".
Greptile SummaryAdds Prior review concerns — derived renderer port exceeding 65535 and test-environment isolation — have been addressed. Two minor points remain:
Confidence Score: 5/5Safe to merge — no blocking issues; remaining findings are minor UX/edge-case P2s. Previous P0/P1 concerns (renderer port > 65535, test env isolation) have been fully addressed. The two remaining issues are P2: a missing warning for out-of-range base ports (silent fallback is safe) and a false-negative in the port-prefix substring check (only affects the warning, not actual behavior). Test coverage is thorough and the core port-selection logic is correct. react_on_rails/lib/react_on_rails/dev/port_selector.rb and react_on_rails/lib/react_on_rails/dev/server_manager.rb have the minor findings noted above. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A([bin/dev start]) --> B{REACT_ON_RAILS_BASE_PORT or CONDUCTOR_PORT set?}
B -->|Yes - first valid var wins| C[base_port returns Integer]
C --> D[select_ports: derive rails=base+0, webpack=base+1, renderer=base+2]
D --> E[apply_base_port_env: unconditionally set PORT, SHAKAPACKER_DEV_SERVER_PORT, RENDERER_PORT, REACT_RENDERER_URL]
B -->|No| F{PORT or SHAKAPACKER_DEV_SERVER_PORT set?}
F -->|Yes| G[Use explicit per-service vars]
F -->|No| H[Auto-detect free ports starting from defaults]
G --> I[apply_explicit_port_env: PORT and WEBPACK assigned conditionally]
H --> I
I --> J{RENDERER_PORT set?}
J -->|No| K([Done - renderer not configured])
J -->|Yes| L{REACT_RENDERER_URL set?}
L -->|No| M[Derive URL from RENDERER_PORT]
L -->|Yes - port matches| N([Done - consistent])
L -->|Yes - port mismatch| O[Warn: vars disagree]
E --> P([ENV_KEYS_TO_PRESERVE propagated to spawned process manager])
M --> P
N --> P
O --> P
Reviews (3): Last reviewed commit: "fix: second round of port selector revie..." | Re-trigger Greptile |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@react_on_rails/lib/react_on_rails/dev/port_selector.rb`:
- Around line 98-102: The base_port method currently allows ENV values up to
65_535 but then derives additional ports as base+1 and base+2; update the
validation in base_port (and any use of BASE_PORT_ENV_VARS) to ensure the chosen
base plus the highest offset (2) stays ≤ 65_535 (i.e., accept bases in the range
1..65_533), so change the conditional that returns val to check val between 1
and (65_535 - 2) and reject/skip values outside that safe range.
In `@react_on_rails/lib/react_on_rails/dev/server_manager.rb`:
- Around line 842-845: The current code may set ENV["REACT_RENDERER_URL"] using
selected[:renderer] even when an existing ENV["RENDERER_PORT"] was preserved;
update the logic so REACT_RENDERER_URL is constructed from the effective port
value (the ENV["RENDERER_PORT"] after the ||= assignment) rather than from
selected[:renderer]; locate the block that references selected[:renderer] in
server_manager.rb (the if selected[:renderer] branch) and change the URL
construction to use ENV["RENDERER_PORT"] (or a local port variable assigned from
ENV["RENDERER_PORT"]) so the URL always matches the actual RENDERER_PORT in use.
In `@react_on_rails/spec/react_on_rails/dev/port_selector_spec.rb`:
- Around line 10-15: Wrap each around hook's example.run in a begin...ensure so
ENV cleanup always runs (e.g., change the around do |example| block that sets
ENV["REACT_ON_RAILS_BASE_PORT"] to use begin; example.run; ensure ... end), and
in the "CONDUCTOR_PORT only" and "out-of-range base port" contexts explicitly
unset or restore both ENV["REACT_ON_RAILS_BASE_PORT"] and ENV["CONDUCTOR_PORT"]
(capture old values, set the test values, run example, then in ensure restore
originals or delete the keys when nil) so base_port's lookup order cannot be
influenced by ambient env vars.
🪄 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: e7ac5b86-7952-413d-89b3-278d22119277
📒 Files selected for processing (17)
docs/oss/building-features/process-managers.mdreact_on_rails/lib/generators/react_on_rails/pro_setup.rbreact_on_rails/lib/generators/react_on_rails/templates/base/base/.env.examplereact_on_rails/lib/react_on_rails/dev/port_selector.rbreact_on_rails/lib/react_on_rails/dev/server_manager.rbreact_on_rails/spec/dummy/Procfile.devreact_on_rails/spec/dummy/Procfile.dev-prod-assetsreact_on_rails/spec/dummy/Procfile.dev-static-assetsreact_on_rails/spec/dummy/Procfile.dev.no.turbolinksreact_on_rails/spec/react_on_rails/dev/port_selector_spec.rbreact_on_rails/spec/react_on_rails/generators/install_generator_spec.rbreact_on_rails/spec/react_on_rails/support/shared_examples/pro_generator_examples.rbreact_on_rails_pro/spec/dummy/Procfile.devreact_on_rails_pro/spec/dummy/Procfile.prodreact_on_rails_pro/spec/dummy/Procfile.staticreact_on_rails_pro/spec/execjs-compatible-dummy/Procfile.devreact_on_rails_pro/spec/execjs-compatible-dummy/Procfile.dev-static
## Summary - Applies `prettier --write` to five tracked docs files that are currently out of compliance on `main`. - No content changes — only whitespace/table-alignment fixes produced by Prettier. ## Why this is needed The formatting drift landed via a docs-only merge to `main`. The `lint-js-and-ruby.yml` workflow is conditionally skipped for docs-only commits on `main` (see the job condition at [`.github/workflows/lint-js-and-ruby.yml:79-87`](https://github.com/shakacode/react_on_rails/blob/main/.github/workflows/lint-js-and-ruby.yml#L79-L87)), so the check never ran on merge. It surfaces on every subsequent code-touching PR because the lint job runs for those (e.g. [#3151](#3151), [#3148](#3148), [#3142](#3142), [#3097](#3097)). Merging this unblocks the `build` → `Check formatting` step on those PRs. ## Test plan - [x] `pnpm start format.listDifferent` passes for the five files - [x] Diff is purely whitespace — no link targets, code blocks, or prose changed 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Documentation** * Improved formatting across API reference, core concepts, migration, and RSC docs: refined table layouts, adjusted column alignment, and standardized emphasis for clearer warnings. * Updated link text and phrasing for several guides for clearer navigation. * Reformatted code examples and JSX/Route snippets for more compact, consistent presentation and improved readability. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
4216467 to
8da5a8a
Compare
Code ReviewOverall this is a clean, well-motivated feature. The implementation is straightforward and the test coverage is solid. I found a few issues worth addressing before merge. Bug: base-port priority not enforced in
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8da5a8a004
ℹ️ 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".
There was a problem hiding this comment.
♻️ Duplicate comments (2)
react_on_rails/lib/react_on_rails/dev/server_manager.rb (1)
836-843:⚠️ Potential issue | 🟠 MajorApply selected ports as the effective env values.
PortSelectornow gives the base port higher priority, but||=lets pre-existingPORT/SHAKAPACKER_DEV_SERVER_PORT/RENDERER_PORToverride that selection before child processes start. This can makeREACT_ON_RAILS_BASE_PORT=4000still boot on stale per-service ports, and it also preserves the previously flagged renderer URL drift.🐛 Proposed fix
def configure_ports selected = PortSelector.select_ports - ENV["PORT"] ||= selected[:rails].to_s - ENV["SHAKAPACKER_DEV_SERVER_PORT"] ||= selected[:webpack].to_s + ENV["PORT"] = selected[:rails].to_s + ENV["SHAKAPACKER_DEV_SERVER_PORT"] = selected[:webpack].to_s if selected[:renderer] - ENV["RENDERER_PORT"] ||= selected[:renderer].to_s - ENV["REACT_RENDERER_URL"] ||= "http://localhost:#{selected[:renderer]}" + ENV["RENDERER_PORT"] = selected[:renderer].to_s + ENV["REACT_RENDERER_URL"] ||= "http://localhost:#{ENV['RENDERER_PORT']}" end rescue PortSelector::NoPortAvailable => e🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@react_on_rails/lib/react_on_rails/dev/server_manager.rb` around lines 836 - 843, The configure_ports method currently uses ||= which lets pre-existing ENV values override PortSelector.select_ports; change the assignments in configure_ports (the selected = PortSelector.select_ports block) to always set ENV["PORT"], ENV["SHAKAPACKER_DEV_SERVER_PORT"], and when selected[:renderer] set ENV["RENDERER_PORT"] and ENV["REACT_RENDERER_URL"] using direct assignment (=) so the selected ports become the effective env values for child processes and the renderer URL is updated consistently.react_on_rails/lib/react_on_rails/dev/port_selector.rb (1)
98-102:⚠️ Potential issue | 🟠 MajorValidate the base port against the highest derived offset.
Line 101 accepts
65_534and65_535, butselect_portsderiveswebpack = base + 1andrenderer = base + 2, producing invalid ports above65_535.🐛 Proposed fix
def base_port + max_base_port = 65_535 - BASE_PORT_RENDERER_OFFSET BASE_PORT_ENV_VARS.each do |var| val = ENV[var]&.to_i - return val if val&.between?(1, 65_535) + return val if val&.between?(1, max_base_port) end nil end🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@react_on_rails/lib/react_on_rails/dev/port_selector.rb` around lines 98 - 102, The base_port method currently accepts ENV values up to 65_535 but select_ports computes webpack = base + 1 and renderer = base + 2, which can yield ports > 65_535; update the validation in base_port (method name base_port, referenced by select_ports) to enforce an upper bound of 65_533 (i.e., ensure val.between?(1, 65_533) or subtract the maximum derived offset before validation) so that adding +1 and +2 cannot produce invalid ports.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@react_on_rails/lib/react_on_rails/dev/port_selector.rb`:
- Around line 98-102: The base_port method currently accepts ENV values up to
65_535 but select_ports computes webpack = base + 1 and renderer = base + 2,
which can yield ports > 65_535; update the validation in base_port (method name
base_port, referenced by select_ports) to enforce an upper bound of 65_533
(i.e., ensure val.between?(1, 65_533) or subtract the maximum derived offset
before validation) so that adding +1 and +2 cannot produce invalid ports.
In `@react_on_rails/lib/react_on_rails/dev/server_manager.rb`:
- Around line 836-843: The configure_ports method currently uses ||= which lets
pre-existing ENV values override PortSelector.select_ports; change the
assignments in configure_ports (the selected = PortSelector.select_ports block)
to always set ENV["PORT"], ENV["SHAKAPACKER_DEV_SERVER_PORT"], and when
selected[:renderer] set ENV["RENDERER_PORT"] and ENV["REACT_RENDERER_URL"] using
direct assignment (=) so the selected ports become the effective env values for
child processes and the renderer URL is updated consistently.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 89dd322b-8ac2-4e3f-9f75-b9ef2476038a
📒 Files selected for processing (18)
.gitignoredocs/oss/building-features/process-managers.mdreact_on_rails/lib/generators/react_on_rails/pro_setup.rbreact_on_rails/lib/generators/react_on_rails/templates/base/base/.env.examplereact_on_rails/lib/react_on_rails/dev/port_selector.rbreact_on_rails/lib/react_on_rails/dev/server_manager.rbreact_on_rails/spec/dummy/Procfile.devreact_on_rails/spec/dummy/Procfile.dev-prod-assetsreact_on_rails/spec/dummy/Procfile.dev-static-assetsreact_on_rails/spec/dummy/Procfile.dev.no.turbolinksreact_on_rails/spec/react_on_rails/dev/port_selector_spec.rbreact_on_rails/spec/react_on_rails/generators/install_generator_spec.rbreact_on_rails/spec/react_on_rails/support/shared_examples/pro_generator_examples.rbreact_on_rails_pro/spec/dummy/Procfile.devreact_on_rails_pro/spec/dummy/Procfile.prodreact_on_rails_pro/spec/dummy/Procfile.staticreact_on_rails_pro/spec/execjs-compatible-dummy/Procfile.devreact_on_rails_pro/spec/execjs-compatible-dummy/Procfile.dev-static
✅ Files skipped from review due to trivial changes (13)
- .gitignore
- react_on_rails_pro/spec/execjs-compatible-dummy/Procfile.dev-static
- react_on_rails/spec/dummy/Procfile.dev-static-assets
- react_on_rails/spec/dummy/Procfile.dev.no.turbolinks
- react_on_rails/spec/dummy/Procfile.dev-prod-assets
- react_on_rails_pro/spec/execjs-compatible-dummy/Procfile.dev
- react_on_rails/lib/generators/react_on_rails/pro_setup.rb
- react_on_rails_pro/spec/dummy/Procfile.prod
- react_on_rails/lib/generators/react_on_rails/templates/base/base/.env.example
- react_on_rails/spec/react_on_rails/generators/install_generator_spec.rb
- react_on_rails/spec/react_on_rails/support/shared_examples/pro_generator_examples.rb
- react_on_rails/spec/dummy/Procfile.dev
- docs/oss/building-features/process-managers.md
🚧 Files skipped from review as they are similar to previous changes (3)
- react_on_rails_pro/spec/dummy/Procfile.static
- react_on_rails_pro/spec/dummy/Procfile.dev
- react_on_rails/spec/react_on_rails/dev/port_selector_spec.rb
Addresses review comments on PR #3142 (REACT_ON_RAILS_BASE_PORT): - Validate base port against the largest derived offset so base+N stays within the valid TCP port range (1..65_535). A base of 65_534 previously passed validation but produced an invalid renderer port of 65_536. - Enforce the documented priority chain ("base port > explicit per-service env vars") in ServerManager.configure_ports. The former `||=` assignments silently preserved a pre-existing PORT/SHAKAPACKER_DEV_SERVER_PORT, making the effective Rails port disagree with the "Base port detected..." log line. When a base port is active, per-service env vars are now assigned unconditionally. - Preserve RENDERER_PORT and REACT_RENDERER_URL across Bundler.with_unbundled_env by adding them to ProcessManager::ENV_KEYS_TO_PRESERVE. Previously they were dropped for process managers launched outside the bundler context. - Derive REACT_RENDERER_URL from an explicit RENDERER_PORT in non-base-port worktrees when the user set the port but not the URL. - Remove the unused DEFAULT_RENDERER_PORT constant (the 3800 fallback only lives in Procfile shell expressions). - Add port_selector_spec cases for the max-safe and overflow base ports, and server_manager_spec cases for base-port priority override and explicit-RENDERER_PORT URL sync. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Review Feedback Addressed (commit b6e16df)I (Claude Code) went through all inline review comments from @claude, @cursor, @chatgpt-codex-connector, @coderabbitai, and @greptile and addressed every real issue raised. After triage (deduplicating overlapping comments across reviewers), six distinct concerns were identified and all six are now fixed in a single commit. Fixes
TestsAdded 5 new specs to On the bot summary comments (@claude, @greptile, @coderabbitai)Their summary bodies restate the inline findings that are already addressed above — no separate action needed. The earlier CodeRabbit "processing" notice is a stale status post. All 16 unresolved review threads are now resolved. |
|
To use Codex here, create an environment for this repo. |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chainLet me quickly verify the key changes in the updated code. 🏁 Script executed: Length of output: 58432
Everything looks solid. The 🧠 Learnings used |
Round 24 review wrap-up — 8 fixes from claude[bot] code reviewI (Claude Code) addressed every item from the latest claude[bot] review (1 review summary + 3 inline comments). All 8 changes landed in 11877c6 on MUST-FIX (2)
DISCUSS (1)
OPTIONAL (5)
Local verification
The 3 inline review threads are resolved. The 5 summary-only items are addressed in this comment plus the diff in 11877c6. |
Code ReviewOverviewThis PR adds The design is solid: the priority chain is clear, ENV mutation is explicitly documented ( Issues1. 2. 3. 4. Breaking rename: Minor Notes
Overall this is a well-thought-out feature with good documentation and edge-case coverage. The four numbered issues above are the ones worth addressing before merge; the minor notes are polish. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 9 total unresolved issues (including 8 from previous reviews).
Bugbot Autofix is ON, but it could not run because on-demand usage is turned off. To enable Bugbot Autofix, turn on on-demand usage and set a spend limit in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 11877c6. Configure here.
MUST-FIX (1):
- port_selector.rb: invalid_base_port_warning now filters `remaining`
with the same numeric + 1..MAX_BASE_PORT check used by base_port_ports
so we never falsely promise "Base port mode will still activate from
CONDUCTOR_PORT" when CONDUCTOR_PORT itself is also invalid (e.g.
REACT_ON_RAILS_BASE_PORT="disabled" + CONDUCTOR_PORT="abc"). Two new
specs lock the double-invalid and out-of-range fallthrough cases.
DISCUSS resolved (3):
- file_manager.rb: narrowed the ArgumentError rescue in socket_active?
to a tight begin/rescue around Socket.sockaddr_un only — that's the
one path Ruby actually raises ArgumentError ("too long unix socket
path"). The wider connect block no longer catches ArgumentError, so a
programming mistake in Socket.new or connect_nonblock surfaces
instead of being silently swallowed.
- server_manager.rb: kept clear_local_renderer_url_after_invalid_port's
delete-on-invalid-port behavior but expanded the comment to spell out
why we clear unconditionally — even when the user URL happens to
match the current Procfile default — so a future Procfile-default
change cannot silently re-introduce a Rails/renderer mismatch.
- port_selector.rb: added a quiet `select_ports` alias as a safety net
for any external caller that was on the pre-bang name. The bang form
remains preferred (round 23 rationale: ENV mutation explicit at the
call site); the alias is documented as deprecated and removable in a
future major.
OPTIONAL (4):
- server_manager.rb: run_production_like now strips whitespace from a
valid PORT (e.g. " 3001 " → "3001") so all bin/dev modes leave
ENV["PORT"] in the same shape — matches overwrite_invalid_port_env's
normalization used by configure_ports.
- server_manager.rb: extracted renderer_env_signal? helper from
pro_renderer_active?. configured_renderer_port_for_kill now returns
nil (not 3800) when no renderer env var is set, so OSS+Pro-gem apps
that never run the renderer don't have `bin/dev kill` widening the
kill scope to an unrelated process bound to 3800. Updated the spec
that locked in the old behavior; added a regression spec for the
legitimate "REACT_RENDERER_URL=http://localhost (no port) → kill 3800"
fallback.
- server_manager.rb: extended apply_explicit_port_env's comment to
spell out the upstream warning relationship —
PortSelector.read_and_sanitize_port_env! has already cleared invalid
PORT/SHAKAPACKER values and warned, so overwrite_invalid_port_env
silently writes the derived port (warning is upstream, not missing).
- port_selector_spec.rb: dropped the redundant `expect(result[:renderer])
.to be <= 65_535` assertion in the MAX_BASE_PORT context — the
preceding `eq(MAX_BASE_PORT + 2)` already pins the value; the second
line falsely implied an independent upper-bound check.
Tests: 266 dev specs pass (added 3 new specs across the round).
RuboCop: lib/react_on_rails/dev and spec/react_on_rails/dev clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Round 25 review wrap-up — 8 fixes from the latest claude/cursor bot passI (Claude Code) addressed every item from the latest claude[bot] code review plus the cursor[bot] inline (commit 2c67e07). All 5 unresolved inline threads have been replied-to and resolved; the 3 review-summary minor notes are addressed below. Inline threads (resolved)
Review-summary minor notes (no inline threads to resolve)
Verification
|
Per PR author feedback, drop the RENDERER_URL → REACT_RENDERER_URL rename in docs/oss/building-features/node-renderer/container-deployment.md. The original round 6 reasoning stands: this docs cleanup is unrelated to base-port mode and shouldn't be bundled with this PR. Restores the file to match origin/main exactly. CHANGELOG entry for configuration-pro.md is unchanged — only this file is reverted. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Code Review:
|
| # surfaces the ENV-mutation side effect at the call site, which was | ||
| # the whole point of the rename. Remove in a future major release. | ||
| def select_ports(**kwargs) | ||
| select_ports!(**kwargs) |
There was a problem hiding this comment.
The deprecated alias calls select_ports! with no user-visible signal that the method is deprecated. Any external caller (generator extension, host-app Rake task) who wired to select_ports before the rename won't know until they read the CHANGELOG or hit a future removal.
Consider emitting a runtime deprecation warning:
| select_ports!(**kwargs) | |
| def select_ports(**kwargs) | |
| warn "[DEPRECATION] ReactOnRails::Dev::PortSelector.select_ports is deprecated; " \ | |
| "use select_ports! instead. Called from #{caller_locations(1, 1).first}" | |
| select_ports!(**kwargs) | |
| end |
| next unless localhost_hostname?(parsed.hostname) | ||
| next unless url.match?(URL_WITH_EXPLICIT_PORT_RE) | ||
|
|
||
| return parsed.port |
There was a problem hiding this comment.
The inline rescue inside an .each block is valid Ruby (it rescues only the current iteration), but it reads as if it rescues the entire method. A reader skimming the code will see return parsed.port followed by rescue and assume the rescue applies to the block and the surrounding method body.
| return parsed.port | |
| def local_renderer_url_port_for_kill | |
| %w[REACT_RENDERER_URL RENDERER_URL].each do |var| | |
| url = ENV.fetch(var, nil) | |
| next if url.nil? || url.strip.empty? | |
| begin | |
| parsed = URI.parse(url) | |
| next unless localhost_hostname?(parsed.hostname) | |
| next unless url.match?(URL_WITH_EXPLICIT_PORT_RE) | |
| return parsed.port | |
| rescue URI::InvalidURIError | |
| next | |
| end | |
| end | |
| nil | |
| end |
| nil | ||
| rescue StandardError => e | ||
| # Genuinely unexpected: resource limits (Errno::EMFILE), interrupted | ||
| # syscall (Errno::EINTR), permission errors, etc. Always-warn so the |
There was a problem hiding this comment.
The fallback to File.expand_path when File.realpath raises SystemCallError is too broad. expand_path does not resolve symlinks, so a directory that exists but can't be realpath-resolved (e.g., broken symlink mid-path, Errno::EACCES on an intermediate directory) can return two different-looking strings for the same physical path — falsely treating the same directory as "different" and deleting the PID file when it should be kept.
The safe outcome here is to keep the PID file (return false from cleanup_rails_pid_file). Propagating or returning nil from same_working_directory? achieves that:
| # syscall (Errno::EINTR), permission errors, etc. Always-warn so the | |
| def same_working_directory?(left, right) | |
| File.realpath(left) == File.realpath(right) | |
| rescue Errno::ENOENT | |
| # One path no longer exists (process exited mid-probe); treat as different. | |
| false | |
| end |
| # or readlink unsupported on this platform. Fall through to lsof. | ||
| nil | ||
| end | ||
|
|
There was a problem hiding this comment.
Adding -w to suppress lsof warnings and -F0n (null-delimited) instead of -Fn would make parsing more robust across old lsof versions that may emit header lines before the n-prefixed cwd entry. As-is, if lsof emits a non-cwd n-prefixed line before the cwd line, this returns the wrong path — low risk with -d cwd, but worth tightening.
| stdout, = Open3.capture2("lsof", "-a", "-p", pid.to_s, "-d", "cwd", "-Fn", "-w", err: File::NULL) |
…y-adapter Brings in #3142 (REACT_ON_RAILS_BASE_PORT for concurrent worktree ports) and #3124 (renderer cache staging alignment with bundle-hash layout). Conflict resolution preserved this branch's rolling-deploy adapter additions: - CHANGELOG: kept rolling-deploy-adapter entry alongside main's updated "Unified renderer cache staging" entry. - docs/pro/node-renderer.md: kept the rolling-deploy-adapter-aware "Rolling deploys" section over main's interim copy. - doctor.rb / doctor_spec.rb: kept check_rolling_deploy_adapter while adopting main's multi-line .kamal/ suggestion, config/deploy/staging.rb scan path, and staging-config spec. - react_on_rails_pro.rb / assets_precompile.rb: kept rolling_deploy_cache_stager require, publish_current_bundle_if_configured call, and supporting private methods. - pre_seed_renderer_cache.rb / renderer_cache_helpers.rb: kept the branch's refactor that moves stage_file / make_relative_symlink into helpers and threads current_hashes into RollingDeployCacheStager.call. - assets.rake: adopted main's NodeRenderer guard and BlockLength disable. - specs: kept rolling_deploy_adapter stub on configuration doubles.
…y-patch-DrhDk * origin/main: docs: document legacy Webpacker compatibility shims (#3225) chore: sync address-review command and import prompt variant (#3271) feat: add REACT_ON_RAILS_BASE_PORT for concurrent worktree port management (#3142) feat: align renderer cache staging with bundle-hash layout (#3124) docs: document benchmark gate tuning plan (#3234) docs: document Gumroad RSC benchmark signal (#3233) docs: document migration proof artifact template (#3227) fix: support nested JavaScript package roots in doctor (#3220) docs: add Claude verify command (#3235) fix: serialize generated pack regeneration (#3231) docs: amend CHANGELOG entry for #3229 scope drift fix: validate selected JavaScript package manager fix: preserve causes when wrapping render errors (#3230) # Conflicts: # CHANGELOG.md
* origin/main: docs: document RSC node renderer test setup (#3223) Clarify Pro pricing and license guidance (#3272) docs: add AI security scanner evaluation plan (#3236) fix: pin pnpm version in scaffolded CI when packageManager is absent (#3172) (#3174) docs: document RSC HTTP response ownership (#3222) docs: document legacy Webpacker compatibility shims (#3225) chore: sync address-review command and import prompt variant (#3271) feat: add REACT_ON_RAILS_BASE_PORT for concurrent worktree port management (#3142) feat: align renderer cache staging with bundle-hash layout (#3124) docs: document benchmark gate tuning plan (#3234) docs: document Gumroad RSC benchmark signal (#3233) docs: document migration proof artifact template (#3227) fix: support nested JavaScript package roots in doctor (#3220) docs: add Claude verify command (#3235) fix: serialize generated pack regeneration (#3231) # Conflicts: # .gitignore # react_on_rails/spec/dummy/Procfile.dev

Summary
REACT_ON_RAILS_BASE_PORTenv var that derives all service ports from a single base value (Rails = base+0, webpack = base+1, renderer = base+2)CONDUCTOR_PORTas a fallback, so Conductor.build works out of the box${PORT:-3000}and${RENDERER_PORT:-3800}patterns instead of hardcoded valuesRENDERER_PORTandREACT_RENDERER_URLenv vars for automatic Pro Node Renderer configurationThis enables coding agent tools (Conductor.build, Codex, Quad Code, etc.) to run multiple worktrees concurrently without port conflicts — just set one env var and everything works.
Changes
Core logic:
PortSelector: new base port priority tier (checked before explicit env vars and auto-detect)ServerManager.configure_ports: setsRENDERER_PORTandREACT_RENDERER_URLwhen base port is activeProcfile templates (all now use env var fallbacks):
Procfile.dev,Procfile.dev-prod-assets,Procfile.dev-static-assetsProcfile.dev,Procfile.prod,Procfile.staticpro_setup.rb): uses${RENDERER_PORT:-3800}in generated Procfile linesDocumentation:
.env.example: documents base port,RENDERER_PORT, andREACT_RENDERER_URLprocess-managers.md: new "Coding Agent / CI Integration" and "Manual Worktree Port Setup (Pro)" sectionsTest plan
REACT_ON_RAILS_BASE_PORT=4000 bin/devprints correct port assignments🤖 Generated with Claude Code
Note
Medium Risk
Touches
bin/devport selection and environment propagation across multiple modes, so misconfiguration could break local dev startup or point SSR at the wrong renderer URL/port. Changes are well-covered by extensive new/updated specs but affect widely-used developer tooling.Overview
Adds deterministic “base port” mode to
bin/dev: whenREACT_ON_RAILS_BASE_PORT(or fallbackCONDUCTOR_PORT) is set, Rails/webpack/node-renderer ports are derived asbase+0/+1/+2and override any conflicting per-service env vars, with warnings.Improves dev reliability around Pro renderer configuration by syncing
RENDERER_PORT↔REACT_RENDERER_URL, warning on legacyRENDERER_URLusage/mismatches, and preserving more runtime env vars across Bundler’s env reset so spawned processes keep the derived ports/URLs.Hardens copied-worktree startup/kill flows by cleaning stale Overmind sockets and cross-directory
tmp/pids/server.pid, updates Procfiles and generator output to use${PORT:-...}/${RENDERER_PORT:-...}defaults, and expands docs/tests to cover the new precedence rules and edge cases.Reviewed by Cursor Bugbot for commit d90fcef. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by CodeRabbit
New Features
Behavior Changes
Documentation
Tests
Chores