textmachine/docs/PROGRESS.md

674 lines
199 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Журнал прогресса
> **⟶ ТЕКУЩЕЕ СОСТОЯНИЕ** (обновляемый блок; на 2026-07-05). **Источник истины по РЕШЕНИЯМ — `architecture/05-decisions-log.md` (D1D12); этот файл — ЖУРНАЛ, не спека.**
> - **Фаза:** 0 (каркас) завершена; машинерия Фазы 1 в основном построена — банк памяти v2, чанкер + txt/epub импорт, disposition/coverage-гейт/эскалация, durable resume, глоссарий→редактор. Следующее: реальный ja→ru прогон end-to-end + пилот Ф2.5.
> - **Стек (2026-07-05):** черновик DeepSeek V4 Flash · редактор **grok-4.3** (thinking-OFF через ЯВНЫЙ `reasoning_effort:none` — дефолт grok = `low`) · судья/апекс Gemini 3.1 Pro (mandatory thinking) · эскалация A: DeepSeek V4 Pro → GLM-5.1 → Gemini · канал B (18+): Grok. **Anthropic выброшен (за дороговизну), OpenAI оставлен.** 6 ключей.
> - **Экономика:** `experiments/08-cost-model-v2.md` (~$0.69 ранобэ / ~$10.94 вебновелла-500) — заменяет старые пороги $0.6 / $5 / $30.
> - Записи ниже — хронология; РАННИЕ (день-0, 04.07) содержат устаревшие цифры/решения (COGS $24, BYOK, Anthropic-Sonnet), переопределённые позже — см. блок выше и 05-decisions-log.
## 2026-07-04 — Старт проекта (MVP-сессия)
- Прочитан стартовый бриф `START_PROMT.MD` (37 пунктов идей).
- Осмотрена кодовая база `/home/ubuntu/projects/vojo/apps/ai-bot`: Go-сервис с адаптерами LLM-провайдеров (gemini, xai, local), роутером, каскадом, фейловером, прайсингом и телеметрией — кандидат на переиспользование.
- Запущен мультиагентный исследовательский воркфлоу (10 направлений параллельно + критик полноты + добор пробелов):
1. Рынок и спрос → `research/01-market.md`
2. Конкуренты и существующие решения → `research/02-competitors.md`
3. Научные работы по agentic/document-level MT → `research/03-academic-agentic-mt.md`
4. LLM API: цены/качество/цензура → `research/04-api-providers.md`
5. Память и глоссарий (банк памяти книги) → `research/05-memory-glossary.md`
6. Локальные модели на 8GB VRAM → `research/06-local-models.md`
7. Методология профессионального худ. перевода → `research/07-translation-methodology.md`
8. Юридические аспекты → `research/08-legal.md`
9. Модель стоимости перевода книги → `research/09-cost-model.md`
10. Ревью vojo/ai-bot на переиспользование → `research/10-vojo-ai-bot-review.md`
- Добор пробелов от критика → `research/11-gap-*.md`
### Исследования завершены (04.07, ~2 млн токенов, 16 агентов)
Все 15 документов в `research/`. Ключевые развязки:
- Статья «про судью-селектора, март 2026» найдена: arXiv:2603.20324 «When Agents Disagree» — но перевода среди её задач нет; на zh→ru/ja→ru нужен собственный пилот (см. `research/11-gap-3.md`).
- MemPalace существует, но форкать нельзя (метрики не подтверждаются) — банк памяти пишем сами: SQLite + спека SillyTavern World Info + память DelTA.
- «Ru-нишу никто не обслуживает» — опровергнуто: Rulate AI-раздел 14,4 тыс. работ, MLate, VseGPT «Нейропереводчик» 999 ₽/мес. Дифференциация — издательское качество, память серии, 18+.
- Экономика сходится: COGS тома ранобэ ~$24 при марже 7096%; главные рычаги — prompt caching (до 98% input) и Batch API (50%).
- OpenAI adult mode заморожен бессрочно — NSFW-канал: Grok / open-weights / DeepSeek / локальная abliterated. Anthropic — только «стерильные» роли.
- RU-сегмент: BYOK-модель (агрегаторы ProxyAPI/VseGPT/AITunnel или прямой DeepSeek), не перепродавать западные токены.
### Синтез (04.07)
- `architecture/01-decisions.md` — 10 решений (Р1 Go-бэкенд на базе vojo/ai-bot; Р2 конфигурируемое ядро пайплайна + пилот 4 рук; Р3 банк памяти на SQLite; Р4 модельный стек и NSFW-роутинг; Р5 экономика вызовов; Р6 durable jobs; Р7 телеметрия/качество; Р8 юр-позиция «инструмент, не платформа»; Р9 прайсинг-гипотеза; Р10 риски).
- `architecture/02-mvp-plan.md` — фазы 03 с критериями приёмки.
- `architecture/components.puml` + `pipeline.puml` (+ отрендеренные .svg) — провалидированы PlantUML.
- `PARALLEL_SESSION_PROMPT.md` — промт для второй сессии («Полигон»: токен-замеры, refusal-бенчмарк, локальный стенд, пилотный корпус, эмбеддинги).
- Проведено адверсариальное ревью синтеза тремя критиками (техархитектура, экономика, red-team): 2 critical + ~15 major находок, все внесены в v2 документов. Главные исправления:
- экономика разделена на контуры «чей ключ» (прямые ключи / ru-агрегаторы ×26 на флагманы / BYOK) — премиум-микс с Sonnet в ru-контуре недоступен;
- разрешён конфликт «кэшируемый префикс vs селективный глоссарий» (зафиксирована раскладка промпта) и «modernc.org/sqlite vs sqlite-vec» (в MVP — brute-force KNN, без C-расширений);
- Фаза 1 получила интерим-правило 18+ (SFW-приёмка, исключение Anthropic при 18+ в brief) — до этого 18+ книги шли бы через Anthropic до появления NSFW-роутера;
- resume пересобран на чанк-чекпоинты (kill -9 теряет максимум один вызов);
- пилот вынесен в отдельную Фазу 2.5, горизонт MVP честно сдвинут до 1011 недель;
- baseline метрики качества заменён с «сырой DeepSeek» на «DeepSeek+глоссарий» (уровень VseGPT), порог — статистический;
- в план добавлены режим онгоинга и series-bible-lite (сегмент «ИИ-фабрик» и проверка рода/ты-вы).
### Следующие шаги
- [~] Фаза 0 (каркас) ЗАВЕРШЕНА; машинерия Фазы 1 в основном построена — сессия «Бэкенд» (промт: `prompts/done/BACKEND_SESSION_PROMPT.md`; шаг 0 — перевалидация решений, финал фаз — агентное селфревью). Осталось: полный стек-wiring, автопопуляция глоссария, реальный ja→ru прогон. Оркестратор делает внешнее ревью её кода.
- [x] Параллельная сессия «Полигон» запущена (эксперименты 0103 идут).
- [ ] Сессия «Редакция» (промпты ролей) — после фиксации формата конфига в Фазе 0.
- [x] Сессия «Валидация банка памяти» — завершена (вердикт GO на схему+гейты; реестр `architecture/06`; ставка гейтится in-house eval'ом в пилоте Ф2.5).
- [ ] Пилот 4 рук для выбора ядра пайплайна + **in-house memory-eval** (Фаза 2.5).
- Роли сессий: «Бэкенд» → `backend/`; «Полигон» → `eval/` + `docs/experiments/`; оркестратор → доки, ревью, синхронизация, дозаправки ресёрча.
- [x] **Дозаправка ресёрча выполнена (04.07, оркестратор)**: 5 документов `research/12-*.md` (~70 режимов отказа: ja, zh, ru-сторона; отзывы потребителей по продуктам; академические таксономии DITING/BlonDe/LitEval/LAIT) + верификация (3 minor: неточная ссылка поправлена; 2 пробела — числительные/меры CJK и западные имена через катакану — включены в карту как дыры с действиями). Итоговая карта «проблема → механизм бэкенда» → `architecture/04-unhappy-paths.md`; в ней раздел «Следствия для плана» — 7 изменений (пре-пасс Annotator в Фазе 2, расширение схемы глоссария, 4 новых дешёвых гейта Фазы 1, судья-анкета с MQM-весами, alignment-защита рефренов, эскалация по цене правки, регрессионный сьют из примеров).
## Бэкенд
### 2026-07-04 — Сессия 1: шаг 0 (перевалидация) завершён
- Донорский код vojo сверен построчно + воркфлоу из 4 критиков (консистентность, Go-исполнимость, донор, онлайн-фактчек цен). Вердикт: **архитектура v2 исполнима, кодить можно**; блокеров нет. Полный вердикт и контракты Фазы 0 → [architecture/03-implementation-notes.md](architecture/03-implementation-notes.md).
- Главные находки валидации (упущения передачи): в `Usage` донора нет cache-write Anthropic (×1.25/×2 — тот же класс ошибки, что недоучёт reasoning 3044%); в транспорте донора скрытый захардкоженный per-attempt таймаут 60 с (полигон видел только 45 с ноги failover); `http.Client{}` донора уйдёт в webshare-прокси на не-loopback локальных адресах (172.x); **Grok 4.1 Fast retired 15.05.2026** — слаги молча редиректят на grok-4.3 с ценой ×9, таблица Р4 устарела; store.go на SQLite — переписывание по семантике, не «адаптация <20%».
- Окружение: git-репо инициализирован, Go 1.26.4 установлен (~/sdk/go, PATH в .bashrc).
**РЕШЕНО** (04.07) ответ оркестратора ниже + ратифицировано в [05-decisions-log](architecture/05-decisions-log.md) (D1D7); детали в 03-implementation-notes §5:
1. Формула премиум-бюджета Р5 «≤2×» после токен-калибровки неоднозначна реализую конфигурируемый $-потолок, формулу уточнить.
2. Политика инвалидации TM сверх brief_hash (prompt_version в ключе? модель? перечанкование?) реализую консервативный вариант, нужно подтверждение.
3. Канал B остался без дешёвого Grok (4.1 Fast retired, grok-4.3 дороже ×9) перевыбрать модель канала B к Фазе 2.
4. Стриминг: эмпирика полигона требует его как keep-alive транспорта (не SSE-фронт) предлагаю перенести из Фазы 3 в Фазу 12; в Фазе 0 закрываю длинными таймаутами.
5. Оркестратору, не блокирует: цифры Р5 устарели ~2× против эксп. 01; задача «cache-hit агрегаторов» задвоена (Фаза 0 бэкенда бэклог полигона предлагаю отдать полигону); мелкие фазовые пометки в диаграммах.
Вопросы владельцу: ключи провайдеров для `backend/.env` (DeepSeek минимум на нём приёмка Фазы 0 с реальным вызовом; Anthropic для проверки cache_control). Не блокируюсь: тесты на httptest-моках.
> **Ответ оркестратора на [НУЖНО РЕШЕНИЕ] (04.07).** Отличный шаг 0 — фактчек Grok и cache-write Anthropic особенно ценны. Решения:
> 1. **Премиум-бюджет**: подтверждаю $-потолок; формула зафиксирована в Р5 (`clamp(price_target × (1 target_margin) est_base_cogs, 0, hard_cap)`, дефолты $5/том, $30/вебновелла-500). «≤2×» — только прикидочная эвристика доков.
> 2. **TM-инвалидация**: консервативный ключ подтверждён и зафиксирован в Р6: `(chunk_src_hash, lang_pair, model_id, prompt_version, brief_hash, context_snapshot_hash)`; перечанкование инвалидирует by design.
> 3. **Канал B**: Р4 обновлён — интерим до Фазы 2: DeepSeek офиц. + локальная abliterated; Grok 4.3 только как дорогая эскалация; перевыбор дешёвого пермиссивного тира — по результатам refusal-бенчмарка полигона.
> 4. **Стриминг**: перенос одобрен — транспортный keep-alive-стриминг в Фазу 12 (без SSE-фронта), зафиксировано в плане; в Фазе 0 — длинные per-роль таймауты.
> 5. **Р5 обновлён** сноской на токен-калибровку (×1.41.75 для zh→ru); задача «cache-hit агрегаторов» снята с Фазы 0 — она в бэклоге полигона.
> **Новая вводная**: готова карта режимов отказа [architecture/04-unhappy-paths.md](architecture/04-unhappy-paths.md) (~70 режимов → механизмы). Перед фиксацией схемы store/глоссария Фазы 1 прочитай раздел «Следствия для плана»: расширение полей глоссария (alias-граф, ranked-set, gender=hidden, first_person, translit_policy), ruby-парсер в спеку импорта, дешёвые детерминированные гейты Фазы 1 (линтер прямой речи, блок-лист транслит-междометий, ёфикатор, число-гейт 万/億), словарь тегов ошибок с MQM-весами в request_log с первого дня. Пороги coverage-гейта уже сняты полигоном (см. его секцию, эксперимент 02).
### 2026-07-04 — Сессия 2: Фаза 0 (каркас) ЗАВЕРШЕНА
Каркас `backend/` собран, приёмка Фазы 0 продемонстрирована **исполняемо**: `tmctl translate --config book.yaml`
гоняет чанк draftedit с полным учётом $ по стадиям в request_log; повторный запуск обслуживается из
чекпоинтов за $0 (ledger неизменен); `kill -9`-тест настоящим SIGKILL подтверждает инвариант
`committed == SUM(checkpoints)` (деньги чекпоинты). `go test ./...`, `go vet`, `-race` зелёные.
- **Порт vojo internal/llm|ledger|obs**: нейтральные типы (+`CacheCreationTokens`, `CacheBoundary`,
`FinishReason`); общий OpenAI-совместимый транспорт (таймауты-параметры per-провайдер, Retry-After с капом,
overflow-safe backoff, LimitReader, оба варианта cache-полей DeepSeek); **нативный Anthropic-адаптер**
(Messages API, `cache_control`, суммирование usage-инварианта, sampling не шлётся); local-адаптер с no-proxy
транспортом (грабли стенда 172.x); failover с анти-flapping брейкером; ledger с cache-write и `PriceForResponse`.
- **internal/store (SQLite, modernc, CGO-free)**: идемпотентные миграции; reserve/settle с потолками книга/день;
**settle+checkpoint одной транзакцией** (закрыта дыра двойной оплаты); flock-владение проектным файлом;
recovery зависших резервов; request_log.
- **internal/config (fail-fast)**: models.yaml (цены с датой проверки, `CheckKeys` preflight), pipeline C1+C2
(граница «конфиг vs код» Р2, `CheckRunnable` guard на механику Фазы 2), book.yaml + brief_hash.
- **internal/pipeline**: детерминированный однопроходный рендер (инвариант §3.1), request-hash (length-prefix,
attempt-измерение), snapshot-pinning с `--resnapshot`, нормализация источника (BOM/CRLF/NFC), мини-раннер
draftedit с resume; cmd/tmctl (translate/report); черновики промптов ролей.
- **Финал агентное селфревью**: `/code-review` (8 линз) + воркфлоу-критики (4 линзы задания) с адверсариальной
верификацией; подтверждённые находки исправлены двумя волнами (детали и остаточный техдолг
[03-implementation-notes §6](architecture/03-implementation-notes.md)). Коммиты: `dc6ea8e` каркас
`a32ec2e` волна 1 волна 2.
Учтено из ответа оркестратора: ключ TM `(chunk_src_hash, lang_pair, model_id, prompt_version, brief_hash,
context_snapshot_hash)` совпадает с составом моего snapshot-payload (prompt_version+model+PromptSHA256 per-role,
brief_hash, chunker/estimator version); перечанкование инвалидирует by design (chunkerVersion в snapshot).
Карту 04-unhappy-paths заберу в схему store/глоссария при старте Фазы 1.
**Остаток техдолга Фазы 0** (осознанные ограничения, не блокеры; детали §6): дневной потолок пер-книжный;
timeout-путь «оплачено-но-потеряно» (≤1 вызов, укладывается в Р6); cache_ttlcache_write под один TTL (5m);
гонка `Runner.clients` (безопасна при последовательном проходе, мьютекс к fan-out Фазы 12).
**Ключи: бэкенд заводится на ДВУХ ключах** (`DEEPSEEK_API_KEY` + `ZAI_API_KEY`) по замечанию владельца сузил
`CheckKeys`: модели стадий проверяются всегда, модели эскалационных цепочек только если включён хоть один гейт
(эскалация запускается по провалу гейта; в Фазе 0 гейты off цепочки недостижимы ключи Anthropic/Kimi не
нужны). Проверено на боевых конфигах: с 2 ключами прогон доходит до сетевого вызова DeepSeek. `.env.example`
размечен «нужны сейчас / Фаза 1+ опционально». Anthropic/Kimi для Фазы 0 не требуются.
### Вопросы от бэкенда — сессии «Полигон» и оркестратору (04.07)
Владелец резонно заметил: бэкенд не должен коммититься в модели, которых полигон не гонял. Прежде чем в Фазе 1
включать эскалацию и фиксировать редактора-дефолт, нужны замеры:
1. **Полигону — Anthropic на «стерильном» канале (SFW).** Sonnet 5 как SFW-эскалация/судья **не валидирован**:
в refusal-бенчмарке Anthropic исключён намеренно (гигиена NSFW-аккаунта, gap-2 §3), но сам эксп. 02 отметил
«уровень L0L1 можно добавить отдельным конфигом для проверки стерильного канала». Можно ли прогнать
Sonnet-5 (промо $2/$10) на чистых SFW-фрагментах качество ru-редактуры/суждения чтобы знать, окупает ли
он цену как эскалация? Если не приоритет бэкенд держит Anthropic **вне** дефолтной цепочки и берёт
валидированную дешёвую модель.
2. **Полигону — качество редактора ru-стиля.** Эксп. 02 мерил роль ЧЕРНОВИКА (отказы/вырезания), но не роль
РЕДАКТОРА. Дефолт C1 GLM-5 на редактуре стоит на утверждении Р4, без замера. Планируется ли маленькое
сравнение GLM-5 vs Kimi-K2.6 (vs Sonnet-5, если будет ключ) по ru-редактуре на нескольких SFW-фрагментах?
От этого зависит дефолт редактора Фазы 1.
3. **Оркестратору — эскалационный дефолт в RU-контуре.** Оставить Anthropic Sonnet дефолтом эскалации или в
RU-контуре взять GLM-5.1/Gemini (Sonnet только прямой контур, где per-book-премиум оправдан)? Это правка
Р4/экономики; бэкенд только исполнитель конфига.
4. **Оркестратору — per-role provider-fallback?** Для batch-джобы (не live-бот) провайдер-недоступность
естественно закрывается durable jobs + чекпоинтами (лёг пауза resume без переоплаты), поэтому
мгновенный fallback на другого провайдера nice-to-have, не блокер. Добавлять ли простой список фоллбеков
на роль (`draft: [deepseek, glm]`) для длинных ночных прогонов, или полагаться на pause/resume? Решение за
оркестратором (владеет Р4/экономикой).
Не блокирует Фазу 0 (принята на DeepSeek+Z.ai); ответы нужны к старту Фазы 1 (эскалация, дефолты ролей).
### Внешнее ревью Фазы 0 — принято (04.07)
Независимая сессия провела построчное ревью `backend/` + исполняемую приёмку + адверсариальный воркфлоу.
**Вердикт: Фаза 0 принята, блокеров ноль.** Детали и диспозиция находок [03-implementation-notes §6](architecture/03-implementation-notes.md).
Кратко: F1 (CheckKeys) уже был закрыт до ревью; F2/F5/F7/F8 исправлены этой волной (local-оверрайды в snapshot;
fail-loud на включённый гейт в Фазе 0; поправка §3.4 под подтверждённый ключ TM; `*.db.lock` в .gitignore);
F3/F4/F6 в техдолг (F3: граница timeout-недоучёта уточнена до `MaxAttempts1`, не «≤1»; честный фикс
idempotency-ключ, отложено). Дизайн-вопросы к владельцу/оркестратору D1D3 (монолингвальный редактор Фазы 1;
per-chunk skip+flag вместо падения; структурный запрет Anthropic в канале B при подключении failover)
зафиксированы в §6, все Фаза 12.
Следующее: Фаза 1 (перевод книги целиком) чанкер, банк памяти v1, гейты (пороги полигона готовы), режим онгоинга.
### Реальная приёмка на живых ключах — PASS (04.07, ревьюер)
Первый реальный прогон провайдеров (раньше всё было на моках главный незакрытый пробел ревью). `tmctl translate`
на `example/book.yaml` (draft=deepseek-v4-flash edit=glm-5, один чанк 264 симв., потолок $1.00):
- **Деньги сходятся до цента**: draft $0.000219 (453·0.14+556·0.28/1e6 ✓), edit $0.001277 (672·1.0+189·3.2/1e6 ✓);
`committed == Σстадий == $0.001496`, `reserved=0`. Порядок величин совпал с прайсингом DeepSeek/z.ai.
- **Цена по ответившей**: z.ai вернул `model=glm-5` edit книжится по цене GLM, НЕ по дешёвому deepseek-якорю
(fallback дал бы $0.000147 в 8.7× меньше); `PriceForResponse` подтверждён на реале.
- **Usage реальный**, не мок: `prompt/completion_tokens` ненулевые в request_log; GLM латентность штатная (58 с,
без ×3) `extra_body thinking:{type:disabled}` фактически применён.
- **Resume**: второй прогон обе стадии из чекпоинтов за **$0**, ledger неизменен (нет двойной оплаты).
- **DeepSeek автокэш на реале**: повторный прогон того же префикса в окне кэша `cached_tokens=384/453`
(поле `prompt_cache_hit_tokens` парсится в `request_log.cached_tokens`), billed по $0.0028/M; `CostUSD`
сошёлся до 7 знаков (`(453384)·0.14 + 384·0.0028 + 1074·0.28 = $0.0003115`). Кэш-путь подтверждён живым провайдером.
- **Пост-ревью правки провалидированы**: F1 (CheckKeys заводится на 2 ключах), F2 (provider temp/maxtok в
snapshot), F5 (fail-loud на включённый гейт), F7 (сноска §3.4) все на месте; Anthropic вычищен из конфигов,
висячих ссылок нет (в `BuildClient` ветка `case "anthropic"` осталась, но `kind: anthropic` в models.yaml нет).
**Новая находка реальной приёмки (исправлена):** `tmctl report` рвался с `context canceled` и печатал таблицу
частично/пусто без строки Ledger (exit 1). Причина `Store.RequestLogRows` отдавал `*sql.Rows` с `defer cancel()`:
контекст отменялся посреди ленивой итерации у вызывающего. Данные и деньги в БД были корректны баг только на
read-пути `report`. Фикс: строки материализуются под таймаутом и возвращаются срезом `[]RequestLogView`;
регрессионный тест `TestRequestLogRowsMaterializes`. `go test ./... -race` зелёные.
**Не покрыто реальным прогоном (честно):** (б) kill-9 посреди реального провайдерского вызова инвариант
`committed==SUM(checkpoints)` доказан unit-тестом `kill9_test.go` (настоящий SIGKILL на SQLite), на реале не
воспроизводил (деньги/один-чанк дисциплина). (в) Anthropic cache_control/usage-сумма Anthropic из стека убран,
проверять больше нечего на этом контуре.
### [НУЖНО РЕШЕНИЕ] перед Фазой 1 (владелец/оркестратор)
Фаза 0 закрыта; перед стартом Фазы 1 нужно закрыть решения ниже (по каждому рекомендация ревьюера).
Фундамент Фазы 1 (чанкер + схема памяти) можно начинать параллельно гейтят только пп. 1, 2, 4.
1. **D1 — что видит редактор:** монолингвальный (черновик) vs билингвальный (черновик+исходник). *Рек:*
монолингвальный стилист; верность/полноту coverage-гейт + билингвальный судья (Р2/04-unhappy-paths; убирает
риск zhru кальки от GLM). Блокирует context assembly, промпты «Редакции», `editor.md` (убрать `{{text}}`).
2. **D2 — диспозиция «плохого» чанка** (пустой/отказ/`finish=length`): падать всем прогоном vs per-chunk
флаг+продолжить. *Рек:* skip+flag+continue (Р4) + механизм `attempt` (на `length` ретрай с бОльшим
max_tokens; N флаг). Ключ resume уже несёт `attempt`. Блокирует главный цикл раннера, resume-семантику флагов.
3. **Финальные модели эскалации** (канал A/B) после вывода Anthropic `[НУЖНО РЕШЕНИЕ]` п.3. *Рек:* A
GLM-5.1/5.2 или Gemini (нативный адаптер Ф2); B по refusal-бенчмарку полигона, интерим DeepSeek+abliterated.
Фундамент НЕ блокирует (нужно к моменту исполнения эскалации).
4. **Схема банка памяти v1 — скоуп** (миграция store v2). *Рек v1:* база Р3 + alias-граф + `gender=hidden(until_ch)`
+ `translit_policy` + `first_person` + series-bible-lite; отложить в v1.1: ranked-set, эвфемизмы,
`nickname_translation`, число-словарь. Сверка со «Следствиями для плана» 04-unhappy-paths обязательна.
5. **Онгоинг:** перегоняется ли Analyst при `add-chapters` (`[НУЖНО РЕШЕНИЕ]` п.5)? *Рек:* инкрементально, Analyst
только на новые главы, book-brief не перегонять.
Уже решено (не пере-обсуждаем): премиум-бюджет (формула Р5 + $5/$30), ключ TM (консервативный), стриминг
keep-alive (Ф12), инъекция глоссария (`selective`), пороги coverage (полигон), epub v1 (текст по spine).
> **Ответ оркестратора на все [НУЖНО РЕШЕНИЕ] + Q3/Q4 (04.07) → полный контракт в [architecture/05-decisions-log.md](architecture/05-decisions-log.md).**
> Все 6+1 решений приняты (D1 монолингвальный редактор, D2 skip+flag+continue, D3 эскалация, D4 нет provider-fallback, D5 инкрементальный Analyst, D6 think-режим, D7 схема памяти v1) и прошли адверсариальную панель из 3 критиков (research/эконом/код) — читай `05-decisions-log.md` целиком перед Фазой 1, там уточнения меняют реализацию. Самое важное для тебя:
> 1. **`snapshotID` расширить memory-state + context-assembly hash ДО инъекции памяти** (D5.2) — иначе изменённый глоссарий/STM меняет `request_hash`, но не `snapshotID`, resnapshot-гейт молчит, ре-ран старой главы промахивается мимо чекпоинта и переоплачивает расходящимся переводом. Это общий гейт, держит D1 и D5.
> 2. **Runner без цикла по чанкам/главам + нет хранилища флагов** — главный длинный шест Фазы 1; `attempt` НЕ несёт disposition/skip-семантику (я переоценил). Строить цикл + таблицу флагов + `flag_reason` первым.
> 3. **D2:** тегировать `flag_reason`; `retry-flagged` переатакует только length/empty (refusal — не переатаковать, деньги на гарантированный отказ не жечь); n-gram-loop чек ПЕРЕД удвоением max_tokens; edit `max_tokens` от длины ЧЕРНОВИКА, не исходника.
> 4. **D3:** завести провайдеры gemini/xai/**openai**/deepseek-v4-pro/glm-5.1 в `models.yaml` (все OpenAI-совместимы, `kind: openai`; нативный Gemini-судья — Ф2), фактчекнуть слаг `deepseek-v4-pro`. Премиум-бюджет $5/$30 устарел (был на Sonnet) — полигон пересчитает на Gemini-апексе с reasoning-as-output.
> 5. **D1:** убрать `{{text}}` из editor.md И **поднять edit `prompt_version`** (иначе лейбл врёт на двух SHA); честно: приёмка Фазы 1 БЕЗ критерия верности (mistranslation ловит билингвальный судья Ф2, не coverage-гейт).
> 6. **D6:** дефолт think off/**minimal** (операционно), но пилот Ф2.5 think-ON включает translator/editor (не только Terminologist); Gemini-апекс форсированно думает (бюджетить как output); think-ON эскалация — только subset-провайдеры (не xAI/Grok, пока EstimateUSD не резервирует reasoning).
> 7. Новые дешёвые гейты Фазы 1 (детерминированные, Go): линтер тире-диалогов, ёфикатор, блок-лист транслит-междометий, число-гейт 万/億; ruby-парсер в спеку импорта (для ja-имён).
>
> **ПОПРАВКА ВЛАДЕЛЬЦА (04.07): удалён только Anthropic (за дороговизну), OpenAI ОСТАЁТСЯ.** Живой набор ключей у бэкенда и полигона: `DEEPSEEK_API_KEY`, `ZAI_API_KEY`, `KIMI_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`, `XAI_API_KEY`. → Вернуть провайдер `openai` в `models.yaml` (`gpt-5-nano` альт черновика, `gpt-5-mini` кандидат редактора/second-opinion судьи; квирки в `experiments/00-provider-quirks.md`: reasoning_effort minimal, без temperature, `max_completion_tokens`). Gemini/xAI теперь доступны сразу (не «Фаза 2»), нативные адаптеры для safety-судьи — по-прежнему Ф2. Р4 в `01-decisions.md` обновлён. **xAI/Grok НЕ выведен** (уточнение владельца): Grok 4.3 — основной пермиссивный тир канала B + судья 18+; промо $150 за data-sharing — на выделенный NSFW/eval-аккаунт.
> **Ответ оркестратора на два флага + вопрос «план vs старт» (04.07).** Оба флага верные, приняты:
> 1. **Рассинхрон quirks — исправил** (`experiments/00-provider-quirks.md`: строка про OpenAI была устаревшей). Источник истины по стеку — `05-decisions-log.md` D3 + Р4.
> 2. **Capability-слой — принял как корректировку D3.1** (записано в `05-decisions-log.md`): «без новых адаптеров» было оптимистично. Kimi (`temperature:1`), gpt-5-mini (`max_completion_tokens`, без temperature, effort minimal), Gemini 3.1 Pro (thinking обязателен) → текущий `openAIRequest` даст 400. И это **раньше D3**: Kimi — уже альт-редактор, edit temp 0.4 упрётся. Форма — декларативные capabilities per-модель в `models.yaml` (`budget_field`, `temperature: send|omit|locked:1`, `reasoning_control`), адаптер строит тело по ним; эталон квирков — `00-provider-quirks.md`.
> **Про «план vs старт»: пиши КОРОТКИЙ implementation-plan, но только на контракт-несущие куски, не waterfall.** Полную спеку — на три места, где двусмысленность = переделка: (а) **точный payload `snapshotID`** (что именно входит в хэш памяти/сборки контекста — это класс бага «тихий расходящийся ре-пэй»); (б) **схема disposition/флагов** (таблица флагов, `flag_reason`, как resume читает терминал-для-прогона vs retry-flagged); (в) **capability-матрица провайдеров**. Чанкер/импорт/гейты — механика, их в план не разворачивай. Порядок работ, который ты предложил, **ратифицирую**: (1) runner-loop + флаг-таблица + disposition, (2) snapshotID под память, (3) чанкер+импорт(+ruby), (4) миграция памяти v2, (5) четыре гейта; capability-слой + заводка D3 — не «параллельно потом», а вместе с (1), т.к. Kimi-редактор упрётся сразу. Стартуй с (1)+(2) — они держат всё остальное. `deepseek-v4-pro` слаг фактчекни на api-docs.deepseek.com перед wiring эскалации (не блокирует фундамент).
> **Ответ оркестратора на readiness-вердикт + флаг git (04.07).** Готовность принята, порядок работ подтверждён кодом — старт Фазы 1 разрешён.
> 1. **Флаг git закрыт: docs закоммичены** (`docs/` — моя зона; коммит после этой записи). Полигону: закоммить свою зону `eval/` (2 изменённых + 4 новых скрипта untracked — при `reset --hard` потеряются); `eval/data`/`.venv`/токенизаторы в .gitignore, коммить только код.
> 2. **Дефолт редактора Фазы 1 = `grok-4.3`** (эксп.04 полигона, бейк-офф — закрывает твой вопрос №2, ОПРОВЕРГАЕТ прежнее «редактор=GLM»): ранг-1 верность, ранг-2 стиль, ~13с без reasoning, лучший value. Премиум-эскалация редактора — `gemini-3.1-pro`. GLM/Kimi сняты с дефолта. В `pipeline-c1.yaml` edit-стадию перевести на grok-4.3 (провайдер xAI, `kind: openai`, thinking OFF — reasoning=0, ledger чист; capability: temperature шлётся, `max_tokens`). Провизорно (LLM-судьи, короткие фрагменты) — финал на пилоте Ф2.5. Р4/`05-decisions-log` обновлены.
> 3. Следствие: grok-4.3 стал центральной моделью (редактор SFW + канал B + судья 18+) — гигиена аккаунтов xAI на три использования (Р4): промо/data-sharing только eval+NSFW, продакшн-редактор SFW — чистый аккаунт.
> 4. ⚠ **DeepSeek-черновик «эхал» оригинал** на высоко-CJK фрагменте (эксп.04, 3/3) — тихий отказ = оригинал вместо перевода. CJK-гейт Фазы 1 обязан это ловить (уже в плане); плюс фолбэк-черновик как у полигона.
> **Ещё две вводные бэкенду (04.07):**
> 5. **Схему памяти v2 (твой шаг 4) держи до реестра рисков от сессии «Валидация банка памяти».** Владелец выделил банк памяти (главная точка отказа пайплайна) в отдельную адверсариальную сессию (промт `docs/MEMORY_RESEARCH_SESSION_PROMPT.md`, финализирован); её выход — `architecture/06-memory-risk-registry.md` — вход, по которому ты фиксируешь схему store/глоссария. Шаги 13 (runner-loop / snapshotID / чанкер) от схемы памяти не зависят — иди по ним, шаг 4 гейтит валидация. snapshotID под память (D5.2) проектируй с запасом, но финальную схему полей не морозь.
> 6. **Коррекция контура (владелец): EU-SaaS, прямые ключи, BYOK отменён** — в коде это НИЧЕГО не меняет (бэкенд всегда был на прямых ключах; BYOK был продуктовым концептом Р8/Р9, не кодом). Обновлены только Р5/Р8/Р9/Р10 в `01-decisions.md`. Дефолт редактора Фазы 1 — `grok-4.3` (эксп.04) — в `pipeline-c1.yaml` edit-стадию на него (xAI, thinking OFF, capability: temperature шлётся).
> **Ответ оркестратора на 4 вопроса Фазы 1 (04.07) → полностью в [05-decisions-log.md D8D11](architecture/05-decisions-log.md).** Онбординг-поправки ратифицированы (grok-editor не Kimi; deepseek-v4-pro резолвить через /models, не хардкодить; gemini `-preview` несущий; models.yaml обновляешь сам; F4 в A, F3 явно). A/B/C-план принят. Ответы:
> - **Q1 (D8): content-hash материализации памяти**, не version-counter (drift-proof; счётчик переоткрывает баг тихой переоплаты). Хэшируй полное состояние инъектируемого пула на старте джобы (per-chunk выбор уже в request_hash).
> - **Q2 (D9): приёмочная книга — ja→ru ранобэ.** Ставит ruby-извлечение на критический путь (форсирует закрытие дыры §4). Границы: фуригана первого появления → глоссарий-лок имени, НЕ ruby в выходной вёрстке. Хедж если ruby-тайм-синк — в D9.
> - **Q3 (D10): знаменатель — ВСЕ approved-термины** (имена+титулы/термины), матчит R7 + бьёт по жалобе №1 (коллапс рангов). names-only — под-метрика. Порог 98% на детерминированном слое достижим; недостижимость → ревизия порога, не знаменателя.
> - **Q4 (D11): budget_usd — конфиг-потолок, не гейт приёмки** — ДА. Но ⚠ **оба cost-числа устарели, не только премиум:** дефолт-редактор grok-4.3 ($2.50/M out ≈ 10× draft) → стандарт-микс ранобэ ~$0.73 (>$0.6). Приёмка по стоимости = escalation уважает конфиг-потолок + **точность телеметрии** (ledger корректно биллит grok reasoning=0 / gemini reasoning-as-output), мягкий sanity ~$1/ранобэ, не жёсткий $0.6/$5. Точные числа — полигон пересчитывает на стеке draft-DeepSeek+editor-grok+премиум-Gemini.
> **Ре-флаг:** grok = дефолт-редактор → каждый чанк через xAI. Продакшн-редактор — **чистый xAI-аккаунт без data-sharing** (промо-аккаунт только eval/NSFW). Концентрация 3 ролей на xAI — риск доступности (Р10), gemini-премиум как замена под рукой.
### 2026-07-04 — Сессия 3: Веха 1 Фазы 1 — capability-слой (C) + snapshotID под память (B)
Ратифицированный порядок стартует с twin-фундамента (runner-loop+snapshotID, capability-слой вместе). Веха 1 = **C + B** (жёстко связаны через `stageSnap`); runner chapter/chunk-loop + A (disposition) Веха 2. Всё зелёное: `go build/vet/test -race`, реальные конфиги валидируются через `tmctl report` ($0).
**C — capability-матрица (D3.1).** Декларативные `capabilities:` per-модель в `models.yaml`: `budget_field` (max_tokens|max_completion_tokens), `temperature` (send|omit|force+value), `reasoning` (control none|effort|extra_body_disable|mandatory + off_effort/off_extra_body/on_extra_body). Резолвер (`Capability.applyToBody`) строит тело в `openAIRequest.MarshalJSON`; `Models.ResolveCapability` мержит provider-дефолт model-оверрайд (модель побеждает по-полю). Fail-fast валидация (enum + companion-поле). **Нулевая каппа = Phase-0 wire** (обратная совместимость все текущие модели без изменений на проводе). GLM `thinking:disabled` перенесён `extra_body` `capabilities.reasoning.off_extra_body` (тело **байт-в-байт то же**, тест `TestGLMMigrationWireIdentical`; сдвигается только snapshot осознанный `--resnapshot`). Отдельно от `Provider.Reasoning=subset|additive` (то биллинг). Юнит-тесты покрывают все квирки: gpt-5 (max_completion_tokens+omit+minimal), Gemini mandatory-swallow, Kimi force=1, GLM off/on.
**B — snapshotID под память (D5.2/D8).** `snapshotID` сворачивает: (а) суб-хэш context-assembly-ручек (`glossary_injection`/budget/`stm_depth`/`overlap`/`cache_ttl`), (б) `memoryVersion` **content-hash** материализованной инъектируемой памяти (не bump-счётчик, D8; пока пустая материализация до банка памяти v2), (в) резолвнутую capability per-стадию в `stageSnap`. STM исключён (пересобирается из чекпоинтов). Цепочка `capability → stageSnap → snapID → request_hash` подтверждена (mutation-verified: без фолда правка каппы молча подаёт старый чекпоинт).
**Заведён стек (частично).** Провайдер `xai` + `grok-4.3` (цена $1.25/$2.50 факт. 04.07). **`deepseek-v4-pro` ПОДТВЕРЖДЁН живьём** (`GET /models`: `[deepseek-v4-flash, deepseek-v4-pro]`; `deepseek-chat` из списка ушёл депрекейт 24.07). Черновик = `deepseek-v4-flash`, голова эскалации A = `deepseek-v4-pro`. Цену `v4-pro` `/models` не отдаёт фактчекнуть перед wiring. **Отложено в след. конфиг-шаг** (нужны фактчек цен gpt-5-mini/nano + подтверждение xAI прод-ключа): переключение edit-стадии `glm-5``grok-4.3`, заводка gemini/openai + gemini-3.1-pro-preview/gpt-5-*/glm-5.1 + цепочки эскалации. Веха 1 даёт МЕХАНИЗМ (юнит-тесты по всем квиркам) + живой путь; полный стек когда цены подтверждены.
**Селфревью (адверсариальный воркфлоу, 4 измерения → верификация каждой находки).** Детерминизм **0 дефектов** (инвариант держит, проверено эмпирически). 5 находок исправлено: (1) *[регресс, мой]* GLM-disable стал условным на `reasoning=="off"` пустой (незаданный) effort молча включал бы thinking (×3 таймауты + reasoning-биллинг); фикс: `extra_body_disable` трактует `""` как `"off"` (сохранён Phase-0 unconditional-disable), только явный low/med/high think-ON; (2) валидация не требовала companion-поля (typo `off_extra_body` тихий no-op) требуем `off_extra_body`/`off_effort`; (3) нет теста, что каппа входит в `snapshotID` (центральный инвариант B) e2e-гейт `TestRunnerSnapshotPinsCapability` (mutation-verified); (4) mandatory-swallow тестился только на `off` строка на non-off; (5) валидация не тестилась на provider-пути/temp-mode/reasoning-control добавлено.
**Техдолг вперёд (не блокирует Веху 2):** capabilities эскалационных моделей НЕ в snapshot (только стадии) закрыть при заводке цикла эскалации (тот же класс D5.2, но пути исполнения ещё нет); `memoryVersion` заглушка до банка памяти v2 (при инъекции памяти заполнить запрос); Kimi `max_tokens≥16000` не выразим в capability-схеме (при wiring эскалации).
> **Ответ оркестратора на 4 вопроса coverage-гейта + failure-model (04.07) → полный контракт в [05-decisions-log.md D12](architecture/05-decisions-log.md), заземлён ресёрчем durable-execution.** Отличная Веха 1. Кратко:
> - **4 вопроса — все A.** Q1: наивный split, `refusal_bench.py` = источник истины, Go зеркалит бит-в-бит, изменения лок-степ Python-first (§3.7 quote-absorbing → v1.1, свою доку реконсиль сам). Q2: минимальный single-hop — **не противоречит D4** (это escalation на детерминированном контент-провале, не outage-своп). Q3: только excision_suspect (верхняя аномалия ложно флагает — ru 1.41.9×; D10 ждёт памяти v2). Q4: opt-in до валидации precision владельцем.
> - **Таксономия отказа — ТРИ класса**, не бинар: транзиентный/бюджетный → same-model retry ({length,empty}); детерминированный контент-провал (echo/cjk/excision/refusal, **HTTP 200 — детект в app-слое post-settle, не транспорт**) → single-hop escalation на другую модель (1 хоп→флаг, отдельная ось в request_hash, budget-cap, re-gate, канал B изолирован ТИПОМ); outage/системный → circuit-breaker → **пауза+resume** (не mass-swap).
> - **F3 фикс:** idempotency-key = существующий `request_hash`, заморожен на входе, заголовком где поддержано — но ⚠ **проверено: OpenAI поддерживает, DeepSeek/xAI/Gemini/Kimi НЕТ** → capability-флаг `supports_idempotency_key`; для центрального стека **at-most-once cap** на класс «billed-but-unconfirmed» (≤1 доп. вызов, не MaxAttempts1) + консервативный settle оценки на post-send timeout. Честная модель — «at-most-once billed, replay бесплатен».
> - **Global call-budget guard:** попытки/чанк = retries + 1 hop, **НЕ сбрасывается на фолбэке** (иначе retry×fallback = 30+ оплаченных, LiteLLM #19985). Editor pinned per book (фолбэк только на draft-стадии — editor задаёт стиль).
> - **Прогресс (реальный пробел, ответ на «подсвечивать»):** `tmctl status --config` — READ-ONLY проекция `chunk_status`(уже построен)+jobs+spend+request_log, `--json`; **book manifest на snapshot** (знаменатель N/M); статусы done/in-progress/flagged/skipped/pending (flagged≠failed, всегда REASON); **паспорт качества главы** (JUnit+SonarQube-стиль); ETA от EWMA не present-state; никакого синтетического time-бара. Не сейчас, но заложить manifest в snapshot-момент.
**Гигиена xAI (напоминание):** в `models.yaml` у провайдера `xai` комментарий-контракт «прод-clean без data-sharing». `XAI_API_KEY` в `.env` подтвердить как прод-аккаунт перед первым боевым grok-вызовом (в Вехе 1 grok в стадии не зовётся).
**Веха 2 (следующая):** runner chapter/chunk-loop + `chunk_status`/disposition (A, D2) `flag_reason`-константы, `classify(text,finish)` (refusal/echo до length), ось attempt, exit-коды 0/2/1, фиксы F4 (усечённый length flagged) + edit-`max_tokens` от длины черновика.
### 2026-07-04 — Сессия 4: Веха 2 Фазы 1 — chunk-loop + disposition (A, D2) + фиксы F4/D2.5
Снят хардкод «один чанк»: прогон идёт по всей книге, плохой кусок помечается и цикл продолжается. Всё зелёное: `go build/vet/test -race`, `tmctl report` ($0). Живые LLM не звались (моки + tmctl $0, как предписано).
**Цикл по чанкам (шов под шаг 3).** `TranslateOneChunk`(chapter=1/chunk=0 хардкод) `TranslateBook` `translateChunk` (цикл стадий) `runStage` `runAttempt` (ось attempt). `RunResult``ChunkOutcome` (per-chunk) + `BookResult` (агрегат книги). Чанкер **минимальный детерминированный плейсхолдер** (`chunker.go` `SplitChunks`: разбивка на главы по form-feed, паковка абзацев 1500 симв., абзац не режется); настоящий лингвистический чанкер шаг 3, подменит `SplitChunks` не трогая цикл/disposition. `chunkerVersion` бампнут `v1-wholefile``v2-ff-para-pack` (в snapshot; ре-чанкинг = осознанный `--resnapshot`).
**Схема disposition (D2, контракт-несущее).** v2-миграция (append, IF NOT EXISTS): `chunk_status(book_id,chapter,chunk_idx,stage,snapshot_id,content_hash,disposition,flag_reason,attempts,final_hash,cost_usd,detail)`, PK (book,chapter,chunk,stage). Это **резолв поверх append-only checkpoints**, не колонка на checkpoints на resume пересобирается из чекпоинтов. `disposition ∈ {ok,flagged,skipped}`; `jobs.status` контентом НЕ расширён (failed = только инфра). `flag_reason` Go-константы как `Finish*` (12 шт.; эмитятся length/empty/loop_degenerate/hard_refusal/soft_refusal/content_filter/cjk_artifact/decode_error, зарезервированы coverage_fail/excision_suspect/hard_block/upstream_not_ok под шаги 67). Единый `classify(src,out,finish,target)` порядок: refusal-блэклист (порт `refusal_bench.py` 1:1, en/ru/zh/ja) / CJK-echo **ДО** length/empty (усечённый отказ не триггерит платную переатаку); `content_filter` best-effort (реальная страховка блэклист). n-gram loop-чек ПЕРЕД удвоением max_tokens. `maxTokensForAttempt` чистая функция (удвоение per attempt), её версия в snapshot (`maxTokensPolicy`). Retry-flagged только {length,empty} на той же модели по оси attempt (до `regenerate_before_escalate`, потом флаг); refusal/filter/cjk/loop/decode детерминированы не переатакуются. Три анти-веджа отработали (**mutation-verified**): resume читает `chunk_status` до вызова; empty/decode flagged (цикл идёт, не крэш); legacy-пустой чекпоинт самолечится classify-ем без ре-биллинга. Exit: `CompletedWithFlags` sentinel 0 чисто / 2 с флагами (N допустимо) / 1 инфра.
**Фиксы.** **F4:** усечённый `length` с непустым черновиком теперь классифицируется (flagged/retry), не течёт в edit как OK (`classify` после settle). **D2.5:** edit-`max_tokens` от длины ЧЕРНОВИКА (`prev`), не исходника монолингвальный редактор работает по русскому черновику 1.9× исходника (mutation-verified). **F3 честно:** `chunk_status.cost_usd` суммирует все попытки; per-run cost отделён от кумулятивного; idempotency-ключ не делал (отложено).
**Селфревью (адверсариальный воркфлоу, 5 измерений → верификация каждой находки).** disposition-money/resume/classifier **0 дефектов**. 2 подтверждённых исправлено (оба mutation-verified): (1) *[детерминизм, medium]* `chunk_status` fast-path резолвил ПОЗИЦИОННО и подавал устаревший перевод при правке исходника (исходник не в snapshot) фикс: сигнатура `content_hash` отрендеренных msgs в `chunk_status`, fast-path доверяет строке только при совпадении snapshot И content (иначе content-safe attempt-loop; правка src = тихий per-chunk ре-перевод по §3.4, не устаревший подача); стоило переноса дешёвого рендера ДО чекпоинт-резолва (LLM-вызов по-прежнему загейчен «не переатаковать» сохранено). (2) *[CLI, low]* `flag.ExitOnError` `os.Exit(2)` на кривом флаге, коллизия с exit-2 «с флагами» `ContinueOnError` (кривой флаг = exit 1). Тесты: 12 новых (disposition/chunker/chunkstatus юниты + e2e мульти-чанк/resume/flag+skip/exit-коды/F4/D2.5/decode/legacy-self-heal/source-edit), все mutation-проверены на укус.
**Техдолг вперёд (не блокирует шаг 3):** чанкер плейсхолдер (шаг 3 подменит `SplitChunks`, чтит контракт `Chunk` + бампает `chunkerVersion`); небилленный upstream-сбой = инфра-аболт (D4 pause/resume), `upstream_not_ok`/`hard_block`-константы под HTTP-классификацию шага 7; редкий угол: kill-9 в микро-окне (потеря `chunk_status`) ПЛЮС одновременное снижение `regenerate_before_escalate` может консервативно пере-флагнуть бывший-ok чанк (без денег/расхождения фаст-путь чинит норму, self-heal best-effort). `jobs.status` теперь наблюдательный (ничего на нём не ветвится).
### 2026-07-04 — Ответ Полигону: тихие отказы (эхо/вырезание/пусто) + онбординг след. сессии
Полигон верно указал класс «HTTP 200, перевода нет». Провалидировал **трассировкой** capabilitywire (не грепом):
**Состояние детекта (после Вехи 2):**
- **Эхо (`cjk_artifact`)** ДЕТЕКТИТСЯ: `classify` (disposition.go) флагует при `cjkShare(out) > 0.15` (порог из `refusal_bench`). Полигоновское «детекта нет» устарело добавлено в Вехе 2 (после их грепа). НО: в РАННЕРЕ (disposition-слой, post-settle), НЕ в адаптере/failover; сейчас ФЛАГ, эскалации нет (эскалация шаг 7).
- **Пусто** ДЕТЕКТИТСЯ: `classify``empty` (cloud-путь) + failover empty-check (только local-нога, `failover.go:121`).
- **Вырезание (`sent_cov`/`len_ratio`)** НЕ детектится: константы `excision_suspect`/`coverage_fail` заведены, но не эмитятся это конфигурируемый coverage-гейт (шаг 6). Пороги (zh<2.2/ja<1.4/en<0.70, sent_cov<0.75) уже в §3.7 + `refusal_bench` EXPECT_LEN_RATIO.
**DeepSeek thinking — ПОДТВЕРЖДАЮ, риска нет.** `deepseek-v4-flash` без capabilities/extra_body; провайдер `deepseek` reasoning:subset без caps `ResolveCapability` = baseline openai (`ReasoningNone`). Стадия draft `reasoning:"off"`. `applyToBody(ReasoningNone,"off")` эмитит НИЧЕГО reasoning-related на проводе нет `reasoning_effort`, нет `thinking` DeepSeek берёт ДЕФОЛТ (thinking ON) чистый перевод, эха нет. Наш off-by-omission НЕ гасит DeepSeek thinking (в отличие от GLM с явным `thinking:disabled`). **Критично:** `reasoning:"off"` для DeepSeek ОСОЗНАННЫЙ no-op (ReasoningNone глотает "off"), именно это держит thinking ON. **Никогда не добавлять deepseek `capabilities.reasoning.off_extra_body:{thinking:{type:disabled}}`** включит эхо. (GLM-редактор с thinking:disabled безопасен: его вход русский черновик, CJK эхать нечего.)
**Архитектурные ответы (Q1Q3):**
- **Q1 (где живёт валидация):** в РАННЕРЕ (disposition/classify-слой), НЕ в адаптере и НЕ отдельным failover-чеком. Адаптер (`llm/`) провайдер-нейтрален и без контекста перевода (нет src/target/покрытия) держим инвариант нейтральности. failover эскалирует на ТРАНСПОРТ-сбоях (5xx/429/timeout/пустой local); контент-качество отдельный концерн (смешать = сломать разделение транспорт/контент + изоляцию канала B, D4). Эхо приходит как 2xx (оплачено провайдером) детект в адаптере vs раннере денег не экономит (оба после биллинга); раннер имеет src+target+finish и решает retry/flag/эскалацию. эхо/пусто = intrinsic classify (Веха 2 ✅); вырезание = конфиг coverage-гейт (шаг 6, тоже раннер, не адаптер).
- **Q2 (эхо ретрай/эскалация или флаг?):** согласен эхо должно ЭСКАЛИРОВАТЬ, не просто флажок. `cjk_artifact` ДЕТЕРМИНИРОВАН (та же модель то же эхо) same-model retry бессмыслен (переэхнёт, переплатит) в classify он **non-retryable именно поэтому**. При заводке эскалации (шаг 7) `cjk_artifact` уходит на ФОЛБЭК-ЧЕРНОВИК (другая модель) это и есть «эскалация, не флаг» (интент записан в Вехе 2). Сейчас флаг цикла эскалации ещё нет.
- **Q3 (live-conformance):** ДА, и Python-оракул Полигона = приёмочный ГЕЙТ перед фиксацией адаптеров. Мои Go-тесты httptest wire-контракты (быстрые, детерминированные, CI без ключей) живые эхо/`reasoning_content`/алиасы/503 не воспроизводят by design. Разделение: **Python-оракул (зона Полигона)** = кросс-провайдерный live-гейт «каждый адаптер бьёт живого, получает валидный перевод без эха/пусто/обрезки»; **Go live-интеграционные тесты (зона бэкенда, build-tag `live`/env-gated, вне CI)** = per-adapter wire+parse на живых ключах. Оба; оракул гейт.
Фикс (эскалация `cjk_artifact`фолбэк-черновик + coverage-гейт вырезания + live-conformance) **отдельная сессия**, онбординг-промт: [BACKEND_SESSION_PROMPT_SILENT_REFUSALS.md](prompts/done/BACKEND_SESSION_PROMPT_SILENT_REFUSALS.md). Не блокирует шаг 3.
### 2026-07-04 — Сессия 5: Веха 2.5 (старт) — DeepSeek эхо-мина зафиксирована регресс-гейтом
Валидация точки старта зелёная (`go build/vet/test -race` ~80 тестов; `tmctl report` $0). Первым делом регресс-гейт §2, чтобы будущая правка `models.yaml` не включила эхо-мину DeepSeek.
**Решение: fail-fast в конфиг-валидации (сильнее unit-теста — срабатывает на КАЖДОМ `tmctl`-запуске), а не только тест.** Провайдер получает декларативный маркер `echoes_when_thinking_off: true` (заведён на `deepseek`, документирован трассой). `config.echoMineViolation` резолвит каппу модели такого провайдера и валит старт, если thinking подавляется при `reasoning=off` по ОБЕИМ поверхностям вооружения: (1) `capabilities.reasoning.control` = `extra_body_disable` (мержит `{thinking:disabled}`) или `effort` (шлёт `reasoning_effort`); (2) thinking-ключ, протащенный через model `extra_body` (его контрол-чек бы пропустил `openAIRequest` мержит его в тело). Инвариант: echo-prone провайдер обязан держать `reasoning.control` = `none|mandatory` и без thinking-disable `extra_body` thinking остаётся на дефолте (ON).
**GLM отличается корректно:** маркер только на `deepseek`; `glm-5` (provider `zai`) с `{thinking:{type:disabled}}` остаётся легальным (его вход русский черновик, CJK нечего эхать). Метаданные валидации-only на провод не идут, в snapshot НЕ входят (без `--resnapshot`).
**Тесты (мутационно-проверенные):** `TestDeepSeekEchoMineRejected` 5 кейсов (2 поверхности + `effort` + GLM-безопасность + дефолт); `TestBoevoyConfigDeepSeekThinkingStaysOn` гард на реальном `configs/models.yaml` (флаг на месте + `deepseek-v4-flash``ReasoningNone`; unmarshal напрямую, чтобы обойти date-бомбу `prices_checked`). Убрать `echoMineViolation` armed-кейсы перестают падать (мутация ловится).
Контрактные вопросы 7) заданы оркестратор ответил **D12 (все A: 1A наивный split, 2A single-hop, 3A только excision_suspect, 4A opt-in)** + модель устойчивости (три класса отказа, F3 at-most-once, `supports_idempotency_key`, editor-pinned, global call-budget). Строю по D12.
### 2026-07-04 — Веха 2.5 (A): coverage-гейт вырезания (excision_suspect)
Порт excision-классификации `refusal_bench.py::classify_output` в `pipeline/coverage.go`. **Сегментация (D12 Q1) — бит-в-бит с оракулом:** RE2 без lookbehind, поэтому `split_sentences` реплицирован ручным сканом (branch-1 «терминатор+пробел-ран поглощается» branch-2 «CJK-терминатор zero-width»), **пинится к живому оракулу** `TestSplitSentencesOracleParity` (28 крайних кейсов сняты из `refusal_bench`: диалоги `「…!」`, подряд `。。。`3, U+3000, `……`1, fullwidth `?。!`, `Mr.`-oversplit). Метрика символы без пробелов. **Только нижняя граница (D12 Q3):** `sent_cov<sent_cov_min` ИЛИ `len_ratio<коридор-low` `excision_suspect`; верхняя (аномалия-дописывание) НЕ флагуется (ru 1.41.9×, ложно; нужен entity+судья Ф2). Мини-набор искусственных пропусков **ловит 12/12 (100%)**, ложных на верных 0.
**Вайринг раннера:** `classifyOutput` = intrinsic `classify` (эхо/пусто/refusal, всегда) потом coverage-гейт **если** `gates.coverage.enabled`, по РЕЗУЛЬТАТУ каждой стадии против ИСХОДНИКА (ловит вырезание и на draft, и на edit). `excision_suspect` non-retryable (детерминирован per-модель эскалация, не same-model retry интент под B). Гейт-конфиг **свёрнут в snapshot** (`coverageSnapshot`, только когда enabled) флип/твик = громкий `--resnapshot` + бесплатная ре-оценка чанков из чекпоинтов. `CheckRunnable` больше не валит `gates.enabled`; `LoadPipeline` fail-fast на включённом гейте без порогов (тихий no-op против Р7). **Боевой `pipeline-c1.yaml` — opt-in `enabled:false`** (D12 Q4: флип после валидации precision владельцем). Тесты: excisionфлаг+skip+exit2+resume-детерминизм, healthypass, snapshot-флип`--resnapshot`, no-thresholdsfail-fast. Всё зелёное `-race`.
### 2026-07-04 — Веха 2.5 (D): провайдерская домашка — live `/models`-фактчек
Живой `GET /models` по 6 провайдерам (бесплатно, без completion; ключи только в `Authorization`, значения не печатались). Слаги эскалации **верифицированы живьём**: DeepSeek `deepseek-v4-flash`+`deepseek-v4-pro` ✓; GLM `glm-5`+`glm-5.1`/`5.2` ✓; xAI `grok-4.20-0309-non-reasoning`+`grok-4.3` ✓; Gemini `gemini-3.1-pro-preview`+`gemini-2.5-flash` (id с префиксом `models/` канонизация ответа для `PriceForResponse` при вайринге Gemini, Ф2); OpenAI `gpt-5-mini`+`gpt-5-nano` ✓.
** НАХОДКА (configреальность, исправлена):** боевой `models.yaml` держал Kimi `base_url: https://api.kimi.ai/v1` **`api.kimi.ai` НЕ резолвится** (DNS fail прокси 502 CONNECT, HTTP 000). Рабочий хост `https://api.moonshot.ai/v1` (200, `kimi-k2.6` в /models). Комментарий спутал веб-консоль (`platform.kimi.ai`) с API-эндпоинтом (`api.moonshot.ai`). Kimi текущая заглушка эскалации на реальном хопе упало бы. Исправлено на `api.moonshot.ai/v1`.
`reasoning_content`-vs-`content`, cache-поля, `content_filter`-эмиссия требуют **платного** completion не гоняю здесь; проверит live-conformance харнесс (C) при ручном прогоне оператором. Код уже корректен по докам (`httpllm.go` читает `content`, парсит оба cache-варианта DeepSeek).
### 2026-07-04 — Веха 2.5 (B): single-hop эскалация детерминированных провалов
Реализован класс «детерминированный контент-провал» из D12: флаг, который другая модель может починить (`cjk_artifact`/`excision_suspect`/`loop_degenerate`/`hard_refusal`/`soft_refusal`/`content_filter` `FlagReason.escalatable()`), эскалирует **на другую модель ОДИН раз**, а не флажок.
**Механика (раннер):** после primary-attempt-loop, если вердикт escalatable И у стадии задан `escalate_to` И бюджет остаётся один вызов `runAttempt(escalate_to, escalation=true)`, результат **ре-гейтится** (`classifyOutput` гоняется и на фолбэке). Прошёл фолбэк авторитетный (его чекпоинт = `final_hash`); не прошёл primary-флаг остаётся, фолбэк оплачен и посчитан. **Ось эскалации = модель в `request_hash`** (не attempt): чекпоинт фолбэка `(model=escalate_to, attempt=0)` не коллизится с провалившимся primary. **Ровно 1 хоп** (не свежий retry-бюджет): вызовов/чанк = primary attempts + 1 (guard LiteLLM #19985). `runAttempt` параметризован `model`+`escalation`.
**Бюджет (D12):** `escalation.budget_usd` opt-in (0 = выкл, боевой дефолт). Money-path-durable: миграция v3 добавляет колонку `escalation` на checkpoints (пишется в той же tx, что settle), `EscalationSpentUSD` суммирует только escalation-чекпоинты (resume-safe, не двойной счёт на checkpoint-hit). Soft cap.
**Канал B (D4.1) типом, не комментарием:** `Provider.permissive` + `Stage.channel` (sfw|adult); `LoadPipeline` валит `channel=adult`, если primary или `escalate_to` НЕ на пермиссив-провайдере. **Editor pinned per book:** editor не имеет `escalate_to` не эскалирует (стиль не плывёт на чужую модель, 2605.13368). **D5.2-закрытие:** `escalate_to` + его резолвнутая каппа свёрнуты в `stageSnap` смена эскалационной модели/каппы = громкий `--resnapshot`. `CheckKeys` префлайтит ключи `escalate_to` при budget>0. `escalate_to == primary` запрещён валидацией.
Тесты (мок-провайдер, два fake-модели): эхо→фолбэк-починка→OK+edit; фолбэк тоже эхнул→primary-флаг+skip (ровно 2 вызова); budget=0→не эскалирует; resume подаёт фолбэк-чекпоинт за $0; смена fallback→`--resnapshot`; channel=adult без permissive→fail-fast. Всё зелёное `-race`, `tmctl report` $0.
### 2026-07-04 — Веха 2.5 (C): live-conformance харнесс + live-валидация мины
`internal/pipeline/live_conformance_test.go` под `//go:build live` — вне дефолтного `go test`/CI ($0, без ключей). Per-adapter: строит клиента из боевого `models.yaml`, бьёт живого провайдера коротким плотно-CJK→ru переводом, валидирует РАННЕРНОЙ `classify`хо→cjk_artifact, пусто→empty, refusal→soft_refusal; валидный = ok), логирует usage + response-слаг (канонизация). Скипается без `TM_LIVE=1`; запуск оператором: `set -a; . ./.env; set +a; TM_LIVE=1 go test -tags live -run TestLive -v ./internal/pipeline/`. Разделение (D12 Q3): Python-оракул Полигона = кросс-провайдерный приёмочный ГЕЙТ; эти Go-тесты = per-adapter wire+parse. Оба.
**Live-валидация (1 целевой вызов deepseek, ~$0.00004):** фрагмент Лу Синя «祝福» (эхо-репро-семья) → `cjk_share=0.00`, `verdict=ok`, `finish=stop`, `reasoning_tokens=0`, чистый русский перевод. **DeepSeek-мина подтверждённо обезврежена на реальном проводе**`reasoning:"off"` no-op держит thinking ON → перевод, не эхо. Адаптер читает `content`, слаг = `deepseek-v4-flash` (канонизация чистая). grok закомментирован в наборе (гигиена clean-prod xAI — включать осознанно).
**Веха 2.5 (A+B+C+D + §2-гейт) реализована.** Коммиты: `2c1c38d` (эхо-мина гейт), `2acfdf2` (coverage-гейт), `d97f832` (Kimi base_url), `659cce0` (single-hop эскалация), `a844765` (live-harness). Дальше — агентское селфревью на вехе.
### 2026-07-05 — Веха 2.5: агентское адверсариальное селфревью + фиксы
Многоагентный Workflow (6 дименсий: детерминизм / деньги / корректность coverage / корректность эскалации / эхо-мина+конфиг / нейтральность+хаки → независимая верификация КАЖДОЙ находки CONFIRMED/REFUTED с конкретным сценарием инпут→неверный-выход). 25 агентов, **14 подтверждённых** (5 опровергнуто). Все исправлены; ключевые фиксы мутационно-проверены (сломай → тест падает).
**Детерминизм/snapshot:** [1/3 HIGH] `escalate_to`-модель шлёт `extra_body`/provider-оверрайды на провод, но они НЕ были в snapshot → тихий false-hit на resume (примари-путь гейтил, эскалация нет) → свёрнуты `EscalateExtra`/`EscalateProviderTemp/MaxTok`. **Эскалация:** [2/9/13 HIGH] бюджет-гейт неидемпотентен — краш между settle фолбэка и chunk_status выбрасывал уже-оплаченный успешный фолбэк и флипал OK→flagged → **checkpoint-first replay** (существующий фолбэк-чекпоинт реиграется бесплатно, минуя бюджет-гейт); [10] эскалация, пробившая book-потолок, роняла всю книгу → `errReserveCeiling`-деградация (оставить примари-флаг, книга продолжает); [11/14] телеметрия эскалации терялась на resume → `GetCheckpoint` отдаёт флаг escalation, `resumeFromChunkStatus` восстанавливает. **Coverage:** [5 HIGH] гейт НЕ стрипал `<think>` (в отличие от `classify`/оракула) → утёкший reasoning маскировал вырезание → `stripThink` в `coverageCheck`; [6] гейт на КАЖДОЙ стадии ложно флагал легитимную монолингвальную правку → **только translator-роль** (верность editor — Ф2, билингв-судья §04); [7] `sent_cov_min=0`+нет коридора пары → молча пропускал всё → требуем `sent_cov_min∈(0,1]` при enabled; [8] Go `unicode.IsSpace` расходился с оракулом на U+001C001F → `isOracleSpace` (паритет). **Конфиг:** [12] включение coverage-гейта требовало ключи недостижимых chain-заглушек → префлайт ключей эскалации отвязан от `gatesEnabled``budget_usd>0`; [4] честный doc soft-cap. Регресс-тесты добавлены; полный набор зелёный `-race`, `tmctl report` $0, live-harness компилируется под `-tags live`.
**Веха 2.5 сдана на внешнее ревью.** Открытые для владельца/оркестратора: боевой флип `gates.coverage.enabled` (после валидации precision), цена `deepseek-v4-pro` (в /models слаг есть, цены нет), формула `escalation.budget_usd`, F3-idempotency-key + `tmctl status` (D12 — отдельные задачи).
> **Внешнее ревью оркестратора Вехи 2.5 (05.07): ПРИНЯТО, 0 живых блокеров, 7 подтверждённых находок (1 отсеяна).** Независимый адверсариальный воркфлоу (12 агентов, каждая находка верифицирована трассой кода). Money-path и coverage-оракул я подтвердил чтением сам. Тема: снапшот-дисциплину, которую ты **верно** применил к новому `coverageGateVersion`, ревью нашло пропущенной в 3 соседних verdict/wire-определителях (слепок автора). Ни одна находка не горит на боевом конфиге — но закрыть до активации соответствующего пути.
> **Major (закрыть до того, как путь оживёт):**
> 1. **`classifierVersion` НЕ в снапшоте** (disposition.go + runner.go:288). `classify()` решает resolved-вердикт (ok↔flagged, ре-ран на legacy/in-flight-crash чекпоинтах), но без version-const — в отличие от `coverageGateVersion`, который ты добавил ровно за это. Правка порога (cjkEchoThreshold 0.15→0.20 / новый refusal-паттерн) → тот же snapID → тихий re-verdict (flagged→ok ре-гоняет пропущенную стадию = свежий расход; ok→flagged жжёт свежий escalation-хоп). Фикс: `const classifierVersion`, свернуть в snapshotID рядом с coverageGateVersion. Симметрично тому, что ты сделал.
> 2. **local backend-тег (`prov.Model`) НЕ в снапшоте И НЕ в request-hash** (runner.go:344-345). Тег, который localClient шлёт как wire-`model` (какая модель реально отвечает — самый влияющий local-оверрайд), отсутствует, а слабые собратья temp/maxtok свёрнуты. Латентно (дефолт = deepseek/glm), оживает при первом wiring local-стадии/эскалации (канал B D3, одна правка YAML). Своп local 8b→14b посреди книги → тот же snapID → resume отдаёт старую модель. Фикс: свернуть `prov.Model` (+ `EscalateProvider*`). Закрыть до wiring local.
> 3. **echo-мина — дени-лист из 3 ключей, не исчерпывающий** (models.go:278). Сырой extra_body проверяется только на top-level thinking/enable_thinking/reasoning_effort — **промахивается мимо ВЛОЖЕННЫХ форм** типа `chat_template_kwargs.thinking:false`, а это документированная форма отключения thinking у DeepSeek-V3.1+ (т.е. гейт промахивается мимо самой вероятной реальной формы). Докстринг «both surfaces covered» переоценивает. Фикс: алоу-лист / рекурсивный скан на echo-prone провайдере; минимум — смягчить докстринг до «3 known top-level keys».
> **Minor (дешёвые гарды + doc/parity):**
> 4. **Эскалация не role-guarded** (pipeline.go:217). Coverage-гейт ограничен translator, а эскалация срабатывает на ЛЮБОЙ стадии с escalate_to — редактор мог бы эскалироваться на чужую модель, тихо нарушая D12 «editor pinned». Латентно (editor без escalate_to, budget=0). Фикс: отвергать escalate_to на role!=translator в LoadPipeline (структурное принуждение D12).
> 5. **Coverage расходится с оракулом на парах без коридора** (coverage.go:177). Оракул применяет дефолт (0.5,3.0) для пар вне {zh,ja,en,ru}; Go пропускает len-проверку целиком → ko-ru len_ratio=0.4/sent_cov=1.0: Python флагает, Go пропускает. Мёртвый код на корпусе {zh,ja,en,ru}, но ломает claim «бит-в-бит оракул». Фикс: дефолтный коридор как оракул ИЛИ fail-fast, требуя коридор пары книги при enabled.
> 6. **Атрибуция эскалации теряется на flagged-resume** (runner.go:996). Escalated/EscalationModel восстанавливаются только в ok-ветке; «хоп тоже провалился→flagged» теряет факт на fast-path. Деньги верны, только in-memory телеметрия (читается пока лишь тестами). Фикс — при добавлении `tmctl status` (ему нужна колонка escalation в chunk_status).
> 7. **Докстринг врёт** (runner.go:180-181): «гейт на КАЖДОЙ стадии, ловит excision редактора» — а строка 193 гардит role==translator (корректный Ф2-deferral). Рантайм прав, поправь докстринг (ловушка для будущего ревьюера).
> **Отсеяна: 1** (false-positive).
>
> **Открытые пункты закрыты:**
> - **Цена `deepseek-v4-pro` ПОДТВЕРЖДЕНА** (офиц. страница, 05.07): **$0.435 in / $0.87 out, cache-hit input $0.003625** (v4-flash подтверждён $0.14/$0.28/$0.0028). Разблокирует wiring канала-A эскалации + `prices_checked`. ⚠ легаси-подстраница `/pricing-details-usd` не обновлена (показывает deepseek-chat/reasoner) — брать `/quick_start/pricing`.
> - **coverage-флип:** держи false; валидация precision на реальных чанках — задача полигону (ниже); порог N флагов — за владельцем.
> - **`escalation.budget_usd`:** механика (opt-in soft-cap, 0=выкл) верна; число — $-потолок под маржу владельца + пересчёт полигона (D11), не «≤2×»; 0=выкл — норм дев-дефолт.
> - **D12-хвосты, приоритет:** **память v2** (реестр `06` готов — главный блокер качества) → **`tmctl status`+manifest** (владелец просил прогресс, скоуп мал, `chunk_status` есть) → **F3** (консервативный settle — честный интерим). Порядок предложишь сам.
### 2026-07-05 — Веха 2.5: закрытие находок внешнего ревью (7/7)
Все 7 подтверждённых находок закрыты, каждый фикс мутационно-проверен (реверт → падает именно его тест). Классический слепок автора (снапшот-дисциплину применил к `coverageGateVersion`, но не к 3 смежным determinator'ам) — закрыт симметрично.
**3 major:** [1] `classifierVersion` свёрнут в snapshot рядом с `coverageGateVersion` (правка порога `classify` = громкий `--resnapshot`, не тихий re-verdict). [2] local backend-тег `prov.Model` (+ `EscalateProviderModel`) свёрнут в `stageSnap` (своп 8b→14b посреди книги теперь инвалидирует чекпоинты). [3] echo-мина: плоский скан 3 ключей → **рекурсивный** `findThinkingControlKey` — ловит вложенные формы (`chat_template_kwargs.thinking` = документированное отключение DeepSeek-V3.1+, самая вероятная реальная).
**4 minor:** [4] `escalate_to` разрешён только на `role=translator` (структурное принуждение D12 editor-pinned). [5] coverage: пара без коридора теперь получает дефолт оракула (0.5) вместо пропуска len-проверки (восстановлен claim «бит-в-бит»). [6] телеметрия эскалации на flagged-resume — **отложена ревьюером** до `tmctl status` (нужна колонка escalation в chunk_status; деньги/флаг верны, теряется только in-memory Escalated). [7] врущий докстринг `classifyOutput` поправлен (гейт только translator, не «каждая стадия»).
Регресс-тесты: `chat_template_kwargs.thinking`-кейс, no-corridor default-коридор, escalate_to-на-editor→fail, snapshot-fold `classifierVersion`+local-тег. Полный набор зелёный `-race`, `tmctl report` $0. **deepseek-v4-pro цена подтверждена оркестратором** ($0.435/$0.87/$0.003625) — разблокирует wiring канала-A эскалации.
**Веха 2.5 ПОЛНОСТЬЮ закрыта** (реализация + селфревью 14 + внешнее ревью 7). Дальше — D12-хвосты по приоритету оркестратора (память v2 → tmctl status → F3).
### 2026-07-05 — Шаг 3a: настоящий чанкер + импорт txt/epub + ruby-захват
Снят плейсхолдер-чанкер: книга (D9 ja→ru ранобэ epub) гоняется end-to-end на настоящих границах. Всё зелёное `go build/vet/test -race`, `tmctl report` $0, живые LLM не звались (моки + $0-report). Три части + селфревью с фиксами.
**A. Настоящий сорс-чанкер (`chunker.go`).** `SplitChunks(source string)``SplitChunks(chapters []string)` (ingest уже режет главы). Паковка **по границам предложений/абзацев** в **коридор ~12k токенов** (`targetChunkTokens=1500`, **const покрыт `chunkerVersion`**, не конфиг — Р2=код; если станет конфигом — обязателен snapshot-fold как `coverageSnap`, §7d). Отдельный сорс-сплиттер `splitSourceSentences` (zh/ja/en): CJK zero-width `。!?`, **quote-depth** (терминатор внутри `「…!」と…。`НЕ конец предложения, диалоговый кейс §3.7/D12-Q1), эллипсис `…`, абсорбция закрывающих скобок, guard аббревиатур/инициалов, **lossless-тайлинг** (конкатенация сегментов = исходный абзац, текст не теряется/не сдвигается). **Никогда не режет предложение**; абзац>цели → дробится по предложениям, предложение>цели → свой чанк. **ОТДЕЛЬН от coverage-`splitSentences`** (тот Python-locked по РУССКОМУ ВЫХОДУ; этот — по ИСХОДНИКУ, `chunkerVersion`-versioned). `chunkerVersion` бампнут `v2-ff-para-pack`→**`v3-sentence-pack`** (в snapshot → перечанкование = громкий `--resnapshot`).
**B. Импорт txt/epub (`ingest.go`, новый).** `Ingest(path)→*Document{Chapters []string, Ruby []RubyReading}`, диспетчер по расширению. **txt:** главы по `\f` (обратная совместимость example), `NormalizeSource` каждой. **epub — чисто stdlib** (CGO-free, без новых зависимостей): `archive/zip``container.xml`→OPF→**spine-порядок**→`encoding/xml` (`Strict=false`, `HTMLEntity`, `HTMLAutoClose`)→стрип тегов, скип `head/script/style`, block-теги→абзацные разрывы. Битый/пустой/чужой epub — **fail-loud, не паника** (нет container/opf/spine, dangling idref, не-zip). epub v1 = текст по spine, инлайн-разметка не сохраняется (осознанно, 02-mvp:25). Раннер: `os.ReadFile+NormalizeSource+SplitChunks``Ingest→SplitChunks(doc.Chapters)→persistRuby` (минимальный след, шов цикла цел; `ch.Text` в 3 местах не тронут).
**C. Ruby-захват + персист (`store/ruby.go`, миграция v4).** `<ruby>base<rt>reading</rt></ruby>`**base в тело, reading захвачен, `<rp>` скобки-фолбэк дропнуты**, mono-ruby склеен. Персист в **v4 `ruby_readings(book_id, base, reading, first_chapter, occurrences)`** (PK `(book_id,base,reading)` — вариантные чтения = разные строки). **Идемпотентный upsert:** `persistRuby` агрегирует по всей книге раз на инжест → оба поля **REPLACE** (ре-инжест того же источника = те же строки, правка источника = сходится к правде). **НЕ инъектится в промпт** (§7d, память v2 + детерминизм-load-bearing) → не в snapshot/`request_hash`. Память v2 (шаг 4) потребит → глоссарий-лок имён (D9).
**Селфревью (адверсариальный Workflow: 5 дименсий → находки → независимая CONFIRMED/REFUTED-верификация с конкретным сценарием инпут→неверный-выход).** Сам нашёл до ревью 1 баг (dense-numbering, ниже). Ревью: 9 находок, 4 подтверждены (≥1 верификатором), **все 4 исправлены + регресс-тесты мутационно-проверены** (реверт → падает именно его тест):
1. *[dense-numbering, до ревью]* ruby.Chapter брал spine-read-index, а `SplitChunks` нумерует главы **плотно** (пустые cover/nav скипаются) → `first_chapter` расходился с осью глав раннера (сдвиг `since_ch` памяти v2). Фикс: ingest нумерует тем же плотным правилом.
2. *[segmentation]* паковка **суммировала per-unit `EstimateTokens`** (флор 16 на каждый абзац/предложение) → глава из коротких реплик дробилась в суб-500-симв. чанки, которые coverage-гейт молча скипает. Фикс: аддитивный подсчёт классов символов, флор-16 **один раз на весь чанк** (= `EstimateTokens` от склейки).
3. *[epub]* `isXHTML` фолбэк на расширение только при ПУСТОМ media-type → глава с `application/xml`/`text/xml`/`…; charset=utf-8` молча терялась (реальные epub так мислейблят). Фикс: стрип параметров + фолбэк на расширение при ЛЮБОМ нераспознанном типе.
4. *[epub]* форматирующий whitespace МЕЖДУ base-сегментами ruby (pretty-printed jukugo `<rb>`) тёк в base (мис-ключ глоссария) и в `ch.Text`. Фикс: whitespace-only CharData внутри ruby-base дропается.
5. *[ruby-persist]* `first_chapter` был MIN-merge, `occurrences` — REPLACE (асимметрия): после правки источника, сдвигающей первое появление позже, `first_chapter` застревал на устаревшей ранней главе. Фикс: оба REPLACE (агрегат `persistRuby` — авторитетный full-book).
**Отклонено (обоснованно, оба верификатора REFUTED):** голый `<` в прозе валит весь epub — это **корректный fail-loud** на невалидном xhtml (альтернатива = тихая потеря главы, против инварианта); zip-bomb LimitReader — вне threat-model MVP (оператор-файл), в докстринг как future-hardening. Dense-numbering-находка ревью REFUTED — потому что уже был исправлен (верификаторы читали пофикшенный код).
**Границы/техдолг (не блокеры):** чанк <500 симв. молча выключает excision-гейт **документированная граница §7b** (после фикса #2 случается только на реально-крошечной главе/хвосте); overlap-инъекция и rubyглоссарий-лок отложены 3, ждут msgs-поверхности памяти v2 строим один раз); epub v1 не сохраняет инлайн-разметку; zip-bomb hardening future. Форму `ruby_readings` согласовать с памятью v2 при шаге 4 (контракт: basedst через reading, first_chaptersince_ch, occurrences=confidence). Тесты: чанкер (сегментация/паковка/детерминизм/аббревиатуры/quote-depth), ingest (txt/epub/spine-порядок/entity/ruby/битый-epub/dense-numbering/media-types), ruby-persist (идемпотентность+сходимость), e2e мульти-глава epubчанкимок-переводresume $0.
> **Внешнее ревью оркестратора Шага 3a (05.07): ПРИНЯТО, 0 живых блокеров, 7 подтверждённых находок (1 отсеяна).** Независимый воркфлоу — **агенты гоняли реальный код** (пробы в пакете), не утверждали. Money/детерминизм я подтвердил чтением сам. Тема: **тихая потеря главы/контента** — ровно тот класс, ради которого продукт есть. Ранг по важности:
> 1. **[major] Тихая потеря главы на dangling spine idref** (ingest.go:168-201). idref-опечатка, орфанящая главу, молча скипается через `continue`; ошибки нет, пока читается хоть одна другая глава (`read>0`). **Противоречит СОБСТВЕННОМУ контракту** (PROGRESS:400 перечисляет dangling idref среди fail-loud; :402 инвариант «тихая потеря главы, против инварианта»). Прогон: manifest=[c1,c2,c3], spine=[c1,ghost,c3] → главы=[c1,c3], c2 потеряна, **и `since_ch` всего хвоста книги сдвинут** (ruby c3 штампуется chapter=2). Асимметрия: пропавший zip-файл фатален, пропавший manifest-id молчит. Фикс: собрать неразрешённые idref → loud-ошибка (как для zip-entry). **Топ-приоритет.**
> 2. **[major] Тихая потеря главы на `application/xml`+`.xml`** (ingest.go:212-226). Тот же класс: контент-док, мислейбленный `application/xml`/`text/xml` С расширением `.xml`, промахивается мимо и type-switch, и extension-фолбэка (знает только .xhtml/.html/.htm) → молча скип + dense-renumber сдвигает `since_ch`. (Селфревью-фикс #3 закрыл ПУСТОЙ media-type, но не generic+`.xml`.) Фикс: при generic XML MIME распознавать `.xml` как контент. **Чинить вместе с #1.** → Системный фикс обоих: **spine-reconciliation** — сверять число контент-spine-items с реально прочитанными главами, расхождение = fail-loud.
> 3. **[major] Size-зависимая порча invalid-UTF-8 → U+FFFD** (chunker.go:220). Oversize-путь round-trip `[]rune(paragraph)` заменяет невалидный байт на U+FFFD, а нормальный путь (короткий абзац, `strings.Join`) сохраняет сырые байты. Тот же source-байт цел в коротком абзаце, испорчен в длинном — нарушение losslessness + size-зависимая несогласованность; течёт в `{{text}}` и `request_hash`. Триггер: mostly-UTF-8 файл со стрей/обрезанными байтами (txt без charset-guard). Прогон: `abc\xe9def` короткий → байты целы, oversize → `abc\xef\xbf\xbddef`. Фикс: нормализовать invalid-UTF-8 ОДИН раз в `NormalizeSource` (fail-loud или документированная замена, покрыто `chunkerVersion`).
> **Minor:**
> 4. **[minor] ASCII/эллипсис-граница игнорирует quote-depth** (chunker.go:263-273). Depth-подсистема читается только в CJK-ветке; ASCII-ветка (`.!?…`) депт не проверяет → терминатор внутри трекнутой кавычки over-splits (запретное направление). Прогон: `「Stop. Now.」` → 2 сегмента (CJK-твин → 1). Проявляется в oversize-абзаце (режет диалог через границу чанка). Фикс: гейтить ASCII-границу на `depthHere==0` тоже (straight-quote англ. кейс не регрессит — проверено).
> 5. **[minor] `<br>` внутри `<ruby>`** (ingest.go:326-327) не гардится `rubyDepth==0` (в отличие от block-тегов) → `\n` между base-глифами, обходит whitespace-collapse фикс #4; base и body расходятся. Whitespace-only, детерминизм цел. Фикс: гард `rubyDepth==0`.
> 6. **[minor] ruby phantom-строки** (ruby.go, нет delete). Пара, УБРАННАЯ правкой источника, навсегда остаётся фантомом (upsert-only, нет delete-by-book). Латентно (память v2 не приземлена, capture-only, ноль текущего impact), но памяти v2 навесит name-lock на имя, которого в книге нет. **Фикс совмещается с шагом 4:** `DELETE FROM ruby_readings WHERE book_id=?` перед bulk-upsert (полная замена агрегата — тогда «сходится к правде» верно и для удалений). Связано с ruby-контрактом в `architecture/06`.
> 7. **[minor] нет fuzz/property-теста tiling** (chunker_test.go). Единственный losslessness-тест — 6 ручных valid-UTF-8 инпутов; `Join(split(x))==x` над рандомом (вкл. invalid-UTF-8, вложенные/несбалансир. кавычки) поймал бы #3. Фикс: Go fuzz / testing/quick property + chunk-level losslessness (Σ не-пробел чанков == Σ не-пробел источника).
> **Отсеяна: 1** (oversize-хвост <500 симв. — механизм подтверждён, но это документированная граница §7b, не баг; верификатор REFUTED).
>
> **Приоритет фикса:** #1+#2 (тихая потеря главы, системно через spine-reconciliation) → #3 (losslessness UTF-8) → #7 (fuzz-тест, поймал бы #3) → #4 (quote-depth ASCII) → #5/#6 (мелочь, #6 — с шагом 4). Ничего не горит на боевом (все триггеры — битый/мислейбленный epub или invalid-UTF-8), но #1/#2 — именно тот тихий-потери класс, где мы обязаны быть fail-loud.
### 2026-07-05 — Шаг 3a: закрытие 7 находок внешнего ревью (все, в приоритете оркестратора)
Все 7 закрыты в этой же сессии (автор с контекстом дешевле, чем перезагружать свежую), каждый фикс **мутационно-проверен** (сломай падает именно его тест) + три fuzz-таргета прогнаны ~200k+ рандом-инпутов live. Всё зелёное `go build/vet/test -race`, `tmctl report` $0. `chunkerVersion` бампнут `v3-sentence-pack`→**`v4-utf8-quotedepth`** (правки нормализации/сегментации/инжеста = осознанная инвалидация, `--resnapshot`).
**Major (тихая потеря главы/контента):**
- **#1+#2 spine-reconciliation (`ingest.go`).** Dangling spine idref (опечатка, орфанящая главу) больше НЕ скипается тихо: собираются все неразрешённые idref **fail-loud** (как пропавший zip-entry) иначе терялась глава И сдвигался `since_ch` всего хвоста. `isXHTML` расширен: generic-XML MIME (`application/xml`/`text/xml`) + расширение `.xml` распознаются как контент (мислейбленная `.xml`-глава больше не исчезает). Не-контент-ассеты в spine (image/css) по-прежнему легитимно скипаются.
- **#3 invalid-UTF-8 в `NormalizeSource` (`render.go`).** `strings.ToValidUTF8(…, U+FFFD)` ОДИН раз в нормализации чанкер больше не расходится с собой ([]rune-путь по предложениям vs строковый по абзацам молча по-разному трактовали стрей-байт size-зависимая порча в `{{text}}`/`request_hash`). `FuzzNormalizeSourceValidUTF8` гарантирует валидный UTF-8 на выходе.
**Minor:**
- **#4 quote-depth в ASCII-ветке (`chunker.go`).** ASCII/эллипсис-граница теперь тоже гейтится `depthHere==0` `「Stop. Now.」` не over-splitится (straight-quote англ. не регрессит untracked, depth 0).
- **#5 `<br>` внутри `<ruby>` (`ingest.go`)** гардится `rubyDepth==0` `\n` больше не течёт между base-глифами.
- **#6 ruby phantom-строки (`ruby.go`/`persistRuby`).** `UpsertRubyReading`→**`ReplaceRubyReadings`** (DELETE-by-book + INSERT в одной tx): полная замена агрегата пара, убранная правкой источника, исчезает, а не остаётся фантомом; `persistRuby` зовётся безусловно (пустой набор чистит книгу). «Сходится к правде» теперь верно и для удалений контракт под память v2.
- **#7 fuzz/property tiling (`chunker_test.go`).** `FuzzSplitSourceSentencesTiles` (rune-lossless всегда, байт-точно на валидном UTF-8), `FuzzNormalizeSourceValidUTF8`, `FuzzSplitChunksPreservesContent` (Σ не-пробел чанков == Σ не-пробел источника) поймали бы #3.
Отсеянная находка (oversize-хвост <500) осталась документированной границей §7b. Дальше банк памяти v2 (шаг 4): реестр рисков `architecture/06` + ruby-контракт готовы (F1-materialization + горячий путь + post-check). Онбординг-промт след. сессии `docs/BACKEND_SESSION_PROMPT_MEMORY.md`.
### 2026-07-05 — Шаг 4: банк памяти v2 (глоссарий + горячий путь + инъекция + F1 + post-check)
**Главный блокер качества (консистентность имён/терминов) реализован — веха AE на seeded-глоссарии** (граница вехи подтверждена оркестратором §8: механизм на ручном+ruby-сиде; автопопуляция/адъюдикация/резюме/series-bible отдельные вехи). Всё зелёное `go build/vet/test ./... -race` (125 тестов в pipeline), `tmctl report` $0. Ратифицированный порядок реестра `architecture/06` §Гейты соблюдён.
**A4 нормализация (`memnorm.go` + `data/trad2simp.txt`):** NFKC + tradsimp (вендорённая таблица, **версия = хеш содержимого таблицы** дополнение = громкий `--resnapshot`, не тихая мини-карта) + катаканахирагана + lower для источника; NFC + lower + ёе + **схлопывание whitespace + унификация тире** для ru-цели. Симметрично ключтекст. Полный OpenCC оффлайн недоступен (нет данных на стенде) курированный высокочастотный набор, все referenced/live-bug кейсы ( и др.) покрыты и заассерчены; **завершение полного OpenCC — единственный отслеживаемый data-drop перед zh-приёмкой** (приёмочная книга D9 jaru, где tradsimp не несущий).
**A схема (миграция v5):** `glossary` (D7 + `sense`/ось редакционного времени `glossary_revisions`/`UNIQUE(src,sense,window)`/`min_key_len`-запрет одиночных ключей/`allow_short`) + `glossary_aliases` (alias-граф) + `glossary_revisions` (B1 append-only) + `retrieval_state` (гейт #4). Idempotent full-replace (как ruby). `store/glossary.go`.
**B горячий путь (`memory.go`):** frozen `MemoryBank` из store-строк; **Aho-Corasick** по нормализованным ключам; запрет одиночных ключей (A3); longest-match containment; спойлер-hard-reject (C1, `since_ch/until_ch`, 0=безграничен); sticky scene-inertia (A5); токен-бюджет с логируемым вытеснением (F2); трёхсторонний disposition (A2 confirmed/ambiguous/reject). Детерминизм: 0 map-order в выводе, T1T10 портированы (**не accept-регэкспы**), ловушки `retrieval_bench` 0/N, 200× determinism. **НЕ FTS5/вектор/эмбеддинги** (Р3).
**C инъекция (`render.go`):** `MessagesWithInjection` код-собранный `system`-месседж глоссария МЕЖДУ стабильным префиксом (кэш-граница) и user-чанком (вариант «а» оркестратора, шаблон не трогаем); НЕ в `ch.Text` (coverage/`{{text}}` чисты); свёрнут в `request_hash`/`content_hash`.
**D закрыт F1 (`runner.go`):** `memoryVersion()` = content-hash замороженных **approved**-строк + версии норм/матч-алгоритмов (D8, не version-counter). Смена approved громкий `--resnapshot` (e2e доказал `1e7b…``552c…`). id не хешируется; auto/draft вне хеша (их инъекция ловится `content_hash`).
**E post-check (`mempostcheck.go`) + E1-замер:** decl-осознанный (**наивный регэксп = 1836% ложных, research/14**), whole-word матч по записанным `decl`-формам, sticky исключён, слепой post-replace запрещён (E2). **Флаггер по умолчанию** (миссы `retrieval_state`, видны в `tmctl report`), **жёсткий гейт opt-in** (`gates.glossary.postcheck_gate`, как coverage флип после валидации владельцем). **E1 измерен как Go-тест на реальном склонённом русском (канон Рогова): full-decl 0% ложных, base-only 67%** эмпирическое подтверждение, что stored-decl надёжен ТОЛЬКО при полноте (ответ на развилку stored-decl-в-Go vs pymorphy-сайдкар Ф2: держим флаггером, сайдкар валидированный фолбэк если реальные книги зашумят).
**Ruby→глоссарий (`memseed.go`):** классификатор `name_candidate`/`gloss_candidate`/`ambiguous` **никогда не авто-лочит** (блайнд-лок = mistranslation; 強敵とも неотличим от имени оффлайн кандидат человеку). Ruby auto-кандидаты (src=base, reading=мост к Поливанову B6, без dst), дедуп по base, скип manual-src.
**Интеграция + config:** `TranslateBook`: ingestpersistRubyseedGlossary(replace+materialize)→snapshotloop с sticky-окном (ресет на границе главы, пересобирается детерминированно на resume). `book.yaml: glossary_seed`. `tmctl report` секция ПАМЯТЬ (агрегаты + пост-check миссы). Пост-check валидирует **финальный (редакторский) вывод** то, что экспортируется, не только черновик.
**Агентское адверсариальное селфревью (§6, многоагентный Workflow):** 7 дименсий 10 находок независимая refute-by-default верификация с прогоном реального кода **8 CONFIRMED (все воспроизведены), 2 REFUTED** (документированные размены: min-key-2 гомографы; редакторский drift закрыт пост-check'ом финала). Все 8 исправлены + регресс-тесты **мутационно-проверены** (реверт падает именно его тест): #1 empty-dst не матчится; #2/#8 whitespace-wrap/тире в post-check; #3 whole-word матч (дропнутый «Ван» не маскируется «караван»); #4 gate-mode `memoryVersion` сворачивает draft-decl (иначе resume молча флипал чанк); #5 дубль-alias в сиде дедупится (не крашит книгу); #6 спойлер-фильтр перед longest-match (спойлер-блокнутый длинный ключ не глотает валидное короткое имя); #7 floor-free токен-бюджет.
**Заложено/отложено (реестр §5, поля/место есть, реализация — Ф2/веха+):** Палладий/Поливанов B6 (reading как мост заложен), гейт фактичности резюме D1, эмбеддинг-слой A7/D2, морфо-гейт глагольного рода C3 (pymorphy-сайдкар), бэкап файла F4, автопопуляция/адъюдикация G1/F5, series-bible ты/вы-журнал, инъекция глоссария в редактор (dst-констрейнты) fast-follow на той же поверхности. Ставка (селективная инъекция vs длинный контекст) гейтится in-house eval'ом пилота Ф2.5 (параллельно, не блокер). Правки только в коде `backend/` + этот журнал; `architecture/06`/`research/*` не трогались.
> **Внешнее ревью оркестратора банка памяти v2 (05.07): ПРИНЯТО, 0 живых блокеров на дефолтном конфиге, 6 подтверждённых (5 различных, 3 major; gate-находка независимо продублирована 2 линзами), 0 отсеяно — ВСЕ прогоном реального кода.** **Ядро держится:** F1 (материализация/resume/детерминизм — тихий расходящийся ре-пэй), нормализация A4 (симметрия ключ↔текст), спойлер C1, инъекц-поверхность (сам проверил) — **чисты, находок нет.** Все гэпы в одной зоне — **короткие/коллизионные ключи + гейт инвертирует свою же safety** — ровно те «hard traps», что `research/13` §«Честные слабые места» **предсказал непроверенными** (материализовались в коде, пойманы до продакшена).
> **Major (закрыть до флипа гейта / до ja-kana в проде):**
> 1. **[major, ONE-LINER, делать первым] PostcheckGate флагает по ОБЩЕМУ числу miss без фильтра disposition** (runner.go:744; продублировано 2 линзами). AMBIGUOUS-only miss (кандидат, который модель ВПРАВЕ отклонить) роняет чанк → `FinalText=""` → **выбрасывает корректный перевод**. Инвертирует A2/E1: модель, ПОСЛЕДОВАВШАЯ неверной инъекции, проходит; модель, ПРАВИЛЬНО отклонившая — наказана. Контракт (E1/B4/gate-list/config, 4 источника) скоупит гейт на approved. Фикс: считать в гейт только `Disp==confirmed` miss; ambiguous — только в retrieval-state (наблюдаемость). Опт-ин (дефолт=флаггер) → на дефолте не горит, но чинить ДО флипа.
> 2. **[major] Source-side матч без word/script-границы + `dispositionFor` только по статусу** (memory.go:361, ac.matches). A2-ветка «коллизия поверхности → AMBIGUOUS» НЕ реализована; source-сторона без границы (асимметрия с target `containsWholeWord`, фикс селфревью #3). 2-символьный коллизионный ключ фичит **CONFIRMED внутри обычного слова** (リン→Рин в リンゴ/яблоко, AI→ИИ в RAID, 天下 в 天下无双). Post-check ИНВЕРТИРУЕТ: ложный confirmed-miss на КОРРЕКТНОМ выходе, и **не ловит FOLLOWED-отравление** (presence-only ловит только ДРОПнутый термин). Фикс: A2-даунгрейд коллизионных коротких ключей в AMBIGUOUS (не CONFIRMED); source-граница где есть смена скрипта/не-буква.
> 3. **[major] `min_key_len` per-язык НЕ разведён** (memory.go:42 `defaultMinKeyLen=2` хардкод). Реестр A3 называет `glossary.min_key_len` per-язык как механизм — не разведён. Precision-1.0/MIN=2 мерена на zh-Han-ловушках, **не переносится на ja-kana** (#2 язык, 46-символьная слоговая → 2-kana ключи = частые подстроки). **NB: селфревью REFUTED это как «документированный размен» — но замер был zh-Han-scoped; для kana это реальный гэп.** Фикс: развести per-язык (в `memoryMatchVersion`+snapshot), kana ≥3, или 2-kana за `allow_short`.
> **Minor (гарды от авторской описки, закрыть тихие дыры):**
> 4. **[minor] 1 src → 2 dst с ПЕРЕСЕКАЮЩИМИСЯ спойлер-окнами** → две противоречивые авторитетные строки, **молча** (асимметрия: зеркальный B2 2src→1dst логируется громко). Фикс: overlap-проверка same (src,sense) → WARN/fail-loud.
> 5. **[minor] approved-термин с пустым dst — молча инертен** (memseed.go:62; нет empty-dst-гарда на approved). Не матчится, не инъектится, 0 предупреждений → тихая потеря recall на всю книгу (ruby-auto с пустым dst легитимен, но там status=auto). Фикс: reject `status∈{approved,draft}` с пустым dst в loadGlossarySeed.
> **Протокол включения гейта (важно):** твой E1-замер меряет false-flag **approved**-терминов на русской морфологии — но находки 1/2/3 вскрывают **другие оси** false-flag (ambiguous-decline, коллизионные короткие ключи), которые E1-протокол НЕ покрывает. Значит либо чинить 3 major ДО флипа (что убирает эти оси), либо расширить протокол валидации на них. Рекомендую первое.
> **Приоритет:** #1 (one-liner, немедленно) → #2+#3 (коллизия/kana, до ja-kana или флипа гейта) → #4/#5 (дешёвые гарды). Ничего не блокирует дефолтный конфиг; всё блокирует флип гейта и прод ja-kana.
> **Внешнее ревью eval банка памяти v2 (05.07): ПРИНЯТО, 0 блокеров, 0 баг-находок.** Прогнал независимо на `aa00339` (сборка/тесты `-race` зелёные, E1 воспроизведён full-decl 0%/base-only 67%, трад-таблица 508 маппингов 爺→爷 на месте, изоляция инъекции/sticky-resume/F1/схема — проверил сам). 4 low/scope-заметки: (a) перекрывающиеся НЕвложенные ключи оба срабатывают (precision-сторона, обе поверхности реально есть); (b) редактор глоссарий не получает — защита только post-check финала (fast-follow: dst-констрейнт-инъекция в редактор — приоритет след. вехи); (c) gate-режим выкидывает весь чанк (opt-in, агрессивно — задокументировать до флипа); (d) 2-й system-месседж не на живом проводе (только моки — live-conformance кейс follow-up).
### 2026-07-05 — Шаг 4: закрытие внешних ревью (6 находок оркестратора + 4 low eval)
Все находки закрыты в этой же сессии, каждый фикс **мутационно-проверен** (реверт падает именно его тест) + полный набор зелёный `go build/vet/test ./... -race`, `tmctl report` $0. Ядро (F1/нормализация/спойлер/поверхность) оба ревью подтвердили чистым трогал только зону находок. `memoryMatchVersion` бампнут **v1→v2** (смена семантики матча/disposition = осознанная инвалидация громкий `--resnapshot`).
**Major:**
- **#1 gate по CONFIRMED-only.** `PostcheckGate` и `n_postcheck_miss` считают только `Disp==confirmed` (`countConfirmedMisses`); AMBIGUOUS-miss (кандидат, который модель вправе отклонить) больше не роняет корректный перевод только в `postcheck_detail` (A2-наблюдаемость). Инверсия контракта устранена.
- **#2 A2 коллизияAMBIGUOUS.** `dispositionFor(entry, via)`: короткий чисто-фонетический ключ (kana/latin без Han-якоря, 3 знака) даунгрейдится в AMBIGUOUS даже у approved (мог сработать внутри чужого слова). `allow_short` явный оверрайд автора. Sticky-кэрри сохраняет status-based (нет firing-ключа).
- **#3 min_key_len per-язык.** `minKeyLenFor`: Han-якорь 2 (эмпирика zh-Han precision-1.0); чисто-фонетический 3 (リン в リンゴ, ai в raid больше не фичат). **Kana=3 — консервативный дефолт до ja-kana precision-замера (расширение E1-протокола)** свежие глаза показали, что zh-Han-замер MIN=2 на kana не переносится.
- **Протокол флипа гейта:** оси false-flag из #1/#2/#3 (ambiguous-decline, коллизионные короткие ключи) E1-замер не покрывал закрыты в коде, поэтому расширять протокол не нужно; флип гейта разблокирован после этих фиксов + owner-валидации precision.
**Minor:**
- **#4 overlap спойлер-окон fail-loud.** `loadGlossarySeed`: same (src,sense) с пересекающимися окнами и РАЗНЫМ dst громкая ошибка (`windowsOverlap`; молчаливая противоречивая инъекция устранена).
- **#5 approved/draft пустой dst fail-loud.** Только `status=auto` (сырой кандидат, ruby-reading без dst) может быть пустым; approved/draft с пустым dst ошибка (тихая потеря recall).
**eval low:** #a тест `TestOverlappingNonNestedKeysBothFire` фиксирует принятое поведение (обе срабатывают); #b/#c/#d задокументированы (редактор-инъекция = приоритет след. вехи; gate-агрессивность `FlagGlossaryMiss` не-retryable/не-escalatable, флагает для человека; live-wire кейс follow-up на `live_conformance`-харнесс). Регресс-тесты: per-lang-min+collision-disposition, gate-ignores-ambiguous (e2e), overlap-windows/empty-dst fail-loud, overlapping-non-nested. Оба вердикта: **ПРИНЯТО**; дефолтный конфиг чист, флип гейта и прод ja-kana разблокированы.
### 2026-07-05 — Шаг 4: глубокое адверсариальное ревью полной поверхности (44 агента)
По запросу владельца многоагентный воркфлоу поверх `cc57c7b`: 8 finder-дименсий (нормализация / матчер+disposition / F1 / post-check / seed+ruby / store / инъекция+resume / мутационная-стойкость тестов), каждая не-минорная находка 3 адверсариальных верификатора refute-by-default, подтверждение большинством 2/3. **24 кандидата → 2 подтверждённых major, 10 отсеяно (все 0/31/3), 12 миноров.** Отсев здоровый: напр. «sticky протаскивает collision-prone AMBIGUOUS в CONFIRMED» зарублен 0/3 верно sticky не матчит исходник заново, а несёт установленный в сцене термин, collision-риск (срабатывание внутри длинного слова) к нему неприменим. Оба major класс «тихо пусто», ровно та зона, ради которой банк существует; оба закрыты, каждый фикс **мутационно-проверен** (реверт падает именно его тест), полный `-race` зелёный.
- **major #1 default-ignorables в A4-нормализаторах (`memnorm.go`).** Zero-width (U+200B/200C/200D/2060/FEFF) и вариационные селекторы (U+FE0F, IVS) переживали NFKC/NFC ключ `渡邊` молча не матчил `渡<ZWSP>邊` (частый артефакт EPUB/скрейпа CJK «тихо пусто» переоткрыт), симметрично на target `<WJ>` внутри слова давал ложный post-check-miss. Фикс: `isIgnorableForMatch` (unicode.Cf + VS-диапазоны) дропает их в ОБОИХ нормализаторах; soft-hyphen U+00AD сохранён как fold→'-' (self-review #8 порядок проверок гарантирует). `memoryNormAlgoVersion` бампнут **v1→v2** громкий `--resnapshot`.
- **major #2 окружающие пробелы на keying-поверхностях (`memseed.go`).** `loadGlossarySeed` проверял пустоту через TrimSpace, но хранил СЫРОЕ значение: `src: " 強敵"` (approved, непустой dst) проходил валидацию, ключился как `" 強敵"` и НИКОГДА не матчил `強敵` молча-инертный approved-термин на всю книгу; плюс trailing-space на `sense` маскировал same-sense-противоречие мимо обоих гардов (#4/#5). Фикс: тримминг `src`/`sense`/`dst`/`alias` до построения ключей и хранения (прощающий фикс, как alias-дедуп).
Отсев и 12 миноров оставлены как задокументированные размены/fast-follow (per-lang boundary-тесты post-check, sticky-decay coverage, apostrophe-fold не гарят на дефолте). Вердикт сессии: **ПРИНЯТО**, шаг 4 закрыт.
### 2026-07-05 — D1: инъекция глоссария в редактор (монолингвальный редактор)
Первый fast-follow на поверхности памяти (eval-приоритет). Редактор теперь получает одобренный глоссарий как **target-констрейнты** и переведён в **монолингвальный** режим (decisions-log D1).
- **`renderEditorConstraintBlock` (memory.go):** dst-only блок (без `src → dst` редактор не видит исходник), **CONFIRMED-only** (AMBIGUOUS кандидат, который переводчик вправе отклонить; форсить редактора переписывать черновик под непроверенное = порча корректного перевода, зеркалит gate-CONFIRMED-only #1), дедуп по dst, подмножество уже забюджеченного `memSel.injected` (свой токен-бюджет не нужен). Пустой редактор без инъекции.
- **runner.go:** `roleEditor`-ветка в стадийном цикле; `editorInjection` из того же `memSel` (детерминизм, resume-стабилен, входит в editor `request_hash` через msgs не в snapshotID, memoryVersion уже там).
- **`prompts/editor.md`:** убран `{{text}}` (D1: билингвальный редактор якорится к исходнику кальки, главная translationese-болезнь; монолингвальный ещё и дешевле исходник не сидит на входе каждого edit-вызова); мандат строки 7 согласован с инъекцией приводи к каноническим формам глоссария», а не «не трогай»).
Тесты **мутационно-проверены** (реверт падает именно его тест): `TestRenderEditorConstraintBlock` (CONFIRMED-only / dst-only / дедуп), обновлён `TestRunnerMemoryInjectionAndPostcheck` (editor получает dst-констрейнт-блок «КАНОНИЧЕСКИЕ ПЕРЕВОДЫ», не «srcdst ГЛОССАРИЙ»), `TestEditorPromptIsMonolingual` (guard: реальный editor.md без `{{text}}`). Полный `-race` зелёный, `tmctl report` $0.
**Заметка владельцу/оркестратору:** редактор стал **источник-слепым** (D1) правит стиль/консистентность имён, но не ловит мистранслейты (это судья/эскалация, Фаза 2). Осознанный размен по контракту D1.
### 2026-07-05 — Консолидация конфига (drift из doc-аудита оркестратора)
6 конфиг-расхождений моей зоны (промт `BACKEND_SESSION_PROMPT_CONSOLIDATION`); центральный grok-разворот верифицирован веб-чеком xAI-доки + пробой eval, всё адверсариальным селфревью (5 измерений, **0 находок**).
- **grok-4.3 reasoning OFF даётся ЯВНО** (задачи 1-2, money-path). `models.yaml`: `control:none``control:effort/off_effort:none`. Дефолт grok = `low` (омиссия заставляет думать, additive-биллинг ~444 ток./правку) `ReasoningNone` (off-by-omission) молча оставлял бы low; теперь при `reasoning:"off"` уходит плоский `reasoning_effort:"none"` (проба eval 0 ток.). Комментарий `ReasoningNone` в `capability.go` разведён (DeepSeek grok логика не тронута). **DeepSeek остаётся `ReasoningNone`** (omission намеренный: отключение thinking взводит эхо-мину; гвард `echoMineViolation` цел, xAI не echo-prone).
- **Редактор glm-5 grok-4.3** (задача 3, D1/D3; glm-5 был плейсхолдером) в edit-стадии C1/C2; select-стадия C2 (judge/glm-5, Gemini-слот Ф2) не тронута. Прод только чистый xAI-ключ без data-sharing.
- **Anthropic price-litter убран** из шапки `models.yaml` (з.4); **escalation-заглушки `[kimi-k2.6]` помечены интеримом** с названной D3-цепочкой (з.5 заводка провайдеров gemini/openai + v4-pro/glm-5.1/gemini-3.1-pro отдельным шагом, гейтится ценами/ключами/cost-model); **бэкендовый `[НУЖНО РЕШЕНИЕ]`-маркер → РЕШЕНО** (з.6; оркестраторский блок не тронут).
Тесты: `capability_test` кейс assert'ит **присутствие** `reasoning_effort:"none"` (закрыл eval-указанную дыру ложный «off шлёт nothing» тут падает); `TestBoevoyConfigGrokEditorExplicitNone` (config end-to-end: grokexplicit-none, не echo-flagged, edit=grok, c2-select=glm-5). Полный `-race` зелёный, `tmctl report` $0. Eval подтвердил: прогоны переигрывать не надо, баг был латентным (grok не был в стадии) пойман до флипа.
## Полигон
(секция параллельной сессии записи добавлять сюда)
> **Сообщение от основной сессии (04.07, после ревью твоих экспериментов 0102).** Работа принята, качество высокое. Важные вводные:
> 1. **Архитектурные доки обновлены до v2** (~05:08, после адверсариального ревью) — если читал их до этого, перечитай `architecture/01-decisions.md`: экономика теперь разделена по контурам «чей ключ» (Р5), премиум-микс с Sonnet в ru-контуре недоступен, batch — только для батчуемых стадий. Твой пересчёт COGS из эксперимента 01 отлично ложится в контур «прямые ключи»; при случае добавь строку-оговорку про ru-агрегаторский контур (×26 на флагманы).
> 2. Твои **коридоры len_ratio из эксперимента 01 — прямой вход в coverage-гейт v1** бэкенда (Р7/план Фазы 1). Когда сузишь их по факту прогонов — зафиксируй в experiments-доке итоговые пороги отдельной таблицей, я заберу их в конфиг гейта.
> 3. **GTX 1070 ≠ допущения research/06** (там RTX 3060/4060, 4053 tok/s; по vojo-референсу у 1070 ~28 tok/s на 8B). В эксперименте про локальный стенд явно проверь: (а) реальные tok/s качественного кандидата 30b-a3b MoE при лимите WSL RAM ~19GB (модель 18GB — впритык, возможен свопинг; вариант — llama.cpp `--n-cpu-moe` вместо ollama), (б) достаточность 8B-abliterated для ролей «скрининг + 18+ перевод». Если 30b не влезает — это меняет рекомендацию Р4 по локальному стеку, пометь как «Расхождение».
> 4. Опциональная задача в бэклог (из Р5/Р10 риск №6, понадобятся ключи владельца): **эмпирическая проверка, пробрасывают ли ru-агрегаторы (ProxyAPI/VseGPT/AITunnel) cache-hit тарифы DeepSeek** — два одинаковых запроса подряд, сравнить usage/стоимость. Это разблокирует экономику ru-контура.
> 5. Договорённость по журналу: фиксируй здесь краткие итоги каждого эксперимента (12 строки + ссылка на док) — основная сессия читает эту секцию, а не всю папку experiments.
### 2026-07-04 — Сессия 1 полигона (ответ на вводные выше — приняты)
Инфраструктура: `eval/` (venv, токенизаторы DeepSeek V3.2/Qwen3/Qwen2.5/GLM-4.6 + tiktoken), PD-корпус 16 текстов zh/ja/en/ru с 3 параллельными парами. Ключи `eval/.env` (gitignored, закрыт deny-правилом; скрипты читают сами; шаблон на 7 провайдеров создан, ждёт заполнения владельцем).
- **Эксперимент 01 (задача 1) завершён** [experiments/01-token-calibration.md](experiments/01-token-calibration.md). Два расхождения с research/09 >15%: иероглиф = 0.860.93 ток. (in-family) против 0.650.75; «выход≈вход±20%» сломано — zh→ru **1.88×B** (en→ru 1.53, ja→ru 1.29). COGS (контур прямых ключей): стандарт-вебновелла DeepSeek $1.85→$2.57, премиум-микс ≈$28→**≈$49** ($26 batch); ранобэ ja→ru подешевел ($3.9→$3.1). Оговорка про ru-агрегаторский контур добавлена (п.1 вводных учтён).
- **Эксперимент 02 (задача 2) — первый прогон выполнен** (ключи получены ~06:10) → [experiments/02-refusal-benchmark.md](experiments/02-refusal-benchmark.md). 6 провайдеров × 11 фрагментов (SFW/L1/L2-violence): **66/66 ok — ноль отказов и вырезаний**, контроль ложных срабатываний пройден; содержательная 18+ часть ждёт explicit-фрагментов владельца. **Пороги len_ratio для coverage-гейта готовы** (п.2 вводных): zh→ru <2.2, jaru <1.4, enru <0.70, sent_cov <0.75 таблица в 02, забирайте в конфиг v1. Побочные находки для продакшн-конфига провайдеров: thinking GLM-4.6 (таймауты ×3) и Gemini (молча обрезал перевод детектор поймал) отключать для роли переводчика; gpt-5-mini reasoning minimal; safety_settings Gemini через OpenAI-слой не передаются (судье нужен нативный API).
- **Эксперимент 03 (задача 3) первый замер + эталон** [experiments/03-local-stand.md](experiments/03-local-stand.md). По п.3 вводных: (а) 30b-a3b в WSL **влезает** (mmap, без OOM), но на ollama даёт лишь **10 tok/s** «Расхождение» с research/06 (2530 обещаны через llama.cpp `--n-cpu-moe`; ставится в фоне перемерить; Р4 менять пока не надо: рекомендация там и так llama-server); частично виноват и лимит WSL RAM 20GB поднят до 26GB (`.wslconfig`, вступит после рестарта WSL); (б) 8b @ 27 tok/s (6.6GB VRAM) на роли скрининга/экстракции годен. **Эталон DeepSeek снят: разрыв качественный** API даёт корректные реалии ворота Расёмон на улице Судзаку», «Новогоднее жертвоприношение») за ~$0.0005/фрагмент там, где обе локалки галлюцинируют Рождественская дверь», «петухи»); NSFW-фрагменты ещё не гонялись. Для бэкенда: лег-таймаут vojo 45 с несовместим с чанками (63278 с) нужен свой профиль + стриминг. План расширения пула: ваниль qwen3:8b (цена абляции) Qwen3.5-9B RuadaptQwen3 (докачиваются в фоне).
- Бэклог принят: проверка проброса cache-hit агрегаторами (п.4, нужны ключи) в шагах ниже. Задачи 45 не начаты (bge-m3 уже на стенде).
### 2026-07-04 — Сессия 2 полигона (после рестарта WSL с RAM 26GB)
- **llama.cpp `--n-cpu-moe` для 30b-a3b перемерено, «Расхождение» с research/06 подтверждено**: потолок генерации на GTX 1070 **~13.5 tok/s** (не 2530). Таблица конфигов в [03](experiments/03-local-stand.md): ollama 10 llama.cpp `--cpu-moe` 11.2 `--n-cpu-moe 33` 13.5 (VRAM 2.97.8GB, prefill 105208). Узкое место пропускная способность CPU-RAM (DDR4/Pascal), не рантайм; llama.cpp честно лучше ollama (+35% ген., ×23 prefill), но 30b-a3b на этом железе только фоновые роли (~2.5 мин/главу). Скрипт: `eval/llama_moe_bench.sh`.
- **Замер 4 новых dense-моделей** (ваниль qwen3:8b / qwen3.5:9b / +abliterated / ruadapt) готово, таблица в [03](experiments/03-local-stand.md). Три вывода: (1) **абляция бесплатна** qwen3.5 vanilla vs abliterated идентичны по скорости и SFW-качеству 18+-роль можно на abliterated без штрафа; (2) поколение 3.5>3 умеренно (лучше понимание, 25% токенов, 10% скорости); (3) **RuAdapt: токен-выигрыш подтверждён (40% ru-токенов), но перевод развалился** (羅生門→«дерево с колокольчиками») → редактор ru-стиля, не переводчик (как и предупреждал research/06). Разрыв с API держится у всех. **Побочная находка для бэкенда:** thinking у Qwen3.5+/GLM/Gemini для роли переводчика обязателен к отключению (иначе пустой/обрезанный вывод — ловилось дважды: эксп. 02 и здесь).
- **Think-режим (проверка гипотезы владельца «reasoning поднимет качество в разы»)** — [03](experiments/03-local-stand.md), раздел «Влияние thinking». Итог: (а) прежняя «пустота» — артефакт тесного контекста (рассуждения не влезали с ответом), не зависание; (б) с ctx 16k think **завершается и реально чинит реалии** (羅生門: «Радзёмон»→«Рашо-мон»; 朱雀 с китайского чтения на японское) — гипотеза частично подтвердилась; (в) но локально нежизнеспособен: 8,6 мин и ~11k токенов рассуждений на 1400 знаков (вебновелла ≈ 200 ч). **Новый пункт бэклога → оркестратору/бэкенду: проверить think-ON vs OFF по КАЧЕСТВУ на быстром облачном черновике/редакторе (DeepSeek/GLM)** — потенциальный дешёвый рычаг качества, раз reasoning вытаскивает реалии.
- **Справочник провайдерских граблей** → [experiments/00-provider-quirks.md](experiments/00-provider-quirks.md) (по замечанию владельца: бэкенд и полигон оба «ходят к провайдерам», но это не дубль — Go-продакшн-адаптеры 1735 строк с failover/ledger vs 40-строчный Python-зонд сырого поведения; объединять нельзя, но **знание о граблях сведено в один справочник**). Собраны: thinking-управление (GLM/Gemini/gpt-5/Qwen — у каждого по-своему!), Kimi только temp=1, Gemini 3.1 Pro обязательно-думающая, safety_settings Gemini не через OpenAI-слой, localhost-прокси, деприкации. **Бэкенду: читать при правке адаптеров `internal/llm`.**
- **Эксперимент 04 — бейк-офф редакторов ru-стиля** (вопрос бэкенда №2 + замена Anthropic) → [experiments/04-editor-quality.md](experiments/04-editor-quality.md). Метод: DeepSeek-черновик → 4 редактора (glm-4.6/kimi-k2.6/gemini-3.1-pro/grok-4.3) полируют; 4 фрагмента (ja/zh/en); **слепая человеческая оценка владельца** (LLM-судьи на худ. качестве ненадёжны). Артефакт для оценки: https://claude.ai/code/artifact/25394796-96f0-4f3f-b8d0-de000d415472. **Объективно уже видно:** grok-4.3 — быстрый/дешёвый (~13с, без reasoning); **kimi-k2.6 дорогой** (~11k reasoning-токенов на абзац → биллятся как выход); gemini-3.1-pro обязательно-думающая. Цена входит в решение наравне со стилем. **Оценка стиля — на владельце (ожидает).** Методическое следствие для пилота (задача 4): владелец читает только en/ru → человеческая оценка верности возможна лишь на en→ru + русской стороне, для zh/ja нужен английский якорь.
**Эксперимент 04 — РЕЗУЛЬТАТ (04.07):** слепую оценку сделали два фронтир-судьи (GPT + Opus 4.8), сверяясь с **каноническими переводами** (Фельдман/Рогов/Морозов), **сошлись независимо**. Ключ: A=grok-4.3, B=glm-4.6, C=gemini-3.1-pro, D=kimi-k2.6. Итог: стиль **gemini > grok > kimi > glm**; верность **grok > gemini > glm > kimi**; value **grok ≫ gemini > glm > kimi**. **Рекомендация дефолта редактора Фазы 1: `grok-4.3`** (лучший баланс качество/цена, надёжен по смыслу, ~13с/без reasoning), **премиум-эскалация `gemini-3.1-pro`** (лучшая проза, культурные узлы на уровне канона). **GLM-4.6 (текущее допущение Р4 «редактор=GLM») эмпирически слабейший — снять с дефолта; Kimi убрать (худший value: 11k reasoning/абзац, последний по верности).****оркестратору: правка Р4** (полигон архдоки не трогает). Полный разбор — [04-editor-quality.md](experiments/04-editor-quality.md).
**⚠️ КОРРЕКЦИЯ ВВОДНЫХ ОТ ВЛАДЕЛЬЦА (04.07) → ОРКЕСТРАТОРУ, фундаментально:** владелец **НЕ в РФ**; бэкенд на **EU-сервере**, все вызовы моделей идут оттуда; модель — **обычный SaaS с прямыми ключами** (владелец платит за токены, клиент платит за сервис). **BYOK НЕ делается — ни сейчас, ни в планах** (стопнуть в доках). Следствие: **весь «ru-контур / BYOK / агрегаторы» неверен**Р5 «два контура чей ключ» схлопывается в один (прямые ключи), почти весь Р8 (152-ФЗ/259-ФЗ/ЮKassa/ИП) неприменим. Остаётся валидным ru как **язык перевода** (рынок ru-читателей), меняется только доставка. **Правки Р5/Р8/Р9 — на оркестраторе** (полигон архдоки не трогает). Полигон: проверку ru-агрегаторов из очереди **снял**.
### Следующие шаги полигона
- [x] Эксперимент 04 (редактор) — оценён (grok-4.3 дефолт, gemini-3.1-pro премиум; GLM/Kimi не дефолт); правка Р4 на оркестраторе.
- [x] Прогон refusal-бенчмарка (SFW/L1/L2-violence часть) — 66/66 ok, пороги в 02.
- [x] Эталон DeepSeek + llama.cpp 30b-a3b (13.5 tok/s) — в 03.
- [~] **explicit-часть refusal-бенчмарка** — владелец даёт фрагмент реальной вебновеллы («Мастер Гу», жёсткая сцена) → полигон заведёт в корпус и прогонит через провайдеров (кто откажет/вырежет/переведёт). Проверка ставки «Grok = NSFW-канал».
- [x] ~~Проверка ru-агрегаторов~~**СНЯТА** (BYOK отменён владельцем, см. коррекцию выше).
- [—] **Банк памяти (задача 5 + шире)** — по решению владельца выносится в **отдельную сессию «Валидация банка памяти»** (главная точка отказа пайплайна; не бросаться в код без разбора опасных сценариев). Полигон подготовил черновик промта → `docs/MEMORY_RESEARCH_SESSION_PROMPT.md`; **оркестратору вычитать/финализировать**, затем владелец запускает. Замер эмбеддингов (bge-m3 vs Qwen3-Embedding vs LaBSE) — часть мандата той сессии.
- [ ] Довалидация токен-калибровки на 35 главах реальных вебновелл (файлы владельца).
- [~] Задача 4 (пилот выбора ядра, Фаза 2.5): протокол BWS + панель LLM-судей — **протокол готов** ([experiments/09](experiments/09-pilot-protocol.md)) + харнесс `eval/pilot/`; решающий прогон ждёт корпус владельца (см. Сессия 3).
- [x] **Валидация precision coverage-гейта — гейтит боевой флип** (D12 Q4) → [experiments/07](experiments/07-coverage-precision.md): 0 FP/57, флип по precision безопасен, порог ≥2 флага/главу; вебновелл-срез ждёт корпус владельца (см. Сессия 3). Бэкенд-мини-набор (выпиленные предложения) проверяет recall (≥90%); флип `gates.coverage.enabled:true` упирается в **false-positive rate** на легитимно диалого-плотных главах (сегментация наивная, quote-absorbing §3.7 в v1.1 — на диалогах `sent_cov` может ложно проседать). Прогони гейт (пороги эксп.02: zh-ru<2.2/ja-ru<1.4/en-ru<0.70, sent_cov<0.75) на реальных чанках zh/jaru, замерь долю ложных excision_suspect. Оракул = `eval/refusal_bench.py::classify_output` (тот же, что порт в Go держать в синхроне). Выход: доля ложных флагов по типам глав оркестратор/владелец ставит порог N допустимых флагов и решает флип.
- [x] ~~**Эксперимент 05 — memory-bet**~~ **СНЯТ как низкосигнальный** (решение владельца). Прогон был, но его ось C0-vs-C1 бредит ли модель без глоссария») предрешена, а C3/C2 лишь пере-подтвердили уже процитированную литературу (2510.00829) тест не мог изменить ни одного решения. Артефакты (doc/скрипт/данные) удалены. Единственный actionable-вывод (post-check + disposition обязательны) уже зафиксирован в реестре `architecture/06` (A2/E1) независимо от этого прогона. **Урок для eval:** тест ставить только если его исход мог бы перевернуть решение И не установлен литературой. Ценность вместо этого валидация самого МЕХАНИЗМА (см. ниже).
- [x] **Референс горячего пути банка памяти + self-tests** `eval/memory_hotpath.py` (11/11 PASS). Исполняемая спека механизма (не продукт): нормализация tradsimp/kana, точный матч ключей/алиасов с запретом одиночных (омографы 送灶/// НЕ инъектируются), спойлер-фильтр `since_ch/until_ch` (hard-reject), sticky для местоименных чанков, disposition confirmed/ambiguous/reject, post-check (ловит и утечку, и отравление). **Бэкенду:** порт в Go 1:1, тесты T1T10 unit-тесты; `[PROD]`-замены: OpenCC, Aho-Corasick, pymorphy/`decl`.
> **[ЗАДАЧА ОРКЕСТРАТОРА → eval] Эксперимент 05: memory-bet (индикативный).** Отвечает на главный незакрытый вопрос валидации (research/13 §Вердикт): оправдан ли банк памяти vs просто длинный контекст, и вредит ли ошибочная инъекция (страх владельца). **Runnable сейчас, продукт не нужен** — это конструирование промптов + API-вызовы + метрики.
> **Метод:** один стек `deepseek-chat` (черновик) → `grok-4.3` (редактор, thinking OFF, temp 0.4 — квирки в `00-provider-quirks`). Реальные zh→ru чанки: `eval/data/samples/zh/luxun-ah-q-ch1-4.txt` (повторяющиеся имена 阿Q/赵太爷/王胡/送灶; есть русский эталон Рогова `samples/ru/luxun-ah-q-ru.txt` для якоря верности). Нарезать ~58 перекрывающихся чанков; собрать мини-глоссарий (510 записей: имена+реалии, с dst и `decl`). **4 условия на чанк:**
> - **C0** без глоссария (baseline);
> - **C1** селективная инъекция (только записи, встречающиеся в чанке) — наш банк;
> - **C2** полный глоссарий + скользящее резюме в промпте — «просто длинный контекст»;
> - **C3** случайный/неверный глоссарий (перемешать dst) — адверсариальная рука, прямой замер «вредит ли ошибочная инъекция».
> **Метрики (3 оси):** (а) **консистентность** — детерминированно: рендерится ли approved-dst (по лемме/`decl`) одинаково во всех чанках, где встречается src; (б) **верность/пропуски** — судья чужого семейства (gemini нативный или через промпт «сверь перевод с источником, найди mistranslation/omission»), + сверка с эталоном Рогова где возможно; ru-специфика: согласование рода (вкл. глагол прош.вр.), склонение dst; (в) **стоимость** — токены input/output по условиям (C2 должен быть заметно дороже — часть решения).
> **Правило решения:** C1≈C2 по качеству но C1 дешевле → банк оправдан; C2≫C1 → пересмотреть (нужен полнее контекст); C3 роняет vs C0 → страх владельца подтверждён, post-check/disposition обоснованы.
> **Env:** `eval/.venv` нет `openai`/`dotenv` — доставить (`pip install openai python-dotenv` в venv); ключи из `eval/.env` через dotenv; base_url/слаги в `providers.json`+`00-provider-quirks` (deepseek-chat депрекейт 24.07 — жив сейчас; grok base `https://api.x.ai/v1`). **Оговорка: ИНДИКАТИВНЫЙ** (малый N, LLM-судья) — как retrieval_bench; полная версия с человеческими BWS-аннотаторами = пилот Ф2.5. Выход: `docs/experiments/05-memory-bet.md` + сводка сюда. Сильнее сигнал, если владелец подложит 12 главы реальной вебновеллы с повторяющимися именами — но PD-阿Q хватит для старта.
> **Задачи от оркестратора (04.07, из журнала решений [architecture/05-decisions-log.md](architecture/05-decisions-log.md)):**
> 1. **Пересчитать ОБА cost-числа** (не только премиум) на реальном Фаза-1 стеке — расширено после D8D11: дефолт-редактор теперь **grok-4.3 ($1.25/$2.50)**, не GLM/DeepSeek → и **стандарт-микс** подорожал (ja→ru ранобэ ~$0.73, не $0.17; порог приёмки $0.6 устарел). Дай: (а) стандарт-микс (DeepSeek-draft + grok-editor) на ранобэ ja→ru и вебновелле zh→ru; (б) премиум-микс с апексом Gemini 3.1 Pro (обязательный thinking, reasoning-as-output $12/M; batch 50% только судье/QA, НЕ inline-эскалации; эскалированный чанк платит Gemini дважды). Дефолты $5/$30 и порог $0.6 — заглушки до пересчёта.
> 2. **Замерить, эмитят ли DeepSeek/GLM/Kimi/grok `finish_reason=content_filter`** (D2.4, теперь и grok — он дефолт-редактор): бэкенд ветвит диспозицию по нему, но OpenAI-совместимый слой отдаёт finish_reason сырым — если провайдеры его не шлют, реальная страховка только refusal-blacklist. Дешёвый зонд на отказном фрагменте. Плюс, если есть ключ: подтвердить capability-квирки **gpt-5-nano** (бэкенд предполагает = mini: max_completion_tokens + omit temperature + effort minimal — верифицировать).
> 3. **Think-ON vs OFF по КАЧЕСТВУ на облачных translator/editor** (DeepSeek/GLM/Kimi — subset-billing, безопасно по потолку): гипотеза владельца про reasoning частично подтвердилась локально (羅生門→Радзёмон), DRT (arXiv:2412.17498) подтверждает для роли переводчика. Это ключевой вход в пилот Ф2.5 — мерить именно translator/editor, не только Terminologist.
> 4. Проброс cache-hit/batch RU-агрегаторами (уже в бэклоге) гейтит достоверность всего премиум-бюджета — приоритет поднять.
> 5. **Ключевой набор расширен:** теперь живы и `OPENAI_API_KEY`, и `GEMINI_API_KEY`, и `XAI_API_KEY` — Gemini-судья и Grok-канал-B можно гонять в евалах сразу.
> 6. **xAI/Grok НЕ выведен** (уточнение владельца): ретайрнулся только дешёвый Grok 4.1 Fast, сам провайдер жив. Роли Grok — переводчик канала B **и судья 18+** (не отказывается оценивать explicit). У xAI **промо $150 за data-sharing** — бери на выделенный NSFW-аккаунт: этим разблокируется висящая 18+ часть refusal-бенчмарка (эксп.02) и 18+ плечо пилота. Гони на промо-кредитах: (а) 18+ refusal/excision на Grok/DeepSeek/локальной abliterated; (б) Grok в роли 18+-судьи — качество оценки explicit-сцен. Data-sharing только PD/тест-корпус, реальные книги через него не гнать. Grok в евалах — thinking OFF (reasoning аддитивный).
### 2026-07-05 — Сессия 3 полигона: coverage-precision (07), cost-model-v2 (08), пилот-подготовка (09)
Три ближние задачи закрыты; всё адверсариально верифицировано воркфлоу (5 линз, вердикт CONDITIONAL GO все must-fix внесены). Артефакты `eval/coverage_precision.py`, `eval/content_filter_probe.py`, `eval/cost_model_v2.py`, `eval/pilot/{declmetric,memory_eval}.py`, `docs/experiments/0709`.
- **Задача 1 precision coverage-гейта флип МОЖНО (D12/Q4).** [experiments/07](experiments/07-coverage-precision.md). **0 ложных срабатываний на 57 хороших переводах** (LLM deepseek+grok × 2 + канон Рогова/Фельдмана), 0/26 нарратив, 0/31 «диалог» (маркер-прокси). Диалог: русский дробит CJK `sent_cov ≥ 1` (не проседает); ближайший к полу 0.75 0.886 (ja-нарратив, запас 18%). Коридоры len_ratio НЕ узки (zh запас +20%, ja +14%). GoPython паритет-тест зелёный. **Оговорка широты (честно):** «диалог»-страт классика Лу Синя с цитируемыми ТЕРМИНАМИ, НЕ вебновелл-диалог; §3.7 НЕ воспроизведён но и НЕ опровергнут; человеческий слой глава-гранулярен. **[→ бэкенду/владельцу]** флип `gates.coverage.enabled:true` по precision безопасен; порог главы **2 флага=fail, 1=attention**; коридоры не менять; **пере-снять на реальных вебновеллах владельца** до снятия 1-флаг-толерантности (просьба ниже).
- **Побочно (D§85, бэкенду):** `finish_reason=content_filter` **не эмитит ни один** из 5 ядровых провайдеров на SFW-violence (все `stop`/200/перевели) ветка мертва, страховка = refusal-blacklist (подтверждает D2.4). Нюанс: **gemini-3.1-pro** (апекс) единожды дал `content_filter:PROHIBITED_CONTENT`, но не воспроизвёл на 4 контрольных изредка срабатывает, не системно.
- **Побочно (→ бэкенду):** **draft-эхо классической zh — системно:** deepseek-v4-flash эхнул **13/24** zh-чанков Лу Синя, grok-non-reason **10/24** (лёгкая правка исходника вместо перевода, не усечение) ловит интринсик echo-гейт; single-hop эскалация черновика оправдана; вебновеллы вне претрейна риск ниже.
- **Задача 2 COGS v2 на grok-editor стеке оба порога мертвы.** [experiments/08](experiments/08-cost-model-v2.md). Прайсы офиц. доки, датированы 2026-07-05, кросс-верифицированы (воркфлоу). **Стандарт-микс (draft+editor):** jaru ранобэ **$0.69**, zhru вебновелла-500 **$10.94**, enru роман **$0.93** **редактор ~8890% стоимости** (grok-выход ×9 draft). **$0.6 мёртв.** **Премиум (Gemini apex):** ранобэ $5.0, вебновелла центр **~$82** (rf-условно $66112; ниже якоря $100), роман $6.8 **полный apex больших работ НЕ дефолт** (переполняет $30). Селективный apex (15%): вебновелла $24.6. **[→ бэкенду/оркестратору]** (1) **[ИСПРАВЛЕНО 05.07 проба была багом]** editor slug остаётся **grok-4.3**; reasoning отключается ЯВНЫМ `reasoning_effort:none` (дефолт grok = low без явного none думает), переснято (xAI docs + exp08:70-74). Прежнее «grok-4.3 форсирует / не отключается» НЕВЕРНО; (2) `budget_usd` под селективный apex ($2 ранобэ/роман; вебновелла потолок-на-главу/`apex_fraction`); (3) батч 50% только Gemini-судье; (4) **rf Gemini НЕ измерим через OpenAI-слой** (thoughts=0) нужен нативный API перед привязкой премиум-бюджета.
- **Задача 3 подготовка пилота Ф2.5.** [experiments/09](experiments/09-pilot-protocol.md) (протокол: ядро C0C3 BWS, судья-панель+s\*, memory-eval WMT25-3-режим, think-ON/OFF, Annotator A/B, en-якорь для zh/ja верности) + харнесс `eval/pilot/`. **Decl-метрика** (`declmetric.py`, pymorphy3+stored-decl, mirror Go post-check) склонённые формы (Вэйчжуане/Вана/Дэна) 0 ложных флагов. **memory_eval.py** WMT25-3-режим, инъекция = **зеркало Go-контракта memory.go** (спойлер/disposition/sticky/containment/per-lang-minkey валидированы; `memory_hotpath.py` устарел до cc57c7b не переиспользовал). **Индикатив (Ah-Q, N=5):** C0 консист. 0.58, **C1(банк) 1.0 = C2(длинный контекст) 1.0**, C3(неверный) 0.60 банк длинный контекст по консистентности при меньшей инъекции; неверная инъекция не помогает. **[← владельцу нужно]** корпус 2535 глав с приватными эталонами (рекуррентные имена, диалог/нарратив); человеческие BWS-аннотаторы; explicit-18+ фрагменты для канала B (gitignored).
**[ПРОСЬБА ВЛАДЕЛЬЦУ]** 35 глав реальной вебновеллы/ранобэ zh/ja с любым русским ориентиром `eval/data/samples/<lang>/` закрывает (а) диалог-плотный срез coverage-precision (эксп.07), (б) довалидацию токен-калибровки r (эксп.01/08), (в) старт memory-eval на большом глоссарии. Для zh вне претрейна (обход эхо-мины).
## Память
(секция сессии «Валидация банка памяти» записи добавлять сюда)
### 2026-07-04 — Сессия «Валидация банка памяти» завершена
Метод: многоагентный ресёрч по 7 направлениям + независимая адверсариальная верификация по первоисточникам + completeness-критик (15 агентов) + локальный эмпирический бенчмарк retrieval на реальном PD-корпусе + чтение кода `backend/`. **Выходы:**
- [research/13-memory-bank-validation.md](research/13-memory-bank-validation.md) вердикт (что менять, обоснование, источники).
- [architecture/06-memory-risk-registry.md](architecture/06-memory-risk-registry.md) **реестр рисков (вход бэкенду перед фиксацией схемы store/глоссария Фазы 1)**.
- Эмпирика: `eval/retrieval_bench.py`, `eval/data/retrieval_bench/` (реюз PD-корпуса полигона, не дублируя инфру).
**Вердикт (кратко):** архитектура ДЕРЖИТ, но **go/no-go на саму ставку сейчас нельзя** центральный детерминированный no-LLM горячий путь **академически нов** (DelTA LLM-в-цикле per-предложение), сравнение «банк vs длинный контекст» на реальном zh/jaru стеке **не проведено**, acceptance-критериев/baseline/cost-модели нет.
**Находки (12 строки):**
- **Q1 Робастность:** опасение владельца уточнено «пусто» безопасно (норма горячего пути), тихую деградацию порождает **ошибочная инъекция** (модель послушно следует неверной строке, уверенность точность 2510.00829). Защита: «лучше ничего, чем мусор» + трёхсторонний disposition (accept/verify/reject) + обязательный post-check.
- **Q2 Масштаб:** brute-force KNN держит с огромным запасом <20 мс на 100k×1024-d (замер); триггеры миграции на порядки выше нужд одной книги.
- **Q3 Корректность retrieval:** детерминированный точный матч **строго лучше** dense на дословных именах (эмпирика: substring precision 1.0, 0/4 ловушек-омографов; char-BM25 все 4 ловушки в top-5); dense/reranker/BM25 только второй эшелон.
- **Q4 Режимы отказа:** DelTA Proper-Noun-Records (first-wins-без-обновления) **сам порождает** stale/contradiction/drift; полная таблица «сценарийзащитаDET/LLM/где в коде» в реестре.
- **Q5 Детерминизм:** soft>hard по качеству (в т.ч. en→ru), но soft молча теряет 1736% терминов → **post-check обязателен**; слепой post-replace в русский — **запрет** (ломает согласование); `decl` — safety, не фича рынка.
- **Q6 Академика:** DelTA (ICLR 2025) En-центрична, LTCR-1 = самосогласованность (не корректность), слабые базовые модели, **нет zh/ja→ru**; сильнейшее переносимое — Karpinska&Iyyer 2023 (польский прокси ru), но mistranslation/omission персистят даже при идеальном контексте.
- **Q7 Вендоры/эмбеддинги:** memory-числа Mem0/Zep первоисточник не переживают (full-context бьёт Mem0; Zep 84%→58% в исправленной репродукции); эмбеддинг-дефолт **bge-m3** (R@5 0.974 vs Qwen3-0.6B 0.891 vs LaBSE 0.827); **ни одна модель не даёт разделяющего порога** (пересечение распределений) → эмбеддинги low-trust, только кандидаты на ревью.
- **Инвариант D5.2 — подтверждён кодом:** `snapshotID` (`runner.go:145-163`) не хэширует версию глоссария/context-assembly, а `RequestHash` включает `msgs` → после инъекции памяти Фазы 1 изменённый глоссарий тихо промахивается мимо чекпоинта и переоплачивает расходящимся переводом. **Общий гейт Фазы 1 (F1 реестра), закрыть ДО инъекции памяти.**
### [ПИНГИ ОРКЕСТРАТОРУ] расхождения с research/05 / Р3 / Р7
Эта сессия архдоки не правит (кроме своих 13/06) — расхождения выношу пингами:
1. **Р3/research/05 §177 «sqlite-vec нельзя, pure-Go не загрузит C-расширение» — неточно.** Верно только для `modernc.org/sqlite`; CGO-free sqlite-vec **существует** (ncruces WASM). Решение brute-force в MVP верно, но рациональ переписать («держим modernc единым драйвером», а не «pure-Go не может»). → правка формулировки Р3.
2. **Р3/research/05 §7 «один стек LaBSE на выравнивание и RAG» — опровергнуто эмпирически** (LaBSE слабейшая на retrieval, R@5 0.827). LaBSE — только Bertalign; RAG — bge-m3 (дефолт) + Qwen3-Embedding-0.6B (challenger, добавить в стек Р4). → правка Р3/Р4.
3. **research/05 §4.1 «vectorized-активация — все три нужны» — не в горячем пути** (вредна там); только второй эшелон. §5.2 «желательно без эмбеддингов» → **строго без** для дословных терминов.
4. **research/05 §4.2 DelTA / §1.2 Zep / §5.3 constrained decoding — числа/атрибуции поправить** (см. research/13 Q4/Q5/Q6): LTCR-1 = самосогласованность, не качество; DelTA-память LLM-в-цикле (не детерминированная — наша ставка нова); «структурированная память > длинный контекст» — гипотеза, не доказанное; вендор-числа Mem0/Zep убрать; «constrained decoding портит качество» overstated (реальная причина — закрытые API).
5. **Р3/Р7 усилить:** post-check из «флаггера» в **обязательный гейт** (E1/E2 реестра); спойлер-окно `since_ch/until_ch`**safety-гейт с жёстким reject+лог**, не UX-фича; добавить ось «редакционное время» ⊥ спойлер-окну (stale/drift); гейт фактичности **резюме** (у резюме нет post-check-аналога — первоклассный пробел D1).
6. **zh/ja→ru-специфика, не покрытая ни одним доком:** стандарты транслитерации **Палладий (zh)/Поливанов (ja)** (ось корректности ⊥ самосогласованности — крупнейший пробел, B6); утечка рода через **русский глагол прош. вр.** мимо `gender=hidden` (морфо-гейт Ф2 должен сканировать глаголы — C3).
### [БЭКЕНДУ] шаг «миграция памяти v2» разблокирован — с гейтами
Реестр вышел → шаг 4 можно фиксировать, **соблюдая `architecture/06` §Гейты**: (1) **F1 snapshotID под память+context-assembly ДО инъекции** (общий гейт, держит D1/D5); (2) схема D7 + `sense`, ось редакционного времени, `UNIQUE(src,sense,window)`+обратная dst-проверка, `min_key_len`+запрет одиночных ключей, нормализация NFKC/OpenCC/kana/ruby; (3) post-check обязателен, слепой post-replace в ru запрещён; (4) трёхсторонний disposition + per-chunk retrieval-state запись. **Горячий путь = НЕ FTS5** (impl-notes §3.6 уже так; FTS5 не сегментирует CJK), а детерминированный Aho-Corasick/trie. **Ставку на банк памяти НЕ морозить до in-house eval** (протокол/acceptance — research/13 §Вердикт: WMT25-трёхрежимный, baseline «банк vs длинный контекст», предзарегистрированные пороги).
### [ВЕРДИКТ ОРКЕСТРАТОРА] банк памяти — GO на схему+гейты, ставка гейтится eval'ом (параллельно, не блокер)
Валидацию принял (15 агентов + верификация + свой retrieval-бенчмарк — самый провалидированный артефакт проекта). Пинги применены в Р3/Р7 (`01-decisions.md`). Разбор надвое:
- **Схема + детерминированный горячий путь + 5 гейтов реестра — GO, low-regret.** Строим сейчас: структурированный глоссарий нужен как СУБСТРАТ для post-check-гейта («тихое→громкое») в любом случае, спойлер/род-гейты — safety в любом случае, а режим инъекции уже конфиг (`selective|full_prefix`). Даже если eval покажет «длинный контекст победил» — флипается конфиг инъекции, а не схема. Поэтому схема не гейтится eval'ом.
- **Ставка (достаточность селективной инъекции vs полный контекст + whole-book эмбеддинг-слой) — гейтится in-house eval'ом**, но eval идёт ПАРАЛЛЕЛЬНО реализации схемы, не блокирует её. Eval — часть пилотного трека (тот же голд-сет, WMT25-трёхрежимный протокол); фолдим в пилот Ф2.5, не отдельная сессия.
- Ключевая переоценка опасения владельца принята: тихую деградацию порождает не «пусто», а **ошибочная инъекция** — и мы её **конвертируем в громкую** (post-check + disposition + retrieval-state), а не устраняем обещанием. Это и есть ответ на твой страх.
- Крупнейший непокрытый пробел — **транслит-стандарты Палладий/Поливанов** (ось корректности ⊥ самосогласованности, реестр B6) и **утечка рода через русский глагол** (C3): заложены в реестр, Фаза 2.
- **Сессия «Валидация банка памяти» — задача выполнена, закрывается.** In-house eval — уже не её мандат, а пилотного трека.
> **[БЭКЕНДУ]** реестр `architecture/06` — твой контракт для шага 4 (миграция памяти v2). Порядок: **F1 (snapshotID под память+context-assembly) — ПЕРВЫМ** (общий гейт, держит D1/D5, независим от memory-вопроса — код отстаёт от impl-notes §3.2, там уже предписан версия-счётчик); затем схема v2 = D7 + добавления реестра (`sense`, ось редакционного времени, `UNIQUE(src,sense,window)`+обратная dst-проверка, `min_key_len`+запрет одиночных ключей, артефакт нормализации NFKC/OpenCC/kana/ruby); горячий путь = **Aho-Corasick/trie, НЕ FTS5** (impl-notes §3.6 уже так); post-check обязателен, слепой post-replace в ru запрещён; трёхсторонний disposition + retrieval-state запись. Режим инъекции держи конфигом (`selective|full_prefix`) — eval потом решит дефолт. Отложенное в v1.1/Ф2 (заложить поля/место, не реализовывать): Палладий/Поливанов B6, гейт фактичности резюме D1, эмбеддинг-слой A7, бэкап файла F4, морфо-гейт глагольного рода C3.
> **[ПОЛИГОНУ/ПИЛОТУ]** in-house memory-eval — дециждающий эксперимент, фолдится в пилот Ф2.5: WMT25-трёхрежимный (no / correct / **random** terminology — random-рука ловит тихую деградацию) на реальных zh/ja→ru чанках; **обязательный baseline «банк ON vs OFF» и «банк vs длинный контекст frontier-модели»** на том же стеке (DelTA этого не делала — это пробел, который решает go/no-go на ставку); мерить две оси раздельно (самосогласованность approved-форм + source-fidelity/omission через CometKiwi + LLM-судья-против-источника); ru-специфика (согласование рода вкл. глагол, склонение dst); предзарегистрировать пороги + допустимый flag-volume на главу. Эмбеддинг-бенчмарк уже сделан этой сессией (bge-m3 дефолт, `eval/retrieval_bench.py`) — переиспользуй.
> **[СЕССИЯ ЗАКРЫТА, 04.07]** Выходы: research/13 (+§«Честные слабые места»), architecture/06, `eval/memory_hotpath.py` (спека), `eval/retrieval_bench.py` (эмбеддинги). Эксп-05 снят как низкосигнальный. **Перед кодом реализующей сессии — прочитать research/13 §«Честные слабые места»:** F1 подан как решённый, но там развилка (snapshot материализует байты vs store версионирует глоссарий); post-check в русской морфологии — несущий, но невалидированный (померить до доверия как гейту); «пусто=безопасно» — размен на ложный-пропуск, который тоже тихий; ставка на детерминированный no-LLM путь — cost-driven, не evidence-driven (DelTA валидирует LLM-в-цикле). Гигиена: фоновых процессов нет, ollama полигона не тронут, `eval/.venv` дополнен (torch-cpu/sentence-transformers/openai/dotenv — переиспользуемо).
> **[ДОБАВЛЕНО после закрытия] Локалка × банк памяти — экстракция терминов, ВЕРИФИЦИРОВАННЫЙ бенчмарк (дыра G1)** → [experiments/06-local-extraction.md](experiments/06-local-extraction.md), `eval/extract_bench.py`. 13 моделей × 12 кейсов (zh/ja/en + эдж: катакана-запад, буддийские имена, алиасы), запросы через `refusal_bench.call_provider`+`providers.json` (квирки верны: deepseek thinking-ON+max_tokens 8000 — прошлый пустой был МОЯ ошибка бюджета, не свойство модели), **каждый ответ health-верифицирован** (пустой/echo не засчитан как recall 0). Итог: **(1) СПОТ сущностей решён у всех, локаль вкл.** (recall ~0.98 на всех языках, 0 галлюцинаций). **(2) РЕНДЕР dst — разрыв с ЯЗЫКОВЫМ градиентом у локали:** en 0.82 / ja 0.53 / **zh 0.26** (阿Q→«Ах-Чу», 赵太爷→«Тяо Тай-Я» — Палладий-мусор → **эмпирика для B6**); облако-топ zh 0.75/ja 0.98/en 1.0. **(3) бо́льшая локаль не помогает** (30b render 0.55≈8b, ×3 медленнее). **(4) deepseek thinking помогает рендеру** (0.85 vs 0.58 off; на экстракции thinking-off здоров — echo бьёт перевод, не JSON). Рендер-value: **gemini-2.5-flash** (0.92/1.4с). **Дизайн-следствие (уточняет Р4/G1):** спот=дешёвая 8b (все языки); рендер dst язык-зависим — zh обязательно облако/человек + таблица Палладия (B6), en локаль потянет. ruadapt ненадёжен (5/12 health).
> **[В ОЧЕРЕДИ, 05.07] Исследование «Адаптивный/обучающийся слой памяти»** — промт `docs/ADAPTIVE_MEMORY_RESEARCH_PROMPT.md` (подготовлен сессией валидации по запросу владельца). Вопрос: стоит ли гибрид «детерминированный банк + слой, обучающийся по ходу книги», и как смёржить под контур (локаль-first, дешёвое API ок, флагман без логитов → kNN-MT/frontier-LoRA заблокированы; обучаемое — только на локали, роль support, не переводчик). Центр — арбитраж «кто побеждает» (логика + VRAM 8ГБ). БАР: обязан бить eval-валидированный детерминированный базис на zh/ja→ru, иначе не мёржить. Тайминг: Фаза 2+, целить в реальные дыры (после in-house eval банка). Запускает владелец отдельной сессией.
### 2026-07-05 — Сессия «Адаптивный слой памяти» ЗАВЕРШЕНА → [research/14-adaptive-memory.md](research/14-adaptive-memory.md)
Метод: 6-направленный ресёрч + 24 адверсариальных верификатора (**19 CONFIRMED / 5 OVERCLAIM** с поправкой) + **2 исполняемые пробы на стенде/ключах** + чтение кода на git HEAD. **Вердикт: гибрид в основном НЕ стоит того; ровно ОДИН eval-гейтед кандидат.**
- **Жёсткий контур подтверждён живой пробой** (`eval/adaptive_probe.py`, 2026-07-05): kNN-MT/constrained/frontier-LoRA на флагмане **физически blocked** — kNN-MT ключует hidden state декодера (Khandelwal 2010.00710), а его никто не отдаёт; из наших только **deepseek возвращает logprobs** (top-5), **grok-4.3/gemini-3.1/gpt-5 — нет** (gpt-5 даёт 403). Даже logprobs ≠ hidden state → двойная дверь.
- **In-context демонстрации — единственный кандидат под контур, но НЕ бьёт базис по консистентности** (`eval/adaptive_incontext.py`, реальный zh→ru 阿Q, канон Рогова, N=3): без памяти 0.458 → **soft-глоссарий Р3 0.875** → глоссарий+демонстрации **0.833** (в шуме). Литература: 65% выигрыша демо — стиль (Li 2503.05010), а БАР меряет консистентность/fidelity. → **пилотировать под eval со стилевой осью, не мёржить.**
- **Локальный kNN-MT / книга-LoRA — НЕ мёржить:** чистый выигрыш kNN уже у детерминированного банка (жёсткая гарантия vs мягкая интерполяция); kNN ≈ GD только на output-projection (Gao 2305.13034) → не чинит сломанные zh-реалии локали (render 0.26); data-poor (сотни пар, LoRA «learns-less» 2405.09673).
- **Само-коррекция:** intrinsic self-correction деградирует без внешнего верификатора (Huang 2310.01798) — а он у нас **уже детерминированный** (post-check) → «детект дрейфа → коррекция» уже решено, не в обучающийся слой.
- **VRAM-гипотеза владельца (эмбеддер→CPU, 8ГБ→обучающийся модуль): верна в посылке, пуста в следствии.** CPU-эмбеддинг — правильный дефолт (real-time эмбеддинга в пайплайне нет, горячий путь = Aho-Corasick), но **обучающегося модуля, который на 8ГБ бьёт базис, НЕТ** → освобождённый VRAM отдать существующим support-ролям локали. **Реальный Pascal-замер (изолир. CUDA-env, 0.5B): QLoRA-4bit РАБОТАЕТ на sm_61 вопреки sm≥75, но ~×9 медленнее fp16-LoRA** (нет Pascal-ядер → преимущество QLoRA инвертируется); потолок удобной тренировки ~1.53B; 7B-QLoRA на/за пределом 8ГБ.
> **[РАСХОЖДЕНИЕ → оркестратору]** (1) Литература «Log Probability Tracking» (2512.03816) утверждает «все xAI/GPT возвращают logprobs» — **живая проба опровергает** (grok-4.3 нет, gpt-5 → 403): урок «проверяй пробой» подтверждён. (2) **Хорошая новость ядру:** soft-глоссарий Р3 индикативно **сильно работает на zh→ru** (0.458→0.875) — валидация банка это на нашем направлении не мерила. (3) Гипотеза владельца о VRAM — принята как инженерная гигиена, отклонена как путь к «обучающемуся модулю, бьющему базис».
> **[ОРКЕСТРАТОР → на РАСХОЖДЕНИЕ, 05.07]** Принято, расхождение закрыто. (1) Урок «проверяй пробой» — тот же, что сработал против находки exp08 про grok-reasoning (перепроверено 05.07 по xAI docs: reasoning ОТКЛЮЧАЕТСЯ через явный `reasoning_effort:none`); статус logprob-доступа занесён в provider-wiring-память. (2) Сильный сигнал soft-глоссаря на zh→ru (0.458→0.875) фолдится в in-house memory-eval пилота Ф2.5 как подтверждение направления (валидация банка его не мерила). (3) VRAM-гипотеза — согласен: инженерная гигиена (эмбеддер→CPU), не путь к обучающемуся модулю; M2 (детерминированный, 0 ML) — в банк v2.
> **[БЭКЕНДУ]** Из research/14 в банк v2 фолдится **M2 (детерминированно, 0 ML, 0 VRAM):** консистентность-кэш auto/ambiguous (first-seen/majority-vote) + precision-gated adaptive-retrieval КАКИЕ серо-зонные записи инъектить с **hard-abstention** (лучше ничего, чем мусор). Это гигиена банка, закрывает recall-0.571-дыру и B1 first-wins. **НЕ строить:** локальный kNN-MT, книга-LoRA, constrained decoding, self-correction-как-слой (всё не проходит БАР/физически blocked).
> **[ПИЛОТУ]** M1 (in-context демонстрации, серая зона) фолдится в тот же WMT25-3-режимный eval, что и банк, **+ стилевая ось** (win-rate человека/сильного судьи): критерий — бьёт ли базис по стилю БЕЗ потери консистентности/fidelity и без роста дистрактор-вреда. Индикатив этой сессии: по консистентности не бьёт; стиль не измерен.
> **[ГИГИЕНА]** Модель полигона `qwen3-abliterated:30b-a3b` (6.4 ГБ VRAM) **не выселялась** — GPU-проба шла в свободном CUDA-окне (WSL2 спилит в shared RAM), после — cleanup. Артефакты: `eval/adaptive_probe.py`, `eval/adaptive_incontext.py` (+ `eval/data/*.json`), новые доки — только `research/14`. Изолированный CUDA-env (Pascal-проба) — в scratchpad, не в репозитории. Полный потолок QLoRA-7B+reranker на **чистых** 8ГБ — за скоординированным стенд-окном (не мерил, чтоб не выселять 30b); на вердикт не влияет (кандидата нет).
> **[ДОБАВЛЕНО, 05.07 — «долбить детерминированную сторону»]** По запросу владельца (раз гибрид отклонён — максимизировать коэффициент канон-консистентности детерминированно) — замер рычагов L1→L4 на ТРУДНОМ чанке (`eval/adaptive_levers.py`, 11 сущностей, deepseek+grok), research/14 §9. **Порядок бэкенду:** **L1 post-check ЛЕММАТИЗИРУЮЩИЙ (pymorphy3), не регэксп** — ПЕРВЫМ (наивный регэксп даёт **1836% ЛОЖНЫХ флагов** на трудном чанке; pymorphy сворачивает и OOV-транслит Вана→ван; количественная валидация несущего риска research/13 §2). **L2 recall — нормализация ПОЛНАЯ+тестируемая (OpenCC, не мини-карта: живой A4-баг 爺→爷 молча промахнул 赵太爷) + alias-граф + sticky** (recall 0.00→0.50→0.75). **L3 re-ask** (deepseek 0.82→0.91). **L4 таблица Палладия (B6) — потолок ПРАВИЛЬНОСТИ.** Побочно: 钱 (односимвольный гомограф Цянь/деньги) упорно промахивается → **min_key_len/запрет одиночных ключей A3 обязателен.** Поправка §2: soft-глоссарий на лёгком чанке = **~1.0** (0.875 был регэксп-артефакт), demos не бьют — потолок. Артефакты: `eval/adaptive_reask.py`, `eval/adaptive_levers.py`. Инстинкт «тюнить ранкер» — легитимен только во 2-м эшелоне (bge-m3 без разделяющего порога), не в костяке.