Files
wiki/tasks/orchestrator/reports/dev-2026-06-04-tracker-edit-fix.md
2026-06-04 13:30:01 +03:00

93 lines
7.0 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 — фикс трекера (дубли сообщений + отставание)
Дата: 2026-06-04
Статус: DONE (PR на ревью, НЕ смержен)
## Задача
Живой Telegram-трекер на ET-013 слал НОВОЕ сообщение вместо редактирования одного
(21 editMessageText / 7 sendMessage). Дубли + старый трекер осиротевал и отставал.
Корень: `edit_telegram` возвращал `False` на ЛЮБОМ 400 (включая Telegram-ответ
"message is not modified"), а `update_task_tracker` трактовал `False` как «edit упал»
→ слал новое сообщение + перезаписывал `tracker_message_id`.
## Сделано
- [x] Правка 1 — `edit_telegram`: различимый результат + not_modified=успех
- [x] Правка 2 — `update_task_tracker`: новое сообщение только при `gone`
- [x] Правка 3 — `render_task_tracker`: «попытка N» у активной перезапущенной стадии
- [x] +13 тестов (мокают httpx)
- [x] Baseline подтверждён, полный pytest зелёный кроме 9 off-limits
- [x] Ветка `fix/tracker-edit-not-modified`, commit `ec9aa74`, PR #22 (НЕ смержен)
## Сдача
- **PR #22** — https://git.mva154.duckdns.org/admin/orchestrator/pulls/22
- Ветка: `fix/tracker-edit-not-modified` (от актуального main `3e5c74c`)
- Commit: `ec9aa74`
- **pytest: 272 passed, 9 failed** (те же off-limits HMAC/401 webhook-тесты;
baseline был 259 passed + 9 failed → +13 новых тестов, 0 регрессий)
## Изменённые файлы
- `src/notifications.py`:
- `edit_telegram(message_id, text) -> str` (было `-> bool`). Возвращает
`EDIT_OK | EDIT_NOT_MODIFIED | EDIT_GONE | EDIT_FAILED`. Разбор `description`
из тела ответа: маркеры not-modified (`"message is not modified"`,
`"exactly the same"`) → `not_modified` (лог DEBUG); маркеры gone
(`"message to edit not found"`, `"message can't be edited"`,
`"message_id_invalid"`) → `gone`; прочий 400 / 5xx / исключение → `failed`.
- `update_task_tracker`: `ok`/`not_modified` → выход без send; `failed`
лог + выход без send; `gone` → send нового + `set_tracker_message_id`.
- `render_task_tracker`: активная стадия = текущая стадия задачи И есть
in-flight (незавершённый) ран её агента (либо нет завершённого вообще).
Если прогонов агента ≥2 → `🔄 Review · попытка N … идёт`, иначе старая
строка `🔄 Review … идёт`. Завершённые ✅ строки не тронуты.
- `tests/test_telegram_tracker.py`: обновлены 2 существующих теста под новый
контракт edit_telegram (`EDIT_OK`/`EDIT_GONE` вместо True/False) + 13 новых.
## Каждая из 3 правок
### Правка 1 — edit_telegram: not_modified = успех, НЕ дубль
Раньше: `return bool(data.get("ok"))` → любой 400 = `False`.
Теперь: при `ok:false` парсим `description` и классифицируем:
`not_modified` (успех) / `gone` / `failed`. not_modified логируется на DEBUG.
### Правка 2 — fallback на новое сообщение ТОЛЬКО при gone
Раньше: `if edit_telegram(...) == False -> send_telegram (новое) + перезапись id`.
Теперь:
- `ok` / `not_modified``return` (ничего не делаем, дубля нет).
- `failed` (сеть/таймаут/5xx/неизвестный 400) → лог DEBUG + `return` (НЕ дубль;
трекер дорисуется на следующем переходе).
- `gone``send_telegram(...)` + `set_tracker_message_id`.
Стиль fire-and-forget сохранён, функция никогда не падает.
### Правка 3 — повторные циклы стадии видимы
У активной перезапущенной стадии показывается `🔄 <Stage> · попытка N … идёт`,
где N = число agent_runs этого агента по задаче. Это делает текст уникальным
между циклами review↔development (меньше not-modified) и честно показывает
переработку. Активная стадия определяется как «текущая стадия задачи + есть
in-flight ран её агента» — поэтому just-finished снимок (агент завершил, задача
ещё не сдвинулась) по-прежнему показывает ✅, а не 🔄. Завершённые строки не тронуты.
## До/после по логике (когда шлётся новое сообщение)
- **До:** новое сообщение слалось при ЛЮБОМ не-True результате edit, включая
not-modified и временные сбои → дубли + осиротевший отстающий трекер.
- **После:** новое сообщение слётся ТОЛЬКО при `gone` (сообщение реально
удалено/слишком старое/невалидный id). not_modified и временные ошибки
оставляют существующий трекер на месте.
## Тесты (добавлено 13)
- edit_telegram: ok / not_modified / "exactly the same" / not_found→gone /
can't-be-edited→gone / unknown400→failed / timeout→failed / 5xx→failed.
- update_task_tracker: not_modified → НЕ зовёт send (id не меняется);
gone → зовёт send + обновляет id; failed → НЕ зовёт send (id не меняется).
- render: «попытка 2» при 2 review-ранах; без «попытка N» при 1 ране;
завершённые ✅ строки без «попытка N».
- Обновлены под новый контракт: test_second_call_edits_existing_message (EDIT_OK),
test_fallback_to_new_message_when_edit_gone (EDIT_GONE).
## Проблемы и решения
- На хосте нет `scp`/`sshpass scp` → файлы переносил через `base64 | ssh 'base64 -d'`.
- Первая версия Правки 3 ломала `test_render_omits_model_when_unknown`: активная
стадия перекрывала ✅ для just-finished рана. Решение: активной считается только
стадия с in-flight раном (или вообще без завершённого) — just-finished показывает ✅.
## Следующий шаг
PR #22 на ревью у Стрима. Сам НЕ мержу.