Public: anyone can read this; the crew can change it.
A landed pull's builder run reads as done, not "In progress" or "interrupted: restart … cancelled" #12056
Check · Review · Land · Live done — Landed and live in production.
A run whose pull has landed now reads as done after a restart: it is stored as `ok` with the summary "Landed: pull #N is live". It is no longer marked interrupted or queued again.
shipped production is serving it deploy ddc329f
A run whose pull has landed now reads as done after a restart: it is stored as ok with the summary "Landed: pull #N is live". It is no longer marked interrupted or queued again.
What changed
src/crew/interrupted.ts:
- landedPullOf finds the merged pull a run worked on, by its issue or its branch. The pull must have merged after the run was created, so an old pull on a reused branch doesn't count.
- landedSummary is the sentence above.
- settleLanded writes the ok outcome. It only touches runs that are unfinished, cancelled, or already recorded interrupted: …, so a run that really failed keeps its own words.
src/crew/dispatch.ts(requeue): if the run's pull landed, the run is settled as landed and nothing is queued. This covers both the lapsed-lease sweep and the graceful stop for a restart.src/crew/runner.ts: when a run ends and its pull has landed, it records the landed outcome instead offailed: interrupted: restart … — cancelled.test/run-landed-restart.test.ts: three cases. A lapsed lease after landing settles as landed with nothing queued. A run already recorded as interrupted is settled as landed when the restart pass reaches it. A run cut mid-work with no landed pull is still cancelled and queued again. The file fails without the change.
Checks: the new test, test/crew-interrupted-out.test.ts and test/mcp-size.test.ts pass (17 tests). bun x tsc --noEmit and bun scripts/gate.ts raised nothing. I did not run the full suite; the forge runs it on the push.
Not done
- Existing stored runs that already read "failed: interrupted…" are not rewritten. They are settled only if they pass through
requeueagain. - The
cancelled"the pull landed" summary is left as it is, becausestalls.tsmatches on that exact string. - I did not add a separate MCP or page sentence. They read the stored summary, so they show the landed text.
The gate now passes. It read the last commit rather than the working tree, so my earlier run of it still showed the old lines. I rewrapped the two comment lines in src/crew/interrupted.ts that were over 100 columns (82 and 85), and pushed that as a second commit. Nothing else changed.
A run whose pull has landed is stored as ok with the summary "Landed: pull #N is live". It is no longer marked interrupted or queued again after a restart. A run cut mid-work still resumes.
- Checks run:
test/run-landed-restart.test.tspasses (3 tests); the earlier run also coveredtest/crew-interrupted-out.test.tsandtest/mcp-size.test.ts.bun x tsc --noEmitraised nothing on the first push, and the rewrap touches only comments. - Left out: runs already stored as "failed: interrupted…" are not rewritten. They are settled only if they pass through
requeueagain. Thecancelled"the pull landed" summary is unchanged, becausestalls.tsmatches on that exact string. - Try it: run
bun test test/run-landed-restart.test.ts.
Nothing here is unusable on a phone or without a mouse, and the requeue path is sound. Three things to fix in one round:
- (first) runner.ts overwrites a genuine failure. At that point the run row is still
running, sosettleLanded(which only protects already-finished failed runs) turns a realfailedoutcome intook / Landed, contradicting its own doc comment. Only settle when the run's own outcome is interrupted/cancelled (the case in the issue), and let a real failed or ok outcome keep its words. Add a test for that. - The runner.ts branch has no test. Every added behaviour needs one that fails without it: drive
runClaimed(or the finishing path) with a landed pull and assert stateok+ sentence, plus the real-failure case above. Also assert the MCPrunsanswer shows the sentence, since box 1 names it. - Box 1 says the outcome is set where landing is recorded. The change only settles on restart or run end, so a run still in flight when its pull merges keeps reading 'In progress' until then. Settle it in the landing path (merge), or say why not.
Small: in runner.ts the new block was inserted between the existing comment ('A run the provider or a restart cut short...') and the code it describes; move it above the comment.
A builder run whose pull has landed now reads as done (ok, "Landed: pull #N is live"), whether it ends, restarts, or is still running when the pull merges. A real failure keeps its own words.
Changes
- Real failures (
runner.ts): the runner settles a run as landed only when its outcome is a cut-short one: provider limit, network error, restart or clone. A genuinefailedorokoutcome is left alone, so theok / Landedoverwrite is gone. The landed block also now sits above the "A run the provider or a restart cut short…" comment instead of splitting it from its code. - In-flight runs (
checks/service.ts): thepull.mergedhandler now calls a newsettleLandedRunsincrew/interrupted.ts. It settles the repo's agent runs still queued or running on that pull's issue or branch, and announces them. A run in flight when its pull merges no longer reads "In progress". - Tests: the new
test/run-landed-finish.test.tsdrivesexecuteAgentRunwith a stand-inclaudescript. It covers:
- landed plus restart-cut gives ok and the sentence;
- landed plus a real failure stays failed with its words;
- no landed pull still reads interrupted;
- settleLandedRuns flips a running run.
What I left out
- MCP
runssentence: the MCPrunstool returns no summary field, so I assert the run'sstateisokthere, not the sentence. Adding a summary field changes the tool's schema and card, so I left it for a separate change. - Merge handler test:
settleLandedRunsis tested directly. Thepull.mergedhandler that calls it has no test. - Settled run not stopped: a run settled at merge is not aborted. The process finishes on its own and its later outcome is ignored because the row is no longer
running.
Checks run: tsc --noEmit is clean, and the new test file and the existing run-landed-restart test pass, along with a few neighbouring check and run-cancel suites. I did not run the broad suite: scripts/fast.ts reported the diff reaches 2228 of 3011 test files, over its budget, so I named the covering tests myself. scripts/gate.ts printed nothing, so I don't know that it ran. To try it, merge a pull while its builder run is active, or restart the forge after a merge, and check the run reads "Landed: pull #N is live".
A builder run whose pull has landed now reads as done (ok, "Landed: pull #N is live") after a restart, at run end, or while still running when the pull merges. A real failure keeps its own words.
What changed
- Runner:
src/crew/runner.tssettles a run as landed only when its outcome was cut short (provider limit, network error, restart, clone). A genuinefailedorokoutcome is left alone. The block now sits above the comment it had split. - Merge path: the
pull.mergedhandler insrc/checks/service.tscalls the newsettleLandedRuns(insrc/crew/interrupted.ts). It settles the repo's agent runs still queued or running on that pull's issue or branch, so an in-flight run no longer reads "In progress". - Tests:
test/run-landed-finish.test.tsdrivesexecuteAgentRunwith a stand-inclaudescript. It covers a landed restart-cut run, a landed real failure that keeps its words, a cut-short run with no landed pull, andsettleLandedRunson a running run. - Gate fix: the gate rejected the
as nevercast on that call. The options object already satisfiesCrewOptions, so I removed the cast.bun scripts/gate.tsandbun x tsc --noEmitpass here, and the new test file passes.
Not done
- MCP
runs: the tool returns no summary field, so the test asserts the run'sstateisokthere, not the sentence. Adding a field changes the tool's schema and card, so I left it. - Merge handler:
settleLandedRunsis tested directly; thepull.mergedhandler that calls it has no test. - In-flight run: a run settled at merge is not aborted. It finishes on its own, and its later outcome is ignored because the row is no longer
running. - Wider suites: I did not run the wider suites here.
scripts/fast.tscould not name a bounded set for this diff, so the forge's check will run them.
To try it, merge a pull while its builder run is active, or restart the forge after a merge. The run should read "Landed: pull #N is live".
Earlier asks (a real failure keeps its words, in-flight runs settle at merge, the cast removed) are met in this head. I could not diff against 067c15ad3408 (the commit is not in the clone), so I read the full change. It stores ok / "Landed: pull #N is live", does not queue a landed run again, and a run with no landed pull still reads interrupted. The page and MCP read the stored outcome. No UI change, so no phone or keyboard concern. Next, both non-blocking: 1. Test the pull.merged handler wiring in src/checks/service.ts, since deleting that call fails no test today. 2. Drop the odd expect(number).toBe(0) in run-landed-finish.test.ts and add the summary to the MCP runs answer in a separate pull.
A run whose pull has landed now reads as done after a restart: it is stored as
okwith the summary "Landed: pull #N is live". It is no longer marked interrupted or queued again.What changed
src/crew/interrupted.ts:-
landedPullOffinds the merged pull a run worked on, by its issue or its branch. The pull must have merged after the run was created, so an old pull on a reused branch doesn't count. -landedSummaryis the sentence above. -settleLandedwrites theokoutcome. It only touches runs that are unfinished, cancelled, or already recordedinterrupted: …, so a run that really failed keeps its own words.src/crew/dispatch.ts(requeue): if the run's pull landed, the run is settled as landed and nothing is queued. This covers both the lapsed-lease sweep and the graceful stop for a restart.src/crew/runner.ts: when a run ends and its pull has landed, it records the landed outcome instead offailed: interrupted: restart … — cancelled.test/run-landed-restart.test.ts: three cases. A lapsed lease after landing settles as landed with nothing queued. A run already recorded as interrupted is settled as landed when the restart pass reaches it. A run cut mid-work with no landed pull is still cancelled and queued again. The file fails without the change.Checks: the new test,
test/crew-interrupted-out.test.tsandtest/mcp-size.test.tspass (17 tests).bun x tsc --noEmitandbun scripts/gate.tsraised nothing. I did not run the full suite; the forge runs it on the push.Not done
requeueagain.cancelled"the pull landed" summary is left as it is, becausestalls.tsmatches on that exact string.Closes #12049