--- type: test-report work_item_id: ORCH-065 result: PASS --- # Test Report — ORCH-065 Тема: job-reaper + проактивный реклейм stale/dead merge-lease + идемпотентная финализация merge. Прогон полного регресса в ветке `feature/ORCH-065-bug-zombie-jobs-merge-lease-ru`. Review-вердикт — APPROVED (v3). ## Окружение - Python: 3.12.13 - pytest: 8.3.3 - Ветка: feature/ORCH-065-bug-zombie-jobs-merge-lease-ru (worktree) - Прод (8500): health `200 {"status":"ok"}` — НЕ перезапускался (self-hosting инвариант соблюдён) - Дата: 2026-06-07 ## Smoke API (прод 8500, read-only) | Endpoint | Результат | |----------|-----------| | `GET /health` | 200 `{"status":"ok","service":"orchestrator"}` | | `GET /status` | 200, активные задачи отдаются (ORCH-065 в `testing`, ET-013 в `development`) | | `GET /queue` | 200, counts/resilience/reconcile/post_deploy присутствуют | Примечание: блок `reaper` в `/queue` прода (8500) ОТСУТСТВУЕТ — ожидаемо, т.к. прод исполняет ещё не задеплоенный (до-ORCH-065) код. Контракт блока `reaper` проверен тестом TC-18 (`tests/test_queue.py::test_tc18_queue_endpoint_has_reaper_block`) против кода ветки — PASS. Curl недоступен в окружении, smoke выполнен через `urllib.request` (read-only, без побочных эффектов на прод). ## Результаты по тест-плану (04-test-plan.yaml) | TC ID | Тип | Модуль | Покрывает | Результат | |-------|-----|--------|-----------|-----------| | TC-01 | unit | test_job_reaper.py | AC-1 (реап мёртвого job без рестарта) | PASS | | TC-02 | unit | test_job_reaper.py | AC-3 (живой агент не реапится) | PASS | | TC-03 | unit | test_job_reaper.py | FR-1.3 (устойчивость reaper_dead_ticks) | PASS | | TC-04 | unit | test_job_reaper.py | FR-1.1/AC-1 (backstop reaper_max_running_s) | PASS | | TC-05 | unit | test_job_reaper.py | AC-4 (исход по результату: done/queued/failed) | PASS | | TC-06 | unit | test_job_reaper.py | AC-5 (атомарность reap-UPDATE guard) | PASS | | TC-07 | unit | test_job_reaper.py | AC-14 (kill-switch reaper_enabled=false) | PASS | | TC-08 | unit | test_job_reaper.py | AC-9 (never-raise per-job) | PASS | | TC-09 | integration | test_queue.py | AC-2 (разблокировка очереди concurrency=1) | PASS | | TC-10 | unit | test_merge_lease_reclaim.py | AC-6 (реклейм lease мёртвого pid) | PASS | | TC-11 | unit | test_merge_lease_reclaim.py | AC-7 (реклейм по TTL сохранён) | PASS | | TC-12 | unit | test_merge_lease_reclaim.py | AC-8 (живой lease не трогается) | PASS | | TC-13 | unit | test_merge_lease_reclaim.py | AC-9 (условность self-hosting/no-op) | PASS | | TC-14 | unit | test_merge_lease_reclaim.py | AC-9 (never-raise при ошибке lease-файла) | PASS | | TC-15 | unit | test_merge_lease_reclaim.py | AC-14 (kill-switch lease_reclaim_enabled=false) | PASS | | TC-16 | unit | test_merge_gate.py | AC-11 (идемпотентность при уже слитом PR) | PASS | | TC-17 | integration | test_merge_gate_race.py | AC-10 (докатывание незавершённого merge) | PASS | | TC-18 | integration | test_queue.py | AC-15 (блок reaper в /queue) | PASS | | TC-19 | unit | test_config.py | AC-13 (контракты STAGE_TRANSITIONS/QG_CHECKS неизменны) | PASS | | TC-20 | unit | test_config.py | §5/AC-14 (новые настройки reaper_*/lease_reclaim_*) | PASS | | TC-21 | unit | test_job_reaper.py | FR-2.1/AC-6 (стартовый реклейм в lifespan) | PASS | Все 21 TC из плана — PASS. ## Сопоставление с критериями приёмки (03-acceptance-criteria.md) - A (AC-1…AC-5): job-reaper — покрыты TC-01..TC-06, TC-09 → PASS - B (AC-6…AC-9): lease-reclaim — покрыты TC-10..TC-15 → PASS - C (AC-10, AC-11): идемпотентная финализация — TC-16, TC-17 → PASS - D (AC-12 прод не трогается, AC-13 контракты, AC-14 kill-switches): TC-07, TC-15, TC-19, TC-20 + smoke прода без рестарта → PASS - E (AC-15 /queue, AC-16 логи/алерты): TC-18 → PASS - F (AC-17 документация): review подтвердил обновление README/internals/ADR-001/adr-0011/CHANGELOG/.env.example (APPROVED) → PASS - G (AC-18 регресс зелёный): `pytest tests/` 747 passed → PASS ## Вывод pytest ### Целевые модули плана ``` $ python -m pytest tests/test_job_reaper.py tests/test_merge_lease_reclaim.py \ tests/test_merge_gate.py tests/test_merge_gate_race.py \ tests/test_queue.py tests/test_config.py -q 92 passed, 1 warning in 3.40s ``` ### Полный регресс ``` $ python -m pytest tests/ -v --tb=short ======================= 747 passed, 1 warning in 15.47s ======================== ``` (1 warning — PydanticDeprecatedSince20 в src/config.py, не связан с ORCH-065, предсуществующий.) ## Итог **PASS.** Полный регресс — 747 passed, 0 failed. Все 21 TC тест-плана зелёные, все критерии приёмки (AC-1…AC-18) подтверждены. Smoke прода — health/status/queue 200 OK, прод-контейнер не перезапускался (self-hosting инвариант соблюдён). Задача готова к переходу на стадию `deploy-staging`.