42 KiB
Реестр рисков банка памяти (v1, 2026-07-04)
Выход сессии «Валидация банка памяти» (промт docs/archive/prompts/MEMORY_RESEARCH_SESSION_PROMPT.md). Это вход для бэкенд-сессии перед фиксацией схемы store/глоссария Фазы 1 (шаг 4 «миграция памяти v2» держится до этого реестра — §Память (с D31 в ../archive/PROGRESS-2026-07-04-10.md), D7).
Метод: многоагентный ресёрч по 7 направлениям + независимая адверсариальная верификация каждой находки по первоисточникам + локальный эмпирический бенчмарк retrieval на реальном PD-корпусе (eval/retrieval_bench.py, eval/data/retrieval_bench/) + чтение реального кода backend/. Полный разбор с источниками и датами — docs/research/13-memory-bank-validation.md. Продуктовый код здесь не пишется — реестр описывает требования к нему.
Главный вывод для чтения таблицы. Опасение владельца («retrieval вернёт пусто/мусор → перевод деградирует тихо») уточнено литературой: пустой retrieval — нормальное и безопасное состояние детерминированного горячего пути (большинство чанков законно не содержат ключей глоссария); откат к базовому поведению модели. Реальная тихая деградация — это ошибочная инъекция (омограф/короткий алиас/спойлер-утечка/низкорелевантный эмбеддинг-сосед): подсунутая строка глоссария работает как мягкая инструкция, и сильная модель ей послушно следует — уверенность растёт, а точность падает (arXiv 2510.00829). Поэтому вся защита строится на двух принципах: «лучше ничего, чем мусор» (не добивать токен-бюджет соседями — arXiv 2401.14887, 2310.01558) и точность важнее полноты на горячем пути, плюс обязательный детерминированный post-check как главный (и почти бесплатный) детектор тихой деградации.
Легенда
- Слой защиты:
DET— детерминированный код (горячий путь или батч, без LLM);LLM— вызов модели (только батч/раз в главу, никогда не в горячем пути инъекции);HUMAN— ручное подтверждение/политика. - Вер./Тяж.: вероятность (В/С/Н) и тяжесть (🔴 критич. / 🟠 высокая / 🟡 средняя). 🔇 = тихая деградация (проходит без явного сигнала — приоритет владельца).
- Фаза: по плану MVP (1 = «перевод книги целиком», 2 = Python-сайдкар/эмбеддинги/судьи).
- Статус: ✅ закрыто дизайном v2 · 🔶 требует уточнения/новой работы в схеме или коде · ❌ дыра, действие обязательно до фиксации схемы.
A. Горячий путь: robustness инъекции памяти
| # | Сценарий отказа (как ломает перевод) | Вер./Тяж. | Механизм защиты | Слой | Где в коде/схеме | Фаза | Статус |
|---|---|---|---|---|---|---|---|
| A1 | Пустой/слабый retrieval трактуется как ошибка → пайплайн «добивает» бюджет ближайшими эмбеддинг-соседями или фоновыми записями → near-miss дистрактор роняет качество (до −67%, 2401.14887; NLI-фильтр спасает, 2310.01558) | С / 🟠🔇 | «Лучше ничего, чем мусор»: на пустом ключевом матче инъектить только активные sticky-записи; бюджет допустимо недозаполнить; фильтр по точности перед сортировкой по приоритету (не только approved>auto) |
DET | сборщик контекста (render.Messages, инъекция между system и user, render.go:133-136) |
1 | 🔶 добавить precision-gate; в research/05 §5.2 бюджет заполняется по приоритету, не по точности |
| A2 | Ошибочная инъекция (омограф/короткий алиас/низкорелевантный сосед) → модель послушно следует мягкой инструкции, уверенность растёт, точность падает (2510.00829) — главный источник тихой деградации | С / 🔴🔇 | Трёхстороннее явное решение на каждую запись-кандидат: CONFIRMED (точный ключ/лемма, approved, спойлер-валидна) → авторитетно; AMBIGUOUS (короткий/общий алиас, коллизия поверхности, auto/draft) → инъекция с явной пометкой «unverified — проверить» + принудительный post-check; REJECT → выкинуть и залогировать. Паттерн CRAG (accept/verify/reject), но каждая ветка наблюдаема |
DET | сборщик контекста + disposition-запись |
1 | ❌ спроектировать трёхсторонний disposition; сейчас инъекции нет вовсе |
| A3 | CJK-подстрока срабатывает на чужом смысле (阿Q, 送灶-обряд vs «送到灶», 炎=пламя vs имя 萧炎, 道/气/修 полисемия) → инъекция неверной записи | В / 🟠🔇 | Запрет одиночных Han/каны/латинской буквы как самостоятельного ключа (schema-констрейнт, не соглашение); longest-match; замена только целой сущности; условные judgment word (GalTransl post-dict). Эмпирика (retrieval_bench): точный многосимвольный подстрочный матч — precision 1.0, 0/4 ложных срабатываний на этих ловушках; char-BM25/фаззи — все 4 ловушки в top-5 → фаззи/одиночные ключи на горячий путь не пускать |
DET | матчер ключей; glossary.min_key_len per-язык; поле sense |
1 | 🔶 ключевая гигиена как констрейнт схемы (новое) |
| A4 | Молчаливо-пустой матч из-за орфографии (упрощ./трад. 鲁/魯, полу/полноширинные, кандзи↔кана 鈴木/すずき, ruby-чтения) → ключ есть в тексте, но не в той форме → запись не инъектируется | В / 🟠🔇 | Обязательный слой нормализации перед матчем (NFKC + OpenCC упрощ./трад. + kana-folding + захват ruby-чтений), симметрично к ключам/алиасам и тексту чанка; версионированный тестируемый артефакт | DET | pre-match нормализация (связать с pre-replace GalTransl); поле aliases |
1 | ❌ в research/05 §5.2 нормализация матчинга не описана — самый вероятный баг «тихо пусто» |
| A5 | Местоименные чанки (имя не встречается, только «он/她/彼») → нужная запись не активируется | В / 🟡 | Sticky scene-inertia (персонажи из предыдущих 1–2 чанков остаются); это состояние, а не retrieval — не решать эмбеддингами | DET | sticky-состояние сборщика | 1 | ✅ (в дизайне; см. World Info sticky) |
| A6 | Lost-in-the-middle: глоссарий закопан между стопкой резюме книги/арки/главы | Н / 🟡 | Авторитетный блок глоссария — рядом с чанком (конец промпта), не в середине; при наших размерах инъекции эффект мал, но избежать бесплатно | DET | раскладка render.Messages (согласовать с кэш-раскладкой Р5) |
1 | 🔶 |
| A7 | Эмбеддинг-порог как тихий гейт (Фаза 2): единый глобальный cosine-порог ведёт себя как эвристика entity-overlap и ломается на сдвиге распределения (репродукция CRAG, 2603.16169); zh/ja→ru литература — и есть сдвиг | С / 🟠🔇 | Эмбеддинг-слой держать low-trust: калибровать порог per-книга/язык на held-out чанках; использовать для генерации кандидатов на ревью (флешбеки, редкие термины), не для тихой инъекции в горячий путь | DET+HUMAN | Фаза-2 retrieval-слой | 2 | 🔶 research/05 подаёт эмбеддинги как безобидный «второй эшелон» без порога/воздержания |
B. Корректность глоссария (реестр «термин → перевод»)
| # | Сценарий отказа | Вер./Тяж. | Механизм защиты | Слой | Где в коде/схеме | Фаза | Статус |
|---|---|---|---|---|---|---|---|
| B1 | Устаревшая запись (stale): первый (наименее информированный) перевод имени лочится на 1000 глав. DelTA Proper Noun Records = first-translation-wins без обновления и без детекции конфликтов → сам механизм ПОРОЖДАЕТ stale/contradiction/drift, а не защищает (2410.08143; LTCR-1 меряет самосогласованность, не корректность — консистентно-неверное имя даёт 100%) | С / 🟠🔇 | Append-only журнал ревизий рендеринга (src, old_dst, new_dst, editorial_ts) отдельной осью от спойлер-окна; смена approved-рендеринга → LLM/HUMAN-подтверждение → точечный ре-перевод по ключу (ReTranslation-by-keyword, LinguaGacha); content-hash в snapshot принуждает перевыполнение |
DET(журнал)+HUMAN | схема: ось «редакционное время» ≠ since_ch/until_ch; ключ TM (Р6) |
1 (поле) / 2 (ре-перевод) | ❌ DelTA-PNR наивно нельзя; в research/05 §4.2 подан как позитив |
| B2 | Противоречивые записи: один термин переведён двумя способами / два исходных → один перевод | С / 🟠 | UNIQUE(src, sense, window) на approved-строках + обратный GROUP BY dst (детект коллизии инъективности); LLM-адъюдикация конфликтов раз в главу батчем (паттерн write-time из Zep/Graphiti, но в SQLite без Neo4j); HUMAN решает |
DET(констрейнт)+LLM(батч) | схема: индексы/констрейнты; тип ranked-set для рангов (v1.1) |
1 (констрейнт) / 2 (адъюдикация) | 🔶 |
| B3 | Разрешение алиасов (名/字/号/прозвища/титулы: «один персонаж = 3–6 людей») | С / 🟠🔇 | Alias-граф с типами (имя/цзы/хао/прозвище/титул) + name-tables (фамилия/имя раздельно); NER-гейт «новая форма имени-подобного токена = блок/флаг» | DET+LLM(экстракция)+HUMAN | схема: aliases→граф (D7 v1); NER-гейт |
1–2 | 🔶 (04-unhappy §1) |
| B4 | Дрейф «термин → утверждённый перевод» по ходу книги (approved-термин передан иначе) | С / 🟠🔇 | Post-check регэксп по склонённым формам (через decl/лемматизатор): approved src/алиас во входе → лемма dst в выходе? нет → флаг редактору; прономинализация не штрафуется, только approved (процедура Р7) |
DET | гейт консистентности глоссария (Р7); поле decl |
1 | ✅ (Р7) — но см. E-post-check |
| B5 | Западные имена через катакану/фонозапись (约翰→«Юэхань» вместо «Джон», ヴァイオレット, васэй-эйго マンション=квартира) | С / 🟡 | Поле translit_policy для псевдоевропейских имён; словарь васэй-эйго (v1.1) |
DET | схема: translit_policy (D7 v1) |
1 (поле) / 2 (словарь) | ✅ (04-unhappy §9, D7) |
| B6 | Нонконформность стандарту транслитерации (zh→ru — Палладий, ja→ru — Поливанов): имя может быть внутренне консистентным, но систематически неверным по стандарту — ось корректности, ортогональная самосогласованности | С / 🟠🔇 | Валидация dst имён собственных против таблиц Палладия/Поливанова на коммите термина; отклонение — флаг/политика проекта |
DET+HUMAN | схема: правило на коммите dst; пресеты стандарта |
2 | 🔶 эмпирически подтверждён (exp06): локаль на zh даёт Палладий-мусор (阿Q→«Ах-Чу», 赵太爷→«Тяо Тай-Я»), рендер zh 0.26; даже облако-топ лишь 0.75 (часть zh→ru реалий без единого канона) → детерминированная таблица Палладия/Поливанова обязательна, «сильной моделью» не закрывается |
C. Спойлеры и род (темпоральная ось)
| # | Сценарий отказа | Вер./Тяж. | Механизм защиты | Слой | Где в коде/схеме | Фаза | Статус |
|---|---|---|---|---|---|---|---|
| C1 | Спойлер-утечка: retrieval отдаёт факт, которого текущая глава знать не должна («учитель — предатель» из гл. 200 в гл. 5) | С / 🟠🔇 | since_ch/until_ch — жёсткий reject с логируемым событием на ОБОИХ путях (ключевой И эмбеддинг), не UX-фича; это safety-гейт |
DET | фильтр окна в сборщике; поля since_ch/until_ch |
1 | 🔶 research/05 трактует спойлер-окно как продуктовую фичу, не как safety |
| C2 | Поздний гендер-твист / намеренная неоднозначность (данмэй, 女扮男装, ta) → вмороженные главы закоммитили род | С / 🟠 | gender=hidden(until_ch) + «дисциплина уклонения» в промпте (безличные/настоящее время) + детерминированный блокер утечки рода; ретро-патч-протокол «с гл. N — так» с показом стоимости |
DET+HUMAN | поле gender=hidden; протокол релиза твиста (D5.1) |
2 | 🔶 (04-unhappy §2, D7) |
| C3 | Утечка рода через русский глагол прош. вр. («сказал» vs «сказала») — gender=hidden защищает существительные/местоимения, но глагол согласуется с полом без имени рядом |
С / 🟠🔇 | Морфо-гейт post-check должен сканировать глагольные формы прош. времени, не только родовые существительные | DET (Python-морфология) | морфо-гейт Фазы 2 (pymorphy/Natasha) | 2 | ❌ под-специфицировано (находка критика; 04-unhappy §2 говорит о согласовании, но не выделяет глагол-без-имени) |
| C4 | Склонение транслитерированных CJK-имён: какие имена склоняются в русском — правило-зависимо (многие ja на гласную несклоняемы, zh-моносиллабы варьируются) → decl для CJK-имён нетривиален → источник ложных флагов/форсов |
С / 🟡 | Правила склоняемости per-пара при заполнении decl; при неуверенности — флаг, не форс |
DET+LLM(заполнение)+HUMAN | заполнение decl (один дешёвый LLM-вызов на коммит термина, Р3) |
1–2 | 🔶 (находка критика) |
D. Иерархическая память (резюме) — «вторая половина банка», почти не покрыта
Строки D1/D2 ниже — ID секции D этого РЕЕСТРА (буква-секция + номер, как A1/E1/F1); НЕ путать с решениями D1–D12 из
05-decisions-log.md.
| # | Сценарий отказа | Вер./Тяж. | Механизм защиты | Слой | Где в коде/схеме | Фаза | Статус |
|---|---|---|---|---|---|---|---|
| D1 | Пропагация ошибки резюме: галлюцинированный/неверный факт в резюме главы инъектируется как авторитетный контекст и компаундится по 1000 глав — post-check-аналога у резюме НЕТ (у глоссария есть GalTransl layer-3, у резюме — ничего) | С / 🟠🔇 | Отдельный gate для резюме: сверка сущностей резюме против глоссария/coverage; батч-судья фактичности резюме раз в арку; резюме — не «авторитет по умолчанию» | DET+LLM(батч) | схема резюме; гейт резюме | 2 | ❌ первоклассный пробел — все направления ~на 90% про глоссарий (находка критика) |
| D2 | Whole-book RAG по резюме — недоказанное расширение: DelTA LTM = ограниченное онлайн-окно ~20 предложений уже-переведённого префикса + LLM-ретривер per-предложение, не whole-document RAG и не детерминированный | С / 🟡 | Держать как гипотезу к проверке, не как доказанное; whole-book семантический слой — Фаза 2, low-trust (см. A7) | DET+HUMAN | Фаза-2 LTM | 2 | 🔶 research/05 §4.2 гласит «retrieval по всему документу» — сверх того, что DelTA показал |
E. Детерминизм и принуждение (Р3 трёхслойная защита)
| # | Сценарий отказа | Вер./Тяж. | Механизм защиты | Слой | Где в коде/схеме | Фаза | Статус |
|---|---|---|---|---|---|---|---|
| E1 | Мягкий глоссарий молча не сработал: LLM оставляет 17–36% терминов неиспользованными (2310.05824) — soft following выигрывает по качеству (DuTerm en-ru, 2511.07461; WMT23 COMET-QE), но проигрывает по adherence | В / 🟠🔇 | Post-check обязателен и это post-CHECK, а не слепой post-replace: для каждого approved-термина с src в чанке — проверить, что склонённая форма dst есть в выходе; нет → флаг/точечный ре-перевод. Это главный (и почти бесплатный) детектор тихой деградации: ловит и «модель проигнорировала», и «мы инъектили неверное» |
DET | post-check гейт (Р7); поле decl |
1 | 🔶 повысить приоритет: не «nice-to-have флаггер», а необязательный→обязательный гейт наблюдаемости |
| E2 | Слепой post-replace в русский выход ломает согласование (принудительная словарная форма в косвенный падеж; 46% ошибок constrained-моделей в en-cs — согласование, 2106.12398) | С / 🟠 | Запретить слепой регэксп-replace форм глоссария в ru-выход; форс только когда термин морфологически инвариантен ИЛИ есть полный decl И падеж резолвится; иначе флаг. Модели дают лемму в мягком глоссарии, склоняет она сама (+47.7 п.п. term accuracy в латышский — Bergmanis&Pinnis) |
DET | post-check; политика форса; decl |
1 | 🔶 decl — не «фича ru-рынка», а safety-механизм грамматичности |
| E3 | Жёсткий constrained decoding как «нельзя» — переоценка: наивный (Grid Beam Search) стоит ~7 BLEU, но plug-and-play (Cascaded Beam Search, 2305.14538) даёт ~0 BLEU-потерь и EMA 0.925 на en-ru. Реальная причина не использовать — недоступен через закрытые frontier-API (нужен доступ к beam/декодеру), а не «портит качество» | — / — | Оставить soft-в-промпте дефолтом (доступно, качество подтверждено); формулировку research/05 conclusion #4 поправить | DET | — | 1 | 🔶 research/05 §5.3 «constrained decoding портит качество» — overstated |
F. Инфраструктура и состояние (код backend/)
| # | Сценарий отказа | Вер./Тяж. | Механизм защиты | Слой | Где в коде/схеме | Фаза | Статус |
|---|---|---|---|---|---|---|---|
| F1 | snapshotID не покрывает память → тихий расходящийся ре-пэй (D5.2). Подтверждено кодом: snapshotID (snapshot.go:82 (до пакета №4 — runner.go:145-163)) хэширует brief/chunker/план-стадий/сэмплинг, но не версию approved-глоссария и не параметры сборки контекста; RequestHash (render.go:158) включает контент msgs; render.go:23-29 декларирует рендер «чистой функцией snapshot». Как только Фаза 1 инъектит память в msgs (render.go:133-136): изменённый глоссарий/STM меняет request_hash, но не snapshotID → resnapshot-гейт (bookrun.go:108/stagerun.go:77 (до пакета №4 — runner.go:260)) молчит → ре-ран старой главы промахивается мимо чекпоинта и переоплачивает расходящимся переводом, ломая инвариант Р6 |
В / 🔴🔇 | Свернуть в snapshot ОБА: (1) состояние памяти (content-hash материализованного approved-глоссария + резюме/series-bible на момент старта джобы — рендер читает замороженную версию, не live; D8: content-hash, НЕ версия-счётчик — счётчик молча дрейфует, если забыли бампнуть) и (2) context-assembly-конфиг (glossary_injection, stm_depth, overlap). Тогда рендер снова чист по snapshot. ✅ УЖЕ СДЕЛАНО (commit 636919c): snapshot содержит context_assembly (GlossaryInjection/GlossaryTokenBudget) + MemoryVersion — материализует память → хеш (выбран мой рекомендованный «материализующий» вариант); Capability тоже свёрнут. memoryVersion() пока хеширует константу-заглушку tm-memory-v1\x00, т.к. банк памяти v2 ещё не приземлился (комментарий в коде явно фиксирует инвариант). |
DET | runner.snapshotID()/memoryVersion()/contextSnap |
сделано; активируется с v2 | ✅ структурно закрыто (636919c). ОСТАЁТСЯ узко: при приземлении глоссария заменить константу в memoryVersion() на хеш ORDER BY-стабильных материализованных строк (замороженных, не live) — иначе F1 тихо регрессирует. |
| F2 | Токен-бюджет: eviction не определён. При превышении бюджета (matched + sticky > лимит) какая запись выпадает — не задано; выпавшая нужная запись = тихая деградация | С / 🟡🔇 | Явная политика приоритета/вытеснения (World Info inclusion-groups: approved>auto; персонажи чанка>фоновые) + логировать факт вытеснения (не молча) | DET | сборщик; retrieval-state запись |
1 | ❌ политика и лог вытеснения не специфицированы (находка критика) |
| F3 | Конкурентность/порядок в SQLite: параллельный перевод чанков + запись auto-записей ломает first-translation-wins и sticky (оба предполагают последовательность); modernc — один писатель |
С / 🟡 | Явное правило: auto-экстракция и коммит терминов — только на границе джоб (impl-notes §3.2 это уже фиксирует); sticky/порядок считаются от детерминированной пересборки чекпоинтов, не от wall-clock порядка | DET | граница джоб; write-пул store | 1 | 🔶 назвать явно (находка критика) |
| F4 | Один SQLite-файл на книгу = SPOF: повреждение файла молча теряет весь глоссарий+резюме | Н / 🟠🔇 | Бэкап/интеграл-чек/версионирование файла книги; экспорт TMX/TBX как побочный бэкап | DET | store; экспорт | 2 | 🔶 нет строки бэкапа/интеграла (находка критика) |
| F5 | Коррелированный отказ судьи-экстрактора: адъюдикация конфликтов и подтверждение кандидатов — одна модель на одних и тех же трудных кейсах (редкие имена, неоднозначный смысл) → систематически-неверный судья тихо промоутит плохие approved-ключи → retrieval-state lock-in | С / 🟠🔇 | Независимая проверка (судья чужого семейства / человек) на промоушене approved-ключа; first-encounter имя не промоутится в approved до батч-подтверждения раз в главу | LLM(2-й)+HUMAN | пайплайн подтверждения терминов | 2 | 🔶 (находка критика; смыкается с A2/B1) |
G. Популяция глоссария и человеческая ёмкость (корень и петля)
| # | Сценарий отказа | Вер./Тяж. | Механизм защиты | Слой | Где в коде/схеме | Фаза | Статус |
|---|---|---|---|---|---|---|---|
| G1 | Качество автоэкстракции (bootstrap): все направления валидируют retrieval, но не популяцию. Мусор/пропуск главного персонажа на входе → горячий путь верно инъектит мусор / молча опускает — корневой отказ выше всего измеренного | С / 🟠🔇 | Разделить задачу экстракции на две (индикативно замерено, eval/extract_bench.py): (а) СПОТ кандидатов-спанов — локаль годится (qwen3-abliterated:8b recall 1.0 на zh+ja, 0 галлюцинаций, ~15с/чанк — дёшево на стенде); (б) РЕНДЕРинг dst — локаль НЕ годится (0.0–0.5: 阿Q→«А Цзы», 羅生門→«Россомаха», 秀才→«шоуцай» — как exp03), dst даёт сильная/облачная модель + человек. First-encounter unknown → status=auto/unconfirmed, гейт (батч-судья/человек) до промоушена в approved; alarm «имя-подобный токен без записи → неизвестная сущность» (DelTA-паттерн). ⚠ deepseek-v4-flash молча вернул пустой ответ на части чанков (祝福 воспроизводимо) — это тот empty-paid-response, что ловят D2/coverage-гейт |
DET(алярм)+LLM(спот=локаль / рендер=облако)+HUMAN | pre-пасс NER; статус-машина термина | 1–2 | 🔶 верифицировано (exp06, 13 моделей × 12 кейсов zh/ja/en): спот локальный OK (recall ~0.98 все языки), рендер локали язык-зависим (en 0.82 / ja 0.53 / zh 0.26) → спот=8b, рендер dst=облако(gemini-flash value)/человек, на zh + таблица Палладия B6 |
| G2 | Человеческая ёмкость — недоказанная петля всей safety-аргументации: почти каждая защита кончается «флаг → редактору/человеку». Объём флагов на главу никто не оценил; при высоком flag-rate «route to human» пусто → деградация тихая на практике | С / 🟠🔇 | Оценить flag-volume на главу на пилоте; alarm-пороги и aggregate «memory-coverage»-сигнал; безлюдный режим: auto→approved с записью в журнал (Р7), но с явной пометкой качества | DET(телеметрия)+HUMAN | retrieval-state запись; отчёт «паспорт качества главы» |
1–2 | ❌ flag-rate × throughput не смоделирован (находка критика) |
Контракт горячего пути (снять противоречие до «где в коде»)
Направления разошлись в описании несущего компонента; резолюция:
- Горячий путь — НЕ FTS5. impl-notes §3.6 (строки 123-124) уже решает: «FTS5 в горячий путь v1 не тащить (unicode61 не сегментирует CJK; селективной инъекции хватает точных ключей/алиасов по обычным индексам)». То есть горячий путь — детерминированный multi-pattern матч (Aho-Corasick/double-array trie по
src+алиасам над нормализованным чанком; для ru/en — по леммам/decl). FTS5/BM25 на горячем пути для zh/ja молча вернёт ничего (дефолтный токенайзер не сегментирует CJK) — их туда не ставить. Эмбеддинги на горячем пути — тоже нет (Р3). Это подтверждено эмпирикой (A3). - sqlite-vec: причину отказа в Р3/research/05 поправить. «pure-Go не загрузит C-расширение» верно только для
modernc.org/sqlite, не как свойство pure-Go:ncruces/go-sqlite3(WASM) +asg017/sqlite-vec-go-bindings/ncruces— официально поддерживаемый CGO-free путь к SIMD-brute-force sqlite-vec. Решение (brute-force KNN в MVP) остаётся верным (эмпирика Q2: <20 мс на 100k×1024-d в чистом numpy; sqlite-vec-scalar 81–108 мс на 1M — на порядки выше нужд одной книги), но рациональ переписать: реальная причина — «держим modernc единым драйвером / избегаем WASM-миграции», а не «pure-Go не может». ncruces+sqlite-vec — самый дешёвый триггер миграции, если вектора станут узким местом.
Гейты для бэкенда перед фиксацией схемы store/глоссария v2
Обязательно закрыть/учесть до заморозки схемы (шаг 4):
- F1 (snapshotID под память + context-assembly) — до инъекции Фазы 1. Класс бага «тихий расходящийся ре-пэй». Payload snapshot: версия-счётчик approved-глоссария + резюме/series-bible +
glossary_injection/stm_depth/overlap; рендер читает pinned-версию. - Схема v1 (подтверждаю D7) + добавить из этого реестра: поле
sense(A3/B-полисемия); ось «редакционное время» отдельно отsince_ch/until_ch(B1); констрейнтыUNIQUE(src,sense,window)+ обратная проверкаdst-коллизий (B2);glossary.min_key_lenper-язык + запрет одиночных ключей (A3); нормализационный артефакт NFKC/OpenCC/kana/ruby (A4). - Post-check из E1/E2 — обязательный гейт, не опциональный флаггер; политика форса только при разрешимом падеже +
decl. - Трёхсторонний disposition инъекции (A2) +
retrieval-stateper-chunk запись (A1/F2/G2:n_exact_hits, n_sticky, n_ambiguous_flagged, n_spoiler_blocked, embedding_tier_used) — наблюдаемость деградации с первого дня. - Отложено в v1.1/Фазу 2 (не блокирует v1-схему, но заложить поля/место): транслит-стандарты Палладий/Поливанов (B6), гейт фактичности резюме (D1), whole-book эмбеддинг-слой low-trust (A7/D2), бэкап/интеграл файла книги (F4), морфо-гейт глагольного рода (C3), измерение экстракции и flag-volume (G1/G2).
Ruby-seed контракт (вход шага 4 из шага 3a — подтверждён оркестратором 05.07)
Шаг 3a захватил ruby/фуригану в ruby_readings(book_id, base, reading, first_chapter, occurrences) (capture-only, не в промпте/hash). Маппинг в глоссарий v2 подтверждён, форма верна, с 3 уточнениями:
base(кандзи) →src;first_chapter→since_ch;occurrences→ приор уверенности (не прямой approved).reading(кана) → НЕ dst напрямую, а мост к правильному dst: это авторитетное произношение, по которому валидируется Поливанов-транслитерация. Ruby прямо усиливает пробел B6 — reading есть ground-truth для транслит-стандарта (без него B6 нерешаем; с ним — механически проверяем).- Уточнение 1 (обязательно): различать имя-чтение vs авторское двойное чтение (фуригана-игра). Ruby двойствен (04-unhappy §4): 鈴木→すずき (имя → name-lock, Поливанов) против 強敵→とも (база и чтение значат РАЗНОЕ — стилистический приём). Блайнд-лок второго (強敵→とも→«друг») = mistranslation. Классифицировать: фонетическая согласованность / паттерн собственного имени → name-lock; несвязанное чтение → переводческая сноска, не лок. Неоднозначное → человеку.
- Уточнение 2: ruby — СИД в auto-кандидатный пул с приором
occurrences, НЕ прямо в approved (статус-машина G1: высоко-частотное чтение → auto-кандидат; батч-судья/человек промоутит в approved до распространения на будущие главы). - Уточнение 3:
decl/genderruby НЕ даёт — они с term-commit LLM-пасса (decl) и контекста (gender). Ruby сидит src+reading→dst, остальное достраивается.
⚠ Перед реализацией прочитай
research/13§«Честные слабые места рекомендаций». Два пункта прямо влияют на этот реестр: F1 подан как решённый фикс, но там реальная развилка (snapshot материализует байты инъекции vs store версионирует глоссарий — я склоняюсь к «байты», но не доказал); E1 post-check — несущий гейт, но его надёжность в русской морфологии сама невалидирована (склонение-осознанный матч шумит → ложные флаги → редакторы игнорируют → safety рушится). Померить пост-check на русском ДО того, как доверять ему как гейту. Исполняемый эталон механизма (не продукт) —eval/memory_hotpath.py(T1–T10 → Go-юниттесты).
In-house eval — обязателен (числа литературы не переносятся)
Ни один процитированный источник не меряет zh/ja→ru (DelTA/TransAgents/Karpinska/WMT25 — En-центричны или ru только как источник; вендорские memory-числа — про chat-память о пользователе, при честной методологии их бьёт ванильный RAG). Поэтому перед заморозкой ставки нужен свой замер на реальном стеке и направлении — детали, acceptance-критерии и протокол (bank-vs-long-context baseline, «random-terminology» адверсариальный arm из WMT25) — в docs/research/13-memory-bank-validation.md §Вердикт. Реестр рисков не заменяет этот замер — он делает провалы явными, что и есть ответ на опасение владельца: тихую деградацию мы конвертируем в громкую (post-check + disposition-лог + retrieval-state), а не устраняем её обещанием.