feat: A - чтение под опечатанным планом свободно (ДР-1 снят в impl)

Под планом авторское чтение больше не блок: свой вывод, лог упавшего шага,
новый файл доступны. Чтение не двигает очередь шагов; impl-чтения логируются
с пометкой impl:true для ретро и не считаются во фронт-лоад порог. Секреты
держит отдельный read-path-deny. Свод зелёный: 4221 passed, 2 skipped.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Дмитрий
2026-06-18 10:40:23 +03:00
parent abf2060328
commit e91aa021f0
5 changed files with 140 additions and 26 deletions
@@ -0,0 +1,95 @@
# Дизайн: свободное чтение под опечатанным планом (снятие гейта ДР-1 в impl-режиме)
**Дата:** 2026-06-18 · **Репозиторий:** claude-brain (управляющий слой) · **Кодовая фраза:** «роутер-наставник».
**Источник:** баги `bags/2026-06-17-wall-read-block-bug.md` (+ `bug1.md`). Пункт **A** роадмапа допила эталона.
**Тип:** дизайн-доказательство (brainstorming → writing-plans). Правки `tools/*.mjs` — далее по церемонии TDD.
---
## 1. Проблема (по факту, с цитатами)
В режиме реализации (под опечатанным планом) чтение разрешено **только по пути текущего шага**.
Всё прочее — блок, включая собственный вывод запущенных инструментов и файлы, появившиеся по ходу.
Корень — **одна строка**: [tools/reading-discipline.mjs:111-116](../../../tools/reading-discipline.mjs#L111-L116),
функция `readingGateDecision`:
```
if (kind !== 'authorial-raw') return { block: false … }; // граф-карта / путь шага / критик-проба — свободно
if (frozenPlan) return { block: true, reason: '…гейт ДР-1 (impl-режим)' }; // ← ЭТО блокирует
return { block: false … signal: true }; // разговорный режим — не блок, лог
```
Вызывается из стены: [tools/enforce-supreme-gate.mjs:271-281](../../../tools/enforce-supreme-gate.mjs#L271-L281)
(`decideReadEvent` → при `ev.gate.block` стена возвращает блок).
### Почему правило бьёт по работе (10 случаев из бага)
Свой вывод сканера в temp-файле не прочитать; результат шага не проверить; ветвление по содержимому
невозможно; диагностика по внешнему логу закрыта; файл, родившийся по ходу или от соседней сессии,
недоступен. Итог — агент **действует вслепую**, чтобы не разворачивать план.
## 2. Что уже сделано (НЕ переделывать)
- **Десинк указателя F-J починен.** Стена двигает счётчик шага только при подтверждённом реальном шаге
(двухтактная «предварительная пометка»): [enforce-supreme-gate.mjs:446-448](../../../tools/enforce-supreme-gate.mjs#L446-L448).
Плюс floor-desync Δ7+: стена не двигает указатель на действие, которое зарубил бы пол
([:315-323](../../../tools/enforce-supreme-gate.mjs#L315-L323)).
- Следствие: **чтение и так не двигает очередь** (чтение никогда не было шагом). Поэтому открыть чтение
безопасно — оно не может сдвинуть план. Главный риск из бага («наивный escape `read:` сдвинет очередь»)
уже снят корнем.
## 3. Решение
**Во время реализации чтение не блокировать. Гейт ДР-1 из блокатора превращается в наблюдателя (лог).**
Обоснование (разобрано с владельцем 2026-06-18): запрет на чтение лечил не ту задачу и не в тот момент.
Цель «прочитать всё для точной спеки» достигается **на этапе планирования**; после печати плана запрет
ничего не добавляет к точности — только мешает проверять. Настоящая защита стены — **совпадение действия
с шагом** (мутацию вне плана не выполнить), а не запрет чтения. Свободное чтение **не расширяет** набор
разрешённых действий, поэтому безопасно; запрет же лишь заставляет действовать вслепую (слепой агент
**опаснее** зрячего — не ловит свою ошибку).
### 3.1 Что меняем (ядро)
1. **`readingGateDecision`** ([reading-discipline.mjs:111-116](../../../tools/reading-discipline.mjs#L111-L116)):
ветка `if (frozenPlan) → block:true` заменяется на **не-блок с сигналом** (`block:false, signal:true`).
В impl-режиме авторское сырьё-чтение становится **залогированным, но разрешённым**.
2. **`recordRead`** ([reading-discipline.mjs:132-140](../../../tools/reading-discipline.mjs#L132-L140)):
сейчас пишет в read-LOG только разговорное (`frozenPlan=false`) сырьё. Расширить: писать и impl-чтения
(`frozenPlan=true`) с пометкой режима — чтобы ретро видело, что читалось под планом.
3. **`enforce-supreme-gate`** (вызов на :271-281): после правки `ev.gate.block` для impl-сырья = false →
чтение проходит. Отдельной правки стены, скорее всего, не нужно (она лишь чтит `ev.gate.block`) —
подтвердить тестом интеграции.
### 3.2 Что НЕ трогаем (границы ответственности)
- **Секрет-гарды.** Защита `.env`/паролей/секретов — **отдельный хук** (`read-path-deny` и секрет-сканеры),
не гейт ДР-1. Он работает в обоих режимах независимо. Снятие ДР-1 его не ослабляет.
- **Критик-проба наставника** (`MENTOR_PROBE_CAP=2/круг`, [reading-discipline.mjs:160-179](../../../tools/reading-discipline.mjs#L160-L179)) —
про чтения САМОГО наставника, отдельный механизм. Не трогаем.
- **Разговорный фронт-лоад-лог** (SE-R7-5, warn «много сырья до заморозки») — остаётся как есть.
- **Машинерия шагов / указатель** — не касаемся (чтение не шаг).
### 3.3 Дисциплинарная заметка (норматив, не код)
В Pravila/GUIDE добавить строку: *если чтение по ходу противоречит замыслу плана — честный ход
«развернуть и перепланировать» (M7 Ф8 re-plan уже разрешён в impl), а не доделывать вслепую.* Стена это
не заставит; ловят наставник/судья/ретро по логу чтений.
## 4. Критерий «починено» (из бага)
- Под опечатанным планом читаются: свой вывод инструментов, файлы, созданные после печати, лог упавшего
шага, файл соседней сессии — **без сдвига очереди шагов**.
- Падение/блок шага НЕ двигает указатель (F-J — регресс-тест держит).
- Секреты (`.env` и т.п.) по-прежнему закрыты `read-path-deny` (не регрессирует).
- read-LOG фиксирует impl-чтения (видно в ретро).
## 5. Тесты (TDD-набросок)
- `readingGateDecision({readKind:'authorial-raw', frozenPlan:true})``block:false, signal:true` (был true).
- `readingGateDecision` для не-сырья — без изменений (граф-карта/путь шага/проба свободны).
- `recordRead` пишет impl-чтение с пометкой режима; разговорное — как раньше.
- Интеграция: под frozenPlan `decideReadEvent(authorial-raw)` → стена пускает Read (регресс на :271-281).
- Регресс F-J: блок шага со-хуком не двигает указатель (уже есть — не ломаем).
- Секрет-регресс: `.env` под планом всё равно режется отдельным гардом (smoke).
## 6. Решения владельца (закрыто 2026-06-18) + риски
- **Q1 — РЕШЕНО: тихо.** impl-чтения логируются ТОЛЬКО для ретро, в баннер не выводятся.
- **Q2 — РЕШЕНО: порога-warn нет.** Чтение под планом легитимно — число не ограничиваем и не пугаем.
- Риск «дрейфа» (читаю и тихо доделываю кривой план вместо re-plan) держится не кодом, а
шаг-гейтом (off-plan действие не пройдёт) + дисциплинарной заметкой §3.3.