Skip to content

🤖 perf: let React Compiler compile ChatPane - #4427

Merged
ThomasK33 merged 1 commit into
mainfrom
perf-compiler-chatpane
Sep 24, 2026
Merged

ThomasK33 merged 1 commit into
mainfrom
perf-compiler-chatpane

Conversation

@ThomasK33

@ThomasK33 ThomasK33 commented Sep 24, 2026 •

Copy link
Copy Markdown
Member

Summary

ChatPaneContent now compiles under React Compiler and leaves the guard baseline.

Implementation

  • handleSendQueuedImmediately threw inside try/catch (unsupported). The interrupt call now goes through runWithCatch, which releases the in-flight guard and rethrows on error. The failure-result path clears the guard and throws outside any try, so the guard is cleared once instead of twice (clearing is idempotent).
  • handleEditQueuedMessage and handleSendQueuedImmediately drop their useCallback wrappers. Their optional-chaining deps (workspaceState?.queuedMessage) did not match what the compiler inferred, so it refused to compile the component. The compiler memoizes both now.

Validation

  • Guard: 11/18 hot components compile (7 known skipped).
  • ChatPane unit tests and tests/ui/chat pass.

Measurements

Electron perf e2e (tests/e2e/scenarios/perf.*.spec.ts, XUM_PROFILE_REACT=1), local, serial, 3 runs each, medians. Baseline is main at 349657d; "after" is the top of this stack (#4429), because the layers were measured together. React time is the summed actualDuration of the profiled subtrees.

Scenario Profiled subtree main stack top
Open chat with a 1000-file review chat-pane.transcript 388 ms 292 ms
Open chat with a 1000-file review chat-pane.input 76 ms 61 ms
Open chat with a 1000-file review all profiled 530 ms 424 ms
Open workspace, large history chat-pane.transcript 331 ms 295 ms
Open workspace, large history chat-pane.input 52 ms 46 ms
Open workspace, medium history chat-pane.transcript 206 ms 191 ms

Commit counts are unchanged; the gain is less work per commit. Typing in a large chat and the review hunk specs show no change beyond noise. ChatInput alone, measured before #4418 landed: New Workspace typing went from 165 CreationControls renders per run to 2.


Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high • Cost: $4.05

@ThomasK33
ThomasK33 added this pull request to stack #4430 September 24, 2026 11:31
@ThomasK33 ThomasK33 changed the title perf: let React Compiler compile ChatPane 🤖 perf: let React Compiler compile ChatPane Sep 24, 2026
@ThomasK33
ThomasK33 marked this pull request as ready for review September 24, 2026 11:56
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-24T14:48:15.420355Z b024f8f New commits
🔒 Security Review ✅ Completed 2026-09-24T14:48:30.178129Z b024f8f New commits
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@ThomasK33

Copy link
Copy Markdown
Member Author

Perf evidence for this PR, from the workspace-open-large investigation (tracked in #4441):

So this PR also removes the one real extra cost behind the 09-21 nightly step. If this PR stalls, the fallback is a small, compiler-safe fix that makes handleEditUserMessage stable.


Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high

@ThomasK33
ThomasK33 added this pull request to the merge queue Sep 24, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Sep 24, 2026
Base automatically changed from perf-compiler-chatinput-compile to main September 24, 2026 14:44
@ThomasK33
ThomasK33 force-pushed the perf-compiler-chatpane branch from fd515ff to b024f8f Compare September 24, 2026 14:45
@ThomasK33
ThomasK33 added this pull request to the merge queue Sep 24, 2026
Merged via the queue into main with commit 48d8284 Sep 24, 2026
30 of 31 checks passed
@ThomasK33
ThomasK33 deleted the perf-compiler-chatpane branch September 24, 2026 15:28
yermakoffivan pushed a commit to yermakoffivan/mux that referenced this pull request Sep 25, 2026
## Summary

The workspace-open perf scenarios now record in-page milestone times:
first transcript row ("useful content ready"), `data-loaded` ("fully
revealed"), and the longest main-thread task. They're written into
`perf-summary.json`, so these numbers no longer depend on when
Playwright's assertion polling happens to notice the change. Addresses
coder#4441.

## Background

The nightly `workspace-open-large` numbers stepped up on 09-21. The
investigation in coder#4441 showed that was mostly a change in what the spec
measures, not extra work:
- coder#4293 moved the `data-loaded` milestone later.
- `toHaveAttribute` polls with a +100/+250/+500/+1000 ms backoff, so the
gap between the real flip and the passing poll went from ~27 ms to ~423
ms.

The small real leftover was fixed by coder#4427.

## Implementation

- `tests/e2e/utils/pageMilestones.ts`:
- A MutationObserver records the first `chat-message` row inside the
message window and the `data-loaded="true"` flip. Its callbacks run in
the same task as the DOM change, so there is no polling quantization.
- A `longtask` PerformanceObserver records the longest task, and pending
entries are drained on read.
- It asserts it wasn't started twice, the window isn't already loaded at
start (otherwise the milestone would read 0), and the first message
never comes after full load.
- `writePerfArtifacts` takes an optional `milestones` field, written as
a top-level key. The change is additive, so `schemaVersion` stays 1.
- The workspace-open spec starts the milestones right before opening the
workspace and asserts that `fullyLoadedMs` was captured.
- Out of scope: versioning the measurement contract (so a trend baseline
resets when a milestone changes meaning) belongs with the deferred trend
reporter in coder#4442.

## Validation

Local, dist build: `perf.workspaceOpen.spec.ts --repeat-each=3`, 18/18
passed. Medians in ms:

| Scenario | First message | Fully loaded | Longest task | Playwright
wall | Wall minus loaded |
|---|---|---|---|---|---|
| large | 806 | 1448 | 274 | 1547 | 171 |
| medium | 772 | 907 | 184 | 1016 | 123 |
| tool-heavy | 772 | 884 | 131 | 1063 | 179 |
| reasoning-heavy | 792 | 891 | 112 | 1091 | 195 |
| large-diff | 1036 | 1089 | 101 | 1103 | 12 |
| small (first test in the worker, cold) | 1135 | 1135 | 170 | 1189 | 54
|

The last column is the polling overhead that the old wall-clock number
included.

## Risks

Test-only. The observer adds one or two `querySelector` calls per
mutation batch inside the profiled window, until both milestones are
seen. That's negligible next to the ~800 ms of script time.

---

_Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking:
`high`_

<!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=high -->
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