From 75fb4069a4b5597a1c6f7d2799ae07a2060693f6 Mon Sep 17 00:00:00 2001 From: claude-bot Date: Fri, 5 Jun 2026 21:00:57 +0000 Subject: [PATCH] architect(ET): auto-commit from architect run_id=126 --- docs/architecture/README.md | 2 +- .../ADR-001-result-field-in-tests-gate.md | 80 +++++++++++++++++++ docs/work-items/ORCH-047/10-tech-risks.md | 10 +++ 3 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 docs/work-items/ORCH-047/06-adr/ADR-001-result-field-in-tests-gate.md create mode 100644 docs/work-items/ORCH-047/10-tech-risks.md diff --git a/docs/architecture/README.md b/docs/architecture/README.md index 3eef0ce..4baebe5 100644 --- a/docs/architecture/README.md +++ b/docs/architecture/README.md @@ -58,7 +58,7 @@ created → analysis → architecture → development → review → testing → ``` - **Длительность** считается launcher'ом (`_monitor_agent`) и пробрасывается в `_post_usage_comments`; для analyst (коммент строится в `stage_engine`) используется DB-фоллбэк `usage.get_agent_duration(task_id, agent)`. -- **Vердикт-парсер** — `src/frontmatter.read_frontmatter_value(...)` (defensive, никогда не raise). Машинные ключи: `verdict:` (reviewer/tester), `deploy_status:` (14-deploy-log.md), `staging_status:` (15-staging-log.md). +- **Vердикт-парсер** — `src/frontmatter.read_frontmatter_value(...)` (defensive, никогда не raise). Машинные ключи: reviewer → `verdict:` (12-review.md); **testing-гейт `check_tests_passed` (13-test-report.md) → любое из трёх равноправных: `result:` (канон промпта тестера), `verdict:`, `status:`** (ORCH-047, ADR-001); deployer → `deploy_status:` (14-deploy-log.md), `staging_status:` (15-staging-log.md). Negative-токен в любом поле авторитетен (перебивает positive). - Формат коммента **не** меняет реестр гейтов и стадий; коммент — отображение, не управление. ## База данных (SQLite) diff --git a/docs/work-items/ORCH-047/06-adr/ADR-001-result-field-in-tests-gate.md b/docs/work-items/ORCH-047/06-adr/ADR-001-result-field-in-tests-gate.md new file mode 100644 index 0000000..a5447c0 --- /dev/null +++ b/docs/work-items/ORCH-047/06-adr/ADR-001-result-field-in-tests-gate.md @@ -0,0 +1,80 @@ +# ADR-001: testing-гейт читает `result:` наравне с `verdict:`/`status:` + +- **Статус:** Accepted +- **Дата:** 2026-06-05 +- **Задача:** ORCH-047 +- **Область:** SHARED quality-gate `check_tests_passed` (общий прод-инстанс: orchestrator + enduro-trails) + +## Контекст + +Quality Gate `check_tests_passed` (`src/qg/checks.py`, парсер `_parse_tests_verdict`) гейтит +переход `testing → deploy-staging`, читая машиночитаемый вердикт ТОЛЬКО из YAML-frontmatter +артефакта `13-test-report.md` (канон гейтов: frontmatter, никогда не проза — см. +`docs/architecture/README.md`). + +Существует рассинхрон контракта между производителем и потребителем вердикта: + +- **Потребитель** (`_parse_tests_verdict`) читает поля `verdict:` и `status:`. +- **Производитель** (`.openclaw/agents/tester.md`, строки 51–56, 78–80) предписывает тестеру + эмитить машиночитаемое поле **`result: PASS|FAIL`** и НЕ упоминает `verdict:`/`status:`. + +Тестер, честно следуя своей инструкции, пишет `result: PASS` без `verdict:`/`status:`. Парсер +попадает в ветку «ни verdict, ни status не заданы» → `(False, "No machine-readable +verdict/status…")` → откат `testing → development` и петля до исчерпания +`MAX_DEVELOPER_RETRIES`. Это наблюдалось на ORCH-17; ORCH-016 прошёл лишь потому, что его отчёт +избыточно нёс И `verdict:`, И `result:`. + +Корень — несовпадение имён поля контракта, а не логики токенов. Наборы positive/negative-токенов +исправны и менять их нельзя (обратная совместимость с реальными отчётами enduro-trails +ET-001…ET-014). + +## Решение + +Привести контракт гейта к тому, что тестеру УЖЕ велено эмитить — со стороны гейта, не трогая +промпт тестера. + +1. `_parse_tests_verdict` читает **три равноправных** машиночитаемых поля из frontmatter: + `result:` (канон промпта тестера), `verdict:`, `status:` (легаси/enduro-trails). Достаточно + ЛЮБОГО одного непустого. +2. Семантика приоритетов сохраняется и распространяется на все три поля через объединённую строку + `fields = f"{verdict} {status} {result}"`: + - negative-токен (`_TESTS_NEGATIVE_TOKENS`) в любом поле → FAIL и **авторитетен** (проверяется + первым, перебивает positive в другом поле); + - иначе positive-токен (`_TESTS_POSITIVE_TOKENS`) в любом поле → PASS; + - ни одно из трёх не задано → FAIL («No machine-readable verdict/status/result…»); + - заданы, но не распознаны → FAIL. +3. Наборы токенов **не изменяются**. +4. Парсер не бросает исключений ни на каком вводе (битый YAML, пустой файл, frontmatter-не-mapping) + → всегда `(False, reason)`. +5. Сигнатура `check_tests_passed`, имя гейта и реестр `QG_CHECKS` **не меняются** — снапшот + `tests/test_qg_registry_snapshot.py` остаётся зелёным. + +### Альтернативы (отклонены) + +- **Править промпт тестера** (`verdict:` вместо `result:`) — отклонено: контракт уже задокументирован + для тестера как `result:`; единичная правка гейта дешевле и не требует переучивать агента, плюс + ломала бы совместимость со старыми отчётами, где встречается `verdict:`/`status:`. +- **Глобальный ADR в `docs/architecture/adr/`** — не требуется: изменение не добавляет гейт/стадию/ + компонент и не меняет топологию; это приведение парсинга существующего гейта к контракту. Канон + гейтов в README обновляется точечно. + +## Последствия + +- **Плюс:** корректные отчёты `result: PASS` проходят гейт; `result: FAIL` надёжно откатывает. + Петля `testing ↔ development` устранена для всех проектов общего инстанса. +- **Плюс:** полная обратная совместимость — отчёты только с `verdict:`/`status:` работают как + раньше; существующие тесты `TestCheckTestsPassed` зелёные без правок (кроме обновления reason-текста + «…verdict/status…» → «…verdict/status/result…»). +- **Минус/ограничение:** число распознаваемых имён поля растёт до трёх — формально шире поверхность + «случайного PASS». Митигируется тем, что negative-токен авторитетен и читается только frontmatter. +- **SHARED-риск:** изменение затрагивает enduro-trails наравне с orchestrator. Регресс по наборам + токенов недопустим → они заморожены; покрытие — `04-test-plan.yaml` (AC-04/AC-05). +- **Self-hosting:** деплой строго через `deploy-staging` (8501); прод-контейнер `orchestrator` + (8500) не перезапускать в рамках разработки/тестинга. + +## Связи + +- BRD/ТЗ: `docs/work-items/ORCH-047/01-brd.md`, `02-trz.md`. +- Канон гейтов и вердикт-парсер: `docs/architecture/README.md`. +- Промпт-производитель: `.openclaw/agents/tester.md` (`result: PASS|FAIL`). +- adr-0003 (staging-гейт) — обязательная страховка перед прод-деплоем self. diff --git a/docs/work-items/ORCH-047/10-tech-risks.md b/docs/work-items/ORCH-047/10-tech-risks.md new file mode 100644 index 0000000..45fa9ed --- /dev/null +++ b/docs/work-items/ORCH-047/10-tech-risks.md @@ -0,0 +1,10 @@ +# Технические риски — ORCH-047 + +| # | Риск | Вероятность | Влияние | Митигация | +|---|------|-------------|---------|-----------| +| R-1 | Регресс набора токенов ломает enduro-trails (SHARED-гейт, общий прод-инстанс) | Низкая | Высокое | Наборы `_TESTS_NEGATIVE_TOKENS`/`_TESTS_POSITIVE_TOKENS` **заморожены** (не трогать). Покрытие AC-05 на реальных формах ET-001…ET-014 + ORCH-016. | +| R-2 | Новое поле `result:` расширяет поверхность ложного PASS | Низкая | Среднее | Negative-токен авторитетен (проверяется первым, перебивает positive). Читается только frontmatter, не проза (AC-03, AC-06, AC-07). | +| R-3 | Парсер бросает исключение на битом вводе → падение `_run_qg` | Низкая | Высокое | Defensive-контракт сохранён: любой ввод (нет frontmatter / битый YAML / не-mapping / пустой) → `(False, reason)`, никогда raise (AC-08). | +| R-4 | Незаметное изменение реестра гейтов | Очень низкая | Среднее | Сигнатура, имя гейта и `QG_CHECKS` неизменны; снапшот `tests/test_qg_registry_snapshot.py` зелёный (AC-10). | +| R-5 | Self-hosting: деплой роняет прод-контейнер всех проектов | Низкая | Высокое | Деплой только через `deploy-staging` (8501); прод `orchestrator` (8500) не перезапускать в dev/test (CLAUDE.md, adr-0003). | +| R-6 | Изменение поведения без обновления golden-source доки → REQUEST_CHANGES на review | Средняя | Низкое | ADR-001 заведён; `docs/architecture/README.md` (вердикт-парсер) обновлён архитектором; `CHANGELOG.md` — дев в том же PR (AC-11). |