# DEV TASK: orchestrator — живой Telegram-трекер задачи (Вариант B+) Репо: `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`. Одна ветка `feat/telegram-live-tracker` от актуального main, **один PR**. Baseline pytest: **243 passed + 10 failed** (10 = off-limits HMAC/401, НЕ чинить). После: passed вырасти (новые тесты), те же 10 failed. --- ## ЦЕЛЬ Сейчас orchestrator шлёт в Telegram ~15 отдельных сообщений на задачу (`src/notifications.py`): старт каждого агента, завершение, переход стадии, QG-pending-шум, тех-мусор (run_id, exit_code, пути логов), устаревший «:approved:». Простыня. Заменить на **ОДНО живое сообщение-трекер** на задачу, которое редактируется (`editMessageText`) на каждой стадии. Отдельными сообщениями с пингом слать **только** то, что требует внимания Славы. --- ## МАКЕТ ТРЕКЕРА (точный формат) **В процессе** (текущая стадия — `🔄 … идёт`): ``` 🛠️ 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 … · идёт ━━━━━━━━━━━━━━━━━━━━━━ 💰 15.1M↓ / 174.6k↑ · $16.68 ``` **На финише** (заголовок `🎉 … — ГОТОВО`, добавляются строки времени и ссылки): ``` 🎉 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.1M↓ / 174.6k↑ · $16.68 ⏱️ Всего 56м · агенты 44м · твоё 8м 🔗 PR #24 · 📦 deployed ``` ### Правила формата (согласованы со Славой): - **Токены на этап:** in/out РАЗДЕЛЬНО — `↓/↑`, где `in = input_tokens + cache_read_tokens + cache_creation_tokens` (полный вход, как в usage.py fix #20 — переиспользуй `_input_total`/`fmt_tokens` оттуда), `out = output_tokens`. - **Модель:** КОРОТКОЕ имя (`opus-4-8`, `sonnet-4.6`). Бери модель агента из конфигурации стадии /agent_runs/launcher (где известно, какой моделью запускался агент). Маппинг полного→короткого: отрезать провайдер-префикс (`tokenator/claude-opus-4-8` → `opus-4-8`, `vibecode/claude-sonnet-4.6` → `sonnet-4.6`). Если модель неизвестна — опустить ` · `. - **Ревью БРД (`⏸️`):** ОТДЕЛЬНАЯ строка между Analysis и Architecture. Время = ТВОЁ (Славы), НЕ агентское: дельта между моментом «BRD готовы / notify_approve_requested» и переходом `analysis→architecture` (gate Approved). Пометка `твоё время ⏳` пока идёт ожидание, `твоё время` после. Пока это ЕДИНСТВЕННОЕ «твоё время» (других gate нет). - **Итого:** `💰 ↓ / ↑ · ` (total_in = сумма полного входа всех агентов). - **Время в Итого:** `⏱️ Всего · агенты · твоё ` где `Всего` = wall-clock от старта задачи до done, `агенты` = сумма длительностей агент-ранов, `твоё` = время ревью БРД. - Время стадии — минуты (`10м`). Если <1м — `<1м`. - Текущая активная стадия: `🔄 … идёт`. Ещё не начатые стадии — НЕ показывать (строка появляется когда стадия стартовала). - Заголовок: `🛠️ · <короткое название задачи>` в процессе, `🎉 · <название> — ГОТОВО` на финише. - На финише добавить `🔗 PR # · 📦 deployed` (PR-номер из флоу; статус деплоя из check_deploy_status: deployed/❌ failed). --- ## АЛЕРТЫ — ОТДЕЛЬНЫМИ сообщениями (с уведомлением) Трекер редактируется молча. ОТДЕЛЬНО (новое сообщение, `disable_notification: false`) слать ТОЛЬКО: - 📋 **Approve-gate:** «ET-012: BRD/ТЗ/AC готовы. Переведите в Approved в Plane для продолжения» (заменить устаревший текст про `:approved:`). - 🚨 **Деплой упал / откат:** как сейчас в launcher.py:495 (`Deploy failed! Rolled back`). - ❌ **Агент упал:** exit_code != 0 (launcher.py:508) — но БЕЗ пути к логам в тексте (в лог, не в ТГ). - 🔴 **Ошибка задачи** (`notify_error`). НЕ слать отдельными: старт агента, завершение агента, переход стадии, QG-pending (`check_ci_green failed: CI state: pending` — это НЕ ошибка, только в лог), QG-passed. --- ## РЕАЛИЗАЦИЯ **Файлы:** `src/notifications.py` (основное), `src/db.py` (хранение message_id + модель/тайминги если их нет), `src/stage_engine.py` (вызовы обновления трекера на переходах), возможно `src/agents/launcher.py` (тайминги старта/финиша агентов). 1. **Хранение message_id трекера:** добавить колонку `tracker_message_id INTEGER` в `tasks` (idempotent ALTER, как `_ensure_column` в db.py). При первом сообщении задачи — `sendMessage`, сохранить `result.message_id`. На каждом переходе — `editMessageText` с полным перерисованным трекером. 2. **Fallback:** если `editMessageText` вернул ошибку (message not found / too old / 400) — отправить НОВОЕ сообщение и обновить tracker_message_id. Никогда не падать (как текущий send_telegram fire-and-forget). 3. **Сбор данных стадий:** длительность стадии, токены (in/out), стоимость, модель — из `agent_runs` по task_id (там уже есть input/output/cache_read/cache_creation_tokens, cost_usd; модель — добавь сохранение если её там нет, либо бери из конфига стадии). Рендер трекера = функция `render_task_tracker(task_id) -> str`, собирающая всё из БД на каждый вызов (stateless рендер). 4. **Время ревью БРД:** зафиксировать timestamp `notify_approve_requested` и timestamp перехода `analysis→architecture`; дельта = «твоё время». Хранить в `tasks` (напр. `brd_review_started_at`, `brd_review_ended_at`) или вычислять из activities/stage-history если они уже логируются. 5. **Короткое имя модели:** хелпер `short_model_name(full) -> str` (отрезать префикс до последнего `/`, затем `claude-` префикс). 6. **parse_mode:** трекер — HTML (как сейчас). Экранировать `<>&` в названии задачи. ### НЕ ТРОГАТЬ - HMAC, project-filter, nginx, openclaw.json, .env, queue (кроме чтения), PLANE_STATES, conftest.py, status-only verdict, gitea_public_url конфиг, Plane-комменты (usage_comment — это ОТДЕЛЬНО, в Plane; НЕ путать с Telegram-трекером, его формат из fix #20 НЕ менять). - Сохранить блок launcher.py:475 (deployer exit_code защита). - cost_usd расчёт. --- ## ТЕСТЫ (обязательно) - `render_task_tracker` на моке agent_runs: правильный формат строк этапов (in↓/out↑, модель, стоимость, время), строка «Ревью БРД · твоё время», блок Итого с тремя временами. - `short_model_name`: `tokenator/claude-opus-4-8`→`opus-4-8`, `vibecode/claude-sonnet-4.6`→`sonnet-4.6`. - Трекер: первое сообщение → sendMessage сохраняет message_id; переход → editMessageText. - Fallback: edit упал → новое сообщение, message_id обновлён. - Алерты: approve-gate/deploy-fail/agent-fail/error шлются ОТДЕЛЬНО; QG-pending/agent-start/ stage-transition НЕ шлются отдельными (только трекер). - Полный pytest зелёный (кроме тех же 10 off-limits). ## СДАЧА - Ветка `feat/telegram-live-tracker`, один PR в Gitea. НЕ мержить сам — на ревью Стрим. - Отчёт: `tasks/orchestrator/reports/dev-2026-06-04-telegram-tracker.md` — commit-хеш, PR-номер, вывод pytest, пример отрендеренного трекера (в процессе + финиш), список того что теперь НЕ шлётся отдельными сообщениями. - Сообщить: PR-номер, результат pytest, пример трекера.