From f61d963f9b9cb4732c0af833f3fc618b7d326dcc Mon Sep 17 00:00:00 2001 From: claude-bot Date: Tue, 9 Jun 2026 17:25:42 +0300 Subject: [PATCH] architect(ET): auto-commit from architect run_id=478 --- ...-developer-rebase-and-deployer-language.md | 135 ++++++++++++++++++ docs/work-items/ORCH-092/10-tech-risks.md | 42 ++++++ 2 files changed, 177 insertions(+) create mode 100644 docs/work-items/ORCH-092/06-adr/ADR-001-developer-rebase-and-deployer-language.md create mode 100644 docs/work-items/ORCH-092/10-tech-risks.md diff --git a/docs/work-items/ORCH-092/06-adr/ADR-001-developer-rebase-and-deployer-language.md b/docs/work-items/ORCH-092/06-adr/ADR-001-developer-rebase-and-deployer-language.md new file mode 100644 index 0000000..dd03e2b --- /dev/null +++ b/docs/work-items/ORCH-092/06-adr/ADR-001-developer-rebase-and-deployer-language.md @@ -0,0 +1,135 @@ +--- +work_item: ORCH-092 +stage: architecture +author_agent: architect +status: accepted +created_at: 2026-06-09 +model_used: 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` (``, шаг 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 ` (`src/merge_gate.py:151`). + +Важная асимметрия прав: авторитетный rebase движка **обязан** делать `--force-with-lease`, чтобы +переписать уже запушенную историю ветки. Developer-промпту это **прямо запрещено** +(``: «❌ Не используй `--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*` сам (это пересекается с запретом + `` и с авторитетной операцией движка, использующей `--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». Обоснование (в порядке веса): +1. **Минимизация регресс-поверхности на самом критичном промпте.** Перевод ~9.6 KB плотного + операционного текста — широкая поверхность для случайного слома verdict-ключа, маркера или + shell-команды (NFR-1 — критичный инвариант). Deployer управляет прод-рестартом 8500 (групповой + self-hosting риск) — здесь цена ошибки максимальна, выгода от churn — нулевая. +2. **Нулевая выгода понимания.** Исполняющая модель (`claude-opus-4-8`) двуязычна; критичные + команды, контракты, exit-code-маппинги и verdict-ключи **англо-нативны** — перевод вокруг них + лишь добавляет риск рассинхрона «русский текст ↔ английская команда». +3. **Исключение, а не дрейф.** Чтобы будущий агент не «починил» язык вслепую, исключение + фиксируется нормативно: (а) запись в `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` diff --git a/docs/work-items/ORCH-092/10-tech-risks.md b/docs/work-items/ORCH-092/10-tech-risks.md new file mode 100644 index 0000000..ca1db6a --- /dev/null +++ b/docs/work-items/ORCH-092/10-tech-risks.md @@ -0,0 +1,42 @@ +--- +work_item: ORCH-092 +stage: architecture +author_agent: architect +status: accepted +created_at: 2026-06-09 +model_used: claude-opus-4-8 +--- + +# 10 — Технические риски: ORCH-092 — Промпт-аудит 6 агентов + +Work Item: **ORCH-092** · Repo: **orchestrator** · Стадия: architecture + +> Информационный (гейтом не парсится). Перечисляет риски реализации и их митигейшн. +> Решения, порождающие/снижающие часть рисков, зафиксированы в +> `06-adr/ADR-001-developer-rebase-and-deployer-language.md`. + +## Реестр рисков + +| ID | Риск | Вер. | Влия. | Митигейшн | +|----|------|------|-------|-----------| +| TR-1 | Массовая текстовая правка 6 промптов случайно ломает machine-verdict ключ (`verdict:`/`result:`/`staging_status:`/`deploy_status:`/`security_status:`) по имени/регистру/значению | Сред. | Выс. | NFR-1 анти-регресс: `tests/test_agent_prompts_canon.py` (`test_machine_verdict_keys_preserved_exact_case`) + `test_agent_frontmatter_no_model.py` зелёные; правка точечная, не переписывание | +| TR-2 | Плейсхолдеры `` / `` сами скопированы моделью буквально (тот же класс бага, что хардкод) | Сред. | Низ. | Явная инструкция «подставь фактическое (`date +%F` / резолв конфига), НЕ копируй из примера»; плейсхолдер визуально не похож на валидное значение | +| TR-3 | Удаление шага `git rebase origin/main` (D1) оставляет ветку на устаревшем `main` в длинной/повторной (rework) стадии development | Низ. | Сред. | Авторитетный `auto_rebase_onto_main` под merge-lease перед слиянием (ORCH-026/043) детерминированно догоняет `main`; serial-gate (ORCH-088) ограничивает расхождение `main` за время одной задачи; срез ветки — от свежего `origin/main` | +| TR-4 | Решение «deployer = EN» (D2) воспринято будущим агентом как дрейф и «починено» переводом → регресс NFR-1 на самом опасном промпте | Низ. | Выс. | Нормативная фиксация исключения: запись в `CLAUDE.md`/README §«Слой промптов» + ожидание EN-deployer в каноне-тесте (FR-11); ADR-001 D2 как ссылка-обоснование | +| TR-5 | Добавление секции `` (developer/reviewer/tester) нарушает нормативный порядок 5 обязательных XML-секций канона 52d | Низ. | Сред. | `` ставится ПОСЛЕ `` (как у `architect.md` — эталон); гаранты `test_five_xml_sections_present` / `test_six_schema_field_names_present` | +| TR-6 | Поднятие критичной рамки в `deployer.md` (FR-6) задевает анти-регресс-маркер (`docker exec orchestrator-staging`, `pr_already_merged`, `8500`, `INFRA-WAIVED`) | Низ. | Выс. | Рамка добавляется/поднимается аддитивно (blockquote в начале ``), маркеры не трогаются; каноне-тест проверяет их наличие | +| TR-7 | Сверка имён гейтов (FR-3) «исправляет» верное имя вслепую (напр. `check_tests_passed`) | Низ. | Сред. | BR-3/A-1: несовпадений на момент анализа НЕТ → правка только реально отсутствующих в `QG_CHECKS`; TC-03 сверяет имена против реального реестра `src/qg/checks.py` | + +## Сводный вывод + +Доминирующий класс рисков — **случайный слом машинного контракта/канона при текстовой правке** +(TR-1/TR-5/TR-6/TR-7), полностью покрываемый структурными анти-регресс-тестами +`tests/test_agent_prompts_canon.py` + `test_agent_frontmatter_no_model.py` (NFR-1). Архитектурные +решения D1/D2 снижают, а не повышают системный риск: D1 устраняет конфликт инструкции с запретом +force-push и отдаёт догон `main` единственному авторитетному владельцу (движок); D2 минимизирует +регресс-поверхность на самом safety-critical промпте. + +Изменение **docs/prompts-only**: `src/**`, `STAGE_TRANSITIONS`, `QG_CHECKS`, схема БД — не тронуты; +прод-контейнер 8500 не перезапускается (NFR-2); всё ревертируемо одним PR (NFR-3). Эскалация +`arch:major-change` **не требуется**; возврат в анализ **не требуется** (ТЗ реализуемо без нарушения +принципов). Остаточный риск для прод-конвейера (self-hosting) — **низкий**.