mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
feat(gateway): wire PM lifecycle verbs through API + MCP + tests
* api/schemas/v2/flow.py: IWillPlanRequest, DelegateRequest, SubmitUpRequest with min_length=1 validators where appropriate. * api/routes/v2/flow_cell_pm.py: give_me_work routes to pm_give_me_work; new endpoints i_will_plan, delegate, submit_up. * api/routes/v2/flow_main_pm.py: new endpoints give_me_work, i_will_plan, delegate. * mcp/flow_server.py: Python wrappers for i_will_plan, delegate, submit_up registered in _TOOLS so manifest-scoped agents can call them. * tests/unit/gateway/test_choreographer_pm_extras.py: 22 tests covering happy + reject paths for each new verb plus i_am_idle's auto-pause behavior. * tests/unit/api/routes/v2/test_flow_cell_pm.py + test_flow_main_pm.py: route-level tests for the new endpoints. Test count: 352 → 381 (+29). make quality-fast green.
This commit is contained in:
@@ -174,3 +174,64 @@ def test_escalate_up_rejects_empty_reason() -> None:
|
||||
)
|
||||
|
||||
assert resp.status_code == _HTTP_422
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_give_me_work_routes_to_pm_give_me_work() -> None:
|
||||
"""POST /api/v2/flow/main_pm/give_me_work delegates to pm_give_me_work."""
|
||||
mock_chore = MagicMock()
|
||||
mock_chore.pm_give_me_work = AsyncMock(return_value=_make_envelope(status="idle"))
|
||||
client = TestClient(_build_app(mock_chore))
|
||||
|
||||
resp = client.post(
|
||||
"/api/v2/flow/main_pm/give_me_work",
|
||||
json={},
|
||||
headers=_HEADERS,
|
||||
)
|
||||
|
||||
assert resp.status_code == _HTTP_200
|
||||
mock_chore.pm_give_me_work.assert_awaited_once()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_i_will_plan_dispatches_to_choreographer() -> None:
|
||||
"""POST /api/v2/flow/main_pm/i_will_plan forwards task_id and plan."""
|
||||
mock_chore = MagicMock()
|
||||
mock_chore.i_will_plan = AsyncMock(
|
||||
return_value=_make_envelope(status="in_progress", task_id=_TASK_ID)
|
||||
)
|
||||
client = TestClient(_build_app(mock_chore))
|
||||
|
||||
resp = client.post(
|
||||
"/api/v2/flow/main_pm/i_will_plan",
|
||||
json={"task_id": _TASK_ID, "plan": "split into backend, frontend, ux cells"},
|
||||
headers=_HEADERS,
|
||||
)
|
||||
|
||||
assert resp.status_code == _HTTP_200
|
||||
mock_chore.i_will_plan.assert_awaited_once()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_delegate_to_cell_pm_dispatches_inputs_bundle() -> None:
|
||||
"""POST /api/v2/flow/main_pm/delegate forwards body via DelegateInputs."""
|
||||
mock_chore = MagicMock()
|
||||
mock_chore.delegate = AsyncMock(
|
||||
return_value=_make_envelope(status="created", task_id=_TASK_ID)
|
||||
)
|
||||
client = TestClient(_build_app(mock_chore))
|
||||
|
||||
resp = client.post(
|
||||
"/api/v2/flow/main_pm/delegate",
|
||||
json={
|
||||
"parent_task_id": _TASK_ID,
|
||||
"title": "Backend slice",
|
||||
"description": "Plan + drive backend work for feature X.",
|
||||
"assigned_to": "be-pm",
|
||||
"team": "backend",
|
||||
},
|
||||
headers=_HEADERS,
|
||||
)
|
||||
|
||||
assert resp.status_code == _HTTP_200
|
||||
mock_chore.delegate.assert_awaited_once()
|
||||
|
||||
Reference in New Issue
Block a user