tickets: an injected plan_halt result for a built plan escalates with stopped-attempt wording
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 36/100
調査の方向性
Start with the plan-halt flow in src/bmad_loop/tickets_engine.py around _drive_story and the result handling at lines 1418-1437; then compare the expected status check in src/bmad_loop/verify.py with result synthesis in src/bmad_loop/devcontract.py. Reproduce with the supplied MockAdapter script and compare the injected plan_halt case with overrun-synth. Done means a supported adapter or reproducible race is identified, or the inconsistent result gets a clearer diagnostic without weakening verification.
索引モデルが issue の本文から書いたものです。
説明
Status (needs confirmation)
- Observed (3/3, engine seam): for an unrefined
plan_checkpointticket, a leg-1 session (aMockAdapterresult injected by the script) that builds and commits pastHalt after planning.behaves as follows:- without
plan_haltin its result, the run pausesplan-checkpointwith "plan review owed for 1.1: the skill implemented before the plan checkpoint" (the dedicated path); - with
"plan_halt": truein its result, it pausesescalationwith "ACTION REQUIRED — manual recovery needed (committed work present) … attempt was stopped with auto-rollback OFF". Thedev-decisionisretrywith "spec status is 'built', expected 'ready-for-dev'".
- without
- Observed control: a leg 1 that honours the halt (plan at
ready-for-dev,plan_halt: true, nothing committed) pausesplan-checkpoint"plan checkpoint for 1.1: review the spec, then resume". - Measured additional control: production
devcontract.synthesize_result(..., plan_halt=True, success_statuses=("built",))omitsplan_haltfor the same built plan, and the engine then pauses with "plan review owed". It setsplan_haltforready-for-dev. A live build-auto/GenericDevAdapter run was not performed, and no operator path producing the contradictory marker has been demonstrated. - Still needed: demonstrate a supported adapter or a reproducible result/plan race that supplies
plan_halt: truewhile the bound plan isbuilt. A skill merely ignoring the halt does not establish that precondition. If you have seen such a result from a real session, please confirm here with the result JSON and the pause stage and message.
Summary
With an injected MockAdapter result containing plan_halt: true and a committed built plan, verification rejects the plan's status and the run pauses for manual recovery. The same built plan processed by production result synthesis reaches the dedicated "plan review owed" pause. No confirmed normal build-auto failure is shown. The guide's promise holds in every row (no bmad-loop commit happens and the run pauses); what differs is the pause: with the flag set, the overrun becomes a failed attempt and an escalation that says the attempt "was stopped" and asks for manual recovery of committed work, instead of the "plan review owed" pause that TicketsEngine._drive_story has for an overrun.
Environment
bmad-loop a5a8f097, Windows 11 10.0.26200, PowerShell 7.6.6 (SHELL unset), Python 3.13.2; TicketsEngine with MockAdapter as an engine seam (not a live generic-adapter validation; no coding CLI); Linux: not run, platform parity unmeasured.
Steps to reproduce
From a bmad-loop checkout at a5a8f097 after uv sync --all-extras, in PowerShell 7 with SHELL removed. Save the script outside the checkout as $env:TEMP\overrun-repro\repro_overrun.py, then run from the checkout root (the script imports the test helpers from tests). Each run creates its sandbox under $env:TEMP.
Remove-Item Env:SHELL -ErrorAction SilentlyContinue
$env:PYTHONUTF8 = '1'
$s = "$env:TEMP\overrun-repro\repro_overrun.py"
uv run python $s overrun-flag # trigger: injected plan_halt on a built plan
uv run python $s overrun # control: no plan_halt
uv run python $s halt # control: the halt honoured
uv run python $s overrun-synth # control: bmad-loop's own result synthesis for the built plan
import json, os, subprocess, sys, tempfile
from pathlib import Path
mode = sys.argv[1]
root = Path(tempfile.mkdtemp(prefix=f"overrun-{mode}-"))
os.environ["BMAD_LOOP_STATE_DIR"] = str(root.parent / (root.name + "-state"))
sys.path.insert(0, "tests")
import conftest as C
from bmad_loop import verify
from bmad_loop.adapters.base import SessionResult
from bmad_loop.adapters.mock import MockAdapter
from bmad_loop.bmadconfig import load_paths
from bmad_loop.journal import Journal, load_state
from bmad_loop.model import RunState
from bmad_loop.policy import GatesPolicy, NotifyPolicy, Policy, ReviewPolicy
from bmad_loop.tickets_engine import TicketsEngine
git = lambda cwd, *a: subprocess.run(["git", "-C", str(cwd), *a], capture_output=True, text=True, check=True).stdout.strip()
lay = C.install_bmad_v7(root)
(root / "src.txt").write_text("original\n", encoding="utf-8")
(root / ".gitignore").write_text(C.V7_GITIGNORE, encoding="utf-8")
C.write_ticket_tree(lay, (C.EpicSpec(1, "epic-cart", "Cart", (C.EntrySpec(1, "Cart model", plan_checkpoint=True),)),))
C._commit_template(root)
plan = Path(C.run_tickets(lay, "find", "1.1")["plan"])
def leg1(spec):
cwd, base = Path(spec.cwd), verify.rev_parse_head(Path(spec.cwd))
if mode.startswith("overrun"): # ignores "Halt after planning.", builds and commits its own work
(cwd / "src.txt").write_bytes(b"cart model\n")
plan.write_bytes(f"---\nticket: 1\nstatus: built\nbaseline_revision: '{base}'\n---\n\n# plan\n".encode())
git(cwd, "add", "-A"); git(cwd, "commit", "-q", "-m", "build 1.1")
status = "built"
else: # honours the halt
plan.write_bytes(f"---\nticket: 1\nstatus: ready-for-dev\nbaseline_revision: '{base}'\n---\n\n# plan\n\nsteps\n".encode())
status = "ready-for-dev"
result = {"workflow": "auto-dev", "spec_file": str(plan), "status": status}
if mode in ("halt", "overrun-flag"):
result["plan_halt"] = True
if mode == "overrun-synth": # control: bmad-loop's own result synthesis for the same built plan
from bmad_loop.devcontract import synthesize_result
result = synthesize_result(plan, story_key="1.1", plan_halt=True, success_statuses=("built",)).result_json
print(" synthesized:", {"status": result.get("status"), "plan_halt": result.get("plan_halt")})
return SessionResult(status="completed", result_json=result)
run_dir = root / ".bmad-loop" / "runs" / "r1"
state = RunState(run_id="r1", project=str(root), started_at="now", initiative=lay.initiative, initiative_folder=str(lay.initiative_folder))
TicketsEngine(paths=load_paths(root, want_tickets=True),
policy=Policy(gates=GatesPolicy(mode="none"), notify=NotifyPolicy(desktop=False, file=True), review=ReviewPolicy(enabled=False)),
adapter=MockAdapter([leg1] * 3), run_dir=run_dir, journal=Journal(run_dir), state=state).run()
st = load_state(run_dir)
print(f"{mode}: paused_stage={st.paused_stage}\n reason: {(st.paused_reason or '').splitlines()[0][:160]}")
print(" journal:", [json.loads(l)["kind"] for l in (run_dir / "journal.jsonl").read_text(encoding="utf-8").splitlines()])
Observed (Windows; trigger and the first two controls 3/3, the synthesis control in its own runs):
overrun-flag: paused_stage=escalation
reason: **ACTION REQUIRED — manual recovery needed (committed work present)**
journal: ['story-start', 'plan-halt', 'session-start', 'session-end', 'dev-decision', 'rollback-manual-required', 'run-paused']
overrun: paused_stage=plan-checkpoint
reason: plan review owed for 1.1: the skill implemented before the plan checkpoint — review the spec, then resume
journal: ['story-start', 'plan-halt', 'session-start', 'session-end', 'dev-decision', 'checkpoint-pause', 'run-paused']
halt: paused_stage=plan-checkpoint
reason: plan checkpoint for 1.1: review the spec, then resume
journal: ['story-start', 'plan-halt', 'session-start', 'session-end', 'plan-halt-proof-of-work-skipped', 'dev-decision', 'checkpoint-pause', 'run-paused']
synthesized: {'status': 'built', 'plan_halt': None}
overrun-synth: paused_stage=plan-checkpoint
reason: plan review owed for 1.1: the skill implemented before the plan checkpoint — review the spec, then resume
journal: ['story-start', 'plan-halt', 'session-start', 'session-end', 'dev-decision', 'checkpoint-pause', 'run-paused']
Source
At a5a8f097:
src/bmad_loop/tickets_engine.py:1002-1034(_drive_story): the comment says "a session that overran the halt still owes the review"; a false return from_dev_phaseexits before either checkpoint pause (_pause_plan_checkpoint,_pause_plan_review_owed).src/bmad_loop/tickets_engine.py:1418-1437: takesbool(result["plan_halt"]), setstask.plan_checkpoint_pending, and passes that flag toverify_dev_tickets.src/bmad_loop/verify.py:9445-9456: selectsPLAN_HALT_STATUS(ready-for-dev) for a marked result andPLAN_BUILTotherwise, so a markedbuiltplan fails (observed as thedev-decisionretry reason).src/bmad_loop/devcontract.py:163-164: "the seam is gated onplan_halt, never on the status alone",PLAN_HALT_STATUS = "ready-for-dev".src/bmad_loop/devcontract.py:635-639: result synthesis marks only a cleanready-for-devresult (if plan_halt and status == PLAN_HALT_STATUS and not escalations: result["plan_halt"] = True);src/bmad_loop/adapters/generic.py:3013-3031calls that synthesizer with the dispatched plan-halt flag.src/bmad_loop/recovery_flow.py:2604-2625: the "stopped" and committed-work recovery wording observed.
Suggested fix
Not validated: consider clearer diagnostic wording for inconsistent adapter results. Do not relax the expected-status verification or route contradictory results to plan approval without a demonstrated supported user path and an explicit contract decision.
- 主要言語
- Python
- スター
- 160
- フォーク
- 68
- 平均マージ
- 1日 6時間
- マージ済み PR(30日)
- 90
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートあり
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
bmad-code-org/bmad-loop のほかの issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 69/100
bmad-code-org/bmad-loop#973 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
bmad-code-org/bmad-loop#965 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
bmad-code-org/bmad-loop#835 ·
メンテナーはふだん 1 日以内に返信
-
area:adapters area:psmux bug P4
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
bmad-code-org/bmad-loop#673 · コメント 8 件 · リアクション 1 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 4/5 1〜2日 初心者へのやさしさ 49/100
bmad-code-org/bmad-loop#971 ·
メンテナーはふだん 1 日以内に返信
bmad-code-org/bmad-loop の issue をすべて見る
似ている issue
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
anchore/grype-db#1149 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
[Bug]: `hermes plugins update` clones an entire monorepo twice - `subdir` is resolved but dropped at both catalog-update call sites対応中かも @HootRock が今日担当しました。 オープンcomp/cli P2 type/perf
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
NousResearch/hermes-agent#142417 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
-
SMC SPEC
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
tenstorrent/tt-oca-harness#3287 ·
メンテナーはふだん 1 日以内に返信
-
bug enhancement python
難易度 2/5 1〜3時間 初心者へのやさしさ 85/100
DewaldOosthuizen/tech-cheat-sheets-and-notes#392 ·
メンテナーはふだん 1 日以内に返信
-
security
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
fabriziosalmi/wildbox#801 ·
メンテナーはふだん 1 日以内に返信