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
{{ message }}
Repository navigation
Commit ca8bdf8
Browse filesBrowse the repository at this point in the historyBrowse files
gluck
committed
fix(cli): only a pushed frame may say a turn has started
CORRECTION FIRST. 8014af7's message asserts that catch-up history reaches
the client through Merge and never Apply. That is false, and it was false
when it was written. Four production callsites feed a read response
straight into Apply: internal/cli/command.go:353 (desync Read),
command.go:401 and stream.go:260 (the two deliberate pager doors), and
stream.go:295 (readHistoryIntoPager). Only livelog_bridge.go and
transcript.go use Merge. Aria 250ebd07 was asked to falsify the claim and
did; the message is left standing rather than amended, so the record shows
what was believed and what turned out to be true.
THE RACE. Enter the pager while a turn is running and the catch-up
ReadBefore snapshots that turn UNSEALED. The turn ends, turn.done lands
and settles the status, and the read response arrives afterwards still
describing the turn as live. Read as a lifecycle edge it says "a turn is
now running" when none is, and nothing will ever say it stopped: the
spinner runs until the session closes. claimsOpen cannot refuse it,
because the snapshot was taken before the seal.
THE CONTENT-BEARING HALF OF THIS PREDATES THE BRANCH. OnLive called
beginTurn on any frame carrying assistant output, read or push, and has
since it was written. A stale catch-up read carrying nodes could relight a
finished turn on main today, with no part of this branch involved.
8014af7 widened the hole from content-bearing pages to inquiry-only ones;
it did not open it. Both halves are fixed here, because a known silent bug
deferred is a bug nobody fixes.
PROVENANCE, NOT A STALENESS CHECK. Apply is the push door and ApplyRead is
the read door: same fold, same order, withholding only the turn-open edge.
A staleness check was considered and rejected. rpc.DoneEntry is {reason,
idle} and carries no turn id, so such a check would have to infer which
turn ended, which is guessing about precisely the ordering that is already
broken, and a heuristic that is usually right is the worst available shape
for a failure that is silent. The caller is holding either a response or a
notification and always knows which; this makes it say so. Routing a read
into the push door now takes typing the wrong word on purpose.
ONE OWNER, NOT TWO GUARDS. Guarding OnTurnOpen alone fixed only the newer
half, which the table-driven test caught. All three routes into the open
slot (the question arriving first, a part carrying nodes, a live delta)
now go through one claim helper that takes the slot AND reports the edge,
so the two cannot drift apart and the push-only gate lives in one place.
OnLive no longer touches the status.
Deleting OnLive's arming needed its own test, because it did cover a case
the inquiry path does not: a client attaching mid-turn receives a live
delta as its first frame, carrying no question, because the question was
broadcast before it was listening. claim() now reports that from the
nodes and live branches. TestJoiningATurnInFlightMarksItRunning pins it,
and replaces a companion test that asserted the duplicate mechanism this
commit removes.
The stale-read test is table-driven over both shapes and fails on the tip:
inquiry-only fails against 8014af7, content-bearing fails against main.
Also narrows a comment from the first commit. "so /nix/store detection is
robust" became "works in every install layout", which traded a banned word
for an absolute claim; it now says what EvalSymlinks actually does.
0 commit comments