diff --git a/docs/changes/unreleased/1534-senior-dev-side-row.md b/docs/changes/unreleased/1534-senior-dev-side-row.md new file mode 100644 index 000000000..6a22a150b --- /dev/null +++ b/docs/changes/unreleased/1534-senior-dev-side-row.md @@ -0,0 +1,10 @@ +--- +kind: fixed +title: a side row hides its clock while its page is open; senior-dev manual matches its row and card +pr: 1534 +surface: [chat, docs] +invalidates: + - "On c34a3a76d, a senior-dev row on the side list kept showing the age from the moment its task page was opened, beside the page's live time. The row now draws no clock while its page is open, and the live age returns when the page closes." + - "The senior-dev manual said the side-list row shows the step and spend under it. The row is one line (#1494). The step and spend are in the row's hover hint and the task page header." + - "The senior-dev manual said the landed card says `ended`. It says `done` for a finished run, `stopped` for a stopped one, and `ended` only for a run that ended without finishing." +--- diff --git a/internal/manual/chat/senior-dev.md b/internal/manual/chat/senior-dev.md index 48dfb9260..3e2109284 100644 --- a/internal/manual/chat/senior-dev.md +++ b/internal/manual/chat/senior-dev.md @@ -49,9 +49,10 @@ work, goes to codeaf's own worker, never to senior-dev. ## Watching senior-dev work — open its task, what it is doing step by step, how long it has run, stop it -A senior-dev run is a task of the conversation that started it. Its row is on the side -list wearing `[senior-dev]` after its title, with the step it is in and what it has spent -so far under it, and a card in the conversation lands when it ends. Its `ended` card +A senior-dev run is a task of the conversation that started it. Its compact side-list +row wears `[senior-dev]` after its title (`[sd]` when narrow) and shows its time while +the page is closed. Hover over the row for its current step and spend; both are also in +the task page header. A card in the conversation lands when it ends. That card stands outside the chat's `worked` fold as soon as the run lands, including while its task page is open; the chat's own work in the wake reply still folds. Click the row or the card, or follow a task link to it, and its task opens **inside the conversation's own @@ -232,8 +233,9 @@ left it; your branch main does not move`. Its ending names your own branch, and adds nothing never deletes what an earlier one committed. Switch the folder to another branch first and the next run cuts its own. -**The card stays quiet.** senior-dev's landed card says the run `ended` (never a red -cross) and `senior-dev's ending went to the chat`; the chat's own reply is where you read +**The card stays quiet.** senior-dev's landed card says `done` when the run finished, +`stopped` when you stopped it, and `ended` when it ended without finishing (never a red +cross), and `senior-dev's ending went to the chat`; the chat's own reply is where you read what came of the work. `ctrl+o` on the card still shows senior-dev's own words. **It has no step cap.** Every run has finite dollar and wall-clock ceilings: by default, diff --git a/internal/tui3/runclock_test.go b/internal/tui3/runclock_test.go index 0a0290b59..c22683634 100644 --- a/internal/tui3/runclock_test.go +++ b/internal/tui3/runclock_test.go @@ -170,3 +170,28 @@ func TestARowWhoseRoomIsOpenDrawsNoStoppedClock(t *testing.T) { t.Fatalf("the row read %q once its room closed, want the whole age 1m 21s", got) } } + +// THE SIDE ROW HIDES A RUN'S CLOCK WHILE ITS ROOM IS OPEN. The room keeps the +// node's clock frozen for its own detail rows, so the compact side row must not +// print that frozen age beside the room's live header. +func TestAProgramSideRowHidesItsClockWhileTheRoomIsOpen(t *testing.T) { + a, _ := programRoomApp(t, 180, 36) + started := programRunBegan + now := started.Add(20 * time.Minute) + a.clock = func() time.Time { return now } + row := func() string { + return plain(a.railEntryRow(railEntry{node: a.tasks[7], group: railRunning}, 70)) + } + if got := row(); !strings.Contains(got, "20m") { + t.Fatalf("the running program's side row reads %q, want its live age", got) + } + openProgramRoomNow(t, a) + now = started.Add(21 * time.Minute) + if got := row(); strings.Contains(got, "20m") || strings.Contains(got, "21m") { + t.Fatalf("the open program's side row reads %q, want no frozen clock", got) + } + a.closeRoom() + if got := row(); !strings.Contains(got, "21m") { + t.Fatalf("the program's side row reads %q after leaving, want its live age", got) + } +} diff --git a/internal/tui3/task.go b/internal/tui3/task.go index 63ec433e8..545962926 100644 --- a/internal/tui3/task.go +++ b/internal/tui3/task.go @@ -4295,6 +4295,11 @@ func (a *app) railEntryRow(e railEntry, width int) string { // took, once it has landed, in the fewest cells: `40s`, `2m`, `1h`. "" for // work that has not started, and for a landed node nobody timed. func (a *app) railAge(node *taskNode) string { + // A ROOM HIDES ITS SIDE CLOCK because the row would otherwise report the + // age frozen when the person opened it beside the room's live time. + if !node.froze.IsZero() { + return "" + } var d time.Duration switch node.state { case session.TaskRunning: