# Причина, по которой человек не видит плана, считается на показе, а не читается из состояния - **Дата:** 2026-08-10 - **Источник:** [openspec/changes/archive/2026-08-10-long-title-to-review/design.md](../../openspec/changes/archive/2026-08-10-long-title-to-review/design.md), Решение 6 и раздел `Risks / Trade-offs`; отчёт триажа того же change, находка 1 ## Контекст Проверка длины целевого имени встала в `layout.BuildLinks` — туда же, где собираются оба предпросмотра экрана ревью. Это дало даром совпадение показанного с применённым, но и вторую половину: непомещающееся имя обнуляет предпросмотр, а без предпросмотра экран прячет команду «Применить». Первым решением панель действий брала текст из `error_msg` — причины, записанной при последнем переходе. Ревью показало, что на самом частом входе этого поля нет вовсе: задача, пришедшая в `review` из-за отсутствия матча, попадает туда с пустой причиной и до раскладки не доходит. Замер триажа на двух деревьях: ``` до изменения: предпросмотр строится, «Применить» доступна, применение доводит до failed с текстом ядра после: предпросмотр пуст, команды нет, причины нет — экран печатает «Подтверди источник», хотя источник ни при чём ``` То есть изменение, чья цель — «человек узнаёт причину», на этом входе диагностируемость ухудшало. ## Решение **Причина отказа считается в момент показа и отдаётся транспорту значением (`worker.ReviewData.PreviewError`); записанная в состоянии используется только когда посчитанной нет.** Цитата из `design.md`, Решение 6: > Оба предпросмотра ревью (карточка и строка источника) строят пути тем же > `BuildLinks`, поэтому вердикт на показе и вердикт на применении совпадают по > устройству, а не по договорённости. Отсюда следует и обратное: раз вердикт считается на показе, там же считается и его причина. Посчитанная предпочитается записанной по двум причинам сразу: записанной может не быть вовсе, а после смены источника она уже про другой план — команды, меняющие эффективный источник, поля ошибки не чистят. **Чтение при этом состояние не двигает.** Построение предпросмотра остаётся без побочных эффектов; причина уходит наружу возвращаемым значением. Это второй случай одного класса за день. Первый — [ADR-2026-08-10-sanitize-at-every-entry](ADR-2026-08-10-sanitize-at-every-entry.md): гарантия, поставленная на запись, не покрывает то, что записано раньше. Здесь она не покрывает то, что не записано вовсе. ## Рассмотренные варианты - **Записывать причину в состояние при построении предпросмотра.** Отвергнуто: чтение начало бы двигать состояние. Запрет уже стоял в коде отдельным комментарием — предпросмотр не переводит задачу в `review` при рассинхроне папок, — и заводить исключение ради текста на экране значило бы снять правило. - **Оставить как есть, записав остаток сценарием спеки.** Отвергнуто на чекпоинте: регресс диагностируемости дошёл бы до боевого окружения на самом частом входе. - **Печатать причину только в баннере состояния, панель не трогать.** Отвергнуто: баннер показывает записанное и на этом входе пуст ровно так же. ## Цена Причина живёт в двух местах — записанная в состоянии и посчитанная на показе, — и порядок между ними держится на ревью, а не на типе. Взамен экран ревью объясняет отсутствие команды всегда, а не только когда причину успели записать, и объяснение относится к текущему плану, а не к прошлому. Побочно: тот же текст может оказаться и в баннере, и в панели, когда записанная причина совпала с посчитанной. Дубль признан приемлемым — он честен, а код, который его снимал бы, дороже.