mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
[feature] sync_branch dev verb — gate-level branch rebase (Phase B1)
Raw shell git is denied to agents (Bash(git:*) base deny), so a developer whose branch fell behind its base had no gate-level rebase — only the CEO/PM-only /rebase HTTP route. sync_branch is the dev verb that wraps the rebase through the gate (traced + evidenced), so the 'everything goes through the gates' invariant holds. - lifecycle: IntentSpec sync_branch (dev-only, ownership-gated, composes=(), git-only — no DB transition); _next_hint_synced helper. - GitService.sync_task_branch: rebase task.branch_name onto its resolved base via rebase_onto_base (fetch + rebase + force-with-lease push). - Choreographer.sync_branch + _sync_branch_preflight_rejection: not_found / unknown-role / spec-gate / no-branch / protected-base guards, then the git op; conflicts abort (no force-push) and steer to resolve-by-hand; git failure steers to i_am_blocked. - HTTP route /api/v1/flow/developer/sync_branch + SyncBranchRequest schema. - MCP tool sync_branch(task_id) + _TOOLS registration (manifest auto-propagates via intents_for_role(Role.DEVELOPER)). Tests: intent spec (5), choreographer handler (8: happy/conflicts/not_found/ not_authorized/no-branch/protected-base/git-failure/audit), route (1), MCP (1). ruff + mypy roboco/ tests/ clean; unit suite green (DB-fixture errors env-only).
This commit is contained in:
@@ -205,3 +205,22 @@ async def test_resume_dispatches_task_id() -> None:
|
||||
)
|
||||
assert resp.status_code == _HTTP_200
|
||||
mock_chore.resume.assert_awaited_once()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_sync_branch_dispatches_task_id() -> None:
|
||||
"""POST sync_branch forwards task_id to Choreographer.sync_branch (git-only)."""
|
||||
mock_chore = MagicMock()
|
||||
mock_chore.sync_branch = AsyncMock(
|
||||
return_value=_make_envelope(status="ok", task_id=_TASK_ID)
|
||||
)
|
||||
client = TestClient(_build_app(mock_chore))
|
||||
resp = client.post(
|
||||
"/api/v1/flow/developer/sync_branch",
|
||||
json={"task_id": _TASK_ID},
|
||||
headers=_HEADERS,
|
||||
)
|
||||
assert resp.status_code == _HTTP_200
|
||||
mock_chore.sync_branch.assert_awaited_once()
|
||||
# the only positional arg beyond x_agent_id is task_id
|
||||
assert str(mock_chore.sync_branch.call_args.args[1]) == _TASK_ID
|
||||
|
||||
Reference in New Issue
Block a user