You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(client): wrap the stage at the terminal's width, never truncate
## Summary
### Why?
The stage column was cut at a hard-coded 120 columns, and the cut fell at the end of the trail — which is exactly where the request currently is. Once the pipeline began reporting its finer stages, an ordinary trail outgrew the line and the run read like this, with the interesting part missing:
```
demo-queue/1 #147 22s accepted → started → validating → validated → batched → speculating → speculated → la…
```
The 120 was never a measurement. The renderer redraws in place by moving the cursor back over the lines it emitted, and a line that wraps physically occupies two rows, which desyncs every redraw after it — so the width had to be bounded somehow, and a constant was cheaper than asking. That trade was invisible while trails were short.
### What?
The renderer now asks the terminal how wide it is, and wraps rather than cuts when a trail still will not fit.
Asking first is what matters: on a wide window the whole trail simply fits on one line, and nobody is held to the narrowest window anyone might have. The fallback is the old constant, used whenever there is no size to discover — a pipe, a file, a CI log — where a stable width is what a log wants anyway.
It asks before every draw, not once at startup. The width is not a property of the process: a watch runs for minutes, and a window dragged narrower inside them leaves every later frame wrapped to a width the window no longer has. The terminal then wraps those lines itself — mid-word, ignoring the column alignment — and because the redraw counts the lines it emitted rather than the lines that appeared, it drifts further with every frame. Sampling once traded that away for an `ioctl` per second.
Knowing the width is also what decides whether to redraw in place at all. Detecting a terminal and measuring it were two separate probes, so a terminal that answered the first and not the second got wrapped to the fallback constant — 120 columns of table in whatever window the reader actually had. They are now one question: no size, no wrapping, render as a log.
When a trail is longer than the line even so, it wraps onto continuation lines indented under the stage column, the way a wrapped error already does. This keeps the redraw honest rather than working around it: every line is one the renderer produced and counted, so the cursor arithmetic still holds, and nothing is ever cut. Piped output is left on a single unwrapped line, since a log is easier to read and grep that way and has no width to respect.
## Test Plan
✅ `bazel test //submitqueue/client:go_default_test` — 75 cases pass, including the pre-existing redraw-accounting ones that pin the property this all rests on: no emitted line exceeds the width.
✅ Seven new cases: a long trail wraps instead of truncating and every status survives it, the end of the trail is on the last line, continuations align under the stage column, no line exceeds the width at 80/100/120/200 columns, a 240-column terminal needs no wrapping at all, piped output stays on one line, and a window too narrow for the columns still wraps to a readable floor rather than one word per line.
✅ The zero-value renderer that tests construct directly falls back to the default width rather than collapsing, which is what keeps the moved tests working unchanged.
✅ A resize is followed: a table drawn at 200 columns and redrawn after the window narrows to 94 keeps every line inside 94. This is the case that reaches a reader as a trail cut mid-word at the window's edge, since the terminal breaks anything the renderer lets past it.
✅ A probe that fails once leaves the last known width alone rather than snapping to the fallback, which on a narrow window is wider than the window.
✅ A terminal whose size cannot be read does not redraw in place, so wrapping never runs against a guessed width.
0 commit comments