Files
orchestrator/docs/work-items/ORCH-020/01-brd.md
claude-bot babc475ec3
All checks were successful
CI / test (push) Successful in 1m15s
analyst(ET): auto-commit from analyst run_id=797
2026-06-17 20:59:30 +03:00

27 KiB
Raw Blame History

work_item, stage, author_agent, status, created_at, model_used
work_item stage author_agent status created_at model_used
ORCH-020 analysis analyst ready-for-review 2026-06-17 claude-opus-4-8

01 — BRD (бизнес-требования): ORCH-020 — Оценка задачи (прогноз стоимости/времени/story points), запускаемая статусом «Оценка»

Work Item: ORCH-020 · Repo: orchestrator · Стадия: analysis

Revision после REJECT (Plane, 2026-06-17). Заказчик отклонил предыдущий пакет: «что я не увидел в БРД — как запускать оценку? Я хотел бы переводить задачу в статус "Оценка", после чего запускался бы механизм оценки, и после завершения оценки задача бы меняла статус на backlog. На оценку я буду отправлять задачи массово через Plane. Также я могу переоценивать задачи много раз.» Этот раунд переписывает модель триггера: оценка теперь — операторское действие, запускаемое выделенным Plane-статусом «Оценка» (а не «автоматически для каждой задачи на start_pipeline», как в отклонённой версии). Прочие требования (что прогнозируем, куда пишем, леджер прогноз↔факт, leaf-инварианты) сохранены и согласованы с новым триггером. Полный пакет 0104 supersedeит прежний по mtime.

1. Бизнес-контекст и проблема

Заказчик планирует работу по бэклогу вручную и хочет до отправки задачи в работу видеть прогноз: сколько задача будет стоить (токены × тариф = $), сколько займёт времени и насколько она сложна (размер в story points). Сейчас этих данных до старта нет: оркестратор собирает фактуру (input_tokens/output_tokens/cache_*/cost_usd/model/effort, тайминги agent_runs.started_at/finished_at, tasks.created_at/updated_at) только постфактум через src/usage.py (task_usage_summary, agent_cost_totals, record_usage). Контур прогноза до старта отсутствует.

Корень REJECT — отсутствовал способ ЗАПУСКА оценки. Заказчик мыслит оценку как операторский жест в Plane, а не как невидимый авто-шаг: он сам решает, какие задачи бэклога оценить, массово переводит их в выделенный статус, получает прогнозы и продолжает планирование. Отклонённая версия прятала триггер в start_pipeline («оценка обязательна для каждой задачи автоматически») и явно называла точку триггера «реализационной деталью» — это и есть то, что заказчик «не увидел» и отверг.

Цитаты заказчика (Plane, 2026-06-17):

  • REJECT: «как запускать оценку? Я хотел бы переводить задачу в статус "Оценка", после чего запускался бы механизм оценки, и после завершения оценки задача бы меняла статус на backlog. На оценку я буду отправлять задачи массово через Plane. Также я могу переоценивать задачи много раз
  • Раунд Needs Input: «В Plane есть поле оценка, туда и нужно записывать оценку. По факту завершения задачи вписать в смежное поле… для оценки есть два поля.»; «Только Шаг 1, без выбора модели»; «Модели не выбираем и не меняем. Это вне скоупа».

Установленные факты по коду (на которые опирается решение, не изобретать):

  • Прецедент «статус-триггер уже есть в платформе. Plane-статусы — слой B (индикация, ORCH-066) и НЕ управляют машиной стадий; но платформа уже имеет операторские action-статусы, запускающие side-механизмы: STOP (ORCH-090, отмена задачи) и Confirm Deploy (ORCH-059, прод-деплой). Оба разбираются в webhooks/plane.py::handle_issue_updated через proj_states.get("<key>") и оба намеренно отсутствуют в plane_sync._DEFAULT_STATES (fail-closed: доска без статуса → None → ветка не активируется). Статус «Оценка» — третий представитель этого же семейства.
  • Маппинг имени статуса → логический ключplane_sync._PLANE_NAME_TO_KEY ("STOP"→"stop", "Confirm Deploy"→"confirm_deploy"); get_project_states резолвит UUID статуса per-project из Plane API.
  • Массовость — «бесплатно». Plane multi-select по N задачам в статус «Оценка» порождает N отдельных issue.updated-вебхуков (по одному на issue); каждый обрабатывается независимо. Отдельный «batch-UX» в оркестраторе не требуется — массовость обеспечивает сам Plane.
  • Фактура для калибровки уже накоплена (agent_runs, агрегаты task_usage_summary / agent_cost_totals, тайминги). Это сырьё для «истории похожих задач».
  • Plane-поля существуют. На issue присутствуют поля estimate_point (ОЦЕНКА) и point (ФАКТ); estimate-система на проекте (project.estimate) на момент анализа не настроена — инфра- предусловие (NFR-7).
  • Выбор модели/эффорта статичен по роли (resolve_agent_model/resolve_agent_effort, ORCH-41/74; дефолт claude-opus-4-8) и в этой задаче не трогается (Шаг 2 вне объёма).
  • leaf-паттерн платформы (serial_gate/coverage_gate/labels/lessons/cancel): never-raise, kill-switch *_enabled, *_repos CSV (пусто → self-hosting only), read-only блок в GET /queue.

2. Объём (scope)

В объёме (Шаг 1 — Оценка, запускаемая статусом)

  • Триггер «Оценка» (ядро правки). Перевод issue в выделенный Plane-статус «Оценка» запускает механизм оценки этой задачи. Оператор делает это вручную и массово (multi-select в Plane).
  • Жизненный цикл статуса: Backlog → (оператор) «Оценка» → [оркестратор: оценка] → (оркестратор) Backlog. По завершении оценки оркестратор сам возвращает issue в статус Backlog.
  • Пере-оценка много раз. Повторный перевод в «Оценка» переоценивает задачу заново (идемпотентно: перезапись estimate_point и строки леджера). Применимо при изменении скоупа.
  • Прогноз четырёх величин: стоимость ($), время, токены и сложность в story points из фиксированной шкалы {1, 2, 3, 5, 8}.
  • Шкала story points (фиксированная, ответ Q-3 = вариант A): 1 — мелкая docs/label/config; 2 — небольшой фикс; 3 — средняя; 5 — сложная (код + тесты); 8 — эпик / разбивать.
  • Запись прогноза в Plane-поле estimate_point (это ОЦЕНКА).
  • Запись факта в Plane-поле point по завершении задачи (фактическая реализованная сложность в story points из фактических токенов/времени/стоимости по той же шкале) — для калибровки.
  • Отображение прогноза на двух поверхностях (ответ Q-5 = оба): Plane-коммент + пункт «Оценка» в общей Telegram-карточке задачи (src/notifications.py) — время, токены, стоимость.
  • Локальный леджер прогноз↔факт (фундамент петли калибровки, связь с ORCH-8): хранение прогноза, факта и дельты, ключ — work_item_id (issue может ещё не иметь pipeline-задачи на момент оценки — она на бэклоге).

Вне объёма

  • Шаг 2 — адаптивный выбор моделей агентов (ответы Q-1/Q-2: «Только Шаг 1, без выбора модели»; «Модели не выбираем и не меняем. Это вне скоупа»). Горячий путь resolve_agent_model/ resolve_agent_effort/_spawn не модифицируется.

    ACTION (поручение заказчика, Plane 16:34): «заведи отдельную задачу в Plane для адаптивного выбора модели и укажи зависимость на мультипровайдеров (ORCH-13)». Создание Plane-issue — действие уровня заказчика/PM и вне write-объёма аналитика (Write ограничен docs/work-items/<id>/*). Фиксирую как обязательный follow-up: новый work item «Адаптивный выбор модели агента по сложности» с зависимостью на ORCH-13; оценщик сложности из ORCH-020 — его вход. Оператору: подтвердить создание или создать вручную.

  • Автопереключение трека по сложности (связка с ORCH-19) — позже; здесь сложность лишь вычисляется и публикуется как сигнал.
  • Авто-ретроспективщик / RICE-приоритизатор (E2/E3 ORCH-8) — вне объёма; леджер — фундамент.
  • Автоматическая оценка КАЖДОЙ задачи на start_pipelineисключена явно (модель отклонённой версии). Оценка — операторский on-demand жест через статус «Оценка».
  • Изменение тарифной/биллинговой модели — используется существующий cost_usd из usage.py.
  • Новый «batch-UX»/массовый эндпоинт как ОСНОВНОЙ путь — не нужен (массовость даёт Plane multi-select → N вебхуков). Программный POST /estimate* допустим лишь как опциональное удобство/диагностика, не как основной триггер (см. TRZ §4).

3. Заинтересованные стороны

  • Заказчик / владелец продукта (Слава) — инициатор оценки (переводит задачи в «Оценка»), потребитель прогноза для планирования бэклога; принимает результат.
  • Оркестратор (self-hosting) — носитель функции; общий прод обслуживает и enduro-trails.
  • Будущая петля саморазвития (ORCH-8) — потребитель леджера прогноз↔факт для калибровки.
  • ORCH-13 (мультипровайдерность) — будущий потребитель сигнала сложности (через follow-up Шаг 2).

4. Бизнес-требования (BR)

Триггер и жизненный цикл (ядро ревизии)

  • BR-T1 — Запуск оценки статусом «Оценка». Перевод issue в выделенный Plane-статус «Оценка» запускает оценку именно этой задачи. Это единственный обязательный способ запуска (массовый и ручной), реализуемый по образцу операторских action-статусов STOP (ORCH-090) / Confirm Deploy (ORCH-059).
  • BR-T2 — Авто-возврат в Backlog. По завершении оценки (успех или best-effort-пропуск) оркестратор сам переводит issue обратно в статус Backlog. Заказчик видит задачу вернувшейся в бэклог с заполненным estimate_point.
  • BR-T3 — Массовость через Plane. Массовый перевод N задач в «Оценка» (multi-select Plane) оценивает все N; каждый issue обрабатывается независимо (N вебхуков). Отдельный массовый UX в оркестраторе не требуется.
  • BR-T4 — Пере-оценка много раз (идемпотентно). Повторный перевод задачи в «Оценка» переоценивает её заново; прогноз и строка леджера перезаписываются (не дублируются). Число пере-оценок не ограничено.
  • BR-T5 — Fail-closed статус. На доске без статуса «Оценка» (enduro / частичная конфигурация / Plane недоступен) триггер не активируется (ключ резолвится в None) — нулевая регрессия; это инфра-предусловие (NFR-7), а не ошибка.
  • BR-T6 — Не нарушать машину стадий и in-flight работу. Статус «Оценка» запускает side- механизм, а не переход стадии. Если у issue есть активная pipeline-задача (queued/running job), триггер — no-op + лог (не выдёргивать выполняемую работу в Backlog, не трогать STAGE_TRANSITIONS). Авто-возврат в Backlog не создаёт цикла: статус Backlog ни одной веткой handle_issue_updated не обрабатывается (no-op-эхо).

Содержание оценки (сохранено, согласовано с триггером)

  • BR-1 — Прогноз. Для задачи оркестратор производит прогноз четырёх величин: стоимость ($), время, токены и сложность в story points из фиксированной шкалы {1,2,3,5,8}.
  • BR-2 — База оценки — история. Прогноз строится на истории похожих завершённых задач (по типу/стадиям/стеку): средние токены/время/стоимость из уже накопленной фактуры (agent_runs, task_usage_summary, agent_cost_totals, тайминги). При отсутствии истории — разумный bootstrap- дефолт (не блокирует).
  • BR-3 — Шкала story points фиксированная с точной семантикой 1/2/3/5/8 (см. §2). Значение 8 — «эпик: разбивать».
  • BR-4 — On-demand, не блокирующая. Оценка производится по запросу (перевод в «Оценка»), а не для каждой задачи автоматически; строго best-effort — сбой/выключение оценки никогда не тормозит конвейер и не меняет маршрут.
  • BR-5 — Доступность до старта работы. Поскольку оператор оценивает задачи на бэклоге (до To Analyse/start_pipeline), прогноз доступен до перевода задачи в работу — он и нужен для планирования отправки задач.
  • BR-7 — Запись прогноза в Plane. Прогноз сложности (story points) записывается в поле issue estimate_point (= ОЦЕНКА).
  • BR-8 — Запись факта в Plane. По завершении задачи (переход в done) фактическая реализованная сложность (story points из фактических токенов/времени/стоимости по той же шкале) записывается в смежное поле point — для калибровки; прогноз estimate_point при этом не перезаписывается.
  • BR-9 — Отображение на двух поверхностях. Прогноз публикуется: (a) Plane-комментом; (b) пунктом «Оценка» в общей Telegram-карточке задачи — время, токены, стоимость.
  • BR-10 — Леджер прогноз↔факт (калибровка). Прогноз и факт сохраняются локально вместе с дельтой (ключ work_item_id); фундамент петли уточнения модели оценки (связь с ORCH-8). Достаточно фиксировать обе величины и дельту (авто-уточнение модели — позже).

5. Нефункциональные требования (NFR)

  • NFR-1 — Оценка ≠ Quality Gate / ≠ переход стадии. Модуль — наблюдатель/продюсер. STAGE_TRANSITIONS / QG_CHECKS / check_* / machine-verdict-ключи (verdict:/result:/ deploy_status:/staging_status:/security_status:/coverage_status:) / схемы существующих таблиц — байт-в-байт не тронуты. Статус «Оценка» не добавляет ребра в машину стадий; он запускает side-механизм и сам возвращает issue в Backlog.
  • NFR-2 — leaf-паттерн. never-raise (любой сбой → warning + безопасный дефолт), kill-switch *_enabled, скоуп *_repos (CSV; пусто → self-hosting only), read-only блок в GET /queue.
  • NFR-3 — self-hosting safety. Модуль не рестартит/не роняет прод-контейнер, не трогает main/ force-push, не вмешивается в горячий путь запуска агентов (resolve_agent_model/ resolve_agent_effort/_spawn не модифицируются). Выключенный флаг / неприменимый репо → нулевая регрессия для enduro-trails и orchestrator.
  • NFR-4 — Стоимость оценки ≪ её ценности. Сама оценка должна быть дешёвой и быстрой относительно выгоды планирования. Выбор механизма (эвристика по истории / отдельный LLM-вызов / гибрид) и баланс «точность vs стоимость» — архитектурное решение (06-adr); в TRZ — лишь требование-ограничение.
  • NFR-5 — Толерантность к массовости. Массовый перевод (десятки задач разом → десятки вебхуков почти одновременно) не должен перегружать прод/конвейер: оценка best-effort, изолирована от control-path; механизм сглаживания нагрузки (дешёвая эвристика / очередь / троттлинг) — деталь 06-adr. Требование: bulk не роняет и не тормозит обслуживание других проектов.
  • NFR-6 — Запись в Plane через существующие примитивы. estimate_point/point/коммент/возврат в Backlog пишутся через plane_sync и подчиняются sandbox write-guard (ORCH-117): в боевом рантайме (uvicorn) — штатная запись, из тест/worktree-процесса — заблокирована. Новых секретов/токенов не вводится.
  • NFR-7 — Fail-safe и инфра-предусловия Plane. (a) Статус «Оценка» должен существовать на доске проекта (его отсутствие = fail-closed no-op, BR-T5). (b) estimate-система Plane со значениями 1/2/3/5/8 (Fibonacci) для estimate_point должна быть настроена; при её отсутствии запись estimate_point/point best-effort пропускается (+ лог) и не роняет конвейер. Детали и точные группы статуса — 07-infra-requirements.md (архитектор).
  • NFR-8 — Обратная совместимость данных. Хранение прогноз↔факт — аддитивная новая таблица (CREATE TABLE IF NOT EXISTS); существующие таблицы/колонки не изменяются.

6. Допущения и ограничения

  • Оценка на бэклоге работает по issue (описание/тип/лейблы из Plane API + история похожих), а не по локальной pipeline-задаче: на момент оценки tasks-строки может не быть → леджер и запись ключуются по work_item_id, task_id — нуллабелен до старта пайплайна.
  • Статус «Оценка» — транзиентный (issue в нём лишь на время оценки, затем Backlog); его Plane-группа (backlog/unstarted) косметична — деталь онбординга/инфры (ORCH-009 расширяется на 23-й статус).
  • Фактура usage.py/agent_runs достаточна для расчёта факта при завершении; «фактические story points» выводятся из факта по той же шкале {1,2,3,5,8}.
  • Без ORCH-13 «выбор модели» бессмыслен (один дефолт) — Шаг 2 корректно вынесен в follow-up.
  • Точная Plane-семантика estimate_point (FK на estimate-point estimate-системы) vs point (целочисленный) — деталь реализации/инфры (архитектор + NFR-7).

7. Критерии успеха

Заказчик массово переводит задачи бэклога в статус «Оценка»; по каждой оркестратор производит прогноз (стоимость/время/токены/story points), пишет его в estimate_point, публикует в Plane-комменте и пункте «Оценка» Telegram-карточки, сохраняет в леджер прогноз↔факт и возвращает issue в Backlog; пере-оценка повтором перевода идемпотентна; по завершении задачи факт пишется в point. Всё это — без единого изменения control-path/гейтов, без касания горячего пути запуска агентов, без выдёргивания in-flight работы; на доске без статуса «Оценка» / при выключенном флаге — нулевая регрессия. Детальные PASS/FAIL — 03-acceptance-criteria.md.

8. Риски

  • Статус «Оценка» дёргает in-flight задачу → снимается BR-T6 (no-op при активном job) + авто- возврат только в Backlog, никогда не трогая стадии.
  • Цикл вебхуков (возврат в Backlog → новый webhook) → снимается тем, что Backlog не обрабатывается ни одной веткой handle_issue_updated (no-op-эхо) — анти-loop по построению.
  • Перегрузка от массового перевода → снимается NFR-5 (best-effort, дешёвый механизм/сглаживание — 06-adr).
  • Запись в боевой Plane (estimate_point/point/коммент/состояние) на общей доске → снимается write-guard (ORCH-117) + best-effort/fail-safe (NFR-6/NFR-7).
  • Неточность прогноза на холодном старте (мало истории) → bootstrap-дефолт + петля калибровки (BR-10).
  • Расползание в Шаг 2 (control-path) → жёсткий out-of-scope + NFR-3. Детальный разбор — 10-tech-risks.md (архитектор).