Skip to content

perf: eliminate idle CPU floor and make replay refresh incremental#395

Merged
sudomaggie merged 12 commits into
developfrom
perf/idle-cpu-and-replay
Jul 16, 2026
Merged

perf: eliminate idle CPU floor and make replay refresh incremental#395
sudomaggie merged 12 commits into
developfrom
perf/idle-cpu-and-replay

Conversation

@Harry19081

Copy link
Copy Markdown
Member

Summary

Follow-up to #390: eliminates the remaining idle CPU load (org2 held a ~6% floor with periodic spikes; the renderer burned on external-session replays), plus the external-history session fixes and the cloud-org chat tab that were pending locally.

Idle CPU

  • orgtrack historical backfill (the ~6% floor): a single file-history read reconciled every imported session in the repo, spawned 1–2 git rev-parse subprocesses per file interaction, and re-reconciled active sessions forever because transcript appends change their fingerprint. Now: priority-file scoped with a bounded backlog batch per run, a 10-minute quiescence gate (live interactions arrive via hook capture; a quiet session is indexed exactly once), a 5-minute TTL short-circuit for repeat requests, and filesystem-based git discovery with a per-cwd cache (zero git subprocesses; parser bumped to v3 to rebuild rows under one id derivation). Verified with process sampling: no orgtrack git processes remain.
  • git status polling: focused interval relaxes 5s → 10s (each poll is a ~130ms git subprocess); a new reference-counted set_source_control_attention signal restores 5s while a Source Control surface is actually visible.

External-session replay

  • Auto-refresh (default 5s) re-read and re-parsed the whole transcript every tick, even minimized. Now three-layered: skipped while hidden; a cheap (mtime, size) stat probe (new claude_code_history_stat command + optional statTranscript source hook) skips unchanged transcripts; and on real appends, loadSessionAtom keeps existing object references for already-loaded imported events so the memoized render pipeline paints only new rows.
  • Sidebar subagent hydration: es_get_child_sessions fired once per visible session on every list refresh (100+ concurrent calls queuing on SQLite, 2.6s avg observed → 0.06s). Children now re-fetch only when the parent's updated_at changes, in batches of 8.
  • Commit reference cards no longer fetch /commits per card (dozens of ~1s requests per replay) — the extracted reference already carries the id, subject and repo name.

Observability

  • The ⌘5 API panel now sees bare fetch() traffic (including ipc://localhost requests with durations) and backend push traffic (tauri events, session IPC channels, websocket + SSE messages) with per-name rates, and hotspot rates no longer extrapolate 2-sample bursts into absurd figures. This panel work is what surfaced the findings above.

Also included (previously unpushed)

  • external history: startup scan, batched sidebar refreshes, active-session refresh, circular-import fix
  • chat: cloud org management as a first-class chat-panel tab; tab hover surface unification
  • docs: 2026-07-16 architecture + frontend UI audits

Verification

cargo check clean; orgtrack (19) and watch tests pass; eslint clean on all touched files; tsc --noEmit introduces no new errors; vitest suites for session atoms, external history, sidebar menu items and chat tab display pass (15 + 23 + 7). Filesystem git discovery validated byte-for-byte against git rev-parse on a real linked worktree.

Render chat tab content and the close affordance within the shared WorkStation tab pill surface. This gives the entire rounded tab a consistent hover state and matches My Station tab composition.\n\nUpdate the tab-bar regression test to verify the close control remains inside the shared surface without nested buttons.

Pre-commit hook ran. Total eslint: 0, total circular: 0
Reuse the external-history rescan API from the sidebar refresh action so enabled provider sessions are updated before the list reloads.\n\nAdd configurable polling for the external session currently open in Chat, with localized 3-second, 5-second, 10-second, and 1-minute cadence options. Clarify the scan settings copy across all supported locales.

Pre-commit hook ran. Total eslint: 0, total circular: 2
Batch all enabled external-history sources into one cache-only IPC request while retaining per-source date-bucket pagination. Add delayed imported-session turn metadata with compact file rows and hover previews. Normalize monitoring rates over the observation window so request bursts are not reported as extreme polling frequencies.

Pre-commit hook ran. Total eslint: 0, total circular: 2
Pre-commit hook ran. Total eslint: 0, total circular: 2
Remove two import cycles reported by the repository-wide Madge scan without changing runtime behavior.

- import the session adapter registry from its leaf module instead of the sync barrel
- derive completed task report types from the existing local Zod wire schema
- preserve the structural compatibility of cloud session comment results

Validation:
- npx madge --circular --json --extensions ts,tsx --ts-config tsconfig.json src/
- npm run lint
- npx tsc --noEmit
- 58 focused Vitest tests

Pre-commit hook ran. Total eslint: 0, total circular: 2
Run an immediate deduplicated incremental scan for enabled non-manual external sources when the app starts, then continue cadence-based scans from completion time. Batch multi-source updates into one native IPC request with clear disabled and reload the sidebar once after a successful scan.

Pre-commit hook ran. Total eslint: 0, total circular: 0
Focused polling relaxes from 5s to 10s — each poll spawns a git status
subprocess (~130ms on this repo), a permanent 2-3% single-core floor.
A new set_source_control_attention command (reference-counted from the
frontend via useSourceControlAttention) restores the fast 5s interval
while a Source Control surface is actually on screen. Also corrects the
stale '4-6 git processes per poll' note: status was consolidated to a
single porcelain=v2 call in January.

Pre-commit hook ran. Total eslint: 0, total circular: 0
The cross-agent provenance backfill kept a ~6% idle CPU floor: every
file-history read reconciled EVERY imported session in the repo, each
file interaction spawned 1-2 git subprocesses for path resolution, and
active sessions were re-reconciled on every run because appends change
their fingerprint.

- reconcile only sessions that touched the requested file, plus a
  bounded backlog batch per run (pre-filtered so completed sessions
  never consume the budget)
- skip sessions whose transcript changed in the last 10 minutes: live
  interactions arrive via hook capture, and a quiet session is indexed
  exactly once because its fingerprint then never changes again
- short-circuit repeat backfill requests within 5 minutes of a finished
  run unless the requested file still has pending sessions (TTL is below
  the quiescence window, so nothing that would have been indexed is
  delayed)
- resolve workspace root / repository id by walking the filesystem
  (.git, gitdir pointers, commondir) instead of spawning git rev-parse
  per interaction, with a per-cwd cache; parser version bumped to v3 so
  reconciled rows rebuild under one id derivation
- new claude_code_history_stat command: cheap (mtime, size) probe so the
  replay auto-refresh can skip unchanged transcripts

Pre-commit hook ran. Total eslint: 0, total circular: 0
The cmd+5 panel only saw axios and tauri invoke, hiding most real
traffic: bare fetch() calls to the IDE server and everything the
backend pushes. Coverage added:

- window.fetch patch while tracking is enabled (HMR noise filtered),
  which also surfaces tauri ipc://localhost requests with durations
- push-traffic recorder with per-name rates: tauri events (via the
  useTauriListen wrappers), session IPC channel messages, code-editor
  websocket messages, and SSE stream events
- hotspot rates report a measured-window rate instead of extrapolating
  2-sample bursts into absurd per-minute figures

Pre-commit hook ran. Total eslint: 0, total circular: 0
External-replay and sidebar hot paths issued heavy redundant backend
work:

- replay auto-refresh (default 5s) re-read and re-parsed the whole
  transcript every tick, even minimized. Now: skipped while the window
  is hidden; a cheap stat probe (new statTranscript source hook, wired
  for claude_code) skips unchanged transcripts entirely; and when new
  lines do arrive, loadSessionAtom keeps existing object references for
  already-loaded imported events (append-only transcripts, immutable
  events; last one excepted for chunk aggregation) so the memoized
  render pipeline only paints new rows
- sidebar subagent hydration fired es_get_child_sessions once per
  visible session on every list refresh (100+ concurrent calls queuing
  on SQLite, 2.6s avg observed). Children now re-fetch only when the
  parent's updated_at changes, in batches of 8
- commit reference cards fetched /commits per card purely to decorate
  the subtitle; dozens of ~1s requests per replay. Removed: the
  reference extracted from the message already carries the commit id,
  subject and repo name

Pre-commit hook ran. Total eslint: 0, total circular: 0
Cloud org management moves from an inline panel into a first-class
chat-panel tab (new cloud-org tab kind with its own display label and
tab-bar treatment), so it participates in tab persistence and
navigation like launchpad/workspace tabs. Covered by updated tab
display/atom unit tests and the cloud org e2e specs.

Pre-commit hook ran. Total eslint: 0, total circular: 0
Pre-commit hook ran. Total eslint: 0, total circular: 0
@sudomaggie

Copy link
Copy Markdown
Collaborator

LGTM

@sudomaggie
sudomaggie merged commit 2ce9b96 into develop Jul 16, 2026
2 checks passed
Harry19081 added a commit that referenced this pull request Jul 16, 2026
Bring PR #354 up to date with develop after PR #395 merged. The new develop commits do not overlap the managed CLI conflict resolution.
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.

2 participants