# Видимость вердикта судьи и наставника (Фикс 1, v2 — робастный канал)

## Цель

Контроллер должен видеть исход проверки наставника и судьи (GO / NO-GO / degraded / skip) на
каждой записи плана или спеки, не обращаясь к внешним логам. Доставка — через проверенный канал
`UserPromptSubmit.additionalContext` (как уже работает recall-память), а не через неподтверждённый
вывод PostToolUse: наставник/судья дозаписывают строку исхода в рантайм-файл, а отдельный
UserPromptSubmit-хук показывает непоказанные строки в начале следующего хода.

## Проверенный канал доставки {#D1}

В репозитории `hookSpecificOutput.additionalContext` доставляется контроллеру **только** на
событии `UserPromptSubmit` (recall-память памяти и инъектор-напоминание используют именно его).
Поэтому строитель вывода нового хука обязан выставлять `hookEventName: 'UserPromptSubmit'`.
Контракт: непустой `additionalContext` → JSON-payload в stdout; пусто → ничего (exit 0).

## Строка исхода {#D2}

Чистый строитель строки: `✅ GO — опечатано` / `🚫 NO-GO: <дословный текст>` /
`⚠ не дозвонился (<причина>)` / `⏭ пропуск (<причина>)`. Текст возражения дословный (verbatim).
Мусор/неизвестный вид → пустая строка (тотальность, не бросает).

## Хранилище исходов {#D3}

Рантайм-файл `verdict-surface-<сессия>.jsonl` (append-only). Контракт: дозаписать исход
(best-effort, сбой fs не ломает хук); прочитать непоказанные; пометить показанными (или усечь).
fs инъектируется для тестов. Не меняет stdout/exit ни одного существующего хука — это снимает
риск совместимости (вывод `exitDecision` остаётся `{}`).

## Покрытие всех записей {#D4}

Дозапись исхода врезается в `main()` обоих производителей — `enforce-judge-gate` и
`enforce-mentor-on-plan-write`, которые уже срабатывают (PostToolUse) на каждую запись плана/спеки.
Срабатывание на каждой записи обеспечивается **существующей** регистрацией этих хуков; новый
UserPromptSubmit-хук (`enforce-verdict-surface`) добавляется в `settings.json` — это шаг владельца,
вне scope кода. Без регистрации нового хука строки копятся в файле и не теряются.

## Интеграционная проверка {#D5}

Сквозной тест на чистых функциях: исход → `appendVerdictOutcome` (store) → `readUnsurfaced`
(store) → строитель UserPromptSubmit-payload → ожидаемый `additionalContext`. Проверяет видимость
end-to-end без зависимости от рантайма Claude Code (отвечает на возражение судьи о integration-test).

## Конвенция и критерий {#D6}

Чистые строители — отдельные экспортируемые функции (тестируются без I/O), образец —
`buildObjectionFeedback` / `ruflo-recall-hook.buildHookOutput`. Каждое поведение — vitest RED→GREEN.
Критерий приёмки: исход GO/NO-GO/degraded/skip даёт свою строку; store кладёт и отдаёт непоказанное;
UserPromptSubmit-payload несёт строку; полная регрессия tools зелёная
(`npx vitest run --root app --config vitest.config.tools.mjs`).

```verified-context-json
[
  {"id":"D1-channel","kind":"EXTRACTED","ref":"tools/ruflo-recall-hook.mjs","anchor":"hookEventName: 'UserPromptSubmit'"},
  {"id":"D3-nostdoutchange","kind":"EXTRACTED","ref":"tools/enforce-hook-helpers.mjs","anchor":"export function exitDecision("}
]
```
