--- work_item: ORCH-111 stage: architecture author_agent: architect status: proposed created_at: 2026-06-15 model_used: claude-opus-4-8 --- # 10 — Технические риски: ORCH-111 — watchdog-алерт на долго живущий тест-процесс Work Item: **ORCH-111** · Repo: **orchestrator** · Стадия: architecture > Информационный (гейтом не парсится). Риски реализации и их митигейшн. ## Реестр рисков | ID | Риск | Вер. | Влия. | Митигейшн | |----|------|------|-------|-----------| | TR-1 | **Расширение привилегии наблюдателя** (`pid: host`): sidecar видит таблицу процессов всего хоста (все контейнеры). | Сред. | Сред. | Привилегия **read-only** и **меньше**, чем уже-смонтированный `docker.sock` (полная интроспекция контейнеров); код читает **только** `/proc//{stat,cmdline}`, **никогда** `/proc//environ`; сигнал дефолт-off; обоснование в ADR-001 D1/D6 + adr-0041. (NFR-2/AC-3) | | TR-2 | **Утечка секретов через cmdline** в Telegram-алерт (если тест-команда содержит чувствительный аргумент). | Низ. | Сред. | Скоуп паттерна — `pytest` (не принимает секретов в аргументах); cmdline в detail **усекать** до ограниченного фрагмента; канал — приватный бот оператора (C-1). | | TR-3 | **Ложные срабатывания** на легитимном длинном прогоне → спам. | Низ. | Сред. | Порог возраста **обязан** > `max(merge_retest_timeout_s=600, coverage_run_timeout_s=900)`; дефолт `WATCHDOG_PROC_AGE_MIN=60` мин (4× запас); cmdline-скоуп; дедуп/cooldown через `decision.decide`/`AlertState` (BR-4/BR-5, по построению D2). | | TR-4 | **Кросс-namespace PID не совпадают** (`pid: host` даёт хост-глобальные PID; `/metrics agents[].pid` — namespace орка) → ненадёжная атрибуция «процесс активного джоба». | Сред. | Низ. | Атрибуция **не** через PID, а через порог возраста (namespace-агностичен) + cmdline-скоуп; дубль с `agent_hung` исключён по построению (claude ≠ pytest). ADR-001 D2. | | TR-5 | **Отсутствие RECOVERY** для исчезнувшего процесса (динамический per-entity ключ — как у `agent_hung`/`stage_stuck`, которые не recovery'ятся при пропадании сущности). | Сред. | Низ. | Синтез `Signal(active=False)` для `proc_blocking`-ключей, alerting=True но исчезнувших из наблюдаемых → один RECOVERY через `decide()` (ADR-001 D4, AC-6). Покрыть интеграционным тестом tick→recovery. | | TR-6 | **PID-recycling**: PID переиспользован после смерти орфана → ложная пара recovery+new-alert. | Низ. | Низ. | Естественный цикл vanish→recovery→new-alert корректен; опционально усилить ключ `("proc_blocking", pid, start_ticks)`. | | TR-7 | **never-raise регресс**: гонка «процесс умер между `listdir(/proc)` и `read`» или битый `/proc` роняет тик. | Низ. | Выс. | Per-pid guard (skip), top-level guard → `[]`; чистый разбор отделён от I/O и покрыт фикстурами; AC-8. | | TR-8 | **Дрейф канона тиража**: ключи добавлены в код, но не синхронизированы в `.env.example`/`.env.watchdog.example`/`LITE_SETUP.md`. | Сред. | Низ. | Key-sync `tests/test_lite_setup_doc.py` (TC-02b) красит PR; норматив NFR-5 «обновить в том же PR»; reviewer-ось ORCH-079 (доки). | | TR-9 | **Не-Linux / нет `/proc`** (тиражная инсталляция на не-Linux) → сигнал не работает. | Низ. | Низ. | Коллектор → `[]` (один сигнал тих, тик жив); сигнал дефолт-off; Linux-специфичность задокументирована (как CPU-liveness `agent_hung`). | ## Сводный вывод Доминирующий класс — **безопасность наблюдателя** (TR-1/TR-2: привилегия `pid: host` + видимость cmdline). Остаточный риск для прод-конвейера **низкий**: все изменения строго в наблюдателе (`watchdog/**` + сервис watchdog), read-only, never-raise, дефолт-off; `src/**` / `/metrics` / `STAGE_TRANSITIONS` / `QG_CHECKS` / `check_*` / схема БД — не тронуты; выкат не рестартит прод-`orchestrator` (NFR-3). Эскалация: рекомендуется лейбл **`arch:major-change`** (изменение топологии/привилегий наблюдателя + новый компонентный сигнал). Возврат в анализ **не требуется** — ТЗ удовлетворяется без нарушения принципов архитектуры (всё в Docker на одном сервере, stdlib-only, без новых зависимостей).