work_item: ORCH-044 title: "Надёжность запуска агента: preflight auth + --effort фикс + пустой лог = провал" notes: > Реальный claude/Popen НЕ спавнится: subprocess и launcher мокаются (паттерн tests/test_resilience.py). БД — свежий per-test sqlite (fixture fresh_db). Файлы учётных данных создаются во временном каталоге (tmp_path) и путь мокается. Сетевые вызовы запрещены — проверяются моками/отсутствием httpx. tests: # ---------------- P1: preflight ловит авторизацию ---------------- - id: TC-01 type: unit description: "Нет .credentials.json при рабочем --version -> preflight.check() = (False, reason про auth)" module: tests/test_preflight_auth.py covers: [AC-1, TR-1.1, TR-1.2] expected: PASS - id: TC-02 type: unit description: "Протухший OAuth (claudeAiOauth.expiresAt в прошлом) -> preflight FAIL про истечение токена" module: tests/test_preflight_auth.py covers: [AC-2, TR-1.2a] expected: PASS - id: TC-03 type: unit description: "Валидный логин (credentials читаемы, expiresAt в будущем) -> preflight OK, без регрессии" module: tests/test_preflight_auth.py covers: [AC-3, TR-1.7] expected: PASS - id: TC-04 type: unit description: "Нечитаемый/битый .credentials.json (невалидный JSON) -> preflight FAIL, не падает исключением" module: tests/test_preflight_auth.py covers: [AC-1, TR-1.2a, TR-3.5] expected: PASS - id: TC-05 type: unit description: "Auth-проверка token-free: при check() не происходит сетевого вызова к API модели (мок httpx/urlopen не вызван)" module: tests/test_preflight_auth.py covers: [AC-5, BR-1, TR-1.6] expected: PASS - id: TC-06 type: unit description: "Auth-результат кешируется: повторные check() в пределах preflight_cache_ttl не перечитывают credentials" module: tests/test_preflight_auth.py covers: [AC-6, TR-1.4] expected: PASS - id: TC-07 type: unit description: "Путь к credentials резолвится от HOME агента (/home/slin), а не от окружения процесса оркестратора" module: tests/test_preflight_auth.py covers: [TR-1.3] expected: PASS - id: TC-08 type: integration description: "QueueWorker._drain_once при preflight auth-fail не клеймит job: job остаётся queued, claude не спавнится, last_preflight_ok=False" module: tests/test_preflight_auth.py covers: [AC-4, BR-2, TR-1.5] expected: PASS # ---------------- P2: решение по --effort ---------------- - id: TC-09 type: unit description: "Вариант B: при дефолтной конфигурации построенная cmd в _spawn НЕ содержит '--effort' (флаг не гасит вывод). При варианте A — тест адаптируется на корректное формирование effort" module: tests/test_effort_flag.py covers: [AC-8, TR-2.2, TR-2.3] expected: PASS - id: TC-10 type: unit description: "resolve_agent_effort согласован с принятым решением (B: нейтрализован/пусто по дефолту; A: валидное значение). Существующий test_resolve_agent_effort обновлён под новый контракт и зелёный" module: tests/test_resolve_agent_effort.py covers: [AC-8, TR-2.4] expected: PASS - id: TC-11 type: integration description: "Дефолтный путь запуска (мок claude, отдающий валидный result-JSON) даёт непустой лог с валидным JSON — воспроизведение инцидента (пустой stdout) не происходит" module: tests/test_effort_flag.py covers: [AC-9, TR-2.3] expected: PASS # ---------------- P3: пустой лог / нет result-JSON = провал ---------------- - id: TC-12 type: integration description: "exit_code=0 + пустой run-лог (0 байт) -> job НЕ done; помечается failed (или queued при retry-бюджете) с информативным error; алерт вызван" module: tests/test_empty_log_failure.py covers: [AC-10, TR-3.1, TR-3.2] expected: PASS - id: TC-13 type: integration description: "exit_code=0 + лог без валидного result-JSON (мусор) -> job трактуется как провал, не done" module: tests/test_empty_log_failure.py covers: [AC-11, TR-3.1] expected: PASS - id: TC-14 type: integration description: "При провале по пустому результату _try_advance_stage НЕ вызывается и успешный usage-коммент НЕ постится" module: tests/test_empty_log_failure.py covers: [AC-12, TR-3.2] expected: PASS - id: TC-15 type: integration description: "exit_code=0 + непустой лог с валидным result-JSON -> job done, авто-advance и usage-коммент работают (нет регрессии)" module: tests/test_empty_log_failure.py covers: [AC-13, TR-3.1] expected: PASS - id: TC-16 type: integration description: "Любой выход процесса не оставляет job в 'running': пустой лог+exit0 завершается терминально (done/failed/queued)" module: tests/test_empty_log_failure.py covers: [AC-14, BR-3, TR-3.4] expected: PASS - id: TC-17 type: unit description: "Классификация пустого результата по умолчанию permanent; transient-маркер в логе уводит в transient-путь (error_classifier)" module: tests/test_empty_log_failure.py covers: [TR-3.3] expected: PASS # ---------------- Регрессия / сквозное ---------------- - id: TC-18 type: unit description: "Регресс: существующие preflight-кейсы (bin missing, --version ok) из test_resilience.py остаются зелёными после добавления auth-слоя" module: tests/test_resilience.py covers: [AC-3, TR-1.7] expected: PASS - id: TC-19 type: integration description: "Полный прогон 'pytest tests/ -q' зелёный — ни один существующий тест не сломан без обоснованного обновления контракта" module: tests/ covers: [AC-16] expected: PASS