# 10-Tech Risks — ORCH-086

Технические риски выбранного решения (ADR-001). Бизнес-риски R1–R5 — в `01-brd.md`; здесь —
реализационные риски конкретного дизайна (одиночный fetch + терминал-скип на F-1).

| # | Риск | Вероятность / Влияние | Митигация (как проверяется) |
|---|------|----------------------|------------------------------|
| TR-A | **Регрессия Guard 2 при рефакторе.** Перевод `_is_blocked_or_needs_input` на внешний резолв `(states, state_uuid)` может незаметно изменить семантику kill-switch `reconcile_skip_blocked_enabled` или консервативный fallback (`return True` при ошибке). | Низкая / Высокая | Поведение флага и fallback сохранить 1:1; контрактный тест AC-6 + регресс-тест Guard 2 (flag off → `False`; ошибка/`state_uuid=None` → `True`). |
| TR-B | **Угол «escape-hatch off + Plane недоступен».** При `reconcile_skip_blocked_enabled=False` и недостижимом Plane не-`cancelled` дрейф-задача может быть продвинута + ложно уведомлена (`state_uuid=None`). | Низкая / Средняя | Принятый деградированный режим (== сегодняшнее поведение, без новой гарантии). Дефолт (`flag=True`) полностью консервативен — основной тест AC-5 идёт под дефолтом. Задокументировано в ADR «Минусы». |
| TR-C | **Двойной сетевой вызов на тик.** Если резолв D1 и Guard 2 случайно оба сделают `fetch_issue_state`, нагрузка горячего цикла вырастет (R4). | Средняя / Средняя | Ровно один `fetch_issue_state` на задачу за тик; тест считает число вызовов `fetch_issue_state` (mock call_count == 1) на пути F-1. |
| TR-D | **Счётчик `skipped_terminal_total` расходится с семантикой F-2.** Двойной инкремент или инкремент не на ту задачу ломает наблюдаемость ORCH-068 (R2). | Низкая / Средняя | Инкремент ровно один раз на терминальную задачу за тик, перед `return`; тест AC-2 проверяет `+1` на задачу и отсутствие `advance`/`_note_unblock`. |
| TR-E | **Терминал-детект ломается на пустых `groups` (fallback).** При недоступности `get_project_state_groups` (пустой dict) `_is_terminal_state` должен корректно падать на логические ключи `done`/`cancelled`, иначе терминал enduro не распознается. | Низкая / Высокая | Переиспользуется существующий `_is_terminal_state` (уже покрыт для F-2); тест AC-2 покрывает обе ветви — (а) по группе, (б) fallback по ключу при пустых `groups`. |
| TR-F | **Порядок гардов.** Если терминал-скип поставить после Guard 2, терминальная задача молча проглатывается консервативным Guard 2 и `skipped_terminal_total` не растёт (теряем метрику успеха). | Низкая / Средняя | Терминал-скип строго ДО Guard 2 (ADR порядок гардов); тест проверяет инкремент счётчика именно при терминале. |
| TR-G | **never-raise в новом helper.** Исключение в `_resolve_issue_status`/`_is_terminal_state` не должно ронять тик и не должно приводить к ложной отправке. | Низкая / Высокая | helper под `try/except` → `(…, None)`; тик уже изолирован `reconcile_gate_once` (`reconciler.py:162`). Тест AC-5: исключение в fetch → тик жив, `send_telegram` не вызван. |
| TR-H | **Анти-регресс легитимного unblock (AC-4).** Слишком широкий терминал/skip-set может задушить полезный алерт о реально застрявшей не-терминальной задаче. | Низкая / Высокая | Терминал-детект строго по `{completed, cancelled}` (+ DB `done`/`cancelled`); регресс-тест AC-4 — не-терминальная задача с зелёным гейтом уведомляет ровно один раз. |

## Зависимости / предпосылки
- `fetch_issue_state`, `get_project_states`, `get_project_state_groups`, `get_project_by_repo` —
  переиспользуются read-only, без изменения контракта (TRZ §1).
- G1 (точная стадия `ET-002`) подтверждается в development по prod-логам/БД и фиксируется в
  `12-review.md` (DoR TRZ §9). Решение робастно независимо от исхода G1.
