feat(loop): continue a stopped run — same objective, a new ceiling, briefed on what already landed (refs #806) - #819
Merged
Merged
Conversation
…iling, briefed on what already landed — refs #806 Slice (ii) of #806: "grant more iterations and continue". Items 1, 2 and 3(b) still wait on the owner decision recorded on the issue; this is the half that needed none. POST /v1/instances/:id/loop/:runId/continue carries a stopped run's objective onto a NEW run. It is not a resumed invocation: a finished agent_loop_runs row has no live Workflow to grant steps to, and #523's option (b) — checkpoint the OBJECTIVE, not the transcript — means there is no transcript to reanimate. The continuity is the resume note, composed at the start of the new run from what the old one left on the record. The route is thin on purpose. driver.start() already picks the repo, opens or reuses the session, runs admission and takes the single-flight claim; assembling any of that here would be a second, quieter copy of the start path. What it decides is only: which runs may be continued (RESUMABLE_STOP_REASONS, refusing everything else with a sentence naming the next step instead), what the new run starts with (the stopped run's objective, its repo via its session, its own step cap unless the caller grants more, clamped by the same #477 account ceiling), and a FRESH budget — #184's rule that every autonomous entry point admits separately, or one admission funds an unbounded chain. The lookback is the whole difference from a restart. #806 item 4 asks that this work "even hours later", and RESUME_NOTE_LOOKBACK_MS is six hours — so a Continue pressed the next morning would have started a run briefed on nothing at all. A continue passes CONTINUE_RESUME_LOOKBACK_MS (30 days) through LoopStartInput → the workflow params → pendingCodingResumeNote → lastUnfinishedRunForRepo. It moves the FLOOR only: the predecessor is still the most recent FINISHED run on the repo, judged afterwards, so a verdict in between still ends the note's job. That is also why the note is NOT pinned to the continued run's id — pinning would skip that check and brief the new run on a checkpoint another run has already consumed. Console: a Continue button beside the ending label, offered only after an ending with no verdict (canContinueRun, pure and tested, with a test that reads the worker's own RESUMABLE_STOP_REASONS so the two lists cannot drift silently). MCP: continue_instance_run, beside start_instance_loop. Not part of #613's sweep — the route is new here, and shipping the console button without a tool would have ADDED a gap to the ratchet #613 is driving to zero. Parity holds at 29 recorded gaps, unchanged. Server 0.1.38 → 0.1.39 with its SURFACE_LOCK entry; 196 → 197 registrations. Verified: 42 new tests (24 route, 13 console-lib, 3 real-schema lookback, 1 driver threading, 1 workflow wiring). Mutation-checked — dropping the lookback at any of its three links, the cross-instance guard, the unfinished-run guard or the ceiling default each turns tests red. Full suite 11,793/11,793; pnpm -r typecheck; biome; docs:drift; all 13 check-*.mjs. Not verified: no live run. That needs a real run stopped for a resumable reason, followed by Continue — agent_trace on the successor shows whether the note fired. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
serge-ivo
pushed a commit
that referenced
this pull request
Sep 19, 2026
… one — refs #821 Run cda38e26 opened PR #819 on this repository, whose whole workflow is commit-and-push to main. The objective told it not to; it did anyway, near its iteration limit. That instruction was layer 1 of the #314 merge-authority gate, and layer 1 is advisory. `direct` is a fourth MergePolicy, and it is the MIRROR of `pr` rather than a rung above it: it PERMITS the trunk — that is the point of it — and forbids `pr.open` instead. The three existing layers carry it unchanged: the Pilot's prompt is told to push to the default branch, the instruction screen refuses to relay "open a PR" to the Engine, and an observed `pr.open` halts the run with an `act.unauthorized` event and a board card. Layer 2 is the one that sits in front of the actual incident — #819 was opened by an Engine the Pilot had instructed — and it is deterministic rather than a request. The default is untouched: DEFAULT_MERGE_POLICY stays `merge`, the repo column still defaults to '' (inherit), and `merge` and `pr` both still permit opening a pull request. Migration 0154 only adds the option to the seeded `merge_policy` select, so the console settings card and MCP `set_instance_settings` both accept it (they validate against the select's options). There is no schema change — `coding_repos.merge_policy` carries no CHECK constraint, so a repo override already stored and already resolved. repo-path-writer's migration walk resolves settingsSchema FIELD ids; 0154 appends an OPTION to an existing field and provably changes no field, so the parser is taught that shape rather than having the assertion loosened. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Slice (ii) of #806 — "grant more iterations and continue". Items 1, 2 and 3(b) still wait on the owner decision recorded on the issue; this is the half that needed none.
What it does
POST /v1/instances/:id/loop/:runId/continuecarries a stopped run's objective onto a new run. Not a resumed invocation: a finishedagent_loop_runsrow has no live Workflow to grant steps to, and #523's option (b) — checkpoint the OBJECTIVE, not the transcript — means there is no transcript to reanimate. The continuity is the resume note, composed at the start of the new run from what the old one left on the record.The route is thin on purpose.
driver.start()already picks the repo, opens or reuses the session, runs admission and takes the single-flight claim. What the route decides is only:RESUMABLE_STOP_REASONS, refusing everything else with a 409 naming the next step instead (adonerun wants a new objective, afailedone wants its outcome read first, acancelledone was a human's decision continuing would quietly undo).The lookback is the whole difference from a restart
#806 item 4 asks that this work "even hours later", and
RESUME_NOTE_LOOKBACK_MSis six hours — so a Continue pressed the next morning would have started a run briefed on nothing at all. A continue passesCONTINUE_RESUME_LOOKBACK_MS(30 days) throughLoopStartInput→ the workflow params →pendingCodingResumeNote→lastUnfinishedRunForRepo.It moves the floor only. The predecessor is still the most recent finished run on the repo, judged afterwards, so a verdict in between still ends the note's job. That is also why the note is not pinned to the continued run's id — pinning would skip that check and brief the new run on a checkpoint another run has already consumed.
Console + MCP
canContinueRunis pure and tested, with a test that reads the worker's ownRESUMABLE_STOP_REASONSso the two lists cannot drift silently.continue_instance_run, besidestart_instance_loop. Not part of MCP parity: 71 console capabilities have no MCP path — the first run's inventory, by group #613's sweep — the route is new here, and shipping the console button without a tool would have added a gap to the ratchet MCP parity: 71 console capabilities have no MCP path — the first run's inventory, by group #613 is driving to zero. Parity holds at 29 recorded gaps, unchanged. Server0.1.38→0.1.39with itsSURFACE_LOCKentry; 196 → 197 registrations.Verified
42 new tests — 24 route, 13 console-lib, 3 real-schema lookback, 1 driver threading, 1 workflow wiring.
Mutation-checked: dropping the lookback at any of its three links, the cross-instance guard, the unfinished-run guard or the ceiling default each turns tests red.
Full suite 11,793/11,793;
pnpm -r typecheck; biome;docs:drift; all 13check-*.mjs.Not verified
No live run. That needs a real run stopped for a resumable reason, followed by Continue —
agent_traceon the successor shows whether the note fired and whether the new run built on it.🤖 Generated with Claude Code