12 KiB
work_item, stage, author_agent, status, created_at, model_used
| work_item | stage | author_agent | status | created_at | model_used |
|---|---|---|---|---|---|
| ORCH-092 | architecture | architect | accepted | 2026-06-09 | claude-opus-4-8 |
ADR-001: Ручной rebase developer и язык промпта deployer
Work Item: ORCH-092 — Промпт-аудит 6 агентов (эпилог эпика ORCH-52)
Стадия: architecture
Сквозная регистрация: N/A — локальное docs/prompts-only решение. Оба решения уточняют
существующий канон промптов (docs/architecture/adr/adr-0021-prompt-canon-anthropic.md,
README §«Слой промптов»), но не вводят ни нового QG, ни стадии, ни компонента, ни смены БД →
нового global ADR не требуют. Долговечность нормативного эффекта обеспечивается анти-регресс-тестом
tests/test_agent_prompts_canon.py (FR-11), а не отдельным сквозным ADR.
Статус
Accepted
Контекст
ORCH-092 — аудит 6 системных промптов .openclaw/agents/*.md. Анализ (BRD §6, TRZ §3) вынес две
развилки, которые analyst намеренно не решал (зона архитектора), потребовав ADR ПЕРЕД правкой
соответствующих строк:
P1-2 / FR-9 — ручной rebase developer. developer.md (<task>, шаг 2 алгоритма) предписывает
git fetch origin && git rebase origin/main. Сверка кодом (BRD A-2) показала, что движок уже
держит свежесть базы детерминированно и автоматически, причём двумя независимыми рубежами:
- Срез ветки от свежего
origin/main— serial-gate (ORCH-088) откладывает создание ветки соstart_pipelineна момент claim analyst-job (launcher._materialize_deferred_branch,src/agents/launcher.py:421), когдаorigin/mainуже содержит код предшественника (done⇔ SHA-в-main, ORCH-071/073).ensure_worktreeрежет worktree от свежегоorigin/main. - Авторитетный pre-merge rebase под merge-lease —
check_branch_mergeable(src/qg/checks.py:697-703) на ребреdeploy-staging → deployвызываетmerge_gate.auto_rebase_onto_main(src/merge_gate.py:113) всегда приpremerge_rebase_always=True(дефолт, ORCH-026). Эта операция завершаетсяgit push --force-with-lease origin <branch>(src/merge_gate.py:151).
Важная асимметрия прав: авторитетный rebase движка обязан делать --force-with-lease, чтобы
переписать уже запушенную историю ветки. Developer-промпту это прямо запрещено
(<constraints>: «❌ Не используй --no-verify / --force-push»). Значит ручной
git rebase origin/main developer'а либо безопасен-но-бесполезен (в начале стадии ветка только что
срезана от свежего main — rebase no-op), либо опасен (после первого push повторный rebase требует
force-push, который developer'у запрещён) — то есть инструкция шага 2 дублирует автоматику и
конфликтует с собственным запретом промпта.
P2-2 / FR-10 — язык deployer. 5 из 6 промптов на русском; deployer.md (~9.6 KB, самый большой
и самый safety-critical: self-hosting, прод-рестарт 8500) — на английском. Нужно решить:
унифицировать на ru ИЛИ зафиксировать исключение (en). Инвариант NFR-1 критичен: machine-verdict
ключи (staging_status:/deploy_status:/security_status: + значения SUCCESS/FAILED/PASS/FAIL),
shell-команды и анти-регресс-маркеры (docker exec orchestrator-staging, pr_already_merged,
8500, INFRA-WAIVED) — байт-в-байт неприкосновенны.
Решение
Сводка
D1: убрать безусловный ручной git rebase origin/main из алгоритма developer; свежесть базы —
инвариант движка (serial-gate + auto_rebase под lease), а не ответственность агента. D2: оставить
deployer.md на английском как явно задокументированное исключение канона; не переводить.
D1 — Developer НЕ делает ручной rebase (закрывает FR-9 / BR-9)
Шаг 2 алгоритма developer (git fetch origin && git rebase origin/main) удаляется как
самостоятельная мутирующая операция. Вместо него — короткая нормативная заметка, что:
- ветка уже срезана движком от свежего
origin/main(serial-gate ORCH-088), поэтому ручная синхра на входе не нужна; - авторитетный догон
mainперед слиянием делает движок (auto_rebase_onto_mainпод merge-lease, ORCH-026/043) на ребреdeploy-staging → deploy; - developer не делает
git rebase/git push --force*сам (это пересекается с запретом<constraints>и с авторитетной операцией движка, использующей--force-with-lease).
Допустимо сохранить read-only git fetch origin (без rebase) — он не мутирует историю и полезен
для сверки с актуальным main; но это не обязательный шаг. Главный инвариант: из алгоритма
исчезает мутирующий git rebase origin/main.
Привязка: FR-9 (промпт приводится в соответствие с ADR), AC-9 (developer не нарушает no-force-push), анти-регресс — маркер «не мержи свой PR» и запрет force-push сохраняются.
D2 — Deployer остаётся на английском (закрывает FR-10 / BR-10)
deployer.md не переводится; язык остаётся английским как зафиксированное исключение из канона
«остальные промпты на ru». Обоснование (в порядке веса):
- Минимизация регресс-поверхности на самом критичном промпте. Перевод ~9.6 KB плотного операционного текста — широкая поверхность для случайного слома verdict-ключа, маркера или shell-команды (NFR-1 — критичный инвариант). Deployer управляет прод-рестартом 8500 (групповой self-hosting риск) — здесь цена ошибки максимальна, выгода от churn — нулевая.
- Нулевая выгода понимания. Исполняющая модель (
claude-opus-4-8) двуязычна; критичные команды, контракты, exit-code-маппинги и verdict-ключи англо-нативны — перевод вокруг них лишь добавляет риск рассинхрона «русский текст ↔ английская команда». - Исключение, а не дрейф. Чтобы будущий агент не «починил» язык вслепую, исключение
фиксируется нормативно: (а) запись в
CLAUDE.md/README §«Слой промптов», (б) анти-регресс-тестtests/test_agent_prompts_canon.py(FR-11) допускает/ожидает EN для deployer.
D2 не отменяет FR-6: критичная рамка «NEVER restart prod 8500» поднимается/усиливается в начале
deployer.md — на английском, в существующем blockquote-стиле. machine-verdict ключи и команды
остаются байт-в-байт (AC-6).
Альтернативы
- D1-альт: оставить ручной rebase «с пояснением». Отвергнуто: пояснение не снимает конфликт с запретом force-push и не устраняет дублирование авторитетной операции движка; «оставить, но объяснить почему оно безопасно» сложнее и хрупче, чем «убрать то, что движок делает лучше».
- D1-альт: оставить как есть. Отвергнуто: BRD/TRZ явно квалифицируют это как нереализуемо-конфликтующую инструкцию (after-push rebase ⇒ нужен запрещённый force-push).
- D2-альт: унифицировать deployer на русский. Отвергнуто: максимальный регресс-риск на самом опасном промпте при нулевой выгоде понимания; противоречит духу «docs/prompts-only, минимум изменений, NFR-1 байт-в-байт».
Последствия
- + Developer-алгоритм перестаёт противоречить собственному запрету force-push; единственный
владелец догона
main— движок (один авторитетный путь, меньше гонок). - + Самый safety-critical промпт (deployer) не подвергается рискованному массовому переводу; NFR-1 защищён структурно.
- + Оба решения — чисто текстовые, ревертируемы одним PR;
src/**не тронут (NFR-2/NFR-3). - − Языковая неоднородность канона (5 ru + 1 en) остаётся. Митигейшн: явная нормативная запись + тест → это документированное исключение, а не необъяснённый дрейф.
- − Теоретически developer может захотеть подтянуть
mainво время длинной стадии и теперь не имеет шага rebase. Митигейшн: серийность репо (ORCH-088) ограничивает расхождениеmainза время одной задачи; авторитетный rebase перед merge закрывает остаточное расхождение детерминированно. - Откат: вернуть строку
git rebase origin/mainвdeveloper.mdшаг 2 и (при желании) перевестиdeployer.md— обе правки текстовые, в одном PR, без изменения кода/схемы.
Ссылки
- BRD:
docs/work-items/ORCH-092/01-brd.md(BR-9, BR-10; §6 A-2) - TRZ:
docs/work-items/ORCH-092/02-trz.md(FR-9, FR-10) - Acceptance:
docs/work-items/ORCH-092/03-acceptance-criteria.md(AC-6, AC-9) - Канон промптов:
docs/architecture/adr/adr-0021-prompt-canon-anthropic.md - Сверено по коду:
src/merge_gate.py:113,151(auto_rebase_onto_main+--force-with-lease),src/qg/checks.py:697-703(check_branch_mergeable→ авто-rebase приpremerge_rebase_always),src/agents/launcher.py:421(_materialize_deferred_branch, отложенный срез ветки ORCH-088) - Риски:
docs/work-items/ORCH-092/10-tech-risks.md