From b7d9b53322dad3f9ed28d2d6cb9fb12f78160800 Mon Sep 17 00:00:00 2001 From: Gros Frumos Date: Wed, 18 Mar 2026 22:36:24 +0200 Subject: [PATCH] kin: KIN-ARCH-024-debugger --- tests/test_kin_128_regression.py | 52 ++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/tests/test_kin_128_regression.py b/tests/test_kin_128_regression.py index 89d9106..b0e6875 100644 --- a/tests/test_kin_128_regression.py +++ b/tests/test_kin_128_regression.py @@ -123,6 +123,58 @@ class TestAnalystInjectionOnRevise: assert data["revise_count"] == 3 assert (data.get("pipeline_steps") or [{}])[0]["role"] == "analyst" + @patch("agents.runner.subprocess.run") + def test_pipeline_with_analyst_first_executes_analyst_as_first_agent(self, mock_run, conn): + """Интеграционный тест: run_pipeline с analyst первым шагом запускает analyst первым. + + Проверяет РЕАЛЬНОЕ выполнение пайплайна через run_pipeline() напрямую, + без мока _launch_pipeline_subprocess — в отличие от других тестов класса, + которые проверяют только JSON-ответ API. + + Структура вызовов subprocess.run: + call[0] — check_claude_auth (cmd: [claude, "-p", "ok", ...]) + call[1] — первый агент пайплайна (должен быть analyst) + """ + analyst_output = { + "status": "done", + "root_problem": "Предыдущий подход не учитывал корневую причину X", + "suggested_approach": "Переработать алгоритм с учётом Y", + "confidence": "high", + } + mock_run.return_value = _mock_success(analyst_output) + + # Шаги, которые revise_task() строит при ревизии 2+ (после инжекции analyst) + analyst_step = { + "role": "analyst", + "model": "sonnet", + "brief": "Задача вернулась на ревизию №2. Проведи анализ.", + } + steps = [analyst_step] + + result = run_pipeline(conn, "P1-001", steps) + + # conftest._mock_check_claude_auth авто-мокирует check_claude_auth для всех тестов, + # поэтому auth-check НЕ занимает slot в call_args_list. + # Ожидаемый порядок вызовов subprocess.run: + # call[0] = analyst (первый шаг пайплайна) + # call[1] = learning extractor (авто-обучение после завершения пайплайна) + assert mock_run.call_count >= 1, ( + f"Ожидалось >= 1 вызова subprocess.run (analyst), " + f"получили {mock_run.call_count}" + ) + + # Первый вызов (индекс 0): cmd = [claude, "-p", prompt, ...] + first_agent_cmd = list(mock_run.call_args_list[0].args[0]) + assert "-p" in first_agent_cmd, "Claude CLI cmd должна содержать -p" + prompt_idx = first_agent_cmd.index("-p") + 1 + first_prompt = first_agent_cmd[prompt_idx] + + # agents/prompts/analyst.md начинается с "You are an Analyst for the Kin..." + assert "Analyst" in first_prompt, ( + f"Первый выполненный агент должен быть analyst. " + f"Промпт начинается с: {first_prompt[:200]}" + ) + # =========================================================================== # 2. Smoke tester: cannot_confirm → blocked; confirmed → continues