Skip to content

perf(compose): optimize chat UI recompositions and allocations#381

Closed
yacosta738 wants to merge 3 commits into
mainfrom
perf/compose-ui-optimizations-14414712215313423242
Closed

perf(compose): optimize chat UI recompositions and allocations#381
yacosta738 wants to merge 3 commits into
mainfrom
perf/compose-ui-optimizations-14414712215313423242

Conversation

@yacosta738
Copy link
Copy Markdown
Contributor

Optimized the Compose Multiplatform Chat UI by isolating the message list recompositions and caching modifiers/brushes. This reduces main-thread work and GC pressure during user typing.

Key changes:

  • Extracted MessageList in ChatWorkspace.kt to isolate it from high-frequency query state changes.
  • Wrapped top-level Modifier chains and Brush objects in remember blocks.
  • Updated ChatInputField to accept a stable onSend callback, avoiding redundant lambda allocations.
  • Documented changes in .agents/journal/bolt-journal.md.

PR created automatically by Jules for task 14414712215313423242 started by @yacosta738

Co-authored-by: yacosta738 <33158051+yacosta738@users.noreply.github.com>
@google-labs-jules
Copy link
Copy Markdown
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 1, 2026

📝 Walkthrough

Summary by CodeRabbit

  • Refactor
    • Improved chat UI performance to reduce re-renders while typing.
    • Reduced memory churn by caching frequently used visual resources.
    • Separated message list from input so messages don't recompute during typing.
    • Made message send handling more consistent and responsive.

Walkthrough

Jetpack Compose runtime optimizations for the chat UI: extracted MessageList to decouple it from input/query state, memoized frequently constructed UI resources (Modifiers, Brushes), and changed ChatInputField to use a stable onSend(String) callback with trimmed input.

Changes

Cohort / File(s) Summary
Documentation
.agents/journal/bolt-journal.md
New journal entry describing the Compose runtime optimizations and component extraction for the chat UI.
Avatar & Input Field
clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatComponents.kt
Added ChatInputFieldProps and refactored ChatInputField to accept props; onSend now receives a trimmed String; AvatarWithGlow and send-button modifiers/brushes are memoized with remember.
Workspace & Message List
clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatWorkspace.kt
Memoized displayMessages and top-level modifiers/brushes; introduced MessageList composable and ChatPanelState; updated wiring to pass ChatInputFieldProps and stable onSend.
CI Workflow
.github/workflows/fix-renovate.yml
Simplified mismatch checks into a single failure condition comparing expected PR head values.
Workspace config
pnpm-workspace.yaml
Downgraded happy-dom version from 20.8.9 to 20.8.8.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • yuniel-acosta
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title follows Conventional Commits style with 'perf' prefix, uses imperative language, and clearly describes the optimization focus on chat UI recompositions.
Description check ✅ Passed The PR description covers the main objectives and key changes effectively, though it lacks explicit sections for testing, documentation impact, and breaking changes as specified in the template.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch perf/compose-ui-optimizations-14414712215313423242

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 and usage tips.

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Apr 1, 2026

Deploying corvus with  Cloudflare Pages  Cloudflare Pages

Latest commit: 10105e4
Status: ✅  Deploy successful!
Preview URL: https://3df13c74.corvus-42x.pages.dev
Branch Preview URL: https://perf-compose-ui-optimization.corvus-42x.pages.dev

View logs

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 1, 2026

✅ Contributor Report

User: @yacosta738
Status: Passed (12/13 metrics passed)

Metric Description Value Threshold Status
PR Merge Rate PRs merged vs closed 89% >= 30%
Repo Quality Repos with ≥100 stars 0 >= 0
Positive Reactions Positive reactions received 10 >= 1
Negative Reactions Negative reactions received 0 <= 5
Account Age GitHub account age 3078 days >= 30 days
Activity Consistency Regular activity over time 108% >= 0%
Issue Engagement Issues with community engagement 0 >= 0
Code Reviews Code reviews given to others 500 >= 0
Merger Diversity Unique maintainers who merged PRs 2 >= 0
Repo History Merge Rate Merge rate in this repo 91% >= 0%
Repo History Min PRs Previous PRs in this repo 190 >= 0
Profile Completeness Profile richness (bio, followers) 90 >= 0
Suspicious Patterns Spam-like activity detection 1 N/A

Contributor Report evaluates based on public GitHub activity. Analysis period: 2025-04-02 to 2026-04-02

@yacosta738 yacosta738 marked this pull request as ready for review April 2, 2026 05:25
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatComponents.kt (2)

283-295: 🧹 Nitpick | 🔵 Trivial

Memoization keys may cause unnecessary re-creations.

The sendButtonModifier remember block uses gradient (itself a remembered Brush) as a key. Since Brush doesn't implement stable equality by default, this could defeat the caching. Consider using corvusColors.gradientPrimary directly as the key instead.

♻️ Suggested fix
     val sendButtonModifier =
-      remember(isEnabled, gradient, corvusColors.glowPurple) {
+      remember(isEnabled, corvusColors.gradientPrimary, corvusColors.glowPurple) {
         Modifier.size(48.dp)
           .shadow(
             elevation = 6.dp,
             shape = CircleShape,
             spotColor = if (isEnabled) corvusColors.glowPurple else Color.Gray,
           )
           .clip(CircleShape)
           .background(
             if (isEnabled) gradient else Brush.linearGradient(listOf(Color.Gray, Color.Gray))
           )
       }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatComponents.kt`
around lines 283 - 295, The remember block for sendButtonModifier is using
gradient (a Brush) as a key which can prevent proper memoization; change the
remember keys to use stable values such as isEnabled and
corvusColors.gradientPrimary (or corvusColors.glowPurple) instead of the
gradient Brush, and then use the existing gradient value inside the block;
update the remember call that creates sendButtonModifier to reference
corvusColors.gradientPrimary (or another stable color/identifier) as the key
while keeping the body unchanged so the modifier isn't recreated unnecessarily.

236-308: ⚠️ Potential issue | 🟡 Minor

Address Detekt pipeline failures.

The pipeline reports:

  • LongParameterList: 7 parameters exceed the threshold of 6.
  • LongMethod: 62 lines exceed the threshold of 60.

Consider extracting the send button into a separate composable (e.g., SendButton) to reduce method length and improve modularity. Alternatively, suppress with justification if the team accepts this structure.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatComponents.kt`
around lines 236 - 308, The ChatInputField composable currently violates Detekt
rules (LongParameterList and LongMethod); fix by extracting the send-button UI
into a new composable SendButton (take isEnabled, gradient/brush, glow color,
onSend and value/trim as needed) and by collapsing multiple parameters into a
single data holder (e.g., ChatInputFieldProps or ChatInputState) so
ChatInputField signature no longer has 7 parameters; update callers to pass the
new props object and move the send-button creation (remember block, Box,
IconButton) into SendButton to reduce ChatInputField length below threshold and
eliminate the LongParameterList violation.
clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatWorkspace.kt (2)

284-326: ⚠️ Potential issue | 🟡 Minor

Acknowledge Detekt LongParameterList on ChatPanel.

The pipeline flags 7 parameters exceeding the threshold of 6. Consider grouping related params into a data class (e.g., combine state, bridgeState, pendingApproval into a ChatPanelState) or suppress with justification.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatWorkspace.kt`
around lines 284 - 326, The ChatPanel function currently has 7 parameters
triggering Detekt LongParameterList; refactor by creating a small data holder
(e.g., ChatPanelState) that groups related params such as state:
ChatWorkspaceState, bridgeState: MobileBridgeUiState, and pendingApproval:
RuntimeApprovalRequest? into one object and update the ChatPanel signature to
accept that ChatPanelState plus the remaining args (messages, query, actions,
modifier), then update all callers to construct and pass the new ChatPanelState
(ensure MessageList still reads modelName from the grouped state, ApprovalCard
receives the grouped pendingApproval, and ChatInputField checks grouped
bridgeState.isChatReady). Alternatively, if grouping is not desired, add a
targeted `@Suppress`("LongParameterList") annotation on the ChatPanel declaration
with a short justification comment.

169-194: ⚠️ Potential issue | 🟠 Major

Add bridgeState to actions remember dependencies for correct state tracking.

The sendMessage function reads bridgeState.isChatReady (line 154), but bridgeState is absent from the remember dependency list (lines 170–177). While Kotlin closures read current values at invocation time, Compose's dependency model requires explicit declaration when a memoized callback's behavior depends on state changes. Without this, the dependency graph is incomplete and the code violates Compose best practices—if bridgeSnapshot changes, actions should recalculate to ensure the closure captures the updated state.

Fix: add bridgeState to remember keys
   val actions =
     remember(
+      bridgeState,
       onRetryBridge,
       onLinkSurface,
       onStartSession,
       onResumeSession,
       onDisconnectReset,
       onApprove,
       onDeny,
     ) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatWorkspace.kt`
around lines 169 - 194, The remember block that builds actions is missing
bridgeState in its dependency keys, causing closures (notably sendMessage which
reads bridgeState.isChatReady) to potentially capture stale state; update the
remember(...) call that constructs ChatWorkspaceActions (the variable actions)
to include bridgeState (or bridgeSnapshot) among its keys so the actions
including sendMessage and the BridgeActions instance are recomputed when
bridgeState changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatWorkspace.kt`:
- Around line 222-231: The current remember block in ChatWorkspace that computes
screenModifier using remember(modifier, colors.background) will frequently miss
cache when callers pass a new Modifier each recomposition; change it to only key
on stable inputs (e.g., colors.background) and compose the incoming modifier
after the remembered base modifier: remember(colors.background) { baseModifier =
fillMaxSize()... } then combine with the parameter (e.g.,
modifier.then(baseModifier)) so the heavy construction is memoized while still
respecting the caller's Modifier. Update references to screenModifier
accordingly in the Column.
- Around line 327-357: The vertical gradient Brush in MessageList is recreated
on every recomposition; memoize it with remember to avoid unnecessary
allocations by creating a remembered val (e.g., val backgroundBrush = remember {
Brush.verticalGradient(listOf(Color.White.copy(alpha = 0.05f),
Color.Transparent)) } ) and use that backgroundBrush in the Box modifier instead
of calling Brush.verticalGradient inline; reference: MessageList and the inline
Brush.verticalGradient call inside the Box.

---

Outside diff comments:
In
`@clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatComponents.kt`:
- Around line 283-295: The remember block for sendButtonModifier is using
gradient (a Brush) as a key which can prevent proper memoization; change the
remember keys to use stable values such as isEnabled and
corvusColors.gradientPrimary (or corvusColors.glowPurple) instead of the
gradient Brush, and then use the existing gradient value inside the block;
update the remember call that creates sendButtonModifier to reference
corvusColors.gradientPrimary (or another stable color/identifier) as the key
while keeping the body unchanged so the modifier isn't recreated unnecessarily.
- Around line 236-308: The ChatInputField composable currently violates Detekt
rules (LongParameterList and LongMethod); fix by extracting the send-button UI
into a new composable SendButton (take isEnabled, gradient/brush, glow color,
onSend and value/trim as needed) and by collapsing multiple parameters into a
single data holder (e.g., ChatInputFieldProps or ChatInputState) so
ChatInputField signature no longer has 7 parameters; update callers to pass the
new props object and move the send-button creation (remember block, Box,
IconButton) into SendButton to reduce ChatInputField length below threshold and
eliminate the LongParameterList violation.

In
`@clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatWorkspace.kt`:
- Around line 284-326: The ChatPanel function currently has 7 parameters
triggering Detekt LongParameterList; refactor by creating a small data holder
(e.g., ChatPanelState) that groups related params such as state:
ChatWorkspaceState, bridgeState: MobileBridgeUiState, and pendingApproval:
RuntimeApprovalRequest? into one object and update the ChatPanel signature to
accept that ChatPanelState plus the remaining args (messages, query, actions,
modifier), then update all callers to construct and pass the new ChatPanelState
(ensure MessageList still reads modelName from the grouped state, ApprovalCard
receives the grouped pendingApproval, and ChatInputField checks grouped
bridgeState.isChatReady). Alternatively, if grouping is not desired, add a
targeted `@Suppress`("LongParameterList") annotation on the ChatPanel declaration
with a short justification comment.
- Around line 169-194: The remember block that builds actions is missing
bridgeState in its dependency keys, causing closures (notably sendMessage which
reads bridgeState.isChatReady) to potentially capture stale state; update the
remember(...) call that constructs ChatWorkspaceActions (the variable actions)
to include bridgeState (or bridgeSnapshot) among its keys so the actions
including sendMessage and the BridgeActions instance are recomputed when
bridgeState changes.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9a5d11cd-f3f8-40c6-989b-6521a1c81b07

📥 Commits

Reviewing files that changed from the base of the PR and between bf3f1e7 and 600afb5.

📒 Files selected for processing (3)
  • .agents/journal/bolt-journal.md
  • clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatComponents.kt
  • clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatWorkspace.kt
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: sonar
  • GitHub Check: pr-checks
  • GitHub Check: Cloudflare Pages
🧰 Additional context used
📓 Path-based instructions (2)
**/*.kt

⚙️ CodeRabbit configuration file

**/*.kt: Enforce null safety (no !!), structured concurrency, and non-blocking suspend code.
Prefer idiomatic Kotlin (expression bodies, sealed types, value classes when justified).
Verify tests follow TDD intent and use backtick test names where applicable.

Files:

  • clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatComponents.kt
  • clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatWorkspace.kt
**/*

⚙️ CodeRabbit configuration file

**/*: Security first, performance second.
Validate input boundaries, auth/authz implications, and secret management.
Look for behavioral regressions, missing tests, and contract breaks across modules.

Files:

  • clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatComponents.kt
  • clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatWorkspace.kt
🧠 Learnings (1)
📚 Learning: 2026-02-21T09:07:52.298Z
Learnt from: yacosta738
Repo: dallay/corvus PR: 62
File: .agents/journal/sentinnel-journal.md:1-1
Timestamp: 2026-02-21T09:07:52.298Z
Learning: Branding guideline: The intentional brand name for the security-first agent in the dallay/corvus repository is 'Sentinnel' (with double n). Do not treat it as a typo of 'Sentinel'. Ensure all agent-related docs and journals under .agents/journal consistently use 'Sentinnel' with double n.

Applied to files:

  • .agents/journal/bolt-journal.md
🪛 GitHub Actions: Scan with Detekt
clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatComponents.kt

[error] 236-236: detekt LongParameterList: The function ChatInputField(...) has too many parameters. The current threshold is set to 6. [LongParameterList]


[error] 236-236: detekt LongMethod: The function ChatInputField is too long (62). The maximum length is 60. [LongMethod]


[error] 589-589: detekt CyclomaticComplexMethod: Function bridgeStateRecovery appears to be too complex based on Cyclomatic Complexity (complexity: 15). Defined complexity threshold for methods is set to '15' [CyclomaticComplexMethod]


[error] 1-1: detekt TooManyFunctions: File 'ChatComponents.kt' with '17' functions detected. Defined threshold inside files is set to '11' [TooManyFunctions]

clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatWorkspace.kt

[error] 126-126: detekt LongParameterList: The function ChatWorkspace(...) has too many parameters. The current threshold is set to 6. [LongParameterList]


[error] 284-284: detekt LongParameterList: The function ChatPanel(...) has too many parameters. The current threshold is set to 6. [LongParameterList]

🔇 Additional comments (4)
clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatComponents.kt (2)

154-156: LGTM — memoized gradient reduces allocations.

Good use of remember(corvusColors.gradientPrimary) to avoid recreating the Brush on every recomposition.

Also applies to: 165-165


239-239: Breaking API change: onSend now takes a String parameter.

The signature changed from onSend: () -> Unit to onSend: (String) -> Unit. The caller in ChatWorkspace.kt (line 321) has been correctly updated to pass actions.onSend, which is properly typed as (String) -> Unit and bound to the sendMessage function.

clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatWorkspace.kt (1)

161-167: LGTM — memoized displayMessages avoids list recreation on keystrokes.

Correctly keyed on messages and state.welcomeMessage.

.agents/journal/bolt-journal.md (1)

16-35: Documentation accurately reflects the code changes.

The entry correctly describes:

  • MessageList extraction to isolate from query state
  • remember usage for modifiers/brushes
  • onSend signature update

Minor: Entry dated 2025-05-24 (line 16) appears before the 2025-05-23 entry (line 36). If intentionally reverse-chronological, consider adding a note; otherwise, reorder for consistency.

…ions

- Optimized `screenModifier` by isolating base modifiers and combining with `then()`.
- Grouped `ChatPanel` and `ChatInputField` parameters into `Immutable` data classes to resolve `LongParameterList`.
- Extracted `SendButton` and `MessageList` to reduce method length and isolate recompositions.
- Added `bridgeState` to `actions` cache keys to ensure closure stability.
- Memoized high-frequency brushes and modifiers with stable keys.

Co-authored-by: yacosta738 <33158051+yacosta738@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatWorkspace.kt (1)

169-195: ⚠️ Potential issue | 🟠 Major

Add onSendMessage to actions remember keys.

sendMessage closes over onSendMessage. Without it in the dependency list, swapping the callback while other keys remain unchanged leaves actions.onSend invoking the stale sender—a behavioral regression.

Fix
   val actions =
     remember(
       bridgeState,
+      onSendMessage,
       onRetryBridge,
       onLinkSurface,
       onStartSession,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatWorkspace.kt`
around lines 169 - 195, The remember block creating actions in ChatWorkspace
closes over sendMessage (used as ChatWorkspaceActions.onSend) but does not list
onSendMessage in the remember keys, causing a stale callback; update the
remember(...) dependency list for the actions variable to include onSendMessage
so that when onSendMessage changes the remembered ChatWorkspaceActions (and its
.onSend) are recomputed.
clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatComponents.kt (1)

252-290: ⚠️ Potential issue | 🟠 Major

Memoize the send callback to prevent unnecessary SendButton recompositions.

Line 289 creates a fresh lambda wrapper around props.onSend on every ChatInputField recomposition. When the user types, the callback reference changes, causing SendButton to recompose despite no functional change. Line 252 also calls trim() on the hot path unnecessarily—use isNotBlank() for the enabled check.

The suggested refactor with rememberUpdatedState and remember is the standard Jetpack Compose pattern: it keeps the callback stable while still reading the latest value when invoked.

Additionally, the behavior change (now trimming input before send) should have test coverage to prevent regressions.

Refactor to apply
+import androidx.compose.runtime.rememberUpdatedState
...
-  val isEnabled = props.enabled && props.value.trim().isNotBlank()
+  val isEnabled = props.enabled && props.value.isNotBlank()
+  val latestValue = rememberUpdatedState(props.value)
+  val latestOnSend = rememberUpdatedState(props.onSend)
+  val onSendClick = remember {
+    { latestOnSend.value(latestValue.value.trim()) }
+  }
...
-      onSend = { props.onSend(props.value.trim()) },
+      onSend = onSendClick,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatComponents.kt`
around lines 252 - 290, The ChatInputField creates a fresh lambda for SendButton
on every recomposition and trims on the hot path; change the enabled check to
use props.value.isNotBlank() (avoid trim on hot path) and stabilize the send
callback by using rememberUpdatedState for props.onSend and then remember to
create a single lambda that calls the current onSend with props.value.trim()
when invoked (refer to SendButton and the onSend prop, and to the isEnabled
computation); also add/adjust tests to cover that input is trimmed only at send
time to prevent regressions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatComponents.kt`:
- Around line 235-240: Add unit tests that cover the new trimmed-send contract
for ChatInputFieldProps: verify that entering only whitespace does not call
onSend and that entering a value with surrounding spaces (e.g., " foo ") results
in a single onSend call with the trimmed string ("foo"). Target the component or
function that consumes ChatInputFieldProps (the chat input composable/renderer)
and simulate user typing and send action; assert onSend is not invoked for
whitespace-only input and invoked exactly once with the trimmed payload for
padded input. Name the tests using backtick-style descriptions (e.g.,
`whitespace-only input is not sent` and `padded input sends trimmed value once`)
and attach them to the appropriate test suite for the chat input UI code that
uses ChatInputFieldProps.

In `@pnpm-workspace.yaml`:
- Line 21: The change downgrades the happy-dom dependency to 20.8.8 which
reintroduces CVE-2026-34226; update the version entry "happy-dom: 20.8.8" back
to "happy-dom: 20.8.9" in the pnpm-workspace.yaml to restore the security patch,
and if you intentionally need a different version add a brief justification in
the PR explaining why the downgrade is necessary and how you mitigate the
vulnerability.

---

Outside diff comments:
In
`@clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatComponents.kt`:
- Around line 252-290: The ChatInputField creates a fresh lambda for SendButton
on every recomposition and trims on the hot path; change the enabled check to
use props.value.isNotBlank() (avoid trim on hot path) and stabilize the send
callback by using rememberUpdatedState for props.onSend and then remember to
create a single lambda that calls the current onSend with props.value.trim()
when invoked (refer to SendButton and the onSend prop, and to the isEnabled
computation); also add/adjust tests to cover that input is trimmed only at send
time to prevent regressions.

In
`@clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatWorkspace.kt`:
- Around line 169-195: The remember block creating actions in ChatWorkspace
closes over sendMessage (used as ChatWorkspaceActions.onSend) but does not list
onSendMessage in the remember keys, causing a stale callback; update the
remember(...) dependency list for the actions variable to include onSendMessage
so that when onSendMessage changes the remembered ChatWorkspaceActions (and its
.onSend) are recomputed.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 46341d98-1edb-4325-845f-eed95eb78468

📥 Commits

Reviewing files that changed from the base of the PR and between 600afb5 and 10105e4.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (4)
  • .github/workflows/fix-renovate.yml
  • clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatComponents.kt
  • clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatWorkspace.kt
  • pnpm-workspace.yaml
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: sonar
  • GitHub Check: pr-checks
  • GitHub Check: Cloudflare Pages
🧰 Additional context used
📓 Path-based instructions (2)
**/*

⚙️ CodeRabbit configuration file

**/*: Security first, performance second.
Validate input boundaries, auth/authz implications, and secret management.
Look for behavioral regressions, missing tests, and contract breaks across modules.

Files:

  • pnpm-workspace.yaml
  • clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatWorkspace.kt
  • clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatComponents.kt
**/*.kt

⚙️ CodeRabbit configuration file

**/*.kt: Enforce null safety (no !!), structured concurrency, and non-blocking suspend code.
Prefer idiomatic Kotlin (expression bodies, sealed types, value classes when justified).
Verify tests follow TDD intent and use backtick test names where applicable.

Files:

  • clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatWorkspace.kt
  • clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatComponents.kt
🪛 GitHub Actions: Scan with Detekt
clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatWorkspace.kt

[error] 126-126: detekt [LongParameterList]: Function ChatWorkspace has too many parameters; current threshold is set to 6.


[error] 214-214: detekt [LongMethod]: Function ChatWorkspaceScreen is too long (64); maximum length is 60.

clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatComponents.kt

[error] 601-601: detekt [CyclomaticComplexMethod]: Function bridgeStateRecovery too complex (complexity: 15); threshold set to 15.


[error] 1-1: detekt [TooManyFunctions]: File has '18' functions; threshold inside files is set to '11'.


[error] 66-66: detekt [FunctionNaming]: Function names should match pattern [a-z][a-zA-Z0-9]*.


[error] 87-87: detekt [FunctionNaming]: Function names should match pattern [a-z][a-zA-Z0-9]*.


[error] 129-129: detekt [FunctionNaming]: Function names should match pattern [a-z][a-zA-Z0-9]*.


[error] 153-153: detekt [FunctionNaming]: Function names should match pattern [a-z][a-zA-Z0-9]*.


[error] 178-178: detekt [FunctionNaming]: Function names should match pattern [a-z][a-zA-Z0-9]*.


[error] 188-188: detekt [FunctionNaming]: Function names should match pattern [a-z][a-zA-Z0-9]*.


[error] 245-245: detekt [FunctionNaming]: Function names should match pattern [a-z][a-zA-Z0-9]*.


[error] 295-295: detekt [FunctionNaming]: Function names should match pattern [a-z][a-zA-Z0-9]*.


[error] 323-323: detekt [FunctionNaming]: Function names should match pattern [a-z][a-zA-Z0-9]*.


[error] 356-356: detekt [FunctionNaming]: Function names should match pattern [a-z][a-zA-Z0-9]*.


[error] 405-405: detekt [FunctionNaming]: Function names should match pattern [a-z][a-zA-Z0-9]*.


[error] 424-424: detekt [FunctionNaming]: Function names should match pattern [a-z][a-zA-Z0-9]*.


[error] 457-457: detekt [FunctionNaming]: Function names should match pattern [a-z][a-zA-Z0-9]*.


[error] 101-101: detekt [MagicNumber]: This expression contains a magic number.


[error] 328-328: detekt [MagicNumber]: This expression contains a magic number.


[error] 334-334: detekt [MagicNumber]: This expression contains a magic number.


[error] 1-1: detekt [File too many functions]: File '/home/runner/work/corvus/corvus/clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatComponents.kt' with '18' functions detected; threshold set to '11'.

🔇 Additional comments (2)
.github/workflows/fix-renovate.yml (1)

157-157: Good hardening of the pre-write head validation.

Including local HEAD mismatch in the same guard correctly blocks write actions when checkout drift occurs, reducing TOCTOU risk.

clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatWorkspace.kt (1)

341-365: Verify recomposition behavior for skippability.

The performance benefit of this MessageList extraction depends on whether strong skipping or immutable collections are used for the messages parameter. Without confirmation, the recomposition win may be smaller than expected. As a secondary optimization concern (per guidelines, after security and behavioral regressions), verify that ChatMessage and List<ChatMessage> support stable/skippable composition before relying on this extraction for performance gains.

Comment on lines +235 to +240
@Immutable
data class ChatInputFieldProps(
val value: String,
val onValueChange: (String) -> Unit,
val onSend: (String) -> Unit,
val placeholder: String,
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.

⚠️ Potential issue | 🟡 Minor

Add regression coverage for the new trimmed-send contract.

This API now changes send semantics, but there is no focused test here for whitespace-only input staying unsendable or for " foo " dispatching "foo" exactly once.

As per coding guidelines, "Verify tests follow TDD intent and use backtick test names where applicable."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@clients/composeApp/src/commonMain/kotlin/com/profiletailors/corvus/ui/chat/ChatComponents.kt`
around lines 235 - 240, Add unit tests that cover the new trimmed-send contract
for ChatInputFieldProps: verify that entering only whitespace does not call
onSend and that entering a value with surrounding spaces (e.g., " foo ") results
in a single onSend call with the trimmed string ("foo"). Target the component or
function that consumes ChatInputFieldProps (the chat input composable/renderer)
and simulate user typing and send action; assert onSend is not invoked for
whitespace-only input and invoked exactly once with the trimmed payload for
padded input. Name the tests using backtick-style descriptions (e.g.,
`whitespace-only input is not sent` and `padded input sends trimmed value once`)
and attach them to the appropriate test suite for the chat input UI code that
uses ChatInputFieldProps.

Comment thread pnpm-workspace.yaml
astro: 6.0.8
astro-vtbot: 2.1.12
happy-dom: 20.8.9
happy-dom: 20.8.8
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.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

Are there any known bugs or issues with happy-dom version 20.8.9 that would require downgrading to 20.8.8? What are the changes between happy-dom 20.8.8 and 20.8.9?

💡 Result:

No, there are no known bugs or issues with happy-dom version 20.8.9 that would require downgrading to 20.8.8. Version 20.8.9 is a patch release that fixes a security vulnerability present in prior versions (including 20.8.8), specifically an issue where cookies from the current origin were incorrectly forwarded to the target origin in fetch requests with credentials: "include". This vulnerability is documented as GHSA-w4gp-fjgq-3q4g and CVE-2026-34226. The change between 20.8.8 and 20.8.9 is solely this security fix, implemented in pull request #2117. No regressions or new bugs specific to 20.8.9 were found in GitHub issues opened after its release on 2026-03-26. Existing open issues predate 20.8.9 and are not attributed to it. Projects are observed upgrading from 20.8.8 to 20.8.9 without reported problems.

Citations:


🌐 Web query:

Are there any security vulnerabilities in happy-dom version 20.8.8 or 20.8.9?

💡 Result:

Yes, there is a known security vulnerability in happy-dom version 20.8.8. Version 20.8.8 fixes CVE-2026-33943 (GHSA-6q6h-j7hj-3r64), a high-severity code injection vulnerability in ECMAScriptModuleCompiler affecting versions up to 20.8.7. However, it is vulnerable to CVE-2026-34226 (GHSA-w4gp-fjgq-3q4g), a high-severity information disclosure vulnerability where fetch requests with credentials: "include" incorrectly attach cookies from the page origin instead of the target origin, allowing cross-origin cookie leakage. This was fixed in version 20.8.9. Version 20.8.9 has no known security vulnerabilities; it is listed as the latest non-vulnerable version by Snyk and patches the fetch cookie issue.

Citations:


Do not downgrade happy-dom: version 20.8.8 contains an unpatched security vulnerability.

This downgrade from 20.8.9 to 20.8.8 reintroduces CVE-2026-34226, a high-severity information disclosure vulnerability where fetch requests with credentials: "include" incorrectly forward cookies from the current origin to target origins. Version 20.8.9 patched this issue; downgrading undoes the fix.

Additionally, this JavaScript dependency change is unrelated to the PR's Compose UI scope and lacks justification. Revert to 20.8.9.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pnpm-workspace.yaml` at line 21, The change downgrades the happy-dom
dependency to 20.8.8 which reintroduces CVE-2026-34226; update the version entry
"happy-dom: 20.8.8" back to "happy-dom: 20.8.9" in the pnpm-workspace.yaml to
restore the security patch, and if you intentionally need a different version
add a brief justification in the PR explaining why the downgrade is necessary
and how you mitigate the vulnerability.

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Apr 2, 2026

@yacosta738 yacosta738 closed this Apr 2, 2026
@yacosta738 yacosta738 deleted the perf/compose-ui-optimizations-14414712215313423242 branch April 6, 2026 12:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant