Summary
On resume of a paused sweep run, a re-armed (resolved) bundle is re-driven only because _ensure_triage reloads the cached triage.json and re-materializes the same bundle under the same _bundle_key, letting _run_bundle find the existing PENDING task. If that reload fails, the re-armed bundle can be silently orphaned and its resolved escalation stranded — the re-drive never runs.
Details
SweepEngine._ensure_triage (src/bmad_loop/sweep.py, ~line 676) short-circuits to the persisted plan on resume:
if triage_path.is_file():
plan, errors = validate_triage(_read_json(triage_path), None)
if plan is not None:
return plan
self.journal.append("sweep-triage-reload-failed", errors=errors)
# ...falls through to running a FRESH triage session
When triage.json is missing/corrupt or fails validate_triage, sweep runs a fresh triage session. That new plan may partition the open ids into differently-named bundles, so a re-armed PENDING task keyed dw-<oldname> (or dw<cycle>-<oldname>) is:
- not re-materialized under a matching
_bundle_key, and
- not picked up by
_materialize_bundles (it filters DEFERRED/ESCALATED, but a re-armed task is PENDING, so it isn't re-driven from that path either).
Net effect: the human resolved the escalation (via bmad-loop resolve, incl. --restore-patch), but the re-drive silently never happens and the bundle's dw ids stay open.
Severity
Low / pre-existing. Not introduced by the #75 patch-restore work (PR #93) — that work relies on the happy reload path, which is the normal case. This is the failure tail.
Possible fixes
- On resume, drive a re-armed escalated bundle directly by
state.paused_story_key (reconstructing its Bundle from the persisted task's dw_ids + key), independent of triage re-materialization — mirroring how the base engine's _finish_inflight re-drives the specific in-flight task.
- Or, at minimum, when a re-armed bundle task exists but the reloaded/fresh plan does not contain it,
log()/journal a loud warning instead of silently dropping it (no-silent-caps).
Context
Surfaced during the #75 pressure-test (finding "e"). See PR #93.
Summary
On resume of a paused sweep run, a re-armed (resolved) bundle is re-driven only because
_ensure_triagereloads the cachedtriage.jsonand re-materializes the same bundle under the same_bundle_key, letting_run_bundlefind the existingPENDINGtask. If that reload fails, the re-armed bundle can be silently orphaned and its resolved escalation stranded — the re-drive never runs.Details
SweepEngine._ensure_triage(src/bmad_loop/sweep.py, ~line 676) short-circuits to the persisted plan on resume:When
triage.jsonis missing/corrupt or failsvalidate_triage, sweep runs a fresh triage session. That new plan may partition the open ids into differently-named bundles, so a re-armedPENDINGtask keyeddw-<oldname>(ordw<cycle>-<oldname>) is:_bundle_key, and_materialize_bundles(it filtersDEFERRED/ESCALATED, but a re-armed task isPENDING, so it isn't re-driven from that path either).Net effect: the human resolved the escalation (via
bmad-loop resolve, incl.--restore-patch), but the re-drive silently never happens and the bundle's dw ids stay open.Severity
Low / pre-existing. Not introduced by the #75 patch-restore work (PR #93) — that work relies on the happy reload path, which is the normal case. This is the failure tail.
Possible fixes
state.paused_story_key(reconstructing itsBundlefrom the persisted task'sdw_ids+ key), independent of triage re-materialization — mirroring how the base engine's_finish_inflightre-drives the specific in-flight task.log()/journal a loud warning instead of silently dropping it (no-silent-caps).Context
Surfaced during the #75 pressure-test (finding "e"). See PR #93.