spec(router-gate): v3.5 S8 TRUE closure via AskUserQuestion-gate

Dedicated brainstorm на S8 (последний acceptable residual после v3.4) — controller-writable markers BRANCH-SWITCH-CONFIRMED / RECOVERY-INTENT: заменены на AskUserQuestion-gate через расширение §4.5 answer parser. Тот же class fix что S5 v3.4 — перенос сигнала в side-channel который controller не контролирует.

V3.5 architectural shift:
- Old: controller wants git rebase → hook видит блокировку → controller пишет BRANCH-SWITCH-CONFIRMED в response → hook читает, allows. Самоодобрение через controller-written text.
- New: controller wants git rebase → hook блокирует → controller обязан AskUserQuestion('Выполнить git rebase main?') с 3 опциями → user picks → §4.5 parser распознаёт git-pattern, пишет approve_git_operation запись в askuser-decisions.jsonl с approved_action_pattern exact → controller retries → hook читает askuser-decisions, exact-match approval, consumes one-shot, allows.

Anti-forgery 4 защиты:
- askuser-decisions.jsonl в protected paths (~/.claude/runtime/*)
- Пишется только §4.5 parser при реальном AskUser-ответе
- Strict exact-match approved_action_pattern против tool_input.command
- 5-min time window + one-shot consumption (consumed flag)

Adversarial pre-check v4.3 — 6 attack-векторов проверены, все заблокированы.

5 spec edits:
- §3 preserved hooks таблица — enforce-branch-switch row переписан (no longer reads response markers, instead reads askuser-decisions)
- §4.5 — новый row + новое enum gate_interpretation: approve_git_operation
- §9 — S8 убран из acceptable residual list. Список residual теперь ПУСТ.
- §10.2 — askuser-decisions schema +consumed/consumed_at/consumed_by_tool_use_id + полный schema приведён
- §11 v3.5 history entry

Implementation budget: 21.5-31h (v3.4) → 22.5-32h (v3.5). +1.1h за: rewrite hook, extend parser, one-shot consumption, schema, spec edits.

Главный урок: класс controller-writable signals закрыт архитектурно через обе v3.4 (file side-channel) и v3.5 (askuser-decisions side-channel). Формула generalisable — любой controller-writable signal закрывается переносом write-канала в protected file который пишет отдельный gate-процесс при harness-driven событии.

Hard wall теперь полный hard. Acceptable residual list пуст.

Verify-sentinel: 1179/1179 vitest tools-only GREEN.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Дмитрий
2026-05-29 08:24:21 +03:00
parent 15bf46a1c0
commit 80c8160203
2 changed files with 111 additions and 20 deletions
+11 -11
View File
@@ -1,6 +1,6 @@
# Brain Status (auto-generated)
Last updated: 2026-05-29T04:50:44.543Z
Last updated: 2026-05-29T05:08:09.114Z
| Контролёр | Состояние | Детали |
|---|---|---|
@@ -8,13 +8,13 @@ Last updated: 2026-05-29T04:50:44.543Z
| C2 Cross-ref consistency | ✅ | [cross-ref-checker] OK — 0 drift in 4 files |
| C3 Observer-of-observer | ✅ | [observer-of-observer] OK — last read 0 week(s) ago |
| C4 Сигнальный статус | ✅ | This file (self-reference) |
| C5 Observer-coverage | ⚠️ | 688 episode(s) this month · Stop-hook + post-commit OK · 20 missed activation(s) — see /brain-retro |
| C5 Observer-coverage | ⚠️ | 689 episode(s) this month · Stop-hook + post-commit OK · 20 missed activation(s) — see /brain-retro |
| C6 Chain map sync | ✅ | [chain-map-checker] OK — 16 chains in sync |
## Метрики (информационные, не алерты)
- Observer evidence: 688 episodes this month, 0 observer_error markers, 139 PII matches before filter
- Legacy v1 episodes (not in factor analysis): 549
- Observer evidence: 689 episodes this month, 0 observer_error markers, 139 PII matches before filter
- Legacy v1 episodes (not in factor analysis): 550
- Last /brain-retro: 2 day(s) ago
- Использование узлов: см. `/brain-retro` (раз в спринт). missed_activations: 20. **Неиспользованные узлы — не алерт, если профильной задачи не было** (Pravila §16.4 v1.36; capability-readiness; см. memory `feedback_brain_unused_tools_not_problem` — outside-repo memory store).
@@ -31,9 +31,9 @@ Baseline дисциплины роутера (этап 2 router discipline overh
| cleanup | 6 | 0.0% | 0.0% |
| refactor | 1 | 0.0% | 0.0% |
Router step distribution: 1: 308, 2: 243, 3: 63, 5: 62
Router step distribution: 1: 309, 2: 243, 3: 63, 5: 62
Boundaries applied (ADR / границы): 75 of 676 эпизодов (11.1%).
Boundaries applied (ADR / границы): 75 of 677 эпизодов (11.1%).
## Активные многоэтапные проекты
@@ -51,10 +51,10 @@ Boundaries applied (ADR / границы): 75 of 676 эпизодов (11.1%).
| Компонент | Токены (in/out) | USD |
|---|---|---|
| Classifier (Sonnet 4.6) | 4586/59217 | $0.90 |
| Classifier (Sonnet 4.6) | 4606/59887 | $0.91 |
| Self-assessment (Sonnet 4.6) | 0/0 | $0.00 |
| Reviewer (Opus 4.7 + fallback) | 0/0 | $0.00 |
| **Итого** | | **$0.90** |
| **Итого** | | **$0.91** |
## Аномалии классификатора
@@ -67,7 +67,7 @@ Episodes since last run: 542 / threshold: 10
## Reviewer: субагент vs fallback
0 эпизодов проверено из 688.
0 эпизодов проверено из 689.
## Reviewer findings
@@ -109,7 +109,7 @@ Episodes since last run: 542 / threshold: 10
| Фраза | За всё время | За сегодня |
|---|---|---|
| `recovery` | 1233 | 336 ⚠️ |
| `recovery` | 1330 | 433 ⚠️ |
| `без скилов` | 233 | 55 ⚠️ |
| `ремонт инфраструктуры` | 229 | 44 ⚠️ |
| `срочно` | 144 | 51 ⚠️ |
@@ -123,7 +123,7 @@ Episodes since last run: 542 / threshold: 10
| PID | Имя | CPU-время | Возраст |
|---|---|---|---|
| 3464 | MsMpEng | 1.27ч | 0.0ч |
| 3464 | MsMpEng | 1.31ч | NaNч |
⚠️ Проверь, не «осиротевшие» ли это процессы от завершённых Claude-сессий.
@@ -1,7 +1,7 @@
# Router-gate hard wall — Дизайн-спецификация (Уровень 4) v3.4
# Router-gate hard wall — Дизайн-спецификация (Уровень 4) v3.5
**Дата:** 2026-05-29
**Версия:** v3.4 (N1/S5 TRUE closure — out-of-band runtime block-file через tool_use_id derived path. V3.3 «honest residual» пересмотрено: реальный fix найден без harness-зависимости через subagent gate-process side-channel)
**Версия:** v3.5 (S8 TRUE closure — `BRANCH-SWITCH-CONFIRMED` controller-writable marker заменён на AskUserQuestion-gate через расширение §4.5 answer parser. **Acceptable residual list теперь пуст** — hard wall полный hard.)
**Автор:** Claude (controller Opus 4.7) под руководством заказчика Дмитрия
**Статус:** Approved by owner — готов к плану implementation
**Тип:** feature — enforcement architecture rewrite
@@ -32,7 +32,7 @@
- Gate budget 2s + fail-CLOSE при таймаутах.
- Bash blocks sub-shells (`backticks`, `$()`, `<()`, `<<` heredocs) + file-watcher для script execution + static content scan.
**Цена:** 21.5-31 часов implementation в 6 этапов через subagent-driven-development. **Закрыто 51 hole** через 5 раундов adversarial audit (v1 → v2 → v3 → v3.2 → v3.3 → v3.4). **S5 TRUE closure в v3.4** — out-of-band runtime block-file `subagent-block-<tool-use-id>.json` (см. §3.4 v3.4). Из 2 acceptable residual v3.3 (S5 + S8) **S5 теперь closed**, остаётся только S8 (BRANCH-SWITCH-CONFIRMED — separate follow-up эпик).
**Цена:** 22.5-32 часов implementation в 6 этапов через subagent-driven-development. **Закрыто 52 hole** через 6 раундов adversarial audit (v1 → v2 → v3 → v3.2 → v3.3 → v3.4 → v3.5). **S5 TRUE closure в v3.4** (subagent block-file side-channel). **S8 TRUE closure в v3.5** — branch-switch hook больше не читает controller-written markers, переключён на AskUserQuestion-gate через расширение §4.5 git-pattern recognition. **Acceptable residual list теперь пуст** — все известные controller-writable signals закрыты через out-of-band каналы (§3.4 file side-channel для S5; §4.5 askuser-decisions side-channel для S8).
**Recovery:** заказчик соглашается быть recovery-каналом ручной правкой `.claude/settings.json` / state-файлов при ошибочном lockout.
@@ -40,6 +40,24 @@
**Сохраняется:** 7 preserved хуков (tdd-gate / coverage-verify / memory-coverage / verify-before-push / rationalization-audit / prompt-injection / branch-switch) — у них своя семантика, не про router. 6 из них теряют свои findOverride escape-фразы — становятся hard-walls тоже.
**Changes v3.4 → v3.5:** dedicated brainstorm на S8 (последний acceptable residual после v3.4) — `BRANCH-SWITCH-CONFIRMED` controller-writable marker заменён на AskUserQuestion-gate. Тот же class fix что S5 v3.4 — перенос сигнала в side-channel который controller не контролирует.
- **Old (S8 в v3.4):** controller wants `git rebase main` → hook видит блокирующее правило → controller пишет `BRANCH-SWITCH-CONFIRMED` в собственном response → hook читает response, allows. Controller сам пишет сигнал — fake trivially.
- **New (S8 в v3.5):** controller wants `git rebase main` → hook видит блокирующее правило → controller обязан AskUserQuestion('Выполнить `git rebase main`?') с 3 опциями (Да/Нет/По другому) → user picks Да → §4.5 answer parser распознаёт git-pattern, пишет `approve_git_operation` запись в `askuser-decisions-<sess>.jsonl` с `approved_action_pattern: "git rebase main"` exact → controller retries `git rebase main` → hook читает askuser-decisions (protected `~/.claude/runtime/*`), видит matching approval, consumes one-shot, allows.
**Anti-forgery:** askuser-decisions.jsonl в protected paths, пишется только §4.5 parser при реальном AskUser-ответе, strict exact-match approved_action_pattern против tool_input.command, 5-min time window, one-shot consumption.
5 spec edits:
- §3 preserved hooks таблица — `enforce-branch-switch` row переписан (no longer reads response markers, instead reads askuser-decisions).
- §4.5 — новый row в answer parsing table + новое значение enum `approve_git_operation`.
- §9 — S8 убран из acceptable residual list. **Список residual теперь пуст.**
- §10.2 — askuser-decisions.jsonl schema +`consumed: boolean` + `approved_action_pattern` поля.
- §11 v3.5 history entry.
Adversarial pre-check (v4.3 audit на новый дизайн) — 6 attack-векторов проверены, все заблокированы.
Budget impact: +1.1h (21.5-31h → 22.5-32h).
**Changes v3.3 → v3.4:** dedicated brainstorm на N1 (закрытие fatal hole S5) выявил реальный механизм out-of-band channel без harness-зависимости. **S5 TRUE closure** (больше не residual). Механизм:
- **Subagent's gate-процесс пишет block-event-файл** по пути derived из `tool_use_id` Task tool: `~/.claude/runtime/subagent-block-<tool-use-id>.json`. Я (controller) НЕ контролирую: (1) generation `tool_use_id` — Anthropic CLI assigns; (2) запись — gate-процесс subagent'а, отдельный node-процесс; (3) сам файл — в `~/.claude/runtime/*` protected paths (§3.1).
@@ -48,6 +66,7 @@
- **Smoke 3** добавлен в §3.2.0 — user-run проверка что subagent gate реально пишет block-file (acceptance: file exists в `~/.claude/runtime/` после blocked Task).
7 spec edits:
- §3.4 переписан — убрана «weak heuristic» framing, заменена «out-of-band channel» закрытием. S5 явно closed.
- §3.1 +`subagent-block-<tool-use-id>.json` explicit-mention.
- §3.2 расширен — subagent gate ТАКЖЕ пишет block-file (parallel к чтению inheritance).
@@ -191,7 +210,7 @@ Self-retrospect #2 (28.05 вечер) подтвердил: 5 commitments утр
| `enforce-verify-before-push` | Свежий verify-sentinel перед commit/push | Теряет `срочно` / `быстрый коммит` / `ремонт инфраструктуры`. Hard-lock для починки verify-инфры |
| `enforce-rationalization-audit` | Soft detector, не блокирует | Не использует findOverride — нет эффекта |
| `enforce-prompt-injection` | Inject контекст-блок в UserPromptSubmit | Использует findOverride для surface активных overrides. После удаления — surface пустой |
| `enforce-branch-switch` | Block dangerous git-операции | Теряет `recovery`. Hard-lock для `git rebase` / `git reset --hard` — требует explicit `BRANCH-SWITCH-CONFIRMED` маркер в response каждый раз |
| `enforce-branch-switch` | Block dangerous git-операции | **v3.5: переписан под AskUserQuestion-gate (S8 TRUE closure).** Теряет `recovery` override И `BRANCH-SWITCH-CONFIRMED`/`RECOVERY-INTENT:` controller-writable markers. Hard-lock для `git rebase` / `git reset --hard` / `git clean -f` / `git checkout --` / `git branch -D` / `git push --force` / `git stash drop` / `git cherry-pick` / `git revert` — controller обязан AskUserQuestion с явным вопросом + 3 опциями; user approves через §4.5 answer parser (новая категория `approve_git_operation`); approval пишется в `askuser-decisions-<sess>.jsonl` (protected); hook читает там exact-match + one-shot consume |
Из 7 preserved хуков 6 используют `findOverride` (все кроме `enforce-rationalization-audit`). После удаления vocab.json эти вызовы будут возвращать `null` всегда — hooks работают корректно, никаких изменений в их коде не требуется.
@@ -319,7 +338,7 @@ V3.2 пытался закрыть S5 regex'ом маркера `{"status":"DONE
| File missing | == 0 | **Assume BLOCKED** (defensive, gate-crash possible). Parent обязан AskUser |
| File read FS error | любое | fail-CLOSE per §3.3 |
4. **Cleanup:** parent gate удаляет block-file после чтения. Background cleanup script (cron / lefthook): orphans > 24h → delete (защита от parent gate crash после read но до delete).
1. **Cleanup:** parent gate удаляет block-file после чтения. Background cleanup script (cron / lefthook): orphans > 24h → delete (защита от parent gate crash после read но до delete).
**Anti-forgery (3 защитных слоя — почему controller не подделает):**
@@ -469,7 +488,6 @@ V3.2 заявлял silent fall-through к Поведениям 2/3/4 при unk
V3.3: если префикс-pattern matched (например `делай foo-bar`), но `foo-bar` **не найден** в registry — gate **обязан** заблокировать любой mutating tool до **mandatory AskUserQuestion** с явным форматом: «Пользователь указал skill `foo-bar`, но он не найден в реестре (возможно опечатка или переименован). Router рекомендует `<rec_node>`. Что делать?» с опциями:
1. «Имел в виду `<closest-fuzzy-match>` — делать его» (если fuzzy-match similarity > 0.7).
2. «Делать `<rec_node>` по рекомендации router'а».
3. «Делать direct без скила».
@@ -553,6 +571,7 @@ Gate не unlock'ает turn просто по факту вызова AskUserQu
| Выбранная опция явно говорит «direct, без скила» / «продолжить без skill'а» / «делать напрямую» | Gate unlock'ает Edit/Write/MultiEdit (но не Bash mutating и не Skill/Task non-baseline). Bash требует whitelist (§5.1) |
| Свободный ответ (заказчик выбрал «Other» и написал текст) | Gate анализирует free-form text по тем же правилам выше. Если интерпретация неоднозначна — gate требует ещё одно AskUserQuestion для уточнения |
| **Любой ответ не матчащий ни один из 4 классов выше** (`stop` / `approve_specific_tool` / `approve_direct_no_skill` / `freeform_clear`) — **default-CLOSE (H4 v4-audit)** | Gate **остаётся заблокированным**. Записывается `gate_interpretation: "no_match_remain_blocked"`. Контроллер обязан вызвать второй AskUserQuestion с переформулированными опциями (включая явные keyword-маркеры stop/approve). Если и второй ответ unmatched → 2/2 limit достигнут → fail-CLOSE: «AskUserQuestion ambiguity loop — заказчик пусть переформулирует prompt с явным указанием действия». Закрывает H4 — keyword stop-list не покрывает естественные фразы типа «подожди» / «обдумаем», теперь это default-CLOSE а не silent-approve. |
| **Опция содержит «выполнить `<git command>`» / «approve `<git command>`» / «делать `<git command>`» / «Да — выполнить `<git command>`»** где `<git command>` matches pattern `git (rebase\|reset\|clean\|checkout --\|branch -[DfF]\|push --force\|stash drop\|cherry-pick\|revert)` (v3.5 — S8 TRUE closure) | Gate пишет в `askuser-decisions-<sess>.jsonl`: `gate_interpretation: "approve_git_operation"`, `approved_tool: "Bash"`, `approved_action_pattern: "<exact git command>"`, `consumed: false`. `enforce-branch-switch.mjs` хук читает эту запись при next Bash tool-attempt — если `tool_input.command` matches `approved_action_pattern` strict exact (case-sensitive), И запись `consumed: false`, И `ts` within 5 minutes — gate allow, helper пишет `consumed: true` обратно (one-shot). Закрывает S8: dangerous git-операции больше не самоодобряются controller-маркером, только через явный AskUser approval с per-operation consent. |
| AskUserQuestion вызван, но заказчик ещё не ответил (in-flight) | Gate ждёт ответ — pre-answer state, никакого unlock |
Все решения логируются в новый файл `~/.claude/runtime/askuser-decisions-<sess>.jsonl`:
@@ -900,7 +919,18 @@ Protected paths должны быть live **до** того как соотве
- **S6 — max 2 AskUserQuestion per turn limit** (§4.5): chain'ы с many mutating tools (>2 шагов с Edit/Write/Bash per ход) НЕ помещаются в один turn — заказчик вынужден re-prompt'ить или делить задачу. **Acceptable UX-tradeoff** — это design choice §4.5 (anti-fatigue), не дыра. Multi-step chains реально работают через переspawning context per next prompt. Документировать в README/onboarding для заказчика.
- **S8 — `BRANCH-SWITCH-CONFIRMED` controller-writable marker** (preserved `enforce-branch-switch` hook): после удаления `recovery` override этот хук требует explicit маркер в каждом ответе на dangerous git-операцию. **Маркер пишется в controller response** controller может self-write его, что есть pre-existing bypass-pattern (зафиксирован в memory `feedback_hook_bypass_pattern_2026-05-28.md`). **Известный residual risk v3.2** — не закрывается в этом эпике. **Follow-up эпик:** «Move BRANCH-SWITCH-CONFIRMED source from response to user-prompt» (заказчик должен явно писать фразу в prompt, аналогично direct-invocation). Budget ~1h на отдельный мини-эпик. Surface как **known-residual-risk** в §11 history v3.2 entry и в STATUS.md C5.
- **S8 — Branch-switch controller-writable markers — CLOSED в v3.5** через AskUserQuestion-gate (§4.5 v3.5 + §3 preserved hooks branch-switch row v3.5). История: v3.2 markers `BRANCH-SWITCH-CONFIRMED`/`RECOVERY-INTENT:` в controller response (controller-writable — fake-able trivially) → v3.4 acknowledged как known-residual «нужен follow-up эпик» → v3.5 TRUE closure: hook больше не читает response markers, controller обязан AskUserQuestion с явным вопросом + 3 опциями; user-approval пишется в `askuser-decisions-<sess>.jsonl` (protected paths); hook читает там exact-match approval + one-shot consume + 5-min time window. Тот же class fix что S5 v3.4 (side-channel вместо controller-written text). Перенесено в §11 как resolved.
### Список acceptable residual теперь пуст (v3.5)
После v3.5 закрытия S8 в §9 не остаётся unresolved holes. **Hard wall — полный hard.** Все известные controller-writable signals (S5 v3.4, S8 v3.5) закрыты через out-of-band каналы:
- **S5 (subagent BLOCKED-protocol):** side-channel file `subagent-block-<tool-use-id>.json` — пишет subagent gate-process, path derived из harness-assigned tool_use_id, file protected.
- **S8 (branch-switch confirmation):** side-channel record в `askuser-decisions-<sess>.jsonl` — пишет §4.5 answer parser при реальном AskUser-ответе пользователя, file protected, exact-match + one-shot.
Класс «controller-writable signals» закрыт архитектурно. Будущие новые механизмы (если появятся в эпике) должны быть design'нуты по тому же паттерну: side-channel write через отдельный процесс/gate + protected paths + harness-derived path или time-bounded one-shot match.
В §9 остаются только N12 (off-topic detection limits — acceptable heuristic 90% coverage), N11 (first-option position bias — soft detector добавлен), S6 (max 2 AskUser per turn UX-tradeoff) и tokenizer-quoting limitation (E1) — все они acknowledged design choices, не security holes.
- **S5 — Subagent BLOCKED-protocol — CLOSED в v3.4** через out-of-band runtime block-file (§3.4 v3.4). История: v3.2 regex-marker (иллюзия) → v3.3 weak heuristic + honest residual → v3.4 TRUE closure через side-channel `subagent-block-<tool-use-id>.json` (subagent gate-process пишет, parent gate читает, controller не контролирует path/file/writer). Перенесено в §11 как resolved.
@@ -985,9 +1015,39 @@ Protected paths должны быть live **до** того как соотве
"options": ["string"],
"chosen_label": "string",
"chosen_text": "string",
"gate_interpretation": "stop_remain_locked|approve_specific_tool|approve_direct_no_skill|ambiguous_requires_followup|no_match_remain_blocked",
"gate_interpretation": "stop_remain_locked|approve_specific_tool|approve_direct_no_skill|ambiguous_requires_followup|no_match_remain_blocked|approve_git_operation",
"approved_tool": "Skill|Edit|Bash|null",
"approved_action_pattern": "string|null"
"approved_action_pattern": "string|null",
"consumed": false,
"consumed_at": null,
"consumed_by_tool_use_id": null
}
```
**v3.5 fields (S8 TRUE closure):**
- `approve_git_operation` — новое значение enum, генерируется §4.5 answer parser когда user choice matches git-pattern (`git rebase|reset|clean|checkout --|...`). См. §4.5 v3.5 row.
- `consumed` — boolean (default false). `enforce-branch-switch.mjs` hook ставит `true` после use approval один раз (one-shot). Subsequent attempts с тем же approval отклоняются как «already used».
- `consumed_at` / `consumed_by_tool_use_id` — audit-trail когда и каким tool_use_id consumed; для brain-retro анализа frequency repeat-approvals.
Schema-update гарантирует backward-compat: старые записи без `consumed`/`consumed_at`/`consumed_by_tool_use_id` интерпретируются как `consumed: false` по default — никакой миграции данных.
```jsonc
// Полный schema-update для askuser-decisions с v3.5:
{
"ts": "<iso-8601>",
"session_id": "<sess>",
"turn_id": "<id>",
"question": "string",
"options": ["string"],
"chosen_label": "string",
"chosen_text": "string",
"gate_interpretation": "...|approve_git_operation",
"approved_tool": "Skill|Edit|Bash|null",
"approved_action_pattern": "string|null",
"consumed": false,
"consumed_at": null,
"consumed_by_tool_use_id": null
}
```
@@ -1243,6 +1303,37 @@ Berkeley-style: use v2 spec, новый план implementation.
## 11. История версий
### v3.5 (2026-05-29, утро, S8 TRUE closure через AskUserQuestion-gate)
Dedicated brainstorm на закрытие S8 (последний acceptable residual после v3.4) — `BRANCH-SWITCH-CONFIRMED` и `RECOVERY-INTENT:` controller-writable markers в response контроллера. История класса: S5 v3.4 закрыто через side-channel file (subagent block-file). S8 теперь закрыто через side-channel record в askuser-decisions.jsonl — symmetric pattern, та же защита от controller-writable signals.
**Что изменилось архитектурно:**
| Что | Раньше (v3.4) | V3.5 |
|---|---|---|
| Сигнал одобрения | Текст-marker `BRANCH-SWITCH-CONFIRMED` в controller response | Запись `approve_git_operation` в `askuser-decisions-<sess>.jsonl` |
| Writer | Controller (свободный текст в response) | §4.5 answer parser при реальном AskUser-ответе пользователя |
| Reader | `enforce-branch-switch.mjs` парсит response substring | `enforce-branch-switch.mjs` читает askuser-decisions.jsonl, strict exact match approval против tool_input.command |
| Защита от fake | None (controller пишет свой текст) | Protected paths (`~/.claude/runtime/*`) + only §4.5 parser пишет + strict exact match + one-shot consume + 5-min window |
**Adversarial pre-check (v4.3 audit на новый дизайн):** 6 attack-векторов проверены до написания spec'а — все заблокированы protected paths + one-shot consumption + strict exact match + time window. True closure, не heuristic.
**5 spec edits:**
- **§3** preserved hooks таблица — row для `enforce-branch-switch` переписан: больше не reads CONFIRMATION_MARKERS из response, теперь reads askuser-decisions для approval. Список dangerous git operations расширен (rebase / reset / clean -f / checkout -- / branch -D / push --force / stash drop / cherry-pick / revert).
- **§4.5** — новый row в answer parsing table: git-pattern recognition (regex matches `git (rebase|reset|clean|checkout --|branch -[DfF]|push --force|stash drop|cherry-pick|revert)`); новое enum значение `gate_interpretation: "approve_git_operation"`.
- **§9** — S8 убран из acceptable residual list. **Список residual теперь пуст** (новая subsection «Список acceptable residual теперь пуст (v3.5)» документирует это явно + класс controller-writable signals закрыт архитектурно для S5+S8).
- **§10.2** — askuser-decisions.jsonl schema +`consumed: boolean` + `consumed_at` + `consumed_by_tool_use_id` поля; enum `gate_interpretation` расширен `approve_git_operation`. Полный schema приведён.
- **§11** v3.5 history entry (этот раздел).
Implementation time: 21.5-31h (v3.4) → **22.5-32h** (v3.5). +1.1h за: rewrite enforce-branch-switch.mjs (0.3h), extend §4.5 parser для git-pattern (0.2h), one-shot consumption mechanism (0.2h), schema update §10.2 (0.1h), spec edits + history (0.3h).
**Главный урок v3.5 (закрытие class controller-writable signals):** Через v3.4 (S5 file side-channel) и v3.5 (S8 askuser-decisions side-channel) подтверждена generalisable формула — любой controller-writable signal закрывается переносом write-канала в protected file который пишет отдельный gate-процесс (или §4.5 parser внутри gate'а) при harness-driven событии (Task spawn = unique tool_use_id; AskUser answer = structured user input). Будущие новые механизмы (если появятся) — design'ить по этой формуле.
**Hard wall теперь полный hard.** Acceptable residual list пуст. Все controller-writable signals архитектурно закрыты. Дальнейшие adversarial аудиты могут найти новые holes в *других* классах (например implementation bugs в boundary conditions, race в новых side-channels) но не в фундаментальном «controller fake-able signal» классе.
Brainstorm methodology: `superpowers:brainstorming` skill — 1 clarifying вопрос (mechanism choice: prompt-marker / AskUser-gate / hybrid / session-budget — выбран AskUser-gate) → дизайн с anti-forgery 4 защитами + 6-attack pre-check → user approval → 5 spec edits.
### v3.4 (2026-05-29, утро, N1/S5 TRUE closure через out-of-band block-file)
Dedicated brainstorm на закрытие N1 (subagent BLOCKED-protocol, S5) — был зафиксирован в v3.3 как unresolvable в controller-writable spec'е (требует harness-level enforcement). Найден **real out-of-band channel** без harness-зависимости через subagent gate-process side-channel write в protected runtime-файл.