8.6 KiB
work_item, stage, author_agent, status, created_at, model_used
| work_item | stage | author_agent | status | created_at | model_used |
|---|---|---|---|---|---|
| ORCH-063 | analysis | analyst | ready-for-review | 2026-06-09 | claude-opus-4-8 |
03 — Критерии приёмки (Acceptance Criteria): ORCH-063 — INFRA: мониторинг диска mva154 + алерт при >85%
Work Item: ORCH-063 · Repo: orchestrator · Стадия: analysis
Формат: каждый критерий имеет PASS (что должно быть истинно для приёмки) и FAIL (что считается провалом). Reviewer/tester проверяет их буквально по файлам репозитория и тестам.
AC-1 — Heartbeat-демон запускается с приложением
Условие: фоновый disk-watchdog периодически измеряет заполнение диска и стартует вместе с приложением без ручного запуска.
- PASS: есть daemon-поток (паттерн
reconciler/job_reaper:threading.Thread(daemon=True)+threading.Event), стартующий вmain.lifespan(послеreaper.start()) и останавливающийся на shutdown; период замера =disk_monitor_interval_s; есть методstatus(). - FAIL: watchdog не стартует автоматически; блокирующий
time.sleepбез чистого stop; замер выполняется в обработчике вебхука/в горячем пути конвейера, а не в отдельном демоне.
AC-2 — Алерт при заполнении ≥ порога
Условие: при заполнении отслеживаемого пути ≥ disk_monitor_threshold_pct (дефолт 85%) оператор
получает Telegram-алерт с действенными деталями.
- PASS: при
used_pct ≥ thresholdвызываетсяsend_telegram(notifying, не silent) с сообщением, содержащим путь/точку монтирования, занято %, свободно (ГБ или %) и порог. - FAIL: алерт не отправляется при превышении; отправляется silent (
disable_notification=True) и не пингует; сообщение без действенных деталей (нет %/пути/свободно).
AC-3 — Анти-спам: не на каждом тике
Условие: при длительном превышении порога алерт не дублируется на каждом тике.
- PASS: алерт отправляется при пересечении порога (переход «ниже→на/выше»); пока заполнение
остаётся выше порога, повторный алерт шлётся не чаще
disk_monitor_realert_s. Решение об отправке выражено чистой функцией от(current_pct, threshold, previous_state, now)и покрыто юнит-тестом. - FAIL: алерт шлётся на каждом тике при стабильном превышении; нет cooldown/состояния; логика отправки не тестируема (зашита в поток с реальным таймером).
AC-4 — Recovery при возврате ниже порога
Условие: при возврате заполнения ниже порога состояние сбрасывается и приходит однократное сообщение восстановления.
- PASS: переход «выше→ниже порога» сбрасывает состояние алерта и отправляет ровно одно recovery-сообщение «диск ниже порога»; последующее новое превышение снова алертит (цикл повторяем).
- FAIL: после спада ниже порога состояние не сбрасывается (новое превышение молчит из-за «залипшего» cooldown); recovery шлётся повторно на каждом тике ниже порога.
AC-5 — Конфигурируемость и kill-switch
Условие: порог, период, период повтора, пути и включение конфигурируемы; выключение даёт нулевую регрессию.
- PASS: в
config.pyестьdisk_monitor_enabled/disk_monitor_interval_s/disk_monitor_threshold_pct/disk_monitor_realert_s/disk_monitor_paths(с env-маппингом); приdisk_monitor_enabled=Falseдемон не стартует,/queue-блок отдаёт{"enabled": false}, поведение приложения идентично текущему. Новые env задокументированы в.env.example. - FAIL: значения захардкожены; нет kill-switch; при выключении меняется поведение конвейера; env не задокументированы.
AC-6 — never-raise (изоляция от конвейера)
Условие: любой сбой watchdog не роняет и не блокирует конвейер.
- PASS: замер по несуществующему/недоступному пути, ошибка
send_telegram, исключение в тике — логируются и не пробрасываются; демон продолжает работу; конвейер и enduro-trails не затронуты. Покрыто тестом (замер по битому пути / исключение в отправке → тик не падает). - FAIL: исключение в тике останавливает поток или всплывает в приложение; недоступный путь роняет замер всех путей.
AC-7 — Наблюдаемость в GET /queue
Условие: состояние watchdog видно в GET /queue.
- PASS: ответ
GET /queueсодержит аддитивный блокdisk_monitorсenabled,threshold_pct,interval_s,paths(последний замер:used_pct, свободно),alerting,last_alert_at; существующие ключи ответа не изменены; блок never-raise (при ошибке — минимальный словарь). - FAIL: блока нет; изменены/сломаны существующие ключи
/queue; блок может выбросить исключение.
AC-8 — Корректный источник замера (хост-ФС)
Условие: замер отражает заполнение хост-раздела, а не overlay-ФС контейнера.
- PASS: дефолтный набор путей — смонтированные хост-пути (
/repos,/app/data); замер по ним репрезентативен для заполняющегося хост-раздела. Источником истины не являетсяshutil.disk_usage("/")(overlay контейнера). - FAIL: мониторится только
/контейнера → ложно-низкое заполнение при реально полном хосте (риск повтора инцидента 07.06).
AC-9 — Документация обновлена (golden source)
Условие: документация обновлена в том же PR (CLAUDE.md §2; reviewer-ось).
- PASS: обновлены
docs/architecture/README.md(компонент + блок/queue),docs/operations/INFRA.md(что мониторится, порог, как отключить, реакция на алерт),.env.example(новыеORCH_DISK_*),CHANGELOG.md(feat:); созданdocs/work-items/ORCH-063/06-adr/ADR-001-*.md. - FAIL: функционал добавлен, но обзорные/операционные доки или ADR не обновлены.
Сводная матрица AC ↔ FR/BR
| AC | Покрывает |
|---|---|
| AC-1 | BR-1 / BR-8 / FR-1 |
| AC-2 | BR-2 / FR-2 / FR-3 |
| AC-3 | BR-3 / FR-4 |
| AC-4 | BR-4 / FR-4 |
| AC-5 | BR-5 / FR-5 / NFR-4 |
| AC-6 | BR-6 / NFR-1 |
| AC-7 | BR-7 / FR-6 |
| AC-8 | NFR-3 / FR-2 |
| AC-9 | CLAUDE.md §2 (документация = golden source) |