From 2a04aff27a695d109e65ba784ed384e15ff9b233 Mon Sep 17 00:00:00 2001 From: Edbert Chan Date: Sat, 12 Sep 2026 19:57:42 -0700 Subject: [PATCH] test(diu-stop): stop-check tests run on the shared judge test base These suites had no judge isolation, so a phrase check that asks the judge could write to the real queue or call a real model. They now inherit JudgeTestCase. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_013smxPCr4XeE7R77zVtN1u4 Change-Id: I76b5a9b6926bab3d871e489198505beb2821a559 --- engine/hooks/diu-stop/tests/test_fix_matrix.py | 7 +++++-- engine/hooks/diu-stop/tests/test_hooks.py | 7 +++++-- engine/hooks/diu-stop/tests/test_limit_agreement.py | 9 +++++++-- engine/hooks/diu-stop/tests/test_plain_words_check.py | 7 ++++++- 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/engine/hooks/diu-stop/tests/test_fix_matrix.py b/engine/hooks/diu-stop/tests/test_fix_matrix.py index 2ebd6c0e..b63a0b77 100644 --- a/engine/hooks/diu-stop/tests/test_fix_matrix.py +++ b/engine/hooks/diu-stop/tests/test_fix_matrix.py @@ -3,11 +3,14 @@ import unittest HOOKS_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +LLM_JUDGE_DIR = os.path.join(os.path.dirname(HOOKS_DIR), "llm-judge") +sys.path.insert(0, LLM_JUDGE_DIR) sys.path.insert(0, HOOKS_DIR) sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) import claude_stop_check # noqa: E402 from test_hooks import run_claude_check # noqa: E402 +from judge_test_base import JudgeTestCase # noqa: E402 LONG_FILLER = " ".join(["word"] * (claude_stop_check.WORD_LIMIT + 20)) @@ -69,7 +72,7 @@ ] -class TestFixDoesNotTripAnotherCheck(unittest.TestCase): +class TestFixDoesNotTripAnotherCheck(JudgeTestCase): """For each known trigger, the message a compliant rewrite would produce must not itself get blocked by any check -- otherwise fixing one finding just bounces you into another before the same-turn retry @@ -91,7 +94,7 @@ def test_fixed_fixtures_are_not_blocked_by_any_check(self): ) -class TestKnownDoubleBlocksResolveByNamingTheBlocker(unittest.TestCase): +class TestKnownDoubleBlocksResolveByNamingTheBlocker(JudgeTestCase): """Some fixes deliberately still trip a second check (see KNOWN_DOUBLE_BLOCKS). `stop_hook_active` no longer releases those -- it only stops the word-count check, so a rewrite cannot smuggle a new diff --git a/engine/hooks/diu-stop/tests/test_hooks.py b/engine/hooks/diu-stop/tests/test_hooks.py index 1ba9764b..91a442bd 100644 --- a/engine/hooks/diu-stop/tests/test_hooks.py +++ b/engine/hooks/diu-stop/tests/test_hooks.py @@ -21,6 +21,8 @@ HOOKS_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) FIXTURES_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "fixtures") +LLM_JUDGE_DIR = os.path.join(os.path.dirname(HOOKS_DIR), "llm-judge") +sys.path.insert(0, LLM_JUDGE_DIR) sys.path.insert(0, HOOKS_DIR) import claude_prompt_reminder # noqa: E402 @@ -28,6 +30,7 @@ import codex_notify # noqa: E402 import install_claude_hook # noqa: E402 import install_codex_notify # noqa: E402 +from judge_test_base import JudgeTestCase # noqa: E402 def run_claude_check(stdin_obj): @@ -65,7 +68,7 @@ def run_codex_notify(argv_tail): return buf.getvalue() -class TestClaudeStopCheck(unittest.TestCase): +class TestClaudeStopCheck(JudgeTestCase): def test_under_limit_prints_nothing(self): blocked, err = run_claude_check({"last_assistant_message": "short reply"}) self.assertFalse(blocked) @@ -177,7 +180,7 @@ def test_malformed_stdin_json_does_not_crash(self): self.assertEqual(buf.getvalue(), "") -class TestUnverifiedClaimCheck(unittest.TestCase): +class TestUnverifiedClaimCheck(JudgeTestCase): """Regression tests for the three real unverified claims a session let through before self-correcting or being corrected by the user (see module docstring). Each `reproduces_the_incident` test asserts the OLD diff --git a/engine/hooks/diu-stop/tests/test_limit_agreement.py b/engine/hooks/diu-stop/tests/test_limit_agreement.py index ccac1588..1746c9bf 100644 --- a/engine/hooks/diu-stop/tests/test_limit_agreement.py +++ b/engine/hooks/diu-stop/tests/test_limit_agreement.py @@ -4,9 +4,14 @@ import sys import unittest -sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +TESTS_DIR = os.path.dirname(os.path.abspath(__file__)) +HOOKS_DIR = os.path.dirname(TESTS_DIR) +LLM_JUDGE_DIR = os.path.join(os.path.dirname(HOOKS_DIR), "llm-judge") +sys.path.insert(0, TESTS_DIR) +sys.path.insert(0, LLM_JUDGE_DIR) from test_hooks import run_claude_check, run_prompt_reminder # noqa: E402 +from judge_test_base import JudgeTestCase # noqa: E402 WORD_COUNT_RE = re.compile(r"\b(\d+) words\b") @@ -28,7 +33,7 @@ def prose(n): return " ".join(["word"] * n) -class TestReminderAndCheckerAgree(unittest.TestCase): +class TestReminderAndCheckerAgree(JudgeTestCase): def test_reminder_states_exactly_one_word_limit(self): self.assertEqual(len(WORD_COUNT_RE.findall(reminder_text())), 1, reminder_text()) diff --git a/engine/hooks/diu-stop/tests/test_plain_words_check.py b/engine/hooks/diu-stop/tests/test_plain_words_check.py index 67e61d16..e3184613 100644 --- a/engine/hooks/diu-stop/tests/test_plain_words_check.py +++ b/engine/hooks/diu-stop/tests/test_plain_words_check.py @@ -8,9 +8,12 @@ from unittest.mock import patch HOOK_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +LLM_JUDGE_DIR = os.path.join(os.path.dirname(HOOK_DIR), "llm-judge") +sys.path.insert(0, LLM_JUDGE_DIR) sys.path.insert(0, HOOK_DIR) import plain_words +from judge_test_base import JudgeTestCase REPLY = "No hook decides differently. Preflight passes and the review unit is engine-runtime." ASKED = "Is it safe?" @@ -36,14 +39,16 @@ def _hit(job_id, closest, category="plain-words-made-up-labels"): return {"id": job_id, "hook": plain_words.HOOK_NAME, "outcome": "hit", "answer": {"match": True, "category": category, "closest": closest}} -class PlainWordsCase(unittest.TestCase): +class PlainWordsCase(JudgeTestCase): def setUp(self): + super().setUp() self._tmp = tempfile.TemporaryDirectory() self.tmp = self._tmp.name self.judge, _ = plain_words._llm_judge() def tearDown(self): self._tmp.cleanup() + super().tearDown() def payload(self, rows=(_user(ASKED), _assistant(REPLY)), **extra): payload = {"last_assistant_message": REPLY}