Skip to content

Commit 658ef95

Browse files
fix(tui): retry acts on the displayed generation, not the session file (#49)
* fix(tui): retry acts on the displayed generation, not the session file The TUI retry action discarded the dashboard's active generation_id and re-derived it from specflow_session.json at the SpecFlow checkout root (resolve_repo_root), where no session file exists when the run belongs to another project or was opened from the Sessions list. cmd_retry_generation also hardcoded resolve_generation_id(None, ...), ignoring any explicit id. Result: retry printed "No previous generation found" and no-oped, leaving the session FAILED. Thread the on-screen generation_id through do_retry into cmd_retry_generation (session file remains the fallback), matching the download-outputs pattern, and add --generation-id to the retry-generation subparser. * fix(tui): update retry-flow test for the generation_id-aware do_retry call
1 parent 7177ee3 commit 658ef95

5 files changed

Lines changed: 17 additions & 9 deletions

File tree

mcp_server/cli.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ async def cmd_retry_generation(args: argparse.Namespace) -> int:
266266
print(f"Using project root: {root}")
267267
set_project_root(root)
268268

269-
generation_id = resolve_generation_id(None, root)
269+
generation_id = resolve_generation_id(args.generation_id, root)
270270
if not generation_id:
271271
print("No previous generation found. Run `specflow run-generation` to start one.")
272272
return 0
@@ -564,7 +564,13 @@ def _build_parser() -> argparse.ArgumentParser:
564564
subparsers.add_parser("check-status", help="Check progress of a running generation")
565565

566566
# retry-generation
567-
subparsers.add_parser("retry-generation", help="Retry a failed generation")
567+
p_retry = subparsers.add_parser("retry-generation", help="Retry a failed generation")
568+
p_retry.add_argument(
569+
"--generation-id",
570+
default=None,
571+
dest="generation_id",
572+
help="Generation ID (default: from specflow_session.json)",
573+
)
568574

569575
# download-outputs
570576
p_dl = subparsers.add_parser(

mcp_server/tests/test_cli.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ async def test_calls_retry_endpoint(self, tmp_project):
283283
from services.session import write_session
284284
write_session("gen-xyz", tmp_project)
285285

286-
args = SimpleNamespace(root_path=str(tmp_project), command="retry-generation")
286+
args = SimpleNamespace(root_path=str(tmp_project), command="retry-generation", generation_id=None)
287287

288288
# check_status_safe returns failed → proceed to retry POST
289289
with patch(
@@ -308,7 +308,7 @@ async def test_blocks_when_already_running(self, tmp_project, capsys):
308308
from services.session import write_session
309309
write_session("gen-running", tmp_project)
310310

311-
args = SimpleNamespace(root_path=str(tmp_project), command="retry-generation")
311+
args = SimpleNamespace(root_path=str(tmp_project), command="retry-generation", generation_id=None)
312312

313313
with patch(
314314
"services.tool_helpers.check_status_safe",

mcp_server/tests/test_tui_app.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,13 +1136,13 @@ async def test_retry_runs_action_when_confirmed(self):
11361136
patch.object(app, "push_screen_wait", new=AsyncMock(return_value=True)),
11371137
patch.object(screen, "_run_suspended", new=AsyncMock()) as run_susp,
11381138
# do_retry is async; force a sync mock so the flow's
1139-
# ``do_retry(root)`` yields a sentinel, not a live coroutine.
1139+
# ``do_retry(root, generation_id)`` yields a sentinel, not a live coroutine.
11401140
patch(
11411141
"tui.app.actions.do_retry", new=MagicMock(return_value="retry-coro")
11421142
) as do_retry,
11431143
):
11441144
await screen._retry_flow()
1145-
do_retry.assert_called_once_with(app.root)
1145+
do_retry.assert_called_once_with(app.root, "gen_x")
11461146
run_susp.assert_awaited_once_with("retry-coro")
11471147

11481148
@pytest.mark.asyncio

mcp_server/tui/actions.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,11 @@ def _ns(**overrides: object) -> SimpleNamespace:
4444
return SimpleNamespace(**base)
4545

4646

47-
async def do_retry(root: Path) -> int:
47+
async def do_retry(root: Path, generation_id: str | None = None) -> int:
4848
"""Retry the current generation (reuses ``cmd_retry_generation`` guards)."""
49-
return await cli.cmd_retry_generation(_ns(root_path=str(root)))
49+
return await cli.cmd_retry_generation(
50+
_ns(root_path=str(root), generation_id=generation_id)
51+
)
5052

5153

5254
async def do_clear_set(set_number: int) -> int:

mcp_server/tui/app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -628,7 +628,7 @@ async def _retry_flow(self) -> None:
628628
)
629629
)
630630
if ok:
631-
await self._run_suspended(actions.do_retry(self.app.root))
631+
await self._run_suspended(actions.do_retry(self.app.root, self._generation_id))
632632

633633
def action_clear(self) -> None:
634634
self.run_worker(self._clear_flow(), exclusive=True)

0 commit comments

Comments
 (0)