# Память кругов для судьи (Фикс 2a) — судья видит свои прошлые претензии

## Цель

Судья в круге 1 остаётся слеп (чистый суд продукт-против-цели). Начиная с круга 2 он видит
СВОИ собственные прошлые претензии **дословной цитатой** и как контроллер их закрыл (раздел
«Переговоры» плана), и обязан сначала проверить, сняты ли именно эти претензии, а новую фатальную
поднимать только с обоснованием, почему её не было видно раньше. Это закрывает цикл
самопротиворечия (каждый круг судья судил заново и цеплялся за новое, часто за им же
потребованное).

## Хранилище кругов {#D1}

Новый модуль `tools/round-memory-store.mjs`: дозапись и чтение дословных претензий по ключу
(task_id, side) в рантайм-файл `round-memory-<taskid>.jsonl` (append-only). Контракт:
`appendRoundObjection({taskId, side, objectionVerbatim})` — пишет verbatim-строку (пустую не
пишет); `readRoundObjections({taskId, side})` — массив дословных строк по порядку кругов. fs
инъектируется. best-effort (сбой fs не ломает судью).

## Блок памяти в промпте судьи {#D2}

`buildJudgePrompt` (`judge-engine.mjs`) получает новые опциональные параметры `priorObjections`
(массив дословных строк) и `controllerResponses` (массив `{round, position}` из «Переговоров»).
Контракт: priorObjections НЕ пуст → в user-часть добавляется блок «ТВОИ ПРОШЛЫЕ ПРЕТЕНЗИИ
(дословно — не противоречь себе)» + «КАК КОНТРОЛЛЕР ИХ ЗАКРЫЛ» + инструкция «сначала проверь
снятие ИМЕННО этих, новое — только с обоснованием». priorObjections пуст (круг 1) → блок
отсутствует, поведение прежнее (слеп). Цитаты дословные, без пересказа.

## Проводка судьи {#D3}

В `runJudgeGate` (`enforce-judge-gate.mjs`): загрузить прошлые претензии судьи по task_id из
round-memory, распарсить `## Переговоры` из контента события (`parseNegotiationSection`), передать
оба в `promptArgs`. После вердикта: если NO-GO — дозаписать дословную претензию текущего круга
(`formatJudgeObjection`) в round-memory (side='judge'). best-effort.

## Дословность (цитата, не пересказ) {#D4}

Претензия хранится и подаётся обратно судье ПОБАЙТНО как вынесена (`formatJudgeObjection` без
сокращения/перефраза). Никаких сводок/пересказов — иначе дрейф формулировки даёт новый цикл.

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

Чистые функции (store read/write, рендер блока в `buildJudgePrompt`) тестируются без I/O / без LLM,
RED→GREEN. Критерий: круг 1 — промпт без блока памяти (слеп); круг 2 — промпт содержит дословную
претензию круга 1; store кладёт и отдаёт дословные строки по порядку; полная регрессия tools
зелёная (`npx vitest run --root app --config vitest.config.tools.mjs`).

```verified-context-json
[
  {"id":"D2-prompt","kind":"EXTRACTED","ref":"tools/judge-engine.mjs","anchor":"export function buildJudgePrompt("},
  {"id":"D3-negotiation","kind":"EXTRACTED","ref":"tools/negotiation-section.mjs","anchor":"export function parseNegotiationSection("}
]
```
