test_org_level_loop.py 4.15 KB
"""U-017 tests: the full Org-level Loop wiring (judge -> record -> route ->
fix -> re-verify -> done), mocked at the subprocess boundary (CLAUDE.md
Testing constraint). Real coverage is in src/test_org_level_loop_e2e.py
(RUN_REAL_AGENT_E2E=1).

Run: python3 -m unittest src.test_org_level_loop -v
"""

import unittest
from unittest.mock import patch

from src import org_level_loop, schema


def _make_trigger(perspective_category, fix_ok=True):
    """Fakes org_node_trigger.trigger_org_node for the whole loop: 3
    perspective calls (all agreeing on perspective_category), one fixer
    call, one verify call."""

    def fake(org_node, prompt, target_folder_path, timeout=300):
        if "CATEGORY:" in prompt:
            return "CATEGORY: {}\nDETAIL: because reasons".format(perspective_category)
        if org_node in ("coder", "planner"):
            return "Fixed it."
        if org_node == "validator":
            return "VERDICT: PASS\nlooks fixed" if fix_ok else "VERDICT: FAIL\nstill broken"
        raise AssertionError("unexpected call: " + org_node)

    return fake


class RunFixLoopTestBase(unittest.TestCase):
    def setUp(self):
        self.conn = schema.connect(":memory:")
        schema.create_schema(self.conn)
        self.conn.execute(
            "INSERT INTO project (project_id, name, target_folder_path, has_git_repo, status) "
            "VALUES ('proj-1', 'P', '/tmp/proj-1', 1, 'active')"
        )
        self.conn.execute(
            "INSERT INTO task (task_id, project_id, goal_text, task_type, status, loop_round, assigned_org_node) "
            "VALUES ('task-1', 'proj-1', 'goal', 'goal', 'validating', 0, 'validator')"
        )
        self.conn.commit()

    def tearDown(self):
        self.conn.close()


class CoderCategoryFastLaneTest(RunFixLoopTestBase):
    def test_coder_category_routes_fast_lane_and_reaches_done(self):
        with patch("src.org_node_trigger.trigger_org_node", side_effect=_make_trigger("coder", fix_ok=True)):
            result = org_level_loop.run_fix_loop(
                self.conn, "task-1", "/tmp/proj-1", "bug desc", "context", "fix it", "verify it"
            )
        self.assertEqual(result["root_cause_category"], "coder")
        self.assertEqual(result["route"], "fast_lane")
        self.assertTrue(result["verified"])
        self.assertEqual(result["final_status"], "done")

        row = self.conn.execute("SELECT status, loop_round FROM task WHERE task_id = 'task-1'").fetchone()
        self.assertEqual(row, ("done", 1))

        bug_row = self.conn.execute(
            "SELECT root_cause_category, suggested_route FROM bug_record WHERE task_id = 'task-1'"
        ).fetchone()
        self.assertEqual(bug_row, ("coder", "fast_lane"))


class PlanningCategoryFullReplanTest(RunFixLoopTestBase):
    def test_planning_category_routes_full_replan(self):
        with patch("src.org_node_trigger.trigger_org_node", side_effect=_make_trigger("planning", fix_ok=True)):
            result = org_level_loop.run_fix_loop(
                self.conn, "task-1", "/tmp/proj-1", "bug desc", "context", "fix it", "verify it"
            )
        self.assertEqual(result["route"], "full_replan")
        self.assertEqual(result["final_status"], "done")
        assigned = self.conn.execute("SELECT assigned_org_node FROM task WHERE task_id = 'task-1'").fetchone()[0]
        # after close_task_done the task is 'done'; assigned_org_node was set
        # to 'planner' by route_org_loop and close_task_done doesn't touch it
        self.assertEqual(assigned, "planner")


class VerificationFailsTest(RunFixLoopTestBase):
    def test_fix_not_verified_leaves_task_out_of_done(self):
        with patch("src.org_node_trigger.trigger_org_node", side_effect=_make_trigger("coder", fix_ok=False)):
            result = org_level_loop.run_fix_loop(
                self.conn, "task-1", "/tmp/proj-1", "bug desc", "context", "fix it", "verify it"
            )
        self.assertFalse(result["verified"])
        self.assertNotEqual(result["final_status"], "done")
        status = self.conn.execute("SELECT status FROM task WHERE task_id = 'task-1'").fetchone()[0]
        self.assertNotEqual(status, "done")


if __name__ == "__main__":
    unittest.main()