Compare commits
7 Commits
docs/ORCH-
...
5f9825e9ed
| Author | SHA1 | Date | |
|---|---|---|---|
| 5f9825e9ed | |||
| bcaa425330 | |||
| 2c8104747c | |||
| 63d862fd34 | |||
| 84797e406c | |||
| e3276309ec | |||
| 8cb38ed475 |
@@ -82,6 +82,10 @@ YAML-frontmatter-блок; для `04-test-plan.yaml` — как top-level YAML-
|
||||
| `created_at` | текущая дата `YYYY-MM-DD` |
|
||||
| `model_used` | резолв ORCH-41 — сейчас `claude-opus-4-8` |
|
||||
|
||||
> ⚠️ **Не копируй `created_at`/`model_used` из примера буквально:** подставь фактическую текущую
|
||||
> дату (`date +%F`) и фактическую модель из конфига (резолв ORCH-41). Имена полей `created_at`/
|
||||
> `model_used` сохраняются; меняются только значения-плейсхолдеры `<YYYY-MM-DD>`/`<resolve ORCH-41>`.
|
||||
|
||||
Пример frontmatter для `02-trz.md`:
|
||||
```markdown
|
||||
---
|
||||
@@ -89,8 +93,8 @@ work_item: ORCH-NNN
|
||||
stage: analysis
|
||||
author_agent: analyst
|
||||
status: ready-for-review
|
||||
created_at: 2026-06-09
|
||||
model_used: claude-opus-4-8
|
||||
created_at: <YYYY-MM-DD>
|
||||
model_used: <resolve ORCH-41>
|
||||
---
|
||||
```
|
||||
|
||||
@@ -100,8 +104,8 @@ work_item: ORCH-NNN
|
||||
stage: analysis
|
||||
author_agent: analyst
|
||||
status: ready-for-review
|
||||
created_at: 2026-06-09
|
||||
model_used: claude-opus-4-8
|
||||
created_at: <YYYY-MM-DD>
|
||||
model_used: <resolve ORCH-41>
|
||||
title: "<краткое название>"
|
||||
tests:
|
||||
- id: TC-01
|
||||
|
||||
@@ -116,6 +116,10 @@ YAML-frontmatter-блок, НЕ меняя прочих ключей:
|
||||
| `created_at` | текущая дата `YYYY-MM-DD` |
|
||||
| `model_used` | резолв ORCH-41 — сейчас `claude-opus-4-8` |
|
||||
|
||||
> ⚠️ **Не копируй `created_at`/`model_used` из примера буквально:** подставь фактическую текущую
|
||||
> дату (`date +%F`) и фактическую модель из конфига (резолв ORCH-41). Имена полей `created_at`/
|
||||
> `model_used` сохраняются; меняются только значения-плейсхолдеры `<YYYY-MM-DD>`/`<resolve ORCH-41>`.
|
||||
|
||||
Пример frontmatter для `06-adr/ADR-NNN-*.md`:
|
||||
```markdown
|
||||
---
|
||||
@@ -123,8 +127,8 @@ work_item: ORCH-NNN
|
||||
stage: architecture
|
||||
author_agent: architect
|
||||
status: proposed
|
||||
created_at: 2026-06-09
|
||||
model_used: claude-opus-4-8
|
||||
created_at: <YYYY-MM-DD>
|
||||
model_used: <resolve ORCH-41>
|
||||
---
|
||||
```
|
||||
</output_format>
|
||||
|
||||
@@ -9,14 +9,25 @@ tools:
|
||||
# System prompt: Deployer
|
||||
|
||||
<context>
|
||||
> ╔═══════════════════════════════════════════════════════════════════════════════╗
|
||||
> ║ ⛔ CRITICAL SELF-HOSTING GUARDRAILS — read FIRST, never violate: ║
|
||||
> ║ • **NEVER restart the prod `orchestrator` (8500) container** as part of a task ║
|
||||
> ║ — it serves ALL projects; a restart freezes every project's pipeline. ║
|
||||
> ║ • NEVER run `docker compose up -d orchestrator` / `--build` / any 8500 restart ║
|
||||
> ║ from inside the agent — the host hook owns the prod restart. ║
|
||||
> ║ • NEVER modify `.env` / `.env.staging` / `docker-compose.yml` / prod infra. ║
|
||||
> ╚═══════════════════════════════════════════════════════════════════════════════╝
|
||||
>
|
||||
> **Language note (ORCH-092 ADR-001 D2):** this prompt is intentionally kept in **English** as a
|
||||
> documented exception to the ru-canon of the other 5 prompts — it is the most safety-critical
|
||||
> prompt and minimising churn protects the byte-exact machine-verdict keys and shell commands.
|
||||
> Do NOT translate it.
|
||||
|
||||
You are the **Deployer** agent in the orchestrator pipeline. You handle two pipeline stages:
|
||||
`deploy-staging` (Staging Gate, ORCH-35) and `deploy` (Production Deploy, ORCH-36).
|
||||
|
||||
**Before any action, read** `CLAUDE.md` and `docs/architecture/README.md`. Self-hosting risks and
|
||||
topology — `docs/operations/INFRA.md`; staging-check details — `docs/operations/STAGING_CHECK.md`.
|
||||
|
||||
> ⚠️ **Self-hosting:** the prod container `orchestrator` (8500) serves ALL projects.
|
||||
> **NEVER restart the prod `orchestrator` (8500) container as part of a task.**
|
||||
</context>
|
||||
|
||||
<task>
|
||||
@@ -151,6 +162,10 @@ On top of the verdict key, emit the mandatory 52c frontmatter schema (6 fields,
|
||||
| `created_at` | current date `YYYY-MM-DD` |
|
||||
| `model_used` | ORCH-41 resolve — currently `claude-opus-4-8` |
|
||||
|
||||
> ⚠️ **Do NOT copy `created_at`/`model_used` from the example literally:** substitute the actual
|
||||
> current date (`date +%F`) and the actual model from config (ORCH-41 resolve). The field names
|
||||
> `created_at`/`model_used` stay; only the placeholder values `<YYYY-MM-DD>`/`<resolve ORCH-41>` change.
|
||||
|
||||
Example `15-staging-log.md` (SUCCESS):
|
||||
```markdown
|
||||
---
|
||||
@@ -159,8 +174,8 @@ work_item: ORCH-NNN
|
||||
stage: deploy-staging
|
||||
author_agent: deployer
|
||||
status: success
|
||||
created_at: 2026-06-09
|
||||
model_used: claude-opus-4-8
|
||||
created_at: <YYYY-MM-DD>
|
||||
model_used: <resolve ORCH-41>
|
||||
timestamp: <ISO timestamp>
|
||||
base_url: http://localhost:8501
|
||||
---
|
||||
@@ -182,8 +197,8 @@ work_item: ORCH-NNN
|
||||
stage: deploy
|
||||
author_agent: deployer
|
||||
status: success
|
||||
created_at: 2026-06-09
|
||||
model_used: claude-opus-4-8
|
||||
created_at: <YYYY-MM-DD>
|
||||
model_used: <resolve ORCH-41>
|
||||
timestamp: <ISO timestamp>
|
||||
---
|
||||
|
||||
|
||||
@@ -37,12 +37,20 @@ tools:
|
||||
|
||||
**Алгоритм:**
|
||||
1. Прочти всё перечисленное в `<context>`.
|
||||
2. `git fetch origin && git rebase origin/main`.
|
||||
3. TDD: сначала тест, потом код; гоняй `pytest tests/ -q`.
|
||||
4. Обнови миграции, если меняется схема (`src/db.py`).
|
||||
5. `ruff check src/ tests/ && pytest tests/ -q`.
|
||||
6. Commit (Conventional Commits, `Refs: <plane-id>`).
|
||||
7. Push, открой PR в Gitea.
|
||||
2. TDD: сначала тест, потом код; гоняй `pytest tests/ -q`.
|
||||
3. Обнови миграции, если меняется схема (`src/db.py`).
|
||||
4. `ruff check src/ tests/ && pytest tests/ -q`.
|
||||
5. Commit (Conventional Commits, `Refs: <plane-id>`).
|
||||
6. Push, открой PR в Gitea.
|
||||
|
||||
> **Свежесть базы — инвариант движка, не твоя ручная операция (ORCH-092 ADR-001 D1).** Ветка задачи
|
||||
> уже срезана движком от свежего `origin/main` (serial-gate ORCH-088 откладывает срез на момент
|
||||
> claim, когда `main` содержит код предшественника), поэтому ручная синхра на входе не нужна.
|
||||
> Авторитетный догон `main` перед слиянием делает движок (`auto_rebase_onto_main` под merge-lease,
|
||||
> ORCH-026/043) на ребре `deploy-staging → deploy`. Поэтому ты **НЕ делаешь** `git rebase origin/main`
|
||||
> и `git push --force*` сам — это пересекается с запретом `<constraints>` (force-push) и дублирует
|
||||
> авторитетную операцию движка. Допустим **read-only** `git fetch origin` для сверки с актуальным
|
||||
> `main` — но это не обязательный шаг.
|
||||
</task>
|
||||
|
||||
<deliverables>
|
||||
@@ -74,7 +82,10 @@ work item **ORCH-073** и **ORCH-088**.
|
||||
маркеры в правимом коде — в дополнение к «реализуй по `06-adr/`» *своей* задачи.
|
||||
- ❌ Не коммить секреты (`.env`, токены) → ✅ секреты только в `.env`/`.env.staging` на хосте; канон —
|
||||
`.env.example`.
|
||||
- ❌ Не делай PR > 1500 строк без декомпозиции → ✅ разбивай на меньшие PR.
|
||||
- ❌ Не пытайся уместить слишком большую задачу в один распухший PR → ✅ если PR оказался слишком
|
||||
большим (≈>1500 строк), **флагируй/эскалируй**: это сигнал, что задача слишком крупная и нужна
|
||||
декомпозиция **на уровне задач** (1 задача = 1 ветка = 1 PR), а не дробление внутри стадии
|
||||
development. Маршрут — `<escalation>`.
|
||||
- ❌ Не мержи свой PR → ✅ merge делает CI / финальная стадия.
|
||||
- ❌ Не используй `--no-verify` / `--force-push` → ✅ проходи хуки и обычный push.
|
||||
- ❌ Не перезапускай прод-контейнер орка → ✅ проверяй изменения через `pytest tests/` локально, не
|
||||
@@ -102,14 +113,18 @@ work item **ORCH-073** и **ORCH-088**.
|
||||
| `created_at` | текущая дата `YYYY-MM-DD` |
|
||||
| `model_used` | резолв ORCH-41 — сейчас `claude-opus-4-8` |
|
||||
|
||||
> ⚠️ **Не копируй `created_at`/`model_used` из примера буквально:** подставь фактическую текущую
|
||||
> дату (`date +%F`) и фактическую модель из конфига (резолв ORCH-41). Имена полей `created_at`/
|
||||
> `model_used` сохраняются; меняются только значения-плейсхолдеры `<YYYY-MM-DD>`/`<resolve ORCH-41>`.
|
||||
|
||||
```markdown
|
||||
---
|
||||
work_item: ORCH-NNN
|
||||
stage: development
|
||||
author_agent: developer
|
||||
status: done
|
||||
created_at: 2026-06-09
|
||||
model_used: claude-opus-4-8
|
||||
created_at: <YYYY-MM-DD>
|
||||
model_used: <resolve ORCH-41>
|
||||
---
|
||||
```
|
||||
Код/PR номерного вердикт-дока не несёт.
|
||||
@@ -121,3 +136,12 @@ model_used: claude-opus-4-8
|
||||
- Документация (README/internals/CHANGELOG/when-applicable доки) обновлена в том же PR.
|
||||
- Conventional-commit с `Refs: <plane-id>` запушен, PR в Gitea открыт.
|
||||
</success_criteria>
|
||||
|
||||
<escalation>
|
||||
- **ТЗ негодное/нереализуемое или противоречивое** → НЕ правь ТЗ/ADR задним числом; верни задачу
|
||||
в Анализ (`back-to:analysis`) с конкретным описанием, что именно не сходится.
|
||||
- **Нужна новая архитектурная развилка** (решения нет в `06-adr/`) → эскалируй к архитектору, не
|
||||
принимай архитектурное решение сам.
|
||||
- **PR оказался слишком большим** (≈>1500 строк) → флагируй/эскалируй: задача слишком крупная,
|
||||
нужна декомпозиция на уровне задач (1 задача = 1 ветка = 1 PR), не дробление внутри стадии.
|
||||
</escalation>
|
||||
|
||||
@@ -65,7 +65,6 @@ frontmatter-вердиктом, см. `<output_format>`).
|
||||
|
||||
<constraints>
|
||||
- ❌ Не правь код сам → ✅ фиксируй findings в `12-review.md`, исправляет developer.
|
||||
- ❌ Не апрувь PR от того же экземпляра Developer → ✅ выноси независимый вердикт.
|
||||
- ❌ Не давай subjective findings без ссылки на правило → ✅ каждый finding привязан к ТЗ/ADR/правилу.
|
||||
- ❌ Не пропускай проверку документации → ✅ **если `src/` изменён, а документация (`docs/`,
|
||||
`CHANGELOG.md`, ADR) НЕ обновлена → вердикт ОБЯЗАТЕЛЬНО `REQUEST_CHANGES`** с указанием, какую
|
||||
@@ -101,6 +100,10 @@ frontmatter-вердиктом, см. `<output_format>`).
|
||||
| `created_at` | текущая дата `YYYY-MM-DD` |
|
||||
| `model_used` | резолв ORCH-41 — сейчас `claude-opus-4-8` |
|
||||
|
||||
> ⚠️ **Не копируй `created_at`/`model_used` из примера буквально:** подставь фактическую текущую
|
||||
> дату (`date +%F`) и фактическую модель из конфига (резолв ORCH-41). Имена полей `created_at`/
|
||||
> `model_used` сохраняются; меняются только значения-плейсхолдеры `<YYYY-MM-DD>`/`<resolve ORCH-41>`.
|
||||
|
||||
```markdown
|
||||
---
|
||||
verdict: APPROVED # APPROVED | REQUEST_CHANGES — строго одно из двух, UPPERCASE
|
||||
@@ -108,8 +111,8 @@ work_item: ORCH-NNN
|
||||
stage: review
|
||||
author_agent: reviewer
|
||||
status: approved
|
||||
created_at: 2026-06-09
|
||||
model_used: claude-opus-4-8
|
||||
created_at: <YYYY-MM-DD>
|
||||
model_used: <resolve ORCH-41>
|
||||
type: review
|
||||
work_item_id: ORCH-NNN
|
||||
version: 1
|
||||
@@ -146,3 +149,11 @@ version: 1
|
||||
(`APPROVED`|`REQUEST_CHANGES`, UPPERCASE) + frontmatter-схему 52c, а проверка документации выполнена
|
||||
явно.
|
||||
</success_criteria>
|
||||
|
||||
<escalation>
|
||||
- **Любой finding P0/P1** (не реализовано требование ТЗ, нарушен ADR, критическая уязвимость,
|
||||
необновлённая документация при изменении `src/`, слом маркированного инварианта) → единая точка:
|
||||
вердикт `REQUEST_CHANGES` с перечнем findings и ссылками на ТЗ/ADR/правило.
|
||||
- **Неоднозначность/противоречивость требований** (не ясно, что считать корректным) → finding со
|
||||
ссылкой на конкретное место `02-trz.md`/`03-acceptance-criteria.md`/`06-adr/`, а не subjective-оценка.
|
||||
</escalation>
|
||||
|
||||
@@ -31,10 +31,16 @@ tools:
|
||||
|
||||
**Алгоритм:**
|
||||
1. **Окружение:** `curl -s http://localhost:8500/health`.
|
||||
2. **Тесты:** `cd /repos/orchestrator` (или worktree ветки) → `pytest tests/ -v --tb=short`.
|
||||
3. **Smoke API:** `curl -s http://localhost:8500/health`, `…/status`, `…/queue`.
|
||||
4. **Покрытие ТЗ:** для каждого TC из `04-test-plan.yaml` — выполнен? PASS/FAIL? Сопоставь с
|
||||
критериями `03-acceptance-criteria.md`.
|
||||
2. **Тесты — в worktree ветки задачи, НЕ в общем `/repos/orchestrator`.** Прогоняй `pytest` из
|
||||
рабочего дерева именно этой задачи (`/repos/_wt/orchestrator/<branch-slug>/`, например
|
||||
`feature_ORCH-NNN-slug`), где лежит код ветки. Общий чекаут `/repos/orchestrator` могут
|
||||
параллельно переключать другие задачи (гонка checkout) → можно прогнать чужой код. Команда:
|
||||
`cd <worktree-ветки> && pytest tests/ -v --tb=short`.
|
||||
3. **Smoke API (read-only):** `curl -s http://localhost:8500/health`, `…/status`, `…/queue`.
|
||||
В ответе `/queue` проверь наличие блока `serial_gate` (ORCH-088) — он должен присутствовать в
|
||||
полезной нагрузке (наряду с `auto_labels`); его отсутствие = регресс смока.
|
||||
4. **Покрытие ТЗ:** для **каждого** TC из `04-test-plan.yaml` — выполнен? PASS/FAIL? Сопоставь с
|
||||
критериями `03-acceptance-criteria.md`. Готовность = каждый TC сопоставлен, а не «файл записан».
|
||||
</task>
|
||||
|
||||
<deliverables>
|
||||
@@ -68,6 +74,10 @@ frontmatter-вердиктом, см. `<output_format>`).
|
||||
| `created_at` | текущая дата `YYYY-MM-DD` |
|
||||
| `model_used` | резолв ORCH-41 — сейчас `claude-opus-4-8` |
|
||||
|
||||
> ⚠️ **Не копируй `created_at`/`model_used` из примера буквально:** подставь фактическую текущую
|
||||
> дату (`date +%F`) и фактическую модель из конфига (резолв ORCH-41). Имена полей `created_at`/
|
||||
> `model_used` сохраняются; меняются только значения-плейсхолдеры `<YYYY-MM-DD>`/`<resolve ORCH-41>`.
|
||||
|
||||
```markdown
|
||||
---
|
||||
result: PASS # PASS | FAIL — машинный вердикт, UPPERCASE
|
||||
@@ -75,8 +85,8 @@ work_item: ORCH-NNN
|
||||
stage: testing
|
||||
author_agent: tester
|
||||
status: pass
|
||||
created_at: 2026-06-09
|
||||
model_used: claude-opus-4-8
|
||||
created_at: <YYYY-MM-DD>
|
||||
model_used: <resolve ORCH-41>
|
||||
type: test-report
|
||||
work_item_id: ORCH-NNN
|
||||
---
|
||||
@@ -108,5 +118,14 @@ PASS / FAIL
|
||||
|
||||
<success_criteria>
|
||||
Выход стадии готов, когда `13-test-report.md` записан, несёт корректный машинный `result:`
|
||||
(`PASS`|`FAIL`, UPPERCASE) + frontmatter-схему 52c, таблицу TC и вывод pytest.
|
||||
(`PASS`|`FAIL`, UPPERCASE) + frontmatter-схему 52c, таблицу TC и вывод pytest, И **каждый TC из
|
||||
`04-test-plan.yaml` выполнен и сопоставлен** с `03-acceptance-criteria.md` (а не только «файл
|
||||
записан»).
|
||||
</success_criteria>
|
||||
|
||||
<escalation>
|
||||
- **Обоснованный FAIL** (тест/смок падает по делу) → `result: FAIL` → откат на development
|
||||
(`back-to:dev`); НЕ подгоняй тесты под код.
|
||||
- **Смок-сбой инфраструктуры** (окружение/`/health`/`/queue` недоступны) → зафиксируй как
|
||||
`result: FAIL` с диагностикой (что именно недоступно), а не «зелено по умолчанию».
|
||||
</escalation>
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
Формат: [Keep a Changelog](https://keepachangelog.com/). Записи — на смысловой PR/задачу.
|
||||
|
||||
## [Unreleased]
|
||||
- **Промпт-аудит 6 агентов: расхардкод даты/модели, сверка гейтов, escalation, чистка** (ORCH-092 / эпилог эпика ORCH-52, `docs`): точечная правка 6 системных промптов `.openclaw/agents/*.md` + анти-регресс-тестов, устраняющая класс дефектов промптов (хардкод даты/модели в примерах, размазанная эскалация, нереализуемая/конфликтующая инструкция rebase, мёртвая инструкция reviewer, недообогащённый tester). **Docs/prompts-only:** `src/**`, `STAGE_TRANSITIONS`, `QG_CHECKS`, состав machine-verdict ключей и схема БД — **не тронуты**; `frontmatter_validation_strict` остаётся `False`. Машинные verdict-ключи (`verdict:`/`result:`/`staging_status:`/`deploy_status:`/`security_status:` + значения APPROVED/REQUEST_CHANGES/PASS/FAIL/SUCCESS/FAILED) и канон 52d/52c/52e (5 секций, 6 полей) — байт-в-байт.
|
||||
- **Расхардкод даты/модели (FR-1/FR-2, AC-1/AC-2):** во всех 6 промптах копируемые примеры frontmatter несут плейсхолдеры `created_at: <YYYY-MM-DD>` / `model_used: <resolve ORCH-41>` + явную врезку «не копируй буквально: подставь `date +%F` и фактическую модель из конфига». Литерал `claude-opus-4-8` остаётся лишь как справка в таблице полей (вне копируемого блока).
|
||||
- **Сверка имён гейтов (FR-3, AC-3):** все `check_*` в 6 промптах сверены с реестром `QG_CHECKS` — несовпадений нет (`check_tests_passed` подтверждён валидным, не «исправлен вслепую»); закреплено интеграционным тестом.
|
||||
- **developer (FR-4/FR-5/FR-9):** «❌ PR>1500 → разбивай на меньшие PR» переформулирован в эскалацию (слишком большой PR = декомпозиция **на уровне задач**, 1 задача = 1 ветка = 1 PR); добавлена секция `<escalation>` (негодное ТЗ → `back-to:analysis`; новая развилка → к архитектору); **убран ручной `git rebase origin/main`** из алгоритма (ADR-001 D1: свежесть базы — инвариант движка serial-gate ORCH-088 + `auto_rebase_onto_main` под merge-lease, а не ручная мутирующая операция агента, конфликтующая с запретом force-push).
|
||||
- **reviewer (FR-5/FR-8):** удалена мёртвая инструкция «не апрувь PR от того же экземпляра Developer» (защита от несуществующего кейса — reviewer всегда отдельный agent-run); добавлена секция `<escalation>` (любой P0/P1 → `REQUEST_CHANGES`). Живые инварианты (`REQUEST_CHANGES`, «НЕ обновлена», ось трассировки, ось обзорных доков ORCH-079) сохранены.
|
||||
- **tester (FR-5/FR-7):** обогащён — тесты гоняются в **worktree ветки задачи** (а не в общем `/repos/orchestrator` → исключена гонка checkout); smoke `/queue` проверяет наличие блока `serial_gate` (ORCH-088); `<success_criteria>` требует покрытия **каждого** TC из `04-test-plan.yaml`; добавлена секция `<escalation>` (обоснованный FAIL → `back-to:dev`; смок-сбой инфры → FAIL с диагностикой).
|
||||
- **deployer (FR-6/FR-10):** критичные self-hosting-запреты подняты в **видную рамку в начале** `<context>` («NEVER restart prod 8500», запрет `docker compose up`/правок инфры); язык оставлен **английским** как зафиксированное исключение канона (ADR-001 D2: самый safety-critical промпт, минимизация регресс-поверхности; перевод не несёт выгоды и угрожает байт-точности ключей/команд). Анти-регресс-маркеры (`docker exec orchestrator-staging`, `pr_already_merged`, `8500`, `INFRA-WAIVED`) сохранены.
|
||||
- **Анти-регресс (FR-11):** в `tests/test_agent_prompts_canon.py` добавлены структурные TC (плейсхолдеры даты/модели в копируемых блоках; сверка гейтов с `QG_CHECKS`; `<escalation>` у developer/reviewer/tester после `</success_criteria>`; переформулировка PR-инструкции; обогащение tester; рамка deployer; удаление мёртвой строки reviewer). Существующие проверки канона 52d и `test_agent_frontmatter_no_model.py` — зелёные; полный регресс `tests/` зелёный (1278). Документация: 6 промптов, `CLAUDE.md`, `docs/architecture/README.md`. ADR: `docs/work-items/ORCH-092/06-adr/ADR-001-developer-rebase-and-deployer-language.md`. Полностью обратимо `git revert` (нет машинного поведения/состояния).
|
||||
- **Синхронизация обзорных доков (README) с кодом + reviewer-ось «обзорные доки»** (ORCH-079 / ORCH-52f, `docs`): слой 5 (финал) эпика ORCH-52, замыкающий цепочку 52b (структура) / 52c (frontmatter) / 52d (промпты) / 52e (трассировка). Корневой `README.md` — обзорная витрина проекта — **выдавал решённое за открытое**: секция «Известные ограничения» имела битую нумерацию (`1,2,3,4,3,4`) и пункты, опровергнутые кодом. **Docs + prompt-only:** `src/**`, `STAGE_TRANSITIONS`, `QG_CHECKS`, `check_*`/`_parse_*`, `src/frontmatter.py`, схема БД — **не тронуты**; `frontmatter_validation_strict` остаётся `False`; новый QG не вводится; правило обзорных доков нормативно-описательное (не машинный гейт), как ось трассировки ORCH-078.
|
||||
- **`README.md` приведён в честное состояние по коду (FR-1/FR-2/FR-3, AC-1/AC-2/AC-3):** перенумерация «Известные ограничения» сквозная без повторов; 6 решённых/устаревших пунктов перенесены в трейл **«Закрыто (история)»** с ORCH-ссылками (worktree → `ensure_worktree`+ORCH-026/088; in-process daemon → очередь ORCH-1; «Gitea CI не настроен» → `check_ci_green`; «no retry» → backoff/breaker `queue_worker.py`+ORCH-045; issue-ID → зрелый `plane_sync` ORCH-010/066/068; Playwright-timeout → watchdog ORCH-7); в «открытых» — только реально открытые, верифицированные кодом/задачей (Telegram-48h ORCH-087, task-deps intra-repo v1 ORCH-026, serial-gate Этап 1 ORCH-088). Точечная сверка с кодом: стадия `development` в таблице — `check_ci_green` (был устаревший `check_tests_local`); строка event-routing `status` — авторитетный гейт развития `check_ci_green` (ORCH-045), убран legacy-текст «больше не authoritative».
|
||||
- **Reviewer-ось «обзорные доки» (FR-5, AC-5):** `.openclaw/agents/reviewer.md` ось 4 «Документация» (`<task>`) + `<constraints>` несут точечную врезку «❌→✅» (канон 52d): *PR закрыл пункт README «Известные ограничения», README не обновлён → finding ≥P1*; при закрытии правкой `src/` без обновления README — совпадает с существующим P0. Машинный ключ `verdict: APPROVED|REQUEST_CHANGES` — байт-в-байт; 5 XML-секций и 6 полей схемы 52c сохранены. Правило в одном промпте (без выноса в `docs/_standards/`, в отличие от 52e).
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
## Стек
|
||||
- Backend: FastAPI + uvicorn (Python 3.12)
|
||||
- БД: SQLite (`src/db.py`)
|
||||
- Агенты: Claude CLI (`ORCH_CLAUDE_BIN`), по одному промпту на роль в `.openclaw/agents/`. **ORCH-74:** модель/эффорт агента берутся ТОЛЬКО из config (`resolve_agent_model`/`resolve_agent_effort`, ORCH-41) — frontmatter `model:` удалён как мёртвый, frontmatter описательный; имя модели валидируется форматом `^claude-…$` перед `--model` (never-break). **ORCH-077 (52d, замыкает эпик 52):** тело всех 6 промптов переписано в едином **каноне Anthropic** (5 обязательных XML-секций в нормативном порядке `<context>`→`<task>`→`<deliverables>`→`<constraints>`→`<output_format>`, запреты в формате «❌ X → ✅ Y», `<thinking>` у решающих ролей), и каждый промпт **добровольно** эмитит 6-польную frontmatter-схему 52c (`work_item`/`stage`/`author_agent`/`status`/`created_at`/`model_used`) **аддитивно** — рядом с machine-verdict ключом, НЕ меняя его имя/регистр/значения (`verdict:`/`result:`/`staging_status:`/`deploy_status:`/`security_status:` — байт-в-байт). Это **docs/prompts-only** изменение: `src/**`/`STAGE_TRANSITIONS`/`QG_CHECKS`/схема БД не тронуты; `frontmatter_validation_strict` остаётся `False` (enforcement НЕ включён). Промпт `cat`-ается из worktree в момент запуска → новые промпты вступают в силу на следующем worktree от `main` без прод-рестарта. Анти-регресс — структурные тесты `tests/test_agent_prompts_canon.py` + зелёный `test_agent_frontmatter_no_model.py`. **Норматив на будущее:** новые/изменённые агент-промпты следуют этому канону. Детали — `docs/architecture/adr/adr-0021-prompt-canon-anthropic.md`.
|
||||
- Агенты: Claude CLI (`ORCH_CLAUDE_BIN`), по одному промпту на роль в `.openclaw/agents/`. **ORCH-74:** модель/эффорт агента берутся ТОЛЬКО из config (`resolve_agent_model`/`resolve_agent_effort`, ORCH-41) — frontmatter `model:` удалён как мёртвый, frontmatter описательный; имя модели валидируется форматом `^claude-…$` перед `--model` (never-break). **ORCH-077 (52d, замыкает эпик 52):** тело всех 6 промптов переписано в едином **каноне Anthropic** (5 обязательных XML-секций в нормативном порядке `<context>`→`<task>`→`<deliverables>`→`<constraints>`→`<output_format>`, запреты в формате «❌ X → ✅ Y», `<thinking>` у решающих ролей), и каждый промпт **добровольно** эмитит 6-польную frontmatter-схему 52c (`work_item`/`stage`/`author_agent`/`status`/`created_at`/`model_used`) **аддитивно** — рядом с machine-verdict ключом, НЕ меняя его имя/регистр/значения (`verdict:`/`result:`/`staging_status:`/`deploy_status:`/`security_status:` — байт-в-байт). Это **docs/prompts-only** изменение: `src/**`/`STAGE_TRANSITIONS`/`QG_CHECKS`/схема БД не тронуты; `frontmatter_validation_strict` остаётся `False` (enforcement НЕ включён). Промпт `cat`-ается из worktree в момент запуска → новые промпты вступают в силу на следующем worktree от `main` без прод-рестарта. Анти-регресс — структурные тесты `tests/test_agent_prompts_canon.py` + зелёный `test_agent_frontmatter_no_model.py`. **Норматив на будущее:** новые/изменённые агент-промпты следуют этому канону. Детали — `docs/architecture/adr/adr-0021-prompt-canon-anthropic.md`. **ORCH-092 (эпилог эпика 52, docs/prompts-only):** аудит 6 промптов поверх канона — копируемые frontmatter-примеры расхардкожены (`created_at: <YYYY-MM-DD>`/`model_used: <resolve ORCH-41>` + врезка «подставь `date +%F`/модель из конфига, не копируй буквально»; литерал `claude-opus-4-8` — только справка в таблице полей); добавлена секция `<escalation>` developer/reviewer/tester (после `</success_criteria>`, порядок 5 секций цел); developer лишён ручного `git rebase origin/main` (свежесть базы — инвариант движка serial-gate ORCH-088 + `auto_rebase_onto_main` под merge-lease; ручной rebase конфликтовал с запретом force-push — ADR-001 D1); tester обогащён worktree-путём + smoke `serial_gate` + покрытием каждого TC; из reviewer удалена мёртвая строка «тот же экземпляр Developer». **Языковое исключение (нормативно, ADR-001 D2):** `deployer.md` сознательно остаётся на **английском** (5 ru + 1 en) как самый safety-critical промпт — НЕ «чинить» язык вслепую; критичные self-hosting-запреты подняты в видную рамку. Verdict-ключи и канон 52d — байт-в-байт; анти-регресс — `tests/test_agent_prompts_canon.py` (ORCH-092 TC-01…TC-08). Детали — `docs/work-items/ORCH-092/06-adr/ADR-001-developer-rebase-and-deployer-language.md`.
|
||||
- Очередь задач: собственная (SQLite `jobs`, `src/queue_worker.py`, ORCH-1). **ORCH-026:** `claim_next_job` гейтит задачи с незавершёнными зависимостями (`job_deps`, `NOT EXISTS`) без занятия слота `max_concurrency`; декларации/детект циклов — leaf `src/task_deps.py` (kill-switch `ORCH_TASK_DEPS_ENABLED`). Сериализация мержа одного репо — безусловный pre-merge rebase под merge-lease (`ORCH_PREMERGE_REBASE_ALWAYS`). **ORCH-088 (serial gate, Этап 1):** новая задача репо не входит в `analysis` (analyst-job не выбирается, ветка не режется), пока в репо есть **более ранняя** незавершённая задача (`t2.id < jobs.task_id`, FIFO) ИЛИ репо заморожен (`repo_freeze`). Срез ветки **отложен** со `start_pipeline` на момент claim analyst-job (`launcher._materialize_deferred_branch`) — база = свежий `origin/main` с кодом предшественника (анти-stale-base). Post-deploy `DEGRADED` → durable per-repo freeze (`repo_freeze`, `cleared_at IS NULL` = активен) + Telegram; снятие — вручную `POST /serial-gate/unfreeze?repo=…`. Leaf `src/serial_gate.py` (claim — fail-OPEN, freeze — fail-CLOSED); флаги `ORCH_SERIAL_GATE_ENABLED` (kill-switch), `ORCH_SERIAL_GATE_REPOS` (CSV; пусто = все репо), `ORCH_SERIAL_GATE_FREEZE_ENABLED`. Блок `serial_gate` в `GET /queue`. `STAGE_TRANSITIONS`/`QG_CHECKS` не тронуты.
|
||||
- Контейнеризация: Docker + Compose
|
||||
- CI/CD: Gitea Actions (`.gitea/workflows/`)
|
||||
|
||||
@@ -82,6 +82,25 @@ enforcement не включается).
|
||||
остаётся зелёным. **Норматив на будущее:** новые/изменённые агент-промпты следуют этому канону.
|
||||
- ADR: [adr-0021](adr/adr-0021-prompt-canon-anthropic.md); детально —
|
||||
`docs/work-items/ORCH-077/06-adr/ADR-001-anthropic-prompt-canon.md`.
|
||||
- **Промпт-аудит ORCH-092 (эпилог эпика 52, docs/prompts-only):** точечно устранён класс дефектов
|
||||
промптов поверх канона 52d. (1) **Расхардкод примеров:** копируемые frontmatter-примеры всех 6
|
||||
промптов несут плейсхолдеры `created_at: <YYYY-MM-DD>` / `model_used: <resolve ORCH-41>` +
|
||||
врезку «подставь `date +%F` и модель из конфига, не копируй буквально» (литерал `claude-opus-4-8`
|
||||
оставлен лишь справкой в таблице полей). (2) **Секция `<escalation>`** добавлена developer/
|
||||
reviewer/tester (после `</success_criteria>`, не нарушая порядок 5 обязательных секций):
|
||||
developer → `back-to:analysis`, tester → `back-to:dev`, reviewer → `REQUEST_CHANGES`.
|
||||
(3) **developer:** убран ручной `git rebase origin/main` — свежесть базы держит движок
|
||||
(serial-gate ORCH-088 + `auto_rebase_onto_main` под merge-lease), а ручной rebase конфликтовал с
|
||||
собственным запретом force-push (ADR-001 D1); «PR>1500 → разбивай» переформулирован в эскалацию
|
||||
на уровне задач. (4) **tester** обогащён worktree-путём, smoke-проверкой блока `serial_gate` и
|
||||
требованием покрытия каждого TC. (5) **reviewer:** удалена мёртвая строка «тот же экземпляр
|
||||
Developer». (6) **Языковое исключение (ADR-001 D2, нормативно):** `deployer.md` сознательно
|
||||
остаётся на **английском** (5 ru + 1 en) — самый safety-critical промпт, минимизация
|
||||
регресс-поверхности у байт-точных verdict-ключей/команд; критичные self-hosting-запреты подняты в
|
||||
видную рамку в начале `<context>`. Это **документированное исключение**, не дрейф: будущему агенту
|
||||
НЕ «чинить» язык deployer вслепую. Машинные verdict-ключи и канон 52d — байт-в-байт; анти-регресс —
|
||||
расширенный `tests/test_agent_prompts_canon.py` (ORCH-092 TC-01…TC-08). ADR:
|
||||
`docs/work-items/ORCH-092/06-adr/ADR-001-developer-rebase-and-deployer-language.md`.
|
||||
|
||||
#### Слой трассировки: стандарт маркеров `ORCH-NNN` (ORCH-078, 52e — слой 4 эпика 52)
|
||||
**Слой 4 (трассировка).** Маркеры `ORCH-NNN`/`ET-NNN` в коде (де-факто **51 уникальный** в `src/`)
|
||||
|
||||
7
docs/work-items/ORCH-092/00-business-request.md
Normal file
7
docs/work-items/ORCH-092/00-business-request.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# Business Request: Промпт-аудит 6 агентов: расхардкод дат/модели + сверка гейтов + escalation + чистка мёртвых инструкций
|
||||
|
||||
Work Item ID: ORCH-092
|
||||
|
||||
## Description
|
||||
|
||||
TBD
|
||||
169
docs/work-items/ORCH-092/01-brd.md
Normal file
169
docs/work-items/ORCH-092/01-brd.md
Normal file
@@ -0,0 +1,169 @@
|
||||
---
|
||||
work_item: ORCH-092
|
||||
stage: analysis
|
||||
author_agent: analyst
|
||||
status: ready-for-review
|
||||
created_at: 2026-06-09
|
||||
model_used: claude-opus-4-8
|
||||
---
|
||||
|
||||
# 01 — BRD (бизнес-требования): ORCH-092 — Промпт-аудит 6 агентов (расхардкод дат/модели, сверка гейтов, escalation, чистка мёртвых инструкций)
|
||||
|
||||
Work Item: **ORCH-092** · Repo: **orchestrator** · Стадия: analysis
|
||||
|
||||
## 1. Бизнес-контекст и проблема
|
||||
|
||||
ORCH-092 — **эпилог эпика ORCH-52** (канонизация системных промптов). После слоёв 52d
|
||||
(XML-канон) и 52e (трассировка маркеров) системный аудит 6 промптов (`.openclaw/agents/*.md`)
|
||||
выявил класс системных дефектов, способных приводить к **дрейфу и багам** в self-hosting-конвейере:
|
||||
|
||||
- **Хардкод даты в примерах.** Во всех 6 промптах пример frontmatter содержит жёсткое
|
||||
`created_at: 2026-06-09`. Исполняющая модель — литеральный Opus 4.8: пример сильнее
|
||||
инструкции «текущая дата». Риск — модель **копирует дату буквально** → все документы
|
||||
всех задач получают одну и ту же дату, метаданные перестают отражать реальность.
|
||||
- **Хардкод модели в примерах.** Пример несёт `model_used: claude-opus-4-8`. Если включат
|
||||
model-routing (ORCH-41), промпты начнут **врать** про использованную модель — ровно та
|
||||
боль, которую слой 52f чинил для README «Известные ограничения».
|
||||
- **Несверённые имена гейтов.** Промпты называют имена QG-функций (`check_*`); при дрейфе
|
||||
кода имя в промпте может разойтись с реальным реестром `QG_CHECKS`. *(Сверка кодом в рамках
|
||||
анализа показала: текущие имена корректны — см. §6, допущение A-1; задача — закрепить сверку
|
||||
как воспроизводимую проверку, а не «починить несуществующий баг».)*
|
||||
- **Логические нестыковки в developer.md.** Инструкция «PR > 1500 строк → разбивай на меньшие
|
||||
PR» **физически невыполнима**: конвейер = 1 задача = 1 ветка = 1 PR, разбить внутри стадии
|
||||
нельзя. Инструкция `git rebase origin/main` в начале алгоритма **дублирует/конфликтует** с
|
||||
автоматикой движка (serial-gate ORCH-088 режет ветку от свежего `origin/main`;
|
||||
`auto_rebase_onto_main` ORCH-026 делает pre-merge rebase сам).
|
||||
- **Размазанная эскалация.** Секцию `<escalation>` имеет только `architect.md`. У developer /
|
||||
reviewer / tester маршруты эскалации (негодное ТЗ, FAIL, REQUEST_CHANGES) растворены в
|
||||
`<constraints>` — нет единой видной точки «куда эскалировать при затыке».
|
||||
- **Консистентность/качество.** `deployer.md` (самый большой, ~9.6 KB, на английском) рискует
|
||||
«утопить» критичный self-hosting-запрет «НЕ рестартить 8500». `tester.md` (самый бедный,
|
||||
~4.7 KB) не фиксирует worktree-путь (были гонки checkout), не проверяет serial_gate-блок и
|
||||
не требует покрытия ТЗ. `reviewer.md` содержит мёртвую инструкцию про «тот же экземпляр
|
||||
Developer» (в конвейере reviewer всегда отдельный agent-run).
|
||||
|
||||
**Это docs/prompts-only задача.** Код (`src/**`, `STAGE_TRANSITIONS`, `QG_CHECKS`, схема БД)
|
||||
**не трогается**. Промпт `cat`-ается из worktree в момент запуска агента, поэтому новые
|
||||
промпты вступают в силу на следующем worktree от `main` **без рестарта прод-контейнера** —
|
||||
что критично для self-hosting (рестарт 8500 встаёт конвейер всех проектов).
|
||||
|
||||
## 2. Объём (scope)
|
||||
|
||||
### В объёме
|
||||
- Правка 6 промптов `.openclaw/agents/{analyst,architect,developer,reviewer,tester,deployer}.md`:
|
||||
расхардкод даты (P0-1) и модели (P0-2) в **копируемых примерах**; сверка имён гейтов (P0-3);
|
||||
переформулировка «PR>1500» в эскалацию (P1-1); добавление `<escalation>` в developer/reviewer/
|
||||
tester (P1-3); рамка критичных запретов в deployer (P2-1); обогащение tester (P2-3); удаление
|
||||
мёртвой инструкции reviewer (P2-4).
|
||||
- **Решения, требующие архитектора** (формализованы как открытые в §6, решаются в `06-adr/`):
|
||||
P1-2 (нужен ли ручной rebase у developer при наличной автоматике), P2-2 (язык deployer:
|
||||
унификация en→ru ИЛИ явно зафиксированное исключение).
|
||||
- Обновление обзорной документации: `CLAUDE.md`, `docs/architecture/README.md` (при
|
||||
необходимости), `CHANGELOG.md`, ADR work item, и **новые/обновлённые структурные тесты**
|
||||
`tests/test_agent_prompts_canon.py` (анти-регресс новых инвариантов).
|
||||
|
||||
### Вне объёма
|
||||
- ❌ Любая правка `src/**`, `STAGE_TRANSITIONS`, `QG_CHECKS`, `check_*`, схемы БД.
|
||||
- ❌ Изменение машинных verdict-ключей (`verdict:` / `result:` / `staging_status:` /
|
||||
`deploy_status:` / `security_status:`) — байт-в-байт неприкосновенны.
|
||||
- ❌ Слом XML-канона 52d (5 обязательных секций в нормативном порядке), 52c-схемы (6 полей),
|
||||
правила трассировки 52e.
|
||||
- ❌ Включение enforcement frontmatter (`frontmatter_validation_strict` остаётся `False`).
|
||||
- ❌ Артефакты других work item.
|
||||
|
||||
## 3. Заинтересованные стороны
|
||||
- **Заказчик / приёмка:** Owner (Слава) — BRD-гейт ручной; решения по P1-2/P2-2.
|
||||
- **Затрагиваются:** все 6 ролей конвейера (исполняют обновлённые промпты), все проекты в
|
||||
общем инстансе (self-hosting), сопровождающие агенты.
|
||||
- **Принимает архитектурные развилки:** архитектор (стадия architecture, `06-adr/`).
|
||||
|
||||
## 4. Бизнес-требования (BR)
|
||||
|
||||
- **BR-1 (P0-1)** — В копируемых примерах frontmatter **всех 6** промптов `created_at` —
|
||||
плейсхолдер `<YYYY-MM-DD>` (НЕ конкретная дата), сопровождённый явной инструкцией: подставить
|
||||
фактическую текущую дату (`date +%F`), НЕ копировать из примера буквально.
|
||||
- **BR-2 (P0-2)** — В копируемых примерах **всех 6** промптов `model_used` — плейсхолдер/резолв
|
||||
(`<resolve ORCH-41>`, НЕ литеральный `claude-opus-4-8`), с оговоркой подставить фактическую
|
||||
модель из конфига. Факт «сейчас `claude-opus-4-8`» допускается как **справка вне копируемого
|
||||
блока** (например в таблице полей), но не как литерал в примере.
|
||||
- **BR-3 (P0-3)** — Все имена гейтов/QG-функций, упомянутые в промптах, **сверены** с реальным
|
||||
реестром `QG_CHECKS` (`src/qg/checks.py`). Реальные несовпадения (если бы нашлись) исправлены;
|
||||
**ложные подозрения не трогаются** (`check_tests_passed` верен). Сверка закреплена
|
||||
воспроизводимым тестом.
|
||||
- **BR-4 (P1-1)** — Инструкция developer «PR > 1500 строк → разбивай на меньшие PR» заменена на
|
||||
**эскалацию**: PR слишком большой → флагировать/эскалировать (задача слишком крупная, нужна
|
||||
декомпозиция **на уровне задач**, не PR).
|
||||
- **BR-5 (P1-3)** — developer / reviewer / tester получают явную секцию `<escalation>` с чёткими
|
||||
маршрутами: developer → `back-to:analysis` при негодном ТЗ; tester → `back-to:dev` при FAIL;
|
||||
reviewer → `REQUEST_CHANGES`. (Существующая `<escalation>` у architect — эталон формата.)
|
||||
- **BR-6 (P2-1)** — Критичные self-hosting-запреты deployer (прежде всего «НЕ рестартить
|
||||
прод 8500») вынесены в **видную рамку в начале** промпта, чтобы не утонуть в объёме.
|
||||
- **BR-7 (P2-3)** — tester обогащён: явный worktree-путь (ветка vs `/repos` — устранить гонки
|
||||
checkout); smoke добавляет проверку блока `serial_gate` в `/queue` (ORCH-088); `success_criteria`
|
||||
упоминает **покрытие ТЗ** (каждый TC из `04-test-plan.yaml`), не только «файл записан».
|
||||
- **BR-8 (P2-4)** — Мёртвая инструкция reviewer «не апрувь PR от того же экземпляра Developer»
|
||||
удалена (защита от несуществующего кейса — reviewer всегда отдельный agent-run), при сохранении
|
||||
всех живых инвариантов оси документации.
|
||||
- **BR-9 (P1-2, решение архитектора)** — Зафиксировать в ADR: должен ли developer выполнять
|
||||
ручной `git rebase origin/main`, или это полностью делает движок (serial-gate + auto_rebase).
|
||||
Промпт приводится в соответствие с принятым решением (убрать/смягчить/оставить с пояснением).
|
||||
- **BR-10 (P2-2, решение архитектора)** — Зафиксировать в ADR язык deployer: унифицировать
|
||||
(en→ru) ЛИБО явно задокументировать исключение («deployer — en, т.к. критичные команды/
|
||||
контракты на en»). При любом исходе machine-verdict ключи и shell-команды **не ломаются**.
|
||||
- **BR-11 (документация)** — Обновлены `CLAUDE.md` / `README` / ADR / `CHANGELOG.md`
|
||||
(golden source = код); добавлены/обновлены структурные тесты анти-регресса новых инвариантов.
|
||||
|
||||
## 5. Нефункциональные требования (NFR)
|
||||
|
||||
- **NFR-1 (анти-регресс, критично)** — verdict-ключи `verdict:` / `result:` / `staging_status:` /
|
||||
`deploy_status:` / `security_status:` сохраняются **байт-в-байт** (имя/регистр/значения);
|
||||
XML-канон 52d (5 секций, нормативный порядок), 52c-схема (6 полей), правило трассировки 52e —
|
||||
сохранены. `tests/test_agent_prompts_canon.py` и `tests/test_agent_frontmatter_no_model.py` —
|
||||
**зелёные**.
|
||||
- **NFR-2 (self-hosting безопасность)** — Изменение docs/prompts-only: `src/**` не тронут,
|
||||
прод-контейнер 8500 **не перезапускается**. Новые промпты применяются на следующем worktree
|
||||
от `main` без прод-рестарта.
|
||||
- **NFR-3 (обратимость)** — Все правки текстовые и ревертируемы одним PR; нет миграций, нет
|
||||
изменения схемы/состояния.
|
||||
- **NFR-4 (консистентность канона)** — Все правки соблюдают канон Anthropic (запреты «❌ X →
|
||||
✅ Y», секции в нормативном порядке); новая секция `<escalation>` размещается так, чтобы не
|
||||
нарушать порядок 5 обязательных секций (после `</output_format>`, как у architect).
|
||||
- **NFR-5 (отсутствие enforcement)** — `frontmatter_validation_strict` остаётся `False`;
|
||||
плейсхолдеры в примерах не вызывают hard-fail валидатора (warning-only).
|
||||
|
||||
## 6. Допущения и ограничения
|
||||
|
||||
- **A-1 (сверено кодом):** реестр `QG_CHECKS` (`src/qg/checks.py`) содержит:
|
||||
`check_analysis_complete`, `check_analysis_approved`, `check_architecture_done`,
|
||||
`check_ci_green`, `check_review_approved`, `check_tests_passed`, `check_reviewer_verdict`,
|
||||
`check_deploy_status`, `check_staging_status`, `check_branch_mergeable`, `check_security_gate`,
|
||||
`check_staging_image_fresh` (+ `check_tests_local` — DEPRECATED). Имена гейтов в промптах
|
||||
(`check_ci_green`, `check_reviewer_verdict`, `check_tests_passed`, `check_deploy_status`,
|
||||
`check_staging_status`, `check_security_gate`) **совпадают**. Реальных несовпадений на момент
|
||||
анализа НЕТ → BR-3 = «закрепить сверку», а не «исправить».
|
||||
- **A-2 (сверено кодом, основание для BR-9):** `auto_rebase_onto_main` (`src/merge_gate.py`)
|
||||
вызывается автоматически в `check_branch_mergeable` (`src/qg/checks.py`) при
|
||||
`premerge_rebase_always=True` (дефолт), а serial-gate (ORCH-088) откладывает срез ветки на
|
||||
свежий `origin/main`. Ручной rebase developer пересекается с этой автоматикой → требует решения
|
||||
архитектора (не менять вслепую).
|
||||
- **A-3:** Канон-тест проверяет **наличие имён полей** `created_at`/`model_used` и **литеральные
|
||||
строки** `author_agent: <role>` / `stage: <stage>` в примере — плейсхолдеры даты/модели этого
|
||||
не нарушают. Ни один тест не утверждает литерал `claude-opus-4-8` внутри промптов.
|
||||
- **Ограничение:** P1-2 и P2-2 — зона архитектора; analyst фиксирует факты и требование-решение,
|
||||
но НЕ принимает решение и НЕ правит вслепую.
|
||||
|
||||
## 7. Критерии успеха
|
||||
|
||||
Аудит-правки внесены во все 6 промптов согласно BR-1…BR-8; архитектурные развилки BR-9/BR-10
|
||||
решены в ADR и отражены в промптах; документация и анти-регресс-тесты обновлены (BR-11);
|
||||
анти-регресс NFR-1 соблюдён (verdict-ключи и канон не сломаны, целевые тесты зелёные).
|
||||
Детальные PASS/FAIL — `03-acceptance-criteria.md`.
|
||||
|
||||
## 8. Риски
|
||||
|
||||
- Случайный слом verdict-ключа/канона при массовой текстовой правке → митигируется
|
||||
структурными тестами (NFR-1).
|
||||
- Плейсхолдер `<YYYY-MM-DD>` / `<resolve ORCH-41>` сам по себе мог бы быть скопирован буквально —
|
||||
митигируется **явной инструкцией** «подставь фактическое, НЕ копируй».
|
||||
- Принятие архитектурного решения (P1-2/P2-2) не аналитиком — митигируется явным выносом в `06-adr/`.
|
||||
- Детальная карта рисков — `10-tech-risks.md` (заполняет архитектор).
|
||||
159
docs/work-items/ORCH-092/02-trz.md
Normal file
159
docs/work-items/ORCH-092/02-trz.md
Normal file
@@ -0,0 +1,159 @@
|
||||
---
|
||||
work_item: ORCH-092
|
||||
stage: analysis
|
||||
author_agent: analyst
|
||||
status: ready-for-review
|
||||
created_at: 2026-06-09
|
||||
model_used: claude-opus-4-8
|
||||
---
|
||||
|
||||
# 02 — ТЗ (TRZ): ORCH-092 — Промпт-аудит 6 агентов
|
||||
|
||||
Work Item: **ORCH-092** · Repo: **orchestrator** · Стадия: analysis
|
||||
|
||||
> ТЗ описывает **конкретные изменения к реализации**, выведенные из BRD и фактического кода.
|
||||
> Архитектурное обоснование/решения (P1-2 rebase, P2-2 язык deployer) — задача архитектора (`06-adr/`).
|
||||
|
||||
## 1. Сводка изменения
|
||||
|
||||
Точечная правка 6 системных промптов `.openclaw/agents/*.md` + обзорной документации + структурных
|
||||
анти-регресс-тестов. **Код приложения не трогается** (docs/prompts-only). Цель — устранить класс
|
||||
дефектов промптов (хардкод даты/модели, размазанная эскалация, нереализуемые/конфликтующие
|
||||
инструкции, мёртвые инструкции, недообогащённые промпты), сохранив канон 52d/52c/52e и
|
||||
машинные verdict-ключи байт-в-байт.
|
||||
|
||||
## 2. Задействованные модули / пути
|
||||
|
||||
| Путь | Действие |
|
||||
|------|----------|
|
||||
| `.openclaw/agents/analyst.md` | изменить — расхардкод `created_at`/`model_used` в примере (FR-1, FR-2) |
|
||||
| `.openclaw/agents/architect.md` | изменить — расхардкод `created_at`/`model_used` в примере (FR-1, FR-2) |
|
||||
| `.openclaw/agents/developer.md` | изменить — расхардкод (FR-1/2); «PR>1500»→эскалация (FR-4); `<escalation>` (FR-5); rebase по решению ADR (FR-9) |
|
||||
| `.openclaw/agents/reviewer.md` | изменить — расхардкод (FR-1/2); `<escalation>` (FR-5); удалить мёртвую инструкцию (FR-8) |
|
||||
| `.openclaw/agents/tester.md` | изменить — расхардкод (FR-1/2); `<escalation>` (FR-5); worktree-путь + serial_gate smoke + покрытие ТЗ (FR-7) |
|
||||
| `.openclaw/agents/deployer.md` | изменить — расхардкод (FR-1/2); рамка критичных запретов (FR-6); язык по решению ADR (FR-10) |
|
||||
| `tests/test_agent_prompts_canon.py` | изменить — добавить TC анти-регресса новых инвариантов (FR-11) |
|
||||
| `CLAUDE.md` | изменить — отразить ORCH-092 (норматив промптов), при необходимости |
|
||||
| `docs/architecture/README.md` | изменить — when-applicable (если затрагивается обзорная карта) |
|
||||
| `CHANGELOG.md` | изменить — запись под `## [Unreleased]` |
|
||||
| `docs/work-items/ORCH-092/06-adr/ADR-001-*.md` | создать (архитектор) — решения P1-2, P2-2 |
|
||||
| `src/**`, `src/qg/checks.py`, `STAGE_TRANSITIONS`, `QG_CHECKS`, схема БД | **НЕ трогать** |
|
||||
|
||||
## 3. Функциональные требования
|
||||
|
||||
### FR-1 — Расхардкод `created_at` в примерах (BR-1, P0-1)
|
||||
Во **всех 6** промптах в копируемом примере frontmatter заменить `created_at: 2026-06-09` на
|
||||
плейсхолдер `created_at: <YYYY-MM-DD>`. Рядом — явная инструкция (в `<output_format>`): «подставь
|
||||
фактическую текущую дату (`date +%F`); НЕ копируй дату из примера буквально». Инвариант: имя поля
|
||||
`created_at` остаётся (канон-тест проверяет наличие имени).
|
||||
|
||||
### FR-2 — Расхардкод `model_used` в примерах (BR-2, P0-2)
|
||||
Во **всех 6** промптах в копируемом примере заменить `model_used: claude-opus-4-8` на
|
||||
`model_used: <resolve ORCH-41>` + оговорку «подставь фактическую модель из конфига, не копируй
|
||||
буквально». Факт «сейчас `claude-opus-4-8`» допустимо оставить как **справку в таблице полей**
|
||||
(вне копируемого блока). Инвариант: имя поля `model_used` остаётся.
|
||||
|
||||
### FR-3 — Сверка имён гейтов с `QG_CHECKS` (BR-3, P0-3)
|
||||
Пройти по каждому промпту, сверить все упомянутые `check_*`/имена QG-функций с реальным реестром
|
||||
`QG_CHECKS` в `src/qg/checks.py`. **Установленный факт:** на момент анализа несовпадений НЕТ
|
||||
(`check_ci_green`, `check_reviewer_verdict`, `check_tests_passed`, `check_deploy_status`,
|
||||
`check_staging_status`, `check_security_gate` — все присутствуют в реестре; `check_tests_passed`
|
||||
верен — подозрение было ложным). Требование: **исправлять только реально несовпадающие** имена
|
||||
(не выдумывать); закрепить сверку воспроизводимым тестом (FR-11/TC-03).
|
||||
|
||||
### FR-4 — «PR>1500» → эскалация (BR-4, P1-1)
|
||||
В `developer.md` (секция `<constraints>`) заменить запрет «❌ Не делай PR > 1500 строк без
|
||||
декомпозиции → ✅ разбивай на меньшие PR» на эскалацию: PR оказался слишком большим → **флагируй/
|
||||
эскалируй** (задача слишком крупная, нужна декомпозиция **на уровне задач**, не внутри стадии;
|
||||
1 задача = 1 ветка = 1 PR). Инвариант FR-6-анти-регресс: маркер «свой PR» («не мержи свой PR»)
|
||||
сохраняется отдельно.
|
||||
|
||||
### FR-5 — Секция `<escalation>` в developer/reviewer/tester (BR-5, P1-3)
|
||||
Добавить секцию `<escalation>` (формат — как у `architect.md`, **после** `</success_criteria>`,
|
||||
чтобы не нарушать нормативный порядок 5 обязательных секций):
|
||||
- **developer:** негодное/нереализуемое ТЗ → вернуть в Анализ (`back-to:analysis`); нужна новая
|
||||
архитектурная развилка → эскалация к архитектору.
|
||||
- **tester:** обоснованный FAIL → откат на development (`back-to:dev`); смок-сбой инфраструктуры →
|
||||
зафиксировать как FAIL с диагностикой.
|
||||
- **reviewer:** любой P0/P1 → `REQUEST_CHANGES` (единая точка); неоднозначность требований →
|
||||
finding со ссылкой на ТЗ/ADR.
|
||||
|
||||
Эскалационные строки консолидируют (не дублируют слепо) то, что было размазано по `<constraints>`.
|
||||
|
||||
### FR-6 — Рамка критичных запретов в deployer (BR-6, P2-1)
|
||||
В `deployer.md` вынести самые критичные self-hosting-запреты в **видную рамку в начале** (сразу
|
||||
после frontmatter / в начале `<context>`), как минимум: «**NEVER restart the prod `orchestrator`
|
||||
(8500) container**». Существующий blockquote усилить/поднять. Инвариант анти-регресса: маркеры
|
||||
`docker exec orchestrator-staging`, `pr_already_merged`, `8500`, `INFRA-WAIVED` сохраняются.
|
||||
|
||||
### FR-7 — Обогащение tester (BR-7, P2-3)
|
||||
В `tester.md`:
|
||||
- **worktree-путь:** явно указать, что тесты гоняются в worktree ветки задачи (а не в общем
|
||||
`/repos/orchestrator`), чтобы исключить гонки checkout; зафиксировать корректный путь алгоритма.
|
||||
- **serial_gate smoke:** в smoke `/queue` добавить проверку наличия блока `serial_gate`
|
||||
(ORCH-088) в ответе.
|
||||
- **покрытие ТЗ:** в `<success_criteria>` добавить, что готовность = каждый TC из
|
||||
`04-test-plan.yaml` выполнен и сопоставлен с `03-acceptance-criteria.md`, а не только «файл
|
||||
записан». Инвариант анти-регресса: маркеры `pytest`, `/health`, `/status`, `/queue` сохраняются.
|
||||
|
||||
### FR-8 — Удаление мёртвой инструкции reviewer (BR-8, P2-4)
|
||||
В `reviewer.md` удалить строку-запрет «❌ Не апрувь PR от того же экземпляра Developer →
|
||||
✅ выноси независимый вердикт» (защита от несуществующего кейса — reviewer всегда отдельный
|
||||
agent-run). Перед удалением убедиться, что ни один тест на неё не опирается (анти-регресс reviewer
|
||||
держит только `REQUEST_CHANGES` и «НЕ обновлена» — они сохраняются). Ось «независимый вердикт по
|
||||
4 осям» остаётся выражена через `<task>`/`<thinking>`.
|
||||
|
||||
### FR-9 — Ручной rebase developer по решению ADR (BR-9, P1-2) — **зона архитектора**
|
||||
Установленный факт (A-2): движок уже выполняет rebase автоматически (`auto_rebase_onto_main` в
|
||||
`check_branch_mergeable`, `premerge_rebase_always=True`; serial-gate режет ветку от свежего
|
||||
`origin/main`). Требование: архитектор в ADR решает — убрать/смягчить/оставить-с-пояснением шаг
|
||||
`git fetch origin && git rebase origin/main` в алгоритме developer; developer.md приводится в
|
||||
соответствие. БЕЗ ADR-решения промпт-строку rebase **не менять**.
|
||||
|
||||
### FR-10 — Язык deployer по решению ADR (BR-10, P2-2) — **зона архитектора**
|
||||
Архитектор решает: унифицировать deployer на русский (как остальные 5) ЛИБО явно задокументировать
|
||||
исключение («deployer — en по причине критичных команд/контрактов»). Инвариант: при любом исходе
|
||||
machine-verdict ключи (`staging_status:`/`deploy_status:`/`security_status:` + значения
|
||||
SUCCESS/FAILED/PASS/FAIL) и shell-команды НЕ переводятся/не ломаются. БЕЗ ADR-решения язык
|
||||
**не менять**.
|
||||
|
||||
### FR-11 — Анти-регресс-тесты новых инвариантов (BR-11)
|
||||
В `tests/test_agent_prompts_canon.py` (pure-text, без импорта `src/`, кроме TC-03 сверки реестра)
|
||||
добавить проверки: плейсхолдеры даты/модели в примерах (нет литерала `created_at: 2026-`/
|
||||
`model_used: claude-opus-4-8` в копируемом блоке); наличие `<escalation>` у developer/reviewer/
|
||||
tester; отсутствие удалённой мёртвой строки reviewer; обогащение tester (serial_gate/worktree/
|
||||
покрытие ТЗ); рамка в deployer. Существующие проверки (5 секций, 6 полей, verdict-ключи,
|
||||
анти-регресс-маркеры) остаются зелёными.
|
||||
|
||||
## 4. Изменения API
|
||||
Нет. Эндпоинты не добавляются и не меняются.
|
||||
|
||||
## 5. Изменения схемы БД
|
||||
Нет. Схема БД не трогается.
|
||||
|
||||
## 6. Требования к новым/изменённым QG checks
|
||||
Нет. `QG_CHECKS` / `check_*` / `STAGE_TRANSITIONS` **не трогаются**. Имена гейтов в промптах лишь
|
||||
**сверяются** с существующим реестром (FR-3). `frontmatter_validation_strict` остаётся `False`
|
||||
(enforcement не включается).
|
||||
|
||||
## 7. Совместимость / регресс
|
||||
|
||||
- **Машинные verdict-ключи** — байт-в-байт: `verdict:` (APPROVED|REQUEST_CHANGES), `result:`
|
||||
(PASS|FAIL), `staging_status:`/`deploy_status:` (SUCCESS|FAILED), `security_status:` (PASS|FAIL).
|
||||
Гарант — `test_machine_verdict_keys_preserved_exact_case`.
|
||||
- **Канон 52d/52c/52e** — 5 секций в нормативном порядке (context→task→deliverables→constraints→
|
||||
output_format), 6 полей схемы, правило трассировки. `<escalation>` добавляется как 6-я
|
||||
необязательная секция ПОСЛЕ `</output_format>`/`</success_criteria>` — порядок обязательной
|
||||
пятёрки не нарушается. Гаранты — `test_five_xml_sections_present`,
|
||||
`test_six_schema_field_names_present`, `test_schema_pins_role_specific_author_and_stage`.
|
||||
- **Frontmatter определения агента** — верхний `---`-блок (name/description, без `model:`)
|
||||
не трогается; примеры схемы живут в теле. Гарант — `tests/test_agent_frontmatter_no_model.py`.
|
||||
- **Область раската / обратимость** — docs/prompts-only; вступает в силу на следующем worktree
|
||||
от `main`; прод-рестарт НЕ требуется; полностью ревертируемо одним PR.
|
||||
- **Полный регресс** `pytest tests/ -q` остаётся зелёным.
|
||||
|
||||
## 8. Артефакты pipeline, создаваемые/обновляемые этой задачей
|
||||
- Анализ (этот пакет): `01-brd.md`, `02-trz.md`, `03-acceptance-criteria.md`, `04-test-plan.yaml`.
|
||||
- Архитектура: `06-adr/ADR-001-*.md` (решения P1-2 FR-9, P2-2 FR-10), при сквозном эффекте —
|
||||
возможный `10-tech-risks.md`.
|
||||
- Разработка: 6 промптов + `tests/test_agent_prompts_canon.py` + `CLAUDE.md`/README/`CHANGELOG.md`.
|
||||
151
docs/work-items/ORCH-092/03-acceptance-criteria.md
Normal file
151
docs/work-items/ORCH-092/03-acceptance-criteria.md
Normal file
@@ -0,0 +1,151 @@
|
||||
---
|
||||
work_item: ORCH-092
|
||||
stage: analysis
|
||||
author_agent: analyst
|
||||
status: ready-for-review
|
||||
created_at: 2026-06-09
|
||||
model_used: claude-opus-4-8
|
||||
---
|
||||
|
||||
# 03 — Критерии приёмки (Acceptance Criteria): ORCH-092 — Промпт-аудит 6 агентов
|
||||
|
||||
Work Item: **ORCH-092** · Repo: **orchestrator** · Стадия: analysis
|
||||
|
||||
Формат: каждый критерий имеет **PASS** (что должно быть истинно для приёмки) и **FAIL**
|
||||
(что считается провалом). Reviewer/tester проверяют буквально по файлам репозитория
|
||||
(`.openclaw/agents/*.md`, `tests/`, `docs/`).
|
||||
|
||||
---
|
||||
|
||||
## AC-1 — `created_at` в примерах всех 6 промптов — плейсхолдер (P0-1, BR-1, FR-1)
|
||||
|
||||
**Условие:** В копируемом примере frontmatter каждого из 6 промптов дата не захардкожена.
|
||||
- **PASS:** В `analyst/architect/developer/reviewer/tester/deployer.md` пример несёт
|
||||
`created_at: <YYYY-MM-DD>` (плейсхолдер); рядом — явная инструкция «подставь фактическую дату
|
||||
(`date +%F`), НЕ копируй из примера». Литерала `created_at: 2026-06-09` (или иной конкретной
|
||||
даты) в **копируемом блоке** нет.
|
||||
- **FAIL:** Хотя бы один промпт оставляет конкретную дату в примере, или отсутствует инструкция
|
||||
«не копируй буквально».
|
||||
|
||||
---
|
||||
|
||||
## AC-2 — `model_used` в примерах — плейсхолдер/резолв (P0-2, BR-2, FR-2)
|
||||
|
||||
**Условие:** В копируемом примере frontmatter каждого из 6 промптов модель не захардкожена.
|
||||
- **PASS:** Пример несёт `model_used: <resolve ORCH-41>` (или эквивалентный плейсхолдер) +
|
||||
оговорку «подставь фактическую модель из конфига». Литерал `claude-opus-4-8` в **копируемом
|
||||
блоке** отсутствует (допускается как справка в таблице полей вне блока).
|
||||
- **FAIL:** Хотя бы один промпт оставляет `model_used: claude-opus-4-8` в копируемом примере,
|
||||
или нет оговорки про подстановку.
|
||||
|
||||
---
|
||||
|
||||
## AC-3 — Имена гейтов сверены с `QG_CHECKS` (P0-3, BR-3, FR-3)
|
||||
|
||||
**Условие:** Все `check_*`/имена QG-функций в промптах соответствуют реестру `QG_CHECKS`.
|
||||
- **PASS:** Каждое имя гейта, встречающееся в 6 промптах, присутствует ключом в
|
||||
`QG_CHECKS` (`src/qg/checks.py`). Реальные несовпадения (если бы были) исправлены; ложные
|
||||
(напр. `check_tests_passed` — верен) НЕ тронуты. Сверка закреплена тестом (см. AC-10/TC-03).
|
||||
- **FAIL:** В промпте остаётся имя гейта, которого нет в `QG_CHECKS`; ИЛИ исправлено верное имя
|
||||
«вслепую» (придуманная замена).
|
||||
|
||||
---
|
||||
|
||||
## AC-4 — developer: «PR>1500» → эскалация (P1-1, BR-4, FR-4)
|
||||
|
||||
**Условие:** Нереализуемая инструкция о разбиении PR переформулирована.
|
||||
- **PASS:** `developer.md` НЕ содержит инструкции «разбивай на меньшие PR»; вместо неё —
|
||||
эскалация: слишком большой PR → флагировать/эскалировать (нужна декомпозиция на уровне задач,
|
||||
1 задача = 1 ветка = 1 PR). Маркер «свой PR» («не мержи свой PR») сохранён.
|
||||
- **FAIL:** Старая формулировка «разбивай на меньшие PR» осталась; ИЛИ при правке удалён маркер
|
||||
«свой PR».
|
||||
|
||||
---
|
||||
|
||||
## AC-5 — `<escalation>` в developer/reviewer/tester (P1-3, BR-5, FR-5)
|
||||
|
||||
**Условие:** Три промпта получили секцию `<escalation>` с чёткими маршрутами.
|
||||
- **PASS:** `developer.md`, `reviewer.md`, `tester.md` содержат `<escalation>`…`</escalation>`
|
||||
(после `</success_criteria>`), с маршрутами: developer → `back-to:analysis`; tester →
|
||||
`back-to:dev` (при FAIL); reviewer → `REQUEST_CHANGES`. Нормативный порядок 5 обязательных
|
||||
секций НЕ нарушен.
|
||||
- **FAIL:** Хотя бы у одного из трёх нет `<escalation>`; ИЛИ её добавление сломало порядок/
|
||||
наличие 5 обязательных секций.
|
||||
|
||||
---
|
||||
|
||||
## AC-6 — deployer: рамка запретов + решённый язык (P2-1/P2-2, BR-6/BR-10, FR-6/FR-10)
|
||||
|
||||
**Условие:** Критичные self-hosting-запреты подняты в видную рамку; вопрос языка решён.
|
||||
- **PASS:** `deployer.md` несёт **в начале** видную рамку с критичным запретом «NEVER restart
|
||||
prod 8500». Язык deployer решён архитектором в `06-adr/`: либо унифицирован на ru, либо
|
||||
зафиксировано явное исключение (en) с обоснованием. Маркеры `docker exec orchestrator-staging`,
|
||||
`pr_already_merged`, `8500`, `INFRA-WAIVED` сохранены; verdict-ключи и команды не сломаны.
|
||||
- **FAIL:** Критичный запрет не выделен/утоплен в тексте; ИЛИ язык не решён (нет ADR-решения);
|
||||
ИЛИ потерян анти-регресс-маркер / сломан verdict-ключ при переводе.
|
||||
|
||||
---
|
||||
|
||||
## AC-7 — tester обогащён (P2-3, BR-7, FR-7)
|
||||
|
||||
**Условие:** tester получил worktree-путь, serial_gate smoke и покрытие ТЗ.
|
||||
- **PASS:** `tester.md`: (а) явно указывает worktree-путь ветки задачи (а не общий
|
||||
`/repos/orchestrator`) для прогона тестов; (б) smoke `/queue` проверяет наличие блока
|
||||
`serial_gate` (ORCH-088); (в) `<success_criteria>` требует покрытия каждого TC из
|
||||
`04-test-plan.yaml` (а не только «файл записан»). Маркеры `pytest`/`/health`/`/status`/`/queue`
|
||||
сохранены.
|
||||
- **FAIL:** Отсутствует любой из трёх пунктов; ИЛИ потерян анти-регресс-маркер tester.
|
||||
|
||||
---
|
||||
|
||||
## AC-8 — Удалена мёртвая инструкция reviewer (P2-4, BR-8, FR-8)
|
||||
|
||||
**Условие:** Строка про «тот же экземпляр Developer» удалена без потери живых инвариантов.
|
||||
- **PASS:** `reviewer.md` НЕ содержит «не апрувь PR от того же экземпляра Developer». Маркеры
|
||||
`REQUEST_CHANGES` и «НЕ обновлена», ось документации, ось трассировки (`TRACEABILITY.md`),
|
||||
ось обзорных доков (`Известные ограничения`, `ORCH-079`) сохранены.
|
||||
- **FAIL:** Мёртвая строка осталась; ИЛИ при удалении пострадал живой инвариант reviewer.
|
||||
|
||||
---
|
||||
|
||||
## AC-9 — АНТИ-РЕГРЕСС: verdict-ключи + канон + `src/` не тронут (NFR-1/2, BR-11)
|
||||
|
||||
**Условие:** Машинные контракты и канон сохранены, код не тронут.
|
||||
- **PASS:** verdict-ключи `verdict:`/`result:`/`staging_status:`/`deploy_status:`/
|
||||
`security_status:` (+ значения APPROVED/REQUEST_CHANGES/PASS/FAIL/SUCCESS/FAILED) — байт-в-байт.
|
||||
5 XML-секций в нормативном порядке + 6 полей 52c во всех 6 промптах. `src/**`,
|
||||
`STAGE_TRANSITIONS`, `QG_CHECKS`, схема БД — без изменений в diff. `git diff --stat` не содержит
|
||||
`src/`. `tests/test_agent_prompts_canon.py` и `tests/test_agent_frontmatter_no_model.py` —
|
||||
зелёные.
|
||||
- **FAIL:** Любой verdict-ключ изменён по имени/регистру/значению; нарушен порядок/наличие 5
|
||||
секций или 6 полей; есть правка `src/`; целевые тесты красные.
|
||||
|
||||
---
|
||||
|
||||
## AC-10 — Документация и тесты обновлены (BR-11, FR-11)
|
||||
|
||||
**Условие:** Обзорная документация и анти-регресс-тесты отражают изменение.
|
||||
- **PASS:** `CHANGELOG.md` несёт запись ORCH-092; `CLAUDE.md`/`docs/architecture/README.md`
|
||||
обновлены при необходимости; `06-adr/ADR-001-*.md` фиксирует решения P1-2/P2-2; новые
|
||||
структурные TC (плейсхолдеры даты/модели, `<escalation>`, удаление мёртвой строки, обогащение
|
||||
tester, рамка deployer, сверка гейтов) добавлены в `tests/test_agent_prompts_canon.py` и
|
||||
зелёные; полный `pytest tests/ -q` зелёный.
|
||||
- **FAIL:** Отсутствует ADR-решение P1-2/P2-2; нет записи в CHANGELOG; новые инварианты не
|
||||
покрыты тестом; регресс красный.
|
||||
|
||||
---
|
||||
|
||||
## Сводная матрица AC ↔ FR/BR
|
||||
|
||||
| AC | Покрывает |
|
||||
|----|-----------|
|
||||
| AC-1 | BR-1 / FR-1 |
|
||||
| AC-2 | BR-2 / FR-2 |
|
||||
| AC-3 | BR-3 / FR-3 |
|
||||
| AC-4 | BR-4 / FR-4 |
|
||||
| AC-5 | BR-5 / FR-5 |
|
||||
| AC-6 | BR-6 / BR-10 / FR-6 / FR-10 |
|
||||
| AC-7 | BR-7 / FR-7 |
|
||||
| AC-8 | BR-8 / FR-8 |
|
||||
| AC-9 | NFR-1 / NFR-2 / FR-9 (rebase по ADR без слома канона) |
|
||||
| AC-10 | BR-9 / BR-11 / FR-9 / FR-11 |
|
||||
89
docs/work-items/ORCH-092/04-test-plan.yaml
Normal file
89
docs/work-items/ORCH-092/04-test-plan.yaml
Normal file
@@ -0,0 +1,89 @@
|
||||
work_item: ORCH-092
|
||||
stage: analysis
|
||||
author_agent: analyst
|
||||
status: ready-for-review
|
||||
created_at: 2026-06-09
|
||||
model_used: claude-opus-4-8
|
||||
title: "Промпт-аудит 6 агентов: расхардкод дат/модели, сверка гейтов, escalation, чистка"
|
||||
framework: pytest
|
||||
scope: >
|
||||
Покрываются структурные (pure-text) инварианты 6 промптов .openclaw/agents/*.md после
|
||||
аудита ORCH-092, плюс анти-регресс канона 52d/52c/52e и машинных verdict-ключей. Вне
|
||||
покрытия: поведение src/ (НЕ трогается), запуск реальных агентов. Полный регресс tests/
|
||||
должен оставаться зелёным. Новые TC живут в tests/test_agent_prompts_canon.py; TC-03 —
|
||||
единственный с импортом QG_CHECKS (integration).
|
||||
|
||||
notes: >
|
||||
Все правки docs/prompts-only — src/ не изменяется, прод-контейнер 8500 не перезапускается.
|
||||
Регрессом считается: слом любого verdict-ключа (verdict:/result:/staging_status:/
|
||||
deploy_status:/security_status:) по имени/регистру/значению; нарушение порядка/наличия 5
|
||||
XML-секций или 6 полей 52c; красный test_agent_prompts_canon.py или
|
||||
test_agent_frontmatter_no_model.py. P1-2 (rebase) и P2-2 (язык deployer) фиксируются ADR —
|
||||
TC проверяют лишь, что промпт согласован и канон/ключи не сломаны.
|
||||
|
||||
tests:
|
||||
- id: TC-01
|
||||
type: unit
|
||||
description: "AC-1: во всех 6 промптах пример frontmatter использует created_at: <YYYY-MM-DD> (нет литерала конкретной даты в копируемом блоке) и несёт инструкцию 'не копируй дату буквально'."
|
||||
module: tests/test_agent_prompts_canon.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-02
|
||||
type: unit
|
||||
description: "AC-2: во всех 6 промптах пример несёт model_used: <resolve ORCH-41> (нет литерала claude-opus-4-8 в копируемом блоке) + оговорку про подстановку фактической модели."
|
||||
module: tests/test_agent_prompts_canon.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-03
|
||||
type: integration
|
||||
description: "AC-3: каждое имя check_* в 6 промптах присутствует ключом в QG_CHECKS (импорт src.qg.checks). check_tests_passed подтверждён валидным; нет имён вне реестра."
|
||||
module: tests/test_agent_prompts_canon.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-04
|
||||
type: unit
|
||||
description: "AC-4: developer.md не содержит 'разбивай на меньшие PR'; содержит эскалацию для слишком большого PR (декомпозиция на уровне задач); маркер 'свой PR' сохранён."
|
||||
module: tests/test_agent_prompts_canon.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-05
|
||||
type: unit
|
||||
description: "AC-5: developer.md, reviewer.md, tester.md содержат секцию <escalation>…</escalation> с маршрутами back-to:analysis / back-to:dev / REQUEST_CHANGES соответственно."
|
||||
module: tests/test_agent_prompts_canon.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-06
|
||||
type: unit
|
||||
description: "AC-7: tester.md содержит явный worktree-путь, smoke-проверку блока serial_gate в /queue (ORCH-088) и упоминание покрытия ТЗ (каждый TC из 04-test-plan) в success_criteria; маркеры pytest//health//status//queue сохранены."
|
||||
module: tests/test_agent_prompts_canon.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-07
|
||||
type: unit
|
||||
description: "AC-6: deployer.md несёт в начале видную рамку с запретом рестарта прод-8500; анти-регресс-маркеры docker exec orchestrator-staging / pr_already_merged / 8500 / INFRA-WAIVED сохранены."
|
||||
module: tests/test_agent_prompts_canon.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-08
|
||||
type: unit
|
||||
description: "AC-8: reviewer.md не содержит 'того же экземпляра Developer'; маркеры REQUEST_CHANGES, 'НЕ обновлена', TRACEABILITY.md, 'Известные ограничения', ORCH-079 сохранены."
|
||||
module: tests/test_agent_prompts_canon.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-09
|
||||
type: unit
|
||||
description: "AC-9 анти-регресс: verdict-ключи (verdict:/result:/staging_status:/deploy_status:/security_status:) и значения (APPROVED/REQUEST_CHANGES/PASS/FAIL/SUCCESS/FAILED) присутствуют байт-в-байт; 5 XML-секций в нормативном порядке + 6 полей 52c во всех 6 промптах (существующие канон-проверки зелёные)."
|
||||
module: tests/test_agent_prompts_canon.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-10
|
||||
type: unit
|
||||
description: "AC-9: верхний frontmatter определения агента остаётся валидным YAML с name/description и без ключа model: во всех 6 промптах (регресс test_agent_frontmatter_no_model.py)."
|
||||
module: tests/test_agent_frontmatter_no_model.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-11
|
||||
type: integration
|
||||
description: "AC-9/AC-10: полный регресс pytest tests/ -q зелёный; git diff не содержит правок src/ (docs/prompts-only)."
|
||||
module: tests/
|
||||
expected: PASS
|
||||
@@ -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` (`<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». Обоснование (в порядке веса):
|
||||
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`
|
||||
42
docs/work-items/ORCH-092/10-tech-risks.md
Normal file
42
docs/work-items/ORCH-092/10-tech-risks.md
Normal file
@@ -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 | Плейсхолдеры `<YYYY-MM-DD>` / `<resolve ORCH-41>` сами скопированы моделью буквально (тот же класс бага, что хардкод) | Сред. | Низ. | Явная инструкция «подставь фактическое (`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 | Добавление секции `<escalation>` (developer/reviewer/tester) нарушает нормативный порядок 5 обязательных XML-секций канона 52d | Низ. | Сред. | `<escalation>` ставится ПОСЛЕ `</success_criteria>` (как у `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 в начале `<context>`), маркеры не трогаются; каноне-тест проверяет их наличие |
|
||||
| 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) — **низкий**.
|
||||
94
docs/work-items/ORCH-092/12-review.md
Normal file
94
docs/work-items/ORCH-092/12-review.md
Normal file
@@ -0,0 +1,94 @@
|
||||
---
|
||||
verdict: APPROVED
|
||||
work_item: ORCH-092
|
||||
stage: review
|
||||
author_agent: reviewer
|
||||
status: approved
|
||||
created_at: 2026-06-09
|
||||
model_used: claude-opus-4-8
|
||||
type: review
|
||||
work_item_id: ORCH-092
|
||||
version: 1
|
||||
---
|
||||
|
||||
# Review ORCH-092
|
||||
|
||||
## Summary
|
||||
|
||||
Промпт-аудит 6 агентов (эпилог эпика ORCH-52), **docs/prompts-only**. PR проверен по 4 осям:
|
||||
соответствие ТЗ (`02-trz.md` FR-1…FR-11), соответствие ADR (`06-adr/ADR-001`), качество кода,
|
||||
качество документации. Все критерии приёмки `03-acceptance-criteria.md` (AC-1…AC-10) выполнены;
|
||||
машинные verdict-ключи и канон 52d/52c/52e — байт-в-байт; `src/**`/`STAGE_TRANSITIONS`/`QG_CHECKS`/
|
||||
схема БД не тронуты. Полный регресс `pytest tests/ -q` — **1278 passed**; целевые
|
||||
`test_agent_prompts_canon.py` + `test_agent_frontmatter_no_model.py` — **75 passed**.
|
||||
|
||||
**Вердикт: APPROVED.** P0/P1/P2-findings нет.
|
||||
|
||||
## Findings
|
||||
|
||||
### P0 — Blocker
|
||||
- _нет_
|
||||
|
||||
### P1 — Must fix
|
||||
- _нет_
|
||||
|
||||
### P2 — Should fix
|
||||
- _нет_
|
||||
|
||||
## Проверка по осям
|
||||
|
||||
### Ось 1 — Соответствие ТЗ / Acceptance
|
||||
- **AC-1 / FR-1 (расхардкод `created_at`):** PASS. Во всех 6 промптах копируемый блок несёт
|
||||
`created_at: <YYYY-MM-DD>` + врезка «не копируй буквально, подставь `date +%F`». Литерала
|
||||
`created_at: 2026-…` в fenced-блоках нет (закреплено `test_orch092_created_at_is_placeholder_not_literal`).
|
||||
- **AC-2 / FR-2 (расхардкод `model_used`):** PASS. `model_used: <resolve ORCH-41>` в примерах;
|
||||
литерал `claude-opus-4-8` остаётся лишь справкой в таблице полей (вне блока).
|
||||
- **AC-3 / FR-3 (сверка гейтов):** PASS. Все `check_*` из 6 промптов присутствуют в `QG_CHECKS`
|
||||
(интеграционный `test_orch092_gate_names_match_qg_registry`); `check_tests_passed` подтверждён
|
||||
валидным, не «исправлен вслепую».
|
||||
- **AC-4 / FR-4 (PR>1500 → эскалация):** PASS. «разбивай на меньшие PR» удалено, переформулировано
|
||||
в декомпозицию на уровне задач; маркер «свой PR» сохранён.
|
||||
- **AC-5 / FR-5 (`<escalation>`):** PASS. developer/reviewer/tester несут `<escalation>` ПОСЛЕ
|
||||
`</success_criteria>` (порядок 5 обязательных секций цел); маршруты ролеспецифичны
|
||||
(`back-to:analysis` / `back-to:dev` / `REQUEST_CHANGES`).
|
||||
- **AC-6 / FR-6+FR-10 (deployer рамка + язык):** PASS. Критичные self-hosting-запреты подняты в
|
||||
видную рамку в начале `<context>` («NEVER restart the prod 8500»); язык — EN по решению ADR D2.
|
||||
- **AC-7 / FR-7 (обогащение tester):** PASS. worktree-путь ветки задачи, smoke-проверка блока
|
||||
`serial_gate` в `/queue`, требование покрытия каждого TC из `04-test-plan.yaml`.
|
||||
- **AC-8 / FR-8 (мёртвая строка reviewer):** PASS. «не апрувь PR от того же экземпляра Developer»
|
||||
удалена; живые инварианты (`REQUEST_CHANGES`, «НЕ обновлена», ось трассировки, ось обзорных доков
|
||||
ORCH-079) сохранены.
|
||||
- **AC-9 / FR-11 (анти-регресс):** PASS. verdict-ключи `verdict:`/`result:`/`staging_status:`/
|
||||
`deploy_status:`/`security_status:` (+ значения) байт-в-байт; 5 секций + 6 полей во всех 6
|
||||
промптах; `git diff --stat -- src/` пуст.
|
||||
- **AC-10 (документация и тесты):** PASS — см. ось 4.
|
||||
|
||||
### Ось 2 — Соответствие ADR
|
||||
- **ADR-001 D1 (убран ручной rebase):** реализовано точно. Шаг `git fetch origin && git rebase
|
||||
origin/main` удалён из алгоритма developer, заменён нормативной заметкой; маркер запрета
|
||||
`--force-push` сохранён. Код-обоснование ADR **верифицировано**: `premerge_rebase_always=True`
|
||||
(config.py:432, дефолт), `auto_rebase_onto_main` + `--force-with-lease` (merge_gate.py:113/151),
|
||||
`_materialize_deferred_branch` (launcher.py:421). Логика верна: developer'у force-push запрещён,
|
||||
а пост-push rebase его требует → ручной шаг был конфликтующим/дублирующим.
|
||||
- **ADR-001 D2 (deployer EN):** реализовано — `deployer.md` оставлен на английском с явной
|
||||
«Language note» как задокументированное исключение; рамка запретов на EN.
|
||||
- **Глобальные ADR:** нарушений нет. Трассировка (`TRACEABILITY.md`): удалённая rebase-строка не
|
||||
несла маркера `ORCH-NNN`; зафиксированные инварианты не сломаны.
|
||||
|
||||
### Ось 3 — Качество кода
|
||||
- `src/` не изменён. Новые TC в `test_agent_prompts_canon.py` содержательны (парсер fenced-блоков,
|
||||
anti-literal regex, ролеспецифичные маршруты, интеграция с реальным реестром `QG_CHECKS`), не
|
||||
тривиальны. Все зелёные.
|
||||
|
||||
### Ось 4 — Документация (ОБЯЗАТЕЛЬНАЯ ПРОВЕРКА)
|
||||
- `src/**` НЕ изменён → правило «src изменён, документация не обновлена = P0» не триггерится.
|
||||
- Документация обновлена сверх требуемого: **CHANGELOG.md** (запись ORCH-092 под `[Unreleased]`),
|
||||
**CLAUDE.md** (абзац ORCH-092 в «Стек/Агенты»), **docs/architecture/README.md** (§«Слой промптов»
|
||||
— пункт ORCH-092), **ADR** `06-adr/ADR-001-developer-rebase-and-deployer-language.md` (решения
|
||||
P1-2/P2-2).
|
||||
- **Обзорные доки (ORCH-079):** PR не закрывает ни одного пункта `README.md` «Известные
|
||||
ограничения» → обновление витрины не требуется.
|
||||
|
||||
## Документация
|
||||
Обновлена полностью и корректно: CHANGELOG.md, CLAUDE.md, docs/architecture/README.md, ADR-001.
|
||||
Дополнительных обновлений не требуется.
|
||||
67
docs/work-items/ORCH-092/13-test-report.md
Normal file
67
docs/work-items/ORCH-092/13-test-report.md
Normal file
@@ -0,0 +1,67 @@
|
||||
---
|
||||
result: PASS
|
||||
work_item: ORCH-092
|
||||
stage: testing
|
||||
author_agent: tester
|
||||
status: pass
|
||||
created_at: 2026-06-09
|
||||
model_used: claude-opus-4-8
|
||||
type: test-report
|
||||
work_item_id: ORCH-092
|
||||
---
|
||||
|
||||
# Test Report — ORCH-092 — Промпт-аудит 6 агентов
|
||||
|
||||
## Окружение
|
||||
- Python: 3.12.13
|
||||
- pytest: 8.3.3
|
||||
- Worktree: `/repos/_wt/orchestrator/feature_ORCH-092-6-escalation` (ветка `feature/ORCH-092-6-escalation`)
|
||||
- Дата: 2026-06-09
|
||||
- Review-вердикт (`12-review.md`): **APPROVED** — предусловие стадии выполнено.
|
||||
|
||||
## Команды
|
||||
```
|
||||
cd /repos/_wt/orchestrator/feature_ORCH-092-6-escalation && python -m pytest tests/ -q
|
||||
python -m pytest tests/test_agent_prompts_canon.py tests/test_agent_frontmatter_no_model.py -q
|
||||
curl -s http://localhost:8500/health → {"status":"ok","service":"orchestrator"}
|
||||
curl -s http://localhost:8500/status → 200 OK (active_tasks[0] = ORCH-092/testing)
|
||||
curl -s http://localhost:8500/queue → serial_gate present: True · auto_labels present: True
|
||||
git diff --stat main -- src/ → пусто (src/ не тронут, docs/prompts-only)
|
||||
```
|
||||
|
||||
## Результаты по тест-плану (`04-test-plan.yaml` ↔ `03-acceptance-criteria.md`)
|
||||
|
||||
| TC ID | AC | Описание | Покрывающий тест | Результат |
|
||||
|-------|----|----------|------------------|-----------|
|
||||
| TC-01 | AC-1 | `created_at: <YYYY-MM-DD>` плейсхолдер во всех 6 промптах + инструкция «не копируй буквально» | `test_orch092_created_at_is_placeholder_not_literal` | PASS |
|
||||
| TC-02 | AC-2 | `model_used: <resolve ORCH-41>` плейсхолдер; нет литерала `claude-opus-4-8` в копируемом блоке | `test_orch092_model_used_is_placeholder_not_literal` | PASS |
|
||||
| TC-03 | AC-3 | каждое имя `check_*` в 6 промптах присутствует ключом в `QG_CHECKS` (импорт `src.qg.checks`) | `test_orch092_gate_names_match_qg_registry` | PASS |
|
||||
| TC-04 | AC-4 | developer: «разбивай на меньшие PR» удалено → эскалация; маркер «свой PR» сохранён | `test_orch092_developer_pr_oversize_is_escalation_not_split` | PASS |
|
||||
| TC-05 | AC-5 | `<escalation>` у developer/reviewer/tester после `</success_criteria>`; маршруты ролеспецифичны | `test_orch092_escalation_section_present_after_success` + `..._routes_are_role_specific` | PASS |
|
||||
| TC-06 | AC-7 | tester: worktree-путь, smoke `serial_gate` в `/queue`, покрытие ТЗ; маркеры pytest//health//status//queue целы | `test_orch092_tester_enriched` | PASS |
|
||||
| TC-07 | AC-6 | deployer: видная рамка запрета рестарта прод-8500; маркеры `docker exec orchestrator-staging`/`pr_already_merged`/`8500`/`INFRA-WAIVED` целы | `test_orch092_deployer_prominent_ban_frame` | PASS |
|
||||
| TC-08 | AC-8 | reviewer: «того же экземпляра Developer» удалена; живые маркеры (`REQUEST_CHANGES`/«НЕ обновлена»/`TRACEABILITY.md`/`Известные ограничения`/`ORCH-079`) целы | `test_orch092_reviewer_dead_line_removed` | PASS |
|
||||
| TC-09 | AC-9 | verdict-ключи байт-в-байт + 5 XML-секций в порядке + 6 полей 52c во всех 6 промптах | `test_machine_verdict_keys_preserved_exact_case` + `test_five_xml_sections_present` + `test_six_schema_field_names_present` | PASS |
|
||||
| TC-10 | AC-9 | верхний frontmatter определения агента валиден, без ключа `model:` | `tests/test_agent_frontmatter_no_model.py` | PASS |
|
||||
| TC-11 | AC-9/AC-10 | полный регресс `pytest tests/ -q` зелёный; `git diff` не содержит правок `src/` | `tests/` (1278 passed) + `git diff --stat main -- src/` пуст | PASS |
|
||||
|
||||
**Итог покрытия:** все 11 TC выполнены и сопоставлены с критериями приёмки AC-1…AC-10. Несопоставленных TC нет.
|
||||
|
||||
## Smoke API (read-only)
|
||||
- `GET /health` → `{"status":"ok","service":"orchestrator"}` — OK.
|
||||
- `GET /status` → 200; активная задача `ORCH-092` на стадии `testing`.
|
||||
- `GET /queue` → 200; блок **`serial_gate` присутствует** (ORCH-088, анти-регресс смока пройден), блок `auto_labels` присутствует (ORCH-089).
|
||||
|
||||
## Вывод pytest
|
||||
```
|
||||
tests/test_agent_prompts_canon.py tests/test_agent_frontmatter_no_model.py — 75 passed in 0.45s
|
||||
|
||||
tests/ (полный регресс):
|
||||
........................................................................ [ 95%]
|
||||
...................................................... [100%]
|
||||
1278 passed, 1 warning in 35.24s
|
||||
```
|
||||
> Единственный warning — `PydanticDeprecatedSince20` (class-based config в `src/config.py`), предсуществующий, не относится к ORCH-092, на результат не влияет.
|
||||
|
||||
## Итог
|
||||
**PASS** — полный регресс (1278 passed) и целевые анти-регресс-тесты (75 passed) зелёные; smoke `/health`/`/status`/`/queue` (включая блок `serial_gate`) — OK; `src/` не тронут (docs/prompts-only). Каждый TC из `04-test-plan.yaml` выполнен и сопоставлен с `03-acceptance-criteria.md`. Задача готова к переходу на `deploy-staging`.
|
||||
35
docs/work-items/ORCH-092/15-staging-log.md
Normal file
35
docs/work-items/ORCH-092/15-staging-log.md
Normal file
@@ -0,0 +1,35 @@
|
||||
---
|
||||
staging_status: SUCCESS
|
||||
work_item: ORCH-092
|
||||
stage: deploy-staging
|
||||
author_agent: deployer
|
||||
status: success
|
||||
created_at: 2026-06-09
|
||||
model_used: claude-opus-4-8
|
||||
timestamp: 2026-06-09T14:45:26Z
|
||||
base_url: http://localhost:8501
|
||||
---
|
||||
|
||||
# Staging Gate Log
|
||||
|
||||
> Машинный вердикт читается ТОЛЬКО из `staging_status:` во frontmatter. `SUCCESS` → дальше; `FAILED` → откат.
|
||||
|
||||
Staging test suite completed against the live staging environment (`orchestrator-staging`, port 8501).
|
||||
Canonical run **inside** the container via the Docker Engine API exec endpoint
|
||||
(`/repos/orchestrator/scripts/staging_check.py --base-url http://localhost:8501 --mode stub`), so the
|
||||
B6 registry-isolation check reads the running instance's own `.env.staging` process-env.
|
||||
|
||||
**Result: 8/10 checks PASS — exit code 0 → SUCCESS.** All REAL pipeline checks green. The two
|
||||
sandbox-infra checks C9a/C9b are *waived* per ORCH-061 (SANDBOX bot accounts are not project members,
|
||||
so pipeline steps 6+ are unreachable in the sandbox — not a pipeline regression).
|
||||
|
||||
INFRA-WAIVED: C9a Branch appears in orchestrator-sandbox, C9b Analyst job enqueued in staging queue (known sandbox-infra; real checks green)
|
||||
VERDICT: SUCCESS (exit 0) — SUCCESS (infra-waived): ['C9a Branch appears in orchestrator-sandbox', 'C9b Analyst job enqueued in staging queue'] are known sandbox-infra checks; all real checks green
|
||||
|
||||
## Results
|
||||
- **Block A (SMOKE)**: PASS — A1 `/health`→200 (status=ok); A2 `/queue`→200 (counts/max_concurrency/resilience present); A3 `ORCH_STAGING=true`.
|
||||
- **Block B (ACCESS)**: PASS — B4 Plane sandbox project accessible (5 projects, sandbox=YES); B5 Gitea `orchestrator-sandbox` accessible push=true; B6 Registry isolation (sandbox=YES, prod-ET=NO, prod-ORCH=NO).
|
||||
- **Block C (E2E, mode=stub)**: C7 create issue in Plane SANDBOX PASS (HTTP 201); C8 trigger pipeline via `/webhook/plane` PASS (HMAC-signed, HTTP 200); C9a branch-in-sandbox FAIL (waived); C9b analyst-job-enqueued FAIL (waived). CLEANUP: Plane issue deleted (HTTP 204), no branch to delete.
|
||||
|
||||
REAL failed: none.
|
||||
SANDBOX_INFRA failed (waived): C9a, C9b.
|
||||
@@ -11,6 +11,7 @@ Covers test-plan TC-01..TC-07. TC-08 lives in
|
||||
regression (TC-10) is the rest of `tests/`.
|
||||
"""
|
||||
import os
|
||||
import re
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -279,3 +280,156 @@ def test_reviewer_carries_overview_docs_axis():
|
||||
assert "ORCH-079" in text, (
|
||||
"reviewer.md does not anchor the overview-docs axis to ORCH-079"
|
||||
)
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# ORCH-092 (epilogue of epic ORCH-52): prompt audit of the 6 agents —
|
||||
# de-hardcode date/model, gate-name parity, escalation sections, dead-line
|
||||
# removal, tester enrichment, deployer ban-frame. Pure-text checks; only
|
||||
# TC-03 imports `src/` (the QG_CHECKS registry parity check).
|
||||
# Covers test-plan TC-01..TC-08 (TC-09/TC-10/TC-11 = existing canon + full regression).
|
||||
# --------------------------------------------------------------------------- #
|
||||
|
||||
|
||||
def _fenced_blocks(text: str) -> list[str]:
|
||||
"""Return the body of every ``` fenced code block (the *copyable* examples)."""
|
||||
blocks: list[str] = []
|
||||
inside = False
|
||||
buf: list[str] = []
|
||||
for line in text.splitlines():
|
||||
if line.lstrip().startswith("```"):
|
||||
if inside:
|
||||
blocks.append("\n".join(buf))
|
||||
buf = []
|
||||
inside = not inside
|
||||
continue
|
||||
if inside:
|
||||
buf.append(line)
|
||||
return blocks
|
||||
|
||||
|
||||
@pytest.mark.parametrize("agent", _AGENTS)
|
||||
def test_orch092_created_at_is_placeholder_not_literal(agent):
|
||||
"""TC-01 (AC-1): copyable example uses a date placeholder + a substitution note.
|
||||
|
||||
The field name `created_at` stays; only its value becomes a placeholder. No
|
||||
literal date may survive inside a ``` fenced (copyable) block, else an agent
|
||||
would copy a stale date verbatim.
|
||||
"""
|
||||
text = _read(agent)
|
||||
assert "created_at: <YYYY-MM-DD>" in text, (
|
||||
f"{agent}.md does not use the created_at: <YYYY-MM-DD> placeholder"
|
||||
)
|
||||
for block in _fenced_blocks(text):
|
||||
assert re.search(r"created_at:\s*\d", block) is None, (
|
||||
f"{agent}.md still hardcodes a literal created_at date in a copyable block"
|
||||
)
|
||||
assert "date +%F" in text, (
|
||||
f"{agent}.md does not instruct to substitute the actual date (date +%F)"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("agent", _AGENTS)
|
||||
def test_orch092_model_used_is_placeholder_not_literal(agent):
|
||||
"""TC-02 (AC-2): copyable example uses a model placeholder, not the literal model.
|
||||
|
||||
`model_used: claude-opus-4-8` is allowed as a reference in the field table
|
||||
(outside the fenced block) but must NOT appear in a copyable example.
|
||||
"""
|
||||
text = _read(agent)
|
||||
assert "model_used: <resolve ORCH-41>" in text, (
|
||||
f"{agent}.md does not use the model_used: <resolve ORCH-41> placeholder"
|
||||
)
|
||||
for block in _fenced_blocks(text):
|
||||
assert "model_used: claude-opus-4-8" not in block, (
|
||||
f"{agent}.md still hardcodes model_used: claude-opus-4-8 in a copyable block"
|
||||
)
|
||||
|
||||
|
||||
def test_orch092_gate_names_match_qg_registry():
|
||||
"""TC-03 (AC-3): every check_* named in the 6 prompts is a real QG_CHECKS key.
|
||||
|
||||
The only test in this module that imports `src/` (integration). Guards against
|
||||
a prompt naming a non-existent gate; confirms check_tests_passed is valid.
|
||||
"""
|
||||
from src.qg.checks import QG_CHECKS
|
||||
|
||||
pattern = re.compile(r"check_[a-z_]+")
|
||||
for agent in _AGENTS:
|
||||
for name in sorted(set(pattern.findall(_read(agent)))):
|
||||
assert name in QG_CHECKS, (
|
||||
f"{agent}.md references gate {name!r} which is absent from QG_CHECKS"
|
||||
)
|
||||
assert "check_tests_passed" in QG_CHECKS, "check_tests_passed must remain a real gate"
|
||||
|
||||
|
||||
def test_orch092_developer_pr_oversize_is_escalation_not_split():
|
||||
"""TC-04 (AC-4): the 'split into smaller PRs' instruction became an escalation."""
|
||||
text = _read("developer")
|
||||
assert "разбивай на меньшие PR" not in text, (
|
||||
"developer.md still carries the unrealisable 'split into smaller PRs' instruction"
|
||||
)
|
||||
assert "на уровне задач" in text and "декомпозиц" in text, (
|
||||
"developer.md does not reframe an oversize PR as task-level decomposition"
|
||||
)
|
||||
assert "свой PR" in text, "developer.md lost the 'свой PR' marker"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("agent", ("developer", "reviewer", "tester"))
|
||||
def test_orch092_escalation_section_present_after_success(agent):
|
||||
"""TC-05 (AC-5): dev/reviewer/tester carry <escalation> after </success_criteria>."""
|
||||
text = _read(agent)
|
||||
# The real section tags sit on their own line (an inline `<escalation>` mention
|
||||
# in <constraints> uses backticks and must not be mistaken for the section).
|
||||
open_m = re.search(r"(?m)^<escalation>\s*$", text)
|
||||
close_m = re.search(r"(?m)^</escalation>\s*$", text)
|
||||
assert open_m and close_m, f"{agent}.md is missing the <escalation> section"
|
||||
success_m = re.search(r"(?m)^</success_criteria>\s*$", text)
|
||||
assert success_m and open_m.start() > success_m.start(), (
|
||||
f"{agent}.md places <escalation> before </success_criteria> (breaks section order)"
|
||||
)
|
||||
|
||||
|
||||
def test_orch092_escalation_routes_are_role_specific():
|
||||
"""TC-05 (AC-5): escalation routes match each role."""
|
||||
assert "back-to:analysis" in _read("developer"), "developer lacks back-to:analysis route"
|
||||
assert "back-to:dev" in _read("tester"), "tester lacks back-to:dev route"
|
||||
assert "REQUEST_CHANGES" in _read("reviewer"), "reviewer lacks REQUEST_CHANGES route"
|
||||
|
||||
|
||||
def test_orch092_tester_enriched():
|
||||
"""TC-06 (AC-7): tester gains worktree path, serial_gate smoke and TRZ coverage."""
|
||||
text = _read("tester")
|
||||
assert "worktree" in text, "tester.md does not mention the task-branch worktree path"
|
||||
assert "serial_gate" in text, "tester.md /queue smoke omits the serial_gate block check"
|
||||
assert "04-test-plan.yaml" in text, "tester.md does not require coverage of every TRZ TC"
|
||||
for marker in _ANTI_REGRESS["tester"]:
|
||||
assert marker in text, f"tester.md lost anti-regress marker {marker!r}"
|
||||
|
||||
|
||||
def test_orch092_deployer_prominent_ban_frame():
|
||||
"""TC-07 (AC-6): deployer carries a prominent prod-8500 ban frame inside <context>."""
|
||||
text = _read("deployer")
|
||||
context = text[text.index("<context>"):text.index("</context>")]
|
||||
assert "8500" in context, "deployer.md <context> frame does not name the prod 8500"
|
||||
assert "NEVER restart the prod" in context, (
|
||||
"deployer.md does not raise the 'NEVER restart prod 8500' ban into the context frame"
|
||||
)
|
||||
for marker in _ANTI_REGRESS["deployer"]:
|
||||
assert marker in text, f"deployer.md lost anti-regress marker {marker!r}"
|
||||
|
||||
|
||||
def test_orch092_reviewer_dead_line_removed():
|
||||
"""TC-08 (AC-8): the dead 'same Developer instance' line is gone; live markers stay."""
|
||||
text = _read("reviewer")
|
||||
assert "того же экземпляра" not in text, (
|
||||
"reviewer.md still carries the dead 'same Developer instance' instruction"
|
||||
)
|
||||
for marker in (
|
||||
"REQUEST_CHANGES",
|
||||
"НЕ обновлена",
|
||||
"TRACEABILITY.md",
|
||||
"Известные ограничения",
|
||||
"ORCH-079",
|
||||
):
|
||||
assert marker in text, f"reviewer.md lost live invariant marker {marker!r}"
|
||||
|
||||
Reference in New Issue
Block a user