analyst(ET): auto-commit from analyst run_id=55
This commit is contained in:
218
docs/work-items/ET-016/01-brd.md
Normal file
218
docs/work-items/ET-016/01-brd.md
Normal file
@@ -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/<plane-id>/`.
|
||||
- **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/<plane-id>/` остаётся неизменным. |
|
||||
| F-04 | Ветки оркестратора именуются `feature/ORCH-NNN-<slug>`, `bugfix/ORCH-NNN-<slug>`. Конвенция в `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 распознаётся | Команда оркестратора, принимающая `<plane-id>`, корректно работает и для `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-` добавляется параллельно.
|
||||
160
docs/work-items/ET-016/02-trz.md
Normal file
160
docs/work-items/ET-016/02-trz.md
Normal file
@@ -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 | Префикс извлекается из `<plane-id>` строго через регэксп `^([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.
|
||||
196
docs/work-items/ET-016/03-acceptance-criteria.md
Normal file
196
docs/work-items/ET-016/03-acceptance-criteria.md
Normal file
@@ -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/<ws>/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/<orch-id>/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.)
|
||||
293
docs/work-items/ET-016/04-test-plan.yaml
Normal file
293
docs/work-items/ET-016/04-test-plan.yaml
Normal file
@@ -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]
|
||||
Reference in New Issue
Block a user