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
bmad-loop resolve <run> --story <key> --no-interactive --no-resume correctly resets task.phase to pending and task.attempt to 0, but leaves the task's sessions[] array untouched. If the dev session dispatched by the following resume does not itself get a chance to write a fresh completed-session record into state.json before the engine process ends (e.g. the process supervising it is killed/interrupted), the nextresume finds sessions[] non-empty, treats the old (pre-rearm) entry as the current attempt's result, and re-decides "pause" on it — even though phase/attempt say a fresh attempt never ran to completion. Repeating rearm does not help: each cycle resets phase/attempt again but never clears sessions[], so the orchestrator keeps re-surfacing the same stale session's result_json (in our case: session from 23:14:25, unmodified, still present after two further rearm cycles hours later).
Steps to reproduce
Get a story into escalated phase with one completed session on record (any CRITICAL escalation works; ours was the unrecognized status in existing story file case from an empty-frontmatter story, see related issues below).
bmad-loop resolve <run> --story <key> --no-interactive --no-resume — confirms "re-armed", state.json now shows phase: pending, attempt: 0, but sessions still has 1 entry (the old one).
bmad-loop resume <run> again. Expected: reconnect to and wait for the still-running session. Actual: resume-verify reads the same pre-rearm sessions[0].result_json and immediately re-decides pause, with the exact same escalation text as before rearm — even though a different (still-running or since-finished) session exists on disk under a different session_id/transcript path.
Expected behavior
A rearm that resets phase/attempt should also clear (or otherwise invalidate) the task's sessions[] array, so a subsequent resume cannot mistake a pre-rearm session's result_json for the current attempt's outcome.
Actual behavior
sessions[] survives rearm untouched. Multiple rearm→resume cycles (we did three) all converged on immediately re-deciding "pause" from the same original completed session record, without ever waiting for or attributing the outcome of the sessions we could independently observe running (live coding-CLI child processes, growing session transcript files under a different session id than the one in state.json).
We worked around this by manually clearing task.sessions to [] (and zeroing task.tokens) directly in state.json (this file lives under the gitignored .bmad-loop/runs/<id>/, so the edit needed no commit) before the next resume — which then dispatched a session whose outcome was correctly recorded.
Which area is this for?
Orchestrator / control loop
bmad-loop Version
0.11.0
Which coding CLI are you using?
Codex (codex)
Operating System
Windows
Relevant log output
(from the diagnostic dump's journal kind histogram for this run — resume-restart=7, run-paused=11, run-resume=14,
across three tasks; the story that hit this bug shows:)
dev-decision attempt=1 session_status=completed action=pause reason="CRITICAL escalation ... unrecognized status in existing story file"
story-escalated
run-paused
--- operator: `resolve --no-interactive --no-resume` -> re-armed, phase=pending, attempt=0, sessions unchanged (1 entry, same session_id) ---
run-resume was_paused=<the CRITICAL escalation above>
resume-verify
dev-decision attempt=1 session_status=completed action=pause reason=<byte-identical to the first one, same session_id/transcript timestamp>
story-escalated
run-paused
--- repeated a second time, identical result, same session_id every time ---
Diagnostic dump (bmad-loop diagnose)
Attached below (sanitized — story keys pseudonymized, no code/prompts/paths). The kind histogram shows the shape: resume-restart=7, run-paused=11, run-resume=14 against only 3 tasks and 4 dev/review sessions total — the great majority of those resume/pause cycles are this bug's symptom on one story.
Description
bmad-loop resolve <run> --story <key> --no-interactive --no-resumecorrectly resetstask.phasetopendingandtask.attemptto0, but leaves the task'ssessions[]array untouched. If the dev session dispatched by the followingresumedoes not itself get a chance to write a fresh completed-session record intostate.jsonbefore the engine process ends (e.g. the process supervising it is killed/interrupted), the nextresumefindssessions[]non-empty, treats the old (pre-rearm) entry as the current attempt's result, and re-decides "pause" on it — even thoughphase/attemptsay a fresh attempt never ran to completion. Repeating rearm does not help: each cycle resetsphase/attemptagain but never clearssessions[], so the orchestrator keeps re-surfacing the same stale session'sresult_json(in our case: session from23:14:25, unmodified, still present after two further rearm cycles hours later).Steps to reproduce
escalatedphase with onecompletedsession on record (any CRITICAL escalation works; ours was theunrecognized status in existing story filecase from an empty-frontmatter story, see related issues below).bmad-loop resolve <run> --story <key> --no-interactive --no-resume— confirms "re-armed",state.jsonnow showsphase: pending,attempt: 0, butsessionsstill has 1 entry (the old one).bmad-loop resume <run>— dispatches a fresh dev session (observable via a new coding-CLI child process and a new session transcript file). If the supervisingbmad-loopprocess is interrupted before that session'sStopevent is fully processed (on native Windows this window is wide — see Hard stop cannot interrupt blocking post-session work on native Windows (file channel has no signal-path equivalent) #698), no new entry is appended/replacingsessions[].bmad-loop resume <run>again. Expected: reconnect to and wait for the still-running session. Actual:resume-verifyreads the same pre-rearmsessions[0].result_jsonand immediately re-decidespause, with the exact same escalation text as before rearm — even though a different (still-running or since-finished) session exists on disk under a differentsession_id/transcript path.Expected behavior
A rearm that resets
phase/attemptshould also clear (or otherwise invalidate) the task'ssessions[]array, so a subsequentresumecannot mistake a pre-rearm session'sresult_jsonfor the current attempt's outcome.Actual behavior
sessions[]survives rearm untouched. Multiple rearm→resume cycles (we did three) all converged on immediately re-deciding "pause" from the same originalcompletedsession record, without ever waiting for or attributing the outcome of the sessions we could independently observe running (live coding-CLI child processes, growing session transcript files under a different session id than the one instate.json).We worked around this by manually clearing
task.sessionsto[](and zeroingtask.tokens) directly instate.json(this file lives under the gitignored.bmad-loop/runs/<id>/, so the edit needed no commit) before the nextresume— which then dispatched a session whose outcome was correctly recorded.Which area is this for?
Orchestrator / control loop
bmad-loop Version
0.11.0
Which coding CLI are you using?
Codex (codex)
Operating System
Windows
Relevant log output
Diagnostic dump (bmad-loop diagnose)
Attached below (sanitized — story keys pseudonymized, no code/prompts/paths). The
kind histogramshows the shape:resume-restart=7,run-paused=11,run-resume=14against only 3 tasks and 4 dev/review sessions total — the great majority of those resume/pause cycles are this bug's symptom on one story.Related issues
Searched first (per CONTRIBUTING.md). Adjacent but distinct:
rearm_escalationadvances the task baseline but not the spec'sbaseline_revision— completed re-drive attempts are mechanically rejected in a loop #640 (rearm_escalationadvancestask.baseline_commitbut not the spec'sbaseline_revision) — same rearm code path, but a different field (baseline_revisionvssessions[]) and a different failure mode (mismatched-baseline retry vs stale-session pause).task.baseline_commitcan drift mid-flight) — also baseline-field drift, but attributes it to concurrent activity on a shared target branch in worktree-isolation mode; our repro is single-story,isolation="none", no concurrent stories, purely repeated rearm cycles.Confirm