Files
wiki/tasks/orchestrator/reports/dev-2026-06-03-deploy-verdict-gate.md
2026-06-04 02:50:01 +03:00

136 lines
7.9 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: БАГ 8 — deploy verdict gate
Дата: 2026-06-03
Статус: DONE
## Задача
Завести QG `check_deploy_status` по образцу `check_reviewer_verdict`, гейтить deploy→done
на машинном вердикте deployer'а (`deploy_status:` из `14-deploy-log.md`), а не на exit_code
LLM-процесса (всегда 0). PR в main, НЕ мержить/деплоить.
## Сделано
- [x] Ветка `fix/deploy-verdict-gate` из свежего main (a0621b9, PR#18)
- [x] Правка 1: `check_deploy_status` + регистрация в QG_CHECKS
- [x] Правка 2: `stages.py` deploy qg None → check_deploy_status
- [x] Правка 3: вердикт-проверка в advance deploy→done
- [x] Тесты: +7 (test_qg) +3 (test_stage_engine), все зелёные
- [x] Commit + push, remote проверен (ORCH-7), PR #19
- [x] Правка 4: НЕ трогал (enduro-trails) — см. ниже
## Изменённые файлы
- `src/qg/checks.py` — новая функция `check_deploy_status` + запись в QG_CHECKS
- `src/stages.py` — deploy `"qg": None``"qg": "check_deploy_status"`
- `src/stage_engine.py` — новая deployer-ветка в `_handle_qg_failure_rollbacks`
- `tests/test_qg.py` — class TestCheckDeployStatus (7 тестов)
- `tests/test_stage_engine.py` — class TestDeployVerdict (3 теста)
## Правка 1 — точный код check_deploy_status (src/qg/checks.py)
```python
def check_deploy_status(repo: str, work_item_id: str, branch: str | None = None) -> tuple[bool, str]:
"""
БАГ 8 fix: gate the deploy -> done transition on the deployer's machine-readable
verdict in 14-deploy-log.md frontmatter, NOT on the LLM process exit code
(which is always 0 on a successful agent session even when the deploy failed).
Mirrors check_reviewer_verdict (S-5): reads ONLY `deploy_status:` from YAML
frontmatter. Returns:
(True, ...) -> deploy_status: SUCCESS
(False, ...) -> deploy_status: FAILED, missing field, or no frontmatter
"""
import yaml
repo_path = _repo_path(repo, branch)
log_path = os.path.join(repo_path, f"docs/work-items/{work_item_id}/14-deploy-log.md")
if not os.path.isfile(log_path):
return False, "Deploy log not found (14-deploy-log.md)"
try:
with open(log_path, "r") as f:
content = f.read()
status = None
if content.startswith("---"):
parts = content.split("---", 2)
if len(parts) >= 3:
try:
fm = yaml.safe_load(parts[1]) or {}
except yaml.YAMLError as e:
return False, f"Invalid YAML frontmatter in deploy log: {e}"
status = str(fm.get("deploy_status", "")).upper().strip()
if status == "SUCCESS":
return True, "Deploy status: SUCCESS"
if status == "FAILED":
return False, "Deploy status: FAILED"
return False, f"No machine-readable deploy_status in frontmatter (got: {status!r})"
except OSError as e:
return False, f"Error reading deploy log: {e}"
```
Регистрация в QG_CHECKS: `"check_deploy_status": check_deploy_status,` (после check_tests_local).
## Правка 2 — stages.py
`"deploy": {"next": "done", "agent": None, "qg": None}`
`"deploy": {"next": "done", "agent": None, "qg": "check_deploy_status"}`
## Правка 3 — ГДЕ нашёл advance deploy→done и как вписал вердикт
Auto-advance унифицирован в `src/stage_engine.py::advance_stage` (ORCH-4/M-3 merge).
launcher.py:_try_advance_stage (стр.648) — тонкий wrapper, который грузит task по (repo,branch)
и вызывает `advance_stage(current_stage=<db stage>, finished_agent=agent)`. Когда deployer
завершается, current_stage="deploy", finished_agent="deployer".
В `advance_stage` QG уже выполняется ГЕНЕРИЧЕСКИ:
- `qg_name = get_qg_for_stage("deploy")` теперь = "check_deploy_status";
- `_run_qg` → ветка «everything else» → `check_deploy_status(repo, work_item_id, branch)` (сигнатура совпала);
- SUCCESS (True) → блок Advance: update_task_stage(done)+notify (агент не запускается, agent=None);
- FAILED (False) → вызывается `_handle_qg_failure_rollbacks(...)`.
В `_handle_qg_failure_rollbacks` НЕ было ветки для deployer → ничего не происходило. Добавил
новую ветку (после architect-ветки, в конце функции), триггер по ВЕРДИКТУ не exit_code:
```python
if agent == "deployer" and qg_name == "check_deploy_status":
update_task_stage(task_id, "development")
notify_stage_change(task_id, current_stage, "development")
plane_notify_stage(work_item_id, current_stage, "development")
result.rolled_back_to = "development"
set_issue_blocked(work_item_id)
notify_qg_failure(task_id, "deploy", "check_deploy_status", reason)
plane_add_comment(work_item_id, "❌ Deploy FAILED (...). Rolled back ...", author="deployer")
send_telegram("🚨 {wid}: Deploy FAILED (...). Rolled back to development. Needs fix.")
result.alerted = True
logger.error(...)
```
launcher.py:475 блок (exit_code-based deployer-failure) НЕ удалён — оставлен как был; он просто
не срабатывает (exit_code=0), а реальный гейт теперь по вердикту. Advance других стадий не тронут.
## Новые тесты
test_qg.py / TestCheckDeployStatus (через tmp 14-deploy-log.md + fixture с monkeypatch repos_dir):
- SUCCESS frontmatter → True; FAILED → False; нет файла → False; нет поля → False;
prose-only без frontmatter → False; get_qg_for_stage("deploy")=="check_deploy_status";
зарегистрирована в QG_CHECKS.
test_stage_engine.py / TestDeployVerdict (pure-logic, БЕЗ TestClient POST):
- FAILED вердикт → НЕ done, откат в development, alerted, set_issue_blocked, send_telegram;
- нет лога → откат в development; SUCCESS → done, агент не запущен, jobs пусто.
## Результат — полный вывод pytest (контейнер)
`docker run --rm -v ... --entrypoint python3 orchestrator-orchestrator -m pytest tests/ -q`
**10 failed, 227 passed**
- passed: 217 (baseline PR#18) + 10 новых = 227 ✓ (не уронил)
- 10 failed — ровно baseline off-limits (9 HMAC/401 в test_webhooks + 1 webhook-POST
test_plane_webhook_event_logged). Их не трогал.
Целевой прогон новых: `pytest TestCheckDeployStatus TestDeployVerdict -v` → 10 passed.
## Статус правки 4 (deployer-промпт enduro-trails)
НЕ трогал (по умолчанию — только orchestrator). **Требует отдельной правки в репо
admin/enduro-trails**: `.openclaw/agents/deployer.md` обязать deployer'а писать YAML-frontmatter
в начало `14-deploy-log.md`:
```
---
deploy_status: SUCCESS # или FAILED
version: vX.Y.Z
---
```
Без этого frontmatter check_deploy_status вернёт False (нет поля) → задача откатится в
development. То есть гейт fail-safe, но для прохождения SUCCESS промпт enduro-trails надо обновить.
## Push / PR (ORCH-7 проверен)
- Коммит: `e4a9c48 fix(deploy): gate deploy->done on deployer verdict, not LLM exit code`
- `git log origin/main..origin/fix/deploy-verdict-gate` → e4a9c48 (remote содержит коммит ✓)
- PR #19: https://git.mva154.duckdns.org/admin/orchestrator/pulls/19 (fix/deploy-verdict-gate → main)
- НЕ мержил, НЕ деплоил — мерж + боевой прогон делает ассистент.