Docs: Clarify .client/.server suffixes vs 'use client' RSC directive#2406
Docs: Clarify .client/.server suffixes vs 'use client' RSC directive#2406AbanoubGhadban wants to merge 10 commits intomasterfrom
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:
WalkthroughDocumentation updates across multiple files clarify that file suffix-based bundling ( Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 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 |
Greptile OverviewGreptile SummaryClarifies the distinction between Major changes:
Issues found:
Confidence Score: 4/5
Important Files Changed
Last reviewed commit: c138ab3 |
.claude/docs/project-architecture.md
Outdated
| A React on Rails auto-bundling feature that controls which **webpack bundle** imports a file. This exists independently of React Server Components and is used with or without RSC: | ||
|
|
||
| - `Component.client.jsx` → client bundle only (browser) | ||
| - `Component.server.jsx` → server bundle only (Node.js SSR). Must have a paired `.client.` file. |
There was a problem hiding this comment.
Inconsistent with glossary: the glossary correctly states .server.jsx goes into "server and the RSC bundle" (line 17 of react_on_rails_pro/docs/react-server-components/glossary.md), but here it says "server bundle only". When RSC is enabled, .server.jsx files are included in both bundles.
| - `Component.server.jsx` → server bundle only (Node.js SSR). Must have a paired `.client.` file. | |
| - `Component.server.jsx` → server bundle (and RSC bundle when RSC enabled). Must have a paired `.client.` file. |
There was a problem hiding this comment.
Fixed — updated to "server bundle (and RSC bundle when RSC enabled)" to match the glossary. Also updated the table rows for consistency.
There was a problem hiding this comment.
Good catch — fixed. .server.jsx now correctly says "server bundle (and RSC bundle when RSC enabled)" in both the bullet point and the table.
AGENTS.md
Outdated
| A React on Rails auto-bundling feature that controls which webpack bundle imports a file. This exists independently of React Server Components and is used with or without RSC: | ||
|
|
||
| - `Component.client.jsx` → imported only in the **client bundle** (browser) | ||
| - `Component.server.jsx` → imported only in the **server bundle** (Node.js SSR) |
There was a problem hiding this comment.
Same inconsistency: should clarify that .server.jsx files go into server bundle AND RSC bundle (when RSC is enabled), not just "server bundle"
| - `Component.server.jsx` → imported only in the **server bundle** (Node.js SSR) | |
| - `Component.server.jsx` → imported only in the **server bundle** (and RSC bundle when RSC enabled) |
There was a problem hiding this comment.
Fixed — same correction applied here.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In @.claude/docs/project-architecture.md:
- Around line 108-114: The documentation block contains fragile, stale
line-number references that will drift; remove all the approximate line
references and leave only the stable method identifiers (e.g.,
common_component_to_path, client_component_to_path, server_component_to_path,
client_entrypoint?, pack_file_contents) and brief descriptions so readers can
grep by name instead of relying on line numbers.
🧹 Nitpick comments (1)
react_on_rails_pro/docs/react-server-components/glossary.md (1)
12-12: Heading level is higher than preceding glossary entry.The first entry "RSC (React Server Component)" at line 3 uses
###(H3), but this new section uses##(H2). This is intentional for visual prominence as a callout, but it breaks the glossary's heading hierarchy — a reader might expect entries to be at consistent levels under the H1 title.
.claude/docs/project-architecture.md
Outdated
| the exception silently stops working. CI guards (`script/check-react-major-version.mjs`) | ||
| will catch version mismatches. | ||
|
|
||
| ## File Suffixes vs. RSC Directive (Important Distinction) |
There was a problem hiding this comment.
| ## File Suffixes vs. RSC Directive (Important Distinction) | |
| ## `.client` and `.server` File Suffixes vs. RSC Directive (Important Distinction) |
There was a problem hiding this comment.
Applied, thanks!
There was a problem hiding this comment.
Applied, thanks!
.claude/docs/project-architecture.md
Outdated
| - **Registration**: Components with `'use client'` are registered via `ReactOnRails.register()`. Components without it are registered via `registerServerComponent()`. | ||
| - **RSC bundling**: The RSC webpack loader uses this directive to decide whether a component is included in the RSC bundle or replaced with a client reference in that bundle. | ||
|
|
||
| Checked by `client_entrypoint?` in `packs_generator.rb`. |
There was a problem hiding this comment.
It'''s a cross-reference to the implementation — helps agents (and developers) know which method in packs_generator.rb handles the '\''use client'\'' detection. Reworded it to read more clearly as a full sentence instead of a terse note.
There was a problem hiding this comment.
It's a cross-reference to the implementation — helps agents (and developers) know which method in packs_generator.rb handles the 'use client' detection. Reworded it to read more clearly as a full sentence.
.claude/docs/project-architecture.md
Outdated
|
|
||
| ### How They Interact | ||
|
|
||
| These are orthogonal. The suffix controls which bundle, the directive controls RSC registration: |
There was a problem hiding this comment.
| These are orthogonal. The suffix controls which bundle, the directive controls RSC registration: | |
| These are orthogonal concerns. The file suffix controls which bundle, and the directive controls RSC registration: |
There was a problem hiding this comment.
Applied, thanks!
There was a problem hiding this comment.
Applied, thanks!
| - Each component gets its own webpack bundle for optimal code splitting | ||
| - No manual `ReactOnRails.register()` calls needed | ||
| - Supports separate `.client.jsx` and `.server.jsx` files for different rendering logic | ||
| - Supports separate `.client.jsx` and `.server.jsx` files for different rendering logic (these control **bundle placement**, not [React Server Components](../../react_on_rails_pro/docs/react-server-components/glossary.md)) |
There was a problem hiding this comment.
| - Supports separate `.client.jsx` and `.server.jsx` files for different rendering logic (these control **bundle placement**, not [React Server Components](../../react_on_rails_pro/docs/react-server-components/glossary.md)) | |
| - Supports separate `.client.jsx` and `.server.jsx` files for different rendering logic (these control **client versus server bundle placement**, not [React Server Components](../../react_on_rails_pro/docs/react-server-components/glossary.md)) |
There was a problem hiding this comment.
Applied, thanks!
|
Heads-up for merge sequencing with the docs cleanup work: I opened #2414 to move internal-only docs out of published trees:
Since #2406 already edits
That keeps agent guidance consistent immediately after the docs move. |
|
Thanks for the heads-up on #2414. Happy to rebase after it merges and update the |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
.claude/docs/project-architecture.md (1)
97-105: Consider scoping the "Registered as" column to RSC-enabled modeThe table is conceptually correct, but the "Registered as" column only reflects RSC-enabled behavior (i.e.,
registerServerComponent()is called instead ofReactOnRails.register()for components without'use client'). In non-RSC configurations the'use client'directive has no effect on registration — all components go throughReactOnRails.register(). A reader who skims the table without reading the preceding RSC-Classification prose (lines 86–90) could wrongly conclude, for example, thatFoo.client.jsxwithout'use client'is always registered as a "Server component".Adding a brief scope note to the table makes this self-contained:
✏️ Proposed clarification
-### How They Interact +### How They Interact (RSC-enabled mode) These are orthogonal concerns. The file suffix controls which bundle, and the directive controls RSC registration: +> **Note**: The "Registered as" column applies only when RSC support is enabled (Pro feature). +> Without RSC, all components are registered via `ReactOnRails.register()` regardless of the `'use client'` directive. + | File | `'use client'`? | Goes into | Registered as |🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.claude/docs/project-architecture.md around lines 97 - 105, Add a short scope note above or below the table clarifying that the "Registered as" column reflects RSC-enabled mode only: in RSC-enabled builds components without the 'use client' directive are registered via registerServerComponent(), whereas in non-RSC configurations all files (e.g., Foo.jsx, Foo.client.jsx, Foo.server.jsx) are registered with ReactOnRails.register() and the 'use client' directive does not affect registration; update the table caption or add a one-line footnote to that effect so readers don’t misinterpret the entries.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.claude/docs/project-architecture.md:
- Line 112: Edit the documentation text for the symbol
`server_component_to_path` to fix the grammar: change the phrase "requires
paired `.client.`" to "requires a paired `.client.`" so the line reads
"`server_component_to_path` — finds `.server.` files (requires a paired
`.client.`)"; no code changes required, just update the doc string/text entry
where `server_component_to_path` is documented.
---
Nitpick comments:
In @.claude/docs/project-architecture.md:
- Around line 97-105: Add a short scope note above or below the table clarifying
that the "Registered as" column reflects RSC-enabled mode only: in RSC-enabled
builds components without the 'use client' directive are registered via
registerServerComponent(), whereas in non-RSC configurations all files (e.g.,
Foo.jsx, Foo.client.jsx, Foo.server.jsx) are registered with
ReactOnRails.register() and the 'use client' directive does not affect
registration; update the table caption or add a one-line footnote to that effect
so readers don’t misinterpret the entries.
PR Review: Docs — Clarify
|
PR Review: Docs — Clarify
|
Review: Docs clarification for
|
…s, apply maintainer suggestions - Fix .server.jsx bundle destination to include RSC bundle when RSC enabled - Remove fragile line-number references from code paths section - Apply heading, wording, and cross-reference improvements from review Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…undle Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The explanatory sentence on line 176 said "only in the server bundle" contradicting line 173 which correctly includes the RSC bundle. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
05415a9 to
e2658e6
Compare
| # These are orthogonal. A .client.jsx file can be a React Server Component (if it lacks | ||
| # 'use client'), and a .server.jsx file can be a React Client Component (if it has 'use client'). | ||
| # | ||
| class PacksGenerator |
There was a problem hiding this comment.
The class-level documentation block is sandwiched between the # rubocop:disable directive and class PacksGenerator. In Ruby, YARD/RDoc convention is to place the documentation comment block immediately above the class keyword. The standard approach would be:
module ReactOnRails
# This class handles two INDEPENDENT classification systems:
# ...
# rubocop:disable Metrics/ClassLength
class PacksGeneratorOr, if the rubocop directive must come first (to suppress a lint warning that might fire on the comment itself), at minimum a blank line between the rubocop comment and the documentation would make it clearer the documentation block belongs to the class below it.
As written, a reader quickly scanning the file sees # rubocop:disable as the only thing "above" the class, and has to look further to find the actual class doc.
There was a problem hiding this comment.
The placement works fine here — the rubocop directive must come before the class definition to suppress the lint warning. The comment block is immediately above the class keyword and reads clearly.
docs/core-concepts/auto-bundling-file-system-based-automated-bundle-generation.md
Show resolved
Hide resolved
Review: Docs clarifying
|
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@docs/core-concepts/auto-bundling-file-system-based-automated-bundle-generation.md`:
- Around line 497-501: The admonition block contains a blank quote line (the
standalone ">" at the end) which triggers markdownlint rule MD028; to fix either
remove the blank blockquote line by merging the admonition into a single
paragraph (update the text inside the block that begins with "[!IMPORTANT]" so
it has no empty ">" line) or disable the rule globally by adding
"no-blanks-blockquote": false to coderabbit.markdownlint-cli2.jsonc; update the
admonition in
docs/core-concepts/auto-bundling-file-system-based-automated-bundle-generation.md
(the [!IMPORTANT] block) or adjust the linter config accordingly.
In `@react_on_rails/lib/react_on_rails/packs_generator.rb`:
- Line 14: The comment string "Component.server.jsx → server bundle (and RSC
bundle when RSC enabled; requires paired .client. file)" is missing the article
"a"; update the comment in react_on_rails::packs_generator.rb (the line
containing that string) to read "...requires a paired .client. file" so the
grammar is correct (apply same change where similar text appears, e.g.,
.claude/docs/project-architecture.md).
docs/core-concepts/auto-bundling-file-system-based-automated-bundle-generation.md
Show resolved
Hide resolved
…mmar in packs_generator - auto-bundling doc: "only in the server bundle" → include RSC bundle qualifier - packs_generator.rb: "requires paired" → "requires a paired" - Collapse multi-paragraph blockquote into single paragraph Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In
`@docs/core-concepts/auto-bundling-file-system-based-automated-bundle-generation.md`:
- Around line 497-499: The blockquote admonition starting with "[!IMPORTANT]"
contains a trailing empty blockquote marker (a lone ">" line) that triggers
MD028; remove the stray blank blockquote marker so the admonition is a
contiguous block (ensure there is no standalone ">" on the following line after
the paragraph that ends with the RSC glossary link), leaving the multi-line
admonition intact without any blank blockquote lines.
Review: HEAD commit e05ef9cThe documentation intent and core technical claims are accurate — this is a genuinely useful clarification of two orthogonal systems. Verified against source:
Three items remain open at HEAD that have been flagged in prior review threads: 1. Table scope note (blocking — factual gap) 2. Heading hierarchy in 3. Blank-line between blockquotes in auto-bundling doc (style) |
.claude/docs/project-architecture.md
Outdated
|
|
||
| The `client_entrypoint?` method in `packs_generator.rb` is what detects this directive during auto-bundling. | ||
|
|
||
| ### How They Interact |
There was a problem hiding this comment.
The "Registered as" column only applies when RSC support is enabled (Pro feature). Without RSC, all components — regardless of file suffix or 'use client' directive — are registered via ReactOnRails.register(). A reader who skims this table without reading the preceding prose could conclude that Foo.client.jsx without 'use client' is "always registered as a Server component", which is wrong for non-Pro installs.
Suggested fix: rename the section heading and add a scope note:
| ### How They Interact | |
| ### How They Interact (RSC-enabled mode) | |
| These are orthogonal concerns. The file suffix controls which bundle, and the directive controls RSC registration: | |
| > **Note**: The "Registered as" column applies only when RSC support is enabled (Pro feature). | |
| > Without RSC, all components are registered via `ReactOnRails.register()` regardless of the `'use client'` directive. | |
There was a problem hiding this comment.
Fixed — renamed heading to "How They Interact (RSC-enabled mode)" and added a note that without RSC all components use ReactOnRails.register().
| - Improved initial page load | ||
| - Better SEO | ||
|
|
||
| ## Important: `.client.` / `.server.` File Suffixes Are Unrelated |
There was a problem hiding this comment.
The new ## Important: section (H2) is inserted after the existing ### RSC (React Server Component) entry (H3). This inverts the expected heading hierarchy — a callout uses a higher-level heading than the preceding glossary entries.
Two clean options:
- Change this heading to
###so it matches the other entries, e.g.:### Note: `.client.` / `.server.` File Suffixes Are Unrelated to RSC - Promote the existing
### RSCentry to##so the glossary has consistent H2 top-level entries.
The content itself is correct and well-placed; it's purely a heading-level issue.
There was a problem hiding this comment.
Added an HTML comment explaining the intentional H2 heading. The callout must visually stand out above the H3 glossary entries to prevent the exact confusion this PR addresses.
| > [!IMPORTANT] | ||
| > **Not related to React Server Components.** The `.client.` and `.server.` file suffixes control **which webpack bundle** imports the file (client bundle vs. server bundle for SSR) — a React on Rails auto-bundling concept that predates React Server Components. If you are using React Server Components (Pro feature), RSC classification is controlled separately by the `'use client'` directive; a `.server.jsx` file is NOT automatically a React Server Component. See the [RSC glossary](../../react_on_rails_pro/docs/react-server-components/glossary.md) for details. | ||
|
|
||
| > Example (dummy app): paired files such as [`ReduxApp.client.jsx`](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails/spec/dummy/client/app/startup/ReduxApp.client.jsx) and [`ReduxApp.server.jsx`](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails/spec/dummy/client/app/startup/ReduxApp.server.jsx), and [`RouterApp.client.jsx`](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails/spec/dummy/client/app/startup/RouterApp.client.jsx) and [`RouterApp.server.jsx`](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails/spec/dummy/client/app/startup/RouterApp.server.jsx). |
There was a problem hiding this comment.
Two consecutive blockquote blocks separated by a blank line (lines 497–498 = the [!IMPORTANT] block; line 500 = the > Example block). No markdownlint config is present in the repo so this won't fail CI, but it can trigger MD028 in external tools. Merging the blank line with a bare > continuation keeps both visually separate while avoiding the issue:
| > [!IMPORTANT] | |
| > **Not related to React Server Components.** The `.client.` and `.server.` file suffixes control **which webpack bundle** imports the file (client bundle vs. server bundle for SSR) — a React on Rails auto-bundling concept that predates React Server Components. If you are using React Server Components (Pro feature), RSC classification is controlled separately by the `'use client'` directive; a `.server.jsx` file is NOT automatically a React Server Component. See the [RSC glossary](../../react_on_rails_pro/docs/react-server-components/glossary.md) for details. | |
| > Example (dummy app): paired files such as [`ReduxApp.client.jsx`](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails/spec/dummy/client/app/startup/ReduxApp.client.jsx) and [`ReduxApp.server.jsx`](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails/spec/dummy/client/app/startup/ReduxApp.server.jsx), and [`RouterApp.client.jsx`](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails/spec/dummy/client/app/startup/RouterApp.client.jsx) and [`RouterApp.server.jsx`](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails/spec/dummy/client/app/startup/RouterApp.server.jsx). | |
| > [!IMPORTANT] | |
| > **Not related to React Server Components.** The `.client.` and `.server.` file suffixes control **which webpack bundle** imports the file (client bundle vs. server bundle for SSR) — a React on Rails auto-bundling concept that predates React Server Components. If you are using React Server Components (Pro feature), RSC classification is controlled separately by the `'use client'` directive; a `.server.jsx` file is NOT automatically a React Server Component. See the [RSC glossary](../../react_on_rails_pro/docs/react-server-components/glossary.md) for details. | |
| > | |
| > Example (dummy app): paired files such as [`ReduxApp.client.jsx`](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails/spec/dummy/client/app/startup/ReduxApp.client.jsx) and [`ReduxApp.server.jsx`](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails/spec/dummy/client/app/startup/ReduxApp.server.jsx), and [`RouterApp.client.jsx`](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails/spec/dummy/client/app/startup/RouterApp.client.jsx) and [`RouterApp.server.jsx`](https://github.com/shakacode/react_on_rails/blob/master/react_on_rails/spec/dummy/client/app/startup/RouterApp.server.jsx). |
There was a problem hiding this comment.
Fixed — added an HTML comment between the two blockquotes to avoid MD028.
…ading intent comment - Add note that "Registered as" column applies only in RSC-enabled mode - Separate consecutive blockquotes with HTML comment to avoid MD028 - Add comment explaining intentional H2 heading in glossary Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Review: Docs — Clarify .client/.server suffixes vs 'use client' RSC directiveThis is a well-targeted PR. The confusion between A few issues to address before merging: 1. Heading hierarchy break in
|
| - Better SEO | ||
|
|
||
| <!-- H2 is intentional here: this callout must stand out above the H3 glossary entries to prevent confusion --> | ||
| ## Important: `.client.` / `.server.` File Suffixes Are Unrelated |
There was a problem hiding this comment.
The heading level here creates a non-monotonic structure: the document goes # React Server Components Glossary (H1) → ### RSC (React Server Component) (H3, skipping H2) → ## Important: … (H2, coming after an H3). MD001 will flag this, and navigation tools/screen readers will present a confusing outline.
Two options:
- Fix the existing hierarchy: change
### RSC (React Server Component)to## RSC (React Server Component)— then this H2 fits naturally before the## Types of Componentssection. - Keep H3 entries as-is, use a callout instead: replace the
##heading with a[!IMPORTANT]or[!WARNING]callout block, which provides visual standout without affecting heading structure.
| ## Important: `.client.` / `.server.` File Suffixes Are Unrelated | |
| > [!IMPORTANT] | |
| > **`.client.` / `.server.` File Suffixes Are Unrelated to React Server Components** |
| A React on Rails auto-bundling feature that controls which webpack bundle imports a file. This exists independently of React Server Components and is used with or without RSC: | ||
|
|
||
| - `Component.client.jsx` → imported only in the **client bundle** (browser) | ||
| - `Component.server.jsx` → imported only in the **server bundle** (and RSC bundle when RSC enabled) |
There was a problem hiding this comment.
Missing pairing constraint. server_component_to_path calls raise_missing_client_component for every .server.jsx that has no matching .client.jsx, so a standalone .server.jsx is a hard error at pack-generation time. An agent reading only this bullet will generate invalid scaffolding.
| - `Component.server.jsx` → imported only in the **server bundle** (and RSC bundle when RSC enabled) | |
| - `Component.server.jsx` → imported only in the **server bundle** (and RSC bundle when RSC enabled). **Must be paired with a `Component.client.jsx` file** — a `.server.jsx` without a matching `.client.jsx` raises an error during pack generation. |
| | `Foo.server.jsx` | Yes | Server bundle (+ RSC bundle) | Client component | | ||
| | `Foo.server.jsx` | No | Server bundle (+ RSC bundle) | Server component | |
There was a problem hiding this comment.
The table presents Foo.server.jsx rows as standalone valid configurations, but server_component_to_path enforces that every .server.jsx must have a paired .client.jsx — omitting the pair raises raise_missing_client_component at pack generation time. Foo.client.jsx has no such pairing requirement.
Consider adding a footnote or a ‡ marker on both Foo.server.jsx rows with a note like: "‡ Requires a paired Foo.client.jsx; a .server.jsx without a matching .client.jsx raises an error." This is important context for agents using this table when scaffolding components.
Pre-existing formatting issues unrelated to this PR's changes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
size-limit report 📦
|
PR Review: Docs - Clarify .client/.server suffixes vs 'use client' RSC directiveThe documentation intent here is solid and addresses a real source of confusion. A few issues worth addressing: Heading hierarchy regression in
|
| collectStreamData(stream1), | ||
| collectStreamData(stream2), | ||
| ]); | ||
| const [data1, data2] = await Promise.all([collectStreamData(stream1), collectStreamData(stream2)]); |
There was a problem hiding this comment.
This formatting change (collapsing to one line) is not related to the docs clarification goal of this PR. While 105 chars is within the printWidth: 110 Prettier config and the format is valid, mixing formatting churn into a docs PR complicates review. Consider moving this to a separate formatting commit or PR.
Clarify across docs and code that
.client./.server.file suffixes (bundle placement) and'use client'directive (RSC classification) are independent concepts. The main goal is avoiding LLM misconception about auto-bundling postfixes and React Server Components — LLMs consistently confuse.server.jsxfiles with React Server Components.Closes #2405
🤖 Generated with Claude Code
Summary by CodeRabbit