117 lines
8.4 KiB
YAML
117 lines
8.4 KiB
YAML
work_item: ORCH-116
|
||
stage: analysis
|
||
author_agent: analyst
|
||
status: ready-for-review
|
||
created_at: 2026-06-16
|
||
model_used: claude-opus-4-8
|
||
title: "Детерминированный test-раннер вместо LLM-тестера (стадия testing)"
|
||
framework: pytest
|
||
scope: >
|
||
Покрывает Phase 1: перехват tester-джоба на стадии testing до _spawn, исполнение
|
||
тест-контракта (pytest через proc_group + опц. read-only smoke), маппинг exit-кода
|
||
в result: PASS|FAIL, запись/push 13-test-report.md, инициацию существующего гейта
|
||
check_tests_passed, two-level outcome (tool-error DEFER, анти-ORCH-110), kill-switch/
|
||
скоуп/backward-compat для репо без тест-контракта, never-raise/fail-safe, изоляцию
|
||
процесса/таймаут (tree-kill), гибрид (LLM не в control-path вердикта), наблюдаемость,
|
||
и анти-дрейф инвариант (STAGE_TRANSITIONS/QG_CHECKS/check_tests_passed/_parse_tests_verdict/
|
||
схема БД не тронуты). Вне покрытия: Phase 2 (project test contract для не-self репо,
|
||
off-control-path LLM-триаж), ORCH-115 staging/deploy-раннер, LLM-роли reviewer/developer,
|
||
живой Claude CLI и живой прод-стенд (мокируются).
|
||
notes: >
|
||
Тесты не требуют живого Claude CLI или сети: subprocess/pytest-run (proc_group) и
|
||
advance_stage мокируются; пьюр-маппинг и рендер frontmatter тестируются напрямую;
|
||
smoke-GET мокируются. Полный регресс tests/ должен оставаться зелёным. Анти-дрейф
|
||
(TC-09) защищает критический инвариант NFR-1. Эталон реализации/покрытия —
|
||
tests/test_orch115_staging_runner.py (ORCH-115).
|
||
|
||
tests:
|
||
- id: TC-01
|
||
type: unit
|
||
description: "applies(repo): enabled=False -> False (откат к LLM); пустой CSV -> True только для orchestrator; непустой CSV -> membership; репо без резолвимого тест-контракта -> False (BR-9 backward-compat); ошибка -> False (never-raise, fail-safe)."
|
||
module: tests/test_orch116_test_runner.py
|
||
expected: PASS
|
||
|
||
- id: TC-02
|
||
type: unit
|
||
description: "Маппинг exit-кода: 0 -> PASS; 1/2/любой ненулевой -> FAIL; None/нечисло/ошибка запуска -> FAIL (fail-closed). Токены PASS/FAIL согласованы с _parse_tests_verdict; второй несогласованный маппинг не вводится."
|
||
module: tests/test_orch116_test_runner.py
|
||
expected: PASS
|
||
|
||
- id: TC-03
|
||
type: unit
|
||
description: "Рендер 13-test-report.md: frontmatter содержит result: PASS|FAIL (UPPERCASE) + 52c-схему (work_item/stage=testing/author_agent=test-runner/status/created_at/model_used=n/a); хвост stdout pytest и smoke-итог копируются в тело."
|
||
module: tests/test_orch116_test_runner.py
|
||
expected: PASS
|
||
|
||
- id: TC-04
|
||
type: integration
|
||
description: "Сгенерированный раннером 13-test-report.md читается НЕИЗМЕНЁННЫМ _parse_tests_verdict -> корректный (bool, reason) для PASS и FAIL (контракт артефакта/гейта check_tests_passed неизменен)."
|
||
module: tests/test_orch116_test_runner.py
|
||
expected: PASS
|
||
|
||
- id: TC-05
|
||
type: integration
|
||
description: "launch_job перехватывает tester-джоб на стадии testing для in-scope репо ДО _spawn (как D1/D2/ORCH-115): _spawn НЕ вызывается, agent_runs не создаётся, возвращается None, jobs-строка ведётся mark_job. _spawn мокирован."
|
||
module: tests/test_orch116_test_runner.py
|
||
expected: PASS
|
||
|
||
- id: TC-06
|
||
type: integration
|
||
description: "Дискриминатор: tester-джоб на стадии НЕ testing (защита) и любой не-tester джоб НЕ перехватываются раннером; should_intercept never-raise -> False при DB-сбое (fall-through к _spawn)."
|
||
module: tests/test_orch116_test_runner.py
|
||
expected: PASS
|
||
|
||
- id: TC-07
|
||
type: integration
|
||
description: "После PASS-вердикта раннер инициирует advance_stage(finished_agent='tester') ровно как завершившийся LLM-tester (advance_stage мокирован/наблюдается) -> check_tests_passed -> testing->deploy-staging; после FAIL — существующий откат testing->development + developer-retry (stage_engine.py:849)."
|
||
module: tests/test_orch116_test_runner.py
|
||
expected: PASS
|
||
|
||
- id: TC-08
|
||
type: integration
|
||
description: "Kill-switch: test_runner_enabled=False -> на testing для orchestrator вызывается _spawn (прежний LLM-путь байт-в-байт), раннер не активируется."
|
||
module: tests/test_orch116_test_runner.py
|
||
expected: PASS
|
||
|
||
- id: TC-09
|
||
type: unit
|
||
description: "Анти-дрейф NFR-1: STAGE_TRANSITIONS (src/stages.py), реестр/имена QG_CHECKS, check_tests_passed/_parse_tests_verdict и токены result:/verdict:/status: неизменны; в схеме БД нет новой таблицы/колонки от ORCH-116. Структурная проверка."
|
||
module: tests/test_orch116_test_runner.py
|
||
expected: PASS
|
||
|
||
- id: TC-10
|
||
type: integration
|
||
description: "Two-level outcome (анти-ORCH-110): сюита НЕ исполнилась (spawn-error/таймаут/returncode None) -> bounded DEFER (re-queue tester-джоба + restart-safe маркер), БЕЗ отката на development и БЕЗ расхода developer-retry; на исчерпании test_runner_infra_max_retries -> fail-closed FAIL + advance + INFRA-alert. Никогда тихий advance/ложный green."
|
||
module: tests/test_orch116_test_runner.py
|
||
expected: PASS
|
||
|
||
- id: TC-11
|
||
type: unit
|
||
description: "never-raise/fail-safe: pytest-run бросает/таймаутит/worktree-ошибка -> раннер не падает, исход FAIL (fail-closed) или bounded DEFER, никогда тихий advance/ложный green; воркер/очередь не клинятся. Все публичные функции test_runner.py never-raise."
|
||
module: tests/test_orch116_test_runner.py
|
||
expected: PASS
|
||
|
||
- id: TC-12
|
||
type: unit
|
||
description: "Изоляция/таймаут: pytest исполняется в worktree ветки задачи через proc_group.run_in_process_group (tree-kill); test_runner_timeout_s применяется; малформ/непозитив -> дефолт 900 + WARNING (never-break); reaper_max_running_s не правится."
|
||
module: tests/test_orch116_test_runner.py
|
||
expected: PASS
|
||
|
||
- id: TC-13
|
||
type: unit
|
||
description: "Self-hosting safety: в командах раннера нет запрещённых литералов (рестарт 8500 / docker compose up orchestrator / --build / force-push main / правки .env); smoke-запросы строго read-only GET (/health,/status,/queue); лог пушится только в фичеветку."
|
||
module: tests/test_orch116_test_runner.py
|
||
expected: PASS
|
||
|
||
- id: TC-14
|
||
type: integration
|
||
description: "Наблюдаемость + гибрид: GET /queue содержит блок test_runner (enabled/repos/target/счётчики runs/pass/fail/tool_error/deferred); на прогон пишется один структурный лог-вердикт, различающий код-фейл и tool-error; LLM не вызывается для вынесения result: в happy/fail-path."
|
||
module: tests/test_orch116_test_runner.py
|
||
expected: PASS
|
||
|
||
- id: TC-15
|
||
type: integration
|
||
description: "Анти-дрейф LLM-карты: llm-call-sites.md (A5)/roadmap (rank 2)/policy обновлены под реализацию (инвариант 'ровно один first_slice=yes' цел); tests/test_llm_call_site_inventory.py и tests/test_llm_determinization_docs.py остаются зелёными после правок."
|
||
module: tests/test_llm_call_site_inventory.py
|
||
expected: PASS
|