17 KiB
work_item, stage, author_agent, status, created_at, model_used
| work_item | stage | author_agent | status | created_at | model_used |
|---|---|---|---|---|---|
| ORCH-100 | analysis | analyst | ready-for-review | 2026-06-10 | claude-opus-4-8 |
01 — BRD (бизнес-требования): ORCH-100 — FND/F1b: sidecar-watchdog (мозг мониторинга, отдельный контейнер)
Work Item: ORCH-100 · Repo: orchestrator · Стадия: analysis
1. Бизнес-контекст и проблема
Задача — фундаментный кирпич F1b домена 0 «Фундамент» эпика автономного саморазвития
(docs/epics/self-evolution.md, §2, §«Архитектурные рамки наблюдаемости»). F1a (ORCH-099) уже
реализовал лёгкий read-only GET /metrics в самом орке — он отдаёт только сырьё (стадии,
очередь, agent-liveness, cost), без порогов/алертов/хранения. F1b — вторая половина пары: мозг
мониторинга, который это сырьё читает, дополняет внешними сигналами (хост, контейнеры, внешние
зависимости) и превращает в алерты.
Боль, которую закрывает F1b. Сегодня платформа слепа к собственному здоровью в реальном
времени. Инциденты 06–09.06 (диск хоста молча дорос до 100% и встал весь конвейер — ORCH-063;
фантом-merge, deploy-петли, флапп-статусы, зомби-jobs) обнаруживались постфактум, человеком.
Частичные стражи существуют, но они живут ВНУТРИ процесса орка (disk_watchdog ORCH-063,
reaper ORCH-065, reconciler ORCH-053): если орк завис/съел память/упал — стражи лягут вместе
с ним, и платформа слепа именно в критический момент.
Архитектурная рамка — установленный факт заказчика (Слава, 09.06), не предмет переизобретения:
- C-1 / C-1б: наблюдатель ОТДЕЛЁН от наблюдаемого. Sidecar-контейнер на том же хосте; КОД
sidecar — в репо орка (папка
watchdog/), но рантайм — ОТДЕЛЬНЫЙ контейнер (свой Dockerfile + сервисorchestrator-watchdogвdocker-compose.yml). Изоляция — на уровне контейнера, не репо. - C-2: без внешнего плеча (одна площадка; принятый риск — падёт весь хост → молчит и наблюдатель).
- C-3: тонкий стек — НЕ Grafana/Prometheus. Хост впритык: RAM 171Mi free / 7.7Gi, диск 92%.
- Разделение ответственности: орк отдаёт сырьё (
/metrics), sidecar — мозг (пороги/алерты/свой Telegram-канал, независимый от кода орка). Орк лёг →/metricsнедоступен = сам сигнал тревоги.
Критический инвариант наблюдаемости: падение/зависание орка должно делать sidecar громче, а
не тише. Если орк не отвечает на /metrics — sidecar жив и обязан зарепортить это как тревогу
«орк не отвечает».
2. Объём (scope)
В объёме
- Новая папка
watchdog/в репо орка: тонкий код sidecar + собственныйDockerfile. - Сервис
orchestrator-watchdogвdocker-compose.yml(отдельный контейнер, свой рестарт/память). - Сбор сигналов (периодический тик): (a)
GET /metricsорка по HTTP; (b) хост — диск %/inode, память, CPU; (c) контейнеры — черезdocker.sockread-only (статусы Up/healthy/restarting/ exited/unhealthy); (d) пинг внешних зависимостей — Plane / Gitea / Anthropic. - Алертинг по порогам: диск≥порог, память, agent-завис >N мин, job-failed, застрявшая стадия,
контейнер-down/unhealthy, внешняя зависимость недоступна, орк-down (
/metricsне отвечает). - Доставка: Telegram через СОБСТВЕННЫЙ канал sidecar (свой токен/chat в
.env), НЕ через код/Telegram-функции орка. - Гигиена алертов: дедупликация + throttle (один алерт на пересечение порога, не флапп) + recovery-сообщение при возврате метрики в норму.
- Управляемость: kill-switch, конфигурируемые пороги, конфигурируемые интервалы.
.env.example: токен/chat watchdog + пороги/интервалы (канон, без секретов).- Документация (
07-infra-requirements.md— разовое инфра-действие) +CHANGELOG.md; pytest зелёный.
Вне объёма
- Любая авто-ремедиация (рестарт контейнеров, очистка диска, requeue jobs). F1b — только наблюдение + алерт (L0 reactive, эпик §9). Авто-фиксы — домен D1 (отдельные задачи).
- Grafana / Prometheus / TSDB / дашборд-UI / исторические графики (C-3 — тонкий стек).
- Изменение
/metricsорка (контракт F1a/ORCH-099 — данность; sidecar — потребитель). Если обнаружится нехватка поля — это отдельная задача-расширение F1a, не часть F1b. - Изменение
STAGE_TRANSITIONS/QG_CHECKS/check_*/ схемы БД орка — sidecar их не касается (он вне процесса орка). - Журнал уроков (F2) — отдельная задача; F1b не пишет в БД орка.
- Второе внешнее плечо мониторинга (L2) — сознательно отложено (C-2).
3. Заинтересованные стороны
- Заказчик / приёмка: Слава (зафиксировал архитектурные рамки 09.06).
- Постановщик / ведение: Стрим.
- Затрагивает: операторов платформы (получатели алертов), все проекты в общем прод-инстансе (enduro-trails и пр.) — sidecar повышает наблюдаемость их общей инфраструктуры, не вмешиваясь.
- Исполнители конвейера: architect (стек, формат хранения порогов, владелец диск-алерта), developer, reviewer, tester, deployer.
4. Бизнес-требования (BR)
- BR-1 (отдельный контейнер). Sidecar собирается в отдельный образ (
watchdog/Dockerfile) и работает как сервисorchestrator-watchdogвdocker-compose.yml— отдельный процесс/память/ рестарт, НЕ внутри процесса орка. - BR-2 (сбор сырья орка). На каждом тике sidecar делает
GET /metricsорка по HTTP и разбирает версионированный конверт (schema_version/stages/queue/agents/cost), толерантно к неизвестным/отсутствующим полям (контракт F1a — additive, версия не растёт на добавление поля). - BR-3 (сбор хоста). Sidecar измеряет хост: заполнение диска (% и, где доступно, inode), память, CPU — по смонтированным хост-путям/интерфейсам, доступным контейнеру.
- BR-4 (сбор контейнеров). Sidecar читает состояние контейнеров через
docker.sock(read-only mount): различает Up / healthy / restarting / exited / unhealthy. Минимум — статус ключевых контейнеров платформы (включая самorchestrator). - BR-5 (пинг зависимостей). Sidecar периодически проверяет доступность внешних зависимостей — Plane, Gitea, Anthropic (лёгкий health/ping, короткий таймаут) — и алертит при недоступности.
- BR-6 (пороговый алертинг). При пересечении порога сигналом (диск≥порог, память, agent-завис >N мин, job-failed, застрявшая стадия, контейнер-down/unhealthy, зависимость недоступна) sidecar шлёт ровно один Telegram-алерт.
- BR-7 (орк-down = тревога). Если
GET /metricsорка не отвечает (таймаут/connection refused/5xx) — sidecar шлёт алерт «орк не отвечает». Это главный сценарий ценности: наблюдатель жив, наблюдаемый лёг. - BR-8 (свой Telegram-канал). Алерты идут через независимый транспорт sidecar — собственные
bot-токен и chat-id из
.env, БЕЗ обращения к коду/функциям/токену орка (иначе падение орка утянуло бы и алерт-канал — нарушение C-1). - BR-9 (дедуп / throttle / recovery). Повторное нахождение метрики за порогом не флаппит: один
алерт на пересечение + анти-спам cooldown между повторами + recovery-сообщение при возврате
метрики в норму. Поведение — по образцу
disk_watchdog(ORCH-063): чистая решающая функция(value, threshold, prev_state, now, cooldown) → alert | realert | recovery | none. - BR-10 (нет дубля диск-алерта). Диск уже алертит
disk_watchdogORCH-063 (порог 85%, через Telegram орка). F1b НЕ должен порождать второй диск-алерт на то же событие. Владельца диск-алерта (sidecar vs внутреннийdisk_watchdog) выбирает архитектор — BRD лишь фиксирует требование «один диск-алерт на событие, без дублирования».
5. Нефункциональные требования (NFR)
- NFR-1 (изоляция / резилентность). Падение/зависание/рестарт орка НЕ роняет sidecar (доказывается: орк down → sidecar продолжает тикать и шлёт алерт). Обратное тоже: sidecar — чисто наблюдатель, его падение не влияет на конвейер.
- NFR-2 (тонкость). Контейнер лёгкий: предсказуемо малое потребление памяти (хост впритык —
171Mi free). Конкретный бюджет памяти и
mem_limit— решение архитектора; BRD требует «в разумных пределах, измеримо». НЕ Grafana/Prometheus. - NFR-3 (never-raise). Любая ошибка сбора/парсинга/сети/отправки — best-effort: один битый
источник деградирует один сигнал, не роняет тик; ошибка тика не роняет демон. По образцу
disk_watchdog/metrics(три уровня never-raise: per-source, per-tick, per-send). - NFR-4 (безопасность self-hosting). Sidecar только читает и шлёт Telegram — НИКОГДА не
трогает диск/контейнеры/прод, не рестартит, не пишет в
docker.sock(mount read-only), не пишет в БД орка, не пушит вmain. Безопасен для общего инстанса (enduro-trails не затронут). - NFR-5 (управляемость / обратимость). Kill-switch (выключить → sidecar инертен/не стартует,
нулевой эффект на орк). Пороги и интервалы конфигурируемы через
.env(не хардкод). - NFR-6 (изоляция контракта). Sidecar толерантен к версии
/metrics: неизвестное поле игнорируется, отсутствие опционального — не падение; ростschema_versionлогируется (предупреждение), не крэшит. - NFR-7 (наблюдаемость самого sidecar). Стартап/тик/решения логируются достаточно, чтобы по логам контейнера понять, что sidecar жив и почему (не)сработал алерт.
6. Допущения и ограничения
- Зависимость: F1b зависит от F1a (ORCH-099) — читает
GET /metrics. Контракт/metrics(envelopeschema_version/generated_at/clk_tck/stages/queue/agents/cost/enabled) — установленный факт, sidecar его потребитель. - Сеть: орк работает
network_mode: host(порт 8500) → из host-network sidecar/metricsдостижим какhttp://127.0.0.1:8500/metrics. Точный сетевой режим sidecar — решение архитектора. docker.sockдоступен на хосте/var/run/docker.sock; монтируется в sidecar read-only.- Разовое инфра-действие (добавить сервис в compose + первый запуск + создать bot/chat watchdog)
выполняется человеком (Слава/Стрим) на хосте — фиксируется в
07-infra-requirements.md. Дальше код watchdog катится через конвейер (self-hosting). - Стек (Python/Go), формат хранения порогов, владелец диск-алерта — зона архитектора в рамках C-1…C-3; BRD их не предрешает.
- Известный принятый риск (C-2): падёт весь хост/Docker → молчит и sidecar (нет внешнего плеча).
- Telegram 48ч и прочие лимиты транспорта — как у орка (best-effort доставка).
7. Критерии успеха
Sidecar стартует отдельным контейнером, на каждом тике собирает сырьё орка + хост + контейнеры +
зависимости, при пересечении порога шлёт ровно один Telegram-алерт со своего канала (throttle +
recovery), при недоступности орка шлёт «орк не отвечает», и переживает падение орка не падая сам.
Тонкий, с kill-switch и конфигурируемыми порогами. Разовое инфра-действие задокументировано, pytest
зелёный, доки + CHANGELOG обновлены. Детальные PASS/FAIL — 03-acceptance-criteria.md.
8. Риски
- Дубль диск-алерта с
disk_watchdogORCH-063 (BR-10) — нужно явное решение владельца (архитектор). - Шум алертов (флапп на границе порога) при недостаточном throttle/recovery — закрывается BR-9.
- Зависимость от
/metrics: ложный «орк-down» при сетевой икоте — нужен разумный таймаут/ретрай в пороге, чтобы единичный transient не флаппил (детали — архитектор/developer). - Ресурсы хоста впритык — sidecar обязан быть лёгким (NFR-2), иначе сам станет частью проблемы.
docker.sockдоступ — строго read-only; риск привилегий минимизируется mount-режимом (NFR-4).- Детальный реестр и митигации —
10-tech-risks.md(заполняет архитектор).