Fix different project same PR number collision problem

Fix (two layers):
1. Root cause — pr_merge and rebase_pr_for_task now take a required project_id and scope the lookup where(pr_number == X AND project_id == Y). Required so no caller can forget — the bug class can't recur. All 4 call sites updated (choreographer cell_pm_complete, the rebase-retry, the superseded close_pull_request now passes project_id, and _verb_runner._do_pr_merge).
2. Crash guard — _finalize_cell_complete None-checks the complete() return and returns a clean invalid_state envelope (with a remediate hint) instead of dereffing None → 500 → respawn loop.
This commit is contained in:
Renn F
2026-06-27 07:19:35 +02:00
parent 53d60da37e
commit 5b931c367f
7 changed files with 193 additions and 20 deletions
+8 -3
View File
@@ -549,14 +549,19 @@ async def test_pr_merge_returns_merge_commit_dict() -> None:
# Merges flow UP the chain (cell -> Main-PM branch), never into master via
# this agent path — target is the integration branch, not the default branch.
with _patch_project_service(fake_project):
out = await svc.pr_merge(11, target="feature/main_pm/root1234")
out = await svc.pr_merge(
11, target="feature/main_pm/root1234", project_id=project_id
)
assert out == {"merge_commit_sha": "abc123sha"}
@pytest.mark.asyncio
async def test_pr_merge_into_default_branch_is_ceo_only() -> None:
"""The agent merge path refuses to merge into a repo's default branch."""
fake_task = MagicMock(project_id=uuid4(), parent_task_id=None, assigned_to=uuid4())
project_id = uuid4()
fake_task = MagicMock(
project_id=project_id, parent_task_id=None, assigned_to=uuid4()
)
fake_project = MagicMock(slug="roboco")
result = MagicMock()
result.scalar_one_or_none.return_value = fake_task
@@ -573,7 +578,7 @@ async def test_pr_merge_into_default_branch_is_ceo_only() -> None:
_patch_project_service(fake_project),
pytest.raises(UnauthorizedError, match="CEO_ONLY"),
):
await svc.pr_merge(11, target="master")
await svc.pr_merge(11, target="master", project_id=project_id)
# Guard fires before any GitHub merge call.
merge_api.assert_not_called()