# ТЗ — ORCH-074: убрать мёртвый frontmatter `model:` + валидация имени модели Work Item ID: ORCH-074 Базируется на: BRD `01-brd.md`. Скоп фиксирован решением Славы (08.06): **G1 + G2 + опц. G4. G3 (routing) НЕ включаем. Эффорт НЕ трогать.** ## 1. Задействованные модули `src/` и файлы | Файл | Изменение | |------|-----------| | `.openclaw/agents/analyst.md` | **G1:** удалить строку `model: claude-sonnet-4-6` из frontmatter | | `.openclaw/agents/architect.md` | **G1:** удалить строку `model: claude-opus-4-7` | | `.openclaw/agents/developer.md` | **G1:** удалить строку `model: claude-sonnet-4-6` | | `.openclaw/agents/reviewer.md` | **G1:** удалить строку `model: claude-opus-4-7` | | `.openclaw/agents/tester.md` | **G1:** удалить строку `model: claude-sonnet-4-6` | | `.openclaw/agents/deployer.md` | **G1:** удалить строку `model: claude-sonnet-4-6` | | `src/agents/launcher.py` | **G2:** добавить валидацию имени модели в `resolve_agent_model` (или helper), по образцу `VALID_EFFORTS`-гарда в `resolve_agent_effort` | | `src/config.py` | **G4 (опц.):** задать `agent_fallback_model` (если архитектор решит). При G2 — возможно добавить константу/настройку валидного формата модели | | `docs/architecture/README.md` | **AC-6:** таблица «модель/эффорт по ролям» актуализирована; нет упоминаний sonnet/opus-4-7 как «модели агента» | | `.env.example` | **AC-3/AC-6:** добавить блок `ORCH_AGENT_MODEL_*` / `ORCH_AGENT_EFFORT_*` / `ORCH_AGENT_FALLBACK_MODEL` (сейчас в `.env.example` их НЕТ) | | `CLAUDE.md` | **AC-6:** при необходимости — отметить, что модель агента берётся ТОЛЬКО из config (frontmatter описательный) | | `CHANGELOG.md` | запись о доработке | | `tests/test_resolve_agent_model.py` | **AC-2:** добавить кейсы валидации мусорного имени | ## 2. G1 — убрать мёртвый frontmatter `model:` Удалить **только** строку `model: …` из YAML-frontmatter каждого из 6 файлов `.openclaw/agents/*.md`. Остальные ключи (`name`, `description`, `tools`/`model`-comment) не трогать. frontmatter остаётся валидным YAML и описательным. Проверка (AC-1): ``` grep -L "^model:" .openclaw/agents/*.md # должны вернуться ВСЕ 6 файлов ``` (`grep -L` печатает файлы БЕЗ совпадения — все 6 не должны содержать `^model:`.) ## 3. G2 — валидация имени модели (never-break) Требование (НЕ предписывает архитектуру — выбор предиката за архитектором): - Резолвенное имя модели валидируется ПЕРЕД возвратом из `resolve_agent_model` (либо в общем helper). Невалидное имя → `logger.warning(...)` + откат на следующий валидный уровень (в пределе — `agent_model_default`, а если и он невалиден → `""`, т.е. без флага `--model`, CLI-дефолт). **Никогда** не вернуть мусор, который попадёт в `--model`. - Поведение — точная аналогия `resolve_agent_effort` (`VALID_EFFORTS`): валидный → как есть; невалидный → лог + дроп. - Предикат валидности (на усмотрение архитектора, рекомендация аналитика): формат-чек `claude-*` (forward-compatible — новые версии моделей не требуют правки allowlist) ЛИБО явный `VALID_MODELS` allowlist (строже, но требует поддержки при выходе новых моделей). **Выбор и обоснование — в ADR.** - **Рекомендация аналитика (форма):** оформить предикат как отдельный чистый helper (напр. `is_valid_model(name) -> bool` рядом с `VALID_EFFORTS`), а не инлайнить в `resolve_agent_model` — тогда ОДИН валидатор переиспользуется и резолвом модели, и чтением fallback (G4, см. §4). Финальная форма — за архитектором. - Инвариант обратной совместимости: ВСЕ ныне используемые валидные имена (`claude-opus-4-8`, а также enduro per-project override) проходят валидацию без изменения поведения. Невалидным считается только мусор (опечатка, `gpt-4`, пустая строка после strip и т.п.). - Контракт уровней резолва ORCH-041 сохраняется: валидация добавляется поверх, механизм приоритетов не меняется. ## 4. G4 — fallback_model (опционально, решает архитектор) - `src/config.py::agent_fallback_model` сейчас `""` (флаг не прокидывается). - Если архитектор решит включить — задать каноничное имя модели; launcher уже прокидывает его в `--fallback-model` (`launcher.py:374-375`, попадает в cmd на строке 388). - **⚠️ Код-факт (проверено 08.06):** fallback читается НАПРЯМУЮ — `fb = settings.agent_fallback_model` (`launcher.py:374`) — и **НЕ проходит** через `resolve_agent_model`, значит валидация G2, добавленная внутри `resolve_agent_model`, его НЕ покроет. Следствие для архитектора: если G4 включается, валидацию имени модели (G2) надо применить ТАКЖЕ к fallback на его месте чтения (или вынести валидатор в отдельный helper, который вызывают ОБА: и резолв модели, и чтение fallback). Иначе опечатка в `agent_fallback_model` обходит G2 и уезжает в `--fallback-model` — нарушение never-break. - Если архитектор решит НЕ включать — оставить `""`, AC-5 помечается N/A в ADR. ## 5. Изменения API / схемы БД - **API (HTTP):** нет. - **Схема БД:** нет миграций. - **CLI-команда агента:** формируется в `launcher._spawn` (строки 384-392). Меняется только КАЧЕСТВО значения `--model` (валидное/дроп), сама структура команды не меняется. ## 6. Требования к QG checks - Новых QG-чеков НЕ требуется. Валидация — это runtime-гард в launcher, не отдельный quality-gate. ## 7. Артефакты pipeline Должны быть созданы/обновлены в ЭТОМ PR (golden source = код + доки): - `docs/architecture/README.md` — таблица «модель/эффорт по ролям». - `.env.example` — блок переменных моделей/эффорта/fallback. - `CHANGELOG.md` — запись. - `06-adr/ADR-NNN-*.md` — решение по предикату валидации (G2) и по G4 (fallback вкл/выкл). - ADR архитектора фиксирует: выбран вариант G1 «убрать» (не «читать frontmatter»). ## 8. Эффорт — НЕ ТРОГАТЬ `agent_effort_*` корректны (`thinking → high`, `tester/deployer → medium`). Менять только при явном отдельном обосновании (вне скоупа этой задачи). ## 9. Грабли - Имена моделей — каноничные строки Claude CLI; сверить с тем, что реально принимает CLI на проде (`ORCH_CLAUDE_BIN`). НЕ хардкодить версию вне `config.py`. - Если frontmatter автогенерится инструментом — убедиться, что `model:` не вернётся. - Self-hosting: НЕ ронять прод-контейнер; деплой через «Confirm Deploy».