--- work_item: ORCH-091 stage: analysis author_agent: analyst status: ready-for-review created_at: 2026-06-09 model_used: claude-opus-4-8 --- # 01 — BRD (бизнес-требования): ORCH-091 — Карточка трекера: фикс «To Analyse» на deploy-staging, отражение откатов, суммирование метрик по попыткам Work Item: **ORCH-091** · Repo: **orchestrator** · Стадия: analysis ## 1. Бизнес-контекст и проблема Live Telegram-карточка задачи (ORCH-067, единственная карточка на задачу, рендер `src/notifications.py::render_task_tracker`) — основной канал, по которому Owner/Слава наблюдают прогресс конвейера. Карточка обязана показывать **честную** текущую картину. Объединены три верифицированных по коду и БД прода (09.06) дефекта одной карточки (ORCH-072 закрыт как дубль; ORCH-091 расширена до полного объёма): - **Дефект 1 (косметика, но вводит в заблуждение).** Заголовок-строка статуса карточки (`📍 `) застревает на «To Analyse», когда задача реально на стадии `deploy-staging`. Корень верифицирован: словарь `_STAGE_STATUS_LABEL` (`src/notifications.py` ~стр. 940) содержит 8 ключей (`created/analysis/architecture/ development/review/testing/deploy/done`), а реальные значения `tasks.stage` — это ключи `STAGE_TRANSITIONS` (`src/stages.py`), среди которых есть `deploy-staging`. Ровно эта стадия не покрыта → `.get(stage, _DEFAULT_STATUS_LABEL)` отдаёт дефолт «To Analyse» (`_DEFAULT_STATUS_LABEL`, ~стр. 950). Программно проверено: из 9 реальных стадий не покрыта **ровно одна** — `deploy-staging` (предпоследняя перед прод-деплоем, видна чаще всего). Сам дефолт-«To Analyse» — мина на будущее: любая новая стадия даст ложный «первый статус». - **Дефект 2 (ложная картина при откате).** При rollback по конвейеру (напр. merge-gate `deploy-staging → development`, ORCH-43; или REQUEST_CHANGES `review → development`) верхние строки `✅ пройдено` (Код-ревью / Тестирование / Внедрение) НЕ снимаются, а внизу снова `🔄 Разработка`. Абсурд: «Внедрение готово ✅, но идёт Разработка 🔄». Корень: цикл рендера в `render_task_tracker` (~стр. 474–505) выводит `✅`-строку для каждой стадии `_TRACKER_STAGES`, у чьего агента есть завершённый прогон (`last_done`), без учёта позиции стадии относительно текущей. - **Дефект 3 (реальное занижение тоталов, не косметика).** Строка стадии берёт ПОСЛЕДНИЙ прогон агента (`run = last_done.get(agent)`, ~стр. 475; `_stage_line`), теряя предыдущие попытки. На задаче с ретраями метрики стадии занижены. Верифицировано на ORCH-069 (`task_id=54`, прод 09.06): developer = 3 прогона Σ $3.98 (карточка показывала ~$0.00 за «Разработка»), reviewer = 3 Σ $2.10, tester = 2 Σ $1.03, deployer = 2 Σ $1.59. Источник истины — таблица `agent_runs` (`cost_usd`, `input_tokens`, `output_tokens`, `cache_read_tokens`, `cache_creation_tokens`, `started_at`/`finished_at`). > **Замечание (факт кода, не противоречие).** Блок тоталов задачи (`💰`/`🔢`/`⏱ Агенты`) > в текущем worktree уже суммирует ВСЕ прогоны (`render_task_tracker` ~стр. 388–404). > Заниженной остаётся **строка стадии** (`_stage_line` показывает только последний прогон). > Требование G4/AC-5 формулируется на уровне строки стадии и инварианта сходимости тоталов > с `SUM(agent_runs)` — реализация/архитектура подбора агрегата за архитектором. ## 2. Объём (scope) ### В объёме - Покрытие `_STAGE_STATUS_LABEL` всеми ключами `STAGE_TRANSITIONS` из единого программного источника истины (не «на глаз», не дублирующим списком). - Осмысленный staging-лейбл для `deploy-staging`, согласованный с моделью статусов ORCH-066/059. - Нейтральный фолбэк для истинно неизвестной/битой стадии (вместо «To Analyse»). - Отражение откатов: снятие `✅` со стадий ПОСЛЕ текущей позиции задачи. - Метрика строки стадии = Σ всех `agent_runs` стадии (💰 стоимость / 🔢 токены / ⏱ время), с сохранением сходимости тоталов задачи с `SUM(agent_runs)` по `task_id`. - Тесты на полноту карты стадий, суммирование метрик, отражение отката; `CHANGELOG.md`. ### Вне объёма - Изменение `STAGE_TRANSITIONS`, схемы БД, реестра `QG_CHECKS`/`check_*`, транспорта нотификаций (`send/edit/delete_telegram`). - Live-overlay ветки (Needs Input / Blocked / Rejected / Cancelled / Confirm Deploy / Deploying / Monitoring) — работают, не трогаем. - Архитектурное решение «как реализовать» (ordering-источник, форма агрегата) — зона архитектора (`06-adr/`). ## 3. Заинтересованные стороны - **Заказчик / приёмка:** Owner (homenet542), Слава (нашёл дефекты 08.06). - **Затрагивается:** все наблюдатели карточек конвейера всех проектов (общий прод-инстанс, self-hosting). Косметика карточки — для всех репо (orchestrator + enduro-trails). ## 4. Бизнес-требования (BR) - **BR-1 (Деф.1, G1)** — `_STAGE_STATUS_LABEL` покрывает КАЖДЫЙ ключ `STAGE_TRANSITIONS`; полнота гарантируется программно (итерация по единому источнику истины `src/stages.py`), а не статичным списком. Для каждой реальной стадии `plane_status_label` возвращает непустой осмысленный лейбл (не дефолт-«To Analyse», кроме реального `created`). - **BR-2 (Деф.1, G1)** — `stage='deploy-staging'` → осмысленный staging-лейбл (напр. «Deploying (staging)» / «⏳ Staging»), согласованный с моделью статусов ORCH-066/059. - **BR-3 (Деф.1, G2)** — фолбэк для истинно неизвестной/битой стадии — нейтральный (напр. «В работе» / stage capitalized), НЕ «To Analyse», чтобы будущая стадия не давала ложный «первый статус». `plane_status_label` остаётся never-raise. - **BR-4 (Деф.2, G3)** — при откате стадии карточка отражает ФАКТИЧЕСКУЮ текущую позицию: с стадий ПОСЛЕ точки отката снимается `✅`; текущая стадия отрисовывается как активная (`🔄`). Сценарий-эталон: после `deploy-staging → development` Разработка = `🔄`, Тестирование/Внедрение — НЕ `✅`. - **BR-5 (Деф.3, G4)** — метрика строки стадии = СУММА всех `agent_runs` этой стадии (по `task_id` + агент стадии) по трём метрикам: 💰 `Σ cost_usd`, 🔢 `Σ (input + output + cache_read + cache_creation)`, ⏱ `Σ (finished_at − started_at)`. Тоталы задачи = суммы по всем стадиям и попыткам, сходятся с `SUM(agent_runs)` по `task_id`. ## 5. Нефункциональные требования (NFR) - **NFR-1 (надёжность)** — `render_task_tracker` и `plane_status_label` остаются **stateless / never-raise**: любая ошибка деградирует к безопасному выводу, конвейер никогда не блокируется рендером карточки. - **NFR-2 (совместимость / регресс)** — существующие метки и строки НЕ меняются: In Review (brd-clock), Awaiting Deploy (`deploy`), Done, live-overlay ветки, строка `Подтверждение BRD`, формат строк стадий/тоталов, эффорт-суффикс (ORCH-087). Изменение аддитивно. - **NFR-3 (источник истины)** — полнота карты стадий выводится из `STAGE_TRANSITIONS` программно; запрещено дублировать перечень стадий руками (анти-рассинхрон на будущее). - **NFR-4 (self-hosting)** — изменения только в `src/notifications.py` + тесты + доки; без правки `STAGE_TRANSITIONS`/схемы БД/QG; без рестарта прод-контейнера в рамках задачи. ## 6. Допущения и ограничения - `tasks.stage` принимает строго значения-ключи `STAGE_TRANSITIONS` (включая `deploy-staging`, `cancelled`). Это инвариант движка стадий. - `cancelled` (ORCH-090) — системный терминал; его статус-лейбл уже рисуется live-overlay (`_LIVE_BRANCH_LABELS['cancelled']`). Для offline-фолбэка `plane_status_label` он не должен давать «To Analyse» (покрывается BR-3 нейтральным фолбэком; явный лейбл для `cancelled` — на усмотрение архитектора, без конфликта с overlay). - Источник метрик — `agent_runs`; стадия `deploy-staging` и `deploy` обслуживаются одним агентом `deployer` — агрегат по агенту корректно покрывает обе (вопрос разнесения staging/prod-прогонов по строкам — зона архитектора, не требование BRD). - Telegram-ограничение 48ч на удаление сирот (ORCH-087) — вне объёма. ## 7. Критерии успеха Карточка показывает корректный статус-заголовок на всех стадиях (включая `deploy-staging`), не «лжёт» о пройденных стадиях после отката, и метрики строки стадии + тоталы сходятся с `SUM(agent_runs)` по `task_id`. Полный регресс `pytest tests/ -q` зелёный. Детальные PASS/FAIL — `03-acceptance-criteria.md`. ## 8. Риски - Рассинхрон карты стадий с `STAGE_TRANSITIONS` в будущем (митигируется NFR-3 + тест полноты). - Регресс существующих меток/строк при правке цикла рендера (митигируется NFR-2 + тесты). - Неверная точка отсчёта «позиции» стадии для отката (ordering) → неверное снятие `✅`. Детали — `10-tech-risks.md` (заполняет архитектор).