Skip to content

orchestrate: interrupt-safe restart — detect a dead cross-session resume, never re-implement landed work #49

Description

@TBarregren

Context — field experience (kntnt-extractor, 2026-07-22, orchestrate 0.16.1; and earlier larger runs)

A 3-issue merge-mode run was killed mid-run by a Claude Code session restart (field trigger, reproducible across several runs: entering the agent view with arrow-left to check progress, then leaving it → a "compact memory?" prompt appears → the background workflow is already dead; the TUI behavior itself is a harness matter outside this plugin, but the plugin must survive it). The completion notification suggested relaunching with resumeFromRunId. That was done — with byte-identical script and args — but Workflow resume is same-session-only, and nothing detected the mismatch: the "resume" silently got zero cache hits and re-ran the entire plan from scratch.

Consequences observed: the engine re-implemented issue #15already independently verified and landed on the default branch — from zero on a new branch; the verifier panel flagged the duplication (high severity), a fix round made the branch tree-identical to main, integrate hit a conflict, reconcile rebased, and three redundant commits landed anyway. The engine was in the middle of the same expensive dance for the also-already-landed #16 when the run was manually stopped and a hand-scoped #17-only run finished the job. In an earlier, larger field run the same failure mode compounded across restarts into 50+ agents and 50+ branches, all wasted.

Root cause

  1. A dead resume degrades silently to a full re-run. resumeFromRunId is same-session-only, but neither the skill nor the engine detects a cross-session resume; the launch proceeds with an empty cache and no warning.
  2. The engine has no idempotence guard. It never checks whether an issue's work already landed before dispatching an implementer. "Landed" exists only in the orchestrator session's memory — lost with the session — and in git history no agent is told to consult.
  3. GitHub state cannot disambiguate. Issues are closed only at finalize, so after a mid-run crash a fully-landed issue is indistinguishable from an untouched one by its open/closed state.

Proposed fix

  1. Durable per-issue landed-marker (shared mechanism with orchestrate: continuous out-of-band progress reporting for multi-hour runs (status command + durable milestone markers) #48). At integrate time, record the landing durably and machine-readably — recommended: a structured comment on the GitHub issue (e.g. orchestrate: landed <sha> on <default-branch>, run <runId>), posted by the integrate step (already the authorized mutator). Decision D1: additionally close the issue at integrate time instead of finalize — the inviolable floor ("close only after independent verification and integration") is already satisfied per issue at that moment, and closed-at-integrate makes GitHub state reflect durable progress; the cost is losing the single close-them-together finalize moment.
  2. Engine preflight guard (idempotence). Before dispatching an implementer, the engine checks the issue for a landed-marker / closed state (a cheap mechanical-tier dispatch, or folded into the implement prompt's mandatory first step with a distinct status: "already-landed" early return). An already-landed issue is skipped with that distinct status — never parked, never re-implemented, never given a second branch. This bounds the damage of any blind restart, whatever caused it.
  3. Skill restart protocol. SKILL.md documents loudly that resumeFromRunId is same-session-only, and prescribes the cross-session restart: never blind-resume — re-run orchestrate.py plan against reality (open issues minus landed-markers), launch a fresh run scoped to the remainder, and hand the new implementers the prior state as context (the recovery that worked by hand on 2026-07-22). If the engine can detect an impossible resume (e.g. an args flag carrying the original session id), it should refuse or park loudly rather than re-run — "detect that the preconditions to continue are gone, then hand over or abort; never start over from zero."

Acceptance criteria

  • An engine run whose plan contains an already-landed issue (landed-marker present, or issue closed) dispatches no implementer for it and reports it with a distinct already-landed status — engine-helpers unit-testable.
  • After a mid-run kill, a fresh orchestrate invocation scopes only the un-landed remainder: no duplicate implementation branch, no duplicate commits, for any previously-landed issue.
  • The landed-marker is written at integrate time, machine-readable, and its format is shared with orchestrate: continuous out-of-band progress reporting for multi-hour runs (status command + durable milestone markers) #48's milestone reporting.
  • SKILL.md states that Workflow resume is same-session-only and specifies the restart protocol; the completion-notification advice can no longer lead a cross-session operator into a silent full re-run.

Companion ticket: #48 (continuous out-of-band progress reporting — the milestone/landed-marker mechanism serves both).


🤖 Generated with Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingready-for-agentFully specified, ready for an AFK agent

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions