# Арбитраж опечатывает: owner-seal-override (Фикс 3)

## Цель

Когда владелец на арбитраже выбирает «Держусь контроллера» или «Своё решение», план/спека должны
РЕАЛЬНО опечататься (frozenPlan/frozenArtifact записаны → стена входит в режим реализации),
несмотря на NO-GO судьи и наставника. Сейчас (баг F-D) «Держусь» обещает «ворота пропустят», но
escape даёт ALLOW лишь на одно действие, а печать требует `verdict.wired==='GO'` — поэтому каждый
шаг потом требует отдельного escape. Нужен подписанный владельцем сигнал owner-seal, который путь
печати чтит как разрешение опечатать по воле владельца.

## Подписанный сигнал owner-seal {#D1}

Новый модуль `tools/seal-override.mjs`. Канон-строка действия: `ownerSealAction(hash)` →
`owner-seal:<hash>` (hash = judgedHashOf(sealableArtifact) для спеки / planId(sealablePlan.steps)
для плана). Это **зарезервированная floor_escape-метка** (как `plan-done`): её не порождает ни одно
реальное действие инструмента, поэтому она срабатывает только на намеренный клик владельца.
Владелец кликает опцию `FLOOR-ESCAPE: owner-seal:<hash>` → существующий env-хук
`enforce-askuser-answer-parser` пишет и ПОДПИСЫВАЕТ запись (ключ владельца) — контроллер подделать
не может. Чтение — через существующие `loadFloorEscapes`/`loadConsumed` + `escapeGrantOpen`.

## Решение о печати {#D2}

Чистая функция `decideSeal({verdict, ownerSealOpen})`: вернуть true, если открыт owner-seal
(`ownerSealOpen===true`) ИЛИ настоящий wired-GO судьи. Иначе false. Owner-seal перевешивает NO-GO.

## Печать по owner-seal {#D3}

`sealOnWiredGo` (`enforce-judge-gate.mjs`) получает параметр `ownerSealOpen`; печатает (sealArtifact
/sealPlan + persist) если `decideSeal(...)` true — то есть и на owner-seal при NO-GO. На owner-seal
для плана **пропускается mentor freeze-gate** (владелец перевешивает и судью, и наставника). Прод-
сборка `sealTurnProd` вычисляет `ownerSealOpen = escapeGrantOpen('owner-seal:'+hash, grants,
consumed)` и передаёт в `sealOnWiredGo`. Печать по owner-seal помечается в seal-записи как
owner-override (аудит: опечатано волей владельца при NO-GO).

## Честный текст арбитража {#D4}

`arbitration-card.mjs`: текст опции «Держусь контроллера» — не «ворота пропустят (escape-грант)»,
а «план/спека опечатывается по твоему решению (owner-seal)». Карточка отдаёт `sealAction`
(каноническую строку `owner-seal:<hash>`), чтобы контроллер поставил её в опцию AskUserQuestion и
клик владельца её подписал. «Своё решение» — владелец вписывает указание, контроллер правит, затем
owner-seal печатает. «Согласен» — переделка без печати (как сейчас).

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

Чистые функции (`ownerSealAction`, `decideSeal`, текст/поля карточки) тестируются без I/O, RED→GREEN.
`sealOnWiredGo` с инъектированными deps: NO-GO + ownerSealOpen=true → sealed:true (sealPlan вызван,
mentorGate пропущен). Критерий: decideSeal truth-table; sealOnWiredGo печатает на owner-seal при
NO-GO; карточка несёт честный текст + sealAction; полная регрессия tools зелёная
(`npx vitest run --root app --config vitest.config.tools.mjs`).

```verified-context-json
[
  {"id":"D2-seal","kind":"EXTRACTED","ref":"tools/enforce-judge-gate.mjs","anchor":"export function sealOnWiredGo("},
  {"id":"D1-escape","kind":"EXTRACTED","ref":"tools/escape-grant.mjs","anchor":"export function escapeGrantOpen("}
]
```
