A page boundary lands wherever it lands, and about half the time that is
between a tool call and its result. The newer page then holds a `ToolEnd`
whose start it never saw, which the fold draws as a row of its own --
correctly, since a call rendering as nothing is indistinguishable from
one that never happened. But when the older page arrived it brought the
real `ToolStart`, and the two lists were concatenated, so the call was
left on screen twice: once as a proper card and once as a nameless
placeholder.
`joinPages` merges the two halves by the call's own id instead, which is
the one thing a page boundary cannot destroy. The older half wins on what
a start knows -- the tool's name, its input -- and the newer on what an
end knows, its output and whether it finished.
The miscount was the visible part; the moving was the point. The extra
row sits exactly at the join, which is where the reader is looking when
the page loads, so everything below it stepped down by a row at the
moment they scrolled into it.
Demonstrated both ways round on a rig of twelve `/tools 8` runs, whose
groups are eight calls each and whose page boundary falls inside the
second one: without this the transcript reads "Called 9 tools" there and
eight everywhere else, with it every group reads eight.
That rig is `/mixed N` in the echo driver, added here: N beats of
paragraphs at three lengths, single tool calls, runs of adjacent ones,
images and peer messages -- every row shape the app draws, in one
session, from a command that costs nothing and produces the same
transcript every time. The paragraphs are deliberately ragged, because a
wall of identical lines looks the same at every offset and makes a scroll
of one line indistinguishable from a scroll of ten, by eye or by
comparing frames.