Files
wiki/tasks/orchestrator/reports/dev-2026-06-04-tests-verdict-fix.md
2026-06-04 16:10:01 +03:00

97 lines
7.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Dev Report: orchestrator — check_tests_passed машинный вердикт (ET-013 fix)
Дата: 2026-06-04
Статус: DONE
## Задача
`check_tests_passed` (src/qg/checks.py:139) гейтила стадию testing→deploy наивным
substring-поиском `if "PASS" in content` по всему телу `13-test-report.md`. На ET-013
тестер выставил `verdict: BLOCKED` / `status: blocked` (провален P1 AC-19), но в теле
были слова «23 passed», «✅ PASS», «All checks passed» → substring нашёлся → True →
недоделанная фича уехала в deploy и доползла до Done. Нужно привести функцию к
машинному контракту, как у уже починённых `check_reviewer_verdict` и `check_deploy_status`.
## Сделано
- [x] ШАГ 0: изучил `check_reviewer_verdict` (эталон, читает `verdict:` из frontmatter)
- [x] Собрал РЕАЛЬНЫЕ значения вердикта по прошлым отчётам ET-001..ET-014
- [x] Переписал `check_tests_passed` + добавил `_parse_tests_verdict` (зеркало эталона)
- [x] Обновил/расширил тесты `TestCheckTestsPassed` (3 → 11 тестов)
- [x] Прогнал unit + полный pytest
- [x] Провалидировал на РЕАЛЬНЫХ отчётах прод-репозитория
- [x] Ветка `fix/tests-machine-verdict`, push, PR #24 (НЕ мержил)
## Изменённые файлы
- `src/qg/checks.py``check_tests_passed` теперь читает ТОЛЬКО frontmatter; новый
helper `_parse_tests_verdict`. НЕ трогал check_reviewer_verdict / check_deploy_status.
- `tests/test_qg.py` — класс `TestCheckTestsPassed` переписан под машинный контракт.
## Положительные значения вердикта по РЕАЛЬНЫМ образцам (verbatim)
| WI | verdict (raw) | status (raw) | трактовка |
|--------|-----------------------------|---------------------|-----------|
| ET-001 | `PASS` | `pass` | ✅ True |
| ET-002 | `PASS` | `pass` | ✅ True |
| ET-005 | `PASS` | `pass` | ✅ True |
| ET-006 | `ready-to-deploy` | `PASSED` | ✅ True |
| ET-007 | `PASS — ready-to-deploy` | `PASS` | ✅ True |
| ET-008 | `stage:ready-to-deploy` | `pass` | ✅ True |
| ET-009 | `PASS` | `PASS` | ✅ True |
| ET-011 | `PASS` | (нет) | ✅ True |
| ET-012 | `PASS` | `ready-to-deploy` | ✅ True |
| ET-013 | `BLOCKED` | `blocked` | ❌ False |
| ET-014 | `PASS` | (нет) | ✅ True |
**Вывод:** поле `verdict` у тестера НЕ единообразно. Чисто `verdict == "PASS"`
сломал бы ET-006 (`ready-to-deploy`) и ET-008 (`stage:ready-to-deploy`). Поэтому:
- **Positive tokens** (нормализация `.upper().strip()`, поиск токена в `verdict`+`status`):
`PASSED`, `PASS`, `READY-TO-DEPLOY`, `READY_TO_DEPLOY`, `GREEN`, `APPROVED`.
- **Negative tokens (авторитетны)**: `BLOCKED`, `FAILED`, `FAIL`, `REQUEST_CHANGES`, `REJECT`, `RED`.
- Логика: нет frontmatter / битый YAML / нет ни verdict ни status → False с причиной;
негативный токен в любом из полей → False (перебивает любой PASS); иначе позитивный
токен → True; иначе → False. Никогда не падает.
## Результат — до/после на ET-013 (на реальном файле прод-репо)
- **До:** substring `"PASS"` в теле → `(True, "Test report indicates PASS")` → deploy.
- **После:** `_parse_tests_verdict``(False, 'Test verdict: BLOCKED (BLOCKED)')` → блок.
Прогон на РЕАЛЬНЫХ отчётах (`/repos/_wt/enduro-trails/feature_ET-014-ui-z-index`):
```
ET-001 (True, 'Test verdict: PASS (PASS)')
ET-005 (True, 'Test verdict: PASS (PASS)')
ET-006 (True, 'Test verdict: READY-TO-DEPLOY (PASS)')
ET-007 (True, 'Test verdict: PASS — READY-TO-DEPLOY (PASS)')
ET-008 (True, 'Test verdict: STAGE:READY-TO-DEPLOY (PASS)')
ET-009 (True, 'Test verdict: PASS (PASS)')
ET-011 (True, 'Test verdict: PASS (PASS)')
ET-012 (True, 'Test verdict: PASS (PASS)')
ET-013 (False, 'Test verdict: BLOCKED (BLOCKED)') <-- bug fixed
ET-014 (True, 'Test verdict: PASS (PASS)')
```
Все 9 ранее прошедших WI остаются True; ET-013 → False. Регрессий нет.
## Обратная совместимость
Строгий машинный контракт сохранён БЕЗ ослабления: у всех реальных прошедших отчётов
ЕСТЬ frontmatter с положительным `verdict:`/`status:`, поэтому fallback на тело не нужен.
Единственная «несовместимость» была в старых pytest-фикстурах (`Result: PASS` в теле без
frontmatter) — они описывали старое substring-поведение. Согласно ТЗ их ПОЧИНИЛ под новый
контракт (добавил frontmatter `verdict:`), а не ослабил проверку. Отсутствие frontmatter
теперь = False (`test_no_frontmatter_fails`).
## Тесты (pytest, прод-контейнер на /repos/orchestrator)
- `TestCheckTestsPassed`: **11 passed** (включая главный кейс ET-013, FAILED, "23 passed"
в теле при BLOCKED, нет frontmatter, нет полей, битый YAML, файла нет).
- Полный прогон: **285 passed, 9 failed**. 9 failed = off-limits `test_webhooks.py`
HMAC/401 — подтверждено pre-existing: при застешенных моих правках на чистом main те же
webhook-тесты падают (их число плавает 910 от запуска к запуску, порядко-зависимы).
Мои изменения их не затрагивают (только `check_tests_passed` + его тесты).
*Прим.:* baseline в ТЗ заявлен 277+9; фактический на этом окружении 276+10 до правки →
285+9 после (net +9 passed: класс вырос 3→11 тестов, минус один плавающий webhook-фейл).
## Сдача
- Ветка: `fix/tests-machine-verdict` (от актуального origin/main, push выполнен).
- PR: **#24** — http://localhost:3000/admin/orchestrator/pulls/24
(внешний: https://git.mva154.duckdns.org/admin/orchestrator/pulls/24). НЕ мержил — на ревью Стрим.
- В main НЕ пушил.
## НЕ трогал
check_reviewer_verdict, check_deploy_status, gitea.py merge-gate, PLANE_STATES,
set_issue_done, launcher deployer-guard, HMAC, queue, stages.py mapping.