Files
orchestrator/docs/architecture/adr/adr-0054-task-estimation-status-trigger.md
claude-bot 6c204548a7
All checks were successful
CI / test (push) Successful in 1m14s
architect(ET): auto-commit from architect run_id=798
2026-06-17 21:16:50 +03:00

9.0 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 architecture architect proposed 2026-06-17 claude-opus-4-8

ADR-0054: Оценка задачи — операторский статус-триггер «Оценка» + детерминированная эвристика по истории

Сквозной (cross-cutting) ADR. Детальное решение задачи — docs/work-items/ORCH-020/06-adr/ADR-001-task-estimation-status-trigger.md.

Статус: Proposed · Дата: 2026-06-17 · Источник: ORCH-020

Контекст

Заказчик планирует бэклог вручную и хочет видеть прогноз стоимости / времени / токенов / сложности (story points {1,2,3,5,8}) до отправки задачи в работу. Ключевое требование триггера (после REJECT 2026-06-17): оценка — операторский жест в Plane (перевод issue в выделенный статус «Оценка», массово через multi-select), а не невидимый авто-шаг на start_pipeline. Шаг 2 (адаптивный выбор модели) — вне объёма.

Решение пересекает несколько подсистем (webhook-роутинг, plane_sync, БД, notifications, stage_engine done-хук), поэтому фиксируется сквозным ADR. Опирается на установленные инварианты платформы:

  • Семейство операторских action-статусов STOP (ORCH-090) / Confirm Deploy (ORCH-059): fail-closed .get("<key>")-ветка в handle_issue_updated, ключ намеренно отсутствует в _DEFAULT_STATES.
  • Write-guard ORCH-117 — все записи в Plane изолированы от тест/worktree-процессов.
  • leaf-паттерн (serial_gate/coverage_gate/bug_fast_track/lessons): never-raise, kill-switch, скоуп *_repos (пусто → self-hosting only), read-only блок в GET /queue.
  • determinization-политика ORCH-118 (llm-usage-policy.md): не вводить avoidable LLM-пути.

Решение

Вводим третий член семейства action-статусов — «Оценка» — как side-механизм, делегирующий новому leaf src/estimator.py. Механизм прогноза — детерминированная эвристика по истории (чистые функции, без LLM-вызова). Аддитивно, под kill-switch, скоуп self-hosting, never-raise, fail-safe:

  1. Триггер (D4). _PLANE_NAME_TO_KEY["Оценка"]="estimate" (НЕ в _DEFAULT_STATES); fail-closed ветка proj_states.get("estimate")handle_estimate (off-loop to_thread, зеркало handle_stop). Взаимоисключение жестов — по различию UUID статусов, не по порядку.
  2. Анти-disruption + авто-возврат + анти-loop (D5). Guard applies(repo) ПЕРВЫМ (локально) + has_active_job_for_task (активный job → no-op, не выдёргивать in-flight). После оценки — set_issue_backlog; backlog не совпадает ни с одной триггер-веткой → возврат = no-op-эхо.
  3. Механизм прогноза (D1/D2/D3). Без LLM: прогноз = средние токены/время/стоимость похожих done-задач (repo + track ORCH-019, через read-only usage.py-агрегаты), bootstrap при пустой истории; story-points — чистая функция-бакетизатор по forecast_cost_usd с конфигурируемыми порогами.
  4. Запись в Plane (D6). Прогноз story-points → set_issue_estimate_point (FK на estimate-point, резолв value→uuid); факт → set_issue_point (устойчивый int); коммент → add_comment. Все под _guard_allows_write (ORCH-117); отсутствие estimate-системы → best-effort пропуск + лог (NFR-7).
  5. Персистентность (D7). Новая аддитивная таблица task_estimates (UNIQUE(work_item_id), UPSERT-идемпотентность пере-оценки; task_id нуллабелен — issue на бэклоге). Фундамент петли калибровки (ORCH-8).
  6. Поверхности (D8). Пункт «Оценка» (время·токены·стоимость) в общей Telegram-карточке (notifications, never-raise, ORCH-087/095-совместимо).
  7. Факт на done (D9). Best-effort врезка в stage_engine.advance_stage (блок next_stage=="done", после terminal-sync): факт из usage.pyset_actual + set_issue_point; estimate_point не перезаписывается.

Главное архитектурное решение — отказ от LLM-оценщика (D1). Причины: NFR-5 (massive multi-select умножил бы LLM-вызовы и конкурировал бы за единственный транспорт launcher._spawn с боевыми агентами, рискуя обслуживанием enduro), NFR-4 (стоимость самой оценки), и политика ORCH-118 (размер задачи деривируем из tool-сигналов — суждение LLM не требуется). Контракт estimate() — граница расширения под будущий гибрид без переписывания вызывающих (но он сейчас НЕ строится).

Инварианты (нормативно)

  • Оценка — наблюдатель/продюсер, НЕ Quality Gate и НЕ переход стадии. STAGE_TRANSITIONS / реестр и имена QG_CHECKS / семантика check_* / machine-verdict-ключи (verdict:/result:/deploy_status:/ staging_status:/security_status:/coverage_status:) / схемы существующих таблицбайт-в-байт не тронуты. Статус «Оценка» не добавляет ребра в машину стадий.
  • Горячий путь не тронут: resolve_agent_model/resolve_agent_effort/_spawn без изменений (Шаг 2 вне объёма — отдельный work item с зависимостью на ORCH-13).
  • Схема БД: ровно одна аддитивная таблица task_estimates (CREATE TABLE IF NOT EXISTS); существующие таблицы не изменяются (NFR-8). Hot-path claim_next_job/очередь её не читают.
  • Self-hosting-безопасность: модуль только читает/пишет свою таблицу, читает usage-агрегаты и пишет в Plane/Telegram — не деплоит, не рестартит прод-контейнер, не трогает main/force-push, без процессов.
  • never-raise / обратимость: все публичные функции и врезки изолированы; estimator_enabled=false / доска без статуса «Оценка» / репо вне estimator_repos → байт-в-байт как до ORCH-020 (enduro и текущий orchestrator не затронуты).
  • Без kill-switch обхода write-guard: записи estimate_point/point/коммент/состояние подчиняются ORCH-117 (anti-drift: тест-процесс физически не пишет в боевой Plane).

Последствия

Оператор получает прогноз для планирования бэклога одним массовым жестом; пере-оценка идемпотентна; заложен леджер прогноз↔факт под петлю калибровки (ORCH-8). Цена — net-new интеграция с Plane-estimate API (estimate_point — FK; смягчено best-effort/fail-safe + устойчивым int-point) и начальные пороги story-points (смягчено конфигурируемостью + леджером). Решение сознательно консервативно (детерминировано, обратимо, согласовано с ORCH-118) и не требует arch:major-change (аддитивный leaf по устоявшемуся паттерну, без новой стадии/правки таблиц/смены БД). Детали, альтернативы и риски — docs/work-items/ORCH-020/06-adr/ADR-001-task-estimation-status-trigger.md, docs/work-items/ORCH-020/07-infra-requirements.md, 08-data-requirements.md, 10-tech-risks.md.