# 02 — ТЗ: Telegram live-tracker, режим bump + русификация **Work Item:** ORCH-042 · См. `01-brd.md`, `03-acceptance-criteria.md`. ## 1. Задействованные модули `src/` | Файл | Что меняется | |------|--------------| | `src/config.py` | Новое поле `Settings.tracker_mode` (env `ORCH_TRACKER_MODE`). | | `src/notifications.py` | Новый helper `delete_telegram(message_id)`; ветвление `update_task_tracker` по режиму; текстовые правки в `_BRD_LABEL`, `_TRACKER_STAGES`, BRD-строке `render_task_tracker`, `_done_link`. | БД — **без изменений** (используется существующая колонка `tasks.tracker_message_id` и хелперы `get_tracker_message_id` / `set_tracker_message_id` в `src/db.py`). API HTTP-эндпоинты оркестратора — **без изменений**. Новые QG checks — **не требуются**. ## 2. Изменения конфигурации (`src/config.py`) Добавить в класс `Settings` (рядом с блоком «Telegram notifications»): ```python # ORCH-042: режим live-трекера задачи. # edit -> карточка редактируется на месте (editMessageText), ДЕФОЛТ (как было). # bump -> при обновлении старое сообщение удаляется и карточка отправляется # заново вниз чата (deleteMessage + sendMessage + repoint message_id), # тихо (disable_notification). Одна карточка на задачу в обоих режимах. # Неизвестное/пустое значение трактуется как edit (см. notifications). tracker_mode: str = "edit" ``` - `env_prefix = "ORCH_"` уже задан → переменная окружения `ORCH_TRACKER_MODE`. - Резолюция режима — в `notifications`: всё, что не равно (case-insensitive, trimmed) `"bump"`, считается `edit`. Не падать на любом значении. ## 3. Изменения нотификаций (`src/notifications.py`) ### 3.1. Новый low-level helper `delete_telegram` Рядом с `send_telegram` / `edit_telegram`. Контракт «never raises». ```python def delete_telegram(message_id: int) -> bool: """Delete a Telegram message. Never raises. Returns True if the message is gone after the call (deleted now, OR Telegram says it's already not there / can't be deleted -> treat as "no longer our problem", caller proceeds to send a fresh card). Returns False only on a transient failure (network / timeout / 5xx / unknown error) where the old message may still be alive. """ ``` Требования к реализации: - Эндпоинт `https://api.telegram.org/bot{token}/deleteMessage`, тело `{chat_id, message_id}`, `timeout=5`. - Нет токена/chat_id → вернуть `False` (как и прочие helpers при отсутствии кредов — ничего не отправлено, ничего не удалено). - `ok:true` → `True`. - `ok:false` с описанием «уже нет / нельзя удалить» (маркеры: `"message to delete not found"`, `"message can't be deleted"`, `"message_id_invalid"`) → `True` (сообщение и так недоступно; не транзиент). - Прочие `ok:false` (неизвестный 400 / 5xx) и исключения (сеть/таймаут) → `False` + `logger.warning`. - Вынести маркеры в модульную константу (по аналогии с `_GONE_MARKERS`), например `_DELETE_GONE_MARKERS`. ### 3.2. Ветвление `update_task_tracker` по режиму Сохранить существующий путь `edit` без изменений поведения. Добавить путь `bump`. Псевдокод целевой логики: ```python def update_task_tracker(task_id: int): try: from .db import get_tracker_message_id, set_tracker_message_id text = render_task_tracker(task_id) mode = (_get_settings().tracker_mode or "edit").strip().lower() mid = get_tracker_message_id(task_id) if mode == "bump": # bump: одна карточка, но всегда внизу. if mid is not None: delete_telegram(mid) # best-effort; fallback -> всё равно шлём новое new_mid = send_telegram(text, disable_notification=True) if new_mid is not None: set_tracker_message_id(task_id, new_mid) # send вернул None (нет кредов / транзиент) -> mid не трогаем, # дубля в пределах вызова нет; перерисуется на следующем переходе. return # mode == "edit" (ДЕФОЛТ): существующая логика без изменений. ... # текущий код edit/EDIT_GONE-fallback as is except Exception as e: logger.warning(f"update_task_tracker({task_id}) failed: {e}") ``` Инварианты bump-ветки: - В пределах ОДНОГО вызова отправляется максимум одно новое сообщение → дублей нет (BR-7). - `set_tracker_message_id` вызывается ТОЛЬКО при успешном `send` (`new_mid is not None`). При сбое send id остаётся прежним; на следующем переходе старый будет удалён (или уже мёртв) и отправлен новый — без накопления карточек. - `delete_telegram` — best-effort: его результат НЕ блокирует отправку новой карточки (BR-6: delete-fail → всё равно шлём новое). - Bump всегда тихий: `disable_notification=True` (BR-4). ### 3.3. Текстовые правки (общие для обоих режимов) | BR | Где | Было | Стало | |----|-----|------|-------| | BR-9 | `_BRD_LABEL` (модульная константа) | `"Ревью БРД"` | `"Подтверждение BRD"` | | BR-10 | `render_task_tracker`, ветка BRD-строки при `review_seconds is not None` | префикс `⏸️` (`⏸️`) | `✅` (`✅`). Ветка ожидания (`review_seconds is None`, с ⏳) — НЕ менять. | | BR-11 | `_TRACKER_STAGES` (метки) | `Analysis / Architecture / Development / Review / Testing / Deploy` | `Анализ / Архитектура / Разработка / Код ревью / Тестирование / Внедрение` | | BR-12 | `_done_link` | `"\U0001f4e6 deployed"` | `"\U0001f4e6 Внедрено"` | Примечания: - В `_TRACKER_STAGES` меняется ТОЛЬКО display-label (2-й элемент кортежа). Ключи стадий (`analysis`,…) и имена агентов (`analyst`,…) НЕ трогать — они завязаны на `_STAGE_ACTIVE_AGENT`, `last_done`, БД. - Выравнивание `{label:<13}` и `{_BRD_LABEL:<13}` оставить как есть (все новые русские метки ≤13 символов; «Подтверждение BRD» длиннее — формат просто не паддит, косметика, поведение не ломает). - Метки используются и в «✅ …»-строках завершённых стадий, и в «🔄 … идёт»-строке активной стадии — обе автоматически станут русскими (правка в одном месте). ## 4. Совместимость и риски - Дефолт `edit` гарантирует нулевую регрессию без явного включения bump (BR-8). Подробно — `10-tech-risks.md` (заводит архитектор/девелопер при необходимости). - Самохостинг: изменения только в коде нотификаций, миграций БД нет, перезапуск self — по стандартной страховке `deploy-staging` (8501) перед prod (см. `CLAUDE.md`). ## 5. Артефакты pipeline, которые ДОЛЖНЫ быть обновлены в этом же PR - `CHANGELOG.md` → запись в `[Unreleased] / Added` (режим bump) + `Changed` (русификация текста). - `docs/architecture/internals.md` — секция про live-tracker: режимы `edit`/`bump`, `ORCH_TRACKER_MODE`, контракт `delete_telegram`. - `.env.example` — `ORCH_TRACKER_MODE=edit` с комментарием. - Тесты — см. `04-test-plan.yaml`. **Существующие тесты в `tests/test_telegram_tracker.py`, проверяющие англоязычные метки (`"✅ Analysis"`, `"🔄 Deploy"`, `"Review"`) и метку `"Ревью БРД"`, ОБЯЗАТЕЛЬНО обновить под новые русские строки** — иначе регрессия в CI. Это правка существующих ассертов, не изменение контракта. ## 6. Замечания по реализации (без расширения scope) - Не вводить новых зависимостей; `httpx` уже используется. - Не менять сигнатуры `send_telegram` / `edit_telegram` / `update_task_tracker` (внешние вызовы из `launcher`/`stage_engine` не трогаются). - Не менять состав отдельных пингов (approve-gate / error / deploy-fail / agent-fail).