work_item: ORCH-109
stage: analysis
author_agent: analyst
status: ready-for-review
created_at: 2026-06-14
model_used: claude-opus-4-8
title: "Timeout budgets + launch-time model telemetry для developer/reviewer"
framework: pytest
scope: >
  Покрывает: launch-time стамп модели в agent_runs.model (FR-1), сохранение launch-стампа
  постфактум-enrich'ем (FR-2), конфигурируемый поднятый тайм-аут developer/reviewer без влияния
  на прочие роли (FR-3) + never-break на малформном конфиге, reaper-инвариант (NFR-4), видимость
  модели+эффорта в строке трекера при timeout-kill (FR-4) и in-flight в get_running_agents (NFR-6),
  guard анти-salvage — timeout-killed прогон не продвигает стадию (FR-5). Вне покрытия: model-routing,
  salvage недоделанной работы, изменения STAGE_TRANSITIONS/QG_CHECKS/схемы (их и не должно быть).
notes: >
  Тесты детерминированы, без сети/LLM/subprocess Claude CLI: используют временную SQLite-БД и
  синтетические agent_runs-ряды; настройки подменяются через monkeypatch/override settings.
  Полный регресс tests/ должен оставаться зелёным; новый файл tests/test_orch109_timeout_model.py.
  Любой найденный разрыв в FR-5 закрывается guard'ом + тестом; если разрыва нет — TC-08 фиксирует
  существующую гарантию как анти-регресс.

tests:
  - id: TC-01
    type: unit
    description: "_resolve_timeout('developer') и ('reviewer') возвращают поднятый сконфигурированный бюджет"
    module: tests/test_orch109_timeout_model.py
    expected: PASS

  - id: TC-02
    type: unit
    description: "_resolve_timeout для analyst/architect/tester/deployer возвращает глобальный agent_timeout_seconds (1800) — прочие роли не затронуты"
    module: tests/test_orch109_timeout_model.py
    expected: PASS

  - id: TC-03
    type: unit
    description: "Малформный/невалидный timeout-конфиг -> _resolve_timeout откатывается на глобальный дефолт + WARNING, без исключения (never-break)"
    module: tests/test_orch109_timeout_model.py
    expected: PASS

  - id: TC-04
    type: integration
    description: "Launch стампит agent_runs.model: после стамп-блока _spawn строка прогона имеет model == resolve_agent_model(agent) (непустую), рядом с effort"
    module: tests/test_orch109_timeout_model.py
    expected: PASS

  - id: TC-05
    type: unit
    description: "Стамп модели изолирован: сбой записи (битый conn) не пробрасывает исключение из launch-пути (never-raise, NFR-2)"
    module: tests/test_orch109_timeout_model.py
    expected: PASS

  - id: TC-06
    type: unit
    description: "record_usage(run_id, None) и record_usage с model=None НЕ затирают launch-стампнутую модель (COALESCE preserve, FR-2)"
    module: tests/test_orch109_timeout_model.py
    expected: PASS

  - id: TC-07
    type: unit
    description: "record_usage с непустой model в usage-JSON уточняет/проставляет agent_runs.model (enrich по-прежнему работает)"
    module: tests/test_orch109_timeout_model.py
    expected: PASS

  - id: TC-08
    type: unit
    description: "Sanity reaper-инварианта: reaper_max_running_s > max(резолвенный тайм-аут всех ролей) + agent_kill_grace_seconds (NFR-4)"
    module: tests/test_orch109_timeout_model.py
    expected: PASS

  - id: TC-09
    type: integration
    description: "Строка стадии трекера (_stage_line) для agent_runs с exit_code=-9 и launch-стампнутыми model+effort рендерит ' · <short_model> · <effort>' (model не null)"
    module: tests/test_orch109_timeout_model.py
    expected: PASS

  - id: TC-10
    type: integration
    description: "get_running_agents отдаёт непустую model для running-job с launch-стампнутой моделью (in-flight видимость /metrics /queue, NFR-6)"
    module: tests/test_orch109_timeout_model.py
    expected: PASS

  - id: TC-11
    type: integration
    description: "Анти-salvage: прогон developer/reviewer с exit_code=-9 не продвигает стадию (development->review / review->testing) автоматически; следует retry/fail-пути"
    module: tests/test_orch109_timeout_model.py
    expected: PASS

  - id: TC-12
    type: integration
    description: "Анти-регресс контрактов: STAGE_TRANSITIONS/QG_CHECKS/check_* и схема agent_runs не изменены (модель пишется в существующую колонку, миграции нет)"
    module: tests/test_orch109_timeout_model.py
    expected: PASS
