diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md
index 9a9893b4..10f1f94c 100644
--- a/docs/PROGRESS.md
+++ b/docs/PROGRESS.md
@@ -1,9 +1,9 @@
# Журнал прогресса
-> **⟶ ТЕКУЩЕЕ СОСТОЯНИЕ** (на 2026-08-01, голова D39.64). **Источник истины по РЕШЕНИЯМ — `architecture/05-decisions-log.md` (D1–D39.64); этот файл — ЖУРНАЛ.**
+> **⟶ ТЕКУЩЕЕ СОСТОЯНИЕ** (на 2026-08-01, голова D39.65). **Источник истины по РЕШЕНИЯМ — `architecture/05-decisions-log.md` (D1–D39.65); этот файл — ЖУРНАЛ.**
> - **Сделано (сводно; детали — 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–64): ОБЩНОСТЬ → АВТОНОМНОСТЬ БАНКА.** Бэкенд-ветка параллели ЗАКРЫТА: фаза 2 общности принята и залендена (D39.64; 9 флагов §5 — очередь владельца, строка 14). Полигон-ветка: $0-сырьё арки банка отработано — **отчёт в дереве, приёмка ПО РЕЛЕЮ владельца** (промт `POLYGON_BANK_RAWMATERIAL_SESSION_PROMPT.md` активен до приёмки). ⚠ **DeepSeek-V4-Flash-0731: веса сменились под слагом — боевая черновая форма покупает пустые ответы; платные прогоны СТОП до ре-пробы (строка 74; оперативно «(в) ждём», D39.63). Перекупок на этой фазе нет — стендовый корпус одноразовый (D39.63).**
-> - **Горизонт (D39.62 «планировать подальше»):** приёмка полигон-сырья (по релею) → дизайн арки АВТОНОМНОСТИ банка (оркестратор: веб-фетч пере-замер под АВТОНОМНЫМ критерием + 36а/36б/36в + Decl-шов/27) → ре-проба flash → СВЕЖИЙ мини-прогон на новом стеке (оси голоса 16/24 · авто-режим · довесок: итерация №2 редакторов D39.22) → свип гипотез качества (рубрика K1–K12 + размеченный стенд пакета-6) → добор идеала → ВТОРАЯ ПАРА живьём (ja→ru; гейтит П5-майнер и §0 фактом) → МАСШТАБ (7,78 млн симв., ~2284 раздела) → пилот Ф2.5 (судья; строка 6 ToS) → Ф3 ридер-IDE (строки 69–71). **Стоячие:** ToS-триггер 25.10 · Ш-2 трипваер до go1.27 · строка 74 перед любым платным прогоном.
+> - **Курс (D39.59–65): ОБЩНОСТЬ ✅ → АВТОНОМНОСТЬ БАНКА (сейчас).** Обе ветки параллели ЗАКРЫТЫ: фаза 2 общности (D39.64; 9 флагов §5 — строка 14) и полигон-сырьё+пробы арки банка (D39.65; строки 21/22 закрыты, 36а/36в с проверенными фиксами, Decl 142/142 null, веса §C2-3 не тюнить). **Текущий шаг = дизайн-пак арки автономности банка (оркестратор, строка 73 — вход собран).** ⚠ **DeepSeek-V4-Flash-0731: веса сменились под слагом — боевая черновая форма покупает пустые ответы; платные прогоны СТОП до ре-пробы (строка 74; оперативно «(в) ждём», D39.63). Перекупок на этой фазе нет — стендовый корпус одноразовый (D39.63).**
+> - **Горизонт (D39.62 «планировать подальше»):** дизайн арки АВТОНОМНОСТИ банка (оркестратор: серия-батчинг · тип-пере-вывод · Decl-шов/27 · 36б · веб-фетч пере-замер под АВТОНОМНЫМ критерием) → ре-проба flash → СВЕЖИЙ мини-прогон на новом стеке (оси голоса 16/24 · авто-режим · довесок: итерация №2 редакторов D39.22) → свип гипотез качества (рубрика K1–K12 + размеченный стенд пакета-6) → добор идеала → ВТОРАЯ ПАРА живьём (ja→ru; гейтит П5-майнер и §0 фактом) → МАСШТАБ (7,78 млн симв., ~2284 раздела) → пилот Ф2.5 (судья; строка 6 ToS) → Ф3 ридер-IDE (строки 69–71). **Стоячие:** ToS-триггер 25.10 · Ш-2 трипваер до go1.27 · строка 74 перед любым платным прогоном.
> - **Стек:** draft deepseek-v4-flash thinking-ON (+банкнота) **⚠0731** → терминолог (та же модель, батчи, экран `target_script`) → editor deepseek-v4-pro БИЛИНГВ ИНТЕРИМ (вендором НЕ тронут; glm-5 резерв) → судья gemini (Ф2, полигон); канал B Mistral+grok; ~$0.85/ранобэ (D30.4) — пере-калибровка после развилки 74.
> - **ЕДИНЫЙ БЭКЛОГ — секция «Бэклог» ниже** (одна таблица, единственный трекер; каждая петля обязана иметь диспозицию: решено / отложено-с-записью / отклонено; ведёт оркестратор).
> - Архивы хроники: `archive/PROGRESS-2026-07-04-10.md` (D31) · `-10-13` (D39.6-гигиена) · `-13-25` (стройка паков 11–16, rerun2) · **`-25-31` (паки 17–20 · мини-прогон · полигон-пакеты 5–8 · ToS · холодный прогон; D39.26–58)**. Записи ниже — живой хвост (эра D39.59+).
@@ -32,12 +32,10 @@
| **— ХВОСТЫ ХОЛОДНОГО ПРОГОНА (исполнен достаточно, D39.58; Р7 владельца) —** | | | | | |
| 16 | Полная цена холодного старта: edit-волна не гонялась (Р7); измерено всё ДО редактуры (драфт+банкнота $0.0247/волна · терминолог $0.006–0.013/проход) | бэкенд | когда-нибудь (следующий живой прогон) | следующий прогон | D39.58 |
| 18 | `蛊` не приходит НИ ОДНИМ каналом (модель объявляет составные, майнер режет по длине) — структурная дыра эмиссии на голове частотного понятия; доставка подписанной короткой строки проверена $0-пином; третий сайт того же порога — алиас-канал `miner_alias.go:44,93` (D39.60) | бэкенд | когда-нибудь | отдельное решение (рядом с 36а) | D39.58, D39.60 |
-| 21 | Пере-замер P1 consistency — сырьё снято холодным прогоном (4 сэмпла, 150 термов, без цензуры), метод полигонский | полигон | скоро | полигон-пакет | D39.52, D39.58 |
-| 22 | Пере-мер весов консолидации §C2-3 при n≥2 — сырьё то же | полигон | скоро | полигон-пакет | D39.45, D39.58 |
| 24 | Остаток: авто-режим флага (проект Б не гонялся) · оси голоса A–D (профили не подписаны; черновик готов — `coldrun-a/SIGN-PACKAGE.md` §3) | бэкенд | когда-нибудь (следующий живой прогон) | следующий прогон | D39.40, D39.58 |
| **— ТЕКУЩАЯ ОЧЕРЕДЬ (D39.59) —** | | | | | |
-| 73 | Арка АВТОНОМНОСТИ банка (курс владельца: подпись опциональна): пере-замер веб-фетча под АВТОНОМНЫМ критерием (пакет-7 мерил не то — аддитив к KWIC против подписи) + механизмы 36а/36б/36в + Decl-шов (майненая сторона не пишет склонённых форм — пост-чек не примет 149 авто-строк; D39.60, бывший дефект #9 пака-21) + Р3-остаток; дизайн после ответов по общности | бэкенд/полигон | скоро | дизайн-арка → ратификация | D39.59, D39.60 |
-| 74 | ⚠ **DeepSeek-V4-Flash-0731: боевая черновая форма покупает пустые ответы — блокер ПЛАТНЫХ прогонов.** Оперативное состояние = «(в) ждать» (D39.63; фаза-2 всё равно $0-код). Перед следующим платным прогоном — ре-проба flash за копейки → если не устаканилось, выбор: (а) флор 16000 (сдвиг request_hash безболезнен — перекупок на этой фазе нет; хвост не закрывает, упор 2/5) или (б) слать `reasoning_effort` явно (вендорская модель, дешевле ~22%; но амендмент `echoMineViolation`, эхо ~6% и качество черновика при `low` не судилось — нужен замер ~$0.05; тогда же предмет для постинструкции/префилла); включение ручки #77 (ре-ген эха перед эскалацией, построена D39.64, дефолт 0) — тем же решением; при включении помнить общий счётчик attempt с length-ре-геном + рост `maxTokensForAttempt` | владелец (по ре-пробе) | перед следующим платным прогоном | ре-проба → решение | D39.61, D39.63, D39.64, POLYGON §12.4 |
+| 73 | Арка АВТОНОМНОСТИ банка — ВХОД СОБРАН (D39.65: 21/22 закрыты, 36а/36в с проверенными фиксами, Decl 142/142 null, веса §C2-3 не тюнить — рычаг в контекстах/серии): дизайн-пак оркестратора = серия-батчинг по морфеме · тип-пере-вывод · Decl-шов (терминолог эмитит формы / морфопроход) · 36б второе мнение · Р3-остаток (сокращённая форма, строка 27) · пере-замер веб-фетча под АВТОНОМНЫМ критерием; заметка: first-occurrence-тест KWIC-консолидатора — кандидат $0-захода | оркестратор → бэкенд | блокер-очереди (следующий шаг) | дизайн-арка → ратификация | D39.59, D39.60, D39.65 |
+| 74 | ⚠ **DeepSeek-V4-Flash-0731: боевая черновая форма покупает пустые ответы — блокер ПЛАТНЫХ прогонов.** Оперативное состояние = «(в) ждать» (D39.63; фаза-2 всё равно $0-код). Перед следующим платным прогоном — ре-проба flash за копейки → если не устаканилось, выбор: (а) флор 16000 (сдвиг request_hash безболезнен — перекупок на этой фазе нет; хвост не закрывает, упор 2/5) или (б) слать `reasoning_effort` явно (вендорская модель, дешевле ~22%; но амендмент `echoMineViolation`, эхо ~6% и качество черновика при `low` не судилось — нужен замер ~$0.05; тогда же предмет для постинструкции/префилла); включение ручки #77 (ре-ген эха перед эскалацией, построена D39.64, дефолт 0) — тем же решением; при включении помнить общий счётчик attempt с length-ре-геном + рост `maxTokensForAttempt`; ⚠ cap 8000 бьёт и СТАДИЮ ТЕРМИНОЛОГА (reasoning 8063/батч, D39.65) — резолюция обязана накрыть терминолога | владелец (по ре-пробе) | перед следующим платным прогоном | ре-проба → решение | D39.61, D39.63, D39.64, POLYGON §12.4 |
| 78 | Леджер денег = НИЖНЯЯ граница: «2xx body decode failed (call IS billed)» — провайдер списал, исходная попытка в `request_log` НЕ попадает (≤$0.009/сессия); дизайн фикса ГОТОВ (GENERALITY_PHASE2 §5.6: `BilledDecodeFails` + per-billed-attempt settle с `Estimated=true`), но это money/ledger-путь — не $0-хастл | бэкенд | когда-нибудь (money-паком) | отдельное решение (дизайн §5.6) | D39.61, D39.64 |
| 79 | Остаточные Cyrillic-хардкоды пар-гейтед DC-чекеров: `checks/repair.go:131` (трим DC1-спана) · `checks/checkers.go:457,474` (`isCyrLetter` словограница register) — инертны без dc-данных пары, но пара С DC-чекерами и не-ru целью потребует правки Go; кандидат на `c.wordScript` | бэкенд | когда-нибудь (следующий пак цель-оси) | ближайшее касание чекеров | D39.64 |
| **— ПАК-21 «чекеры»: РАСТВОРЁН (D39.62); шестёрка исполнена 2/6 фазой 2 (D39.64: #11 · строка 26), остаток — ниже —** | | | | | |
@@ -57,9 +55,9 @@
| 34а | Экран кодировки не видит `` без XML-объявления (епаб с gb18030-метой прочтётся как UTF-8) — до-паковая дыра, сознательно не тронута пачкой 14а (паритет со старым ридером) | бэкенд | когда-нибудь | отдельное решение | D39.54, SMALLPACK §8 |
| 35 | Не-CJK майнер/банк: en-детектора не существует (hanRuns=0), ja с zh-таблицами активно неверен (0/10); нужен второй ДЕТЕКТОР (прототип `mine_nonhan.py`) + G1–G10 требования generic-майнера (вкл. квадратичность G9 ≈4.6 ч) | бэкенд | когда-нибудь | отдельный пак generic-майнера (с ja→ru) | D39.37(8), D39.43, D39.50 п.8, POLYGON_PREMEASURE §6 |
| 36 | Кластеризация майнера глотает родовые титулы (族长/学堂家老 в кластере 葛家) — закрыто на границе сборки входа, сама кластеризация не чинилась | бэкенд | когда-нибудь | отдельное решение | D39.43, D39.45 |
-| 36а | Валидация поля `type` терма — НЕПРОВЕРЕННАЯ третья колонка черновой модели решает ветку транскрипции (`元石`=name ⇒ «юаньши»; механизм «слишком китаизированно»); дешёвые экраны: сверка с классификатором майнера · экран «name с многословным строчным dst» · требование обоснования от роли | бэкенд | скоро (перед следующим банком) | малый дизайн (Р3, приоритет сессии) | D39.58 |
+| 36а | Валидация поля `type` терма — ПРОМЕРЕНО (D39.65): ненадёжен 12–22%, place ~61%, 2 строгих branch-harm 元石/元海; фикс проверен живьём — сфокусированный классификатор той же моделью чинит 6/6 harm-направления; дизайн-кандидаты: тип-эмиссия терминологом из контекста + $0-экран «name/place с многословным строчным dst» | бэкенд | скоро (вход дизайн-пака 73) | дизайн-пак арки банка | D39.58, D39.65 |
| 36б | Второе мнение по банку: рецензент ДРУГОЙ моделью, несогласия — отдельной колонкой подписной таблицы (судья-с-декоем в роли рецензента; решает владелец, D39.46-ограничение не бьёт) | бэкенд/полигон | когда-нибудь | отдельный дизайн (Р4) | D39.58, D39.51 п.4 |
-| 36в | Консистентность СЕРИЙ термов не обеспечена (甲等→«класс Цзя» при 乙等→«ранг И» — роль не видит серии, батчи режут) | бэкенд | когда-нибудь | с дизайном 36а/36б | D39.58 |
+| 36в | Серийная консистентность — ПРИЧИННО показана граница батча (甲等«класс»/батч-5 vs 乙丙丁等«ранг»/батч-0) и фикс живьём (D39.65): со-батчинг серии = согласованно+детерминированно, серий-зависим (转 no-op); реализация без пар-литералов — кластер по общей исходной морфеме; канон-пин родового слова между книгами — отдельный дизайн | бэкенд | скоро (вход дизайн-пака 73) | дизайн-пак арки банка | D39.58, D39.65 |
| 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 |
@@ -102,6 +100,10 @@
| 69 | Gemini API «под-18» обязательство на конечный продукт (независимо от лейблов) | владелец | когда-нибудь | Ф3 / отдельное решение | D39.32, D39.34(7) |
| 70 | Action-security gate перед выдачей tools/webfetch (D25 п.5) | бэкенд | когда-нибудь | Ф3 | D39.34(7) |
| 71 | Планы research/22: epub-tag-rewrite · Q7-леджер | бэкенд | когда-нибудь | Ф3 | D39.34(7) |
+## Оркестратор №9 + полигон — СЫРЬЁ АРКИ БАНКА + ПРОБЫ ФИКСОВ ПРИНЯТЫ (D39.65), 01.08
+
+Отчёты: [`archive/reports/POLYGON_BANK_RAWMATERIAL_2026-08-01.md`](archive/reports/POLYGON_BANK_RAWMATERIAL_2026-08-01.md) ($0, часть 2 §12.7 корректно пропущена без слова) и [`archive/reports/POLYGON_BANK_PROBES_2026-08-01.md`](archive/reports/POLYGON_BANK_PROBES_2026-08-01.md) ($0.027831/31 вызовов, два пути до 1e-6; ⚠ куплены сверх буквы промта — оговорка в шапке). Приёмка по слову владельца без пере-прогона оркестратора; внутренняя верификация отчётов — пре-регистрация, двойные пути счёта, слепые грейдеры, критик. Итог: строки 21/22 ЗАКРЫТЫ (нестабильность 43.3%; §C2-3 точна, но на холодном решает терминолог по KWIC 50/75 — веса не тюнить) · 36а/36в переведены в «дизайн с проверенными фиксами» (классификатор чинит 6/6 harm; со-батчинг серии детерминированно унифицирует) · Decl 142/142 null · ⚠ cap 8000 бьёт и терминолога — внесено в строку 74. Харнесс `eval/bank_autonomy/` заленден; промт → архив. Следующий шаг курса — дизайн-пак арки автономности банка (строка 73, вход собран).
+
## Оркестратор №9 + бэкенд — ОБЩНОСТЬ ФАЗА 2 ПРИНЯТА И ЗАЛЕНДЕНА (D39.64), 01.08
Отчёт: [`archive/reports/GENERALITY_PHASE2_2026-08-01.md`](archive/reports/GENERALITY_PHASE2_2026-08-01.md) (ревью-шапка). Приёмка исполнением: `-race` 14/14 · майнер-парити EXACT воспроизведён байт-в-байт · 7 приёмочных тестов PASS свежим прогоном · **Ш-1 сверен независимой классификацией диффа голдена (не их маской): 172 строки = ровно 5 осей, вердикт/wire/stage_text — ноль** · адверсариальное 6-агентное ревью — ни одно несущее утверждение не опровергнуто; байт-идентичность манифест-less пака доказана пробой HEAD-vs-дерево (`langpack-v2-a28ed743c99c`). Закрыты строки 72 (обе фазы общности) · 75 (ko-баг) · 76 (эмбед-плоскость) · 77 (ре-ген-ручка, дефолт 0) · 26 (translitInterjections) · 32 (ru-target долг слоя 7). Новые: строка 14 (4 data-флага §5 на подпись) · строка 79 (остаточные Cyrillic-хардкоды DC-чекеров). Ниты отчёта: флагов 9, не «10»; дрейф 4 line-номеров; «ратифицированный тест» segmentation — частично мёртвая ветка (блокер настоящий — контракт держат `pipeline.go:839-848` + голден-фикстура); корпус labels/ для дефектов пака-21 на стенде ЕСТЬ — барьер = утраченный в scratch харнесс. Промт фазы-2 → архив.
@@ -146,6 +148,9 @@ Q1 = П1 цель-шов санкционирован («главное бэке
*(Закрытые записи 25–31.07 — пак-18 · мини-прогон · фикс-пак · сквозная проверка · хендофф 26.07 · ресёрч общности фаза 1 — в [archive/PROGRESS-2026-07-25-31.md](archive/PROGRESS-2026-07-25-31.md).)*
## Полигон
+
+**Сырьё арки банка + пробы фиксов (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 a32bc626..e7edd01a 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -11,17 +11,17 @@
## Структура
-- `architecture/` — синтез. **Источник истины по решениям — [`05-decisions-log.md`](architecture/05-decisions-log.md) (D1–D39.64); при конфликте с любым доком он выше.**
+- `architecture/` — синтез. **Источник истины по решениям — [`05-decisions-log.md`](architecture/05-decisions-log.md) (D1–D39.65); при конфликте с любым доком он выше.**
- `01-decisions.md` — принципы Р1–Р10; `02-mvp-plan.md` — фазы и приёмка (v3, 09.07); `03-implementation-notes.md` — контракты Фазы 0; `04-unhappy-paths.md` — ~70 режимов отказа → механизм; `06-memory-risk-registry.md` — реестр рисков банка памяти; **[`09-target-architecture.md`](architecture/09-target-architecture.md) — целевая 7-слойная архитектура (D39; статус стройки — шапка-таблица; инвариант общности §0.1)** · [`10-prompt-architecture.md`](architecture/10-prompt-architecture.md) — консолидированная промпт-заметка (концерн 4) · [`12-go-style-notes.md`](architecture/12-go-style-notes.md) — норматив общности §0 + Go-ответы. **Исполненные (архив 25.07, санкция владельца, → `archive/architecture/`):** [`07-strategic-review.md`](archive/architecture/07-strategic-review.md) (стратаудит 09.07 — курс исполнен) · [`08-sync-audit-ledger.md`](archive/architecture/08-sync-audit-ledger.md) (ледджер синк-аудита — отработан) · [`11-implementation-plan.md`](archive/architecture/11-implementation-plan.md) (план пака-11 — исполнен целиком); `components.puml`/`pipeline.puml` — диаграммы (перерисованы 25.07 под пост-пак-16 реальность: волновой исполнитель, пакетный сплит пака-15, repair-петля за `enabled:false`, generic content-labels D39.25; владелец смотрит PlantUML-расширением VS Code; вручную НЕ рендерить).
- `experiments/` — эмпирика «Полигона»: `00-provider-quirks` (читать перед любым вызовом провайдера), `01-token-calibration`, `02-refusal-benchmark`, `03-local-stand`, `04-editor-quality`, `06-local-extraction`, `07-coverage-precision`, `08-cost-model-v2` (актуальная денежная модель), `09-pilot-protocol` (пилот Ф2.5 + поправки D13), `10-explicit-benchmark` (18+ violence-рука канала B), `11-erotica-benchmark` (erotica по трём парам/регистрам — закрытие D14.4, D22), `12-quality-diagnosis`/`13-translator-bakeoff`/`14-quality-empirics`/`14b-meaning-battery` (дуга качества «мерить→строить», закрыты → D30/D32/D37/D38), `15-segmentation-empirics` (exp15: когезия под floor-шумом, фертильность — закрыт → D39.7/D39.8), `16-bank-mining` (exp16: WHICH/WHAT банк-майнинга — закрыт → D39.10).
- `research/` — фактура исследований 04–05.07: `01–10` базовые, `11-gap-*` добор критиком, `12-*` режимы отказа/отзывы/таксономии (+ два внешних материала с провенанс-шапками), `13` валидация памяти, `14` адаптивная память, `15` голос и состояние (принят, D21), **`16` ридер-IDE (принят с ревью-шапкой, D29)**, **`17` внешняя критика GPT-5.6 (принят с ревью-шапкой, D25)** — у 16/17 читать шапку прежде тела. **`18` рычаги качества (два отчёта, D36)** · **`19` нарезка+когезия+контракт t/e (D39.1)** · **`20` банк-майнинг W1.5 (D39.6)** · **`21` обзор LLM-транспорта чужих харнессов (23.07: наш транспорт опережает/вровень со всеми 11)** · **`22` доменные харнессы перевода (24.07: калибрующий — ядро подтверждено, впереди COGS/18+/общность/измеренность, позади Q4-выпуск и gate+repair-петля; сиквел `02`/`05`)** — у всех ревью-шапки. ⚠ Часть под superseded-баннерами (01/02/03/04/05/09 и gap-1/2/5) — **читай баннер прежде содержимого**.
- `PROGRESS.md` — **журнал** (CURRENT-STATE сверху, ниже хронология; НЕ источник решений).
-- **Активные хендофф-промты (01.08; всё остальное — в `archive/prompts/` с баннерами-исходами):** [`ORCHESTRATOR_SESSION_PROMPT.md`](ORCHESTRATOR_SESSION_PROMPT.md) (роль/нормы; состояние НЕ дублирует) · [`POLYGON_BANK_RAWMATERIAL_SESSION_PROMPT.md`](POLYGON_BANK_RAWMATERIAL_SESSION_PROMPT.md) (**ТЕКУЩИЙ полигонный**: $0-сырьё арки банка — отработан, отчёт в дереве, приёмка по релею владельца) · [`POLYGON_PACKAGE4_SESSION_PROMPT.md`](POLYGON_PACKAGE4_SESSION_PROMPT.md) (residual-трекер пилота/18+/echo, отложен; P4-хвост из него закрыт D39.61). Закрытые 30.07–01.08 (промты в `archive/prompts/`, отчёты с ревью-шапками в `archive/reports/`): пак-19 «голос/состояние» (D39.54–56) · холодный мини-прогон (D39.58) · ToS-речек (D39.57) · ресёрч общности фаза 1 (D39.60) · полигон Р6+P4 (D39.61) · **фаза 2 общности (D39.64)**.
+- **Активные хендофф-промты (01.08; всё остальное — в `archive/prompts/` с баннерами-исходами):** [`ORCHESTRATOR_SESSION_PROMPT.md`](ORCHESTRATOR_SESSION_PROMPT.md) (роль/нормы; состояние НЕ дублирует) · [`POLYGON_PACKAGE4_SESSION_PROMPT.md`](POLYGON_PACKAGE4_SESSION_PROMPT.md) (residual-трекер пилота/18+/echo, отложен; P4-хвост из него закрыт D39.61). Закрытые 30.07–01.08 (промты в `archive/prompts/`, отчёты с ревью-шапками в `archive/reports/`): пак-19 «голос/состояние» (D39.54–56) · холодный мини-прогон (D39.58) · ToS-речек (D39.57) · ресёрч общности фаза 1 (D39.60) · полигон Р6+P4 (D39.61) · **фаза 2 общности (D39.64)** · **полигон «сырьё арки банка»+пробы (D39.65)**.
- `archive/` — `prompts/`: закрытые сессионные промты (только история, инструкции оттуда не исполнять) · `reports/`: отчёты паков/ресёрч-сессий с ревью-шапками (живая фактура приёмок — на них ссылаются D-лог и активные промты) · `architecture/`: исполненные арх-доки (07 стратревью · 08 синк-ледджер · 11 план пака-11) · четыре слайса хроники `PROGRESS-2026-07-{04-10,10-13,13-25,25-31}.md`.
-## Статус (2026-08-01, голова D39.64 — эра «общность → автономность банка»)
+## Статус (2026-08-01, голова D39.65 — эра «общность → автономность банка»)
-Полная карта состояния НЕ здесь: фазы/курс/очередь/горизонт — в шапке [`PROGRESS.md`](PROGRESS.md) (CURRENT-STATE + единый бэклог), решения — в [`architecture/05-decisions-log.md`](architecture/05-decisions-log.md) (карта актуальности; свежая голова — с хвоста файла). Коротко: Ф0/Ф1 ✅ · арх-ресет D39 (паки 11–16) ✅ · паки 17–20 ✅ · мини-прогон и холодный прогон приняты (D39.37/58) · карта языковой привязки движка снята (D39.60: книго-ось чиста; ja→ru безопасна без правки Go, en→ru — нет) · Р1–Р4 закрыты (D39.63) · пак-21 растворён (D39.62) · **фаза 2 общности принята (D39.64: цель/скрипт-швы по данным, эмбед-хеш, манифест-по-каналам; голден вердикт-нейтрален)**. Полигон-ветка: $0-сырьё арки банка отработано — отчёт в дереве, приёмка по релею владельца. ⚠ DeepSeek-0731 сменил веса под слагом — платные прогоны СТОП до ре-пробы (бэклог-строка 74). Дальше: приёмка полигон-сырья → арка автономности банка → свежий мини-прогон → свип гипотез → добор идеала → вторая пара (ja→ru) → МАСШТАБ → пилот Ф2.5 → Ф3 ридер-IDE.
+Полная карта состояния НЕ здесь: фазы/курс/очередь/горизонт — в шапке [`PROGRESS.md`](PROGRESS.md) (CURRENT-STATE + единый бэклог), решения — в [`architecture/05-decisions-log.md`](architecture/05-decisions-log.md) (карта актуальности; свежая голова — с хвоста файла). Коротко: Ф0/Ф1 ✅ · арх-ресет D39 (паки 11–16) ✅ · паки 17–20 ✅ · мини-прогон и холодный прогон приняты (D39.37/58) · карта языковой привязки движка снята (D39.60: книго-ось чиста; ja→ru безопасна без правки Go, en→ru — нет) · Р1–Р4 закрыты (D39.63) · пак-21 растворён (D39.62) · **фаза 2 общности принята (D39.64: цель/скрипт-швы по данным, эмбед-хеш, манифест-по-каналам; голден вердикт-нейтрален)**. Полигон-ветка закрыта D39.65 (строки 21/22, фиксы 36а/36в проверены живьём). Текущий шаг — дизайн-пак арки автономности банка (оркестратор). ⚠ DeepSeek-0731 сменил веса под слагом — платные прогоны СТОП до ре-пробы (бэклог-строка 74). Дальше: арка автономности банка → свежий мини-прогон → свип гипотез → добор идеала → вторая пара (ja→ru) → МАСШТАБ → пилот Ф2.5 → Ф3 ридер-IDE.
## Доступные ключи от моделей
DEEPSEEK_API_KEY, ZAI_API_KEY, KIMI_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, XAI_API_KEY, MISTRAL_API_KEY
diff --git a/docs/architecture/05-decisions-log.md b/docs/architecture/05-decisions-log.md
index 49c02e00..1d90fbfd 100644
--- a/docs/architecture/05-decisions-log.md
+++ b/docs/architecture/05-decisions-log.md
@@ -1,4 +1,4 @@
-# Журнал решений оркестратора — контракт D1–D39.64 (развязки 04.07 · пакеты 09–10.07 · приёмка/качество-первым/пивот/эмпирика 11–12.07 · арх-ресет+стройка пере-прогонного стека 13–19.07)
+# Журнал решений оркестратора — контракт D1–D39.65 (развязки 04.07 · пакеты 09–10.07 · приёмка/качество-первым/пивот/эмпирика 11–12.07 · арх-ресет+стройка пере-прогонного стека 13–19.07)
> **⟶ КАРТА АКТУАЛЬНОСТИ (ревизия D31, продлена до D38.2 [12.07]; исторические записи ниже НЕ переписываются — дисциплина D23.3).** Читая контракт целиком, держи под рукой, что чем перекрыто:
> ⚠ **Навигация (актуализация 01.08):** карта ниже детально покрывает D1–D39.28; решения D39.29–63 живут хронологически в теле файла, **свежая голова — С ХВОСТА** (новые ноты аппендятся вниз). Сводка текущей головы и очередь — CURRENT-STATE в `../PROGRESS.md`.
@@ -167,7 +167,7 @@ grok-4.3 теперь дефолт-редактор → **каждый чанк
# Пост-ревью решения D13–D17 + D18–D21 (2026-07-09, оркестратор)
-Ратификация выводов стратегического ревью [`07-strategic-review.md`](07-strategic-review.md) (метод: 14 сборщиков + 9 адверсариальных верификаторов, 8 CONFIRMED / 1 PARTIAL). Владелец подтвердил курс 09.07 (вкл. «Rust — нет, не сейчас»: Р1/Go остаётся; вопрос закрыт до пост-пилота и требует конкретного триггера, где Go упирается). Каждое решение ниже — контракт для следующих сессий «Бэкенд»/«Полигон»; хендофф-промты выдаёт оркестратор.
+Ратификация выводов стратегического ревью [`07-strategic-review.md`](../archive/architecture/07-strategic-review.md) (метод: 14 сборщиков + 9 адверсариальных верификаторов, 8 CONFIRMED / 1 PARTIAL). Владелец подтвердил курс 09.07 (вкл. «Rust — нет, не сейчас»: Р1/Go остаётся; вопрос закрыт до пост-пилота и требует конкретного триггера, где Go упирается). Каждое решение ниже — контракт для следующих сессий «Бэкенд»/«Полигон»; хендофф-промты выдаёт оркестратор.
## D13. Пилот Ф2.5 — поправки протокола (гейтят валидность главного решения). ✅
@@ -1203,3 +1203,5 @@ API-529-долг закрыт: 8-осевой refute-by-default воркфлоу
## D39.63 — Р2/Р4 ОТВЕЧЕНЫ + ФИГУРА RESNAPSHOT РАСТВОРЕНА ПОСЫЛКОЙ ВЛАДЕЛЬЦА (01.08): **(1) Р2 = ЗНАЧЕНИЕ**: контракт семейства детекторов единиц/шкал (DC1-часы · магнитуды 万/億 · 成-доли · любой пересчёт) — жёсткий флаг ТОЛЬКО за неверное ЗНАЧЕНИЕ; неконвертированная в единицы читателя форма = мягкий счётчик/линт, НЕ дефект (согласуется с precision 1.000 против 0.167 разметки пакета-6); контракт передан фазе-2 промтом; **(2) Р4 — норма подтверждена** («Ладно»): у правила бывает потолок полноты by construction, записывается в контракт правила, «неразрешимая речь/мысль» не дефект и поклассово не переспрашивается ⇒ **строка 1 (Р1–Р4) ЗАКРЫТА ЦЕЛИКОМ** (Р1 расщеплён D39.60, Р3 закрыт D39.44 Q4); **(3) владелец оспорил посылку «один общий resnapshot» — и ПРАВ для текущей фазы**: боевых книг в полёте нет, стендовый корпус ОДНОРАЗОВЫЙ (старые БД остаются читаемым $0-сырьём, перекупать их не для чего), каждый следующий замер — СВЕЖИЙ мини-прогон на новом стеке ⇒ фигура D39.60 п.(2) вырождается в дисциплину секвенирования: платных замеров не покупать, пока фаза-2 не залендена (иначе меряем вчерашний стек); механика `--resnapshot`/условных фолдов/П0-хеширования остаётся и строится — она про эру боевых книг после МАСШТАБА; побочное упрощение: данные-правки (шестёрка · #8 两 · класс speech-cue) на этой фазе перестают быть «дорогими»; **(4) развилка 74 — оперативное состояние «(в) ждать» по умолчанию**: платных прогонов до конца фазы-2 нет; перед следующим платным прогоном — ре-проба flash за копейки, довесок того же прогона — итерация №2 редакторов (D39.22); **(5) само-ревью выданных промтов по вопросу владельца — три дыры найдены и закрыты правками**: контракт Р2 вписан бэкенду · заметка о параллельной сессии и заморозке бинаря — обоим · карта чтения — полигону; параллельный запуск двух сессий подтверждён безопасным (зоны и артефакты не пересекаются) (01.08, оркестратор №9). ✅
## D39.64 — ОБЩНОСТЬ ФАЗА 2 ПРИНЯТА И ЗАЛЕНДЕНА ($0 — ноль платных вызовов, `--resnapshot` НЕ запускался; приёмка исполнением + адверсариальное 6-агентное ревью оркестратора: ни одно несущее утверждение отчёта не опровергнуто): построено **П0** — `lang.EmbeddedVersion()` (sha256 эмбед-данных, framing как у `Load`) БЕЗУСЛОВНЫМ фолдом в снапшот, дыра эмбед-плоскости ЗАКРЫТА (строка 76; мутационный тест: байт `target-ru.txt`/`injection.txt` = громкий resnapshot); **П1 цель-шов слоя 7 по данным** — `isRuTarget`×6 УДАЛЁН → `TargetActive()`/`TargetScriptNonLatin()`, токенизатор цели `TokenizeScript` с алфавитом из `word_script` данных + Mn-фолд U+0301 (#11 закрыт) = ЕДИНЫЙ шов линт↔репэйр (долг `repair.go` РЕПЭЙНУТ), `ExportNormalize`-гейт (7 сайтов), `ruSanitizer`→per-run поля `Checkers`, реестр целей из эмбед-файлов; книга `target_lang: en` инертна ПО ОТСУТСТВИЮ данных (мут.тест) — строка 32 ЗАКРЫТА; **П2 скрипт-шов источника** — `cjkShare`→`sourceScriptShare` по ОБЪЯВЛЕННОМУ письму (новый `lang-script.txt` + единый реестр `scriptRanges`), Hangul в CJK-leak: живой баг ko ЗАКРЫТ (строка 75), en/ko-эхо больше не слепые (вердикт-вокабуляр `cjk_artifact` сохранён); **П3** — 話-глава данными · sourceAbbrevs по языку книги · generic-детект глав без units («Chapter 12») · sizing-таксономия в ОДНОМ доме (`text.DenseScript`); **П4** — табличные опц-файлы + манифест-по-каналам: источник без пиньинь-морфологии грузится без Palladius-файлов, манифест-less пак БАЙТ-ИДЕНТИЧЕН (`langpack-v2-a28ed743c99c` — независимая проба оркестратора HEAD-vs-дерево), `packAlgoVersion` НЕ бампался — самый жёсткий блокер слоя данных СНЯТ; **шестёрка 2/6** — #11 + `translitInterjections`→данные (строка 26 закрыта); **#77** — ручка `RegenerateEchoBeforeEscalate` (дефолт 0 = байт-в-байт текущее поведение; гейт D19.2 не тронут; включение — решением при ре-пробе 74; при включении помнить: общий счётчик attempt с length-ре-геном + рост `maxTokensForAttempt` на каждом ре-гене). Верификация оркестратора: `-race` 14/14 · **Ш-1 НЕЗАВИСИМОЙ классификацией диффа голдена: 172 строки = ровно 5 осей** (`embedded_version` НОВАЯ · cheapgate-v6 · sanitizer-v7-hangul-leak · classify-v2 · chunker-v6; content_hash/disp/wire-тела/stage_text — 0) · майнер-парити EXACT (`n=13618`, катастрофы точны, recall 0.9655) · перекупок НЕТ (D39.63). Приёмочный критерий «пара, которой нет в репо, проходит слой без правки Go» ДЕРЖИТСЯ для П0/П1/П2/П4 + generic-П3 (свип: новых языковых ветвлений диф не внёс; остатки = документированные ru-дефолт-обёртки + флаги). **9 флагов §5 (не «10» — off-by-one) — очередь владельца (строка 14):** ё-фолд→данные (вердикт-несущий банк, сдвиг `memory_version`) · segmentation-фолбэк громким (ломает контракт corridor-фолбэка — `pipeline.go:839-848` + голден-фикстура на нём) · Fertility-map (калибровка ждёт боевого токенизатора) · encoding-реестр · 4 дефекта пака-21 → пакет-чекеров при свежем мини-прогоне (корпус `labels/` на стенде ЕСТЬ — барьер = утраченный в scratch харнесс) · #78 money-путь (дизайн §5.6 готов, не $0-хастл — строка 78 остаётся). Новая строка 79: остаточные Cyrillic-хардкоды пар-гейтед DC-чекеров (`checks/repair.go:131` · `checkers.go:457,474`) — инертны без dc-данных пары, кандидат на `c.wordScript`. Строки 72 · 75 · 76 · 77 · 26 · 32 ЗАКРЫТЫ (01.08, оркестратор №9). ✅
+
+## D39.65 — ПОЛИГОН «$0-СЫРЬЁ АРКИ БАНКА» + ПЛАТНЫЕ ПРОБЫ ФИКСОВ ПРИНЯТЫ (по слову владельца без пере-прогона оркестратора — «всё уже прогнано»; внутренняя верификация отчётов: пре-регистрация до вскрытия · каждый агрегат двумя независимыми путями CONFIRM до цифры · два слепых грейдера · критик полноты с 11 вправленными пере-натяжками): отчёты `POLYGON_BANK_RAWMATERIAL_2026-08-01.md` (часть 1, $0; якорь целостности `spend ≡ Σ checkpoints = $0.126068` сошёлся с D39.58) и `POLYGON_BANK_PROBES_2026-08-01.md` (**$0.027831 / 31 вызовов, два пути до 1e-6; ⚠ куплены СВЕРХ буквы промта** — часть 2 §12.7 корректно пропущена без слова, но этот проб-пакет самоназначен с потолком $0.10; статус слова владельца зафиксирован при релее). **РАТИФИЦИРОВАННЫЕ ФАКТЫ (вход дизайн-пака арки автономности банка, строка 73):** (1) **строка 21 ЗАКРЫТА** — консистентность P1 терминолога: нестабильность **43.3%** (n≥2=127; 12 из 55 = ОДИН сдвиг конвенции 古月 «Гуюэ»→«Гу Юэ»); проходы ВЛОЖЕНЫ (75⊆127⊆150, 0 отсева) ⇒ чистая ре-выборка при фиксированном входе этим сырьём НЕ изолируема; смена батча — умеренная ассоциация (OR 2.56, p=0.041), НЕ драйвер; ЧИЩЕ и без мульти-проходности: ФИНАЛЬНЫЙ банк серийно несогласован — 甲等→«класс» (батч 5) vs 乙丙丁等→«ранг» (батч 0), причинно на границе батча ⇒ механизм 36в; (2) **строка 22 ЗАКРЫТА** — §C2-3 ведёт себя ТОЧНО как ратифицирована (term-топ==частота 43/43, 0 нулевых score), НО НИЗКИЙ РЫЧАГ НА ХОЛОДНОМ (neighbour структурно мёртв на пустом каноне, conform N/A для term-тяжёлого банка; сработал 2/23 и только на ничьих): фактический консолидатор = ТЕРМИНОЛОГ ПО KWIC — финал ≠ §C2-3-топ в **50/75 (66.7%)**, сочинено вне drafts 10–15/75 (образец: 转-серия «оборот»→«ранг» ×7 единообразно); COLD-START-скоуп оговорён, на тёплом каноне не переносится; ⇒ **весá §C2-3 для холодного/автономного банка НЕ тюнить** — рычаг в контекстах и серия-осознанности роли; «эффективный консолидатор» ≠ «верный» (качество переопределений не судилось); (3) **36а промерен**: `type` ненадёжен **12–22%** (place ~61% — самый шумный; term 0/95 — не путается никогда; направление = нарицательное→ошибочно имя), **2 строгих branch-harm** «слишком китаизированно» (元石→юаньши, 元海→Юаньхай — реалии мис-типированы name→транслит; до 9 широких), защита сегодня = ХРУПКОЕ контекст-переопределение роли; проба фикса: **сфокусированный классификатор той же моделью чинит 6/6 harm-направления** (+~10 п.п. к базлайну «верить draft-типу» 68.4%); (4) **36в подтверждён живьём**: со-батчинг серии в ОДИН вызов даёт согласованное + ДЕТЕРМИНИРОВАННОЕ родовое слово (等: 3 варианта порознь → 1 вместе; экстраполяция 丁=«четвёртый» вне всех drafts) и серий-зависим (转 no-op); реализация без пар-литералов — кластер по общей исходной морфеме; (5) **Decl: 142/142 null** — холодный банк без единой формы склонения, E1/E2 без входа (шов в 73); (6) утечка алфавита 0/150 и «слишком китаизированно» — РАЗНЫЕ поверхности отказа: закрытие первой не закрывает вторую; (7) ⚠ **ИНФРА-МИНА: cap 8000 бьёт и СТАДИЮ ТЕРМИНОЛОГА на 0731** (reasoning 8063 на батч при finish=stop на cap 16000) — резолюция развилки 74 ОБЯЗАНА накрыть терминолога (внесено в строку 74); (8) кандидат следующего $0-захода — first-occurrence-тест KWIC-консолидатора (позитивное обоснование вместо вывода-по-исключению; в заметки 73). Харнесс `eval/bank_autonomy/` заленден; строки 21/22 закрыты; 36а/36в переведены со статуса «замерить» на «дизайн с проверенными кандидатами» (01.08, оркестратор №9). ✅
diff --git a/docs/POLYGON_BANK_RAWMATERIAL_SESSION_PROMPT.md b/docs/archive/prompts/POLYGON_BANK_RAWMATERIAL_SESSION_PROMPT.md
similarity index 88%
rename from docs/POLYGON_BANK_RAWMATERIAL_SESSION_PROMPT.md
rename to docs/archive/prompts/POLYGON_BANK_RAWMATERIAL_SESSION_PROMPT.md
index 2a921cbe..642a7f54 100644
--- a/docs/POLYGON_BANK_RAWMATERIAL_SESSION_PROMPT.md
+++ b/docs/archive/prompts/POLYGON_BANK_RAWMATERIAL_SESSION_PROMPT.md
@@ -1,5 +1,7 @@
# Промт полигон-сессии: $0-сырьё для арки автономности банка (строки 21/22 + аудит типов 36а)
+> **⚠ АРХИВ (01.08.2026): исполнен и ПРИНЯТ — D39.65.** Часть 1 ($0) исполнена целиком; часть 2 (§12.7) корректно пропущена без слова владельца; сверх промта куплены wire-пробы фиксов 36в/36а ($0.027831 — оговорка санкции в шапке отчёта проб). Отчёты: [`archive/reports/POLYGON_BANK_RAWMATERIAL_2026-08-01.md`](../reports/POLYGON_BANK_RAWMATERIAL_2026-08-01.md) · [`archive/reports/POLYGON_BANK_PROBES_2026-08-01.md`](../reports/POLYGON_BANK_PROBES_2026-08-01.md). Инструкции отсюда НЕ исполнять.
+
**Выдан 01.08.2026, оркестратор №9.** Зона: `eval/` + `docs/experiments/`. Назначение: три замера на УЖЕ ОПЛАЧЕННОМ сырье холодного прогона (`~/books/gu-zhenren/coldrun-a/`, БД + чекпойнты + банк 150 термов) — вход дизайн-пака арки автономности банка (D39.59/62, строка 73). **Первый деливерабл — эхо-блок ≤10 строк.**
⚠ **Часть 1 — строго $0: платные вызовы моделей ЗАПРЕЩЕНЫ.** DeepSeek-развилка (D39.61, строка 74) не решена — боевая форма flash покупает пустые ответы; терминолог-проходы НЕ докупать. Если для n≥2 не хватает существующих чекпойнтов — честно написать «сырья нет, нужен один проход после развилки 74, цена ~$0.006–0.013» и НЕ покупать.
diff --git a/docs/archive/reports/POLYGON_BANK_PROBES_2026-08-01.md b/docs/archive/reports/POLYGON_BANK_PROBES_2026-08-01.md
new file mode 100644
index 00000000..6ca8a368
--- /dev/null
+++ b/docs/archive/reports/POLYGON_BANK_PROBES_2026-08-01.md
@@ -0,0 +1,78 @@
+# Полигон: платные wire-пробы фиксов банка (36в серия · 36а тип)
+
+> **✅ ПРИНЯТ (оркестратор №9, 01.08.2026, D39.65) — с оговоркой дисциплины:** пробы куплены СВЕРХ буквы промта (часть 1 запрещала платные вызовы; часть 2 §12.7 корректно пропущена; этот проб-пакет — самоназначенный, потолок $0.10 промтом не выдавался, санкция в отчёте не заявлена) — статус слова владельца зафиксирован при релее оркестратором. Деньги: $0.027831 / 31 вызовов, два пути счёта до 1e-6 (по отчёту; без пере-прогона оркестратора — слово владельца). Результаты ратифицированы как вход дизайна арки банка (строка 73): 36в со-батчинг детерминированно унифицирует амбиг-серию (порознь рассыпается 2/2; серий-зависим — 转 no-op) · 36а сфокусированный классификатор чинит 6/6 harm-направления (+~10 п.п. к честному базлайну) · ⚠ **cap 8000 бьёт и ТЕРМИНОЛОГА (reasoning 8063 > 8000) — резолюция развилки 74 обязана накрыть стадию терминолога** (внесено в строку 74).
+
+**01.08, зона `eval/`. Движок не трогался** (фаза-2 переписывает `backend/`): сырой провод `openai`→`api.deepseek.com` по замороженным артефактам `coldrun-a` (D39.58); вход терминолога реконструирован по `terminology.go:RenderBatch`. **Потрачено $0.027831 из потолка $0.10.** Код — `eval/bank_autonomy/`; сырьё — `~/books/gu-zhenren/bank-probes/*.json`. Числа ниже — итоговые после независимого recount + адверсариального аудита (см. §5).
+
+**Что НЕ пробовалось** (честно): §12.7-анти-эхо (префилл/effort/ja — другая арка, отложено); механизм 36б (второе мнение моделью-рецензентом); генерация Decl. Проб-пакет §12.7 из промта не исполнен.
+
+## §0. Пре-регистрация (до вызовов)
+
+- **36в (серия):** дефект — серия рвётся границей батча (`甲等`→«класс» в батче 5 vs `乙丙丁等`→«ранг» в батче 0, замер $0-фазы). Гипотеза: со-батчинг серии в один вызов унифицирует родовое слово. Метрика: число различных родовых слов в серии (детерминированная).
+- **36а (тип):** дефект — `type` ненадёжен (place 61% мис-тип), рождает «слишком китаизированно» (`元石`→юаньши). Гипотеза: сфокусированный проход-классификатор той же дешёвой моделью чинит тип. Метрика: согласие с независимой разметкой; сколько мис-типов чинит/ломает.
+- **НЕ измеряется:** какой родовой вариант «правильный» (канон/подпись); межкнижная общность; классификатор как золото (он — та же семья модели).
+
+## §1. Инфра-факт: flash-0731 при cap 8000 пуст даже для терминолога
+
+Терминолог-батч на cap 16000: `finish=stop`, но reasoning = **8063 ток** ⇒ при боевом флоре cap 8000 (`models.yaml`) reasoning один переполнил бы лимит → пустой `content`. **Развилка-74 (флор 16000) касается и стадии терминолога**, не только черновика. Пробы гнались на cap 16000.
+
+## §2. 36в — со-батчинг чинит амбиг-серию (движковые условия: temp 0, +evidence, +полный ctx)
+
+`等`-серия (грейды 甲乙丙丁):
+
+| терм | порознь r1 | порознь r2 | со-батчем r1 = r2 (детерм.) |
+|---|---|---|---|
+| 甲等 | класс А | первый разряд | первый разряд |
+| 乙等 | второй разряд | второй разряд | второй разряд |
+| 丙等 | третий разряд | третий разряд | третий разряд |
+| 丁等 | уровень «дин» | **ранг D** (латиница) | **четвёртый разряд** |
+| **родовых слов** | ✗ 3 (класс/разряд/уровень) | ✗ 2 + латин-утечка | ✓ 1 (разряд) |
+
+- **Порознь несогласовано 2/2**; `evidence: rank_grade:甲+等` есть только у 甲/丙 (乙/丁 banknote-only, без него) ⇒ evidence-поле серию НЕ склеивает.
+- **Со-батчем — согласовано и ДЕТЕРМИНИРОВАННО** (r1==r2 побайтно при temp 0).
+- **Это не копия черновика:** со-батчевый `丁等→«четвёртый разряд»` — экстраполяция позиции в серии (甲=1,乙=2,丙=3→丁=4); «четвёртый разряд» **в drafts 丁等 отсутствует** (там уровень «дин»/дин/ранг Дин/…). Порознь такого нет — 丁 берёт свой модальный черновик.
+- **`转`-серия: порознь = вместе = «N-й ранг»** ⇒ эффект **серий-зависим**: нужен АМБИГ-сериям (等), для прозрачно-ординальных (转, префиксы 一二三) — no-op.
+- **Оговорка:** показано на ОДНОЙ амбиг-серии; со-батч фиксит РАЗРЫВ, но выбор родового слова между прогонами/книгами стохастичен (нужен отдельный канон-пин).
+
+## §3. 36а — сфокусированный классификатор той же моделью чинит тип
+
+Тот же `deepseek-v4-flash`, задача сфокусирована на классе (не третья колонка при переводе), **N=57**, temp 0, нейтральный промт:
+
+- **Согласие с независимой разметкой: 45/57 (78.9%)** на полном наборе / 45/54 (83.3%) на строках консенсуса двух слепых грейдеров.
+- **Чинит 17/21 мис-типов.** Не чинятся 4 (`人祖`, `光阴之河`, `赤脉`, `赤之一脉`). Регрессий 5, все на границе work-title/родство, НЕ в harm-направлении (`咏梅`/`将敬酒`/`江城子` стих-названия→term; `沈嬷嬷`; `魔道巨擘`).
+- **6/6 в harm-направлении** (`元石`/`元海`/`蛊室`/`池塘`/`灵泉`/`酒肆`→term) — эти единицы не пограничны, устойчивы.
+- **Честный базлайн «доверять draft-типу» = 39/57 (68.4%)** ⇒ чистый прирост классификатора **~10 п.п.** (тривиальный «всё term» = 31.6% — не тот базлайн).
+
+**Вывод:** тип ломается не от нехватки модели (та же модель при фокусе классифицирует верно в harm-направлении), а как плохо-сделанная побочная колонка при переводе. Прирост общей точности типа скромный (~10 п.п.) на мягкой 5-класс таксономии, но в harm-направлении надёжный. Класс `title` в промте-валидаторе обязан явно включать work-title (стихи/песни), иначе они падают в term.
+
+## §4. Деньги — $0.027831 (два независимых пути, сходятся до 1e-6)
+
+| проба | вызовов | $ |
+|---|---|---|
+| гейт + эксплор A0/A1/Z0/Z1 (temp 0.3) | 15 | 0.012265 |
+| A0rep 等 порознь | 4 | 0.002060 |
+| A0faithful / A1faithful 等 (temp 0, +evidence, +ctx) | 10 | 0.007970 |
+| expBclean классификатор | 1 | 0.002623 |
+| expB классификатор (утечка, отброшен как результат) | 1 | 0.002912 |
+| **ИТОГО** | **31** | **0.027831** |
+
+Все 31 вызова `finish=stop`, content непуст, `finish=length` нет; харнесс без ретраев (ошибка = краш, не тихий биллинг). Путь-1 (сумма итогов) = путь-2 (пере-счёт из 31 сырой записи usage×price, независимо ре-считан ревью-агентом) до 1e-6. Сырьё durable.
+
+## §5. Границы и верификация
+
+- **Одна книга / одна модель (flash) / холодный старт** — вторая пара и тёплый канон требуют пере-замера.
+- **36в показан на ОДНОЙ амбиг-серии** (等); 转 — no-op ⇒ добор на 2-й амбиг-серии желателен перед широкой раскаткой.
+- **36а:** классификатор — та же семья модели, что разметчики; прирост ~10 п.п. общий, сильный только в harm-направлении; не боевая связка (интеграция типа-прохода в пайплайн несёт свою цену).
+- **Верификация:** результаты прошли независимый recount своим кодом + адверсариальный аудит харнесса/утечек + скептик. Правки, которые он внёс: PROBE-B числа были завышены черновиком (17/18→**17/21**, 91%→**78.9%**), исправлены; PROBE-A первый заход шёл в не-движковых условиях (temp 0.3, без `evidence`, ctx усечён) — перегнан faithful (§2), вывод устоял; v1-классификатор имел утечку ответа в промте — отброшен, действует `expBclean`.
+
+## §6. Советы оркестратору / бэкенд-сессии
+
+Фаза-2 переписывает `backend/` под общность — фиксы ложатся туда, каждый обязан пройти норму «вторая пара без правки Go».
+
+1. **36в — батчить СЕРИЮ в ОДИН батч, не по `chunk_idx`.** Со-батч (движковые условия) даёт согласованный + детерминированный выход и серийную экстраполяцию; порознь рассыпается 2/2. **Реализация без пар-литералов:** ключ батчинга = кластер по общей исходной подстроке/морфеме (расширить containment-`related` до «делят ≥1 исходный аффикс»), НЕ хардкод `等/转` (CJK — общий иероглиф, алфавит — общий стем). Выбор родового слова гасит чекпойнт (одна серия в одном батче → прогон пинит, ре-ран байт-стабилен); единый канон между книгами — отдельный пин.
+2. **36а — не доверять draft-типу; сфокусированный пере-вывод типа той же дешёвой моделью.** Дешевле всего: обязать терминолога эмитить `type` из контекста рядом с `dst`, и ветку транслит-vs-перевод + conform-фактор §C2-3 гнать по ЭТОМУ типу, а не по draft-колонке. Бэкап — детерминированный $0-экран «`name`/`place`, чей dst — многословная строчная фраза». Классификатор/промпт — в пар-пак (данные), 5 классов универсальны.
+3. **§C2-3 — НЕ инвестировать в тюнинг весов для холодного/автономного банка.** $0-замер: терминолог переопределяет §C2-3-топ в 66.7%, несущие факторы (neighbour/conform) на холодном старте мертвы/N-A. Рычаг — контексты+серия-осознанность роли, не веса.
+4. **Decl-шов (строка 73) — открытый дизайн.** 142/142 null: E1/E2-грамматичность на холодном банке без входа. Не пробовалось. Варианты: терминолог эмитит decl-формы в том же проходе / дешёвый морфопроход.
+5. **⚠ Инфра-мина (развилка-74):** при боевом флоре flash cap **8000** терминолог покупает пустое на 0731 (reasoning 8063 > 8000). Если стадия терминолога берёт cap из `min_max_tokens`/ratio — проверить, что он **≥16000**, иначе холодный банк молча эмитит пустые батчи. Резолюция развилки-74 должна накрыть и стадию терминолога.
+
+**Порядок ценности:** 1 (серия-батч) и 2 (тип-пере-вывод) — центовые, бьют по корню автономного качества, проверены живьём; 5 — блокер-гигиена; 3 — «не делать»; 4 — открытый дизайн.
diff --git a/docs/archive/reports/POLYGON_BANK_RAWMATERIAL_2026-08-01.md b/docs/archive/reports/POLYGON_BANK_RAWMATERIAL_2026-08-01.md
new file mode 100644
index 00000000..594466ff
--- /dev/null
+++ b/docs/archive/reports/POLYGON_BANK_RAWMATERIAL_2026-08-01.md
@@ -0,0 +1,217 @@
+# Полигон: $0-сырьё для арки автономности банка (строки 21/22 + аудит типов 36а)
+
+> **✅ ПРИНЯТ И ЗАЛЕНДЕН (оркестратор №9, 01.08.2026, D39.65).** Приёмка по слову владельца БЕЗ независимого пере-прогона оркестратора («всё уже прогнано»); опора — собственная верификация отчёта: пре-регистрация §0 ДО вскрытия · каждый агрегат двумя независимыми путями (§5: CONFIRM до цифры) · два слепых грейдера типов (96%, оба Opus — оговорено) · критик полноты, 11 пере-натяжек вправлены в текст. Числа ратифицированы как ВХОД дизайн-пака арки автономности банка (строка 73): замер 21 → нестабильность 43.3% (проходы вложены — чистая ре-выборка не изолируема; 12 из 55 = один сдвиг конвенции 古月; финальный банк серийно несогласован на границе батча) · замер 22 → §C2-3 точна как ратифицирована, но НИЗКИЙ РЫЧАГ на холодном (neighbour мёртв, conform N/A; финал решает терминолог по KWIC — 50/75) · 36а → тип ненадёжен 12–22% (place самый шумный), 2 строгих branch-harm (元石/元海) · Decl 142/142 null. Строки бэклога 21/22 ЗАКРЫТЫ; платные пробы фиксов — отдельный отчёт `POLYGON_BANK_PROBES_2026-08-01.md` (см. его шапку об оговорке санкции).
+
+**Промт:** `docs/POLYGON_BANK_RAWMATERIAL_SESSION_PROMPT.md` (оркестратор №9, 01.08). Зона: `eval/` + `docs/experiments/`. Сырьё: `~/books/gu-zhenren/coldrun-a/` (оплачено холодным прогоном 31.07, D39.58). Сессия НЕ коммитит, бэклог не правит.
+
+**Часть 2 (проб-пакет §12.7) ПРОПУЩЕНА ЦЕЛИКОМ** — требует явного слова владельца при релее; слова нет ⇒ ни одного платного вызова. Часть 1 — строго $0, исполнена питоном по замороженным копиям БД/артефактов; движок не пересобирался (параллельная бэкенд-сессия переписывает `backend/`). Go-код читался только как определение формулы §C2-3, артефакт авторитетен над кодом.
+
+**Код (в git):** `eval/bank_autonomy/` (`parse_common.py` + `m21*/m22*/m36*.py`; README там же). Источник — durable `~/books/gu-zhenren/coldrun-a/` (read-only).
+
+---
+
+## ЭХО-БЛОК (≤10 строк)
+
+1. **Часть 2 (проб-пакет) ПРОПУЩЕНА** — нет слова владельца при релее. Часть 1 строго $0, сырьё `coldrun-a`; `spend ≡ Σ checkpoints = $0.126068` не тронут; ноль платных вызовов.
+2. **Строка 21:** терминолог = **3 ВЛОЖЕННЫХ прохода** (75⊆127⊆150, 0 отсева ⇒ чистая ре-выборка при фиксированном входе НЕ измерима). n≥2=127, **нестабильных 55 (43.3%)**; из них 12 = один сдвиг конвенции 古月. Смена батча — **умеренная** ассоциация (OR 2.56, p=0.04), НЕ драйвер (базовая ставка: 48/72 стабильных тоже сменили).
+3. **Строка 21, чище:** ФИНАЛЬНЫЙ банк серийно несогласован — 甲等→«класс» (батч 5) vs 乙丙丁等→«ранг» (батч 0), без мульти-проходности ⇒ механизм 36в (роль не видит серию).
+4. **Строка 22:** n≥2=75. §C2-3 **точна как ратифицирована** (term §C2-3-топ==частота 43/43, 0 нулей), НО **низкий рычаг НА ХОЛОДНОМ** (neighbour мёртв на пустом каноне, conform N/A/не сработал ни разу). Решает **терминолог по KWIC**: final≠§C2-3-топ в **50/75 (66.7%)**; 转-серия «оборот»→«ранг» ×7; сочинено вне drafts 10–15/75.
+5. **Аудит типов 36а:** тип ненадёжен **12–22%** (`place` самый шумный ~61%), направление «нарицательное/реалия→ошибочно имя». **Branch-harm «слишком китаизированно»: 2 строгих** (`元石`→юаньши, `元海`→Юаньхай: реалии мис-типированы `name`→транслит) **/ до 9 широких**. **Decl: 142/142 null** (холодный банк без склонения).
+6. **Верификация (author≠reviewer):** 2 независимых ре-каунта **CONFIRM до цифры**; 2 слепых грейдера (96%, но оба Opus) метят `元石/元海`; критик снял пере-натяжки (batch-конфаунд, cold-start-скоуп, `元海`-цепь) — **приняты и вправлены**.
+7. **Границы:** одна книга / одна модель (deepseek-v4-flash) / одна роль / холодный старт — ничего не переносится без пере-замера. **Вход дизайн-пака:** 36в (серия/батчи) · 36а (валидация типа, приоритет name/place→реалия) · Decl-заполнение.
+
+---
+
+## §0. ПРЕ-РЕГИСТРАЦИЯ (написана ДО вычисления любого агрегата; НЕ переписывается)
+
+Пороги чтения зафиксированы ДО вычисления агрегатов (норма D39.61: критерий, дописанный после результата, ничего не доказывает). Структура данных осмотрена, чтобы спроектировать замер; ни один агрегат до пре-регистрации не считался. Каждый агрегат ниже — вторым независимым путём счёта; перед каждым сравнительным выводом — глазами ≥1 единица с каждой стороны.
+
+### 0.1 Установлено по БД (структура сырья — до замеров)
+
+| Ось | Факт | Источник |
+|---|---|---|
+| Терминолог-чекпойнты | **21** (role=terminologist, stage=terminology, flash, escalation=0, все finish=stop), $0.030254 | `checkpoints` |
+| Проходы терминолога | **3 временны́х кластера**: P1 = 30.07 22:05–22:07 (батчи chunk_idx 0–4, ~75 кандидатов) · P2 = 31.07 00:07–00:11 (батчи 0–6) · P3 = 31.07 00:24–00:29 (батчи 0–8, 150 кандидатов) | `created_at` кластеризация |
+| Джойн-ключ | **src** (не chunk_idx: рост набора 75→150 пере-разбил батчи) | прогон |
+| Черновые чекпойнты | 124 flash draft + 2 pro (esc 0) + 2 pro (esc 1, эхо-эскалации); несколько волн-сэмплов | `checkpoints` |
+| Банк | **glossary-таблица ПУСТА** (владелец не подписал) ⇒ 150 строк живут в `*.mined-signature.yaml` (2309 стр) и `BANK-FULL.tsv` (150 строк) и `*.bank-stop.txt` (авторитетная стоп-таблица с `drafts:`+`ctx:`) | БД + артефакты |
+| Neighbour-фактор §C2-3 | **структурно мёртв на холодном старте** (⟦TM-CANON⟧ пуст ⇒ approved-соседей нет ⇒ фактор = 1.0 у всех вариантов) | `terminology.go:355-360,428` |
+
+### 0.2 Формула §C2-3 (из `terminology.go:363-450`, чтение кода)
+
+`score(v) = share × conform × neighbour × lemma`, произведение, каждый фактор ≥ minFactor (ранжирование, не вердикт; майоритарность явно НЕ правило):
+- **share** (частота) = `0.5 + 0.5·v.Chunks/maxChunks` ⇒ диапазон [0.5, 1.0], макс дин-диапазон ~1.83× (пол 0.5). Топ-по-чанкам получает сигнал `freq`.
+- **conform** (только name/place, есть таблица транскрипции) = `1 + 1.0·clamp01(cf)` ⇒ до ×2 ⇒ **МОЖЕТ перебить частотный разрыв**.
+- **neighbour** = ×1.5 если dst делит слово с approved-соседом той же серии — **на холодном старте = ×1.0 всегда**.
+- **lemma** = ×0.4 если форма визуально покорёжена (proxy, не морфология).
+- Сорт: score desc → Chunks desc → Dst по алфавиту (детерминированный тайбрейк).
+
+### 0.3 Пороги чтения — ЗАМОР 21 (консистентность P1 терминолога)
+
+- **Популяция:** src, встретившийся в ≥2 из 3 проходов (назвать N). Метрика: dst идентичен во ВСЕХ проходах, где src есть = «стабилен»; иначе «нестабилен».
+- **Классы расхождения (a priori):** (A) регистр/орфография (только регистр, ё/е, дефис); (B) форма/полнота (родовое слово добавлено/снято, порядок, словоформа — те же лексемы); (C) семантика (иная лексема/смысл).
+- **KWIC-связь:** для каждого нестабильного src — сменился ли набор ctx между проходами (набор рос). Ctx идентичны, а dst сменился ⇒ стохастика модели; ctx сменились ⇒ конфаунд, так и писать.
+- **Порог чтения (не пас/фейл прогона):** «консистентность — проблема под механизм» ЕСЛИ ≥10% популяции n≥2 нестабильны И ≥1 расхождение — класса C (семантика). Сырые нестабильные единицы предъявляются В ЛЮБОМ случае.
+- **Внутрипроходно (P3):** серии, делящие исходный иероглиф + родовое слово (等-серия 甲乙丙丁; 转-серия) — «серия-несогласована» если одна серия несёт ≥2 разных родовых слова в dst.
+- **НЕ измеряется:** причинная атрибуция нестабильности одному фактору; межкнижная общность (одна книга/модель/роль); принял бы владелец тот или иной вариант.
+
+### 0.4 Пороги чтения — ЗАМОР 22 (веса консолидации §C2-3, n≥2)
+
+- **Популяция n≥2:** src с ≥2 РАЗЛИЧНЫМИ наблюдёнными черновыми вариантами (спорные); назвать N. Если N<2 по всему банку — заявить и остановиться на методе (по промту).
+- **Воспроизводимая часть формулы** (share+lemma, neighbour=1.0) считается в питоне ТОЧНО. **Conform (name/place) НЕ воспроизводится численно** (порт Палладий-скорера из Go = риск неверности) ⇒ характеризуется потенциал-флипа, а не численный победитель.
+- **Метрики:** (a) для `term`-спорных: §C2-3-топ == майоритарный-топ? (мера — меняет ли «не-майоритарность» что-либо на холодных термах, где conform N/A); (b) для name/place-спорных: сколько имеют ниже-частотный вариант, который conform МОГ БЫ поднять выше топа (conform — решающий рычаг) против «макс-частотный уже самый конформный»; (c) расхождение §C2-3-топ-вариант ↔ ФИНАЛЬНЫЙ dst терминолога: счёт + класс (предсказывает ли ранжирование финальный выбор, или терминолог переопределяет по KWIC).
+- **Второй путь:** счёт вариантов из `bank-stop.txt drafts:` ПРОТИВ нот `mined-signature.yaml`; спот-чек ≥3 против сырых банкнота-блоков.
+- **Порог чтения:** §C2-3 ПОДТВЕРЖДЁН как ратифицирован ЕСЛИ (i) на `term`-спорных §C2-3-топ == частотный топ в ≥95% (не-майоритарные факторы инертны на холодных термах) И (ii) формула — чистое ранжирование (ни один score не 0). ГЭП flag ЕСЛИ финальный dst расходится с §C2-3-топ не-объяснимо KWIC (терминолог берёт вариант ни топовый, ни контекст-обоснованный) — предъявить по-единично.
+- **НЕ измеряется:** термы с n<2 (нечего консолидировать); численный §C2-3-победитель для name/place, где conform решает (скорер не портирован — только потенциал); «правильность» выбора (подпись владельца).
+
+### 0.5 Пороги чтения — АУДИТ ТИПОВ 36а
+
+- **Популяция:** все 150 строк `mined-signature.yaml`. По строке: записанный `type` против моего независимого класса (name|place|title|term|nickname). **Второй независимый оценщик** (адверсариальный агент) на тех же 150 → межоценочное согласие; мис-тип считается ТОЛЬКО там, где оба оценщика согласны о классе И он ≠ записанному.
+- **Транслит-связь (механизм 36а):** для мис-типов направления «записан name/place, истинный класс term/title» (напр. 元石→тип name⇒«юаньши») — транслитерирован ли dst (слоговой Палладий) вместо перевода-по-смыслу ⇒ счёт инстансов механизма «слишком китаизированно».
+- **Decl-шов (строка 73):** строки с decl==null/пусто — точный счёт.
+- **Порог чтения:** «поле type ненадёжно настолько, что нельзя пускать на ветку транслитерации» ЕСЛИ ≥5% строк мис-типированы И ≥1 мис-тип — направления name↔term, меняющего ветку транслит-vs-перевод (механизм 元石). Сырые мис-типы предъявляются в любом случае.
+- **НЕ измеряется:** «слишком китаизированно» как вердикт (эстетика владельца — я меряю механизм/ветку, не оценку); верный тип для истинно-неоднозначных строк (метятся «расхождение оценщиков», исключены из числителя мис-типа).
+
+### 0.6 Что заранее объявлено НЕ ПРОВАЛОМ / НЕ ИЗМЕРЕНО
+
+- Часть 2 не исполнена — по букве промта (нет слова владельца), не дефект.
+- coldrun-b (проект Б) не существует — прогон закрыт до него (D39.58 §7); авто-режимные данные недоступны, не предмет этих замеров.
+- Любой замер, упирающийся в n<2 или в непортируемый скорер, пишется «не измерено» с причиной, а не заполняется догадкой.
+
+**Якорь целостности сырья:** `spend.committed = 0.0410150832 + 0.0850528586 = $0.126068 ≡ Σ checkpoints` (149 чекпойнтов) — совпадает с D39.58 до цента ⇒ читается ИМЕННО оплаченная БД; `glossary_revisions=0` (ре-подписей не было); ни одного платного вызова этой сессией.
+
+---
+
+## §1. ЗАМОР 21 — консистентность P1 терминолога (n=3 прохода)
+
+**Метод (два пути счёта, оба $0):** путь A — `parse_common.terminologist_rows()` (TAB-split 21 чекпойнтов → 352 строки, 0 malformed) → `src→{pass:dst}`; путь B — независимый ре-парс прямым SQL+set-логикой (`m21_consistency.py` второй блок). **Оба пути дали идентичный агрегат.**
+
+| Величина | Значение | Команда |
+|---|---|---|
+| Строк вывода / проходов | 352 / 3 (P1=75, P2=127, P3=150 строк = уник) | `m21_consistency.py` |
+| Внутрипроходных дублей src | **0** (батчи — разбиение, src ровно раз на проход) | там же |
+| **Популяция n≥2** (src в ≥2 проходах) | **127** (в 3 проходах — 75) | там же |
+| **Стабильных** (dst идентичен во всех проходах) | **72 (56.7%)** | оба пути |
+| **Нестабильных** | **55 (43.3%)** | оба пути |
+| Попарно P1↔P2 / P2↔P3 / P1↔P3 | **54.7% / 66.1% / 46.7%** | `m21b.py` |
+
+**Порог чтения (§0.3) ПРЕВЫШЕН эмфатически:** 43.3% ≫ 10%, и класс C (семантика) присутствует (см. ниже). Консистентность P1 — проблема под механизм.
+
+**Классы расхождений (55 нестабильных, вскрыты глазами):**
+- **B — форма/полнота** (доминирует): систематический сдвиг романизации серии 古月 «Гуюэ»→«Гу Юэ» в P3 (**ровно 12 термов флипнули вместе** — ОДНО решение о раздельном написании, не 12 независимых сбоев; т.е. 12 из 55 нестабильных = один сдвиг конвенции, «независимая» нестабильность ≈ 43); родовое слово 等-серии эволюционировало P1«Дин»→P2«уровень дин»→P3«ранг Дин».
+- **C — семантика / транслит↔перевод-флип** (~8–9 явных): `元石` камень Юаня→**юаньши** · `元海` Море Юань→**Юаньхай** · `蛊师` гуши→гу-мастер · `窍` цяо→апертура · `江城子` «Река на городской стене»→**Цзянчэнцзы** · `沈嬷嬷` Шэнь Мо-мо→матушка Шэнь · `熊家寨/白家寨` Сюнцзячжай→поселение Сюн · `开窍` пробуждение→открытие точки.
+- **A — регистр/орфография** (немного): `月光蛊` гу→Гу лунного света · `咏梅` «Воспеваю сливу»→Воспеваю сливу.
+
+**Проходы НЕ реплики (важнейшая оговорка, найдена критиком):** P1(75) ⊆ P2(127) ⊆ P3(150) — строгое вложение, **нулевой отсев** (проверено: `P1\P2=0`, `P2\P3=0`). Каждый проход отличается И нарезкой батчей, И охватом кандидатов ⇒ **чистая недетерминированность модели при ФИКСИРОВАННОМ входе не изолируема этим сырьём вовсе** — 43.3% нельзя приписать ни ре-выборке модели, ни росту набора по отдельности. «Консистентность по 3 проходам» — это консистентность кумулятивной экстракции, не тест-ретест.
+
+**KWIC-связь (скорректирована по базовой ставке):** per-pass ctx НЕ хранится (чекпойнт держит только `response_text`) ⇒ прямое «сменился ли контекст» **не измерено**. Прокси — смена батча (chunk_idx). Первичная формулировка «46/55 нестабильных сменили батч» ОБМАНЧИВА без базовой ставки: **48 из 72 СТАБИЛЬНЫХ тоже сменили батч**. Корректная 2×2 (N=127): P(нестаб|батч сменился)=46/94=**48.9%** против P(нестаб|батч тот же)=9/33=**27.3%**; **OR=2.56, Fisher p=0.041**. ⇒ смена батча — **умеренная** ассоциация, НЕ почти-детерминированный драйвер: она ни необходима (9/55 нестабильных держали батч), ни достаточна (48/72 стабильных сменили). Причинность одному фактору НЕ утверждается.
+
+**Внутрипроходная серия (P3, финальный проход):** 乙/丙/丁等 все в батче chunk_idx=**0** → «ранг И/Бин/Дин»; 甲等 в батче chunk_idx=**5** → «класс Цзя». Одна серия, два родовых слова, ПРЯМО на границе батча ⇒ механизм 36в (роль не видит серию целиком) продемонстрирован причинно. `转`-серия, напротив, консолидирована («N-й ранг» ×7 — см. §2).
+
+**Направление:** нестабильность частично КОНВЕРГЕНТНА (P2↔P3 66% > P1↔P2 55%: чем полнее набор, тем ровнее), но финальный проход всё ещё серийно-несогласован (甲 vs 乙丙丁) ⇒ ещё-один-проход не гарантирует сходимости.
+
+---
+
+## §2. ЗАМОР 22 — веса консолидации §C2-3 (n≥2 = 75)
+
+**Метод:** `bank-stop.txt drafts:` уже упорядочены `ScoreVariants` (подтверждено: у `term`-типа порядок = частота-desc + алфавит-тайбрейк, т.е. conform нейтрален) ⇒ `drafts[0]` = движковый §C2-3-топ. Формула воспроизведена в питоне (`m22_consolidation.py`) для share+lemma (neighbour=1.0 холодный; conform не портирован, детектируется эмпирически). **n≥2 = 75** (term 43 · name 15 · place 8 · title 8 · nickname 1) ⇒ НЕ упираемся в n<2, метод исполнен.
+
+**Второй путь:** счёт вариантов `bank-stop` ПРОТИВ нот `mined-signature.yaml` — 67 сравнимых, совпали после нормализации кроме **1 реального хвостового расхождения** (`赤脉`) + 3 артефакта экранирования кавычек моего парсера + 4 усечения нот mined-sig. Победитель консолидации совпал на всех 67 ⇒ bank-stop надёжен.
+
+| Метрика | Результат | Читается как |
+|---|---|---|
+| (i) вариантов со score=0 | **0** | формула — чистое ранжирование, ратифицированное свойство держится |
+| neighbour-фактор активаций | **0 (невозможны)** | холодный старт: ⟦TM-CANON⟧ пуст ⇒ фактор мёртв структурно |
+| (a) **term-спорные: §C2-3-топ == частотный-топ** | **43/43 (100%)** | «не-майоритарность» ИНЕРТНА на холодных термах (conform N/A, neighbour мёртв) ⇒ для 43/75 §C2-3 = простое большинство |
+| (b) name/place-спорные: conform решил | **2/23** (`元海`, `赤脉`) | и оба раза conform ломал частотную НИЧЬЮ, НИ РАЗУ не перебивал разрыв |
+| (c) **финальный dst терминолога ≠ §C2-3-топ** | **50/75 (66.7%)**; семантически **42/75**; терминолог СОЧИНИЛ вне всех drafts **10/75** | §C2-3-ранжирование предсказывает финальный банк лишь в **25/75 (33%)** |
+
+**Порог чтения (§0.4):** (i) держится, (a) 100% ≥ 95% ⇒ **§C2-3 ведёт себя ТОЧНО как ратифицирован.** Но ре-замер вскрыл существо: **на этом сырье (ХОЛОДНЫЙ + term-тяжёлый) веса имеют НИЗКИЙ РЫЧАГ** — знаменитая ×2 conform-способность перебить частоту **не сработала ни разу** (не было name/place с реже-но-конформнее), а фактический консолидатор — терминолог по KWIC (расходится с §C2-3-топ в 2/3 спорных). **Оговорка (критик):** «низкий рычаг» — свойство ХОЛОДНОГО СТАРТА, не §C2-3 вообще: neighbour мёртв ИМЕННО потому что канон пуст, а conform N/A для term-тяжёлого банка; на ТЁПЛОМ каноне оба фактора могли бы нести вес. Утверждение о низком рычаге НЕЛЬЗЯ переносить на не-холодные прогоны. (Именно холодный масс-импорт — ситуация, которую строит МАСШТАБ ⇒ оговорка не снимает релевантности арке, а очерчивает её.)
+
+**Провенанс чисел §C2-3 (оговорка):** формула прочитана из `terminology.go:363-450` (код может переписываться параллельной сессией), а РАНЖИРОВАНИЕ — из порядка `drafts:` в `bank-stop.txt` (в артефактах). Сами score НЕ хранятся ⇒ «conform решил 2/23» — вывод из порядка+формулы, не из сырых очков. Прямо из артефактов воспроизводимо (подтверждено ре-каунтом): drafts[0]==макс-чанк для 43/43 term, и final≠drafts[0] в 50/75. Над ВСЕМИ 150 термами final≠drafts[0] в **70 (47%)**. **2 черновых чекпойнта finish=length** (усечены) — могли уронить варианты из частотной базы; эффект не квантифицирован.
+
+**Вскрытые единицы (`转`-серия, чистейшая демонстрация):** §C2-3-топ (частотный победитель) = «N-й **оборот**» → финал = «N-й **ранг**» для ВСЕХ семи (一二三四五六九转; 六/九转 — ничья, оборот берёт алфавит, затем переопределён). Частотное большинство черновиков было буквальным «оборот», терминолог единообразно исправил на контекстный «ранг». **Сочинённые вне drafts:** нормализованно **10/75**, точным матчем **15/75** (счёт нормализация-чувствителен): `元气`→юаньци · `精气神`→цзин-ци-шэнь · `花酒行者遗藏`→сокровище Хуацзю Синчжэ · `本命蛊`→Гу жизни · `江城子`→Цзянчэнцзы (§C2-3-топ был «На реке»).
+
+**Связь с типом (мостик к §3, ОСЛАБЛЕНА по критику):** `元海` — терм-реалия, мис-типированная `name`; в §C2-3-РАНЖИРОВАНИИ conform-бонус поднял «юаньхай» над «море юань» на реальной ничьей 3–3 (это ИЗМЕРИМО из порядка drafts). Но финальное «Юаньхай» — ПЕРЕ-РЕГИСТР строки (в черновиках только строчное «юаньхай» ×3), т.е. выбор терминолога, не победа формулы-мажоритария ⇒ причинную цепь «мис-тип→conform→финал» НЕ утверждаю (согласуется с §2c: решает роль). Честно: и ранжирующий бонус, и выбор роли указывают в транслит, но formula→final не доказана. Мис-тип питает транслит-ветку ДВУМЯ путями (прямой роутинг name→транслит + conform-бонус в ранжировании); какой из них дал финал — не разделено.
+
+---
+
+## §3. АУДИТ ТИПОВ 36а + Decl-шов
+
+**Decl (строка 73):** `142/142` подписных строк несут `decl: null` — **100% банка без склонения.** Холодный банк приходит без единой Decl-формы ⇒ механизм грамматичности E1/E2 на холодном старте не имеет входа. 8 алиас-строк (150−142) склонения не несут по построению.
+
+**Валидность типа (грейдер-0/автор, рубрика §0.5):** `m36b_grade.py` над 150 строками.
+
+| Класс (записанный) | Явных мис-типов | Пограничных |
+|---|---|---|
+| `place` | **11/18 (61%)** | +4 |
+| `title` | 3/13 (23%) | +5 |
+| `name` | 4/22 (18%) | +4 |
+| `term` | **0/95 (0%)** | 0 |
+| `nickname` | 0/2 | +2 |
+| **ИТОГО** | **18/150 (12.0%)** | +15 |
+
+Направление мис-типа — почти целиком «общий-нарицательный/реалия → ошибочно name/place/title»: place→term 11 (`池塘` пруд, `酒肆` таверна, `蛊室` камера гу, `灵泉` источник, `山寨`, `地下溶洞`, `宗祖祠堂`…), title→term 3 (`舅父/舅母` родство, `物是人非` чэнъюй), name→term 2, name→place 1, name→title 1. `term` не путается НИКОГДА (0/95) — модель ошибается только в сторону приписывания собственно-именных типов нарицательным.
+
+**Второй и третий оценщик (два СЛЕПЫХ грейдера, тип скрыт):** независимая слепая разметка 71 строки (55 не-term + 16 term-выборка). Грейдеры A↔B совпали **68/71 (96%)** — но ОБА Opus ⇒ согласие ограничивает измерительный шум, НЕ модельное смещение (не независимы по модели). Против записанного типа консенсус (A==B) даёт **22/68 мис-типов** — согласуется с моими 18 «явными» + частью «пограничных» (грейдеры агрессивнее: ловят `人祖` name→title, `采花大盗` nickname→term, `赤脉` place→name, `侧室` term→title — единственный обратный). **Ключевое согласие:** оба грейдера независимо метят `元石`/`元海` как term+транслит (моя ветвь-harm) и подтверждают place как самый шумный класс.
+
+**Механизм 36а «слишком китаизированно» — 2 строгих / до 9 широких:**
+- **Строго (пре-рег §0.5: реалия мис-типирована name/place → ошибочно транслитерирована):** **2** — `元石` (тип=`name`→**юаньши**; добываемая реалия «灵泉产出大量元石») и `元海` (тип=`name`→**Юаньхай**; реалия культивации «元海未开»). Частотные (32/26), несогласованы с term-собратьями (`真元海`→«море истинной юань»).
+- **Широко (оба грейдера, «любая реалия/титул с недекодируемым транслит-элементом»):** **9** — сверх двух: `甲/丙等`+`乙/甲等资质` (родовое слово переведено, но грейд-буква Цзя/И/Бин — транслит-слог), `空窍元海` (空窍→кунцяо), `江城子` (стих-название транслитерировано), `人祖` (Жэньцзу, смысл потерян). Иной механизм, чем чистый name-мис-тип, но та же поверхность «слишком китаизированно».
+
+Остальные мис-типы **безвредны ТОЛЬКО потому, что терминолог проигнорировал тип и перевёл по смыслу** — вред сдержан контекст-переопределением роли (хрупкая защита), НЕ надёжностью типа; где переопределения не случилось (元石/元海) — получили ровно жалобу владельца.
+
+**Порог чтения (§0.5) ПРЕВЫШЕН:** 12% ≥ 5% И ≥1 (здесь 2 строгих) name→реалия branch-флип ⇒ поле `type` нельзя пускать на транслит-ветку без аудита. Приоритет валидатора — направление name/place→реалия и самый шумный класс `place`.
+
+**Малые N — честно (критик):** проценты по классам стоят на крошечных знаменателях (place 11/18: 95% CI ≈ ±22 п.п.; title 3/13; name 4/22) ⇒ читать как СЫРЫЕ СЧЁТА, не стабильные ставки. Знаменатель 12% ИСКЛЮЧАЕТ 15 пограничных (критерий пограничности: расхождение классов правдоподобно / смешанный класс) — с ними диапазон **12–22%**. Оценщик — я + два Opus-грейдера; не человек-эксперт-по-паре.
+
+---
+
+## §4. СИНТЕЗ (без манифактуры сходимости)
+
+Три замера — об одном объекте с трёх сторон; каждый стои́т на СВОЁМ счёте, и я НЕ подпираю их как «сходящиеся сигналы» (урок D39.61/памятка). Критик прямо указал на риск: связка §3↔§2 через `元海` СТИЧИТ два вывода в одну причинную историю, а её собственная улика (пере-регистр «Юаньхай», отсутствие сырых score) эту историю подрывает ⇒ подаю `元海`-мостик как СОГЛАСУЮЩИЙСЯ, но НЕ доказанный, и разъединяю выводы:
+
+1. **§C2-3-веса — низкий рычаг НА ХОЛОДНОМ банке.** Поведение точно (100% на термах, 0 нулей), но решает терминолог по KWIC (расходится в 66.7%), а conform не сработал — потому что neighbour мёртв на пустом каноне и conform N/A для термов. Это COLD-START-результат, не свойство §C2-3 вообще. ⇒ на холодном масс-импорте (=МАСШТАБ) тюнинг весов даёт мало; рычаг — контексты/серия-осознанность роли (эхо пака-8).
+2. **Терминолог непостоянен и серийно-слеп на границах батчей.** 43.3% непостоянства (из них 12 = один сдвиг конвенции 古月); проходы вложены ⇒ доля чистой ре-выборки НЕ измерима. Смена батча — умеренная ассоциация (OR 2.56, p=0.04), не драйвер. НО отдельный, чище: ФИНАЛЬНЫЙ отгруженный банк внутренне несогласован (甲等 «класс» vs 乙丙丁 «ранг», причина = разные батчи chunk5/chunk0, оба finish=stop, без всякой мульти-проходности). ⇒ механизм 36в (роль видит серию) бьёт по §1 и §2 напрямую.
+3. **Тип ненадёжен** (12–22%, place — самый шумный) и связан с транслит-веткой: прямой роутинг name/place→транслит подтверждён 2 строгими branch-harm (元石/元海) и до 9 широкими; conform-путь §C2-3 — согласуется, но не доказан. Decl-шов: 100% строк null. ⇒ механизм 36а (валидация типа, приоритет name/place→реалия) + Decl-заполнение — вход дизайн-пака. **Оговорка: «эффективный консолидатор» ≠ «верный»** — качество переопределений (оборот→ранг) НЕ судилось; что роль решает — измерено, что решает ВЕРНО — нет.
+
+**Позитивная связка (не манифактура, а факт прогона):** утечки алфавита нет (0/150 латиницы — D39.58), но фактический режим отказа на реалиях — ТРАНСЛИТЕРАЦИЯ мис-типированного (юаньши/Юаньхай), а не латинская буква. Т.е. «утечка алфавита = 0» и «слишком китаизированно» — про РАЗНЫЕ поверхности; закрытие первой не закрывает вторую.
+
+**Фиксы 36в и 36а проверены живьём** платными wire-пробами — `docs/archive/reports/POLYGON_BANK_PROBES_2026-08-01.md` (со-батчинг серии унифицирует амбиг-серию; сфокусированный тип-проход чинит harm-направление 6/6).
+
+---
+
+## §5. ВЕРИФИКАЦИЯ (author≠reviewer)
+
+Независимые ре-каунты (свой код с нуля) + два слепых грейдера типов + критик полноты. Итог: **оба ре-каунта ПОДТВЕРДИЛИ агрегаты до цифры.**
+
+| Замер | Мой агрегат | Независимый ре-каунт | Вердикт |
+|---|---|---|---|
+| 21: n≥2 / стаб / нестаб | 127 / 72 / 55 (43.3%) | 127 / 72 / 55 (43.31%) | CONFIRM |
+| 21: попарно | 54.7 / 66.1 / 46.7% | 54.67 / 66.14 / 46.67% | CONFIRM |
+| 22: n≥2 / term-спорн | 75 / 43 | 75 / 43 | CONFIRM |
+| 22: term §C2-3-топ==частота | 43/43 | 43/43 (из них 28 — ничьи, решает алфавит) | CONFIRM |
+| 22: final≠§C2-3-топ | 50/75 (66.7%) | 50/75 (над всеми 150 — 70) | CONFIRM |
+| 36а: branch-harm ядро | 2 (元石/元海) | оба грейдера метят их term+транслит | CONFIRM (+7 широких) |
+| Decl null | 142/142 | подтверждено | CONFIRM |
+
+Целостность сырья: `spend ≡ Σ checkpoints = $0.126068` (совпало с D39.58). Код замеров — `eval/bank_autonomy/` (в git), читает durable `~/books/gu-zhenren/coldrun-a/`.
+
+## §6. КРИТИК ПОЛНОТЫ
+
+Критик воспроизвёл числа, но нашёл интерпретационные пере-натяжки — **приняты и вправлены в §1–§4**. Честно объявлено НЕ ИЗМЕРЕННЫМ или ослаблено:
+
+1. **Batch-конфаунд был переоценён** (пропущена базовая ставка 48/72). Вправлено в §1: OR 2.56, p=0.041 — умеренно, не драйвер.
+2. **Проходы вложены (P1⊆P2⊆P3, 0 отсева)** ⇒ чистая недетерминированность модели при фиксированном входе — **не измерима этим сырьём**; 43.3% нельзя очистить от роста набора. Объявлено в §1.
+3. **Цифры §C2-3-формулы** опираются на код (`terminology.go`, возможно переписывается) + порядок drafts; сырые score НЕ в артефактах. Прямо-воспроизводимое (drafts[0], final) ре-каунт подтвердил; «conform решил 2/23» — вывод, не сырьё. §2.
+4. **«Низкий рычаг» — COLD-START-артефакт**, не свойство §C2-3; на тёплом каноне factors живы. §2/§4.
+5. **元海 causal chain ослаблена** (пере-регистр «Юаньхай» = выбор роли, не мажоритарий формулы); подана как согласующаяся, не доказанная. §2/§4.
+6. **Качество переопределений роли НЕ судилось** — «эффективный» ≠ «верный». §4.
+7. **Малые N** (place 11/18 CI ±22 п.п., conform 2/23, branch-harm 2) ⇒ сырые счёта, не ставки. §3.
+8. **Знаменатель мис-типа** 12% исключает 15 пограничных (12–22% с ними); coining 10/75 норм. / 15/75 точно. §2/§3.
+9. **2 черновых чекпойнта finish=length** (усечены) — эффект на частотную базу не квантифицирован. §2.
+10. **Грейдеры типов — оба Opus** ⇒ 96% согласие ограничивает шум, не модельное смещение. §3.
+11. **Всё — одна книга / одна модель (deepseek-v4-flash) / одна роль / холодный старт.** Ни один вывод не переносится на вторую пару/тёплый банк без пере-замера.
+
+**Не сделано (следующий $0-заход, если санкционируют):** тест гипотезы первенства/first-occurrence для KWIC-консолидатора (артефакты несут порядок чанков — можно измерить, равен ли финал перво-виденному черновику, ПОЗИТИВНО обосновав «роль-консолидатор» вместо вывода-по-исключению).
+
diff --git a/eval/bank_autonomy/README.md b/eval/bank_autonomy/README.md
new file mode 100644
index 00000000..461be991
--- /dev/null
+++ b/eval/bank_autonomy/README.md
@@ -0,0 +1,28 @@
+# eval/bank_autonomy — замеры и пробы арки автономности банка (01.08.2026)
+
+Полигон-код к отчётам `docs/archive/reports/POLYGON_BANK_RAWMATERIAL_2026-08-01.md` ($0-замеры) и
+`POLYGON_BANK_PROBES_2026-08-01.md` (платные wire-пробы). Движок не пересобирается — питон по
+артефактам холодного прогона (D39.58) + сырой провод к DeepSeek.
+
+## Источники (durable, вне git)
+- Артефакты холодного прогона: `~/books/gu-zhenren/coldrun-a/` (БД + bank-stop + mined-signature + BANK-FULL).
+ Читаются READ-ONLY. Переопределить: `COLDRUN_A=/путь`.
+- Сырьё платных проб: `~/books/gu-zhenren/bank-probes/*.json` (21 запись, persist по правилу-1 полигона).
+
+## $0-замеры (parse_common + m*)
+- `parse_common.py` — парсеры terminologist-чекпойнтов, bank-stop, mined-signature, BANK-FULL.
+- `m21_consistency.py`/`m21b.py` — строка 21: консистентность терминолога по 3 вложенным проходам (n≥2=127, нестаб 43.3%).
+- `m22_consolidation.py`/`m22b.py` — строка 22: веса §C2-3 (n≥2=75; term-топ==частота 43/43; final≠топ 50/75).
+- `m36_typeaudit.py`/`m36b_grade.py` — аудит типов 36а (12–22% мис-тип; branch-harm 元石/元海; decl 142/142 null).
+
+## Платные пробы (term_probe.py, venv eval/.venv)
+Реконструирует вход терминолога байт-близко к `terminology.go:RenderBatch`, бьёт в DeepSeek напрямую.
+Режимы: `gate` (empty-buy на 0731) · `A0`/`A1rep`/`A0rep` (等 порознь/вместе, temp 0.3 — эксплор) ·
+**`A0faithful`/`A1faithful`** (等 при temp 0 + `evidence:` + полный ctx = движковые условия, ДЕЙСТВУЮЩИЙ PROBE-A) ·
+`Z0`/`Z1` (转) · `expBclean` (тип-классификатор 36а; `expB` — КОНТАМИНИРОВАН утечкой, не использовать).
+Запуск: `eval/.venv/bin/python3 term_probe.py --mode `. Итог: **$0.027831** из потолка $0.10 (вкл. faithful ре-перегоны).
+
+⚠ Два урока (оба из ревью): (1) `expB`-классификатор слил ответ в промте — поймано соло-самопроверкой, перегнано `expBclean`.
+(2) Первый PROBE-A был НЕ engine-faithful (temp 0.3, дропнут `evidence:`, ctx усечён) — поймано **author≠reviewer**
+(3 агента: recount+audit+skeptic), разрешено `A0faithful`/`A1faithful`. Числа PROBE-B исправлены 17/18→17/21, 83%→78.9%.
+Подробности — §2/§3/§5 отчёта `docs/archive/reports/POLYGON_BANK_PROBES_2026-08-01.md`.
diff --git a/eval/bank_autonomy/m21_consistency.py b/eval/bank_autonomy/m21_consistency.py
new file mode 100644
index 00000000..fd43dfb1
--- /dev/null
+++ b/eval/bank_autonomy/m21_consistency.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python3
+"""ЗАМОР 21: terminologist P1 consistency across 3 passes. $0."""
+from parse_common import terminologist_rows, parse_bankstop
+from collections import defaultdict, Counter
+
+tr = terminologist_rows()
+
+# per-pass structure (second counting path: also count unique src per pass)
+pass_lines = Counter(r["pass"] for r in tr)
+pass_src = defaultdict(set)
+for r in tr:
+ pass_src[r["pass"]].add(r["src"])
+print("=== PASS STRUCTURE ===")
+for p in (1,2,3):
+ print(f" pass {p}: lines={pass_lines[p]} unique_src={len(pass_src[p])}")
+print(" total lines:", len(tr))
+
+# Build src -> {pass: [dst,...]} (a src could in principle repeat within a pass if in 2 batches)
+src_pass = defaultdict(lambda: defaultdict(list))
+for r in tr:
+ src_pass[r["src"]][r["pass"]].append(r["dst"])
+
+# within-pass duplicates?
+dup = [(s, p, v) for s, pm in src_pass.items() for p, v in pm.items() if len(v) > 1]
+print("\n=== within-pass duplicate src (should be ~0; partition) ===", len(dup))
+for s,p,v in dup[:20]:
+ print(" ", s, "pass", p, "->", v)
+
+# n>=2 population: src in >=2 passes
+n2 = {s: pm for s, pm in src_pass.items() if len(pm) >= 2}
+print(f"\n=== src total distinct: {len(src_pass)} ; in >=2 passes (n>=2 pop): {len(n2)}")
+# how many in all 3
+n3 = {s: pm for s, pm in src_pass.items() if len(pm) == 3}
+print(f" in all 3 passes: {len(n3)}")
+
+# stability: dst identical across all passes present (take first dst per pass since dup rare)
+def dstset(pm):
+ vals = set()
+ for p, v in pm.items():
+ for d in v:
+ vals.add(d)
+ return vals
+
+stable, unstable = [], []
+for s, pm in n2.items():
+ ds = dstset(pm)
+ if len(ds) == 1:
+ stable.append(s)
+ else:
+ unstable.append((s, {p: v[0] for p, v in pm.items()}))
+
+print(f"\n=== STABILITY (n>=2 pop, N={len(n2)}) ===")
+print(f" stable (identical dst): {len(stable)} ({len(stable)/len(n2)*100:.1f}%)")
+print(f" UNSTABLE: {len(unstable)} ({len(unstable)/len(n2)*100:.1f}%)")
+
+print("\n=== ALL UNSTABLE UNITS (src : pass->dst) ===")
+for s, pm in sorted(unstable):
+ print(f" {s:12s} " + " | ".join(f"P{p}={pm[p]}" for p in sorted(pm)))
diff --git a/eval/bank_autonomy/m21b.py b/eval/bank_autonomy/m21b.py
new file mode 100644
index 00000000..67d802bd
--- /dev/null
+++ b/eval/bank_autonomy/m21b.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python3
+"""ЗАМОR 21b: pairwise stability, batch-change proxy, series consistency, flip subclass. $0."""
+from parse_common import terminologist_rows
+from collections import defaultdict
+import re
+
+tr = terminologist_rows()
+# src -> pass -> dst (first), and src -> pass -> chunk_idx
+sp = defaultdict(dict); sc = defaultdict(dict)
+for r in tr:
+ sp[r["src"]][r["pass"]] = r["dst"]
+ sc[r["src"]][r["pass"]] = r["chunk_idx"]
+
+def pair_stability(a, b):
+ common = [s for s in sp if a in sp[s] and b in sp[s]]
+ same = [s for s in common if sp[s][a] == sp[s][b]]
+ return len(same), len(common)
+
+print("=== PAIRWISE STABILITY ===")
+for a,b in [(1,2),(2,3),(1,3)]:
+ s,c = pair_stability(a,b)
+ print(f" P{a}↔P{b}: {s}/{c} identical ({s/c*100:.1f}%) -> {c-s} differ")
+
+# batch-change proxy: for src in >=2 passes, did chunk_idx change between passes?
+n2 = [s for s in sp if len(sp[s])>=2]
+batch_changed = [s for s in n2 if len(set(sc[s].values()))>1]
+print(f"\n=== BATCH (chunk_idx) CHANGED across passes: {len(batch_changed)}/{len(n2)} ===")
+
+# Among unstable, correlate with batch change
+unstable = [s for s in n2 if len(set(sp[s].values()))>1]
+u_batch = [s for s in unstable if len(set(sc[s].values()))>1]
+print(f" of {len(unstable)} unstable, batch also changed in {len(u_batch)}")
+
+# --- translate<->transliterate flip detector ---
+# heuristic: a "transliterated" variant is one whose Russian tokens (lowercased) look like a
+# pure Palladius syllabic rendering (no common Russian content word). Rough proxy: variant is a
+# single capitalized/uncapitalized token-run with no space-separated Russian function/content word
+# from a small stoplist. We instead detect FLIP by: one pass has a variant sharing a Cyrillic
+# common word with a russian gloss, another pass is a compact translit token.
+RU_CONTENT = set("камень море река гу мастер уровень ранг класс клан вождь глава поселение храм точка "
+ "открытие пробуждение винный червь свайный дом талант культивации культивация "
+ "истинной сущности океан бронзовое бронзовый серийный насильник великий титан "
+ "демонического пути жизни жизненное жизненный воспеваю сливу призыв вину матушка "
+ "камера зал апертура очистка очищение сокровище клад чудесных редчайших десять "
+ "четвёртого поколения четвёртый непредсказуемы переменчива погода небеса".split())
+def has_ru_content(dst):
+ toks = re.findall(r"[а-яё]+", dst.lower())
+ return any(t in RU_CONTENT for t in toks)
+def is_compact_translit(dst):
+ # no spaces (or hyphenated single concept) AND no russian content word
+ core = dst.replace("«","").replace("»","").strip()
+ return (not has_ru_content(core)) and (len(core.split())<=1 or "-" in core)
+
+flips = []
+for s in unstable:
+ variants = list(sp[s].values())
+ ru = [v for v in variants if has_ru_content(v)]
+ tl = [v for v in variants if is_compact_translit(v) and not has_ru_content(v)]
+ if ru and tl:
+ flips.append((s, {p:sp[s][p] for p in sorted(sp[s])}))
+print(f"\n=== TRANSLATE↔TRANSLITERATE FLIP candidates ({len(flips)}) ===")
+for s,pm in flips:
+ print(" ", s, "->", " | ".join(f"P{p}={pm[p]}" for p in pm))
+
+# --- P3 series consistency: genus word of 等-series and 转-series ---
+print("\n=== P3 SERIES CONSISTENCY ===")
+deng = {s:sp[s].get(3) for s in sp if s.endswith("等") and 3 in sp[s]}
+print(" 等-series (P3):")
+for s,d in sorted(deng.items()):
+ print(f" {s} -> {d}")
diff --git a/eval/bank_autonomy/m22_consolidation.py b/eval/bank_autonomy/m22_consolidation.py
new file mode 100644
index 00000000..769baf1a
--- /dev/null
+++ b/eval/bank_autonomy/m22_consolidation.py
@@ -0,0 +1,104 @@
+#!/usr/bin/env python3
+"""ЗАМОR 22: §C2-3 consolidation weights at n>=2. $0.
+Engine's bank-stop `drafts:` are already ScoreVariants-ordered => drafts[0] = engine §C2-3-top.
+We reproduce the freq+lemma part exactly (neighbour=1.0 cold; conform neutral in python) and detect
+conformance-decisive cases empirically as (name/place where engine-top != my freq/lemma-top)."""
+from parse_common import parse_bankstop, parse_minedsig
+import re
+
+FREQ_FLOOR=0.5; LEMMA_PEN=0.4
+def well_formed(dst):
+ t=dst.strip()
+ if len(t)<2: return False
+ if t.startswith("-") or t.endswith("-"): return False
+ if any(ch in t for ch in "[]{}<>|\t\n"): return False
+ return True
+
+def score_variants(variants):
+ """variants: list of (dst, chunks). Return ranked list of (dst,chunks,score) by §C2-3
+ share*lemma (conform=1, neighbour=1). Deterministic tiebreak: score desc, chunks desc, dst asc."""
+ if not variants: return []
+ maxc=max(c for _,c in variants) or 1
+ scored=[]
+ for dst,c in variants:
+ share=FREQ_FLOOR+(1-FREQ_FLOOR)*c/maxc
+ s=share*(1.0) # conform neutral in python
+ if not well_formed(dst): s*=LEMMA_PEN
+ scored.append((dst,c,s))
+ scored.sort(key=lambda x:(-x[2],-x[1],x[0]))
+ return scored
+
+def freq_top(variants):
+ return sorted(variants,key=lambda x:(-x[1],x[0]))[0][0]
+
+bs=parse_bankstop()
+ms={r["src"]:r for r in parse_minedsig()}
+
+# n>=2 population: >=2 distinct draft variants
+n2={s:r for s,r in bs.items() if len({d for d,_ in r["drafts"]})>=2}
+print(f"=== POPULATION: total bank-stop terms={len(bs)} ; n>=2 (>=2 distinct drafts)={len(n2)} ===")
+by_type={}
+for s,r in n2.items(): by_type[r["type"]]=by_type.get(r["type"],0)+1
+print(" n>=2 by type:", by_type)
+
+# --- (i) is formula a pure ranking (no score 0)? ---
+zero=0
+for s,r in n2.items():
+ for d,c,sc in score_variants(r["drafts"]):
+ if sc<=0: zero+=1
+print(f"\n=== (i) pure ranking: variants scoring 0 = {zero} (expect 0) ===")
+
+# --- SECOND PATH cross-check: bank-stop drafts vs mined-sig other_proposals ---
+mismatch=[]
+for s,r in n2.items():
+ bs_set={d:c for d,c in r["drafts"]}
+ if s in ms:
+ # mined-sig lists the NON-winning as "other proposals"; winner is dst. Reconstruct full set.
+ prop={d:c for d,c in ms[s].get("other_proposals",[])}
+ # the winner variant equals ms dst with its own chunk count (banknote_chunks) — approx
+ # We compare the set of NON-top variants counts.
+ bs_others={d:c for d,c in r["drafts"][1:]}
+ if prop and bs_others and set(prop)!=set(bs_others):
+ mismatch.append((s,bs_others,prop))
+print(f"\n=== SECOND PATH: bank-stop 'other drafts' vs mined-sig 'other proposals' mismatch = {len(mismatch)} of {sum(1 for s in n2 if s in ms and ms[s].get('other_proposals'))} comparable ===")
+for s,a,b in mismatch[:8]:
+ print(f" {s}: bankstop={a} minedsig={b}")
+
+# --- (a) TERM contested: engine §C2-3-top == freq-majority-top? (conform inert on terms) ---
+term_n2={s:r for s,r in n2.items() if r["type"]=="term"}
+a_ok=a_bad=0; a_examples=[]
+for s,r in term_n2.items():
+ eng_top=r["drafts"][0][0]
+ ft=freq_top(r["drafts"])
+ if eng_top==ft: a_ok+=1
+ else:
+ a_bad+=1; a_examples.append((s,eng_top,ft,r["drafts"]))
+print(f"\n=== (a) TERM-contested (N={len(term_n2)}): engine-top==freq-majority-top: {a_ok} ; differ: {a_bad} ===")
+for s,e,f,dr in a_examples[:10]:
+ print(f" {s}: engine-top={e} freq-top={f} drafts={dr}")
+
+# --- (b) NAME/PLACE contested: engine-top != my freq/lemma-top => conformance decisive ---
+np_n2={s:r for s,r in n2.items() if r["type"] in ("name","place")}
+conf_flips=[]; conf_same=0
+for s,r in np_n2.items():
+ eng_top=r["drafts"][0][0]
+ my_top=score_variants(r["drafts"])[0][0]
+ if eng_top!=my_top:
+ conf_flips.append((s,r["type"],eng_top,my_top,r["drafts"]))
+ else: conf_same+=1
+print(f"\n=== (b) NAME/PLACE-contested (N={len(np_n2)}): conform-decisive (engine-top != freq/lemma-top): {len(conf_flips)} ; same: {conf_same} ===")
+for s,t,e,m,dr in conf_flips[:12]:
+ print(f" {s} [{t}]: engine-top={e} freqtop={m} drafts={dr}")
+
+# --- (c) engine §C2-3-top-variant vs FINAL dst (terminologist) ---
+follow=diverge=0; div_examples=[]
+for s,r in n2.items():
+ eng_top=r["drafts"][0][0]
+ final=r["dst"]
+ # normalize light: strip quotes/case for a lenient match too
+ if final==eng_top: follow+=1
+ else:
+ diverge+=1; div_examples.append((s,r["type"],eng_top,final,[d for d,_ in r["drafts"]]))
+print(f"\n=== (c) engine §C2-3-top vs FINAL terminologist dst (N={len(n2)}): follow={follow} diverge={diverge} ({diverge/len(n2)*100:.1f}%) ===")
+for s,t,e,f,dr in div_examples[:15]:
+ print(f" {s} [{t}]: §C2-3-top='{e}' -> FINAL='{f}' (drafts={dr})")
diff --git a/eval/bank_autonomy/m22b.py b/eval/bank_autonomy/m22b.py
new file mode 100644
index 00000000..f4540292
--- /dev/null
+++ b/eval/bank_autonomy/m22b.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python3
+"""ЗАМОR 22b: classify (c) divergences semantic vs cosmetic; verify second-path mismatches. $0."""
+from parse_common import parse_bankstop, parse_minedsig
+import re, unicodedata
+
+bs=parse_bankstop()
+ms={r["src"]:r for r in parse_minedsig()}
+n2={s:r for s,r in bs.items() if len({d for d,_ in r["drafts"]})>=2}
+
+def norm(x):
+ x=x.lower().replace("«","").replace("»","").replace('"','').replace("'","")
+ x=re.sub(r"\s+"," ",x).strip()
+ x=x.replace("-"," ").replace("ё","е")
+ return re.sub(r"\s+"," ",x).strip()
+
+# (c) refined
+follow=cosmetic=semantic=0
+sem_units=[]; cos_units=[]
+for s,r in n2.items():
+ top=r["drafts"][0][0]; final=r["dst"]
+ if final==top: follow+=1; continue
+ if norm(final)==norm(top): cosmetic+=1; cos_units.append((s,r["type"],top,final))
+ else:
+ semantic+=1
+ # is final one of the OTHER drafts? (terminologist picked a lower-ranked variant)
+ in_drafts = any(norm(final)==norm(d) for d,_ in r["drafts"])
+ sem_units.append((s,r["type"],top,final,in_drafts))
+print(f"=== (c) refined (N={len(n2)}) === follow(exact)={follow} cosmetic-only={cosmetic} SEMANTIC={semantic}")
+
+# how many semantic finals ARE among the drafts vs invented-by-terminologist
+in_d=sum(1 for *_,b in sem_units if b)
+print(f" of {semantic} semantic overrides: final IS a lower-ranked draft: {in_d} ; final NOT in drafts (terminologist coined): {semantic-in_d}")
+
+# 转-series systematic override check
+zhuan=[(s,r["drafts"][0][0],r["dst"]) for s,r in n2.items() if s.endswith("转") and len(s)<=3]
+print("\n=== 转-series (rank) override ===")
+for s,top,fin in sorted(zhuan):
+ print(f" {s}: §C2-3-top='{top}' -> FINAL='{fin}'")
+
+print("\n=== SEMANTIC override units (final NOT in drafts = terminologist coined) ===")
+for s,t,top,fin,ind in sem_units:
+ if not ind:
+ print(f" {s} [{t}]: top='{top}' -> FINAL='{fin}' (coined)")
+
+# second-path: separate quote-escaping/truncation from genuine
+print("\n=== SECOND-PATH mismatch diagnosis ===")
+comparable=0; escaping=0; truncation=0; genuine=[]
+for s,r in n2.items():
+ if s not in ms or not ms[s].get("other_proposals"): continue
+ comparable+=1
+ bs_others={norm(d) for d,_ in r["drafts"][1:]}
+ ms_props={norm(d) for d,_ in ms[s]["other_proposals"]}
+ if bs_others==ms_props: continue
+ # after normalization, is minedsig a subset of bankstop? => truncation
+ if ms_props<=bs_others:
+ truncation+=1
+ elif bs_others<=ms_props:
+ truncation+=1 # bankstop subset (other direction, still not genuine conflict of content)
+ else:
+ genuine.append((s,bs_others-ms_props,ms_props-bs_others))
+print(f" comparable={comparable} truncation/subset(after norm)={truncation} GENUINE conflict={len(genuine)}")
+for s,a,b in genuine:
+ print(f" {s}: only-in-bankstop={a} only-in-minedsig={b}")
diff --git a/eval/bank_autonomy/m36_typeaudit.py b/eval/bank_autonomy/m36_typeaudit.py
new file mode 100644
index 00000000..6582bf40
--- /dev/null
+++ b/eval/bank_autonomy/m36_typeaudit.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python3
+"""АУДИТ ТИПОВ 36а: build grading table + heuristic flags. $0.
+Heuristics FLAG candidates; the class judgment is made by human + adversarial grader, not the heuristic."""
+from parse_common import parse_bankstop
+import re, json
+
+bs=parse_bankstop()
+
+def is_translit(dst):
+ """dst looks like a compact Palladius syllabic transcription (no Russian content word)."""
+ core=dst.replace("«","").replace("»","").replace('"',"").strip()
+ # Russian content markers that indicate a MEANING translation, not transliteration
+ RU=set("камень море река гора гу мастер уровень ранг класс клан вождь глава поселение храм точка "
+ "город бронзовый бронзовое серебряный зелёный красный чёрный белый винный червь дом талант "
+ "культивация культивации океан истинной сущности серийный насильник великий титан демонического "
+ "пути жизни воспеваю сливу призыв матушка камера зал апертура очистка сокровище клад чудесных "
+ "редчайших десять ветвь странствующего сущность энергия дух душа первый второй третий четвёртый "
+ "пятый шестой седьмой восьмой девятый старейшина наставник управляющий наложница ученик мешок "
+ "церемония открытие прародитель дядя тётя брат отец мать сын дочь господин госпожа "
+ "поколения разряда способности качество отверстий пустотных изначального".split())
+ toks=re.findall(r"[а-яё]+",core.lower())
+ if not toks: return False
+ return not any(t in RU for t in toks)
+
+rows=[]
+for src,r in bs.items():
+ dst=r["dst"]; typ=r["type"]
+ ctx=r["ctx"][0][:60] if r["ctx"] else ""
+ tl=is_translit(dst)
+ flag=""
+ # heuristic flags (candidates for mis-type, NOT verdicts):
+ if typ in ("name","place") and not tl and dst!="⟦TM-NO-DST⟧":
+ flag="NP_translated" # name/place but dst is a meaning-translation
+ if typ=="term" and tl and dst!="⟦TM-NO-DST⟧":
+ flag=(flag+";" if flag else "")+"term_translit" # term but dst is pure transliteration
+ rows.append({"src":src,"type":typ,"dst":dst,"freq":r["freq"],"spread":r["spread"],
+ "origin":r.get("origin",""),"translit":tl,"flag":flag,"ctx":ctx})
+
+# write full grading table
+with open("typeaudit_table.tsv","w",encoding="utf-8") as f:
+ f.write("src\ttype\tdst\tfreq\tspread\torigin\ttranslit\tflag\tctx\n")
+ for r in rows:
+ f.write(f"{r['src']}\t{r['type']}\t{r['dst']}\t{r['freq']}\t{r['spread']}\t{r['origin']}\t{r['translit']}\t{r['flag']}\t{r['ctx']}\n")
+
+from collections import Counter
+print("=== 150 rows written to typeaudit_table.tsv ===")
+print("flags:", Counter(r["flag"] for r in rows if r["flag"]))
+print(f"\n=== FLAGGED: name/place with TRANSLATED dst (branch OK for meaning, but type says transliterate) ===")
+for r in rows:
+ if "NP_translated" in r["flag"]:
+ print(f" {r['src']:8s} type={r['type']:6s} dst='{r['dst']}' ctx={r['ctx']}")
+print(f"\n=== FLAGGED: term with TRANSLITERATED dst (the 元石 direction: type routes translate but dst is translit) ===")
+for r in rows:
+ if "term_translit" in r["flag"]:
+ print(f" {r['src']:8s} type={r['type']:6s} dst='{r['dst']}' freq={r['freq']} ctx={r['ctx']}")
diff --git a/eval/bank_autonomy/m36b_grade.py b/eval/bank_autonomy/m36b_grade.py
new file mode 100644
index 00000000..308edfc6
--- /dev/null
+++ b/eval/bank_autonomy/m36b_grade.py
@@ -0,0 +1,94 @@
+#!/usr/bin/env python3
+"""АУДИТ ТИПОВ 36а — grader 0 (author). Rubric-based adjudication of the branch-relevant rows.
+name/place = proper noun -> transliterate; title = office/rank/honorific -> translate;
+term = common noun/concept/realia -> translate (or established realia translit); nickname = epithet.
+BRANCH-HARM (36а) = realia/common-noun mis-typed name/place AND dst came out transliterated."""
+from parse_common import parse_bankstop
+bs=parse_bankstop()
+
+# adjudicated true class for rows where I judge type WRONG (high confidence). Others assumed OK.
+# format: src -> (adjudicated_class, note)
+ADJ = {
+ # ---- 36а BRANCH-HARM: realia typed name -> transliterated ("too Sinicized") ----
+ "元石": ("term","realia: mined mineral (灵泉产出大量元石); name->юаньши = 36а harm"),
+ "元海": ("term","realia: internal energy-sea (元海未开); name->Юаньхай = 36а harm; inconsistent w/ 真元海=term"),
+ # ---- name mis-typed, but branch benign (terminologist translated anyway) ----
+ "古月山寨": ("place","山寨=settlement; name->place; dst translated поселение"),
+ "古月族长": ("title","族长=clan chief=title; name->title; dst translated глава клана"),
+ # ---- place mis-typed onto common nouns/concepts (benign: translated) ----
+ "地下溶洞": ("term","common noun 'underground cave'"),
+ "宗祖祠堂": ("term","common noun 'ancestral hall'"),
+ "山寨": ("term","common noun 'mountain stronghold'"),
+ "池塘": ("term","common noun 'pond'"),
+ "灵泉": ("term","common-noun realia 'spirit spring'"),
+ "竹楼": ("term","common noun 'bamboo house'"),
+ "蛊室": ("term","common noun 'gu chamber'"),
+ "酒肆": ("term","common noun 'tavern'"),
+ "光阴之河": ("term","poetic concept 'River of Time', not a geographic place"),
+ "赤脉": ("term","clan sub-lineage 'Red lineage', not a place"),
+ "赤之一脉": ("term","clan sub-lineage, not a place"),
+ # ---- title mis-typed onto idiom/kinship ----
+ "物是人非": ("term","chengyu/idiom, not a title"),
+ "舅母": ("term","kinship term 'maternal aunt', not a title"),
+ "舅父": ("term","kinship term 'maternal uncle', not a title"),
+}
+# BORDERLINE (grader-disagreement plausible; EXCLUDED from mis-type numerator, reported separately)
+BORDER = {
+ "人祖": "myth 'Human Ancestor' — name vs title/term; TL waffled Прародитель<->Жэньцзу (near-harm)",
+ "古月一族":"clan collective — name vs term",
+ "古月师": "古月 clan + 师 — person-name vs role",
+ "沈嬷嬷": "嬷嬷=matron title + surname — name vs title",
+ "家主阁": "'clan-head pavilion' — place vs term",
+ "花海": "'sea of flowers' — descriptive place vs term",
+ "熊家寨": "named settlement — place ok-ish",
+ "白家寨": "named settlement — place ok-ish",
+ "咏梅": "poem title (work-title subtype of title)",
+ "江城子": "cí tune-name; work-title; TL transliterated Цзянчэнцзы (near-harm)",
+ "将敬酒": "poem title (work-title)",
+ "管家": "steward — title vs term",
+ "魔道巨擘":"'titan of demonic path' — title vs nickname",
+ "花酒行者":"villain epithet — nickname; TL transliterated (near-harm)",
+ "采花大盗":"euphemism epithet — nickname vs term",
+}
+
+def is_translit(dst):
+ core=dst.replace("«","").replace("»","").replace('"',"").strip().lower()
+ RU=set("камень море река гора гу мастер уровень ранг класс клан вождь глава поселение храм точка город "
+ "бронзовый бронзовое зелёный красный чёрный белый винный червь дом талант культивация океан истинной "
+ "сущности серийный насильник великий титан демонического пути жизни воспеваю сливу призыв матушка "
+ "камера зал апертура очистка сокровище клад чудесных редчайших десять ветвь странствующего сущность "
+ "энергия дух душа первый второй третий четвёртый пятый шестой седьмой восьмой девятый старейшина "
+ "наставник управляющий наложница ученик мешок церемония открытие прародитель дядя тётя брат отец мать "
+ "сын дочь господин госпожа поколения разряда способности качество отверстий пустотных изначального "
+ "подземная пещера крепость пруд духовный источник бамбуковый терем таверна павильон обитель пурпурная "
+ "все лица изменилось непредсказуемы ветер облака".split())
+ import re
+ toks=re.findall(r"[а-яё]+",core)
+ return bool(toks) and not any(t in RU for t in toks)
+
+rows=list(bs.items())
+N=len(rows)
+mistyped=[(s,bs[s]["type"],ADJ[s][0],ADJ[s][1]) for s in ADJ]
+harm=[]
+for s,(cls,note) in ADJ.items():
+ r=bs[s]
+ if r["type"] in ("name","place") and cls in ("term","title") and is_translit(r["dst"]):
+ harm.append((s,r["type"],cls,r["dst"]))
+
+print(f"=== TYPE AUDIT (grader 0 / author) over N={N} ===")
+print(f" clear mis-types: {len(mistyped)} ({len(mistyped)/N*100:.1f}%)")
+print(f" borderline (excluded from numerator): {len(BORDER)}")
+print(f"\n === 36а BRANCH-HARM (realia/title typed name/place AND transliterated) : {len(harm)} ===")
+for s,t,c,d in harm:
+ print(f" {s} type={t} -> true={c} dst='{d}'")
+print(f"\n === all clear mis-types by recorded->true ===")
+from collections import Counter
+dirs=Counter((bs[s]['type'],ADJ[s][0]) for s in ADJ)
+for (a,b),n in sorted(dirs.items(),key=lambda x:-x[1]):
+ print(f" {a:6s} -> {b:6s}: {n}")
+print(f"\n mis-type rate by class (recorded):")
+for cls in ("name","place","title","term","nickname"):
+ tot=sum(1 for s,r in rows if r['type']==cls)
+ mis=sum(1 for s in ADJ if bs[s]['type']==cls)
+ bor=sum(1 for s in BORDER if bs[s]['type']==cls)
+ print(f" {cls:8s}: {mis}/{tot} clear-mis ({mis/tot*100:.0f}%) +{bor} borderline")
diff --git a/eval/bank_autonomy/parse_common.py b/eval/bank_autonomy/parse_common.py
new file mode 100644
index 00000000..24390479
--- /dev/null
+++ b/eval/bank_autonomy/parse_common.py
@@ -0,0 +1,144 @@
+#!/usr/bin/env python3
+"""Common parsers over the coldrun-a paid artifacts (D39.58). $0 — no model calls.
+Reads the durable book artifacts read-only (outside git, per CLAUDE.md). Override dir with $COLDRUN_A."""
+import sqlite3, re, sys, os
+
+SCRATCH = os.environ.get("COLDRUN_A", "/home/ubuntu/books/gu-zhenren/coldrun-a")
+DB = os.path.join(SCRATCH, "guzhenren-coldrun-a.db")
+
+def con():
+ c = sqlite3.connect(f"file:{DB}?mode=ro", uri=True)
+ return c
+
+# ---------- Terminologist passes ----------
+def pass_of(ts):
+ # ts like '2026-07-30 22:05:01'
+ if ts < "2026-07-31":
+ return 1
+ if ts < "2026-07-31 00:20":
+ return 2
+ return 3
+
+def terminologist_rows():
+ """Return list of dicts: pass, chunk_idx, ts, src, dst (one per output line)."""
+ c = con()
+ rows = []
+ for chunk_idx, ts, rt in c.execute(
+ "SELECT chunk_idx, created_at, response_text FROM checkpoints "
+ "WHERE role='terminologist' ORDER BY created_at"):
+ p = pass_of(ts)
+ for ln in rt.split("\n"):
+ ln = ln.rstrip("\n")
+ if not ln.strip():
+ continue
+ # format: srcdst (exactly two fields per prompt)
+ if "\t" in ln:
+ parts = ln.split("\t")
+ else:
+ # tolerant fallback: split on runs of spaces (report both counts)
+ parts = re.split(r"\s{2,}", ln.strip(), maxsplit=1)
+ if len(parts) < 2:
+ rows.append({"pass": p, "chunk_idx": chunk_idx, "ts": ts,
+ "src": parts[0].strip() if parts else "", "dst": "",
+ "malformed": True})
+ continue
+ rows.append({"pass": p, "chunk_idx": chunk_idx, "ts": ts,
+ "src": parts[0].strip(), "dst": parts[1].strip(),
+ "malformed": False})
+ c.close()
+ return rows
+
+# ---------- bank-stop.txt ----------
+def parse_bankstop():
+ """Return dict src -> {dst, origin, type, freq, spread, evidence:[...], drafts:[(v,n)], ctx:[full multi-line window]}.
+ Captures the `evidence:` line and GROUPS multi-line KWIC windows (a `ctx:` line + its indented
+ continuation lines), matching terminology.go RenderBatch (fix after 01.08 author!=reviewer audit)."""
+ path = os.path.join(SCRATCH, "guzhenren-coldrun-a.db.bank-stop.txt")
+ lines = open(path, encoding="utf-8").read().split("\n")
+ recs = {}; cur = None; in_ctx = False
+ FIELD = ("origin=", "evidence:", "drafts:", "aliases:", "related:", "ctx:", "src ")
+ i = 0
+ while i < len(lines):
+ ln = lines[i]
+ if ln and not ln.startswith(" ") and "\t" in ln and i+1 < len(lines) and lines[i+1].lstrip().startswith("origin="):
+ src, dst = ln.split("\t", 1)
+ cur = {"src": src.strip(), "dst": dst.strip(), "evidence": [], "drafts": [], "ctx": []}
+ recs[src.strip()] = cur; in_ctx = False; i += 1; continue
+ if cur is not None:
+ s = ln.strip()
+ if s.startswith("origin="):
+ m = dict(re.findall(r"(\w+)=([^\s]+)", s))
+ cur.update(origin=m.get("origin",""), type=m.get("type",""),
+ freq=int(m.get("freq","0")), spread=int(m.get("spread","0"))); in_ctx=False
+ elif s.startswith("evidence:"):
+ cur["evidence"] = [e.strip() for e in s[len("evidence:"):].split(",") if e.strip()]; in_ctx=False
+ elif s.startswith("drafts:"):
+ for part in s[len("drafts:"):].strip().split(" | "):
+ mm = re.match(r"^(.*?)\s*×(\d+)$", part.strip())
+ if mm: cur["drafts"].append((mm.group(1).strip(), int(mm.group(2))))
+ elif part.strip(): cur["drafts"].append((part.strip(), 1))
+ in_ctx=False
+ elif s.startswith("ctx:"):
+ cur["ctx"].append(s[len("ctx:"):].strip()); in_ctx=True
+ elif s == "":
+ in_ctx=False
+ elif in_ctx and ln.startswith(" "):
+ cur["ctx"][-1] += "\n" + s # continuation line of the current KWIC window
+ i += 1
+ return recs
+
+# ---------- mined-signature.yaml ----------
+def parse_minedsig():
+ """Return list of records with all scalar fields + parsed 'other proposals' from note."""
+ path = os.path.join(SCRATCH, "guzhenren-coldrun-a.db.mined-signature.yaml")
+ txt = open(path, encoding="utf-8").read()
+ recs = []
+ cur = None
+ for ln in txt.split("\n"):
+ if re.match(r"^ - src:", ln):
+ if cur: recs.append(cur)
+ cur = {}
+ cur["src"] = ln.split("src:",1)[1].strip().strip('"')
+ elif cur is not None:
+ m = re.match(r"^ (\w+): (.*)$", ln)
+ if m:
+ k, v = m.group(1), m.group(2)
+ cur[k] = v.strip()
+ if cur: recs.append(cur)
+ # parse note -> other proposals list of (variant,count)
+ for r in recs:
+ note = r.get("note", "")
+ props = []
+ mm = re.search(r"other proposals:\s*(.*?)(?:;|$)", note)
+ if mm:
+ for part in mm.group(1).split(","):
+ p = re.match(r'\s*"(.*?)"\s*×(\d+)', part)
+ if p:
+ props.append((p.group(1), int(p.group(2))))
+ r["other_proposals"] = props
+ # banknote chunk count
+ bn = re.search(r"banknote,\s*(\d+)\s*chunk", note)
+ r["banknote_chunks"] = int(bn.group(1)) if bn else None
+ return recs
+
+# ---------- BANK-FULL.tsv ----------
+def parse_bankfull():
+ path = os.path.join(SCRATCH, "BANK-FULL.tsv")
+ rows = []
+ with open(path, encoding="utf-8") as f:
+ header = f.readline().rstrip("\n").split("\t")
+ for ln in f:
+ cells = ln.rstrip("\n").split("\t")
+ d = dict(zip(header, cells))
+ rows.append(d)
+ return header, rows
+
+if __name__ == "__main__":
+ tr = terminologist_rows()
+ print("terminologist output lines:", len(tr), "malformed:", sum(r["malformed"] for r in tr))
+ bs = parse_bankstop()
+ print("bank-stop terms:", len(bs))
+ ms = parse_minedsig()
+ print("mined-signature records:", len(ms))
+ h, bf = parse_bankfull()
+ print("BANK-FULL rows:", len(bf), "header:", h)
diff --git a/eval/bank_autonomy/term_probe.py b/eval/bank_autonomy/term_probe.py
new file mode 100644
index 00000000..93668b15
--- /dev/null
+++ b/eval/bank_autonomy/term_probe.py
@@ -0,0 +1,179 @@
+#!/usr/bin/env python3
+"""Standalone terminologist wire-probe (backend-independent; direct DeepSeek API).
+Reconstructs the terminologist batch input BYTE-CLOSE to engine RenderBatch (terminology.go:629-660)
+from FROZEN coldrun-a artifacts. Tests fixes for the measured bank defects. $ tracked two ways."""
+from __future__ import annotations
+import argparse, json, os, sys, time
+from pathlib import Path
+from dotenv import load_dotenv
+from openai import OpenAI
+
+REPO = Path("/home/ubuntu/projects/textmachine")
+SC = Path(__file__).resolve().parent # eval/bank_autonomy (for the parse_common import)
+RAW = Path.home() / "books" / "gu-zhenren" / "bank-probes" # durable paid-data sink (outside git)
+RAW.mkdir(exist_ok=True)
+load_dotenv(REPO / "eval" / ".env") # loads DEEPSEEK_API_KEY without us reading .env
+PRICE_IN, PRICE_CACHED, PRICE_OUT = 0.14, 0.0028, 0.28 # flash, models.yaml
+
+TERM_PROMPT = REPO / "backend/prompts/zh-ru/terminologist.md"
+USER_SEP = "\n---USER---\n"
+
+def render_terminologist(text_block: str) -> tuple[str,str]:
+ raw = TERM_PROMPT.read_text(encoding="utf-8")
+ # strip HTML comments
+ 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(); user = user
+ for k,v in vals.items():
+ system = system.replace("{{"+k+"}}", v); user = user.replace("{{"+k+"}}", v)
+ return system, user.strip()
+
+def render_batch(cands: list[dict]) -> str:
+ """Reproduce terminology.go RenderBatch layout from bank-stop fields."""
+ b = []
+ for c in cands:
+ b.append(f"### {c['src']}")
+ b.append(f"key: {c.get('key',c['src'])}\ntype: {c['type']}\norigin: {c['origin']}\nfreq: {c['freq']}\nsince_ch: 0")
+ if c.get("related"): b.append(f"related: {', '.join(c['related'])}")
+ if c.get("evidence"): b.append(f"evidence: {', '.join(c['evidence'])}") # engine emits this (RenderBatch:640)
+ if c.get("drafts"):
+ vs = " | ".join(f"{d} ×{n}" for d,n in c["drafts"])
+ b.append(f"drafts: {vs}")
+ for k in c.get("ctx",[]): b.append(f"ctx: {k}")
+ b.append("")
+ return "\n".join(b).rstrip("\n")
+
+def call(client, system, user, cap, tag, temperature=0.3, prefill=None, effort=None):
+ msgs = [{"role":"system","content":system},{"role":"user","content":user}]
+ if prefill is not None:
+ msgs.append({"role":"assistant","content":prefill,"prefix":True})
+ kw = dict(model="deepseek-v4-flash", messages=msgs, max_tokens=cap)
+ if temperature is not None: kw["temperature"]=temperature
+ if effort: kw["extra_body"]={"reasoning_effort":effort}
+ t0=time.time(); r=client.chat.completions.create(**kw)
+ ch=r.choices[0]; msg=ch.message
+ content=msg.content or ""; reasoning=getattr(msg,"reasoning_content",None) or ""
+ u=r.usage; pt=getattr(u,"prompt_tokens",0)or 0; ct=getattr(u,"completion_tokens",0)or 0
+ det=getattr(u,"completion_tokens_details",None); rt=(getattr(det,"reasoning_tokens",0) if det else 0)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,ts=time.strftime("%Y-%m-%dT%H:%M:%SZ",time.gmtime()),model_returned=r.model,
+ cap=cap,finish=ch.finish_reason,content_chars=len(content),reasoning_chars=len(reasoning),
+ prompt_tokens=pt,cached_tokens=cached,completion_tokens=ct,reasoning_tokens=rt,
+ cost_usd=round(cost,6),latency_s=round(time.time()-t0,1),
+ system=system,user=user,content=content,reasoning_content=reasoning,prefill=prefill)
+ (RAW/f"{tag}.json").write_text(json.dumps(rec,ensure_ascii=False,indent=1),encoding="utf-8")
+ print(f"[{tag}] model={r.model} finish={ch.finish_reason} cap={cap} out={ct} "
+ f"(reason_tok={rt}) content={len(content)}c ${cost:.6f} {rec['latency_s']}s")
+ print(f" CONTENT: {content!r}")
+ return rec
+
+def client():
+ key=os.environ.get("DEEPSEEK_API_KEY")
+ if not key: print("нет DEEPSEEK_API_KEY",file=sys.stderr); sys.exit(2)
+ return OpenAI(api_key=key,base_url="https://api.deepseek.com/v1",timeout=600)
+
+# ---- build candidates from bank-stop ----
+sys.path.insert(0, str(SC))
+from parse_common import parse_bankstop
+BS = parse_bankstop()
+def cand(src, related=None):
+ r=BS[src]
+ return {"src":src,"key":src,"type":r["type"],"origin":r.get("origin",""),
+ "freq":r["freq"],"drafts":r["drafts"],"ctx":r["ctx"],"related":related or [],
+ "evidence":r.get("evidence",[])} # engine-faithful: carry evidence + full multi-line ctx
+
+DENG=["甲等","乙等","丙等","丁等"]
+ZHUAN=["一转","二转","三转","四转","五转","六转","九转"]
+
+# PROBE-B type classifier prompt (candidate 36a validator, NOT the shipped role)
+CLASSIFIER_SYS = """Ты — классификатор терминов книги «蛊真人» (перевод zh→ru). Тебе дан список исходных
+терминов с контекстами из текста. По КАЖДОМУ определи КЛАСС из ровно пяти:
+ name — имя человека или собственное имя клана/семьи (транслитерируется)
+ place — собственное географическое название (транслитерируется)
+ title — должность, звание, титул, обращение, родственная роль (переводится по смыслу)
+ term — нарицательное, понятие, реалия культивации, идиома (переводится по смыслу)
+ nickname — прозвище/эпитет
+Решай по ИСХОДНИКУ и КОНТЕКСТУ, а не по тому, «выглядит ли оно как имя». Общее нарицательное
+(пруд, таверна, комната, источник) — это term/place по смыслу, НЕ имя. Реалия культивации (元石,
+元海) — это term, даже если звучит как имя.
+Формат ответа — по одной строке на термин, ровно два поля через ТАБУЛЯЦИЮ: термин и класс.
+Пример: 方源\tname"""
+
+# CLEAN classifier — NO book-specific examples (fixes the answer-leak in expB)
+CLASSIFIER_SYS_CLEAN = """Ты — классификатор терминов книги при переводе zh→ru. Тебе дан список
+исходных терминов с контекстами из текста. По КАЖДОМУ определи КЛАСС из ровно пяти:
+ name — имя человека или собственное имя клана/семьи
+ place — собственное географическое или локационное название
+ title — должность, звание, титул, обращение или родственная роль
+ term — нарицательное существительное, понятие, реалия или идиома
+ nickname — прозвище или эпитет
+Решай ТОЛЬКО по смыслу исходника и по контексту, а не по тому, «выглядит ли оно как имя».
+Формат ответа — по одной строке на термин, ровно два поля через ТАБУЛЯЦИЮ: термин и класс."""
+
+def classifier_user(cands):
+ b=["Термины:\n"]
+ for c in cands:
+ b.append(f"### {c['src']}")
+ for k in c["ctx"][:3]: b.append(f"ctx: {k}")
+ b.append("")
+ return "\n".join(b).rstrip("\n")
+
+if __name__=="__main__":
+ ap=argparse.ArgumentParser(); ap.add_argument("--mode",required=True); a=ap.parse_args()
+ cl=client(); total=0.0
+ if a.mode=="gate":
+ block=render_batch([cand(x) for x in DENG]); s,u=render_terminologist(block)
+ rec=call(cl,s,u,16000,"gateA1-dengbatch"); total+=rec["cost_usd"]
+ elif a.mode=="A0": # SCATTERED control: each 等-term ALONE (mimics batch split)
+ for x in DENG:
+ block=render_batch([cand(x)]); s,u=render_terminologist(block)
+ rec=call(cl,s,u,16000,f"A0-scattered-{x}"); total+=rec["cost_usd"]
+ elif a.mode=="A1rep": # co-batched reps (stochastic stability of unification)
+ for i in (2,3):
+ block=render_batch([cand(x) for x in DENG]); s,u=render_terminologist(block)
+ rec=call(cl,s,u,16000,f"A1-dengbatch-rep{i}"); total+=rec["cost_usd"]
+ elif a.mode=="Z0": # 转-series scattered
+ for x in ZHUAN:
+ block=render_batch([cand(x)]); s,u=render_terminologist(block)
+ rec=call(cl,s,u,16000,f"Z0-scattered-{x}"); total+=rec["cost_usd"]
+ elif a.mode=="Z1": # 转-series co-batched
+ block=render_batch([cand(x) for x in ZHUAN]); s,u=render_terminologist(block)
+ rec=call(cl,s,u,16000,"Z1-zhuanbatch"); total+=rec["cost_usd"]
+ elif a.mode=="expB": # type classifier over name/place/title + realia controls
+ want=[s for s,r in BS.items() if r["type"] in ("name","place","title","nickname")]
+ # add realia controls known mis-typed or correct
+ for extra in ("元石","元海","真元","蛊室","空窍"):
+ if extra not in want: want.append(extra)
+ cands=[cand(s) for s in want]
+ u=classifier_user(cands)
+ rec=call(cl,CLASSIFIER_SYS,u,16000,"expB-typeclassify",temperature=0.0); total+=rec["cost_usd"]
+ elif a.mode=="expBclean": # RE-RUN with neutral prompt (no answer leak)
+ want=[s for s,r in BS.items() if r["type"] in ("name","place","title","nickname")]
+ for extra in ("元石","元海","真元","蛊室","空窍"):
+ if extra not in want: want.append(extra)
+ cands=[cand(s) for s in want]
+ u=classifier_user(cands)
+ rec=call(cl,CLASSIFIER_SYS_CLEAN,u,16000,"expBclean-typeclassify",temperature=0.0); total+=rec["cost_usd"]
+ elif a.mode=="A0rep": # scattered 等 rep (de-confound stochasticity)
+ for x in DENG:
+ block=render_batch([cand(x)]); s,u=render_terminologist(block)
+ rec=call(cl,s,u,16000,f"A0rep-scattered-{x}"); total+=rec["cost_usd"]
+ elif a.mode=="A0faithful": # FAITHFUL scattered: temp 0, WITH evidence + full multi-line ctx (author!=reviewer fix)
+ for r in (1,2):
+ for x in DENG:
+ block=render_batch([cand(x)]); s,u=render_terminologist(block)
+ rec=call(cl,s,u,16000,f"A0f-scattered-{x}-r{r}",temperature=0.0); total+=rec["cost_usd"]
+ elif a.mode=="A1faithful": # FAITHFUL co-batched: temp 0, WITH evidence + full ctx
+ for r in (1,2):
+ block=render_batch([cand(x) for x in DENG]); s,u=render_terminologist(block)
+ rec=call(cl,s,u,16000,f"A1f-dengbatch-r{r}",temperature=0.0); total+=rec["cost_usd"]
+ print(f"\n=== spent this invocation: ${total:.6f} ===")