docs router-mentor: оглавление + рецепт escape + дедуп
This commit is contained in:
@@ -1,13 +1,31 @@
|
||||
# Как работать под стеной «роутер-наставник» (шпаргалка для сессий)
|
||||
|
||||
> Читать ПЕРЕД работой под стеной. **Обновлено 16.06.2026** — Фикс 1/2/3 (видимость вердикта,
|
||||
> память кругов, owner-seal арбитраж) + находки F-J/F-K. Цель — не разбираться по исходникам.
|
||||
> память кругов, owner-seal арбитраж) + находки F-J/F-K + точный рецепт escape. Цель — не
|
||||
> разбираться по исходникам.
|
||||
|
||||
**Суть:** под стеной реальная работа (Edit/Write/Bash по коду) проходит ТОЛЬКО как шаг
|
||||
**опечатанного** плана. Поток: спека → (печать) → план → (печать) → шаги по порядку →
|
||||
авто-завершение. Печать встаёт за **ОДИН заход**.
|
||||
|
||||
## Рецепт церемонии (точные форматы — иначе печать не встанет)
|
||||
## Содержание
|
||||
|
||||
1. [Рецепт церемонии](#рецепт-церемонии) — как поставить спеку+план, чтобы печать встала
|
||||
2. [Частые ошибки](#частые-ошибки) — учись на чужих шишках (вкл. десинк F-J)
|
||||
3. [Нельзя: правка машинерии стены (F-K)](#нельзя-правка-машинерии-стены-f-k)
|
||||
4. [Видимость вердикта (Фикс 1)](#видимость-вердикта-фикс-1) — вердикт виден сам
|
||||
5. [Память кругов (Фикс 2)](#память-кругов-фикс-2)
|
||||
6. [Арбитраж: owner-seal (Фикс 3)](#арбитраж-owner-seal-фикс-3)
|
||||
7. [Как узнать состояние стены](#как-узнать-состояние-стены) — одна проба
|
||||
8. [Аварийный выход владельца (escape)](#аварийный-выход-владельца-escape) — как дать правильно
|
||||
9. [Коммит](#коммит)
|
||||
10. [Пуш кода через стену](#пуш-кода-через-стену)
|
||||
11. [Судьи-машины](#судьи-машины)
|
||||
12. [Минимальный пример и что под капотом](#минимальный-пример-и-что-под-капотом)
|
||||
|
||||
## Рецепт церемонии
|
||||
|
||||
Точные форматы — иначе печать не встанет.
|
||||
|
||||
**1. СПЕКА** — Write НОВОГО файла в `docs/superpowers/specs/<уникальное-имя>.md`:
|
||||
|
||||
@@ -32,11 +50,11 @@
|
||||
**3. Реализация** — шаги по порядку, каждый Edit/Write/Bash совпадает с **текущим** шагом (op+object).
|
||||
Стена двигает указатель по одному. После последнего шага печать снимается сама → разговорный режим.
|
||||
|
||||
## Частые ошибки (учись на чужих шишках)
|
||||
## Частые ошибки
|
||||
|
||||
- **Ловушка устаревшего указателя.** Повторный план **байт-в-байт** = тот же `plan_id` → старая
|
||||
позиция НЕ сбрасывается → застреваешь. Лечение: другой план (другое имя/шаги → новый `plan_id`)
|
||||
ИЛИ `FLOOR-ESCAPE: plan-done` (см. ниже). Удаление файлов НЕ помогает (позиция в runtime).
|
||||
ИЛИ `FLOOR-ESCAPE: plan-done` (см. escape). Удаление файлов НЕ помогает (позиция в runtime).
|
||||
- **Авторская запись.** Свободно пишется только **НОВЫЙ** `.md` в `specs/`/`plans/`. Существующий
|
||||
файл и код — только как шаг плана (либо escape, см. F-K).
|
||||
- **Чтение кода.** В режиме реализации чтение вне путей текущего шага блокируется. Свободно — в
|
||||
@@ -48,11 +66,12 @@
|
||||
- **Десинк указателя (F-J, 16.06).** Если PreToolUse-блокер (тупой судья навыков / `normative §6`)
|
||||
роняет действие exit-2, а `enforce-supreme-gate` (раньше в цепочке) УЖЕ сдвинул указатель — план
|
||||
застревает (указатель уехал, действие не прошло). **Сброс:** `FLOOR-ESCAPE: plan-done` ИЛИ новый
|
||||
план с другим именем. (Корень для brain: supreme-gate не должен двигать указатель, если со-хук блокнёт.)
|
||||
план с другим именем. (Второй, отдельный десинк — на пуше кода, см. «Пуш кода через стену».)
|
||||
(Корень для brain: supreme-gate не должен двигать указатель, если со-хук блокнёт.)
|
||||
- **Наставник/судья async** (~25-32с). Печать встаёт не мгновенно. Per-attempt таймаут 90с
|
||||
(`HEAVY_LLM_TIMEOUT_MS`). degraded («не дозвонился») → просто повтор.
|
||||
|
||||
## ⛔ Правка машинерии стены под стеной — НЕЛЬЗЯ (F-K, 16.06)
|
||||
## ⛔ Нельзя: правка машинерии стены (F-K)
|
||||
|
||||
Файлы `tools/enforce-*.mjs`, `judge-*`, `mentor-*`, `floor-*`, `escape-grant`, `plan-lock` и т.п. —
|
||||
**discipline-source**: `enforce-normative-content-rules §6` блокирует их правку под стеной как «ЗАКОН»,
|
||||
@@ -61,22 +80,26 @@ CARD-путь (`sealedPlanCoversEdit` под опечатанным планом
|
||||
**Правь такие файлы в ТЕРМИНАЛЕ** (node-скрипт string-replace по точным якорям + бэкап + verify) и
|
||||
**сразу коммить** — несохранённые правки tracked-файлов теряются на `git restore` (инцидент 16.06).
|
||||
|
||||
## Видимость вердикта (Фикс 1, 16.06) — лог антитуннеля больше НЕ нужен
|
||||
## Видимость вердикта (Фикс 1)
|
||||
|
||||
Исход судьи/наставника на каждой судимой записи теперь **виден контроллеру**: хук
|
||||
`enforce-verdict-surface` (UserPromptSubmit) показывает строку
|
||||
Лог антитуннеля больше НЕ нужен. Исход судьи/наставника на каждой судимой записи теперь **виден
|
||||
контроллеру**: хук `enforce-verdict-surface` (UserPromptSubmit) показывает строку
|
||||
`✅ GO — опечатано / 🚫 NO-GO: <дословно> / ⚠ не дозвонился (<причина>) / ⏭ пропуск (<причина>)`
|
||||
в начале **СЛЕДУЮЩЕГО** хода. Требует регистрации хука в `settings.json` (UserPromptSubmit). Чтение
|
||||
`~/.claude/runtime` по-прежнему закрыто — но вердикт спрашивать у владельца больше не надо.
|
||||
|
||||
## Память кругов (Фикс 2, 16.06)
|
||||
Под капотом: `enforce-verdict-surface` + `verdict-surface-store` + `verdict-outcome-line`.
|
||||
|
||||
## Память кругов (Фикс 2)
|
||||
|
||||
- **Судья:** круг 1 слеп (чистый суд продукт-против-цели); круг 2+ видит СВОИ прошлые претензии
|
||||
**дословной цитатой** + как контроллер их закрыл (из `## Переговоры`) → не противоречит себе.
|
||||
- **Наставник:** видит свои прошлые претензии + **доводы контроллера**, обязан переоценить ТЕКУЩИЙ
|
||||
план (снятое не повторять). (Полный «единый цикл» спека=план — в дизайн-доке для brain.)
|
||||
|
||||
## Арбитраж — owner-seal (Фикс 3, 16.06)
|
||||
Под капотом: `round-memory-store` + блоки памяти в `buildJudgePrompt`/`buildMentorVerdictPrompt`.
|
||||
|
||||
## Арбитраж: owner-seal (Фикс 3)
|
||||
|
||||
На тупике (3-й круг подряд NO-GO) карточка даёт 3 кнопки:
|
||||
|
||||
@@ -84,38 +107,54 @@ CARD-путь (`sealedPlanCoversEdit` под опечатанным планом
|
||||
- **Согласен с замечанием** → контроллер переделывает, счётчик сброшен;
|
||||
- **Своё решение** → владелец вписывает указание → правка → печать.
|
||||
|
||||
«Держусь/Своё» владелец подписывает кликом `FLOOR-ESCAPE: owner-seal:<hash>` — путь печати
|
||||
(`sealOnWiredGo`) ставит frozenPlan/frozenArtifact несмотря на NO-GO (минуя и mentor freeze-gate).
|
||||
«Держусь/Своё» владелец подписывает кликом по кнопке-метке `FLOOR-ESCAPE: owner-seal:<hash>` — путь
|
||||
печати (`sealOnWiredGo`) ставит frozenPlan/frozenArtifact несмотря на NO-GO (минуя и mentor freeze-gate).
|
||||
|
||||
## Как узнать состояние (одна проба)
|
||||
Под капотом: `seal-override` + owner-seal в `sealOnWiredGo`/`sealTurnProd`.
|
||||
|
||||
Безобидный не-readonly Bash, напр. `node --version` (`echo` режет router-gate как не-whitelist):
|
||||
## Как узнать состояние стены
|
||||
|
||||
Одна проба — безобидный не-readonly Bash, напр. `node --version` (`echo` режет router-gate как не-whitelist):
|
||||
|
||||
- блок «разговорный режим» → стена включена, чисто (нет печати);
|
||||
- блок «ожидался шаг N: …» → ты в середине плана на шаге N (возможно, застрял — см. F-J);
|
||||
- выполнилось → стена снята (или открыт escape).
|
||||
|
||||
## Аварийный выход владельца (escape) — разовое подписанное разрешение
|
||||
## Аварийный выход владельца (escape)
|
||||
|
||||
Владелец в ответе на **AskUserQuestion** пишет метку `FLOOR-ESCAPE: <action>` — каноническая строка
|
||||
([tools/escape-grant.mjs](../../tools/escape-grant.mjs)):
|
||||
Разовое подписанное разрешение на ОДНО действие под стеной. Владелец даёт его **в ответе на
|
||||
AskUserQuestion**: в ответе должна **буквально** присутствовать метка `FLOOR-ESCAPE: <action>` —
|
||||
среда ищет её регэкспом в конце ответа (`/FLOOR-ESCAPE:\s*(.+)$/`, см.
|
||||
[tools/askuser-answer-parser.mjs](../../tools/askuser-answer-parser.mjs)::`toFloorEscapeRecord`).
|
||||
Каноны `<action>` ([tools/escape-grant.mjs](../../tools/escape-grant.mjs)::`canonicalAction`):
|
||||
|
||||
- Bash → `bash:<норм. команда>` · PowerShell → `powershell:<норм. команда>`
|
||||
- Skill → `skill:<имя в нижнем регистре>` · Write/Edit → `write:<путь, lowercase + прямые слэши>`
|
||||
- Skill → `skill:<имя lowercase>` · Write/Edit → `write:<путь>`
|
||||
- MCP → `mcp:<имя>:<args-json>`
|
||||
- Завершить застрявший план → `plan-done` (резерв-метка, не от реального действия)
|
||||
- Опечатать на арбитраже → `owner-seal:<hash>` (Фикс 3)
|
||||
- Завершить застрявший план → `plan-done` (резерв-метка) · Опечатать на арбитраже → `owner-seal:<hash>` (Фикс 3)
|
||||
|
||||
Среда (`enforce-askuser-answer-parser`, PostToolUse) пишет и **подписывает** пропуск ключом владельца
|
||||
(`router-mentor-receipts`); одноразовый, окно **5 минут**, точное совпадение `canonicalAction`.
|
||||
**Применяй escape СРАЗУ** (дитёж → истечение окна).
|
||||
**Канон пути для `write:`** — абсолютный, **lowercase**, прямые слэши `/`, NFC (ровно как даёт
|
||||
`pathNormalizeSafe`). Пример: `write:c:/моя/проекты/портал crm/документация/docs/superpowers/router-mentor-wall-guide.md`.
|
||||
Грант одноразовый, окно **5 минут**, точное посимвольное совпадение `canonicalAction` с действием
|
||||
инструмента. **Применяй escape СРАЗУ** (иначе окно истечёт).
|
||||
|
||||
**Активация (обязательна в settings.json):** PostToolUse `AskUserQuestion` → `enforce-askuser-answer-parser`
|
||||
(writer) + `Edit|Write|MultiEdit|Bash|PowerShell` → `enforce-floor-escape-consume` (one-shot). Без них клик
|
||||
уходит «в никуда».
|
||||
### Как дать escape ПРАВИЛЬНО (иначе клик уходит «в никуда») — урок 16.06
|
||||
|
||||
- ✅ **Контроллер делает САМУ кнопку AskUserQuestion = строкой `FLOOR-ESCAPE: <action>`**, владелец
|
||||
её осознанно выбирает. Тогда ответ = текст кнопки = содержит метку → среда подписывает грант.
|
||||
Это и есть «контроллер спрашивает — владелец выбирает — но ответ сформулирован верно».
|
||||
- ❌ **Обычная кнопка** («Разрешаю», «Ок», «Да») — её текст НЕ содержит `FLOOR-ESCAPE:` → грант НЕ
|
||||
пишется → стена держит. (Грабли: 3 клика подряд впустую, прежде чем поняли причину.)
|
||||
- ❌ **Контроллер уговаривает владельца вписать метку в свободное поле ответа** — защита
|
||||
`detectOtherSocialEng` (`askuser-answer-parser.mjs`) ловит такие фразы-подсказки как соц-инженерию
|
||||
и флагует. Не диктуй текст в свободное поле — **давай метку готовой кнопкой**.
|
||||
|
||||
**Что escape чтит:** стена М2 / пол М5 / судья М4 / гейт памяти (память/нормативка). **НЕ чтит:**
|
||||
`router-gate` (git — отдельный канал) и `normative §6` для discipline-source (F-K — правь терминалом).
|
||||
`router-gate` (git — отдельный канал, см. «Коммит») и `normative §6` для discipline-source (F-K — правь терминалом).
|
||||
|
||||
**Активация (обязательна в settings.json):** PostToolUse `AskUserQuestion` → `enforce-askuser-answer-parser`
|
||||
(writer, подписывает грант ключом `router-mentor-receipts`) + `Edit|Write|MultiEdit|Bash|PowerShell` →
|
||||
`enforce-floor-escape-consume` (one-shot, гасит грант). Без них клик уходит «в никуда».
|
||||
|
||||
## Коммит
|
||||
|
||||
@@ -128,22 +167,30 @@ CARD-путь (`sealedPlanCoversEdit` под опечатанным планом
|
||||
- **git auto-gc на Windows** может зациклить `Unlink … .idx failed. Try again? (y/n)` (pack держит
|
||||
др. процесс — VSCode Git / gitea) → жми **`n`**; коммит уже создан. Профилактика: `git config gc.auto 0`.
|
||||
|
||||
## Что под капотом
|
||||
## Пуш кода через стену
|
||||
|
||||
- Стена = `enforce-supreme-gate` (PreToolUse на всё); оркестратор = `enforce-mentor-then-judge`
|
||||
(PostToolUse Write) гонит наставника → судью по очереди.
|
||||
- Фикс 1: `enforce-verdict-surface` + `verdict-surface-store` + `verdict-outcome-line`. Фикс 2:
|
||||
`round-memory-store` + блоки памяти в `buildJudgePrompt`/`buildMentorVerdictPrompt`. Фикс 3:
|
||||
`seal-override` + owner-seal в `sealOnWiredGo`/`sealTurnProd`.
|
||||
- Живой шов: env `ROUTER_MENTOR_SEAM_ENABLED=1`, `ROUTER_MENTOR_JUDGE_ENABLED=1`,
|
||||
`ROUTER_MENTOR_JUDGE_MODE=block` + ключи наставника/судьи/роутера.
|
||||
Пуш кода (не docs-only) проходит частокол ПОСЛЕ печати плана: verify-gate → criterion-gate → pre-push.
|
||||
Порядок гейтов и грабли (урок 16.06):
|
||||
|
||||
## Минимальный пример церемонии
|
||||
|
||||
Задача: чистый модуль `tools/<имя>.mjs` через TDD. Спека: 5 секций `{#D1..D5}` + verified-context
|
||||
(якорь на `cost-pricing.mjs`) + `## Цель`. План: `skills-json` `["test-driven-development"]`; шаги
|
||||
тест-RED → vitest-RED → модуль → vitest-GREEN → … → регрессия. Регрессия (одиночная команда):
|
||||
`npx vitest run --root app --config vitest.config.tools.mjs`.
|
||||
1. **verify-gate** (`enforce-verify-gate`) требует свежую подписанную расписку. Производит её
|
||||
**`node tools/produce-verify-receipt.mjs`** (гонит tools-сюиту vitest, подписывает по отпечатку
|
||||
staged-diff). Ставь ПЕРВЫМ шагом плана. Расписка — side-channel файл
|
||||
`~/.claude/runtime/verify-receipt.json`, НЕ аргумент push (судья может ошибочно требовать «шаг
|
||||
доставки расписки» — опровергай: хук сам читает фиксированный путь).
|
||||
2. **criterion-gate** (`enforce-criterion-gate`) на git push с кодом требует валидный frozen-plan.
|
||||
⚠️ **Десинк:** если push — ПОСЛЕДНИЙ шаг плана, supreme-gate (раньше в цепочке) на совпадении
|
||||
удаляет frozen-plan ДО проверки criterion-gate → `frozenPlanValid=false` → ложный блок «кодовое
|
||||
изменение без валидного запечатанного плана». **Лечение:** сделать push НЕ-терминальным — добавить
|
||||
шаг ПОСЛЕ него (push исходники не правит → criteria=[] → гейт пропустит).
|
||||
⚠️ **Трейлинг-шаг — МУТИРУЮЩИЙ, не read-only.** read-only (`git log`) выполнится, но не сдвинет
|
||||
impl-указатель → план повиснет (потребуется `plan-done`). Бери мутирующий завершающий шаг.
|
||||
3. **lefthook pre-push** (gitleaks/lychee) — локальный git-хук, НЕ стена. На pre-existing находках
|
||||
обходи ТОЧЕЧНО: `LEFTHOOK_EXCLUDE=<hook1>,<hook2> git push …` (не глухой `LEFTHOOK=0` — судья
|
||||
флагует его `[heavy]`). Имена хуков — из вывода pre-push.
|
||||
4. **Квирк наставника:** чистый GO с пустым `recommendation` → проверка-содержательности рубит
|
||||
(`no_mentor_go`) → судья НЕ вызывается → план не печатается. Обход: добавь в `## Переговоры` круг,
|
||||
прямо приглашающий наставника записать forward-`recommendation`. Корень — баг машинерии (см.
|
||||
`docs/superpowers/2026-06-16-mentor-empty-recommendation-bug.md` → claude-brain).
|
||||
|
||||
## Судьи-машины
|
||||
|
||||
@@ -155,3 +202,15 @@ CARD-путь (`sealedPlanCoversEdit` под опечатанным планом
|
||||
|
||||
**Правки памяти/CLAUDE.md под стеной:** объяви `claude-md-management` в `skills-json` И реально вызови
|
||||
до записи — иначе гейт памяти/судья навыков заблокируют.
|
||||
|
||||
## Минимальный пример и что под капотом
|
||||
|
||||
**Пример церемонии.** Задача: чистый модуль `tools/<имя>.mjs` через TDD. Спека: 5 секций `{#D1..D5}` +
|
||||
verified-context (якорь на `cost-pricing.mjs`) + `## Цель`. План: `skills-json`
|
||||
`["test-driven-development"]`; шаги тест-RED → vitest-RED → модуль → vitest-GREEN → … → регрессия.
|
||||
Регрессия (одиночная команда): `npx vitest run --root app --config vitest.config.tools.mjs`.
|
||||
|
||||
**Под капотом.** Стена = `enforce-supreme-gate` (PreToolUse на всё); оркестратор =
|
||||
`enforce-mentor-then-judge` (PostToolUse Write) гонит наставника → судью по очереди. Живой шов: env
|
||||
`ROUTER_MENTOR_SEAM_ENABLED=1`, `ROUTER_MENTOR_JUDGE_ENABLED=1`, `ROUTER_MENTOR_JUDGE_MODE=block` +
|
||||
ключи наставника/судьи/роутера. Имена хуков Фиксов 1/2/3 — в их разделах выше.
|
||||
|
||||
Reference in New Issue
Block a user