From 2bf23192b2f8a1af5942fb87887ff08b47d861ec Mon Sep 17 00:00:00 2001 From: eshulman2 Date: Mon, 29 Jun 2026 18:39:48 +0300 Subject: [PATCH] Acknowledge epic revision comments on epic --- src/forge/orchestrator/worker.py | 9 ++++-- tests/unit/orchestrator/test_worker.py | 43 ++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/forge/orchestrator/worker.py b/src/forge/orchestrator/worker.py index 7c56de78..988925e0 100644 --- a/src/forge/orchestrator/worker.py +++ b/src/forge/orchestrator/worker.py @@ -1277,6 +1277,11 @@ async def _post_resume_ack_comment( if source_ticket_key and source_ticket_key != ticket_key else "" ) + comment_target_key = ( + source_ticket_key + if source_ticket_key and source_ticket_key != ticket_key + else ticket_key + ) if signal_type == "question": message = ( @@ -1292,11 +1297,11 @@ async def _post_resume_ack_comment( try: jira = JiraClient() try: - await post_status_comment(jira, ticket_key, message) + await post_status_comment(jira, comment_target_key, message) finally: await jira.close() except Exception as e: - logger.warning(f"Failed to post resume acknowledgement to {ticket_key}: {e}") + logger.warning(f"Failed to post resume acknowledgement to {comment_target_key}: {e}") @staticmethod def _stage_label_for_node(current_node: str) -> str: diff --git a/tests/unit/orchestrator/test_worker.py b/tests/unit/orchestrator/test_worker.py index 5b64958e..89c13dc9 100644 --- a/tests/unit/orchestrator/test_worker.py +++ b/tests/unit/orchestrator/test_worker.py @@ -95,6 +95,7 @@ async def test_question_comment_sets_is_question_flag( assert result["revision_requested"] is False assert result["is_paused"] is False ack_comment_mocks.assert_awaited_once() + assert ack_comment_mocks.await_args.args[1] == "TEST-123" ack_text = ack_comment_mocks.await_args.args[2] assert "received your question" in ack_text assert "the PRD" in ack_text @@ -135,6 +136,7 @@ async def test_normal_feedback_still_works( assert result["feedback_comment"] == "Please add more detail to the security section" assert result["is_paused"] is False ack_comment_mocks.assert_awaited_once() + assert ack_comment_mocks.await_args.args[1] == "TEST-123" ack_text = ack_comment_mocks.await_args.args[2] assert "received your revision request" in ack_text assert "regenerating" in ack_text @@ -176,9 +178,50 @@ async def test_task_phase_feedback_from_epic_sets_current_epic_key( assert result["current_epic_key"] == "TEST-124" assert result["current_task_key"] is None ack_comment_mocks.assert_awaited_once() + assert ack_comment_mocks.await_args.args[1] == "TEST-124" ack_text = ack_comment_mocks.await_args.args[2] assert "from TEST-124" in ack_text + @pytest.mark.asyncio + async def test_plan_phase_feedback_from_epic_acknowledges_epic( + self, + worker: OrchestratorWorker, + base_message: QueueMessage, + base_state: dict, + ack_comment_mocks, + ): + """Comments on an Epic during plan review are acknowledged on that Epic.""" + state = { + **base_state, + "current_node": "plan_approval_gate", + "epic_keys": ["TEST-124"], + } + payload = { + **base_message.payload, + "source_ticket_key": "TEST-124", + "comment": {"body": "!Please revise this epic plan"}, + "changelog": {"items": []}, + } + message = QueueMessage( + message_id=base_message.message_id, + event_id=base_message.event_id, + source=base_message.source, + event_type="comment_created", + ticket_key=base_message.ticket_key, + payload=payload, + ) + + result = await worker._handle_resume_event(message, state) + + assert result["revision_requested"] is True + assert result["feedback_comment"] == "Please revise this epic plan" + assert result["current_epic_key"] == "TEST-124" + ack_comment_mocks.assert_awaited_once() + assert ack_comment_mocks.await_args.args[1] == "TEST-124" + ack_text = ack_comment_mocks.await_args.args[2] + assert "received your revision request" in ack_text + assert "from TEST-124" in ack_text + @pytest.mark.asyncio async def test_retry_at_task_approval_gate_clears_stale_epic_and_task_keys( self,