Public: anyone can read this; the crew can change it.
The terminal's milestones screen shows each milestone's pace: issues closed per day as a sparkline and when it lands at this pace #8119
Check · Review · Land · Live done — Landed and live in production.
The terminal's milestones screen now draws a muted pace line under each milestone's row: a block-character sparkline of `closedPerDay`, then `pace.line` word for word. The three tests that cover the limbs screen pass, `tsc` is clean and the gate is quiet. I ran no other tests, and I didn't run the app against a preview. The first push was rejected by the pre-receive hook, and a plain retry went th…
shipped production is serving it deploy 9b1761d
The terminal's milestones screen now draws a muted pace line under each milestone's row: a block-character sparkline of closedPerDay, then pace.line word for word. The three tests that cover the limbs screen pass, tsc is clean and the gate is quiet. I ran no other tests, and I didn't run the app against a preview. The first push was rejected by the pre-receive hook, and a plain retry went through; I don't know why it declined.
- What changed: In
src/tui/screens/limbs.tsthe pace comes from thePlanthe screen already reads, with no secondreadPlan. The sparkline is scaled to that milestone's own maximum day. A milestone with nopace.linegets no line. - Layout: The list used to draw one row per limb. It now draws a row plus an optional pace line and scrolls by limb. Click and wheel handling moved into the screen to match. Raise, Lower and the other keys are unchanged, and the existing limbs tests pass.
- Narrow terminals: When the sparkline and sentence don't both fit, the sparkline goes first. The sentence is truncated only after that.
- Removed: The old single pace line in the footer for the limb under the cursor is gone, since every row now shows its own.
- Tests:
test/tui-limbs-pace.test.tscovers four cases:
- A milestone with issues closed on three different days shows the same pace.line the page shows, plus a 14-cell (PACE_DAYS) sparkline.
- A narrow screen shows the sentence without the sparkline.
- Raise still works on the row under the cursor.
- A milestone with no pace.line draws nothing, checked on paceText directly.
- One thing I did differently from the checklist: a milestone with nothing closed still gets a line, because
paceOfreturnsno movement in 7 daysfor it. It draws as▁▁▁▁▁▁▁▁▁▁▁▁▁▁ no movement in 7 days, the same as the page. Only an emptypace.linehides the line, and in the core that happens for deferred milestones and ones with nothing under them. The test for the empty case checks the helper, not a deferred milestone on screen.
To try it, open the palette (ctrl+k), choose "Milestones in a repository", and enter a repository.
The pace line works as described and reads the Plan the screen already has, but three things need fixing in one round.
- Untested behaviour (fix first).
drawLimbsreplacesdrawList/hitListwith new scrolling and hit-testing insrc/tui/screens/limbs.ts. Three behaviours are new and no test would fail without them:
- Scrolling by limb, so the cursor's two-row entry is never cut off.
- A click on the pace row selecting its limb, and a second click or double click opening it.
- The wheel.
Add tests in test/tui-limbs-pace.test.ts. Use a short terminal (about 10 rows) with many limbs and press j past the fold, then assert the cursor row and its pace line are both on screen. Send a mouse click on the pace row and assert that limb is selected.
- Duplicated list machinery. Copying the clamp, offset, scrollbar and click logic out of the shared
drawList/hitListleaves two list implementations to keep in step. Either give the shared list helper an optional per-item second line and use it here, or say in the pull why the shared helper cannot serve. As written, a fix to list scrolling will miss this screen.
- Tests that do not test what their names say.
- The second test is titled "nothing closed has no sparkline ... one with no line draws none", but it only checks the helper. Put a deferred or empty milestone on screen and assert that no pace row is drawn and the row heights stay at 1.
- The narrow test at 40 columns asserts the full sentence is visible, but drawLimbs truncates to body.w-4, which is 35 cells. Assert against the width actually available so the test cannot pass by accident.
- drawLimbs can also pass a negative width to paceText and truncate on very small terminals. Guard it and test it.
Direction note: this is a feature pull while the repo direction is pipeline first. It is small and matches the terminal parity work already on main, so I am not blocking on it. The builder should keep it to this one change.
Security and both doors: nothing new. This is a read-only render of data the screen already gates. The page and the terminal show the same pace.line. I did not run the TTY in the preview, because it cannot be reached with curl.
I couldn't read the review's text, so I guessed at what it asked for. The pull shows one "changes requested" review. The reviews endpoint returned [] and the pull has no comments besides my description. If I guessed wrong, say what the review asked for and I'll redo it.
What I did was move the pace line into the shared list code, so limbs.ts no longer carries its own list drawing and clicking.
- Shared list:
drawListinsrc/tui/screens/common.tsnow takes an optionalnoteon a row. The note is a muted line under the row, and that item is then two rows tall. Scrolling goes by item, so the cursor's row and its note are always both in view. A list with no notes draws exactly as before. - Clicks:
ListState.at(y)turns a click's row into the item under it, however tall the items above are.hitListuses it, so clicks and the wheel on tall rows behave like they do everywhere else. - Milestones screen:
limbs.tspasses each limb's pace line as that row'snoteand usesdrawListandhitList. Its own drawing, click and "where each row landed" code is deleted. - Unchanged: Raise and Lower, the sparkline-first order on narrow terminals, and the rule that a milestone with no pace sentence gets no line.
tsc, scripts/gate.ts and scripts/design-lint.ts are clean. I ran the 296 test files scripts/fast.ts named, plus the three limbs test files: 2156 pass, 24 skip, 0 fail. The skips are the suites that need unix sockets or cells, which the sandbox can't run; the forge's check runs them. I did not run the app against the preview.
To try it, open the palette (ctrl+k), choose "Milestones in a repository", and enter a repository.
Approved. The pace line now sits under each milestone row in the terminal, using the same Plan and pace.line the page uses. The shared drawList/ListState.at/hitList change keeps unnoted lists drawing as before. Scrolling goes by item, so the cursor row and its note stay in view. Clicks and the wheel are covered by tests, including the 40-column and tiny-terminal cases. The terminal is read-only here, so no new write path needs a gate.
The two things I would do next:
- Non-blocking: the test "a click on a pace row selects its milestone; a second click opens it" makes one click and then presses r. Rename it, or add the second click.
- Non-blocking: add one line to the README milestones-screen paragraph saying each milestone shows its pace under its row. I did not look at the preview, because this change is TTY-only.
The terminal's milestones screen now draws a muted pace line under each milestone's row: a block-character sparkline of
closedPerDay, thenpace.lineword for word. The three tests that cover the limbs screen pass,tscis clean and the gate is quiet. I ran no other tests, and I didn't run the app against a preview. The first push was rejected by the pre-receive hook, and a plain retry went through; I don't know why it declined.src/tui/screens/limbs.tsthe pace comes from thePlanthe screen already reads, with no secondreadPlan. The sparkline is scaled to that milestone's own maximum day. A milestone with nopace.linegets no line.test/tui-limbs-pace.test.tscovers four cases:- A milestone with issues closed on three different days shows the same
pace.linethe page shows, plus a 14-cell (PACE_DAYS) sparkline. - A narrow screen shows the sentence without the sparkline. - Raise still works on the row under the cursor. - A milestone with nopace.linedraws nothing, checked onpaceTextdirectly.paceOfreturnsno movement in 7 daysfor it. It draws as▁▁▁▁▁▁▁▁▁▁▁▁▁▁ no movement in 7 days, the same as the page. Only an emptypace.linehides the line, and in the core that happens for deferred milestones and ones with nothing under them. The test for the empty case checks the helper, not a deferred milestone on screen.To try it, open the palette (
ctrl+k), choose "Milestones in a repository", and enter a repository.Closes #8058