docs(standards): pipeline docs standard — manifest + templates + ADR-naming
Создан golden source структуры номерных документов work item (ORCH-52b, слой 1 эпика ORCH-52). Docs-only: STAGE_TRANSITIONS / QG_CHECKS / check_* / схема БД не трогаются (AC-6). - docs/_standards/PIPELINE_DOCS.md — манифест «стадия→агент→документ→категория→ гейт→frontmatter machine-key» (сверен с src/stages.py и src/qg/checks.py) + раздел ADR-naming. Манифест документирует поведение гейтов, источник истины остаётся код (ADR-001 §D2); честно различает machine-verdict (12/13/14/15/17) и информационные (00/08/10/16) доки; под-гейты ребра deploy-staging→deploy отмечены как врезки в advance_stage. - docs/_templates/* — 15 копируемых скелетов; машинные доки несут точный frontmatter-ключ из _parse_* (verdict/result/deploy_status/staging_status/ security_status/post_deploy_status). - Точки-ссылки: CLAUDE.md, docs/architecture/README.md; запись CHANGELOG. - tests/test_orch_52b_docs_standard.py — TC-01..TC-20 структурные проверки; полный pytest tests/ зелёный (1177 passed). Refs: ORCH-075 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,10 @@
|
|||||||
Формат: [Keep a Changelog](https://keepachangelog.com/). Записи — на смысловой PR/задачу.
|
Формат: [Keep a Changelog](https://keepachangelog.com/). Записи — на смысловой PR/задачу.
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
- **Стандарт документов конвейера: `docs/_standards/PIPELINE_DOCS.md` + `docs/_templates/` + ADR-naming** (ORCH-075 / ORCH-52b, `docs`): зафиксирован golden source структуры номерных документов work item (`00-business-request.md` … `17-security-report.md`). **Docs-only**, нулевой рантайм-риск: `STAGE_TRANSITIONS` / `QG_CHECKS` / `check_*` / `src/stage_engine.py` / схема БД — **не трогаются** (изменения только под `docs/**` + `CLAUDE.md`).
|
||||||
|
- **Манифест** `docs/_standards/PIPELINE_DOCS.md` — карта «стадия → агент → документ → категория (`required`/`when-applicable`/`optional`) → гейт/механизм → frontmatter machine-key», сверенная с `src/stages.py` (`STAGE_TRANSITIONS`) и `src/qg/checks.py` (`_parse_*`). Манифест **документирует** поведение гейтов, но НЕ источник истины (источник — код, ADR-001 §D2); честно различает machine-verdict доки (`12`→`verdict:`, `13`→`result:`, `14`→`deploy_status:`, `15`→`staging_status:`, `17`→`security_status:`) и информационные (`00/08/10/16` — гейтом не парсятся). Под-гейты ребра `deploy-staging→deploy` (security/merge/image-freshness) помечены как врезки в `advance_stage`, а не строки `STAGE_TRANSITIONS`.
|
||||||
|
- **Шаблоны** `docs/_templates/*` (15 копируемых скелетов) — для каждого `required`/`when-applicable` дока; машинные доки несут точный frontmatter-ключ из ground-truth (`_parse_*`), чтобы скопированный скелет проходил гейт без угадывания. Служебные каталоги `docs/_standards/` / `docs/_templates/` лежат ВНЕ `docs/work-items/<plane-id>/` → невидимы гейтам наличия файлов (`check_architecture_done`/`check_analysis_complete`).
|
||||||
|
- **ADR-naming** зафиксирован: `docs/work-items/<plane-id>/06-adr/ADR-NNN-<kebab-slug>.md` (NNN с `001`); сквозные решения дублируются в `docs/architecture/adr/adr-NNNN-<slug>.md` (4-значная нумерация). Точки-ссылки: `CLAUDE.md` (раздел «Артефакты задачи» + правило 2), `docs/architecture/README.md` (раздел «Стандарт документов конвейера»). Тесты: `tests/test_orch_52b_docs_standard.py` (TC-01…TC-20, структурные проверки наличия/секций/frontmatter). ADR: `docs/work-items/ORCH-075/06-adr/ADR-001-pipeline-docs-standard.md`, сквозной `docs/architecture/adr/adr-0019-pipeline-docs-standard.md`.
|
||||||
- **Авто-режим по лейблам: autoApprove (авто-BRD) + autoDeploy (авто-деплой)** (ORCH-089, `feat`): сняты **два** человеческих гейта конвейера, тормозящих пакетный автономный прогон (эпик ORCH-088) — гейт BRD (`analysis`: ручной `Approved`) и гейт прод-деплоя (`deploy` Phase A: ручной `Confirm Deploy`, ORCH-059). Решение выборочно (лейбл Plane на задаче), декларативно, обратимо и **не трогает ни одной технической проверки**. Аддитивно по образцу условных под-гейтов (ORCH-035/043/058/088): leaf `src/labels.py` (never-raise) + две точечные врезки + флаги; `STAGE_TRANSITIONS`/`QG_CHECKS`/`check_*`/схема БД — **без изменений**.
|
- **Авто-режим по лейблам: autoApprove (авто-BRD) + autoDeploy (авто-деплой)** (ORCH-089, `feat`): сняты **два** человеческих гейта конвейера, тормозящих пакетный автономный прогон (эпик ORCH-088) — гейт BRD (`analysis`: ручной `Approved`) и гейт прод-деплоя (`deploy` Phase A: ручной `Confirm Deploy`, ORCH-059). Решение выборочно (лейбл Plane на задаче), декларативно, обратимо и **не трогает ни одной технической проверки**. Аддитивно по образцу условных под-гейтов (ORCH-035/043/058/088): leaf `src/labels.py` (never-raise) + две точечные врезки + флаги; `STAGE_TRANSITIONS`/`QG_CHECKS`/`check_*`/схема БД — **без изменений**.
|
||||||
- **`autoApprove`** → врезка в `stage_engine._handle_analysis_approved_flow` (ветка `files_ok`) ПОСЛЕ `In Review`+коммента: `set_issue_approved` (индикация) + лог/Telegram/Plane-коммент + `advance_stage(..., finished_agent=None)` — **тот же путь, что человеческий Approved** (`approved-via-status` → `analysis → architecture` + `mark_brd_review_ended`). Без дублирования переходной логики; re-entrancy безопасна (вложенный вызов идёт с `finished_agent=None`, не входит в analyst-ветку).
|
- **`autoApprove`** → врезка в `stage_engine._handle_analysis_approved_flow` (ветка `files_ok`) ПОСЛЕ `In Review`+коммента: `set_issue_approved` (индикация) + лог/Telegram/Plane-коммент + `advance_stage(..., finished_agent=None)` — **тот же путь, что человеческий Approved** (`approved-via-status` → `analysis → architecture` + `mark_brd_review_ended`). Без дублирования переходной логики; re-entrancy безопасна (вложенный вызов идёт с `finished_agent=None`, не входит в analyst-ветку).
|
||||||
- **`autoDeploy`** → врезка в `stage_engine._handle_self_deploy_phase_a` сразу после advance на `deploy`+`clear_state` (ДО «ask-human»): лог/Telegram/Plane-коммент + `_handle_self_deploy_phase_b(...)` (idempotency-маркер `INITIATED`, статус `Deploying`, finalizer). Пропускаются лишь индикативно-человеческие шаги (`APPROVE_REQUESTED`+`Awaiting Deploy`+«смените на Confirm Deploy»). **BR-5 структурно:** Phase A достигается только после зелёных под-гейтов ребра `deploy-staging → deploy` (security → merge-gate → image-freshness → staging) → autoDeploy физически не деплоит сломанное.
|
- **`autoDeploy`** → врезка в `stage_engine._handle_self_deploy_phase_a` сразу после advance на `deploy`+`clear_state` (ДО «ask-human»): лог/Telegram/Plane-коммент + `_handle_self_deploy_phase_b(...)` (idempotency-маркер `INITIATED`, статус `Deploying`, finalizer). Пропускаются лишь индикативно-человеческие шаги (`APPROVE_REQUESTED`+`Awaiting Deploy`+«смените на Confirm Deploy»). **BR-5 структурно:** Phase A достигается только после зелёных под-гейтов ребра `deploy-staging → deploy` (security → merge-gate → image-freshness → staging) → autoDeploy физически не деплоит сломанное.
|
||||||
|
|||||||
@@ -122,9 +122,11 @@ created → analysis → architecture → development → review → testing →
|
|||||||
## Артефакты задачи (`docs/work-items/<plane-id>/`)
|
## Артефакты задачи (`docs/work-items/<plane-id>/`)
|
||||||
`00-business-request.md`, `01-brd.md`, `02-trz.md`, `03-acceptance-criteria.md`, `04-test-plan.yaml`, `06-adr/ADR-NNN-slug.md`, `07-infra-requirements.md`, `08-data-requirements.md`, `10-tech-risks.md`, `12-review.md`, `13-test-report.md`, `14-deploy-log.md`, `15-staging-log.md`, `16-post-deploy-log.md` (post-deploy наблюдение, ORCH-021), `17-security-report.md` (security-гейт: `security_status:`/secrets/deps, ORCH-022).
|
`00-business-request.md`, `01-brd.md`, `02-trz.md`, `03-acceptance-criteria.md`, `04-test-plan.yaml`, `06-adr/ADR-NNN-slug.md`, `07-infra-requirements.md`, `08-data-requirements.md`, `10-tech-risks.md`, `12-review.md`, `13-test-report.md`, `14-deploy-log.md`, `15-staging-log.md`, `16-post-deploy-log.md` (post-deploy наблюдение, ORCH-021), `17-security-report.md` (security-гейт: `security_status:`/secrets/deps, ORCH-022).
|
||||||
|
|
||||||
|
**Стандарт документов (ORCH-075, ORCH-52b):** структура каждого дока, карта «стадия→агент→документ→гейт→machine-key» и конвенция ADR-naming зафиксированы в `docs/_standards/PIPELINE_DOCS.md` (golden source); копируемые скелеты — в `docs/_templates/`. Перед написанием номерного дока бери скелет из `docs/_templates/` и не меняй имя machine-key frontmatter (регистр чувствителен — иначе гейт упадёт ложно).
|
||||||
|
|
||||||
## Правила для агентов
|
## Правила для агентов
|
||||||
1. Перед любым действием прочесть этот файл и `docs/architecture/README.md`.
|
1. Перед любым действием прочесть этот файл и `docs/architecture/README.md`.
|
||||||
2. **Документация = golden source наравне с кодом.** Изменил функционал → обнови доку В ТОМ ЖЕ PR. Архитектурное решение → заведи ADR. Обнови `CHANGELOG.md`.
|
2. **Документация = golden source наравне с кодом.** Изменил функционал → обнови доку В ТОМ ЖЕ PR. Архитектурное решение → заведи ADR (формат — `docs/_standards/PIPELINE_DOCS.md` §4). Структура номерных доков и шаблоны — `docs/_standards/PIPELINE_DOCS.md` + `docs/_templates/`. Обнови `CHANGELOG.md`.
|
||||||
3. Никогда не править артефакты других этапов.
|
3. Никогда не править артефакты других этапов.
|
||||||
4. Никогда не комментировать ТЗ задним числом — если ТЗ не годится, возвращай в Анализ.
|
4. Никогда не комментировать ТЗ задним числом — если ТЗ не годится, возвращай в Анализ.
|
||||||
5. Никогда не закрывать задачу самостоятельно — это делает CI / финальная стадия.
|
5. Никогда не закрывать задачу самостоятельно — это делает CI / финальная стадия.
|
||||||
|
|||||||
138
docs/_standards/PIPELINE_DOCS.md
Normal file
138
docs/_standards/PIPELINE_DOCS.md
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
# PIPELINE_DOCS — стандарт документов конвейера (golden source структуры)
|
||||||
|
|
||||||
|
> **Назначение.** Единая карта «стадия → агент → документ → категория → гейт/механизм →
|
||||||
|
> frontmatter machine-key» + конвенция ADR-naming. Это **golden source структуры** номерных
|
||||||
|
> документов work item (`00-business-request.md` … `17-security-report.md`), который каждая
|
||||||
|
> агентская роль пишет на своей стадии.
|
||||||
|
>
|
||||||
|
> **Статус истины (важно).** Манифест **документирует** текущее поведение гейтов, но НЕ является
|
||||||
|
> их источником истины. Источник истины — код: `src/stages.py` (`STAGE_TRANSITIONS`),
|
||||||
|
> `src/qg/checks.py` (`QG_CHECKS` / `check_*` / `_parse_*`), `src/stage_engine.py`. При будущей
|
||||||
|
> правке гейта первична правка кода, манифест обновляется следом (ORCH-075 / ADR-001 §D2).
|
||||||
|
>
|
||||||
|
> **Копируемые скелеты** каждого документа — в каталоге [`docs/_templates/`](../_templates/):
|
||||||
|
> «скопировал → заполнил → не угадываешь структуру/ключ».
|
||||||
|
|
||||||
|
Введён задачей **ORCH-075** (ORCH-52b — слой 1 эпика ORCH-52). Сквозной ADR:
|
||||||
|
[`docs/architecture/adr/adr-0019-pipeline-docs-standard.md`](../architecture/adr/adr-0019-pipeline-docs-standard.md);
|
||||||
|
детально — `docs/work-items/ORCH-075/06-adr/ADR-001-pipeline-docs-standard.md`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Конвейер стадий (ground-truth `STAGE_TRANSITIONS`)
|
||||||
|
|
||||||
|
```
|
||||||
|
created → analysis → architecture → development → review → testing → deploy-staging → deploy → done
|
||||||
|
↑ │
|
||||||
|
└──── REQUEST_CHANGES ──────┘ (откат на development, max 3 retries)
|
||||||
|
```
|
||||||
|
|
||||||
|
Каждое ребро несёт ровно один exit-гейт (`src/stages.py`):
|
||||||
|
`check_analysis_approved → check_architecture_done → check_ci_green → check_reviewer_verdict →
|
||||||
|
check_tests_passed → check_staging_status → check_deploy_status`.
|
||||||
|
|
||||||
|
**Под-гейты ребра `deploy-staging → deploy`** (`check_security_gate` → `check_branch_mergeable` →
|
||||||
|
`check_staging_image_fresh`) — это **врезки в `advance_stage`**, а НЕ строки `STAGE_TRANSITIONS`.
|
||||||
|
Аналогично под-гейт ребра `deploy → done` (`_handle_merge_verify`, ORCH-071/073) — врезка, не
|
||||||
|
зарегистрированный QG. Карта стадий о них не «лжёт»: они не являются стадиями.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Манифест: документ → агент → категория → стадия → гейт → machine-key
|
||||||
|
|
||||||
|
Категории: **required** (пишется всегда), **when-applicable** (пишется при наличии предмета:
|
||||||
|
инфра / данные / security / post-deploy — отсутствие не нарушение), **optional** / **legacy**.
|
||||||
|
|
||||||
|
| Документ | Владелец-агент | Категория | Стадия написания | Гейт / механизм проверки | Frontmatter machine-key |
|
||||||
|
|----------|----------------|-----------|------------------|--------------------------|-------------------------|
|
||||||
|
| `00-business-request.md` | система (Plane webhook `_create_initial_docs`) / заказчик | required | `created` (инициализация) | не гейтится (вход) | — |
|
||||||
|
| `01-brd.md` | analyst | required | `analysis` | exit-гейт `analysis→architecture` = `check_analysis_approved` (Approved + полнота файлов); helper `check_analysis_complete` (наличие `01/02/03/04`) | — |
|
||||||
|
| `02-trz.md` | analyst | required | `analysis` | то же | — |
|
||||||
|
| `03-acceptance-criteria.md` | analyst | required | `analysis` | то же | — |
|
||||||
|
| `04-test-plan.yaml` | analyst | required | `analysis` | то же | — |
|
||||||
|
| `06-adr/ADR-NNN-<slug>.md` | architect | required | `architecture` | `check_architecture_done` (наличие каталога `06-adr/` ≥1 файл ИЛИ `07-infra-requirements.md`) | — |
|
||||||
|
| `07-infra-requirements.md` | architect | when-applicable | `architecture` | `check_architecture_done` (учитывается при наличии) | — |
|
||||||
|
| `08-data-requirements.md` | architect | when-applicable | `architecture` | информационный (гейтом не парсится) | — |
|
||||||
|
| `10-tech-risks.md` | architect | required | `architecture` | информационный (гейтом не парсится) | — |
|
||||||
|
| `12-review.md` | reviewer | required | `review` | `check_reviewer_verdict` | `verdict:` (`APPROVED` \| `REQUEST_CHANGES`) |
|
||||||
|
| `13-test-report.md` | tester | required | `testing` | `check_tests_passed` (`_parse_tests_verdict`) | `result:` / `verdict:` / `status:` (`PASS` \| `FAIL` \| `BLOCKED`; три равноранговых, ORCH-047) |
|
||||||
|
| `14-deploy-log.md` | deployer / deploy-finalizer | required | `deploy` | `check_deploy_status` (`_parse_deploy_status`) | `deploy_status:` (`SUCCESS` \| `FAILED`) |
|
||||||
|
| `15-staging-log.md` | deployer | required (self-hosting) | `deploy-staging` | `check_staging_status` (self-hosting; иначе N/A — ORCH-35) | `staging_status:` (`SUCCESS` \| `FAILED`) |
|
||||||
|
| `16-post-deploy-log.md` | post-deploy-monitor | when-applicable | пост-`done` наблюдение (ORCH-021; не ребро `STAGE_TRANSITIONS`) | информационный (гейтом не парсится) | `post_deploy_status:` (`HEALTHY` \| `DEGRADED`) |
|
||||||
|
| `17-security-report.md` | security-гейт (детерминированный, ORCH-022) | when-applicable | под-гейт ребра `deploy-staging→deploy` | `check_security_gate` (врезка в `advance_stage`) | `security_status:` (`PASS` \| `FAIL`) |
|
||||||
|
|
||||||
|
### Примечания манифеста (нормативные)
|
||||||
|
|
||||||
|
- **Под-гейты ребра `deploy-staging→deploy`** (`check_security_gate` → `check_branch_mergeable` →
|
||||||
|
`check_staging_image_fresh`) исполняются как врезки в `advance_stage`, а НЕ строки
|
||||||
|
`STAGE_TRANSITIONS`. Не путать с exit-гейтами рёбер.
|
||||||
|
- **`09-review.md`** — legacy fallback от старой нумерации; **канон — `12-review.md`**. В основную
|
||||||
|
таблицу как канон не вносится; reviewer пишет `12-review.md`.
|
||||||
|
- **Категория `when-applicable`** = документ пишется при наличии соответствующего предмета
|
||||||
|
(инфра / данные / security / post-deploy). Его отсутствие — не нарушение приёмки.
|
||||||
|
- **`05-…` / `09-…` / `11-…`** — зарезервированные/legacy номера, в текущем каноне не используются.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Machine-verdict доки vs информационные (честный механизм проверки)
|
||||||
|
|
||||||
|
**Machine-verdict доки** — гейт читает ТОЛЬКО YAML-frontmatter (никогда прозу), маппит ключ в
|
||||||
|
вердикт. Имя ключа чувствительно к регистру; значение парсер приводит к верхнему регистру.
|
||||||
|
|
||||||
|
| Документ | Machine-key | Парсер (`src/qg/checks.py`) | Эффект вердикта |
|
||||||
|
|----------|-------------|-----------------------------|-----------------|
|
||||||
|
| `12-review.md` | `verdict:` | `check_reviewer_verdict` | `APPROVED` → дальше; `REQUEST_CHANGES` → откат на `development` |
|
||||||
|
| `13-test-report.md` | `result:` / `verdict:` / `status:` | `_parse_tests_verdict` | `PASS` → дальше; `FAIL`/`BLOCKED` → откат |
|
||||||
|
| `14-deploy-log.md` | `deploy_status:` | `_parse_deploy_status` | `SUCCESS` → `done`; `FAILED` → откат (БАГ-8) |
|
||||||
|
| `15-staging-log.md` | `staging_status:` | `_parse_staging_status` | `SUCCESS` → дальше; `FAILED` → откат (self-hosting; иначе N/A) |
|
||||||
|
| `17-security-report.md` | `security_status:` | `check_security_gate` | `PASS` → дальше; `FAIL` → откат |
|
||||||
|
|
||||||
|
**Информационные доки** — гейтом НЕ парсятся (структура ничего не блокирует):
|
||||||
|
`00-business-request.md` (вход), `08-data-requirements.md`, `10-tech-risks.md`,
|
||||||
|
`16-post-deploy-log.md` (несёт `post_deploy_status:`, но это телеметрия петли уроков ORCH-8 /
|
||||||
|
наблюдаемость, не гейт).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Конвенция ADR-naming
|
||||||
|
|
||||||
|
### Per-work-item ADR (основное)
|
||||||
|
|
||||||
|
- **Путь:** `docs/work-items/<plane-id>/06-adr/`
|
||||||
|
- **Имя файла:** `ADR-NNN-<kebab-slug>.md`
|
||||||
|
- `NNN` — 3-значный, начинается с `001`; инкремент при нескольких ADR в одной задаче
|
||||||
|
(`ADR-001-…`, `ADR-002-…`).
|
||||||
|
- `<kebab-slug>` — kebab-case (нижний регистр, слова через дефис), отражает суть решения.
|
||||||
|
- **Стадия:** пишет **architect** на стадии `architecture`; гейтится `check_architecture_done`
|
||||||
|
(наличие каталога `06-adr/` ≥ 1 файла).
|
||||||
|
|
||||||
|
### Сквозной (cross-cutting) ADR
|
||||||
|
|
||||||
|
Решения, затрагивающие несколько компонентов/ролей или поведение всего конвейера, **дублируются**
|
||||||
|
в глобальный реестр:
|
||||||
|
|
||||||
|
- **Путь:** `docs/architecture/adr/`
|
||||||
|
- **Имя файла:** `adr-NNNN-<kebab-slug>.md` (4-значная сквозная нумерация, последовательная по
|
||||||
|
всему репозиторию; на момент ORCH-075 реестр доходит до `adr-0019`).
|
||||||
|
|
||||||
|
### Примеры из репозитория (реальные, проверенные)
|
||||||
|
|
||||||
|
- `docs/work-items/ORCH-088/06-adr/ADR-001-serial-gate.md`
|
||||||
|
- `docs/work-items/ORCH-089/06-adr/ADR-001-auto-label-gates.md`
|
||||||
|
- `docs/work-items/ORCH-071/06-adr/ADR-001-merge-verify-gate.md`
|
||||||
|
- Сквозные: `docs/architecture/adr/adr-0017-serial-gate.md`,
|
||||||
|
`docs/architecture/adr/adr-0018-auto-label-gates.md`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Как пользоваться шаблонами
|
||||||
|
|
||||||
|
1. Скопируй нужный скелет из [`docs/_templates/`](../_templates/) в
|
||||||
|
`docs/work-items/<plane-id>/` под канонным именем (для ADR — `06-adr/ADR-001-<slug>.md`).
|
||||||
|
2. Заполни секции; **не удаляй** machine-key frontmatter у machine-verdict доков и **не меняй имя
|
||||||
|
ключа** (регистр чувствителен — иначе гейт упадёт ложно).
|
||||||
|
3. Сверяйся с манифестом (§2–§3): какой агент, на какой стадии, какой гейт читает документ.
|
||||||
|
|
||||||
|
> Стандарт **описательный** (слой 1). Машинная проверка соответствия шаблонам/frontmatter —
|
||||||
|
> отдельная задача ORCH-52c; до неё соблюдение — на ответственности агента и reviewer'а
|
||||||
|
> (правило CLAUDE.md «обновлена ли документация»).
|
||||||
8
docs/_templates/00-business-request.md
vendored
Normal file
8
docs/_templates/00-business-request.md
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# Business Request: <краткий заголовок задачи>
|
||||||
|
|
||||||
|
Work Item ID: ORCH-NNN
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<Что хочет заказчик/Владелец своими словами: проблема, желаемый результат, контекст.
|
||||||
|
Допускается `TBD` на входе — analyst уточняет на стадии `analysis` и формализует в 01-brd.md.>
|
||||||
34
docs/_templates/01-brd.md
vendored
Normal file
34
docs/_templates/01-brd.md
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# 01 — BRD (бизнес-требования): ORCH-NNN — <название>
|
||||||
|
|
||||||
|
Work Item: **ORCH-NNN** · Repo: **<repo>** · Стадия: analysis
|
||||||
|
|
||||||
|
## 1. Бизнес-контекст и проблема
|
||||||
|
<Зачем задача, какую боль/риск закрывает. Установленные факты — не изобретать.>
|
||||||
|
|
||||||
|
## 2. Объём (scope)
|
||||||
|
|
||||||
|
### В объёме
|
||||||
|
- <что делаем>
|
||||||
|
|
||||||
|
### Вне объёма
|
||||||
|
- <что явно НЕ делаем — чтобы исключить расползание>
|
||||||
|
|
||||||
|
## 3. Заинтересованные стороны
|
||||||
|
<Кто заказчик, кого затрагивает, кто принимает результат.>
|
||||||
|
|
||||||
|
## 4. Бизнес-требования (BR)
|
||||||
|
- **BR-1** — <требование, проверяемое>
|
||||||
|
- **BR-2** — …
|
||||||
|
|
||||||
|
## 5. Нефункциональные требования (NFR)
|
||||||
|
- **NFR-1** — <надёжность / совместимость / обратимость / безопасность>
|
||||||
|
- **NFR-2** — …
|
||||||
|
|
||||||
|
## 6. Допущения и ограничения
|
||||||
|
<Допущения, на которых стоит решение; внешние ограничения.>
|
||||||
|
|
||||||
|
## 7. Критерии успеха
|
||||||
|
<Резюме; детальные PASS/FAIL — в 03-acceptance-criteria.md.>
|
||||||
|
|
||||||
|
## 8. Риски
|
||||||
|
<Краткий перечень; детали — 10-tech-risks.md (заполняет архитектор).>
|
||||||
30
docs/_templates/02-trz.md
vendored
Normal file
30
docs/_templates/02-trz.md
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# 02 — ТЗ (TRZ): ORCH-NNN — <название>
|
||||||
|
|
||||||
|
Work Item: **ORCH-NNN** · Repo: **<repo>** · Стадия: analysis
|
||||||
|
|
||||||
|
> ТЗ описывает **конкретные изменения к реализации**, выведенные из BRD и фактического кода.
|
||||||
|
> Архитектурное обоснование/решения — задача архитектора (06-adr).
|
||||||
|
|
||||||
|
## 1. Сводка изменения
|
||||||
|
<Что меняется, в одном-двух абзацах.>
|
||||||
|
|
||||||
|
## 2. Задействованные модули / пути
|
||||||
|
| Путь | Действие |
|
||||||
|
|------|----------|
|
||||||
|
| `src/<module>.py` | изменить / создать |
|
||||||
|
|
||||||
|
## 3. Функциональные требования
|
||||||
|
### FR-1 — <название>
|
||||||
|
<Поведение, контракт, инварианты. Привязать к BR.>
|
||||||
|
|
||||||
|
## 4. Изменения API
|
||||||
|
<Новые/изменённые эндпоинты; либо «Нет.».>
|
||||||
|
|
||||||
|
## 5. Изменения схемы БД
|
||||||
|
<Таблицы/миграции/индексы; либо «Нет.».>
|
||||||
|
|
||||||
|
## 6. Требования к новым/изменённым QG checks
|
||||||
|
<Изменения `QG_CHECKS` / `check_*`; либо «Нет.».>
|
||||||
|
|
||||||
|
## 7. Совместимость / регресс
|
||||||
|
<Обратная совместимость, kill-switch, область раската, обратимость.>
|
||||||
31
docs/_templates/03-acceptance-criteria.md
vendored
Normal file
31
docs/_templates/03-acceptance-criteria.md
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# 03 — Критерии приёмки (Acceptance Criteria): ORCH-NNN — <название>
|
||||||
|
|
||||||
|
Work Item: **ORCH-NNN** · Repo: **<repo>** · Стадия: analysis
|
||||||
|
|
||||||
|
Формат: каждый критерий имеет **PASS** (что должно быть истинно для приёмки) и **FAIL**
|
||||||
|
(что считается провалом). Любой машинный/ручной reviewer проверяет их буквально по файлам
|
||||||
|
репозитория.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## AC-1 — <краткий заголовок>
|
||||||
|
|
||||||
|
**Условие:** <проверяемое условие>
|
||||||
|
- **PASS:** <что должно быть истинно>
|
||||||
|
- **FAIL:** <что считается провалом>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## AC-2 — <краткий заголовок>
|
||||||
|
|
||||||
|
**Условие:** <…>
|
||||||
|
- **PASS:** <…>
|
||||||
|
- **FAIL:** <…>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Сводная матрица AC ↔ FR/BR
|
||||||
|
| AC | Покрывает |
|
||||||
|
|----|-----------|
|
||||||
|
| AC-1 | BR-1 / FR-1 |
|
||||||
|
| AC-2 | BR-2 / FR-2 |
|
||||||
20
docs/_templates/04-test-plan.yaml
vendored
Normal file
20
docs/_templates/04-test-plan.yaml
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
work_item: ORCH-NNN
|
||||||
|
title: "<краткое название тест-плана>"
|
||||||
|
framework: pytest
|
||||||
|
scope: "<что покрывается тестами; что вне покрытия>"
|
||||||
|
notes: >
|
||||||
|
<Свободные заметки: окружение, особенности, что считается регрессом.
|
||||||
|
Полный регресс tests/ должен оставаться зелёным.>
|
||||||
|
|
||||||
|
tests:
|
||||||
|
- id: TC-01
|
||||||
|
type: unit # unit | integration
|
||||||
|
description: "<что проверяет тест>"
|
||||||
|
module: tests/test_<feature>.py
|
||||||
|
expected: PASS
|
||||||
|
|
||||||
|
- id: TC-02
|
||||||
|
type: integration
|
||||||
|
description: "<…>"
|
||||||
|
module: tests/test_<feature>.py
|
||||||
|
expected: PASS
|
||||||
43
docs/_templates/06-adr-ADR-NNN-slug.md
vendored
Normal file
43
docs/_templates/06-adr-ADR-NNN-slug.md
vendored
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# ADR-NNN: <Заголовок решения>
|
||||||
|
|
||||||
|
> **Шаблон ADR.** Скопируй в `docs/work-items/<plane-id>/06-adr/ADR-NNN-<kebab-slug>.md`.
|
||||||
|
> `NNN` начинается с `001`, инкремент при нескольких ADR в задаче. `<kebab-slug>` — нижний
|
||||||
|
> регистр, слова через дефис. Сквозное (cross-cutting) решение дополнительно дублируй в
|
||||||
|
> `docs/architecture/adr/adr-NNNN-<kebab-slug>.md` (4-значная глобальная нумерация).
|
||||||
|
> См. `docs/_standards/PIPELINE_DOCS.md` §4.
|
||||||
|
|
||||||
|
Work Item: **ORCH-NNN** — <короткое описание>
|
||||||
|
Стадия: **architecture**
|
||||||
|
Сквозная регистрация: **`docs/architecture/adr/adr-NNNN-<slug>.md`** (если решение
|
||||||
|
кросс-каттинговое; иначе — «N/A, локальное решение задачи»).
|
||||||
|
|
||||||
|
## Статус
|
||||||
|
Proposed <!-- Proposed | Accepted | Superseded by ADR-… -->
|
||||||
|
|
||||||
|
## Контекст
|
||||||
|
<Какую проблему решаем; факты, сверенные с кодом (`src/…`); почему «как есть» не годится.>
|
||||||
|
|
||||||
|
## Решение
|
||||||
|
|
||||||
|
### Сводка
|
||||||
|
<Суть выбранного решения в одном-двух абзацах.>
|
||||||
|
|
||||||
|
### D1 — <название аспекта решения>
|
||||||
|
<Конкретное решение по аспекту, инварианты, привязка к FR/AC.>
|
||||||
|
|
||||||
|
### D2 — <название аспекта решения>
|
||||||
|
<…>
|
||||||
|
|
||||||
|
## Альтернативы
|
||||||
|
- **<альтернатива>** — отвергнуто: <почему>.
|
||||||
|
|
||||||
|
## Последствия
|
||||||
|
- **+** <положительный эффект>
|
||||||
|
- **−** <издержка / приятый компромисс + митигейшн>
|
||||||
|
- **Откат:** <как полностью откатить изменение>
|
||||||
|
|
||||||
|
## Ссылки
|
||||||
|
- BRD: `docs/work-items/ORCH-NNN/01-brd.md`
|
||||||
|
- TRZ: `docs/work-items/ORCH-NNN/02-trz.md`
|
||||||
|
- Acceptance: `docs/work-items/ORCH-NNN/03-acceptance-criteria.md`
|
||||||
|
- Сверено по коду: `src/…`
|
||||||
19
docs/_templates/07-infra-requirements.md
vendored
Normal file
19
docs/_templates/07-infra-requirements.md
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# 07 — Инфра-требования: ORCH-NNN — <название>
|
||||||
|
|
||||||
|
Work Item: **ORCH-NNN** · Repo: **<repo>** · Стадия: architecture
|
||||||
|
|
||||||
|
> When-applicable. Если инфраструктура не затрагивается — оставить явные `N/A` по пунктам
|
||||||
|
> (файл создаётся для аудитопригодности, а не из-за изменения топологии).
|
||||||
|
|
||||||
|
## I-1. Топология / окружения
|
||||||
|
<Контейнеры, порты, сеть, тома, хост; либо `N/A`.>
|
||||||
|
|
||||||
|
## I-2. Переменные окружения / секреты
|
||||||
|
<Новые env-переменные, изменения `.env` / `.env.example`, секреты; либо `N/A`.>
|
||||||
|
|
||||||
|
## I-3. Деплой / рестарт
|
||||||
|
<Требуется ли рестарт прод-контейнера; self-hosting инвариант (не ронять прод вне staging);
|
||||||
|
либо `N/A`.>
|
||||||
|
|
||||||
|
## I-4. CI/CD
|
||||||
|
<Изменения `.gitea/workflows/`, новые тестовые шаги; либо «без изменений».>
|
||||||
15
docs/_templates/08-data-requirements.md
vendored
Normal file
15
docs/_templates/08-data-requirements.md
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# 08 — Требования к данным: ORCH-NNN — <название>
|
||||||
|
|
||||||
|
Work Item: **ORCH-NNN** · Repo: **<repo>** · Стадия: architecture
|
||||||
|
|
||||||
|
> When-applicable / информационный (гейтом не парсится). Если данные/схема не затрагиваются —
|
||||||
|
> оставить явные `N/A`.
|
||||||
|
|
||||||
|
## Изменения схемы БД
|
||||||
|
<Новые/изменённые таблицы, индексы, миграции (`init_db`); либо `N/A`.>
|
||||||
|
|
||||||
|
## Новые/изменённые сущности
|
||||||
|
<Поля, колонки, инварианты данных; либо «Нет.».>
|
||||||
|
|
||||||
|
## Совместимость данных / миграции
|
||||||
|
<Аддитивность, идемпотентность миграций, restart-safe, влияние на общую прод-БД; либо `N/A`.>
|
||||||
16
docs/_templates/10-tech-risks.md
vendored
Normal file
16
docs/_templates/10-tech-risks.md
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# 10 — Технические риски: ORCH-NNN — <название>
|
||||||
|
|
||||||
|
Work Item: **ORCH-NNN** · Repo: **<repo>** · Стадия: architecture
|
||||||
|
|
||||||
|
> Информационный (гейтом не парсится). Перечисляет риски реализации и их митигейшн.
|
||||||
|
|
||||||
|
## Реестр рисков
|
||||||
|
|
||||||
|
| ID | Риск | Вер. | Влия. | Митигейшн |
|
||||||
|
|----|------|------|-------|-----------|
|
||||||
|
| TR-1 | <описание риска> | Низ./Сред./Выс. | Низ./Сред./Выс. | <как снижаем> |
|
||||||
|
| TR-2 | <…> | | | |
|
||||||
|
|
||||||
|
## Сводный вывод
|
||||||
|
<Доминирующий класс рисков; нужна ли эскалация `arch:major-change` / возврат в анализ;
|
||||||
|
итоговая оценка остаточного риска для прод-конвейера (self-hosting).>
|
||||||
31
docs/_templates/12-review.md
vendored
Normal file
31
docs/_templates/12-review.md
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
---
|
||||||
|
type: review
|
||||||
|
work_item_id: ORCH-NNN
|
||||||
|
verdict: APPROVED # APPROVED | REQUEST_CHANGES (machine-key — читает check_reviewer_verdict)
|
||||||
|
version: 1
|
||||||
|
---
|
||||||
|
|
||||||
|
# Review ORCH-NNN
|
||||||
|
|
||||||
|
> Машинный вердикт читается ТОЛЬКО из `verdict:` во frontmatter (никогда из прозы).
|
||||||
|
> `APPROVED` → дальше по конвейеру; `REQUEST_CHANGES` → откат на `development`.
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
<Краткая оценка: реализовано ли по ТЗ/ADR, покрытие тестами, обновлена ли документация.>
|
||||||
|
|
||||||
|
## Оси проверки
|
||||||
|
<Корректность, соответствие ADR/инвариантам, тесты, документация, совместимость/регресс.>
|
||||||
|
|
||||||
|
## Findings
|
||||||
|
|
||||||
|
### P0 — Blocker
|
||||||
|
- (нет)
|
||||||
|
|
||||||
|
### P1 — Must fix
|
||||||
|
- (нет)
|
||||||
|
|
||||||
|
### P2 — Should fix
|
||||||
|
- (нет)
|
||||||
|
|
||||||
|
## Документация
|
||||||
|
<Обновлена ли документация (README/CLAUDE/CHANGELOG/архитектура) в том же PR. Нет → REQUEST_CHANGES.>
|
||||||
33
docs/_templates/13-test-report.md
vendored
Normal file
33
docs/_templates/13-test-report.md
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
---
|
||||||
|
type: test-report
|
||||||
|
work_item_id: ORCH-NNN
|
||||||
|
result: PASS # PASS | FAIL | BLOCKED (machine-key — читает _parse_tests_verdict)
|
||||||
|
---
|
||||||
|
|
||||||
|
# Test Report — ORCH-NNN
|
||||||
|
|
||||||
|
> Машинный вердикт читается ТОЛЬКО из frontmatter. Канонический ключ — `result:`; равнорангово
|
||||||
|
> допускаются `verdict:` / `status:` (ORCH-047). Любой негативный токен (`FAIL`/`BLOCKED`) —
|
||||||
|
> авторитетен.
|
||||||
|
|
||||||
|
## Окружение
|
||||||
|
- Python: <версия>
|
||||||
|
- pytest: <версия>
|
||||||
|
- Дата: YYYY-MM-DD
|
||||||
|
- Worktree: `feature/ORCH-NNN-<slug>`
|
||||||
|
|
||||||
|
## Результаты
|
||||||
|
|
||||||
|
### Полный регресс
|
||||||
|
<`pytest tests/ -q` — итог (N passed); прод-контейнер не трогается.>
|
||||||
|
|
||||||
|
### Профильные сюиты
|
||||||
|
<Целевые тесты задачи.>
|
||||||
|
|
||||||
|
### Сопоставление с тест-планом
|
||||||
|
| TC ID | Описание | Тест-функция | Результат |
|
||||||
|
|-------|----------|--------------|-----------|
|
||||||
|
| TC-01 | <…> | test_… | PASS |
|
||||||
|
|
||||||
|
### Сопоставление с критериями приёмки
|
||||||
|
<AC-1…AC-N — покрыт каким тестом / результат.>
|
||||||
14
docs/_templates/14-deploy-log.md
vendored
Normal file
14
docs/_templates/14-deploy-log.md
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
deploy_status: SUCCESS # SUCCESS | FAILED (machine-key — читает _parse_deploy_status)
|
||||||
|
work_item: ORCH-NNN
|
||||||
|
hook_exit_code: 0
|
||||||
|
deployed_by: deploy-finalizer
|
||||||
|
---
|
||||||
|
|
||||||
|
# Deploy log — ORCH-NNN
|
||||||
|
|
||||||
|
> Машинный вердикт читается ТОЛЬКО из `deploy_status:` во frontmatter.
|
||||||
|
> `SUCCESS` → `done`; `FAILED` → откат на `development` (БАГ-8).
|
||||||
|
|
||||||
|
<Краткое описание деплоя: что выкачено, exit-code хука, кто/что зафиксировало вердикт
|
||||||
|
(детерминированный finalizer Фаза C, не LLM, для self-hosting).>
|
||||||
20
docs/_templates/15-staging-log.md
vendored
Normal file
20
docs/_templates/15-staging-log.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
staging_status: SUCCESS # SUCCESS | FAILED (machine-key — читает _parse_staging_status)
|
||||||
|
timestamp: YYYY-MM-DDTHH:MM:SSZ
|
||||||
|
base_url: http://localhost:8501
|
||||||
|
---
|
||||||
|
|
||||||
|
# Staging Gate Log
|
||||||
|
|
||||||
|
> Машинный вердикт читается ТОЛЬКО из `staging_status:` во frontmatter. Реален для self-hosting
|
||||||
|
> (`orchestrator`); для прочих репо гейт — N/A (ORCH-35). `SUCCESS` → дальше; `FAILED` → откат.
|
||||||
|
|
||||||
|
Staging test suite — итог (например: «All REAL pipeline checks passed»). Запуск канонически
|
||||||
|
внутри контейнера `orchestrator-staging` (8501).
|
||||||
|
|
||||||
|
## Results
|
||||||
|
- **Block A (SMOKE)**: <…>
|
||||||
|
- **Block B (ACCESS)**: <…>
|
||||||
|
- **Block C (E2E)**: <…>
|
||||||
|
|
||||||
|
REAL failed: <none | перечень>.
|
||||||
21
docs/_templates/16-post-deploy-log.md
vendored
Normal file
21
docs/_templates/16-post-deploy-log.md
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
post_deploy_status: HEALTHY # HEALTHY | DEGRADED (информационный, гейтом НЕ парсится — телеметрия ORCH-021)
|
||||||
|
action_taken: NONE # NONE | ALERT_ONLY | ROLLBACK_OK | ROLLBACK_FAILED
|
||||||
|
work_item: ORCH-NNN
|
||||||
|
window_s: 900
|
||||||
|
checks_total: 0
|
||||||
|
checks_failed: 0
|
||||||
|
---
|
||||||
|
|
||||||
|
# Post-deploy log — ORCH-NNN
|
||||||
|
|
||||||
|
> Пост-`done` наблюдение прода (ORCH-021). НЕ ребро `STAGE_TRANSITIONS`, гейтом не парсится —
|
||||||
|
> frontmatter машиночитаем для петли уроков ORCH-8 / наблюдаемости.
|
||||||
|
|
||||||
|
Окно наблюдения: <window_s>s; опросов всего: <checks_total>, с провалом: <checks_failed>.
|
||||||
|
|
||||||
|
## Серия наблюдений
|
||||||
|
<Краткая серия сигналов health / доли 5xx; классификация HEALTHY/DEGRADED.>
|
||||||
|
|
||||||
|
## Решение
|
||||||
|
<Реакция: для self-hosting всегда `ALERT_ONLY` (ручной approve, тик не откатывает прод).>
|
||||||
26
docs/_templates/17-security-report.md
vendored
Normal file
26
docs/_templates/17-security-report.md
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
security_status: PASS # PASS | FAIL (machine-key — читает check_security_gate)
|
||||||
|
work_item: ORCH-NNN
|
||||||
|
secrets_found: 0
|
||||||
|
deps_blocking: 0
|
||||||
|
deps_warning: 0
|
||||||
|
deps_audit_degraded: false
|
||||||
|
---
|
||||||
|
|
||||||
|
# Security Report — ORCH-NNN
|
||||||
|
|
||||||
|
> Детерминированный security-гейт (ORCH-022) — под-гейт ребра `deploy-staging→deploy` (врезка в
|
||||||
|
> `advance_stage`, не строка `STAGE_TRANSITIONS`). Машинный вердикт читается ТОЛЬКО из
|
||||||
|
> `security_status:`. `PASS` → дальше; `FAIL` → откат.
|
||||||
|
|
||||||
|
## Verdict
|
||||||
|
<clean / blocking: N secrets, M blocking CVE(s).>
|
||||||
|
|
||||||
|
## Secrets
|
||||||
|
<secret-scanning (gitleaks, offline): None | перечень.>
|
||||||
|
|
||||||
|
## Dependencies (blocking)
|
||||||
|
<dependency audit (pip-audit): None | перечень блокирующих CVE.>
|
||||||
|
|
||||||
|
## Dependencies (warning)
|
||||||
|
<Не блокирующие предупреждения зависимостей.>
|
||||||
@@ -41,6 +41,18 @@ created → analysis → architecture → development → review → testing →
|
|||||||
|
|
||||||
**Канон гейтов:** машинные вердикты читаются ТОЛЬКО из YAML-frontmatter, никогда из прозы. Лог-файлы мержатся в `origin/main` отдельным PR; гейт читает из `origin/main`.
|
**Канон гейтов:** машинные вердикты читаются ТОЛЬКО из YAML-frontmatter, никогда из прозы. Лог-файлы мержатся в `origin/main` отдельным PR; гейт читает из `origin/main`.
|
||||||
|
|
||||||
|
### Стандарт документов конвейера (ORCH-075, ORCH-52b)
|
||||||
|
Структура номерных документов work item (`00-business-request.md` … `17-security-report.md`),
|
||||||
|
карта «стадия → агент → документ → категория → гейт/механизм → frontmatter machine-key» и
|
||||||
|
конвенция ADR-naming зафиксированы как golden source в
|
||||||
|
[`docs/_standards/PIPELINE_DOCS.md`](../_standards/PIPELINE_DOCS.md); копируемые скелеты — в
|
||||||
|
[`docs/_templates/`](../_templates/). Манифест **документирует** поведение гейтов (источник истины
|
||||||
|
остаётся код: `src/stages.py`, `src/qg/checks.py`), честно различая machine-verdict доки
|
||||||
|
(`12/13/14/15/17` — несут читаемый гейтом ключ) и информационные (`00/08/10/16` — гейтом не
|
||||||
|
парсятся). Это слой 1 (описательный); машинная проверка соответствия — задача ORCH-52c. ADR:
|
||||||
|
[adr-0019](adr/adr-0019-pipeline-docs-standard.md), детально —
|
||||||
|
`docs/work-items/ORCH-075/06-adr/ADR-001-pipeline-docs-standard.md`.
|
||||||
|
|
||||||
### Модель и эффорт по ролям (ORCH-41, валидация ORCH-74)
|
### Модель и эффорт по ролям (ORCH-41, валидация ORCH-74)
|
||||||
Модель и `--effort` каждого агента берутся из config (`src/config.py`), резолвятся `launcher.resolve_agent_model` / `resolve_agent_effort` по приоритету **project-override (`projects_json` `agent_models`/`agent_efforts`) > `ORCH_AGENT_MODEL_<AGENT>`/`ORCH_AGENT_EFFORT_<AGENT>` > `*_default` > CLI-дефолт (без флага)**. **Эффорт (ORCH-081):** ниже `*_default` добавлен непустой **per-role floor** — class-default поля `agent_effort_<role>` из `config.py` (его пустой env перебить не может). Floor — строго последний уровень (ниже default) и срабатывает ТОЛЬКО когда все уровни пусты, поэтому пустые прод-`ORCH_AGENT_EFFORT_*=` (которые pydantic трактует как явное `''` и обнуляют дефолт) больше не приводят к запуску без `--effort`: каждая роль получает свой канонический пол (developer=`xhigh`, tester/deployer=`medium`, прочие=`high`). Непустой явный конфиг по-прежнему побеждает floor; опечатка вне `VALID_EFFORTS` дропается валидацией ДО floor (never-break, не маскируется). См. `docs/work-items/ORCH-081/06-adr/ADR-001-effort-resolution-floor.md`. frontmatter `model:` в `.openclaw/agents/*.md` **удалён** (ORCH-74 G1) — он был мёртвой/лживой декларацией (launcher его не читает); config — единственный источник правды о модели. Model-routing (G3) НЕ включён — все 6 агентов на `claude-opus-4-8`.
|
Модель и `--effort` каждого агента берутся из config (`src/config.py`), резолвятся `launcher.resolve_agent_model` / `resolve_agent_effort` по приоритету **project-override (`projects_json` `agent_models`/`agent_efforts`) > `ORCH_AGENT_MODEL_<AGENT>`/`ORCH_AGENT_EFFORT_<AGENT>` > `*_default` > CLI-дефолт (без флага)**. **Эффорт (ORCH-081):** ниже `*_default` добавлен непустой **per-role floor** — class-default поля `agent_effort_<role>` из `config.py` (его пустой env перебить не может). Floor — строго последний уровень (ниже default) и срабатывает ТОЛЬКО когда все уровни пусты, поэтому пустые прод-`ORCH_AGENT_EFFORT_*=` (которые pydantic трактует как явное `''` и обнуляют дефолт) больше не приводят к запуску без `--effort`: каждая роль получает свой канонический пол (developer=`xhigh`, tester/deployer=`medium`, прочие=`high`). Непустой явный конфиг по-прежнему побеждает floor; опечатка вне `VALID_EFFORTS` дропается валидацией ДО floor (never-break, не маскируется). См. `docs/work-items/ORCH-081/06-adr/ADR-001-effort-resolution-floor.md`. frontmatter `model:` в `.openclaw/agents/*.md` **удалён** (ORCH-74 G1) — он был мёртвой/лживой декларацией (launcher его не читает); config — единственный источник правды о модели. Model-routing (G3) НЕ включён — все 6 агентов на `claude-opus-4-8`.
|
||||||
|
|
||||||
|
|||||||
214
tests/test_orch_52b_docs_standard.py
Normal file
214
tests/test_orch_52b_docs_standard.py
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
"""ORCH-075 (ORCH-52b) — структурные проверки стандарта документов конвейера.
|
||||||
|
|
||||||
|
Docs-only задача: проверяется НАЛИЧИЕ и СТРУКТУРА новых файлов-стандартов/шаблонов
|
||||||
|
(`docs/_standards/PIPELINE_DOCS.md`, `docs/_templates/*`) и обновление точек-ссылок
|
||||||
|
(`CLAUDE.md`, `docs/architecture/README.md`, `CHANGELOG.md`). Тесты НЕ меняют
|
||||||
|
`QG_CHECKS`/`STAGE_TRANSITIONS` и не вводят новый гейт (это ORCH-52c).
|
||||||
|
|
||||||
|
Покрытие тест-плана 04-test-plan.yaml: TC-01…TC-20 (TC-21 — полный регресс `pytest tests/`).
|
||||||
|
"""
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
REPO_ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
STANDARDS = REPO_ROOT / "docs" / "_standards"
|
||||||
|
TEMPLATES = REPO_ROOT / "docs" / "_templates"
|
||||||
|
MANIFEST = STANDARDS / "PIPELINE_DOCS.md"
|
||||||
|
|
||||||
|
# Все номерные доки реального набора (TRZ §FR-1, AC-1).
|
||||||
|
NUMBERED_DOCS = ["00", "01", "02", "03", "04", "06", "07", "08", "10",
|
||||||
|
"12", "13", "14", "15", "16", "17"]
|
||||||
|
|
||||||
|
# Шаблоны required/when-applicable доков (TRZ §2, AC-2).
|
||||||
|
TEMPLATE_FILES = [
|
||||||
|
"00-business-request.md",
|
||||||
|
"01-brd.md",
|
||||||
|
"02-trz.md",
|
||||||
|
"03-acceptance-criteria.md",
|
||||||
|
"04-test-plan.yaml",
|
||||||
|
"06-adr-ADR-NNN-slug.md",
|
||||||
|
"07-infra-requirements.md",
|
||||||
|
"08-data-requirements.md",
|
||||||
|
"10-tech-risks.md",
|
||||||
|
"12-review.md",
|
||||||
|
"13-test-report.md",
|
||||||
|
"14-deploy-log.md",
|
||||||
|
"15-staging-log.md",
|
||||||
|
"16-post-deploy-log.md",
|
||||||
|
"17-security-report.md",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _read(path: Path) -> str:
|
||||||
|
return path.read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
# --- TC-01 -----------------------------------------------------------------
|
||||||
|
def test_tc01_manifest_exists_and_nonempty():
|
||||||
|
"""docs/_standards/PIPELINE_DOCS.md существует и непустой."""
|
||||||
|
assert MANIFEST.is_file(), f"манифест не найден: {MANIFEST}"
|
||||||
|
assert len(_read(MANIFEST).strip()) > 0, "манифест пустой"
|
||||||
|
|
||||||
|
|
||||||
|
# --- TC-02 -----------------------------------------------------------------
|
||||||
|
def test_tc02_manifest_mentions_all_numbered_docs():
|
||||||
|
"""Манифест упоминает все номерные доки набора."""
|
||||||
|
content = _read(MANIFEST)
|
||||||
|
missing = []
|
||||||
|
for num in NUMBERED_DOCS:
|
||||||
|
# Документ упоминается как `NN-...` или `NN-adr` — ищем по префиксу `NN-`.
|
||||||
|
if f"{num}-" not in content:
|
||||||
|
missing.append(num)
|
||||||
|
assert not missing, f"в манифесте не упомянуты доки: {missing}"
|
||||||
|
|
||||||
|
|
||||||
|
# --- TC-03 -----------------------------------------------------------------
|
||||||
|
def test_tc03_manifest_lists_owner_agents():
|
||||||
|
"""Манифест указывает владельцев-агентов конвейера (TC-03: analyst/architect/
|
||||||
|
reviewer/tester/deployer/система). `developer` не владеет номерным доком — пишет код+PR."""
|
||||||
|
content = _read(MANIFEST).lower()
|
||||||
|
for agent in ["analyst", "architect", "reviewer", "tester", "deployer"]:
|
||||||
|
assert agent in content, f"в манифесте нет владельца-агента: {agent}"
|
||||||
|
assert "систем" in content, "в манифесте нет системного владельца (Plane webhook)"
|
||||||
|
|
||||||
|
|
||||||
|
# --- TC-04 -----------------------------------------------------------------
|
||||||
|
def test_tc04_manifest_has_categories():
|
||||||
|
"""Манифест содержит категории required / when-applicable / optional."""
|
||||||
|
content = _read(MANIFEST)
|
||||||
|
for category in ["required", "when-applicable", "optional"]:
|
||||||
|
assert category in content, f"в манифесте нет категории: {category}"
|
||||||
|
|
||||||
|
|
||||||
|
# --- TC-05 -----------------------------------------------------------------
|
||||||
|
def test_tc05_templates_dir_has_all_templates():
|
||||||
|
"""docs/_templates/ существует и содержит шаблоны для всех required/when-applicable доков."""
|
||||||
|
assert TEMPLATES.is_dir(), f"каталог шаблонов не найден: {TEMPLATES}"
|
||||||
|
missing = [name for name in TEMPLATE_FILES if not (TEMPLATES / name).is_file()]
|
||||||
|
assert not missing, f"отсутствуют шаблоны: {missing}"
|
||||||
|
|
||||||
|
|
||||||
|
# --- TC-06..TC-11 — frontmatter machine-keys -------------------------------
|
||||||
|
def _assert_frontmatter_key(template_name: str, key: str):
|
||||||
|
content = _read(TEMPLATES / template_name)
|
||||||
|
assert content.lstrip().startswith("---"), f"{template_name}: нет YAML-frontmatter"
|
||||||
|
head = content.split("---", 2)
|
||||||
|
assert len(head) >= 3, f"{template_name}: frontmatter не закрыт"
|
||||||
|
assert f"{key}:" in head[1], f"{template_name}: нет machine-key `{key}:` во frontmatter"
|
||||||
|
|
||||||
|
|
||||||
|
def test_tc06_review_template_has_verdict():
|
||||||
|
"""Шаблон 12-review содержит frontmatter-ключ verdict:."""
|
||||||
|
_assert_frontmatter_key("12-review.md", "verdict")
|
||||||
|
|
||||||
|
|
||||||
|
def test_tc07_test_report_template_has_result():
|
||||||
|
"""Шаблон 13-test-report содержит frontmatter-ключ result:."""
|
||||||
|
_assert_frontmatter_key("13-test-report.md", "result")
|
||||||
|
|
||||||
|
|
||||||
|
def test_tc08_deploy_log_template_has_deploy_status():
|
||||||
|
"""Шаблон 14-deploy-log содержит frontmatter-ключ deploy_status:."""
|
||||||
|
_assert_frontmatter_key("14-deploy-log.md", "deploy_status")
|
||||||
|
|
||||||
|
|
||||||
|
def test_tc09_staging_log_template_has_staging_status():
|
||||||
|
"""Шаблон 15-staging-log содержит frontmatter-ключ staging_status:."""
|
||||||
|
_assert_frontmatter_key("15-staging-log.md", "staging_status")
|
||||||
|
|
||||||
|
|
||||||
|
def test_tc10_security_report_template_has_security_status():
|
||||||
|
"""Шаблон 17-security-report содержит frontmatter-ключ security_status:."""
|
||||||
|
_assert_frontmatter_key("17-security-report.md", "security_status")
|
||||||
|
|
||||||
|
|
||||||
|
def test_tc11_post_deploy_template_has_post_deploy_status():
|
||||||
|
"""Шаблон 16-post-deploy-log содержит frontmatter-ключ post_deploy_status:."""
|
||||||
|
_assert_frontmatter_key("16-post-deploy-log.md", "post_deploy_status")
|
||||||
|
|
||||||
|
|
||||||
|
# --- TC-12 -----------------------------------------------------------------
|
||||||
|
def test_tc12_brd_template_has_mandatory_sections():
|
||||||
|
"""Шаблон 01-brd содержит обязательные секции (TRZ §FR-2.1)."""
|
||||||
|
content = _read(TEMPLATES / "01-brd.md")
|
||||||
|
for section in ["Бизнес-контекст", "Объём", "Бизнес-требования", "Нефункциональные требования"]:
|
||||||
|
assert section in content, f"01-brd: нет секции `{section}`"
|
||||||
|
|
||||||
|
|
||||||
|
# --- TC-13 -----------------------------------------------------------------
|
||||||
|
def test_tc13_trz_template_has_mandatory_sections():
|
||||||
|
"""Шаблон 02-trz содержит обязательные секции (TRZ §FR-2.1)."""
|
||||||
|
content = _read(TEMPLATES / "02-trz.md")
|
||||||
|
for section in ["Задействованные модули", "Изменения API", "Изменения схемы БД",
|
||||||
|
"QG checks"]:
|
||||||
|
assert section in content, f"02-trz: нет секции `{section}`"
|
||||||
|
|
||||||
|
|
||||||
|
# --- TC-14 -----------------------------------------------------------------
|
||||||
|
def test_tc14_ac_template_has_pass_fail_block():
|
||||||
|
"""Шаблон 03-acceptance-criteria содержит блок AC-N с метками PASS и FAIL."""
|
||||||
|
content = _read(TEMPLATES / "03-acceptance-criteria.md")
|
||||||
|
assert "AC-1" in content, "03-ac: нет блока AC-N"
|
||||||
|
assert "**PASS:**" in content, "03-ac: нет метки PASS"
|
||||||
|
assert "**FAIL:**" in content, "03-ac: нет метки FAIL"
|
||||||
|
|
||||||
|
|
||||||
|
# --- TC-15 -----------------------------------------------------------------
|
||||||
|
def test_tc15_test_plan_template_is_valid_yaml():
|
||||||
|
"""Шаблон 04-test-plan.yaml — валидный YAML с work_item и списком tests."""
|
||||||
|
data = yaml.safe_load(_read(TEMPLATES / "04-test-plan.yaml"))
|
||||||
|
assert isinstance(data, dict), "04-test-plan: корень не словарь"
|
||||||
|
assert "work_item" in data, "04-test-plan: нет ключа work_item"
|
||||||
|
assert isinstance(data.get("tests"), list) and data["tests"], "04-test-plan: tests не список"
|
||||||
|
first = data["tests"][0]
|
||||||
|
for key in ["id", "type", "description", "module", "expected"]:
|
||||||
|
assert key in first, f"04-test-plan: в элементе tests нет ключа `{key}`"
|
||||||
|
|
||||||
|
|
||||||
|
# --- TC-16 -----------------------------------------------------------------
|
||||||
|
def test_tc16_adr_naming_section_present():
|
||||||
|
"""Раздел ADR-naming фиксирует формат ADR-NNN-<slug>.md с нумерацией с 001 и kebab-slug."""
|
||||||
|
content = _read(MANIFEST)
|
||||||
|
assert "ADR-NNN-" in content, "нет формата ADR-NNN-<slug>.md"
|
||||||
|
assert "06-adr" in content, "нет пути 06-adr/"
|
||||||
|
assert "001" in content, "не зафиксирована нумерация с 001"
|
||||||
|
assert "kebab" in content.lower(), "нет правила kebab-case для slug"
|
||||||
|
|
||||||
|
|
||||||
|
# --- TC-17 -----------------------------------------------------------------
|
||||||
|
def test_tc17_adr_naming_matches_real_repo():
|
||||||
|
"""ADR-naming совпадает с реальными ADR в репо (пример из манифеста существует)."""
|
||||||
|
# Манифест приводит ORCH-088 как пример; реальный файл должен существовать.
|
||||||
|
adr_dir = REPO_ROOT / "docs" / "work-items" / "ORCH-088" / "06-adr"
|
||||||
|
real = list(adr_dir.glob("ADR-001-*.md"))
|
||||||
|
assert real, f"реальный ADR-001-*.md не найден в {adr_dir}"
|
||||||
|
# И глобальный реестр следует 4-значной конвенции.
|
||||||
|
global_adr = REPO_ROOT / "docs" / "architecture" / "adr"
|
||||||
|
assert list(global_adr.glob("adr-0019-*.md")), "глобальный adr-0019-*.md не найден"
|
||||||
|
|
||||||
|
|
||||||
|
# --- TC-18 -----------------------------------------------------------------
|
||||||
|
def test_tc18_claude_md_links_standard():
|
||||||
|
"""CLAUDE.md содержит ссылку на docs/_standards/PIPELINE_DOCS.md."""
|
||||||
|
content = _read(REPO_ROOT / "CLAUDE.md")
|
||||||
|
assert "docs/_standards/PIPELINE_DOCS.md" in content
|
||||||
|
|
||||||
|
|
||||||
|
# --- TC-19 -----------------------------------------------------------------
|
||||||
|
def test_tc19_architecture_readme_links_standard():
|
||||||
|
"""docs/architecture/README.md содержит ссылку на стандарт документов."""
|
||||||
|
content = _read(REPO_ROOT / "docs" / "architecture" / "README.md")
|
||||||
|
assert "PIPELINE_DOCS.md" in content
|
||||||
|
|
||||||
|
|
||||||
|
# --- TC-20 -----------------------------------------------------------------
|
||||||
|
def test_tc20_changelog_mentions_task():
|
||||||
|
"""CHANGELOG.md содержит запись об ORCH-52b/ORCH-075 в разделе Unreleased."""
|
||||||
|
content = _read(REPO_ROOT / "CHANGELOG.md")
|
||||||
|
unreleased = content.split("## [Unreleased]", 1)
|
||||||
|
assert len(unreleased) == 2, "нет раздела ## [Unreleased]"
|
||||||
|
# Берём срез до следующего релизного заголовка, если он есть.
|
||||||
|
body = unreleased[1].split("\n## ", 1)[0]
|
||||||
|
assert "ORCH-075" in body or "ORCH-52b" in body, "в Unreleased нет записи ORCH-075/ORCH-52b"
|
||||||
Reference in New Issue
Block a user