diff --git a/bags/router-mentor-wall-GUIDE.md b/bags/router-mentor-wall-GUIDE.md index 807a9de..f5b48f9 100644 --- a/bags/router-mentor-wall-GUIDE.md +++ b/bags/router-mentor-wall-GUIDE.md @@ -13,6 +13,14 @@ Закрыты главные баги стены: теперь она контролирует КАЧЕСТВО (наставник+судья), а механику/ необратимое не сваливает на владельца. Коммиты: B+C ч.2 `bc1d2a3`, D1 `bbc053e`, D2 `b47a71c`, §3.4 `cdcaf61`. +- **⛔ ПОДДЕЛКА СОГЛАСИЯ ЗАКРЫТА (эпик consent-forgery, A+B1-B5+C).** Несущая дыра: контроллер сочинял + ярлык кнопки `FLOOR-ESCAPE: owner-seal:`, среда возвращала его как «ответ» без действия + владельца → подписанный грант → план опечатывался «одобрен владельцем». **Фикс:** согласие — ТОЛЬКО + из свободного ввода владельца (лёгкое) ИЛИ из его терминала (тяжёлое). Кнопка-с-меткой и диктовка + метки больше не дают грант. **Рецепт escape ниже ИНВЕРТИРОВАН** (см. «Аварийный выход»). Коммиты: + A `cdc32b1`, B1 `dec0ed5`, B2 `f870907`, B3 `29287d7`, B4 `5bcf229`, B5 `11969ac`, C `0d31e62`. + Спека `specs/2026-06-18-consent-forgery-fix-design.md`. + - **Осмотр сайта под планом (B+C ч.2, `op:"session"`).** Чтобы пройтись/пощёлкать (логин, формы, чужой сайт), план объявляет ОДИН шаг-сеанс: `{op:"session", goal, tools:[действующие инструменты], produces:"<итоговый файл>"}`. Внутри сеанса смотришь/кликаешь по живым `ref` сколько нужно (указатель @@ -193,41 +201,51 @@ CARD-путь (`sealedPlanCoversEdit` под опечатанным планом - блок «ожидался шаг N: …» → ты в середине плана на шаге N (возможно, застрял — см. F-J); - выполнилось → стена снята (или открыт escape). -## Аварийный выход владельца (escape) +## Аварийный выход владельца (escape) — ОБНОВЛЕНО 18.06.2026 (фикс подделки согласия) -Разовое подписанное разрешение на ОДНО действие под стеной. Владелец даёт его **в ответе на -AskUserQuestion**: в ответе должна **буквально** присутствовать метка `FLOOR-ESCAPE: ` — -среда ищет её регэкспом в конце ответа (`/FLOOR-ESCAPE:\s*(.+)$/`, см. -[tools/askuser-answer-parser.mjs](../../tools/askuser-answer-parser.mjs)::`toFloorEscapeRecord`). -Каноны `` ([tools/escape-grant.mjs](../../tools/escape-grant.mjs)::`canonicalAction`): +> ⛔ **Старый рецепт «контроллер кладёт `FLOOR-ESCAPE:` в КНОПКУ» БОЛЬШЕ НЕ РАБОТАЕТ.** После фикса +> подделки согласия (эпик consent-forgery: A + B1-B5 + C) ответ, дословно совпавший с ярлыком +> контроллерской кнопки, согласием НЕ считается (anti-button — среда могла вернуть кнопку без действия +> владельца). Согласие — только из СВОБОДНОГО ввода владельца ЛИБО из его ТЕРМИНАЛА. Спека: +> `docs/superpowers/specs/2026-06-18-consent-forgery-fix-design.md`. + +**Два класса согласия (Поза 1, решение владельца 18.06):** + +**ЛЁГКОЕ** — `write:<путь>`, безопасный `bash:`, `skill:<имя>`. Владелец САМ набирает метку +`FLOOR-ESCAPE: ` в поле «Другое» ответа AskUserQuestion (свободный ввод; среда ищет +`/FLOOR-ESCAPE:\s*(.+)$/`, `toFloorEscapeRecord`). Контроллер кнопку-с-меткой НЕ делает (anti-button +отвергнет) и метку дословно НЕ диктует (anti-dictation `detectOtherSocialEng` → грант не пишется). +Грант одноразовый, окно **5 минут**, точное совпадение `canonicalAction`. **Применяй СРАЗУ.** + +**ТЯЖЁЛОЕ** — `owner-seal:`, `ops-runbook:`, `commit:`, `plan-done`, `gate3-arb:*`, +разрушительный `bash:`/`powershell:` (rm-rf/force-push/migrate:fresh/db:wipe). **ТОЛЬКО из ТЕРМИНАЛА +владельца:** + +``` +node tools/owner-consent.mjs +``` + +Скрипт подписывает терминальный грант (`origin:owner-terminal`) ключом keychain. Контроллер запустить +с пользой не может: его Bash без доступа к keychain → грант не подписан → читатель отвергает; и +`~/.claude/runtime` он не пишет (пол). Читатели тяжёлого принимают грант ТОЛЬКО при валидной подписи +(**fail-closed** без ключа — `loadTerminalGrants`). + +**Каноны ``** ([tools/escape-grant.mjs](../../tools/escape-grant.mjs)::`canonicalAction`): - Bash → `bash:<норм. команда>` · PowerShell → `powershell:<норм. команда>` -- Skill → `skill:<имя lowercase>` · Write/Edit → `write:<путь>` -- MCP → `mcp:<имя>:` -- Завершить застрявший план → `plan-done` (резерв-метка) · Опечатать на арбитраже → `owner-seal:` (Фикс 3) +- Skill → `skill:<имя lowercase>` · Write/Edit → `write:<путь>` · MCP → `mcp:<имя>:` +- Завершить план → `plan-done` · Арбитраж gate3 → `gate3-arb:accept:` / `gate3-arb:continue:` +- Опечатать на арбитраже → `owner-seal:` · Деплой → `ops-runbook:` · Коммит → `commit:` -**Канон пути для `write:`** — абсолютный, **lowercase**, прямые слэши `/`, NFC (ровно как даёт -`pathNormalizeSafe`). Пример: `write:c:/моя/проекты/портал crm/документация/docs/superpowers/router-mentor-wall-guide.md`. -Грант одноразовый, окно **5 минут**, точное посимвольное совпадение `canonicalAction` с действием -инструмента. **Применяй escape СРАЗУ** (иначе окно истечёт). +**Канон пути для `write:`** — абсолютный, **lowercase**, прямые слэши `/`, NFC (как `pathNormalizeSafe`). -### Как дать escape ПРАВИЛЬНО (иначе клик уходит «в никуда») — урок 16.06 +**Что escape чтит:** стена М2 / пол М5 / судья М4 / гейт памяти. **НЕ чтит:** `router-gate` (git — +отдельный канал, см. «Коммит») и `normative §6` для discipline-source (F-K — правь терминалом). -- ✅ **Контроллер делает САМУ кнопку AskUserQuestion = строкой `FLOOR-ESCAPE: `**, владелец - её осознанно выбирает. Тогда ответ = текст кнопки = содержит метку → среда подписывает грант. - Это и есть «контроллер спрашивает — владелец выбирает — но ответ сформулирован верно». -- ❌ **Обычная кнопка** («Разрешаю», «Ок», «Да») — её текст НЕ содержит `FLOOR-ESCAPE:` → грант НЕ - пишется → стена держит. (Грабли: 3 клика подряд впустую, прежде чем поняли причину.) -- ❌ **Контроллер уговаривает владельца вписать метку в свободное поле ответа** — защита - `detectOtherSocialEng` (`askuser-answer-parser.mjs`) ловит такие фразы-подсказки как соц-инженерию - и флагует. Не диктуй текст в свободное поле — **давай метку готовой кнопкой**. - -**Что escape чтит:** стена М2 / пол М5 / судья М4 / гейт памяти (память/нормативка). **НЕ чтит:** -`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, гасит грант). Без них клик уходит «в никуда». +**Активация (settings.json):** PostToolUse `AskUserQuestion` → `enforce-askuser-answer-parser` +(writer: **anti-button** + **anti-dictation**; подписывает грант ключом `router-mentor-receipts`) + +`Edit|Write|MultiEdit|Bash|PowerShell` → `enforce-floor-escape-consume` (one-shot гасит лёгкий грант). +Тяжёлый терминальный канал — скрипт `tools/owner-consent.mjs` (запускает владелец, вне гейтов). ## Коммит