---
work_item: ORCH-062
stage: analysis
author_agent: analyst
status: ready-for-review
created_at: 2026-06-09
model_used: claude-opus-4-8
---

# 01 — BRD (бизнес-требования): ORCH-062 — INFRA: авто-prune docker build cache на mva154

Work Item: **ORCH-062** · Repo: **orchestrator** · Стадия: analysis

## 1. Бизнес-контекст и проблема

**Установленный факт (инцидент 07.06.2026).** Хост-диск mva154 тихо дорос до 100% и положил
**весь конвейер всех проектов** (один прод-инстанс `orchestrator` на общей БД/очереди обслуживает
и `enduro-trails`, и `orchestrator`). Доминирующий «пожиратель» в этом инциденте — **docker build
cache**: частые пересборки образа (`docker compose up -d --build` при прод-деплое, пересборки
staging-образа `--profile staging` и `check_staging_image_fresh` ORCH-058) накапливают слои build
cache, который дорос до **≈11 ГБ**. Заполнение диска положило **CI + Gitea** и остановило приём
вебхуков/обработку очереди.

**Что уже сделано (ORCH-063, не дублировать).** Введён фоновый daemon `src/disk_watchdog.py`,
который **только сигнализирует** (Telegram-алерт при заполнении ≥85%). В ADR/INFRA ORCH-063 явно
зафиксировано: *«watchdog только сигнализирует — он не трогает диск/контейнер … Авто-очистка — вне
объёма ORCH-063 (отдельная задача)»*. **ORCH-062 — и есть эта отдельная задача:** автоматическое
освобождение места за счёт build cache, чтобы инцидент 07.06 не повторялся и не требовал ручного
вмешательства оператора.

**Приоритет:** P1 (риск повторной полной остановки конвейера всех проектов).

## 2. Объём (scope)

### В объёме
- Автоматическое периодическое освобождение **docker build cache** на хосте mva154, чтобы он не
  мог бесконтрольно дорасти до заполнения диска.
- Удержание «тёплого» недавнего кэша (политика хранения по возрасту, ориентир из запроса —
  `until=24h`), чтобы не убивать скорость штатных пересборок.
- Наблюдаемость результата авто-prune для оператора (когда последний раз отработал, сколько
  освобождено / текущий объём build cache).
- Обратимость: kill-switch и конфигурируемость периода/порога/политики хранения.
- Документирование операционной процедуры в `docs/operations/INFRA.md` (и инфра-требований в
  `07-infra-requirements.md` — заполняет архитектор).

### Вне объёма
- **Очистка прочих «пожирателей» диска** (старые worktree-каталоги `/home/slin/repos/_wt/*`
  завершённых задач, логи, dangling-образы `docker image prune`) — это **ручная** операция
  оператора по ORCH-063; авто-уборка этих категорий — отдельные задачи, здесь НЕ делается.
- **Изменение поведения disk-watchdog** (`src/disk_watchdog.py`, пороги/алерты ORCH-063) — не
  трогаем; ORCH-062 ортогонален и комплементарен (watchdog сигналит, pruner убирает).
- **Любое управление конвейером / стадиями / Quality Gates.** Авто-prune — операционная фоновая
  задача, НЕ элемент `STAGE_TRANSITIONS` / `QG_CHECKS` (ровно как watchdog/reconciler/job_reaper).
- **Перезапуск/рестарт прод-контейнера** `orchestrator` ради уборки — категорически вне объёма
  (self-hosting групповой риск).
- Выбор между конкретными механизмами реализации (heartbeat-демон в приложении vs host
  `daemon.json builder.gc` vs host-cron) — это **архитектурное решение** (06-adr), не предмет BRD.

## 3. Заинтересованные стороны

- **Owner / оператор (slin, homenet542@gmail.com)** — заказчик, принимает результат, владеет
  хостом mva154 и его host-prerequisites.
- **Все прод-проекты** (`enduro-trails`, `orchestrator`) — косвенно затронуты: общий инстанс,
  общий диск; падение диска = простой всех.
- **Self-hosting контур** — изменение касается инструмента, который работает в проде и обслуживает
  другие проекты; безопасность изменения критична.

## 4. Бизнес-требования (BR)

- **BR-1 (авто-освобождение)** — docker build cache очищается **автоматически, периодически, без
  ручного вмешательства** оператора, так что он не может бесконтрольно заполнить диск (устранение
  корня инцидента 07.06).
- **BR-2 (удержание тёплого кэша)** — очистка удаляет преимущественно **старый** build cache
  (политика по возрасту, ориентир `until=24h`); свежий кэш недавних сборок сохраняется, чтобы
  штатные пересборки не теряли скорость без необходимости.
- **BR-3 (self-hosting безопасность)** — операция уборки **никогда не нарушает работу запущенных
  контейнеров и не удаляет образы/слои, используемые работающими прод-контейнерами**, и **никогда
  не рестартит/не роняет прод**. Затрагивается **только build cache** (`docker builder prune`), не
  образы запущенных сервисов.
- **BR-4 (наблюдаемость)** — оператор может увидеть состояние авто-prune: включён ли, когда
  последний раз отработал, объём/освобождено (через тот же канал наблюдаемости, что у фоновых
  демонов — блок в `GET /queue`, и/или Telegram при значимом освобождении).
- **BR-5 (обратимость)** — поведение управляется **kill-switch**: выключение возвращает систему к
  поведению «как сейчас» 1:1 (никакой авто-уборки), как у `ORCH_DISK_MONITOR_ENABLED` /
  `ORCH_RECONCILE_ENABLED`.
- **BR-6 (конфигурируемость)** — период, порог запуска и политика хранения (возраст/объём
  удержания) задаются конфигом (env), с безопасными дефолтами; невалидные значения деградируют на
  дефолт (как валидаторы ORCH-063).

## 5. Нефункциональные требования (NFR)

- **NFR-1 (never-raise)** — фоновая уборка не должна ронять процесс/конвейер ни на одном уровне:
  ошибка docker-команды / недоступность docker.sock / таймаут логируются и проглатываются (как
  per-tick/per-send never-raise в `disk_watchdog.py`).
- **NFR-2 (изоляция от Quality Gate)** — `STAGE_TRANSITIONS` / `QG_CHECKS` / `check_*` / схема БД
  **не изменяются**; авто-prune — операционный демон/процедура, не гейт.
- **NFR-3 (нулевая регрессия при выключении)** — при выключенном kill-switch поведение байт-в-байт
  как до задачи; никакого фонового потока/процедуры не стартует.
- **NFR-4 (низкий оверхед)** — частота уборки — порядка часов; сама команда `docker builder prune`
  дешева и не должна влиять на латентность конвейера; уборка не должна конкурировать за ресурсы с
  активными сборками сверх необходимого.
- **NFR-5 (best-effort состояние)** — учёт «когда убирали в последний раз» может быть in-memory /
  best-effort (как анти-спам watchdog'а): сброс при рестарте безопасен (приведёт максимум к одной
  лишней безопасной уборке), без новой миграции БД.
- **NFR-6 (документируемость)** — операционная процедура, env-переменные и поведение при сбое
  зафиксированы в `docs/operations/INFRA.md` и `.env.example` в том же PR (golden source = код+доки).

## 6. Допущения и ограничения

- **A-1.** У контейнера `orchestrator` есть доступ к `/var/run/docker.sock` (через `group_add:
  ["999"]`, gid docker — НЕ удалять, ORCH-040), что технически позволяет приложению вызывать
  `docker builder prune`. Это **не предрешает** выбор реализации (демон в приложении vs host-уровень).
- **A-2.** `docker builder prune` по контракту docker затрагивает **только build cache**, не
  останавливает контейнеры и не удаляет образы запущенных сервисов — это основа безопасности BR-3.
- **A-3.** Доминирующий «пожиратель» в инциденте — именно build cache (≈11 ГБ); прочие категории
  (worktree/логи/dangling-образы) адресуются отдельно (см. Вне объёма).
- **A-4.** Хост — mva154 (`network_mode: host`), uid рантайма 1000:1000; любые host-prerequisites
  (например, права на docker.sock, настройка `daemon.json` если выбран этот путь) — процедура
  Owner, в git не коммитятся (по аналогии с P-1…P-4 в INFRA.md).
- **Ограничение C-1.** Нельзя рестартить docker daemon в рабочее время без окна тишины, если
  выбранный архитектором путь (`daemon.json builder.gc`) требует перезапуска демона — это решает и
  планирует архитектор/Owner (вне объёма кода).

## 7. Критерии успеха

- Build cache на mva154 удерживается в безопасных пределах **автоматически**: после внедрения
  повторение сценария 07.06 (build cache → 11 ГБ → диск 100%) предотвращается без ручных действий.
- Свежие сборки не теряют скорость без необходимости (тёплый кэш ≤ политики хранения сохраняется).
- Запущенные прод-контейнеры и обслуживание `enduro-trails` не затронуты; прод не рестартился.
- Оператор видит состояние авто-prune и может его выключить одним флагом.
- Детальные PASS/FAIL — в `03-acceptance-criteria.md`.

## 8. Риски

Краткий перечень (детальная проработка — `10-tech-risks.md`, заполняет архитектор):
- **R-1.** Слишком агрессивная политика (`-a` без возрастного фильтра / малый `until`) убивает
  тёплый кэш → каждая сборка «холодная» и медленная. Митигирует BR-2 (удержание по возрасту).
- **R-2.** Гонка уборки с активной сборкой staging/прод-образа (`check_staging_image_fresh`,
  build-once retag) → теоретически удаление кэша во время сборки. `docker builder prune` штатно не
  трогает кэш, занятый активной сборкой, но политику/таймиг проверить (адресует архитектор).
- **R-3.** Реализация через host-`daemon.json` требует рестарта docker daemon → риск для
  self-hosting; реализация через демон в приложении требует доступа к docker.sock и устойчивости к
  его недоступности.
- **R-4.** Ошибочное расширение скоупа на `docker image prune` / `system prune` → удаление образов
  запущенных контейнеров. Жёстко исключено BR-3 (только build cache).
