Skip to content

fix(app): reduce reactive cascade overhead on session switch#36853

Open
BYK wants to merge 1 commit into
anomalyco:devfrom
BYK:byk/reactive-cascade
Open

fix(app): reduce reactive cascade overhead on session switch#36853
BYK wants to merge 1 commit into
anomalyco:devfrom
BYK:byk/reactive-cascade

Conversation

@BYK

@BYK BYK commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Re-filed from #31517, which was auto-closed by the periodic PR-cleanup bot (age-based, not on technical grounds). Rebased onto latest dev.

Issue for this PR

Fixes #31548

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Scope note: This PR originally bundled three web-UI perf fixes (skip Shiki during streaming, single store mutation per SSE delta, scroll-anchor thrashing). Upstream has since addressed all three independently — Shiki now runs in a Web Worker, the event reducer dual-writes the accum store, and the timeline was rewritten with projection + solid-virtual virtualization. This PR is now reduced to the one change that is still relevant: cutting reactive-cascade overhead on session switch.

Reduces redundant reactive work that runs on every session switch (and during streaming):

  • Lazy findMessage() instead of messageById Map recreation (use-session-hash-scroll.ts): the Map was rebuilt (O(n) insertions) on every visibleUserMessages change, including during streaming. Replaced with a lazy linear scan, and the wrapping memo that lacked an equality comparator was removed.
  • { equals: same } on the diffs memo (session.tsx): downstream components no longer re-render when diff content is unchanged.
  • Primitive string key for the dir/id on() effect (session.tsx): SolidJS on() uses ===, so the previous object literal always re-ran the effect body even when dir/id were unchanged. Now keyed on a primitive string.
  • Removed the redundant historyLoader.userMessages memo that rewrapped visibleUserMessages() with { equals: same } — the input already uses the same comparator.

How did you verify your code works?

  • bun typecheck from packages/app — clean for all touched files
  • Built with OPENCODE_CHANNEL=latest bun run script/build.ts --single — build + smoke test passed (v1.17.12)
  • Tested session switching between cached sessions

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

@github-actions

Copy link
Copy Markdown
Contributor

Thanks for your contribution!

This PR doesn't have a linked issue. All PRs must reference an existing issue.

Please:

  1. Open an issue describing the bug/feature (if one doesn't exist)
  2. Add Fixes #<number> or Closes #<number> to this PR description

See CONTRIBUTING.md for details.

@BYK
BYK force-pushed the byk/reactive-cascade branch from 3139eed to 9b669a5 Compare July 17, 2026 11:57
- Replace messageById Map recreation in useSessionHashScroll with a lazy
  findMessage() linear scan. The Map was rebuilt (O(n) insertions) on every
  visibleUserMessages change including during streaming. Also removes the
  wrapping memo that lacked an equality comparator.
- Add { equals: same } to the diffs memo so downstream components don't
  re-render when diff content is unchanged.
- Replace object allocation in dir/id effect with a primitive string key.
  SolidJS on() uses === comparison, so the old object always triggered the
  effect body even when dir and id hadn't changed.
- Remove redundant historyLoader.userMessages memo that rewrapped
  input.visibleUserMessages() with { equals: same } — the input already
  uses the same comparator.
@BYK
BYK force-pushed the byk/reactive-cascade branch from 9b669a5 to bb09a34 Compare July 17, 2026 13:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Web UI: high CPU during streaming, layout thrashing, and session switch lag

1 participant