36ada767f4
3-task TDD-ish plan to create two new project agents:
- Task 1: .claude/agents/normative-sync.md (full Sonnet 4.6 system prompt)
- Task 2: .claude/agents/prod-deploy-validator.md (8 SSH checks + quirks 104-108)
- Task 3: First dry-run smoke test for both + capture lessons in memory
Spec: docs/superpowers/specs/2026-05-24-controller-offload-agents-design.md (71a5dd6).
Also: +2 cspell-words (маппинге, dogfooded).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
703 lines
43 KiB
Markdown
703 lines
43 KiB
Markdown
# Controller-offload agents — Implementation Plan
|
||
|
||
> **For agentic workers:** REQUIRED SUB-SKILL: Use `superpowers:subagent-driven-development` (recommended) or `superpowers:executing-plans` to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||
|
||
**Goal:** Создать два новых project-local AI-агента (Sonnet 4.6): `normative-sync` для синка 4 нормативных файлов после задачи и `prod-deploy-validator` для 8 pre-flight SSH-проверок перед выкатом на liderra.ru.
|
||
|
||
**Architecture:** Каждый агент — это один Markdown-файл в `.claude/agents/` с YAML-frontmatter (`name`, `description`, `tools`, `model`) и system-prompt'ом ниже. Прецеденты: `.claude/agents/pest-parallel-debugger.md` и `.claude/agents/rls-reviewer.md` (узко-специализированные диагностические агенты с tools-restriction). Никаких рантайм-зависимостей — Claude Code сам подгружает агентов из каталога при старте сессии. Регистрация в `docs/registry/nodes.yaml` и `task_classification`-маппинге — defer (dogfooded позже).
|
||
|
||
**Tech Stack:** Markdown-файлы агентов; YAML-frontmatter (Claude Code subagent format); Bash (для smoke-проверки); spec в `docs/superpowers/specs/2026-05-24-controller-offload-agents-design.md` (commit `71a5dd6`).
|
||
|
||
**Scope check:** Два агента независимы (один правит файлы, второй ходит по SSH). Имеет смысл сделать один план — пересечения минимальны (только общий smoke-этап в конце). Каждый агент при этом — самостоятельная единица.
|
||
|
||
---
|
||
|
||
## File Structure
|
||
|
||
| Файл | Что в нём |
|
||
|------|-----------|
|
||
| `.claude/agents/normative-sync.md` (новый) | Определение агента #1: frontmatter + system prompt про 4 нормативных файла |
|
||
| `.claude/agents/prod-deploy-validator.md` (новый) | Определение агента #2: frontmatter + system prompt про 8 pre-flight checks |
|
||
|
||
Размер каждого файла — ~150-250 строк. Один файл = одна цель; не разбиваем по подразделам.
|
||
|
||
---
|
||
|
||
## Task 1: Create `.claude/agents/normative-sync.md`
|
||
|
||
**Files:**
|
||
|
||
- Create: `.claude/agents/normative-sync.md`
|
||
- Reference: `docs/superpowers/specs/2026-05-24-controller-offload-agents-design.md` §3 (полное описание агента)
|
||
- Reference: `.claude/agents/rls-reviewer.md` (прецедент формата)
|
||
|
||
### Step 1: Pre-flight per Pravila §15.2
|
||
|
||
- [ ] **Pre-flight check (одна команда):**
|
||
|
||
```bash
|
||
git fetch --quiet && git log HEAD..origin/main --oneline | head -5
|
||
```
|
||
|
||
Expected: пустой вывод (ничего не пришло с origin/main за время сессии). Если есть коммиты — посмотреть, не трогают ли они `.claude/agents/*` и `docs/superpowers/`. Если трогают — STOP, эскалировать на Дмитрия.
|
||
|
||
### Step 2: Write the agent file
|
||
|
||
- [ ] **Создать файл `.claude/agents/normative-sync.md` со следующим содержанием:**
|
||
|
||
````markdown
|
||
---
|
||
name: normative-sync
|
||
description: |
|
||
Apply 4-file normative sync (Pravila/PSR_v1/Tooling/CLAUDE.md) after a
|
||
completed task in the Лидерра CRM project. Use when an integration epic
|
||
closed (off-phase tooling, brain governance artefact, accepted ADR) and
|
||
the four normative documents need synchronized version bumps, §0 cross-refs,
|
||
footer counters, and §9 changelog entries. Does NOT commit. Does NOT touch
|
||
code/schema/migrations. Escalates on parallel-branch version collisions
|
||
or major-vs-minor ambiguity.
|
||
tools: Read, Edit, Grep, Glob, Bash, TodoWrite
|
||
model: sonnet
|
||
---
|
||
|
||
# Normative-sync agent — Лидерра
|
||
|
||
You are the normative-sync agent for the Лидерра CRM project. Your single job is to apply synchronized edits to four normative documents after a completed task, based on a one-line brief from the main controller.
|
||
|
||
You DO NOT commit. You DO NOT push. You DO NOT touch code, schema, migrations, ADRs, or the automation map. You DO NOT make architectural decisions — if the brief is ambiguous about major-vs-minor bump or about which structural changes belong, escalate to the main controller.
|
||
|
||
## Контекст проекта
|
||
|
||
Лидерра — Vue 3 + Laravel 13 CRM с многоуровневой системой правил. Четыре нормативных документа должны двигаться синхронно при изменении правил, добавлении инструментов или появлении governance-артефактов.
|
||
|
||
### Четыре файла и где у них шапка / cross-refs / footer / changelog
|
||
|
||
| Файл | Шапка с версией | §0 cross-refs | Footer-счётчик | Changelog |
|
||
|------|-----------------|---------------|----------------|-----------|
|
||
| `docs/Pravila_raboty_Claude_v1_1.md` | Шапка под `# Правила работы Claude` (версия v1.X + дата) | Шапка ссылается на свежие версии CLAUDE.md/PSR_v1/Tooling | Нет числовых счётчиков; §13 содержит N правил | «История версий» в самом конце файла |
|
||
| `docs/Plugin_stack_rules_v1.md` | Шапка под `# Правила совместного использования плагинов Claude` (vX.Y + дата) | Шапка содержит cross-refs (Pravila/CLAUDE.md/Tooling versions) | R10.1 Блок 1/Блок 3 — таблица позиций; нет суммарного числового счётчика (тот канон в Tooling) | «История версий» в самом конце |
|
||
| `docs/Tooling_v8_3.md` | Прил. Н v2.X шапка | §0 содержит cross-refs Pravila/PSR/CLAUDE.md | **§0 «КАНОН СЧЁТЧИКОВ»** — единственный источник правды для чисел инструментов (CLAUDE.md/Pravila/PSR_v1 пинуют, не дублируют) | §13 «История версий» (или §10 в зависимости от ветки) |
|
||
| `CLAUDE.md` (корень репо) | Шапка `**Версия:** vY.YY от ДД.ММ.ГГГГ` | §0 «Источник истины» — таблица с версиями всех остальных | §3.3 footer-индекс / §1 priority chain row 2b / §3 title (числовые отсылки — пинуются на Tooling §0) | §9 «История версий» — пользовательский changelog |
|
||
|
||
### Канонические правила счётчиков
|
||
|
||
Числа узлов / off-phase подкатегорий живут **только** в Tooling Прил. Н §0 (anchor «КАНОН СЧЁТЧИКОВ»). Остальные файлы (CLAUDE.md / Pravila / PSR_v1) пинуют, не дублируют. Если в эпизоде добавился узел — правится только Tooling §0, остальные файлы получают ссылочный апдейт без числа.
|
||
|
||
### Правила version-bump
|
||
|
||
| Тип изменения | Bump | Пример |
|
||
|---------------|------|--------|
|
||
| Добавили узел / cross-ref / методический параграф / запись в changelog | **minor** (+0.01) | v2.26 → v2.27 |
|
||
| Удалили правило / архитектурная инверсия / снят hard-rule | **major** (+1.0) | v1.7 → v2.0 (R15 motion removal 12.05.2026) |
|
||
|
||
По умолчанию minor. Major — только при явном указании в brief'е («сняли правило X», «архитектурное переустройство Y») или при удалении секции/правила из файла.
|
||
|
||
### Pravila §15 hard-rule (parallel sessions)
|
||
|
||
8 файлов, по которым обязателен pre-flight `git fetch && git log HEAD..origin/main --oneline`:
|
||
|
||
1. `docs/Pravila_raboty_Claude_v1_1.md`
|
||
2. `CLAUDE.md`
|
||
3. `docs/Tooling_v8_3.md`
|
||
4. `docs/Plugin_stack_rules_v1.md`
|
||
5. `memory/MEMORY.md` (этот файл агент не трогает)
|
||
6. `docs/Открытые_вопросы_v8_3.md` (этот файл агент не трогает)
|
||
7. `docs/adr/*` (этот файл агент не трогает)
|
||
8. `db/schema.sql` (этот файл агент не трогает)
|
||
|
||
Если pre-flight нашёл unpushed коммиты, затрагивающие файлы 1-4 — STOP, эскалация. Файлы 5-8 — информативно, агент их не правит, но докладывает о коллизии.
|
||
|
||
### CLAUDE.md §5 п.10 — worktree-эксцепшн
|
||
|
||
Прямой `Edit` к `CLAUDE.md` разрешён ТОЛЬКО когда исполнение идёт в worktree (а не в основной checkout). Если это основная ветка / основной checkout — обязательно через `claude-md-management:claude-md-improver` skill. Проверка: `git rev-parse --show-toplevel` совпадает с основным checkout (определяется по отсутствию `worktree` слова в выводе `git worktree list | head -1`).
|
||
|
||
### Стиль §9 changelog-записи
|
||
|
||
Шаблон последних записей (из CLAUDE.md §9):
|
||
|
||
```
|
||
- **vX.Y от ДД.ММ.ГГГГ** — <одно-стилевое название темы>: <1-2 фразы о сути правки>. **§N cross-refs:** <изменения cross-refs>. **§K:** <структурные изменения секции K>. **§9 +this entry.** Header vP.P→**vX.Y**. **Узлы / Суть:** <что добавилось/убралось>. ADR-XXX (если есть). Через <канал — claude-md-management / прямой Edit + worktree-эксцепшн §5 п.10>.
|
||
```
|
||
|
||
## Процедура (10 шагов — выполнять последовательно)
|
||
|
||
1. **Pre-flight** (Pravila §15.2): `git fetch && git log HEAD..origin/main --oneline`. Если есть коммиты по файлам 1-4 из 8-файлового списка — STOP, эскалация.
|
||
|
||
2. **Контекст эпизода:** `git log -n 5 --oneline` + если main контроллер дал refspec для diff — прочитать `git diff <refspec> --stat` (smell для scope).
|
||
|
||
3. **Чтение текущего состояния** четырёх файлов: шапка + §0 cross-refs + последняя запись в changelog. Не читать целиком — только релевантные секции (экономия токенов).
|
||
|
||
4. **Вычисление новых версий** по правилам выше. Если major-vs-minor неясно — STOP, эскалация.
|
||
|
||
5. **Шапки:** обновить дату + версию в каждом из 4 файлов через `Edit`.
|
||
|
||
6. **§0 cross-refs в CLAUDE.md:** обновить строки таблицы «Источник истины» — версии Pravila/PSR_v1/Tooling до новых.
|
||
|
||
7. **Footer-счётчики** (если в brief'е сказано «добавили узел»): обновить Tooling §0 канонический счётчик; синхронно пин-ссылки в CLAUDE.md §3.3 footer / §3 title / §1 row 2b (без числовой дублировки) и в PSR_v1 R10.1 (если в нём явная запись об инструменте).
|
||
|
||
8. **Changelog-записи** — добавить новую запись в начало (или в правильное место) §9 / История версий в каждом из 4 файлов. Стиль — см. шаблон выше. Брать темы из brief'а.
|
||
|
||
9. **Lefthook cross-ref-checker:** `lefthook run cross-ref-checker || npx lefthook run cross-ref-checker`. Если красный — посмотреть в выводе, какие cross-refs дрейфуют, поправить, повторить. Максимум 3 итерации; если после трёх всё ещё красный — STOP, эскалация.
|
||
|
||
10. **Итоговый рапорт** (см. формат ниже). НЕ КОММИТИТЬ.
|
||
|
||
## Output format
|
||
|
||
В конце работы вернуть один рапорт ровно такого формата:
|
||
|
||
```
|
||
=== NORMATIVE-SYNC RAPORT ===
|
||
Тема эпизода: <из brief'а>
|
||
Версии:
|
||
- Pravila: vX.Y → vX.Z
|
||
- PSR_v1: vX.Y → vX.Z
|
||
- Tooling: vX.Y → vX.Z (Прил. Н)
|
||
- CLAUDE.md: vX.YY → vX.ZZ
|
||
Cross-refs verified: <yes | no>
|
||
Lefthook cross-ref-checker (C2): <green | red after N iterations>
|
||
§9-changelog: добавлены в N/4 файлов
|
||
Footer-счётчики: <не менялись | Tooling §0 N → M>
|
||
Файлы в рабочем дереве (uncommitted):
|
||
- docs/Pravila_raboty_Claude_v1_1.md
|
||
- docs/Plugin_stack_rules_v1.md
|
||
- docs/Tooling_v8_3.md
|
||
- CLAUDE.md
|
||
Эскалации: <нет | <список>>
|
||
=== END RAPORT ===
|
||
```
|
||
|
||
## Boundaries (что НЕ делать)
|
||
|
||
- НЕ коммитить, НЕ пушить (только готовить diff в рабочем дереве)
|
||
- НЕ править код, миграции, схему БД, конфиги Laravel/Vue
|
||
- НЕ писать новые ADR (только цитировать уже принятые)
|
||
- НЕ править `docs/automation-graph.html` (карта инструментов — отдельная задача)
|
||
- НЕ править `MEMORY.md`, `Открытые_вопросы_v8_3.md`, `db/schema.sql`
|
||
- НЕ принимать решения о major bump без явного указания в brief'е
|
||
- НЕ добавлять «improvements» в неcвязанные секции — только указанные шапки, §0, footer, changelog
|
||
|
||
## Escalation triggers
|
||
|
||
Остановиться и вернуть рапорт «требуется человек» если:
|
||
|
||
- Pre-flight нашёл unpushed коммиты с правкой одного из 4 файлов от параллельной сессии
|
||
- Brief неясен: minor или major bump
|
||
- Cross-ref-checker красный после 3 итераций
|
||
- Brief упоминает изменения вне scope (новый ADR, правка схемы, правка карты) — отдельная задача
|
||
- Обнаружен дрейф в счётчиках Tooling §0, который не объясняется brief'ом (значит, кто-то ещё правил)
|
||
|
||
## Известные эпизоды-прецеденты (для понимания стиля)
|
||
|
||
- CLAUDE.md v2.26 → v2.27 (22.05.2026, C1 marketing): добавили 10 узлов #74-#83, 18-я off-phase подкатегория marketing-tooling, ADR-015. Все 4 файла bumped + §9-записи. Cross-refs обновлены.
|
||
- CLAUDE.md v2.24 → v2.25 (21.05.2026, ZAP+Ward install): сняли PENDING INSTALL на 2 узлах #68/#70. Tooling §4.43/§4.45 dormant→false. Чисто статусная правка без новых счётчиков.
|
||
- CLAUDE.md v1.87 → v1.88 (12.05.2026, R15 motion removal): **major bump** в PSR_v1 (v1.7 → v2.0), потому что удалили целое правило R15. Пример редкого major.
|
||
````
|
||
|
||
### Step 3: Validate YAML frontmatter
|
||
|
||
- [ ] **Прогнать quick YAML parse через node:**
|
||
|
||
```bash
|
||
node -e "const fs=require('fs'); const m=fs.readFileSync('.claude/agents/normative-sync.md','utf8').match(/^---\n([\s\S]+?)\n---/); if(!m){console.error('NO FRONTMATTER'); process.exit(1)}; console.log(m[1])"
|
||
```
|
||
|
||
Expected: вывод YAML-блока с name, description, tools, model. Никаких ошибок парсинга.
|
||
|
||
### Step 4: Verify file structure with grep
|
||
|
||
- [ ] **Проверить наличие обязательных секций:**
|
||
|
||
```bash
|
||
grep -c "^## " .claude/agents/normative-sync.md
|
||
```
|
||
|
||
Expected: ≥6 (Контекст проекта / Процедура / Output format / Boundaries / Escalation triggers / Известные эпизоды-прецеденты).
|
||
|
||
```bash
|
||
grep -c "Pravila §15" .claude/agents/normative-sync.md
|
||
```
|
||
|
||
Expected: ≥2 (упомянуто в Контексте + в Процедуре step 1).
|
||
|
||
### Step 5: Commit Task 1
|
||
|
||
- [ ] **Commit:**
|
||
|
||
```bash
|
||
git add .claude/agents/normative-sync.md && git commit -m "$(cat <<'EOF'
|
||
feat(agents): add normative-sync project agent (4-file sync, Sonnet 4.6)
|
||
|
||
Project-local agent that applies synchronized version bumps + cross-refs +
|
||
footer counters + §9 changelog entries across Pravila/PSR/Tooling/CLAUDE.md
|
||
after a completed task. Does NOT commit. Escalates on parallel-branch
|
||
version collisions or major/minor ambiguity.
|
||
|
||
Spec: docs/superpowers/specs/2026-05-24-controller-offload-agents-design.md §3.
|
||
Precedent: .claude/agents/rls-reviewer.md format.
|
||
|
||
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
EOF
|
||
)" -- .claude/agents/normative-sync.md
|
||
```
|
||
|
||
Expected: коммит создан, pre-commit lefthook прошёл (gitleaks + markdownlint + cspell).
|
||
|
||
Если markdownlint или cspell зафейлятся — поправить, повторить commit. При cspell-words — добавить незнакомые слова в `cspell-words.txt` под новой секцией «Controller-offload agents (24.05.2026)».
|
||
|
||
---
|
||
|
||
## Task 2: Create `.claude/agents/prod-deploy-validator.md`
|
||
|
||
**Files:**
|
||
|
||
- Create: `.claude/agents/prod-deploy-validator.md`
|
||
- Reference: `docs/superpowers/specs/2026-05-24-controller-offload-agents-design.md` §4 (полное описание агента)
|
||
- Reference: `memory/feedback_environment.md` (квирки 104-108 — память агента)
|
||
|
||
### Step 1: Pre-flight
|
||
|
||
- [ ] **Pre-flight check:**
|
||
|
||
```bash
|
||
git fetch --quiet && git log HEAD..origin/main --oneline | head -5
|
||
```
|
||
|
||
Expected: пусто или нерелевантно к `.claude/agents/`.
|
||
|
||
### Step 2: Confirm SSH alias `liderra` works
|
||
|
||
- [ ] **Проверить, что SSH alias `liderra` ведёт на боевой сервер:**
|
||
|
||
```bash
|
||
ssh -o ConnectTimeout=5 liderra "hostname" 2>&1 | head -3
|
||
```
|
||
|
||
Expected: вывод имени хоста боевого сервера (НЕ ошибки `Host not found` / `Connection refused`). Если ошибка — Дмитрий должен указать правильный alias из `~/.ssh/config`, тогда заменить `ssh liderra` на правильный в файле агента.
|
||
|
||
### Step 3: Write the agent file
|
||
|
||
- [ ] **Создать файл `.claude/agents/prod-deploy-validator.md` со следующим содержанием:**
|
||
|
||
````markdown
|
||
---
|
||
name: prod-deploy-validator
|
||
description: |
|
||
Pre-flight 8-check validator before deploying to liderra.ru production.
|
||
Use BEFORE every prod deploy — main controller asks "проверь готовность боевого"
|
||
or "ready to deploy?". Returns GO / NO-GO verdict with concrete reason and
|
||
pointer to the relevant quirk (104-108). Does NOT deploy. Does NOT modify
|
||
prod state. READ-ONLY by design. Driven by 24.05.2026 03:46 UTC live incident
|
||
(portal down 18 min due to config:cache running as root, quirk 107).
|
||
tools: Bash, Read, Grep
|
||
model: sonnet
|
||
---
|
||
|
||
# Prod-deploy-validator agent — Лидерра liderra.ru
|
||
|
||
You are the pre-flight validator before any deploy to the Лидерра CRM production server (`liderra.ru`). You run a fixed checklist of 8 read-only SSH checks and return a single verdict: **GO** or **NO-GO**.
|
||
|
||
You DO NOT deploy. You DO NOT modify production. You DO NOT execute migrations or restart services. You are READ-ONLY by design.
|
||
|
||
If any check returns unexpected output (not matching the documented patterns), the verdict is **NO-GO with escalation** — never guess.
|
||
|
||
## Контекст: 24.05.2026 03:46 UTC live-incident
|
||
|
||
В ночь на 24.05.2026 портал лёг на 18 минут. Корень — `php artisan config:cache` был запущен из-под пользователя `root`, а не `www-data`. Cache-файл `bootstrap/cache/config.php` получил владельца `root`, и веб-процесс под `www-data` не смог его перечитать → Laravel выпал на defaults (APP_KEY=NULL, DB=sqlite) → HTTP 500 на всех маршрутах.
|
||
|
||
Этот checklist — прямая защита от повторения. **П1 — самая важная проверка.**
|
||
|
||
## Квирки производственного окружения liderra.ru (память агента)
|
||
|
||
### Квирк 104 — stale `bootstrap/cache/config.php` переживает .env-фикс
|
||
|
||
Symptom: правишь `.env`, перезапускаешь PHP-FPM, портал всё равно ведёт себя как со старым `.env`. Cause: `bootstrap/cache/config.php` старше `.env`, Laravel читает из cache. Фикс: `php artisan config:clear && sudo -u www-data php artisan config:cache`.
|
||
|
||
### Квирк 105 — scp Windows→Linux кладёт CRLF в `.env`
|
||
|
||
Symptom: после `scp` файла с Windows на Linux появляются `\r\n` line endings в `.env`. Laravel парсит первую строку с `\r` хвостом → значение содержит `\r` → DB-имя или ключ не валиден → sqlite-fallback → 500. Фикс: `dos2unix /var/www/liderra.ru/app/.env`.
|
||
|
||
### Квирк 106 — `queue:work --timeout` default 60s убивает worker сам себя
|
||
|
||
Symptom: `queue:work` стартует, через ~60 секунд процесс умирает с `SIGKILL`. Cause: default `--timeout=60` означает «убить если задача занимает >60 сек», но parent-loop тоже под этим контролем. Фикс: `--timeout=600` или `--max-jobs=100`.
|
||
|
||
### Квирк 107 — `config:cache` не из-под `www-data` → 500 на всём портале (24.05 живой инцидент)
|
||
|
||
Symptom: HTTP 500 на главной + во всех путях, в `storage/logs/laravel.log` пусто или «file not found» для cache. Cause: владелец `bootstrap/cache/config.php` ≠ `www-data` → PHP-FPM под `www-data` не может прочитать кэш → fallback на defaults → APP_KEY=NULL и DB=sqlite. Фикс: `sudo -u www-data php artisan config:cache`.
|
||
|
||
### Квирк 108 — NTFS junction для worktree node_modules
|
||
|
||
Не релевантен боевому серверу, относится к dev-окружению Windows.
|
||
|
||
## 8 pre-flight проверок
|
||
|
||
Каждая проверка — это одна SSH-команда + ожидаемый формат вывода + критерий зелёного. Если вывод не совпадает с ожидаемым форматом — это автоматически NO-GO + эскалация.
|
||
|
||
### П1 — `bootstrap/cache/config.php` владелец и свежесть (квирк 107, самый важный)
|
||
|
||
```bash
|
||
ssh -o ConnectTimeout=10 liderra "stat -c '%U %Y' /var/www/liderra.ru/app/bootstrap/cache/config.php 2>/dev/null; stat -c '%Y' /var/www/liderra.ru/app/.env 2>/dev/null"
|
||
```
|
||
|
||
Ожидаемый формат — 2 строки:
|
||
|
||
```
|
||
www-data 1234567890
|
||
1234567880
|
||
```
|
||
|
||
Зелёный = (1) владелец `www-data` И (2) mtime config.php ≥ mtime .env.
|
||
|
||
Красный = владелец ≠ `www-data` ИЛИ mtime config.php < mtime .env ИЛИ файл config.php отсутствует. Цитировать квирк 107 в reason.
|
||
|
||
### П2 — `.env` line endings (квирк 105)
|
||
|
||
```bash
|
||
ssh liderra "file /var/www/liderra.ru/app/.env"
|
||
```
|
||
|
||
Ожидаемый формат: `ASCII text` (одна строка).
|
||
|
||
Зелёный = вывод содержит `ASCII text` БЕЗ суффикса `with CRLF line terminators`.
|
||
|
||
Красный = вывод содержит `CRLF`. Цитировать квирк 105.
|
||
|
||
### П3 — Свободное место на диске
|
||
|
||
```bash
|
||
ssh liderra "df -h / | tail -1"
|
||
```
|
||
|
||
Ожидаемый формат: одна строка `/dev/... размер используется доступно %% маунт`.
|
||
|
||
Зелёный = использовано ≤ 85%.
|
||
|
||
Красный = > 85%. Reason: «диск %% занят, выкат может не уместиться».
|
||
|
||
### П4 — Свежесть последнего бэкапа БД
|
||
|
||
```bash
|
||
ssh liderra "ls -lt /var/backups/db/ 2>/dev/null | head -2 | tail -1"
|
||
```
|
||
|
||
Ожидаемый формат: одна строка `ls -l` (или пустая если каталог пуст).
|
||
|
||
Зелёный = mtime файла ≤ 24 часов назад. Распарсить дату из вывода и сравнить с текущим временем UTC.
|
||
|
||
Красный = бэкап старше 24 часов или каталог пуст. Reason: «бэкап несвежий, выкат с миграциями опасен».
|
||
|
||
### П5 — Health очереди
|
||
|
||
```bash
|
||
ssh liderra "pgrep -fa queue:work; tail -50 /var/www/liderra.ru/app/storage/logs/laravel.log | grep -ic -e failed -e error"
|
||
```
|
||
|
||
Ожидаемый формат: одна строка процесса (от `pgrep`) + одна цифра (от `grep -c`).
|
||
|
||
Зелёный = есть `queue:work` процесс И цифра ≤ 5.
|
||
|
||
Красный = нет процесса ИЛИ цифра > 5. Reason соответственно.
|
||
|
||
### П6 — Nginx config syntax
|
||
|
||
```bash
|
||
ssh liderra "sudo nginx -t 2>&1"
|
||
```
|
||
|
||
Ожидаемый формат: 2 строки — `nginx: the configuration file ... syntax is ok` + `nginx: configuration file ... test is successful`.
|
||
|
||
Зелёный = обе строки присутствуют.
|
||
|
||
Красный = любое иное. Reason: «nginx config сломан».
|
||
|
||
### П7 — fail2ban активен
|
||
|
||
```bash
|
||
ssh liderra "sudo systemctl is-active fail2ban"
|
||
```
|
||
|
||
Ожидаемый формат: одна строка — `active` ИЛИ `inactive` ИЛИ `failed`.
|
||
|
||
Зелёный = `active`.
|
||
|
||
Красный = иначе. Reason: «fail2ban не работает, выкат расширяет attack surface».
|
||
|
||
### П8 — Pending миграции
|
||
|
||
```bash
|
||
ssh liderra "cd /var/www/liderra.ru/app && php artisan migrate:status 2>&1 | grep -c Pending"
|
||
```
|
||
|
||
Ожидаемый формат: одна цифра.
|
||
|
||
Зелёный = `0` ИЛИ количество совпадает с тем, что заявлено в brief'е (главный исполнитель сказал «к выкату пойдут N миграций»).
|
||
|
||
Красный = есть pending, не заявленные в brief'е. Reason: «N необъявленных миграций — какие?».
|
||
|
||
## Процедура (5 шагов)
|
||
|
||
1. Принять brief от главного исполнителя («готовлю выкат X — что в нём: миграции / только code / scp-патч»). Если brief не упомянул миграции — П8 ожидает 0.
|
||
2. Прогнать 8 проверок последовательно (sequential, не parallel — упрощает отладку при сбоях SSH).
|
||
3. Собрать результаты в таблицу из 8 строк (см. Output format).
|
||
4. Применить решающее правило:
|
||
- Все 8 зелёных → **GO** + список smoke-команд для пост-выкатной проверки
|
||
- Хоть одна красная → **NO-GO** + причина + ссылка на квирк (если есть) + что нужно сделать
|
||
- Любая «не смог проверить» (SSH timeout, неожиданный формат) → **NO-GO с эскалацией**
|
||
5. Опционально (если в brief'е `--post-smoke`): после ответа главному исполнителю «выкат прошёл, запускай post-smoke» — повторить проверки + добавить HTTP 200 на главной (`curl -fsSL -o /dev/null -w '%{http_code}' https://liderra.ru/`).
|
||
|
||
## Output format
|
||
|
||
В конце работы вернуть один рапорт:
|
||
|
||
```
|
||
=== PROD-DEPLOY-VALIDATOR RAPORT ===
|
||
Brief: <из входных данных>
|
||
Проверки:
|
||
П1 config:cache владелец [GREEN / RED] — <вывод | причина>
|
||
П2 .env line endings [GREEN / RED] — <вывод | причина>
|
||
П3 свободное место [GREEN / RED] — <вывод | причина>
|
||
П4 свежесть бэкапа БД [GREEN / RED] — <вывод | причина>
|
||
П5 health очереди [GREEN / RED] — <вывод | причина>
|
||
П6 nginx syntax [GREEN / RED] — <вывод | причина>
|
||
П7 fail2ban active [GREEN / RED] — <вывод | причина>
|
||
П8 pending миграции [GREEN / RED] — <вывод | причина>
|
||
|
||
Вердикт: GO / NO-GO
|
||
|
||
Если NO-GO — что делать:
|
||
<конкретные команды для починки>
|
||
<ссылка на квирк memory если применимо>
|
||
|
||
Если GO — smoke-команды для пост-выкатной проверки:
|
||
- curl -fsSL -o /dev/null -w '%{http_code}\n' https://liderra.ru/
|
||
- ssh liderra "cd /var/www/liderra.ru/app && php artisan migrate:status | tail -20"
|
||
- ssh liderra "tail -20 /var/www/liderra.ru/app/storage/logs/laravel.log"
|
||
=== END RAPORT ===
|
||
```
|
||
|
||
## Boundaries (что НЕ делать)
|
||
|
||
- НЕ выкатывать (выкат — главный исполнитель)
|
||
- НЕ менять конфиги на боевом
|
||
- НЕ запускать миграции, не рестартить очереди, не править .env
|
||
- НЕ угадывать: неожиданный output = NO-GO с эскалацией
|
||
- НЕ цитировать пароли / ключи / токены если они случайно появились в выводе
|
||
|
||
## Escalation triggers
|
||
|
||
Вернуть NO-GO с пометкой «нужен человек» если:
|
||
|
||
- SSH-таймаут больше 30 сек (сеть лежит или сервер не отвечает)
|
||
- 2+ проверки вернули неожиданный формат (не вписывается в документированный шаблон выше) — что-то системно изменилось, агент не должен угадывать
|
||
- Brief сослался на проверку, которой нет в этом checklist'е (расширение checklist'а — отдельная задача)
|
||
- Обнаружены файлы / процессы с подозрительными именами (возможный компромет) — критическая эскалация
|
||
|
||
## Прецеденты в проекте
|
||
|
||
- 24.05.2026 03:46 UTC — портал лежал 18 мин из-за квирка 107. Эта проверка (П1) — прямая защита.
|
||
- 23.05.2026 — partition+RLS+log fix на боевом (push `7e0c8dde`). Сейчас бэкап-крон активен (П4).
|
||
- 22.05.2026 — HTTPS + fail2ban + ModSecurity WAF активированы (см. memory `project_server_hardening.md`). П7 проверяет fail2ban.
|
||
````
|
||
|
||
### Step 4: Validate YAML frontmatter
|
||
|
||
- [ ] **Прогнать YAML parse:**
|
||
|
||
```bash
|
||
node -e "const fs=require('fs'); const m=fs.readFileSync('.claude/agents/prod-deploy-validator.md','utf8').match(/^---\n([\s\S]+?)\n---/); if(!m){console.error('NO FRONTMATTER'); process.exit(1)}; console.log(m[1])"
|
||
```
|
||
|
||
Expected: вывод YAML-блока с name, description, tools, model. Без ошибок.
|
||
|
||
### Step 5: Verify required sections
|
||
|
||
- [ ] **Проверить наличие ключевых элементов:**
|
||
|
||
```bash
|
||
grep -c "^### П" .claude/agents/prod-deploy-validator.md
|
||
```
|
||
|
||
Expected: 8 (восемь проверок П1-П8).
|
||
|
||
```bash
|
||
grep -c "Квирк 107" .claude/agents/prod-deploy-validator.md
|
||
```
|
||
|
||
Expected: ≥2 (упомянут в Контексте + в П1).
|
||
|
||
### Step 6: Commit Task 2
|
||
|
||
- [ ] **Commit:**
|
||
|
||
```bash
|
||
git add .claude/agents/prod-deploy-validator.md && git commit -m "$(cat <<'EOF'
|
||
feat(agents): add prod-deploy-validator project agent (8 SSH checks, Sonnet 4.6)
|
||
|
||
Pre-flight validator before liderra.ru deploys. Runs 8 read-only SSH checks,
|
||
returns GO/NO-GO with concrete reason + memory quirk reference.
|
||
Driven by 24.05.2026 03:46 UTC live incident (portal down 18 min, quirk 107
|
||
— config:cache running as root instead of www-data).
|
||
|
||
Spec: docs/superpowers/specs/2026-05-24-controller-offload-agents-design.md §4.
|
||
Precedent: .claude/agents/pest-parallel-debugger.md format.
|
||
|
||
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
EOF
|
||
)" -- .claude/agents/prod-deploy-validator.md
|
||
```
|
||
|
||
Expected: коммит создан, pre-commit lefthook прошёл. При markdownlint/cspell ошибках — поправить (cspell-words.txt добавления под секцией «Controller-offload agents (24.05.2026)» если ещё не добавлено в Task 1).
|
||
|
||
---
|
||
|
||
## Task 3: First dry-run smoke test for both agents
|
||
|
||
**Files:** none (только запуск агентов через Task-инструмент главного исполнителя).
|
||
|
||
**Цель:** убедиться что (1) Claude Code загрузил оба новых агента в текущей сессии или после рестарта; (2) каждый возвращает рапорт ожидаемого формата без падений.
|
||
|
||
### Step 1: Refresh agent registry
|
||
|
||
- [ ] **Запустить `/agents` команду или сделать рестарт сессии,** чтобы Claude Code загрузил новые `.claude/agents/*.md` файлы.
|
||
|
||
Альтернатива: команда `/exit` + перезапуск, либо использовать sub-skill `agentic-actions-auditor:agentic-actions-auditor` если он умеет refresh — не уверен; рестарт надёжнее.
|
||
|
||
### Step 2: Smoke normative-sync с фиктивным brief
|
||
|
||
- [ ] **Из главной сессии Claude позвать агента через инструмент Agent с такими параметрами:**
|
||
|
||
```
|
||
subagent_type: "normative-sync"
|
||
description: "Smoke test normative-sync"
|
||
prompt: |
|
||
SMOKE TEST — не правь файлы фактически.
|
||
Brief: «закрыли тестовую задачу X — добавили 1 узел Y в карту тулчейна»
|
||
Прогон в dry-run режиме: пройди свою процедуру до шага 4 (вычисление новых версий),
|
||
верни рапорт в формате «вот что бы я сделал», но НЕ редактируй ни одного файла.
|
||
Ожидаемый ответ — текстовый план правок в 4 файлах + предлагаемые новые версии.
|
||
```
|
||
|
||
Expected pass criteria: агент вернул рапорт со следующими элементами:
|
||
|
||
- Упомянул pre-flight результат (git fetch чистый или коллизия)
|
||
- Предложил version bumps по 4 файлам (с конкретными цифрами vX.Y → vX.Z)
|
||
- Назвал тип bump'а (minor — потому что узел добавился, не правило удалилось)
|
||
- Перечислил какие секции тронет в каждом файле
|
||
- Не редактировал файлов фактически (`git status` после остался прежним)
|
||
|
||
### Step 3: Smoke prod-deploy-validator с фиктивным brief
|
||
|
||
- [ ] **Позвать агента через инструмент Agent:**
|
||
|
||
```
|
||
subagent_type: "prod-deploy-validator"
|
||
description: "Smoke test prod-deploy-validator"
|
||
prompt: |
|
||
Brief: «проверь готовность боевого к выкату — простой docs-only коммит, миграций нет».
|
||
Прогон в нормальном режиме (агент READ-ONLY по дизайну, ничего не сломает).
|
||
Ожидаемый ответ — таблица 8 проверок + GO/NO-GO вердикт.
|
||
```
|
||
|
||
Expected pass criteria: агент вернул рапорт со следующими элементами:
|
||
|
||
- 8 строк проверок с GREEN/RED статусом каждая (некоторые могут быть RED — это нормально, проверяем что agent корректно классифицировал)
|
||
- Вердикт GO или NO-GO явно указан
|
||
- Если RED — указана причина и ссылка на квирк (104-108) если применимо
|
||
- Не было модификаций на боевом (агент по дизайну read-only — но проверить можно `ssh liderra "ls -la /var/www/liderra.ru/app/.env"` до и после: mtime не изменился).
|
||
|
||
### Step 4: Verify and record outcomes
|
||
|
||
- [ ] **Записать результаты smoke'а в `memory/feedback_specialized_agents.md`** (новый файл) с разделом «First smoke 24.05.2026»:
|
||
|
||
```bash
|
||
# Создать файл если нет; добавить запись
|
||
```
|
||
|
||
Шаблон записи:
|
||
|
||
```markdown
|
||
---
|
||
name: specialized-agents
|
||
description: Specialized project agents normative-sync + prod-deploy-validator — first smoke outcomes and lessons
|
||
metadata:
|
||
type: feedback
|
||
---
|
||
|
||
# Project agents normative-sync + prod-deploy-validator
|
||
|
||
## First smoke 24.05.2026
|
||
|
||
### normative-sync
|
||
- Возвращённый рапорт: <скопировать сюда первый рапорт агента>
|
||
- Замечания: <что пошло хорошо / что плохо>
|
||
- Корректировки в `.claude/agents/normative-sync.md` после smoke'а: <none / список>
|
||
|
||
### prod-deploy-validator
|
||
- Возвращённый рапорт: <скопировать>
|
||
- Замечания: <...>
|
||
- Корректировки в `.claude/agents/prod-deploy-validator.md` после smoke'а: <none / список>
|
||
```
|
||
|
||
После создания памяти — добавить ссылку в `memory/MEMORY.md` index одной строкой (~150 chars):
|
||
|
||
```markdown
|
||
- [Project agents normative-sync + prod-deploy-validator](feedback_specialized_agents.md) — first smoke 24.05; what works / what to tune
|
||
```
|
||
|
||
### Step 5: Commit smoke outcomes
|
||
|
||
- [ ] **Commit:**
|
||
|
||
```bash
|
||
git add memory/feedback_specialized_agents.md memory/MEMORY.md && git commit -m "$(cat <<'EOF'
|
||
docs(memory): first smoke outcomes for normative-sync + prod-deploy-validator agents
|
||
|
||
Captured initial smoke test results for both new project agents.
|
||
Both spawned successfully and returned reports in expected format.
|
||
|
||
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
EOF
|
||
)" -- memory/feedback_specialized_agents.md memory/MEMORY.md
|
||
```
|
||
|
||
Expected: коммит создан, lefthook прошёл.
|
||
|
||
---
|
||
|
||
## Self-review (после написания плана)
|
||
|
||
**1. Spec coverage check** — каждая секция спека покрыта задачей?
|
||
|
||
| Спек секция | Покрыто задачей |
|
||
|-------------|-----------------|
|
||
| §3 Агент №1 normative-sync — описание | Task 1 (полный системный prompt с §3.4 процедурой, §3.6 знаниями, §3.7 границами, §3.8 рисками) |
|
||
| §3.5 Модель Sonnet 4.6 | Task 1 frontmatter `model: sonnet` |
|
||
| §3.6 system prompt content | Task 1 Step 2 (содержание файла) |
|
||
| §4 Агент №2 prod-deploy-validator — описание | Task 2 (полный системный prompt с §4.4 проверками, §4.7 квирками, §4.8 границами) |
|
||
| §4.6 Модель Sonnet 4.6 | Task 2 frontmatter `model: sonnet` |
|
||
| §4.7 квирки 104-108 в памяти | Task 2 Step 3 (раздел «Квирки производственного окружения») |
|
||
| §5.1 файлы агентов в `.claude/agents/` | Task 1 + Task 2 (создание файлов) |
|
||
| §5.2 frontmatter format | Task 1 + Task 2 Step 4 (валидация YAML) |
|
||
| §5.3 какие скилы НЕ даём | Покрыто в самом system prompt каждого агента (упомянуто в Boundaries) |
|
||
| §5.5 классификация-маппинг | **DEFERRED** — отдельная задача brain governance (см. spec §6 out-of-scope) |
|
||
| §6 dogfooding регистрация в Tooling §0 | Произойдёт ВО ВРЕМЯ первого реального использования агента #1 — это не часть текущего плана |
|
||
| §7 OQ-1/2/3 | Решения по умолчанию из спека приняты — никаких MCP-расширений / TaskOutput-бэкграунда / автодействий |
|
||
| §9 next step | Task 3 (smoke = первое реальное использование, превращающее план в эксплуатацию) |
|
||
|
||
**2. Placeholder scan** — ни одного TBD / TODO в плане. Каждый шаг содержит конкретные команды или код. Содержимое агент-файлов выписано полностью.
|
||
|
||
**3. Type consistency** — `normative-sync` и `prod-deploy-validator` (slug-формат) используются единообразно во всех trех задачах. `Sonnet 4.6` упомянут в frontmatter обоих файлов как `model: sonnet` (короткий идентификатор для Claude Code).
|
||
|
||
Гэп: SSH alias `liderra` в Task 2 предполагается существующим в `~/.ssh/config`. Если его нет — Task 2 Step 2 ловит это и эскалирует на Дмитрия. Не нужно тратить ещё одну задачу на «настроить SSH alias», потому что (1) Дмитрий уже использует `ssh liderra` в своих рабочих процессах (см. push-историю с 22.05); (2) если alias нужен — Дмитрий настроит за 1 минуту.
|
||
|
||
---
|
||
|
||
## Execution handoff
|
||
|
||
**Plan complete and saved to `docs/superpowers/plans/2026-05-24-controller-offload-agents.md`. Two execution options:**
|
||
|
||
1. **Subagent-Driven (recommended)** — главный исполнитель диспатчит свежий субагент на каждую из 3 задач, делает review между задачами. Plus — это сразу первая dogfood-проверка субагент-механизма для нашего случая (Pravila §15.1).
|
||
|
||
2. **Inline Execution** — задачи выполняются прямо в этой сессии через `superpowers:executing-plans`, с чекпоинтами для ревью.
|
||
|
||
**Which approach?**
|