diff --git a/docs/observer/STATUS.md b/docs/observer/STATUS.md index b9a16691..81b446d1 100644 --- a/docs/observer/STATUS.md +++ b/docs/observer/STATUS.md @@ -1,6 +1,6 @@ # Brain Status (auto-generated) -Last updated: 2026-05-29T03:32:43.655Z +Last updated: 2026-05-29T03:41:09.334Z | Контролёр | Состояние | Детали | |---|---|---| @@ -8,13 +8,13 @@ Last updated: 2026-05-29T03:32:43.655Z | 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 | ⚠️ | 669 episode(s) this month · Stop-hook + post-commit OK · 20 missed activation(s) — see /brain-retro | +| C5 Observer-coverage | ⚠️ | 671 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: 669 episodes this month, 0 observer_error markers, 131 PII matches before filter -- Legacy v1 episodes (not in factor analysis): 530 +- Observer evidence: 671 episodes this month, 0 observer_error markers, 131 PII matches before filter +- Legacy v1 episodes (not in factor analysis): 532 - 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: 300, 2: 237, 3: 63, 5: 60 +Router step distribution: 1: 302, 2: 237, 3: 63, 5: 60 -Boundaries applied (ADR / границы): 75 of 660 эпизодов (11.4%). +Boundaries applied (ADR / границы): 75 of 662 эпизодов (11.3%). ## Активные многоэтапные проекты @@ -51,10 +51,10 @@ Boundaries applied (ADR / границы): 75 of 660 эпизодов (11.4%). | Компонент | Токены (in/out) | USD | |---|---|---| -| Classifier (Sonnet 4.6) | 3628/48891 | $0.74 | +| Classifier (Sonnet 4.6) | 3660/49643 | $0.76 | | Self-assessment (Sonnet 4.6) | 0/0 | $0.00 | | Reviewer (Opus 4.7 + fallback) | 0/0 | $0.00 | -| **Итого** | | **$0.74** | +| **Итого** | | **$0.76** | ## Аномалии классификатора @@ -67,7 +67,7 @@ Episodes since last run: 542 / threshold: 10 ## Reviewer: субагент vs fallback -0 эпизодов проверено из 669. +0 эпизодов проверено из 671. ## Reviewer findings @@ -112,7 +112,7 @@ Episodes since last run: 542 / threshold: 10 | `recovery` | 914 | 17 ⚠️ | | `ремонт инфраструктуры` | 229 | 44 ⚠️ | | `без скилов` | 201 | 23 ⚠️ | -| `срочно` | 118 | 25 ⚠️ | +| `срочно` | 131 | 38 ⚠️ | | `memory dump` | 17 | 0 | | `direct ok` | 6 | 0 | | `быстрый коммит` | 3 | 0 | @@ -123,7 +123,7 @@ Episodes since last run: 542 / threshold: 10 | PID | Имя | CPU-время | Возраст | |---|---|---|---| -| 3464 | MsMpEng | 1.07ч | 0.0ч | +| 3464 | MsMpEng | 1.08ч | NaNч | ⚠️ Проверь, не «осиротевшие» ли это процессы от завершённых Claude-сессий. diff --git a/docs/superpowers/specs/2026-05-28-router-gate-hard-wall-design.md b/docs/superpowers/specs/2026-05-28-router-gate-hard-wall-design.md index 4e9ccf41..3c9cd084 100644 --- a/docs/superpowers/specs/2026-05-28-router-gate-hard-wall-design.md +++ b/docs/superpowers/specs/2026-05-28-router-gate-hard-wall-design.md @@ -1,12 +1,45 @@ -# Router-gate hard wall — Дизайн-спецификация (Уровень 4) v3 +# Router-gate hard wall — Дизайн-спецификация (Уровень 4) v3.1 **Дата:** 2026-05-28 -**Версия:** v3 (closes 10 holes found in v2 adversarial audit) +**Версия:** v3.1 (clarification pass — TL;DR, schemas, test strategy, success metrics, cross-refs) **Автор:** Claude (controller Opus 4.7) под руководством заказчика Дмитрия **Статус:** Approved by owner — готов к плану implementation **Тип:** feature — enforcement architecture rewrite **Предшественник:** [docs/superpowers/plans/2026-05-28-router-discipline-level-1-2.md](../plans/2026-05-28-router-discipline-level-1-2.md) (Уровни 1+2, merged ранее в день) +--- + +## TL;DR + +**Цель:** Закрыть все обходы router-рекомендаций. Controller (Claude) физически не может действовать без явного разрешения заказчика. + +**Решение:** Один PreToolUse-хук `tools/enforce-router-gate.mjs` заменяет 5 старых хуков и vocab.json. На каждый tool call gate резолвит «разрешено / заблокировано» по 4 поведениям: + +1. **Direct invocation** заказчика (strict whitelist: slash-cmd / `Skill(X)` / `используй #N` / `делай `) → allow. +2. **Single router-рекомендация** → allow только matching Skill/Task + read-only baseline; mutating требует AskUserQuestion approval. +3. **Chain router-рекомендация** → allow только текущий шаг chain (state persists across turns, TTL 24h); progression after matching skill invoked. +4. **Silence** (router молчит) → mutating tools блокируются до AskUserQuestion с 1/2+/0-формат предложениями. + +**Безопасная база (всегда разрешено):** Read / Grep / Glob / LS / TodoWrite / AskUserQuestion (с лимитом 2 per turn) / read-only MCP. Bash — отдельный whitelist (§5.1). + +**Ключевые защиты:** + +- AskUserQuestion НЕ unlock'ает turn автоматически — gate парсит ответ заказчика и unlock'ает только для approved action. +- Protected paths (`~/.claude/runtime/*`, `tools/enforce-*.mjs`, etc) — hard-deny независимо от unlock. +- Subagent inheritance через env vars (`CLAUDE_GATE_INHERIT=true`), не text-prefix. +- Subagent constraints: нет AskUser, нет recursive Task, max 3 parallel. +- Atomic file writes + `proper-lockfile` для race-free state. +- Gate budget 2s + fail-CLOSE при таймаутах. +- Bash blocks sub-shells (`backticks`, `$()`, `<()`, `<<` heredocs) + file-watcher для script execution + static content scan. + +**Цена:** 13.5-20 часов implementation в 6 этапов через subagent-driven-development. **Закрыто 20 holes** через 3 раунда adversarial audit (v1 → v2 → v3). + +**Recovery:** заказчик соглашается быть recovery-каналом ручной правкой `.claude/settings.json` / state-файлов при ошибочном lockout. + +**Удаляется:** 5 хуков (chain-recommendation / classifier-match / graph-first / semgrep-security / override-limit) + `enforce-override-vocab.json` (7 фраз обхода больше не работают). + +**Сохраняется:** 7 preserved хуков (tdd-gate / coverage-verify / memory-coverage / verify-before-push / rationalization-audit / prompt-injection / branch-switch) — у них своя семантика, не про router. 6 из них теряют свои findOverride escape-фразы — становятся hard-walls тоже. + **Changes v2 → v3:** §3.2 переписан под env-based subagent inheritance (вместо text-prefix). Добавлены §3.4 Subagent constraints (no AskUser, no recursive Task), §3.5 Atomic state writes / file locking, §3.6 Gate budget / timeout (2s hard limit, fail-CLOSE), §5.2 Static content scan для node/python/vitest. §3.1 расширен path normalization (resolve + realpath + case-fold). §4.5 ограничен max 2 AskUserQuestion per turn. §4.7 при silence использует task_classification вместо recommendation. §5.1 добавлены file-watcher + broad sweep hard-blacklist для sub-shells. §7 добавлен coverage-hint coordination layer. §8 пересчитан (13.5-20h эпик). **Changes v1 → v2:** добавлены §3.1 (protected paths), §3.2 (subagent inheritance), §3.3 (failure modes), §4.5 (AskUserQuestion answer parsing), §4.6 (post-skill partial unlock), §4.7 (question quality detector), §5.1 (Bash content rules). §4 Поведение 1 переписан со strict whitelist. @@ -663,10 +696,283 @@ Hint удаляется при Stop event (cleanup). - Pravila §16 brain governance, §17 universal skill-coverage — будет обновляться отдельной задачей через `claude-md-management` после этого эпика. - Текущая enforcement-архитектура: 5 PreToolUse хуков + vocab.json в `tools/`. +### 10.1. Function and registry references + +Концепции упомянутые в спеке и их источники: + +- **`nodeMatches(recommendation, toolUse)`** — pure function для сравнения router-рекомендации (`#19`, `superpowers:writing-plans`) с tool invocation (Skill/Task). Существует в текущем `tools/enforce-classifier-match.mjs:42-66`. В реализации Уровня 4 переносится в `tools/router-gate-decide.mjs` как exported function. Обрабатывает aliases через registry: `#NN` ↔ `node.id`, `superpowers:X` / `skill:X` через canonical lookup в registry. +- **Registry источник** — `docs/registry/nodes.yaml` — единственный source of truth для skill/node names, aliases, slugs. Gate использует `tools/registry-load.mjs` для чтения. Direct-invocation strict whitelist (§4 Поведение 1) сравнивает с `node.name` и `node.slug` из этого реестра. +- **Subagent_type matching** — для Task tool gate сравнивает `tool_input.subagent_type` (например `coder-agent`) с recommendation в формате `slug` или `name` через тот же `nodeMatches()` с alias resolution. +- **Coverage-hint cross-ref recovery (§7.1 ↔ §6):** при coverage mismatch flag попадает в rationalization-flags и сюрфейсится в next prompt. Заказчик видит «прошлый turn нарушил coverage hint» — это уже surface, не блок. Если coverage-hint критичен (например я аннотировал `direct` но gate ожидал `skill:X`), заказчик использует §6 recovery уровень 3 (правка router-state) чтобы выровнять. +- **SDD-skill impact** — `superpowers:subagent-driven-development` skill активно использует Task tool. С §3.4 constraints (no AskUser в субагенте, no recursive Task, max 3 parallel) — sub-skill будет работать но с ограничениями: контроллер не сможет делегировать больше 3 субагентов параллельно (раньше можно было N), и subagent при lockout эскалирует через parent's AskUser. Skill сам **не правится** в этом эпике; impact документируется как known-behavior-change в release notes. + +### 10.2. State file schemas + +Все state-файлы — JSON или JSONL. Структуры: + +**`~/.claude/runtime/router-state-.json`** (существует, не меняется в v4): + +```jsonc +{ + "schema_version": 1, + "ts": "", + "session_id": "", + "classification": { + "task_type": "feature|bugfix|analysis|planning|conversation|memory-sync|ambiguous|unknown", + "confidence": 0.0, + "recommended_node": "#19|null", + "recommended_chain": ["#55", "#19", "#56"], + "triggers_matched": ["string"], + "primary_rationale": "string" + }, + "source": "prefilter|regex|llm|cache" +} +``` + +**`~/.claude/runtime/chain-state-.json`** (новый в v4): + +```jsonc +{ + "schema_version": 1, + "chain_active": ["#55", "#19", "#56"], + "chain_step": 1, + "initialized_at": "", + "last_step_at": "" +} +``` + +**`~/.claude/runtime/askuser-decisions-.jsonl`** (новый в v4) — append-only: + +```jsonc +{ + "ts": "", + "session_id": "", + "turn_id": "", + "question": "string", + "options": ["string"], + "chosen_label": "string", + "chosen_text": "string", + "gate_interpretation": "stop_remain_locked|approve_specific_tool|approve_direct_no_skill|ambiguous_requires_followup", + "approved_tool": "Skill|Edit|Bash|null", + "approved_action_pattern": "string|null" +} +``` + +**`~/.claude/runtime/router-gate-decisions.jsonl`** (новый в v4) — append-only: + +```jsonc +{ + "ts": "", + "session_id": "", + "turn_id": "", + "tool_name": "Edit|Write|Skill|Task|Bash|...", + "tool_input_summary": "string (truncated for log)", + "decision": "allow|block|unlock", + "reason": "string", + "behavior_branch": "1_direct_invocation|2_single_rec|3_chain|4_silence", + "state_snapshot": { + "rec_node": "string|null", + "rec_chain": ["string"], + "chain_step": 0, + "askuser_called_this_turn": false, + "askuser_count_this_turn": 0, + "skill_invoked_matching": false, + "is_direct_invocation": false, + "edited_files_this_turn": ["path"] + }, + "gate_latency_ms": 0 +} +``` + +**`~/.claude/runtime/subagent-inheritance-.json`** (новый в v4) — short-lived: + +```jsonc +{ + "schema_version": 1, + "parent_session_id": "", + "parent_router_state_path": "absolute path", + "parent_chain_state_path": "absolute path", + "allowed_actions": ["pattern"], + "subagent_constraints": { + "can_use_askuser": false, + "can_spawn_task": false, + "max_parallel": 1 + }, + "created_at": "" +} +``` + +**`~/.claude/runtime/coverage-hint-.json`** (новый в v4) — short-lived per turn: + +```jsonc +{ + "ts": "", + "session_id": "", + "turn_id": "", + "expected_coverage": "skill:X|direct:Y|chain:[...]", + "reason": "string", + "first_mutating_tool": "Skill|Edit|...", + "first_mutating_tool_ts": "" +} +``` + +**`~/.claude/runtime/gate-errors.jsonl`** (новый в v4) — append-only: + +```jsonc +{ + "ts": "", + "session_id": "", + "error_type": "state_missing|state_malformed|gate_internal|timeout|lock_contention", + "error_message": "string", + "stack_trace": "string (optional)", + "tool_attempted": "string" +} +``` + +**`~/.claude/runtime/gate-config.json`** (новый в v4) — tuning параметры: + +```jsonc +{ + "max_decision_time_ms": 2000, + "state_cache_ttl_ms": 5000, + "transcript_lookback_turns": 5, + "max_askuser_per_turn": 2, + "max_parallel_subagents": 3, + "chain_state_ttl_hours": 24, + "lock_timeout_ms": 1000 +} +``` + +### 10.3. Test strategy + +Покрытие тестами по слоям: + +**Pure decision-функции (unit, vitest):** + +- `decide()` — 4 поведения × ~10 вариаций = ~40 тестов (§4). +- `parseAskUserAnswer()` — stop/skill/direct/freeform classification = ~15 тестов (§4.5). +- `detectDirectInvocation()` — strict whitelist patterns + negative cases = ~15 тестов (§4 Поведение 1). +- `bashCommandClassify()` — whitelist/blacklist/sub-shell sweep + tokenizer edge cases = ~25 тестов (§5.1). +- `staticContentScan()` — fs.write / exec patterns + protected paths = ~15 тестов (§5.2). +- `pathNormalize()` — resolve/realpath/case/env = ~10 тестов (§3.1). +- `questionQualityCheck()` — missing-stop / leading / off-topic = ~12 тестов (§4.7). +- `chainStateUpdate()` — progression / TTL / replace-on-new-chain = ~10 тестов (§3 chain-state). + +**Integration тесты (vitest + temp fs):** + +- Atomic state writes — concurrent simulated writers, no corruption = ~10 тестов (§3.5). +- File locking — lock acquire/release + timeout fail-CLOSE = ~5 тестов (§3.5). +- Gate budget enforcement — slow decision → fail-CLOSE = ~5 тестов (§3.6). +- State cache invalidation на mtime change = ~5 тестов (§3.6). + +**Subagent inheritance (вместе с расширением subagent-prompt-prefix):** + +- Env-vars set + inheritance file write/read = ~8 тестов (§3.2). +- Subagent constraints — AskUser blocked / Task nested blocked / parallel > 3 blocked = ~8 тестов (§3.4). + +**Golden snapshot tests (decision traces):** + +- 10-15 end-to-end сценариев записанных как input → expected decision trace JSON. Покрывают типичные real workflows (writing-plans → Edit → Bash вышеуказанной vitest, chain progression across turns, silence + AskUser + Edit). + +**Smoke тесты (полная Claude сессия):** + +- Запустить Claude с тестовым prompt'ом, проверить что новый gate активен и старые не fire'ятся = 5-7 manual scenarios. + +**Регрессия после каждого этапа:** `npx vitest run --exclude=".claude/**" --exclude="app/**" --exclude="tools/ruflo-*"` — должна оставаться GREEN. + +**Целевое покрытие тестами:** ~150 новых unit-тестов + 10-15 integration + 10-15 golden snapshots + 5-7 smoke. + +### 10.4. Success metrics + +После реализации и прогона ~1 неделю под Уровнем 4: + +**Метрики которые должны drop'нуться к нулю (quantitative):** + +- `~/.claude/runtime/override-usage.jsonl` — пустеет полностью (хука нет, vocab нет). +- `hook-outcomes.jsonl` Cut 11 buckets (`passed-inline-override`, `passed-global-override`) — не пишутся. +- Brain-retro Table 5 bucket `direct_ignored_rec` (Skill should have been used but wasn't) — 0 (gate physically блокирует). +- Rationalization flags `rationalization-phrase: временно` и подобные — должны drop'нуться значительно (но не до нуля — soft detector). + +**Метрики которые должны вырасти (quantitative):** + +- `router-gate-decisions.jsonl` entries per day — fresh source данных. +- `askuser-decisions-.jsonl` entries — visible user approval pattern. +- Brain-retro Table 12-new `approved-alternative-skill` — показывает где я ловлю плохие рекомендации router'а. + +**Качественные метрики (brain-retro #11 после прогона):** + +- Brain-retro Table 13-new `Lockout incidents` показывает <5 incidents per 100 episodes — gate помогает, не раздражает. +- Self-retrospect #3 (через ~50 episodes под Уровнем 4) подтверждает: attitude commitments больше не нужны — гибридная архитектура enforce'ит. +- Reviewer Table «node_quality» percentages: correct % > 60% (vs 41% on 28.05), wrong_node < 5% (vs 11%). +- Time-to-first-action в типичной задаче не превышает baseline +30% (acceptable friction от AskUser). + +**Acceptance criteria для перехода в production:** + +- 150+ unit tests GREEN. +- 10+ integration tests GREEN. +- 5 smoke scenarios passing. +- Manual prod test: 1 час real workflow без false-positive блокировок. +- Brain-retro #11 (через 1 неделю) показывает 0 missed activations, 0 bypass attempts via gate. + +### 10.5. Rollback plan + +Если v4 ломает critical workflows и заказчик хочет откатиться: + +**Уровень 1 — выключить новый gate, сохранить остальное:** + +В `.claude/settings.json` секции `PreToolUse` удалить запись про `tools/enforce-router-gate.mjs`. Все остальные 7 preserved хуков продолжают работать. Эффект: возврат к dynamics v3 без router-routing enforcement (vocab.json уже удалён, нет escape-фраз). + +**Уровень 2 — revert all v4 commits:** + +```bash +git revert +``` + +Восстанавливает 5 удалённых хуков + vocab.json. Полный возврат к pre-эпику состоянию. + +**Уровень 3 — checkout v2 spec baseline (для rebuild с нуля):** + +```bash +git checkout b510a758 -- docs/superpowers/specs/2026-05-28-router-gate-hard-wall-design.md +``` + +Berkeley-style: use v2 spec, новый план implementation. + +### 10.6. Этапы и параллелизм + +Большинство этапов и подэтапов в §8 могут идти параллельно через subagent-driven-development: + +**Sequential обязательно:** + +- Этап 1 (pure decision module) → ВСЕ другие подэтапы (1.1-1.8 расширяют этот модуль). +- Этап 2 (удаление хуков) → Этап 3 (регистрация в settings.json — нужно знать какие удалить). +- Этап 6 (brain-retro adaptation) → после Этапа 3 (нужны real data из нового gate). + +**Параллелизуемое:** + +- Этапы 1.1 / 1.2 / 1.3 / 1.4 / 1.5 / 1.6 / 1.7 / 1.8 — независимые подмодули, можно делегировать одновременно (max 3 параллельных Task tool вызовов per §3.4). +- Этап 2.1 (subagent-prompt-prefix расширение) и 2.2 (subagent constraints) — параллельны с этапом 2 (удаление хуков). + +**Оценочное wall-clock с параллелизмом:** 6-9 часов вместо 13.5-20 sequential. Но это требует чёткой координации между субагентами и хорошего decomposition в writing-plans. + --- ## 11. История версий +### v3.1 (2026-05-28, поздний вечер, после комплексного анализа) + +Clarification pass — не новые архитектурные решения, а **уточнения для implementer'а**: + +- TL;DR в начале спека для быстрого orientation. +- §10.1 — явные cross-refs: `nodeMatches()` source, registry source (`docs/registry/nodes.yaml`), SDD-skill impact, coverage-hint ↔ recovery resolution. +- §10.2 — JSON Schema-ish определения всех 7 state-файлов (router-state / chain-state / askuser-decisions / router-gate-decisions / subagent-inheritance / coverage-hint / gate-errors / gate-config). +- §10.3 — test strategy: ~150 unit + 10-15 integration + 10-15 golden snapshot + 5-7 smoke. +- §10.4 — success metrics: quantitative (override drops to 0, gate-decisions growing) + качественные (lockout incidents < 5/100 ep, correct% > 60%) + acceptance criteria. +- §10.5 — rollback plan (3 уровня от выключения хука до polnogo revert). +- §10.6 — этапы и parallelism: что sequential, что параллелизуемо через SDD. Wall-clock 6-9h с parallelism вместо 13.5-20h sequential. + +Этот pass — для подготовки к writing-plans skill в next session: implementer должен иметь всё необходимое чтобы не делать implicit decisions. + ### v3 (2026-05-28, поздний вечер) Adversarial audit спека v2 от controller'а выявил 10 новых дыр, из них: