---
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 (косметика, но вводит в заблуждение).** Заголовок-строка статуса карточки
  (`📍 <status_label>`) застревает на «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` (заполняет архитектор).
