analyst(ET): auto-commit from analyst run_id=490
This commit is contained in:
145
docs/work-items/ORCH-062/01-brd.md
Normal file
145
docs/work-items/ORCH-062/01-brd.md
Normal file
@@ -0,0 +1,145 @@
|
||||
---
|
||||
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).
|
||||
139
docs/work-items/ORCH-062/02-trz.md
Normal file
139
docs/work-items/ORCH-062/02-trz.md
Normal file
@@ -0,0 +1,139 @@
|
||||
---
|
||||
work_item: ORCH-062
|
||||
stage: analysis
|
||||
author_agent: analyst
|
||||
status: ready-for-review
|
||||
created_at: 2026-06-09
|
||||
model_used: claude-opus-4-8
|
||||
---
|
||||
|
||||
# 02 — ТЗ (TRZ): ORCH-062 — INFRA: авто-prune docker build cache на mva154
|
||||
|
||||
Work Item: **ORCH-062** · Repo: **orchestrator** · Стадия: analysis
|
||||
|
||||
> ТЗ описывает **требуемое поведение и точки изменения**, выведенные из BRD и фактического кода.
|
||||
> **Выбор механизма реализации — за архитектором (`06-adr`).** Запрещено комментировать ТЗ задним
|
||||
> числом: если требование не годится — вернуть в Анализ.
|
||||
|
||||
## 1. Сводка изменения
|
||||
|
||||
Ввести **автоматическое периодическое освобождение docker build cache** на хосте mva154, чтобы
|
||||
build cache не мог дорасти до заполнения диска (корень инцидента 07.06.2026, ≈11 ГБ → диск 100% →
|
||||
падение CI+Gitea+конвейера всех проектов). Это комплемент к disk-watchdog (ORCH-063, «только
|
||||
сигнал»): watchdog предупреждает, **pruner убирает**. Требование — безопасно для self-hosting
|
||||
(только build cache, без рестарта прода, never-raise), обратимо (kill-switch), наблюдаемо (`GET
|
||||
/queue`) и конфигурируемо.
|
||||
|
||||
**Развилка реализации (решает архитектор, фиксируется в `06-adr` + `07-infra-requirements.md`):**
|
||||
- **Вариант A — heartbeat-демон в приложении:** новый leaf-модуль, фоновый
|
||||
`threading.Thread(daemon=True)`, моделируемый **1:1 на `src/disk_watchdog.py`**
|
||||
(`start()/stop()/status()`, `threading.Event`, per-tick never-raise, kill-switch, блок в `GET
|
||||
/queue`), который периодически вызывает `docker builder prune` через docker.sock.
|
||||
- **Вариант B — host-уровень `daemon.json builder.gc.defaultKeepStorage`:** конфигурация
|
||||
garbage-collection BuildKit на хосте (инфра-процедура Owner, без кода приложения).
|
||||
- **Вариант C — host-cron** `docker builder prune -af --filter until=24h` (инфра-процедура Owner).
|
||||
|
||||
ТЗ ниже формулирует требования **инвариантно к выбору**; колонка «применимость» в §2 помечает, что
|
||||
именно затрагивается при code-пути (Вариант A). Если архитектор выбирает чистый инфра-путь (B/C),
|
||||
изменения `src/**` не требуются, а предметом становятся `07-infra-requirements.md` + INFRA.md +
|
||||
host-процедура (см. §7, §5 теста).
|
||||
|
||||
## 2. Задействованные модули / пути
|
||||
|
||||
| Путь | Действие | Применимость |
|
||||
|------|----------|--------------|
|
||||
| `src/build_cache_pruner.py` (новый leaf) | создать: фоновый демон-pruner по образцу `src/disk_watchdog.py` | Вариант A |
|
||||
| `src/config.py` | добавить флаги kill-switch/период/политика хранения (блок рядом с `disk_monitor_*`, строки ~392–442) + валидаторы | Вариант A (часть флагов — и для B/C как декларация) |
|
||||
| `src/main.py` | в `lifespan` — `start()`/`stop()` нового демона рядом с `disk_watchdog.start()/stop()` (строки ~113–120); в `GET /queue` — блок наблюдаемости рядом с `"disk_monitor": disk_watchdog.status()` (строка ~186) | Вариант A |
|
||||
| `.env.example` | задокументировать новые env-переменные (канон) | A / B / C (декларация) |
|
||||
| `docs/operations/INFRA.md` | секция «авто-prune build cache» + переменные в карте env; уточнить, что освобождение build cache теперь автоматизировано (ORCH-063 говорил «ручная операция») | A / B / C (обязательно) |
|
||||
| `docs/work-items/ORCH-062/06-adr/ADR-001-*.md` | решение по выбору механизма + параметрам (архитектор) | A / B / C |
|
||||
| `docs/work-items/ORCH-062/07-infra-requirements.md` | host-prerequisites/процедура (docker.sock / daemon.json / cron) (архитектор) | A / B / C |
|
||||
| `tests/test_build_cache_pruner.py` (новый) | unit/integration по `04-test-plan.yaml` | Вариант A |
|
||||
| `CHANGELOG.md` | запись в `## [Unreleased]` | A / B / C |
|
||||
|
||||
> Модуль-pruner должен быть **leaf** (как `disk_watchdog.py`, `serial_gate.py`, `task_deps.py`):
|
||||
> без обратных зависимостей на `stage_engine`/`stages`/`qg`, чтобы не задевать конвейер.
|
||||
|
||||
## 3. Функциональные требования
|
||||
|
||||
### FR-1 — периодическая авто-уборка build cache (BR-1)
|
||||
Build cache очищается автоматически по расписанию/периодически без участия оператора. Для code-пути
|
||||
(A): фоновый поток с периодом `prune_interval_s` (порядка часов) вызывает уборку каждый тик. Для
|
||||
инфра-пути (B/C): garbage-collection BuildKit / cron обеспечивают эквивалентную периодичность.
|
||||
Привязка: BR-1.
|
||||
|
||||
### FR-2 — политика удержания тёплого кэша (BR-2)
|
||||
Уборка по умолчанию удаляет **старый** build cache, удерживая свежий. Ориентир из бизнес-запроса —
|
||||
возрастной фильтр `--filter until=24h` (для пути A: команда вида `docker builder prune -f --filter
|
||||
until=<retention>`), либо порог объёма `builder.gc.defaultKeepStorage` (для пути B). Параметры
|
||||
удержания конфигурируемы (см. §ниже). Флаг `-a/--all` применять **только** в сочетании с возрастным
|
||||
фильтром/политикой удержания, не как «снести весь кэш». Привязка: BR-2.
|
||||
|
||||
### FR-3 — self-hosting-безопасность операции (BR-3, NFR-2)
|
||||
- Уборка затрагивает **исключительно build cache** — команда строго `docker builder prune`
|
||||
(BuildKit GC). **Запрещены** `docker image prune`, `docker system prune`, любое удаление образов
|
||||
запущенных сервисов и любая остановка/рестарт контейнеров.
|
||||
- Операция **никогда не рестартит и не роняет прод-контейнер** `orchestrator` (групповой риск
|
||||
self-hosting).
|
||||
- Для пути A: вызов docker — неблокирующий конвейер, с таймаутом; недоступность docker.sock →
|
||||
пропуск тика (never-raise).
|
||||
- Привязка: BR-3, NFR-1, NFR-2.
|
||||
|
||||
### FR-4 — наблюдаемость (BR-4)
|
||||
Состояние авто-prune доступно оператору. Для пути A — блок в `GET /queue` (как `disk_monitor`):
|
||||
`enabled`, `interval_s`, `retention`, `last_run_ts`, и (best-effort) результат последней уборки
|
||||
(освобождено байт / текущий объём build cache, если доступно из `docker builder prune`/`du`).
|
||||
Опционально — Telegram-сообщение при значимом освобождении (как recovery-сообщение watchdog'а).
|
||||
Для пути B/C — наблюдаемость через хост (`docker system df`), описанная в INFRA.md. Привязка: BR-4.
|
||||
|
||||
### FR-5 — kill-switch + конфигурируемость (BR-5, BR-6, NFR-3)
|
||||
- `*_enabled` (kill-switch, дефолт безопасный): выключено → демон не стартует (путь A) / процедура
|
||||
неактивна; поведение 1:1 как до задачи (NFR-3).
|
||||
- Конфигурируемые: период (`*_interval_s`), политика удержания (возраст `until` и/или объём
|
||||
`keep_storage`), опц. порог запуска. Невалидные значения → лог-warning + дефолт (как валидаторы
|
||||
`disk_monitor_interval_s`/`disk_monitor_threshold_pct` в `config.py`).
|
||||
- Область раската — безопасная: операция привязана к хосту mva154; не вводит per-repo гейтов.
|
||||
- Привязка: BR-5, BR-6.
|
||||
|
||||
### FR-6 — never-raise на всех уровнях (NFR-1)
|
||||
Любая ошибка (subprocess-сбой, ненулевой rc, таймаут, недоступность docker.sock, parsing-ошибка
|
||||
вывода) логируется и проглатывается; фоновый цикл/процедура продолжает жить и не влияет на
|
||||
конвейер. Для пути A — `try/except` per-tick и per-команда, как `_run`/`tick`/`_send` в
|
||||
`disk_watchdog.py`. Привязка: NFR-1, NFR-5.
|
||||
|
||||
## 4. Изменения API
|
||||
|
||||
**Внешних HTTP-эндпоинтов оркестратора (`src/main.py`) НЕ добавлять и не менять контрактно.**
|
||||
Допустимо (путь A): `GET /queue` дополнить **read-only** блоком `build_cache_pruner`/аналогичным
|
||||
ключом (наблюдаемость, не источник истины) — по образцу блока `disk_monitor`. Внутренний контракт
|
||||
нового модуля (путь A) — `start()` / `stop(timeout)` / `status() -> dict`, 1:1 как `DiskWatchdog`.
|
||||
|
||||
## 5. Изменения схемы БД
|
||||
|
||||
**Нет.** Схема БД (`src/db.py`) не трогается. Учёт «времени последней уборки» — in-memory /
|
||||
best-effort (NFR-5), новой миграции не требуется (как анти-спам-состояние disk-watchdog).
|
||||
|
||||
## 6. Требования к новым/изменённым QG checks
|
||||
|
||||
**Нет.** `QG_CHECKS` / `check_*` / `_parse_*` / `STAGE_TRANSITIONS` / `src/stage_engine.py` **не
|
||||
изменяются**. Авто-prune — операционный фоновый демон/процедура (категория `reconciler` /
|
||||
`job_reaper` / `disk_watchdog`), **не** элемент реестра Quality Gate.
|
||||
|
||||
## 7. Совместимость / регресс · артефакты pipeline
|
||||
|
||||
- **Обратная совместимость / обратимость:** kill-switch (FR-5) выключает фичу в 1:1-исходное
|
||||
состояние; никаких изменений поведения для `enduro-trails` и для конвейера (демон ортогонален).
|
||||
- **Область раската:** только хост mva154 / self-hosting инстанс; фича не вводит per-repo гейтов и
|
||||
не меняет рёбер конвейера.
|
||||
- **Артефакты pipeline, которые должны быть созданы/обновлены:**
|
||||
- `06-adr/ADR-001-*.md` — выбор механизма (A/B/C) + параметры удержания/периода (архитектор).
|
||||
- `07-infra-requirements.md` — host-процедура: доступ к docker.sock (A) / правка `daemon.json` +
|
||||
окно рестарта docker daemon (B) / cron-юнит (C) (архитектор).
|
||||
- `10-tech-risks.md` — детализация R-1…R-4 из BRD (архитектор).
|
||||
- `docs/operations/INFRA.md` — секция авто-prune + карта env; снять формулировку ORCH-063
|
||||
«освобождение места — ручная операция» в части build cache.
|
||||
- `.env.example` — новые переменные.
|
||||
- `CHANGELOG.md` — `## [Unreleased]`.
|
||||
- `12-review.md`, `13-test-report.md`, `14-deploy-log.md`, `15-staging-log.md` — по ходу конвейера.
|
||||
- `tests/` — реализовать тесты из `04-test-plan.yaml` (путь A).
|
||||
129
docs/work-items/ORCH-062/03-acceptance-criteria.md
Normal file
129
docs/work-items/ORCH-062/03-acceptance-criteria.md
Normal file
@@ -0,0 +1,129 @@
|
||||
---
|
||||
work_item: ORCH-062
|
||||
stage: analysis
|
||||
author_agent: analyst
|
||||
status: ready-for-review
|
||||
created_at: 2026-06-09
|
||||
model_used: claude-opus-4-8
|
||||
---
|
||||
|
||||
# 03 — Критерии приёмки (Acceptance Criteria): ORCH-062 — авто-prune docker build cache на mva154
|
||||
|
||||
Work Item: **ORCH-062** · Repo: **orchestrator** · Стадия: analysis
|
||||
|
||||
Формат: каждый критерий имеет **PASS** (что должно быть истинно для приёмки) и **FAIL** (что
|
||||
считается провалом). Reviewer/tester проверяют их буквально по файлам репозитория и поведению.
|
||||
|
||||
> Критерии сформулированы инвариантно к выбору механизма (heartbeat-демон A / `daemon.json` B /
|
||||
> cron C). Где критерий специфичен пути A (код), это помечено; при выборе B/C его проверяет
|
||||
> эквивалент на хосте, задокументированный в `07-infra-requirements.md` / INFRA.md.
|
||||
|
||||
---
|
||||
|
||||
## AC-1 — Авто-уборка build cache выполняется без оператора
|
||||
|
||||
**Условие:** build cache очищается автоматически и периодически (BR-1/FR-1).
|
||||
- **PASS:** существует автоматический механизм (демон-тик пути A / BuildKit GC пути B / cron пути C),
|
||||
который без ручного вмешательства запускает уборку build cache с настроенным периодом; механизм
|
||||
описан в `06-adr` и INFRA.md.
|
||||
- **FAIL:** уборка возможна только ручным запуском оператором; либо механизм не описан/не внедрён.
|
||||
|
||||
---
|
||||
|
||||
## AC-2 — Удерживается тёплый недавний кэш
|
||||
|
||||
**Условие:** очистка по умолчанию удаляет старый кэш, сохраняя свежий (BR-2/FR-2).
|
||||
- **PASS:** команда/политика по умолчанию несёт возрастной фильтр (ориентир `until=24h`) или порог
|
||||
объёма (`builder.gc.defaultKeepStorage`); `-a/--all` (если используется) применяется только в
|
||||
паре с фильтром удержания. Параметр удержания конфигурируем.
|
||||
- **FAIL:** дефолт безусловно сносит весь build cache (например, `docker builder prune -af` без
|
||||
возрастного фильтра/порога), убивая тёплый кэш каждой сборки.
|
||||
|
||||
---
|
||||
|
||||
## AC-3 — Self-hosting безопасность: только build cache, без рестарта прода
|
||||
|
||||
**Условие:** операция затрагивает только build cache и не нарушает работу контейнеров (BR-3/FR-3).
|
||||
- **PASS:** используется строго `docker builder prune` (BuildKit GC); в коде/процедуре **нет**
|
||||
`docker image prune`, `docker system prune`, остановки/рестарта контейнеров или прод-деплоя;
|
||||
обслуживание `enduro-trails` и прод-контейнер `orchestrator` не затрагиваются.
|
||||
- **FAIL:** найдено любое удаление образов запущенных сервисов / `system prune` / любая
|
||||
остановка/рестарт прод-контейнера в рамках уборки.
|
||||
|
||||
---
|
||||
|
||||
## AC-4 — never-raise: уборка не роняет конвейер
|
||||
|
||||
**Условие:** ошибки уборки изолированы (NFR-1/FR-6).
|
||||
- **PASS:** сбой docker-команды, ненулевой rc, таймаут или недоступность docker.sock логируются и
|
||||
проглатываются; фоновый цикл/процедура продолжает работу; конвейер не падает. (Путь A:
|
||||
per-tick/per-команда `try/except`, как `disk_watchdog._run`/`tick`.)
|
||||
- **FAIL:** ошибка уборки всплывает в процесс/останавливает фоновый цикл/влияет на обработку очереди.
|
||||
|
||||
---
|
||||
|
||||
## AC-5 — kill-switch отключает фичу в исходное состояние
|
||||
|
||||
**Условие:** обратимость одним флагом (BR-5/FR-5/NFR-3).
|
||||
- **PASS:** при выключенном `*_enabled` демон не стартует (путь A) / процедура неактивна; поведение
|
||||
системы 1:1 как до задачи; (путь A) `GET /queue` показывает `enabled=false`. Флаг задокументирован
|
||||
в `.env.example` и INFRA.md.
|
||||
- **FAIL:** фича работает при выключенном флаге, либо kill-switch отсутствует/не документирован.
|
||||
|
||||
---
|
||||
|
||||
## AC-6 — Конфигурируемость с безопасными дефолтами
|
||||
|
||||
**Условие:** период/политика удержания настраиваемы, невалид деградирует на дефолт (BR-6/FR-5).
|
||||
- **PASS:** период (`*_interval_s`) и политика удержания (возраст/объём) читаются из env с
|
||||
безопасными дефолтами; невалидное значение → лог-warning + дефолт (как валидаторы
|
||||
`disk_monitor_*` в `src/config.py`).
|
||||
- **FAIL:** параметры захардкожены без возможности конфигурации, либо невалидное значение роняет
|
||||
старт/процедуру.
|
||||
|
||||
---
|
||||
|
||||
## AC-7 — Наблюдаемость состояния авто-prune
|
||||
|
||||
**Условие:** оператор видит состояние уборки (BR-4/FR-4).
|
||||
- **PASS:** (путь A) `GET /queue` содержит read-only блок авто-prune (`enabled`, `interval_s`,
|
||||
`retention`, `last_run_ts`, best-effort результат последней уборки); `status()` never-raise.
|
||||
(Путь B/C) способ наблюдения (`docker system df`) описан в INFRA.md.
|
||||
- **FAIL:** состояние авто-prune нигде не наблюдаемо.
|
||||
|
||||
---
|
||||
|
||||
## AC-8 — Изоляция от Quality Gate и схемы БД
|
||||
|
||||
**Условие:** конвейер и гейты не затронуты (NFR-2/FR §5,§6).
|
||||
- **PASS:** `STAGE_TRANSITIONS`, `QG_CHECKS`, `check_*`, `_parse_*`, `src/stage_engine.py` и схема
|
||||
БД (`src/db.py`) — без изменений; новый модуль (путь A) — leaf без зависимостей на конвейер.
|
||||
- **FAIL:** изменён любой элемент реестра гейтов / переходов стадий / схемы БД, либо введена новая
|
||||
миграция ради учёта уборки.
|
||||
|
||||
---
|
||||
|
||||
## AC-9 — Документация и регресс
|
||||
|
||||
**Условие:** golden source обновлён, полный регресс зелёный (NFR-6).
|
||||
- **PASS:** `docs/operations/INFRA.md` обновлён (секция авто-prune + env-карта; снята формулировка
|
||||
ORCH-063 «освобождение build cache — ручная операция»); `.env.example` несёт новые ключи;
|
||||
`CHANGELOG.md` имеет запись Unreleased; `06-adr/ADR-001-*.md` и `07-infra-requirements.md`
|
||||
заполнены; `pytest tests/ -q` зелёный.
|
||||
- **FAIL:** функционал изменён, но INFRA.md/.env.example/CHANGELOG/ADR не обновлены; либо регресс
|
||||
`tests/` красный.
|
||||
|
||||
---
|
||||
|
||||
## Сводная матрица AC ↔ FR/BR
|
||||
| AC | Покрывает |
|
||||
|----|-----------|
|
||||
| AC-1 | BR-1 / FR-1 |
|
||||
| AC-2 | BR-2 / FR-2 |
|
||||
| AC-3 | BR-3 / FR-3 / NFR-2 |
|
||||
| AC-4 | NFR-1 / FR-6 |
|
||||
| AC-5 | BR-5 / FR-5 / NFR-3 |
|
||||
| AC-6 | BR-6 / FR-5 |
|
||||
| AC-7 | BR-4 / FR-4 |
|
||||
| AC-8 | NFR-2 / FR-5 / FR-6 (TRZ §5,§6) |
|
||||
| AC-9 | NFR-6 |
|
||||
95
docs/work-items/ORCH-062/04-test-plan.yaml
Normal file
95
docs/work-items/ORCH-062/04-test-plan.yaml
Normal file
@@ -0,0 +1,95 @@
|
||||
work_item: ORCH-062
|
||||
stage: analysis
|
||||
author_agent: analyst
|
||||
status: ready-for-review
|
||||
created_at: 2026-06-09
|
||||
model_used: claude-opus-4-8
|
||||
title: "Авто-prune docker build cache на mva154 — план тестов"
|
||||
framework: pytest
|
||||
scope: >
|
||||
Покрывает code-путь (Вариант A — heartbeat-демон src/build_cache_pruner.py по образцу
|
||||
src/disk_watchdog.py): чистая decision-логика (надо ли убирать на этом тике), построение
|
||||
безопасной docker-команды с политикой удержания, never-raise на ошибках subprocess/таймаут/
|
||||
недоступность docker.sock, kill-switch (демон не стартует), наблюдаемость status()/GET /queue,
|
||||
интеграция в lifespan. ВНЕ покрытия pytest: реальный вызов docker (subprocess мокается — тесты
|
||||
не должны трогать настоящий docker daemon), реальное освобождение диска. Если архитектор выберет
|
||||
чистый инфра-путь (B daemon.json / C cron) без кода src/**, применимые TC сводятся к ручной
|
||||
host-верификации, описанной в 07-infra-requirements.md / INFRA.md (см. TC-10).
|
||||
notes: >
|
||||
docker-вызовы изолируются моками (monkeypatch subprocess.run / docker-клиента) — НИ ОДИН тест не
|
||||
выполняет настоящий `docker builder prune`. Время/период инъектируются (now_provider), как в
|
||||
тестах disk_watchdog. Полный регресс `pytest tests/ -q` остаётся зелёным; STAGE_TRANSITIONS /
|
||||
QG_CHECKS / схема БД не затрагиваются — отдельных гейт-тестов фича не добавляет.
|
||||
|
||||
tests:
|
||||
- id: TC-01
|
||||
type: unit
|
||||
description: "decide-функция: при включённом pruner и истёкшем периоде с прошлой уборки решение = PRUNE"
|
||||
module: tests/test_build_cache_pruner.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-02
|
||||
type: unit
|
||||
description: "decide-функция: период с прошлой уборки не истёк → решение = SKIP (анти-частота, NFR-4)"
|
||||
module: tests/test_build_cache_pruner.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-03
|
||||
type: unit
|
||||
description: "Построение docker-команды несёт возрастной фильтр удержания (until=<retention>) и НЕ содержит image/system prune (FR-2/FR-3/AC-2/AC-3)"
|
||||
module: tests/test_build_cache_pruner.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-04
|
||||
type: unit
|
||||
description: "never-raise: subprocess бросает исключение / возвращает ненулевой rc → тик не падает, ошибка залогирована (FR-6/AC-4)"
|
||||
module: tests/test_build_cache_pruner.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-05
|
||||
type: unit
|
||||
description: "never-raise: недоступность docker.sock (FileNotFoundError/PermissionError) → тик пропускается, цикл жив (FR-6/AC-4)"
|
||||
module: tests/test_build_cache_pruner.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-06
|
||||
type: unit
|
||||
description: "never-raise: таймаут docker-команды (TimeoutExpired) проглатывается, фоновый цикл продолжает работу (FR-6/AC-4)"
|
||||
module: tests/test_build_cache_pruner.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-07
|
||||
type: unit
|
||||
description: "kill-switch: при *_enabled=False start() — no-op, фоновый поток не стартует (FR-5/AC-5/NFR-3)"
|
||||
module: tests/test_build_cache_pruner.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-08
|
||||
type: unit
|
||||
description: "config: невалидный *_interval_s / retention → лог-warning + безопасный дефолт, старт не падает (FR-5/AC-6)"
|
||||
module: tests/test_build_cache_pruner.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-09
|
||||
type: unit
|
||||
description: "status() never-raise и содержит enabled/interval_s/retention/last_run_ts + best-effort результат последней уборки (FR-4/AC-7)"
|
||||
module: tests/test_build_cache_pruner.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-10
|
||||
type: unit
|
||||
description: "Изоляция от Quality Gate: модуль-pruner — leaf, не импортирует stage_engine/stages/qg; STAGE_TRANSITIONS и QG_CHECKS не изменены (NFR-2/AC-8)"
|
||||
module: tests/test_build_cache_pruner.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-11
|
||||
type: integration
|
||||
description: "lifespan: при включённом флаге демон стартует в app-lifespan и корректно останавливается на shutdown (рядом с disk_watchdog), docker замокан (FR-1/AC-1)"
|
||||
module: tests/test_build_cache_pruner.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-12
|
||||
type: integration
|
||||
description: "GET /queue содержит read-only блок авто-prune с состоянием (enabled/interval_s/retention/last_run_ts); при выключенном флаге enabled=false (FR-4/AC-5/AC-7)"
|
||||
module: tests/test_build_cache_pruner.py
|
||||
expected: PASS
|
||||
Reference in New Issue
Block a user