mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
fix(gateway): cell PM completes its own cell task; drop main-PM handoff
submit_up bubbled the cell task to Main PM (_handoff_to_main_pm), but
main_pm_complete rejects any task with a parent_task_id ("only operates
on root tasks"), so the cell->root PR had no one to merge it and the
cell task wedged at awaiting_pm_review. _maybe_advance_parent_to_pm_review
already intends the CELL PM to complete it.
Cell PM now owns cell completion:
- submit_up no longer hands off to Main PM; the cell task stays assigned
to the cell PM, which is respawned to complete() it. Removed the
now-unused _handoff_to_main_pm.
- cell_pm_complete resolves the merge target from the parent task's real
branch_name (shared merge_chain.resolve_parent_branch, also used by the
PR side-effects) so the cell->root PR merges into feature/main_pm/...,
not the team-mis-derived feature/<cellteam>/... (same root cause as the
prior PR-base fix).
- submit_up description + next_hint updated; lifecycle artifacts regen.
Main PM still only completes the ROOT (root->master + escalate-to-CEO).
First run to reach cell-PM bubble-up exposed this.
This commit is contained in:
@@ -2,8 +2,15 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
from uuid import uuid4
|
||||
|
||||
import pytest
|
||||
from roboco.services.gateway.merge_chain import branch_depth, parent_branch_for
|
||||
from roboco.services.gateway.merge_chain import (
|
||||
branch_depth,
|
||||
parent_branch_for,
|
||||
resolve_parent_branch,
|
||||
)
|
||||
|
||||
_DEPTH_ROOT = 1
|
||||
_DEPTH_ONE_SUBTASK = 2
|
||||
@@ -44,6 +51,47 @@ class TestParentBranchFor:
|
||||
parent_branch_for("not-a-branch")
|
||||
|
||||
|
||||
class TestResolveParentBranch:
|
||||
"""#181/#182: base/target comes from the parent TASK's branch_name, which
|
||||
is correct across a team boundary; parent_branch_for is the fallback."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_uses_parent_task_branch_across_team(self) -> None:
|
||||
root_id = uuid4()
|
||||
task = MagicMock(
|
||||
parent_task_id=root_id,
|
||||
branch_name="feature/backend/ROOT0001--CELL0001",
|
||||
)
|
||||
task_service = AsyncMock()
|
||||
# Root lives under a DIFFERENT team prefix than the cell.
|
||||
task_service.get = AsyncMock(
|
||||
return_value=MagicMock(branch_name="feature/main_pm/ROOT0001")
|
||||
)
|
||||
result = await resolve_parent_branch(task, task_service)
|
||||
assert result == "feature/main_pm/ROOT0001"
|
||||
task_service.get.assert_awaited_once_with(root_id)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_falls_back_when_no_parent(self) -> None:
|
||||
task = MagicMock(parent_task_id=None, branch_name="feature/backend/ROOT0001")
|
||||
task_service = AsyncMock()
|
||||
# No parent → root→master.
|
||||
assert await resolve_parent_branch(task, task_service) == "master"
|
||||
task_service.get.assert_not_called()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_falls_back_when_parent_has_no_branch(self) -> None:
|
||||
task = MagicMock(
|
||||
parent_task_id=uuid4(),
|
||||
branch_name="feature/backend/ROOT0001--CELL0001",
|
||||
)
|
||||
task_service = AsyncMock()
|
||||
task_service.get = AsyncMock(return_value=MagicMock(branch_name=None))
|
||||
# Parent exists but has no branch yet → string derivation.
|
||||
result = await resolve_parent_branch(task, task_service)
|
||||
assert result == "feature/backend/ROOT0001"
|
||||
|
||||
|
||||
def test_branch_depth_master_is_zero() -> None:
|
||||
"""Line 28: master returns 0."""
|
||||
assert branch_depth("master") == 0
|
||||
|
||||
Reference in New Issue
Block a user