Files
orchestrator/docs/work-items/ORCH-109/03-acceptance-criteria.md

8.4 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-109 analysis analyst ready-for-review 2026-06-14 claude-opus-4-8

03 — Критерии приёмки (Acceptance Criteria): ORCH-109 — timeout budgets + launch-time model telemetry

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

Формат: каждый критерий имеет PASS (что должно быть истинно для приёмки) и FAIL (что считается провалом). Reviewer/tester проверяет их буквально по файлам репозитория и тестам.


AC-1 — Модель стампится в agent_runs.model в момент launch

Условие: запуск любого агента через launcher._spawn записывает резолвенную модель в agent_runs.model строки прогона ДО завершения процесса.

  • PASS: после стампа на launch (UPDATE agent_runs SET model=…/объединённый с effort) SELECT model FROM agent_runs WHERE id=<run_id> возвращает resolve_agent_model(agent) (непустую модель для текущей конфигурации — claude-opus-4-8); при пустом резолве — NULL. Запись происходит рядом со стампом эффорта (launcher._spawn).
  • FAIL: модель пишется только в usage.record_usage (постфактум); строка прогона имеет model IS NULL до завершения; стамп не изолирован и роняет launch при ошибке БД.

AC-2 — Постфактум-enrich не затирает launch-стамп при оборванном JSON

Условие: usage.record_usage с отсутствующей/None-моделью не обнуляет launch-стампнутую модель.

  • PASS: record_usage(run_id, None) и record_usage(run_id, {... "model": None}) для строки с launch-стампнутой моделью → model остаётся прежним непустым (семантика COALESCE(?, model)); record_usage(run_id, {... "model": "claude-opus-4-8"}) → модель проставлена/уточнена.
  • FAIL: оборванный/малформный JSON приводит к model = NULL; enrich затирает корректный launch-стамп.

AC-3 — Тайм-аут developer/reviewer поднят и конфигурируем без влияния на прочие роли

Условие: launcher._resolve_timeout(agent) возвращает поднятый бюджет для developer/reviewer и неизменный глобальный дефолт для остальных.

  • PASS: при сконфигурированном override _resolve_timeout("developer") и _resolve_timeout("reviewer") возвращают поднятые значения; _resolve_timeout("analyst"), ("architect"), ("tester"), ("deployer") возвращают settings.agent_timeout_seconds (1800 по умолчанию). Конфигурация описана в config.py и .env.example.
  • FAIL: изменён бюджет роли вне {developer, reviewer}; значение захардкожено; бюджет не настраивается через config.

AC-4 — Малформный timeout-конфиг → безопасный откат (never-break)

Условие: невалидный/малформный конфиг тайм-аутов не роняет прогон и не ломает старт.

  • PASS: при малформном agent_timeout_overrides_json (или невалидном выделенном ключе) _resolve_timeout(...) возвращает глобальный дефолт + пишет WARNING; процесс не падает.
  • FAIL: исключение пробрасывается; прогон/старт падает на плохом env.

AC-5 — Reaper-инвариант сохранён

Условие: reaper_max_running_s > max(резолвенный тайм-аут любого агента) + agent_kill_grace_seconds.

  • PASS: с применённой конфигурацией бюджетов sanity-тест подтверждает неравенство для всех ролей (developer/reviewer включительно); при необходимости reaper_max_running_s поднят синхронно.
  • FAIL: поднятый бюджет developer/reviewer + grace ≥ reaper_max_running_s → job-reaper может реапнуть здоровый долгий прогон.

AC-6 — Строка стадии трекера показывает модель+эффорт при timeout/kill

Условие: для прогона с exit_code = -9 (timeout-kill) с launch-стампнутыми model+effort строка стадии рендерит оба значения.

  • PASS: notifications-рендер строки стадии (_stage_line) для такого agent_runs-ряда содержит · <short_model> · <effort> (например · opus-4-8 · xhigh); модель не null/пустая.
  • FAIL: при exit_code=-9 строка показывает стоимость без модели (суффикс модели опущен), т.к. model IS NULL.

AC-7 — In-flight видимость модели в /metrics и /queue

Условие: db.get_running_agents отдаёт модель для running job'а (до завершения прогона).

  • PASS: для running-job с launch-стампнутой моделью get_running_agents()[i]["model"] непуст; GET /metrics agents[].model непуст для активного агента.
  • FAIL: model остаётся null для running-job до завершения прогона.

AC-8 — Timeout-killed прогон не продвигает стадию (анти-salvage)

Условие: прогон developer/reviewer с exit_code != 0 (timeout-kill) не вызывает переход development → review / review → testing.

  • PASS: регресс-тест подтверждает, что прогон с exit_code = -9 не продвигает стадию автоматически (следует retry/fail-пути; advance — только при чистом exit + зелёный exit-гейт). Salvage-режим отсутствует.
  • FAIL: убитый по тайм-ауту прогон «протекает» в следующую стадию без явного решения; либо введён неявный auto-salvage.

AC-9 — Неприкосновенность контрактов и схемы

Условие: задача не трогает машину стадий, гейты и схему БД.

  • PASS: диффы НЕ содержат изменений STAGE_TRANSITIONS, реестра QG_CHECKS, check_*/_parse_*, machine-verdict ключей, CREATE TABLE/ALTER TABLE. agent_runs.model используется как есть.
  • FAIL: любое из перечисленного изменено.

AC-10 — Документация и регресс

Условие: конфиг задокументирован, полный регресс зелёный.

  • PASS: комментарий-паспорт в config.py (блок ORCH-7) и .env.example описывают бюджеты developer/reviewer; CHANGELOG.md/CLAUDE.md/docs/architecture/README.md обновлены в том же PR; pytest tests/ -q зелёный; новые тесты ORCH-109 проходят.
  • FAIL: конфиг не задокументирован; документация рассинхронизирована с кодом; регресс красный.

Сводная матрица AC ↔ FR/BR

AC Покрывает
AC-1 BR-1 / FR-1
AC-2 BR-2 / FR-2
AC-3 BR-3 / FR-3
AC-4 BR-3 / FR-3 / NFR-2
AC-5 NFR-4 / FR-3
AC-6 BR-4 / FR-4
AC-7 BR-4 / FR-4 / NFR-6
AC-8 BR-5 / FR-5
AC-9 NFR-1 / NFR-3 / FR-5
AC-10 BR-6 / FR-6 / NFR-1