Files
wiki/tasks/orchestrator/reports/dev-2026-06-04-telegram-tracker.md
2026-06-04 11:50:01 +03:00

8.1 KiB
Raw Blame History

Dev Report: orchestrator — живой Telegram-трекер задачи (Вариант B+)

Дата: 2026-06-04 Статус: DONE

Задача

Заменить ~15 отдельных ТГ-сообщений на задачу одним живым сообщением-трекером (editMessageText по стадиям). Отдельными сообщениями с пингом — только approve-gate, deploy-fail, agent-fail, error.

Результат (кратко)

  • PR: #21 — admin/orchestrator#21
  • Ветка: feat/telegram-live-tracker от main (2801983)
  • Commit: 9a0298d
  • pytest: 259 passed, 9 failed (те же off-limits HMAC/401 в test_webhooks.py). Baseline на этом хосте — 244 passed, 9 failed; +15 новых проходящих тестов, 0 новых падений. (В ТЗ значился baseline 243+10 — на этом хосте фактически 244+9, набор падений идентичный и не тронут.)
  • НЕ смержен — на ревью Стрим.

Изменённые файлы (6, +893/-35)

  • src/db.py — idempotent ALTER-ы: tasks.tracker_message_id, tasks.title, tasks.brd_review_started_at, tasks.brd_review_ended_at, agent_runs.model. Хелперы: get/set_tracker_message_id, mark_brd_review_started/ended.
  • src/usage.pyshort_model_name() (отрезает провайдер-префикс и claude-); _extract_model() парсит модель из result-JSON (modelUsage); record_usage сохраняет модель (COALESCE, не затирает существующую).
  • src/notifications.py — ядро:
    • render_task_tracker(task_id) — stateless рендер из agent_runs + task.
    • update_task_tracker(task_id) — sendMessage→store id→editMessageText, fallback на новое сообщение при фейле edit, всегда disable_notification=true.
    • edit_telegram(), send_telegram() теперь возвращает message_id.
    • notify_* переведены в режим «только трекер / только лог», кроме 4 алертов.
  • src/stage_engine.py — штамп brd_review_ended на переходе analysis→architecture.
  • src/webhooks/plane.py — сохранение title задачи при создании.
  • tests/test_telegram_tracker.py — новые тесты (см. ниже).

Формат трекера

В процессе (deploy идёт)

🛠️ ET-012 · Треки с зума z5
━━━━━━━━━━━━━━━━━━━━━━
✅ Analysis      10м · 1.1M↓/39.6k↑ · $2.38 · opus-4-8
⏸️ Ревью БРД     8м · твоё время
✅ Architecture  9м · 1.5M↓/34.4k↑ · $2.24 · opus-4-8
✅ Development   11м · 8.4M↓/45.8k↑ · $7.29 · opus-4-8
✅ Review        3м · 1.2M↓/12.9k↑ · $1.53 · sonnet-4.6
✅ Testing       5м · 1.2M↓/19.5k↑ · $1.51 · sonnet-4.6
🔄 Deploy        …   · идёт
━━━━━━━━━━━━━━━━━━━━━━
💰 13.4M↓ / 152.2k↑ · $14.95

(пока Deploy ещё не финишировал — токены deployer-а не учтены в Итого; на финише учтутся.) Пока идёт ожидание ревью БРД, строка показывает · твоё время ⏳.

На финише

🎉 ET-012 · Треки с зума z5 — ГОТОВО
━━━━━━━━━━━━━━━━━━━━━━
✅ Analysis      10м · 1.1M↓/39.6k↑ · $2.38 · opus-4-8
⏸️ Ревью БРД     8м · твоё время
✅ Architecture  9м · 1.5M↓/34.4k↑ · $2.24 · opus-4-8
✅ Development   11м · 8.4M↓/45.8k↑ · $7.29 · opus-4-8
✅ Review        3м · 1.2M↓/12.9k↑ · $1.53 · sonnet-4.6
✅ Testing       5м · 1.2M↓/19.5k↑ · $1.51 · sonnet-4.6
✅ Deploy        6м · 1.6M↓/22.4k↑ · $1.73 · opus-4-8
━━━━━━━━━━━━━━━━━━━━━━
💰 15.0M↓ / 174.6k↑ · $16.68
⏱️ Всего 56м · агенты 44м · твоё 8м
🔗 PR #24 · 📦 deployed

(Точные значения совпадают с макетом из ТЗ; токены in = input+cache_read+cache_creation, out — отдельно; модель — короткая; время в минутах, <1м → <1м.)

Что теперь НЕ шлётся отдельными сообщениями (только трекер / лог)

  • Старт агента (notify_agent_started) → refresh трекера.
  • Завершение агента (notify_agent_finished) → refresh трекера.
  • Переход стадии (notify_stage_change) → refresh трекера.
  • QG-pending / QG-failed (notify_qg_failure, notify_qg_result) → только лог (CI state: pending — не ошибка).
  • QG-passed → только лог.
  • Тех-мусор (run_id, exit_code, пути логов) — убран из ТГ-текста.

Что ОСТАЁТСЯ отдельным сообщением (с пингом, disable_notification=false)

  • 📋 Approve-gate (notify_approve_requested) — текст про перевод в Approved (устаревший :approved: заменён). Заодно стартует «твоё время» (BRD review clock).
  • 🚨 Deploy упал / откат (send_telegram в launcher.py и stage_engine.py) — без изменений.
  • Агент упал, exit_code != 0 (send_telegram в launcher) — путь к логам только в лог-файл (в коде launcher уже так; текст ТГ не содержит run_id-мусора по новым правилам трекера).
  • 🔴 Ошибка задачи (notify_error).

Тесты (tests/test_telegram_tracker.py)

  • short_model_name: tokenator/claude-opus-4-8→opus-4-8, vibecode/claude-sonnet-4.6→sonnet-4.6, None/'' → ''.
  • парсинг модели из modelUsage.
  • render_task_tracker: строки этапов (in↓/out↑·cost·model), строка Ревью БРД (твоё время / при ожидании), активная стадия 🔄 идёт, блок Итого 💰, финиш ⏱️ (три времени) + 🔗/📦, экранирование <>& в названии, опускание модели если неизвестна.
  • send/edit/fallback: первое сообщение → send + store id (silent); переход → editMessageText существующего; edit-фейл → новое сообщение + обновлённый id.
  • алерты: approve-gate и error шлются ОТДЕЛЬНО (disable_notification=false); stage-change / agent-start / QG-pending НЕ шлют отдельных сообщений.

Проблемы и решения

  • f-string + backslash на Python 3.10 (прод-хост): литерал с \uXXXX внутри {...:<13} ломал парсинг. Решено — вынес метку «Ревью БРД» в константу _BRD_LABEL.
  • локальный import httpx в _done_link мешал моку → перешёл на module-level httpx.
  • Источник модели: конфиг launcher задаёт --model не для всех агентов; надёжный источник — modelUsage из result-JSON → сохраняю в agent_runs.model.
  • title задачи в tasks не хранился → добавил колонку + populate при создании.

НЕ тронуто (по ТЗ)

  • usage_comment / Plane-комменты (формат fix #20), PLANE_STATES, launcher.py deployer-guard, HMAC/queue/cost-расчёт, conftest, nginx/.env.

Деплой

Код в проде НЕ задеплоен (образ собирается из src в image, не из репо) — это задача мержа/CI после ревью. Миграции БД idempotent (_ensure_column), безопасны на живой проде при следующем init_db().