# O9 — лимит доли INFERRED в проверенном контексте (дизайн)

**Дата:** 2026-06-13. **Кодовая фраза:** «роутер-наставник».
**Статус:** дизайн утверждён владельцем (порог < 0.5 строго, AskUser 2026-06-13).
**Первоисточник:** `2026-06-10-router-mentor-live-rebuild-design.md` §5.5 / §5.5-R6.3 / §10
(O9 — design-choice OPEN). Роадмап `2026-06-12-router-mentor-roadmap.md`.

## Цель

Закрыть открытый вопрос O9: добавить в `verifyArtifact` (`tools/context-verity.mjs`)
структурный лимит доли INFERRED-цитат в проверенном контексте наставника — второй рубеж
против «формально проверенного» контекста, где 1 EXTRACTED + масса INFERRED проходят `ok:true`.

## Контекст (проблема)

§5.5-R6.3 (строка 138 первоисточника): без лимита доли поток с массой INFERRED-цитат
«проверен» формально — всё downgraded ушло в INFERRED, а freeze-gate его не блокирует
(он про неразрешённую EXTRACTED, не про долю INFERRED). Текущий `verifyArtifact` уже требует
≥1 EXTRACTED (VA-9), резолв всех EXTRACTED, derivation_ref у каждой INFERRED (VF-1),
отсутствие unknown-kind (SE-A1) — но НЕ ограничивает долю INFERRED. Атака: 1 EXTRACTED +
99 INFERRED (у каждой derivation_ref) → ok:true.

## Решение {#o9}

Третий рубеж в `verifyArtifact` — лимит доли INFERRED, через три зафиксированных ответа:

1. **Порог.** Экспортируемая константа `INFERRED_SHARE_MAX = 0.5` (зеркало `MIN_ANCHOR_LENGTH`,
   пометка design-choice O9). Страж требует `share < 0.5` СТРОГО: доля INFERRED ≥ 0.5
   блокирует. Большинство проверенного контекста обязано быть твёрдыми EXTRACTED. Ничья 50/50
   НЕ проходит. Клапан для законных INFERRED-тяжёлых случаев — owner-sign-off / escape (вне модуля).
2. **Знаменатель = 0.** Страж возвращает true («не решает»). Пустой артефакт уже валит ok по VA-9
   (extractedCount > 0); доля-страж не маскирует причину «пусто» и не решает при 0/0.
3. **Формула (одна строка):**
   `const inferredShareOk = total === 0 ? true : inferredCount / total < INFERRED_SHARE_MAX;`
   где `total = extractedCount + inferredCount`, `inferredCount` = число записей `kind==='INFERRED'`.

**Композиция ok:** к четырём существующим условиям добавляется `&& inferredShareOk`.
**Наблюдаемость:** при нарушении — один artifact-level `flagged {id:null, reason:'…(O9)'}`;
возврат дополняется полем `inferredCount` (зеркало `extractedCount`).
**Граница (намеренно):** доля-страж кусается только в чистом случае (все EXTRACTED резолвятся);
в нечистом ok уже false по downgrade. Downgraded-из-EXTRACTED НЕ считаем INFERRED (по исходному
kind), двойного счёта нет. Клапан INFERRED-тяжёлых случаев — вне модуля (§5.5).

## Тесты (TDD)

INFERRED_SHARE_MAX экспортирована = 0.5 · share<0.5 (2 EXTRACTED + 1 INFERRED) → ok сохраняется ·
share=0.5 → ok:false + flagged O9 · share>0.5 → ok:false · total=0 → ok:false по VA-9 без O9-флага ·
1 EXTRACTED + 99 INFERRED → ok:false (атака §5.5-R6.3) · downgraded не инфлейтит inferredCount ·
verifyArtifact().inferredCount присутствует.

## Границы scope

Только `tools/context-verity.mjs` + `tools/context-verity.test.mjs`. Freeze-gate / sign-off / escape
НЕ трогаются (клапан INFERRED-тяжёлых случаев живёт там). Регрессия tools-only база 3829 GREEN,
целевая ~3837, 0 регрессий в соседних машинах. Существующий тест 50/50 (1 EXTRACTED + 1 INFERRED →
ok:true) переписан под новый порог (добавлен 2-й EXTRACTED, share<0.5) — следствие решения порога.

## Ссылки

§5.5 / §5.5-R6.3 / §10 `2026-06-10-router-mentor-live-rebuild-design.md`. Sub-plan A
`2026-06-10-router-mentor-subplan-a-context-verity.md`. Роадмап `2026-06-12-router-mentor-roadmap.md`.
