Skip to content

[BUG] resolve --no-resume rearm leaves task.sessions[] stale, so resume re-decides on the pre-rearm session #705

Description

@TerranUlm

Description

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 next resume 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

  1. 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).
  2. 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).
  3. 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 supervising bmad-loop process is interrupted before that session's Stop event 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/replacing sessions[].
  4. 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.

# bmad-loop diagnostic dump (sanitized)

_Identifiers are pseudonymized; code, prompts, paths and free text are redacted. Safe to share._

## Environment
- **bmad-loop version:** 0.11.0
- **python:** 3.14.2
- **os:** Windows 11
- **sys.platform:** win32
- **win32 on WSL distro path:** no
- **multiplexer:** PsmuxMultiplexer
- **tmux:** tmux 3.3.8; psmux 3.3.8 (66cf613 2026-08-18)
- **schema / generated:** v1 @ 2026-08-24T00:13:13Z

## Run `20260823-084323-2058` (story)
- **project:** `project-704da20744b8`
- **started:** 2026-08-23
- **state:** finished=False stopped=False paused=False
- **epic / sweep_cycle:** 5 / 1
- **tasks:** 3
- **phase histogram:** awaiting-operator=1, done=1, review-running=1
- **token totals:** cache_creation_tokens=0, cache_read_tokens=10131584, input_tokens=5296923, output_tokens=42990, total=15471497, weighted=6353071
- **sessions by status:** completed=4
- **sessions by role:** dev=3, review=1

### Tasks
| alias | epic | phase | att | rev | committed | spec | dw | sessions | weighted | raw |
|---|---|---|---|---|---|---|---|---|---|---|
| `s5-5db05db7a3bc` | 5 | awaiting-operator | 1 | 0 | True | True | 0 | 1 | 652917 | 5138575 |
| `s5-5d427343711c` | 5 | done | 1 | 1 | True | True | 0 | 2 | 5269816 | 7258859 |
| `s5-17671e722bb1` | 5 | review-running | 1 | 1 | False | True | 0 | 1 | 430338 | 3074063 |

### Journal
- **entries:** 113
- **duration (s):** 62668.528
- **escalations / defers / plugin-errors:** 4 / 0 / 0
- **kind histogram:** attempt-worktree-preserved=2, dev-decision=10, plugins-active=15, resume-restart=7, resume-review=1, resume-verify=6, review-result=1, review-skipped-awaiting-operator=1, rollback-auto=2, rollback-manual-required=6, rollback-owned-spec-manual-required=1, rollback-owned-spec-normalized=2, rollback-owned-spec-snapshot-missing=1, rollback-skipped-clean=2, run-paused=11, run-resume=14, run-start=1, session-end=5, session-start=9, spec-deferrals-harvested=3, story-awaiting-operator=1, story-done=1, story-escalated=4, story-escalation-resolved=3, story-start=3, token-budget-exceeded=1

_Per-task event counts:_
- `s5-17671e722bb1`: attempt-worktree-preserved=2, dev-decision=3, resume-restart=7, resume-review=1, resume-verify=3, rollback-auto=2, rollback-manual-required=2, rollback-owned-spec-manual-required=1, rollback-owned-spec-normalized=2, rollback-owned-spec-snapshot-missing=1, rollback-skipped-clean=2, run-paused=6, story-escalated=3, story-escalation-resolved=3
- `s5-5d427343711c`: dev-decision=1, resume-verify=1, story-start=1
- `s5-5db05db7a3bc`: dev-decision=2, resume-verify=2, review-skipped-awaiting-operator=1, rollback-manual-required=1, run-paused=1, spec-deferrals-harvested=2, story-awaiting-operator=1, story-start=1
- `story-162d8a40b4ce`: dev-decision=1, rollback-manual-required=1, run-paused=1, session-end=1, session-start=1
- `story-3265b1e11336`: dev-decision=2, rollback-manual-required=1, run-paused=2, session-end=2, session-start=5, story-escalated=1
- `story-5cc6a825cd62`: review-result=1, session-end=1, session-start=1, story-done=1, story-start=1, token-budget-exceeded=1
- `story-c4a573c296a5`: dev-decision=1, rollback-manual-required=1, run-paused=1, session-end=1, session-start=1, spec-deferrals-harvested=1

### Run-dir files (counts only)
- **logs:** 9 files, 19856168 bytes, 9216 lines
- **tasks:** 13 files, 832398 bytes
- **events:** 11 files, 3502 bytes

Related issues

Searched first (per CONTRIBUTING.md). Adjacent but distinct:

Confirm

  • I've searched for existing issues
  • If I attached a diagnose dump, I reviewed it and confirmed it contains no PII, secrets, or project-specific information
  • I'm using the latest version

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions