27 KiB
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-инварианты) сохранены и согласованы с новым триггером. Полный пакет01–04supersede’ит прежний по 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,*_reposCSV (пусто → 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/pointbest-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-системы) vspoint(целочисленный) — деталь реализации/инфры (архитектор + 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(архитектор).