From 6a5ca3f8044f8012f0a785ad6050aaab9b84cc6f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 27 May 2026 07:51:17 +0000 Subject: [PATCH 1/2] Initial plan From b0a2df9912291f6b99ced6c813bb348354e7ecb5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 27 May 2026 07:54:14 +0000 Subject: [PATCH 2/2] fix: ground merged news summaries in cited sources --- src/wazzup/ai.py | 3 +++ tests/test_ai.py | 17 +++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/wazzup/ai.py b/src/wazzup/ai.py index adf4283..2cd7cb0 100644 --- a/src/wazzup/ai.py +++ b/src/wazzup/ai.py @@ -370,6 +370,8 @@ def generate_structured_summary(self, request: SummaryRequest) -> SummaryRespons "Every bullet must include citations containing source item IDs from the input. " "Merge input items into one bullet when they describe the same story, campaign, incident, vendor, " "product, or affected organization; cite every source item ID that supports the merged bullet. " + "Do not infer winners, outcomes, timelines, or cause-and-effect details that are not explicitly stated " + "in the cited input items. " "Otherwise preserve the input order so newly published hourly articles stay at the top. " "Do not include Markdown fences or commentary." ) @@ -628,6 +630,7 @@ def build_prompt_payload(request: SummaryRequest) -> dict[str, Any]: "Keep bullets concise and source-grounded.", "Preserve the input item order so newly published hourly articles stay at the top, except when merging related items into one synthesized bullet.", "Merge closely related input items into one synthesized bullet when they describe the same story, campaign, incident, vendor, product, or affected organization; cite every source item ID that supports the merged bullet.", + "Do not infer winners, outcomes, timelines, or cause-and-effect details unless the cited item titles or summaries explicitly say so.", "When an input item includes relatedItems, treat the item and relatedItems as one correlated story and cite every source item ID that supports the bullet.", ], } diff --git a/tests/test_ai.py b/tests/test_ai.py index b43f3d4..b7fee37 100644 --- a/tests/test_ai.py +++ b/tests/test_ai.py @@ -218,6 +218,22 @@ def test_prompt_allows_synthesized_bullets_for_related_items(self) -> None: self.assertIn("same story", style_guide) self.assertIn("cite every source item ID", style_guide) + def test_prompt_style_guide_blocks_unsupported_merged_claims(self) -> None: + payload = build_prompt_payload( + SummaryRequest( + kind="hourly", + window_start="2026-05-06T20:00:00Z", + window_end="2026-05-06T21:00:00Z", + generated_at="2026-05-06T21:00:00Z", + timezone="Europe/Amsterdam", + summary_language="en", + items=[], + ) + ) + style_guide = "\n".join(payload["styleGuide"]) + self.assertIn("Do not infer winners, outcomes, timelines, or cause-and-effect details", style_guide) + self.assertIn("explicitly say so", style_guide) + def test_prompt_style_guide_requires_english_translation(self) -> None: payload = build_prompt_payload( SummaryRequest( @@ -309,6 +325,7 @@ def fake_run(command, capture_output, cwd, env, text): # type: ignore[no-untype self.assertEqual(DEFAULT_COPILOT_AGENT, command[command.index("--agent") + 1]) prompt = command[command.index("-p") + 1] self.assertIn("Merge input items into one bullet", prompt) + self.assertIn("Do not infer winners, outcomes, timelines, or cause-and-effect details", prompt) self.assertNotIn("Create one bullet for each input item", prompt) return Mock(returncode=0, stdout="", stderr="")