diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md index e4bfd326..5f83fe6e 100644 --- a/docs/PROGRESS.md +++ b/docs/PROGRESS.md @@ -1,7 +1,7 @@ # Журнал прогресса > **⟶ ТЕКУЩЕЕ СОСТОЯНИЕ** (на 2026-08-04, голова D39.101; сессия оркестратора №12 ЗАКРЫТА — передача №13). -> - **ПЕРЕДАЧА №12 → №13 (D39.101, 04.08).** Первая задача №13: **приёмка банк-арбитража** (отчёт `research/24-bank-arbitration.md` · харнесс `eval/bank_arbitration/` · черновик отчёта в `archive/reports/` — лежат в дереве НЕ залендены; потрачено **$0.1073** — ⚠ числа пинга внутренне расходятся, сверить на приёмке; потолок ратифицирован $1.20, пинг называет $1.00; пинг — секция «Полигон» ниже; приёмка адверсариальная, клеймы — с репликацией; при лендинге поправить в шапке `research/24` путь заархивированного промта). Дальше бэкенд-очередь: промт пака экрана 46 (D39.94 п.3: фикстура 113 ПЕРВОЙ, денежный шаг ТОЛЬКО с подписью владельца) · малый пак tools/go.mod (строка 118, D39.97 п.4) · блокеры контракта 99/100/101/103/125. **Вахта deepseek-v4-pro: триггер «>05.08» НАСТУПАЕТ** — при аномалии редакторского арма пере-проба + вендор-changelog (реестр 108; `medium` на DeepSeek не ставить). Открыто на владельце: 116 (порог подан) · мини-проба 44 «low+16k» (~$0.05) · подпись денежного шага 46 · лист В-3+К-6 (фразы замечаний) · запуск S3 (первым шагом правки спеки D39.100). **P0 ОТРАБОТАЛА к моменту передачи**: отчёт + дизайн-ответы К-4/К-7/К-12/П-5 предложениями — `platform/docs/platform-PROGRESS.md` (батарея зелёная, healthz/readyz против живого Postgres 18.4 — со слов журнала, НЕ перепроверено); живое дерево `platform/*` целиком, включая модифицированный `go.mod`, ждёт **ПРИЁМКИ №13** — не трогать и не заметать коммитом; там же ТРИ открытых вопроса, один — ВЛАДЕЛЬЦУ (авто-резюме `paused` после сброса лимитов). Вопросы владельцу из отчёта банка поднимет приёмка №13. +> - **ПЕРЕДАЧА №12 → №13 (D39.101, 04.08) — задача (i) ИСПОЛНЕНА: приёмка банк-арбитража ЗАВЕРШЕНА (D39.102, 04.08).** research/24 + харнесс + черновик ПРИНЯТЫ и залендены; все числа чисты пере-раном (12-агентный воркфлоу 8/8 CONFIRMED · 23/23 адресов §A по HEAD · деньги из сырья $0.107334 ≈ леджер; расхождение пинга = склейка инкрементов C+E — маркер в «Полигоне»); строки 128–132 заведены (фикс-пак банка 128 — ГЕЙТ подписи владельца), строка 5 пере-скоуплена (консилиум закрыт классом; остаток — рецензент спорных кластеров при ре-пробе 74); **4 вопроса владельцу — D39.102 п.4**. Дальше бэкенд-очередь: промт пака экрана 46 (D39.94 п.3: фикстура 113 ПЕРВОЙ, денежный шаг ТОЛЬКО с подписью владельца) · малый пак tools/go.mod (строка 118, D39.97 п.4) · блокеры контракта 99/100/101/103/125. **Вахта deepseek-v4-pro: триггер «>05.08» НАСТУПАЕТ** — при аномалии редакторского арма пере-проба + вендор-changelog (реестр 108; `medium` на DeepSeek не ставить). Открыто на владельце: 116 (порог подан) · мини-проба 44 «low+16k» (~$0.05) · подпись денежного шага 46 · лист В-3+К-6 (фразы замечаний) · запуск S3 (первым шагом правки спеки D39.100) · **4 вопроса банка (D39.102 п.4: мини-голд алиасов · «Гуюэ» слитно = пар-норма? · проба редакторского провода ~$0.05 · промт фикс-пака 128)**. **P0 ОТРАБОТАЛА к моменту передачи**: отчёт + дизайн-ответы К-4/К-7/К-12/П-5 предложениями — `platform/docs/platform-PROGRESS.md` (батарея зелёная, healthz/readyz против живого Postgres 18.4 — со слов журнала, НЕ перепроверено); живое дерево `platform/*` целиком, включая модифицированный `go.mod`, ждёт **ПРИЁМКИ №13** — не трогать и не заметать коммитом; там же ТРИ открытых вопроса, один — ВЛАДЕЛЬЦУ (авто-резюме `paused` после сброса лимитов). Вопросы владельцу из отчёта банка ПОДНЯТЫ приёмкой (D39.102 п.4). > - **Сессия №12 (03–04.08) — закрыта, всё принято и заленжено:** пак стандартов + дофикс archguard (D39.96/97: `.golangci.yml` 0 issues · `make battery` = единая точка входа · tmvet/archguard 38 посадок, 9/9 мутаций · x/net 0.57 живой пробой PASS 3/3 · конфиги 112 → **платные прогоны разблокированы**) · фронт S2 + дофикс по ревью (D39.98) · **контракт API v0, форма OpenAPI 3.1, строка 95 закрыта** (D39.99: три пасса приёмки, 19/19 находок вправлено, типы фронта ГЕНЕРЯТСЯ из спеки) · решения владельца К-1/К-8(→ПТ-35/П-5)/К-5/К-6/К-3 + **платформа открыта промтом P0** (D39.100) · git-канон v2 «коммитит только оркестратор» разнесён по носителям (D39.98). Лендинги: `e8d4ac0`…`0e64efe` (бэкенд, 7 коммитов) · `02872b6`…`94a24b7` (фронт/контракт/платформа/доки, 9). > - **Сделано (сводно; детали — D-лог и архив-слайсы):** Ф0 ✅ · Ф1-инфра ✅ · арх-ресет D39 (7 слоёв, паки 11–16) ✅ · паки 17 «канал B» · 18 «долги» · 19 «голос/состояние» · 20 «банк+терминолог» ✅ (D39.26–28/31/41–56) · мини-прогон (D39.37) и ХОЛОДНЫЙ прогон (D39.58: recall банка 0.918/0.980, банк приходит переведённым) приняты · полигон-пакеты 5–8, ToS-речек (D39.57), Р6+P4 (D39.61) закрыты · **карта языковой привязки движка (D39.60): 149 сайтов/45 файлов, книго-ось чиста (4), ja→ru безопасно без правки Go, en→ru — нет** · Р1–Р4 закрыты целиком (D39.63: Р2 = ЗНАЧЕНИЕ, Р4 = норма потолка recall) · **ФАЗА 2 ОБЩНОСТИ ✅ (D39.64: П0 эмбед-хеш · П1 цель-шов · П2 скрипт-шов, ko-баг закрыт · П3 нарезка · П4 манифест-по-каналам; голден вердикт-нейтрален 0/172, майнер-парити EXACT)** · жанровый словарь отменён как класс (D39.47) · петля ремонта построена и НЕ включена (D39.38). > - **Курс:** ОБЩНОСТЬ ✅ → КАЧЕСТВО БАНКА ✅ → ПАКЕТ-ЧЕКЕРОВ ✅ (D39.59–78) → **ФРОНТ-ЭРА открыта** (D39.81–100: зоны `frontend/`+`platform/` живые, контракт API ратифицирован). Развилка блокера 0731 решена вариантом (б) и ИСПОЛНЕНА (D39.87/91: `reasoning_effort:"low"` черновику + ручка эффорта бэнк-ролям, код `553f1a3`); отладочный прогон C не стартовал ⇒ **строка 16 жива и оси голоса 13б без данных**; пак экрана 46 — дизайн заморожен (D39.92 п.1 + D39.93), промт ждёт выдачи; coldrun-b фаза C заморожена чекпойнтом — легитимный исход (D39.86); эталон денег/поведения — coldrun-a (read-only). Числа и хроника закрытых паков — D-лог D39.79–97, сюда НЕ дублируются. @@ -19,7 +19,7 @@ | **— ВИСИТ НА ВЛАДЕЛЬЦЕ —** | | | | | | | 2 | Четыре вопроса границы «алгоритмического идеала» (Annotator · семантический судья · ja→ru §B5 · ru-target до/после) | владелец | скоро (гейт «добора идеала» перед МАСШТАБОМ) | отдельное решение | D39.33, D39.38 | | 4 | **Ре-чек ToS по триггерам** — первый ИСПОЛНЕН 31.07, дельт вердиктов нет (D39.57); предмет Google-мониторинга перевешен на цепочку договора (PUP · Additional ToS · Google APIs ToS); следующие: квартал 25.10.2026 · первая лейблованная книга · любая правка `accepts_labels` | владелец/полигон | скоро (следующий триггер 25.10.2026) | отдельное решение (правило) | D39.32, D39.57 | -| 5 | **Судья-с-декоем/36б «второе мнение» → РАСШИРЕНО ДО АРБИТРАЖА БАНКА (D39.89), ПРОМТ ВЫДАН.** Бэкенд-стройка ЗАКРЫТА дизайном (D39.69): маршрут = полигон-ЗАМЕР нужности рецензента-другого-семейства ПОВЕРХ §1+§2 (Q2); переживёт замер → тонкая колонка наблюдаемости, не гейт. **Вход владельца 02.08 добавил в тот же замер четыре вопроса, которых в Q2 не было:** (i) калибровка САМООЦЕНКИ моделей как сигнала (числа против слов · устойчивость · **сравнимость между моделями**), (ii) взвешенный арбитраж против равноправного «консилиума без голоса», (iii) **связность системы термов как ограничение** — единица арбитража обязана быть КЛАСТЕРОМ (семья корня · серия · регистр · алиас-граф), а не строкой (по-терминный argmax возвращает классом дефект, вылеченный со-батчингом, D39.65 стр.21), (iv) инжект/фетч отдельной осью (мерить послушание и ВРЕД, не recall). Приоры против наивной формы уже есть: судья = катастроф-экран, не ранжировщик (D39.46) · канал отказа нестабилен, размах 0.375 (D39.50) · согласие прогонов слабое, Жаккар 0.077–0.40 (D39.50). Гейт всего — **голд-набор** (ядро: сид v2 53 `approved` + BANK-FULL 150 + банк coldrun-a; мини-голд алиасов §E-1 research/20 ждёт владельца с 17.07). Промт `BANK_ARBITRATION_RESEARCH_SESSION_PROMPT.md` (потолок $2.00, суб-потолки, пре-регистрация; легитимный исход — «закрыть по нужности»). ⚠ **ЗАХОД 02.08 ЗАПУЩЕН И ДОСРОЧНО ЗАКРЫТ ВЛАДЕЛЬЦЕМ — «требуются фиксы в бэкенд» (D39.90). Артефакта в дереве НЕТ:** ни `docs/research/24-*`, ни `eval/bank_arbitration/`, ни свежих файлов в `~/books` ⇒ **находки того захода НЕ сохранены; если они ценны — их надо вынуть из истории сессии, иначе работа повторяется с нуля.** Рекомендация оркестратора №10 к пере-запуску (ПОДРЕЗАТЬ, а не гонять целиком): **держать** §3-A (критика кода, $0 — она и вскрывает нужные бэкенд-фиксы), **B1** голд (гейт всего) и **B3** формы консилиума с контролем «одна модель N раз»; **свернуть** B2 (калибровка уверенности) до под-пробы внутри B3 — как отдельная работа она дорога, а приоры D39.46/D39.50 уже сильно против неё; **отложить** §5-C (инжект/фетч) до бэкенд-доработок, потому что мерить послушание инъекции без движка нечем. Потолок с $2.00 к $1.20 · **02.08 вечер (D39.92): владелец напомнил про заход — статус: промт жив, заход был ПРЕРВАН владельцем, находки только в истории той сессии (вопрос: вытащит ли их владелец), пере-запуск — по подрезке D39.90 п.5 ($1.20), промт подрежет оркестратор перед выдачей** → **04.08 ПЕРЕ-ЗАПУСК ИСПОЛНЕН, промт заархивирован (`archive/prompts/`, D39.101)** (скоуп резался релеем, тело промта не правилось): артефакты в дереве, пинг — секция «Полигон»; предыдущий ⚠ «артефакта в дереве НЕТ» относится к прерванному заходу 02.08 и ЗАКРЫТ | полигон/ресёрч | **НА ПРИЁМКЕ №13** (заход исполнен 04.08, артефакты в дереве не залендены) | замер → дизайн → решение | D39.50 п.6, D39.58, D39.69, D39.70 (Q2), D39.89, **D39.90** | +| 5 | **Судья-с-декоем/36б «второе мнение» → РАСШИРЕНО ДО АРБИТРАЖА БАНКА (D39.89), ПРОМТ ВЫДАН.** Бэкенд-стройка ЗАКРЫТА дизайном (D39.69): маршрут = полигон-ЗАМЕР нужности рецензента-другого-семейства ПОВЕРХ §1+§2 (Q2); переживёт замер → тонкая колонка наблюдаемости, не гейт. **Вход владельца 02.08 добавил в тот же замер четыре вопроса, которых в Q2 не было:** (i) калибровка САМООЦЕНКИ моделей как сигнала (числа против слов · устойчивость · **сравнимость между моделями**), (ii) взвешенный арбитраж против равноправного «консилиума без голоса», (iii) **связность системы термов как ограничение** — единица арбитража обязана быть КЛАСТЕРОМ (семья корня · серия · регистр · алиас-граф), а не строкой (по-терминный argmax возвращает классом дефект, вылеченный со-батчингом, D39.65 стр.21), (iv) инжект/фетч отдельной осью (мерить послушание и ВРЕД, не recall). Приоры против наивной формы уже есть: судья = катастроф-экран, не ранжировщик (D39.46) · канал отказа нестабилен, размах 0.375 (D39.50) · согласие прогонов слабое, Жаккар 0.077–0.40 (D39.50). Гейт всего — **голд-набор** (ядро: сид v2 53 `approved` + BANK-FULL 150 + банк coldrun-a; мини-голд алиасов §E-1 research/20 ждёт владельца с 17.07). Промт `BANK_ARBITRATION_RESEARCH_SESSION_PROMPT.md` (потолок $2.00, суб-потолки, пре-регистрация; легитимный исход — «закрыть по нужности»). ⚠ **ЗАХОД 02.08 ЗАПУЩЕН И ДОСРОЧНО ЗАКРЫТ ВЛАДЕЛЬЦЕМ — «требуются фиксы в бэкенд» (D39.90). Артефакта в дереве НЕТ:** ни `docs/research/24-*`, ни `eval/bank_arbitration/`, ни свежих файлов в `~/books` ⇒ **находки того захода НЕ сохранены; если они ценны — их надо вынуть из истории сессии, иначе работа повторяется с нуля.** Рекомендация оркестратора №10 к пере-запуску (ПОДРЕЗАТЬ, а не гонять целиком): **держать** §3-A (критика кода, $0 — она и вскрывает нужные бэкенд-фиксы), **B1** голд (гейт всего) и **B3** формы консилиума с контролем «одна модель N раз»; **свернуть** B2 (калибровка уверенности) до под-пробы внутри B3 — как отдельная работа она дорога, а приоры D39.46/D39.50 уже сильно против неё; **отложить** §5-C (инжект/фетч) до бэкенд-доработок, потому что мерить послушание инъекции без движка нечем. Потолок с $2.00 к $1.20 · **02.08 вечер (D39.92): владелец напомнил про заход — статус: промт жив, заход был ПРЕРВАН владельцем, находки только в истории той сессии (вопрос: вытащит ли их владелец), пере-запуск — по подрезке D39.90 п.5 ($1.20), промт подрежет оркестратор перед выдачей** → **04.08 ПЕРЕ-ЗАПУСК ИСПОЛНЕН, промт заархивирован (`archive/prompts/`, D39.101)** (скоуп резался релеем, тело промта не правилось): артефакты в дереве, пинг — секция «Полигон»; предыдущий ⚠ «артефакта в дереве НЕТ» относится к прерванному заходу 02.08 и ЗАКРЫТ → **04.08 ПРИЁМКА №13 ИСПОЛНЕНА (D39.102): ПРИНЯТ и заленден; Q2 отвечен — семейства не окупаются (C3−SC=+3 и все три = один кластер 古月; glm-соло 25/45 > совет 23/45); равноправный совет · кросс-модельные веса · self-consistency · селекция · отказ-сигнал ЗАКРЫТЫ классом; фикс-пак банка = строка 128 (гейт подписи)** | полигон/ресёрч | **ОСТАТОК ГЕЙЧЕН ре-пробой 74** (рецензент спорных КЛАСТЕРОВ, роутинг family/series-юнитами — G4, D39.102 п.2) | замер (остаток) → решение | D39.50 п.6, D39.58, D39.69, D39.70 (Q2), D39.89, **D39.90** | | 6 | **Строка Gemini в `accepts_labels`** — ждёт слова владельца о подписи интерпретации сужения как разрешения; ре-чек 31.07 понизил приоритет: подпись даёт ПРАВО, но не судью 18+ (фильтр неконфигурируем D22.6 + обход запрещён договором) — возвращаться при вопросе, требующем именно права | владелец | когда-нибудь | отдельное решение | D39.32, D39.57 | | 7 | Q2 «редактор под `sexually-explicit`» (grok-4.3 интерим · glm-5 после сверки ToS Z.AI · mistral вон) | владелец | когда-нибудь (перед первой explicit-книгой) | отдельное решение | D39.27 п.7 | | 8 | D22.7 пер-чанковый L3-скрин — несня­тое предусловие первой erotica-книги в проде, отдельный гейт | владелец | когда-нибудь | отдельное решение | D22.7, CURRENT-STATE (оркестратор) | @@ -62,7 +62,7 @@ | 36б | **Второе мнение по банку**: рецензент ДРУГОЙ моделью, несогласия — отдельной колонкой подписной таблицы (судья-с-декоем в роли рецензента; решает владелец, D39.46-ограничение не бьёт). ⚠ **ДИСПОЗИЦИЯ ПРИВЕДЕНА В СООТВЕТСТВИЕ (D39.90): бэкенд-стройки НЕТ** — D39.69 закрыл её по нужности, маршрут = полигон-ЗАМЕР (строка **5**, промт выдан); переживёт замер → тонкая колонка наблюдаемости, не гейт. Прежняя форма «отдельный дизайн (Р4)» в зоне бэкенда была устаревшей и завышала счёт бэкенд-очереди | полигон (замер) → бэкенд (только если переживёт) | когда-нибудь (через строку 5) | замер строки 5 → решение | D39.58, D39.51 п.4, D39.69, **D39.90** | | 36г | **Проводной формат каналов пересказан прозой в каждом пар-промпте, парсер в Go, связи нет** — формат в шаблон движка (`{{banknote_format}}`); линты держат класс, дублирование остаётся | бэкенд | когда-нибудь (со следующей правкой промптов) | отдельное решение (Р5) | D39.58 | | 37 | **Квадратичности: `AttachKWIC`** (16.8 с / 2000 кандидатов; фикс — многошаблонный поиск) + src-правило банкноты при промахе чанк-пути (строка × длина книги; на 10 главах не видна) | бэкенд | когда-нибудь | отдельное решение | D39.45, PACK20_BANK_BUILD §8.5.1, D39.58 | -| 38 | Смета не видит пере-покупку прохода терминолога на каждой итерации подписи (роль не пишет `chunk_status`, не видна `projectRebill`) | бэкенд | когда-нибудь | отдельное решение | D39.45, PACK20_BANK_BUILD §8.5.2 | +| 38 | Смета не видит пере-покупку прохода терминолога на каждой итерации подписи (роль не пишет `chunk_status`, не видна `projectRebill`) · хвост приёмки №13 (СО СЛОВ слепого ревью, НЕ верифицировано): адрес чекпойнта батча = ординал при частотной сортировке растущего набора кандидатов ⇒ реюз чекпойнтов прохода ~0 на инкрементальной книге (`terminology.go:925-931`) | бэкенд | когда-нибудь | отдельное решение | D39.45, PACK20_BANK_BUILD §8.5.2, D39.102 | | 39 | S12 частичен: `malformedSeparatorAt` не ловит подмену слова разделителя и обрыв токена (комментарий обещает) | бэкенд | когда-нибудь | отдельное решение | D39.45, PACK20_BANK_BUILD §8.5.3 | | 40 | `bankTokenBudget`: worst-case зашит zh→ru (признанная утечка §0; CJK-цель недобирает вдвое) | бэкенд | когда-нибудь | отдельное решение | D39.45, PACK20_BANK_BUILD §8.5.4 | | 41 | golden: вторая фикстура С langpack (сейчас пинится только фолбэк-путь) ; + golden-счётчики голоса (хвост D39.58) | бэкенд | когда-нибудь | отдельное решение | D39.37(6) | @@ -75,6 +75,11 @@ | 48 | Направленная банкнота — вернуться по замеру покрытия терминолога | бэкенд | когда-нибудь | отдельное решение | D39.42 | | 48а | **Серийный шаринг банка** — РЕАЛИЗАЦИЯ (экспорт подписанного глоссария как сид-YAML следующей книги серии; спойлер-окна плющатся в since_ch=0); контракт round-trip держится тестом, самой фичи нет | бэкенд | когда-нибудь (перед второй книгой серии) | отдельное решение | D39.42 задел (а), PACK20_BANK_BUILD З-а | | 48б | **Импорт «оригинал + чужой перевод» как режим данных терминолога** (target-агностичный вход есть контрактом; сам режим + провенанс источника + юр-сторона в юр-пакете) | бэкенд/владелец | когда-нибудь | отдельное решение + Ф2.5 (юр) | D39.42 задел (б), PACK20_BANK_BUILD З-б | +| 128 | **Фикс-пак банка (вход §G research/24, класс D39.71):** G1 семейный со-батч из ПАР-ДАННЫХ (имя=префикс/реалия=суффикс, без транзитивности, серия сильнее семьи; + многорунные модификаторы серий — 十一转 рвёт со-батч равнодлинности на ранге 11; + майнерские containment-пары в один юнит) · G2 intra-run `ConsolidationConflicts` ($0; 18/149 на живом банке) · G3 наблюдаемость (Signals/Invented/Conf в стоп-таблицу · ловушка числового хвоста ParseReply · alias-джойн подписной карты `miner_emit.go:242` — владелец подписывает, не видя alias-рендерингов · имена эвиктнутых при NEvicted · per-batch спросили/ответили + WARN на пустой ответ батча/классификатора) · G5 счёт голосов по нормализованной форме + Via-провенанс фолда (первый-выигрывает врёт на wire) · опции: перф 37 (Aho-Corasick в membank готов) · гигиена (мёртвая колонка `BanknoteTruncated` + стейл-комменты · NoDst-префикс-матч для латиница-target). Цена фолда: перекупка бэнк-батчей один раз (центы), волны/снапшоты не двигаются; G2/G3 — evidence-сторона, вне снапшота | бэкенд | скоро (ГЕЙТ: подпись владельца — вопрос №4 D39.102 п.4) | фикс-пак одним промтом | D39.102, research/24 §G | +| 129 | **Банкнота-парсер теряет хвост многословного dst** (находка приёмки №13 против клейма A10): `banknote.go:236` берёт `parts[1]` голым при 3-польном формате — «Фан Юань» с двойным пробелом банкует полу-имя «Фан», хвост уезжает в колонку типа и падает в `"term"`; ре-джойн терминолога (`terminology.go:880-885`) ровно этот класс чинит с комментарием. Фикс = ре-джойн середины при последнем поле ∈ закрытому словарю типов; двигает observed → авто-банк (memory_version там, где случай реален) — цену назвать при выдаче | бэкенд | скоро (хвостом 128 либо отдельно) | малое касание | D39.102 п.3 | +| 130 | **emitRankCap × writeAutoBank: терм, выпавший из топ-200, МОЛЧА стирается из авто-банка посреди книги** — `miner_emit.go:119-123` кап ДО эмиссионных фильтров (seed/rejects слотов НЕ освобождают — исключаются после капа), `mining.go:448-460` перезапись файла целиком без мерджа против «накопительного» замысла пака-20; оплаченная консолидация теряется, редактор теряет ⟨проверить⟩-constraint без сигнала; FL-3 ратифицирован ДО авто-провода D39.42 — взаимодействие не ратифицировалось. Минимум $0 = дифф старого/нового авто-файла + WARN с именами; накопительный мердж/освобождение слотов — СТОП-решение (двигает банк → memory_version) | бэкенд | скоро | $0-минимум + СТОП-решение | D39.102 п.3 | +| 131 | **Кап инъекции не считает маркер и гендер-ноты**: `glossaryLineTokens` бюджетирует только «src → dst» (`memory.go:512-515` против рендера `:698-708`) — авто-книга (все строки Ambiguous с ⟨проверить⟩) превышает `glossary_token_budget` ~на 40–60% при budget 800; биллинг/потолки компенсированы (резервация по фактическому рендеру, `stagerun.go:469-477`), сам кап не исполняется. Фикс двигает состав инъекций → RequestHash → перекупка волн ⇒ СТОП-решение с названной ценой | бэкенд | когда-нибудь | СТОП-решение | D39.102 п.3 | +| 132 | **Стойкий (пост-ретрайный) аутедж ТОЛЬКО банк-провайдера валит весь ран** вопреки коммент-контракту «optional step never aborts» (`terminologist.go:630-634` — деградация только на ceiling; транспортные ретраи гасят transient, `httpllm.go:126-160`; потерь нет — чекпойнты реплеятся за $0): решить — деградировать в «термы неконсолидированы»+WARN либо честно переписать коммент | бэкенд | когда-нибудь | малое касание через СТОП-решение | D39.102 п.3 | | 49 | **Этапы Б+В спеки D15.2** (content-addressed resume / `guard_hash` — D39.31 сознательно не строил) ; этап В = tmctl export-контракт D29.1 (annot-v1 · цвет-мап+rollup · политика красных fail-closed) + операторский протокол-документ релиза гендер-твиста (D5.1): сам механизм УЖЕ построен — until_ch-правка → точечный re-edit со сметой и $0-пере-пином (`repin.go`/`rebill.go`, D39.42 п.5/D39.45) | бэкенд | скоро (ПОДТЯНУТА D39.81: annot-v1 = источник замечаний для фронта — критический путь подключения) | отдельное решение (annot-половина — по контракту 14, D39.99) | D39.34(4), D33 п.5, D39.81 | | 49а | **ALTER-шаги миграций v8–v14 не идемпотентны вопреки шапке `migrate.go:9-11`** (полу-применённая БД не сходится; счётчик версий скрывает) — находка критика полноты пака-19 | бэкенд | когда-нибудь | отдельное решение | D39.56, PACK19_BUILD §6.9 | | 50 | F3-остаток идемпотентности | бэкенд | когда-нибудь | отдельное решение | D39.34(4) | @@ -130,6 +135,10 @@ | 123 | **Полигон: `jieba==0.42.1` — build-time зависимость артефакта контраста `eval/exp16/data/jieba_dict_general_zh.txt`** (пере-собран бэкенд-сессией 03.08, полный sha256 сошёлся с пином `16-bank-mining.md`); дописать в манифест окружения полигона с пометкой «build-time, не runtime» | полигон | когда-нибудь | строка манифеста | D39.96 п.6, отчёт §7-4/§6 | | 124 | **Калибровка снапшота (вопрос владельца 04.08, разбор D39.97 п.5): нацеленность, не агрессивность.** Три оси одним дизайн-паком: (а) недо-чувствительность — вердикт-несущие вызовы x/text не свёрнуты (вход: строка 119); (б) пере-охват — `EmbeddedVersion` фолдит все пары разом → пер-парный хеш (родня 115/120); (в) дешёвая перекупка: `tmctl resnapshot --dry-run` — байт-сверка тел по чекпойнтам (`msgsContentHash`), идентичные юниты пере-привязываются без пере-вызова, платятся только изменившиеся. «Поведенческий отпечаток вместо строки версии» отложен (пол ≠ доказательство) | бэкенд | когда-нибудь (перед МАСШТАБОМ — когда перекупки станут реальными деньгами) | дизайн-пак по D39.97 п.5 | D39.97 | +## Оркестратор №13 — ПРИЁМКА БАНК-АРБИТРАЖА: research/24 ПРИНЯТ и заленден (D39.102), 04.08 + +Адверсариальная приёмка тремя контурами: 12-агентный воркфлоу пере-ранил все строки «заявление=команда» — 8/8 CONFIRMED без расхождения чисел, 23/23 адресов §A подтверждены по HEAD `7f6270a`; независимый пересчёт денег из сырья $0.107334 ≈ леджер (расхождение пинга = склейка инкрементов C+E — маркер в «Полигоне»); слепое ревью кода банка (author≠reviewer) + 12 опровергателей дали находки СВЕРХ отчёта → строки 128–132 (главные: банкнота-парсер теряет хвост многословного dst; emitRankCap×writeAutoBank молча стирает термы из авто-банка; кап инъекции не считает маркер/гендер-ноты). Корзина «закрыть по нужности» ратифицирована целиком; строка 5 пере-скоуплена (остаток — рецензент спорных кластеров при ре-пробе 74, роутинг кластерными юнитами). 4 вопроса владельцу — D39.102 п.4; оговорки приёмки — ревью-шапка research/24. + ## Оркестратор №12 — ЗАКРЫТИЕ СЕССИИ, передача №13 (D39.101), 04.08 Доки актуализированы и подрезаны (CURRENT-STATE сжат, банк-промт заархивирован исполненным, README без стейла), голова D-лога D39.101. №13 начинает с приёмки банк-арбитража, дальше бэкенд-очередь (промт экрана 46 · tools/go.mod · блокеры контракта); вахта deepseek НАСТУПАЕТ >05.08. Грабли и нормы передачи — D39.101 п.4. @@ -319,6 +328,8 @@ Q1 = П1 цель-шов санкционирован («главное бэке **Арбитраж банка (строка 5, пере-запуск промта D39.89 по слову владельца, потолок $1.00) — ИСПОЛНЕН, отчёт `docs/research/24-bank-arbitration.md`, потрачено $0.0896 (04.08).** Главное: (1) голд 53 approved сида → 45 в BANK-FULL, из них у 27 промахов прод-банка верный dst лежал в вариантах черновиков лишь у 5 ⇒ **потолок любого «выбора из вариантов» = 17/45, селекционный арбитраж закрыт классом**; (2) свежий терминолог-соло (flash-low) бьёт бесплатный базис §C2-3 **+8/−0**, а **равноправный консилиум НЕ окупается**: +3 к само-согласованности = одна конвенция 古月; лучший одиночка glm-5 25/45 > лучший совет 23/45; добавление grok РОНЯЕТ совет 23→20; C3conf(взвешенный уверенностью) ≡ C3; ⟦TM-NO-DST⟧ = 0 на 35 вызовах трёх семейств; (3) **вербализованная ЧИСЛОВАЯ уверенность разделяет внутри модели** (AUC 0.77–0.85, слова хуже 0.63) при тотальной overconfidence (~88 при точности ~50%) — жить ей ordinal-очередью ревью, не арбитром; (4) **химера семьи 古月 воспроизведена причинно на границе батча** (свежий deepseek: «Гу Юэ» ровно в батче 2, «Гуюэ» ровно в батче 0), а по-терминная МАРШРУТИЗАЦИЯ (улики-первым) сама создала химеру 转-серии ⇒ единица арбитража/роутинга — кластер; DetectSeries разнодлинные семьи (古月×15, 蛊×14) не видит; (5) **проба инжекта: инъекция поднимает следование канону 43%→95%, НЕВЕРНАЯ строка законом принимается 6/6, с маркером ⟨проверить⟩ — тоже 6/6 (Δ=0 п.п.): пометка на транслятор-проводе поведенчески пуста**, цена неверной строки банка = ~100% заражение; (6) индустриальный обзор: стандарта арбитража термов не существует, наш дизайн впереди ближайшего аналога (DelTA first-wins); пропущенных стандартов нет. Рекомендации тремя корзинами в §D (строить: кластер-канал семей · intra-run CanonConflicts · наблюдаемость Signals/invented/conf · нормализованный голос foldVariants; закрыть: равноправный совет · кросс-модельные веса · self-consistency · селекция · отказ-сигнал). 4 вопроса владельцу в отчёте (мини-голд алиасов · конвенция составных фамилий · проба редакторского провода · фикс-пак корзины 1). Два адверсариальных раунда author≠reviewer пройдены (р.2 поймал 4 неточности, все вправлены; моя ложная оговорка про grok-ростер снята сырьём). **Достройка по вопросам владельца (тот же день, +$0.0161, итог $0.0960):** (а) $0-демо ценности на живом банке — intra-run чек связности поймал бы **18 невидимых противоречий на 149 финалов (12%)**, а нормализованный фолд голосов двигает топ лишь 1/75 (понижен до косметики); (б) **мультиязычная проверка ja→ru и en→ru (`multilang_probe.py`): направление инжект-выводов ПЕРЕНОСИТСЯ** — закон слушается, неверная строка принимается (ja 2/2, en 1/1), маркер Δ=0 на обеих парах; попутно ja-батч бэнк-вызова вернул термы упрощённым китайским — off-language класс, который парослепой экран `OffLanguage` отбил бы (несущая защита для будущей ja-пары). **Кросс-пары по слову владельца (тот же день, +$0.0113, итог $0.1073): §F/§G отчёта.** F1 zh→en: свежая en-редакция по тому же ростеру дала «Rank 1..9 · Grade A/B/C/D · Aperture · Gu Master» — **41/45 (91%) совпадений класса решения с подписями владельца** (банк НЕ однобокий; буквенный маппинг 甲→A, недостижимый для ru-моделей, en-моделью взят — довод за сид/бриф-канал); fan-канон RI по памяти сессии ещё ближе к владельцу (元石 primeval stone = «первобытный камень»); ру-специфика ровно одна — слитность «Гуюэ». F2 en→zh (Кристофф-2026): deepseek идеально связал семью *-blood (X血者), **glm сломал корень внутри ОДНОГО батча** и разошёлся в имени Aaron между соседними окнами (艾伦↔亚伦) — дрейф, от которого банк существует, воспроизведён на en→zh; deepseek выдумал 5 незапрошенных строк (нужность гарда `want[key]` кросс-парно подтверждена); личная оценка прозы обеих моделей — «редактируемо-издательская», узкое место всех направлений — термы, не слог. **§G — дизайн-синк алгоритмов бэкенда** (готовый вход фикс-пака класса D39.71): G1 `DetectFamilies` (данные-гейтед, имя=префикс/реалия=суффикс, без транзитивности, мёрж в seriesID) · G2 `ConsolidationConflicts` (18/149 на живом банке) · G3 наблюдаемость (Signals/Invented/Conf + фикс ParseReply-джойна) · G4 кластерный роутинг рецензента · G5 фолд-косметика · G6 явные «не делать». **Финальный рерайт отчёта по слову владельца (04.08):** сага/хроника правок убраны, факты и оговорки сохранены, §G сведён к уровню алгоритмов; **раунд 3 адверсариала (независимый агент по диффу v1→v2): числа 100% чисты пере-раном, новые клеймы подтверждены первоисточниками; его блокер (рерайт сжал зарегистрированные пре-реги §0/§E/§F) закрыт восстановлением пре-регов дословно с явной пометкой девиаций, потери фактов возвращены.** v1-черновик — `docs/archive/reports/DRAFT_BANK_ARBITRATION_V1_2026-08-04.md` (помечен черновиком в шапке и именем; перенесён по слову владельца 04.08). Сырьё durable `~/books/gu-zhenren/bank-arbitration/` (84 json), харнесс `eval/bank_arbitration/`. НЕ закоммичено — лендит оркестратор. +**→ ПРИЁМКА №13 (04.08, D39.102): ПРИНЯТО и залендено.** Поправка арифметики пинга выше: инкремент §E = **+$0.0065** ($0.0896 → $0.0960); «+$0.0161» — склейка инкрементов пробы C и §E ($0.0097+$0.0065), леджер отчёта чист (независимый пересчёт из сырья $0.107334). Оговорки приёмки — ревью-шапка `research/24`; находки сверх отчёта — строки 128–132. + **Сырьё арки банка + пробы фиксов (01.08) — приняты и залендены, детали в журнале выше (D39.65).** *(Закрытые записи 26.07 — пакет-6 «размеченный набор» (D39.39) и пакет-8 «три пре-замера» (D39.43–46/50/52) — в [archive/PROGRESS-2026-07-25-31.md](archive/PROGRESS-2026-07-25-31.md); пакеты Р6+P4 и ToS — журнал выше (D39.57/61).)* diff --git a/docs/README.md b/docs/README.md index ba62029f..300b1818 100644 --- a/docs/README.md +++ b/docs/README.md @@ -13,9 +13,9 @@ - [09-target-architecture.md](architecture/09-target-architecture.md) — целевая 7-слойная архитектура (статус стройки — шапка-таблица; §3 — карта находок H/L) · [10-prompt-architecture.md](architecture/10-prompt-architecture.md) — промпт-слой · [12-go-style-notes.md](architecture/12-go-style-notes.md) — норматив общности §0 · [13-tech-debt-anchors.md](architecture/13-tech-debt-anchors.md) — якоря техдолга (справочник к бэклогу, НЕ трекер) · [14-api-contract/](architecture/14-api-contract/) — **контракт API v0 фронт↔платформа (D39.99)**: нормативная спека OpenAPI 3.1 (типы фронта генерятся из неё) + компаньон-README (провенанс ✓/◆/○, К-вопросы; зонная копия `frontend/docs/api-contract/` — байт-зеркало, сверять при лендинге). - Исторические, читать через ⚠-баннеры: [01-decisions.md](architecture/01-decisions.md) (Р1–Р10) · [02-mvp-plan.md](architecture/02-mvp-plan.md) · [03-implementation-notes.md](architecture/03-implementation-notes.md) · [04-unhappy-paths.md](architecture/04-unhappy-paths.md) · [06-memory-risk-registry.md](architecture/06-memory-risk-registry.md). - `experiments/` — эмпирика полигона: [00-provider-quirks.md](experiments/00-provider-quirks.md) — **читать перед любым вызовом провайдера**; [08-cost-model-v2.md](experiments/08-cost-model-v2.md) — денежная модель; [09-pilot-protocol.md](experiments/09-pilot-protocol.md) — пилот Ф2.5; остальные 01–16 — отчёты закрытых экспериментов (судьба — в баннерах/D-логе). -- `research/` — фактура ресёрчей 01–23 (+24 арбитраж банка — в дереве, НЕ залендён, ждёт приёмки №13); у принятых — ревью-шапки, часть тел под ⚠ superseded: **читай баннер прежде содержимого**. Ключевые для навигации: 15 голос · 16 ридер-IDE · 17 внешняя критика · 18 рычаги качества · 19 нарезка · 20 банк-майнинг · 21 обзор транспорта · 22 доменные харнессы · 23 шов движок↔платформа (читать перед любым кодом стыка). +- `research/` — фактура ресёрчей 01–24; у принятых — ревью-шапки, часть тел под ⚠ superseded: **читай баннер прежде содержимого**. Ключевые для навигации: 15 голос · 16 ридер-IDE · 17 внешняя критика · 18 рычаги качества · 19 нарезка · 20 банк-майнинг · 21 обзор транспорта · 22 доменные харнессы · 23 шов движок↔платформа (читать перед любым кодом стыка) · 24 арбитраж банка (ПРИНЯТ D39.102: консилиум закрыт классом, вход фикс-пака банка — §G). - [PROGRESS.md](PROGRESS.md) — журнал: CURRENT-STATE + **ЕДИНЫЙ БЭКЛОГ** (единственный трекер) + живой хвост хроники. НЕ источник решений. -- Активные хендофф-промты сессий (состав обновляется при каждом лендинге — норма D39.80): [ORCHESTRATOR_SESSION_PROMPT.md](ORCHESTRATOR_SESSION_PROMPT.md) (роль/нормы; состояния не дублирует) · [POLYGON_PACKAGE4_SESSION_PROMPT.md](POLYGON_PACKAGE4_SESSION_PROMPT.md) (полигон, отложен) · **платформа: [../platform/docs/PLATFORM_SESSION_PROMPT.md](../platform/docs/PLATFORM_SESSION_PROMPT.md) (P0 ИСПОЛНЕН 04.08 — ждёт приёмки №13, D39.101 п.3-iv; дерево `platform/*` не залендено, не трогать)** · фронт: `frontend/docs/S3_SESSION_PROMPT.md` (замок ОТКРЫТ — контракт ратифицирован D39.99; первый шаг — правки спеки по D39.100). Зонные журналы фронта/платформы — `frontend-PROGRESS.md` / `platform-PROGRESS.md` в их зонах (решение владельца 04.08: прогресс зон только там). **Бэкендного активного промта НЕТ** — пак стандартов + дофикс archguard исполнены, приняты и залендены (D39.96/97, 04.08; промты в `archive/prompts/`); следующие бэкендные: пак экрана 46 (промт ждёт выдачи по D39.94 п.3) и малый пак tools/go.mod (строка 118, D39.97 п.4). Банк-арбитраж: промт ИСПОЛНЕН пере-запуском 04.08 и заархивирован (`archive/prompts/`); отчёт `research/24` + `eval/bank_arbitration/` в дереве НЕ залендены — **первая задача приёмки оркестратора №13**. +- Активные хендофф-промты сессий (состав обновляется при каждом лендинге — норма D39.80): [ORCHESTRATOR_SESSION_PROMPT.md](ORCHESTRATOR_SESSION_PROMPT.md) (роль/нормы; состояния не дублирует) · [POLYGON_PACKAGE4_SESSION_PROMPT.md](POLYGON_PACKAGE4_SESSION_PROMPT.md) (полигон, отложен) · **платформа: [../platform/docs/PLATFORM_SESSION_PROMPT.md](../platform/docs/PLATFORM_SESSION_PROMPT.md) (P0 ИСПОЛНЕН 04.08 — ждёт приёмки №13, D39.101 п.3-iv; дерево `platform/*` не залендено, не трогать)** · фронт: `frontend/docs/S3_SESSION_PROMPT.md` (замок ОТКРЫТ — контракт ратифицирован D39.99; первый шаг — правки спеки по D39.100). Зонные журналы фронта/платформы — `frontend-PROGRESS.md` / `platform-PROGRESS.md` в их зонах (решение владельца 04.08: прогресс зон только там). **Бэкендного активного промта НЕТ** — пак стандартов + дофикс archguard исполнены, приняты и залендены (D39.96/97, 04.08; промты в `archive/prompts/`); следующие бэкендные: пак экрана 46 (промт ждёт выдачи по D39.94 п.3) и малый пак tools/go.mod (строка 118, D39.97 п.4). Банк-арбитраж: исполнен, ПРИНЯТ и заленден (D39.102, 04.08); следующий бэнк-шаг — фикс-пак строки 128 (ГЕЙТ: подпись владельца, D39.102 п.4). - Зоны фронта (чужие, читать при касании стыка; каждая ведёт СВОЙ зонный бэклог — единый бэклог их строк не принимает, D39.84): [../frontend/](../frontend/) — веб-интерфейс: промт фронт-сессий S0–S7 + [STACK_DECISIONS.md](../frontend/docs/STACK_DECISIONS.md) (пины версий точными числами и ловушки, сверены с вебом 02.08) + [BACKLOG.md](../frontend/docs/BACKLOG.md) · [../platform/](../platform/) — SaaS control plane: README + [BACKLOG.md](../platform/BACKLOG.md) (П-1..П-5) + `docs/` (промт P0 · зонный журнал `platform-PROGRESS.md`). - `archive/` — история ([правила архива](archive/README.md)): закрытые промты (`prompts/`) · отчёты с ревью-шапками (`reports/` — на них ссылаются приёмки) · исполненные арх-доки (`architecture/`) · слайсы хроники `PROGRESS-*.md`. Инструкции оттуда не исполнять. - Диаграммы: [../backend/docs/components.puml](../backend/docs/components.puml) · [../backend/docs/pipeline.puml](../backend/docs/pipeline.puml) — дом рядом с кодом (D39.80), правятся бэкендом одним коммитом с кодом; вручную НЕ рендерить (владелец смотрит PlantUML-расширением VS Code). diff --git a/docs/architecture/05-decisions-log.md b/docs/architecture/05-decisions-log.md index 050b9d74..70f743a8 100644 --- a/docs/architecture/05-decisions-log.md +++ b/docs/architecture/05-decisions-log.md @@ -1467,3 +1467,15 @@ API-529-долг закрыт: 8-осевой refute-by-default воркфлоу **4. Грабли преемнику (проверено на себе):** пермишен-классифаер блокирует сорсинг `.env` — живые пробы промтом бэкенд-сессии или `!`-командой владельца · счёт очереди ТОЛЬКО скриптом по таблице (ручной список «скоро» недосчитывает жирные веса) · cwd в Bash-вызовах липнет между командами — пути абсолютные или с `cd` в начале · чужое незакоммиченное в дереве (артефакты арбитража) не трогать и не «прибирать» · голову D-лога и шапку PROGRESS сверять грепом перед закрытием (отставание головы — известный класс дефекта). **5. ДОБОР (тот же день): владелец поймал «актуализацию» на частичности — исполнен ПОЛНЫЙ док-свип** (6 сканеров по кластерам, 89 находок: 17 operative-wrong · 42 stale-pointer · 2 архив-кандидата · 28 nice-to-have; 11 файлов чисты). Применено ~60 правок по 15 файлам: CLAUDE.md (координация зонных журналов · контракт в источниках · онбординг платформы) · глоссарий +7 терминов (Платформа · S/P-нумерация · зонные журналы · контракт 14 · провенанс · ПТ-N · paused) · PROGRESS (два ПОТЕРЯННЫХ хроникальных заголовка D39.97/98 восстановлены — мои же правки их съели; пять 95-указателей → контракт 14; штампы; амендмент-маркеры «короткой приёмки»; разрыв таблицы склеен) · голова D-лога: два supersede-указателя (D39.88 · норма 30.07) · 09-target (стейл isRuTarget → D39.64; баннер пост-D39.101; ссылка на архив) · 10-prompt (пар-пути; язык промпта = Р6 отрицателен; Q4a/Q4c измерены; снапшот-фолд построен) · 13-tech-debt (9 закрытий стрелками «→ Dxx») · полигон-промт (P4-хвост ЗАКРЫТ ×2 · пре-рег-исключение · указатели) · ПТ-реестр (6 + квалификация STACK-путей) · ревью-шапки research/16 и /23 (контракт ратифицирован) · фронт-промты (S3: замок открыт, строка 95 снята; стоящий: 5 датированных поправок D39.99/100) · **S2-промт заархивирован** (`archive/prompts/FRONTEND_S2_SESSION_PROMPT.md`). **Отложено до приёмки P0 (зона живая): 2 правки `platform/README.md`** (стейл «промта ещё нет»; «живая стоимость» против D39.84) и архивация P0-промта — №13 при лендинге платформы. Урок — в памяти оркестратора (`doc-actualization-means-full-sweep`). (04.08.2026, оркестратор №12). ✅ + +## D39.102 — ПРИЁМКА БАНК-АРБИТРАЖА (оркестратор №13): research/24 ПРИНЯТ — все числа чисты пере-раном; консилиум закрыт классом, бэкенд-доработки спланированы строками 128–132, 4 вопроса владельцу (04.08). ✅ + +**1. Вердикт.** Отчёт `research/24-bank-arbitration.md` + харнесс `eval/bank_arbitration/` + черновик v1 (`archive/reports/`) ПРИНЯТЫ и залендены. Верификация тремя контурами: (а) 12-агентный воркфлоу — пере-раны ВСЕХ строк «заявление = команда» ($0, офлайн по сырью): 8/8 CONFIRMED без единого расхождения чисел; 23/23 адресов §A подтверждены по HEAD `7f6270a`; веб-сверка §D по первоисточникам; байт-сверка инжект-пробы с рендером движка; (б) независимое ревью харнесса: деньги пересчитаны из сырья — $0.107334 против $0.107335 (округление записи), цены = `models.yaml`, 84/84 finish=stop, слаг-дрейфа нет, голд 53/53 против сида; арифметика ПИНГА («+$0.0161») — склейка инкрементов C+E, леджер чист; «потолок $1.00» — со слов сессии (ратифицирован $1.20, D39.90 п.5), при факте $0.107 беспредметно; (в) слепое ревью кода банка (author≠reviewer) + 12 опровергателей. Оговорки приёмки (конфаунд армов C/D · хрупкий C4 · SC=недетерминизм провайдера · пары-иллюстрации A4 · атрибуция Xiong'23) — в ревью-шапке research/24; выводов отчёта они не двигают. + +**2. Ратификации по итогам замера** (в русле приоров D39.46/50/65/69): корзина «закрыть по нужности» ратифицирована ЦЕЛИКОМ — равноправный консилиум как прод-механизм · кросс-модельное взвешивание уверенностью · self-consistency N прогонов · селекция «выбери из вариантов» (потолок 17/45 классом) · отказ-сигнал ⟦TM-NO-DST⟧ · эмбеддинг-фетч (остаётся закрыт D39.69). Строка 5 пере-скоуплена: остаток Q2 = рецензент-второго-семейства ТОЛЬКО на спорных КЛАСТЕРАХ (слот при ре-пробе 74), роутинг целыми family/series-юнитами (урок E1-химеры), эмиссия рецензента — та же draft/⟨проверить⟩ (инвариант D39.42 §C2-7 не тронут). Вербализованная числовая уверенность — ordinal-очередь ревью ВНУТРИ модели (AUC 0.77–0.85), не арбитр и не кросс-модельный сигнал. Маркер ⟨проверить⟩ на транслятор-проводе поведенчески пуст (Δ=0) — доктрина «неподписанное с пометкой» получает цену; проба редакторского провода — вопрос владельцу. + +**3. Бэкенд-доработки строками.** **128** — фикс-пак банка (вход §G, класс D39.71; гейт — подпись владельца, вопрос №4 отчёта). **129** — банкнота-парсер теряет хвост многословного dst (`banknote.go:236` против ре-джойна `terminology.go:880-885`; находка приёмки против клейма A10). **130** — emitRankCap×writeAutoBank: терм, выпавший из топ-200, молча стирается из авто-банка посреди книги; FL-3 ратифицирован ДО авто-провода D39.42, взаимодействие не ратифицировалось. **131** — кап инъекции не считает маркер/гендер-ноты: авто-книга превышает бюджет ~на 40–60% (биллинг компенсирован резервацией по рендеру); фикс двигает RequestHash ⇒ СТОП-решение. **132** — стойкий аутедж ТОЛЬКО банк-провайдера валит ран вопреки коммент-контракту «optional step never aborts». Строка 38 дополнена указателем «со слов» (ординал-адресация чекпойнтов). Опровергнуто/не заводится: term-класс эмиссии (ратифицирован замером D39.43/50, гейт Q7 строки 18) · «луна»-пример Палладия (жадная сегментация не даёт; класс «сама/вода» реален, бласт-радиус — порядок drafts под подписью) · NoDst-почти-сентинел на zh-ru (target_script обязателен конфигом, OffLanguage отбивает; остаток — латиница-target, хвост 128). + +**4. Вопросы владельцу** (подняты отчётом, приёмка подтверждает): (i) мини-голд алиасов §E-1 research/20 (висит с 17.07) — делать?; (ii) «Гуюэ» слитно — пар-норма Палладия для составных фамилий (данные класса Z-B3, чинит 8/45) или вкус книги (канал — сид)?; (iii) санкция пробы редакторского провода двухсекционки (~$0.05); (iv) выдать промт фикс-пака 128 одним паком (перекупка бэнк-батчей — центы)? Рекомендация оркестратора: (ii) пар-норма и (iv) да. + +**5. Гигиена лендинга:** путь промта в шапке research/24 → архив; аннотации приёмки в §A4/§D; пинг «Полигон» получил закрывающий маркер с поправкой арифметики; README/CURRENT-STATE актуализированы; `platform/*` не тронуто; сырьё (84 json) сверено sha256-манифестом до/после пере-ранов — байт-нетронуто; `gold.jsonl`/`forms_dump.json` пере-раном воспроизведены байт-в-байт. diff --git a/docs/archive/reports/DRAFT_BANK_ARBITRATION_V1_2026-08-04.md b/docs/archive/reports/DRAFT_BANK_ARBITRATION_V1_2026-08-04.md new file mode 100644 index 00000000..50a5e974 --- /dev/null +++ b/docs/archive/reports/DRAFT_BANK_ARBITRATION_V1_2026-08-04.md @@ -0,0 +1,773 @@ +> ⚠ **ЧЕРНОВИК (v1, НЕ действующая редакция).** Рабочая версия отчёта research/24 до финального рерайта 04.08 — сохранена как архив-черновик: полная хроника сессии, пре-регистрации в исходной записи. **Действующая редакция — `docs/research/24-bank-arbitration.md`**; при любом расхождении верить ей. Числа обоих файлов идентичны (сверено раундом 3 адверсариала). + +# research/24 — Арбитраж банка памяти: консилиум, уверенность моделей, инжект/фетч + +**Сессия ресёрч+полигон, 04.08.2026.** Исполнение `docs/BANK_ARBITRATION_RESEARCH_SESSION_PROMPT.md` +(выдан D39.89; пере-запуск после прерванного захода 02.08 — артефактов того захода в дереве нет, D39.90 п.5). +Не закоммичено — лендит оркестратор. + +## Эхо-шапка + +- **Скоуп:** проверка гипотезы владельца (консилиум без голоса · самооценка уверенности · инжект/фетч) + + прямой запрос владельца 04.08: общий взгляд на алгоритм банка, «хватает ли текущего», индустриальный + стандарт, который могли пропустить. +- **Подрезка D39.90 п.5 учтена:** A целиком · B1 голд · B3 формы консилиума с контролем «одна модель N раз» · + B2 свёрнута до под-пробы внутри B3 · C — малая адресная проба (владелец 04.08 назвал инжект явно, поэтому + не отложена совсем, а сокращена). +- **Деньги:** потолок владельца 04.08 = **$1.00** (перекрывает $2.00 промта и $1.20 подрезки); + суб-потолки сессии: пробы B ≤ $0.70 · проба C ≤ $0.30. Факт — §Деньги в конце. +- **Зона записи:** этот файл + `eval/bank_arbitration/` + секция «Полигон» в PROGRESS. Сырьё моделей — + durable в `~/books/gu-zhenren/bank-arbitration/`. Не коммичу. +- **Стенд:** пробы своим харнессом против API напрямую (не через движок — в `backend/` незакоммиченный пак + живой сессии); перенос выводов в движок называется явно. `coldrun-a` — только чтение. +- Базлайн качества банка = **coldrun-a** (D39.86: coldrun-b сломан транспортом, сравнение с ним запрещено). + +--- + +## §0. ПРЕ-РЕГИСТРАЦИЯ ПРОБ (записано ДО первого платного вызова; норма D39.46) + +Дата/время фиксации: 2026-08-04, до каких-либо платных вызовов этой сессии. Голд (§B1) собран ДО +пре-регистрации ($0), его числа: 53 approved сида → 45 в BANK-FULL coldrun-a, из них 34 со spread≥2. + +### Пассы (все — полный голд-набор одним батч-протоколом, engine-faithful RenderBatch): + +| Пасс | Модель | Режим | Что несёт | +|---|---|---|---| +| ds1..ds3 | deepseek-v4-flash | `reasoning_effort:"low"`, temp 0 | S1 (свежий одиночный) + SC (само-согласованность N=3) + числовая уверенность 0–100 | +| dsw | deepseek-v4-flash | то же | словесная шкала уверенности (точно/скорее да/не уверен/не знаю) | +| glm1 | glm-5 | thinking disabled (форма движка) | второе семейство + числовая уверенность | +| mis1 | mistral-large-2512 | без reasoning | третье семейство + числовая уверенность | +| gro1 (опция при остатке бюджета) | grok-4.3 | дефолт (low) | четвёртое семейство, чувствительность состава совета | + +Эффорты каждого пасса печатаются в отчёте (иначе числа несравнимы — §7 промта). + +### Формы арбитража (агрегация офлайн, $0): + +- **P0 — бесплатный базис §C2-3:** топ-вариант ранжирования движка (колонка вариантов BANK-FULL, + bankStopRows рендерит best-ranked first). Термы без вариантов → P0 пуст (честный отказ базиса). +- **P1 — прод-референс:** сведённый dst coldrun-a (терминолог на до-катоверных весах). +- **S1** = ds1. **SC** = большинство(ds1,ds2,ds3), при 3-стороннем расхождении → ds1. +- **C3 — равноправный совет:** большинство(ds1, glm1, mis1) по нормализованному совпадению; + полное расхождение → P0-топ, если хоть один голос совпал с ним, иначе ds1. +- **C3conf — взвешенный:** argmax по сумме заявленных уверенностей проголосовавших за вариант моделей. +- **E1 — улики-первым:** P0 стоит; «спорный» терм := (spread≥2 И разрыв top1−top2 по чанкам ≤1) ИЛИ + singleton-улика (top1 предложен 1 чанком) → на спорных решает C3. Цена печатается долей от полного совета. + +### Метрики: + +- Точность против голда: нормализованное точное совпадение (casefold · ё→е · схлоп пробелов · срез «»/кавычек). + Промахи вскрываются глазами; спорные эквивалентности печатаются отдельно, автоматом НЕ засчитываются. +- Парные сравнения форм: счёт термов «A прав ∧ B неправ» против обратного (не голые проценты). +- **Кластерная связность:** семьи 古月-* (7 поверхностей, РАЗНОЙ длины — DetectSeries её не видит), + 蛊-* (蛊师/蛊虫/月光蛊 + голова 蛊 вне банка), серии 等/转 (равнодлинные — детектируются). Метрика: + консистентность конвенции внутри семьи у каждой формы (одна голова/конвенция у всех членов — да/нет), + и отдельно: даёт ли по-терминный агрегатор химеру там, где одиночная модель консистентна. +- **B2-под-проба (уверенность):** AUC(уверенность → верно/неверно по голду) per-model (bootstrap 90% CI); + устойчивость: медиана |Δconf| ds1↔ds2↔ds3 и доля флипов ответа; сравнимость шкал: |Δ средних conf| между + моделями на одном наборе; канал отказа: счёт ⟦TM-NO-DST⟧ и его стабильность между ds1..ds3. + +### Критерии (успех/провал, зафиксированы ДО запуска): + +1. **БАР (в):** форма «бьёт базис P0», если парное преимущество (термы A-прав-P0-неправ минус обратные) + ≥ **+5** на 45 голд-термах. Меньше — «не бьёт» (на N=45 меньшее неотличимо от шума). +2. **Q2 (окупаются ли семейства):** C3 против SC парное преимущество ≥ **+3**; меньше ⇒ «разные семейства + не окупаются, хватает N прогонов одной модели» (легитимный исход). +3. **Уверенность разделяет**, если AUC ≥ 0.70 и нижняя граница CI > 0.5 минимум у 2 моделей из 3; + иначе — «уверенность как арбитр закрыта по нужности». Числа против слов: |ΔAUC| ≥ 0.05 решает форму. + Шкалы несравнимы, если |Δ средних conf| > 20 п. ⇒ сырой кросс-модельный скор как решающее правило запрещён. +4. **Кластеры:** ≥1 новая химера у C3 там, где SC/P1 консистентны ⇒ возражение §4 промта подтверждено + (единица арбитража обязана быть кластером). +5. **Проба C (инжект, формат RenderGlossaryBlock/RenderEditorConstraintBlock байт-близко):** + 6 чанков × 4 арма (без инъекции · верный закон · НЕВЕРНАЯ строка законом · та же неверная строка + с маркером ⟨проверить⟩), deepseek-v4-flash low, temp 0. Критерии: маркер «читается мягче закона», если + послушание(закон-неверный) − послушание(⟨проверить⟩-неверный) ≥ **20 п.п.**; «пометка = закон» (дефект), + если < **10 п.п.** Вред реален, если неверная строка законом принимается в ≥ **50%** случаев. + Между 10 и 20 п.п. — «неразделимо на N=6×набор строк», честно печатается. + +### Смета ДО запуска (проектная): + +B: deepseek 4 пасса ≈ $0.02 · glm-5 ≈ $0.04 · mistral ≈ $0.02 · grok (опция) ≈ $0.05 → **≈ $0.13**. +C: 24 вызова flash-low ≈ **$0.05**. Итого ≈ $0.18 из $1.00. СТОП-условия: любой суб-потолок +(B $0.70 / C $0.30) = стоп+релей. + +*(Секции §A–§D заполняются после исполнения; эта пре-регистрация после запуска не правится.)* + +--- + +## §A. Критика текущего алгоритма в коде (Работа A, $0; диагноз, не правка) + +Маршрут терма: `miner/` (WHICH) → `banknote.go` (WHAT, голоса чанков) → `terminology.go` +Merge/AttachKWIC/ScoreVariants → `series.go` co-батчинг → `classify.go` тип-фаза → `terminologist.go` +(эмиссия auto/draft) → `membank/memory.go` Select/Render → `mempostcheck.go`. Классы дефектов: +**сломано** (неверный результат) · **хрупко** (верно случайно) · **дорого** (непропорциональная цена) · +**слепо** (класс не покрыт/не виден). Все адреса перечитаны в HEAD этой сессией. + +### A1. Единица решения — строка; связность системы термов держится тремя СЛУЧАЙНЫМИ механизмами — «слепо» + +- `ScoreVariants` ранжирует варианты одного кандидата независимо (`terminology.go:393-450`); единственный + межстрочный фактор `neighbourAgrees` требует УЖЕ подписанной строки (`terminology.go:465-482`) — на + холодном/автономном банке мёртв (замер D39.65: сработал 2/23 и только на ничьих). Посылка промта + подтверждена чтением. +- `DetectSeries` ловит ТОЛЬКО равнодлинные наборы с общей головой и одной варьирующей позицией + (`series.go:37-42`, без транзитивного замыкания — осознанно). **Семьи общего корня РАЗНОЙ длины не + ловятся ничем:** в живом BANK-FULL их две крупных — 古月-семья (15 поверхностей: 古月 · 古月博 · + 古月冻土 · 古月山寨 …) и 蛊-семья (14: 蛊师 · 蛊虫 · 月光蛊 · 本命蛊 · 一转蛊师 …). Цена измерена + голдом: **конвенция 古月 («Гуюэ» одним словом против «Гу Юэ») стоила 8 из 45 голд-строк** — восемь + промахов ОДНИМ решением (§B1). +- Третий, нигде не записанный компенсатор: Merge сортирует кандидатов по ключу (`terminology.go:212`), + поэтому ПРЕФИКСНЫЕ семьи (古月*) получают смежность в батче случайно — а СУФФИКСНЫЕ (X蛊 — + голово-финальная морфология, главный класс CJK-реалий) рассеиваются: в батчах этой сессии 月光蛊 → + батч 0, 本命蛊/蛊师/蛊虫 → батч 1, 一转蛊师/三转蛊师 → батч 3. Связность 蛊-семьи не защищена вообще. +- **Вердикт-тройка:** посылка — верна и ШИРЕ записанной (в D-логе названы серии, префикс-лотерея не + названа); нужность — межстрочная связность подтверждена деньгами голда (8/45); форма — кластер-канал + «семья по общей морфеме» (кандидат уже назван в D39.65 п.4: «кластер по общей исходной морфеме»), + НЕ транзитивный, головой из `script-series.txt`-данных; альтернатива «второй проход ре-чтения» дороже + и не чинит рассеяние по батчам. + +### A2. Потолок арбитража-как-СЕЛЕКЦИИ измерен: 22 из 27 промахов не имели верного ответа в вариантах — гейт на класс дизайнов + +По голду §B1: у 27 промахов прод-консолидации верный (подписанный) dst лежал в вариантах черновиков +только у 5. **Максимум ЛЮБОЙ формы «выбери лучший из предложенных» = 17/45 (12 у базиса §C2-3 + 5).** +Все дизайны вида «модели голосуют по вариантам / скор выбирает победителя» упираются в этот потолок ДО +всякого вопроса о калибровке. Верный dst чаще требует ГЕНЕРАЦИИ по контексту (гора Цинмао · смертный · +класс А) либо знания конвенции пары/владельца. Это сужение посылки гипотезы консилиума, полученное $0. + +### A3. `Related`/`containmentRelations` — обрезка на ПЕРВЫЕ 4 по алфавиту — «хрупко» (минор) + +`terminology.go:242-256`: скан отсортированных mined-ключей, break на 4 — выбор лексикографический, не +по релевантности; для 蛊 с 14 родственными поверхностями показанные 4 произвольны. Заявка «контекст для +человека и модели, не индекс» честна, но выбор ЭТИХ четырёх ничем не мотивирован. Форма: тот же cap, но +по числу общих рун (механика веса уже написана в `CanonFor`, `terminology.go:714-765`). Нужность — +низкая, пока A1 не построен; вместе с кластер-каналом закрывается сама. + +### A4. Однопроходность: внутри-прогонные противоречия консолидаций не проверяет НИКТО — «слепо», $0-фикс-кандидат + +- Канон читается один раз ДО всех батчей (`terminologist.go:284`); решения батча i невидимы батчу i+1. +- `CanonConflicts` сверяет консолидации только с ПОДПИСАННЫМ банком (`terminologist.go:335`, + `terminology.go:787-812`). Пара свежих консолидаций, противоречащих ДРУГ ДРУГУ (蛊师 ⊂ 一转蛊师 с + потерянной головой; 空窍→«кунцяо» при 开窍→«открытие точки»), не проверяется ничем — хотя весь + механизм (containment + lexemeSubset) уже написан строк на 20 выше. На автономном курсе (D39.59/67: + подпись опциональна) подписанных строк ноль и деterministic-рубеж связности ПУСТ. +- **Вердикт-тройка:** посылка — курс на автономность делает канон-якорь пустым на самом важном прогоне + (первом); нужность — прямая (это second-half дефекта A1); форма — прогнать СУЩЕСТВУЮЩИЙ + `CanonConflicts` по парам consolidated×consolidated ($0, чистая функция) против альтернативы + «второй платный проход само-ревью» (платный, не детерминированный). + +### A5. `foldVariants` фолдит только байт-идентичные dst — частотный фактор дробится об орфографию — «хрупко» + +`terminology.go:222-237`. «лунный гу ×2» + «Лунный гу ×1» + «гу лунного света ×1» считаются разными +вариантами; §C2-3 видит осколки, а не конвенцию (живой пример — 月光蛊, spread=7 при фактических ~4 +конвенциях). Реальную частоту конвенции не видит ни скоринг, ни владелец в колонке spread. Форма: голос +считать по НОРМАЛИЗОВАННОЙ цели (casefold + ё/е + схлоп дефис/пробел), поверхности показывать сырыми; +альтернатива «оставить как есть» завышает spread и раздаёт частотный фактор случайно. + +### A6. KWIC: сэмплинг = ПЕРВЫЕ N вхождений — смещение к началу книги — «слепо»; плюс строка 37 «дорого» + +`kwicFor` берёт первые maxPer вхождений в порядке (chapter, chunk) (`terminology.go:308-329`) — термин, +чей смысл раскрывается/сдвигается поздно, показан ролью только ранними контекстами. Замер D39.50 +(«3×40 достаточен, не пере-открывать») мерил РАЗМЕР сетки подача×ширина, не СТРАТЕГИЮ сэмплинга — +ось «первые-N против стратифицированных по книге» не мерена никем (не пере-открываю размер, называю +ось). Плюс подтверждена квадратичность строки 37: скан всех чанков на кандидата, `window()` пересчитывает +руны префикса на каждом вхождении (`terminology.go:332-346`); multi-pattern автомат уже есть в репо +(`membank/memory.go:872-918`) — переиспользовать, не писать новый. + +### A7. Наблюдаемость арбитража: «почему у терма такой dst» сегодня НЕОТВЕТИМО — «слепо», гейтит любой будущий арбитраж + +- `Variant.Signals` — аудит-трейл §C2-3 (`terminology.go:86`) — вычисляется и ВЫБРАСЫВАЕТСЯ: в + стоп-таблицу идут только «dst ×N» (`mining.go:256-270`), Signals не читает ни один потребитель. +- `reasoning_content` терминолога не персистится нигде (grep по `llm/`+`store/`: единственное вхождение — + док-коммент `capability.go:63`); чекпойнт хранит только content. +- Сочинённый вне улик dst (10–15/75 по D39.65) не флагуется: колонки «dst ∉ вариантов черновиков» нет — + а это $0-предикат по уже собранным данным. +- Итог: оператор видит «вот варианты, вот финал»; связать финал с уликой, контекстом или хотя бы фактом + «финал изобретён вне улик» нельзя. Любой будущий консилиум/рецензент, чей выход тоже не будет + трассируем, умножит эту слепоту, а не вылечит. + +### A8. Эмиссия (переквантифицировано голдом, чинить НЕ порогом): банк-автоном не видит 15% подписанного канона + +8 из 53 подписанных термов вообще отсутствуют в BANK-FULL: 蛊 (голова книги — строка 18, сид-половина) · +修炼/修行 (класс term, recall 0.040 — D39.43/50, расширение закрыто механизмом) · 资质 · 长生 · 江牙 · +月影蛊 · 血颅蛊. Ничего нового против D39.50 — но это ЧИСЛО стоит держать рядом с любым разговором о +качестве арбитража: у лучшего арбитра нет строк, которых нет. + +### A9. Инжект-сторона: точечные наблюдения + +- Бюджет режется ПРЕФИКС-катом (`memory.go:615-628`): первая переполнившая строка обрезает всё после + себя, включая короткие строки, которые влезли бы. Порядок приоритетный, страдает наименее доверенный + хвост — «дорого» в мягкой форме, недозаполнение шире необходимого. Минор. +- Sticky-глубина 2 со сбросом на границе главы (`memory.go:112`) — местоименная сцена глубже двух чанков + теряет канон; осознанный дизайн, как дефект не измерен. +- **Двухсекционная инъекция: приор промта подтверждён — замера «⟨проверить⟩ читается мягче закона» не + существовало** (тесты пинят байты рендера, не поведение модели). Проба C этого пака — первый замер + (транслятор-провод; редакторский провод остаётся немеряным — см. критик полноты). +- Пост-чек `mempostcheck.go` — честный флаггер: decl-aware, sticky исключён, известный recall-класс + назван в доке (`mempostcheck.go:160-176`). Дефектов сверх записанного не нашёл. + +### A10. Банкнота: форма верная + +Невоспроизводимость (Жаккар 0.077–0.40) компенсируется агрегацией по ВСЕМ прогонам с голосами по чанкам +(`banknote.go:470-505`), суперседед-ответы включены осознанно; порядок колонок восстанавливается +инвариантом засвидетельствованности. Дефектов сверх записанного не нашёл. + +--- + +## §B. Арбитраж: голд · базисы · формы консилиума · уверенность + +### B1. Голд-набор и его смещение ($0) + +**Сборка:** `eval/bank_arbitration/build_gold.py` → `gold/gold.jsonl` (провенанс на каждой строке). +Ядро = сид v2 (`~/books/gu-zhenren/guzhenren-seed-v2.yaml`): 53 записи `status:approved` с подписанным +dst. Джойн по нормализованной поверхности (src + алиасы) против банка coldrun-a (BANK-FULL.tsv 150 +поверхностей + KWIC/варианты из bank-stop таблицы): + +- **45 из 53 в банке**; из них **34 со spread≥2** (есть из чего выбирать). +- **8 не в банке** — и это ровно известные дыры эмиссии, переквантифицированные голдом (§A8): + 蛊 · 修炼 · 修行 · 资质 · 长生 · 江牙 · 月影蛊 · 血颅蛊. + +**Смещение, честно:** (1) сид = термы, до которых у владельца дошли руки — сдвиг к важным и уже спорным; +(2) сид писался ПОСЛЕ прогонов exp13–16, часть подписей могла быть сформулирована при виде машинных +вариантов — «независимость» голда от машинного словаря неполная; (3) один голд — одна книга одной пары; +(4) термы с «вкусовым» dst (класс А/Б/В/Г; Монах Цветочного Вина) недостижимы для модели без брифа — +это не дефект голда, а свойство задачи (D39.47), но долю таких строк надо помнить при чтении точностей. +Мини-голд алиасов §E-1 research/20 в этот голд НЕ входит (запрос владельцу — §Вопросы). + +### B2-предварительное. Бесплатные базисы против голда ($0, `score_baselines.py`) + +| Базис | Точность | Комментарий | +|---|---|---| +| **P0** — топ-вариант §C2-3 (ранжирование движка, колонка BANK-FULL) | **12/45** | бесплатный детерминированный базис БАР-(в) | +| **P1** — сведённый dst терминолога coldrun-a (до-катоверные веса) | **18/45** | парно к P0: **+7/−1** — платная консолидация УЖЕ бьёт формулу | + +**Анатомия 27 промахов P1 (все единицы вскрыты в сырье скрипта):** +- **8 промахов = ОДНА конвенция 古月** («Гу Юэ X» против подписанного «Гуюэ X» одним словом — правило + Палладия для составной фамилии, ср. Сыма/Оуян; лежит в note сида). Кластерный дефект A1 в деньгах. +- **4 промаха = серия 等** («класс Цзя»/«ранг И»… против «класс А/Б/В/Г») — серийная несвязность + выбор + регистра владельцем; подписанного ответа НЕТ ни в одном черновом варианте. +- Остальное — класс «слишком китаизированно»/реалия-транслит (空窍→кунцяо · 元海→Юаньхай · 真元→чжэньюань · + 元石→юаньши · 青茅山→Цинмаошань · 花酒行者→Хуацзю Синчжэ …) + лексические выборы (凡人 · 困境 · 炼化). +- **Ключевое число: только у 5 из 27 промахов верный dst вообще ЛЕЖАЛ в вариантах черновиков.** + ⇒ **потолок ЛЮБОЙ формы «выбери из предложенного» = 17/45.** Селекционные консилиумы («модели + голосуют по вариантам», «скор выбирает победителя») упираются в потолок ДО вопроса о калибровке. + Верный dst чаще требует генерации по контексту или знания конвенции пары/владельца. +- Оговорка адверсариального прохода: несправедливо засчитанных промахов **0** — нормализация уже фолдит + регистр/ё/кавычки; единственная нефолдженная ось (пробел слитно/раздельно) НЕСЁТ подписанное решение + владельца в обе стороны (古月→«Гуюэ» слитно, но 人祖→«Жэнь Цзу» раздельно), фолдить её нельзя. Если бы + владелец когда-нибудь объявил эту ось неканоничной, P1 поднялся бы до 26/45 — сид фиксирует обратное. + +### B3. Формы консилиума против базиса (платные пассы; критерии §0) + +Все пассы прошли начисто: 30+5 вызовов, каждый `finish=stop`, отказов и пустых тел ноль; эффорты в +таблице §0 (deepseek `reasoning_effort:"low"` — печатаю явно: на вендор-дефолте high бэнк-вызовы +покупают пустое, D39.86). Ответы всех пассов — 63/63 строк, парсер потерь не зафиксировал. + +| Форма | Точность | Против P0 (парно) | Комментарий | +|---|---|---|---| +| P0 базис §C2-3 | 12/45 | — | ни одного термина, где P0 прав, а любая свежая форма неправа | +| P1 прод coldrun-a | 18/45 | +7/−1 | старые веса, era-конфаунд (см. критик полноты) | +| **S1** deepseek-соло (low) | **20/45** | **+8/−0** | | +| SC = 3× та же модель | 20/45 | +8/−0 | **+0/−0 против S1 — само-согласованность не покупает ничего** | +| **C3** совет 3 семейств | **23/45** | **+11/−0** | против SC: **+3/−0** — ровно на пороге критерия 2 | +| C3conf взвешенный | 23/45 | +11/−0 | **+0/−0 против C3 — веса из уверенности не двигают ничего** | +| E1 улики-первым | 22/45 | +10/−0 | −1 против C3; **создал химеру** (см. B4) | +| glm-5 соло | **25/45** | | **лучший одиночка выше лучшего совета** | +| mistral-соло | 23/45 | | | +| grok-4.3 соло | 12/45 | | худший — на уровне бесплатного базиса | +| C4 = совет 4 семейств | 20/45 | | **добавление слабого члена УРОНИЛО совет 23→20** | + +**Вердикты по критериям §0:** +1. **БАР (в) пройден** — но не консилиумом, а СВЕЖЕСТЬЮ: уже одиночный deepseek на low бьёт базис +8/−0. + Честная формула: «платная генеративная консолидация по KWIC бьёт бесплатную формулу» — это + пере-подтверждение D39.65 (роль = эффективный консолидатор), теперь с голдом и знаком КАЧЕСТВА, + которого у D39.65 не было. +2. **Q2 (окупаются ли семейства): формально +3 = порог, содержательно — НЕТ.** Все три добычи C3 против + SC — строки ОДНОЙ конвенции 古月 (glm+mistral переголосовали deepseek «слитно»). Это не три + независимых выигрыша, а один кластерный. При этом: лучший одиночка (glm 25/45) > лучший совет (23/45); + совет из 4 хуже совета из 3 (grok тянет к «Гу Юэ» и на паритетах ломает большинство); C3conf ≡ C3. + **Равноправный совет как прод-механизм закрыть; что остаётся жить — рецензент/эскалация спорных + КЛАСТЕРОВ вторым семейством (замер Q2 строки 5 — см. §D).** +3. **Уверенность (B2-под-проба): числовая самооценка РАЗДЕЛЯЕТ внутри модели** — AUC ds 0.770 + (CI90 0.656–0.879) · glm 0.851 (0.742–0.947) · mistral 0.825 (0.719–0.915); критерий «≥0.70 и CI>0.5 + у ≥2 моделей» ВЫПОЛНЕН. Словесная шкала хуже числовой: AUC 0.630 (0.556–0.704), ΔAUC≈0.14 ≥ 0.05. + Устойчивость: медиана размаха conf между тремя повторами 10 п., флипов ответа 9/45. + **НО:** (а) все модели тотально overconfident — средняя conf 87.7–90.1 при точности 44–56%: + как ВЕРОЯТНОСТЬ шкала не значит ничего, работает только как РАНГ внутри одной модели; (б) средние + шкал между моделями совпали (Δ<3 п.) при РАЗНОЙ точности ⇒ одинаковое число ≠ одинаковое качество. + ⚠ Пре-рег-метрика сравнимости (|Δ средних| > 20) при этом НЕ сработала — она слепа ровно к этому + случаю «одинаково overconfident при разной точности»; вывод «сырой кросс-модельный скор как решающее + правило запрещён» — ПОСТ-ХОК уточнение неудачной операционализации, и держится он на + пре-зарегистрированной ФОРМЕ C3conf, которая дала +0/−0 делом; (в) согласуется с литературой + (Kadavath 2022 · Tian 2023 · «Overconfidence is Key» 2024 — см. §D-индустрия). + **Форма жизни уверенности: ordinal-очередь ревью, не арбитр.** +4. **Канал отказа: ⟦TM-NO-DST⟧ = 0 использований во всех 7 пассах** — модели никогда не отказываются. + Оговорка субстрата: D39.50 мерил размах сентинела на ХВОСТЕ расширенной эмиссии; наш субстрат — + банк-строки голда, так что пере-подтверждена половина приора («роль всегда отвечает строкой»), + не весь. + +### B4. Кластерная связность (возражение §4 промта — проверено) + +Три семьи с голдом: 古月 (8 строк, разнодлинная — DetectSeries НЕ видит), серии 转 и 等 (равнодлинные — +видит и со-батчит; в пробе со-батчены по форме движка): + +| Семья | P1 (прод) | S1 (соло) | C3 (совет) | E1 (улики-первым) | +|---|---|---|---|---| +| 古月 | консистентна («Гу Юэ» — раздельно, ПРОТИВ подписи) | **ХИМЕРА** (4׫Гу Юэ» + 4׫Гуюэ») | консистентна («Гуюэ» = подпись) | консистентна | +| 转 | консистентна («ранг») | консистентна | консистентна | **ХИМЕРА («оборот»+«ранг»)** | +| 等 | **ХИМЕРА** («класс Цзя»/«ранг И» — дефект D39.65) | консистентна («уровень X», мимо голда) | консистентна | консистентна | + +- **Химера S1 на 古月 воспроизведена ПРИЧИННО на границе батча:** семья разрезана батчами 0 и 2 + (ключ-сортировка дала смежность, но пакер разрезал), и deepseek дал «Гу Юэ» ровно членам батча 2 и + «Гуюэ» ровно членам батча 0. Это дефект класса D39.65 строка 21 (甲等→«класс»/乙等→«ранг» через + границу батча), повторённый на СЕМЬЕ, которую серия-детектор не со-батчит. Механизм лечения известен + и уже ратифицирован для серий (§1 D39.69) — его надо расширить на семьи (§D п.1). +- **E1 создал химеру там, где ВСЕ голосующие консистентны:** для неспорного 一转 E1 взял P0-топ «первый + оборот», для спорных членов — советское «ранг». **Честно к пре-регу: критерий 4 §0 буквально + зарегистрирован для C3 — и у C3 он НЕ сработал** (совет химер не создал); химеру дала по-терминная + МАРШРУТИЗАЦИЯ E1 — тот же класс дефекта, шире зарегистрированного носителя. Содержательный вывод + стоит на E1-факте: **любой роутинг (какому арбитру отдать строку) обязан быть кластерным, не + построчным — иначе он ломает серию так же, как по-терминный argmax.** +- Совет химер не создал (модели внутренне консистентны и согласны 2:1 в одну сторону на всех строках + семьи) — и один раз химеру ПОЧИНИЛ. Опасность совета — не химера, а систематически неверная конвенция + при согласии слабых членов (C4: grok+deepseek-батч-2 давали «Гу Юэ»-большинство на части строк). + +### B5. Стоимость в терминах КНИГИ (обязательство §4 промта) + +Измеренные цены пассов на 63-термовом голд-ростере (5 батчей, engine-faithful): +deepseek-low ≈ $0.0063/пасс (среднее трёх; медиана $0.0068) · glm-5 $0.0185 · mistral $0.0128 · grok $0.0265. +Пер-терм: ds ≈ $0.0001 · glm ≈ $0.0003 · mis ≈ $0.0002 · grok ≈ $0.0004. + +Допущение о словаре (названо): книга 1000 глав ≈ 1000–3000 РАЗЛИЧНЫХ банк-строк (насыщение по Хипсу; +стенд: 10 глав → 150 эмитированных при cap 200; альфавит кандидатов книги 13 246 — но эмиссия капится). +На 2000 строк: + +| Механизм | $ на книгу 1000 глав | +|---|---| +| Терминолог-соло (сегодня, low) | **$0.20–0.60** | +| + серия/семья-со-батч + intra-run чек + наблюдаемость (§D п.1–3) | то же + центы | +| Совет 3 семейств полный | $1.2–3.6 | +| Рецензент спорных кластеров (2-я модель, доля спорных 50% по BANK-FULL) | $0.5–1.5 | +| Инжект-ось (для сравнения): ≤800 ток/чанк × ~4600 чанк-вызовов двух волн | ≤$0.5–2 инпут-токенов ГРАНИЦА СВЕРХУ (реальный блок много меньше потолка; кэш удешевляет) | + +Рабочая гипотеза промта «в арбитраже можно покупать расточительно, в инжекте каждая строка платная» +подтверждается НАПОЛОВИНУ: оси действительно разные (арбитраж насыщается, инжект рекуррентен), но на +сегодняшних flash-ценах и 800-токовом потолке они СОИЗМЕРИМЫ ($ единицы за книгу и там и там), порядки +разойдутся только на дорогих моделях/больших потолках. Расточительность в арбитраже дёшева — но §B3 +показал, что покупать расточительно НЕЧЕГО: совет не приносит. + +--- + +## §C. Инжект/фетч: послушание и вред (проба C, $0.0097) + +6 окон источника (500–570 симв., 2–6 голд-термов каждое, разнесены по главам) × 4 арма × +deepseek-flash-low, temp 0, формат движка байт-близко (блок = `glossary_header` + «src → dst», +инъекция вторым system-сообщением — `MessagesWithInjection`, `render.go:246-262`). 24 вызова, все stop. + +| Арм | Верные строки: dst в выходе | Неверная строка: WRONG в выходе | +|---|---|---| +| A без инъекции | 9/21 (43%) — спонтанное совпадение с каноном | 0/6 | +| B верный закон | **20/21 (95%)** | 0/6 | +| C НЕВЕРНАЯ строка законом | 20/21 (по верным) | **6/6 (100%)** | +| D та же строка с ⟨проверить⟩ | 21/21 (по верным) | **6/6 (100%)** | + +**Вердикты по критериям §0 п.5:** +- **Инъекция — мощный управляемый рычаг:** 43% → 95% следования канону. Рычаг есть; recall банка + (0.918, D39.58) не был продуктовой метрикой — вот продуктовая. +- **Вред симметричен и тотален: неверная строка законом принимается 6/6.** В 5 из 6 окон неверный + вариант ПОЛНОСТЬЮ вытеснил верный (единственное исключение — w1 真元, где модель употребила оба). + Доктрина «банк обязан приходить верным автономно» (D39.59/67/77) получает цену ошибки числом: + каждая неверная строка банка = ~100% заражение всех чанков, где терм встречается. +- **Маркер ⟨проверить⟩ на транслятор-проводе НЕ смягчает ничего: Δ послушания = 0 п.п.** (6/6 против + 6/6; критерий дефекта «<10 п.п.» сработал). Заявленная семантика «неподтверждённый кандидат» + байт-честно доезжает до провода и поведенчески НЕ отличается от закона. N=6 — интервал широкий + (точечная оценка 100%, нижняя граница 61%), но нулевую дельту на этом N не отличить от малой — а + вот от «смягчает вдвое» уже отличить можно. +- Оговорка: это ТРАНСЛЯТОР-провод (черновая волна). Редакторский провод (двухсекционный + `RenderEditorConstraintBlock` с «вправе перевести иначе») НЕ мерен — см. критик полноты. Фетч-сторону + (Select/precision) не трогали: recall уже измерен, эмбеддинг-ретривал закрыт D39.69 и данными этой + сессии не реоткрывается. + +--- + +## §D. Рекомендации (Работа D) — инженерно, тремя корзинами + +Сначала индустриальная рамка (веб-обзор этой сессии, 7 направлений, источники с URL в сырье агента; +ключевые: DelTA ICLR'25 · CRAT · DITING/AgentEval'25 · WMT24-Literary zh→ru · WMT25-Terminology findings · +Kadavath'22/Tian'23 (калибровка) · TBX ISO 30042/MQM/memoQ · Netflix KNP · Bergmanis&Pinnis EACL'21): + +- **Индустриального стандарта «как арбитрировать перевод ТЕРМИНА» не существует.** MBR/COMET/QE-метрики + тренированы на предложениях и документированно слепы к именованным сущностям — к короткой строке + неприменимы; word-level QE требует своей разметки. Человеческая индустрия (TBX/memoQ/Netflix KNP) + решает это ПРОЦЕССОМ (роли+статусы+трассировка), автоматического арбитра ни у кого нет. +- **Наш дизайн на фоне академии не отстаёт, а опережает:** ближайший аналог банка — DelTA (proper-noun + records) — использует «первый перевод фиксируется», что мы опровергли у себя же (first-occurrence-тест + D39.69); наш скоринг+терминолог строго сильнее. Пропущенных «стандартов харнессов» обзор НЕ нашёл. +- Что индустрия ЗНАЕТ, а мы ещё нет (входы в корзины ниже): негативный слой термбазы + (deprecated/forbidden, TBX) · лемма-инъекция/лемма-верификация для морфологически богатой цели + (Bergmanis&Pinnis: +47.7 п.п. term accuracy на латышском; у нас decl-half уже есть) · причинный A/B + «no/proper/random glossary» как штатная самопроверка ценности банка (WMT25) · эскалация только спорных + с двумя оценщиками и арбитром (AgentEval) · вербализованная уверенность = ordinal внутри модели, + никогда кросс-модельно (Kadavath/Tian — наш замер §B3 п.3 совпал с литературой точь-в-точь). + +### Корзина 1 — СТРОИТЬ СЕЙЧАС (дёшево, детерминированно, под измеренную нужду) + +1. **Кластер-канал «семья по общей морфеме» в со-батчинг** (лечит §A1; основание: химера 古月 + воспроизведена причинно на границе батча — §B4; серия-со-батч уже доказал лечение — D39.65/D39.69 §1). + Форма: детект «≥K поверхностей делят морфему из ≥N рун» БЕЗ транзитивного замыкания, голово-стороннее + правило из `script-series.txt`-данных (пара без данных — инертна; ревью-вопрос общности проходит). + Фолд-цена: меняется состав батчей → перекупка батчей бэнк-ролей (центы), волны/снапшоты не двигаются. +2. **Intra-run чек связности: `CanonConflicts` по парам consolidated×consolidated** (лечит §A4; $0, + чистая функция уже написана, нужен второй вызов + WARN/колонка в стоп-таблице). Фолд: нет (evidence). + **Ценность промерена на живом банке (`value_demo.py`): 18 невидимых сегодня противоречий на 149 + финалов coldrun-a (12%)** — 空窍→«кунцяо» при 开窍→«открытие точки», 元海空窍→«полость Юаньхая» при + 元海→«Юаньхай», 四代族长 без «главы клана» и т.д. +3. **Наблюдаемость арбитража** (лечит §A7): (а) печатать `Variant.Signals` в стоп-таблицу; (б) колонка + «invented» = dst ∉ вариантов черновиков ($0-предикат; D39.65 мерил 10–15/75 вручную — станет + бесплатным счётчиком); (в) колонка conf терминолога (см. п.4). Фолд: нет. +4. **Уверенность как ordinal-очередь ревью** (основание §B3 п.3: AUC 0.77–0.85 внутри модели, повтор + стабилен ±10 п.): третье поле в ответе терминолога, в стоп-таблице сортировка «сначала неуверенное». + ЗАПРЕЩЁННАЯ форма зафиксирована: кросс-модельное сравнение и «скор решает» (C3conf: +0; шкалы + overconfident ~88 при точности ~50%). Фолд: правка промпт-файла = PromptSHA256 → перекупка батчей + терминолога один раз. ⚠ Ловушка реализации: `ParseReply` сегодня джойнит ВСЁ после первого поля в dst + (`terminology.go:885` — защита от двойного пробела в имени) — числовой хвост-уверенность надо снимать + ДО джойна, иначе conf молча въедет в dst и пройдёт `wellFormedLemma`. +5. **Голос §C2-3 по нормализованной цели в `foldVariants`** — ПОНИЖЕНО до косметики после замера + (`value_demo.py`): частотный топ честно сдвигается лишь у **1/75** строк со spread≥2 (первая версия + замера давала 38 — ловушка тай-брейка, поймана самопроверкой). Реальная ценность — честная колонка + spread для владельца (сегодня 月光蛊 показывает spread=7 при ~4 конвенциях), не качество выбора. + Делать заодно с п.3, отдельного касания не стоит. + +### Корзина 2 — ИЗМЕРИТЬ ПРЕЖДЕ ЧЕМ РЕШАТЬ + +6. **Рецензент-второе-семейство на СПОРНЫХ КЛАСТЕРАХ** (наследник Q2/строки 5; это НЕ равноправный + совет — тот закрыт корзиной 3). Числа этой сессии — вход: glm-соло 25/45 лучший; спорных 50% полного + банка; роутинг обязан быть кластерным (E1-химера, §B4). Замер добора: рецензент только на кластерах + с несогласием/низким conf, счёт «чинит/ломает/цена» против терминолог-соло. Слот при ре-пробе 74 уже + ратифицирован (D39.70 Q2, D39.79 п.6). **Инвариант §0 п.4 — явно, как требует промт:** выход + рецензента — та же draft/⟨проверить⟩-эмиссия и колонка несогласия в стоп-таблице; согласие двух + моделей НЕ поднимает статус и НИЧЕГО не утверждает — эмиссионные ветки auto/draft не трогаются. +7. **KWIC-сэмплинг: первые-N против стратифицированных по книге** (§A6; ~$0.02 на харнессе этой сессии; + размер сетки НЕ пере-открывать — D39.50). +8. **Причинный A/B банка по-WMT25 (no/proper/random) на первой edit-волне добора идеала** — цена/вред + банка на продуктовой метрике; random-арм у нас теперь откалиброван пробой C (вред 100% на + транслятор-проводе — ждём цифру редакторского контура). +9. **Редакторский провод двухсекционки** (§C-оговорка): та же проба на editor.md с + CONFIRMED-секцией против «вправе перевести иначе»-секции. Если и там Δ≈0 — вся конструкция + «неподтверждённое С ПОМЕТКОЙ» (D39.42 п.3) стоит на несуществующем поведенческом различии, и это + вопрос владельцу уровня доктрины. +10. **Негативный слой (TBX deprecated/forbidden)**: $0-замер на coldrun-финалах — как часто отвергнутые + варианты подписанных термов рецидивируют в выходах; ненулевой поток → дешёвый линт по леммам + отвергнутых форм (дом — существующий пост-чек, не новый механизм). +11. **Конвенция составных фамилий (Палладий: слитно)** как данные пар-промпта терминолога/классификатора: + дата-правка, чинит 8/45 голд-строк «бесплатно» (glm/mistral уже следуют ей сами). Замер: N составных + фамилий на второй книге пары до/после. ⚠ это ПАР-ПРАВИЛО транскрипции (класс Z-B3-узкого правила, + ратифицированного), не жанровый словарь — D39.47 не задет; подтверждение владельца всё же спрошено + (§Вопросы), потому что «Гуюэ» стоит в его подписи, а не в нашем правиле. + +### Корзина 3 — ЗАКРЫТЬ ПО НУЖНОСТИ (все — числами этой сессии) + +12. **Равноправный консилиум N семейств как прод-механизм** — прирост к SC = одна конвенция (+3 строки + одного кластера); лучший одиночка (25/45) > лучший совет (23/45); C4 хуже C3 (слабый член + вычитает); цена ×3–5. Гипотеза владельца «консилиум без голоса» на этих данных НЕ окупается. +13. **Взвешенный арбитраж кросс-модельной уверенностью** — C3conf ≡ C3 (+0/−0); шкалы overconfident и + несравнимы между моделями (наш замер + литература). Закрыть как решающее правило (ordinal-очередь — + корзина 1 п.4 — живёт). +14. **Само-согласованность «одна модель N раз»** — SC−S1 = +0/−0 при 9/45 флипах: разброс есть, + информации в нём нет. (thinking-режим DeepSeek игнорирует temperature — управляемой вариативности + для self-consistency-ансамбля просто нет.) +15. **Селекционный арбитраж (« выбери лучший из вариантов черновиков»)** — потолок 17/45 по построению + (§B2), закрыть классом, не формой. +16. **Канал отказа/⟦TM-NO-DST⟧ как сигнал уверенности** — 0 использований на 7 пассах × 3 семействах; + D39.50 пере-подтверждён. Строить на отказе нечего. +17. **Эмбеддинг-фетч** — закрыт D39.69; наши данные (recall не мерили, послушание уже 95% на точном + матче) реопен-условия не создают. + +### Обязательные оси §6 промта, не закрытые корзинами выше + +- **Холодный старт против накопленного банка:** все пробы этой сессии — холодные (канон-якорь пуст, + как в автономном первом прогоне). На накопленном банке появляется ⟦TM-CANON⟧ и фактор соседей — + механика «дозревания» (подписанная строка чинит соседей через якорь) НЕ мерена никем; вход в замер + добора идеала: та же проба с непустым каноном. +- **Вторая пара (ja→ru):** не двигается этими данными; не-CJK-детектора нет (строка 35) — кластер-канал + корзины 1 обязан прийти данными (`script-series.txt`-класс), не Go-веткой, тогда пара без данных + инертна и ревью-вопрос общности проходит. +- **Серийный шаринг банка (48а/48б):** не двигается; заметка — экспортируемый сид-YAML уже несёт + конвенции (Гуюэ-класс) в следующую книгу серии, то есть шаринг = ещё один канал доставки конвенций, + усиливающий довод корзины 1 п.11. + +### Свободная критика (процессное правило №4 — куда на самом деле смотрит качество банка) + +Гипотеза владельца проверена и в своей сильной форме («равноправный совет», «уверенность решает») +НЕ подтверждена. Но проверка показала, где качество банка лежит на самом деле, числами: +1. **Достоверность строк важнее арбитража формы** — инъекция исполняется на 95% и заражает на 100%; + один неверный dst = все чанки терма. Дешевле всего чинится КЛАСТЕРНЫМИ решениями (8/45 одной + конвенцией) и наблюдаемостью (invented/conf/Signals), а не советом. +2. **Reachability: 8/53 подписанных термов банк вообще не видит** (включая головной 蛊) — лучший + арбитр бессилен без строки. Сид-половина строки 18 и Q7-замер стоят выше по рычагу, чем любой + консилиум. +3. **Пометка ⟨проверить⟩ поведенчески пуста на транслятор-проводе** — «худшее, что может сделать плохой + вызов» (инвариант §0 п.4) на практике равно «положить неверный канон в книгу до подписи». Это + усиливает и доктрину автономной верности банка, и цену п.1. +4. Владельческий регистр («класс А/Б/В/Г», «Монах Цветочного Вина») автономно недостижим ПО ПОСТРОЕНИЮ + (D39.47 прав) — доля таких строк в голде ≈ четверть промахов; единственный канал их доставки — + сид/бриф/шаринг серии, и никакой арбитраж это не изменит. + +--- + +## Вопросы владельцу (короткий список) + +1. **Мини-голд алиасов** (§E-1 research/20, висит с 17.07): для кластер-канала корзины 1 он полезен, но + не гейт. Если делать — конкретный запрос: подписать алиас-поверхности сущностей слайса-25 по списку, + который сгенерит код (~20–30 мин, метод уже описан в research/20 §E-1). Решение: делать/нет? +2. **Конвенция составных фамилий** (корзина 2 п.11): подтвердить, что «Гуюэ слитно (ср. Сыма, Оуян)» — + ПАР-норма транскрипции Палладия, а не вкус этой книги. Если да — дата-правка пар-промпта (батчи + терминолога перекупятся один раз, центы). Если это вкус книги — канал доставки только сид, правка + не делается. +3. **Двухсекционка редактора** (корзина 2 п.9): санкция на ~$0.05-пробу редакторского провода. Если и + там Δ≈0 — доктрину «неподписанное С ПОМЕТКОЙ» надо будет пере-обсуждать (сегодня она защищает + меньше, чем записано). +4. Сводный: корзину 1 (пп.1–5, $0-код + центовые перекупки батчей) — передавать бэкенду одним + фикс-паком по образцу D39.71? + +## Критик полноты (против себя) + +- **Один голд, одна книга, одна пара, 45 строк.** Все точности — с широкими интервалами (±14 п.п.); + парные сравнения честнее точечных, но 古月-кластер коррелирует 8 строк — эффективный N меньше + номинального. Кросс-книжная воспроизводимость не проверена. +- **Era-конфаунд P1:** прод-референс — терминолог на ДО-катоверных весах; S1−P1=+2 может быть весами, + а не свежестью. На вывод «совет не окупается» не влияет (сравнение C3↔SC↔S1 — одна эра), на + «свежий соло бьёт прод» — влияет, оговорено. +- **Пробы — только холодный старт** (без канон-якоря); поведение с непустым ⟦TM-CANON⟧ не мерено. +- **Проба C: N=6 неверных строк, один транслятор, один арм-порядок.** Редакторский провод не мерен + вовсе. Вред 100% — точечная оценка с нижней границей 61%. +- ~~gro1 видел на один терм больше~~ — **оговорка СНЯТА адверсариальным раундом 2 пере-проверкой + сырья:** все 7 пассов видели идентичный 63-термовый ростер (二转 лёг в ростер ДО старта процесса + пассов; `### 二转` стоит в батче 3 каждого пасса, 63/63 ответов у всех). Ранняя версия оговорки + опиралась на память сессии, а не на сырьё — ошибка была консервативной (ослабляла выводы зря). +- **Словесная шкала уверенности** мерена на одной модели (deepseek); вывод «числа > слова» — + внутри-deepseek-овый. +- **Кластерные метрики** — 3 семьи; регистры обращений и алиас-графы (два других класса из §4 промта) + голдом не покрыты — мини-голд алиасов (вопрос 1) закрыл бы третий. +- **E1-правило «спорный»** — одно из возможных; не тюнил и не перебирал (пре-рег), химера E1 может + быть свойством именно этого правила; вывод «роутинг обязан быть кластерным» от этого не зависит + (химера возникает у любого правила, режущего семью). +- **Инжект-смета книги** — верхняя граница по потолку 800 ток.; фактический размер блока на живой + книге не считан. + +## Адверсариальный проход (author≠reviewer) + +- **Раунд 1 (до платных выводов):** два независимых агента-скептика. Кодовый: 7/7 клеймов §A + CONFIRMED с file:line (один нит — механика равной длины серий живёт в `series.go:46-66`, а не + только 37-42; принято). Голд-скептик: числа воспроизведены пере-раном байт-в-байт; гипотеза + «промахи несправедливы из-за нормализации» ОПРОВЕРГНУТА (0 несправедливых; ось пробела несёт + подпись владельца в обе стороны — Гуюэ слитно, Жэнь Цзу раздельно); джойн сида чист (пере-джойн + точным равенством дал тот же сплит 45/8); порядок вариантов BANK-FULL = §C2-3-ранжирование + (байт-сверка со стоп-таблицей, 150/150). +- **Раунд 2 (по готовому отчёту, платные выводы §B/§C):** два независимых агента (числа · логика/комплаенс). + **Числовой:** все 11 точностей форм, все парные сравнения, AUC с CI (бутстрап сидирован — до 3-го + знака), устойчивость, вся таблица пробы C и деньги до 6-го знака — CONFIRMED пере-раном; корреляция + химеры S1 с границей батча подтверждена ШИРЕ голда (ds1-b0: все 6 членов слитно, включая не-голдовые + 古月藻榭/古月陈博; ds1-b2: все 7 раздельно). **Поймано и вправлено этим же лендингом:** (1) «3×Гу Юэ» + → 4× (счёт семьи); (2) ячейки 等-серии печатались скриптом как химера из-за грубого фильтра голов — + метрика починена (голова = первое не-числительное слово), скрипт теперь печатает ровно таблицу §B4; + (3) «медиана» → «среднее» у цены ds-пасса. **Логический:** пре-рег-комплаенс критериев 1/5 — буквальный; + расхождение «порог +3 формально пройден, а совет закрыт» признано ЧЕСТНЫМ (вскрытие единиц обязательно + по норме, коррелированный кластер 8 строк ≈ эффективный N~1 — и это уже стояло в тексте); критерий 4 + переформулирован честно (сработал у E1, не у зарегистрированного C3); правило сравнимости шкал помечено + пост-хок уточнением; оговорка про gro1/二转 ОПРОВЕРГНУТА сырьём и снята; инвариант «терминолог не может + утвердить» рекомендациями §D не нарушен (проверено по-пунктно), к п.6 корзины 2 дописана явная + draft/auto-клауза; чужие зоны не тронуты (git status: только свои файлы + PROGRESS-секция по мандату). + +## Заявление = команда (приёмка пере-ранит) + +Все скрипты — `eval/bank_arbitration/`, питон `eval/.venv/bin/python3`: + +| Число | Команда | +|---|---| +| 53/45/8, голд | `build_gold.py` | +| P0 12/45 · P1 18/45 · 27 промахов · 5-в-вариантах | `score_baselines.py` | +| пассы ds/glm/mis/dsw | `consilium_probe.py --passes ds1,ds2,ds3,dsw,glm1,mis1` (+ `retry_mis_b4.py` после 429) | +| grok-пасс | `consilium_probe.py --passes gro1` | +| формы S1/SC/C3/C3conf/E1, AUC, кластеры, деньги-2-путь | `arbitrate.py` | +| серии BANK-FULL · spread≥2 50% · соло-точности · C4 · деньги | `extras_checks.py all` | +| проба C: прогон / счёт | `inject_probe.py` / `inject_probe.py --score` | +| A4-демо 18/149 · A5-демо 1/75 | `value_demo.py` | +| §E ja/en: прогон / счёт | `multilang_probe.py` / `multilang_probe.py --score` | +| §F: прогон / джойн 45 пар | `crosslang_bank.py --part all` / `python -c "from crosslang_bank import score_f1; score_f1()"` | + +Сырьё (полные тела запросов/ответов, usage, цены): `~/books/gu-zhenren/bank-arbitration/*.json` — +35 файлов консилиума + 24 инжекта. Провенанс голда — поле provenance каждой строки gold.jsonl. + +## §E. Достройка по вопросам владельца 04.08 (пре-регистрация ДО запуска — здесь; результаты ниже) + +Вопрос владельца: «не слишком ли подвержен влиянию zh→ru пары? на диске есть ja и en книги». +Признание честное: ВСЯ эмпирика §B/§C — одна пара. Два самых переносимых вывода до-меряются на +`isekai_majutsushi_jp.txt` (ja→ru) и `fifty_shades_1_en.txt` (en→ru), `multilang_probe.py`, deepseek-low: + +- **E-inject** (2 ja-окна + 1 en-окно × 4 арма A/B/C/D, дизайн §C): критерии ТЕ ЖЕ, что §0 п.5 — + маркер «пуст», если Δ послушания wrong-строке закон↔⟨проверить⟩ < 10 п.п.; вред реален при ≥50% + принятия. Перенос подтверждён, если направление ja/en совпадает с zh (рычаг ↑, вред ~100%, маркер ~0). +- **E-family** (ja): семья общего корня РАЗНОЙ длины 魔術/魔術師 намеренно разрезана границей двух + батчей терминолог-структурного промпта. Критерий: если корневые конвенции dst разошлись через + границу — батч-граничная химера НЕ zh-специфична. +- Оговорки, названные до запуска: ja/en-паков в репо нет ⇒ промпты пробы НЕ engine-faithful (проба + феномена, не движка); голда для ja/en нет ⇒ скорится ПОВЕДЕНИЕ (послушание/связность), не + правильность против канона. Смета ≤$0.04; суб-потолок C не пересекается (отдельная достройка в + общем потолке $1.00). + +*(результаты §E вписываются после прогона, пре-рег не правится)* + +### §E-результаты ($0.006472, 14 вызовов, все stop; `multilang_probe.py --score`) + +**E-inject — направление zh-выводов ПЕРЕНОСИТСЯ на обе пары:** + +| Пара | A (без инъекции) | B (закон) | C (wrong закон) | D (wrong ⟨проверить⟩) | +|---|---|---|---|---| +| ja→ru, верные строки | 1/3 | 3/3 | 3/3 | 2/3 | +| ja→ru, WRONG принят | 0/2 | 0/2 | **2/2** | **2/2** (Δ=0) | +| en→ru, верные строки | 2/2 | 2/2 | 2/2 | 2/2 | +| en→ru, WRONG принят | 0/1 | 0/1 | **1/1** | **1/1** (Δ=0) | + +Инъекция слушается ≈полностью, неверная строка принимается, маркер ⟨проверить⟩ не смягчает ничего — +на ja и en ровно как на zh (§C). N крошечный (ja 2 окна, en 1) — это проверка НАПРАВЛЕНИЯ, не величины; +единицы вскрыты глазами (en: «Кому: Кристиан Грэй» — неверная орфография въехала даже в шапку письма). + +**E-family — задуманный тест связности корня не состоялся, но поймал находку крупнее:** на ja-входе +батч 0 бэнк-структурного вызова вернул «переводы» УПРОЩЁННЫМ КИТАЙСКИМ (魔術→魔术 · 洗脳→洗脑 · +国王→国王) при чистом батче 1 (魔術師→маг · 魔力→мана · 勇者→герой). Это off-language класс на +не-родной паре, и он подтверждает ДВЕ вещи: (1) экран языка ответа (`ParseReply`/OffLanguage, +парослепой по построению) для будущей ja-пары — не гигиена, а несущая защита: он эти строки отбил бы +громко; (2) root-связность 魔術↔魔術師 через границу батча осталась НЕизмеренной (батч 0 негоден) — +честно в критик полноты. Оговорка §E-пре-рега в силе: промпты пробы не engine-faithful, это проба +феномена. + +## §F. Кросс-пары по слову владельца 04.08: zh→en (близость к банку) и en→zh (Кристофф) — пре-регистрация + +Слово владельца: «мало ориентироваться только на мой банк — он однобокий; оцени в т.ч. художественность +лично на свой вкус; пары zh→en (близость к моему банку) и en→zh (книга Кристоффа)». + +- **F1 zh→en:** тот же 63-термовый ростер, тот же терминолог-протокол, target=английский + (транскрипция pinyin). Метрики: (а) **стратегия-близость** — по каждому голд-терму сравнивается КЛАСС + решения (смысловой перевод / транслит / гибрид) у en-выхода против подписанного ru владельца; доля + совпадений классов = «примерная близость банка к тому, что выбрала бы свежая en-редакция»; (б) сверка + с fan-каноном Reverend Insanity ПО ПАМЯТИ МОДЕЛИ-автора отчёта — помечается как справочная (память, + не источник); неуверенные строки честно пропускаются; (в) **личная оценка художественности** en-выбора + автором отчёта — субъективная, так и лейблится. +- **F2 en→zh:** `Empire of the Dawn` (Кристофф, epub на диске; книга 2026 года — претрейн-контаминация + минимальна). Майнинг ~12 рекуррентных термов + 2 окна прозы; терминолог-проход en→zh и перевод окон + (deepseek-low и glm-5 — китайско-родная модель для контраста). Метрики: связность семей терминов; + **личная оценка художественности zh-прозы** автором отчёта (регистр, каденс, кальки) — субъективная. +- Критерий «близость к банку» (F1): ≥70% совпадения классов решения = «банк владельца НЕ однобокий, + его выборы совпадают с независимой en-редакцией»; <50% = «банк несёт сильную ru-специфику» (обе + формулировки легитимны — это описание, не экзамен). +- Смета ≤$0.08. Оговорка: en→zh и zh→en паков в движке нет — проба переносимости ПОДХОДА, не движка. + +### §F-результаты ($0.011310, 11 вызовов, все stop; `crosslang_bank.py`, джойн — `score_f1()`) + +**F1 zh→en: банк владельца НЕ однобокий — 41/45 (91%) совпадений класса решения** с независимой +свежей en-редакцией (порог пре-рега 70% взят с запасом; классификация ручная, автор отчёта; полный +джойн печатается командой). Самое сильное: + +- **Свежая en-редакция дала «Rank 1..9», «Grade A/B/C/D», «Aperture», «Gu Master», «Spring-Autumn + Cicada», «Mortal» — то есть РОВНО классы подписей владельца** («ранг», «класс А/Б/В/Г», «апертура», + «гу-мастер», «Весенне-осенняя цикада», «смертный»), включая буквенный маппинг 甲→A, который ни один + ru-черновик и ни одна ru-модель не выдали. Выбор владельца — не идиосинкразия, а конвергентная + редакторская логика; ru-модели до неё не дотягиваются приором — ещё один довод за канал сид/бриф. +- Сверка с fan-каноном Reverend Insanity ПО ПАМЯТИ автора отчёта (помечено: память, не источник): + уверенно помню Gu Master · aperture · Spring Autumn Cicada · Rank N · A-grade aptitude · Fang Yuan · + Gu Yue · Bai Ning Bing · Ren Zu · Hope Gu · Moonlight Gu · **primeval stone/sea** — свежий en-проход + совпал почти всюду, а где разошёлся (元石 «Yuan Stone» против fan «primeval stone»), fan-канон + оказался ближе к владельцу («первобытный камень» = дословно primeval stone). Банк владельца ≈ + анг. fan-канон даже теснее, чем свежая модель. +- 4 расхождения класса: 白家寨/熊家寨 (en транслит против семантики владельца — при том что 古月山寨 + en сам перевёл «Gu Yue Village»: **та же семейная несвязность 寨-семьи воспроизвелась в en-проходе**, + дефект A1 кросс-языковой) · 元石/元海 (en гибрид, владелец семантика). +- Ру-специфика подтверждена ровно одна: слитность «Гуюэ» (en-канон пишет «Gu Yue» двумя словами — + правило Палладия для составных фамилий действительно живёт только в ru-транскрипции). +- Оговорка: en-проход видел ru-варианты черновиков как улики смысла (велено явно «not as English + candidates»); следование им не слепое — на 元石 модель ушла от ru-улики. + +**F2 en→zh (Кристофф, Empire of the Dawn 2026 — контаминация минимальна):** + +- Терм-таблицы: deepseek дал **идеальную корневую связность семьи *-blood** (冷血者/高血者/苍血者 — + единый шаблон X血者), а **glm-5 сломал корень ВНУТРИ одного батча** (冷血者/高血族/苍白血 — три + разных шаблона): со-батчинг необходим, но НЕ достаточен — межмодельная и внутримодельная дисперсия + связности реальна и вне CJK-источника. Плюс deepseek **выдумал 5 незапрошенных строк** (Patience, + Liathe, Ashdrinker…) — ровно класс, который экран `want[key]` в `ParseReply` отбивает; кросс-парное + подтверждение нужности этого гарда. +- Проза (2 окна × 2 модели, читал лично; оценки субъективные, так и лейблятся): оба черновика — + добротный жанровый уровень, стилистическая разница меньше терминологической. deepseek: точнее к + термам и образам («银钢为歌,转轮火枪为鼓» — отличная передача «silversteel their song…»; «墓志铭» + для меча Epitaph — верно), местами буквален («完好无损» для unbroken — смысловой промах). glm: + местами идиоматичнее («勒得我骨节作响», «任凭时光流转、潮汐更替,也无法锈蚀»), но с реальными + дефектами: **оставил английское слово в переводе («兄弟 forever»)**, выронил клаузу, «红痰» + (красная мокрота) — регистр-провал, «克斯特尔»-класс ошибок у deepseek — транслит говорящего + названия Kestrels против glm-ского верного «红隼». И несущая единица: **glm сам разошёлся в имени + Aaron между двумя соседними окнами (艾伦 ↔ 亚伦)** — межчанковый дрейф имени, ровно то, от чего + банк существует, воспроизведён на en→zh за два вызова. +- Личный вывод по художественности (вкус автора, не мера): прозовое качество дешёвых моделей на + en→zh и zh→en уже «редактируемо-издательское»; узкое место всех четырёх направлений одно и то же — + дисциплина термов и конвенций, не слог. Ставка проекта на банк как центральную ценность этим + подтверждается с третьей стороны. + +## §G. Дизайн-синк: как я бы доработал алгоритмы банка в бэкенде (код читан HEAD, не правлен) + +Конкретика уровня функций — готовый вход для фикс-пака класса D39.71. Всё сохраняет инварианты: +эмиссия auto/draft не трогается, терминолог не может утвердить, Select/пост-чек/эскалация без изменений. + +**G1. `DetectFamilies` рядом с `DetectSeries` (`terminology/series.go`).** Вход тот же `[]Candidate` + +`FamilyParams` из ДАННЫХ (`script-series.txt`, новая колонка; пара без данных — канал инертен): +- реалии: общий СУФФИКС-морфема длины ≥MinRootRunes при head-final письме (семьи 蛊-*, *-寨, *-血); + имена (тип после классификатора §2): общий ПРЕФИКС ≥2 рун (семья 古月-*) — асимметрия имя/реалия + тоже данные, не Go-ветка; +- БЕЗ транзитивного замыкания: якорь группы = сама корневая морфема; кандидат входит в ≤1 семью, + приоритет более длинного корня (специфичное бьёт общее), затем большей семьи; серия (G-существующая) + сильнее семьи — серийные члены из семей исключаются (等-серия не должна утонуть в 等-семье); +- выход — тот же `map[string]int`, мёржится с seriesID перед `Batch` (со-батч механизм уже готов, + oversize-WARN уже есть). Цена фолда: состав батчей → RequestHash бэнк-батчей — перекупка батчей + один раз (центы), волны/снапшоты не двигаются. Замер-основание: §B4 (химера на границе батча), + §F2 (семья *-blood), §A1 (8/45 голда одной конвенцией). + +**G2. `ConsolidationConflicts(cands, out)` (`terminology/terminology.go`).** Тонкий брат +`CanonConflicts`: те же containment+`lexemeSubset`, но правая сторона — сами консолидации прогона. +Вызов в `runTerminologist` после сборки `out` (рядом с :335), WARN с именованными парами + счётчик в +`terminologyResult` + колонка стоп-таблицы. $0, не фолдится (evidence-сторона). Замер-основание: +18/149 невидимых противоречий на живом банке (`value_demo.py`). + +**G3. Наблюдаемость (`mining.go` + `terminology.go`):** `BankStopRow` += `Signals []string` (уже +вычислены — просто печать), `Invented bool` (норм-dst ∉ вариантов), `Conf int`; `ParseReply` — если +ПОСЛЕДНЕЕ поле ` \d{1,3}` — снять его как conf ДО джойна f[1:] (иначе conf молча въезжает в dst); +строка «третье поле — уверенность 0–100» в промпт-файл роли (дата-правка, PromptSHA → перекупка +батчей тем же разом, что G1). `reasoning_content` в схему НЕ заводить — debug-сайдкар рядом со +стоп-таблицей за флагом гейта. Основание: §A7, AUC 0.77–0.85 (§B3). + +**G4. Правило кластерного роутинга** — в дизайн замера рецензента (строка 5): любой селективный +арбитраж (спорные к рецензенту) маршрутизирует ТОЛЬКО целыми family/series-юнитами. Основание: +E1-химера §B4. Это правило дизайна, кода сейчас не требует. + +**G5. `foldVariants`:** счёт голосов по `NormalizeTargetForm`-фолду, показ сырых форм; рядом со +spread — «конвенций» (folded spread). Косметика (двигает топ 1/75 — §D п.5), делать заодно с G3. + +**G6. Не делать (замеры этого пака):** равноправный совет · кросс-модельные веса · self-consistency · +селекция из вариантов · отказ-сигнал · эмбеддинг-фетч (§D корзина 3). Series-детектор, Merge, +AttachKWIC-семантика (кроме строки 37-перфа), Select, пост-чек — не трогать. + +Порядок: G1+G2+G3+G5 — один фикс-пак (одна перекупка батчей, голден не движется); G4 — вход замера +строки 5 при ре-пробе 74; строка 37 (перф AttachKWIC через готовый Aho-Corasick из membank) — по +желанию тем же паком. + +## Деньги + +| Проба | Потолок | Факт | +|---|---|---| +| B: ds1+ds2+ds3+dsw | — | $0.021991 | +| B: glm1 | — | $0.018495 | +| B: mis1 | — | $0.012808 | +| B: gro1 (опция) | — | $0.026546 | +| **Итого B** | ≤$0.70 | **$0.079840** | +| **Проба C (инжект)** | ≤$0.30 | **$0.009713** | +| §E мультиязычная достройка (по вопросу владельца, тот же день) | — | $0.006472 | +| §F кросс-пары zh→en / en→zh (по слову владельца, тот же день) | ≤$0.08 | $0.011310 | +| **ВСЕГО** | **≤$1.00 (слово владельца 04.08)** | **$0.107335** | + +Суб-потолки не тронуты и близко; СТОП-условий не наступало. Эффорты: deepseek — `reasoning_effort:"low"` +во всех вызовах (в сырье каждый файл несёт поле effort); glm-5 — thinking disabled (форма движка); +mistral/grok — вендор-дефолт. Слаги фактчекнуты live `/models` перед пассами. diff --git a/docs/research/24-bank-arbitration.md b/docs/research/24-bank-arbitration.md new file mode 100644 index 00000000..420eead1 --- /dev/null +++ b/docs/research/24-bank-arbitration.md @@ -0,0 +1,501 @@ +# research/24 — Арбитраж банка памяти: консилиум · уверенность · инжект/фетч · кросс-пары + +> **РЕВЬЮ-ШАПКА ПРИЁМКИ (оркестратор №13, 04.08.2026).** Статус: **ПРИНЯТ**, залендено этим коммитом (D39.102). Метод — адверсариальная приёмка тремя контурами. **(1) Пере-раны:** 12-агентный воркфлоу пере-ранил ВСЕ строки таблицы «заявление = команда» ($0, офлайн по сырью) — 8/8 CONFIRMED, ни одного расхождения чисел (голд 53/45/8/34 · базисы 12/18/27/5 · формы S1/SC/C3/C3conf/E1/C4 · AUC с CI · химеры B4 по сырью батчей · инжект-таблица · 18/149 · 1/75 · §E/§F по сырью); все 23 адреса §A подтверждены по HEAD `7f6270a` (3 уточнения координат: сброс sticky живёт в `wave.go:84-86`; фикстура A8 — дистилл `testdata/bankfull-surfaces.txt`; механизм series до ~:76); байт-сверка инжект-пробы с движком: заголовок/маркер/«src → dst»/второй system байт-идентичны (gender-нота не моделируется — для безгендерного глоссария рендер совпадает). **(2) Харнесс и деньги:** независимый пересчёт из сырья $0.107334 против записанных $0.107335 (округление на записи); цены = `models.yaml`; 84/84 finish=stop; слаг-дрейфа нет; голд 53/53 против сида, пере-сборка детерминистична байт-в-байт. **(3) Слепое ревью кода банка** (author≠reviewer, без чтения этого отчёта) + 12 опровергателей: находки СВЕРХ §A заведены строками 128–132 (главные: банкнота-парсер теряет хвост многословного dst против клейма A10 «дефектов нет»; emitRankCap×writeAutoBank молча стирает термы из авто-банка; кап инъекции не считает маркер/гендер-ноты). +> **Оговорки приёмки (выводов не двигают):** (а) в скоринге армов C/D — regex-конфаунд: голд-rx 真元 матчится внутри верного перевода 元海 ⇒ «верные строки» C/D завышены до 2 ячеек; выводы «wrong принят 6/6 · Δ=0 · вытеснение 5/6» стоят на другой метрике и не задеты; (б) C4=20/45 хрупок — 2-2-тай в 7/45 термов решается порядком голосов; вывод «совет закрыть» стоит на C3−SC=+3 (один кластер) и glm-соло 25>23, не на C4; (в) фоллбек C3 несимметричен (сработал 5/45, эффект мал); SC при temp=0 меряет недетерминизм провайдера, не сэмплинг; (г) иллюстративные пары A4 склеены не как печатает скрипт (см. аннотацию в §A4); (д) «точность 44–56%» — числовые пассы; словесный dsw = 40.0%; (е) 18 оплаченных доп-поверхностей ростера кодом почти не скорятся — выводы по ним ручные по сырью; (ж) атрибуция литературы уверенности поправлена аннотацией в §D (Xiong et al. 2023, не Kadavath/Tian); DelTA first-wins и WMT25 подтверждены первоисточниками; (з) «потолок $1.00 — слово владельца 04.08» — со слов сессии (ратифицированный потолок $1.20, D39.90 п.5); при факте $0.107 беспредметно; арифметика ПИНГА в PROGRESS («+$0.0161») — склейка инкрементов C+E, леджер отчёта чист. + +**Ресёрч+полигон сессия, 04.08.2026.** Исполнение `docs/archive/prompts/BANK_ARBITRATION_RESEARCH_SESSION_PROMPT.md` (заархивирован D39.101) +(D39.89; пере-запуск — артефактов захода 02.08 в дереве не было, D39.90 п.5; подрезка учтена: B2 +свёрнута в под-пробу B3, C сокращена). Плюс прямой вопрос владельца 04.08: общий взгляд на алгоритм +банка — хватает ли текущего, не пропущен ли индустриальный стандарт (ответ — §D); и достройки того же +дня: мультиязычность (§E), кросс-пары и художественность (§F), дизайн-направления (§G). +Потолок владельца 04.08 **$1.00**, факт **$0.107335**. +Зона записи: этот файл + `eval/bank_arbitration/` + секция «Полигон» PROGRESS; сырьё durable +`~/books/gu-zhenren/bank-arbitration/` (84 json). Пробы — своим харнессом против API (в `backend/` +незакоммиченный пак чужой сессии); `coldrun-a` — только чтение; базлайн качества банка = coldrun-a +(D39.86). Не закоммичено — лендит оркестратор. Кода бэкенда не правлено. + +--- + +## §0. ПРЕ-РЕГИСТРАЦИЯ ПРОБ (записано ДО первого платного вызова; норма D39.46) + +Дата/время фиксации: 2026-08-04, до каких-либо платных вызовов этой сессии. Голд (§B1) собран ДО +пре-регистрации ($0), его числа: 53 approved сида → 45 в BANK-FULL coldrun-a, из них 34 со spread≥2. + +### Пассы (все — полный голд-набор одним батч-протоколом, engine-faithful RenderBatch): + +| Пасс | Модель | Режим | Что несёт | +|---|---|---|---| +| ds1..ds3 | deepseek-v4-flash | `reasoning_effort:"low"`, temp 0 | S1 (свежий одиночный) + SC (само-согласованность N=3) + числовая уверенность 0–100 | +| dsw | deepseek-v4-flash | то же | словесная шкала уверенности (точно/скорее да/не уверен/не знаю) | +| glm1 | glm-5 | thinking disabled (форма движка) | второе семейство + числовая уверенность | +| mis1 | mistral-large-2512 | без reasoning | третье семейство + числовая уверенность | +| gro1 (опция при остатке бюджета) | grok-4.3 | дефолт (low) | четвёртое семейство, чувствительность состава совета | + +Эффорты каждого пасса печатаются в отчёте (иначе числа несравнимы — §7 промта). + +### Формы арбитража (агрегация офлайн, $0): + +- **P0 — бесплатный базис §C2-3:** топ-вариант ранжирования движка (колонка вариантов BANK-FULL, + bankStopRows рендерит best-ranked first). Термы без вариантов → P0 пуст (честный отказ базиса). +- **P1 — прод-референс:** сведённый dst coldrun-a (терминолог на до-катоверных весах). +- **S1** = ds1. **SC** = большинство(ds1,ds2,ds3), при 3-стороннем расхождении → ds1. +- **C3 — равноправный совет:** большинство(ds1, glm1, mis1) по нормализованному совпадению; + полное расхождение → P0-топ, если хоть один голос совпал с ним, иначе ds1. +- **C3conf — взвешенный:** argmax по сумме заявленных уверенностей проголосовавших за вариант моделей. +- **E1 — улики-первым:** P0 стоит; «спорный» терм := (spread≥2 И разрыв top1−top2 по чанкам ≤1) ИЛИ + singleton-улика (top1 предложен 1 чанком) → на спорных решает C3. Цена печатается долей от полного + совета. + +### Метрики: + +- Точность против голда: нормализованное точное совпадение (casefold · ё→е · схлоп пробелов · срез «»/кавычек). + Промахи вскрываются глазами; спорные эквивалентности печатаются отдельно, автоматом НЕ засчитываются. +- Парные сравнения форм: счёт термов «A прав ∧ B неправ» против обратного (не голые проценты). +- **Кластерная связность:** семьи 古月-* (7 поверхностей, РАЗНОЙ длины — DetectSeries её не видит), + 蛊-* (蛊师/蛊虫/月光蛊 + голова 蛊 вне банка), серии 等/转 (равнодлинные — детектируются). Метрика: + консистентность конвенции внутри семьи у каждой формы (одна голова/конвенция у всех членов — да/нет), + и отдельно: даёт ли по-терминный агрегатор химеру там, где одиночная модель консистентна. +- **B2-под-проба (уверенность):** AUC(уверенность → верно/неверно по голду) per-model (bootstrap 90% CI); + устойчивость: медиана |Δconf| ds1↔ds2↔ds3 и доля флипов ответа; сравнимость шкал: |Δ средних conf| между + моделями на одном наборе; канал отказа: счёт ⟦TM-NO-DST⟧ и его стабильность между ds1..ds3. + +### Критерии (успех/провал, зафиксированы ДО запуска): + +1. **БАР (в):** форма «бьёт базис P0», если парное преимущество (термы A-прав-P0-неправ минус обратные) + ≥ **+5** на 45 голд-термах. Меньше — «не бьёт» (на N=45 меньшее неотличимо от шума). +2. **Q2 (окупаются ли семейства):** C3 против SC парное преимущество ≥ **+3**; меньше ⇒ «разные семейства + не окупаются, хватает N прогонов одной модели» (легитимный исход). +3. **Уверенность разделяет**, если AUC ≥ 0.70 и нижняя граница CI > 0.5 минимум у 2 моделей из 3; + иначе — «уверенность как арбитр закрыта по нужности». Числа против слов: |ΔAUC| ≥ 0.05 решает форму. + Шкалы несравнимы, если |Δ средних conf| > 20 п. ⇒ сырой кросс-модельный скор как решающее правило запрещён. +4. **Кластеры:** ≥1 новая химера у C3 там, где SC/P1 консистентны ⇒ возражение §4 промта подтверждено + (единица арбитража обязана быть кластером). +5. **Проба C (инжект, формат RenderGlossaryBlock/RenderEditorConstraintBlock байт-близко):** + 6 чанков × 4 арма (без инъекции · верный закон · НЕВЕРНАЯ строка законом · та же неверная строка + с маркером ⟨проверить⟩), deepseek-v4-flash low, temp 0. Критерии: маркер «читается мягче закона», если + послушание(закон-неверный) − послушание(⟨проверить⟩-неверный) ≥ **20 п.п.**; «пометка = закон» (дефект), + если < **10 п.п.** Вред реален, если неверная строка законом принимается в ≥ **50%** случаев. + Между 10 и 20 п.п. — «неразделимо на N=6×набор строк», честно печатается. + +Смета до запуска ≈$0.18 (B ≈$0.13 + C ≈$0.05); СТОП-условия: суб-потолки B $0.70 / C $0.30. + +*(Эта пре-регистрация после запуска не правится. §E и §F пре-регистрированы отдельно в своих секциях, +тоже до своих запусков. Фактическая реализация пробы C: инъекция вторым system-сообщением — +`MessagesWithInjection`, транслятор-провод; редакторский рендер `RenderEditorConstraintBlock`, названный +в зарегистрированном скоупе, в пробу НЕ вошёл — невымеренность редакторского провода честно стоит в §C +и критике полноты.)* + +--- + +## §A. Критика алгоритма в коде ($0; диагноз, не правка; адреса сверены в HEAD) + +Маршрут: `miner/` → `banknote.go` → `terminology.go` (Merge/AttachKWIC/ScoreVariants) → `series.go` → +`classify.go` → `terminologist.go` → `membank/memory.go` → `mempostcheck.go`. Классы: **сломано / +хрупко / дорого / слепо**. + +Вердикт-тройки §0-п.1 промта (посылка/нужность/форма) свёрнуты в прозу каждого пункта: посылка — +проверка адреса в HEAD, нужность — замер, форма — выбранная против названной альтернативы. + +**A1. Единица решения — строка; связность семей термов не защищена — «слепо».** +`ScoreVariants` ранжирует варианты одного кандидата (`terminology.go:393-450`); межстрочный фактор +`neighbourAgrees` требует подписанной строки (`:465-482`) — на автономном банке мёртв (D39.65: 2/23). +`DetectSeries` ловит только равнодлинные наборы с общей головой (`series.go:30,46-66`); **семьи общего +корня разной длины не ловит ничем**: в BANK-FULL их две крупных — 古月×15 и 蛊×14 поверхностей. +Ключ-сортировка Merge (`terminology.go:212`) даёт префиксным семьям (古月*) смежность случайно, а +суффиксные (X蛊 — голово-финальная морфология CJK) рассеиваются по батчам. Цена по голду: конвенция +古月 = 8 из 45 строк одним решением (§B2). Существенно: **промпт роли УЖЕ требует родства** +(«Сохраняй родство однокоренных терминов», `prompts/zh-ru/terminologist.md`) — дефект структурный +(семья режется границей батча/вызова), инструкцией не лечится. Форма лечения — семейный со-батч (§G1); +альтернатива «второй проход ре-чтения» дороже и рассеяние по батчам не чинит. + +**A2. Потолок арбитража-как-селекции: 17/45.** У 22 из 27 промахов прод-консолидации верного dst НЕТ +в вариантах черновиков (§B2) ⇒ любой «выбор из предложенного» ограничен 12+5=17/45 по построению. +Гейт на класс дизайнов до всякой калибровки. + +**A3. `Related`: обрезка на первые 4 по алфавиту** (`terminology.go:242-256`) — выбор лексикографический, +не по релевантности. «Хрупко», минор; форма — cap по числу общих рун (механика веса уже есть в +`CanonFor`); закрывается вместе с A1. + +**A4. Внутрипрогонные противоречия консолидаций не проверяет никто — «слепо», $0-фикс.** +`CanonConflicts` сверяет только с подписанным банком (`terminologist.go:335`; канон читается один раз +до батчей, `:284`); пары свежих консолидаций (蛊师 ⊂ 一转蛊师) не сверяются, хотя механика +containment+`lexemeSubset` уже написана (`terminology.go:787-812`). На автономном прогоне подписей ноль +и рубеж пуст. Форма — тот же детерминированный проход по консолидациям ($0); альтернатива «платный +проход само-ревью» не детерминирована и дороже. **Замер на живом банке (`value_demo.py`): 18 невидимых +противоречий на 149 финалов (12%)** — 空窍→«кунцяо» при 开窍→«открытие точки», 元海空窍→«полость Юаньхая» при 元海→«Юаньхай» и т.д. *[аннотация приёмки №13: пары — иллюстрация класса; фактический вывод `value_demo.py` флагует 空窍→«кунцяо» и 开窍→«открытие точки» каждый против 窍→«апертура», а пара 元海空窍↔元海 containment-алгоритмом непорождаема (лексемный матч считает вложение унаследованным); числа 18/149 и 1/75 точны пере-раном]* + +**A5. `foldVariants` фолдит только байт-идентичные dst** (`terminology.go:222-237`): регистровые +микроварианты дробят счёт («лунный гу ×2» + «Лунный гу ×1»), spread завышен для владельца. Замер: +частотный топ реально двигается лишь у **1/75** строк — косметика колонки spread, не качество выбора. + +**A6. KWIC: первые N вхождений в порядке глав** (`terminology.go:308-329`) — сэмплинг смещён к началу +книги; ось «первые-N против стратифицированных» не мерена (D39.50 мерил размер сетки, не стратегию). +Плюс перф (строка 37 трекера): квадратичность + пересчёт рун префикса на вхождение (`:332-346`); +multi-pattern автомат уже есть в `membank/memory.go:872-918`. + +**A7. Наблюдаемость: «почему у терма такой dst» неответимо — «слепо», гейтит любой будущий арбитраж.** +`Variant.Signals` вычисляется и выбрасывается (в стоп-таблицу идут только «dst ×N», `mining.go:256-270`); +`reasoning_content` не персистится нигде (grep llm/store: только док-коммент `capability.go:63`); +сочинённый вне улик dst (10–15/75 по D39.65) не флагуется, хотя предикат «dst ∉ вариантов» — $0. + +**A8. Эмиссия: 8 из 53 подписанных термов вообще не в банке** (蛊 · 修炼 · 修行 · 资质 · 长生 · 江牙 · +月影蛊 · 血颅蛊) — известные дыры (строка 18, recall term=0.040), переквантифицированы голдом: лучший +арбитр бессилен без строки. + +**A9. Инжект-сторона.** Бюджет режется префикс-катом (`memory.go:615-628`): первая переполнившая +строка обрезает всё после, включая влезающие — минор. Sticky=2 со сбросом на границе главы +(`memory.go:112`) — осознанно; местоименная сцена глубже двух чанков теряет канон, как дефект не +измерено. Замера «⟨проверить⟩ мягче закона» не существовало — закрыт пробой C +(§C). Пост-чек — честный флаггер, дефектов сверх записанного нет. + +**A10. Банкнота — форма верная** (агрегация всех прогонов с голосами по чанкам, `banknote.go:470-505`); +дефектов сверх записанного нет. + +--- + +## §B. Арбитраж: голд · базисы · формы · уверенность · кластеры · цена книги + +### B1. Голд ($0, `build_gold.py` → `gold/gold.jsonl`, провенанс на строке) + +Сид v2 53 approved → джойн по нормализованной поверхности+алиасам с BANK-FULL coldrun-a (150): +**45 в банке, 34 со spread≥2, 8 не в банке** (список в A8). Смещение: сид сдвинут к важным/спорным +термам; часть подписей могла формулироваться при виде машинных вариантов; одна книга одной пары; +~четверть строк — вкусовой регистр владельца, автономно недостижимый по построению (D39.47). +Мини-голд алиасов §E-1 research/20 не входит (вопрос владельцу). + +### B2. Бесплатные базисы ($0, `score_baselines.py`) + +| Базис | Точность | Парно | +|---|---|---| +| P0 (топ §C2-3) | 12/45 | — | +| P1 (терминолог coldrun-a, старые веса) | 18/45 | +7/−1 к P0 | + +Анатомия 27 промахов P1 (все единицы вскрыты): **8 = одна конвенция 古月** («Гу Юэ» против подписанного +«Гуюэ» слитно — правило Палладия для составной фамилии, лежит в note сида) · **4 = серия 等** («класс +Цзя»/«ранг И» против «класс А/Б/В/Г»; подписанного ответа нет ни в одном черновом варианте) · +остальное — класс «слишком китаизированно» (空窍→кунцяо · 元海→Юаньхай · 元石→юаньши · …). +**Только у 5 из 27 промахов верный dst лежал в вариантах ⇒ потолок селекции 17/45** (A2). +Нормализация промахов честная: несправедливых 0 (регистр/ё/кавычки фолдятся; ось пробела несёт +подпись владельца в обе стороны — «Гуюэ» слитно, но «Жэнь Цзу» раздельно; фолдить её нельзя). +Контрфакт: объяви владелец ось пробела неканоничной — P1 поднялся бы до 26/45; сид фиксирует обратное. + +### B3. Формы против базиса (платные пассы; 35 вызовов, все finish=stop, 63/63 строк в каждом; +ростер 63 = 45 голд-в-банке + 18 до-строек членов семей/серий для кластерных метрик) + +| Форма | Точность | К P0 | Примечание | +|---|---|---|---| +| P0 | 12/45 | — | ни одного терма «P0 прав, свежая форма неправа» | +| P1 | 18/45 | +7/−1 | конфаунд эры весов при сравнении со свежими | +| **S1 ds-соло (low)** | **20/45** | **+8/−0** | | +| SC 3× та же модель | 20/45 | +8/−0 | к S1: **+0/−0** | +| **C3 совет 3 семейств** | **23/45** | **+11/−0** | к SC: **+3/−0** — все 3 добычи = один кластер 古月 | +| C3conf взвешенный | 23/45 | +11/−0 | к C3: **+0/−0** | +| E1 улики-первым | 22/45 | +10/−0 | к C3: −1; создал химеру (§B4) | +| glm-5 соло | **25/45** | | лучший одиночка > лучший совет | +| mistral соло | 23/45 | | | +| grok-4.3 соло | 12/45 | | уровень бесплатного базиса | +| C4 совет 4 семейств | 20/45 | | слабый член уронил совет 23→20 | + +Риск совета — не химера, а систематически неверная конвенция при согласии слабых членов (в C4 +grok + deepseek-батч-2 давали «Гу Юэ»-большинство на части строк семьи). + +Вердикты по критериям §0: +1. **БАР пройден** — свежей генеративной консолидацией (уже S1 +8/−0), не консилиумом как таковым; + это пере-подтверждение D39.65 «роль — эффективный консолидатор», теперь с голдом и знаком КАЧЕСТВА, + которого у D39.65 не было. +2. **Q2: формально +3 = порог, содержательно семейства не окупаются** — все три добычи C3 против SC + суть одна конвенция 古月 (коррелированный кластер из 8 строк, эффективный N≈1); лучший одиночка + (glm 25/45) выше лучшего совета; C4 хуже C3; C3conf ≡ C3. Прод-механизм «равноправный совет» — + закрыть (§D). +3. **Числовая уверенность разделяет внутри модели:** AUC ds 0.770 (CI90 0.656–0.879) · glm 0.851 + (0.742–0.947) · mistral 0.825 (0.719–0.915); словесная шкала хуже: 0.630 (0.556–0.704). + Повтор ds1..ds3: медиана размаха conf 10 п., флипов ответа 9/45. Все модели overconfident + (средняя conf 87.7–90.1 при точности 44–56%) — шкала работает как РАНГ внутри модели, не как + вероятность и не кросс-модельно (пре-рег-метрика Δ-средних этот случай не ловит — уточнение + пост-хок; делом подтверждено формой C3conf: +0). Форма жизни — ordinal-очередь ревью, не арбитр. +4. **Канал отказа: ⟦TM-NO-DST⟧ = 0 на всех 7 пассах четырёх семейств** (6 печатает `arbitrate.py`, + gro1 сверен по сырью). Подтверждает «роль всегда отвечает строкой»; субстрат — банк-строки голда, + не хвост эмиссии, где D39.50 мерил размах. + +### B4. Кластерная связность (`arbitrate.py`) + +| Семья | P1 | S1 | C3 | E1 | +|---|---|---|---|---| +| 古月 (8, разнодлинная — вне DetectSeries) | конс. «Гу Юэ» (против подписи) | **ХИМЕРА 4׫Гу Юэ»+4׫Гуюэ»** | конс. «Гуюэ» = подпись | конс. | +| 转 (равнодлинная, со-батчена) | конс. «ранг» | конс. | конс. | **ХИМЕРА «оборот»+«ранг»** | +| 等 (равнодлинная, со-батчена) | **ХИМЕРА «класс»/«ранг»** (дефект D39.65) | конс. «уровень» (мимо голда) | конс. | конс. | + +- **Химера S1-古月 коррелирует с границей батча идеально и шире голда** (сырьё: ds1-b0 — все 6 членов + слитно, ds1-b2 — все 7 раздельно): дефект класса D39.65 воспроизведён на семье, которую + серия-детектор не со-батчит. +- **E1 создал химеру там, где все голосующие консистентны** (неспорному 一转 достался P0-топ «оборот», + спорным — советский «ранг»). Зарегистрированный критерий 4 у C3 не сработал (C3 химер не создал, + одну починил); химеру дала по-терминная МАРШРУТИЗАЦИЯ — тот же класс дефекта. Вывод: любой роутинг + (какому арбитру отдать строку) обязан быть кластерным. + +### B5. Цена в терминах книги (63-термовый ростер, 5 батчей) + +Допущение о словаре, названо: 1000 глав ≈ 1000–3000 РАЗЛИЧНЫХ строк банка (насыщение по Хипсу; стенд: +10 глав → 150 эмитированных при cap 200; альфавит кандидатов книги 13 246, эмиссия капится). +Пассы: ds-low ≈ $0.0063 (среднее трёх) · glm-5 $0.0185 · mistral $0.0128 · grok $0.0265; +пер-терм ≈ $0.0001 / $0.0003 / $0.0002 / $0.0004. +На 2000 строк: терминолог-соло **$0.20–0.60/книга**; совет 3 семейств $1.2–3.6; рецензент спорных +(50% строк банка по spread≥2) $0.5–1.5. Инжект-ось: ≤800 ток/чанк × ~4600 чанк-вызовов двух волн = +верхняя граница $0.5–2 инпута. Гипотеза «оси расходятся на порядки» держится наполовину: оси разные +(арбитраж насыщается, инжект рекуррентен), но на flash-ценах соизмеримы; расточительность в арбитраже +дёшева — однако покупать расточительно нечего (совет не приносит). + +--- + +## §C. Инжект: послушание и вред (проба C; 24 вызова, все stop; `inject_probe.py --score`) + +6 окон источника × 4 арма, deepseek-flash-low, формат байт-близко к движку (второе system-сообщение). + +| Арм | Верные строки в выходе | Неверная строка принята | +|---|---|---| +| A без инъекции | 9/21 (43%) | 0/6 | +| B верный закон | **20/21 (95%)** | 0/6 | +| C неверная строка законом | 20/21 | **6/6** | +| D та же с ⟨проверить⟩ | 21/21 | **6/6 (Δ=0 п.п.)** | + +- Инъекция — мощный рычаг: 43%→95% следования канону (продуктовая метрика, которой recall 0.918 не был). +- **Вред тотален: неверная строка принимается 6/6; в 5 из 6 окон полностью вытеснила верную.** Цена + неверной строки банка ≈ 100% заражение чанков терма. Доктрина «банк обязан приходить верным + автономно» (D39.59/67/77) получает цену ошибки числом. +- **Маркер ⟨проверить⟩ на транслятор-проводе поведенчески пуст (Δ=0 < 10 п.п. — зарегистрированный + дефект).** N=6: нижняя граница принятия 61%; нулевую дельту от малой не отличить, от «смягчает + вдвое» — уже да. +- Не мерено: редакторский провод (двухсекционный `RenderEditorConstraintBlock`); фетч-сторона не + трогалась (эмбеддинг-ретривал закрыт D39.69, данные реопен не создают). + +--- + +## §D. Рекомендации тремя корзинами + +Индустриальная рамка (веб-обзор, 7 направлений; ключевые: DelTA ICLR'25 · CRAT · DITING/AgentEval'25 · +WMT25-Terminology · Kadavath'22/Tian'23 · TBX/MQM/memoQ · Netflix KNP · Bergmanis&Pinnis EACL'21): +стандарта автоматического арбитража ТЕРМИНА не существует (MBR/COMET/QE слепы к коротким строкам и +сущностям; индустрия людей решает процессом — роли/статусы/трассировка). Наш дизайн впереди ближайшего +академического аналога (DelTA: «первый перевод фиксируется» — у нас опровергнуто). Применимое, чего +нет: негативный forbidden-слой термбазы · лемма-инъекция/верификация · причинный A/B +no/proper/random-глоссарий · эскалация только спорных · вербализованная уверенность строго +внутримодельно. Наш замер уверенности совпал с литературой (overconfidence, несравнимость шкал). *[аннотация приёмки №13, веб-сверка по первоисточникам: overconfidence ВЕРБАЛИЗОВАННОЙ уверенности — Xiong et al. 2023 (arXiv:2306.13063), не Kadavath'22/Tian'23; Kadavath'22 — base-модели в правильном формате скорее хорошо калиброваны (P(True)); Tian'23 — RLHF ломает калибровку вероятностей, вербализованная ЛУЧШЕ; «несравнимость шкал» — вывод НАШЕГО замера (C3conf +0), литературой прямо не формулируется; DelTA first-wins и WMT25-terminology подтверждены]* + +**Строить сейчас** ($0-код + центовые перекупки батчей; механизм — §G): +1. Семейный со-батчинг (кластер-канал) — основание: §B4, §F2, 8/45 голда. +2. Внутрипрогонная сверка консолидаций — основание: 18/149 на живом банке. +3. Наблюдаемость: Signals + «выдумано вне улик» + conf-колонка — основание: §A7, AUC 0.77–0.85. + +**Измерить прежде чем решать:** +4. Рецензент-второе-семейство ТОЛЬКО на спорных кластерах (Q2-слот строки 5 при ре-пробе 74; роутинг + кластерный — E1-урок; выход рецензента — та же draft/⟨проверить⟩-эмиссия, согласие моделей ничего + не утверждает). +5. KWIC-сэмплинг первые-N против стратифицированных (~$0.02). +6. Причинный A/B банка no/proper/random на первой edit-волне добора идеала. +7. Редакторский провод двухсекционки (~$0.05): если и там Δ≈0 — доктрина «неподписанное С ПОМЕТКОЙ» + защищает меньше, чем записано, и это вопрос владельцу уровня доктрины. +8. Негативный слой (TBX forbidden): $0-счёт рецидивов отвергнутых форм на coldrun-финалах → при + ненулевом потоке дешёвый линт в пост-чеке. +9. Конвенция составных фамилий (Палладий: слитно) как данные пар-промпта — чинит 8/45; это + пар-правило транскрипции (класс Z-B3), не жанровый словарь, D39.47 не задет; подтверждение + владельца спрошено (Вопросы п.2). + +**Закрыть по нужности** (все — числами этой сессии): +10. Равноправный консилиум как прод-механизм (§B3 п.2). +11. Взвешивание кросс-модельной уверенностью (C3conf +0; шкалы несравнимы). +12. Само-согласованность N прогонов (SC−S1=+0; thinking игнорирует temperature — управляемой + вариативности нет). +13. Селекция «выбери из вариантов» — потолок 17/45, закрыт классом. +14. Отказ-сигнал ⟦TM-NO-DST⟧ — 0 использований на 3 семействах. +15. Эмбеддинг-фетч — остаётся закрытым (D39.69). + +**Оси §6 промта:** холодный старт — вся эмпирика холодная; «дозревание» тёплого банка (подписанная +строка чинит соседей через ⟦TM-CANON⟧) не мерено никем — вход в добор идеала. Вторая пара — кластер- +канал обязан прийти данными (не-CJK-детектора нет, строка 35). Серийный шаринг (48а/48б) — не +двигается; экспорт сида уже несёт конвенции в следующую книгу — усиливает п.9. + +**Свободная критика (правило №4):** качество банка лежит не в форме арбитража, а в +(1) достоверности строк (инъекция исполняется на 95% и заражает на 100%), (2) кластерных решениях +(8/45 одной конвенцией), (3) reachability (8/53 термов банк не видит — сид-половина строки 18 трекера +и Q7-замер эмиссии стоят выше по рычагу, чем любой консилиум), (4) вкусовом регистре владельца, +автономно недостижимом по построению — канал только сид/бриф/шаринг серии. Здесь и далее «строка N» — +строки бэклога PROGRESS, не строки кода. + +--- + +## §E. Перенос на ja→ru и en→ru + +Пре-регистрация (зафиксирована до запуска, дословно): **E-inject** — 2 ja-окна + 1 en-окно × 4 арма +A/B/C/D, дизайн §C; критерии ТЕ ЖЕ, что §0 п.5 — маркер «пуст», если Δ послушания wrong-строке +закон↔⟨проверить⟩ < 10 п.п.; вред реален при ≥50% принятия; перенос подтверждён, если направление +ja/en совпадает с zh (рычаг ↑, вред ~100%, маркер ~0). **E-family** (ja) — семья общего корня РАЗНОЙ +длины 魔術/魔術師 намеренно разрезана границей двух батчей терминолог-структурного промпта; критерий: +если корневые конвенции dst разошлись через границу — батч-граничная химера НЕ zh-специфична. +Оговорки, названные до запуска: ja/en-паков в репо нет ⇒ промпты пробы НЕ engine-faithful (проба +феномена, не движка); голда для ja/en нет ⇒ скорится ПОВЕДЕНИЕ, не правильность. Смета ≤$0.04. + +Исполнение: `multilang_probe.py`, книги `isekai_majutsushi_jp.txt` / `fifty_shades_1_en.txt`, +deepseek-low; 14 вызовов, факт $0.006472. + +| Пара | A | B закон | C wrong-закон | D wrong-⟨проверить⟩ | +|---|---|---|---|---| +| ja верные / wrong принят | 1/3 / 0/2 | 3/3 / 0/2 | 3/3 / **2/2** | 2/3 / **2/2 (Δ=0)** | +| en верные / wrong принят | 2/2 / 0/1 | 2/2 / 0/1 | 2/2 / **1/1** | 2/2 / **1/1 (Δ=0)** | + +Направление §C переносится на обе пары (N крошечный — проверка направления, не величины; единицы +вскрыты: en — «Кому: Кристиан Грэй» с неверной орфографией из инъекции). Family-тест ja (魔術/魔術師 +через границу батчей) не состоялся по назначению, но поймал важнее: **батч 0 вернул термы упрощённым +китайским** (魔術→魔术) — off-language класс на не-родной паре; парослепой экран +`ParseReply`/OffLanguage эти строки отбил бы — для будущей ja-пары он несущая защита, не гигиена. + +## §F. Кросс-пары по слову владельца + +Пре-регистрация (зафиксирована до запуска, дословно): **F1 zh→en** — тот же 63-термовый ростер, тот же +терминолог-протокол, target=английский (транскрипция pinyin); метрики: (а) стратегия-близость — по +каждому голд-терму сравнивается КЛАСС решения (смысловой перевод / транслит / гибрид) у en-выхода +против подписанного ru владельца, доля совпадений = «примерная близость банка к тому, что выбрала бы +свежая en-редакция»; (б) сверка с fan-каноном Reverend Insanity ПО ПАМЯТИ автора отчёта — помечается +как справочная (память, не источник), неуверенные строки пропускаются; (в) личная оценка +художественности en-выбора автором — субъективная, так и лейблится. **F2 en→zh** — `Empire of the +Dawn` (Кристофф, epub на диске; книга 2026 — претрейн-контаминация минимальна); майнинг ~12 +рекуррентных термов + 2 окна прозы; терминолог-проход en→zh и перевод окон (deepseek-low и glm-5); +метрики: связность семей термов; личная оценка художественности zh-прозы — субъективная. Критерий +близости F1: **≥70%** совпадения классов = «банк владельца НЕ однобокий»; **<50%** = «банк несёт +сильную ru-специфику» (обе формулировки легитимны — описание, не экзамен). Смета ≤$0.08. Оговорка: +en→zh и zh→en паков в движке нет — проба переносимости ПОДХОДА, не движка. + +Исполнение: `crosslang_bank.py`, 11 вызовов, факт $0.011310. ⚠ Девиация от пре-рега, названная: +вместо «~12 термов майнингом» взято **15** — майнер выдал одни имена, реалии добраны руками по +частотам (семья *-blood — намеренный тест корня); состав в `TERMS_F2` скрипта. + +**F1: банк владельца НЕ однобокий — 41/45 (91%) совпадений класса решения** (классификация ручная, +автор; полный джойн — `score_f1()`). Свежая en-редакция дала «Rank 1..9 · Grade A/B/C/D · Aperture · +Gu Master · Spring-Autumn Cicada · Mortal» — ровно классы подписей владельца, включая буквенный маппинг +甲→A, который ни один ru-черновик и ни одна ru-модель не дали (довод за канал сид/бриф: конвергентная +редакторская логика, до которой ru-модели не дотягиваются приором). Fan-канон Reverend Insanity по +памяти автора (помечено: память, не источник) ещё ближе к владельцу: 元石 fan «primeval stone» = +«первобытный камень» при свежем «Yuan Stone». 4 расхождения: 白家寨/熊家寨 (en транслит при +собственном «Gu Yue Village» — несвязность 寨-семьи воспроизвелась и в en) · 元石/元海. Ру-специфика +ровно одна: слитность «Гуюэ» (en-канон — «Gu Yue» двумя словами). Оговорка: en-проход видел +ru-варианты как улики смысла (велено «not as English candidates»; на 元石 от ru-улики ушёл). + +**F2:** deepseek — идеальная корневая связность *-blood (冷血者/高血者/苍血者), **glm сломал корень +внутри одного батча** (冷血者/高血族/苍白血): со-батчинг необходим, но не достаточен. deepseek +**выдумал 5 незапрошенных строк** — кросс-парное подтверждение нужности экрана `want[key]` в +ParseReply. **glm разошёлся в имени Aaron между соседними окнами (艾伦↔亚伦)** — межчанковый дрейф, +от которого банк существует, воспроизведён на en→zh за два вызова; в прозе glm оставил английское +слово («兄弟 forever») и выронил клаузу. Личная оценка прозы (вкус автора, субъективно): оба черновика +«редактируемо-издательские»; deepseek точнее к термам, glm местами идиоматичнее; стилистическая +разница меньше терминологической. Узкое место всех четырёх направлений — термы и конвенции, не слог. + +## §G. Направления доработки алгоритмов банка (общий уровень; детали — за сессией-исполнителем) + +Инварианты не трогаются: эмиссия auto/draft, «терминолог не может утвердить», Select/пост-чек/эскалация. + +1. **Семейный со-батчинг.** Детект семей по общей корневой морфеме из ПАР-ДАННЫХ (для имён — общая + начальная морфема-фамилия, для реалий — общая головная морфема; асимметрия — тоже данные); без + транзитивного замыкания (якорь — сама морфема, специфичный длинный корень бьёт общий короткий); + серия сильнее семьи; семья идёт в один батч целиком тем же механизмом, что серии. Пара без данных — + канал инертен. Цена: перекупка батчей терминолога один раз (центы), волны/снапшоты не двигаются. +2. **Внутрипрогонная сверка консолидаций** между собой (то же containment+лексемное правило, что у + канон-чека) — WARN с именованными парами + колонка стоп-таблицы. $0, вне снапшота. +3. **Наблюдаемость арбитража:** печать сигналов скоринга в стоп-таблицу; флаг «dst выдуман вне + вариантов черновиков»; третье поле «уверенность 0–100» в ответе роли → сортировка листа подписи + «сначала неуверенное» (запрещённая форма зафиксирована: кросс-модельное сравнение и «скор решает»). + Ловушка парсера: числовой хвост надо снимать до склейки полей ответа, иначе он молча въедет в dst. + `reasoning_content` в схему не заводить (сайдкар за debug-флагом, вне снапшота). +4. **Кластерный роутинг** любого будущего селективного арбитража (рецензент спорных — строка 5): + маршрутизация только целыми семья/серия-юнитами (урок E1-химеры). +5. **Счёт голосов по нормализованной форме** при сохранении сырых форм для показа — косметика колонки + spread (топ двигается 1/75), делать заодно с п.3. +6. **Не делать:** корзина 3 §D; series-детектор, Merge, семантика KWIC (кроме перфа строки 37 — + multi-pattern автомат в репо уже есть), Select, пост-чек — без изменений. + +Пункты 1+2+3+5 — один фикс-пак (одна перекупка батчей, голден не движется); п.4 — правило в дизайн +замера строки 5. + +--- + +## Вопросы владельцу + +1. **Мини-голд алиасов** (§E-1 research/20, висит с 17.07): полезен кластер-каналу, не гейт. Делать? + (метод и объём ~20–30 мин описаны в research/20 §E-1). +2. **«Гуюэ слитно» — пар-норма Палладия для составных фамилий или вкус книги?** Если пар-норма — + дата-правка пар-промпта (перекупка батчей, центы); если вкус — канал только сид. +3. **Проба редакторского провода двухсекционки** (~$0.05) — санкция? При Δ≈0 доктрина «неподписанное + С ПОМЕТКОЙ» требует пере-обсуждения. +4. Корзину «строить сейчас» (§G п.1–3,5) — передавать бэкенду одним фикс-паком класса D39.71? + +## Критик полноты + +- Один голд, одна книга, 45 строк; 古月-кластер коррелирует 8 строк — эффективный N меньше номинала; + интервалы точностей ±14 п.п.; кросс-книжная воспроизводимость не проверена. +- P1 — терминолог на до-катоверных весах: сравнение S1↔P1 конфаундится сменой весов (внутри одной + эры C3↔SC↔S1 конфаунда нет). +- Вся эмпирика — холодный старт; поведение с непустым ⟦TM-CANON⟧ не мерено. +- Проба C: N=6 неверных строк, один транслятор-провод, один арм-порядок; редакторский провод не мерен. +- §E: ja 2 окна / en 1 окно — направление, не величина; family-тест ja не состоялся (батч 0 негоден). +- §F: классификация стратегий ручная (автор); fan-канон — память модели; en-проход видел ru-улики. +- Словесная шкала уверенности мерена на одной модели; E1-правило «спорный» одно из возможных + (вывод о кластерном роутинге от него не зависит). +- Кластерные метрики — 3 семьи + *-blood; регистры обращений и алиас-графы голдом не покрыты. +- Инжект-смета книги — верхняя граница по потолку 800 ток., фактический размер блока не считан. +- Самопроверка ловила и свои дефекты метрик: первая версия A5-замера давала 38 «сдвигов» — ловушка + тай-брейка на связках ×1, честная метрика (слитые голоса строго обогнали сырой топ) даёт 1/75. + +## Адверсариальные проходы (author≠reviewer) + +- **Раунд 1 (до платных выводов):** два независимых агента. Код §A: 7/7 CONFIRMED по file:line. + Голд: числа воспроизведены пере-раном байт-в-байт; «промахи несправедливы из-за нормализации» + ОПРОВЕРГНУТО (0 несправедливых); джойн чист (пере-джойн точным равенством — тот же сплит 45/8); + порядок вариантов BANK-FULL = ранжирование §C2-3 (байт-сверка со стоп-таблицей 150/150). +- **Раунд 2 (по готовому отчёту):** агент чисел + агент логики/комплаенса. Все точности, парные, + AUC/CI, таблица пробы C и деньги — CONFIRMED пере-раном; батч-корреляция химеры подтверждена шире + голда. Исправлено по находкам: счёт семьи 4×+4× (было 3×), метрика связности приведена к + «заявление=команда», «медиана»→«среднее», честная формулировка критерия 4 (сработал у E1, не у C3), + Δ-метрика шкал помечена пост-хок, снята ложная оговорка про grok-ростер (все 7 пассов видели + идентичные 63 терма — сверено сырьём), к рецензенту дописана draft/auto-клауза. +- **Раунд 3 (ревью диффа финального рерайта, этот файл против v1):** независимый агент по + антипаттернам приёмки; числа сверены пере-раном — 100% чисты; новые клеймы (в т.ч. «промпт роли уже + требует родства») подтверждены первоисточниками; блокер — рерайт сжал зарегистрированные §0/§E/§F — + закрыт восстановлением пре-регов дословно (плюс явная пометка девиаций: реализация пробы C — + транслятор-провод при зарегистрированном редакторском рендере в скоупе; §F ~12→15 термов); + потери фактов (риск состава совета, контрфакт 26/45, D-якоря, рычаг-приоритет, основания B5) + возвращены; правки читабельности внесены. + +## Заявление = команда (приёмка пере-ранит; скрипты — `eval/bank_arbitration/`, питон `eval/.venv/bin/python3`) + +| Число | Команда | +|---|---| +| 53/45/8, голд | `build_gold.py` | +| P0 12/45 · P1 18/45 · 27 промахов · 5-в-вариантах | `score_baselines.py` | +| пассы ds/glm/mis/dsw | `consilium_probe.py --passes ds1,ds2,ds3,dsw,glm1,mis1` (+ `retry_mis_b4.py` после 429 Mistral) | +| grok-пасс | `consilium_probe.py --passes gro1` | +| формы, парные, AUC, кластеры, деньги-2-путь | `arbitrate.py` | +| серии BANK-FULL · spread≥2 50% · соло-точности · C4 | `extras_checks.py all` | +| проба C | `inject_probe.py` / `--score` | +| A4 18/149 · A5 1/75 | `value_demo.py` | +| §E ja/en | `multilang_probe.py` / `--score` | +| §F: прогон / джойн 45 пар | `crosslang_bank.py --part all` / `python -c "from crosslang_bank import score_f1; score_f1()"` | + +Сырьё: `~/books/gu-zhenren/bank-arbitration/*.json` — 84 файла (полные тела, usage, цены, effort в +каждом). Эффорты: deepseek `reasoning_effort:"low"` во всех вызовах; glm-5 thinking disabled; mistral/ +grok вендор-дефолт. Слаги фактчекнуты live `/models` перед пассами. Провенанс голда — поле provenance +каждой строки gold.jsonl. Полная версия отчёта до финального рерайта — черновик +`docs/archive/reports/DRAFT_BANK_ARBITRATION_V1_2026-08-04.md`. + +## Деньги + +| Проба | Потолок | Факт | +|---|---|---| +| B: ds1+ds2+ds3+dsw | — | $0.021991 | +| B: glm1 | — | $0.018495 | +| B: mis1 | — | $0.012808 | +| B: gro1 (опция) | — | $0.026546 | +| **Итого B** | ≤$0.70 | **$0.079840** | +| Проба C (инжект) | ≤$0.30 | **$0.009713** | +| §E ja/en достройка | — | $0.006472 | +| §F кросс-пары | ≤$0.08 | $0.011310 | +| **ВСЕГО** | **≤$1.00 (слово владельца 04.08)** | **$0.107335** | + +СТОП-условий не наступало; суб-потолки не тронуты. diff --git a/eval/bank_arbitration/arbitrate.py b/eval/bank_arbitration/arbitrate.py new file mode 100644 index 00000000..7c012308 --- /dev/null +++ b/eval/bank_arbitration/arbitrate.py @@ -0,0 +1,247 @@ +#!/usr/bin/env python3 +"""$0-агрегация проб консилиума по пре-регистрации research/24 §0. + +Формы: P0 (топ §C2-3) · P1 (прод coldrun-a) · S1 (ds1) · SC (majority ds1..3) · +C3 (majority ds1,glm1,mis1) · C3conf (взвешенный уверенностью) · E1 (улики-первым). +Метрики: точность против голда · парные сравнения · кластерная связность · +B2 (AUC уверенности, устойчивость, сравнимость шкал, канал отказа) · деньги вторым путём. +""" +import collections +import json +import re +import unicodedata +from pathlib import Path + +HERE = Path(__file__).resolve().parent +RAW = Path.home() / "books" / "gu-zhenren" / "bank-arbitration" +GOLD = [json.loads(l) for l in open(HERE / "gold" / "gold.jsonl", encoding="utf-8")] +NODST = "⟦TM-NO-DST⟧" +WORD2NUM = {"точно": 95, "скорее да": 70, "не уверен": 40, "не знаю": 10} +FIELD = re.compile(r"\t| {2,}|\s*\|\s*") + + +def ntgt(s: str) -> str: + s = unicodedata.normalize("NFKC", s or "").casefold().replace("ё", "е") + for ch in "«»\"'": + s = s.replace(ch, "") + return " ".join(s.split()) + + +def eq(a: str, b: str) -> bool: + return ntgt(a) == ntgt(b) and ntgt(a) != "" + + +def parse_pass(tag: str) -> dict: + """src -> (dst, conf|None). Терпимый к «третье поле съедено в dst».""" + out = {} + cost = 0.0 + for f in sorted(RAW.glob(f"{tag}-b*.json")): + rec = json.load(open(f, encoding="utf-8")) + cost += rec["cost_usd"] + for ln in rec["content"].split("\n"): + ln = ln.strip() + if not ln or ln.startswith("#"): + continue + parts = [p.strip() for p in FIELD.split(ln) if p.strip()] + if len(parts) < 2: + continue + src = parts[0] + conf = None + rest = parts[1:] + last = rest[-1].casefold() if rest else "" + if len(rest) >= 2: + if re.fullmatch(r"\d{1,3}", rest[-1]): + conf = int(rest[-1]) + rest = rest[:-1] + elif last in WORD2NUM: + conf = WORD2NUM[last] + rest = rest[:-1] + dst = " ".join(rest) + if src not in out: + out[src] = (dst, conf) + return {"map": out, "cost": cost} + + +def majority(votes: list[str], fallback: str) -> str: + cnt = collections.Counter(ntgt(v) for v in votes if v and v != NODST) + if not cnt: + return fallback + top, n = cnt.most_common(1)[0] + if n >= 2: + for v in votes: # вернуть сырую форму первого голоса за победителя + if ntgt(v) == top: + return v + return fallback + + +def conf_weighted(pairs: list[tuple[str, int | None]], fallback: str) -> str: + w = collections.defaultdict(float) + raw = {} + for dst, conf in pairs: + if not dst or dst == NODST: + continue + w[ntgt(dst)] += (conf if conf is not None else 50) + raw.setdefault(ntgt(dst), dst) + if not w: + return fallback + return raw[max(w, key=lambda k: (w[k], k))] + + +def auc(scores_pos, scores_neg): + """Ранговая AUC (Mann-Whitney), плюс bootstrap 90% CI.""" + import random + def one(p, n): + if not p or not n: + return None + wins = ties = 0 + for a in p: + for b in n: + if a > b: + wins += 1 + elif a == b: + ties += 1 + return (wins + ties / 2) / (len(p) * len(n)) + point = one(scores_pos, scores_neg) + if point is None: + return None, (None, None) + rng = random.Random(24) + bs = [] + for _ in range(2000): + p = [rng.choice(scores_pos) for _ in scores_pos] + n = [rng.choice(scores_neg) for _ in scores_neg] + v = one(p, n) + if v is not None: + bs.append(v) + bs.sort() + return point, (bs[int(0.05 * len(bs))], bs[int(0.95 * len(bs))]) + + +def main(): + inb = [r for r in GOLD if r["in_bank"]] + gold_by_src = {r["bank_src"]: r for r in inb} + + passes = {t: parse_pass(t) for t in ["ds1", "ds2", "ds3", "dsw", "glm1", "mis1"]} + for t, p in passes.items(): + print(f"pass {t}: {len(p['map'])} строк, ${p['cost']:.6f}") + total = sum(p["cost"] for p in passes.values()) + print(f"деньги проб B (второй путь, из сырья): ${total:.6f}") + + # формы + forms = {} + for src, g in gold_by_src.items(): + variants = g.get("variants") or [] + p0 = variants[0][0] if variants else "" + ds = [passes[t]["map"].get(src, ("", None)) for t in ("ds1", "ds2", "ds3")] + glm = passes["glm1"]["map"].get(src, ("", None)) + mis = passes["mis1"]["map"].get(src, ("", None)) + s1 = ds[0][0] + sc = majority([d[0] for d in ds], fallback=s1) + c3votes = [ds[0][0], glm[0], mis[0]] + c3 = majority(c3votes, fallback=(p0 if any(eq(v, p0) for v in c3votes) else s1)) + c3conf = conf_weighted([ds[0], glm, mis], fallback=s1) + contested = (g.get("spread", 0) >= 2 and len(variants) >= 2 and variants[0][1] - variants[1][1] <= 1) \ + or (variants and variants[0][1] == 1) + e1 = c3 if contested else p0 + forms[src] = dict(P0=p0, P1=g.get("bank_dst", ""), S1=s1, SC=sc, C3=c3, C3conf=c3conf, E1=e1, + contested=contested) + + names = ["P0", "P1", "S1", "SC", "C3", "C3conf", "E1"] + print("\n=== Точность против голда (45) ===") + accs = {} + for n in names: + ok = [s for s, f in forms.items() if eq(f[n], gold_by_src[s]["gold_dst"])] + accs[n] = set(ok) + print(f" {n}: {len(ok)}/45") + print(f" спорных термов (E1 зовёт совет): {sum(1 for f in forms.values() if f['contested'])}/45") + + print("\n=== Парные сравнения (A-прав-B-неправ / B-прав-A-неправ) ===") + for a, b in [("S1", "P0"), ("SC", "P0"), ("C3", "P0"), ("C3conf", "P0"), ("E1", "P0"), + ("C3", "SC"), ("C3", "S1"), ("SC", "S1"), ("C3conf", "C3"), ("E1", "C3"), ("S1", "P1"), ("C3", "P1")]: + x = len(accs[a] - accs[b]); y = len(accs[b] - accs[a]) + print(f" {a} vs {b}: +{x} / -{y} (net {x - y:+d})") + + print("\n=== Единицы: где C3 разошёлся с голдом, а S1/SC были правы (и наоборот) ===") + for s in sorted((accs["S1"] | accs["SC"]) - accs["C3"]): + f = forms[s] + print(f" C3 потерял {s}: gold={gold_by_src[s]['gold_dst']!r} S1={f['S1']!r} C3={f['C3']!r}") + for s in sorted(accs["C3"] - (accs["S1"] | accs["SC"])): + f = forms[s] + print(f" C3 добыл {s}: gold={gold_by_src[s]['gold_dst']!r} S1={f['S1']!r} C3={f['C3']!r}") + + # кластеры + FAMS = { + "古月-семья": [s for s in forms if s.startswith("古月")], + "转-серия": [s for s in forms if s.endswith("转") and len(s) == 2], + "等-серия": [s for s in forms if s.endswith("等") and len(s) == 2], + } + NUMERALS = {"первый", "второй", "третий", "четвертый", "пятый", "шестой", "седьмой", "восьмой", "девятый"} + + def kind_of(fam: str, v: str) -> str: + """Конвенция строки: 古月 — слитно/раздельно ГДЕ БЫ ни стояла фамилия; серии — не-числительная голова.""" + s = ntgt(v) + if not s: + return "<пусто>" + if fam == "古月-семья": + if "гу юэ" in s: + return "раздельно" + if "гуюэ" in s: + return "слитно" + return "иное:" + s + words = [w for w in s.replace("«", " ").replace("»", " ").split() if w not in NUMERALS] + # конвенция серии = ГОЛОВА (родовое слово) — первое не-числительное слово («уровень цзя» и + # «уровень и» делят конвенцию «уровень»; модификатор серии различен по построению) + return words[0] if words else s + + print("\n=== Кластерная связность (одна конвенция на семью?) ===") + for fam, members in FAMS.items(): + if len(members) < 2: + continue + print(f" {fam} ({len(members)}):") + for n in ["P1", "S1", "SC", "C3", "C3conf", "E1"]: + kinds = {kind_of(fam, forms[m][n]) for m in members} + coherent = len(kinds) == 1 + print(f" {n}: {'КОНСИСТЕНТНА (' + next(iter(kinds)) + ')' if coherent else 'ХИМЕРА ' + str(sorted(kinds))}") + for m in members: + print(f" {m}: gold={gold_by_src[m]['gold_dst']!r} S1={forms[m]['S1']!r} glm={passes['glm1']['map'].get(m,('',))[0]!r} mis={passes['mis1']['map'].get(m,('',))[0]!r}") + + # B2: уверенность + print("\n=== B2: уверенность ===") + for t in ["ds1", "glm1", "mis1", "dsw"]: + pos, neg = [], [] + for s, g in gold_by_src.items(): + dst, conf = passes[t]["map"].get(s, ("", None)) + if conf is None or not dst or dst == NODST: + continue + (pos if eq(dst, g["gold_dst"]) else neg).append(conf) + a, (lo, hi) = auc(pos, neg) + mean = (sum(pos) + sum(neg)) / max(1, len(pos) + len(neg)) + print(f" {t}: AUC={a if a is None else round(a,3)} CI90=({lo and round(lo,3)},{hi and round(hi,3)}) " + f"n_prav={len(pos)} n_neprav={len(neg)} средняя conf={round(mean,1)}") + # устойчивость ds1..ds3 + diffs, flips = [], 0 + n_common = 0 + for s in gold_by_src: + recs = [passes[t]["map"].get(s) for t in ("ds1", "ds2", "ds3")] + if any(r is None for r in recs): + continue + n_common += 1 + cs = [r[1] for r in recs if r[1] is not None] + if len(cs) >= 2: + diffs.append(max(cs) - min(cs)) + if len({ntgt(r[0]) for r in recs}) > 1: + flips += 1 + diffs.sort() + med = diffs[len(diffs) // 2] if diffs else None + print(f" устойчивость ds1..ds3: медиана размаха conf={med} п., флипов ответа {flips}/{n_common}") + # отказы + for t in passes: + nod = sum(1 for d, _ in passes[t]["map"].values() if d == NODST) + print(f" {t}: ⟦TM-NO-DST⟧ = {nod}") + + (HERE / "forms_dump.json").write_text( + json.dumps({s: forms[s] for s in sorted(forms)}, ensure_ascii=False, indent=1), encoding="utf-8") + print("\nформы записаны в forms_dump.json") + + +if __name__ == "__main__": + main() diff --git a/eval/bank_arbitration/build_gold.py b/eval/bank_arbitration/build_gold.py new file mode 100644 index 00000000..87dac1bf --- /dev/null +++ b/eval/bank_arbitration/build_gold.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python3 +"""B1: голд-набор арбитража банка (промт BANK_ARBITRATION §4 B1, $0). + +Ядро голда = сид v2 (~/books/gu-zhenren/guzhenren-seed-v2.yaml): 53 записи status:approved +с подписанным владельцем dst. Джойн против банка coldrun-a (BANK-FULL.tsv + bank-stop +таблица с KWIC и вариантами черновиков) — по нормализованной поверхности src + алиасам. + +Выход: gold/gold.jsonl — по строке на голд-терм с провенансом: + src, gold_dst (подпись владельца), gold_alt (decl-формы и алиасы dst — НЕ считаются + верным ответом арбитража, лежат для справки), type, seed_note, + in_bank (нашёлся ли в BANK-FULL), bank_dst (что сконсолидировал терминолог coldrun-a), + bank_origin/freq/spread, variants [(dst, chunks)] в ПОРЯДКЕ ранжирования §C2-3 + (bankStopRows рендерит best-ranked first — это и есть бесплатный базис P0), + contexts (KWIC из bank-stop), provenance. + +Смещение голда named честно в отчёте: сид = термы, до которых дошли руки владельца. +Читает всё READ-ONLY. Не вызывает моделей. $0. +""" +import json +import os +import sys +import unicodedata + +sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "bank_autonomy")) +import parse_common # noqa: E402 + +import yaml # noqa: E402 + +SEED = os.path.expanduser("~/books/gu-zhenren/guzhenren-seed-v2.yaml") +BANKFULL = os.path.join(parse_common.SCRATCH, "BANK-FULL.tsv") +OUT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "gold", "gold.jsonl") + + +def norm_src(s: str) -> str: + """Зеркало text.NormalizeSourceKey для нашего среза: NFKC + lower. + trad2simp/kana-fold не нужны — сид и банк оба simplified-zh (проверяется джойном: + непарные строки печатаются, глазами).""" + return unicodedata.normalize("NFKC", s or "").strip().lower() + + +def load_seed(): + doc = yaml.safe_load(open(SEED, encoding="utf-8")) + out = [] + for t in doc.get("terms", []): + if t.get("status") != "approved" or not t.get("dst"): + continue + aliases = [a["alias"] for a in t.get("aliases", []) if a.get("alias")] + decl = (t.get("decl") or {}).get("forms") or [] + out.append({ + "src": t["src"], "gold_dst": t["dst"], "type": t.get("type", "term"), + "aliases": aliases, "gold_alt": decl, "seed_note": t.get("note", ""), + "since_ch": t.get("since_ch", 0), + }) + return out + + +def load_bankfull(): + """BANK-FULL.tsv: src, сведённый_dst, origin, type, freq, spread, варианты, n_ctx.""" + rows = {} + with open(BANKFULL, encoding="utf-8") as f: + header = f.readline() + assert header.startswith("src\t"), header + for ln in f: + p = ln.rstrip("\n").split("\t") + if len(p) < 8: + continue + variants = [] + for part in p[6].split(" | "): + part = part.strip() + if not part: + continue + if "×" in part: + d, _, n = part.rpartition("×") + variants.append((d.strip(), int(n))) + else: + variants.append((part, 1)) + rows[norm_src(p[0])] = { + "src": p[0], "bank_dst": p[1] if p[1] != "—" else "", + "origin": p[2], "type": p[3], "freq": int(p[4]), "spread": int(p[5]), + "variants": variants, + } + return rows + + +def main(): + seed = load_seed() + bank = load_bankfull() + stop = parse_common.parse_bankstop() # src -> {..., ctx: [...]} + stop_by_norm = {norm_src(k): v for k, v in stop.items()} + + gold, matched, unmatched = [], 0, [] + for t in seed: + surfaces = [t["src"]] + t["aliases"] + hit = None + hit_surface = None + for s in surfaces: + if norm_src(s) in bank: + hit = bank[norm_src(s)] + hit_surface = s + break + rec = { + "src": t["src"], "gold_dst": t["gold_dst"], "type": t["type"], + "gold_alt": t["gold_alt"], "aliases": t["aliases"], "seed_note": t["seed_note"], + "in_bank": hit is not None, + "provenance": f"seed v2 approved (владелец) src={t['src']}; bank=coldrun-a BANK-FULL" + + (f" via surface {hit_surface}" if hit_surface and hit_surface != t["src"] else ""), + } + if hit: + matched += 1 + st = stop_by_norm.get(norm_src(hit["src"]), {}) + rec.update({ + "bank_src": hit["src"], "bank_dst": hit["bank_dst"], "bank_origin": hit["origin"], + "bank_type": hit["type"], "freq": hit["freq"], "spread": hit["spread"], + "variants": hit["variants"], "contexts": st.get("ctx", []), + "evidence": st.get("evidence", []), + }) + else: + unmatched.append(t["src"]) + gold.append(rec) + + os.makedirs(os.path.dirname(OUT), exist_ok=True) + with open(OUT, "w", encoding="utf-8") as f: + for r in gold: + f.write(json.dumps(r, ensure_ascii=False) + "\n") + + n_var2 = sum(1 for r in gold if r["in_bank"] and len(r.get("variants", [])) >= 2) + print(f"seed approved: {len(seed)} | matched in BANK-FULL: {matched} | not in bank: {len(unmatched)}") + print(f"of matched: spread>=2 (арбитражные, есть из чего выбирать): {n_var2}") + print("not in bank:", ", ".join(unmatched)) + print(f"wrote {OUT}") + + +if __name__ == "__main__": + main() diff --git a/eval/bank_arbitration/consilium_probe.py b/eval/bank_arbitration/consilium_probe.py new file mode 100644 index 00000000..a36905b3 --- /dev/null +++ b/eval/bank_arbitration/consilium_probe.py @@ -0,0 +1,269 @@ +#!/usr/bin/env python3 +"""B3(+B2): пробы консилиума по пре-регистрации research/24 §0. Прямой API, не движок. + +Пассы: ds1..ds3 (deepseek flash, effort low, само-согласованность) · dsw (словесная шкала) · +glm1 (glm-5, thinking off) · mis1 (mistral-large-2512) · gro1 (grok-4.3, опция --grok). +Вход — engine-faithful RenderBatch-блоки из bank-stop coldrun-a (серии со-батчены, как §1 движка). +Сырьё — durable ~/books/gu-zhenren/bank-arbitration/. Деньги считаются из usage × цены models.yaml. +""" +from __future__ import annotations +import argparse +import collections +import json +import os +import sys +import time +from pathlib import Path + +from dotenv import load_dotenv +from openai import OpenAI + +REPO = Path("/home/ubuntu/projects/textmachine") +HERE = Path(__file__).resolve().parent +RAW = Path.home() / "books" / "gu-zhenren" / "bank-arbitration" +RAW.mkdir(exist_ok=True) +load_dotenv(REPO / "eval" / ".env") # ключи грузит скрипт; значения наружу не печатаются + +sys.path.insert(0, str(HERE.parent / "bank_autonomy")) +from parse_common import parse_bankstop # noqa: E402 + +# Цены — backend/configs/models.yaml (prices_checked 2026-07-10): input/cached/output за 1M. +PRICES = { + "deepseek-v4-flash": (0.14, 0.0028, 0.28), + "glm-5": (1.0, 0.2, 3.2), + "mistral-large-2512": (0.5, 0.5, 1.5), + "grok-4.3": (1.25, 1.25, 2.50), +} +PROVIDERS = { + "deepseek-v4-flash": ("https://api.deepseek.com/v1", "DEEPSEEK_API_KEY"), + "glm-5": ("https://api.z.ai/api/paas/v4", "ZAI_API_KEY"), + "mistral-large-2512": ("https://api.mistral.ai/v1", "MISTRAL_API_KEY"), + "grok-4.3": ("https://api.x.ai/v1", "XAI_API_KEY"), +} + +TERM_PROMPT = REPO / "backend/prompts/zh-ru/terminologist.md" +USER_SEP = "\n---USER---\n" +BATCH_RUNES = 6000 # terminologyDefaultBatchRunes + +CONF_NUM = ("\n\nДОПОЛНЕНИЕ К ФОРМАТУ (только для этого прогона): добавь ТРЕТЬЕ поле через " + "табуляцию — твою уверенность в выбранном переводе ЧИСЛОМ от 0 до 100 " + "(0 — наугад, 100 — абсолютно уверен). Пример: 师父\tнаставник\t85") +CONF_WORD = ("\n\nДОПОЛНЕНИЕ К ФОРМАТУ (только для этого прогона): добавь ТРЕТЬЕ поле через " + "табуляцию — твою уверенность в выбранном переводе РОВНО ОДНИМ из выражений: " + "точно | скорее да | не уверен | не знаю. Пример: 师父\tнаставник\tточно") + +# Экстра-поверхности для кластерной метрики (все живут в BANK-FULL; голд-dst у них нет, +# скорим только связность конвенции внутри семьи). +EXTRAS = [ + "二转", "四转", "九转", # достройка 转-серии + "甲等资质", "乙等资质", "丙等资质", # серия 3 + "初阶", "中阶", "高阶", # серия 4 + "古月师", "古月族长", "古月一族", "古月陈博", "古月藻榭", "古月山寨", # 古月-семья (разнодлинная) + "蛊室", "本命蛊", "希望蛊", "炼蛊", "一转蛊师", "三转蛊师", # 蛊-семья +] + +SERIES = { + "zhuan": ["一转", "二转", "三转", "四转", "五转", "六转", "九转"], # 二转 из BANK-FULL, добран в EXTRAS + "deng": ["甲等", "乙等", "丙等", "丁等"], + "dengzizhi": ["甲等资质", "乙等资质", "丙等资质"], + "jie": ["初阶", "中阶", "高阶"], +} + + +def render_terminologist(text_block: str) -> tuple[str, str]: + raw = TERM_PROMPT.read_text(encoding="utf-8") + out, rest = [], raw + while True: + i = rest.find("") + rest = rest[j + 3:] + canon = "".join(out) + head, user = canon.split(USER_SEP, 1) + vals = {"source_lang": "zh", "target_lang": "ru", "genre": "вебновелла", + "audience": "взрослые читатели вебновелл", "title": "蛊真人", "venuti": "0.60", + "honorifics": "keep", "transcription": "palladius", "footnotes": "minimal", + "text": text_block} + system = head.strip() + for k, v in vals.items(): + system = system.replace("{{" + k + "}}", v) + user = user.replace("{{" + k + "}}", v) + return system, user.strip() + + +def block_of(c: dict) -> str: + b = [f"### {c['src']}", + f"key: {c['src']}\ntype: {c['type'] or 'term'}\norigin: {c['origin']}\nfreq: {c['freq']}\nsince_ch: 0"] + if c.get("evidence"): + b.append(f"evidence: {', '.join(c['evidence'])}") + if c.get("drafts"): + b.append("drafts: " + " | ".join(f"{d} ×{n}" for d, n in c["drafts"])) + for k in c.get("ctx", []): + b.append(f"ctx: {k}") + return "\n".join(b) + + +def build_roster() -> list[dict]: + bs = parse_bankstop() + gold = [json.loads(l) for l in open(HERE / "gold" / "gold.jsonl", encoding="utf-8")] + srcs = [r["bank_src"] for r in gold if r.get("in_bank")] + for e in EXTRAS: + if e not in srcs: + srcs.append(e) + roster = [] + missing = [] + for s in srcs: + if s not in bs: + missing.append(s) + continue + r = bs[s] + roster.append({"src": s, "type": r.get("type", "term"), "origin": r.get("origin", ""), + "freq": r.get("freq", 0), "drafts": r.get("drafts", []), + "ctx": r.get("ctx", []), "evidence": r.get("evidence", [])}) + if missing: + print("NOT in bank-stop (пропущены):", ", ".join(missing)) + return roster + + +def batches_of(roster: list[dict]) -> list[list[dict]]: + """Реплика Batch(): ключ-сортировка → серии contiguous → пак ≤6000 рун → батчи по freq desc.""" + sid = {} + for i, members in enumerate(SERIES.values(), 1): + for m in members: + sid[m] = i + ordered = sorted(roster, key=lambda c: c["src"]) + # series contiguous, anchored at first member position + out_order, emitted = [], set() + by_sid = collections.defaultdict(list) + for c in ordered: + if sid.get(c["src"]): + by_sid[sid[c["src"]]].append(c) + for c in ordered: + s = sid.get(c["src"]) + if not s: + out_order.append(c) + elif s not in emitted: + out_order.extend(by_sid[s]) + emitted.add(s) + batches, cur, size = [], [], 0 + i = 0 + while i < len(out_order): + j = i + 1 + if sid.get(out_order[i]["src"]): + s = sid[out_order[i]["src"]] + while j < len(out_order) and sid.get(out_order[j]["src"]) == s: + j += 1 + unit = out_order[i:j] + n = sum(len(block_of(c)) + 2 for c in unit) + if cur and size + n > BATCH_RUNES: + batches.append(cur) + cur, size = [], 0 + cur.extend(unit) + size += n + i = j + if cur: + batches.append(cur) + batches.sort(key=lambda b: -sum(c["freq"] for c in b)) + return batches + + +def call(client: OpenAI, model: str, system: str, user: str, tag: str, + effort: str | None, thinking_off: bool, cap: int = 16000) -> dict: + msgs = [{"role": "system", "content": system}, {"role": "user", "content": user}] + kw = dict(model=model, messages=msgs, max_tokens=cap, temperature=0) + extra = {} + if effort: + extra["reasoning_effort"] = effort + if thinking_off: + extra["thinking"] = {"type": "disabled"} + if extra: + kw["extra_body"] = extra + t0 = time.time() + r = client.chat.completions.create(**kw) + ch = r.choices[0] + content = ch.message.content or "" + reasoning = getattr(ch.message, "reasoning_content", None) or "" + u = r.usage + pt = getattr(u, "prompt_tokens", 0) or 0 + ct = getattr(u, "completion_tokens", 0) or 0 + cached = getattr(getattr(u, "prompt_tokens_details", None), "cached_tokens", 0) or 0 + pin, pcache, pout = PRICES[model] + cost = (pt - cached) / 1e6 * pin + cached / 1e6 * pcache + ct / 1e6 * pout + rec = dict(tag=tag, model=model, model_returned=r.model, effort=effort or ("thinking-off" if thinking_off else "default"), + ts=time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()), cap=cap, + finish=ch.finish_reason, prompt_tokens=pt, cached_tokens=cached, + completion_tokens=ct, cost_usd=round(cost, 6), latency_s=round(time.time() - t0, 1), + content=content, reasoning_chars=len(reasoning), system=system, user=user) + (RAW / f"{tag}.json").write_text(json.dumps(rec, ensure_ascii=False, indent=1), encoding="utf-8") + print(f"[{tag}] {model} finish={ch.finish_reason} in={pt}(c{cached}) out={ct} ${cost:.6f} {rec['latency_s']}s content={len(content)}c") + return rec + + +def slug_check(model: str) -> None: + base, keyenv = PROVIDERS[model] + key = os.environ.get(keyenv) + if not key: + print(f"SKIP {model}: нет {keyenv}") + raise KeyError(keyenv) + cl = OpenAI(api_key=key, base_url=base, timeout=120) + ids = [m.id for m in cl.models.list().data] + ok = model in ids + print(f"/models {model}: {'OK' if ok else 'ОТСУТСТВУЕТ! listing=' + ','.join(ids[:20])}") + if not ok: + raise RuntimeError(f"слаг {model} не листится") + + +def client_for(model: str) -> OpenAI: + base, keyenv = PROVIDERS[model] + return OpenAI(api_key=os.environ[keyenv], base_url=base, timeout=600) + + +PASSES = { + # tag: (model, effort, thinking_off, conf_instruction) + "ds1": ("deepseek-v4-flash", "low", False, CONF_NUM), + "ds2": ("deepseek-v4-flash", "low", False, CONF_NUM), + "ds3": ("deepseek-v4-flash", "low", False, CONF_NUM), + "dsw": ("deepseek-v4-flash", "low", False, CONF_WORD), + "glm1": ("glm-5", None, True, CONF_NUM), + "mis1": ("mistral-large-2512", None, False, CONF_NUM), + "gro1": ("grok-4.3", None, False, CONF_NUM), +} + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--passes", default="ds1,ds2,ds3,dsw,glm1,mis1") + ap.add_argument("--dry", action="store_true", help="напечатать батчи и смету, без вызовов") + a = ap.parse_args() + + roster = build_roster() + batches = batches_of(roster) + print(f"roster={len(roster)} терм., batches={len(batches)}: " + + " ".join(f"#{i}:{len(b)}терм/{sum(len(block_of(c))+2 for c in b)}рун" for i, b in enumerate(batches))) + if a.dry: + for i, b in enumerate(batches): + print(f"--- batch {i}: {' '.join(c['src'] for c in b)}") + return + + want = [p.strip() for p in a.passes.split(",") if p.strip()] + for model in sorted({PASSES[p][0] for p in want}): + slug_check(model) + + total = 0.0 + for p in want: + model, effort, toff, conf = PASSES[p] + cl = client_for(model) + for i, b in enumerate(batches): + system, user = render_terminologist("\n\n".join(block_of(c) for c in b)) + rec = call(cl, model, system, user + conf, f"{p}-b{i}", effort, toff) + total += rec["cost_usd"] + time.sleep(1.0) + print(f"TOTAL cost this run: ${total:.6f}") + + +if __name__ == "__main__": + main() diff --git a/eval/bank_arbitration/crosslang_bank.py b/eval/bank_arbitration/crosslang_bank.py new file mode 100644 index 00000000..54a04128 --- /dev/null +++ b/eval/bank_arbitration/crosslang_bank.py @@ -0,0 +1,182 @@ +#!/usr/bin/env python3 +"""§F: кросс-пары. F1 — zh→en терминолог-проход по голд-ростеру (близость стратегий к ru-банку +владельца). F2 — en→zh на Empire of the Dawn (Кристофф): майнинг термов + терминолог-проход + перевод +двух окон (deepseek-low и glm-5). Сырьё → ~/books/gu-zhenren/bank-arbitration/ (общий durable пака). +""" +from __future__ import annotations +import argparse +import collections +import json +import os +import re +import time +import zipfile +from pathlib import Path + +from dotenv import load_dotenv +from openai import OpenAI + +REPO = Path("/home/ubuntu/projects/textmachine") +HERE = Path(__file__).resolve().parent +RAW = Path.home() / "books" / "gu-zhenren" / "bank-arbitration" +KRISTOFF = Path.home() / "books" / "Kristoff_Jay_-_Empire_of_the_Vampire_3_-_Empire_of_the_Dawn.epub" +load_dotenv(REPO / "eval" / ".env") + +import sys # noqa: E402 +sys.path.insert(0, str(HERE)) +import consilium_probe as cp # noqa: E402 (ростер, батчер, call, цены, клиенты) + +TERM_EN_SYS = """You are the terminologist of a publishing-grade translation from Chinese into English. +Book: «蛊真人» (a cultivation webnovel). You are given the book's term list; for each term — contexts +from the SOURCE and renderings the draft translators already proposed (in Russian — a parallel edition; +treat them as evidence of meaning, not as English candidates). You see the whole book at once; pick ONE +English rendering per term, consistent across the whole book. Transcribe personal and place names in +pinyin; translate titles, ranks and realia by MEANING. Keep families of related terms sharing a source +morpheme consistent in English. Dictionary form, no explanations. +Answer format: one line per term, exactly two fields separated by a TAB: source term, English rendering.""" + +TERM_ZH_SYS = """你是一部出版级奇幻小说英译中项目的术语专家。小说:《Empire of the Dawn》(Jay Kristoff, +吸血鬼史诗奇幻)。给你这本书的术语表:每个术语附有原文语境。你能看到整本书,请为每个术语选定ONE个 +统一的中文译名,全书一致。人名用约定俗成的音译;头衔、组织、事物按意义翻译,要求文学性、符合奇幻 +小说的中文语感。同源术语的译名要保持词根呼应。只给词典形式,不要解释。 +回答格式:每行一个术语,两个字段,用制表符分隔:原文术语、中文译名。""" + +TRANSLATE_ZH_SYS = """你是一位专业文学翻译家,把英文小说译成中文。这是 Jay Kristoff 的吸血鬼史诗奇幻 +《Empire of the Dawn》。要求:逐句翻译,不删不增;中文要有文学性,句式自然,避免翻译腔;对话用中文 +小说的标点习惯。人名音译。只输出译文,不要任何前言、注释或 markdown。""" + + +def epub_text() -> str: + out = [] + with zipfile.ZipFile(KRISTOFF) as z: + for n in sorted(z.namelist()): + if n.endswith((".xhtml", ".html")): + html = z.read(n).decode("utf-8", "ignore") + txt = re.sub(r"<[^>]+>", " ", html) + txt = re.sub(r"&[a-z]+;", " ", txt) + out.append(re.sub(r"\s+", " ", txt)) + return "\n".join(out) + + +def mine_en_terms(text: str, top=14): + """Рекуррентные капитализированные термы: имена + двусловные (The X / X Y).""" + stop = {"The", "But", "And", "She", "His", "Her", "They", "That", "This", "What", "When", "With", + "For", "Not", "You", "All", "Was", "Had", "Chapter", "Then", "Now", "There", "One", "It's", + "Book", "Part", "From", "Like", "Still", "Yet", "So", "In", "On", "At", "He", "We", "If", + "God", "Oui", "Non", "Mademoiselle", "Monsieur"} + words = collections.Counter(re.findall(r"\b[A-Z][a-zà-ÿé]+(?:\s[A-Z][a-zà-ÿé]+)?\b", text)) + cand = [(w, n) for w, n in words.most_common(400) + if n >= 15 and w.split()[0] not in stop and len(w) > 3] + # предпочесть двусловные и явные имена/реалии + seen, out = set(), [] + for w, n in cand: + head = w.split()[0] + if head in seen: + continue + seen.add(head) + out.append((w, n)) + if len(out) == top: + break + return out + + +def kwic(text, term, per=3, width=60): + out, frm = [], 0 + while len(out) < per: + i = text.find(term, frm) + if i < 0: + break + out.append(text[max(0, i - width):i + len(term) + width]) + frm = i + len(term) + return out + + +def run_f1(models=("deepseek-v4-flash",)): + roster = cp.build_roster() + batches = cp.batches_of(roster) + total = 0.0 + for model in models: + cl = cp.client_for(model) + short = {"deepseek-v4-flash": "ds", "glm-5": "glm"}[model] + for i, b in enumerate(batches): + user = "Термины книги:\n\n" + "\n\n".join(cp.block_of(c) for c in b) + rec = cp.call(cl, model, TERM_EN_SYS, user, f"xen-{short}-b{i}", + "low" if model.startswith("deepseek") else None, model == "glm-5") + total += rec["cost_usd"] + time.sleep(1) + return total + + +# F2-ростер: майнер дал имена; реалии добраны РУКАМИ по частотам (раскрыто в отчёте). Семья +# *-blood (coldblood/highblood/paleblood) — намеренный тест корневой связности в zh. +TERMS_F2 = ["Dior", "Gabriel", "Phoebe", "Celene", "Voss", "silversaint", "coldblood", "highblood", + "paleblood", "Forever King", "Grail", "San Michon", "aegis", "duskdancer", "famille"] + + +def run_f2(): + text = epub_text() + print(f"epub text: {len(text)} chars") + terms = [(t, text.count(t)) for t in TERMS_F2] + print("terms:", terms) + blocks = [] + for t, n in terms: + blocks.append(f"### {t}\nfreq: {n}\n" + "\n".join(f"ctx: {c}" for c in kwic(text, t))) + user = "Terms:\n\n" + "\n\n".join(blocks) + total = 0.0 + for model, short in [("deepseek-v4-flash", "ds"), ("glm-5", "glm")]: + cl = cp.client_for(model) + rec = cp.call(cl, model, TERM_ZH_SYS, user, f"xzh-term-{short}", + "low" if model.startswith("deepseek") else None, model == "glm-5") + total += rec["cost_usd"] + time.sleep(1) + # два окна прозы (~900 симв.), разнесённые + paras = [p for p in text.split("\n") if len(p) > 400] + wins = [paras[3][:1200], paras[len(paras) // 2][:1200]] + for k, w in enumerate(wins): + for model, short in [("deepseek-v4-flash", "ds"), ("glm-5", "glm")]: + cl = cp.client_for(model) + rec = cp.call(cl, model, TRANSLATE_ZH_SYS, "翻译下面的段落:\n\n" + w, f"xzh-prose-w{k}-{short}", + "low" if model.startswith("deepseek") else None, model == "glm-5") + total += rec["cost_usd"] + time.sleep(1) + return total + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--part", default="all", choices=["f1", "f2", "all", "mine"]) + a = ap.parse_args() + if a.part == "mine": + print(mine_en_terms(epub_text())) + return + total = 0.0 + if a.part in ("f1", "all"): + total += run_f1() + if a.part in ("f2", "all"): + total += run_f2() + print(f"TOTAL crosslang: ${total:.6f}") + + +if __name__ == "__main__": + main() + + +def score_f1(): + """Джойн en-консолидаций с голдом: печать пар (src, ru владельца, en свежий) для таблицы §F.""" + import glob + en = {} + for f in sorted(glob.glob(str(RAW / "xen-ds-b*.json"))): + for ln in json.load(open(f, encoding="utf-8"))["content"].split("\n"): + if "\t" in ln: + s, d = ln.split("\t", 1) + en[s.strip()] = d.strip() + gold = [json.loads(l) for l in open(HERE / "gold" / "gold.jsonl", encoding="utf-8")] + n = 0 + for r in gold: + if not r.get("in_bank"): + continue + s = r["bank_src"] + if s in en: + n += 1 + print(f"{s}\t{r['gold_dst']}\t{en[s]}") + print(f"# joined: {n}") diff --git a/eval/bank_arbitration/extras_checks.py b/eval/bank_arbitration/extras_checks.py new file mode 100644 index 00000000..35b02262 --- /dev/null +++ b/eval/bank_arbitration/extras_checks.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python3 +"""$0-довески отчёта research/24 (заявление = команда): реплика DetectSeries на BANK-FULL · +доля spread>=2 на полном банке · чувствительность состава совета (grok, C4) · деньги из сырья.""" +import collections +import glob +import json +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parent)) +from arbitrate import parse_pass, eq, majority # noqa: E402 + +BANKFULL = "/home/ubuntu/books/gu-zhenren/coldrun-a/BANK-FULL.tsv" +RAW = str(Path.home() / "books" / "gu-zhenren" / "bank-arbitration") +GOLD = [json.loads(l) for l in open(Path(__file__).resolve().parent / "gold" / "gold.jsonl", encoding="utf-8")] + + +def series_replica(): + surfs = [l.split("\t")[0] for l in open(BANKFULL, encoding="utf-8").read().split("\n")[1:] if l.strip()] + groups = collections.defaultdict(list) + order = [] + for s in surfs: + rs = list(s) + n = len(rs) + if n < 2: + continue + for pos in range(n - 1): # head-final: последняя руна — голова + skel = (n, pos, "".join(rs[:pos]) + "\x00" + "".join(rs[pos + 1:])) + if skel not in groups: + order.append(skel) + if s not in groups[skel]: + groups[skel].append(s) + order.sort(key=lambda g: -len(groups[g])) + assigned = {} + sid = 0 + for g in order: + fresh = [k for k in groups[g] if k not in assigned] + if len(fresh) >= 3: + sid += 1 + for k in fresh: + assigned[k] = sid + series = collections.defaultdict(list) + for k, v in assigned.items(): + series[v].append(k) + for i, ms in sorted(series.items()): + print("series", i, ":", " ".join(sorted(ms))) + + +def contested_share(): + rows = [l.split("\t") for l in open(BANKFULL, encoding="utf-8").read().split("\n")[1:] if l.strip()] + sp = [int(r[5]) for r in rows if len(r) > 5] + n2 = sum(1 for s in sp if s >= 2) + print(f"BANK-FULL: {len(sp)} строк, spread>=2: {n2} ({n2 / len(sp):.0%})") + + +def council4(): + inb = {r["bank_src"]: r for r in GOLD if r["in_bank"]} + p = {t: parse_pass(t) for t in ["ds1", "glm1", "mis1", "gro1"]} + acc = {} + for t in p: + ok = [s for s, g in inb.items() if eq(p[t]["map"].get(s, ("", None))[0], g["gold_dst"])] + acc[t] = set(ok) + print(f"{t}: {len(ok)}/45 (cost ${p[t]['cost']:.6f})") + c4 = set() + for s, g in inb.items(): + votes = [p[t]["map"].get(s, ("", None))[0] for t in ["ds1", "glm1", "mis1", "gro1"]] + if eq(majority(votes, fallback=votes[0]), g["gold_dst"]): + c4.add(s) + print(f"C4 (majority из 4): {len(c4)}/45") + print("gro1-only wins:", sorted(acc["gro1"] - (acc["ds1"] | acc["glm1"] | acc["mis1"]))) + for m in sorted(s for s in inb if s.startswith("古月")): + print(" ", m, "gro1=", p["gro1"]["map"].get(m, ("", None))[0]) + + +def money(): + tot = 0.0 + by = collections.defaultdict(float) + for f in glob.glob(RAW + "/*.json"): + r = json.load(open(f)) + tag = r["tag"].split("-b")[0].split("-w")[0] + by[tag] += r["cost_usd"] + tot += r["cost_usd"] + for t, c in sorted(by.items()): + print(f"{t}: ${c:.6f}") + print(f"TOTAL: ${tot:.6f}") + + +if __name__ == "__main__": + cmd = sys.argv[1] if len(sys.argv) > 1 else "all" + if cmd in ("series", "all"): + series_replica() + if cmd in ("contested", "all"): + contested_share() + if cmd in ("c4", "all"): + council4() + if cmd in ("money", "all"): + money() diff --git a/eval/bank_arbitration/forms_dump.json b/eval/bank_arbitration/forms_dump.json new file mode 100644 index 00000000..a1f0fb45 --- /dev/null +++ b/eval/bank_arbitration/forms_dump.json @@ -0,0 +1,452 @@ +{ + "一转": { + "P0": "первый оборот", + "P1": "первый ранг", + "S1": "первый ранг", + "SC": "первый ранг", + "C3": "первый ранг", + "C3conf": "первый ранг", + "E1": "первый оборот", + "contested": false + }, + "丁等": { + "P0": "уровень «дин»", + "P1": "ранг Дин", + "S1": "уровень «дин»", + "SC": "уровень «дин»", + "C3": "уровень «дин»", + "C3conf": "уровень «дин»", + "E1": "уровень «дин»", + "contested": true + }, + "三转": { + "P0": "третий оборот", + "P1": "третий ранг", + "S1": "третий ранг", + "SC": "третий ранг", + "C3": "третий ранг", + "C3conf": "третий ранг", + "E1": "третий ранг", + "contested": true + }, + "丙等": { + "P0": "уровень «бин»", + "P1": "ранг Бин", + "S1": "уровень «бин»", + "SC": "уровень «бин»", + "C3": "уровень «бин»", + "C3conf": "уровень «бин»", + "E1": "уровень «бин»", + "contested": true + }, + "乙等": { + "P0": "уровень «и»", + "P1": "ранг И", + "S1": "уровень «и»", + "SC": "уровень «и»", + "C3": "уровень «и»", + "C3conf": "уровень «и»", + "E1": "уровень «и»", + "contested": true + }, + "五转": { + "P0": "пятый оборот", + "P1": "пятый ранг", + "S1": "пятый ранг", + "SC": "пятый ранг", + "C3": "пятый ранг", + "C3conf": "пятый ранг", + "E1": "пятый ранг", + "contested": true + }, + "人祖": { + "P0": "Жэнь-цзу", + "P1": "Жэньцзу", + "S1": "Жэньцзу", + "SC": "Жэньцзу", + "C3": "Жэньцзу", + "C3conf": "Жэньцзу", + "E1": "Жэньцзу", + "contested": true + }, + "元海": { + "P0": "юаньхай", + "P1": "Юаньхай", + "S1": "юаньхай", + "SC": "море юань", + "C3": "юаньхай", + "C3conf": "юаньхай", + "E1": "юаньхай", + "contested": true + }, + "元石": { + "P0": "юаньши", + "P1": "юаньши", + "S1": "юаньши", + "SC": "камень юань", + "C3": "юаньши", + "C3conf": "юаньши", + "E1": "юаньши", + "contested": true + }, + "六转": { + "P0": "шестой оборот", + "P1": "шестой ранг", + "S1": "шестой ранг", + "SC": "шестой ранг", + "C3": "шестой ранг", + "C3conf": "шестой ранг", + "E1": "шестой ранг", + "contested": true + }, + "凡人": { + "P0": "простой человек", + "P1": "простой человек", + "S1": "обычный человек", + "SC": "простой человек", + "C3": "простой человек", + "C3conf": "обычный человек", + "E1": "простой человек", + "contested": true + }, + "古月": { + "P0": "Гу Юэ", + "P1": "Гу Юэ", + "S1": "Гу Юэ", + "SC": "Гу Юэ", + "C3": "Гуюэ", + "C3conf": "Гуюэ", + "E1": "Гуюэ", + "contested": true + }, + "古月冻土": { + "P0": "Гу Юэ Дунту", + "P1": "Гу Юэ Дунту", + "S1": "Гу Юэ Дунту", + "SC": "Гу Юэ Дунту", + "C3": "Гуюэ Дунту", + "C3conf": "Гуюэ Дунту", + "E1": "Гуюэ Дунту", + "contested": true + }, + "古月博": { + "P0": "Гу Юэ Бо", + "P1": "Гу Юэ Бо", + "S1": "Гу Юэ Бо", + "SC": "Гу Юэ Бо", + "C3": "Гуюэ Бо", + "C3conf": "Гуюэ Бо", + "E1": "Гуюэ Бо", + "contested": true + }, + "古月山寨": { + "P0": "поселение Гуюэ", + "P1": "поселение Гу Юэ", + "S1": "поселение Гу Юэ", + "SC": "поселение Гу Юэ", + "C3": "поселение Гуюэ", + "C3conf": "поселение Гуюэ", + "E1": "поселение Гуюэ", + "contested": false + }, + "古月漠北": { + "P0": "Гу Юэ Мо Бэй", + "P1": "Гу Юэ Мобэй", + "S1": "Гуюэ Мобэй", + "SC": "Гуюэ Мобэй", + "C3": "Гуюэ Мобэй", + "C3conf": "Гуюэ Мобэй", + "E1": "Гуюэ Мобэй", + "contested": true + }, + "古月漠尘": { + "P0": "Гу Юэ Мочэнь", + "P1": "Гу Юэ Мочэнь", + "S1": "Гуюэ Мочэнь", + "SC": "Гуюэ Мочэнь", + "C3": "Гуюэ Мочэнь", + "C3conf": "Гуюэ Мочэнь", + "E1": "Гуюэ Мочэнь", + "contested": true + }, + "古月赤城": { + "P0": "Гуюэ Чичэн", + "P1": "Гу Юэ Чичэн", + "S1": "Гуюэ Чичэн", + "SC": "Гуюэ Чичэн", + "C3": "Гуюэ Чичэн", + "C3conf": "Гуюэ Чичэн", + "E1": "Гуюэ Чичэн", + "contested": true + }, + "古月赤练": { + "P0": "Гу Юэ Чилянь", + "P1": "Гу Юэ Чилянь", + "S1": "Гуюэ Чилянь", + "SC": "Гуюэ Чилянь", + "C3": "Гуюэ Чилянь", + "C3conf": "Гуюэ Чилянь", + "E1": "Гуюэ Чилянь", + "contested": true + }, + "四代族长": { + "P0": "вождь четвёртого поколения", + "P1": "вождь четвёртого поколения", + "S1": "четвёртый глава клана", + "SC": "четвёртый глава клана", + "C3": "четвёртый глава клана", + "C3conf": "четвёртый старейшина", + "E1": "четвёртый глава клана", + "contested": true + }, + "困境": { + "P0": "Куньцзин", + "P1": "Невзгоды", + "S1": "Трудности", + "SC": "Трудности", + "C3": "Трудности", + "C3conf": "Трудности", + "E1": "Трудности", + "contested": true + }, + "家老": { + "P0": "старейшина", + "P1": "старейшина", + "S1": "старейшина", + "SC": "старейшина", + "C3": "старейшина", + "C3conf": "старейшина", + "E1": "старейшина", + "contested": true + }, + "希望蛊": { + "P0": "Гу Надежды", + "P1": "Гу Надежды", + "S1": "гу Надежды", + "SC": "гу Надежды", + "C3": "гу Надежды", + "C3conf": "гу Надежды", + "E1": "гу Надежды", + "contested": true + }, + "开窍": { + "P0": "открытие акупунктурной точки", + "P1": "открытие точки", + "S1": "открытие точки", + "SC": "открытие точки", + "C3": "открытие точки", + "C3conf": "открытие точки", + "E1": "открытие точки", + "contested": true + }, + "方正": { + "P0": "Фан Чжэн", + "P1": "Фан Чжэн", + "S1": "Фан Чжэн", + "SC": "Фан Чжэн", + "C3": "Фан Чжэн", + "C3conf": "Фан Чжэн", + "E1": "Фан Чжэн", + "contested": false + }, + "方源": { + "P0": "Фан Юань", + "P1": "Фан Юань", + "S1": "Фан Юань", + "SC": "Фан Юань", + "C3": "Фан Юань", + "C3conf": "Фан Юань", + "E1": "Фан Юань", + "contested": false + }, + "族长": { + "P0": "глава клана", + "P1": "глава клана", + "S1": "глава клана", + "SC": "глава клана", + "C3": "глава клана", + "C3conf": "глава клана", + "E1": "глава клана", + "contested": true + }, + "春秋蝉": { + "P0": "Цикада Весны и Осени", + "P1": "Цикада Весны и Осени", + "S1": "Цикада весны и осени", + "SC": "Цикада весны и осени", + "C3": "Цикада весны и осени", + "C3conf": "Цикада весны и осени", + "E1": "Цикада весны и осени", + "contested": true + }, + "月光蛊": { + "P0": "лунный гу", + "P1": "Гу лунного света", + "S1": "лунный гу", + "SC": "лунный гу", + "C3": "лунный гу", + "C3conf": "лунный гу", + "E1": "лунный гу", + "contested": true + }, + "月兰花": { + "P0": "лунная орхидея", + "P1": "лунная орхидея", + "S1": "лунная орхидея", + "SC": "лунная орхидея", + "C3": "лунная орхидея", + "C3conf": "лунная орхидея", + "E1": "лунная орхидея", + "contested": true + }, + "本命蛊": { + "P0": "гу-талисман судьбы", + "P1": "Гу жизни", + "S1": "жизненная гу", + "SC": "жизненная гу", + "C3": "жизненная гу", + "C3conf": "основная гу", + "E1": "жизненная гу", + "contested": true + }, + "沈翠": { + "P0": "Шэнь Цуй", + "P1": "Шэнь Цуй", + "S1": "Шэнь Цуй", + "SC": "Шэнь Цуй", + "C3": "Шэнь Цуй", + "C3conf": "Шэнь Цуй", + "E1": "Шэнь Цуй", + "contested": false + }, + "炼化": { + "P0": "очистка (гу)", + "P1": "очистка", + "S1": "рафинирование", + "SC": "рафинирование", + "C3": "рафинирование", + "C3conf": "рафинирование", + "E1": "рафинирование", + "contested": true + }, + "熊家寨": { + "P0": "Сюнцзячжай", + "P1": "поселение Сюн", + "S1": "Сюнцзячжай", + "SC": "Сюнцзячжай", + "C3": "поселение Сюн", + "C3conf": "поселение Сюн", + "E1": "поселение Сюн", + "contested": true + }, + "甲等": { + "P0": "уровень «цзя»", + "P1": "класс Цзя", + "S1": "уровень «цзя»", + "SC": "уровень «цзя»", + "C3": "уровень «цзя»", + "C3conf": "уровень «цзя»", + "E1": "уровень «цзя»", + "contested": true + }, + "白凝冰": { + "P0": "Бай Нин Бин", + "P1": "Бай Нинбин", + "S1": "Бай Нинбин", + "SC": "Бай Нинбин", + "C3": "Бай Нинбин", + "C3conf": "Бай Нинбин", + "E1": "Бай Нинбин", + "contested": true + }, + "白家寨": { + "P0": "Байцзячжай", + "P1": "поселение Бай", + "S1": "Байцзячжай", + "SC": "Байцзячжай", + "C3": "поселение Бай", + "C3conf": "поселение Бай", + "E1": "поселение Бай", + "contested": true + }, + "真元": { + "P0": "истинная юань", + "P1": "чжэньюань", + "S1": "истинная юань", + "SC": "истинная юань", + "C3": "истинная юань", + "C3conf": "истинная юань", + "E1": "истинная юань", + "contested": true + }, + "空窍": { + "P0": "пустота", + "P1": "кунцяо", + "S1": "пустотная полость", + "SC": "пустотная полость", + "C3": "пустотная полость", + "C3conf": "пустотная полость", + "E1": "пустотная полость", + "contested": true + }, + "花酒行者": { + "P0": "Хуацзю Синчжэ", + "P1": "Хуацзю Синчжэ", + "S1": "Скиталец Цветка и Вина", + "SC": "Скиталец Цветка и Вина", + "C3": "Скиталец Цветка и Вина", + "C3conf": "Скиталец Цветка и Вина", + "E1": "Хуацзю Синчжэ", + "contested": false + }, + "蛊师": { + "P0": "гу-мастер", + "P1": "гу-мастер", + "S1": "гу-мастер", + "SC": "гу-мастер", + "C3": "гу-мастер", + "C3conf": "гу-мастер", + "E1": "гу-мастер", + "contested": false + }, + "蛊虫": { + "P0": "гу-червь", + "P1": "гу-червь", + "S1": "гу-червь", + "SC": "гу-червь", + "C3": "гу-червь", + "C3conf": "гу-червь", + "E1": "гу-червь", + "contested": false + }, + "转": { + "P0": "ранг", + "P1": "ранг", + "S1": "ранг", + "SC": "ранг", + "C3": "ранг", + "C3conf": "ранг", + "E1": "ранг", + "contested": true + }, + "酒虫": { + "P0": "Винный червь", + "P1": "Винный червь", + "S1": "винный червь", + "SC": "винный червь", + "C3": "винный червь", + "C3conf": "винный червь", + "E1": "винный червь", + "contested": true + }, + "青茅山": { + "P0": "Цинмаошань", + "P1": "Цинмаошань", + "S1": "Цинмаошань", + "SC": "Цинмаошань", + "C3": "Цинмаошань", + "C3conf": "Цинмаошань", + "E1": "Цинмаошань", + "contested": true + } +} \ No newline at end of file diff --git a/eval/bank_arbitration/gold/gold.jsonl b/eval/bank_arbitration/gold/gold.jsonl new file mode 100644 index 00000000..76298ed0 --- /dev/null +++ b/eval/bank_arbitration/gold/gold.jsonl @@ -0,0 +1,53 @@ +{"src": "方源", "gold_dst": "Фан Юань", "type": "name", "gold_alt": ["Фан Юаня", "Фан Юаню", "Фан Юанем", "Фан Юане"], "aliases": ["古月方源"], "seed_note": "pinyin: Fāng Yuán; protagonist. Given name declines like currency юань (юаня/юаню/юанем/юане); surname Фан fixed", "in_bank": true, "provenance": "seed v2 approved (владелец) src=方源; bank=coldrun-a BANK-FULL", "bank_src": "方源", "bank_dst": "Фан Юань", "bank_origin": "both", "bank_type": "name", "freq": 189, "spread": 11, "variants": [["Фан Юань", 11], ["Фан Чжэн", 6], ["Гу Юэ Фан Юань", 2], ["Гу Юэ Фанчжэн", 2], ["Гуюэ Фанчжэн", 2], ["Гу Юэ Фан Чжэн", 1], ["Гу Юэ Фанюань", 1], ["Гуюэ Фан Чжэн", 1], ["Гуюэ Фанчжэнь", 1], ["Гуюэ Фанъюань", 1], ["Гуюэ Фаньюань", 1]], "contexts": ["纵身亡魔心仍不悔\n“方源,乖乖地交出春秋蝉,我给你个痛快!”\n“方老魔,你不要妄图反抗了,今日我们正", "起来,就是要踏破你的魔窟。这里早已经布下天罗地网,这次你必定身首异处!”\n“方源你个该死的魔头,你为了练成春秋蝉,杀了千万人的性命。你已经犯下了滔天的罪孽,罪无", ",我恨不得吃你肉,喝你的血!今天,我要让你生不如死!!”\n......\n方源一身残破的碧绿大袍,披头散发,浑身浴血,环顾四周。\n山风吹得血袍飘荡,如战旗"], "evidence": ["surname:方", "formant_suffix:源"]} +{"src": "方正", "gold_dst": "Фан Чжэн", "type": "name", "gold_alt": ["Фан Чжэна", "Фан Чжэну", "Фан Чжэном", "Фан Чжэне"], "aliases": ["古月方正"], "seed_note": "pinyin: Fāng Zhèng; protagonist's twin brother, тест дал разряд А. Given name -н declines hard", "in_bank": true, "provenance": "seed v2 approved (владелец) src=方正; bank=coldrun-a BANK-FULL", "bank_src": "方正", "bank_dst": "Фан Чжэн", "bank_origin": "alias", "bank_type": "name", "freq": 68, "spread": 1, "variants": [["Фан Чжэн", 6]], "contexts": ["色。\n“是你啊,我的孪生弟弟。”他微微扬起眉头,表情恢复了一贯的冷漠。\n方正低下头,看着自己的脚尖,这是他的招牌动作:“看到哥哥的窗户没有关,就想悄悄的进来", "这些念头已经有许多年了,日积月累地积压在内心深处。像是一块巨石压着心胸,这些年方正的头垂得越来越低,也越加沉默寡言。\n“担心......”想到舅父舅母,方源在", "这里,方源不禁失笑。回过头对着这个弟弟,淡淡地看了一眼,道:“你退下罢。”\n方正不禁心中一悸,感觉哥哥的目光如冰刃般犀利,似乎洞穿到了他内心的最深处。\n在这"], "evidence": []} +{"src": "古月", "gold_dst": "Гуюэ", "type": "name", "gold_alt": [], "aliases": [], "seed_note": "pinyin: Gǔ Yuè; the clan / compound surname (родовое имя). Rendered one word per Palladius (cf. Сыма, Оуян); ends -э → invariant. 家族/一族 = клан/род added by translator", "in_bank": true, "provenance": "seed v2 approved (владелец) src=古月; bank=coldrun-a BANK-FULL", "bank_src": "古月", "bank_dst": "Гу Юэ", "bank_origin": "banknote", "bank_type": "term", "freq": 96, "spread": 1, "variants": [["Гу Юэ", 1]], "contexts": ["源于一座座高脚吊楼,虽称不上万家灯火,却也有数千的规模。\n正是坐落在青茅山的古月山寨,给广袤幽静的山峦增添了一份浓郁的人烟气息。\n古月山寨的最中央,是一座大", "正是坐落在青茅山的古月山寨,给广袤幽静的山峦增添了一份浓郁的人烟气息。\n古月山寨的最中央,是一座大气辉煌的楼阁。此时正举办着祭祀大典,因此更是灯火通明,光辉", "列宗保佑,希望此次开窍大典中能多多涌现出资质优秀的少年,为家族增添新血和希望!”古月族长中年模样,两鬓微霜,一身素白庄重的祭祀服装,跪在棕黄色的地板上,直着上身,双"], "evidence": []} +{"src": "白凝冰", "gold_dst": "Бай Нинбин", "type": "name", "gold_alt": [], "aliases": [], "seed_note": "pinyin: Bái Níngbīng; genius of the Bai clan (rival talent). GENDER: hidden until reveal (ratified D19.3; mechanism D5.1) — the FIRST-30 text refers to the character as 他/«он» (節1) while canon is female, so render with genderless constructions until disclosure rather than defaulting to a gender. until_ch=0 (open window) — set it to the reveal chapter once determined, then add a post-reveal gender:female row from that chapter (non-overlapping window).", "in_bank": true, "provenance": "seed v2 approved (владелец) src=白凝冰; bank=coldrun-a BANK-FULL", "bank_src": "白凝冰", "bank_dst": "Бай Нинбин", "bank_origin": "banknote", "bank_type": "name", "freq": 3, "spread": 2, "variants": [["Бай Нин Бин", 1], ["Бай Нинбин", 1]], "contexts": ["这样的天才出现了。”\n“不错,白家寨、熊家寨这些年都有天才涌现。尤其是白家的白凝冰,天资真是恐怖。”\n不知是谁,提及到白凝冰这个名字,众家老的脸上不由地浮现出", "寨这些年都有天才涌现。尤其是白家的白凝冰,天资真是恐怖。”\n不知是谁,提及到白凝冰这个名字,众家老的脸上不由地浮现出一层忧色。\n此子的资质极端出色,短短两年功", "禀的人,都有优秀的修行资质。\n“若是此子测出甲等资质,好生培养,也未必不能和白凝冰抗衡。就算是乙等资质,日后定也能独当一面,成为古月一族的一面旗帜。不过他这样的早"], "evidence": []} +{"src": "古月博", "gold_dst": "Гуюэ Бо", "type": "name", "gold_alt": [], "aliases": [], "seed_note": "pinyin: Gǔyuè Bó; the current clan head (族长). Ends -о → invariant", "in_bank": true, "provenance": "seed v2 approved (владелец) src=古月博; bank=coldrun-a BANK-FULL", "bank_src": "古月博", "bank_dst": "Гу Юэ Бо", "bank_origin": "banknote", "bank_type": "name", "freq": 1, "spread": 1, "variants": [["Гу Юэ Бо", 1]], "contexts": ["“谁都别争了。这个孩子谁栽培,都没有本族长亲自栽培的好。谁有异议,就是反对我古月博!”古月族长双眼赤红,一扫先前的失望颓废,整个人都癫狂了。"], "evidence": []} +{"src": "古月冻土", "gold_dst": "Гуюэ Дунту", "type": "name", "gold_alt": [], "aliases": [], "seed_note": "pinyin: Gǔyuè Dòngtǔ; the maternal uncle/guardian (舅父). Ends -у → invariant", "in_bank": true, "provenance": "seed v2 approved (владелец) src=古月冻土; bank=coldrun-a BANK-FULL", "bank_src": "古月冻土", "bank_dst": "Гу Юэ Дунту", "bank_origin": "banknote", "bank_type": "name", "freq": 1, "spread": 2, "variants": [["Гу Юэ Дунту", 1], ["Гуюэ Дунту", 1]], "contexts": ["上,面目表情都笼罩着一层阴影,看不大分明。\n看到方源随身带来的那两坛酒,舅父古月冻土的眉头拧成了疙瘩,他开口道:“时间一晃,你们已经十五岁了。竟然都有蛊师资质,尤其"], "evidence": []} +{"src": "古月漠尘", "gold_dst": "Гуюэ Мочэнь", "type": "name", "gold_alt": ["Гуюэ Мочэня", "Гуюэ Мочэню", "Гуюэ Мочэнем", "Гуюэ Мочэне"], "aliases": [], "seed_note": "pinyin: Gǔyuè Mòchén; power-holding elder (家老), head of the 漠 branch, 漠北's grandfather. Given name -нь declines soft (like конь)", "in_bank": true, "provenance": "seed v2 approved (владелец) src=古月漠尘; bank=coldrun-a BANK-FULL", "bank_src": "古月漠尘", "bank_dst": "Гу Юэ Мочэнь", "bank_origin": "alias", "bank_type": "name", "freq": 6, "spread": 1, "variants": [["Гу Юэ Мочэнь", 1]], "contexts": ["又纷纷向其中一位家老投去羡慕的目光。\n这家老也是一副马脸,正是古月漠北的爷爷古月漠尘。他脸上早已经荡漾起笑意,又挑衅地看了一眼自己的老对头:“怎么样,我的孙儿不差吧", "投来羡慕的目光。\n“哈哈哈,三十六步,三十六步!”古月赤练大叫着,示威地瞪着古月漠尘。\n这次轮到古月漠尘脸色铁青了。\n“古月赤城么......”人群中,方源", "哈哈哈,三十六步,三十六步!”古月赤练大叫着,示威地瞪着古月漠尘。\n这次轮到古月漠尘脸色铁青了。\n“古月赤城么......”人群中,方源若有所思的摩挲着下巴。"], "evidence": []} +{"src": "古月漠北", "gold_dst": "Гуюэ Мобэй", "type": "name", "gold_alt": ["Гуюэ Мобэя", "Гуюэ Мобэю", "Гуюэ Мобэем", "Гуюэ Мобэе"], "aliases": [], "seed_note": "pinyin: Gǔyuè Mòběi; youth, разряд Б, grandson of 漠尘", "in_bank": true, "provenance": "seed v2 approved (владелец) src=古月漠北; bank=coldrun-a BANK-FULL", "bank_src": "古月漠北", "bank_dst": "Гу Юэ Мобэй", "bank_origin": "both", "bank_type": "name", "freq": 7, "spread": 3, "variants": [["Гу Юэ Мо Бэй", 1], ["Гу Юэ Мочэнь", 1], ["Гуюэ Мобэй", 1]], "contexts": [",就是老成持重的古月族长,也微微蹙眉。\n就在这时,学堂家老喊出第三个名字:“古月漠北。”\n“在!”一个身穿麻布衣衫的马脸少年,轻喝一声,越众而出。\n他身材高", "少年们隔岸看得目瞪口呆,学堂家老欢喜得大叫起来:“好,古月漠北,乙等资质,来这里,让我看看你的元海。”\n古月漠北便又回到学堂家老的身边,后", "家老欢喜得大叫起来:“好,古月漠北,乙等资质,来这里,让我看看你的元海。”\n古月漠北便又回到学堂家老的身边,后者伸出手,搭在少年的肩膀,闭目凝神探查了一番,便收回手"], "evidence": ["surname:古月"]} +{"src": "古月赤练", "gold_dst": "Гуюэ Чилянь", "type": "name", "gold_alt": ["Гуюэ Чиляня", "Гуюэ Чиляню", "Гуюэ Чилянем", "Гуюэ Чиляне"], "aliases": [], "seed_note": "pinyin: Gǔyuè Chìliàn; red-haired elder (家老), head of the 赤 branch, rival of 漠尘. Given name -нь soft", "in_bank": true, "provenance": "seed v2 approved (владелец) src=古月赤练; bank=coldrun-a BANK-FULL", "bank_src": "古月赤练", "bank_dst": "Гу Юэ Чилянь", "bank_origin": "both", "bank_type": "name", "freq": 10, "spread": 2, "variants": [["Гу Юэ Чилянь", 1], ["Гуюэ Чичэн", 1]], "contexts": ["他脸上早已经荡漾起笑意,又挑衅地看了一眼自己的老对头:“怎么样,我的孙儿不差吧,古月赤练。”\n家老古月赤练一头红发,此时冷哼一声,并未答话,脸色阴沉得很是难看。", ",又挑衅地看了一眼自己的老对头:“怎么样,我的孙儿不差吧,古月赤练。”\n家老古月赤练一头红发,此时冷哼一声,并未答话,脸色阴沉得很是难看。\n半个时辰之后,已有一", "。\n就在这时,学堂家老喊道:“古月赤城。”\n听到这个名字,家老们纷纷看向古月赤练,这是古月赤练的孙子。\n古月赤城身材矮小,满脸麻子,捏着拳头,满脸出汗,显得"], "evidence": ["surname:古月"]} +{"src": "古月赤城", "gold_dst": "Гуюэ Чичэн", "type": "name", "gold_alt": ["Гуюэ Чичэна", "Гуюэ Чичэну", "Гуюэ Чичэном", "Гуюэ Чичэне"], "aliases": [], "seed_note": "pinyin: Gǔyuè Chìchéng; youth, разряд Б, grandson of 赤练", "in_bank": true, "provenance": "seed v2 approved (владелец) src=古月赤城; bank=coldrun-a BANK-FULL", "bank_src": "古月赤城", "bank_dst": "Гу Юэ Чичэн", "bank_origin": "alias", "bank_type": "name", "freq": 8, "spread": 1, "variants": [["Гуюэ Чичэн", 1]], "contexts": ["一族后辈的资质是越来越弱了。”族长深深的叹息着。\n就在这时,学堂家老喊道:“古月赤城。”\n听到这个名字,家老们纷纷看向古月赤练,这是古月赤练的孙子。\n古月赤", "月赤城。”\n听到这个名字,家老们纷纷看向古月赤练,这是古月赤练的孙子。\n古月赤城身材矮小,满脸麻子,捏着拳头,满脸出汗,显得特别的紧张。\n他踏上对岸,光点纷", "步,这才停步。\n“又一个乙等!”学堂家老叫喊着。\n少年们骚动起来,纷纷向古月赤城投来羡慕的目光。\n“哈哈哈,三十六步,三十六步!”古月赤练大叫着,示威地瞪着"], "evidence": []} +{"src": "江牙", "gold_dst": "Цзян Я", "type": "name", "gold_alt": [], "aliases": [], "seed_note": "pinyin: Jiāng Yá; a rank-1 гу-мастер at the inn (節12/15/17). Monosyllabic given name Я kept invariant", "in_bank": false, "provenance": "seed v2 approved (владелец) src=江牙; bank=coldrun-a BANK-FULL"} +{"src": "花酒行者", "gold_dst": "Монах Цветочного Вина", "type": "nickname", "gold_alt": ["Монаха Цветочного Вина", "Монаху Цветочного Вина", "Монаха Цветочного Вина", "Монахом Цветочного Вина", "Монахе Цветочного Вина"], "aliases": [], "seed_note": "[signoff:approved] подпись: НЕ «Странник Цветов и Вина»/«Винный Странник»; 行者=монах, 花酒=цветочное вино. (было: «Странник Цветов и Вина»). [v2:DRAFT⚑] флагманы: сохранить 花 (=блуд; 采花大盗). Владелец предпочёл «Винный Странник» — за ним. (было: «Винный Странник»). pinyin: Huājiǔ Xíngzhě (Palladius: Хуацзю Синчжэ); demonic rank-5 гу-мастер, a 采花大盗 (womanizer-bandit). TRANSLATE-vs-TRANSLIT FLAG: 酒=вино + 行者=странник; 花 alludes to his crimes. Owner may prefer translit Хуацзю Синчжэ", "in_bank": true, "provenance": "seed v2 approved (владелец) src=花酒行者; bank=coldrun-a BANK-FULL", "bank_src": "花酒行者", "bank_dst": "Хуацзю Синчжэ", "bank_origin": "banknote", "bank_type": "nickname", "freq": 15, "spread": 3, "variants": [["Хуацзю Синчжэ", 4], ["Скиталец Цветка и Вина", 1], ["Хуацзю-синчжэ", 1]], "contexts": ["年来,家族也没有出现几位四转强者,来增强血脉。四代族长是唯一的五转强者,结果却和花酒行者同归于尽,没有留下血脉后裔。古月一族后辈的资质是越来越弱了。”族长深深的叹息着。", "一位,是四代族长。天资卓越,一直修行到了五转蛊师的境界。要不是那个卑鄙无耻的魔头花酒行者偷袭的话,兴许能晋升成六转蛊师也说不定。唉......”\n说到这里,古月师深", "到这里,古月师深深一叹。\n讲台下,少年们都义愤填膺地叫嚷起来。\n“都是那花酒行者,太阴险狡诈了!”\n“可惜我们四代族长宅心仁厚,英年早逝。”\n“只恨我没"], "evidence": []} +{"src": "沈翠", "gold_dst": "Шэнь Цуй", "type": "name", "gold_alt": [], "aliases": [], "seed_note": "pinyin: Shěn Cuì; 方源's personal maid (丫鬟), an 舅父/舅母 informer. Female name ending -й → invariant", "in_bank": true, "provenance": "seed v2 approved (владелец) src=沈翠; bank=coldrun-a BANK-FULL", "bank_src": "沈翠", "bank_dst": "Шэнь Цуй", "bank_origin": "both", "bank_type": "name", "freq": 19, "spread": 1, "variants": [["Шэнь Цуй", 5]], "contexts": ["您洗漱。”就在此刻,楼下传来一个少女的声音。\n方源低头一看,是自己的贴身丫鬟沈翠。\n她姿容只能算上中等,但打扮得好,穿着一身绿衫,长袖长裤,脚下是绣花鞋,黑", "上了楼。\n水是调好的温水,用来洗脸。漱口则用柳条沾着雪盐,能净齿白牙。\n沈翠温柔的伺候着,脸上带着笑颜,眉目含春。而后又为方源穿衣结扣,在这过程中时不时地用", ",自己地位一落千丈,她顿时就翻了脸,没少给过自己白眼。\n方正来的时候,正看到沈翠为方源抚平胸口衣衫上的褶皱,眼中不由地闪过一丝羡慕嫉妒的光。\n这些年跟着哥哥"], "evidence": ["surname:沈", "formant_prefix:沈", "formant_suffix:翠"]} +{"src": "四代族长", "gold_dst": "Четвёртый глава рода", "type": "title", "gold_alt": ["Четвёртого главы рода", "Четвёртому главе рода", "Четвёртого главу рода", "Четвёртым главой рода", "Четвёртом главе рода"], "aliases": [], "seed_note": "[reseed:approved D38.5] 四代族长 draft→approved (D38 §3: approved-длинный выигрывает longest-match над вложенным 族长 → 族长 больше не съедается неверно). pinyin: sìdài zúzhǎng; the legendary 4th-generation clan head (rank-5), unnamed; recurs 節7/13/15/16. Descriptor, not a personal name. Forms gen/dat/acc/instr/prep", "in_bank": true, "provenance": "seed v2 approved (владелец) src=四代族长; bank=coldrun-a BANK-FULL", "bank_src": "四代族长", "bank_dst": "вождь четвёртого поколения", "bank_origin": "alias", "bank_type": "title", "freq": 8, "spread": 3, "variants": [["вождь четвёртого поколения", 1], ["старейшина четвёртого поколения", 1], ["четвёртый старейшина клана", 1]], "contexts": ["“唉,血脉越来越稀薄,加上这些年来,家族也没有出现几位四转强者,来增强血脉。四代族长是唯一的五转强者,结果却和花酒行者同归于尽,没有留下血脉后裔。古月一族后辈的资质", "者,就有两位。一位是一代族长,是我们的老祖宗,就是他创立了古月山寨。还有一位,是四代族长。天资卓越,一直修行到了五转蛊师的境界。要不是那个卑鄙无耻的魔头花酒行者偷袭的话", "们都义愤填膺地叫嚷起来。\n“都是那花酒行者,太阴险狡诈了!”\n“可惜我们四代族长宅心仁厚,英年早逝。”\n“只恨我没有早生几百年,否则见到那个魔头,定要拼死揭"], "evidence": []} +{"src": "古月山寨", "gold_dst": "деревня Гуюэ", "type": "place", "gold_alt": ["деревни Гуюэ", "деревне Гуюэ", "деревню Гуюэ", "деревней Гуюэ", "деревне Гуюэ"], "aliases": [], "seed_note": "[signoff:approved] подпись: «деревня Гуюэ» (НЕ «селение»/«стан»). (было: «селение Гуюэ»). [v2:OK] «стан» = воинский лагерь; 山寨 здесь — укреплённое селение/деревня. (было: «стан Гуюэ»). pinyin: Gǔyuè Shānzhài; the clan's mountain stronghold on 青茅山. 山寨=горный стан/крепость (choice: стан)", "in_bank": true, "provenance": "seed v2 approved (владелец) src=古月山寨; bank=coldrun-a BANK-FULL", "bank_src": "古月山寨", "bank_dst": "поселение Гу Юэ", "bank_origin": "both", "bank_type": "name", "freq": 9, "spread": 9, "variants": [["поселение Гуюэ", 3], ["Гу Юэ Шаньчжай", 1], ["Гуюэ", 1], ["Гуюэ Шаньчжай", 1], ["Гуюэшаньчжай", 1], ["поселение Гу Юэ", 1], ["поселение Гуюэшань", 1], ["посёлок Гуюэшаньчжай", 1], ["горная крепость Гуюэ", 1]], "contexts": ["源于一座座高脚吊楼,虽称不上万家灯火,却也有数千的规模。\n正是坐落在青茅山的古月山寨,给广袤幽静的山峦增添了一份浓郁的人烟气息。\n古月山寨的最中央,是一座大气辉", "正是坐落在青茅山的古月山寨,给广袤幽静的山峦增添了一份浓郁的人烟气息。\n古月山寨的最中央,是一座大气辉煌的楼阁。此时正举办着祭祀大典,因此更是灯火通明,光辉绚烂", "满口都是清新湿润的山间空气,沁人心脾。\n这是阁楼第三层,族长放眼望去,大半个古月山寨都一览无余。\n此刻深夜,寨中大多数人家却还有着灯火,和平时大不相同。\n明"], "evidence": ["surname:古月", "topo_suffix:寨"]} +{"src": "白家寨", "gold_dst": "деревня Бай", "type": "place", "gold_alt": ["деревни Бай", "деревне Бай", "деревню Бай", "деревней Бай", "деревне Бай"], "aliases": [], "seed_note": "[signoff:approved] консистентно-выровнено под 古月山寨→деревня (диклоуз владельцу). (было: «селение Бай»). [v2:OK] согласовано. (было: «стан Бай»). pinyin: Bái jiā zhài; neighbouring stronghold of the Bai clan", "in_bank": true, "provenance": "seed v2 approved (владелец) src=白家寨; bank=coldrun-a BANK-FULL", "bank_src": "白家寨", "bank_dst": "поселение Бай", "bank_origin": "banknote", "bank_type": "place", "freq": 2, "spread": 2, "variants": [["Байцзячжай", 1], ["поселение Бай", 1]], "contexts": ["甲等资质的少年出现。我们古月一族已经有三年没有这样的天才出现了。”\n“不错,白家寨、熊家寨这些年都有天才涌现。尤其是白家的白凝冰,天资真是恐怖。”\n不知是谁,", "独领风骚。甚至就连老一辈们都感觉到了这位后起之秀的压力。\n假以时日,他必然是白家寨的顶梁柱。至少也是独当一面的强者。没有人怀疑过这一点。\n“不过今年参加开窍大"], "evidence": []} +{"src": "熊家寨", "gold_dst": "деревня Сюн", "type": "place", "gold_alt": ["деревни Сюн", "деревне Сюн", "деревню Сюн", "деревней Сюн", "деревне Сюн"], "aliases": [], "seed_note": "[signoff:approved] консистентно-выровнено под 古月山寨→деревня (диклоуз владельцу). (было: «селение Сюн»). [v2:OK] согласовано. (было: «стан Сюн»). pinyin: Xióng jiā zhài; neighbouring stronghold of the Xiong (Bear) clan", "in_bank": true, "provenance": "seed v2 approved (владелец) src=熊家寨; bank=coldrun-a BANK-FULL", "bank_src": "熊家寨", "bank_dst": "поселение Сюн", "bank_origin": "banknote", "bank_type": "place", "freq": 1, "spread": 2, "variants": [["Сюнцзячжай", 1], ["поселение Сюн", 1]], "contexts": ["的少年出现。我们古月一族已经有三年没有这样的天才出现了。”\n“不错,白家寨、熊家寨这些年都有天才涌现。尤其是白家的白凝冰,天资真是恐怖。”\n不知是谁,提及到白"], "evidence": []} +{"src": "青茅山", "gold_dst": "гора Цинмао", "type": "place", "gold_alt": ["горы Цинмао", "горе Цинмао", "гору Цинмао", "горой Цинмао", "горе Цинмао"], "aliases": [], "seed_note": "pinyin: Qīngmáo Shān; the mountain where 古月山寨 sits. 青茅=«зелёный тростник/аир». Forms gen/dat/acc/instr/prep", "in_bank": true, "provenance": "seed v2 approved (владелец) src=青茅山; bank=coldrun-a BANK-FULL", "bank_src": "青茅山", "bank_dst": "Цинмаошань", "bank_origin": "both", "bank_type": "place", "freq": 7, "spread": 2, "variants": [["Цинмаошань", 3], ["гора Цинмао", 2]], "contexts": ["这时,轰的一声,方源悍然自爆。\n......\n春雨绵绵,悄无声息地滋润着青茅山。\n夜已经深了,丝丝凉风吹拂着细雨。\n青茅山却不黑暗,从山腰至山脚,闪着", "春雨绵绵,悄无声息地滋润着青茅山。\n夜已经深了,丝丝凉风吹拂着细雨。\n青茅山却不黑暗,从山腰至山脚,闪着许多莹莹的微光,好像是披着一条灿烂的光带。\n这些", "这些光来源于一座座高脚吊楼,虽称不上万家灯火,却也有数千的规模。\n正是坐落在青茅山的古月山寨,给广袤幽静的山峦增添了一份浓郁的人烟气息。\n古月山寨的最中央,是"], "evidence": ["topo_suffix:山"]} +{"src": "蛊", "gold_dst": "гу", "type": "term", "gold_alt": [], "aliases": [], "seed_note": "pinyin: gǔ; THE core concept (гу — a living tool-creature). Indeclinable neuter. Single-char → does not fire on hot path (A3); a concept anchor. Appears bound in compounds (蛊师, 蛊虫, 月光蛊…)", "in_bank": false, "provenance": "seed v2 approved (владелец) src=蛊; bank=coldrun-a BANK-FULL"} +{"src": "蛊师", "gold_dst": "гу-мастер", "type": "title", "gold_alt": ["гу-мастера", "гу-мастеру", "гу-мастером", "гу-мастере", "гу-мастеров", "гу-мастерам", "гу-мастерами", "гу-мастерах"], "aliases": [], "seed_note": "pinyin: gǔshī; a gu master — one who rears/refines/wields гу. Head noun мастер declines; «гу-» fixed. Acc(anim)=gen [v2: +мн.ч. D24.4]", "in_bank": true, "provenance": "seed v2 approved (владелец) src=蛊师; bank=coldrun-a BANK-FULL", "bank_src": "蛊师", "bank_dst": "гу-мастер", "bank_origin": "banknote", "bank_type": "term", "freq": 52, "spread": 5, "variants": [["гу-мастер", 5], ["гуши", 3], ["мастер гу", 2], ["гу ши", 1], ["гу-ши", 1]], "contexts": ["上不由地浮现出一层忧色。\n此子的资质极端出色,短短两年功夫,就已经修行到三转蛊师。在年轻一辈中,可谓独领风骚。甚至就连老一辈们都感觉到了这位后起之秀的压力。", "要在特定的时间才能开启。\n“最关键的还是修为啊。自己如今元海未开,还没有踏上蛊师的修行之路,根本就是个凡人!必须得尽快修行,增长修为,赶在历史之前,尽可能的抢占", "就没有能力在危机重重的群山中穿梭,一头普通的山猪都能够要了我的性命。若能达到三转蛊师的修为,就有基本能力自保,在这方世界中跋山涉水了。”\n以五百年锻炼出来的魔道"], "evidence": []} +{"src": "蛊虫", "gold_dst": "гу-червь", "type": "term", "gold_alt": ["гу-червя", "гу-червю", "гу-червя", "гу-червём", "гу-черве"], "aliases": [], "seed_note": "[signoff:approved] подпись: гу-червь (подтверждено). (было: «гу-червь»). [v2:DRAFT⚑] «гу-тварь» пейоративно; «гу-червь»/«гу». Согласование зависит от рода «гу». (было: «гу-тварь»). pinyin: gǔchóng; the gu creature (near-synonym of 蛊). FLAG: could be «гу-существо»/«гу». Forms gen/dat/acc/instr/prep (fem -рь)", "in_bank": true, "provenance": "seed v2 approved (владелец) src=蛊虫; bank=coldrun-a BANK-FULL", "bank_src": "蛊虫", "bank_dst": "гу-червь", "bank_origin": "banknote", "bank_type": "term", "freq": 33, "spread": 5, "variants": [["гу-червь", 3], ["гу (мн.ч.)", 1], ["гу насекомое", 1], ["гучун", 1], ["кукурузные черви", 1]], "contexts": [",只要不太过度使用,就能重复利用着。\n也许春秋蝉就是那种只能使用一次的消耗类蛊虫。\n“不过就算是没了,也可以再炼制一只。前世我能炼制,今生难道就不能吗?”可", "中,河畔花海就好像是一大片的蓝绿地毯,点缀着数不清的珍珠。\n“月兰花,是很多蛊虫的食材。这片花海,可以说是家族最大的培养基地了。”方源对此心知肚明。\n“好美", "源精气神的凝结,象征着他十五年来积蓄出来的生命潜能。\n蛊师就是用这真元来催动蛊虫,也就是说,从此刻起,方源就正式迈入一转蛊师的行列。\n空窍已开,再没有希望蛊"], "evidence": []} +{"src": "本命蛊", "gold_dst": "гу Жизни", "type": "term", "gold_alt": [], "aliases": [], "seed_note": "[signoff:approved] подпись: «гу Жизни» (возврат к v1-форме; НЕ «жизненный гу»); инвариант как гу+генитив. (было: «жизненный гу»). [v2:DRAFT⚑] оба: НЕ «гу Жизни» (читается как ВИД). СТАТУС, не вид. Согласование зависит от рода «гу». (было: «гу Жизни»). pinyin: běnmìng gǔ; a gu master's first-refined, life-bound primary gu (性命交修). FLAG rendering: «гу Жизни» / «главное гу» / «природное гу» — owner's call", "in_bank": true, "provenance": "seed v2 approved (владелец) src=本命蛊; bank=coldrun-a BANK-FULL", "bank_src": "本命蛊", "bank_dst": "Гу жизни", "bank_origin": "banknote", "bank_type": "term", "freq": 9, "spread": 7, "variants": [["гу-талисман судьбы", 1], ["жизненная гу", 1], ["жизненный червь-гу", 1], ["личная гу", 1], ["основной гу", 1], ["основной гучун", 1], ["родовой червь", 1]], "contexts": ["酒虫露面。可惜,就是不见那酒虫,结果令人十分失望。\n“若是找到那酒虫,炼化为本命蛊,比家族中的月光蛊要好多了。眨眼间,已经到了四月,时不我待呀。”方源叹了一口气,", "你们如何冥想,察看自身的空窍元海。如何打坐,调动体内的真元。现在是时候炼化你们的本命蛊了。这节课结束后,你们就去学堂里的蛊室,挑选蛊虫。选了蛊虫之后,就回家潜修。直到", "况,都会选择一转蛊虫进行首次炼化。\n而蛊师炼化的第一只蛊虫,意义重大,称之为本命蛊,性命交修。一旦灭亡,蛊师必定遭受重创。\n“唉,原本指望能得到花酒行者的酒虫"], "evidence": []} +{"src": "凡人", "gold_dst": "смертный", "type": "term", "gold_alt": ["смертного", "смертному", "смертного", "смертным", "смертном", "смертные", "смертных", "смертными"], "aliases": [], "seed_note": "pinyin: fánrén; a mortal (non-cultivator). Forms gen/dat/acc(anim)/instr/prep [v2: +мн.ч. D24.4]", "in_bank": true, "provenance": "seed v2 approved (владелец) src=凡人; bank=coldrun-a BANK-FULL", "bank_src": "凡人", "bank_dst": "простой человек", "bank_origin": "banknote", "bank_type": "term", "freq": 2, "spread": 1, "variants": [["простой человек", 1]], "contexts": ["“最关键的还是修为啊。自己如今元海未开,还没有踏上蛊师的修行之路,根本就是个凡人!必须得尽快修行,增长修为,赶在历史之前,尽可能的抢占先机,捞够好处。”\n而", "陈博脸色顿时苍白,咬着牙,穿过河水,回到原处。没有资质,今后就只能作为一个凡人活着,在家族中也只能是最底层的地位。\n他身躯摇摇欲坠,打击太大了,等于是扼杀"], "evidence": []} +{"src": "开窍", "gold_dst": "открытие апертуры", "type": "term", "gold_alt": ["открытия апертуры", "открытию апертуры", "открытием апертуры", "открытии апертуры"], "aliases": [], "seed_note": "[v2:OK] согласовано с 空窍→апертура; 开窍大典 = обряд открытия апертуры. (было: «открытие врат»). pinyin: kāiqiào; the aperture-opening (开窍大典 = обряд открытия врат) that makes one a гу-мастер. 窍=«врата». Head открытие declines; врат fixed", "in_bank": true, "provenance": "seed v2 approved (владелец) src=开窍; bank=coldrun-a BANK-FULL", "bank_src": "开窍", "bank_dst": "открытие точки", "bank_origin": "banknote", "bank_type": "term", "freq": 18, "spread": 3, "variants": [["открытие акупунктурной точки", 1], ["открытие отверстия", 1], ["открытие точки", 1]], "contexts": ["此时正举办着祭祀大典,因此更是灯火通明,光辉绚烂。\n“列祖列宗保佑,希望此次开窍大典中能多多涌现出资质优秀的少年,为家族增添新血和希望!”古月族长中年模样,两鬓", "“时间过的真是太快了,一眨眼,一年就都过去了。”\n“上一届的开窍大典就像是昨天发生的一样,依旧历历在目呢。”\n“明日就是一年一度的开窍大典了", "一届的开窍大典就像是昨天发生的一样,依旧历历在目呢。”\n“明日就是一年一度的开窍大典了,不知道今年会涌现出什么样的家族新血呢?”\n“唉,希望有甲等资质的少年"], "evidence": []} +{"src": "空窍", "gold_dst": "апертура", "type": "term", "gold_alt": ["апертуры", "апертуре", "апертуру", "апертурой", "апертуре"], "aliases": [], "seed_note": "[signoff:approved] подпись: апертура (подтверждено). (было: «апертура»). [v2:OK] оба флагмана — топ-проблема: «врата» ломают грамматику («одни врата»); «апертура» = фан-вики жанра. (было: «врата»). pinyin: kōngqiào (also 元海空窍); the aperture that houses the 元海. Rendered «врата» (pluralia). Forms gen/dat/acc/instr/prep", "in_bank": true, "provenance": "seed v2 approved (владелец) src=空窍; bank=coldrun-a BANK-FULL", "bank_src": "空窍", "bank_dst": "кунцяо", "bank_origin": "banknote", "bank_type": "term", "freq": 28, "spread": 10, "variants": [["пустота", 2], ["Полая впадина", 1], ["кунцяо", 1], ["кунцяо (пустота)", 1], ["кунцяо (пустотная акупунктура)", 1], ["пустое отверстие", 1], ["пустой канал", 1], ["пустота (копчик)", 1], ["пустотная полость", 1], ["пустотный меридиан", 1]], "contexts": ["未来的路,会很精彩\n空窍玄妙异常,虽然寄托在方源体内,但是却不和五脏六腑同处一个空间。你可以说它无限大,", "大,又可以说它无限小。\n有人称之为紫府,有人称之为华池。不过更多人称之为元海空窍。\n整个空窍呈球形,空窍表面流动着白光,是一层光膜。就是先前的希望蛊炸裂开来", "限小。\n有人称之为紫府,有人称之为华池。不过更多人称之为元海空窍。\n整个空窍呈球形,空窍表面流动着白光,是一层光膜。就是先前的希望蛊炸裂开来,凝聚的一层光。"], "evidence": []} +{"src": "元海", "gold_dst": "море истинной ци", "type": "term", "gold_alt": ["моря истинной ци", "морю истинной ци", "морем истинной ци", "море истинной ци"], "aliases": [], "seed_note": "[signoff:approved] подпись: море истинной ци (подтверждено). (было: «море истинной ци»). [v2:OK] согласовано с 真元→истинная ци. (было: «море истинной энергии»). pinyin: yuánhǎi; the essence sea inside the aperture (reservoir of 真元). Head море declines", "in_bank": true, "provenance": "seed v2 approved (владелец) src=元海; bank=coldrun-a BANK-FULL", "bank_src": "元海", "bank_dst": "Юаньхай", "bank_origin": "both", "bank_type": "name", "freq": 26, "spread": 7, "variants": [["юаньхай", 3], ["море юань", 3], ["Юаньхай", 1], ["Море Изначального", 1], ["Море Энергии", 1], ["море энергии", 1], ["море юаня", 1]], "contexts": ["隔十万八千里,就是需要在特定的时间才能开启。\n“最关键的还是修为啊。自己如今元海未开,还没有踏上蛊师的修行之路,根本就是个凡人!必须得尽快修行,增长修为,赶在历", "目瞪口呆,学堂家老欢喜得大叫起来:“好,古月漠北,乙等资质,来这里,让我看看你的元海。”\n古月漠北便又回到学堂家老的身边,后者伸出手,搭在少年的肩膀,闭目凝神探", "在少年的肩膀,闭目凝神探查了一番,便收回手,点点头,在纸上记录起来:“古月漠北,元海六成六,可大力栽培。”\n这资质从上到下,分甲乙丙丁四等。\n一位丁等资质的"], "evidence": ["surname:元", "topo_suffix:海"]} +{"src": "真元", "gold_dst": "истинная ци", "type": "term", "gold_alt": ["истинной ци", "истинной ци", "истинную ци", "истинной ци", "истинной ци"], "aliases": [], "seed_note": "[v2:OK] оба: НЕ «истинная энергия» (физикализм); ци — жанровая норма; отделить от 元气. (было: «истинная энергия»). pinyin: zhēnyuán; true essence that powers гу. Colour by rank: 青铜(r1 бронзовая)/赤铁(r2 красножелезная)/白银(r3 серебряная). Forms gen/dat/acc/instr/prep", "in_bank": true, "provenance": "seed v2 approved (владелец) src=真元; bank=coldrun-a BANK-FULL", "bank_src": "真元", "bank_dst": "чжэньюань", "bank_origin": "banknote", "bank_type": "term", "freq": 41, "spread": 6, "variants": [["истинная юань", 3], ["истинная ци", 2], ["истинный юань", 2], ["чжэньюань", 2], ["истинная сущность", 1], ["чжэньюань (истинная энергия)", 1]], "contexts": ["如镜,呈现一片碧青之色,却又浓稠无比,带着铜的光泽。\n这是一转蛊师才有的青铜真元凝结,俗称青铜海。\n海面不到空窍的一半高度,只有四成四。这也是丙等资质的局限", "面不到空窍的一半高度,只有四成四。这也是丙等资质的局限。\n每一滴的海水,都是真元,代表着方源精气神的凝结,象征着他十五年来积蓄出来的生命潜能。\n蛊师就是用这", ",代表着方源精气神的凝结,象征着他十五年来积蓄出来的生命潜能。\n蛊师就是用这真元来催动蛊虫,也就是说,从此刻起,方源就正式迈入一转蛊师的行列。\n空窍已开,再"], "evidence": []} +{"src": "元石", "gold_dst": "первобытный камень", "type": "term", "gold_alt": ["первобытного камня", "первобытному камню", "первобытный камень", "первобытным камнем", "первобытном камне", "первобытные камни", "первобытных камней", "первобытным камням", "первобытными камнями", "первобытных камнях"], "aliases": [], "seed_note": "[signoff:approved] подпись: «первобытные камни» → канон.ед. «первобытный камень» (НЕ «изначальный»/«первокамень»); +мн.ч. D24.4. (было: «изначальный камень»). [v2:OK] «первокамень» → «двадцать первокамень» читается как «двадцать первый»; согласован с рядом 元. (было: «первокамень»). pinyin: yuánshí; primeval stone — the currency and cultivation fuel (≈ gold). Forms gen/dat/acc/instr/prep [v2: +мн.ч. D24.4]", "in_bank": true, "provenance": "seed v2 approved (владелец) src=元石; bank=coldrun-a BANK-FULL", "bank_src": "元石", "bank_dst": "юаньши", "bank_origin": "both", "bank_type": "name", "freq": 32, "spread": 4, "variants": [["юаньши", 3], ["камень юань", 2], ["каменный слиток юань", 1], ["камень юаня", 1]], "contexts": ["迁徙到南疆,在这青茅山驻扎下来。就是看中了这里地下溶洞的一口灵泉。这灵泉产出大量元石,可以说是古月山寨的根基。”\n行了数百步,却是越来越暗,并且依稀听到了水声。", "蛊虫,再来学堂继续上课。同时,这也是你们的第一场考核。谁能拔得头筹,就会有二十块元石的丰厚奖励。”\n喔!\n下一刻,整个学堂都欢呼起来。\n“终于要炼化蛊虫", "开了蛊室,方源直接去了酒肆。\n“掌柜的,来两坛陈酒。”方源掏掏口袋,将仅剩的元石碎块,放在柜台上。\n这些天来,他都会来此买酒,然后再去山寨周边晃荡搜索,意图"], "evidence": ["surname:元"]} +{"src": "转", "gold_dst": "ранг", "type": "title", "gold_alt": ["ранга", "рангу", "рангом", "ранге"], "aliases": [], "seed_note": "pinyin: zhuǎn; the rank tier. Ladder 一转…九转 = ранги 1–9; each rank has 4 substages 初阶/中阶/高阶/巅峰 = начальная/средняя/высшая ступень, пик. Single-char → does not fire (A3); anchor for «ранг»", "in_bank": true, "provenance": "seed v2 approved (владелец) src=转; bank=coldrun-a BANK-FULL", "bank_src": "转", "bank_dst": "ранг", "bank_origin": "banknote", "bank_type": "term", "freq": 62, "spread": 1, "variants": [["ранг", 1]], "contexts": ["西下,落日的余晖将山边的晚霞点燃,一时间绚烂如火。\n一直静如雕塑的方源,慢慢转身。\n群雄顿时一阵骚动,齐齐后退一大步。\n此刻,方源脚下的灰白山石,早已", "着这青山落日,方源轻声一笑:“青山落日,秋月春风。当真是朝如青丝暮成雪,是非成败转头空。”\n说这话的时候,眼前忽的就浮现出前世地球上的种种。\n他本是地球上", "浮现出前世地球上的种种。\n他本是地球上的华夏学子,机缘巧合穿越到这方世界。辗转颠簸三百年,纵横世间两百余年,五百多年光阴悠悠,却是晃眼即逝。\n深埋在心底的"], "evidence": []} +{"src": "一转", "gold_dst": "первый ранг", "type": "title", "gold_alt": ["первого ранга", "первому рангу", "первым рангом", "первом ранге"], "aliases": [], "seed_note": "pinyin: yī zhuǎn; Rank 1 (方源's tier). Acc=nom (inanim)", "in_bank": true, "provenance": "seed v2 approved (владелец) src=一转; bank=coldrun-a BANK-FULL", "bank_src": "一转", "bank_dst": "первый ранг", "bank_origin": "banknote", "bank_type": "term", "freq": 16, "spread": 2, "variants": [["первый оборот", 3], ["первый ранг", 1]], "contexts": ["这资质从上到下,分甲乙丙丁四等。\n一位丁等资质的少年,培养个三年,就能晋升成一转的资深蛊师,成为家族的基石。\n一位丙等资质的少年,培养两年,大多都能成为二转", "海。\n海水平滑如镜,呈现一片碧青之色,却又浓稠无比,带着铜的光泽。\n这是一转蛊师才有的青铜真元凝结,俗称青铜海。\n海面不到空窍的一半高度,只有四成四。这", "的生命潜能。\n蛊师就是用这真元来催动蛊虫,也就是说,从此刻起,方源就正式迈入一转蛊师的行列。\n空窍已开,再没有希望蛊汇入方源体内。\n方源收起心神,只觉得"], "evidence": []} +{"src": "三转", "gold_dst": "третий ранг", "type": "title", "gold_alt": ["третьего ранга", "третьему рангу", "третьим рангом", "третьем ранге"], "aliases": [], "seed_note": "pinyin: sān zhuǎn; Rank 3 (elders, 白凝冰)", "in_bank": true, "provenance": "seed v2 approved (владелец) src=三转; bank=coldrun-a BANK-FULL", "bank_src": "三转", "bank_dst": "третий ранг", "bank_origin": "banknote", "bank_type": "term", "freq": 8, "spread": 2, "variants": [["третий оборот", 2], ["третий ранг", 1]], "contexts": ["的脸上不由地浮现出一层忧色。\n此子的资质极端出色,短短两年功夫,就已经修行到三转蛊师。在年轻一辈中,可谓独领风骚。甚至就连老一辈们都感觉到了这位后起之秀的压力。", "根本就没有能力在危机重重的群山中穿梭,一头普通的山猪都能够要了我的性命。若能达到三转蛊师的修为,就有基本能力自保,在这方世界中跋山涉水了。”\n以五百年锻炼出来的", "代表着某种安全。\n“哼,短时间之内,就姑且在这牢笼里折腾拳脚吧。只要晋升蛊师三转,就离开这穷山僻壤。不过幸好,明天就是开窍大典,此后不久就能正式开启蛊师的修行。"], "evidence": []} +{"src": "五转", "gold_dst": "пятый ранг", "type": "title", "gold_alt": ["пятого ранга", "пятому рангу", "пятым рангом", "пятом ранге"], "aliases": [], "seed_note": "pinyin: wǔ zhuǎn; Rank 5 (四代族长, 花酒行者)", "in_bank": true, "provenance": "seed v2 approved (владелец) src=五转; bank=coldrun-a BANK-FULL", "bank_src": "五转", "bank_dst": "пятый ранг", "bank_origin": "banknote", "bank_type": "term", "freq": 6, "spread": 3, "variants": [["пятый оборот", 2], ["пятый ранг", 1], ["пятый чжуань", 1]], "contexts": ["来越稀薄,加上这些年来,家族也没有出现几位四转强者,来增强血脉。四代族长是唯一的五转强者,结果却和花酒行者同归于尽,没有留下血脉后裔。古月一族后辈的资质是越来越弱了", "等资质,元海充足,是空窍的八九成,这样的人自然天赋最高,最适合蛊师修行,能修行到五转。”\n“至于六转向上的蛊师,每一个都是传奇,具体的我也不太清楚。我们古月一族", "师,每一个都是传奇,具体的我也不太清楚。我们古月一族,也没有出现过六转蛊师,但是五转、四转蛊师都有过。”\n少年们的耳朵都竖起来,双眼炯炯发亮地听着。\n许多人"], "evidence": []} +{"src": "六转", "gold_dst": "шестой ранг", "type": "title", "gold_alt": ["шестого ранга", "шестому рангу", "шестым рангом", "шестом ранге"], "aliases": [], "seed_note": "pinyin: liù zhuǎn; Rank 6 (春秋蝉, 方源's past-life peak)", "in_bank": true, "provenance": "seed v2 approved (владелец) src=六转; bank=coldrun-a BANK-FULL", "bank_src": "六转", "bank_dst": "шестой ранг", "bank_origin": "banknote", "bank_type": "term", "freq": 3, "spread": 2, "variants": [["шестой оборот", 1], ["шестой ранг", 1]], "contexts": ["空窍的八九成,这样的人自然天赋最高,最适合蛊师修行,能修行到五转。”\n“至于六转向上的蛊师,每一个都是传奇,具体的我也不太清楚。我们古月一族,也没有出现过六转蛊", "于六转向上的蛊师,每一个都是传奇,具体的我也不太清楚。我们古月一族,也没有出现过六转蛊师,但是五转、四转蛊师都有过。”\n少年们的耳朵都竖起来,双眼炯炯发亮地听着", "直修行到了五转蛊师的境界。要不是那个卑鄙无耻的魔头花酒行者偷袭的话,兴许能晋升成六转蛊师也说不定。唉......”\n说到这里,古月师深深一叹。\n讲台下,少年"], "evidence": []} +{"src": "甲等", "gold_dst": "класс А", "type": "title", "gold_alt": ["класса А", "классу А", "классом А", "классе А"], "aliases": [], "seed_note": "[reseed:approved D38.5] грейд 甲等→«класс А» (D37: развести с 转→«ранг»; было «разряд», draft→approved). pinyin: jiǎděng; top aptitude grade (方正). Схема 甲乙丙丁 = класс А>Б>В>Г (все четыре); голова «класс» склоняется, буква инвариант.", "in_bank": true, "provenance": "seed v2 approved (владелец) src=甲等; bank=coldrun-a BANK-FULL", "bank_src": "甲等", "bank_dst": "класс Цзя", "bank_origin": "both", "bank_type": "title", "freq": 24, "spread": 8, "variants": [["уровень «цзя»", 2], ["класс «Цзя»", 1], ["класс Цзя", 1], ["ранг Цзя", 1], ["талант первого разряда", 1], ["уровень Цзя", 1], ["цзя", 1], ["цзя (уровень \"цзя\")", 1]], "contexts": ["一年一度的开窍大典了,不知道今年会涌现出什么样的家族新血呢?”\n“唉,希望有甲等资质的少年出现。我们古月一族已经有三年没有这样的天才出现了。”\n“不错,白家", "不忘,或者力气大如成人等等天赋异禀的人,都有优秀的修行资质。\n“若是此子测出甲等资质,好生培养,也未必不能和白凝冰抗衡。就算是乙等资质,日后定也能独当一面,成为", "面,成为古月一族的一面旗帜。不过他这样的早慧,乙等资质的可能性不大,极有可能就是甲等。”这一念生出,古月族长的嘴角不由地微微翘起,浮现出一抹微笑。\n旋即,咳嗽一"], "evidence": ["rank_grade:甲+等"]} +{"src": "乙等", "gold_dst": "класс Б", "type": "title", "gold_alt": ["класса Б", "классу Б", "классом Б", "классе Б"], "aliases": [], "seed_note": "[reseed:approved D38.5] грейд 乙等→«класс Б» (D37: развести с 转→«ранг»; было «разряд», draft→approved). pinyin: yǐděng; 2nd aptitude grade (漠北, 赤城).", "in_bank": true, "provenance": "seed v2 approved (владелец) src=乙等; bank=coldrun-a BANK-FULL", "bank_src": "乙等", "bank_dst": "ранг И", "bank_origin": "banknote", "bank_type": "term", "freq": 10, "spread": 6, "variants": [["уровень «и»", 2], ["класс И", 1], ["ранг И", 1], ["талант второго разряда", 1], ["уровень И", 1], ["и", 1]], "contexts": ["修行资质。\n“若是此子测出甲等资质,好生培养,也未必不能和白凝冰抗衡。就算是乙等资质,日后定也能独当一面,成为古月一族的一面旗帜。不过他这样的早慧,乙等资质的可", "。就算是乙等资质,日后定也能独当一面,成为古月一族的一面旗帜。不过他这样的早慧,乙等资质的可能性不大,极有可能就是甲等。”这一念生出,古月族长的嘴角不由地微微翘起,", "少年们隔岸看得目瞪口呆,学堂家老欢喜得大叫起来:“好,古月漠北,乙等资质,来这里,让我看看你的元海。”\n古月漠北便又回到学堂家老的身边,后者伸出"], "evidence": []} +{"src": "丙等", "gold_dst": "класс В", "type": "title", "gold_alt": ["класса В", "классу В", "классом В", "классе В"], "aliases": [], "seed_note": "[reseed:approved D38.5] грейд 丙等→«класс В» (D37: развести с 转→«ранг»; было «разряд», draft→approved). pinyin: bǐngděng; 3rd aptitude grade (方源).", "in_bank": true, "provenance": "seed v2 approved (владелец) src=丙等; bank=coldrun-a BANK-FULL", "bank_src": "丙等", "bank_dst": "ранг Бин", "bank_origin": "both", "bank_type": "title", "freq": 23, "spread": 10, "variants": [["уровень «бин»", 2], ["бин", 1], ["бин (уровень \"бин\")", 1], ["класс «Бин»", 1], ["класс Бин", 1], ["ранг Бин", 1], ["талант третьего разряда", 1], ["третий ранг (бин)", 1], ["уровень «бинь»", 1], ["уровень Бин", 1]], "contexts": ["压过自己这个亲哥哥。\n而至于自己的资质嘛......\n呵呵,最高的只是个丙等罢了。\n命运总是爱开玩笑。\n一胎双胞,哥哥资质只是丙等,却独享天才之名十", "呵呵,最高的只是个丙等罢了。\n命运总是爱开玩笑。\n一胎双胞,哥哥资质只是丙等,却独享天才之名十几年。弟弟默默无闻,反而有着甲等天资。\n开窍的结果,让族人", "真是木秀于林风必催之。”听着耳边的议论声,方源心中冷笑着。\n难怪在测出自己的丙等资质后,会四面环敌,很长一段时间都受着苛刻、白眼、冷遇。\n身后弟弟方正越来越"], "evidence": ["rank_grade:丙+等", "formant_prefix:丙"]} +{"src": "丁等", "gold_dst": "класс Г", "type": "title", "gold_alt": ["класса Г", "классу Г", "классом Г", "классе Г"], "aliases": [], "seed_note": "[reseed:approved D38.5] грейд 丁等→«класс Г» (D37: развести с 转→«ранг»; было «разряд», draft→approved). pinyin: dīngděng; lowest aptitude grade.", "in_bank": true, "provenance": "seed v2 approved (владелец) src=丁等; bank=coldrun-a BANK-FULL", "bank_src": "丁等", "bank_dst": "ранг Дин", "bank_origin": "banknote", "bank_type": "term", "freq": 4, "spread": 5, "variants": [["уровень «дин»", 2], ["дин", 1], ["ранг Дин", 1], ["талант низшего разряда", 1], ["уровень Дин", 1]], "contexts": ["漠北,元海六成六,可大力栽培。”\n这资质从上到下,分甲乙丙丁四等。\n一位丁等资质的少年,培养个三年,就能晋升成一转的资深蛊师,成为家族的基石。\n一位丙等", "脸色阴沉得很是难看。\n半个时辰之后,已有一半少年踏足过花海,涌现了不少丙等、丁等的资质,当然毫无资质的占了几乎一半。\n“唉,血脉越来越稀薄,加上这些年来,家", "方源顶着压力,继续往前走。\n“十步以下,是没有修行资质。十步到二十步之间,是丁等资质。二十步到三十步之间,是丙等资质。三十步到四十步,是乙等资质。四十步到五十步"], "evidence": []} +{"src": "春秋蝉", "gold_dst": "Весенне-осенняя цикада", "type": "term", "gold_alt": ["Весенне-осенней цикады", "Весенне-осенней цикаде", "Весенне-осеннюю цикаду", "Весенне-осенней цикадой", "Весенне-осенней цикаде"], "aliases": [], "seed_note": "pinyin: Chūnqiū Chán (Palladius: Чуньцю Чань); a rank-6 蝉/cicada gu — 方源's life gu, powers rebirth/time-reversal. 春秋 connotes «годы/время». Forms gen/dat/acc/instr/prep", "in_bank": true, "provenance": "seed v2 approved (владелец) src=春秋蝉; bank=coldrun-a BANK-FULL", "bank_src": "春秋蝉", "bank_dst": "Цикада Весны и Осени", "bank_origin": "banknote", "bank_type": "term", "freq": 13, "spread": 3, "variants": [["Цикада Весны и Осени", 1], ["Цикада весны и осени", 1], ["Чуньцючань", 1]], "contexts": ["纵身亡魔心仍不悔\n“方源,乖乖地交出春秋蝉,我给你个痛快!”\n“方老魔,你不要妄图反抗了,今日我们正道各大派联合起来,", "早已经布下天罗地网,这次你必定身首异处!”\n“方源你个该死的魔头,你为了练成春秋蝉,杀了千万人的性命。你已经犯下了滔天的罪孽,罪无可恕,罄竹难书!”\n“魔头,", ",就是不修善果,杀人放火。天地不容,举世皆敌,还要纵情纵横。\n“若是刚炼成的春秋蝉有效,来生还是要做邪魔!”这般想着,方源情不自禁放声大笑。\n“老魔,你笑什么"], "evidence": []} +{"src": "月光蛊", "gold_dst": "гу Лунного света", "type": "term", "gold_alt": [], "aliases": [], "seed_note": "pinyin: Yuèguāng Gǔ; the Gu Yue clan's signature rank-1 gu (Moonlight Gu). «гу»+genitive → invariant", "in_bank": true, "provenance": "seed v2 approved (владелец) src=月光蛊; bank=coldrun-a BANK-FULL", "bank_src": "月光蛊", "bank_dst": "Гу лунного света", "bank_origin": "banknote", "bank_type": "term", "freq": 33, "spread": 7, "variants": [["лунный гу", 2], ["Гу Лунного света", 1], ["Лунный гу", 1], ["гу Лунного Света", 1], ["гу лунного света", 1], ["лунный свет гу", 1], ["лунный червь-гу", 1]], "contexts": ["是不见那酒虫,结果令人十分失望。\n“若是找到那酒虫,炼化为本命蛊,比家族中的月光蛊要好多了。眨眼间,已经到了四月,时不我待呀。”方源叹了一口气,视线转向窗外。", "者尸骨仍旧未见端倪,也不知道什么时候能找到,或者被别人发现。保险起见,还是选一只月光蛊吧。”\n方源一边心中暗叹,一边径直走向左手墙侧。\n在这面墙洞位置稍稍靠上", "月一族的秘法培育而来,其他地方没有,可以说是古月一族的标志象征。\n都是一转的月光蛊,差别极其细微。方源随意挑选了一只,拿在手上。\n月光蛊很轻,堪比一张薄纸的重"], "evidence": []} +{"src": "酒虫", "gold_dst": "Винный червь", "type": "term", "gold_alt": ["Винного червя", "Винному червю", "Винным червём", "Винном черве", "Винные черви", "Винных червей", "Винным червям", "Винными червями", "Винных червях"], "aliases": [], "seed_note": "pinyin: Jiǔ Chóng; Wine Worm — a prized rank-1 gu (was 花酒行者's life gu). 虫=червь. Acc(anim)=gen", "in_bank": true, "provenance": "seed v2 approved (владелец) src=酒虫; bank=coldrun-a BANK-FULL", "bank_src": "酒虫", "bank_dst": "Винный червь", "bank_origin": "banknote", "bank_type": "term", "freq": 17, "spread": 7, "variants": [["Винный червь", 2], ["Цзючун (винный гу)", 1], ["винная гу", 1], ["винный червь", 1], ["винный червь-гу", 1], ["гу вина", 1], ["цзючун", 1]], "contexts": ["失恋而醉酒的族内蛊师,烂醉如泥地躺在山寨外,结果四溢的酒香气息,意外地引来了一头酒虫。\n蛊师大喜,想要捕捉。酒虫慌忙逃窜,蛊师紧追不舍,顺着酒虫的踪迹,发现了一", "躺在山寨外,结果四溢的酒香气息,意外地引来了一头酒虫。\n蛊师大喜,想要捕捉。酒虫慌忙逃窜,蛊师紧追不舍,顺着酒虫的踪迹,发现了一处隐秘的洞口,通往地下。\n酒", "意外地引来了一头酒虫。\n蛊师大喜,想要捕捉。酒虫慌忙逃窜,蛊师紧追不舍,顺着酒虫的踪迹,发现了一处隐秘的洞口,通往地下。\n酒虫是很珍贵的一种蛊,这蛊师带着酒"], "evidence": []} +{"src": "希望蛊", "gold_dst": "гу Надежды", "type": "term", "gold_alt": [], "aliases": [], "seed_note": "pinyin: Xīwàng Gǔ; Hope Gu — obtained at 开窍 (from the 人祖/Human-Ancestor legend, 節5). «гу»+genitive → invariant", "in_bank": true, "provenance": "seed v2 approved (владелец) src=希望蛊; bank=coldrun-a BANK-FULL", "bank_src": "希望蛊", "bank_dst": "Гу Надежды", "bank_origin": "banknote", "bank_type": "term", "freq": 8, "spread": 4, "variants": [["Гу Надежды", 2], ["гу Надежды", 1], ["гу надежды", 1], ["червь-гу Надежды", 1]], "contexts": ["阵光点。\n光点飘摇,笼罩住方源的全身,最后悉数投入到他的体内。\n“这就是希望蛊了。”方源心中喃喃。负责人虽然没有说明,但他知道的很清楚。\n这每一个光点,都", "这每一个光点,都是一只蛊。\n蛊名为希望。\n有一个最古老的传说,就是说的希望蛊。\n传说,这个世界刚刚形成的时候,一片蛮荒,野兽横行,出现了第一个人类,名字", "交给了这只蛊后,这只蛊忽然绽放出无限的光明,在这光明中,困境们惊恐地大叫:“这是希望蛊,快撤,我们困境最怕希望了。”\n困境兽群顿时仓皇而退。\n人祖目瞪口呆,从"], "evidence": []} +{"src": "月影蛊", "gold_dst": "гу Лунной тени", "type": "term", "gold_alt": [], "aliases": [], "seed_note": "pinyin: Yuèyǐng Gǔ; Moon-Shadow Gu, a rank-4 gu of the 四代族长 (節15). «гу»+genitive → invariant", "in_bank": false, "provenance": "seed v2 approved (владелец) src=月影蛊; bank=coldrun-a BANK-FULL"} +{"src": "月兰花", "gold_dst": "лунная орхидея", "type": "term", "gold_alt": ["лунной орхидеи", "лунной орхидее", "лунную орхидею", "лунной орхидеей", "лунной орхидее"], "aliases": [], "seed_note": "pinyin: yuèlánhuā; Moon Orchid — gu-food flower the clan cultivates by the underground spring (節4/15). Forms gen/dat/acc/instr/prep", "in_bank": true, "provenance": "seed v2 approved (владелец) src=月兰花; bank=coldrun-a BANK-FULL", "bank_src": "月兰花", "bank_dst": "лунная орхидея", "bank_origin": "banknote", "bank_type": "term", "freq": 2, "spread": 1, "variants": [["лунная орхидея", 1]], "contexts": ["水草,以及河底的沙石。\n在河的对岸,是一片花海。\n这是古月一族有意栽培的月兰花,花瓣如月牙,呈现出清丽淡雅的蓝粉色。花茎如玉,花心闪耀着,好像是珍珠在光下的折", ",在黑暗的背景中,河畔花海就好像是一大片的蓝绿地毯,点缀着数不清的珍珠。\n“月兰花,是很多蛊虫的食材。这片花海,可以说是家族最大的培养基地了。”方源对此心知肚明。"], "evidence": []} +{"src": "血颅蛊", "gold_dst": "гу Кровавого черепа", "type": "term", "gold_alt": [], "aliases": [], "seed_note": "pinyin: Xuèlú Gǔ; Blood-Skull Gu — the aptitude-raising gu central to the plot. SPOILER: named in the cover blurb but first appears in-body at 第193节 (line ~16887); since_ch=193. «гу»+genitive → invariant", "in_bank": false, "provenance": "seed v2 approved (владелец) src=血颅蛊; bank=coldrun-a BANK-FULL"} +{"src": "长生", "gold_dst": "бессмертие", "type": "term", "gold_alt": ["бессмертия", "бессмертию", "бессмертие", "бессмертием", "бессмертии"], "aliases": [], "seed_note": "[v2-NEW:OK] chángshēng; вечная жизнь/бессмертие — сквозная тема; НЕ «долголетие»", "in_bank": false, "provenance": "seed v2 approved (владелец) src=长生; bank=coldrun-a BANK-FULL"} +{"src": "族长", "gold_dst": "глава клана", "type": "title", "gold_alt": ["главы клана", "главе клана", "главу клана", "главой клана", "главе клана"], "aliases": [], "seed_note": "[v2-NEW:OK] zúzhǎng; глава клана — НАД старейшинами; черновик путал со «старейшиной». ⚠ консистентность род/клан — см. sign-off", "in_bank": true, "provenance": "seed v2 approved (владелец) src=族长; bank=coldrun-a BANK-FULL", "bank_src": "族长", "bank_dst": "глава клана", "bank_origin": "alias", "bank_type": "title", "freq": 32, "spread": 1, "variants": [["глава клана", 1]], "contexts": ["保佑,希望此次开窍大典中能多多涌现出资质优秀的少年,为家族增添新血和希望!”古月族长中年模样,两鬓微霜,一身素白庄重的祭祀服装,跪在棕黄色的地板上,直着上身,双手合", "白色祭服,都是家族中的家老、话事人,执掌着各方面的权柄。\n祈祷了一番后,古月族长率先弯腰,双手平摊,掌心紧紧贴着地板,磕头。额头碰在棕色的地板上,发出轻轻的砰砰", "年他创作的《将敬酒》、《咏梅》,还有《江城子》我也听说过,真是天才!”\n古月族长最后一个走出宗祖祠堂,慢慢地关上门,便听到走廊中家老们的议论声音。\n顿时就知"], "evidence": []} +{"src": "家老", "gold_dst": "старейшина", "type": "title", "gold_alt": ["старейшины", "старейшине", "старейшину", "старейшиной", "старейшине"], "aliases": [], "seed_note": "[v2-NEW:OK] jiālǎo; старейшина клана; развести с 族长", "in_bank": true, "provenance": "seed v2 approved (владелец) src=家老; bank=coldrun-a BANK-FULL", "bank_src": "家老", "bank_dst": "старейшина", "bank_origin": "alias", "bank_type": "term", "freq": 54, "spread": 3, "variants": [["старейшина", 2], ["старейшина клана", 1], ["старейшина рода", 1]], "contexts": ["烟袅袅。\n在他的身后,也同样跪着十余人。他们穿着宽大的白色祭服,都是家族中的家老、话事人,执掌着各方面的权柄。\n祈祷了一番后,古月族长率先弯腰,双手平摊,掌", "摊,掌心紧紧贴着地板,磕头。额头碰在棕色的地板上,发出轻轻的砰砰声。\n身后的家老们各个表情肃穆,也随着默默效仿。\n一时间,宗族祠堂中尽是额头碰撞地板的轻响。", "大典完毕,众人慢慢地从地板上站起身来,静静地走出庄严的祠堂。\n在走廊中,众家老默默地舒了一口气,气氛为之一松。\n议论声渐渐地起来。"], "evidence": []} +{"src": "困境", "gold_dst": "Беды", "type": "term", "gold_alt": ["Бед", "Бедам", "Беды", "Бедами", "Бедах"], "aliases": [], "seed_note": "[v2-NEW:OK] kùnjìng; стая зверей в легенде о Первопредке; имя стаи", "in_bank": true, "provenance": "seed v2 approved (владелец) src=困境; bank=coldrun-a BANK-FULL", "bank_src": "困境", "bank_dst": "Невзгоды", "bank_origin": "banknote", "bank_type": "term", "freq": 16, "spread": 3, "variants": [["Куньцзин", 1], ["Невзгоды", 1], ["Трудности", 1]], "contexts": ["一个人类,名字叫人祖。他茹毛饮血,生活十分困难。\n尤其是还有一群野兽,名字叫困境,特别喜欢人祖的味道,想要吃掉他。\n人祖没有山石般强硬的身躯,没有野兽的利齿", ",想要吃掉他。\n人祖没有山石般强硬的身躯,没有野兽的利齿爪牙,怎么和这群叫做困境的野兽争斗呢?他的食物来源很不稳定,整天东躲西藏,处在大自然食物链的低端,几乎就", "生活开始改善了,他开始有稳定的食物来源,有能够自保的力量。他好勇斗狠,击败了很多困境。但很快就吃了苦头。最后他发现,力量不是万能的,它也需要恢复和修养,不能随意挥霍"], "evidence": []} +{"src": "炼化", "gold_dst": "очистить и подчинить", "type": "term", "gold_alt": [], "aliases": [], "seed_note": "[v2-NEW:OK] liànhuà; очистить-и-подчинить живого гу; НЕ «переплавить». Кратко «очистить»", "in_bank": true, "provenance": "seed v2 approved (владелец) src=炼化; bank=coldrun-a BANK-FULL", "bank_src": "炼化", "bank_dst": "очистка", "bank_origin": "banknote", "bank_type": "term", "freq": 27, "spread": 1, "variants": [["очистка (гу)", 1]], "contexts": ["繁衍生息的过程中,先贤们逐步发现了蛊虫的奥妙。已经开辟空窍,运用本身真元来喂养、炼化、操控这些蛊,达到各种目的的人,我们统称为蛊师。”\n“而你们在七天前的开窍大", "吸引到酒虫露面。可惜,就是不见那酒虫,结果令人十分失望。\n“若是找到那酒虫,炼化为本命蛊,比家族中的月光蛊要好多了。眨眼间,已经到了四月,时不我待呀。”方源叹了", "来,我教会你们如何冥想,察看自身的空窍元海。如何打坐,调动体内的真元。现在是时候炼化你们的本命蛊了。这节课结束后,你们就去学堂里的蛊室,挑选蛊虫。选了蛊虫之后,就回"], "evidence": []} +{"src": "修炼", "gold_dst": "культивация", "type": "term", "gold_alt": ["культивации", "культивации", "культивацию", "культивацией", "культивации"], "aliases": [], "seed_note": "[signoff:approved] подпись: культивация (НЕ «совершенствование»). (было: «культивация»). [v2-NEW:DRAFT⚑] xiūliàn; культивация/культивировать", "in_bank": false, "provenance": "seed v2 approved (владелец) src=修炼; bank=coldrun-a BANK-FULL"} +{"src": "修行", "gold_dst": "культивация", "type": "term", "gold_alt": ["культивации", "культивации", "культивацию", "культивацией", "культивации"], "aliases": [], "seed_note": "[signoff:approved] подпись: согласовано с 修炼=культивация. (было: «культивация»). [v2-NEW:DRAFT⚑] xiūxíng; практика культивации; согласовано с 修炼", "in_bank": false, "provenance": "seed v2 approved (владелец) src=修行; bank=coldrun-a BANK-FULL"} +{"src": "人祖", "gold_dst": "Жэнь Цзу", "type": "name", "gold_alt": [], "aliases": [], "seed_note": "[signoff:approved] подпись: транслит «Жэнь Цзу» (НЕ «Первопредок», НЕ «Рен Зу»); -у → инвариант. (было: «Первопредок»). [v2-NEW:DRAFT⚑] Rénzǔ; говорящее имя (Праотец человечества). НЕ «Рен Зу» (англ.релей-ошибка)", "in_bank": true, "provenance": "seed v2 approved (владелец) src=人祖; bank=coldrun-a BANK-FULL", "bank_src": "人祖", "bank_dst": "Жэньцзу", "bank_origin": "banknote", "bank_type": "name", "freq": 14, "spread": 3, "variants": [["Жэнь-цзу", 1], ["Жэньцзу", 1], ["Прародитель", 1]], "contexts": ["人祖三蛊,希望开窍\n霎时间,周围一静,无数道目光向自己投射而来。\n“真是越来", "传说,这个世界刚刚形成的时候,一片蛮荒,野兽横行,出现了第一个人类,名字叫人祖。他茹毛饮血,生活十分困难。\n尤其是还有一群野兽,名字叫困境,特别喜欢人祖的", "叫人祖。他茹毛饮血,生活十分困难。\n尤其是还有一群野兽,名字叫困境,特别喜欢人祖的味道,想要吃掉他。\n人祖没有山石般强硬的身躯,没有野兽的利齿爪牙,怎么和这"], "evidence": []} +{"src": "资质", "gold_dst": "талант", "type": "term", "gold_alt": ["талант", "таланта", "таланту", "талантом", "таланте", "таланты", "талантов", "талантам", "талантами", "талантах"], "aliases": [], "seed_note": "D39.21 owner canon (24.07): 资质 = «талант» (классы 甲乙丙丁 = А/Б/В/Г уже в сиде); «ресурсы/квалификация/способности» — дрейф-варианты rerun2, канон закрывает.", "in_bank": false, "provenance": "seed v2 approved (владелец) src=资质; bank=coldrun-a BANK-FULL"} diff --git a/eval/bank_arbitration/inject_probe.py b/eval/bank_arbitration/inject_probe.py new file mode 100644 index 00000000..225793d5 --- /dev/null +++ b/eval/bank_arbitration/inject_probe.py @@ -0,0 +1,200 @@ +#!/usr/bin/env python3 +"""Проба C (инжект, пре-рег research/24 §0 п.5): послушание и ВРЕД инъекции глоссария +на транслятор-проводе. 6 чанков × 4 арма: A без инъекции · B верный закон · C НЕВЕРНАЯ строка +законом · D та же неверная строка с ⟨проверить⟩. deepseek-v4-flash, effort low, temp 0. + +Формат байт-близко к движку: messages = [system(translator.md), system(глоссарий-блок), user(text)] +(MessagesWithInjection, render.go:246-262); блок = glossary_header + "src → dst" строки, +маркер = " ⟨проверить⟩" (internal/lang/data/injection.txt). Сырьё durable в ~/books/.../bank-arbitration/. +""" +from __future__ import annotations +import argparse +import json +import re +import time +import unicodedata +from pathlib import Path + +from dotenv import load_dotenv +from openai import OpenAI +import os + +REPO = Path("/home/ubuntu/projects/textmachine") +RAW = Path.home() / "books" / "gu-zhenren" / "bank-arbitration" +SRC = Path.home() / "books" / "gu-zhenren" / "coldrun-a" / "guzhenren-ch1-10.gb18030.txt" +load_dotenv(REPO / "eval" / ".env") + +GLOSSARY_HEADER = ("ГЛОССАРИЙ (используй эти утверждённые переводы имён и терминов последовательно; " + "строки с пометкой ⟨проверить⟩ — неподтверждённые кандидаты):") +MARKER = " ⟨проверить⟩" +PRICE_IN, PRICE_CACHED, PRICE_OUT = 0.14, 0.0028, 0.28 + +# терм: (gold_dst, wrong_dst, gold_rx, wrong_rx) — regex по нормализованному выходу +TERMS = { + "空窍": ("апертура", "пустота", r"апертур", r"пустот"), + "真元": ("истинная ци", "чжэньюань", r"истинн\w* ци\b", r"чж[эе]н[ьи]?юан"), + "元石": ("первобытный камень", "юаньши", r"первобытн\w* кам", r"юаньши"), + "元海": ("море истинной ци", "Юаньхай", r"мор\w{0,2} истинн\w* ци", r"юаньхай"), + "蛊师": ("гу-мастер", "гуши", r"гу-мастер", r"\bгуши\b"), + "族长": ("глава клана", "вождь клана", r"глав\w{0,2} клана", r"вожд\w* клана"), + "月光蛊": ("Гу лунного света", "лунный гу", r"гу лунного света", r"лунн\w{0,2} гу\b"), + "春秋蝉": ("Весенне-осенняя цикада", "Цикада Весны и Осени", r"весенне-осенн", r"цикад\w{0,2} весны и осени"), +} +WRONG_PRIORITY = ["空窍", "真元", "元石", "元海", "蛊师", "月光蛊", "春秋蝉", "族长"] + +TRANSLATOR = REPO / "backend/prompts/zh-ru/translator.md" +USER_SEP = "\n---USER---\n" + + +def render_translator(text: str) -> tuple[str, str]: + raw = TRANSLATOR.read_text(encoding="utf-8") + head, user = raw.split(USER_SEP, 1) + vals = {"source_lang": "zh", "target_lang": "ru", "genre": "вебновелла", + "audience": "взрослые читатели вебновелл", "title": "蛊真人", "venuti": "0.60", + "honorifics": "keep", "transcription": "palladius", "footnotes": "minimal", "text": text} + for k, v in vals.items(): + head = head.replace("{{" + k + "}}", v) + user = user.replace("{{" + k + "}}", v) + return head.strip(), user.strip() + + +def pick_windows(n=6, lo=500, hi=1200): + text = SRC.read_text(encoding="gb18030") + paras = [p for p in text.split("\n") if p.strip()] + wins = [] + i = 0 + while i < len(paras): + buf, j = "", i + while j < len(paras) and len(buf) < lo: + buf += paras[j] + "\n" + j += 1 + if len(buf) > hi: + buf = buf[:hi] + terms = [t for t in TERMS if t in buf] + if len(terms) >= 2: + wins.append((i, buf, terms)) + i = j + 3 # разнести окна + else: + i += 1 + # ранжир: больше термов, разнесённость по книге + wins.sort(key=lambda w: (-len(w[2]), w[0])) + chosen, used = [], set() + for w in wins: + if any(abs(w[0] - u) < 30 for u in used): + continue + chosen.append(w) + used.add(w[0]) + if len(chosen) == n: + break + return chosen + + +def block_for(terms: list[str], wrong: str | None, marked: bool) -> str: + lines = [] + for t in terms: + gold, bad, _, _ = TERMS[t] + if t == wrong: + lines.append(f"{t} → {bad}" + (MARKER if marked else "")) + else: + lines.append(f"{t} → {gold}") + return GLOSSARY_HEADER + "\n" + "\n".join(lines) + + +def norm(s: str) -> str: + return " ".join(unicodedata.normalize("NFKC", s).casefold().replace("ё", "е").split()) + + +def call(cl, system, inj, user, tag): + msgs = [{"role": "system", "content": system}] + if inj: + msgs.append({"role": "system", "content": inj}) + msgs.append({"role": "user", "content": user}) + t0 = time.time() + r = cl.chat.completions.create(model="deepseek-v4-flash", messages=msgs, max_tokens=16000, + temperature=0, extra_body={"reasoning_effort": "low"}) + ch = r.choices[0] + content = ch.message.content or "" + u = r.usage + pt = u.prompt_tokens or 0 + ct = u.completion_tokens or 0 + cached = getattr(getattr(u, "prompt_tokens_details", None), "cached_tokens", 0) or 0 + cost = (pt - cached) / 1e6 * PRICE_IN + cached / 1e6 * PRICE_CACHED + ct / 1e6 * PRICE_OUT + rec = dict(tag=tag, model_returned=r.model, effort="low", finish=ch.finish_reason, + ts=time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()), + prompt_tokens=pt, cached_tokens=cached, completion_tokens=ct, + cost_usd=round(cost, 6), latency_s=round(time.time() - t0, 1), + injection=inj, user=user, content=content) + (RAW / f"{tag}.json").write_text(json.dumps(rec, ensure_ascii=False, indent=1), encoding="utf-8") + print(f"[{tag}] finish={ch.finish_reason} out={ct} ${cost:.6f} {rec['latency_s']}s") + return rec + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--plan", action="store_true") + ap.add_argument("--score", action="store_true") + a = ap.parse_args() + wins = pick_windows() + if a.plan: + for k, (i, buf, terms) in enumerate(wins): + cand = [t for t in WRONG_PRIORITY if t in terms]; wrong = cand[k % len(cand)] + print(f"win{k} @para{i} len={len(buf)} terms={terms} wrong={wrong}") + print(" " + buf[:120].replace("\n", " / ")) + return + if a.score: + score(wins) + return + cl = OpenAI(api_key=os.environ["DEEPSEEK_API_KEY"], base_url="https://api.deepseek.com/v1", timeout=600) + total = 0.0 + for k, (i, buf, terms) in enumerate(wins): + cand = [t for t in WRONG_PRIORITY if t in terms]; wrong = cand[k % len(cand)] + system, user = render_translator(buf) + arms = { + "A": None, + "B": block_for(terms, wrong=None, marked=False), + "C": block_for(terms, wrong=wrong, marked=False), + "D": block_for(terms, wrong=wrong, marked=True), + } + for arm, inj in arms.items(): + rec = call(cl, system, inj, user, f"inj-w{k}-{arm}") + total += rec["cost_usd"] + time.sleep(0.5) + print(f"TOTAL проба C: ${total:.6f}") + + +def score(wins): + rows = [] + for k, (i, buf, terms) in enumerate(wins): + cand = [t for t in WRONG_PRIORITY if t in terms]; wrong = cand[k % len(cand)] + for arm in "ABCD": + f = RAW / f"inj-w{k}-{arm}.json" + if not f.exists(): + continue + out = norm(json.load(open(f, encoding="utf-8"))["content"]) + for t in terms: + gold, bad, grx, brx = TERMS[t] + rows.append(dict(win=k, arm=arm, term=t, is_wrong_term=(t == wrong), + gold_hit=bool(re.search(grx, out)), wrong_hit=bool(re.search(brx, out)))) + import collections + def rate(sel): + sel = list(sel) + return f"{sum(1 for r in sel if r['gold_hit'])}/{len(sel)} gold, {sum(1 for r in sel if r['wrong_hit'])}/{len(sel)} wrong" + print("=== послушание (все термы, верные строки) ===") + for arm in "ABCD": + sel = [r for r in rows if r["arm"] == arm and not r["is_wrong_term"]] + print(f" arm {arm}: {rate(sel)}") + print("=== НЕВЕРНАЯ строка (6 термов) ===") + for arm in "ABCD": + sel = [r for r in rows if r["arm"] == arm and r["is_wrong_term"]] + print(f" arm {arm}: {rate(sel)} (в C/D инъецирован WRONG)") + print("=== единицы: неверный терм по армам ===") + byterm = collections.defaultdict(dict) + for r in rows: + if r["is_wrong_term"]: + byterm[(r["win"], r["term"])][r["arm"]] = (r["gold_hit"], r["wrong_hit"]) + for (w, t), arms in sorted(byterm.items()): + print(f" w{w} {t}: " + " ".join(f"{a}:(gold={arms[a][0]},wrong={arms[a][1]})" for a in sorted(arms))) + + +if __name__ == "__main__": + main() diff --git a/eval/bank_arbitration/multilang_probe.py b/eval/bank_arbitration/multilang_probe.py new file mode 100644 index 00000000..b37b5250 --- /dev/null +++ b/eval/bank_arbitration/multilang_probe.py @@ -0,0 +1,241 @@ +#!/usr/bin/env python3 +"""§E-достройка по вопросу владельца 04.08: переносятся ли выводы §C (инжект) и §B4 (батч-граница +семьи) с пары zh→ru на ja→ru и en→ru. Книги: ~/books/isekai_majutsushi_jp.txt · fifty_shades_1_en.txt. + +Части: + inject-ja: 2 окна × 4 арма (A/B/C/D как в inject_probe) — послушание · вред · пустота маркера; + inject-en: 1 окно × 4 арма — то же на en→ru; + family-ja: семья 魔術/魔術師 (общий корень, РАЗНАЯ длина) НАМЕРЕННО разрезана на 2 батча + терминолог-структурного промпта (source_lang=ja, поливанов) — проверка батч-граничной + химеры конвенции корня вне zh. Голда нет — скорится СВЯЗНОСТЬ, не правильность. + +deepseek-v4-flash, reasoning_effort low, temp 0. Сырьё → ~/books/gu-zhenren/bank-arbitration/ (общий +durable-синк пака). НЕ engine-faithful по паре (ja/en-паков в репо нет) — это проба ФЕНОМЕНА, не движка. +""" +from __future__ import annotations +import argparse +import json +import os +import re +import time +import unicodedata +from pathlib import Path + +from dotenv import load_dotenv +from openai import OpenAI + +REPO = Path("/home/ubuntu/projects/textmachine") +RAW = Path.home() / "books" / "gu-zhenren" / "bank-arbitration" +load_dotenv(REPO / "eval" / ".env") +PRICE_IN, PRICE_CACHED, PRICE_OUT = 0.14, 0.0028, 0.28 + +GLOSSARY_HEADER = ("ГЛОССАРИЙ (используй эти утверждённые переводы имён и терминов последовательно; " + "строки с пометкой ⟨проверить⟩ — неподтверждённые кандидаты):") +MARKER = " ⟨проверить⟩" + +BOOKS = { + "ja": dict( + path=Path.home() / "books" / "isekai_majutsushi_jp.txt", + src_lang="японский", transcription="поливанов", + terms={ + "勇者": ("герой", "храбрец", r"геро(й|я|ю|ем|е|и|ев)", r"храбрец"), + "魔力": ("магическая сила", "мана", r"магическ\w* сил", r"\bман(а|ы|у|ой|е)\b"), + "国王": ("король", "государь", r"корол(ь|я|ю|ем|е|ев)", r"государ"), + "魔術": ("магия", "чародейство", r"маги(я|и|ю|ей)", r"чародейств"), + "洗脳": ("промывание мозгов", "зомбирование", r"промыв\w* мозг", r"зомбир"), + }, + wrong_priority=["魔力", "国王", "洗脳", "魔術", "勇者"], + n_windows=2, win_lo=400, win_hi=900, skip=25, + ), + "en": dict( + path=Path.home() / "books" / "fifty_shades_1_en.txt", + src_lang="английский", transcription="практическая транскрипция", + terms={ + "Christian Grey": ("Кристиан Грей", "Кристиан Грэй", r"кристиан\w* грей", r"грэй"), + "Kate": ("Кейт", "Катя", r"\bкейт\b", r"\bкат(я|и|е|ю|ей)\b"), + "Anastasia": ("Анастейша", "Анастасия", r"анастейш", r"анастаси"), + }, + wrong_priority=["Kate", "Christian Grey", "Anastasia"], + n_windows=1, win_lo=600, win_hi=1200, skip=0, + ), +} + +TRANSLATOR_SYS = """Ты — профессиональный литературный переводчик с языка «{src}» на русский. +Жанр: художественная проза. Переводи ВСЕ предложения исходника: ничего не пропускай и не добавляй. +Пиши живым литературным русским языком. Транскрипция имён: {tr}. +Род и форму имён собственных и терминов бери из приложенного глоссария (если он есть). +Выведи ТОЛЬКО перевод, без преамбул, комментариев и markdown.""" + +FAMILY_SYS = """Ты — терминолог издательского перевода с языка «японский» на язык «русский». +Тебе дан список терминов книги с контекстами из исходника. Выбери ОДИН перевод на термин, единый +для всей книги. Сохраняй родство однокоренных терминов. Имена — транскрипцией ({tr}); понятия — +по смыслу. Давай словарную форму без пояснений. +Формат ответа: по одной строке на термин, ровно два поля через ТАБУЛЯЦИЮ: термин и перевод.""" + +# family-ja: 魔術 в батче 1, 魔術師 в батче 2 — граница режет семью общего корня (разной длины). +FAMILY_BATCHES = [["魔術", "国王", "洗脳"], ["魔術師", "魔力", "勇者"]] + + +def norm(s: str) -> str: + return " ".join(unicodedata.normalize("NFKC", s).casefold().replace("ё", "е").split()) + + +def pick_windows(cfg): + text = cfg["path"].read_text(encoding="utf-8") + paras = [p for p in text.split("\n") if p.strip() and not p.startswith(("http", "===", "URL"))] + wins, i = [], cfg.get("skip", 0) + while i < len(paras): + buf, j = "", i + while j < len(paras) and len(buf) < cfg["win_lo"]: + buf += paras[j] + "\n" + j += 1 + if len(buf) > cfg["win_hi"]: + buf = buf[:cfg["win_hi"]] + terms = [t for t in cfg["terms"] if t in buf] + if len(terms) >= 2: + wins.append((i, buf, terms)) + i = j + 5 + else: + i += 1 + wins.sort(key=lambda w: (-len(w[2]), w[0])) + chosen, used = [], set() + for w in wins: + if any(abs(w[0] - u) < 40 for u in used): + continue + chosen.append(w) + used.add(w[0]) + if len(chosen) == cfg["n_windows"]: + break + return chosen + + +def block_for(cfg, terms, wrong, marked): + lines = [] + for t in terms: + gold, bad, _, _ = cfg["terms"][t] + if t == wrong: + lines.append(f"{t} → {bad}" + (MARKER if marked else "")) + else: + lines.append(f"{t} → {gold}") + return GLOSSARY_HEADER + "\n" + "\n".join(lines) + + +def call(cl, system, inj, user, tag): + msgs = [{"role": "system", "content": system}] + if inj: + msgs.append({"role": "system", "content": inj}) + msgs.append({"role": "user", "content": user}) + t0 = time.time() + r = cl.chat.completions.create(model="deepseek-v4-flash", messages=msgs, max_tokens=16000, + temperature=0, extra_body={"reasoning_effort": "low"}) + ch = r.choices[0] + content = ch.message.content or "" + u = r.usage + pt, ct = u.prompt_tokens or 0, u.completion_tokens or 0 + cached = getattr(getattr(u, "prompt_tokens_details", None), "cached_tokens", 0) or 0 + cost = (pt - cached) / 1e6 * PRICE_IN + cached / 1e6 * PRICE_CACHED + ct / 1e6 * PRICE_OUT + rec = dict(tag=tag, model_returned=r.model, effort="low", finish=ch.finish_reason, + ts=time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()), prompt_tokens=pt, + cached_tokens=cached, completion_tokens=ct, cost_usd=round(cost, 6), + latency_s=round(time.time() - t0, 1), injection=inj, user=user, content=content) + (RAW / f"{tag}.json").write_text(json.dumps(rec, ensure_ascii=False, indent=1), encoding="utf-8") + print(f"[{tag}] finish={ch.finish_reason} out={ct} ${cost:.6f} {rec['latency_s']}s") + return rec + + +def kwic(text, term, per=3, width=40): + out, frm = [], 0 + while len(out) < per: + i = text.find(term, frm) + if i < 0: + break + out.append(text[max(0, i - width):i + len(term) + width].replace("\n", " ")) + frm = i + len(term) + return out + + +def run_inject(cl, lang): + cfg = BOOKS[lang] + total = 0.0 + for k, (i, buf, terms) in enumerate(pick_windows(cfg)): + cand = [t for t in cfg["wrong_priority"] if t in terms] + wrong = cand[(2 * k + 1) % len(cand)] + system = TRANSLATOR_SYS.format(src=cfg["src_lang"], tr=cfg["transcription"]) + user = "Переведи следующий фрагмент:\n\n" + buf + for arm, inj in {"A": None, "B": block_for(cfg, terms, None, False), + "C": block_for(cfg, terms, wrong, False), + "D": block_for(cfg, terms, wrong, True)}.items(): + total += call(cl, system, inj, user, f"ml-{lang}-w{k}-{arm}")["cost_usd"] + time.sleep(0.5) + return total + + +def run_family(cl): + text = BOOKS["ja"]["path"].read_text(encoding="utf-8") + total = 0.0 + for bi, batch in enumerate(FAMILY_BATCHES): + blocks = [] + for t in batch: + blocks.append(f"### {t}\nkey: {t}\ntype: term\nfreq: {text.count(t)}\n" + + "\n".join(f"ctx: {c}" for c in kwic(text, t))) + user = "Термины книги:\n\n" + "\n\n".join(blocks) + total += call(cl, FAMILY_SYS.format(tr="поливанов"), None, user, f"ml-fam-b{bi}")["cost_usd"] + time.sleep(0.5) + return total + + +def score(): + rows = [] + for lang in BOOKS: + cfg = BOOKS[lang] + for k, (i, buf, terms) in enumerate(pick_windows(cfg)): + cand = [t for t in cfg["wrong_priority"] if t in terms] + wrong = cand[(2 * k + 1) % len(cand)] + for arm in "ABCD": + f = RAW / f"ml-{lang}-w{k}-{arm}.json" + if not f.exists(): + continue + out = norm(json.load(open(f, encoding="utf-8"))["content"]) + for t in terms: + gold, bad, grx, brx = cfg["terms"][t] + rows.append(dict(lang=lang, win=k, arm=arm, term=t, is_wrong=(t == wrong), + gold_hit=bool(re.search(grx, out)), wrong_hit=bool(re.search(brx, out)))) + for lang in BOOKS: + print(f"=== {lang} ===") + for arm in "ABCD": + ok = [r for r in rows if r["lang"] == lang and r["arm"] == arm and not r["is_wrong"]] + wr = [r for r in rows if r["lang"] == lang and r["arm"] == arm and r["is_wrong"]] + print(f" arm {arm}: верные {sum(r['gold_hit'] for r in ok)}/{len(ok)} gold; " + f"wrong-терм: gold {sum(r['gold_hit'] for r in wr)}/{len(wr)}, WRONG {sum(r['wrong_hit'] for r in wr)}/{len(wr)}") + print("=== family-ja (связность корня 魔術/魔術師 через границу батча) ===") + for bi in (0, 1): + f = RAW / f"ml-fam-b{bi}.json" + if f.exists(): + print(f" batch {bi}:") + for ln in json.load(open(f, encoding="utf-8"))["content"].split("\n"): + if ln.strip(): + print(" ", ln) + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--plan", action="store_true") + ap.add_argument("--score", action="store_true") + a = ap.parse_args() + if a.plan: + for lang in BOOKS: + for k, (i, buf, terms) in enumerate(pick_windows(BOOKS[lang])): + cand = [t for t in BOOKS[lang]["wrong_priority"] if t in terms] + print(f"{lang} win{k} @{i} len={len(buf)} terms={terms} wrong={cand[(2 * k + 1) % len(cand)]}") + print(" " + buf[:110].replace("\n", " / ")) + return + if a.score: + score() + return + cl = OpenAI(api_key=os.environ["DEEPSEEK_API_KEY"], base_url="https://api.deepseek.com/v1", timeout=600) + total = run_inject(cl, "ja") + run_inject(cl, "en") + run_family(cl) + print(f"TOTAL multilang: ${total:.6f}") + + +if __name__ == "__main__": + main() diff --git a/eval/bank_arbitration/retry_mis_b4.py b/eval/bank_arbitration/retry_mis_b4.py new file mode 100644 index 00000000..01d22497 --- /dev/null +++ b/eval/bank_arbitration/retry_mis_b4.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +"""Добор mis1-b4 после 429 (rate limit Mistral): пауза + одиночный повтор с бэкоффом.""" +import time +import consilium_probe as cp + + +def main(): + roster = cp.build_roster() + batches = cp.batches_of(roster) + b = batches[4] + system, user = cp.render_terminologist("\n\n".join(cp.block_of(c) for c in b)) + cl = cp.client_for("mistral-large-2512") + for attempt in range(4): + try: + time.sleep(20 * (attempt + 1)) + cp.call(cl, "mistral-large-2512", system, user + cp.CONF_NUM, "mis1-b4", None, False) + return + except Exception as e: # noqa: BLE001 + print(f"attempt {attempt}: {type(e).__name__}: {e}") + raise SystemExit("mis1-b4 не добран") + + +if __name__ == "__main__": + main() diff --git a/eval/bank_arbitration/score_baselines.py b/eval/bank_arbitration/score_baselines.py new file mode 100644 index 00000000..6b8f4280 --- /dev/null +++ b/eval/bank_arbitration/score_baselines.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 +"""$0: точность бесплатного базиса P0 (§C2-3 топ-вариант) и прод-референса P1 (сведённый dst +coldrun-a) против голда; разбор промахов по классам (конвенция 古月 · реалия-транслит · прочее). +Единицы печатаются целиком (норма: вывод на агрегате до вскрытия единиц запрещён).""" +import json +import unicodedata +from pathlib import Path + +HERE = Path(__file__).resolve().parent +GOLD = [json.loads(l) for l in open(HERE / "gold" / "gold.jsonl", encoding="utf-8")] + + +def ntgt(s: str) -> str: + s = unicodedata.normalize("NFKC", s or "").casefold().replace("ё", "е") + for ch in "«»\"'": + s = s.replace(ch, "") + return " ".join(s.split()) + + +def eq(a: str, b: str) -> bool: + return ntgt(a) == ntgt(b) and ntgt(a) != "" + + +inb = [r for r in GOLD if r["in_bank"]] +print(f"голд в банке: {len(inb)} (из 53 approved)") + +p0_ok, p1_ok = [], [] +p0_none = [] +for r in inb: + variants = r.get("variants") or [] + p0 = variants[0][0] if variants else "" + if not p0: + p0_none.append(r["src"]) + r["_p0"] = p0 + if eq(p0, r["gold_dst"]): + p0_ok.append(r["src"]) + if eq(r.get("bank_dst", ""), r["gold_dst"]): + p1_ok.append(r["src"]) + +print(f"P0 (топ §C2-3 из вариантов черновиков) == gold: {len(p0_ok)}/{len(inb)} (термов без вариантов: {len(p0_none)}: {p0_none})") +print(f"P1 (сведённый dst терминолога coldrun-a) == gold: {len(p1_ok)}/{len(inb)}") + +# парное сравнение P1 vs P0 +p1_not_p0 = [r["src"] for r in inb if eq(r.get("bank_dst", ""), r["gold_dst"]) and not eq(r["_p0"], r["gold_dst"])] +p0_not_p1 = [r["src"] for r in inb if not eq(r.get("bank_dst", ""), r["gold_dst"]) and eq(r["_p0"], r["gold_dst"])] +print(f"P1-прав-P0-неправ: {len(p1_not_p0)} {p1_not_p0}") +print(f"P0-прав-P1-неправ: {len(p0_not_p1)} {p0_not_p1}") + +print("\n=== ЕДИНИЦЫ: промахи P1 (bank_dst != gold) с классом ===") +for r in inb: + if eq(r.get("bank_dst", ""), r["gold_dst"]): + continue + cls = "конвенция-古月" if r["src"].startswith("古月") and "гу юэ" in ntgt(r.get("bank_dst", "")) else "" + if not cls and r.get("bank_dst") and ntgt(r["bank_dst"]).replace(" ", "").replace("-", "") == ntgt(r["gold_dst"]).replace(" ", "").replace("-", ""): + cls = "орфография (дефис/слитно)" + print(f" {r['src']}: gold={r['gold_dst']!r} bank={r.get('bank_dst','')!r} p0={r['_p0']!r} spread={r.get('spread')} {('['+cls+']') if cls else ''}") + +print("\n=== ЕДИНИЦЫ: было ли верное в вариантах, когда P1 промахнулся ===") +n_had = 0 +for r in inb: + if eq(r.get("bank_dst", ""), r["gold_dst"]): + continue + had = any(eq(v[0], r["gold_dst"]) for v in (r.get("variants") or [])) + n_had += had + print(f" {r['src']}: gold-в-вариантах={'ДА' if had else 'нет'} variants={[v[0] for v in (r.get('variants') or [])][:6]}") +print(f"промахов P1 с верным ответом, ЛЕЖАВШИМ в вариантах: {n_had}") diff --git a/eval/bank_arbitration/value_demo.py b/eval/bank_arbitration/value_demo.py new file mode 100644 index 00000000..9627ea47 --- /dev/null +++ b/eval/bank_arbitration/value_demo.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 +"""$0-демо ценности рекомендаций §D корзины 1 на ЖИВОМ банке coldrun-a (вопрос владельца 04.08 +«насколько алгоритмы лучше текущего»): + A4: intra-run конфликты consolidated×consolidated (containment + лексемный subset — реплика + CanonConflicts/lexemeSubset из terminology.go) — сколько противоречий сегодня НЕ видит никто; + A5: сдвиг ЧАСТОТНОГО топа вариантов при фолде голосов по нормализованной форме. +""" +import unicodedata +from pathlib import Path +import sys + +sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "bank_autonomy")) +from parse_common import parse_bankstop # noqa: E402 + +STEM_MIN, SLACK = 3, 2 # stemMinPrefix / stemSuffixSlack (terminology.go:379-386) + + +def norm(s): + s = unicodedata.normalize("NFKC", s or "").casefold().replace("ё", "е") + for ch in "«»\"'": + s = s.replace(ch, "") + return " ".join(s.split()) + + +def words(s): + return [w for w in "".join(c if c.isalnum() else " " for c in norm(s)).split() if len(w) > 1] + + +def same_lexeme(a, b): + if a == b: + return True + n = 0 + while n < len(a) and n < len(b) and a[n] == b[n]: + n += 1 + shorter = min(len(a), len(b)) + if (n == len(a) or n == len(b)) and shorter >= STEM_MIN: + return True + return n >= max(shorter - SLACK, STEM_MIN) + + +def lexeme_subset(need, have): + return all(any(same_lexeme(w, h) for h in have) for w in need) if need else True + + +def a4_conflicts(): + bs = parse_bankstop() + finals = {s: r["dst"] for s, r in bs.items() if r.get("dst") and r["dst"] != "—"} + out = [] + for a, da in finals.items(): + for b, db in finals.items(): + if a == b or b not in a: # b строго содержится в a (containment, как CanonConflicts) + continue + if not lexeme_subset(words(db), words(da)): + out.append((a, da, b, db)) + print(f"A4-демо: финалов с dst {len(finals)}; НЕВИДИМЫХ сегодня внутри-прогонных противоречий " + f"(составной терм теряет перевод вложенного): {len(out)}") + for a, da, b, db in sorted(out): + print(f" {a}→{da!r} не несёт {b}→{db!r}") + + +def a5_topshift(): + bs = parse_bankstop() + shifted = [] + for s, r in bs.items(): + vs = r.get("drafts") or [] + if len(vs) < 2: + continue + raw_top, raw_top_n = vs[0][0], vs[0][1] # порядок §C2-3 (частота — главный фактор при пустом каноне) + folded = {} + for d, n in vs: + folded[norm(d)] = folded.get(norm(d), 0) + n + fold_top = max(folded, key=lambda k: (folded[k], k)) + # ЧЕСТНЫЙ сдвиг: слитые голоса ОБОГНАЛИ сырой топ (строго больше). Равенство после фолда — + # тай-брейк, не эффект нормализации (ловушка первой версии этого скрипта — поймана самопроверкой). + if norm(raw_top) != fold_top and folded[fold_top] > raw_top_n: + shifted.append((s, raw_top, fold_top, vs)) + print(f"\nA5-демо: строк со spread>=2: {sum(1 for r in bs.values() if len(r.get('drafts') or [])>=2)}; " + f"частотный топ ЧЕСТНО сдвигается нормализованным фолдом (слитые голоса обогнали сырой топ) у: {len(shifted)}") + for s, rt, ft, vs in sorted(shifted): + print(f" {s}: сырой топ {rt!r} → фолднутый {ft!r} ({' | '.join(f'{d}×{n}' for d,n in vs[:5])})") + + +if __name__ == "__main__": + a4_conflicts() + a5_topshift()