Skip to content

refactor(ui): React architecture debt cleanup (post #430 converge) #477

Description

@Astro-Han

Background

The #430 converge series (motion / typography / spacing) is fully merged and token governance is complete. The React architecture cleanup surfaced by that work is tracked here; the CSS-side cleanup is tracked separately in #476.

Verified against main at 2791ea4c on 2026-07-04, after #489, #497, #502, #508, and #512 merged.

Scope

This issue covers React component structure, AppShell state ownership, async UI polish, effect callback stability, and evidence-based render performance. It does not cover token values, visual redesign, or CSS architecture debt.

The high-priority React cleanup is now effectively complete. The remaining question is whether a very small evidence-based memo pass is worth doing. Do not add broad memoization without prop-stability or render-count evidence.

Completed

PR4 — Async and lazy boundaries are done

Done in #489fix/ui-react): harden async and lazy boundaries.

What changed:

  • Made chat model switching and session row actions rejection-safe while preserving owner-side toast feedback.
  • Added compact Suspense fallbacks only where the target surface is already known to be visible.
  • Kept ArtifactPane fallback intentionally null unless AppShell owns an explicit artifact/list-error visibility gate.
  • Added contracts for async pending cleanup, lazy fallback scope, and startup fail-soft behavior.

PR5 — Tool activity preview split is done

Done in #497refactor(ui-react): split tool activity previews.

What changed:

  • Reduced tool-activity.tsx from the original 1494-line catch-all into a smaller shell plus focused preview owners.
  • Preserved result rendering behavior, redaction, truncation, and fallback ordering through behavior contracts.
  • Removed topology-heavy tests during review and kept coverage on user-visible preview contracts.

Current snapshot: packages/ui/src/tool-activity.tsx is 326 lines on main at 2791ea4c.

PR6 — Session list module split is done

Done in #502refactor(ui-react): split session list modules.

What changed:

  • Reduced session-list-panel.tsx from the original 1103-line mixed owner into a small shell plus session-history-list.tsx and session-sidebar-nav.tsx owners.
  • Removed stale module-panel props and dead sessions nav branches.
  • Kept behavior contracts for row actions, busy state, scroll area, and time bucket copy.

Current snapshot:

  • packages/ui/src/session-list-panel.tsx: 48 lines.
  • packages/ui/src/session-history-list.tsx: 854 lines.

PR7 — AppShell session UI state is done

Done in #508refactor(ui-react): consolidate app shell session state.

What changed:

  • Consolidated the per-session UI map state behind a local hook/reducer boundary.
  • Preserved same-session cleanup and active-session behavior.
  • Fixed the nested thinking/truncated update risk during review by making map updates merge against latest state.

PR8 — AppShell effect callback stability is done

Done in #512refactor(ui-react): stabilize app shell effect callbacks.

What changed:

  • Replaced the local latest-ref pattern with React 19 useEffectEvent for long-lived subscription, timer, and listener callbacks.
  • Preserved mount-once bootstrap subscriptions and activeId-keyed active-session subscriptions.
  • Kept ordinary UI callbacks, such as the plan reminder toast action, outside the Effect Event boundary.
  • Added behavior tests proving captured old subscription callbacks dispatch to the latest handler without resubscribing.

Current Size Snapshot

Measured on main at 2791ea4c:

FileLinesStatus
apps/desktop/src/renderer/app-shell.tsx1464Still large, but per-session state and effect callback boundaries are now separated.
packages/ui/src/tool-activity.tsx326Split target addressed.
packages/ui/src/chat-view.tsx1506Still large; hot path already has memoized materialization and TurnView.
packages/ui/src/session-list-panel.tsx48Split target addressed.
packages/ui/src/session-history-list.tsx854New focused owner; revisit only if it becomes hard to review.

app-shell.tsx and chat-view.tsx are still large, but the original highest-risk seams have been reduced. Further splitting should require a concrete review or maintenance problem, not line count alone.

Remaining

Optional PR9 — Evidence-based memo pass

Candidate title: perf(ui-react): assess targeted memo boundaries.

Recommended handling:

  • First prove prop stability or repeated render cost for a narrow boundary, likely SessionRow, ToolActivity, or an extracted tool preview component.
  • Add memo only where the test or measurement shows it avoids unrelated rerenders without hiding unstable props.
  • Do not touch TurnView as a first move; it is already memoized.
  • If there is no useful evidence, leave the code alone and close this issue with a note that memo work is not justified right now.

Close criteria

This issue can be closed once we either:

  • decide to skip PR9 because no render evidence justifies it, or
  • land one small PR9 that adds only proven memo boundaries.

Out of scope

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions