Problem
Every sidebar panel builds display lines, hover texts, and click actions as separately maintained parallel-indexed vectors — ~180-line near-clone function pairs whose alignment is guarded only by hand-maintained actions.resize(...) backfills. This was called out during #3898 as the real fix.
Evidence
crates/tui/src/tui/sidebar.rs — task_panel_rows (:1282) vs task_panel_hover_texts (:1463): the bash-jobs summary label is computed verbatim twice, the stale-shell Ctrl+X hint twice, the empty-state predicate twice.
- Same pairing for every panel:
work_panel_lines/work_panel_hover_texts, hotbar_panel_lines/hotbar_panel_hover_texts, subagent_panel_rows/subagent_panel_hover_texts.
- Consumer
render_sidebar_section zips three parallel Vecs positionally in sidebar_hover_rows.
Impact
Every sidebar copy or layout change must be made twice in lockstep (×4 panels); a missed branch silently shows the wrong hover tooltip or fires the wrong click action on the wrong row — the index-drift class the #3028/#3030 comments in the file warn about.
Proposed approach
struct SidebarRow { line: Line<'static>, hover: Option<String>, action: Option<String> }; each panel builder emits Vec<SidebarRow> in a single pass; render_sidebar_section accepts it and derives the three vectors internally. Tasks panel first (worst duplication, strongest pinning tests — task_panel_rows_and_hover_share_one_snapshot), then Work/Subagents/Hotbar mechanically.
Acceptance criteria
- The four
*_hover_texts functions are deleted; no duplicated format! bodies remain between a panel's line and hover paths.
- The existing ~2,700 lines of sidebar tests pass with signature-only updates.
Notes
Builds on the TaskPanelRowSets sharing from #3898 (PR #3902). Pairs naturally with splitting sidebar.rs into per-panel submodules afterward.
Problem
Every sidebar panel builds display lines, hover texts, and click actions as separately maintained parallel-indexed vectors — ~180-line near-clone function pairs whose alignment is guarded only by hand-maintained
actions.resize(...)backfills. This was called out during #3898 as the real fix.Evidence
crates/tui/src/tui/sidebar.rs—task_panel_rows(:1282) vs:1463): the bash-jobs summary label is computed verbatim twice, the stale-shell Ctrl+X hint twice, the empty-state predicate twice.task_panel_hover_texts(work_panel_lines/work_panel_hover_texts,hotbar_panel_lines/hotbar_panel_hover_texts,subagent_panel_rows/subagent_panel_hover_texts.render_sidebar_sectionzips three parallel Vecs positionally insidebar_hover_rows.Impact
Every sidebar copy or layout change must be made twice in lockstep (×4 panels); a missed branch silently shows the wrong hover tooltip or fires the wrong click action on the wrong row — the index-drift class the #3028/#3030 comments in the file warn about.
Proposed approach
struct SidebarRow { line: Line<'static>, hover: Option<String>, action: Option<String> }; each panel builder emitsVec<SidebarRow>in a single pass;render_sidebar_sectionaccepts it and derives the three vectors internally. Tasks panel first (worst duplication, strongest pinning tests —task_panel_rows_and_hover_share_one_snapshot), then Work/Subagents/Hotbar mechanically.Acceptance criteria
*_hover_textsfunctions are deleted; no duplicatedformat!bodies remain between a panel's line and hover paths.Notes
Builds on the
TaskPanelRowSetssharing from #3898 (PR #3902). Pairs naturally with splitting sidebar.rs into per-panel submodules afterward.