Fix: Usage pane caption overflows the terminal when the stacked legend wraps
Nobody has claimed this yet.
Assessment
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 78/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- go
- Domain
- cli, testing-qa
Research direction
Start with authbridge/cmd/abctl/tui/usage_render.go:172-178 and trace renderStackedBars, axisCaption, and renderLegend in usage_stacked.go:481-537. Run TestUsageStackedChart_FitsTheChartBudget in layout_fit_test.go:321, then add the long model-name wrapping case described in the issue. Done means the stacked chart fits its budget without the caption overflowing at the reported widths and heights.
Written by the indexing model from the issue text.
Description
The stacked chart's caption gate budgets one legend line, but renderLegend wraps — so the unit caption reappears at heights where the grouped chart does not fit.
Follow-up to a must-fix review comment on #1061 (comment) that arrived 16 minutes after the PR merged and was never addressed. Live on main as of 31f14c4e.
The bug
authbridge/cmd/abctl/tui/usage_render.go:172-178
// stackedChartFloor: the same, plus the blank separator and at least one legend line.
// renderLegend emits one line per wrap and never zero, so one is its minimum.
stackedChartFloor = barChartFloor + 2
The comment is accurate about renderLegend's minimum. The gate then spends that minimum as if it were the actual cost. renderLegend (usage_stacked.go:481-537) flushes a line whenever plain+cost > width, so grouped by model at 66 columns it returns 2 lines at 3 series, 2 at 4, and 3 at 5. axisCaption therefore opens at a budget the stacked frame does not fit into, and the caption is the single row that tips the pane past the terminal.
This is the same defect #1061 set out to fix — a caption gated on height so it cannot overrun the pane — unfixed for the wrapping case.
Reproduction
Grouped by model with three realistic model names (claude-3-5-sonnet-20241022, gpt-4o-2024-11-20, gemini-1.5-pro-002), sweeping widths 66–140 × budgets 13–40 and counting only cases that fit without the caption and overflow with it — 30 cases:
w=66 budget=16 afford=16 withCaption=17 noCaption=16 legend=2
w=67 budget=16 afford=16 withCaption=17 noCaption=16 legend=2
w=68 budget=16 afford=16 withCaption=17 noCaption=16 legend=2
w=69 budget=16 afford=16 withCaption=17 noCaption=16 legend=2
On the composed pane that is 66x27 and 80x27. Reachable from ordinary user state: [b] cycles the grouping (README.md:564) and usage.group persists in settings, so a grouped chart survives a restart.
Why CI is green
TestUsageStackedChart_FitsTheChartBudget (layout_fit_test.go:321) tests the right property and is well constructed, but its fixture groups by status with "200" / "429" / "500" — three short labels that fit one legend line at every width it checks, so the wrapping case is unreachable from it. Same shape of blind spot as fitModel's snapshot being ungrouped, which #1061 diagnosed and fixed one layer down.
Suggested fix
Make the floor reflect the legend actually rendered rather than its lower bound: compute the legend before the caption decision and include its real line count in the height the gate checks. renderStackedBars already builds legendSeries and letters before it calls axisCaption, so the legend can be rendered first and its length passed in.
Add a case to TestUsageStackedChart_FitsTheChartBudget with long labels (model names) so the wrapping path is covered.
CodeRabbit's second comment on the same PR (here) points at the same spot from the renderer side.
- Dominant language
- Go
- Stars
- 13
- Forks
- 40
- Avg merge
- 12h 9m
- Merged PRs (30d)
- 164
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from rossoctl/cortex
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
-
nice to have
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
-
stale
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
-
bug
Difficulty 4/5 3-5 days Newbie friendliness 25/100
Similar issues
-
Difficulty 1/5 Under an hour Newbie friendliness 84/100
-
enhancement needs triage
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
-
kind/cleanup
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
kubernetes-sigs/kueue#15947 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
sympozium-ai/sympozium#627 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 86/100