auto-sync: 2026-06-04 13:20:01

This commit is contained in:
Stream
2026-06-04 13:20:10 +03:00
parent 71020d84a0
commit 8838e3a575

View File

@@ -0,0 +1,92 @@
# DEV TASK: orchestrator — фикс трекера (дубли сообщений + отставание)
Репо: `slin@82.22.50.71:/home/slin/repos/orchestrator` (пароль `motoZ@yaz2010`).
Push в main запрещён (pre-receive hook) → **только PR в Gitea**.
Gitea токен: `docker exec orchestrator printenv ORCH_GITEA_TOKEN`.
Одна ветка `fix/tracker-edit-not-modified` от актуального main, **один PR**.
Baseline pytest на этом проде: **259 passed + 9 failed** (9 = off-limits HMAC/401, НЕ чинить).
---
## КОНТЕКСТ / БАГ (подтверждён на живой задаче ET-013)
Живой Telegram-трекер (PR #21, `src/notifications.py`) на боевом прогоне ET-013 повёл себя так:
- За прогон: **21 editMessageText, но 7 sendMessage** — трекер 7 раз прислал НОВОЕ сообщение
вместо редактирования одного. Слава жалуется: «сообщение не одно, а при изменении приходит новое».
- Часть `editMessageText` падает с **HTTP 400 Bad Request**. Это НЕ сбой Telegram — это ответ
`"message is not modified"` (текст трекера не изменился между переходами, напр. повторный
цикл review→development→review рисует ту же строку).
### Корень (точно)
`edit_telegram` (notifications.py ~76-97):
```python
data = resp.json()
return bool(data.get("ok")) # 400 "not modified" -> ok:false -> возвращает False
```
Возвращает `False` на ЛЮБОМ 400. А `update_task_tracker` (~374-392) трактует `False` как
«edit не удался» → вызывает `send_telegram(...)` (новое сообщение) и перезаписывает
`tracker_message_id`. Итог: дубли + старый трекер «осиротевает» и больше не обновляется
(отстаёт от реальности — застрял на снимке Review, хотя был ещё цикл dev→review).
---
## ЧТО СДЕЛАТЬ (3 правки)
### Правка 1 — `edit_telegram`: "not modified" = успех, НЕ дубль
В `edit_telegram` разобрать тело ответа Telegram. Если `ok:false`, но
`description` содержит `"message is not modified"` (или `"exactly the same"`) —
**вернуть `True`** (редактировать нечего, всё в порядке, дубль НЕ нужен).
Логировать на DEBUG, не на WARNING.
### Правка 2 — fallback на новое сообщение ТОЛЬКО при реально пропавшем сообщении
Сейчас `update_task_tracker`: `if edit_telegram(...) == False -> send_telegram (новое)`.
Изменить логику так, чтобы новое сообщение слалось **только** когда исходное реально
нельзя редактировать:
- `"message to edit not found"` / `"message can't be edited"` / `"MESSAGE_ID_INVALID"`
сообщение пропало/удалено → fallback на новое (как сейчас), обновить tracker_message_id.
- Любой другой провал edit (сеть, таймаут, временный 5xx, неизвестный 400) →
**НЕ слать новое**, просто залогировать и выйти (трекер дорисуется на следующем переходе).
Плодить дубли на временных ошибках нельзя.
Реализация: пусть `edit_telegram` возвращает не голый bool, а различимый результат —
например enum/строку (`"ok"` | `"not_modified"` | `"gone"` | `"failed"`), либо tuple
`(ok: bool, gone: bool)`. `update_task_tracker` шлёт новое сообщение только при `gone`.
`"ok"` и `"not_modified"` → ничего не делать. `"failed"` → лог + выход без нового сообщения.
Никогда не падать (текущий стиль fire-and-forget сохранить).
### Правка 3 — повторные циклы стадии видимы (чтобы текст реально менялся)
Чтобы трекер не «застывал» на повторных проходах одной стадии (review↔development),
у АКТИВНОЙ стадии в `render_task_tracker` показывать признак повторного захода/попытки,
например: `🔄 Review · попытка 2 … идёт` (номер попытки = число записей agent_runs этого
агента по задаче, или attempts из jobs если доступно). Завершённые стадии (✅) НЕ трогать —
формат финальной строки прежний. Это и делает текст уникальным между циклами (меньше
not-modified), и честно показывает Славе, что идёт переработка.
- Если данных о попытке нет — рисовать как раньше (`🔄 Review … идёт`), без «попытка N».
- Считать попытку аккуратно: повторный запуск ТОЙ ЖЕ стадии (например 2-й review), а не
суммарно все агенты. Бери число прогонов агента этой стадии для текущей задачи.
### НЕ ТРОГАТЬ
- Формат завершённых строк (`✅ Stage Nм · in↓/out↑ · $ · model`), блок Итого, «Ревью БРД»,
short_model_name, миграции, usage_comment/Plane-комменты, PLANE_STATES, HMAC, queue,
launcher deployer-guard, отдельные алерты (approve/deploy-fail/agent-fail/error).
- disable_notification трекера (всегда silent).
---
## ТЕСТЫ (обязательно, мокать httpx)
- `edit_telegram`: ответ 400 `"message is not modified"` → трактуется как успех (не gone, не дубль).
- `edit_telegram`: 400 `"message to edit not found"` → gone.
- `edit_telegram`: 200 ok → ok.
- `edit_telegram`: таймаут/5xx → failed (не gone).
- `update_task_tracker`: edit not_modified → НЕ зовёт send_telegram (нет дубля).
- `update_task_tracker`: edit gone → зовёт send_telegram + обновляет tracker_message_id.
- `update_task_tracker`: edit failed (временная) → НЕ зовёт send_telegram.
- `render_task_tracker`: повторный заход стадии (2 review-рана) → `попытка 2` в активной строке;
один заход → без «попытка N»; завершённые строки без изменений.
- Полный pytest зелёный кроме тех же 9 off-limits.
## СДАЧА
- Ветка `fix/tracker-edit-not-modified`, один PR в Gitea. НЕ мержить сам — на ревью Стрим.
- Отчёт: `tasks/orchestrator/reports/dev-2026-06-04-tracker-edit-fix.md`
commit-хеш, PR-номер, вывод pytest, что изменилось в каждой из 3 правок,
до/после по логике (когда теперь шлётся новое сообщение, а когда нет).
- Сообщить: PR-номер, результат pytest, краткое описание фикса.