Skip to content

Cap the returned list at ten scrollable rows; total the session's tokens in the header - #3

Merged
simoncoombes merged 2 commits into
mainfrom
returned-list-cap
Sep 12, 2026
Merged

simoncoombes merged 2 commits into
mainfrom
returned-list-cap

Conversation

@simoncoombes

Copy link
Copy Markdown
Owner

Two fixes to the same screen.

The RETURNED list is capped at ten rows and scrolls

It grew with the run and took a third of the pane with it — a fan-out of twenty left fourteen rows of finished work under a single live agent. The pane is for what is happening now; the list is the receipt. Ten rows now, however tall the pane, and a short pane still gets less since the live agents are budgeted first.

Capping alone would only have moved the problem: the cursor's order comes from the rows the frame painted, so j stopped dead at the window's edge and the old +n more named agents no key could reach. selectionOrder now splices the whole list in where the drawn rows are, so j past the bottom row selects the one below it and the next frame scrolls to it. The window otherwise holds still.

+n more is gone; the heading carries the window's position instead (RETURNED 18 left, 1-10 / 18 right), in the form the tree's own scroll already uses.

RETURNED 18                                            1-10 / 18
────────────────────────────────────────────────────────────────
  review-homepage…    opus-5 · high                   8:40  100k
  …

The header totals the session, not the run

The header sat above rows whose own numbers added up to half as much again as the total it claimed. Replaying one real session's transcript: main plus agents came to 5.89M against a header reading 3.9M.

The cause is structural. Run.Tokens accrues only from its own UserPromptSubmitted and nothing seeds it, so a pane attaching to a session already in flight replays the transcript behind that moment — main and the agents carry work the run's counter never saw. World.Tokens sums main and every agent that earned a row, which is exactly what is on screen. Run.Tokens is left alone; a run summary is a run-scoped aggregate and that is what it is for.

The count is also no longer gated on a run being in flight, where the line was simply blank. The clock beside it stays the run's.

Tests

New coverage for the ten-row cap, the window's position line, and j scrolling past the edge; the header test asserts the session total and that the run's partial count is gone. scroll_40_agents.golden regenerated. Full suite passes — the three codexsrc failures are pre-existing on main.

The list at the foot grew with the run and took a third of the pane with it.
A fan-out of twenty left fourteen rows of finished work under a single live
agent, which is the wrong way round: the pane is for what is happening now,
and the list is the receipt. It now holds ten rows however tall the pane, and
a short pane still gives it less, since the live agents are budgeted first.

Capping alone would only have moved the problem, because the rows under the
cut were unreachable. The cursor's order comes from the rows the frame
actually painted (selectableIDs), so j stopped dead at the window's edge and
the old "+n more" line named agents no key could reach. selectionOrder now
splices the whole returned list in where the drawn rows are, so j past the
bottom row selects the agent below it and the next frame's returnedWindow
scrolls to bring it on screen. The window otherwise holds still (§3.13): a
return landing at the top never shifts the row being read.

That also retires the cursor-swap hack, which kept a selected agent below the
cut on screen by giving it the last drawn slot — a row out of list order,
sitting where a different agent's row had been a frame earlier.

"+n more" is gone with it. The heading carries the window's position instead
("RETURNED 18" left, "1-10 / 18" right), which says strictly more, says it in
the form the tree's own scroll already uses, and gives the row back.
The header sat above a tree and a RETURNED list whose own numbers added up to
half as much again as the total it was claiming, which is the one thing a
total may not do. Replaying one real session's transcript: main plus the
agents came to 5.89M against a header reading 3.9M.

The cause is structural, not arithmetic. Run.Tokens accrues only from the
moment its UserPromptSubmitted arrives, and nothing seeds it — a pane that
attaches to a session already in flight replays the whole transcript behind
that moment, so main and every agent carry work the run's counter never saw.
The rows are lifetime totals; the header was a partial one.

World.Tokens sums main and every agent that earned a row, which is exactly
what is on screen. Quiet agents add nothing by construction: a token is one
of the things that earns a row in the first place. Run.Tokens is left alone,
since a run summary is a run-scoped aggregate and that is what it is for.

The count is also no longer gated on a run being in flight. It was the one
number on that line worth having with no run open, and the line was simply
blank there.

The clock beside it stays the run's. That is what "how long has this been
going" means, and no other clock answers it.
@simoncoombes
simoncoombes merged commit 08eedc4 into main Sep 12, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant