work_item: ORCH-068 description: > Регрессионные и модульные тесты на устранение livelock reconciler F-2 (спам _note_unblock для синхронизированной done-задачи) и связанного бага кэша статусов. Все тесты офлайн: Plane API / Telegram / dispatch мокаются. Целевые модули: src/reconciler.py, src/plane_sync.py. tests: # ---------- P0: основной баг (livelock / спам) ---------- - id: TC-01 type: unit description: > Синхронизированная done-задача (Plane=Done, БД=done, нет активных job): один тик F-2 -> _note_unblock НЕ вызван, send_telegram НЕ вызван, unblocked_total не изменился, 0 jobs. (AC-1, AC-7) module: tests/test_reconciler_plane.py expected: PASS - id: TC-02 type: unit description: > Терминал «схлопнут» с approved по UUID: issue в Done с тем же UUID, что и approved-набор, НЕ заходит ни в одну ветку in_progress/approved/rejected (silence). Проверка проектно-независимого исключения терминалов. (AC-2) module: tests/test_reconciler_plane.py expected: PASS - id: TC-03 type: unit description: > Cancelled терминал также исключён из actionable-выборки -> тик = silence, 0 нотификаций. (AC-2) module: tests/test_reconciler_plane.py expected: PASS - id: TC-04 type: unit description: > _note_unblock не вызывается после no-op dispatch: handle_verdict не сдвинул стадию (задача уже в целевом состоянии) -> 0 нотификаций. (AC-3) module: tests/test_reconciler_plane.py expected: PASS - id: TC-05 type: unit description: > Дедуп: два последовательных тика по одной синхронизированной задаче без изменения состояния -> суммарно 0 повторных уведомлений. (AC-4) module: tests/test_reconciler_plane.py expected: PASS - id: TC-06 type: unit description: > Нет регресса: Plane=Approved, локальная стадия не продвинута, grace выдержан, нет активных job -> handle_verdict доигран, задача продвинута, _note_unblock вызван РОВНО один раз. (AC-5) module: tests/test_reconciler_plane.py expected: PASS - id: TC-07 type: unit description: > Нет регресса для in_progress (task is None -> старт пайплайна, 1 unblock) и rejected (task существует -> откат, 1 unblock), оба только при реальном изменении состояния. (AC-6) module: tests/test_reconciler_plane.py expected: PASS - id: TC-08 type: unit description: > never-raise: list_issues_by_state / get_project_states / _dispatch / send_telegram бросают исключение -> тик не падает, ошибка изолирована и залогирована, прочие issues обработаны. (AC-8) module: tests/test_reconciler_plane.py expected: PASS - id: TC-09 type: unit description: > Kill-switch: reconcile_enabled=False -> F-2 не выполняется; reconcile_plane_enabled=False -> F-2 не выполняется, F-1 не затронут. (AC-9) module: tests/test_reconciler_plane.py expected: PASS - id: TC-10 type: integration description: > End-to-end F-2 на двух проектах (enduro И orchestrator): задача в Done на каждом -> тик reconcile_plane_once = 0 нотификаций / 0 jobs на обоих, независимо от алиасинга статусов проекта. Главный регресс-тест бага. (AC-1, AC-2) module: tests/test_reconciler_plane.py expected: PASS # ---------- P1: связанный баг кэша статусов ---------- - id: TC-11 type: unit description: > Устаревший _STATES_CACHE обновляется без рестарта: после появления нового статуса срабатывает выбранный механизм (TTL/flush) -> следующий get_project_states содержит новый статус. (AC-12) module: tests/test_plane_states_cache.py expected: PASS - id: TC-12 type: unit description: > Совместимость по умолчанию: при дефолтных настройках get_project_states не регрессирует — enduro отдаёт свои UUID, fallback на _DEFAULT_STATES при недоступности API сохранён. (AC-13) module: tests/test_plane_states_cache.py expected: PASS # ---------- P0: общий прогон ---------- - id: TC-13 type: integration description: > Полный набор pytest tests/ -q зелёный (нет регресса в reconciler/plane/qg/ stage_engine). (AC-15) module: tests/ expected: PASS