From 167538c7b1b72f7bef12e37ee1946e6abd755999 Mon Sep 17 00:00:00 2001 From: claude-bot Date: Tue, 9 Jun 2026 13:40:55 +0300 Subject: [PATCH] analyst(ET): auto-commit from analyst run_id=453 --- docs/work-items/ORCH-076/01-brd.md | 151 ++++++++++++++++++ docs/work-items/ORCH-076/02-trz.md | 124 ++++++++++++++ .../ORCH-076/03-acceptance-criteria.md | 104 ++++++++++++ docs/work-items/ORCH-076/04-test-plan.yaml | 122 ++++++++++++++ 4 files changed, 501 insertions(+) create mode 100644 docs/work-items/ORCH-076/01-brd.md create mode 100644 docs/work-items/ORCH-076/02-trz.md create mode 100644 docs/work-items/ORCH-076/03-acceptance-criteria.md create mode 100644 docs/work-items/ORCH-076/04-test-plan.yaml diff --git a/docs/work-items/ORCH-076/01-brd.md b/docs/work-items/ORCH-076/01-brd.md new file mode 100644 index 0000000..729d6dd --- /dev/null +++ b/docs/work-items/ORCH-076/01-brd.md @@ -0,0 +1,151 @@ +# 01 — BRD (бизнес-требования): ORCH-076 — ORCH-52c: протокол handoff + frontmatter-контракт (writer/валидатор/схема) + +Work Item: **ORCH-076** · Repo: **orchestrator** · Стадия: analysis + +## 1. Бизнес-контекст и проблема + +Это **слой 2 эпика ORCH-52** (стандартизация документного конвейера). Слой 1 (ORCH-52b / +ORCH-075) уже в `main`: создан **описательный** стандарт `docs/_standards/PIPELINE_DOCS.md` ++ копируемые скелеты `docs/_templates/*`. Стандарт честно фиксирует карту «стадия → агент → +документ → гейт → frontmatter machine-key», но прямо помечен как слой описательный: +«Машинная проверка соответствия шаблонам/frontmatter — отдельная задача ORCH-52c». + +Установленные факты (проверено в репо на ветке задачи): + +- **`src/frontmatter.py` = ТОЛЬКО reader.** Единственная функция + `read_frontmatter_value(path, key) -> str | None` (single-key, ~2.6 KB). В docstring + модуля прямой коммент: *«merging into a single parser is a follow-up task»* — это и есть + ORCH-52c. Контракт reader — **never raises** (любая ошибка → `None` + `logger.debug`). +- **Протокол вердиктов размазан по отдельным парсерам с дублированной ~10-строчной + YAML-frontmatter-логикой:** + - `src/qg/checks.py::check_reviewer_verdict` — читает `verdict:` из `12-review.md`; + - `src/qg/checks.py::_parse_tests_verdict` — читает `result:`/`verdict:`/`status:` из + `13-test-report.md` (три равноранговых поля, ORCH-047); + - `src/qg/checks.py::_parse_deploy_status` — читает `deploy_status:` из `14-deploy-log.md`; + - `src/qg/checks.py::_parse_staging_status` — читает `staging_status:` из `15-staging-log.md`; + - `src/security_gate.py::parse_security_status` — читает `security_status:` из `17-security-report.md`; + - `src/post_deploy.py` — пишет/читает `post_deploy_status:` в `16-post-deploy-log.md`; + - `src/review_parse.py` — defensive-извлечение прозы (`_strip_frontmatter`). + Каждый парсер заново реализует `content.startswith("---")` → `split("---", 2)` → + `yaml.safe_load`. Единого контракта нет → риск рассинхрона (разная обработка ошибок, + разный набор токенов, разный регистр). +- **Нет формальной спеки handoff:** нигде не зафиксировано «что КАЖДАЯ стадия ОБЯЗАНА + оставить на выходе» (полный список артефактов + обязательные frontmatter-ключи) как + единый контракт передачи между стадиями. + +**Боль/риск:** без единого контракта чтения вердиктов и без обязательной схемы frontmatter +каждая правка одного парсера может разойтись с остальными; новый агентский документ легко +написать с неверным ключом/регистром (гейт упадёт ложно), а отсутствие машинной проверки +схемы оставляет соблюдение стандарта на ручную дисциплину reviewer'а. + +**⚠️ Self-hosting.** Задача меняет КОД, читающий вердикты НА ГЕЙТАХ (review/staging/security/ +tester/deploy) в инструменте, который сейчас обслуживает прод (enduro-trails) из общего +инстанса. Любой регресс чтения вердикта = остановка конвейера всех проектов. Поэтому +рефакторинг обязан быть строго обратно совместимым и fail-safe. + +## 2. Объём (scope) + +### В объёме +- **Спека handoff** в `docs/_standards/` (рядом с `PIPELINE_DOCS.md`): формальный контракт + «стадия → обязательный выход» (какие документы + какие frontmatter-ключи обязательны на + выходе каждой стадии), согласованный с манифестом ORCH-52b. +- **Расширение `src/frontmatter.py`:** к существующему reader добавить **writer** (запись + YAML-frontmatter) и **валидатор** обязательной схемы. Обязательная схема: + `work_item`, `stage`, `author_agent`, `status`, `created_at`, `model_used`. +- **Единый контракт вердиктов в одном месте** (док + единый frontmatter-API): гейты + (reviewer→`verdict:`, tester→`result:`, deployer→`deploy_status:`, staging→`staging_status:`, + security→`security_status:`) читают СТАНДАРТНЫЕ поля через единый frontmatter-API, а не + через разрознённые ad-hoc парсеры. +- Обновление документации (CLAUDE.md, architecture/README, ADR — глобальный и per-work-item, + CHANGELOG). + +### Вне объёма +- **Правка промптов агентов** (`.openclaw/agents/*.md`), чтобы те эмитили новую полную схему + — это **ORCH-52d** (слой 3). +- **Ретро-фит старых документов** (дописывание новой схемы в уже существующие work-items). +- Изменение `STAGE_TRANSITIONS` и **состава** `QG_CHECKS` (какие гейты существуют). +- Изменение **семантики** вердиктов (какое значение → какой переход) — только КАК они + читаются. +- Включение hard-fail валидации схемы по умолчанию (дефолт — warning; hard-fail только под + явно включённым kill-switch). + +## 3. Заинтересованные стороны + +- **Заказчик / Owner** — Слава (homenet542): подтверждает BRD (ручной гейт остаётся ручным). +- **Самообслуживаемый инструмент (self-hosting)** — оркестратор правит сам себя; задача — + первый боевой тест `autoDeploy` (см. примечание ниже). +- **Затрагиваемые роли конвейера** — reviewer / tester / deployer / security-гейт (их + вердикты теперь читаются через единый API); architect/analyst (новая обязательная схема + для будущих документов, фактическое внедрение — ORCH-52d). +- **Другие проекты (enduro-trails)** — НЕ должны почувствовать изменений (нулевая регрессия). + +## 4. Бизнес-требования (BR) + +- **BR-1** — `src/frontmatter.py` предоставляет полный набор операций над YAML-frontmatter: + **reader** (сохранён без изменения контракта), **writer** (сериализация frontmatter в + документ), **валидатор** (проверка обязательной схемы). +- **BR-2** — Обязательная схема frontmatter определена и проверяема: поля `work_item`, + `stage`, `author_agent`, `status`, `created_at`, `model_used`. +- **BR-3** — Создана формальная спека handoff в `docs/_standards/`, согласованная с + `PIPELINE_DOCS.md`: для каждой стадии указано, какие документы и какие frontmatter-ключи + она обязана оставить на выходе. +- **BR-4** — Контракт вердиктов сведён в ОДНО место; все пять гейтов-вердиктов + (review/staging/security/tester/deploy) читают стандартные поля через единый + frontmatter-API, а не через разрознённые парсеры. +- **BR-5** — Семантика вердиктов неизменна: то же значение → тот же переход/откат, что и + сейчас (включая трёх-полевой контракт tester'а ORCH-047 и токен-логику BLOCKED/FAILED). + +## 5. Нефункциональные требования (NFR) + +- **NFR-1 (обратная совместимость, критично self-hosting)** — Существующие документы-вердикты + БЕЗ новой полной схемы ПРОДОЛЖАЮТ читаться гейтами (fallback на текущее поведение). Старый + `12/13/14/15/17`-док без `work_item/stage/...` парсится по вердикт-ключу как раньше. +- **NFR-2 (never-raise / fail-safe)** — Ошибка writer'а или валидатора НЕ роняет конвейер + (тот же контракт, что у reader: любая ошибка → лог + безопасное значение, исключение + наружу не выходит). +- **NFR-3 (валидатор не self-block)** — Валидатор обязательной схемы НЕ является hard-fail + на гейте по умолчанию (иначе сама ORCH-52c заблокировала бы себя на собственном деплое, + т.к. её документы и документы соседей ещё без полной схемы). Дефолт — warning/лог; + жёсткость — под kill-switch (флаг). +- **NFR-4 (нулевая регрессия для enduro)** — Поведение для не-self-hosting репозиториев и + всех существующих гейтов остаётся 1:1; полный регресс `tests/` зелёный. +- **NFR-5 (обратимость)** — Поведенческие изменения (если есть, напр. строгая валидация) + закрываются kill-switch с дефолтом, эквивалентным прежнему поведению. + +## 6. Допущения и ограничения + +- Frontmatter везде в каноне — ведущий YAML-блок между `---` … `---` (как в `qg/checks.py` + и `frontmatter.py`). +- Источник истины о поведении гейтов остаётся КОД (`src/stages.py`, `src/qg/checks.py`, + `src/stage_engine.py`); спека/манифест документируют, а не управляют (правило ORCH-075). +- `model_used` в схеме — это модель, которой документ создан; фактический источник значения + для агентских доков — резолв `resolve_agent_model` (ORCH-41); проставление в реальные + документы агентами — ORCH-52d, вне scope. +- `pyyaml` уже зависимость проекта (используется во всех существующих парсерах). +- Реализационные решения (одна функция-парсер vs класс, точная сигнатура writer/валидатора, + имя модуля контракта вердиктов) — прерогатива архитектора (06-adr), здесь не предрешаются. + +## 7. Критерии успеха + +Задача успешна, если: `src/frontmatter.py` несёт reader+writer+валидатор обязательной схемы; +спека handoff создана и согласована с `PIPELINE_DOCS.md`; все пять гейтов-вердиктов читают +через единый frontmatter-API; старые доки-вердикты продолжают проходить гейты (анти-регресс); +ошибка writer/валидатора не роняет конвейер, hard-fail валидации под kill-switch (дефолт — +warning); `STAGE_TRANSITIONS` и состав `QG_CHECKS` не изменены, семантика вердиктов неизменна; +документация обновлена; **сама ORCH-52c проходит свои гейты** (включая первый боевой +`autoDeploy`). Детальные PASS/FAIL — `03-acceptance-criteria.md`. + +## 8. Риски + +- **Регресс чтения вердикта на гейте** → остановка конвейера всех проектов (главный риск + self-hosting). Митигация — строгая обратная совместимость + полный регресс тестов гейтов. +- **Самоблокировка валидатором** на собственном деплое (документы без полной схемы). + Митигация — NFR-3 (валидатор не hard-fail по умолчанию). +- **Расхождение спеки handoff с фактом кода** → «лживый» стандарт. Митигация — согласование + с `PIPELINE_DOCS.md` и явная пометка «источник истины — код». +- **Первый боевой `autoDeploy`** — авто-подтверждение прод-деплоя орка (см. примечание). + Детали митигации/наблюдения — задача архитектора (`10-tech-risks.md`). + +> **Примечание (АВТО-ДЕПЛОЙ).** На этой задаче выставлен лейбл `autoDeploy` (ORCH-089): орк +> САМ подтверждает прод-деплой после зелёного staging + всех тех-гейтов. BRD-гейт остаётся +> ручным (Слава подтверждает BRD). Это первый боевой тест `autoDeploy`. diff --git a/docs/work-items/ORCH-076/02-trz.md b/docs/work-items/ORCH-076/02-trz.md new file mode 100644 index 0000000..bf2632f --- /dev/null +++ b/docs/work-items/ORCH-076/02-trz.md @@ -0,0 +1,124 @@ +# 02 — ТЗ (TRZ): ORCH-076 — ORCH-52c: протокол handoff + frontmatter-контракт (writer/валидатор/схема) + +Work Item: **ORCH-076** · Repo: **orchestrator** · Стадия: analysis + +> ТЗ описывает **конкретные изменения к реализации**, выведенные из BRD и фактического кода. +> Архитектурное обоснование/решения (как именно структурировать модуль контракта вердиктов, +> точные сигнатуры) — задача архитектора (06-adr). + +## 1. Сводка изменения + +ORCH-52c превращает `src/frontmatter.py` из single-key reader в полный frontmatter-контракт +(**reader + writer + валидатор обязательной схемы**) и сводит **разрознённое чтение вердиктов** +гейтов к **единому frontmatter-API**, не меняя ни состав гейтов, ни семантику вердиктов. +Дополнительно создаётся **формальная спека handoff** в `docs/_standards/`, согласованная с +манифестом ORCH-52b (`PIPELINE_DOCS.md`). Всё строго обратно совместимо (старые доки читаются +как раньше), never-raise, валидатор не hard-fail по умолчанию (kill-switch). + +## 2. Задействованные модули / пути + +| Путь | Действие | +|------|----------| +| `src/frontmatter.py` | **изменить** — добавить writer + валидатор + чтение всего frontmatter (multi-key/dict); reader `read_frontmatter_value` сохранить (контракт неизменен) | +| `src/qg/checks.py` | **изменить** — `check_reviewer_verdict`, `_parse_tests_verdict`, `_parse_deploy_status`, `_parse_staging_status` перевести на чтение через единый frontmatter-API (поведение/токены/семантика 1:1) | +| `src/security_gate.py` | **изменить** — `parse_security_status` читает `security_status:` через единый API (семантика 1:1) | +| `src/post_deploy.py` | **изменить (по решению архитектора)** — чтение `post_deploy_status:` через единый API (информационный, не гейт) | +| `src/review_parse.py` | **возможно изменить** — `_strip_frontmatter` может использовать общий хелпер; контракт «never raise → ""» сохранить | +| `src/config.py` | **изменить** — добавить kill-switch строгой валидации (напр. `frontmatter_validation_strict: bool = False`) | +| `docs/_standards/HANDOFF_PROTOCOL.md` (имя — на усмотрение архитектора/стандарта) | **создать** — формальная спека handoff «стадия → обязательный выход» | +| `docs/_standards/PIPELINE_DOCS.md` | **изменить** — связать со спекой handoff, отметить что ORCH-52c реализовала машинный контракт | +| `tests/test_frontmatter.py` | **создать** — unit на reader/writer/валидатор/round-trip | +| `tests/` (гейты) | **изменить/создать** — анти-регресс тесты чтения вердиктов через новый API | +| `CLAUDE.md`, `docs/architecture/README.md`, `CHANGELOG.md`, ADR | **изменить/создать** — документация | + +## 3. Функциональные требования + +### FR-1 — Writer frontmatter (BR-1) +В `src/frontmatter.py` добавить функцию записи: принимает данные frontmatter (mapping +ключ→значение) и тело документа, возвращает/записывает строку с каноничным ведущим +YAML-блоком `---\n…\n---\n`. Формат на 100% совместим с существующими парсерами +(`split("---", 2)` + `yaml.safe_load`). **never-raise** (NFR-2): ошибка сериализации/записи → +лог + безопасный результат, исключение наружу не выходит. Точная сигнатура (in-memory render +vs запись в файл, перезапись существующего frontmatter) — решение архитектора. + +### FR-2 — Валидатор обязательной схемы (BR-2, NFR-3) +В `src/frontmatter.py` добавить валидатор, проверяющий наличие обязательных полей схемы: +`work_item`, `stage`, `author_agent`, `status`, `created_at`, `model_used`. Возвращает +структурированный результат (список отсутствующих/невалидных полей + признак валидности). +**Поведение по умолчанию — warning/лог, НЕ blocker** (NFR-3): отсутствие полей не роняет +конвейер и не заваливает гейт. Жёсткость (hard-fail) включается ТОЛЬКО kill-switch'ем +`frontmatter_validation_strict` (дефолт `False`). never-raise. + +### FR-3 — Полночтение frontmatter / единый reader-API (BR-1, BR-4) +В `src/frontmatter.py` добавить чтение ВСЕГО frontmatter как mapping (а не только single-key), +поверх которого строится единый доступ к вердикт-полям. Существующий +`read_frontmatter_value(path, key)` сохраняется без изменения контракта (обратная +совместимость вызывающих — `notifications.build_status_comment` и т.п.). never-raise. + +### FR-4 — Единый контракт чтения вердиктов (BR-4, BR-5, NFR-1) +Пять гейтов-вердиктов читают свои стандартные поля через единый frontmatter-API: + +| Гейт / парсер | Документ | Стандартное поле | Семантика (НЕИЗМЕННА) | +|---------------|----------|------------------|------------------------| +| `check_reviewer_verdict` | `12-review.md` | `verdict:` | `APPROVED`→дальше; `REQUEST_CHANGES`→откат на development | +| `_parse_tests_verdict` | `13-test-report.md` | `result:` / `verdict:` / `status:` (3 равноранговых, ORCH-047) | `PASS`→дальше; `FAIL`/`BLOCKED`→откат; негативный токен авторитетен | +| `_parse_deploy_status` | `14-deploy-log.md` | `deploy_status:` | `SUCCESS`→done; `FAILED`→откат (БАГ-8) | +| `_parse_staging_status` | `15-staging-log.md` | `staging_status:` | `SUCCESS`→дальше; `FAILED`→откат (self-hosting; иначе N/A) | +| `parse_security_status` | `17-security-report.md` | `security_status:` | `PASS`→дальше; `FAIL`→откат | + +Требование: **только механизм чтения** унифицируется (одна точка парсинга YAML-frontmatter); +наборы токенов (`_TESTS_NEGATIVE_TOKENS`/`_TESTS_POSITIVE_TOKENS`), приведение к верхнему +регистру, обработка «no frontmatter / bad YAML / missing key», fallback `worktree → origin/main` +для deploy/staging — сохраняются 1:1. Возврат каждого `check_*` — прежний `tuple[bool, str]`. + +### FR-5 — Обратная совместимость старых доков (NFR-1, критично) +Документ-вердикт БЕЗ новых полей схемы (`work_item/stage/author_agent/status/created_at/ +model_used`), но с вердикт-ключом (`verdict:`/`result:`/`deploy_status:`/…) ДОЛЖЕН читаться +гейтом ровно как сейчас. Новая схема — аддитивна; её отсутствие не влияет на чтение вердикта. + +### FR-6 — Спека handoff (BR-3) +Создать в `docs/_standards/` формальную спеку «стадия → обязательный выход»: для каждой стадии +(`created`→`analysis`→`architecture`→`development`→`review`→`testing`→`deploy-staging`→`deploy` +→`done`) перечислить обязательные документы и обязательные frontmatter-ключи на выходе. +Согласовать с таблицей §2 `PIPELINE_DOCS.md` (тот же набор документов/ключей/гейтов), явно +указать «источник истины — код». Различать machine-verdict доки и информационные (как в +`PIPELINE_DOCS.md` §3). + +## 4. Изменения API + +Нет. HTTP-эндпоинты не добавляются/не меняются. (Опционально архитектор может предложить блок +наблюдаемости в `GET /queue` для счётчика валидации — НЕ требование данной задачи.) + +## 5. Изменения схемы БД + +Нет. Таблицы/миграции/индексы не затрагиваются. Контракт работает на файлах +(YAML-frontmatter) и in-memory. + +## 6. Требования к новым/изменённым QG checks + +- **Состав `QG_CHECKS` НЕ изменяется** (никаких новых/удалённых зарегистрированных гейтов) — + AC-6 / правило CLAUDE.md. +- Изменяется только **внутренняя реализация чтения вердикта** существующих `check_*`/`_parse_*` + (делегирование единому frontmatter-API). Сигнатуры и возвращаемые значения (`tuple[bool,str]`) + — неизменны. +- Новый kill-switch `frontmatter_validation_strict` (config) управляет жёсткостью валидатора + схемы; дефолт `False` (warning-only) → нулевая поведенческая регрессия. + +## 7. Совместимость / регресс + +- **Обратная совместимость (NFR-1):** старые доки-вердикты без новой схемы читаются как + раньше; контракт `read_frontmatter_value` неизменен; формат writer'а совместим с + существующими парсерами. +- **never-raise (NFR-2):** writer/валидатор/единый reader не выбрасывают исключений в + конвейер (паттерн текущего `frontmatter.py`). +- **kill-switch / обратимость (NFR-3, NFR-5):** `frontmatter_validation_strict=False` (дефолт) + → валидация только логирует; `True` → строгий режим (на будущее). Поведение деградирует к + прежнему при дефолтном флаге. +- **Неизменность контрактов (AC-6):** `STAGE_TRANSITIONS`, состав `QG_CHECKS`, семантика + вердиктов, fallback `worktree→origin/main`, трёх-полевой контракт tester (ORCH-047), + токен-логика BLOCKED/FAILED — без изменений. +- **Нулевая регрессия enduro (NFR-4):** для не-self-hosting репо поведение 1:1; условные гейты + (ORCH-35/43/58) не затрагиваются по существу. +- **Полный регресс `tests/` зелёный** перед мержем. +- **self-hosting:** не перезапускать прод-контейнер вручную; деплой через штатный путь; + первый боевой `autoDeploy` (наблюдение — за стадией deploy). diff --git a/docs/work-items/ORCH-076/03-acceptance-criteria.md b/docs/work-items/ORCH-076/03-acceptance-criteria.md new file mode 100644 index 0000000..978b7f2 --- /dev/null +++ b/docs/work-items/ORCH-076/03-acceptance-criteria.md @@ -0,0 +1,104 @@ +# 03 — Критерии приёмки (Acceptance Criteria): ORCH-076 — ORCH-52c: протокол handoff + frontmatter-контракт + +Work Item: **ORCH-076** · Repo: **orchestrator** · Стадия: analysis + +Формат: каждый критерий имеет **PASS** (что должно быть истинно для приёмки) и **FAIL** +(что считается провалом). Любой машинный/ручной reviewer проверяет их буквально по файлам +репозитория. Критерии прямо отражают AC из постановки задачи (AC-1…AC-7). + +--- + +## AC-1 — frontmatter: reader + writer + валидатор + +**Условие:** `src/frontmatter.py` несёт полный контракт. +- **PASS:** в `src/frontmatter.py` есть (а) сохранённый reader `read_frontmatter_value` с + прежним контрактом; (б) **writer** (запись/рендер YAML-frontmatter); (в) **валидатор** + обязательной схемы, проверяющий поля `work_item`, `stage`, `author_agent`, `status`, + `created_at`, `model_used`. Все три покрыты unit-тестами. +- **FAIL:** отсутствует writer ИЛИ валидатор; или валидатор не проверяет полный список из + 6 обязательных полей; или контракт reader сломан (изменена сигнатура/поведение). + +--- + +## AC-2 — спека handoff создана и согласована + +**Условие:** формальный контракт handoff в `docs/_standards/`. +- **PASS:** в `docs/_standards/` создан документ-спека, где для КАЖДОЙ стадии указано, какие + документы и какие frontmatter-ключи она обязана оставить на выходе; набор документов/ключей/ + гейтов согласован с `PIPELINE_DOCS.md` §2–§3 (нет противоречий); `PIPELINE_DOCS.md` + обновлён ссылкой на спеку и отметкой о реализации машинного контракта в ORCH-52c. +- **FAIL:** спека отсутствует, не в `docs/_standards/`, покрывает не все стадии, или + противоречит `PIPELINE_DOCS.md` (другой набор ключей/документов). + +--- + +## AC-3 — единый контракт вердиктов + +**Условие:** гейты читают вердикты через единый frontmatter-API. +- **PASS:** контракт вердиктов сведён в ОДНО место (единый frontmatter-API); все пять + вердикт-точек — `check_reviewer_verdict` (`verdict:`), `_parse_tests_verdict` + (`result:`/`verdict:`/`status:`), `_parse_deploy_status` (`deploy_status:`), + `_parse_staging_status` (`staging_status:`), `parse_security_status` (`security_status:`) — + парсят YAML-frontmatter через этот API, а не дублированной ad-hoc логикой. +- **FAIL:** хотя бы один из пяти гейтов по-прежнему содержит собственную дублированную + реализацию парсинга YAML-frontmatter вместо единого API. + +--- + +## AC-4 — анти-регресс: старые доки читаются, ORCH-52c проходит свои гейты (критично self-hosting) + +**Условие:** обратная совместимость + самопрохождение. +- **PASS:** документ-вердикт БЕЗ новой полной схемы (только с вердикт-ключом) читается гейтом + ровно как до задачи (подтверждено тестом для каждого из пяти гейтов); полный регресс + `tests/` зелёный; **сама ORCH-52c проходит свои гейты** (review→testing→staging→deploy) + и доезжает до `done`. +- **FAIL:** любой старый док-вердикт перестал читаться/изменил вердикт; регресс `tests/` + красный; задача застряла/откатилась на собственном гейте из-за нового контракта. + +--- + +## AC-5 — never-raise + валидатор не hard-fail по умолчанию (kill-switch) + +**Условие:** fail-safe и не-самоблокирующая валидация. +- **PASS:** ошибка writer'а/валидатора логируется и НЕ роняет конвейер (исключение наружу не + выходит, подтверждено тестом на битом вводе); валидация обязательной схемы по умолчанию — + warning/лог, НЕ blocker; hard-fail доступен ТОЛЬКО под kill-switch + (`frontmatter_validation_strict`, дефолт `False`). +- **FAIL:** ошибка writer/валидатора пробрасывается в конвейер; ИЛИ отсутствие полей схемы + по умолчанию заваливает гейт/останавливает задачу; ИЛИ нет kill-switch для строгого режима. + +--- + +## AC-6 — STAGE_TRANSITIONS и состав QG_CHECKS не изменены; семантика неизменна + +**Условие:** инварианты конвейера. +- **PASS:** `src/stages.py::STAGE_TRANSITIONS` и реестр `QG_CHECKS` (`src/qg/checks.py`) — + без изменений по составу (те же стадии, те же зарегистрированные гейты); семантика каждого + вердикта (значение → переход/откат) идентична прежней, включая ORCH-047 (3 равноранговых + поля tester) и приоритет негативного токена. +- **FAIL:** изменён состав `STAGE_TRANSITIONS`/`QG_CHECKS`; или хоть один вердикт даёт другой + переход при том же значении, что до задачи. + +--- + +## AC-7 — документация обновлена + +**Условие:** golden-source документации синхронна с кодом. +- **PASS:** обновлены `CLAUDE.md`, `docs/architecture/README.md`, `CHANGELOG.md`; заведён + ADR per-work-item (`docs/work-items/ORCH-076/06-adr/ADR-001-*.md`) и сквозной + (`docs/architecture/adr/adr-NNNN-*.md`); спека handoff и `PIPELINE_DOCS.md` согласованы. +- **FAIL:** функционал изменён, но доки/ADR/CHANGELOG не обновлены (reviewer → + REQUEST_CHANGES по правилу CLAUDE.md №6). + +--- + +## Сводная матрица AC ↔ FR/BR +| AC | Покрывает | +|----|-----------| +| AC-1 | BR-1 / BR-2 / FR-1 / FR-2 / FR-3 | +| AC-2 | BR-3 / FR-6 | +| AC-3 | BR-4 / FR-4 | +| AC-4 | NFR-1 / NFR-4 / FR-5 | +| AC-5 | NFR-2 / NFR-3 / NFR-5 / FR-2 | +| AC-6 | BR-5 / NFR-1 | +| AC-7 | правило CLAUDE.md №2/№6 | diff --git a/docs/work-items/ORCH-076/04-test-plan.yaml b/docs/work-items/ORCH-076/04-test-plan.yaml new file mode 100644 index 0000000..d50ef2b --- /dev/null +++ b/docs/work-items/ORCH-076/04-test-plan.yaml @@ -0,0 +1,122 @@ +work_item: ORCH-076 +title: "ORCH-52c — handoff-протокол + frontmatter writer/валидатор/единый контракт вердиктов" +framework: pytest +scope: > + Покрывается: writer/валидатор/единое чтение frontmatter (src/frontmatter.py); + чтение пяти гейтов-вердиктов через единый API при семантике 1:1; обратная + совместимость старых доков без новой схемы; never-raise; kill-switch строгой + валидации. Вне покрытия: правка промптов агентов (ORCH-52d), ретро-фит старых + документов, изменение STAGE_TRANSITIONS/состава QG_CHECKS. +notes: > + Полный регресс tests/ должен оставаться зелёным (анти-регресс гейтов, AC-4/AC-6). + Регресс = любой существующий тест гейтов (review/tester/deploy/staging/security), + ставший красным, или изменение вердикта при том же входном значении. + Тесты не должны требовать сети (frontmatter — файловый/in-memory контракт). + +tests: + # --- frontmatter.py: writer / валидатор / reader (AC-1, AC-5) --- + - id: TC-01 + type: unit + description: "Writer сериализует mapping в каноничный ведущий YAML-frontmatter (--- ... ---), читаемый существующими парсерами" + module: tests/test_frontmatter.py + expected: PASS + + - id: TC-02 + type: unit + description: "Round-trip: writer записал frontmatter -> reader read_frontmatter_value возвращает те же значения по ключам" + module: tests/test_frontmatter.py + expected: PASS + + - id: TC-03 + type: unit + description: "Валидатор: полная схема (work_item/stage/author_agent/status/created_at/model_used) -> valid=True, нет отсутствующих полей" + module: tests/test_frontmatter.py + expected: PASS + + - id: TC-04 + type: unit + description: "Валидатор: отсутствие части обязательных полей -> valid=False со списком отсутствующих, но БЕЗ исключения (warning-only по умолчанию)" + module: tests/test_frontmatter.py + expected: PASS + + - id: TC-05 + type: unit + description: "never-raise: writer и валидатор на битом вводе (None/не-mapping/нечитаемый путь/битый YAML) не выбрасывают исключение, возвращают безопасное значение + лог" + module: tests/test_frontmatter.py + expected: PASS + + - id: TC-06 + type: unit + description: "reader read_frontmatter_value сохраняет прежний контракт (single-key, None на ошибку/отсутствие, strip, регистр сохранён)" + module: tests/test_frontmatter.py + expected: PASS + + - id: TC-07 + type: unit + description: "kill-switch frontmatter_validation_strict: False -> отсутствие полей не блокирует; True -> строгий режим сигнализирует невалидность" + module: tests/test_frontmatter.py + expected: PASS + + # --- единый контракт вердиктов: чтение через общий API, семантика 1:1 (AC-3, AC-6) --- + - id: TC-08 + type: unit + description: "check_reviewer_verdict через единый API: verdict: APPROVED -> (True); REQUEST_CHANGES -> (False); отсутствие -> (False) — как до задачи" + module: tests/test_qg_verdicts.py + expected: PASS + + - id: TC-09 + type: unit + description: "_parse_tests_verdict через единый API: ORCH-047 три равноранговых поля (result/verdict/status), приоритет негативного токена (BLOCKED/FAILED) сохранён" + module: tests/test_qg_verdicts.py + expected: PASS + + - id: TC-10 + type: unit + description: "_parse_deploy_status через единый API: deploy_status SUCCESS -> (True); FAILED -> (False); missing/bad YAML -> (False) — семантика БАГ-8 неизменна" + module: tests/test_qg_verdicts.py + expected: PASS + + - id: TC-11 + type: unit + description: "_parse_staging_status через единый API: SUCCESS/FAILED семантика и условность ORCH-35 (non-self -> N/A pass) сохранены" + module: tests/test_qg_verdicts.py + expected: PASS + + - id: TC-12 + type: unit + description: "parse_security_status через единый API: security_status PASS -> (True); FAIL -> (False) — семантика неизменна" + module: tests/test_security_gate.py + expected: PASS + + # --- обратная совместимость / анти-регресс (AC-4) --- + - id: TC-13 + type: unit + description: "Старый док-вердикт БЕЗ новой схемы (только verdict/result/deploy_status/staging_status/security_status) читается каждым из пяти гейтов как до задачи" + module: tests/test_qg_verdicts.py + expected: PASS + + - id: TC-14 + type: unit + description: "Док С новой полной схемой + вердикт-ключом читается гейтом с тем же вердиктом, что и без схемы (схема аддитивна, не влияет на вердикт)" + module: tests/test_qg_verdicts.py + expected: PASS + + - id: TC-15 + type: integration + description: "fallback worktree -> origin/main для check_deploy_status/check_staging_status сохранён при чтении через единый API" + module: tests/test_qg_verdicts.py + expected: PASS + + # --- инварианты конвейера (AC-6) --- + - id: TC-16 + type: unit + description: "Состав QG_CHECKS и STAGE_TRANSITIONS не изменён (тот же набор ключей/стадий, что эталон)" + module: tests/test_stages_invariants.py + expected: PASS + + # --- полный регресс --- + - id: TC-17 + type: integration + description: "Полный прогон tests/ зелёный (нет регресса существующих тестов гейтов и конвейера)" + module: tests/ + expected: PASS