Files
orchestrator/docs/work-items/ORCH-044/02-trz.md
2026-06-06 07:50:54 +00:00

144 lines
14 KiB
Markdown
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.
# 02 — Техническое задание (ТЗ)
**Work Item:** ORCH-044
**Основано на:** 01-brd.md
> Примечание: ТЗ фиксирует **что** должно измениться и **наблюдаемое поведение**.
> Выбор конкретной реализации (например, формат проверки `.credentials.json` vs парсинг
> маркера в логе) — за архитектором (стадия architecture, ADR). Где описаны варианты —
> это границы допустимого решения, а не предписание.
> ## ⛔ КОРРЕКЦИЯ SCOPE ВЛАДЕЛЬЦЕМ (Слава, 06.06) — ЧИТАТЬ ПЕРВЫМ
>
> **P2 (`--effort`) ПОЛНОСТЬЮ ИСКЛЮЧЁН из этой задачи.** Решение владельца:
> - effort **НУЖЕН и работает** — его **НЕЛЬЗЯ** убирать как unsupported. **Вариант B запрещён.**
> - В ORCH-044 **НЕ трогать** `--effort`: ни `_spawn` effort_flag, ни `resolve_agent_effort`, ни дефолты `agent_effort_*` в `config.py`, ни ORCH-41 effort-доки.
> - Текущий прод-хотфикс `ORCH_AGENT_EFFORT_*=""` в `.env` **оставить как есть** — не снимать, не менять.
> - Полноценный возврат effort (расследование флагов + json) вынесен в **ОТДЕЛЬНУЮ задачу ORCH-50** («Эффорт агентов: заставить --effort работать с --print/json»). Туда же — любое расследование причины пустого stdout.
>
> **Архитектор/дев игнорируют все TR-2.x и AC-7/AC-8/AC-9, относящиеся к effort.** Реализуем ТОЛЬКО:
> - **P1** — preflight ловит auth (ОБА подхода: проактивно cred-файл `expiresAt` + постфактум маркер `Not logged in`);
> - **P3** — пустой лог / нет result-JSON ⇒ job `failed` (не `done`, не вечный `running`).
>
> Заголовок задачи содержит «--effort фикс» по историческим причинам — это НЕ часть scope. Effort = ORCH-50.
## 1. Задействованные модули `src/`
| Модуль | Текущее место | Изменение |
|--------|---------------|-----------|
| `src/preflight.py` | `_run_version`, `_compute`, `check` | Добавить дешёвую token-free проверку авторизации (P1) |
| `src/config.py` | блок ORCH-41 effort (стр. 98108), новый блок настроек preflight-auth | Настройки auth-проверки; решение по effort-дефолтам (P2) |
| `src/agents/launcher.py` | `_spawn` (effort_flag, стр. 290292, 303311), `_monitor_agent` (стр. 460615), `_finalize_job` (стр. 630667) | Решение по `--effort` (P2); детекция пустого лога / отсутствия result-JSON (P3) |
| `src/queue_worker.py` | `_drain_once` claim-gating (стр. 158165) | Учесть новый auth-fail preflight в гейтинге клейма (P1) — при необходимости |
| `src/db.py` | `mark_job` | Использование существующего перевода job → `failed` (P3); новых колонок не требуется |
Новых файлов модулей не предполагается обязательно; допускается выделение хелпера
(например, `_check_auth()` в `preflight.py`) — на усмотрение архитектора.
## 2. Требования по проблемам
### P1 — Preflight ловит авторизацию (token-free)
- **TR-1.1.** Preflight ДОЛЖЕН, помимо `os.path.exists(bin)` и `claude --version`, выполнять
**дешёвую проверку авторизации без обращения к API модели и без prompt-ping**.
- **TR-1.2.** Допустимые подходы (выбор — за архитектором, ADR):
- (a) Проверка существования и читаемости файла учётных данных
`~/.claude/.credentials.json` (HOME агента — `/home/slin`, см. launcher env, стр. 326)
и валидности OAuth-токена по дате истечения внутри
(`claudeAiOauth.expiresAt`, epoch ms) — `expiresAt <= now` ⇒ протух ⇒ fail;
- (b) Парсинг реального run-вывода на маркер `Not logged in` (и подобные) с переводом
job в провал и размыканием/учётом circuit breaker.
- Подход (a) предпочтителен как **проактивный** (ловит ДО клейма); (b) — как защитная
сетка постфактум. Допускается комбинация.
- **TR-1.3.** Путь к файлу учётных данных ДОЛЖЕН резолвиться согласованно с тем HOME,
под которым launcher реально спавнит claude (`/home/slin`), а не из окружения процесса
оркестратора (аналогично тому, как `_claude_bin()` следует за реально исполняемым путём).
- **TR-1.4.** Результат auth-проверки кешируется тем же механизмом, что и version-check
(`preflight_cache_ttl`), чтобы не читать файл на каждый тик воркера.
- **TR-1.5.** При `auth=fail`: `check()` возвращает `(False, reason)` с **информативным
reason** (например, `claude not logged in: credentials missing` / `OAuth token expired at
<iso>`). Job НЕ клеймится (поведение `_drain_once` уже корректно при `ok=False`).
- **TR-1.6.** Граница ответственности: preflight остаётся **локальным** (BR-1). Сетевая
валидация токена у провайдера — вне объёма.
- **TR-1.7.** Поведение при «всё хорошо» не меняется: залогинен + валидный токен ⇒ `ok=True`.
### P2 — Решение по `--effort`
- **TR-2.1.** Провести расследование (стадия architecture/development): причина пустого
stdout при `--effort` + `--print --output-format json` в CLI 2.1.142 — несовместимость
с json-форматом, иной синтаксис флага, или баг CLI. Зафиксировать вывод в ADR/`10-tech-risks.md`.
- **TR-2.2.** По итогам выбрать **ровно один** исход и привести к нему код+доки+дефолты:
- **Вариант A (вернуть effort):** найден корректный способ (например, иной синтаксис или
несовместимость только с конкретным output-format) — `--effort` снова формируется в
`_spawn` корректно; прод-хотфикс `ORCH_AGENT_EFFORT_*=""` снимается; добавить
регресс-тест, что вывод не пустой.
- **Вариант B (unsupported):** effort несовместим — **убрать `--effort` из активного пути
запуска** (`_spawn` не формирует `effort_flag`), убрать/нейтрализовать дефолты effort в
`config.py`, обновить ORCH-41-доки (INFRA.md, internals.md) пометив фичу как unsupported
на данной версии CLI. `resolve_agent_effort` либо удаляется, либо документированно
оставляется заглушкой (решение — ADR).
- **TR-2.3.** Независимо от A/B: **не должно остаться «мёртвого» флага**, который тихо гасит
вывод. После задачи запуск с дефолтной конфигурацией прода ДОЛЖЕН давать непустой
result-JSON.
- **TR-2.4.** Изменение дефолтов/удаление флага не должно ломать `resolve_agent_model`
(модель — независимая фича ORCH-41) и существующие тесты `test_resolve_agent_effort.py`
(их допустимо обновить под новый контракт).
### P3 — Пустой лог / нет result-JSON ⇒ провал
- **TR-3.1.** В `_monitor_agent`/`_finalize_job`: при `exit_code == 0` ДОЛЖНА выполняться
**проверка валидности результата** перед тем как считать job успешным:
- run-лог **непустой** (размер > 0 и/или содержит непустой текст), И
- из него извлекается **валидный result-JSON** (тот же контракт, что использует
`usage._extract_last_json_object` / `parse_usage_from_log`).
- **TR-3.2.** Если результат невалиден (пустой лог ИЛИ нет валидного JSON) при `exit_code==0`,
job ДОЛЖЕН трактоваться как **провал**:
- НЕ переводиться в `done`;
- попасть в путь ретрая/провала (`attempts < max_attempts` ⇒ requeue, иначе `failed`),
аналогично permanent-ветке `_finalize_permanent`, с информативным `error`
(например, `empty run log / no result JSON (run_id=...)`);
- сгенерировать алерт (Telegram), как прочие провалы;
- НЕ выполнять авто-advance стадии (`_try_advance_stage`) и НЕ постить «успешный»
status-коммент.
- **TR-3.3.** Классификация такого провала: по умолчанию — **permanent** (это не 429/overload).
Если в логе присутствует transient-маркер (через `error_classifier`) — допускается
transient-путь. Auth-провал (`Not logged in`) — на усмотрение архитектора: может
маршрутизироваться как сигнал брейкеру (P1/TR-1.2b).
- **TR-3.4.** Никогда не оставлять job в `running` навечно из-за пустого результата: либо
`done` (валидно), либо `failed`/`queued`(retry). (Watchdog ORCH-7 продолжает закрывать
случай таймаута; здесь закрывается случай «быстрая смерть с exit 0».)
- **TR-3.5.** Защитность: вся проверка обёрнута так, что её собственная ошибка не роняет
монитор (как и прочий код `_monitor_agent`); при сомнении — fail-safe в сторону провала job.
## 3. Изменения API
Нет новых/изменённых HTTP-endpoint'ов. Допускается обогащение поля `preflight_reason` в
`/queue` (через существующий `worker.status()` / `QueueWorker.last_preflight_reason`) более
информативным auth-сообщением — без изменения схемы ответа.
## 4. Изменения схемы БД
Нет. Используются существующие колонки `jobs` (`status`, `error`, `attempts`,
`max_attempts`, `transient_attempts`) и `agent_runs`. Новых таблиц/колонок не требуется.
## 5. Требования к новым QG checks
Новых Quality Gate проверок не требуется — изменения в слое запуска/preflight, не в гейтах
стадий. Реестр `QG_CHECKS` не меняется.
## 6. Конфигурация (env / config.py)
- Возможные новые настройки preflight-auth (имена — на усмотрение архитектора), например:
- `ORCH_PREFLIGHT_CHECK_AUTH` (bool, default true) — включение auth-проверки;
- путь к credentials, если не выводится из HOME автоматически.
- Решение по effort-дефолтам (`agent_effort_*`) согласно TR-2.2 (нейтрализовать при варианте B).
- Все новые настройки документируются в `config.py` docstring и в INFRA.md (env-карта).
## 7. Артефакты pipeline (обязательны к созданию/обновлению)
- `06-adr/ADR-NNN-*.md` — решение по подходу preflight-auth (a/b/комбо) и по effort (A/B).
- `10-tech-risks.md` — риск ложноположительной auth-проверки, риск регрессии effort, риск
fail-safe-провала на легитимных пустых выводах.
- `12-review.md`, `13-test-report.md` — по стадиям.
- Обновить `docs/operations/INFRA.md` и `docs/architecture/internals.md` (effort-секции),
`CHANGELOG.md`. Документация = golden source (правило агентов №2).
## 8. Ограничения и запреты
- ❌ Prompt-ping в preflight (жжёт rate limit) — запрещено (BR-1, комментарий в preflight.py).
- ❌ Сетевые вызовы к API модели в preflight.
- ❌ Оставлять job в `running` без таймаута при пустом результате.
-`--no-verify`/обход хуков без одобрения Owner.
- ⚠️ Self-hosting: не ронять прод-контейнер `orchestrator`; проверка изменений — через
staging (8501) перед прод-деплоем (см. CLAUDE.md, INFRA.md).