# 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).