fix: a person's stop reaches a run - #1250
Closed
santoshkumarradha wants to merge 10 commits into
Closed
santoshkumarradha wants to merge 10 commits into
santoshkumarradha wants to merge 10 commits into
Conversation
The line exists so the engine sees a person's gestures in the order they were made. The run's summary, a sentence a model writes under a budget of ten seconds that nobody pressed for, was asked through it, and stood in front of whatever a person did next. Measured on a real screen: a press on a run's row waited 7.6 s for a read that took 2 ms, and a stop or a pause pressed in that window would have waited the same. The summary is now asked beside the line, its fold unchanged. A pause pressed while the summary is held on a channel is answered before it returns, gestures made meanwhile still reach the plan in the order they were made, and a structural law names with its reason every door that may be asked beside the line, so a gesture cannot be moved there. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The follow was offered its read on every tick of the paint clock and held back only while one was out, so a fast engine was asked again the moment it answered: 509 reads over the wire in ninety seconds on a real screen, about six a second, for one open page. It now reads once every three seconds, the rail's own beat, counted from the last time the page was read for any reason, and only while the task is queued or running. A page on a task that has ended is read once, to open it. Counted through the real server and client: twenty ticks a beat over five beats cost 120 reads before and cost five now; twenty beats on an ended task cost none. The follow stays in the ordered line because its fold replaces the page and a note re-reads it too. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
santoshkumarradha
added a commit
that referenced
this pull request
Sep 19, 2026
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Every verb refused the run's own task, so a run a person stopped had no ending the store could hold: it stayed open and the next hand-off in the same conversation adopted it, stopped work included. StopRoot cancels the run's task and every task still open in one transaction, leaves every ended task as it ended, and is a no-op on a run that is already over. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A run's rows wear task numbers and are not in the task graph, so the stop every surface sends for one (task:N) was refused with 'there is no task N in this session' and the run carried on to its own landing: four of four on the real binary. The run was started on a context nothing could cut and no cancel was kept. The page's stop on the run's own task was refused with the store's sentence about who owns what. The id a surface already sends is now resolved to whoever owns the row: the live run first, the graph second. A stop ends the run in the store first (so no part of it reads as a failure and the next hand-off cannot adopt it), cuts the context every worker and call runs under, and keeps what was made on the run's own branch without putting anything in the person's folder. The person is told once where the work is and how it comes in or goes away. A stop on a joined row ends that work only. The page's stop on the run's task is the same stop. A ledger law lists every function that publishes a row in a state a stop means something in, with the cancel kind that reaches its owner and the test that proves it by stopping one. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…offers no verb the store refuses On the run's own page the foot offered 'x stop it' and 'p pause', and the store refuses both there for every caller, so both answered 'the harness owns the root task'. x on the run's own task now raises the stop card (the page steps aside for it, as a job's page does) and the card's 'stop it' ends the run through the plan's own door; p is not offered there and is a letter, because nothing holds a whole run. A stop on a run nobody is running any more ends it in the store. A hold asked of a run answers in a person's words. A law holds the foot to the store by property: for every kind of row a run's store can hold, every word the foot offers is pressed against a real store over the real wire, and none may be refused. The page-open hold let nothing past: ctrl+c is now read before the hold and before the page, every ending of the read ends the hold (an answer for a front the person left used to leave it standing), and a key that leaves the page ends the replay. x typed while the run's own page opens reaches the card. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…n it Measured on the real binary: a run stopped in its first seconds drew 'branch kept' beside 'it had changed nothing'. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
santoshkumarradha
force-pushed
the
fix/a-stop-reaches-the-run
branch
from
September 19, 2026 05:29
fe0fa1d to
f55c27e
Compare
A surface asks for the run's summary again whenever its rows move, and a stop moves them, so every stop taken from the run's page was followed about twenty seconds later by one more model call about work the person had just ended the spend on: three of three in the usage ledger on the real binary. The run's own task is cancelled by nothing but a person's stop, so that state is the test, and the last reading the run had stands. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
santoshkumarradha
marked this pull request as ready for review
September 19, 2026 14:23
Member
Author
|
Landed on |
This was referenced Sep 19, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What was wrong
With the belt on, nothing a person pressed could stop a run. Measured on the real binary, hosted, at trunk 12840ee on 2026-09-19:
xover an empty box, thenstop iton the cardthere is no task 1 in this session; the run carried on and landed by itselfx stop iton the run's own pagethe harness owns the root taskp pauseon the run's own pagethe harness owns the root taskCause, read in the code. A run's rows wear task numbers and are not in the task graph, and the stop a surface sends for a row is
task:N, which only the graph answered. The run was started on a context nothing could cut, and no cancel was kept anywhere. The store refuses every verb on the run's own task for every caller, and the page offered two of them.What changed
The store (
internal/plandb).StopRootis the runtime's verb for a person's word. It ends the run's own task and every task still open in one write, and leaves ended tasks as they ended. A run left open in its store is adopted by the next hand-off, so a stop has to be written there.The session. The id a surface already sends is resolved to whoever owns the row: the live run first, the graph second. Nothing on the wire changes, so a window built before this change stops a run through an engine built after it, and the model's own stop ends a run too. A stop goes in this order: the store first, so no part reads as a failure and the next hand-off cannot adopt the run; the context next, so every worker and every call it has out ends now; the work last, committed on the run's own branch with the copy given back. Nothing is merged into the folder and no model turn is bought to narrate the ending. A stop on a row that joined a run ends that work only. The page's stop on the run's own task is the same stop, and on a run nobody is running any more it ends the run in the store.
The surface.
xon the run's own page raises the stop card, and the page steps aside for it the way a background job's page does.p pauseis not offered under the run's own task and is a letter there.ctrl+cis read before a page that is on its way and before the page. Every ending of the page's read ends the key hold, including an answer for a tab the person has left. That read is already bounded by the wire's own call deadline, which answers no page. A key that leaves the page ends the replay, soxtyped while the run's own page opens reaches the card.What a person is told. On the run's page and once in the conversation:
A run stopped before it changed anything says
stopped · it had changed nothing, and then neither the sentence nor the row names a branch.No further model call. A surface asks for a run's four-line summary again whenever its rows move, and a stop moves them. The engine declines a summary for a run a person stopped; the last reading stands.
Two laws
internal/session: every function that publishes a row in a state a stop means something in is listed with the cancel kind that reaches its owner and the test that proves it by stopping one. A new publisher fails the law until it has both. I removed the run's entry to check it: the law namedstartKnownTaskRunand its line.internal/tui3: for every kind of row a run's store can hold, every verb word the foot offers is pressed against a real store over the real wire, and none may be refused. I putp pauseback under the run's own task to check it: the law quoted the store's refusal.Not in this change
ctrl+c,/quitand a closed window do not stop a run today: the window closes, the run carries on in the engine and its work lands by itself. Measured three of three for each at 12840ee, and ten of ten in a separate reproduction with the terminal killed under the window. That is unchanged here. It is a separate open question and not a regression of this change.Hosted acceptance, real binary, belt on
Nine drives at 8ca974c, the same code without the summary commit, then eight ledger probes on the later heads.
runningafterstop itxin the conversationxon the run's own pagextyped in the page-load gapChild pids: the engine's pid and its child pids were recorded before each stop. Five drives had no child alive at that instant and four had one shell child. Every recorded pid was gone after the stop, and the engine had no children, nine of nine.
Page foot on the run's own task, every page drive:
↑↓ scroll · enter send · x stop it · esc back.Usage ledger rows stamped after the stop instant, read 60 s after it:
No billed row was ever stamped after a stop. The one kind of row that was is a marker, not a call: a model name,
unbilled: true, no dollars, no tokens, no role, about 20.5 s after the stop. The engine writes it when it looks up the receipt of a call whose stream ended before its usage block and finds none. A stop cuts a call mid-stream, so the marker is the bookkeeping of a call that began before the stop and was cut by it. I first read it as a new summary call. The summary commit is still right, because a test shows the engine did make that call when asked, twice, and now makes none. It is not what the marker is, and the body says so rather than claim zero.The day figure on screen lags by a beat. In one drive it moved after a stop. The ledger had no row for that; it was earlier spend drawn late. Nobody should read that figure as spend after a stop.
One drive took 7.09 s for the row to leave
running, with a shell child alive at the stop. The row saysrunningfor that time. A small follow-up branch gives the row thestoppingreading a stopped task already has; it is not in this PR so this head stays the one that was proven.All drives used a throwaway home with private permissions. Each removed the key copy first, ended its own engine by socket holder and executable equality, then removed the home. No drive home remains.
How "the worker is gone and the spend has ended" is checked. The worker is not a process: it is a goroutine in the engine, and its steps are short-lived shell children. So each drive records the engine's pid and its child pids before the stop, and checks those pids are gone after it. Spend is read from the usage ledger's rows stamped after the stop instant. The day figure on screen is drawn on a beat and can show earlier spend late, so it is not the evidence.
Proof
internal/tui3exit 0 in 324 s, wholeinternal/sessionexit 0 in 246 s.internal/plandb,internal/run,internal/manual,internal/guard,internal/namelawok;make test-lawsexit 0;gofmt -l ./cmd ./internalempty.there is no task 71 in this session,the harness owns the root task, the foot offeringp pause,ctrl+cheld with the page's keys, the hold left standing, two summary calls after a stop.worker-harness.mdwith three probes, and the sentence about the run's own task intask-controls.md. The store's old refusal is no longer quoted as the answer.🤖 Generated with Claude Code