diff --git a/engine/hooks/diu-stop/claude_stop_check.py b/engine/hooks/diu-stop/claude_stop_check.py index 079f8f7..29b5004 100755 --- a/engine/hooks/diu-stop/claude_stop_check.py +++ b/engine/hooks/diu-stop/claude_stop_check.py @@ -68,6 +68,7 @@ FENCE_MARKER = "```" FENCED_BODY_RE = re.compile(r"```[^\n]*\n(.*?)```", re.DOTALL) INLINE_CODE_RE = re.compile(r"`([^`\n]+)`") +FILE_LINE_RE = re.compile(r"(? |\+\+\+ |--- |@@ |diff --git|commit [0-9a-f]{7,}|[0-9a-f]{7,10} )" r"|Traceback|^\s*at [\w.$<>]+ \(.*:\d+:\d+\)" @@ -143,10 +144,15 @@ def find_unverified_claim(message): truth check.""" fenced_output = any(OUTPUT_SHAPE_RE.search(body) for body in FENCED_BODY_RE.findall(message)) for para in re.split(r"\n\s*\n", message): + para = FENCED_BODY_RE.sub("", para) + if not para.strip(): + continue if FENCE_MARKER in para: continue if markers.excuses_paragraph(para): continue + if FILE_LINE_RE.search(para): + continue inline = INLINE_CODE_RE.findall(para) if inline and (fenced_output or any(OUTPUT_SHAPE_RE.search(code) for code in inline)): continue diff --git a/engine/hooks/diu-stop/tests/test_hooks.py b/engine/hooks/diu-stop/tests/test_hooks.py index d18ae41..ef25678 100644 --- a/engine/hooks/diu-stop/tests/test_hooks.py +++ b/engine/hooks/diu-stop/tests/test_hooks.py @@ -305,6 +305,31 @@ def test_unrelated_later_backtick_does_not_suppress_causal_claim(self): self.assertTrue(blocked) self.assertIn("unverified-shaped claim", err.lower()) + def test_fenced_block_does_not_silence_later_prose_in_same_paragraph(self): + message = ( + "I checked the local snippet.\n" + "```text\n" + "unrelated fenced content\n" + "```\n" + "This fixes it now." + ) + blocked, err = run_claude_check({"last_assistant_message": message}) + self.assertTrue(blocked) + self.assertIn("this fixes it", err.lower()) + + def test_file_line_citation_still_silences_claim_after_fence_normalization(self): + message = ( + "I checked the relevant snippet.\n" + "```ts\n" + "const guard = true;\n" + "```\n" + "The issue was the stale guard at file.ts:1276." + ) + self.assertIsNone(claude_stop_check.find_unverified_claim(message)) + blocked, err = run_claude_check({"last_assistant_message": message}) + self.assertFalse(blocked) + self.assertEqual(err, "") + def test_hedge_i_think_it_happened_without_evidence_is_flagged(self): message = "I think the deploy happened around 2am, so that's why the build is stale." blocked, err = run_claude_check({"last_assistant_message": message})