fix-wg-tui

Fix: wg tui re-parses graph.jsonl on every frame (55% CPU)

Metadata

Statusdone
Assignedagent-1083
Agent identityf51439356729d112a6c404803d88015d5b44832c6c584c62b96732b63c2b0c7e
Created2026-04-29T11:50:30.391818088+00:00
Started2026-04-29T12:14:46.828449820+00:00
Completed2026-04-29T12:15:34.462675401+00:00
Tagseval-scheduled
Eval score0.52
└ blocking impact0.35
└ completeness0.45
└ coordination overhead0.45
└ correctness0.60
└ downstream usability0.50
└ efficiency0.75
└ intent fidelity0.84
└ style adherence0.65

Description

Description

Per diagnose-wg-tui findings (artifact: .wg/output/diagnose-wg-tui/findings.md):

render::draw_chat_tab (src/tui/viz_viewer/render.rs:3054-3055) calls app.active_tab_ids_and_labels() and app.list_user_board_entries() on every redraw. Both helpers internally call workgraph::parser::load_graph(graph_path) (state.rs:13362 and :13470), so each redraw fully JSON-deserializes a 2.19 MB / 683-task graph TWICE.

With chat tab active and any animation/streaming, the adaptive poll runs at 50-200 ms (state.rs:7212), producing 10-40 graph reloads/second. Perf profile attributes ~55% of CPU to serde_json deserialize + matching malloc/free/BTreeMap allocator churn driven by these reloads.

Implementation (priority 1 from findings.md)

  1. Add cached fields to VizApp in src/tui/viz_viewer/state.rs:
    • cached_chat_tab_entries: Vec<(u32, String)>
    • cached_user_board_entries: Vec<(String, String)>
  2. Add &Graph-taking variants of the three helpers (or make them inherent on &Graph):
    • list_coordinator_ids_and_labels (state.rs:13360)
    • list_user_board_entries (state.rs:13468)
    • live_chat_count (state.rs:13344)
  3. In maybe_refresh() (state.rs:6772), at the existing if let Ok(graph) = load_graph(...) block (state.rs:7035), populate the cached fields from &graph whenever the graph reloads. Also populate inside the fs-watcher fast-path block at state.rs:6809.
  4. Replace the two render.rs:3054-3055 calls with reads of the cached fields. Also audit list_coordinator_ids callers in render and event paths to use the cache.
  5. Optional but recommended: cache the loaded Graph itself on VizApp and make the other ~22 load_graph callsites in src/tui/viz_viewer/state.rs reuse it (see perf-callgraph.txt for the call list).

Validation

  • Failing test or benchmark first: open wg tui against a graph with 500+ tasks, switch to chat tab, capture perf record -F 99 for 20s. Before fix: serde_json + libc allocator symbols dominate. After fix: those drop below 1% on idle.
  • cargo build and cargo test pass with no regressions
  • Manual smoke: wg tui, chat tab visible, idle for 30s — top should show <5% CPU
  • No regression in tab-bar correctness: creating a new chat (wg add with chat-loop tag), archiving a chat, and abandoning a chat all reflect immediately in the tab bar
  • Verify against fix-pty-scrollback: if duplication symptom disappears after this fix, mark fix-pty-scrollback as duplicate; otherwise it has its own root cause and stays open

Files (estimated scope)

  • src/tui/viz_viewer/state.rs — VizApp fields, helper signatures, maybe_refresh wiring
  • src/tui/viz_viewer/render.rs — replace lines 3054-3055 with cache reads

Depends on

Required by

Log