114 lines
10 KiB
Markdown
114 lines
10 KiB
Markdown
# 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):**
|
||
1. В Telegram висит карточка с заголовком «📍 To Analyse», хотя конвейер прошёл весь путь и все
|
||
стадии ✅ вплоть до «Внедрение».
|
||
2. Статусы деплоя не отражены (нет строки «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. `bump` vs `edit` — что реально надёжнее против сирот.** Замерить, не предполагать.
|
||
`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.
|
||
</content>
|
||
</invoke>
|