architect(ET): auto-commit from architect run_id=585
This commit is contained in:
@@ -122,6 +122,42 @@ F1b (рамка C-1: наблюдатель отделён от наблюдае
|
||||
`docs/work-items/ORCH-100/06-adr/ADR-001-sidecar-watchdog.md`,
|
||||
`docs/work-items/ORCH-100/07-infra-requirements.md`.
|
||||
|
||||
## Turnkey-онбординг проектов (ORCH-009 — design)
|
||||
|
||||
Операторская способность развернуть **новый** проект одним проходом: Plane-проект (статусы с
|
||||
точными именами + лейблы под машинные контракты) → Gitea-репо (+per-repo webhook) → каркас репо
|
||||
(kit) → запись реестра → верификация. Реализуется **вне рантайма и вне конвейера**: `src/**`
|
||||
байт-в-байт (`STAGE_TRANSITIONS`/`QG_CHECKS`/`check_*`/machine-verdict/схема БД — не тронуты),
|
||||
kill-switch не нужен (активация — только явный запуск CLI человеком). Эталон — сам репозиторий
|
||||
orchestrator (каноны ORCH-52b/c/d/e); enduro-trails эталоном не является.
|
||||
|
||||
- **Kit `onboarding/repo-skeleton/`** — параметризуемый каркас нового репо: 6 промптов агентов
|
||||
канона 52d/92 (язык — канон орка: 5 ru + deployer en, ADR-001 D2 ORCH-092), паспорт `CLAUDE.md`,
|
||||
`AGENTS.md` (точка входа агентов: карта доков + правила), `CONTRIBUTING.md`, `README`/`CHANGELOG`,
|
||||
скелет `docs/` с обязательным `operations/INFRA.md`, `.env.example`. Плейсхолдеры `{{NAME}}` +
|
||||
stdlib-рендер (без новых зависимостей); словарь — `onboarding/placeholders.json`. **Канон не
|
||||
форкается (BR-2):** `docs/_templates/` + `docs/_standards/` не хранятся в kit — копируются live
|
||||
из чекаута орка в момент материализации.
|
||||
- **CLI `scripts/onboard_project.py`** — `plan` (дефолт, GET-only, ноль мутаций) / `apply`
|
||||
(идемпотентный ensure, без delete-операций) / `verify` (round-trip реестра через фактический
|
||||
`projects._parse_projects_json`, резолв всех статусов включая fail-closed `Confirm Deploy`/`STOP`,
|
||||
лейблы, webhook, полнота kit, скан неразрешённых плейсхолдеров). Имена статусов — read-only
|
||||
импорт `plane_sync._PLANE_NAME_TO_KEY` (22, нулевой дрейф); канонические группы фиксированы ADR
|
||||
(код-критично: `STOP`→`cancelled` ORCH-090; терминальные группы только у Done/Cancelled/STOP —
|
||||
иначе terminal-detection ORCH-068 ложно терминалит). Gitea-webhook переиспользует глобальный
|
||||
`ORCH_GITEA_WEBHOOK_SECRET`; initial push — **только** в свежесозданный пустой репо (INV-4 не
|
||||
затрагивается). Скрипт никогда не рестартит прод / не правит `.env` / ничего не удаляет;
|
||||
регистрация в реестре = операторские env + управляемый рестарт (runbook). Недоступное в
|
||||
Plane CE API → `manual-step` (fail-safe).
|
||||
- **Runbook `docs/operations/ONBOARDING.md`** — чеклист всех слоёв, явные ручные шаги, smoke на
|
||||
**staging-контуре** (8501, изолированная БД) с одноразовым sandbox-проектом, откат.
|
||||
- **Анти-дрейф:** структурные канон-тесты kit (аналог `tests/test_agent_prompts_canon.py`) +
|
||||
снапшот-тест `STAGE_TRANSITIONS`/`QG_CHECKS`.
|
||||
|
||||
Подробнее: [adr-0035](adr/adr-0035-turnkey-project-onboarding.md), детально —
|
||||
`docs/work-items/ORCH-009/06-adr/ADR-001-turnkey-onboarding-kit-and-cli.md` (D1…D11),
|
||||
`docs/work-items/ORCH-009/07-infra-requirements.md`.
|
||||
|
||||
## Конвейер и Quality Gates
|
||||
|
||||
```
|
||||
|
||||
80
docs/architecture/adr/adr-0035-turnkey-project-onboarding.md
Normal file
80
docs/architecture/adr/adr-0035-turnkey-project-onboarding.md
Normal file
@@ -0,0 +1,80 @@
|
||||
---
|
||||
work_item: ORCH-009
|
||||
stage: architecture
|
||||
author_agent: architect
|
||||
status: proposed
|
||||
created_at: 2026-06-10
|
||||
model_used: claude-opus-4-8
|
||||
---
|
||||
|
||||
# adr-0035: Turnkey-онбординг проектов — kit + операторский CLI + runbook (ORCH-009)
|
||||
|
||||
## Статус
|
||||
Proposed
|
||||
|
||||
## Контекст
|
||||
|
||||
Подключение нового проекта к оркестратору — ручная археология по разрозненным докам и памяти;
|
||||
каждый пропущенный шаг даёт **тихую деградацию**: без промптов в репо конвейер проекта не работает
|
||||
вовсе (launcher резолвит `.openclaw/agents/<role>.md` относительно worktree репо задачи); без
|
||||
точных имён статусов Plane ветки `Confirm Deploy` (ORCH-059) / `STOP` (ORCH-090) молча не
|
||||
активируются (fail-closed); без лейблов `autoApprove`/`autoDeploy`/`Bug` авто-режимы (ORCH-089)
|
||||
и багфикс-трек (ORCH-019) молча выключены (fail-safe). Эталон онбординга — **сам репозиторий
|
||||
orchestrator** (каноны ORCH-52b/c/d/e кодифицированы в `docs/_templates/`, `docs/_standards/`,
|
||||
`.openclaw/agents/`). Домен D5.2 эпика саморазвития: способность разворачивать новый проект
|
||||
одним проходом.
|
||||
|
||||
## Решение
|
||||
|
||||
Способность реализуется **вне рантайма и вне конвейера** — `src/**` байт-в-байт не меняется
|
||||
(`STAGE_TRANSITIONS`/`QG_CHECKS`/`check_*`/machine-verdict/схема БД/контракт `projects.py`
|
||||
нетронуты), kill-switch не нужен (активация — только явный запуск операторского CLI):
|
||||
|
||||
1. **Onboarding-kit `onboarding/repo-skeleton/`** — параметризуемый каркас нового репо:
|
||||
6 промптов агентов канона 52d/92 (5 XML-секций, «❌→✅», эмиссия схемы 52c, verdict-ключи
|
||||
байт-в-байт; язык — канон орка: 5 ru + deployer en), паспорт `CLAUDE.md`, `AGENTS.md`
|
||||
(точка входа агентов), `CONTRIBUTING.md`, `README.md`, `CHANGELOG.md`, скелет `docs/` с
|
||||
обязательным `operations/INFRA.md`, `.env.example`. Плейсхолдеры `{{NAME}}` + stdlib-рендер
|
||||
(без новых pip-зависимостей); словарь — `onboarding/placeholders.json` (биекция со
|
||||
вхождениями в kit держится тестами). **Канон не форкается:** `docs/_templates/` +
|
||||
`docs/_standards/` НЕ хранятся в kit — копируются live из чекаута орка в момент материализации.
|
||||
2. **Операторский CLI `scripts/onboard_project.py`** — `plan` (дефолт, GET-only, ни одной
|
||||
мутации) / `apply` (идемпотентный ensure, без delete-операций) / `verify`. Шаги: Plane-проект →
|
||||
22 статуса с точными именами из `plane_sync._PLANE_NAME_TO_KEY` (read-only импорт — нулевой
|
||||
дрейф; канонические группы фиксированы: `STOP`→`cancelled`, терминальные группы только у
|
||||
Done/Cancelled/STOP — иначе terminal-detection ORCH-068 ложно терминалит) → лейблы → Gitea-репо
|
||||
(+per-repo webhook `push`/`pull_request`/`status`; HMAC-секрет **переиспользуется** из
|
||||
`ORCH_GITEA_WEBHOOK_SECRET` — приёмник один на все репо) → материализация kit + initial push
|
||||
**только в свежесозданный пустой репо** (INV-4 не затрагивается) → merged-вывод
|
||||
`ORCH_PROJECTS_JSON`, провалидированный фактическим `projects._parse_projects_json`
|
||||
(round-trip). Недоступное в Plane CE API → `manual-step` со ссылкой на runbook (fail-safe).
|
||||
Скрипт **никогда** не рестартит прод, не правит `.env`, не пушит в существующие репо, ничего
|
||||
не удаляет.
|
||||
3. **Runbook `docs/operations/ONBOARDING.md`** — полный чеклист: предусловия (токены) → скрипт →
|
||||
операторские шаги (env + управляемый рестарт с self-hosting-предупреждением; UI-only Plane) →
|
||||
верификация (`verify` + smoke) → откат. Smoke-контур — **staging (8501, изолированная БД)** +
|
||||
одноразовый sandbox-проект (`SMK`); протокол — «Журнал smoke-прогонов» в runbook.
|
||||
|
||||
Анти-дрейф — структурные тесты kit (аналог `tests/test_agent_prompts_canon.py`) + снапшот-тест
|
||||
`STAGE_TRANSITIONS`/`QG_CHECKS` (контроль ненарушения `src`). Branch protection `main` новых репо
|
||||
**не включается** (ломала бы PR-merge API merge-актора — ложные HOLD класса ORCH-093).
|
||||
|
||||
## Последствия
|
||||
|
||||
- **+** Новый проект разворачивается одним проходом проверяемо: все слои (Plane-контракты,
|
||||
webhook, промпты, дока, реестр) закрыты скриптом+runbook; тихие деградации ловит `verify`.
|
||||
- **+** Нулевой риск рантайма: изменение docs/templates/scripts/tests-only; регресс
|
||||
enduro/orchestrator невозможен по построению; общая БД не читается и не пишется скриптом.
|
||||
- **+** Единый эталон без форка: новые репо получают живой канон момента онбординга;
|
||||
обновления канона в них едут обычными PR с reviewer-gate.
|
||||
- **−** Регистрация в реестре остаётся операторской (env + управляемый рестарт — Ф-3,
|
||||
сознательное ограничение NFR-2); разрыв «создано, но не зарегистрировано» виден через `verify`.
|
||||
- **−** Закрытый список read-only импортов из `src` (`projects._parse_projects_json`,
|
||||
`plane_sync._PLANE_NAME_TO_KEY`, поля `config.settings`) — связь с приватными именами;
|
||||
поломка при рефакторинге видимая (тесты), расширение списка — только через ADR.
|
||||
- **Ограничение:** способность ≠ исполнение: онбординг конкретного заказчика — операторская
|
||||
эксплуатация (вне ORCH-009); тиражирование на новый хост — ORCH-10 (вне объёма).
|
||||
|
||||
Детально: `docs/work-items/ORCH-009/06-adr/ADR-001-turnkey-onboarding-kit-and-cli.md`
|
||||
(D1…D11 — раскладка, плейсхолдеры, copy-vs-template split, импорт src, группы статусов,
|
||||
webhook-секрет, формат реестра, smoke-контур, языковая политика, branch protection, форма CLI).
|
||||
@@ -0,0 +1,341 @@
|
||||
---
|
||||
work_item: ORCH-009
|
||||
stage: architecture
|
||||
author_agent: architect
|
||||
status: proposed
|
||||
created_at: 2026-06-10
|
||||
model_used: claude-opus-4-8
|
||||
---
|
||||
|
||||
# ADR-001: Turnkey-онбординг проектов — kit `onboarding/` + операторский CLI + runbook
|
||||
|
||||
Work Item: **ORCH-009** — Онбординг проектов в оркестратор (turnkey: Plane + репо + агенты + инфра)
|
||||
Стадия: **architecture**
|
||||
Связь: BRD `01-brd.md`, ТЗ `02-trz.md`, AC `03-acceptance-criteria.md`, тест-план `04-test-plan.yaml`,
|
||||
инфра `07-infra-requirements.md`, риски `10-tech-risks.md`.
|
||||
Сквозная регистрация: **`docs/architecture/adr/adr-0035-turnkey-project-onboarding.md`**
|
||||
(решение кросс-каттинговое: новая способность уровня всего оркестратора — масштабирование на
|
||||
новые проекты, домен D5.2 эпика саморазвития).
|
||||
|
||||
## Статус
|
||||
Proposed
|
||||
|
||||
---
|
||||
|
||||
## Контекст
|
||||
|
||||
Онбординг нового проекта сегодня — ручная археология по `SETUP_WEBHOOKS.md`/`INFRA.md`/памяти;
|
||||
любой пропуск даёт тихую деградацию (BRD §1.2): без промптов в репо конвейер проекта не работает
|
||||
вовсе (Ф-1: launcher резолвит `.openclaw/agents/<role>.md` **относительно worktree репо задачи**);
|
||||
без точных имён статусов ветки `Confirm Deploy`/`STOP` молча не активируются (fail-closed,
|
||||
`src/plane_sync.py:130-165`); без лейблов авто-режимы/багфикс-трек молча выключены (fail-safe,
|
||||
`src/labels.py`/`src/bug_fast_track.py`).
|
||||
|
||||
Ограничения, заданные анализом и проверенные по коду:
|
||||
|
||||
- **NFR-1:** `src/**` не меняется; `STAGE_TRANSITIONS`/`QG_CHECKS`/`check_*`/machine-verdict
|
||||
ключи/схема БД/контракт `projects.py` — байт-в-байт. Задача docs/templates/scripts/tests-only.
|
||||
- **Ф-2:** агент видит только worktree своего репо → каноны обязаны быть **скопированы** в новый
|
||||
репо (ссылка на репо орка агенту недоступна).
|
||||
- **Ф-3:** реестр строится при импорте из `ORCH_PROJECTS_JSON` (`src/projects.py::_load_projects`);
|
||||
регистрация = правка `.env` + **операторский** управляемый рестарт.
|
||||
- **Ф-6:** Plane-webhook — workspace-level, уже существует (в CE создаётся SQL-ом, внешнего API
|
||||
нет); Gitea-webhook — per-repo, через API (`push`/`pull_request`/`status`, HMAC).
|
||||
- **Ф-7:** живой канон — `docs/_templates/` (16 скелетов), `docs/_standards/` (3 стандарта),
|
||||
`.openclaw/agents/*.md` (канон 52d/92).
|
||||
- Эталон онбординга = **сам репозиторий orchestrator** (актуализация Владельца 10.06);
|
||||
enduro-trails эталоном не является.
|
||||
|
||||
ТЗ оставило архитектору 8 открытых вопросов (OQ-1…OQ-8) — все закрываются ниже (D1…D11).
|
||||
|
||||
---
|
||||
|
||||
## Решение
|
||||
|
||||
### Сводка
|
||||
|
||||
Три артефакта + тесты, всё **вне конвейера и вне рантайма**:
|
||||
|
||||
1. **Onboarding-kit** `onboarding/repo-skeleton/` — параметризуемый каркас нового репо
|
||||
(6 промптов канона 52d/92, паспорт `CLAUDE.md`, `AGENTS.md`, `CONTRIBUTING.md`, скелет `docs/`
|
||||
с обязательным `operations/INFRA.md`); словарь плейсхолдеров — `onboarding/placeholders.json`.
|
||||
2. **Операторский CLI** `scripts/onboard_project.py` — `plan` (дефолт, GET-only) / `apply`
|
||||
(идемпотентный ensure) / `verify`; Plane (проект+статусы+лейблы) → Gitea (репо+webhook) →
|
||||
материализация kit (рендер + live-copy канона) + initial push → генерация записи реестра →
|
||||
отчёт `created/skipped(exists)/manual-step`.
|
||||
3. **Runbook** `docs/operations/ONBOARDING.md` — полный чеклист, явные ручные шаги
|
||||
(env + управляемый рестарт; UI-only Plane), верификация (verify + smoke на staging), откат.
|
||||
|
||||
Никакого нового кода в горячих путях; kill-switch не нужен (способность активируется только
|
||||
явным запуском CLI человеком — TRZ §7).
|
||||
|
||||
### D1 — Раскладка: top-level `onboarding/` (OQ-1)
|
||||
|
||||
**Решение: `onboarding/` в корне репо** — ровно как предложено ТЗ:
|
||||
|
||||
```
|
||||
onboarding/
|
||||
README.md ← устройство kit: словарь плейсхолдеров, правило «канон не форкается»,
|
||||
copy-vs-template карта (D3), как запускать тесты kit
|
||||
placeholders.json ← словарь плейсхолдеров (single source of truth, D2)
|
||||
repo-skeleton/ ← дерево зеркалит целевой репо (FR-1)
|
||||
.openclaw/agents/{analyst,architect,developer,reviewer,tester,deployer}.md
|
||||
CLAUDE.md AGENTS.md CONTRIBUTING.md README.md CHANGELOG.md .env.example
|
||||
docs/ARCHITECTURE.md docs/PIPELINE.md docs/PRODUCT_VISION.md
|
||||
docs/operations/INFRA.md
|
||||
docs/architecture/adr/README.md ← стаб реестра сквозных ADR (дир непустая, самоописуема)
|
||||
docs/work-items/.gitkeep docs/history/.gitkeep
|
||||
```
|
||||
|
||||
Отвергнуто:
|
||||
- **`docs/_onboarding/`** — смешивает kit (продукт-артефакт, исходник для ЧУЖИХ репо) с
|
||||
документацией самого орка; шаблоны промптов под `docs/` рядом с живыми `docs/_templates/`
|
||||
провоцируют путаницу «какая копия живая» (прямо риск R-1/R-5 BRD) и ложные срабатывания
|
||||
doc-тулинга.
|
||||
- **`scripts/onboarding/`** — смешивает данные (дерево skeleton) с исполняемым кодом; `scripts/`
|
||||
в этом репо — плоские утилиты (`staging_check.py`, deploy-hook).
|
||||
|
||||
Top-level каталог делает границу физической: **всё под `onboarding/` предназначено новому репо,
|
||||
ничто под `onboarding/` не исполняется рантаймом орка.** Структурные тесты канона гоняются по
|
||||
`onboarding/repo-skeleton/.openclaw/agents/*.md` отдельно от живых промптов орка (TC-03…08 ↔
|
||||
существующий `tests/test_agent_prompts_canon.py` не пересекаются).
|
||||
|
||||
### D2 — Механизм подстановки: `{{NAME}}` + stdlib, без новых зависимостей (OQ-2)
|
||||
|
||||
**Решение: синтаксис `{{PLACEHOLDER_NAME}}`** (верхний регистр, `[A-Z][A-Z0-9_]*`), подстановка —
|
||||
простой проход `str.replace` по словарю; после рендера — обязательный скан
|
||||
`re.compile(r"\{\{[A-Z][A-Z0-9_]*\}\}")` на неразрешённые плейсхолдеры (ошибка в apply/verify,
|
||||
PASS-условие AC-5/TC-09).
|
||||
|
||||
- **`string.Template` отвергнут:** kit-шаблоны (INFRA.md, `.env.example`, промпты) содержат
|
||||
shell-сниппеты с `$VAR`/`${VAR}` — синтаксис `$` коллидирует и потребовал бы экранирования по
|
||||
всему kit (хрупко, нечитабельно).
|
||||
- **Jinja2 отвергнут:** новая pip-зависимость (ТЗ §9 запрещает без обоснования) + условная логика
|
||||
в шаблонах = второй язык программирования в kit → выше риск дрейфа. Kit обязан быть тупым.
|
||||
- Синтаксис `{{…}}` визуально различим, greppable; в Markdown/YAML kit-файлов естественно не
|
||||
встречается, остаточные случаи ловит скан.
|
||||
|
||||
**Словарь — `onboarding/placeholders.json`** (машиночитаемый single source of truth; формат:
|
||||
`{ "NAME": {"description": …, "required": bool, "default": …|null, "example": …} }`):
|
||||
|
||||
| Плейсхолдер | Смысл | Обяз. |
|
||||
|---|---|---|
|
||||
| `{{PROJECT_NAME}}` | человекочитаемое имя проекта | да |
|
||||
| `{{PROJECT_DESCRIPTION}}` | 1–2 фразы «зачем проект» (README/PRODUCT_VISION) | да |
|
||||
| `{{REPO}}` | имя Gitea-репо (== каталог под `/repos`) | да |
|
||||
| `{{GITEA_OWNER}}` | owner/org репо в Gitea | да |
|
||||
| `{{WORK_ITEM_PREFIX}}` | префикс work-item (`ET`/`ORCH`-аналог) | да |
|
||||
| `{{PLANE_PROJECT_ID}}` | uuid Plane-проекта (известен после Plane-шага apply) | да |
|
||||
| `{{STACK}}` | стек проекта (описательно) | да |
|
||||
| `{{TEST_CMD}}` | команда тестов (напр. `pytest -q`) | да |
|
||||
| `{{PROD_PORT}}` / `{{STAGING_PORT}}` | порты прод/staging | да |
|
||||
|
||||
Расширение словаря = правка `placeholders.json` + kit + тестов в одном PR. Тесты держат
|
||||
**биекцию**: каждый плейсхолдер, встречающийся в kit, объявлен в словаре, и каждый объявленный —
|
||||
используется (нет мёртвых/опечаточных).
|
||||
|
||||
### D3 — Copy-vs-template split (OQ-3, BR-2)
|
||||
|
||||
| Класс | Файлы | Механизм |
|
||||
|---|---|---|
|
||||
| **Live-copy канона** (НЕ хранится в kit) | `docs/_templates/**` (16), `docs/_standards/**` (3) | копируются скриптом **verbatim из рабочего чекаута репо орка в момент материализации** |
|
||||
| **Параметризуемые шаблоны** (хранятся в kit) | 6 промптов, `CLAUDE.md`, `AGENTS.md`, `CONTRIBUTING.md`, `README.md`, `CHANGELOG.md`, `docs/ARCHITECTURE.md`, `docs/PIPELINE.md`, `docs/PRODUCT_VISION.md`, `docs/operations/INFRA.md`, `docs/architecture/adr/README.md`, `.env.example` | рендер `{{…}}` (D2) |
|
||||
| **Скелет-каркас** | `docs/work-items/.gitkeep`, `docs/history/.gitkeep` | копия как есть |
|
||||
|
||||
- Канон копируется **байт-в-байт, без переписывания**: ORCH-примеры внутри стандартов
|
||||
(`PIPELINE_DOCS.md` цитирует ORCH-088 и т.п.) остаются примерами — это не «утечка», а
|
||||
иллюстрация (утечкой считается орк-литерал там, где должен быть параметр — AC-5/TC-10:
|
||||
префикс work-item, порты 8500/8501, self-hosting-правила в паспорте/промптах).
|
||||
- Повторный `apply` существующие файлы в целевом репо **не перезаписывает** (идемпотентность
|
||||
BR-9): обновление канона в уже-онбордженных репо едет их обычными PR с reviewer-gate;
|
||||
новые онбординги автоматически получают свежий канон (live-copy, ТЗ §7).
|
||||
- Источник live-copy — чекаут, из которого запущен скрипт; скрипт проверяет наличие обоих
|
||||
каталогов и (в verify) количество скелетов ≥ 16 / стандартов ≥ 3.
|
||||
|
||||
### D4 — Скрипту разрешён read-only импорт `src` — закрытый список (OQ-4)
|
||||
|
||||
**Решение: импортировать, не снапшотить.** Закрытый список импортов:
|
||||
|
||||
| Импорт | Зачем |
|
||||
|---|---|
|
||||
| `src.projects._parse_projects_json`, `src.projects.ProjectConfig` | round-trip валидация генерируемой записи реестра фактическим парсером (AC-6/TC-12) |
|
||||
| `src.plane_sync._PLANE_NAME_TO_KEY` | точные канонические имена 22 статусов байт-в-байт (AC-7/TC-13) |
|
||||
| `src.config.settings` (read-only поля) | имена лейблов `auto_approve_label`/`auto_deploy_label`/`bug_fast_track_label` (дефолты `autoApprove`/`autoDeploy`/`Bug`), URL/токены Plane/Gitea из env |
|
||||
|
||||
- **Почему не снапшот:** дублирование констант = гарантированный дрейф (R-2); AC-6 и так требует
|
||||
фактический парсер; снапшот потребовал бы отдельного «теста синхронизации», который и есть
|
||||
признание дрейфа. Импорт даёт нулевой дрейф **по построению**.
|
||||
- Импорт безопасен: `src.projects` → `src.config` (pydantic-settings с дефолтами, инстанцируется
|
||||
без env); `src.plane_sync` module-level считает только строки из settings; `httpx` — уже
|
||||
зависимость проекта (`requirements.txt`), **новых pip-зависимостей нет**.
|
||||
- Импорт приватных имён (`_parse_projects_json`, `_PLANE_NAME_TO_KEY`) — сознательная,
|
||||
санкционированная ТЗ связь (ТЗ §2 разрешает явно). **Список закрыт:** любой новый импорт из
|
||||
`src` — только через обновление этого ADR. Контроль ненарушения `src` — снапшот-тест TC-21
|
||||
(`STAGE_TRANSITIONS`/`QG_CHECKS`) + AC-12 (diff).
|
||||
- Скрипт запускается из корня чекаута орка (runbook-предусловие); `sys.path`-шим в начале файла
|
||||
(паттерн `scripts/staging_check.py`).
|
||||
|
||||
### D5 — Plane-провижининг: канонические статусы + группы + fail-safe (OQ-5, BR-7)
|
||||
|
||||
**Ensure-семантика:** `GET states` → создать недостающие по точным именам (ключи
|
||||
`_PLANE_NAME_TO_KEY`, 22 имени); существующие (включая CE-дефолтные Backlog/Todo/In Progress/
|
||||
Done/Cancelled нового проекта) — `skipped(exists)` по совпадению имени. Аналогично лейблы:
|
||||
`autoApprove`/`autoDeploy`/`Bug` (имена — из `settings`, D4).
|
||||
|
||||
**Канонические группы статусов** (Plane: `backlog|unstarted|started|completed|cancelled`) —
|
||||
фиксируются этим ADR; код-критичные констрейнты выделены:
|
||||
|
||||
| Статус | Группа | Констрейнт |
|
||||
|---|---|---|
|
||||
| Backlog | `backlog` | |
|
||||
| Todo, To Analyse | `unstarted` | |
|
||||
| In Progress, Analysis, Architecture, Development, Code-Review, Review, Testing, Awaiting Deploy, Deploying, Monitoring after Deploy, Needs Input, In Review, Blocked, Approved, Confirm Deploy | `started` | **рабочие/гейтовые статусы НЕ в терминальных группах** — иначе terminal-detection ORCH-068 (`{uuid→group}`, группы `completed`/`cancelled` = терминал) ложно сочтёт живую задачу терминальной |
|
||||
| Rejected | `started` | reject = rework-петля в анализ, задача жива → НЕ `cancelled` |
|
||||
| Done | `completed` | терминал |
|
||||
| Cancelled | `cancelled` | терминал |
|
||||
| **STOP** | **`cancelled`** | **требование ORCH-090** (fail-closed: без статуса/группы ветка cancel не активируется) |
|
||||
|
||||
**Fail-safe (CE-пробелы):** код орка использует только GET states — доступность POST
|
||||
project/states/labels в Plane CE не гарантирована. Любой недоступный вызов (403/404/405/501/
|
||||
нереализовано) → шаг помечается **`manual-step`** со ссылкой на соответствующий раздел runbook
|
||||
(точное имя статуса + группа для ручного создания в UI), скрипт не падает (AC-7/TC-14).
|
||||
Заведомо ручные шаги: порядок статусов на доске (drag-and-drop, UI-only), workspace-webhook
|
||||
(существует, Ф-6 — verify печатает команду проверки, не создаёт).
|
||||
|
||||
### D6 — Gitea-провижининг: репо + webhook + initial push только в пустой репо (BR-9)
|
||||
|
||||
- **Репо:** `POST /api/v1/...` под `{{GITEA_OWNER}}`, `auto_init=false` (репо рождается пустым;
|
||||
`main` создаёт initial push). Существует → `skipped(exists)`.
|
||||
- **Webhook (per-repo):** events `push`/`pull_request`/`status`, `content_type: json`,
|
||||
`branch_filter: "*"`, URL = внешний URL орка `/webhook/gitea` (формат `SETUP_WEBHOOKS.md`).
|
||||
**Секрет: приёмник `src/webhooks/gitea.py` валидирует ОДИН глобальный
|
||||
`ORCH_GITEA_WEBHOOK_SECRET` на все репо** → скрипт **переиспользует** существующий секрет из
|
||||
env (никогда не генерит новый при наличии — новый сломал бы HMAC всех вебхуков); секрет
|
||||
отсутствует в env → сгенерить `secrets.token_hex(20)` + вывести оператору для `.env`
|
||||
(первичная настройка). В логах/отчёте секрет всегда маскируется (NFR-3).
|
||||
- **Initial push:** материализованный kit коммитится (`feat: onboarding skeleton (ORCH-009 kit)`)
|
||||
и пушится в `main` **только если репо свежесоздан/пуст** (Gitea `empty: true`); непустой репо →
|
||||
`manual-step` (kit-файлы НИКОГДА не пушатся поверх существующего контента). Это единственный
|
||||
разрешённый push: новый пустой репо до регистрации в реестре не является участником конвейера →
|
||||
**INV-4 (мерж только через PR-merge API) не затрагивается** (ТЗ §9).
|
||||
|
||||
### D7 — Запись реестра: полный merged-массив, скрипт `.env` не трогает (BR-8)
|
||||
|
||||
**Решение: скрипт выводит (а) standalone-запись нового проекта и (б) полный merged-массив
|
||||
`ORCH_PROJECTS_JSON`** = существующие записи verbatim + новая в конец. Источник существующих:
|
||||
текущий env / `--env-file` (дефолт — `.env` в корне чекаута, если есть); источника нет → только
|
||||
standalone-запись + инструкция. Перед выводом merged-массив прогоняется через
|
||||
`projects._parse_projects_json` (round-trip: поля новой записи совпадают, существующие не
|
||||
потеряны/не искажены — AC-6/TC-12).
|
||||
|
||||
- **Почему full-array, а не диф:** оператор вставляет одну строку в `.env` атомарно — ручное
|
||||
слияние JSON в env-строке (экранирование, запятые) и есть источник ошибок R-4.
|
||||
- Скрипт **не правит** `.env` прода и **не рестартит** контейнер (NFR-2): печатает строку +
|
||||
инструкцию «добавь в `.env` → управляемый рестарт оркестратора (self-hosting: групповое окно,
|
||||
выполнять осознанно)» со ссылкой на runbook. `verify` после рестарта показывает разрыв
|
||||
«создано, но не зарегистрировано» (R-4).
|
||||
|
||||
### D8 — Песочница для smoke: staging-контур 8501 + одноразовый SMK-проект (OQ-6, AC-13)
|
||||
|
||||
**Решение: smoke выполняется на staging-контуре** (`orchestrator-staging`, 8501, изолированная БД
|
||||
`./data/staging`) с **одноразовым** sandbox: Plane-проект `onboarding-smoke` (префикс `SMK`) +
|
||||
Gitea-репо `onboarding-smoke`, онбордженные самим скриптом. Регистрация — в `ORCH_PROJECTS_JSON`
|
||||
**staging-окружения** (`.env.staging`) + рестарт staging (свободен, в отличие от прод-инварианта).
|
||||
Прогон: тестовая задача SMK → стадия `analysis` → проверить следы чтения паспорта/`AGENTS.md` и
|
||||
артефакты `docs/work-items/SMK-…/` по канону `PIPELINE_DOCS.md`.
|
||||
|
||||
- **Прод-контур отвергнут:** smoke-задача писала бы конвейерные строки в общую прод-БД и жила бы
|
||||
в общей очереди с enduro/ORCH — шум и риск в общем инстансе (дух NFR-2).
|
||||
- Протокол прогона — раздел **«Журнал smoke-прогонов»** в `ONBOARDING.md` (дата, параметры,
|
||||
PASS/FAIL по чек-листу AC-13); для приёмки ORCH-009 первый протокол обязателен, ссылка на него —
|
||||
из `13-test-report.md` задачи. Судьба sandbox-артефактов: архив/удаление вручную по разделу
|
||||
«Откат» runbook (скрипт не удаляет ничего — BR-9).
|
||||
|
||||
### D9 — Языковая политика kit-промптов: канон орка (OQ-7, AC-4)
|
||||
|
||||
**Решение: 5 ru + deployer en** — ровно языковая раскладка канона орка, нормативная по
|
||||
ADR-001 D2 ORCH-092 (deployer — самый safety-critical промпт, en-раскладка минимизирует
|
||||
регресс-поверхность байт-точных verdict-ключей/команд). Kit наследует канон без отступлений;
|
||||
per-project отступление возможно позже **только** решением в собственном ADR нового проекта
|
||||
(правило фиксируется в `onboarding/README.md` и шаблоне `CONTRIBUTING.md`). Проверяется TC-08.
|
||||
|
||||
### D10 — Branch protection `main` нового репо: НЕ включать (OQ-8)
|
||||
|
||||
**Решение: не включать.** Merge-актор конвейера — Gitea PR-merge API под токеном орка
|
||||
(INV-4; `src/merge_gate.py`, ORCH-093): required-approvals/required-status-checks дали бы
|
||||
405/409-класс отказов `merge_pr` → ложные HOLD (ровно класс инцидента ORCH-063). Сам орк живёт
|
||||
без protection — защита `main` держится конвенцией (агенты не пушат `main`; мерж только через
|
||||
PR API) и скоупом токенов. Решение фиксируется в runbook; пересмотр — при мультитенант-hardening
|
||||
(D5.6, вне объёма).
|
||||
|
||||
### D11 — Форма CLI и тестируемость без сети (BR-11, NFR-5)
|
||||
|
||||
**Один файл `scripts/onboard_project.py`** (операторская UX: один очевидный энтрипойнт; паттерн
|
||||
`scripts/staging_check.py`), внутри — слои:
|
||||
|
||||
- **Чистое ядро:** `build_plan(params, observed) -> Plan` — без I/O; `Plan` = упорядоченный список
|
||||
шагов закрытого списка BR-1: `plane.project → plane.states(22) → plane.labels(3) → gitea.repo →
|
||||
gitea.webhook → kit.materialize+push → registry.emit`. Рендер kit — чистая функция
|
||||
`render(text, params)` (D2), в plan-режиме выполняется **in-memory** (ни одной записи на диск —
|
||||
AC-8/TC-16); материализация на диск (temp-dir → git init/commit/push) — только в `apply`.
|
||||
- **Тонкие клиенты** `PlaneClient`/`GiteaClient` (httpx; единственные точки сети) — инжектируются
|
||||
→ в тестах мокаются целиком (NFR-5: ноль сетевых вызовов, TC-13…18).
|
||||
- **Режимы:** `plan` (дефолт) — только GET-пробы текущего состояния + полный план без единой
|
||||
мутации; `apply` — ensure-исполнение (идемпотентно, без delete-операций вовсе); `verify` —
|
||||
GET-пробы + локальные проверки (registry round-trip, резолв всех логических ключей включая
|
||||
`confirm_deploy`/`stop`, лейблы, webhook активен, kit-файлы в репо, скан неразрешённых
|
||||
плейсхолдеров).
|
||||
- **Отчёт:** человекочитаемый + `--json`; статус каждого шага
|
||||
`created | skipped(exists) | manual-step | planned | error`; exit-коды: `0` — чисто, `2` — есть
|
||||
`manual-step`/gap в verify, `1` — ошибка. Каждый шаг логируется (BR-11).
|
||||
|
||||
---
|
||||
|
||||
## Альтернативы (сводно)
|
||||
|
||||
- **`docs/_onboarding/` / `scripts/onboarding/`** — отвергнуто (D1): смешение kit с живой докой
|
||||
орка / данных с кодом.
|
||||
- **Jinja2 / `string.Template`** — отвергнуто (D2): новая зависимость и логика в шаблонах /
|
||||
коллизия `$` с shell-сниппетами.
|
||||
- **Снапшот констант `src` + тест синхронизации** — отвергнуто (D4): узаконенный дрейф; импорт
|
||||
даёт нулевой дрейф по построению.
|
||||
- **Генерация нового webhook-секрета per-repo** — отвергнуто (D6): приёмник валидирует один
|
||||
глобальный секрет; новый сломал бы HMAC существующих вебхуков.
|
||||
- **Диф-вывод реестра** — отвергнуто (D7): ручное слияние JSON-в-env — источник ошибок R-4.
|
||||
- **Smoke на прод-контуре** — отвергнуто (D8): запись в общую прод-БД/очередь.
|
||||
- **Branch protection `main`** — отвергнуто (D10): ломает PR-merge API актора (ложные HOLD).
|
||||
|
||||
## Последствия
|
||||
|
||||
- **+** Turnkey-способность D5.2: один проход + runbook вместо археологии; тихие деградации
|
||||
(статусы/лейблы/промпты) закрываются проверяемо (`verify` + структурные тесты).
|
||||
- **+** Нулевой риск рантайма: `src/**` байт-в-байт, нового кода в горячих путях нет, kill-switch
|
||||
не нужен; регресс enduro/orchestrator невозможен по построению.
|
||||
- **+** Анти-дрейф структурный: live-copy канона (BR-2) + единые канон-тесты kit (NFR-4) +
|
||||
биекция словаря плейсхолдеров.
|
||||
- **−** Операторские шаги остаются ручными (env + управляемый рестарт; UI-only Plane): осознанное
|
||||
ограничение NFR-2 (никакой автоматики рестартов) — митигировано runbook + verify (видимый разрыв).
|
||||
- **−** Импорт приватных имён `src` связывает скрипт с внутренними идентификаторами — митигировано
|
||||
закрытым списком (D4) и тем, что рефакторинг имён мгновенно валит импорт в тестах (видимая,
|
||||
не тихая поломка).
|
||||
- **−** Kit-шаблоны промптов требуют сопровождения при эволюции канона — митигировано общими
|
||||
структурными требованиями тестов (расхождение ловит CI, NFR-4).
|
||||
- **Откат:** удалить `onboarding/`, `scripts/onboard_project.py`, `docs/operations/ONBOARDING.md`,
|
||||
тесты — репо в исходном состоянии (ТЗ §7); внешние сущности (sandbox/созданные проекты) —
|
||||
вручную по разделу «Откат» runbook.
|
||||
|
||||
## Ссылки
|
||||
|
||||
- BRD: `docs/work-items/ORCH-009/01-brd.md` · TRZ: `02-trz.md` · AC: `03-acceptance-criteria.md`
|
||||
· Test plan: `04-test-plan.yaml`
|
||||
- Сверено по коду: `src/projects.py` (`ProjectConfig`, `_parse_projects_json`, `_load_projects`),
|
||||
`src/plane_sync.py:94-165` (`_DEFAULT_STATES`, `_PLANE_NAME_TO_KEY` — 22 имени, fail-closed
|
||||
`Confirm Deploy`/`STOP`), `src/qg/checks.py::check_architecture_done`, `src/config.py`
|
||||
(`auto_*_label`/`bug_fast_track_label`), `requirements.txt` (httpx уже есть)
|
||||
- Операции: `docs/operations/SETUP_WEBHOOKS.md` (формат Gitea-webhook; Plane workspace-webhook —
|
||||
SQL-only), `docs/operations/INFRA.md`
|
||||
- Стандарты: `docs/_standards/PIPELINE_DOCS.md` (§4 ADR-naming), `HANDOFF_PROTOCOL.md`,
|
||||
`TRACEABILITY.md`
|
||||
- ADR: adr-0001 (registry), adr-0017/0018 (паттерны условности), adr-0021/0022 (канон промптов/
|
||||
трассировка), adr-0026 (STOP, группа `cancelled`), ORCH-092 `ADR-001` D2 (язык deployer),
|
||||
сквозной **adr-0035-turnkey-project-onboarding**
|
||||
66
docs/work-items/ORCH-009/07-infra-requirements.md
Normal file
66
docs/work-items/ORCH-009/07-infra-requirements.md
Normal file
@@ -0,0 +1,66 @@
|
||||
---
|
||||
work_item: ORCH-009
|
||||
stage: architecture
|
||||
author_agent: architect
|
||||
status: proposed
|
||||
created_at: 2026-06-10
|
||||
model_used: claude-opus-4-8
|
||||
---
|
||||
|
||||
# 07 — Инфра-требования: ORCH-009 — Turnkey-онбординг проектов
|
||||
|
||||
Work Item: **ORCH-009** · Repo: **orchestrator** · Стадия: architecture
|
||||
|
||||
> Топология оркестратора **не меняется** (NFR-1/NFR-2: `src/**` и compose не трогаются).
|
||||
> Файл фиксирует **предусловия исполнения способности** (токены/доступы/контуры) и инфра-границы
|
||||
> операторского скрипта. Детали решений — `06-adr/ADR-001-turnkey-onboarding-kit-and-cli.md`.
|
||||
|
||||
## I-1. Топология / окружения
|
||||
|
||||
- **Прод (`orchestrator`, 8500):** не затрагивается. Скрипт не создаёт/не останавливает/не
|
||||
рестартит контейнеры; в общую БД не пишет (читает только файлы чекаута и внешние API).
|
||||
- **Staging (`orchestrator-staging`, 8501, БД `./data/staging`):** контур smoke-прогона (ADR D8).
|
||||
Регистрация sandbox-проекта — в `.env.staging`; рестарт staging — штатный, свободный
|
||||
(прод-инвариант на него не распространяется).
|
||||
- **Новые внешние сущности** (создаются скриптом в `apply`): Plane-проект, Gitea-репо +
|
||||
per-repo webhook. Аддитивно: существующие проекты/репо не модифицируются (BR-9).
|
||||
- **Запуск скрипта:** хост mva154, из корня чекаута репо orchestrator. Среда исполнения —
|
||||
venv с `requirements.txt` (httpx уже в зависимостях; новых pip-зависимостей нет) **или**
|
||||
`docker compose exec orchestrator python scripts/onboard_project.py …` (read-only к рантайму,
|
||||
без рестартов). Канонический способ фиксирует runbook `docs/operations/ONBOARDING.md`.
|
||||
|
||||
## I-2. Переменные окружения / секреты
|
||||
|
||||
**Новых env-переменных не вводится.** Используются существующие (предусловия запуска):
|
||||
|
||||
| Переменная | Роль в онбординге |
|
||||
|---|---|
|
||||
| `ORCH_PLANE_API_TOKEN` (+ `ORCH_PLANE_API_URL`, `ORCH_PLANE_WORKSPACE_SLUG`) | создание/чтение Plane-проекта, статусов, лейблов; токен с правом создания проектов в workspace |
|
||||
| `ORCH_GITEA_TOKEN` (+ Gitea base URL) | создание репо (под `{{GITEA_OWNER}}`), per-repo webhook; токен с правом create-repo + hooks |
|
||||
| `ORCH_GITEA_WEBHOOK_SECRET` | **переиспользуется** для webhook нового репо (приёмник валидирует один глобальный секрет, ADR D6); отсутствует → скрипт генерит и печатает оператору для `.env` |
|
||||
| `ORCH_PROJECTS_JSON` | источник существующих записей для merged-вывода (ADR D7); **применение новой строки — операторский шаг** |
|
||||
|
||||
- Секреты — только в `.env`/`.env.staging` на хосте, в гит не попадают (правило #8 CLAUDE.md);
|
||||
в логах/отчётах скрипта секреты маскируются (NFR-3).
|
||||
- Kit несёт собственный `.env.example` нового проекта (дескрипторы без значений) — канон секретов
|
||||
транслируется в онбордируемые репо.
|
||||
|
||||
## I-3. Деплой / рестарт
|
||||
|
||||
- **Скрипт НИКОГДА не рестартит/не останавливает прод-контейнер** (NFR-2, self-hosting инвариант).
|
||||
- Регистрация проекта в реестре (Ф-3): правка `.env` (строка `ORCH_PROJECTS_JSON` из отчёта
|
||||
скрипта) + **управляемый операторский рестарт** оркестратора — групповое окно для ВСЕХ проектов
|
||||
общего инстанса; runbook помечает шаг self-hosting-предупреждением и командой проверки
|
||||
(`GET /queue`, резолв статусов нового проекта).
|
||||
- TTL-self-heal статусов Plane (ORCH-068, 300с) рестарта не требует: статусы/лейблы, созданные
|
||||
после регистрации, подхватываются без вмешательства.
|
||||
- Деплой самой задачи ORCH-009 — штатный конвейер: изменение docs/scripts/tests-only, образ
|
||||
пересобирается стандартно, staging-гейт (8501) обязателен как обычно.
|
||||
|
||||
## I-4. CI/CD
|
||||
|
||||
- `.gitea/workflows/` — **без изменений**: новые тесты (`tests/test_onboarding_kit.py`,
|
||||
`test_onboarding_script.py`, `test_onboarding_invariants.py`) подхватываются существующим
|
||||
pytest-шагом; все детерминированы, без сети (NFR-5).
|
||||
- Инфра-предусловий в образе нет: скрипт — операторский CLI вне рантайма, в образ ничего
|
||||
дополнительно не запекается.
|
||||
42
docs/work-items/ORCH-009/10-tech-risks.md
Normal file
42
docs/work-items/ORCH-009/10-tech-risks.md
Normal file
@@ -0,0 +1,42 @@
|
||||
---
|
||||
work_item: ORCH-009
|
||||
stage: architecture
|
||||
author_agent: architect
|
||||
status: proposed
|
||||
created_at: 2026-06-10
|
||||
model_used: claude-opus-4-8
|
||||
---
|
||||
|
||||
# 10 — Технические риски: ORCH-009 — Turnkey-онбординг проектов
|
||||
|
||||
Work Item: **ORCH-009** · Repo: **orchestrator** · Стадия: architecture
|
||||
|
||||
> Информационный (гейтом не парсится). Детализирует риски BRD §8 (R-1…R-5) до уровня решений
|
||||
> `06-adr/ADR-001`; митигейшены привязаны к D-решениям и TC тест-плана.
|
||||
|
||||
## Реестр рисков
|
||||
|
||||
| ID | Риск | Вер. | Влия. | Митигейшн |
|
||||
|----|------|------|-------|-----------|
|
||||
| TR-1 | **Drift канона** (R-1): копия `_templates`/`_standards` в новых репо разъезжается с живым каноном орка; kit-промпты отстают от эволюции канона 52d | Сред. | Сред. | BR-2/D3: live-copy в момент онбординга, второй редактируемой копии канона нет; NFR-4: структурные канон-тесты kit (TC-03…08) ловят расхождение в CI; обновление онбордженных репо — их обычные PR |
|
||||
| TR-2 | **Тихая деградация Plane-контрактов** (R-2): опечатка в имени статуса/лейбла или неверная **группа** → fail-closed/fail-safe ветки (`Confirm Deploy`, `STOP`, авто-лейблы, `Bug`) молча не работают; рабочий статус в группе `completed`/`cancelled` → terminal-detection ORCH-068 ложно терминалит живую задачу | Сред. | Выс. | D4: имена импортируются из `_PLANE_NAME_TO_KEY` (нулевой дрейф по построению, TC-13); D5: канонические группы зафиксированы таблицей ADR с код-критичными констрейнтами (STOP→`cancelled`, терминальные группы только Done/Cancelled/STOP); `verify` резолвит ВСЕ логические ключи включая `confirm_deploy`/`stop` |
|
||||
| TR-3 | **Скрипт с боевыми токенами** (R-3): ошибка = разрушительное действие на общих Plane/Gitea | Низ. | Выс. | BR-9/D11: `plan` (GET-only) — дефолт; delete-операций в коде нет вовсе (TC-18); аддитивный ensure (TC-17); push только в свежесозданный пустой репо (`empty: true`, D6); существующие сущности не модифицируются |
|
||||
| TR-4 | **Разрыв «создано, но не зарегистрировано»** (R-4): оператор не применил env+рестарт → проект невидим для орка | Сред. | Сред. | D7: merged-массив одной строкой (без ручного слияния JSON); runbook: явный операторский шаг с self-hosting-предупреждением + команда проверки; `verify` показывает разрыв (TC-12, AC-11) |
|
||||
| TR-5 | **Утечка орк-специфики в kit** (R-5): новый репо получает ORCH-префикс, порты 8500/8501, self-hosting-правила орка | Сред. | Сред. | D2: скан неразрешённых плейсхолдеров после рендера; TC-10: явный тест на утечки; биекция словаря `placeholders.json` ↔ kit (мёртвые/опечаточные плейсхолдеры не живут) |
|
||||
| TR-6 | **Поломка HMAC существующих вебхуков**: генерация нового per-repo секрета при едином глобальном `ORCH_GITEA_WEBHOOK_SECRET` приёмника | Низ. | Выс. | D6: секрет **переиспользуется** из env (новый генерится только при полном отсутствии — первичная настройка); секрет маскируется в логах/отчёте (NFR-3) |
|
||||
| TR-7 | **Связь скрипта с приватными именами `src`** (`_parse_projects_json`, `_PLANE_NAME_TO_KEY`): рефакторинг src валит скрипт | Низ. | Низ. | D4: закрытый список импортов (расширение — только через ADR); поломка видимая, не тихая — импорт падает в тестах (TC-12/13) на том же PR, что рефакторит src; снапшот TC-21 гардит сам src |
|
||||
| TR-8 | **Plane CE API-пробелы** (OQ-5): POST project/states/labels недоступен в CE → провижининг неполон | Сред. | Низ. | D5: fail-safe деградация в `manual-step` со ссылкой на runbook (имя+группа для UI-создания), не падение (TC-14); `verify` подтверждает итоговую полноту независимо от способа создания |
|
||||
| TR-9 | **Smoke загрязняет общий контур**: прогон способности в проде = строки в общей БД/очереди | Низ. | Сред. | D8: smoke только на staging (8501, изолированная БД, `.env.staging`); sandbox-сущности одноразовые, снос вручную по разделу «Откат» runbook |
|
||||
|
||||
## Сводный вывод
|
||||
|
||||
Доминирующий класс — **операционные риски исполнения способности** (TR-2/TR-3/TR-4): они
|
||||
митигированы структурно (импорт констант вместо копий, GET-only дефолт, отсутствие delete-операций,
|
||||
verify-режим), а не дисциплиной. Рисков для прод-конвейера самой задачи **нет по построению**:
|
||||
`src/**` байт-в-байт (AC-12/TC-21), нового кода в горячих путях нет, kill-switch не требуется —
|
||||
способность активируется только явным запуском операторского CLI.
|
||||
|
||||
Эскалация `arch:major-change` **не требуется**: ни новой стадии, ни нового рантайм-компонента,
|
||||
ни изменения БД — это docs/templates/scripts/tests-only способность (новая стадия/компонент
|
||||
конвейера не вводится). Возврат в анализ не требуется: ТЗ выполнимо без нарушения принципов.
|
||||
Остаточный риск для прод-конвейера (self-hosting): **низкий**.
|
||||
Reference in New Issue
Block a user