# 10 — Технические риски (ORCH-065)

| # | Риск | Вероятн. | Влияние | Митигация |
|---|------|----------|---------|-----------|
| R-1 | **Ложноположительный реап живого долгого агента** (AC-3). Reaper помечает зомби работающий агент → потеря работы, дубль-запуск. | Сред. | Высокое | Tier-1 требует `reaper_dead_ticks`(≥2) подряд тиков мёртвого pid; живой pid = `os.kill(pid,0)` без `ProcessLookupError`. Tier-3 потолок `reaper_max_running_s` выбирается заведомо > max `agent_timeout`+grace. Юнит-тест TC-02/TC-03. |
| R-2 | **Ложный `done` без выполненной работы.** Reaper при exit0-зомби помечает job done, хотя git-push/advance не случились (monitor умер до них). | Сред. | Высокое | Реап exit0 НЕ форсит done напрямую — идёт через **gate-driven** `_try_advance_stage`: канонический QG проверяет наличие артефакта/PR; нет артефакта → красный гейт → НЕ advance → ветка «исход неуспешен» (requeue). Источник истины — гейт, не «exit0». |
| R-3 | **pid-reuse / namespace.** Номер pid переиспользован новым процессом → ложное «жив» (lease не реклеймится; зомби-job не реапится по Tier-1). | Низк. | Сред. | Lease: условие «pid мёртв **ИЛИ** TTL истёк» — TTL добивает в любом случае. Job-reaper: Tier-3 backstop по времени ловит то, что Tier-1 пропустил. Допущение «один pid-namespace» зафиксировано в 07-infra. |
| R-4 | **Гонка reaper vs поздно доехавший monitor / стартовый `requeue_running_jobs`** → двойная обработка строки. | Сред. | Сред. | Атомарный reap-claim `UPDATE ... WHERE id=? AND status='running'` + проверка `rowcount` (образец `claim_next_job`). Reaper стартует ПОСЛЕ `requeue_running_jobs` в lifespan. Юнит-тест TC-06. |
| R-5 | **Реклейм живого lease** → параллельный конфликтный merge, риск красного `main` self-hosting. | Низк. | Высокое | `reclaim_stale_lease` освобождает ТОЛЬКО при «держатель мёртв ИЛИ TTL истёк»; живой держатель в пределах TTL не трогается. holder-aware `release_merge_lease(repo, branch)`. Юнит-тест TC-12. |
| R-6 | **Реклейм инициирует git-операцию / трогает прод-контейнер** (нарушение self-hosting safety, AC-12). | Низк. | Высокое | Реклейм = только удаление файла-lease (`os.remove`), без git. Reaper не вызывает деплой-хук/рестарт. Явный инвариант в ADR + тест/ревью. |
| R-7 | **Идемпотентность merge не достигнута**: повторный проход стадии делает второй merge уже слитого PR. | Сред. | Сред. | never-raise guard `pr_already_merged(repo,branch)` (читает состояние PR) консультируется перед merge → уже слит = no-op. `branch_is_behind_main==False` пропускает rebase+re-test. Юнит-тест TC-16, интеграция TC-17. |
| R-8 | **streak-счётчик in-memory теряется при рестарте** → задержка реапа или сброс прогресса. | Низк. | Низкое | Рестарт-сценарий покрыт стартовым `requeue_running_jobs` (мгновенно чистит running). Периодический reaper нужен лишь для зомби БЕЗ рестарта; сброс счётчика лишь переоткладывает реап на `reaper_dead_ticks` тиков. |
| R-9 | **never-raise нарушен** — необработанное исключение валит daemon-поток reaper → защита тихо отключается. | Низк. | Сред. | Per-job изоляция `try/except` (образец `reconciler.reconcile_gate_once`) + внешний `try/except` в `_run`. Юнит-тест TC-08/TC-14. |
| R-10 | **Регресс существующих тестов** merge_gate/queue/reconciler/deploy. | Низк. | Сред. | Контракты неизменны (`STAGE_TRANSITIONS`/`QG_CHECKS`/`check_*`/exit-коды хука); только новая колонка + новый поток + флаги (дефолт сохраняет поведение). Полный прогон `pytest tests/ -q` (regression в 04-test-plan). |

## Открытые вопросы / follow-up
- **Полная автоматизация merge-финализации.** Если деплой-merge (deployer/ORCH-36
  detached host-process) окажется не полностью идемпотентным к повторному проходу,
  может понадобиться доп. работа поверх `pr_already_merged`. Здесь закрываем
  технический блокер; полный авто-approve деплоя — ORCH-54.
- Допущение «агенты — дочерние процессы в одном pid-namespace» (R-3) должно быть
  пересмотрено, если упаковка агентов изменится (отдельные контейнеры).
