Files
orchestrator/docs/work-items/ORCH-020/04-test-plan.yaml
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

150 lines
9.0 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
work_item: ORCH-020
stage: analysis
author_agent: analyst
status: ready-for-review
created_at: 2026-06-17
model_used: claude-opus-4-8
title: "Оценка задачи, запускаемая Plane-статусом «Оценка»: триггер/возврат в Backlog/массовость/пере-оценка + прогноз {токены,время,стоимость,story points}, запись в Plane, карточка, леджер прогноз↔факт, leaf-инварианты"
framework: pytest
scope: >
Покрывается: распознавание статуса «Оценка» как триггера (handle_estimate),
fail-closed при отсутствии статуса, авто-возврат issue в Backlog + анти-loop,
анти-disruption in-flight (no-op при активном job), массовость (N вебхуков -> N оценок),
идемпотентная пере-оценка (UPSERT по work_item_id), расчёт прогноза из истории (usage-агрегаты),
маппинг величин -> story-point bucket {1,2,3,5,8} (чистая функция), never-raise/bootstrap при
пустой истории, запись прогноза в estimate_point и факта в point (через guard ORCH-117, fail-safe
при отсутствии estimate-конфига), пункт "Оценка" в Telegram-карточке, read-only блок estimator в
GET /queue, аддитивная таблица task_estimates (ключ work_item_id, task_id нуллабелен),
kill-switch + скоуп (пусто -> self-hosting only).
Вне покрытия: адаптивный выбор модели (Шаг 2, вне объёма), авто-уточнение модели оценки (ORCH-8),
автопереключение трека по сложности (ORCH-19).
notes: >
Тесты используют изолированную временную SQLite-БД (фикстура init_db во временном файле) и
замоканные plane_sync/notifications/usage/get_project_states — без сети, без боевого Plane/Telegram,
без LLM. Триггер тестируется на уровне handle_issue_updated/handle_estimate с подставленными
proj_states (UUID статуса "Оценка"). Запись в Plane проверяется на уровне вызова write-хелперов под
guard (ORCH-117 autouse-floor conftest держит opt-in OFF — сетевая запись физически невозможна из
теста). Control-path анти-регресс: STAGE_TRANSITIONS/QG_CHECKS/check_*/machine-verdict/схемы
существующих таблиц не меняются; полный регресс tests/ остаётся зелёным.
tests:
- id: TC-01
type: integration
description: "Триггер: new_state == proj_states['estimate'] -> handle_estimate вызывается; estimate-статус добавлен в _PLANE_NAME_TO_KEY как 'Оценка'->'estimate' (AC-T1)"
module: tests/test_orch020_estimator.py
expected: PASS
- id: TC-02
type: integration
description: "Fail-closed: 'estimate' отсутствует в _DEFAULT_STATES; на проекте без статуса proj_states.get('estimate') is None -> ветка инертна, handle_estimate не зовётся, нет KeyError (AC-T5)"
module: tests/test_orch020_estimator.py
expected: PASS
- id: TC-03
type: integration
description: "handle_estimate на backlog-issue (нет pipeline-задачи): прогноз вычислен, записан, затем set_issue_backlog -> issue возвращён в Backlog (AC-T1, AC-T2)"
module: tests/test_orch020_estimator.py
expected: PASS
- id: TC-04
type: integration
description: "Анти-disruption: issue с активным job (has_active_job_for_task=True) -> handle_estimate no-op + лог, оценка не запускается, статус не меняется (AC-T6)"
module: tests/test_orch020_estimator.py
expected: PASS
- id: TC-05
type: integration
description: "Анти-loop: возврат в Backlog не алиасит триггер-ветки (Backlog-UUID != estimate/stop/to_analyse/confirm_deploy/approved/rejected) -> входящий 'state->Backlog' webhook = no-op-эхо (AC-T6)"
module: tests/test_orch020_estimator.py
expected: PASS
- id: TC-06
type: integration
description: "Массовость: N issue.updated со state='Оценка' -> N независимых вызовов handle_estimate, каждый даёт прогноз; один webhook не гасит остальные (AC-T3)"
module: tests/test_orch020_estimator.py
expected: PASS
- id: TC-07
type: integration
description: "Идемпотентная пере-оценка: повторный перевод в 'Оценка' -> UPSERT по work_item_id обновляет одну строку task_estimates и estimate_point, не дублирует (AC-T4)"
module: tests/test_orch020_estimator.py
expected: PASS
- id: TC-08
type: unit
description: "estimate() возвращает {forecast_tokens,forecast_seconds,forecast_cost_usd,story_points}, story_points в {1,2,3,5,8} (AC-1)"
module: tests/test_orch020_estimator.py
expected: PASS
- id: TC-09
type: unit
description: "Маппинг величин -> story-point bucket: точная семантика 1/2/3/5/8 на граничных входах (AC-2)"
module: tests/test_orch020_estimator.py
expected: PASS
- id: TC-10
type: unit
description: "Пустая история -> bootstrap-дефолт, не исключение; estimate() never-raise при битых данных (AC-1, AC-9)"
module: tests/test_orch020_estimator.py
expected: PASS
- id: TC-11
type: unit
description: "Расчёт факта на done из usage-агрегатов (токены/время/стоимость) маппится в story-point bucket (AC-4)"
module: tests/test_orch020_estimator.py
expected: PASS
- id: TC-12
type: integration
description: "Прогноз пишется в estimate_point через set_issue_estimate_point; факт — в point через set_issue_point; поля не перепутаны, прогноз не затирается (AC-3, AC-4)"
module: tests/test_orch020_estimator.py
expected: PASS
- id: TC-13
type: integration
description: "Telegram-карточка содержит пункт 'Оценка' (время/токены/стоимость); пустой прогноз -> пункт опускается, карточка не падает (AC-5)"
module: tests/test_orch020_estimator.py
expected: PASS
- id: TC-14
type: integration
description: "Plane-коммент с прогнозом постится через add_comment (best-effort) (AC-6)"
module: tests/test_orch020_estimator.py
expected: PASS
- id: TC-15
type: unit
description: "kill-switch estimator_enabled=false -> модуль инертен (handle_estimate no-op, нет записей в Plane/карточку/таблицу); applies() локален и first (AC-9)"
module: tests/test_orch020_estimator.py
expected: PASS
- id: TC-16
type: unit
description: "Скоуп estimator_repos пуст -> активен только self-hosting orchestrator; enduro-trails -> no-op (AC-9)"
module: tests/test_orch020_estimator.py
expected: PASS
- id: TC-17
type: integration
description: "GET /queue содержит read-only блок estimator (флаг/скоуп/счётчики прогнозов/записей/возвратов); existing-поля не меняются (AC-9)"
module: tests/test_orch020_estimator.py
expected: PASS
- id: TC-18
type: unit
description: "Аддитивная таблица task_estimates: CREATE TABLE IF NOT EXISTS идемпотентна; record_estimate/set_actual/get_estimate хранят прогноз+факт+дельту с ключом work_item_id (task_id нуллабелен); существующие таблицы не изменены (AC-12)"
module: tests/test_orch020_estimator.py
expected: PASS
- id: TC-19
type: integration
description: "fail-safe записи в Plane: estimate-система не настроена -> set_issue_estimate_point/point best-effort пропуск + лог, без падения; авто-возврат в Backlog всё равно отрабатывает (AC-12, AC-T2, NFR-7)"
module: tests/test_orch020_estimator.py
expected: PASS
- id: TC-20
type: unit
description: "Анти-регресс control-path: STAGE_TRANSITIONS/QG_CHECKS/check_*/machine-verdict-ключи, resolve_agent_model/resolve_agent_effort не изменены; статус 'Оценка' не добавлен как ребро стадий (AC-10, AC-11)"
module: tests/test_orch020_estimator.py
expected: PASS