10 KiB
01-BRD — ORCH-087
Заголовок: Трекер-карточка застревает на старом статусе («To Analyse») + осиротевшие карточки при bump; + эффорт в строке стадии.
Тип: Багфикс (UX live-трекера) + малое расширение карточки.
Приоритет: MEDIUM.
Зона: src/notifications.py (update_task_tracker bump-режим, render_task_tracker), src/db.py (хранение message_id'ов задачи + колонка agent_runs.effort), src/agents/launcher.py (стамп фактического эффорта).
Связь: ORCH-042 (введён bump), ORCH-067 (формат карточки, статус-строка, ссылки), ORCH-052h/ORCH-081 (эффорт реально работает), ORCH-080 (link-preview).
1. Контекст и проблема
Live-трекер ведёт одну карточку на задачу (update_task_tracker). Дефолтный режим — bump
(ORCH-067): на каждом обновлении delete_telegram(old_mid) (best-effort, НЕ блокирует send) →
send_telegram(new) (тихо, вниз чата) → set_tracker_message_id(new_mid) — но указатель
tasks.tracker_message_id хранит только последний message_id.
Симптом (Слава, скриншот 08.06, задача ORCH-082):
- В Telegram висит карточка с заголовком «📍 To Analyse», хотя конвейер прошёл весь путь и все стадии ✅ вплоть до «Внедрение».
- Статусы деплоя не отражены (нет строки «Awaiting Deploy / Confirm Deploy»), хотя задача реально
на стадии
deploy.
Код-аудит 08.06 (предварительная гипотеза, подлежит ПОДТВЕРЖДЕНИЮ — см. G0):
render_task_tracker СЕЙЧАС рендерит корректно (заголовок текущей стадии, deploy виден). Значит
карточка со скриншота — осиротевшая старая (msg 18204), застрявшая на первом рендере
(_DEFAULT_STATUS_LABEL = "To Analyse"). bump не удалил её: при рассинхроне tracker_message_id
(сбой send → new_mid=None → указатель не перезаписан; рестарт орка между delete и send;
пересоздание во время ручного фикса/CLI) часть карточек осиротевает и навсегда замирает на старом
статусе. Проверено: бот МОЖЕТ удалять (deleteMessage → ok:true для 18204 и 18227) — дело не в
правах, а в потере ссылки на старые message_id.
Это диагноз-кандидат, его нельзя принимать на веру (см. требование G0 ниже — расследование должно установить точную механику, потому что предыдущие диагнозы уже путали причины).
2. Цели (бизнес-уровень)
- G0 (расследование ПЕРВЫМ, до фикса): установить ТОЧНУЮ механику бага по данным, не вслепую.
- G1: Не оставлять осиротевших карточек: при
bumpстарая карточка удаляется ВСЕГДА, либо хранится список ВСЕХ созданных message_id задачи и незакрытые подчищаются. - G2: Заголовок живой карточки отражает ТЕКУЩУЮ стадию (не застывает на «To Analyse»).
- G3: Статусы деплой-цикла (Awaiting Deploy / Confirm Deploy / Deploying / Monitoring / Done) видны на карточке на соответствующих стадиях.
- G4 (расширение): В строку каждой стадии карточки добавить уровень эффорта рядом с моделью.
3. G0 — обязательное расследование (вход в ADR)
Вывод G0 оформляется архитектором в 06-adr/ ДО фикса. Расследование обязано ответить на:
- R-1. Сколько РЕАЛЬНО карточек одной задачи висело в чате к моменту бага — собрать
message_idиз логов/Telegram (сирот могло быть >1, а не ровно 2). - R-2. В какие МОМЕНТЫ
tracker_message_idрассинхронизируется с реальными сообщениями: (a)sendвернулNone(нет креды/transient) → mid не перезаписан; (b) рестарт орка междуdeleteиsend; (c) пересоздание карточки во время CLI-фикса/ручных операций; (d) гонка двухupdate_task_trackerподряд (быстрые стадии); (e)deleteупал (rate-limit/48ч), ноsendпрошёл. По каждому пункту — подтвердить/опровергнуть как реальный источник сирот. - R-3. Почему ИМЕННО заголовок застывает на «To Analyse»: это старый рендер (до смены stage) или
баг плана-лейбла? Воспроизвести на staging: прогнать задачу, на КАЖДОЙ стадии зафиксировать
факт в Telegram (заголовок + тело) против БД (
tasks.stage). - R-4.
bumpvsedit— что реально надёжнее против сирот. Замерить, не предполагать.editправит ОДНО сообщение in-place (нет сирот, но карточка не уезжает вниз чата);bumpдержит карточку внизу (фича-просьба ORCH-042), но плодит сирот при рассинхроне. Дать обоснованную рекомендацию С ДАННЫМИ (оставитьbumpс гарантированной зачисткой ИЛИ перейти наedit).
4. G4 — эффорт в строке стадии (расширение)
Сейчас строка стадии показывает модель (opus-4-8), но не эффорт. После ORCH-052h/ORCH-081 эффорт
реально применяется (developer=xhigh, tester/deployer=medium, прочие=high). Нужно показывать
фактически применённый уровень рядом с моделью.
- Формат (компактно, на усмотрение архитектора):
… · opus-4-8 · xhighИЛИ… · opus-4-8/xhigh. Пример полной строки:✅ Разработка 7м · 4.9M↓/32k↑ · $3.97 · opus-4-8 · xhigh. - Источник эффорта (предпочтительно): сохранять ФАКТИЧЕСКИ применённый эффорт в
agent_runs(то, что реально ушло в CLI), а не пересчитыватьresolve_agent_effort(agent)на рендере — новая колонкаagent_runs.effort(как уже естьagent_runs.model). Это надёжнее: не зависит от изменения конфига между запуском и рендером. - developer-строка показывает
xhigh; механические (tester/deployer) —medium. - Архитектор вправе вынести G4 отдельной мелкой задачей; по умолчанию — в этом же PR (одна зона:
notifications.py+agent_runs).
5. Не-цели
- Не плодить дубликаты — инвариант «одна карточка на задачу» сохранить.
- Не пинговать —
disable_notificationостаётся (карточка тихая). - Не ломать ссылки ORCH-067 (
plane_issue_link) и подавление link-preview ORCH-080. - Не менять
STAGE_TRANSITIONS,QG_CHECKS, статусную модель ORCH-066. - Не трогать поведение для не-self проектов сверх необходимого (общая БД/очередь — enduro-trails).
6. Ограничения / грабли
- Telegram 48ч: сообщения старше 48ч удалить нельзя (
deleteMessageвернёт «message can't be deleted»). Для совсем старых сирот зачистка может не сработать — документировать как ограничение (поведениеdelete_telegram: такой исход трактуется как «уже не наша проблема»,_DELETE_GONE_MARKERS). - Rate-limit / 429 на массовом удалении при накопившихся сиротах.
- Общая БД/очередь с enduro-trails — любое изменение схемы строго аддитивно и идемпотентно
(
_ensure_column), нулевая регрессия для других проектов. - never-raise: компонент нотификаций никогда не валит конвейер (CLAUDE.md, ORCH-067).
7. Заинтересованные лица
- Owner / наблюдатель (Слава) — видит карточку, инициатор бага.
- Self-hosting прод — карточки всех проектов из одного инстанса.
8. Критерии успеха (бизнес)
См. 03-acceptance-criteria.md. Кратко: завершённая задача не оставляет карточек с устаревшим
заголовком; единственная актуальная карточка показывает текущий статус включая deploy-цикл; сироты
не возникают/подчищаются при сбое send/рестарте; эффорт виден в каждой строке стадии; pytest
зелёный, never-raise.