64 KiB
Журнал решений оркестратора — развязки перед Фазой 1 (2026-07-04) + пост-ревью D13–D17 (2026-07-09)
Ответ на вопросы бэкенд-сессии (PROGRESS §«Вопросы от бэкенда», §«[НУЖНО РЕШЕНИЕ] перед Фазой 1») и полигона (think-режим). Каждое решение прошло адверсариальную панель из 3 критиков (research / экономика / исполнимость в коде Фазы 0); ни одно не отклонено, все уточнены. Это контракт Фазы 1 — бэкенд исполняет отсюда; при конфликте с буквой 01-decisions/02-mvp-plan — источник истины здесь (потом сольём в основные доки).
Статусы: ✅ принято · ✅+ принято с уточнением панели.
D12. Модель устойчивости к отказам (веха coverage-гейта, 04.07) — заземлена на durable-execution prior-art
4 вопроса бэкенда + большой вопрос владельца «падать ли / фолбечиться / как не терять книгу». Заземлено ресёрчем (Temporal / Step Functions / Airflow / River / Stripe idempotency / OpenRouter/LiteLLM fallback; проверено по первоисточникам).
4 вопроса — все A:
- Q1 (сегментация): порт 1:1 наивного split.
refusal_bench.py::split_sentences= источник истины (он же приёмочный оракул); Go зеркалит бит-в-бит; любое изменение — Python-first, лок-степ. §3.7 «поглощение кавычек» → v1.1 (координированно). Иначе Go-гейт и Python-оракул разъедутся. - Q2 (эскалация): минимальный single-hop. НЕ противоречит D4: D4 запрещал массовый outage-своп, а это точечная эскалация ОДНОГО чанка на детерминированном контент-провале. Нужна сейчас (DeepSeek-эхо воспроизводим). Минимально: 1 хоп → флаг; полные цепочки — шаг 7.
- Q3 (детект): только excision_suspect (нижняя граница). Верхняя аномалия-дописывание ложно флагает (ru-выход 1.4–1.9× исходника) — нужен entity-счёт+судья (Ф2); coverage_fail/D10 блокирован памятью v2.
- Q4 (активация): opt-in (
enabled:false), тестами. Боевой флип — после валидации precision владельцем на реальных чанках (порог N флагов — за владельцем); до починки диалоговой сегментации флип ложно флагал бы диалого-плотные главы. [exp07, коммит3911baf]: precision гейта = 0 ложных/57 на реальных чанках; вердикт главы — ≥2 флага→fail, 1→attention;finish_reason=content_filterне эмитит ни один из 5 провайдеров (ветка эмпирически мертва). Флипenabled:trueвсё ещё за подписью владельца.
Таксономия отказа — ТРИ класса (не бинар «фолбэк vs пауза» — это мис-фрейминг):
| Класс | Триггер | Реакция |
|---|---|---|
| Транзиентный / бюджетный | 429/5xx/timeout; finish=length/пустой |
same-model retry (ось attempt, бо́льший max_tokens); ретраятся только {length, empty} |
| Детерминированный контент-провал | echo / cjk_artifact / excision / refusal — HTTP 200! детектит app-слой post-settle, НЕ транспорт | single-hop escalation на ДРУГУЮ модель (same-model retry бессмыслен); 1 хоп → флаг; отдельная ось модели в request_hash (не attempt); escalation.budget_usd; результат ре-гейтится; канал B изолирован ТИПОМ (permissive/nil-guard в failover.go), пишет новую TM-запись (model_id в ключе) |
| Outage / системный | 503-storm, 429-исчерпание, terminal-4xx, ceiling — не per-chunk | circuit-breaker (Azure Closed/Open/Half-Open, ~30с health-окно) → пауза джобы + resume (НЕ mass-swap: D4, стиль поплывёт + TM-инвалидация); супервизор рестартит tmctl |
F3 фикс (оплаченный неидемпотентный вызов):
- Provider idempotency-key = существующий
request_hash, заморожен на входе (константа через транспорт-ретраи и resume), в заголовкеIdempotency-Keyгде поддержано. ⚠ Матрица (проверено по первоисточникам): OpenAI поддерживает; DeepSeek / xAI / Gemini / Kimi — НЕТ. Центральный стек (draft-DeepSeek, editor-grok, judge-Gemini) provider-dedup не имеет → не архитектурить F3 вокруг него. Capability-флагsupports_idempotency_keyв models.yaml (в готовый capability-слой). - Для непокрытого стека — at-most-once cap: класс «billed-but-unconfirmed» (2xx с нечитаемым НЕусечённым телом / чистый timeout после отправки) получает бюджет ≤1 доп. вызова, не
MaxAttempts−1(Temporal «maxAttempts=1 для non-idempotent»). Восстанавливает приёмку «≤1 вызов». + консервативный settle оценки (не Release) на post-send-timeout, чтобы потолок не был слеп (расширить существующийBilledDecodeError-путь); ledger-состояние AMBIGUOUS-BILLED. Честная модель — «at-most-once billed, replay бесплатен», не exactly-once (saga/exactly-once на оплаченный вызов не мапятся).
Consistency-aware fallback by stage: draft-фолбэк свободно (editor ре-нормализует стиль — 2605.13368); editor pinned per book (на отказе editor — пауза / same-family, не чужая модель); model-per-chunk логировать для последующего uniformity-пасса. Global call-budget guard: суммарные попытки на чанк = retries_on_primary + 1 fallback hop, НЕ сбрасывается на фолбэке (иначе retry×fallback = 30+ оплаченных вызовов — LiteLLM #19985).
Прогресс — единственный реальный пробел (ответ на «подсвечивать прогресс»):
tmctl status --config book.yaml— READ-ONLY проекцияchunk_status+jobs+spend+request_log(Temporal query-handler аналог; 0 LLM, 0 replay);--json(стабильные disposition/flag_reason enum как контракт) для CI/IDE.chunk_statusбэкенд УЖЕ построил — read-model есть; нет только команды и знаменателя.- Book manifest на snapshot (всего глав/чанков-на-главу) — иначе честный N/M невозможен. Вести unit-счётом (done/in-progress/flagged/skipped/pending), % только из N/M; никакого синтетического time-бара (fictional-bar анти-паттерн, Cloud Four).
- Словарь статусов (Airflow/Step-Functions): flagged≠failed (
jobs.status.failed= infra-only), skipped с upstream-reason; всегда REASON (GitLab «explain why skipped»). - Паспорт качества главы (JUnit
<testsuite>+ SonarQube gate): chunks total/ok/flagged/skipped, worst flag_reason, coverage-вердикт (pass|attention|fail по 500–2500-char порогам), $, версия — против «проклятия 300-й главы» (04-unhappy §10). - ETA от сглаженного throughput (EWMA α≈2/(n+1)), не present-state; unit-счёт ведущий, ETA вторично. Деньги в status: committed/reserved/ceiling%, F3-честный кумулятив, projected book cost = (cost/done-chunk)×remaining. Re-drivable флагнутые (Step Functions redrive), не трогать DispOK.
Не строить (cautions верификатора): distributed-движок (Temporal/Step Functions инфра — мы single-node/один файл, брать паттерны не инфру и не их HA-числа); прозрачный cross-provider fallback главного пути (D4); детектор контент-провала в транспорте (обязан быть app-слой post-settle — транспорт видит 200); real-time SSE-прогресс (Ф3, IDE вне MVP); наивный параллелизм чанков (гонка Runner.clients + «коммит терминов только на границе джоб»).
Вторая волна развязок Фазы 1 (04.07, вопросы бэкенда после survey) — D8–D11
Онбординг-поправки бэкенда ратифицированы: (1) дефолт-редактор grok-4.3 @ temp 0.4 thinking-OFF (не Kimi — «Kimi-editor 400» как повод для capability-слоя снят; живые 400 дают Gemini/gpt-5); (2) deepseek-v4-pro нигде не подтверждён → слаг канала A резолвить через /models, не хардкодить (deepseek-chat депрекейт 2026-07-24, ~3 недели — миграция черновика срочная); (3) Gemini wire-слаг gemini-3.1-pro-preview (суффикс несущий, голый → 404); (4) models.yaml на диске отстаёт — бэкенд обновляет сам (его зона); (5) F4 (усечённый length течёт в edit как OK) чинить в A, F3 (retryable-but-paid переоплата) учесть явно. A/B/C-план бэкенда принят как есть.
D8 (Q1) — memory-компонент snapshotID: content-hash материализации (не version-counter). ✅
Хэшировать детерминированно ORDER-BY-материализованное полное состояние инъектируемой памяти на старте джобы (approved-глоссарий + резюме + series-bible-lite — тот пул, из которого per-chunk селективная инъекция потом выбирает; сам per-chunk выбор детерминирован и уже покрыт request_hash через rendered messages). Drift-proof — решающий довод: version-counter (буква §3.2/D5.2) молча дрейфует, если забыли бампнуть, и переоткрывает ровно тот баг тихой переоплаты, который D5.2 закрывает. Content-hash забыть нельзя. Стоимость (хэш пула раз на джобу, не на чанк) — ничтожна, не горячий путь. Правит §3.2: memory-компонент снапшота = content-hash, не счётчик.
D9 (Q2) — приёмочная книга Фазы 1 = ja→ru ранобэ (~150k токенов). ✅+
Причины: соответствует флагманскому «ранобэ»; COGS-запас (R5 ~$3.1 стандарт vs потолок); ставит ruby/фуригану на критический путь импорта — форсирует закрытие известной дыры (04-unhappy §4), иначе отложат и забудут. Уточнение (границы ruby): извлекать чтения фуриганы при первом появлении → глоссарий-лок имени, НЕ сохранять ruby в выходной вёрстке (это остаётся ограничением epub-v1, план:25). Хедж: если полное ruby-извлечение окажется тайм-синком, блокирующим веху — принять на ранобэ, где чтения имён капчатся из первого появления обычным путём, а полный ruby-лок — fast-follow внутри Фазы 1. CJK-echo (zh) тестируется CJK-гейтом отдельно (не требует zh-приёмочной книги). Все три пары строятся; коммерческая проверка пар — пилот Ф2.5.
D10 (Q3) — знаменатель глоссарной консистентности = ВСЕ approved-термины (имена + выдуманные термины/титулы). ✅
Матчит букву R7 («гейт считает approved-термины») и — важнее — бьёт по реальной жалобе №1 читателей: коллапс терминосистемы рангов/титулов («Immortal, immortal or immortal», 04-unhappy §1) страшнее скачущих имён. Гейт параметризовать (знаменатель = вхождения src/алиасов, числитель = лемма dst по decl), names-only — как под-метрика для диагностики. Порог 98% — на детерминированном слое (pre-replace+инъекция+post-check) достижим (механизм не модель-зависим); если приёмка покажет систематическую недостижимость — ревизуем порог, НЕ знаменатель (не геймить метрику сужением).
D11 (Q4) — премиум-микс: конфиг-потолок, не гейт приёмки ✅+ — но ОБА cost-числа устарели, не только премиум.
budget_usd = R5-clamp; дефолты под селективный apex (пересчёт ВЫПОЛНЕН — exp08): ранобэ/роман $2, вебновелла — потолок-на-главу/$82) не дефолт. Приёмка держится на резюмируемости + гейтах + точности телеметрии денег, а не на конкретном премиум-числе (exp01 намерял ~$49/$26 на Sonnet-апексе — заменено exp08 на Gemini-апексе с reasoning-as-output).
Расширение за рамки вопроса бэкенда: порог стандарт-микса $0.6 ТОЖЕ устарел — он считался с дешёвым редактором (GLM/DeepSeek), а дефолт-редактор теперь grok-4.3 ($2.50/M output ≈ 10× дороже draft). Пересчёт ja→ru ранобэ: draft ~$0.065 + grok-editor apex_fraction; полный apex вебновеллы ($0.67 = **$0.73 стандарт-микс** (выше $0.6). Экономика при этом здоровая (том <$1 против якоря $100 — маржа огромна), но конкретные приёмочные числа ($0.6 стандарт, $5 премиум) оба устарели после смены редактора на grok. → Приёмка Фазы 1 по стоимости = (а) escalation уважает конфигурируемый budget_usd (тест механизма); (б) телеметрия денег точна (ledger корректно биллит grok/gemini с их квирками — grok reasoning=0 при thinking-OFF через ЯВНЫЙ reasoning_effort:none — дефолт grok = low, gemini reasoning-as-output); мягкий sanity-check ~$0.69/ранобэ (exp08), жёсткий гейт $0.6/$5 СНЯТ. Числа пересчитаны — exp08 (draft DeepSeek + editor grok + премиум Gemini).
Ре-флаг (grok как центральная модель — усилилось с D8): гигиена аккаунтов xAI критична
grok-4.3 теперь дефолт-редактор → каждый чанк каждой книги идёт через xAI. Значит: (1) дефолт-редактор продакшна — чистый xAI-аккаунт БЕЗ data-sharing (промо-$150-аккаунт с data-sharing — только eval/NSFW, реальные книги через него нельзя, research/08); (2) концентрация трёх ролей (редактор+канал B+судья 18+) на xAI — риск доступности (Р10 №6): провайдер лёг → пауза/resume (D4), премиум-редактор gemini как валидированная замена под рукой.
D1. Редактор C1 — монолингвальный. ✅+
Решение: редактор Фазы 1 видит только черновик + одобренный глоссарий (dst-термины как target-констрейнты), не исходник. Убрать {{text}} из prompts/editor.md.
Обоснование: издательская норма (редактор не знает язык оригинала — research/07); билингвальный редактор в zh→ru якорится к исходнику и плодит кальки (главная translationese-болезнь); монолингвальный редактор к тому же дешевле (исходник не сидит на входе каждого edit-вызова).
Уточнения панели (обязательны):
- Честно: coverage-гейт НЕ контролирует верность. Он ловит только omission/дописывание по длине; same-length mistranslation (свап рода, «кто кого», неверная полисемия) проходит насквозь. Значит в Фазе 1 верность после черновика не контролирует ничто до билингвального судьи Фазы 2. Это допустимо (Фаза 1 — инфраструктурная веха), но записать прямо: приёмка Фазы 1 не содержит критерия верности — не маскировать это coverage-гейтом.
- Пилот Ф2.5: плечо C1 (draft→editor) меряется на win-rate только вместе с живым билингвальным судьёй — иначе C1 по собственному признанию полирует неверное в «гладко-неверное».
- Код: убрать
{{text}}меняет SHA256 шаблона → resnapshot-гейт сработает громко (хорошо), ноprompt_version: "v0-draft"вpipeline-c1.yamlстанет врать (тот же лейбл на двух SHA). Поднять editprompt_versionпри этой правке.
D2. Диспозиция плохого чанка — skip+flag+continue. ✅+
Решение: finish=length → ретрай с бо́льшим max_tokens до капа, потом флаг; hard refusal/content_filter → флаг+продолжить; пустой оплаченный → skip+flag (не падение прогона); soft refusal (blacklist) → флаг. Флагнутый чанк не коммитит мусор/пустоту в TM.
Уточнения панели (обязательны):
attemptэтого НЕ несёт (переоценка в моём ответе). В коде Фазы 0 нет ни цикла по чанкам (chapter=1/chunk=0 захардкожены,runner.go:235), ни хранилища флагов, ни статуса «skipped/flagged»; любой ненормальный путь сейчас =SetJobStatus(failed)+return. Механика skip+flag+continue — net-new работа Фазы 1 (цикл + таблица флагов + колонка disposition, читаемая resume-путём).attempt— необходим, но не достаточен.- Тегировать
flag_reason.retry-flaggedпереатакует толькоlength/emptyна той же модели;content_filter/refusal детерминирован per-модель/канал — повтор на том же SFW-канале снова откажет и снова спишет деньги. В Фазе 1 refusal-флаги просто не переатаковать (деньги на гарантированный отказ не жечь); маршрутизация в канал B/эскалацию — Фаза 2. - Детектор вырождения перед удвоением max_tokens. У дешёвого черновика
finish=lengthчаще всего — repetition-loop; бо́льший max_tokens лишь оплачивает больше повтора (усугубляется неидемпотентными ретраями F3). Дешёвый n-gram-loop чек ПЕРЕД удвоением → при вырождении сразу флаг, без оплаты цикла. content_filterненадёжен как ветка: OpenAI-совместимый адаптер отдаётfinish_reasonсырым (httpllm.go), пробрасывают ли его DeepSeek/GLM/Kimi — не проверено. Реальная страховка — refusal-blacklist гейт, а не ветка по finish_reason. Полигону: замерить, эмитят ли провайдерыcontent_filter. [exp07: НЕ эмитит ни один из 5 — ветка эмпирически мертва, страховка = refusal-blacklist гейт.]- Edit
max_tokensсчитать от длины ЧЕРНОВИКА, не исходника (runner.go:283-287сейчас от source). Для монолингвального редактора (D1), чей вход/выход ≈ русский черновик (~1.9× токенов исходника zh→ru), оценка от source мис-сайзит бюджет и ложно триггерит length-ретрай.
D3. Эскалация. ✅+
Решение: канал A — DeepSeek V4 Pro → GLM-5.1 → апекс Gemini 3.1 Pro; канал B (18+) — Grok 4.3 основной пермиссивный тир + DeepSeek офиц. + локальная abliterated. Sonnet удалён (Anthropic — дорого); OpenAI остаётся (ключ есть) — GPT-5 nano альт черновика, GPT-5 mini кандидат в редакторы/second-opinion судьи.
Правка по xAI (04.07, вопрос владельца — xAI НЕ выведен): ретайрнулся только дешёвый Grok 4.1 Fast; сам провайдер жив, ключ есть. grok-4.3 ($1.25/$2.50) — средний тир, не «дорогой крайний». Роли Grok: (а) переводчик канала B (самый пермиссивный крупный API — стандарт R-rated); (б) судья/QA 18+ контента — не отказывается оценивать explicit, в отличие от Gemini (нужен нативный safety-off) и Claude (отказ). Ограничения: reasoning xAI аддитивный → канал B с thinking OFF, а think-ON на Grok — только после reasoning-буфера в EstimateUSD (D6.2). Промо xAI $150 за data-sharing: брать на выделенный NSFW/eval-аккаунт для PD/тест-корпуса и refusal/18+-бенчмарка (разблокирует висящую 18+ часть эксп.02) — но не гнать через data-sharing реальные/конфиденциальные клиентские книги (конфликт с ToS-гарантией и zero-retention режимом B2B, research/08).
Правка редактора (04.07, эксп.04 полигона — бейк-офф): дефолт-редактор Фазы 1 = grok-4.3. Слепой бейк-офф glm-4.6 / kimi-k2.6 / gemini-3.1-pro / grok-4.3 на 4 фрагментах (2 фронтир-судьи, сверка с каноническими ru-переводами, согласие независимо): grok-4.3 — ранг-1 верность, ранг-2 стиль, самый дешёвый+быстрый (~13с без reasoning) → лучший value «одной модели на роль». gemini-3.1-pro — лучшая проза → премиум-эскалация редактора. GLM-4.6 слабейший (опровергает допущение Р4 «редактор=GLM»; перемерить при GLM-5), Kimi худший value (~11k reasoning-ток./абзац, ранг-последний по верности) → оба сняты с дефолта редактора. Это закрывает вопрос бэкенда №2 (дефолт редактора). Оговорка: LLM-судьи на коротких фрагментах — провизорный дефолт Фазы 1; эксп.04 кормил редактор БИЛИНГВАЛЬНО (исходник+черновик), а боевой редактор D1 — МОНОЯЗЫЧНЫЙ (только черновик) → рейтинг grok на моноредактуре строго не перенесён (exp08 §Ограничения, Quality-transfer риск), проверяется в пилоте; финальный выбор редактора/ядра — человеческий пилот Ф2.5. Р4 обновлён. Следствие: grok-4.3 стал центральной моделью (редактор SFW + канал B + судья 18+) — гигиена аккаунтов xAI на три использования (Р4), редактор с thinking OFF через ЯВНЫЙ reasoning_effort:none (дефолт grok = low; ledger чист).
Уточнения панели (обязательны):
- Часть моделей ОТСУТСТВУЕТ в конфиге (частично закрыто на 05.07). Заведены с тех пор:
grok-4.3+ провайдерxai(commit636919c);deepseek-v4-proподтверждён живьём и по цене ($0.435/$0.87). Ещё НЕ заведены: провайдерыgemini/openai, моделиdeepseek-v4-pro/glm-5.1/gemini-3.1-proвmodels.yaml; цепочки эскалации всё ещё[kimi-k2.6]-заглушки; редактор всё ещёglm-5. Задача бэкенда (см. промт консолидации): завести недостающие провайдеры+модели+цены и заменить заглушки цепочкой D3.- ПОПРАВКА (принял корректировку бэкенда): «без новых адаптеров» было оптимистично. Провайдеры OpenAI-совместимы по эндпоинту, но не по телу запроса: текущий
openAIRequestвсегда шлётtemperature+max_tokens, а Kimi требуетtemperature: 1(иначе 400), gpt-5-mini —max_completion_tokensбез temperature +reasoning_effort: minimal, Gemini 3.1 Pro — обязательный thinking (thinking_budget: 0→ 400). Это не строчка в yaml, а per-model capability-слой в адаптере, и он нужен раньше D3: Kimi — уже альтернативный редактор Р4, edit-стадия на temp 0.4 даст 400 на первом вызове. → Capability-слой — фундаментальный элемент Фазы 1. Форма (согласована с принципом «модели/цены только в конфиге», Р4): каждая модель вmodels.yamlдекларирует возможности —budget_field: max_tokens|max_completion_tokens,temperature: send|omit|locked:1,reasoning_control: none|extra_body_disable|effort_minimal|mandatory; адаптер строит тело запроса по ним.experiments/00-provider-quirks.md— эталонная таблица квирков.
- ПОПРАВКА (принял корректировку бэкенда): «без новых адаптеров» было оптимистично. Провайдеры OpenAI-совместимы по эндпоинту, но не по телу запроса: текущий
- Премиум-бюджет $5/$30 УСТАРЕЛ — выведен из калибровки на Sonnet $3/$15. Апекс теперь Gemini 3.1 Pro ($2/$12 ≤200k) с обязательным thinking (reasoning биллится как output $12/M — тот же класс недоучёта, что сжёг vojo 30–44%). Плюс
batch −50%к inline-эскалации неприменим (последовательна из-за STM), только к судье/QA. Плюс Gemini = и апекс, и судья → эскалированный чанк платит Gemini дважды (перевод+ре-джадж), оба с форсированным reasoning. Полигону: пересчитать бюджет на фактическом Sonnet-free стеке с reasoning-as-output, batch только на судью. До пересчёта — $-потолок конфигурируемый (D-эконом ниже), дефолты $5/$30 держим как консервативную заглушку.
D4. Provider-fallback — НЕ добавлять для облачных draft/edit. ✅+
Решение: авто-кросс-провайдерного фоллбека для облачных ролей нет (фоллбек драфта = разный стиль/термины по чанкам + model_id в ключе TM обнулит хиты на ре-ране). Провайдер лёг → durable pause → resume. Локальный→облако failover из vojo — только для local-ролей, channel-aware. Ночь — супервизор перезапускает tmctl.
Уточнения панели (обязательны):
- Channel-aware изоляция в коде НЕ обеспечена (дыра).
FailoverConfigне имеет поля канала/пермиссивности — изоляция сейчас лишь doc-comment для вызывающего; сам failover в Фазе 0 не подключён. Хуже: ветка «fallback отсутствует → fail loud» сделает nil-panic (нет nil-guard,c.fallback.Completeразыменует nil), а путь «пустой local-контент → облако» — ровно тот сайлент-шип, о котором предупреждает заголовок, без guard. При подключении failover (Фаза 2): изоляцию канала B делать типом (поле permissive/channel) или явной fail-loud веткой на nil-fallback, а не комментарием. - Формулировка «resume бесплатен» переусилена: техдолг F3 — retryable-но-оплаченные вызовы не идемпотентны, resume может переплатить прерванный in-flight (до
MaxAttempts−1). Точнее: «resume переоплачивает максимум прерванный in-flight, всё равно кратно дешевле mixed-model failover». - Local→cloud failover для local-ролей канала A (экстракция глоссария, дешёвый судья-гейт) при OOM 8GB GPU молча превращает $0-вызовы в платные облачные — un-budgeted; пометить (телеметрия должна показывать, когда local-роль ушла в облако).
D5. Онгоинг Analyst — инкрементально. ✅+
Решение: book-brief заморожен; новые главы — Analyst инкрементально расширяет резюме и ищет новые термины; approved-глоссарий/series-bible наследуются read-only, новые термины append, approved не ревизуются молча (research/07); разрешение gender=hidden-твиста — ручное событие.
Уточнения панели (обязательны):
- Проактивная эвристика
gender=hidden. Онгоинг структурно теряет преимущество «книга целиком видит твист заранее»: инкрементальный Analyst не видит ещё не загруженных глав, поздний реверс-трап (女扮男装) → уже вмороженные главы закоммитили род. Митигация: когда Analyst в загруженных главах видит намеренную неоднозначность (омофонное ta / pro-drop без дизамбигуации), ставитьgender=hiddenи гнать безродовые конструкции (гайд ООН) до раскрытия, а не дефолтить в мужской (TACL-биас). Плюс ретро-патч-протокол «с тома N — так» с показом стоимости пере-перевода вмороженных глав, которые твист фальсифицировал. - КРИТИЧНО (impl):
snapshotIDне покрывает память и сборку контекста. Сейчас хэширует только brief_hash + план стадий + defaults, не context-assembly (glossary_injection/stm_depth/overlap) и не инъектированный глоссарий/резюме/series-bible. Как только Фаза 1 начнёт инъектить память вmsgs: изменённая память меняетrequest_hash(msgs в нём), ноsnapshotIDне меняется → resnapshot-гейт не сработает → ре-ран старой главы молча промахивается мимо чекпоинта и переоплачивает расходящимся переводом — ломается сам инвариант Р6, на который D5 опирается. Свернуть memory-state + context-assembly hash вsnapshotIDДО того, как приедет инъекция Фазы 1. Это общий гейт Фазы 1 — держит и D1 (глоссарий редактору), и D5.
D6. Think-режим — не глобальный дефолт, но пилотить на переводчике. ✅+ (существенно переписано)
Решение: reasoning_effort per-роль, дефолт off/minimal для draft/edit — но по операционным причинам (эмпирика полигона: GLM ×3 таймауты, Gemini жрёт max_tokens, gpt-5-mini выжигает бюджет — 00-provider-quirks), НЕ потому что «reasoning вредит переводу».
Переписанное обоснование (панель отозвала мою посылку): прежняя «think ломает роль переводчика — пустой вывод» — отозванная находка: PROGRESS:230 исправляет её («пустота — артефакт тесного контекста, не зависание; с ctx 16k think завершается и реально чинит реалии: 羅生門→Радзёмон, чтение 朱雀»). DRT (research/03, arXiv:2412.17498) независимо показывает: long-CoT над метафорами/сравнениями поднимает литперевод — это роль ПЕРЕВОДЧИКА. Владелец был прав в гипотезе.
Уточнения (обязательны):
- Пилот Ф2.5 think-ON vs OFF по качеству включает draft/translator и editor (не только Terminologist+эскалацию, как я ошибочно сузил) — именно туда указывают и полигон, и DRT. Дефолт-off остаётся до результатов пилота.
- Скоуп think-ON эскалации — только subset-billing провайдеры (deepseek/zai/kimi, где reasoning ⊆ completion ≤ maxTokens,
EstimateUSDпокрывает). xAI/Grok исключить из think-ON покаEstimateUSDне резервирует явный reasoning-бюджет (additive reasoning xAI → «потолок пробьётся» ровно на премиум-пути канала B). - Gemini-апекс/судья — форсированный think-ON (не чтит
reasoning='off'→ HTTP 400). Заложить его в бюджет как reasoning-as-output ($12/M), а не как opt-in.runner.goшлётst.Reasoning— адаптеру Geminioffпридётся молча глотать; этот кейс назвать явно. - «×2–3 COGS» занижает многословных ризонеров: Kimi-k2.6 ~11k reasoning-ток./абзац = ×4…×20 на output этой роли — учесть в бюджете эскалации.
D7. Схема банка памяти v1 — скоуп. ✅+
Решение (подтверждаю рекомендацию бэкенда с двумя правками):
- v1 (store v2-миграция): база Р3 (
src, dst, type, aliases, gender, speech, decl, since_ch/until_ch, status, note) + alias-граф (типы: имя/цзы/хао/прозвище/титул) +gender=hidden(until_ch)+translit_policy(западные имена через катакану —04-unhappy §9) +first_person+ series-bible-lite = gender + ты/вы. - Правка 1 (панель D5): ты/вы в series-bible-lite — журнал событий переходов, а не статичная матрица пар (переход ты↔вы — сюжетное событие,
12-ru-target §2). Полеgender— с проактивной установкойhiddenAnalyst-ом на неоднозначности (D5.1). - Правка 2:
nickname_translationоставить в v1 (это одна колонка + лок «перевести раз навсегда»,04-unhappy §1относит в Фазу 1); дорогая только логика первичного перевода сильной моделью — её можно отложить, но поле держать. - Отложить в v1.1:
ranked-set(инъективность ступеней), словарь эвфемизмов, число-словарь мер/разрядов (сам число-гейт — Фаза 1, а словарь конвертаций — v1.1). - Обязательно: сверка с «Следствиями для плана»
04-unhappy-paths; иsnapshotIDпокрывает состояние памяти (D5.2) — иначе схема памяти без хеша в снапшоте молча ломает resume.
Q3/Q4 бэкенда — прямые ответы
- Q3 (эскалационный дефолт RU-контура): см. D3 — не-Anthropic, дёшево-первым (DeepSeek Pro/GLM-5.1), апекс Gemini; Sonnet не дефолт (удалён). В будущем зарубежном контуре премиум-эскалация опциональна, но не сейчас.
- Q4 (per-role provider-fallback): см. D4 — нет для облачных draft/edit; pause/resume; local→cloud только для local-ролей, channel-aware типом.
Требования Фазы 1, не покрытые 6 решениями (из «missed» панели) — в скоуп
- Runner без цикла по чанкам/главам — главный длинный шест (chapter/chunk захардкожены). Цикл + хранилище флагов + disposition-колонка — фундамент, на который опираются D2, D5, гейты, эскалация. Строить первым.
snapshotIDрасширить memory-state + context-assembly hash ДО инъекции (см. D5.2) — общий гейт.- ruby/фуригана-парсер в спеку импорта Фазы 1 (детерминированная часть,
04-unhappy-paths §4). Противоречие с планом:25 («epub v1 фуригану не сохраняет») разрешить: для ja→ru фуригана несёт авторские чтения имён → глоссарий-лок; молчаливая потеря подрывает приёмку ≥98% консистентности ja-книг. Извлекать чтения на инжесте (не сохранять инлайн-разметку, а выхватить ruby в глоссарий). - Дешёвые детерминированные гейты Фазы 1 (были в
04-unhappy-paths §6/§9, но выпали из плана): линтер тире-диалогов (Розенталь §47–52), ёфикатор, блок-лист транслит-междометий, число-гейт разрядов 万/億. Самый дешёвый и заметный читателю класс — «максимум воспринимаемого качества за минимум денег». Морфозависимые (канцелярит) остаются Фазой 2 (Python-сайдкар); эти четыре — детерминированные, Go, Фаза 1. - Экономика инвалидации TM (
[НУЖНО РЕШЕНИЕ] п.2в): смена параметров чанкера = полная инвалидация «как смена brief» с показом стоимости — да, подтверждаю (ключ TM от src-чанка, перечанкование by design инвалидирует; пользователю показывать $ пере-перевода). prompt_version и model_id в ключе (уже зафиксировано Р6) означают: правка промпта обнуляет TM-библиотеку, эскалация пишет новую запись — это осознанная плата за корректность, не баг.
Экономические открытые пункты (полигону, гейтят достоверность бюджета)
- Пересчёт премиум-бюджета на Sonnet-free стеке с reasoning-as-output (D3.2), апекс Gemini 3.1 Pro (форсированный thinking).
Проброс cache-hit/batch RU-агрегаторами— СНЯТО (коррекция владельца 04.07: EU-SaaS, прямые ключи, BYOK отменён; см. Р5). Вся cache/batch-экономика теперь по прямым ключам без оговорок — это канон.budget_usd: 0вpipeline-c1.yaml— заглушка; $-потолок владелец задаёт по ценовому намерению, дефолты $5/$30 держим до пересчёта.
Пост-ревью решения D13–D17 (2026-07-09, оркестратор)
Ратификация выводов стратегического ревью 07-strategic-review.md (метод: 14 сборщиков + 9 адверсариальных верификаторов, 8 CONFIRMED / 1 PARTIAL). Владелец подтвердил курс 09.07 (вкл. «Rust — нет, не сейчас»: Р1/Go остаётся; вопрос закрыт до пост-пилота и требует конкретного триггера, где Go упирается). Каждое решение ниже — контракт для следующих сессий «Бэкенд»/«Полигон»; хендофф-промты выдаёт оркестратор.
D13. Пилот Ф2.5 — поправки протокола (гейтят валидность главного решения). ✅
Дополнения к experiments/09-pilot-protocol.md (полигон вносит в док и харнесс ДО пре-регистрации):
- Новый арм: «моно vs билингв редактор на ОДНОЙ модели, простой general-промпт» — прямой тест D1. Основание (верифицировано по PDF arXiv:2605.13368, вкл. en→ru): monolingual-рефайнмент теряет accuracy с ПЕРВОГО прохода (−2.2…−5.6 MQM у всех 6 моделей), general-рефайнмент С исходником даёт тот же fluency при accuracy ~flat и лучшем overall. Существующий 7-bis (моно-бейкофф МОДЕЛЕЙ) сохраняется — это другой вопрос.
- C2 — только с ГЕТЕРОГЕННЫМИ кандидатами (draft-кандидаты от разных моделей, не N сэмплов одной): на гомогенных селекция ≈ монета (2603.20324: WR 0.512 homogeneous; LitMT 2606.05924: best-of-8+судья — последнее место). Иначе плечо C2 предрешено и жжёт бюджет впустую.
- Панель судей — переконфигурация: (а) 2–3 семейства максимум — 9 судей ≈ 2 эффективных голоса (2605.29800), лучший одиночный ≥ панели; (б) 11+ повторов на вердикт со свапом позиций A/B — одиночный прогон нестабилен (13.6% флипов, парафраз меняет исход в 25%; 2606.13685); (в) агрегация медианой/Bradley-Terry (JP-TL-Bench-паттерн), не средним; (г) grok исключён из судейства grok-редактированных выходов (нарушение собственного анти-self-preference правила §5); (д) валидация судьи — по κ против человеческого IAA + tie-rate/top-1 within-prompt (2603.12520), не по средней корреляции.
- Пре-регистрация расширена: MDE/мощность (число BWS-наборов), N аннотаторов ≥3 (при «минимум владелец» κ неисчислим — тогда честно писать «безκ-режим»), развести имена: C0–C3 = конфигурации ядра, M0–M3 = режимы терминологии memory-eval (коллизия имён в exp09 устранена).
- Харнесс чинится ДО решающего прогона (верифицированные дефекты): memory_eval — стрип/запрет эха глоссарий-преамбулы, сохранение ПОЛНЫХ выходов (не out[:160]), реализация fidelity-оси (без неё правило «M3 роняет vs M0» непроверяемо; текущий индикатив ЗАНИЖАЕТ вред неверной инъекции — chunk1-C3 надут эхом); оценочные артефакты — пере-рандомизация меток по фрагментам, ключ/цены ВНЕ артефакта (слепота exp04 была структурно сломана: ключ лежал в том же документе при LLM-оценке). Инструменты: Pearmut (2601.02933) вместо самописного BWS-тулинга — оценить перед постройкой своего.
- Think-арм grok-редактора требует reasoning-буфера в
EstimateUSD(D6.2) — иначе экономически главный think-вопрос пилот не ответит; бэкенду заложить до прогона.
D14. Канал B (18+) — ревизия состава. ✅
- DeepSeek ВЫВЕДЕН из explicit-части канала B: ToS DeepSeek (upd 2026-03-27) §3.4(5) прямо запрещает «pornographic, obscene, or sexually explicit (e.g., sexual chatbots)» — верифицировано по первоисточнику. Для violence-фрагментов (не sexually explicit) DeepSeek остаётся допустим. Интерим D3 «DeepSeek офиц. + локальная abliterated» сужается до «локальная abliterated + Grok».
- Mistral — кандидат-фолбэк канала B: Usage Policy (eff. 2026-06-11) не содержит бланкетного запрета adult-текста (только CSAM/NCII/эксплуатация) — верифицировано по первоисточнику. Полигону: прогнать refusal/excision-пробу Mistral на explicit-корпусе, бэкенду — слот в конфиге при положительной пробе.
- Обоснование xAI поправлено: «цитата Маска про R-rated текст» — на деле про Grok Imagine (картинки); опора — сам AUP xAI (нет бланкетного запрета adult-текста; запрещены CSAM и порно реальных лиц). Позиция стабильна на 09.07, но политика xAI волатильна — мониторинг остаётся.
- 18+ эмпирика — единственный critical ревью: refusal/excision на explicit-корпусе (Grok/Mistral/abliterated) + качество Grok-судьи 18+ + поведение Gemini-судьи на explicit — обязательная рука exp02/пилота. Гейтится фрагментами от владельца.
D15. Resume-экономика и онгоинг. ✅
Верифицировано исполнением: snapshotID вшит в RequestHash → любой --resnapshot (флип гейта, append approved-терминов, бамп версии классификатора) переоплачивает ВСЮ книгу, включая байт-идентичные запросы; redrive флагнутых нет. Решения:
- Текущий all-or-nothing ПРИЕМЛЕМ для статичной приёмочной книги Ф1 (гейт громкий, расхождений не бывает) — НЕ чинить до приёмки.
- Онгоинг-режим (
add-chapters, сегмент «ИИ-фабрик») ГЕЙТИТСЯ одним из двух: content-addressed переиспользование чекпоинтов (msgsContentHashуже существует —render.go:233-249) ИЛИ селективный redrive. Бэкенду: спека-дизайн (не код) в ближайший пакет; реализация — Ф1.5. - Немедленно (в ближайший бэкенд-пакет): исправить лгущие комментарии
runner.go:156-160/coverage.go:29-33(«re-classify for FREE» верно только внутри неизменного снапшота);tmctl status+ redrive флагнутых — приоритет D12-хвостов подтверждён (status → redrive → F3); бампнуть editprompt_version(D1-уточнение №3 не исполнено — один лейблv0-draftна два SHA).
D16. Банк памяти — фиксы границ доверия (4 верифицированных дыры). ✅
Ядро (F1/нормализация/спойлер/детерминизм/инъекция) ревью подтвердило чистым; все находки — на границах доверия, каждая воспроизведена временным Go-тестом:
- Полисемия same-src: две approved-записи (один src, разные sense/dst, пересекающиеся окна) инжектятся ОБЕ как CONFIRMED + post-check даёт гарантированный confirmed-miss (с гейтом ON — детерминированный livelock чанка). Фикс: fail-loud на пересекающихся окнах разных sense в
loadGlossarySeedИЛИ даунгрейд обоих совпадений в AMBIGUOUS. (memory.go:198-204,299-306;memseed.go:155-163) - Sticky-апгрейд: collision-prone AMBIGUOUS попадает в activeIDs без disposition (
memory.go:323) → в следующем чанке sticky даёт status-based CONFIRMED, минуя post-check, прямо в редакторские констрейнты. Фикс: наследовать disposition исходного матча в sticky-кэрри (или не класть не-CONFIRMED в activeIDs). ⚠ Это был ложно-негативный отсев 44-агентного ревью (0/3) — рациональ «sticky несёт установленный в сцене термин» не проверялась на коллизионном входе; бэкенду выборочно перепроверить остальные отсевы того ревью. - Source-граница для фонетических ключей ≥4:
rose(approved) фаерится CONFIRMED внутриroseanne— collision-даунгрейд покрывает только ≤3, Aho-Corasick границ не знает, target-сторона границу имеет (асимметрия). Фикс: script/word-граница на source-стороне для фонетических скриптов. - Ruby-чтение не матчится: для ручных терминов чтение выбрасывается (
memseed.go:217-220), у auto-кандидатов surfaces строятся только при непустом dst → ja-чанк с именем каной даёт 0 матчей. До реализации B6: ruby-reading → auto-alias ручного термина; интерим — обязательный пункт чек-листа подготовки ja-книги: kana-написания сид-имён вносить als aliases руками. Плюс: kana-precision замер (minKeyLenPhonetic=3 — «консервативный дефолт до замера») — полигону, расширение E1-протокола; C4-автозаполнениеdeclостаётся Ф2, но признаётся условием реалистичности жёсткого postcheck-гейта.
D17. D1 (монолингвальный редактор) — статус понижен до «дефолт Ф1, оспорен внешним замером». ✅
D1 остаётся дефолтом Фазы 1 (менять конфигурацию до пилота не будем — kalki-риск не опровергнут, а вакуум верности Ф1 уже признан D1.1). Но: (а) сильная форма обоснования («исходник в контексте редактора ⇒ кальки») понижена до гипотезы — подтверждений в литературе 2025–26 нет, кальки документированы как болезнь ДРАФТА; (б) экономический довод слаб (билингв-редактор = +15–20% стандарт-микса ≈ +$0.10–0.14/ранобэ); (в) решает пилот-арм D13.1. Если арм покажет паритет верности при моно — D1 подтверждается дёшево; если налог на верность воспроизведётся — флип на «редактор с исходником, простой промпт» дешевле любой альтернативной митигции.
Ратификации по итогам внешнего ревью двух пакетов (09.07 вечер, оркестратор)
Оба пакета (бэкенд D15/D16, полигон D13-харнесс) прошли внешнее ревью оркестратора (7 ревьюеров, всё исполнением: моки, мутационные реверты, CLI-прогоны $0, пересчёт данных). Вердикты: оба ACCEPT_WITH_FIXES, залендены (153277e, 9afea37) — блокеров на дефолтном конфиге нет, деньги/корректность целы. Решения:
- D16.3-дивергенция бэкенда (kana/Han без source-границы) — РАТИФИЦИРОВАНА. Кана-граница рушит recall (すずきは-класс: TP 15→1 — независимая эмпирика полигона, exp09 §6-bis), homograph-класс длино-инвариантен и границей не лечится. Митигация kana-омографов — POS/known-word-гейтинг или ruby-якорь → скоуп B6 (вместе с Палладий/Поливанов-валидатором). MIN=3 для фонетических ключей ратифицирован как дефолт (kana-замер полигона; precision там trap-set-относительная — не продовая метрика).
- Спека D15.2 — направление ратифицировано, реализация ЗАБЛОКИРОВАНА до доработки (3 дизайн-дыры ревью): (а) fast-path-гард обязан покрывать ВЕСЬ wire stage-план (текущий драфт теряет model/temp/reasoning/maxTokens-деривацию → смена temperature или reasoning low→none тихо отдаёт stale-текст — ре-открытие F1); (б) расщепление memory_version (wire vs verdict) — ОБЯЗАТЕЛЬНО, не «опционально» (иначе append-термина/toggle гейта = переоплата книги, главный сценарий не материализуется; подсказка ревью: postcheck пересчитывается вживую и в chunk_status не хранится — memory_version можно целиком убрать из ключа вызова); (в) замена loud-гейта согласия — pre-flight dry-run «N чанков, ~$X» с порогом явного флага (Р6-класс согласия на трату не демонтируется без замены). Плюс: полевой маппинг всего снапшота (wire/verdict/dropped), судьба chunk_status.snapshot_id/status-ридеров, sequencing миграции ДО первой онгоинг-книги, blast-radius append-а моделировать со sticky+eviction+каскадом стадий.
- D14.2 Mistral: refusal-часть ПРИНЯТА (11/11 ok, провенанс на месте), fidelity-числа (85–95) НЕ приняты — сырых выходов и судейских вердиктов в репо нет (провенанс-обещание не выполнено); пере-прогнать с персистом до финализации D14.2. Explicit-часть — ждёт фрагменты владельца.
- Pearmut — отказ ратифицирован (нет BWS); инструмент пилота = тонкий свой + Potato-фронт + attention-checks.
- Новые задачи бэкенду (следующий пакет): (а) GB18030-детект/конверсия в ingest (реальные zh .txt — не UTF-8; укусит на первой живой книге); (б) homophone first-wins — major ревью: при двух ручных омофонах (разные dst, чтение ≥4 каны) алфавитно-первый получает авторитетный kana-алиас CONFIRMED (attachRubyAliasesToManual видит коллизию только вторым проходом; группировать чтения по нормализованному ключу МЕЖДУ базами до аттача); (в) закрепить мутационно инвариант redrive «DispOK-стадии не сбрасываются» (тест с флагом на ПОСЛЕДНЕЙ стадии; сейчас мутант выживает) + тест --reason-селектора; (г) snapshot-чек ДО ResetChunkStages (сейчас громкий отказ redrive уничтожает флаг-телеметрию); (д) minors: --json exit-код при флагах, developer-подсказка для gate-промоченного glossary_miss (redrive-тупик), README «миграции v1–v6», ETA→EWMA или пометка отступления.
- Новые задачи полигону (следующий пакет): (а) зеркало ↔ Go: дозеркалить suppressUnboundedPhonetic (D16.3) и апостроф-фолд memnorm-v3 (оба продемонстрированы расхождением; критично для en→ru руки пилота); (б) эхо-детектор — ловить хвостовой/встроенный эхо-глоссарий, не только преамбулу; (в) Mistral-переснятие с персистом (п.3); (г) байт-синк заголовка инъекции с Go (⟨проверить⟩-пояснение); (д) minors: ts в refusal-записи, «508→500» trad2simp-дедуп/пометка, in-file карантин старых C-меточных данных.
- Гигиена:
*.key.jsonдобавлен в .gitignore (остаточный риск утечки ключа слепоты); правило git-координации мультисессий внесено в CLAUDE.md (инцидент: перезапись истории оркестратором при грязном дереве полигона — недопустимо без сверки чужих правок).
Сопутствующие правки доков (оркестратор, 09.07)
02-mvp-plan.md → v3 (мёртвые пороги/интерим-18+/фазовые списки синхронизированы с D-логом); обе *.puml → v3 (убраны Opus/BYOK/«≤2×», дорисованы ре-гейт эскалации, три класса отказов D12, человек в петле, фазовые пометки); superseded-баннеры на research/01, 02, 03, 04, 09; провенанс-шапки на research/12-architecture-as-antipattern.md и 12-common-failures.md (происхождение не зафиксировано — до уточнения владельцем числа оттуда не абсорбировать как факты); закрытые промты → docs/archive/prompts/; онбординг: корневой CLAUDE.md + backend/README.md + eval/README.md.