fix(gateway): main_pm completes an in_progress root; walk it to CEO

A root resumed from paused (its subtasks all terminal) sits in
in_progress, but escalate_to_ceo requires source=awaiting_pm_review and
nothing moves the root there — submit_up is cell-PM-only. main_pm_complete
rejected the in_progress root ("expected awaiting_pm_review"), so the
chain stalled one step short of CEO.

main_pm_complete now:
- accepts in_progress (own root, subtasks terminal) in addition to
  awaiting_pm_review;
- after opening the root->master PR (which sets pr_created), walks the
  root in_progress->awaiting_pm_review via the TaskService transition
  (role-validated, no gateway team-match) so escalate_to_ceo's source
  gate passes;
- then escalates -> awaiting_ceo_approval.

The root->master PR is non-empty because the cell->root PR was already
merged into the root branch (the prior cell-completion fix). Updated
test_main_pm_complete_wrong_status (in_progress is now valid; uses paused)
and added a regression test for the in_progress->CEO path.
This commit is contained in:
Renn F
2026-05-23 06:15:48 +02:00
parent e3def6b3a2
commit a8056892b6
3 changed files with 90 additions and 3 deletions
@@ -909,10 +909,12 @@ async def test_main_pm_complete_not_assigned() -> None:
@pytest.mark.asyncio
async def test_main_pm_complete_wrong_status() -> None:
# #183: in_progress is now an accepted source (root resumed from paused);
# use paused — a genuinely non-completable status — to exercise the guard.
main_pm_id = uuid4()
task_id = uuid4()
task = MagicMock(
status="in_progress",
status="paused",
assigned_to=main_pm_id,
parent_task_id=None,
title="t",