auto-sync: 2026-06-03 22:10:01
This commit is contained in:
@@ -146,3 +146,14 @@ approved=a519a341-dada-4a91-8910-7604f82b79c5 rejected=ba958f3c-5db5-461d-
|
||||
**Фикс (для Dev):** в handle_comment игнорировать комменты, автором которых является бот/агент (analyst/architect/... или служебный actor). Проверять author/actor вебхука: если это наш сервисный аккаунт или один из агентов — return (no action). Только комменты РЕАЛЬНОГО человека (Слава) должны триггерить approved/rejected/answer-to-questions.
|
||||
**NB:** PLANE_STATES в Enduro Trails корректен — один In Progress (b873d9eb). «5 In Progress» ранее — статусы ДРУГИХ проектов, ложная тревога.
|
||||
**Состояние:** #6 сейчас In Progress (откачен), task 26 stage=analysis, артефакты в feature/ET-011-untitled готовы. После фикса бага3 — повторить и убедиться что In Review держится.
|
||||
|
||||
---
|
||||
|
||||
## РЕШЕНО: чистая статусная модель управления конвейером (03.06, подтверждено Славой)
|
||||
Слава управляет конвейером ТОЛЬКО статусами. Комменты НИКОГДА не триггерят переходы. Финальная модель:
|
||||
- **Одобрение** → Слава ставит статус **Approved** → оркестратор двигает на след. стадию (сам ставит статус стадии).
|
||||
- **Отклонение** → Слава СНАЧАЛА пишет коммент с причиной, ПОТОМ ставит **Rejected** → оркестратор откатывает + читает причину из последнего коммента.
|
||||
- **Ответ на вопросы analyst** (задача в Needs Input) → Слава пишет коммент(ы), ПОТОМ САМ возвращает статус в **In Progress** → оркестратор перезапускает агента текущей стадии (читает комменты). Триггер = СТАТУС In Progress, не коммент.
|
||||
- Комментный механизм (:approved:/:rejected:/answer-by-comment) — ВЫПИЛИВАЕТСЯ полностью.
|
||||
ТЗ: tasks/orchestrator/DEV_TASK_STATUS_ONLY_VERDICT.md
|
||||
Ключевая правка vs прошлого PR: handle_status_start теперь должен ПЕРЕЗАПУСКАТЬ агента при возврате In Progress из Needs Input (не просто idempotent-skip), отличая от защиты-дублей через running-job/prev-status.
|
||||
|
||||
73
tasks/orchestrator/DEV_TASK_STATUS_ONLY_VERDICT.md
Normal file
73
tasks/orchestrator/DEV_TASK_STATUS_ONLY_VERDICT.md
Normal file
@@ -0,0 +1,73 @@
|
||||
# DEV TASK — Вердикт ТОЛЬКО статусами (выпил комментного approve + фикс эхо-самоудара)
|
||||
|
||||
**Проект:** orchestrator | **Сервер:** slin@82.22.50.71 | **Репо:** /home/slin/repos/orchestrator | **Контейнер:** orchestrator (8500)
|
||||
**Ветка:** `fix/status-only-verdict` из свежего main (`git checkout main && git pull && git checkout -b fix/status-only-verdict`).
|
||||
|
||||
⚠️ **ГРАБЛЯ push (ORCH-7):** после push `git log origin/main..origin/fix/status-only-verdict` ДОЛЖЕН показать коммиты ДО отчёта «PR готов».
|
||||
ℹ️ Токен Gitea для PR: `docker exec orchestrator printenv ORCH_GITEA_TOKEN`.
|
||||
|
||||
## Контекст и ПРАВИЛЬНАЯ модель (источник правды — решение Славы, подтверждено 03.06)
|
||||
Слава управляет конвейером **ТОЛЬКО СТАТУСАМИ**. **Комменты НИКОГДА не триггерят переходы.** Точная модель:
|
||||
- **Одобрение стадии** → Слава ставит статус **Approved** → оркестратор двигает на следующую стадию (сам выставляет статус следующей стадии).
|
||||
- **Отклонение** → Слава **сначала пишет коммент с причиной**, **потом** ставит статус **Rejected** → оркестратор откатывает + читает причину из последнего коммента.
|
||||
- **Ответ на вопросы аналитика** (задача в **Needs Input**) → Слава пишет коммент(ы) с ответами, **потом сам возвращает статус в In Progress** → оркестратор перезапускает агента текущей стадии (analyst читает комменты из Plane). Триггер — СТАТУС In Progress, НЕ коммент.
|
||||
|
||||
**КОММЕНТНЫЙ МЕХАНИЗМ УПРАВЛЕНИЯ ВЫПИЛИВАЕТСЯ ПОЛНОСТЬЮ.** `:approved:`/`:rejected:` в комментах + «answer-to-questions по комменту» — всё убрать. Они создавали баг 3 (эхо-самоудар): analyst постит свой коммент «жду approved» → handle_comment ловит свой же коммент → откатывает In Review → In Progress.
|
||||
|
||||
## БАГ 3 (root) — самоудар + лишний PATCH
|
||||
**Симптом:** analyst довёл задачу до **In Review** корректно, через 0.1с статус откатился в **In Progress**, уведомления нет.
|
||||
**Две причины:**
|
||||
|
||||
### Причина A — handle_comment управляет конвейером (выпилить весь механизм)
|
||||
`src/webhooks/plane.py`, `handle_comment` (~397-490): **весь комментный механизм управления выпиливается.**
|
||||
- Ветка `if ":approved:" in comment_body:` (~427-431) → **ВЫПИЛИТЬ.**
|
||||
- Ветка `if ":rejected:" in comment_body:` (~420-424) → **ВЫПИЛИТЬ.**
|
||||
- Ветка `if current_stage == "analysis":` (answer-to-questions по комменту, ~433-490) → **ВЫПИЛИТЬ.** Ответ на вопросы теперь идёт через возврат СТАТУСА в In Progress (см. ниже handle_status_start), не через коммент.
|
||||
- Итого `handle_comment` либо удаляется целиком (и роутер `comment.created` → no-op/лог), либо сводится к чистому логированию без side-effect. Реши сам — главное: **ни один коммент не меняет статус и не запускает агентов.** Сохрани QG-лог если он информативен, но без действий.
|
||||
|
||||
### Причина A2 — возврат в In Progress из Needs Input должен ПЕРЕЗАПУСКАТЬ агента
|
||||
`handle_status_start` (~161-172) сейчас идемпотентен: `if existing task → not restarting`. Это правильно для защиты от дублей, НО ломает кейс «ответ на вопросы»: Слава вернул задачу из **Needs Input** в **In Progress**, ожидая что analyst перезапустится. **Надо:** если task существует И задача «ждала» (предыдущий статус был needs_input / стадия analysis в ожидании) → **перезапустить агента текущей стадии** (enqueue), чтобы он прочитал новые комменты Славы.
|
||||
- Как отличить «обычный повторный In Progress» (защита от дублей) от «ответ на вопросы»: проверь предыдущий Plane-статус issue (был needs_input) ИЛИ флаг ожидания в БД. Определи самый надёжный способ на проде (есть ли в БД поле статуса/ожидания; или GET issue даёт прошлый статус через activity). Если нет running job по task И стадия активная (analysis) → перезапуск analyst с пометкой «прочитай свежие комменты Славы и доработай артефакты». Защита от дублей (нет двойного запуска при двойном webhook) — сохрани через проверку running job в очереди.
|
||||
- ⚠️ Если надёжно определить «был needs_input» сложно — отчитайся с вариантом реализации ДО мержа (это ключевая развилка). Минимально: рестарт если стадия analysis И нет активной/running job для task.
|
||||
|
||||
### Причина B — handle_verdict(Approved) сам сбивает статус в In Progress
|
||||
`handle_verdict` (~170-200), ветка `if approved:` (~185):
|
||||
```python
|
||||
set_issue_in_progress(work_item_id) # ← УБРАТЬ
|
||||
await _try_advance_stage(...)
|
||||
```
|
||||
`set_issue_in_progress` здесь лишний — он откатывает статус назад перед advance. `_try_advance_stage` сам выставит статус следующей стадии (architecture/development/...). **Убрать `set_issue_in_progress` из ветки approved.** Проверь, что `_try_advance_stage` действительно сам ставит статус стадии (если НЕ ставит — тогда вместо in_progress выставить статус нужной стадии, НЕ in_progress).
|
||||
|
||||
## REJECT: причина из коммента в handle_verdict
|
||||
Сейчас `handle_verdict(approved=False)` передаёт фиксированную заглушку причины. **Надо:** при Rejected-статусе дотянуть **последний коммент** issue из Plane API (GET comments, взять самый свежий от человека) как `reason` и передать в `_rollback_stage`. Слава пишет причину отдельным комментом ПЕРЕД/вместе со сменой статуса.
|
||||
- GET comments endpoint: `{PLANE_BASE}/workspaces/{WORKSPACE}/projects/{pid}/issues/{issue_id}/comments/` (тот же PLANE_HEADERS). Взять последний по created_at, стрипнуть HTML.
|
||||
- Если коммента нет → заглушка «Rejected via status, no reason comment».
|
||||
|
||||
## Ограничения
|
||||
- 🚫 НЕ трогай: nginx/openclaw.json/.env-секреты/deploy-хук/HMAC/verify_plane_signature/очередь(queue_worker/jobs кроме чтения)/webhook URL в БД Plane/per-agent authorship/PLANE_STATES UUID/M-6 derive/uniqueness-guard(из PR #11)/fetch_issue_description(PR #11)/conftest.py.
|
||||
- Conventional Commits, отдельные коммиты: `fix(webhook): remove comment-based approve, keep status-only verdict`, `fix(webhook): drop redundant in_progress reset on Approved`, `feat(webhook): pull reject reason from latest comment`.
|
||||
- ⚠️ Старые тесты `test_webhooks.py::test_plane_approved_advances_stage`, `test_plane_rejected_rolls_back`, `test_verdict_status.py` проверяют КОММЕНТНЫЙ `:approved:`/`:rejected:`. Раз комментный механизм выпиливается — **перепиши их под статусную модель** (approve/reject через handle_verdict по СТАТУСУ). Тесты, проверяющие что коммент `:approved:` двигает стадию — перепиши на обратное утверждение: «коммент НЕ триггерит переход».
|
||||
|
||||
## Тесты (контейнер)
|
||||
`IMG=$(docker inspect orchestrator --format '{{.Config.Image}}'); docker run --rm -v /home/slin/repos/orchestrator:/code -w /code --entrypoint python3 $IMG -m pytest tests/ -q`
|
||||
Новые/обновлённые:
|
||||
- `test_inreview_comment_does_not_revert`: задача в In Review, прилетает ЛЮБОЙ коммент → статус НЕ меняется, агенты НЕ запускаются. **Главный тест бага 3.**
|
||||
- `test_any_comment_no_pipeline_action`: коммент с `:approved:`/`:rejected:`/произвольным текстом → никаких side-effect (статус/очередь не трогаются).
|
||||
- `test_approved_status_advances_without_inprogress_reset`: Approved-статус → advance, БЕЗ промежуточного PATCH в in_progress.
|
||||
- `test_rejected_status_pulls_reason_from_comment`: Rejected-статус + последний коммент с причиной (мок GET comments) → reason передан в rollback.
|
||||
- `test_inprogress_from_needs_input_relaunches_analyst`: задача в analysis/needs_input → возврат статуса в In Progress → analyst перезапущен (enqueue), читает комменты. + защита: двойной In Progress webhook не плодит двойной запуск.
|
||||
- Перепиши `test_plane_approved_advances_stage`/`test_plane_rejected_rolls_back`/`test_verdict_status` под статусную модель.
|
||||
|
||||
## Проверка (ассистент проверит вживую боевым прогоном)
|
||||
| # | Что | Критерий |
|
||||
|---|-----|----------|
|
||||
| 1 | In Review держится | analyst → In Review, статус НЕ откатывается, уведомление с просьбой одобрить приходит |
|
||||
| 2 | Approved-статус | Слава ставит Approved → задача уходит в Architecture, БЕЗ мелькания In Progress |
|
||||
| 3 | Rejected-статус+коммент | Слава ставит Rejected + коммент причины → откат, analyst получает причину |
|
||||
| 4 | коммент не рулит | `:approved:` в комменте больше НЕ двигает задачу |
|
||||
| 5 | тесты | baseline не сломан + новые passed |
|
||||
| 6 | git | PR в main, remote содержит коммиты |
|
||||
|
||||
## Отчёт
|
||||
- НЕ деплоить, НЕ мержить (мерж — ассистент после живой проверки + боевого прогона #6).
|
||||
- В отчёте: что именно выпилил (файл:строки), **как реализовал перезапуск агента при возврате In Progress из Needs Input** (как отличаешь от защиты-дублей — ключевая развилка, опиши подробно), как тянешь reject-reason, какие старые тесты переписал и как, вывод релевантных тестов. Если что-то в коде разошлось с этим ТЗ (напр. _try_advance_stage сам НЕ ставит статус стадии, или нет способа узнать прошлый статус) — **отчитайся ДО мержа, не выдумывай**. Один исполнитель.
|
||||
Reference in New Issue
Block a user