architect(ET): auto-commit from architect run_id=400
This commit is contained in:
@@ -42,13 +42,13 @@ created → analysis → architecture → development → review → testing →
|
||||
**Канон гейтов:** машинные вердикты читаются ТОЛЬКО из YAML-frontmatter, никогда из прозы. Лог-файлы мержатся в `origin/main` отдельным PR; гейт читает из `origin/main`.
|
||||
|
||||
### Модель и эффорт по ролям (ORCH-41, валидация ORCH-74)
|
||||
Модель и `--effort` каждого агента берутся из config (`src/config.py`), резолвятся `launcher.resolve_agent_model` / `resolve_agent_effort` по приоритету **project-override (`projects_json` `agent_models`/`agent_efforts`) > `ORCH_AGENT_MODEL_<AGENT>`/`ORCH_AGENT_EFFORT_<AGENT>` > `*_default` > CLI-дефолт (без флага)**. frontmatter `model:` в `.openclaw/agents/*.md` **удалён** (ORCH-74 G1) — он был мёртвой/лживой декларацией (launcher его не читает); config — единственный источник правды о модели. Model-routing (G3) НЕ включён — все 6 агентов на `claude-opus-4-8`.
|
||||
Модель и `--effort` каждого агента берутся из config (`src/config.py`), резолвятся `launcher.resolve_agent_model` / `resolve_agent_effort` по приоритету **project-override (`projects_json` `agent_models`/`agent_efforts`) > `ORCH_AGENT_MODEL_<AGENT>`/`ORCH_AGENT_EFFORT_<AGENT>` > `*_default` > CLI-дефолт (без флага)**. **Эффорт (ORCH-081):** ниже `*_default` добавлен непустой **per-role floor** — class-default поля `agent_effort_<role>` из `config.py` (его пустой env перебить не может). Floor — строго последний уровень (ниже default) и срабатывает ТОЛЬКО когда все уровни пусты, поэтому пустые прод-`ORCH_AGENT_EFFORT_*=` (которые pydantic трактует как явное `''` и обнуляют дефолт) больше не приводят к запуску без `--effort`: каждая роль получает свой канонический пол (developer=`xhigh`, tester/deployer=`medium`, прочие=`high`). Непустой явный конфиг по-прежнему побеждает floor; опечатка вне `VALID_EFFORTS` дропается валидацией ДО floor (never-break, не маскируется). См. `docs/work-items/ORCH-081/06-adr/ADR-001-effort-resolution-floor.md`. frontmatter `model:` в `.openclaw/agents/*.md` **удалён** (ORCH-74 G1) — он был мёртвой/лживой декларацией (launcher его не читает); config — единственный источник правды о модели. Model-routing (G3) НЕ включён — все 6 агентов на `claude-opus-4-8`.
|
||||
|
||||
| Агент | Модель | Эффорт |
|
||||
|-------|--------|--------|
|
||||
| analyst | claude-opus-4-8 | high |
|
||||
| architect | claude-opus-4-8 | high |
|
||||
| developer | claude-opus-4-8 | high |
|
||||
| developer | claude-opus-4-8 | xhigh |
|
||||
| reviewer | claude-opus-4-8 | high |
|
||||
| tester | claude-opus-4-8 | medium |
|
||||
| deployer | claude-opus-4-8 | medium |
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
# ADR-001: Per-role floor для резолва `--effort`, устойчивый к пустому env
|
||||
|
||||
**Work Item:** ORCH-081 (ORCH-52h) · **Эпик:** ORCH-052 (после ORCH-074)
|
||||
**Связанные:** ORCH-41 (резолв model/effort), ORCH-074 (валидация модели, `is_valid_model`)
|
||||
|
||||
## Статус
|
||||
Accepted
|
||||
|
||||
## Контекст
|
||||
|
||||
В проде `resolve_agent_effort()` возвращает `''` для всех 6 агентов, хотя в
|
||||
`src/config.py` заданы осмысленные дефолты (`high`/`medium`). Итог: флаг `--effort`
|
||||
не передаётся в Claude CLI, каждый агент бежит на встроенном CLI-дефолте, а не на
|
||||
заявленном уровне. Для Opus 4.8 reasoning-эффорт сильнее влияет на качество, чем у
|
||||
прежних моделей, → прямой удар по предсказуемости качества всего конвейера (включая
|
||||
enduro-trails из общего инстанса).
|
||||
|
||||
### Корень (точная механика)
|
||||
Pydantic Settings трактует **присутствующую** env-переменную — даже пустую
|
||||
(`ORCH_AGENT_EFFORT_DEVELOPER=` без значения) — как явное значение и **перебивает**
|
||||
дефолт класса: поле `= ''`. В проде пусты И per-agent (`ORCH_AGENT_EFFORT_<ROLE>=`),
|
||||
И default (`ORCH_AGENT_EFFORT_DEFAULT=`). Цепочка резолва (`_resolve_agent_attr`):
|
||||
|
||||
```
|
||||
project-override (agent_efforts) → пусто
|
||||
per-agent env ('') → falsy → skip
|
||||
default ('') → falsy → skip
|
||||
→ '' (уровень 4: без флага)
|
||||
```
|
||||
|
||||
Привычный откат «per-agent пуст → взять default» не спасает: откатываться не на что —
|
||||
default тоже пуст. Нужен непустой **per-role** «пол» (floor) ниже default.
|
||||
|
||||
### Дополнительное ограничение (урок 08.06)
|
||||
Хост-правки env, положенные в git-managed файл, **не переживают деплой**. Источник
|
||||
правды реальных значений — `.env` на хосте (gitignored). Значит, фикс обязан быть
|
||||
**code-side robust**: даже если прод-`.env` снова окажется с пустыми
|
||||
`ORCH_AGENT_EFFORT_*`, эффорт всё равно резолвится в целевые значения.
|
||||
|
||||
## Рассмотренные варианты
|
||||
|
||||
### Вариант A — `field_validator` в `config.py` (coerce пустой → дефолт на уровне поля)
|
||||
Валидатор каждого `agent_effort_*` конвертирует пустую строку в канонический дефолт
|
||||
поля.
|
||||
**Отклонён:** ломает приоритет FR-2. Если per-agent поле всегда непустое, оно ВСЕГДА
|
||||
бьёт `default` (уровень 3 становится мёртвым для роли с пустым env). Сценарий: оператор
|
||||
ставит `ORCH_AGENT_EFFORT_DEFAULT=max`, per-agent оставляет пустыми — намерение «все
|
||||
роли на max», но coercion на уровне поля даст каждой роли её per-role дефолт, а не
|
||||
`max`. Floor обязан стоять **строго ниже** default, а это видно только в резолвере,
|
||||
где доступна вся цепочка приоритетов.
|
||||
|
||||
### Вариант B — explicit hardcoded map `{analyst: high, …}` в `launcher.py`
|
||||
Отдельная константа-карта per-role floor.
|
||||
**Отклонён как первичный:** вводит **второй источник правды** рядом с дефолтами
|
||||
`config.py`. Баг, который мы чиним, — это и есть дрейф/рассинхрон конфигурации;
|
||||
заводить новую поверхность дрейфа концептуально неверно (карту и config надо вручную
|
||||
держать в синхроне).
|
||||
|
||||
### Вариант C — floor в резолвере, значение = class-default поля (ПРИНЯТО)
|
||||
Floor применяется как **последний** уровень в `resolve_agent_effort`, ниже `default`,
|
||||
а его значение берётся из **декларированного class-default** соответствующего поля
|
||||
`Settings` (через `model_fields`), который пустой env НЕ может перебить.
|
||||
|
||||
## Решение
|
||||
|
||||
Фикс кладётся в `resolve_agent_effort` (`src/agents/launcher.py`), `_resolve_agent_attr`
|
||||
остаётся общим с model-резолвом и **не трогается** (floor — effort-специфичен).
|
||||
|
||||
### Цепочка резолва (новая, уровень 4 — floor)
|
||||
```
|
||||
1. project-override (projects_json.agent_efforts[agent]) — непустой побеждает
|
||||
2. per-agent env (settings.agent_effort_<agent>) — непустой побеждает
|
||||
3. global default (settings.agent_effort_default) — непустой побеждает
|
||||
4. per-role FLOOR (class-default поля agent_effort_<agent>) — НОВОЕ, непустой пол
|
||||
↓ (только если все 1–3 пусты)
|
||||
5. валидация VALID_EFFORTS → невалидное дропается в '' (ORCH-41, never-break)
|
||||
```
|
||||
|
||||
### Ключевые инварианты реализации
|
||||
- **Floor = class-default поля, а не instance-значение.** `type(settings).model_fields[f"agent_effort_{agent}"].default` возвращает декларированный дефолт (`high`/`medium`/`xhigh`), который пустой env не клобберит. Это восстанавливает значение, которое pydantic дал бы, не будь спурьозного `VAR=`. **Единый источник правды — `config.py`**: developer-апгрейд на `xhigh` делается одной правкой поля, floor подтягивается автоматически.
|
||||
- **Floor применяется ДО валидации и ТОЛЬКО при пустом резолве.** Порядок критичен для FR-3: явная опечатка (`turbo`) — непустая, поэтому floor НЕ применяется, и значение штатно дропается валидацией в `''`. Floor не маскирует мусор.
|
||||
- **Floor — строго уровень 4 (ниже default).** Непустой явный env/override/`default` по-прежнему побеждает floor (FR-2). Floor срабатывает лишь когда сконфигурировать эффорт забыли/занулили на всех уровнях.
|
||||
- **Unknown-agent fallback:** если поля `agent_effort_<agent>` нет (имя не из 6 ролей), floor деградирует на class-default `agent_effort_default` (`high`) — непустой безопасный пол, never-break.
|
||||
|
||||
### Сопутствующая правка config (FR-4)
|
||||
`config.py`: `agent_effort_developer` `high → xhigh` (канон Opus 4.8: coding/agentic роль).
|
||||
Это единственное изменение значений; остальные (`analyst/architect/reviewer=high`,
|
||||
`tester/deployer=medium`) подтверждаются и фиксируются устойчиво. Поскольку floor =
|
||||
class-default, апгрейд автоматически становится и новым floor для developer.
|
||||
|
||||
### Целевые значения (floor при полностью пустом env)
|
||||
| agent | floor |
|
||||
|-------|-------|
|
||||
| analyst | high |
|
||||
| architect | high |
|
||||
| developer | **xhigh** |
|
||||
| reviewer | high |
|
||||
| tester | medium |
|
||||
| deployer | medium |
|
||||
|
||||
## Последствия
|
||||
|
||||
**Плюсы**
|
||||
- Code-side robust: пустой прод-`.env` больше не обнуляет эффорт; целевые уровни
|
||||
гарантированы без зависимости от хост-правок, которые не переживают деплой.
|
||||
- Единый источник правды (`config.py`); нулевой риск дрейфа floor-карты.
|
||||
- Приоритет резолва и контракт ORCH-41 сохранены 1:1; непустой явный конфиг работает
|
||||
как раньше (полная обратная совместимость).
|
||||
- Валидация ORCH-41 не регрессирует — опечатки по-прежнему дропаются, never-break.
|
||||
|
||||
**Минусы / ограничения**
|
||||
- Лёгкая зависимость от pydantic-v2 API (`model_fields[...].default`) — публичный
|
||||
стабильный атрибут, но это связь с внутренним устройством Settings. Замокать в тестах
|
||||
тривиально.
|
||||
- «CLI-дефолт без флага» как исход для 6 штатных ролей становится недостижим — это
|
||||
намеренно: для известных ролей всегда есть непустой пол. Unknown-agent сохраняет
|
||||
безопасный непустой fallback.
|
||||
|
||||
**Не затрагивается**
|
||||
- API endpoints — нет. Схема БД — нет. QG checks / гейты конвейера — нет.
|
||||
Model-резолв (ORCH-074) — нет. Путь проброса `--effort` в `_spawn` (стр. ~434) — нет
|
||||
(только верификация тестом, FR-3/FR-5).
|
||||
|
||||
## Деплой (self-hosting)
|
||||
Правка касается инструмента, обслуживающего в проде и другие проекты. Прод-контейнер
|
||||
`orchestrator` не ронять в рамках задачи; деплой — штатно `deploy-staging` (8501) →
|
||||
`Confirm Deploy`. Рекомендуется привести прод-`.env` к каноне `.env.example`
|
||||
(developer=xhigh, остальные непустые), НО фикс обязан работать и без этого (FR-1).
|
||||
Проверка в проде (AC-6) фиксируется в `14-deploy-log.md`.
|
||||
17
docs/work-items/ORCH-081/10-tech-risks.md
Normal file
17
docs/work-items/ORCH-081/10-tech-risks.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# 10 — Технические риски: ORCH-081 (ORCH-52h)
|
||||
|
||||
| ID | Риск | Вероятн. | Влияние | Митигация |
|
||||
|----|------|----------|---------|-----------|
|
||||
| R-1 | **Floor маскирует опечатку.** Если floor применить ПОСЛЕ/ВМЕСТО валидации, мусорное `turbo` подменится на floor вместо дропа → регрессия never-break ORCH-41. | низк. | средн. | Floor строго ДО валидации и ТОЛЬКО при пустом резолве (значение `turbo` непустое → floor не трогается → дроп). Покрыть тестом FR-3 (опечатка → `''`). |
|
||||
| R-2 | **Floor перебивает явный конфиг.** Ошибка порядка → floor встанет выше default/per-agent и `ORCH_AGENT_EFFORT_DEFAULT=max` перестанет применяться. | низк. | средн. | Floor — строго уровень 4 (ниже default). Тест FR-2: непустой default/per-agent/override побеждает floor. |
|
||||
| R-3 | **Зависимость от pydantic-internal** `model_fields[...].default`. Будущий мажор pydantic может сменить API → floor отвалится. | низк. | низк. | Публичный стабильный атрибут pydantic v2. Тест AC-1/AC-2 поймает регрессию сразу (floor вернёт не то/пусто). Фиксируется версией pydantic в зависимостях. |
|
||||
| R-4 | **Дрейф floor vs config** при выборе hardcoded-карты. | — | — | Снят архитектурно: floor = class-default поля, единый источник правды (см. ADR-001, вариант B отклонён). |
|
||||
| R-5 | **Self-hosting:** правка резолва эффорта затрагивает запуск ВСЕХ агентов всех проектов общего инстанса; ошибка ломает конвейер enduro-trails тоже. | низк. | высок. | Обязательный `deploy-staging` (8501) перед прод-деплоем; прод-контейнер не ронять вне штатного хука; `Confirm Deploy`-гейт. Post-deploy проверка AC-6 по логам запуска агента. |
|
||||
| R-6 | **Прод-`.env` снова с пустыми `ORCH_AGENT_EFFORT_*`** после деплоя (урок 08.06: git-managed env не переживает). | средн. | низк. | Именно это и закрывает фикс (FR-1, code-side robust): эффорт резолвится в floor независимо от состояния `.env`. Приведение `.env` к каноне — рекомендация, не зависимость. |
|
||||
| R-7 | **`xhigh` не принимается CLI-слоем.** developer-апгрейд бессмыслен, если `xhigh ∉ VALID_EFFORTS`. | очень низк. | средн. | `xhigh` уже в `VALID_EFFORTS` (`launcher.py:22`); добавления не требуется — только верификация тестом (FR-5). |
|
||||
|
||||
## Сводный вывод
|
||||
Изменение локализовано в `resolve_agent_effort` + один дефолт `config.py`; не трогает
|
||||
API, схему БД, QG-гейты, model-резолв и путь проброса `--effort`. Главный остаточный
|
||||
риск — операционный (R-5, self-hosting), снимается штатным staging-гейтом. Контракт
|
||||
ORCH-41/ORCH-074 сохранён, обратная совместимость полная.
|
||||
Reference in New Issue
Block a user