From c284d5888b535bffd89ff799c5125c96faa92677 Mon Sep 17 00:00:00 2001 From: eshulman2 Date: Fri, 7 Aug 2026 13:43:43 +0300 Subject: [PATCH] Scope task takeover work by repository --- containers/entrypoint.py | 9 +++++++++ src/forge/workflow/nodes/task_takeover_execution.py | 7 +++++++ src/forge/workflow/nodes/task_takeover_review.py | 8 ++++++++ tests/unit/containers/test_entrypoint_review.py | 8 ++++++++ .../unit/workflow/nodes/test_task_takeover_execution.py | 4 ++++ tests/unit/workflow/nodes/test_task_takeover_review.py | 2 ++ 6 files changed, 38 insertions(+) diff --git a/containers/entrypoint.py b/containers/entrypoint.py index 40dd36ae..f10bfd86 100644 --- a/containers/entrypoint.py +++ b/containers/entrypoint.py @@ -694,6 +694,7 @@ async def run_reviewer_agent( workspace: Path, review_instructions: str, task_key: str, + task_description: str = "", ) -> str: """Run reviewer agent with review.md instructions. @@ -701,6 +702,7 @@ async def run_reviewer_agent( workspace: Path to the workspace directory. review_instructions: Instructions from review.md body. task_key: Jira task key for tracing. + task_description: Implementation context, including repository scope. Returns: The reviewer agent's output text. @@ -725,6 +727,12 @@ async def run_reviewer_agent( ## Review Instructions {review_instructions} +## Task Context and Repository Scope +{task_description} + +Evaluate completeness only within the repository scope stated above. Requirements assigned +to other repositories are not missing from this implementation; they are handled separately. + ## Verdict Format After reviewing the code, you MUST output your verdict as either: - APPROVED - if the implementation meets all requirements @@ -861,6 +869,7 @@ async def run_review_loop( workspace=workspace, review_instructions=instructions, task_key=task_key, + task_description=task_description, ) except Exception as e: logger.error(f"Reviewer agent failed: {e}") diff --git a/src/forge/workflow/nodes/task_takeover_execution.py b/src/forge/workflow/nodes/task_takeover_execution.py index e9f455da..810abc0d 100644 --- a/src/forge/workflow/nodes/task_takeover_execution.py +++ b/src/forge/workflow/nodes/task_takeover_execution.py @@ -102,6 +102,13 @@ async def execute_task_changes(state: TaskTakeoverState) -> TaskTakeoverState: task_prompt = ( f"You are implementing changes for task takeover [{current_task}].\n\n" + f"## Repository Execution Scope\n" + f"Current repository: `{current_repo}`\n" + f"Implement and validate only the approved-plan steps that belong to " + f"`{current_repo}`. Do not search for, create, or modify files assigned to " + f"other repositories in the plan. Those repositories are handled in separate " + f"workspaces. Completion for this run is evaluated only against the current " + f"repository's scope.\n\n" f"{feedback_section}" f"## Approved Implementation Plan\n{plan_content}\n\n" f"## Task Description\n{task_description}\n\n" diff --git a/src/forge/workflow/nodes/task_takeover_review.py b/src/forge/workflow/nodes/task_takeover_review.py index 94837f53..68651d2e 100644 --- a/src/forge/workflow/nodes/task_takeover_review.py +++ b/src/forge/workflow/nodes/task_takeover_review.py @@ -97,6 +97,14 @@ async def run_qualitative_review(state: WorkflowState) -> WorkflowState: git_diff=git_diff, workspace_path=workspace_path, ) + prompt_content = ( + "## Repository Review Scope\n" + f"Current repository: `{current_repo}`\n" + "Review only requirements and changes belonging to this repository. Do not " + "reject this repository's work because plan steps assigned to other repositories " + "are absent; those are implemented and reviewed separately.\n\n" + f"{prompt_content}" + ) runner = ContainerRunner(settings) result, response = await run_review_container( diff --git a/tests/unit/containers/test_entrypoint_review.py b/tests/unit/containers/test_entrypoint_review.py index 3a7eaedc..eb1fc4ff 100644 --- a/tests/unit/containers/test_entrypoint_review.py +++ b/tests/unit/containers/test_entrypoint_review.py @@ -101,9 +101,13 @@ async def test_returns_agent_output(self, tmp_path: Path): workspace=tmp_path, review_instructions="Check for bugs", task_key="TEST-123", + task_description="Current repository: owner/repo", ) assert result == "APPROVED" + system_prompt = mock_create.call_args.kwargs["system_prompt"] + assert "Current repository: owner/repo" in system_prompt + assert "handled separately" in system_prompt @pytest.mark.asyncio async def test_system_prompt_contains_instructions(self, tmp_path: Path): @@ -305,6 +309,10 @@ async def mock_reviewer_side_effect(*_args, **_kwargs): assert result is True assert mock_reviewer.call_count == 2 mock_worker.assert_called_once() + assert all( + call.kwargs["task_description"] == "Description" + for call in mock_reviewer.call_args_list + ) # Check feedback was passed to worker worker_call = mock_worker.call_args diff --git a/tests/unit/workflow/nodes/test_task_takeover_execution.py b/tests/unit/workflow/nodes/test_task_takeover_execution.py index a519f1ce..b53e450b 100644 --- a/tests/unit/workflow/nodes/test_task_takeover_execution.py +++ b/tests/unit/workflow/nodes/test_task_takeover_execution.py @@ -115,6 +115,10 @@ async def test_successful_execution(self) -> None: assert kwargs["workspace_path"] == Path("/tmp/ws") assert "Approved Implementation Plan" in kwargs["task_description"] assert "inject at least one new or modified test file" in kwargs["task_description"] + assert "Current repository: `acme/backend`" in kwargs["task_description"] + assert "Do not search for, create, or modify files assigned to other repositories" in ( + kwargs["task_description"] + ) assert "config" not in kwargs # Verify GitOperations were performed diff --git a/tests/unit/workflow/nodes/test_task_takeover_review.py b/tests/unit/workflow/nodes/test_task_takeover_review.py index d8d960fc..f53fc9e7 100644 --- a/tests/unit/workflow/nodes/test_task_takeover_review.py +++ b/tests/unit/workflow/nodes/test_task_takeover_review.py @@ -142,6 +142,8 @@ async def test_run_qualitative_review_success(self, base_task_state: TaskTakeove assert kwargs["repo_name"] == "owner/repo" assert "previous_task_keys" not in kwargs assert "config" not in kwargs + assert "Current repository: `owner/repo`" in kwargs["task_description"] + assert "Do not reject this repository's work" in kwargs["task_description"] assert "task-takeover-review skill" in kwargs["task_description"] @pytest.mark.asyncio