From dabc08bd3a4ca7bd827b27239938613c53fe5468 Mon Sep 17 00:00:00 2001 From: claude-bot Date: Tue, 2 Jun 2026 19:05:00 +0000 Subject: [PATCH] analyst(ET): auto-commit from analyst run_id=55 --- docs/work-items/ET-016/01-brd.md | 218 +++++++++++++ docs/work-items/ET-016/02-trz.md | 160 ++++++++++ .../ET-016/03-acceptance-criteria.md | 196 ++++++++++++ docs/work-items/ET-016/04-test-plan.yaml | 293 ++++++++++++++++++ 4 files changed, 867 insertions(+) create mode 100644 docs/work-items/ET-016/01-brd.md create mode 100644 docs/work-items/ET-016/02-trz.md create mode 100644 docs/work-items/ET-016/03-acceptance-criteria.md create mode 100644 docs/work-items/ET-016/04-test-plan.yaml diff --git a/docs/work-items/ET-016/01-brd.md b/docs/work-items/ET-016/01-brd.md new file mode 100644 index 0000000..79a333e --- /dev/null +++ b/docs/work-items/ET-016/01-brd.md @@ -0,0 +1,218 @@ +--- +type: brd +work_item_id: ET-016 +title: "BRD: [ORCH-7] Self-hosting — оркестратор пилит сам себя через конвейер" +version: 1 +status: draft +created_at: 2026-06-02 +updated_at: 2026-06-02 +authors: + - "agent:analyst" +related: + - "ORCH-1..ORCH-6" +--- + +# BRD — ET-016: Self-hosting оркестратора openclaw + +## 1. Цель + +Сделать так, чтобы код самого оркестратора **openclaw** (агентные +промпты `.openclaw/agents/*.md`, runtime, пайплайн-скрипты, конфиги +бюджета, политики безопасности) **разрабатывался тем же конвейером**, +которым он разрабатывает enduro-trails. Конкретно: + +1. Изменение в любом артефакте оркестратора попадает в систему как + обычный work item (Plane), получает ID `ORCH-NNN`, проходит стадии + `analysis → architecture → development → testing → review → deploy` + и выезжает в продакшн без ручных вмешательств владельца. +2. Конвейер умеет **безопасно обновлять самого себя** (bootstrap-проблема): + момент апдейта оркестратора не должен ломать активные run-ы и не + должен «съесть» собственный артефакт деплоя. +3. На выходе ET-016 демонстрируется **smoke-кейс**: реальный work item + `ORCH-DEMO-01`, который меняет тривиальную деталь в одном из + агентных промптов (например, добавляет строку в раздел «Запрещено» + у `developer.md`), пройдён конвейером end-to-end, изменение + присутствует на продакшн-инстансе оркестратора, история стадий + зафиксирована в Plane и в `docs/work-items/ORCH-DEMO-01/`. + +ET-016 — это **«доказать, что конвейер замыкается на себя»**, а не +полное переписывание оркестратора. + +## 2. Контекст + +### Что уже есть (ORCH-1..ORCH-6) + +- **ORCH-1..3** — базовый конвейер: 6 агентов (analyst, architect, + developer, tester, reviewer, deployer), модели Sonnet 4.6 / Opus 4.7, + оформление артефактов в `docs/work-items//`. +- **ORCH-4** — интеграция с Plane (work item ID — `ET-NNN` для + enduro-trails) и Gitea API (`http://localhost:3000`, токен + `ORCH_GITEA_TOKEN`). +- **ORCH-5** — деплой-хук (`/home/slin/bin/enduro-deploy-hook.sh`), + smoke-тесты, rollback на предыдущий tag. +- **ORCH-6** — UI-тестовый раннер для visual-регрессии + (`/home/slin/tools/ui-test/run_tests.js`). +- В каждом managed-репозитории (`enduro-trails` — единственный на + текущий момент) лежит `.openclaw/agents/*.md` — снимок системных + промптов агентов на момент клонирования. Runtime оркестратора и + главные конфиги (бюджеты, политики, scheduler) живут **вне репозитория + managed-проекта**, в отдельной кодовой базе оркестратора. + +### Где живёт код оркестратора сейчас + +На момент составления BRD точное расположение runtime-кода оркестратора +**в этом репозитории не зафиксировано**. Предположительно — отдельный +репозиторий `openclaw` рядом с `enduro-trails` на хосте mva154. Эта +неопределённость — **ключевое решение для архитектора** (см. §7 и +TRZ §3). + +### Почему «self-hosting» — отдельная задача + +Бутстрап-проблема: текущий пайплайн рассчитан на работу с одним +managed-репозиторием `enduro-trails` через `.task-deploy.md`, branch +naming `feature/ET-NNN-…`, Gitea repo `admin/enduro-trails`. Чтобы +конвейер работал на собственном коде, нужны: + +- отдельный Plane-проект и префикс ID (`ORCH-`); +- отдельный target-репозиторий в Gitea; +- отдельный deploy-хук; +- защита от self-update во время активного run (race на тот же + агентный промпт); +- защита от «убийства родителя»: если ORCH-NNN ломает деплой, должна + быть возможность откатиться без участия сломанного оркестратора. + +### Связи + +- **enduro-trails** — managed-проект, остаётся работать в обычном + режиме. ET-016 НЕ меняет процесс работы с ET-NNN. +- **Plane** — добавляется проект `ORCH` с тем же набором стадий. +- **Gitea** — добавляется репозиторий `admin/openclaw` (или фиксируется + существующий). +- **mva154** — здесь живёт production-инстанс оркестратора, сюда же + деплоится новая версия. + +## 3. Scope + +### In scope + +| # | Функция | +| ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| F-01 | Зафиксировать местоположение исходного кода оркестратора (один из вариантов: отдельный репо `openclaw` / `openclaw-runtime` / `.openclaw/` в этом же репо) — решение фиксирует архитектор в ADR. | +| F-02 | В Plane создаётся проект `ORCH` с тем же конвейером стадий: `analysis → architecture → development → testing → review → deploy`. | +| F-03 | Префикс ID `ORCH-` распознаётся orchestrator-router-ом наряду с `ET-`. Работает как минимум с двумя префиксами; путь к артефактам `docs/work-items//` остаётся неизменным. | +| F-04 | Ветки оркестратора именуются `feature/ORCH-NNN-`, `bugfix/ORCH-NNN-`. Конвенция в `CLAUDE.md` оркестратора повторяет конвенцию enduro-trails. | +| F-05 | Deploy-хук для оркестратора (`/home/slin/bin/openclaw-deploy-hook.sh` или аналог) — отдельный от `enduro-deploy-hook.sh`. Перезапуск оркестратора через `docker compose` / `systemctl` — на усмотрение архитектора. | +| F-06 | **Safe self-update**: апдейт оркестратора не должен прерывать активные work item-ы. Допускается стратегия draining (новые run-ы не стартуют, ждём завершения активных, затем рестарт). | +| F-07 | **Rollback без живого оркестратора**: deploy-хук оркестратора должен уметь откатиться к предыдущему tag-у даже если новая версия не стартует (cron-сторож, systemd-таймер или внешний скрипт). | +| F-08 | **Audit trail**: каждое изменение кода оркестратора привязано к work item ORCH-NNN; запрещён прямой push в `main` без PR (защита branch protection в Gitea). | +| F-09 | **Запрет на изменение чужих work-item ID**: агент, работая над `ORCH-NNN`, не может писать в `docs/work-items/ET-*` и наоборот (см. правила в `CLAUDE.md`). | +| F-10 | Smoke-демо: создать work item `ORCH-DEMO-01` (или с реальным ID, выданным Plane), провести через все стадии. Изменение тривиальное — например, дополнить раздел «Запрещено» в `developer.md` строкой про запрет коммита бинарных артефактов > 5 MB. | +| F-11 | Документация: `docs/architecture/self-hosting.md` (или раздел в README оркестратора) с описанием бутстрап-сценария и rollback-процедуры. | +| F-12 | CI для оркестратора: lint YAML-frontmatter агентов, dry-run прогона на тестовом work item-е, smoke-tests `make orch-smoke`. | + +### Out of scope + +- **Multi-tenancy оркестратора** (один инстанс — несколько managed-проектов разной природы). Сейчас и так enduro-trails единственный, и self-hosting сам по себе — это лишь добавление второго проекта `ORCH`. +- **Замена моделей** (Sonnet → Haiku и т. п.) или изменение их по дефолту. +- **Миграция Plane на другую систему трекинга**. +- **Изменение конвенции Conventional Commits**. +- **Полный рефакторинг runtime оркестратора**. Если в ходе работы выявлены глубинные проблемы (например, runtime не разделяет агентные сессии корректно) — открыть отдельный work item `ORCH-NNN+1`. +- **Замена Gitea на GitHub/GitLab**. +- **Перевод оркестратора на k8s** (см. запреты архитектора). +- **Real-time observability dashboard оркестратора**. В этой задаче — только access-логи и `docs/work-items/<…>/14-deploy-log.md`. + +## 4. Сценарии использования + +### UC-01. Owner правит промпт агента developer + +1. Owner создаёт в Plane задачу `ORCH-42`: «У developer запретить коммит файлов > 5 MB». +2. Конвейер пикает задачу, спавнит analyst-агента → артефакты в `docs/work-items/ORCH-42/`. +3. Стадии прокручиваются автоматически до deployer. +4. Deployer мерджит PR в `main` репозитория оркестратора, тэгает `vX.Y.Z`, запускает `openclaw-deploy-hook.sh`. +5. Хук дожидается завершения активных run-ов (draining ≤ 30 мин), затем рестартует оркестратор с новой версией. +6. Smoke: новый запуск любого ET-задачи показывает обновлённого `developer` агента (например, через лог системного промпта). + +### UC-02. Деплой ORCH-NNN сломал runtime + +1. После рестарта healthcheck FAIL (оркестратор не стартует). +2. Внешний сторож (cron каждые 60 сек, или systemd `OnFailure=`) ловит сбой и откатывает к предыдущему tag. +3. Деплой-лог `docs/work-items/ORCH-NNN/14-deploy-log.md` фиксирует rollback. +4. Work item ORCH-NNN возвращается в `back-to:dev` через Plane API. + +### UC-03. Active run во время self-update + +1. ET-099 в стадии `development` (developer-агент работает 12 минут). +2. ORCH-43 переходит в `deploy`. +3. Деплой-хук видит активный run → ждёт `DRAIN_TIMEOUT_SEC` (default 1800). +4. Активный run завершается успешно → рестарт оркестратора → ORCH-43 деплой успешен. +5. (Альтернатива) DRAIN_TIMEOUT истёк → деплой откладывается (статус work-item `deploy:pending`) либо принудительно прерывает run по флагу `--force` (НЕ default). + +## 5. Метрики успеха + +| Метрика | Критерий | +| -------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| Plane-проект ORCH создан | Видим в Plane UI; конвейер umеет создавать work item ORCH-NNN. | +| Префикс ORCH распознаётся | Команда оркестратора, принимающая ``, корректно работает и для `ET-NNN`, и для `ORCH-NNN`. Тест: `orch pick ORCH-DEMO-01` стартует конвейер. | +| Smoke-демо пройдено | ORCH-DEMO-01 (или аналог) завершён со статусом `done`; изменение в `developer.md` присутствует в `main` репо оркестратора; tag прописан; healthcheck PASS. | +| Бутстрап без даунтайма | В UC-03 активный ET-99 не падает; деплой ORCH-43 не теряет свой собственный артефакт. | +| Rollback работает | Имитация сломанного релиза (deploy-хук получает заведомо битый tag) → внешний сторож откатывает за ≤ 5 минут; деплой-лог отражает откат. | +| Branch protection | Попытка push в `main` оркестратора без PR (`git push origin main` напрямую) — отклоняется Gitea с 403. | +| Раздельные deploy-хуки | `enduro-deploy-hook.sh` и `openclaw-deploy-hook.sh` (или унифицированный хук с режимом `--target=enduro|orch`) — путь решения за архитектором. Тестово запускаются по отдельности, не пересекаются. | +| CI оркестратора зелёный | `make orch-lint` (валидация YAML-frontmatter всех `.openclaw/agents/*.md`) и `make orch-smoke` (dry-run одного агента) — оба возвращают 0. | +| Документация Self-hosting | `docs/architecture/self-hosting.md` (или раздел в README оркестратора) содержит: где код, как деплоится, как откатывается, как читать логи, какие env. | +| Время «созыва» | От открытия ORCH-NNN в Plane до автоматического старта analyst-стадии — ≤ 5 минут (как и для ET-NNN). | + +## 6. Риски + +| # | Риск | Вероятность | Влияние | Митигация | +| ---- | ------------------------------------------------------------------------------------------------- | ----------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | +| R-1 | Деплой ORCH-NNN роняет оркестратор → следующие задачи не пикаются | Средняя | Критическое | F-07: внешний сторож (systemd `OnFailure` или cron-watchdog) откатывает за ≤ 5 мин; healthcheck endpoint у оркестратора обязателен. | +| R-2 | Self-update во время активного run → потеря состояния | Средняя | Высокое | F-06: draining-стратегия с таймаутом; persistent state run-ов на диске (если ещё нет — отдельный work item, не в scope ET-016). | +| R-3 | Bootstrap-парадокс: ORCH-NNN ломает analyst → следующие ORCH-NNN не могут пройти анализ | Низкая | Критическое | Канарейка: после деплоя оркестратора прогон smoke-задачи `ORCH-CANARY-MIN` (фиктивная no-op задача) — если smoke FAIL, rollback. | +| R-4 | Два префикса (`ET-`, `ORCH-`) → роутер коллизит / перепутывает managed-репозитории | Средняя | Высокое | F-03: явная таблица маппинга `prefix → repo → deploy_hook` в конфиге оркестратора; unit-тест на роутер. | +| R-5 | Owner случайно push-ит в `main` оркестратора напрямую → audit-trail сломан | Низкая | Среднее | F-08: Gitea branch protection на `main`; required reviews ≥ 1. | +| R-6 | Сторонний разработчик правит `.openclaw/agents/*.md` в репо enduro-trails — изменение не доходит до runtime | Высокая | Среднее | Документация (F-11): `.openclaw/agents/*.md` в enduro-trails — это **снимок**, изменения надо вносить в репозиторий оркестратора и деплоить. Опционально (out of scope): pre-commit hook предупреждает. | +| R-7 | Plane не умеет работать с двумя проектами одновременно → необходима ручная конфигурация | Низкая | Низкое | F-02: проверка на стадии анализа; если оказывается «не умеет» — эскалация к Owner. | +| R-8 | Deploy-хук оркестратора требует прав, которых нет у service-аккаунта (`systemctl restart openclaw`) | Средняя | Среднее | F-05: уточнить с DevOps на стадии TRZ; альтернатива — рестарт через `docker compose restart openclaw` без sudo (если оркестратор контейнеризован). | +| R-9 | Раздельные репо → конвенция CLAUDE.md дрейфует между ними | Средняя | Низкое | F-11: указать в обоих CLAUDE.md ссылку на канонический документ конвенций; периодический ручной audit. | +| R-10 | Размер бюджета токенов в `.openclaw/budget.yaml` отличается для ET и ORCH задач | Средняя | Низкое | TRZ может зафиксировать раздельные бюджеты в одном файле (раздел `projects.ORCH.budget`) либо два файла. Решение архитектора. | + +## 7. Зависимости + +### Инфра + +- mva154: production-инстанс оркестратора (предположительно Docker-контейнер `openclaw` в общем `docker-compose.yml` либо отдельный stack). +- Gitea: создать (или подтвердить существование) репозитория `admin/openclaw`. Включить branch protection на `main`. +- Plane: создать проект с ID-префиксом `ORCH`, настроить стадии `analysis`/`architecture`/`development`/`testing`/`review`/`deploy`/`done`. +- systemd / cron: настроить внешний watchdog для R-1 / R-3 митигации. + +### Код / конфиги + +- Runtime оркестратора (репозиторий, конкретное местоположение — решение архитектора). +- `.openclaw/agents/*.md` — канонические версии живут в репозитории оркестратора; снимок в enduro-trails синхронизируется через CI / периодический pull (out of scope какой именно механизм, но **факт расхождения не приемлем** — это R-6). +- `/home/slin/bin/openclaw-deploy-hook.sh` (новый) или расширение `enduro-deploy-hook.sh` параметром `--target` (решение архитектора). +- Env-переменные оркестратора (`ORCH_GITEA_TOKEN`, `DEPLOY_SSH_*`, потенциально `ORCH_PROJECTS=ET,ORCH` или подобная карта префиксов). + +### Документация + +- `docs/architecture/self-hosting.md` (или README в репозитории оркестратора) — бутстрап-сценарий, rollback, env. +- ADR в `docs/work-items/ET-016/06-adr/`: + - `ADR-NNNN-orch-repo-location.md` — где живёт код оркестратора (отдельный repo vs. submodule vs. monorepo); + - `ADR-NNNN-orch-deploy-strategy.md` — как обновляется (docker restart vs. systemd vs. blue-green); + - `ADR-NNNN-orch-self-update-draining.md` — стратегия draining активных run-ов; + - `ADR-NNNN-orch-watchdog.md` — выбор сторожа (systemd OnFailure vs. cron-script vs. internal). +- Обновления CLAUDE.md оркестратора и/или enduro-trails (раздел про двойной префикс ID). + +### Связи с другими work items + +- Без `ORCH-1..ORCH-6` ET-016 невозможен — там создан базовый конвейер. +- После ET-016 разблокируются дальнейшие задачи `ORCH-NNN` (рефакторинг агентов, обновление промптов, добавление новых стадий и т. п.) — все они будут идти через self-hosted конвейер. +- ET-016 НЕ зависит от текущих ET-001..ET-009 (продуктовая работа не пересекается). + +## 8. Допущения + +- A-1: Plane умеет работать с несколькими проектами и кастомными префиксами. Если нет — Owner эскалирует, ET-016 уходит в `back-to:analysis` с конкретной проблемой. +- A-2: Gitea admin-токен (`ORCH_GITEA_TOKEN`) имеет права на создание репо и установку branch protection. +- A-3: На mva154 есть свободные ресурсы (~512 MB RAM, ~5% CPU) для отдельного контейнера/процесса оркестратора либо текущий контейнер уже включает runtime. +- A-4: Owner готов один раз вручную провести bootstrap-деплой первой версии «self-hosted» оркестратора (по определению он не может задеплоить сам себя, пока не задеплоен). +- A-5: На время выполнения ET-016 заморозка прода не нужна; обычные ET-задачи продолжают работать, потому что инфраструктура для `ORCH-` добавляется параллельно. diff --git a/docs/work-items/ET-016/02-trz.md b/docs/work-items/ET-016/02-trz.md new file mode 100644 index 0000000..da0eb5b --- /dev/null +++ b/docs/work-items/ET-016/02-trz.md @@ -0,0 +1,160 @@ +--- +type: trz +work_item_id: ET-016 +title: "ТЗ: Self-hosting оркестратора openclaw" +version: 1 +status: draft +created_at: 2026-06-02 +updated_at: 2026-06-02 +authors: + - "agent:analyst" +based_on: "01-brd.md v1" +--- + +# ТЗ — ET-016: Self-hosting оркестратора + +## 1. Краткое резюме + +Конвейер оркестратора openclaw должен уметь разрабатывать свой собственный +код через те же стадии, через которые он разрабатывает enduro-trails. +ET-016 добавляет второй managed-проект `ORCH`, реализует безопасный +self-update и доказывает работоспособность smoke-кейсом. + +Архитектурно ключевые решения (расположение репо, стратегия деплоя, +draining, watchdog) — за architect-агентом; в ТЗ зафиксированы +**требования к поведению**, не реализация. + +## 2. Функциональные требования + +### 2.1 Plane-проект ORCH + +| ID | Требование | +| ----- | ----------------------------------------------------------------------------------------------------------------------- | +| FR-01 | В Plane существует проект с префиксом `ORCH` (название проекта на усмотрение Owner, например «openclaw runtime»). | +| FR-02 | Стадии проекта ORCH совпадают по составу со стадиями enduro-trails: `analysis`, `architecture`, `development`, `testing`, `review`, `deploy`, `done`, `back-to:*`. | +| FR-03 | Лейблы `arch:major-change`, `back-to:analysis`, `back-to:dev`, `back-to:review`, `stage:ready-to-deploy` доступны в обоих проектах. | +| FR-04 | Owner может создать work item ORCH-NNN из Plane UI; конвейер в течение ≤ 5 минут пикает его и запускает стадию analysis. | + +### 2.2 Роутер префиксов + +| ID | Требование | +| ----- | ----------------------------------------------------------------------------------------------------------------------- | +| FR-05 | В конфигурации оркестратора есть машиночитаемая таблица маппинга `prefix → {plane_project, gitea_repo, deploy_hook, claude_md_path}`. | +| FR-06 | Поддерживаются минимум два префикса: `ET` (managed-проект enduro-trails) и `ORCH` (managed-проект openclaw runtime). | +| FR-07 | Префикс извлекается из `` строго через регэксп `^([A-Z]+)-(\d+)$` (Plane-конвенция). | +| FR-08 | При неизвестном префиксе оркестратор останавливает запуск с явной ошибкой `unknown_prefix=XXX`, без падений и без коллизий с другим проектом. | + +### 2.3 Репозиторий оркестратора + +| ID | Требование | +| ----- | ----------------------------------------------------------------------------------------------------------------------- | +| FR-09 | Существует Gitea-репозиторий, в котором живёт код оркестратора. Конкретное имя (`admin/openclaw`, `admin/openclaw-runtime` и т. п.) фиксируется ADR. | +| FR-10 | В корне репозитория оркестратора есть свой `CLAUDE.md` с конвенциями (Conventional Commits, ветки `feature/ORCH-NNN-…`). | +| FR-11 | На ветке `main` репозитория оркестратора включена Gitea branch protection: required reviews ≥ 1, прямой push запрещён. | +| FR-12 | Существуют ветки и теги вида `feature/ORCH-NNN-…`, `vMAJOR.MINOR.PATCH` (semver) — формат идентичен enduro-trails. | + +### 2.4 Деплой оркестратора + +| ID | Требование | +| ----- | ----------------------------------------------------------------------------------------------------------------------- | +| FR-13 | Существует deploy-хук, перезапускающий production-инстанс оркестратора на mva154. Имя/путь — за ADR (например, `/home/slin/bin/openclaw-deploy-hook.sh`). | +| FR-14 | Хук неинтерактивный: запускается SSH-командой без TTY, возвращает корректный exit code (0 — успех, ≠ 0 — fail). | +| FR-15 | Хук выполняет healthcheck оркестратора после рестарта (endpoint и его формат — за ADR; минимум — TCP-ping порта runtime либо `GET /healthz` 200). | +| FR-16 | При неуспешном healthcheck в течение `HEALTHCHECK_TIMEOUT_SEC` (default 60) хук вызывает rollback на предыдущий tag и возвращает exit 1. | +| FR-17 | После успешного rollback healthcheck повторно проверяется; если и rollback не поднимает оркестратор — хук возвращает exit 2 (critical), Owner получает уведомление (механизм out of scope; минимум — запись в журнал systemd / Docker logs). | + +### 2.5 Safe self-update + +| ID | Требование | +| ----- | ----------------------------------------------------------------------------------------------------------------------- | +| FR-18 | Перед рестартом оркестратора deploy-хук переводит его в режим `drain`: новые work item-ы не пикаются. | +| FR-19 | Активные run-ы продолжают работу до завершения либо до `DRAIN_TIMEOUT_SEC` (default 1800, конфигурируемо). | +| FR-20 | По истечении DRAIN_TIMEOUT хук имеет два режима: `wait-and-fail` (default — отложить деплой, work item ORCH-NNN остаётся в `deploy:pending`) и `force` (прервать активные run-ы — допустимо только при явном флаге, не default). | +| FR-21 | После рестарта оркестратор автоматически выходит из `drain` (флаг сбрасывается). | +| FR-22 | Состояние `drain` персистентно (файл / БД / lock); рестарт хоста сохраняет его до явного снятия. | + +### 2.6 Watchdog и rollback вне оркестратора + +| ID | Требование | +| ----- | ----------------------------------------------------------------------------------------------------------------------- | +| FR-23 | Существует механизм восстановления, **не зависящий от живости оркестратора**: внешний sensor каждые `WATCHDOG_INTERVAL_SEC` (default 60) проверяет здоровье runtime; если N=3 подряд отказа — автоматически откатывает к предыдущему tag. | +| FR-24 | Конкретный механизм (systemd `OnFailure=`, отдельный systemd-таймер, cron, supervisord) — за ADR. | +| FR-25 | Watchdog **сам не подвержен self-update** (живёт вне deploy-хука оркестратора; апгрейд watchdog — ручной). | +| FR-26 | Лог откатов watchdog пишет в файл (например `/var/log/openclaw-watchdog.log`); каждое срабатывание — отдельная строка с timestamp, from_tag, to_tag, reason. | + +### 2.7 Smoke-демо (доказательство замыкания) + +| ID | Требование | +| ----- | ----------------------------------------------------------------------------------------------------------------------- | +| FR-27 | В рамках ET-016 создаётся реальный work item `ORCH-DEMO-01` (или иной ORCH-NNN, выданный Plane), содержащий **тривиальное** изменение в одном из агентных промптов. Рекомендация: добавить в `developer.md` в раздел «Запрещено» строку про коммит бинарных файлов > 5 MB. | +| FR-28 | Work item проходит все стадии конвейера автоматически, без ручных переходов, кроме Owner-approval, если затронутая ADR `arch:major-change` (для smoke — НЕ затрагивает, должен пройти без approval). | +| FR-29 | После деплоя ORCH-DEMO-01: в репозитории оркестратора в `main` появляется изменённый файл; production-инстанс перезапущен; следующая стартующая ET-задача показывает обновлённого `developer` агента (валидация: первая строка системного промпта содержит новую строку в разделе «Запрещено»). | +| FR-30 | Полный артефакт-набор `docs/work-items/ORCH-DEMO-01/` создан и закоммичен. | + +### 2.8 CI оркестратора + +| ID | Требование | +| ----- | ----------------------------------------------------------------------------------------------------------------------- | +| FR-31 | В репозитории оркестратора есть Gitea Actions workflow на push в `feature/ORCH-*` и PR в `main`: lint + smoke. | +| FR-32 | Lint включает: валидация YAML-frontmatter каждого `.openclaw/agents/*.md` (поля `name`, `description`, `model`, `tools` обязательны и корректного типа). | +| FR-33 | Smoke включает: dry-run запуск одного агента на синтетическом work item-е (без реальных Anthropic вызовов — режим mock или stub). | +| FR-34 | CI запрещает мерж PR в `main` при FAIL любого из шагов. | + +### 2.9 Sync `.openclaw/` снимков + +| ID | Требование | +| ----- | ----------------------------------------------------------------------------------------------------------------------- | +| FR-35 | После deploy ORCH-NNN снимок `.openclaw/agents/*.md` в managed-репозиториях (enduro-trails и будущих) должен быть обновлён. | +| FR-36 | Механизм синхронизации — за ADR. Минимум — автоматический PR из CI оркестратора в каждый managed-репозиторий с заголовком `chore(openclaw): sync agents from ORCH-NNN`. | +| FR-37 | Дрейф `.openclaw/` в managed-репозитории относительно репо оркестратора виден через CI managed-репозитория (например, `make orch-snapshot-check` в CI enduro-trails). | + +## 3. Архитектурные решения (передаются архитектору) + +Архитектор обязан в стадии architecture зафиксировать ADR по следующим вопросам: + +1. **Где живёт runtime-код оркестратора?** + - Вариант A: отдельный Gitea-репозиторий `admin/openclaw` рядом с enduro-trails. + - Вариант B: monorepo с подкаталогом `orchestrator/` (не рекомендуется — нарушает изоляцию). + - Вариант C: подмодуль `.openclaw/` в каждом managed-репозитории (не рекомендуется — синхронизация будет адом). + - **Рекомендация анализа**: вариант A. +2. **Стратегия деплоя на mva154**: docker compose restart / systemd unit / blue-green. +3. **Draining стратегия**: lock-файл / DB-флаг / signal SIGTERM / k8s-style PreStop hook (последнее out of scope — k8s запрещён). +4. **Watchdog**: systemd `OnFailure=` + Restart= / отдельный systemd timer / cron-script / отдельный docker-контейнер. +5. **Sync `.openclaw/`**: автоматический PR / `git subtree pull` в CI managed-репо / симлинки на хосте (нежелательно). +6. **Healthcheck endpoint**: формат и порт — за ADR; минимум — `GET /healthz` HTTP 200 / `curl localhost:PORT`. +7. **Конфиг префиксов**: где хранится таблица `prefix → {plane_project, gitea_repo, …}` — YAML в репо оркестратора, env-переменные, иное. + +## 4. Нефункциональные требования + +| ID | Требование | +| ------ | ----------------------------------------------------------------------------------------------------------------------- | +| NFR-01 | Время полного self-update (от merge PR ORCH-NNN до завершения healthcheck): ≤ 10 минут при пустом draining-окне. | +| NFR-02 | Время watchdog-rollback: ≤ 5 минут от момента детекции FAIL. | +| NFR-03 | Расход RAM оркестратора после рестарта: не превышает baseline ± 20 %. | +| NFR-04 | Логи деплоя оркестратора ротируются (logrotate / docker log-driver): не более 100 MB на инстанс. | +| NFR-05 | Все env-переменные оркестратора (включая токены) задаются через `.env` или systemd-EnvironmentFile, не через git. | +| NFR-06 | Конфиги (`prefix-map`, `budget.yaml`) валидируются на старте; некорректный конфиг → старт прерывается с явной ошибкой. | +| NFR-07 | Безопасность: deploy-хук оркестратора **не имеет прав** на изменение `.openclaw/agents/` в managed-репо в обход PR. | + +## 5. Out of scope (повтор для строгости) + +- Замена моделей агентов. +- Multi-tenancy (несколько managed-проектов разной природы — кроме связки ET + ORCH). +- Real-time observability dashboard. +- Миграция Gitea / Plane / Anthropic API. +- Полный рефакторинг внутреннего runtime оркестратора. +- Поддержка более двух префиксов одновременно (только ET и ORCH в этой задаче; расширение — отдельный work item). + +## 6. Открытые вопросы (Q&A для architect и Owner) + +| # | Вопрос | К кому | +| --- | --------------------------------------------------------------------------------------------------------------------------------------- | ---------- | +| Q-1 | Какой Gitea-репозиторий выбран для runtime оркестратора? Создавать новый или использовать существующий? | architect + Owner | +| Q-2 | На каком порту слушает healthcheck оркестратора сейчас (если есть)? | architect | +| Q-3 | Управляется ли production оркестратора через docker compose или systemd unit? | architect | +| Q-4 | Допустимо ли требовать у Owner ручной bootstrap первой self-hosted версии (см. A-4 BRD §8)? | Owner | +| Q-5 | Plane: поддерживается ли создание нового проекта с произвольным префиксом без миграции? | Owner | +| Q-6 | Нужен ли в smoke-демо отдельный «канареечный» прогон фиктивного ET-задания после деплоя оркестратора (R-3 BRD §6)? | architect | +| Q-7 | Должен ли watchdog уметь уведомлять Owner (Telegram/email)? Если да — это отдельный work item или включено в ET-016? | Owner | + +Аналитик рекомендует: Q-7 — отдельный work item (out of scope). Остальные — обязательно ответить в ADR. diff --git a/docs/work-items/ET-016/03-acceptance-criteria.md b/docs/work-items/ET-016/03-acceptance-criteria.md new file mode 100644 index 0000000..e39a352 --- /dev/null +++ b/docs/work-items/ET-016/03-acceptance-criteria.md @@ -0,0 +1,196 @@ +--- +type: acceptance-criteria +work_item_id: ET-016 +title: "AC: Self-hosting оркестратора" +version: 1 +status: draft +created_at: 2026-06-02 +updated_at: 2026-06-02 +authors: + - "agent:analyst" +--- + +# Acceptance Criteria — ET-016 + +Все AC формулируются как «given-when-then», чтобы tester мог их прогнать +вручную или автоматически. Каждый AC привязан к одному или нескольким +FR из `02-trz.md`. + +## AC-01. Plane-проект ORCH существует и видим конвейеру + +**Given** Plane API запущен на `http://localhost:8080` (или текущий адрес из env). +**When** обратиться `GET /api/v1/workspaces//projects/?identifier=ORCH`. +**Then** ответ 200, в списке проектов есть проект с `identifier="ORCH"`, +у него заданы стадии `analysis`, `architecture`, `development`, `testing`, +`review`, `deploy`, `done`. + +Соответствует: FR-01..FR-04. + +## AC-02. Роутер префиксов работает для ET и ORCH + +**Given** оркестратор запущен в режиме CLI `orch --version` возвращает 0. +**When** запустить `orch route ET-001` и `orch route ORCH-DEMO-01`. +**Then** обе команды возвращают exit 0, печатают разные `gitea_repo`, +разные `claude_md_path`, разные `deploy_hook`. При запуске +`orch route XYZ-001` (неизвестный префикс) команда возвращает exit ≠ 0 +с сообщением, содержащим строку `unknown_prefix=XYZ`. + +(Конкретное имя команды `orch route` — указатель; tester валидирует +эквивалент после implementation согласно ADR.) + +Соответствует: FR-05..FR-08. + +## AC-03. Репо оркестратора защищён branch protection + +**Given** Gitea доступен, token имеет admin-права. +**When** попытаться `git push origin main` напрямую в репо оркестратора. +**Then** push отклонён с кодом 403 / `protected branch`. Mерж через PR с +≥ 1 approve работает. + +Соответствует: FR-09..FR-12. + +## AC-04. Deploy-хук успешного релиза + +**Given** в репо оркестратора есть мердж в `main` и tag `v0.X.Y` для +тривиального изменения (например, обновление комментария в README). +**When** запустить `ssh slin@127.0.0.1 bash /home/slin/bin/openclaw-deploy-hook.sh v0.X.Y` +(или эквивалент по ADR). +**Then**: +- Exit code 0. +- Healthcheck endpoint возвращает 200 в течение ≤ 60 секунд после рестарта. +- Запись в логе оркестратора отражает рестарт. +- Текущий tag оркестратора (через `orch --version` или эквивалент) — `v0.X.Y`. + +Соответствует: FR-13..FR-17. + +## AC-05. Deploy-хук неуспешного релиза → rollback + +**Given** в репо оркестратора есть tag `v0.X.Z` (заведомо битый — например, +синтаксическая ошибка в YAML-frontmatter одного из агентов; tester подкладывает локально для теста). +**When** запустить deploy-хук с этим тегом. +**Then**: +- Healthcheck FAIL в пределах HEALTHCHECK_TIMEOUT_SEC. +- Хук автоматически переключает на предыдущий tag. +- Healthcheck PASS после rollback. +- Exit code = 1 (релиз провален, но runtime жив). +- `docs/work-items//14-deploy-log.md` (если применимо) или + `/var/log/openclaw-deploy.log` содержит запись об откате. + +Соответствует: FR-16..FR-17. + +## AC-06. Draining не убивает активный run + +**Given** запущен ET-99 (синтетическая длинная задача, ≥ 5 минут — например, развёрнутый pytest на enduro-trails). +**When** запустить deploy ORCH-NNN с `DRAIN_TIMEOUT_SEC=900`. +**Then**: +- Оркестратор переводится в `drain`, новые ET / ORCH задачи не пикаются (validate: создать ET-100 в Plane — он не должен стартовать пока drain). +- ET-99 продолжает работать, не падает. +- После завершения ET-99 (≤ 10 минут) оркестратор рестартует. +- После рестарта `drain` сбрасывается; ET-100 пикается. + +Соответствует: FR-18..FR-22. + +## AC-07. Watchdog откатывает сломанный релиз без участия оркестратора + +**Given** оркестратор задеплоен в заведомо сломанной версии (healthcheck FAIL), но +deploy-хук по какой-то причине не отработал rollback (имитируется: tester убивает процесс хука после tag-switch, до healthcheck). +**When** ждать `WATCHDOG_INTERVAL_SEC * 3` секунд (default 60 × 3 = 180 сек). +**Then**: +- Watchdog обнаружил FAIL. +- Watchdog инициировал rollback к предыдущему tag. +- Healthcheck PASS после rollback (≤ 5 минут от старта инцидента). +- `/var/log/openclaw-watchdog.log` содержит строку с `from_tag`, `to_tag`, `reason`. + +Соответствует: FR-23..FR-26. + +## AC-08. Smoke-демо ORCH-DEMO-01 пройден end-to-end + +**Given** ET-016 завершён до стадии deploy; всё что выше — задеплоено. +**When** Owner создаёт в Plane work item с заголовком «Добавить запрет на коммит файлов > 5 MB в developer.md», префикс ORCH, без лейбла `arch:major-change`. +**Then**: +- Конвейер пикает работу в ≤ 5 минут. +- Стадии проходят: analysis → architecture → development → testing → review → deploy → done. +- В репозитории оркестратора в `main`: файл `.openclaw/agents/developer.md` (или путь до него в этом репо) содержит новую строку в разделе «Запрещено». +- На production-инстансе оркестратора эта новая строка присутствует (validate: после деплоя стартует любая следующая задача, в логе системного промпта `developer` есть новая строка). +- `docs/work-items/ORCH-DEMO-01/` содержит полный набор артефактов (01..14 по соглашению, кроме тех, что не применимы — например, 04b/08, если задача не UI/не data). +- Tag оркестратора инкрементирован на 1 patch. +- Healthcheck PASS. + +Соответствует: FR-27..FR-30 (главное «доказательство замыкания»). + +## AC-09. Прямой push в `main` оркестратора заблокирован + +**Given** разработчик с admin-токеном Gitea. +**When** `git push origin main` в репо оркестратора напрямую (минуя PR). +**Then** push отклонён с 403; работает только merge через PR. + +Соответствует: FR-08, FR-11. + +## AC-10. Изоляция work-item-ID между ET и ORCH + +**Given** одновременно открыты ET-099 (стадия development) и ORCH-099 (стадия development). +**When** developer-агент по ORCH-099 пытается записать файл в `docs/work-items/ET-099/` (синтетическая попытка через tester-задачу). +**Then** запись отклонена (tooling-уровень — например, sandbox / pre-commit-hook / агентный guard). Минимум — reviewer-агент в ORCH-099 видит факт записи в чужой work-item и помечает P0 finding `cross-work-item-write`. + +Соответствует: FR-09 (BRD). + +## AC-11. CI оркестратора блокирует мерж невалидного промпта + +**Given** в репо оркестратора открыт PR с битым YAML-frontmatter одного агента (например, `model: ` без значения). +**When** Gitea Actions запускает workflow. +**Then** lint FAIL; PR не может быть смержен; в комментариях PR — ссылка на ошибку. + +Соответствует: FR-31..FR-34. + +## AC-12. Sync `.openclaw/` снимка в enduro-trails + +**Given** ORCH-DEMO-01 успешно задеплоен (AC-08 пройден). +**When** проверить `.openclaw/agents/developer.md` в репо enduro-trails в ветке `main`. +**Then** либо: +- (а) файл уже обновлён (если автоматическая синхронизация через PR прошла) — в `main` enduro-trails есть merge-commit с заголовком, содержащим `sync agents from ORCH-DEMO-01`; +- (б) открыт PR с такой синхронизацией (если выбран ADR-вариант с ручным merge снимка). + +В обоих случаях запуск `make orch-snapshot-check` (или эквивалент) в репо enduro-trails показывает корректность снимка (хеш файлов в `.openclaw/agents/` совпадает с релизом оркестратора). + +Соответствует: FR-35..FR-37. + +## AC-13. Документация Self-hosting опубликована + +**Given** ET-016 завершён до стадии review. +**When** проверить наличие `docs/architecture/self-hosting.md` (или README раздел в репо оркестратора, как зафиксирует ADR). +**Then** документ содержит обязательно: +- Где живёт runtime-код оркестратора (репо, путь на сервере). +- Команды для bootstrap первой версии. +- Команды для rollback вручную (если watchdog не сработал). +- Описание env-переменных оркестратора. +- Описание формата конфига префиксов. +- Контакты эскалации (Owner email/Telegram). + +Соответствует: F-11 BRD, NFR-05. + +## AC-14. Бюджет токенов задачи соблюдён + +**Given** ET-016 завершён. +**When** orchestrator подсчитывает суммарный расход токенов по всем стадиям. +**Then** суммарный расход не превышает бюджет, заданный в `.openclaw/budget.yaml` для work item типа `infrastructure` (или ближайшего аналога). При превышении — finding P1 в `12-review.md`. + +Соответствует: правило #5 для агентов из CLAUDE.md. + +## AC-15. Артефакты ET-016 полные + +**Given** ET-016 на стадии review. +**When** проверить `docs/work-items/ET-016/`. +**Then** присутствуют: +- 00-business-request.md (входной) +- 01-brd.md +- 02-trz.md +- 03-acceptance-criteria.md (этот файл) +- 04-test-plan.yaml +- 06-adr/ (минимум 3 ADR по списку из §3 TRZ) +- 07-infra-requirements.md +- 10-tech-risks.md +- 12-review.md +- 13-test-report.md +- 14-deploy-log.md + +(Файлы 04b-ui-test-cases.md и 08-data-requirements.md не применимы — задача не UI и не data-bound.) diff --git a/docs/work-items/ET-016/04-test-plan.yaml b/docs/work-items/ET-016/04-test-plan.yaml new file mode 100644 index 0000000..09b9f54 --- /dev/null +++ b/docs/work-items/ET-016/04-test-plan.yaml @@ -0,0 +1,293 @@ +--- +type: test-plan +work_item_id: ET-016 +title: "Test plan: Self-hosting оркестратора" +version: 1 +status: draft +created_at: 2026-06-02 +updated_at: 2026-06-02 +authors: + - "agent:analyst" +--- + +# Test plan ET-016 — Self-hosting оркестратора +# +# Структура: unit / integration / e2e / manual. +# UI / Playwright тестов нет — задача не затрагивает фронтенд enduro-trails. +# Все тесты доступны для запуска через `make orch-test` в репозитории оркестратора +# и через CI Gitea Actions. + +unit: + - id: U-01 + name: "prefix_router: распознаёт ET и ORCH" + suite: orchestrator/tests/test_prefix_router.py + fr_refs: [FR-05, FR-06, FR-07, FR-08] + description: | + Параметризованный тест: входы "ET-001", "ORCH-099", "ABC-1", "et-1", + "ET-", "ET-001-x". Проверить корректное извлечение префикса и номера + для валидных IDs и raise UnknownPrefixError / InvalidIdError для невалидных. + expected: + - "ET-001 → (prefix=ET, num=1)" + - "ORCH-099 → (prefix=ORCH, num=99)" + - "ABC-1 → UnknownPrefixError(prefix='ABC')" + - "et-1 → InvalidIdError" + - "ET- → InvalidIdError" + + - id: U-02 + name: "prefix_map: загрузка конфига и валидация" + suite: orchestrator/tests/test_prefix_map.py + fr_refs: [FR-05] + description: | + Загрузить prefix-map YAML с ключами ET и ORCH. Проверить, что для + каждого префикса определены plane_project, gitea_repo, deploy_hook, + claude_md_path. Битый YAML или отсутствующий ключ → ConfigError. + expected: + - "valid yaml → dict с двумя префиксами" + - "yaml без gitea_repo для ORCH → ConfigError('missing gitea_repo')" + + - id: U-03 + name: "agent_frontmatter_validator: lint всех .openclaw/agents/*.md" + suite: orchestrator/tests/test_agent_lint.py + fr_refs: [FR-32] + description: | + Прочитать каждый файл из .openclaw/agents/, распарсить YAML-frontmatter, + проверить обязательные поля (name, description, model, tools). + Параметризован по списку файлов. + expected: + - "все 6 файлов проходят валидацию" + - "синтетический файл с пустым model → ValidationError" + + - id: U-04 + name: "drain_state: запись и чтение" + suite: orchestrator/tests/test_drain_state.py + fr_refs: [FR-18, FR-21, FR-22] + description: | + Установить drain=True, перезапустить процесс (имитация), проверить, + что состояние сохранилось. Снять drain — проверить, что новые run-ы пикаются. + expected: + - "set_drain(True) → файл /var/lib/openclaw/drain существует" + - "set_drain(False) → файл удалён" + - "is_drained() читает корректно после рестарта" + + - id: U-05 + name: "deploy_hook_arg_parser: target=enduro|orch" + suite: orchestrator/tests/test_deploy_hook.py + fr_refs: [FR-13, FR-14] + description: | + Если выбрана стратегия унифицированного deploy-хука (ADR §3.2), + параметризовать тест на --target=enduro и --target=orch. + Проверить, что для каждого target используется правильный compose + файл / systemd unit / git path. + expected: + - "--target=enduro вызывает enduro-deploy steps" + - "--target=orch вызывает orch-deploy steps" + - "--target=unknown → exit 2" + +integration: + - id: I-01 + name: "orchestrator стартует и пикает работу с обоими префиксами" + suite: orchestrator/tests/integration/test_pickup.py + fr_refs: [FR-04, FR-05] + description: | + Замокать Plane API так, чтобы он отдавал одно work item ET-X + и одно ORCH-Y. Запустить scheduler. Проверить, что оба пикаются, + каждый стартует со своим claude_md_path, своим gitea_repo. + expected: + - "ET-X стартует analyst в репо enduro-trails" + - "ORCH-Y стартует analyst в репо оркестратора" + - "Логи содержат корректные пути к CLAUDE.md" + + - id: I-02 + name: "Gitea branch protection действительно блокирует push в main" + suite: orchestrator/tests/integration/test_gitea_protection.py + fr_refs: [FR-11] + description: | + Через локальный Gitea (testcontainer / тестовый инстанс с тем же + настроенным репо): попытка `git push origin main` напрямую → ожидаем + ошибку 403 / "protected branch". Push в feature-ветку → успех. + expected: + - "direct push to main → fail (403)" + - "push to feature/ORCH-1-test → success" + + - id: I-03 + name: "Healthcheck endpoint возвращает 200 после старта" + suite: orchestrator/tests/integration/test_healthcheck.py + fr_refs: [FR-15] + description: | + Поднять оркестратор в test-режиме (например, через docker compose + из репо оркестратора), проверить /healthz возвращает 200 в течение + 30 секунд после старта. Убить процесс — /healthz → connection refused. + expected: + - "GET /healthz → 200 within 30s" + - "после kill: GET /healthz → connection refused" + + - id: I-04 + name: "Drain mode: новые run-ы не пикаются, активные не падают" + suite: orchestrator/tests/integration/test_drain.py + fr_refs: [FR-18, FR-19, FR-21] + description: | + Запустить mock-задачу длительностью 60 сек. После 10 сек активной + задачи установить drain=True. Создать второй mock-work-item. + Проверить: активная задача завершилась успешно, второй work item + НЕ был запущен. Снять drain → второй пикается. + expected: + - "active run completes successfully" + - "queued work item not picked while drain=True" + - "after drain=False: queued work item picked" + + - id: I-05 + name: "Sync agents PR создаётся после deploy ORCH-NNN" + suite: orchestrator/tests/integration/test_sync_pr.py + fr_refs: [FR-35, FR-36] + description: | + Имитировать успешный deploy ORCH-NNN, содержащий изменение в + .openclaw/agents/developer.md. Проверить, что в Gitea для репо + enduro-trails открыт PR с заголовком, содержащим "sync agents from ORCH-NNN". + expected: + - "PR exists in admin/enduro-trails" + - "PR head branch: chore/openclaw-sync-ORCH-NNN" + - "PR diff содержит обновлённый developer.md" + + - id: I-06 + name: "Snapshot check скрипт обнаруживает дрейф" + suite: orchestrator/tests/integration/test_snapshot_check.py + fr_refs: [FR-37] + description: | + Артифициально внести изменение в `.openclaw/agents/developer.md` в + enduro-trails (без соответствующего изменения в репо оркестратора). + Запустить `make orch-snapshot-check`. Ожидаем exit ≠ 0 и diff в выводе. + После приведения файлов в соответствие → exit 0. + expected: + - "drift detected → exit 1, diff printed" + - "after sync → exit 0" + +e2e: + - id: E-01 + name: "ORCH-DEMO-01 smoke: полный конвейер end-to-end" + suite: manual + scripts/e2e_orch_demo.sh + fr_refs: [FR-27, FR-28, FR-29, FR-30] + description: | + Создать work item в Plane с заголовком из FR-27 BRD (добавить строку + в "Запрещено" у developer.md). Запустить конвейер. Дождаться done. + Проверить: + - В репозитории оркестратора в main новая строка присутствует. + - В production-инстансе оркестратора (mva154) код обновлён + (запустить следующую ET-задачу, в логе её analyst-стадии вытащить + system prompt developer-агента, ожидаемая новая строка присутствует). + - В docs/work-items/ORCH-DEMO-01/ присутствуют все обязательные артефакты. + - В Gitea репо оркестратора есть tag vX.Y.Z+1. + - Deploy-лог записан. + expected: + - "work item status: done в Plane" + - "tag vX.Y.Z+1 в репо оркестратора" + - "developer-агент содержит новую строку" + - "healthcheck PASS на production" + + - id: E-02 + name: "Сломанный релиз → watchdog rollback" + suite: manual + scripts/e2e_watchdog_rollback.sh + fr_refs: [FR-23, FR-24, FR-26] + description: | + Подложить локально tag vX.Y.Z+2 c заведомо битой YAML-frontmatter + одного из агентов. Запустить deploy-хук, ИМИТИРОВАТЬ зависание хука + (kill -STOP) до этапа healthcheck. Подождать 3 интервала watchdog (≥ 180 сек). + Проверить, что watchdog откатил релиз. + expected: + - "watchdog log содержит запись с from_tag=vX.Y.Z+2, to_tag=vX.Y.Z+1" + - "healthcheck PASS после rollback" + - "production-инстанс на tag vX.Y.Z+1" + + - id: E-03 + name: "ET-задача продолжает работать во время self-update ORCH-задачи" + suite: manual + scripts/e2e_concurrent_run.sh + fr_refs: [FR-19, FR-20] + description: | + Запустить синтетическую длинную ET-задачу (mock, 5 минут). + Через 1 минуту запустить deploy ORCH-NNN (любой тривиальный). + Дождаться завершения ET-задачи, затем рестарта оркестратора, затем + успеха ORCH-NNN. + expected: + - "ET-задача завершена успешно" + - "ORCH-NNN deploy success" + - "Промежуточный лог содержит фазу drain" + - "Очередной new work item не пикался во время drain" + + - id: E-04 + name: "Прямой push в main репо оркестратора отклоняется" + suite: manual + fr_refs: [FR-11] + description: | + Из любой машины с push-доступом: `git push origin main` напрямую в + репо оркестратора → ожидаем 403/protected branch. + expected: + - "git push fails with exit ≠ 0" + - "stderr содержит 'protected branch' или 'push declined'" + + - id: E-05 + name: "Cross-write блокирован: ORCH-агент не пишет в docs/work-items/ET-*" + suite: manual + orchestrator/tests/integration/test_cross_write_guard.py + fr_refs: [F-09 BRD, AC-10] + description: | + Запустить ORCH-99-mock с developer-агентом, которому в задаче + требуется (синтетически) записать файл `docs/work-items/ET-099/test.md`. + Ожидаем: либо tooling-level block (sandbox), либо reviewer P0 finding. + expected: + - "запись отклонена ИЛИ зафиксирован P0 в 12-review.md ORCH-99" + +manual: + - id: M-01 + name: "Документация self-hosting.md проверка" + fr_refs: [AC-13] + description: | + Открыть docs/architecture/self-hosting.md и убедиться вручную в + наличии разделов: bootstrap, rollback, env-переменные, формат + prefix-map, контакты эскалации. + + - id: M-02 + name: "Проверка branch protection в Gitea UI" + fr_refs: [FR-11] + description: | + Зайти в Gitea, открыть repo settings → branches → main, убедиться: + "Enable Push Protection" вкл, "Require pull request" вкл, минимум 1 reviewer. + + - id: M-03 + name: "Проверка бюджета токенов в .openclaw/budget.yaml" + fr_refs: [AC-14] + description: | + Открыть .openclaw/budget.yaml. Убедиться, что есть отдельная запись + для задач типа infrastructure (либо ORCH-задач). Сравнить с фактическим + расходом ET-016 (из лога оркестратора). + +# Минимальный smoke на CI оркестратора (Gitea Actions): +ci_smoke: + - id: CI-01 + name: "make orch-lint" + description: | + Запускается на каждый push в feature/ORCH-* и PR в main. + Включает U-01..U-03. + fr_refs: [FR-31, FR-32] + blocks_merge: true + + - id: CI-02 + name: "make orch-smoke" + description: | + Запускается на каждый PR в main репо оркестратора. + Включает I-01, I-03, I-04 (mock Anthropic API через stub). + fr_refs: [FR-33, FR-34] + blocks_merge: true + +# Регрессия enduro-trails: убедиться, что ET-016 не сломал обычный конвейер. +regression_enduro: + - id: R-01 + name: "Любая существующая ET-задача всё ещё пикается" + description: | + Создать тривиальную ET-задачу (например, "обновить дату в README"), + убедиться, что конвейер для неё работает как раньше. + fr_refs: [NFR-03] + + - id: R-02 + name: "Production enduro-trails не упал во время ET-016 deploy" + description: | + В моменты деплоя ORCH-* (если они идут параллельно с прогоном ET-задачи) + запрашивать /api/health enduro-trails и убеждаться, что 200 OK. + fr_refs: [BRD §3 out-of-scope]