397777089e
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
136 lines
14 KiB
Markdown
136 lines
14 KiB
Markdown
# Протокол сессии — 2026-06-13 (роутер-наставник)
|
||
|
||
> Записи в раздел «Решения» делает Claude ТОЛЬКО по команде владельца «фиксируй …».
|
||
> Самовольные записи Claude запрещены (строгий запрет).
|
||
|
||
## Решения
|
||
|
||
### Р1 (2026-06-13) — способ сборки L1→L2
|
||
|
||
Выбран **способ B**: наставник — первый хук (выносит вердикт), судья — хук ПОСЛЕ наставника
|
||
(судит вслепую, печатает). Судья делается **fail-safe**: нет вердикта наставника для этого
|
||
плана → судья молчит, не дедлочит. Поведение: наставник → судья → печать судьи; счётчики 3+3;
|
||
карточка владельцу при тупике.
|
||
|
||
### Р2 (2026-06-13) — канал доставки замечаний контроллеру (обязательно, принцип №1)
|
||
|
||
На КАЖДЫЙ NO-GO (наставника или судьи) хук обязан отдать контроллеру ПОЛНЫЙ текст замечания
|
||
через канал обратной связи, который Claude реально получает (feedback хука / exit-2 stderr) —
|
||
НЕ `console.error` в пустоту и НЕ только в рантайм-файл. Проверяемо: после NO-GO контроллер
|
||
буквально видит текст замечания в своём контексте. Спека §2 П1 это требует, но в коде НЕ
|
||
реализовано — это и есть корень мучений. Не зависит от A/B.
|
||
|
||
### Р3 (2026-06-13) — канонический поток L1→L2 (эталон, словами владельца)
|
||
|
||
**Круг L1 — контроллер ↔ наставник (до 3 раз):**
|
||
|
||
1. Контроллер пишет план → его смотрит ТОЛЬКО наставник. Судья ещё не в курсе.
|
||
2. Наставник: «пункт 2 плохой, переделай». Счётчик L1 = 1.
|
||
3. Контроллер переписал → наставник смотрит снова: «теперь ок». Счётчик L1 → сброс.
|
||
(если за 3 круга не сошлись → карточка владельцу: «я и наставник спорим, реши».)
|
||
4. Наставник доволен → САМ несёт план судье. Судья видит план ВПЕРВЫЕ.
|
||
|
||
**Круг L2 — наставник передал → судья (до 3 раз):**
|
||
5. Судья судит ВСЛЕПУЮ (не зная мнения наставника):
|
||
|
||
- Судья GO → судья ПОДПИСЫВАЕТ печать. План запечатан. Контроллеру приходит «GO, делай». ✅
|
||
- Судья NO-GO → его замечание возвращается контроллеру. Счётчик L2 = 1. Контроллер переписал
|
||
→ снова к наставнику (L1 заново) → наставник одобрил → снова судье (L2 = 2)…
|
||
- (3 NO-GO судьи подряд → карточка владельцу.)
|
||
|
||
1. Контроллер НИ РАЗУ не общается с судьёй напрямую. Печатает ТОЛЬКО судья.
|
||
|
||
### Р4 (2026-06-13) — чистое завершение плана (выход в разговорный)
|
||
|
||
По коду: после выполнения плана контроллер ЗАСТРЕВАЕТ в режиме реализации — следующее действие
|
||
блокируется «план исчерпан» (`enforce-supreme-gate.mjs:217`); выйти можно только ручным удалением
|
||
`frozen-plan` или новой сессией (стена сама печать не снимает — грепом подтверждено).
|
||
**Решение:** добавить ЧИСТОЕ завершение — когда последний шаг плана выполнен ИЛИ владелец сказал
|
||
«готово», стена САМА снимает печать (удаляет `frozen-plan`) и возвращается в разговорный. Ручное
|
||
удаление файла больше не нужно.
|
||
|
||
### Р5 (2026-06-13) — состояние сессии для передачи в новую
|
||
|
||
**Пивот:** O9 (исходная задача — лимит доли INFERRED) **ПАРКНУТА** — судья-ИИ через aitunnel
|
||
таймаутил (500/timeout), печать спеки/плана не вставала. Код `context-verity.mjs`/`.test.mjs`
|
||
**НЕ тронут** (изменений O9 на диске нет). Orphan-файлы `specs/2026-06-13-o9-*.md` +
|
||
`plans/2026-06-13-o9-*.md` (v1+r2) — мусор, удалить.
|
||
**Сделано:** через `brainstorming` → `writing-plans` собран redesign согласования L1→L2:
|
||
|
||
- спека `specs/2026-06-13-l1-l2-negotiation-redesign-design.md` (простым языком, с примерами);
|
||
- план `plans/2026-06-13-l1-l2-negotiation-redesign-plan.md` (6 фаз, TDD);
|
||
- решения Р1-Р4 (выше).
|
||
**СТЕНА СНЯТА** (maintenance: `.claude/settings.json` = `{"hooks":{}}`, бэкап
|
||
`.claude/settings.json.bak-before-maintenance-2026-06-13`). Edit/Write/Bash свободны, цикла печати нет.
|
||
**Остаток:** исполнить план, начать с **Фазы 0 (smoke канала замечаний — ГЕЙТ)**, inline TDD.
|
||
**Риски:** судья-транспорт aitunnel нестабилен; канал доставки замечаний контроллеру — критичная
|
||
неизвестность (Фаза 0 её снимает). Коммиты — владелец; settings.json — владелец.
|
||
|
||
### Р6 (2026-06-13) — наставник видит контекст, судья судит вслепую (уточнение Р3, Фаза 3 спека)
|
||
|
||
Наставник судит спеку (и план) и даёт замечания, и **ОБЯЗАН видеть контекст** (verified-context,
|
||
переговоры — наставник работает рядом с контроллером, как старший коллега). Судья судит
|
||
**ВСЛЕПУЮ** — контекст НЕ видит, на суд идёт только сам артефакт (спека/план), чтобы оценка была
|
||
честной и независимой. Действует одинаково для спеки (gate1) и плана (gate2).
|
||
|
||
### Р7 (2026-06-13) — наставник заворачивает на содержательном несогласии (фикс круга L1)
|
||
|
||
Сквозной смоук способа B (Фаза 6.3) вскрыл: наставник доносил замечание контроллеру ТОЛЬКО при
|
||
сломанном/degraded вердикте; содержательное «пункт 2 плохой, переделай» оформлялось как валидный
|
||
вердикт → проходило как **GO** → молча, до контроллера не доходило, счётчик L1 не рос. То есть
|
||
круг L1 из Р3 НЕ работал — несогласие наставника тонуло. **Решение — Подход А:** в вердикт
|
||
наставника добавить явное поле `decision: "GO" | "NO-GO"` (как у судьи). Логика: `blocked =
|
||
wired && (decision==='NO-GO' ИЛИ вердикт сломан)`; на NO-GO контроллеру приходит СУТЬ
|
||
(`recommendation` + `reasoning` + `plan_points_addressed`, не «есть замечание»); `mentor-GO`
|
||
пишется только при `wired && ok && decision==='GO'`; счётчик L1 растёт на NO-GO (3 → карточка).
|
||
**Видимость вердикта — ТОЛЬКО на NO-GO** (на GO тихо, минимум шума). Судья (уже имеет decision +
|
||
objections), печать, счётчик-механика, finish-грант, стена — БЕЗ изменений. Реализация — через
|
||
живой цикл способа B (спека→наставник→судья→печать→план→печать→правки) + TDD, план со скил-цепочкой.
|
||
|
||
### Р8 (2026-06-13) — мерж роутера в наставника (Подход 1): роутер СОХРАНЯЕТ мозг
|
||
|
||
**Решение владельца:** наставник — ЕДИНЫЙ рецензент: судит спеку + план + **выбор скилов в плане**,
|
||
заворачивает NO-GO на любом несогласии. Роутер сливается с наставником по **Подходу 1**: наставник
|
||
на ревью плана зовёт классификатор **как функцию**.
|
||
**ГАРАНТИЯ (страх владельца снят): «становится функцией» НЕ значит «теряет мозг».** Мозг роутера
|
||
сохраняется ЦЕЛИКОМ: `classify()` — 3 слоя (prefilter → LLM → regex-fallback) + **граф скилов/узлов**
|
||
(`docs/registry/nodes.yaml` через `registry-load.mjs`, с per-node атрибут-**карточками**) +
|
||
эмбеддинги/PAMYATKA. Меняется ТОЛЬКО проводка: `classify()` зовёт **наставник** (а не дохлый
|
||
`router-prehook`), результат идёт в **вердикт наставника** (а не в файл-в-стол). На пенсию — лишь
|
||
обёртки-хуки `router-prehook` / `chain-recommendation` / `graph-first` (пустые посредники), НЕ мозг.
|
||
**Предпосылка:** план ОБЪЯВЛЯЕТ выбранные скилы структурно (иначе судить нечего). Этот мерж
|
||
ПОГЛОЩАЕТ фикс наставник-NO-GO (Р7) — он фундамент (наставник обязан уметь NO-GO).
|
||
|
||
### Р9 (2026-06-13) — состояние сессии для передачи в новую (handoff)
|
||
|
||
**СДЕЛАНО этой сессией (на диске, НЕ закоммичено — коммиты за владельцем):**
|
||
|
||
1. **Redesign согласования L1→L2, Фазы 0–6** (план `2026-06-13-l1-l2-negotiation-redesign-plan.md`):
|
||
Ф0 smoke-гейт канала (PostToolUse exit-2 ДОХОДИТ до контроллера, подтверждено фактом, хуки без
|
||
рестарта); Ф1 канал замечаний (`objection-delivery.mjs` `buildObjectionFeedback`/`buildDegradedFeedback`;
|
||
наставник+судья отдают дословный текст на NO-GO; degraded «не дозвонился» §9; root-cause:
|
||
`formatJudgeObjection` читал `verdict.blocking`, не `.objections`); Ф2 способ B
|
||
(`mentor-go-store.mjs` домен `MENTOR_GO`; наставник пишет mentor-GO/не печатает; судья fail-safe
|
||
сам печатает; дедлок-фикс снят); Ф3 спека тем же сценарием (`runMentorSpecVerdict`+`onSpecWrite`,
|
||
binding к хешу артефакта; судья gate1 под mentor-GO; `bindingHashForJudge`); Ф4 счётчики per
|
||
task-id (mentor+judge); Ф5 чистое завершение (`removeFrozenPlan`, авто после последнего шага +
|
||
finish-грант `PLAN_FINISH_ACTION='plan-done'`, Вариант А). **Полная регрессия 3877 passed + 2 skip,
|
||
0 регрессий.**
|
||
2. **способ B settings.json** отдан владельцу (наставник→судья оба PostToolUse, судья снят из Pre).
|
||
Владелец активировал → **сквозной смоук Ф6.3 вскрыл ДВА бага:** (A) наставник доносит замечание
|
||
только при СЛОМАННОМ вердикте — содержательное «переделай» тонет (Р7); (B) **роутер работает в
|
||
пустоту**: `classify()` зовёт только `router-prehook`, который пишет в файл и отдаёт контроллеру
|
||
`{}`; хуки `chain-recommendation`/`graph-first` в способ-B вообще не зарегистрированы.
|
||
3. **Дизайн мержа** (Р7/Р8 + спека `2026-06-13-router-mentor-merge-design.md` + план
|
||
`2026-06-13-router-mentor-merge-plan.md`, 9 задач TDD): наставник — единый рецензент
|
||
(спека+план+скилы), зовёт `classify()` как функцию (мозг роутера цел: 3 слоя + граф `nodes.yaml`
|
||
- карточки), заворачивает NO-GO. Поглощает Р7.
|
||
**СОСТОЯНИЕ СРЕДЫ:** **СТЕНА СНЯТА** (maintenance, `.claude/settings.json` = `{"hooks":{}}`; способ-B
|
||
бэкап у владельца + `settings - Copy.json`). Edit/Write/Bash свободны.
|
||
**ОСТАЛОСЬ:** исполнить план мержа (9 задач, inline TDD), затем владелец вернёт способ-B стену +
|
||
повторит смоук. Реализация НЕ начата.
|
||
**ПРОТОКОЛ:** записи только по команде владельца «фиксируй». Цепочка скилов исполнения: executing-plans
|
||
ИЛИ test-driven-development (inline RED→GREEN); systematic-debugging на баг; brainstorming перед
|
||
новым дизайном; /graphify или Grep/Read перед вопросом по коду. Регрессия — ТОЛЬКО
|
||
`npx vitest run --root app --config vitest.config.tools.mjs` (баре, без cd/&&/пайпа).
|