Files
orchestrator/docs/work-items/ORCH-086/02-trz.md

9.7 KiB
Raw Blame History

02-TRZ — ORCH-086: терминал-скип и dedup на пути F-1 реконсилятора

Техническое задание. Архитектурное решение (КАК именно) — за архитектором (ADR). Здесь — ЧТО должно измениться и инварианты.

1. Задействованные модули src/

  • src/reconciler.py — основной (и, как ожидается, единственный) изменяемый модуль:
    • Reconciler._reconcile_gate_task (стр.180228) — путь F-1, где находится баг.
    • Reconciler._note_unblock (стр.444477) — точка отправки уведомления + dedup-guard.
    • Reconciler._is_terminal_state (стр.327344) — существующий терминал-детект (сейчас зовётся только из F-2); переиспользуется в F-1.
    • Reconciler._is_blocked_or_needs_input (стр.230288) — уже делает fetch_issue_state; желательно переиспользовать его результат, чтобы не удваивать сетевой вызов.
  • Возможно затрагиваемые (read-only переиспользование, без изменения контракта): src/plane_sync.py (fetch_issue_state, get_project_states, get_project_state_groups), src/projects.py (get_project_by_repo). Изменять их не требуется.
  • НЕ затрагиваются: src/stages.py (STAGE_TRANSITIONS), src/qg/checks.py (QG_CHECKS), src/stage_engine.py (advance_stage/advance_if_gate_passed), src/db.py (схема), src/config.py (новые флаги не вводятся).

2. Требуемые изменения (функциональные)

TR-1 (G2): терминал-скип на пути F-1

В _reconcile_gate_task ДО вызова _note_unblock (а лучше — до/вместо доведения терминальной задачи до advance_if_gate_passed) добавить проверку: является ли задача терминальной.

  • Терминальность определяется тем же способом, что и в F-2 (_is_terminal_state): первичный дискриминатор — группа статуса Plane issue ∈ {completed, cancelled}; fallback (группа недоступна) — логические ключи done/cancelled проекта. Это покрывает грабли R1 (enduro vs orchestrator).
  • Дополнительно: терминальной считается и задача, чья стадия в БД оркестратора{done, cancelled} (на случай дрейфа Plane↔БД; get_active_tasks_for_reconcile уже отсекает done, но cancelled — нет).
  • Терминальная задача → return без advance и без _note_unblock; инкремент self.skipped_terminal_total (единая семантика с F-2, стр.363).
  • Скип безусловный (как терминал-скип F-2 — без отдельного kill-switch). Это НЕ маскирует легитимный replay: реально застрявшая задача терминальной в Plane не бывает.

Где именно ставить проверку (до advance_if_gate_passed или внутри/перед _note_unblock) — решает архитектор. Рекомендация: ставить как ранний guard в _reconcile_gate_task рядом с Guard 1/Guard 2 (чтобы терминальная задача даже не запускала advance_if_gate_passed/гейт). Если терминал-детект требует Plane-статус, он логично переиспользует fetch из Guard 2.

TR-2 (G3): проброс state_uuid в _note_unblock из F-1

Вызов на стр.228 должен передавать state_uuid (текущий Plane-state issue), чтобы in-memory dedup-guard (_unblock_dedup, стр.459463) работал и на пути F-1:

# было:
self._note_unblock(task.get("work_item_id") or str(task_id), stage)
# должно (концептуально):
self._note_unblock(task.get("work_item_id") or str(task_id), stage, state_uuid)
  • state_uuid — текущий uuid статуса issue в Plane (тот же, что используется для терминал-детекта TR-1).
  • Если Plane недоступен и state_uuid достоверно получить нельзя → допустимо передать None (dedup деградирует в no-op, как сегодня), НО приоритетно сначала отрабатывает терминал-скип TR-1; never-raise сохраняется.
  • Сигнатуру _note_unblock не менять (3-й параметр state_uuid уже опциональный, стр.445).

TR-3: переиспользование сетевого вызова (R4, нефункц., желательно)

F-1 не должен делать > 1 обращения к Plane API на задачу за тик ради статуса. _is_blocked_or_needs_input уже вызывает fetch_issue_state. Архитектор решает форму переиспользования (например, вынести резолв (project_states, groups, current_state_uuid) в один helper, питающий Guard 2 + терминал-скип TR-1 + dedup TR-2). Допустимо и без рефакторинга, если число вызовов на тик не растёт значимо.

3. Контракты и инварианты (НЕ нарушать)

  • never-raise: каждая единица работы F-1 изолирована (_reconcile_gate_task уже под try/except в reconcile_gate_once, стр.162168). Любая ошибка терминал-детекта/fetch → не падает тик; консервативное поведение (R3): при невозможности достоверно определить терминальность — НЕ слать ложно, но и не глушить легитимный (см. AC-4: легитимный unblock — это реальная смена стадии не-терминальной задачи; терминал-неопределённость к нему не относится).
  • silence-when-in-sync: терминальная (= полностью синхронизированная) задача → тишина (инвариант ORCH-068 AC-1/AC-2, теперь и для F-1).
  • Легитимный unblock сохраняется: не-терминальная реально застрявшая задача с зелёным гейтом по-прежнему advance + уведомление (AC-4).
  • Наблюдаемость ORCH-068: skipped_terminal_total инкрементируется при терминал-скипе F-1; deduped_total — при подавлении повтора dedup'ом; unblocked_total/last_unblocked — только при реальной отправке. Снимок status() (стр.516528) и блок reconcile в GET /queue — без структурных изменений.
  • Условность мультипроекта: терминал-детект работает и для enduro, и для orchestrator (по группе статуса + fallback). Пайплайн/статусы enduro не трогаются.

4. Изменения API

Нет. HTTP-эндпоинты не меняются. GET /queue блок reconcile сохраняет форму (значения счётчиков — наблюдаемое поведение).

5. Изменения схемы БД

Нет. Миграции нет. (Терминальность Plane резолвится онлайн, как в ORCH-068 / Guard 2 — Вариант A без колонки статуса в tasks.)

6. Новые/изменённые QG checks

Нет. Реестр QG_CHECKS и STAGE_TRANSITIONS не меняются.

7. Конфигурация

Новые флаги НЕ вводятся. Терминал-скип безусловен (как у F-2). Существующие reconcile_enabled, reconcile_notify_unblock, reconcile_skip_blocked_enabled, reconcile_plane_enabled — без изменений семантики. (reconcile_skip_blocked_enabled гейтит ТОЛЬКО Guard 2; терминал-скип TR-1 ему НЕ подчиняется.)

8. Артефакты pipeline, подлежащие обновлению (документация = golden source)

  • docs/architecture/README.md — раздел «Reconciler … ORCH-068»: дописать, что терминал-исключение и dedup теперь покрывают и F-1 (gate-side), не только F-2.
  • CHANGELOG.md — запись fix: про ORCH-086.
  • docs/work-items/ORCH-086/06-adr/ADR-NNN-*.md — ADR (создаёт архитектор).
  • (Опционально) краткая ссылка в ADR ORCH-068, что F-1-пробел закрыт ORCH-086.

9. Готовность к development (Definition of Ready)

  • G1 подтверждён по prod-логам/БД (точная стадия ET-002 и путь срабатывания задокументированы в ADR/12-review).
  • Тест-план 04-test-plan.yaml реализован в tests/test_reconciler.py.
  • pytest tests/ -q зелёный.