# ТЗ — ORCH-047: `_parse_tests_verdict` читает `result:` наравне с `verdict:`/`status:` ## 1. Задействованные модули `src/` | Файл | Что меняется | |------|--------------| | `src/qg/checks.py` | Функция `_parse_tests_verdict` (стр. ~223–265). Добавить чтение поля `result:` из frontmatter и включить его в проверку токенов наравне с `verdict:`/`status:`. Обновить докстринг функции и `check_tests_passed`. | Точка входа `check_tests_passed(repo, work_item_id, branch)` (стр. ~182) и реестр `QG_CHECKS` НЕ меняются (сигнатура и имя гейта те же). ## 2. Требуемое поведение `_parse_tests_verdict` Вход — строковое тело `13-test-report.md`. Выход — `tuple[bool, str]`. 1. Нет frontmatter (`content` не начинается с `---`) → `(False, "No YAML frontmatter ...")`. 2. Frontmatter некорректен (split по `---` даёт < 3 частей) → `(False, "Malformed YAML frontmatter ...")`. 3. YAML не парсится → `(False, "Invalid YAML frontmatter ...: ")` (никогда не raise). 4. YAML не mapping → `(False, "Malformed YAML frontmatter ... (not a mapping)")`. 5. Прочитать три поля, нормализовать (`str(...).upper().strip()`, защита от `None`): - `verdict` - `status` - **`result` ← НОВОЕ** 6. Если ВСЕ три пусты → `(False, "No machine-readable verdict/status/result in test report frontmatter")`. 7. Собрать объединённую строку полей `fields = f"{verdict} {status} {result}"`. 8. Если в `fields` встречается ЛЮБОЙ negative-токен (`_TESTS_NEGATIVE_TOKENS`) → `(False, "Test verdict: <значение> ()")`. **Negative авторитетен** — проверяется ПЕРВЫМ, перебивает любой positive. 9. Иначе если встречается ЛЮБОЙ positive-токен (`_TESTS_POSITIVE_TOKENS`) → `(True, "Test verdict: <значение> (PASS)")`. 10. Иначе (заданы, но не распознаны) → `(False, "No recognized PASS verdict in frontmatter (...)")`. Наборы токенов НЕ изменяются (важно для обратной совместимости с enduro-trails): ```python _TESTS_NEGATIVE_TOKENS = ("BLOCKED", "FAILED", "FAIL", "REQUEST_CHANGES", "REJECT", "RED") _TESTS_POSITIVE_TOKENS = ("PASSED", "PASS", "READY-TO-DEPLOY", "READY_TO_DEPLOY", "GREEN", "APPROVED") ``` > Примечание для разработчика (порядок токенов): negative-список проверяется раньше positive — это даёт авторитетность отрицания. Внутри positive-набора `"PASSED"` идёт перед `"PASS"` лишь для аккуратного reason-текста; на результат (bool) порядок не влияет, т.к. это подстрочный поиск. ## 3. Контракт поля (golden source) После изменения машиночитаемыми полями testing-гейта считаются **три равноправных**: `result:` (канон промпта тестера), `verdict:`, `status:` (легаси/enduro-trails). Достаточно ЛЮБОГО одного. Это и есть приведение гейта к тому, что тестеру велено эмитить в `.openclaw/agents/tester.md` (`result: PASS|FAIL`). ## 4. Изменения API Нет. HTTP-эндпоинты (`/health`, `/status`, `/queue`, вебхуки) не затрагиваются. Сигнатуры функций гейта не меняются. ## 5. Изменения схемы БД Нет. ## 6. Требования к новым QG checks Новых гейтов нет. Меняется внутренняя логика существующего `check_tests_passed` (через `_parse_tests_verdict`). Реестр `QG_CHECKS` без изменений → снапшот-тест `tests/test_qg_registry_snapshot.py` должен остаться зелёным. ## 7. Артефакты pipeline (создать/обновить в этом PR) - `docs/work-items/ORCH-047/06-adr/ADR-001-*.md` — **обязательно** (правило 2 CLAUDE.md): ADR на изменение семантики SHARED testing-гейта (влияет на все проекты общего инстанса). Заводит архитектор. - `docs/architecture/README.md` — обновить строку о вердикт-парсере (раздел «Plane Sync», п. про машинные ключи): для testing-гейта перечислить `result:`/`verdict:`/`status:`. - `CHANGELOG.md` — запись `fix:` про ORCH-047. - `tests/test_qg.py` — добавить кейсы на `result:` (см. `04-test-plan.yaml`). ## 8. Нефункциональные требования - Парсер не бросает исключений ни на каком вводе. - Изменение читает только frontmatter, не прозу (канон гейтов). - Полная обратная совместимость: существующие тесты `TestCheckTestsPassed` остаются зелёными без правок (кроме, возможно, переименования reason-строки в п.6 BRD — текст причины «No machine-readable verdict/status...» обновляется на «...verdict/status/result...», соответствующий ассерт при наличии обновить). ## 9. Деплой Self-hosting: стандартный путь через `deploy-staging` (8501) перед прод-деплоем. Прод-контейнер `orchestrator` (8500) не перезапускать в рамках разработки/тестинга.