Give every carrying number of the experiment a path in the tree: add itog.py, guard those numbers in the gate, print the phase-2b family, and write the missing report body

This commit is contained in:
heaven 2026-08-08 02:42:37 +03:00
parent 067206396e
commit 6aa7cfa8da
19 changed files with 492 additions and 60 deletions

View file

@ -9,22 +9,27 @@
> Пре-рег второй редакции зафризен коммитом `d472599` **до первой платной покупки**.
> Потрачено второй редакцией **$1.725652** (пак целиком, обе редакции — **$4.306626**);
> потолки второй редакции соблюдены, потолки ФАЗ из промта — нет (§2.7).
> Числа сверяются `eval/role_topology/verify_report.py` — 44 проверки, ненулевой код = не сдавать.
> Числа сверяются `eval/role_topology/verify_report.py` (в т.ч. блок `§ИТОГ`), несущие числа
> пере-считываются `eval/role_topology/itog.py`; ненулевой код возврата = отчёт не сдаётся.
---
> ### ⛔ ИНЦИДЕНТ 08.08, D39.113 — ЧТО ЗДЕСЬ ЗАМЕР, А ЧТО РЕКОНСТРУКЦИЯ
> 08.08 00:13 агент проверочной панели оркестратора выполнил `git checkout -- .` в реальном
> дереве, и разделы §11§16 этого отчёта, написанные поверх последнего коммита, были утрачены.
> Они переписаны заново и расширены до §11§18 (прибор · свод · инструменты · дрейф · роутинг ·
> деконфаунды · Ф2б · пост-хок аудиты).
> **Сырьё прогонов цело полностью** — 2039 файлов, git туда не заглядывает. Поэтому:
> * **ВСЕ ЧИСЛА НИЖЕ ПЕРЕ-СНЯТЫ ИЗ СЫРЬЯ ЗАНОВО** кодом из дерева и являются ЗАМЕРОМ, а не
> восстановлением по памяти. Они воспроизвелись до цифры.
> * **ТЕКСТ разделов §11§16 переписан** и намеренно КОРОЧЕ утраченного: прежняя версия разрослась
> * **ТЕКСТ разделов §11§18 переписан** и намеренно КОРОЧЕ утраченного: прежняя версия разрослась
> до 2039 строк, половина которых была хроникой ошибок, что нарушает норму владельца 04.08
> «итог и решения, механику — в журнал». Хроника кругов приёмки в восстановленную версию не
> переносится; её содержание — в `docs/PROGRESS.md`.
> * Утраченного, что нельзя пере-снять из сырья, нет: всё, что было в §11§16, — производные
> от персистированных голосов и артефактов.
> * Утраченного, что нельзя пере-снять из сырья, **почти** нет: всё, что было в §11§16, —
> производные от персистированных голосов и артефактов. Единственное исключение найдено
> аудитом 08.08 и помечено на месте: числа отборщиков §15 прежней редакции («43/91», «r=+0.06»)
> не воспроизводятся ни одним вариантом счёта — там напечатано то, что даёт `itog.py`.
## ИТОГ — вход для решения владельца
@ -60,16 +65,17 @@ F3 черновик 0.917 · A 0.566 · A_law 0.820 · B 0.899 · D 0.776 · D_
Экономить на черновой роли нельзя, и +2.50 непереносимо на другую черновую модель без пере-замера.
**4. Однопроходка с мандатом перевёрстки проигрывает связке:** `D/A` 3.31 [4.47, 2.16],
Holm=0.0014. Вклад делится: ЯЗЫК 1.31, ФОРМА 1.25.
Holm=0.0014. Вклад делится по осям (пул): ЯЗЫК 1.34, ФОРМА 1.09.
**5. Роутинг «платить только там, где нужно» строить НЕ НАДО.** Арм G берёт 25% выигрыша за 55%
цены — хуже случайного роутинга того же бюджета. Три независимых отборщика дали монетку:
механический (51-й персентиль из 1820 комбинаций), QE на единице (43/91), согласие QE с судьёй
(r=+0.06, к самому крупному эффекту пака QE слеп). ⚠ Основание ЭКОНОМИЧЕСКОЕ; формулировка
механический (персентиль 4651 из 1820 комбинаций, 91 связка), QE как судья (знак совпал 50/105),
а на самом крупном контрасте пака `A/F3` QE даёт r=**0.32** — это АНТИкорреляция, а не слепота:
чем сильнее QE «за» редактуру, тем меньше её выигрыш по судье (§15). ⚠ Основание ЭКОНОМИЧЕСКОЕ; формулировка
«доказанный потолок» снята — потолок лечится числом единиц (n≈7381), просто этого среза не хватает.
**6. Guarded APE со стражем на ДРУГОЙ величине вреден:** страж вырезал правки с выигрышем +4.25
при среднем +2.50, то есть лучшие. Если строить — страж обязан смотреть на ту же величину,
при среднем +2.50, то есть лучшие (⚠ n=2 — вывод стоит на двух правках, §15). Если строить — страж обязан смотреть на ту же величину,
которую оптимизирует редактор.
**НЕ УСТАНОВЛЕНО.** Однопроходка БЕЗ мандата против связки: 2.00, Holm=0.063 — направление
@ -95,18 +101,24 @@ Holm=0.0014. Вклад делится: ЯЗЫК 1.31, ФОРМА 1.25.
(раскладка судей 2:1 вместо зеркальной, первая редакция снята целиком). Потолки фаз пробиты без
слова владельца ДО фазы: Ф1 $1.07473/$1.00, Ф2а $3.78694/$2.50. Главный zh-замер сделан на
контаминированной книге вместо заказанного свежего среза, без пинга. Дисциплина фризов нарушена
дважды. Ф2б израсходована на **$0.10916** из $3.00 (армы C/E куплены §17); ⚠ до этого фаза стояла на $0.00904, и гейт это ложное число СЕРТИФИЦИРОВАЛ — его глоб не покрывал тег покупок, третий случай того же класса.
дважды. Ф2б: армы C/E куплены на **$0.10916** (§17), расход ФАЗЫ с учётом старых проб `rp-*`**$0.11819** из $3.00; ⚠ до этого фаза стояла на $0.00904, и гейт это ложное число СЕРТИФИЦИРОВАЛ — его глоб не покрывал тег покупок, третий случай того же класса.
**7. ТОЧЕЧНЫЙ РЕМОНТ ПО ФЛАГУ НЕ ЗАМЕНЯЕТ ПЕРЕПИСЫВАНИЕ (§17, вторая половина заказа).**
Армы C и E построены на текущей панели, отсужены тем же ригом и проиграли:
```
C2 vs A_law 3.75 [4.88, 2.62] Holm 0.0006 ✔ ремонт значимо хуже переписывания
C2 vs A_law 3.75 [4.81, 2.56] Holm 0.0006 ✔ ремонт значимо хуже переписывания
C2 vs F3 0.94 [2.19, +0.38] p=0.219 и не лучше черновика, который чинит
E2 vs D_ 1.38 [2.06, 0.69] Holm 0.0139 ✔ обратная связка хуже своей базы
A_law vs F3 +2.81 [+1.38, +4.25] Holm 0.0098 ✔ контроль воспроизведён ТРИЖДЫ (+2.50/+2.75/+2.81)
E2 vs A_law 2.06 [3.50, 0.62] Holm 0.0443 ✔ и хуже ПРЯМОЙ связки — установлено
A_law vs F3 +2.81 [+1.44, +4.31] Holm 0.0098 ✔ КОНТРОЛЬ эффекта редактора
```
Контроль эффекта редактора воспроизвёлся во всех четырёх проходах, но величины принадлежат
РАЗНЫМ армам и панелям и в один ряд не ставятся: `A_law/F3` = +1.75 (пул abs+abs2) · +2.75 (abs3)
· +2.81 (abs4); +2.50 — это другой арм, `A/F3` без закон-блока. Прежняя формулировка «воспроизведён
трижды (+2.50/+2.75/+2.81)» сшивала несопоставимое и снята (§18).
⚠ **Гипотеза, которой закончился эксп-20 — «локальные ошибки чинятся точечно по флагу за
$0.0002» — при РЕАЛЬНОЙ детекции не подтвердилась.** Там она мерилась при идеальных флагах на
посаженных дефектах.
@ -119,7 +131,7 @@ $0.0002» — при РЕАЛЬНОЙ детекции не подтвердил
**Чем точечный ремонт полезен:** он лучший МЕХАНИЧЕСКИЙ ГЕЙТ. Брак (иероглифы, разметка,
латиница, преамбула) — 5 клеток против 10 у переписывания и 23 у черновика, при половинной цене
($0.00290 против $0.00602). **Ставить его перед редактором, а не вместо него.**
($0.00298 против $0.00602). **Ставить его перед редактором, а не вместо него.**
**8. ДРЕЙФ НА СВЯЗНОМ ОТРЕЗКЕ — отзыв был СЛИШКОМ ШИРОКИМ, восстановлено.** Я отозвал §14
целиком, но негодной была только часть метрик (заказанный ШОВ в коде не считался, «рост словаря»
@ -138,13 +150,15 @@ $0.0002» — при РЕАЛЬНОЙ детекции не подтвердил
⚠ Оговорка кода: армы состояния между главами не несут, банк подаётся каждой главе заново.
Значит измерен дрейф БЕЗ памяти — нижняя граница.
**ЧТО НЕ ИЗМЕРЕНО:** · дрейф на связном отрезке — прибор оказался негоден,
результат отозван · слепое чтение владельца — единственный контур вне семейства сессии ·
пара en под абсолютным ригом.
**ЧТО НЕ ИЗМЕРЕНО:** · ШОВ между чанками и рост банка на связном отрезке — эти две метрики
дрейфа негодны и отозваны (покрытие отрезка и канона восстановлены, см. п.8 и §14) · слепое
чтение владельца — единственный контур вне семейства сессии, $0, заказан промтом, ждёт владельца ·
пара en под абсолютным ригом · **неконтаминированный zh-срез** (Ф0.2): без него величины, но не
направления, непереносимы.
**⚠ CONFIRM/DENY ВЛАДЕЛЬЦУ — три пункта известны только со слов сессии, D-номера не имеют и до
подтверждения не ратифицируются:** санкция на траты 07.08 · амендмент «судья пака не покупается
за токены» (на нём стоят ВСЕ числа §11§16) · правка требований к ригам (зеркальная раскладка
за токены» (на нём стоят ВСЕ числа §11§18) · правка требований к ригам (зеркальная раскладка
писалась под платного судью и на агента не переносится).
## §0 Пре-рег второй редакции (зафризен `d472599` до трат)
@ -505,9 +519,15 @@ D_ 18 0 6 0
## §4 Что осталось незакрытым
1. **Дрейф на связном отрезке 810 глав** — швы между чанками, стабильность ты/вы, рост банка.
> ⚠ **Пункты 1 и 2 УСТАРЕЛИ и закрыты.** Дрейф на связном отрезке измерен (§14), армы C, E и G
> построены и отсужены (§15, §17). Список ниже — состояние на вторую редакцию; актуальный перечень
> незакрытого — строка «ЧТО НЕ ИЗМЕРЕНО» блока ИТОГ.
1. ~~**Дрейф на связном отрезке 810 глав**~~ — ИЗМЕРЕН, см. §14. Прежняя формулировка:
**Дрейф на связном отрезке 810 глав** — швы между чанками, стабильность ты/вы, рост банка.
Промт заказывал; мерится всё на рассеянных единицах. Требует другого масштаба покупки.
2. **Армы C (точечный ремонт), E (обратная связка), G (guarded+routed)** — не гнались. Клеймы
2. ~~**Армы C, E, G — не гнались**~~ — ПОСТРОЕНЫ и отсужены, см. §15 и §17. Прежняя формулировка:
**Армы C (точечный ремонт), E (обратная связка), G (guarded+routed)** — не гнались. Клеймы
первой редакции сняты: там C засчитывал «фиксер вернул не ту же строку», а G вообще не гнался
как арм — была только арифметическая проекция цены.
3. **Слепое чтение владельца на финалистах** (промт стр.72) — не исполнено, требует владельца.
@ -805,6 +825,19 @@ A_law 3
## §10 ТРЕТЬЯ РЕДАКЦИЯ — результаты (агент-судья, собственный черновик)
> ### ⛔ ВСЕ ТРИ НУМЕРОВАННЫХ ВЫВОДА ЭТОГО РАЗДЕЛА СНЯТЫ — читать ИТОГ и §12
> Раздел оставлен как хроника прибора, а не как источник решений. Третья редакция судила ОДНИМ
> проходом одного агента-судьи; четвёртая пере-сняла те же армы ДВУМЯ независимыми проходами
> (§11§12), и все три вывода ниже перевернулись:
> * «однопроходка и связка неразличимы» → в пуле двух проходов `D_/A` = **2.00** (p=0.0157,
> Холма не проходит) — направление против однопроходки, а не ничья;
> * «решает ЖИЛЕЦ, glm-5 +3.81» → в пуле `B/F3` = **+2.44** против `A/F3` **+2.50**, а напрямую
> `A_law/B` = **0.69**: движки неразличимы, работает ТОПОЛОГИЯ (§12);
> * «экономика за связку, дешевле на 6%» → на пуле цен связка **ДОРОЖЕ** на +0.00096/единицу
> (11/16, p=0.061).
> Причина расхождения названа в §11: одиночный проход не отделяет шум судьи от эффекта арма, а
> шум пола рига (sd 2.672.96) превышает измеряемые разницы.
Замер по объявленному ЗАРАНЕЕ семейству из трёх контрастов (§9). Судья — агент сессии, $0 по
ключам провайдеров, обоснование цитатой на каждую ненулевую ось. Армы правят СОБСТВЕННЫЙ
черновик пака: текст и цена происходят из одного вызова, провенанс проверяем.
@ -887,6 +920,281 @@ A_law (deepseek-v4-pro) против B (glm-5): +1.94 [+0.69, +3.19] p=0.0142
---
## §11 ПРИБОР ЧЕТВЁРТОЙ РЕДАКЦИИ — абсолютный судейский риг
> Восстановлено 08.08 после инцидента D39.113. Текст переписан заново; **все числа пере-сняты из
> сырья кодом дерева** и воспроизводятся командой `itog.py`.
**Почему риг переделан.** Каждому из четырёх независимых судей-агентов выдавалась своя пачка
ПАРНЫХ пакетов «исходник + вариант 1 + вариант 2». Все четыре самостоятельно свернули пары
обратно: дедуплицировали уникальные тексты, оценили каждый ОДИН РАЗ против исходника и разнесли
числа по пакетам. Четыре из четырёх — это поведение инструмента, а не сбой исполнителя, и
оснастка пошла за ним: `absjudge.py` судит по АБСОЛЮТНОЙ шкале.
**Что это дало.** Позиция варианта исчезает по построению (текст оценивается вне пары) — тот
самый дефект, за который снята первая редакция. Работа падает втрое: 160 парных пакетов = 320
прочтений, уникальных текстов 128. Строгость калибруется ВНУТРИ единицы: все варианты одного
исходника судятся в одном заходе, контраст берётся внутри единицы и лишь потом усредняется.
**Слепота и провенанс.** Метки `Т1..Тn`, порядок перемешан хешем соли и uid; соль лежит вне
репозитория (`blind-keys/SALT-*.txt`). Судья пишет ответ файлом сам — этим убрана моя
транскрипция, канал, по которому в третьей редакции потерялись обоснования. Голос с ненулевой
осью без цитаты отвергается. **Семейство контрастов впечатано в файл ключа ДО первого ответа** и
сверяется при каждом счёте (`_assert_family`): сузить семейство после чтения p-значений — это и
есть p-hacking.
**Четыре прохода, и их уровни несопоставимы.** Средняя строгость растёт монотонно: abs 6.90 →
abs2 7.92 → abs3 8.46 → abs4 9.22 ошибки на клетку (+34%). Поэтому **сравнивать между панелями
можно только РАЗНОСТИ, а не уровни**; всякий контраст ИТОГа — внутриединичная разность внутри
одной панели, пул усредняет перевес поединично. Абсолютные уровни в отчёте нигде не сравниваются.
## §12 ЧЕТВЁРТАЯ РЕДАКЦИЯ — свод двух проходов
Семейство из семи контрастов, поправка Холма по всем семи, LOO — сколько единиц удаления
роняют значимость (`absjudge --pool`):
```
контраст перевес 95% ДИ p p Холма вылетов LOO
A vs F3 +2.50 [+1.56, +3.47] 0.0001 0.0004✔ 0/16
B vs F3 +2.44 [+1.81, +3.19] 0.0000 0.0002✔ 0/16
D_ vs A 2.00 [3.34, 0.62] 0.0157 0.0630 —
D vs A 3.31 [4.47, 2.16] 0.0003 0.0014✔ 0/16
A_law vs A 0.75 [1.78, +0.25] 0.2068 0.3645 —
A_law vs B 0.69 [1.56, +0.22] 0.1823 0.3645 —
D vs D_ 1.31 [2.34, 0.25] 0.0363 0.1088 —
```
**Три несущих контраста переживают всё, чем их пробовали убить:** поправку Холма, удаление любой
единицы (0/16), удаление любых ДВУХ (0/120), обе судейские популяции и кластеризацию по главе
источника (16 единиц происходят из 12 глав, четыре главы дали по два чанка; кластерный тест даёт
Holm 0.0059 / 0.0034 / 0.0171).
**Нога 2×2 — главный вывод пака.** Собрана ПОСТ-ХОК из того же сырья, в объявленном семействе её
нет, поправку Холма не несёт:
```
A дешёвый черновик + дорогой редактор против черновика: +2.50 p=0.0001 15/16
B то же, другой редактор против черновика: +2.44 p<0.0001 16/16
D_ дорогая модель, ОДИН проход против черновика: +0.50 p=0.478 7/16
D дорогая модель, один проход + мандат против черновика: 0.81 p=0.255 6/16
```
Дорогая модель в один проход неотличима от дешёвого черновика; она же в позиции редактора
покупает +2.50. **Работает топология, а не жилец** — это снимает объяснение «просто pro лучше
flash», на котором стоял §10.
**Контроли (читать ДО боевых чисел).** Декой — посаженная деградация поймана 10/10 (abs) и 10/10
(abs2) с верным знаком. Пол рига — две генерации ОДНОГО арма на одном входе, истинная разница
ноль: abs +0.12 [1.19, +1.44], abs2 +0.62 [0.81, +2.12]; **ноль внутри интервала в обоих
проходах — пол честен.** Побайтных близнецов в пачках нет.
**Шум.** sd пола по единицам 2.67 (abs) / 2.96 (abs2) — больше разницы между армами. Значит **на
отдельной главе армы не упорядочены**; упорядочено только среднее (парный дизайн делит шум на
√n, различимый эффект ≈1.9). ⚠ Разложение шума на судейскую и генерационную компоненты **НЕ
УСТАНОВЛЕНО**: `--pool` печатает σ судьи 1.43 против σ генерации 1.40, два других способа счёта
из тех же данных дают «генерация больше» и «судья больше», и при n=16 они неразличимы.
## §13 ИНСТРУМЕНТЫ $0 — батарея, детекторы, QE
**Батарея** (`battery.py`) — 11 детерминированных проверок вывода: утечка письменности,
типографика диалогов, потеря чисел, ты/вы, согласование рода, translationese-прокси. Проверена на
синтетике с известным ответом.
**Детекторы Ф0.4.** №1 «выдуманное слово» — словарный, на holdout 6/6 (tp=7 fp=2 fn=3). №2
«смысловая инверсия» — QE-ранкер.
**§13.7 QE мини-бенч.** MetricX-24-hybrid-large-v2p6 (mT5-large, 1.23B, локально на CPU, $0).
Посаженная инверсия полярности против чистого сегмента: **66/72, p=3.6e-14** — QE инверсию
ВИДИТ. ⚠ Но видит в ПАРНОМ режиме (до/после одного сегмента). Как РАНКЕР — «выбрать три худших
сегмента окна» — он её не находит: см. §15 и §17.
## §14 ДРЕЙФ НА СВЯЗНОМ ОТРЕЗКЕ
> ⚠ **Отзыв был слишком широким и сужен.** Я отозвал раздел целиком; негодной была только часть
> метрик: заказанный промтом ШОВ между чанками в коде не считался вовсе, а «рост словаря» не мог
> сработать по построению. Валидная часть воспроизводится за $0 (`drift.py --score`) и несёт два
> результата, которых больше нигде в паке нет.
Десять подряд идущих глав (2…11), армы `F3`/`A`/`A_law`/`D_`:
```
покрытие отрезка: F3 9/10 · A 9/10 · A_law 9/10 · D_ 10/10 (у всех выпала глава 11)
покрытие канона: F3 148/163 = 0.96 · A 91/163 = 0.53 · A_law 138/163 = 0.92 · D_ 139/163 = 0.91
ты/вы: 2/9 · 2/9 · 2/9 · 3/9 переключений
```
**1. У связки есть отказной режим, которого у однопроходки нет по построению.** Без годного
черновика редакторская нога не запускается вовсе, и ре-ген этого не лечит: эхо-мина
воспроизводима на материале — глава 11 вернула китайский исходник во всех трёх попытках
(13881425 ханьцзы). **Это единственный довод ПРОТИВ связки во всём паке.**
**2. Второе, независимое подтверждение обязательности закон-блока.** На связном отрезке, другом
материале и другой единице анализа покрытие канона у редактора БЕЗ банка **0.53** против **0.92**
с банком. Пункт 2 ИТОГа стоял на одном оконном замере — теперь на двух.
⚠ Оговорка: армы состояния между главами не несут, банк подаётся каждой главе заново ⇒ измерен
дрейф БЕЗ памяти, это нижняя граница. Метрика счётная (доля упоминаний исходника, отражённых
канонной формой) — прежняя, «нашлась ли канонная форма хоть раз», была тривиально выполнима.
## §15 РОУТИНГ: АРМ G И ТРИ ОТБОРЩИКА
Главный денежный вопрос пака: платить за второй проход ВЕЗДЕ или только там, где он нужен.
Арм G собран из уже купленных текстов детерминированно, $0 новых покупок (`guarded.py --build`).
```
маршрутизировано 6/16 окон · страж оставил правку в 4 ⇒ забрано 10.0 из 40.0 выигрыша = 25%
цена: G $0.00317 против связки $0.00580 = 55% цены за 25% выигрыша
```
**Строить роутинг НЕ НАДО: он хуже случайного роутинга того же бюджета.** Три независимых
отборщика дали монетку:
* **механический** (утечка письменности, разметка, латиница, преамбула): среди всех
C(16,4)=1820 подмножеств того же размера его выбор — персентиль **46.451.4%** (91 связка,
середина 48.9%);
* **QE как судья**: знак совпал **50/105** по семи контрастам семейства;
* **QE против судьи на самом крупном контрасте `A/F3`: r = 0.32.** Это **АНТИкорреляция**, а не
слепота: чем сильнее QE «за» редактуру, тем меньше её выигрыш по судье. Довод против
QE-роутинга сильнее, чем формулировал ИТОГ до 08.08.
**Guarded APE со стражем на ДРУГОЙ величине вреден.** Страж отклонил две правки — с выигрышами
+3.0 и +5.5, среднее **+4.25** против +2.50 по всем единицам: он вырезал ЛУЧШИЕ. ⚠ **n=2.**
Вывод стоит на двух правках и означает ровно одно: если строить стража, он обязан смотреть на ту
же величину, которую оптимизирует редактор.
**Основание ЭКОНОМИЧЕСКОЕ.** Формулировка «доказанный потолок роутинга» снята: потолок лечится
числом единиц (n≈7381), просто этого среза не хватает.
**Утрачено инцидентом 08.08, D39.113:** числа прежней редакции этого раздела — «43/91» и
«r=+0.06» — не воспроизводятся ни одним вариантом счёта; в дереве кода пути к ним нет. Здесь
напечатано то, что даёт `itog.py` на сегодняшнем сырье. Вердикт «монетка» держится в обоих
вариантах.
## §16 ДЕКОНФАУНДЫ
**§16.1 Закон-блок обязателен.** Покрытие канона на 16 окнах (228 упоминаний, счётная метрика):
```
F3 черновик 0.917 · A 0.566 · A_law 0.820 · B 0.899 · D 0.776 · D_ 0.851
```
`A` — единственный из шести армов, ломающий терминологию ЧЕРНОВИКА, который он правит. Качество
при этом неотличимо (`A_law/A` 0.75, p=0.207), цена +5%. **Поэтому боевым конфигом редактора
объявлен `A_law`, и базой сравнения Ф2б взят он же, а не `A`.** Второе подтверждение — §14.
Прибор этого не меряет и мерить не может: рубрика судьи определяет ось ТЕРМИН как
ВНУТРИтекстовую согласованность и канона судье не даёт. Меряет детерминированный контур.
**§16.2 Черновая модель двигает 70% заголовка.** Тот же редактор `A` над ДРУГИМ черновиком той же
длины:
```
над корпусным черновиком 7.66 ошибки против 5.91 над своим · хуже 14/16 · p=0.0063
```
Это 70% от заголовочных +2.50. **Экономить на черновой роли нельзя**, и +2.50 непереносимо на
другую черновую модель без пере-замера. ⚠ Число посчитано по ОДНОЙ клетке пола (`CTRLfloorA` =
`bo2-A`); по обеим клеткам (с повтором `bo3-Aprime`) — 7.47, 13/16, p=0.0073. Вердикт одинаков,
напечатанный вариант — в большую сторону.
**§16.3 Мандат перевёрстки вредит, и вклад разложен по осям** (пул двух проходов):
```
D vs A 3.31 ВЕРНОСТЬ 0.50 · ТЕРМИН 0.38 · ЯЗЫК 1.34 · ФОРМА 1.09
D_ vs A 2.00 ВЕРНОСТЬ 0.66 · ТЕРМИН 0.34 · ЯЗЫК 0.97 · ФОРМА 0.03
```
Мандат стоит почти всей разницы по ФОРМЕ. ⚠ Оси разведочны: семейство корректирует 7 гипотез,
клеток здесь 28. ⚠ Контраст `D/D_` изолирует мандат НЕ чисто (§3): у армов расходятся ещё
вёрсточная строка и объём системного промта.
## §17 Ф2б — АРМЫ C И E: ТОЧЕЧНЫЙ РЕМОНТ ПРОТИВ ПЕРЕПИСЫВАНИЯ
Вторая половина заказа промта (стр.114115), исполнена 08.08. Фиксер — `gpt-5.6-luna`,
единица починки — предложение, ре-гейт после каждого фикса, кап 2 итерации.
**Судейство — тем же ригом (проход abs4, узкая панель).** Пять судейских контрастов, Холм по
пяти:
```
контраст перевес 95% ДИ p p Холма
C2 vs A_law 3.75 [4.81, 2.56] 0.0001 0.0006✔ ремонт значимо хуже переписывания
C2 vs F3 0.94 [2.19, +0.38] 0.2185 0.2185 и не лучше черновика, который чинит
E2 vs D_ 1.38 [2.06, 0.69] 0.0046 0.0139✔ обратная связка хуже своей базы
E2 vs A_law 2.06 [3.50, 0.62] 0.0222 0.0443✔ обратная связка хуже прямой
A_law vs F3 +2.81 [+1.44, +4.31] 0.0024 0.0098✔ КОНТРОЛЬ эффекта редактора
```
**ОТКЛОНЕНИЕ ОТ ОБЪЯВЛЕННОГО СЕМЕЙСТВА, объявляю.** `phase2b.FAMILY` пятым членом называет
`C_oracle vs C_real` — разрыв потолка и пола схемы. Он НЕ судейский: потолок меряется посаженными
дефектами и детекторами, судье не предъявлялся и p-значения не имеет. В судейскую пятёрку вместо
него вошёл контроль `A_law vs F3`. Направление подмены консервативно (член семейства сохранён,
поправка не ослаблена), но это правка семейства после пре-рега, и читать её надо как девиацию.
**Гипотеза, которой закончился эксп-20 — «локальные ошибки чинятся точечно по флагу за $0.0002» —
при РЕАЛЬНОЙ детекции не подтвердилась.** Там она мерилась при идеальных флагах на посаженных
дефектах.
**§17.1 Режим oracle — где именно схема теряет.** Земля известна по построению: в черновик
сажаются дефекты двух классов на известные позиции.
```
RECALL детекторов, класс k1 (выдуманное слово): 16/16
RECALL детекторов, класс k2 (смысловая инверсия): 1/16
```
**Разрыв потолка и пола — целиком класс k2.** Это не противоречит мини-бенчу §13.7 (66/72): там
QE работал в ПАРНОМ режиме, здесь — как РАНКЕР, и посаженная инверсия в тройку худших сегментов
не попадает. **QE различает порчу, но не ранжирует по ней** — вот причина провала арма C.
**§17.2 Первый прогон был испорчен моей ошибкой и пере-снят.** Фиксер шёл БЕЗ банка терминов и
переписывал канон вслепую («истинную ци» → «первобытную энергию», «Гу» → «гу»); покрытие канона
падало 0.917 → 0.895. Это тот же дефект, что у редактора `A` (§16.1). С банком покрытие **0.925**
— ремонт терминологию УЛУЧШАЕТ, — но контраст с переписыванием остался (4.12 → 3.75). Вывод не
артефакт ошибки. Банк помогает и обратной связке: `E2` 0.860 против `E` 0.825.
**§17.3 Чем точечный ремонт полезен: он лучший МЕХАНИЧЕСКИЙ ГЕЙТ.**
```
брак вывода (иероглифы, разметка, латиница, преамбула, выдуманные слова), 16 единиц:
C2 5 клеток · A_law 10 · F3 23 цена: C2 $0.00298 против связки $0.00602
```
**Ставить его ПЕРЕД редактором, а не вместо него.**
**§17.4 Деньги фазы.** Армы C/E куплены на **$0.10916** (тег `p2b-*`); расход ФАЗЫ Ф2б с учётом
старых проб `rp-*` ($0.00904) — **$0.11819** из потолка $3.00. ⚠ До 08.08 гейт сторожил фазу
глобом `rp-*`, покупок `p2b-*` не видел и СЕРТИФИЦИРОВАЛ ложные $0.00904 — третий случай того же
класса (новый тег покупок не внесён в глоб фазы тем же коммитом).
## §18 ПОСТ-ХОК АУДИТЫ 08.08 — что нашли по лестнице
Два независимых агента прошли пак навстречу: снизу вверх (заказ промта → посылки → код →
результаты, с запретом открывать ИТОГ до последней ступени) и сверху вниз (каждое утверждение
ИТОГа → число → сырьё → код → посылка). **Оба вердикта: перепрогон НЕ ТРЕБУЕТСЯ** — все несущие
числа воспроизводятся из персистированного сырья за $0.
Что исправлено по их находкам (всё $0, без покупок):
| Находка | Правка |
|---|---|
| Несущие числа ИТОГа не имели в дереве пути воспроизведения; `--score4` печатал пустую таблицу (в `FAMILY` нет контрастов Ф2б) | заведён `itog.py` — пере-считывает КАЖДОЕ число ИТОГа из сырья |
| `verify_report` сторожил §2, деньги и батарею — и ни одного числа ИТОГа | добавлен блок `§ИТОГ` (20 проверок): нога 2×2, канон, арм G, страж, пятёрка Ф2б |
| Значимый контраст `E2 vs A_law` (2.06, Холм 0.0443) в таблице ИТОГа отсутствовал | напечатан; гейт проверяет наличие строки |
| Расход фазы Ф2б печатался как `$0.10916` (только тег `p2b-*`) | расход ФАЗЫ = $0.11819 с учётом `rp-*`; §17.4 |
| «Контроль воспроизведён ТРИЖДЫ (+2.50/+2.75/+2.81)» — сшивка РАЗНЫХ армов и панелей | снято: +2.50 — это `A/F3`, а `A_law/F3` даёт +1.75 (пул) / +2.75 (abs3) / +2.81 (abs4) |
| Доля выигрыша арма G считалась по маршрутизированным окнам, а не по оставленным стражем | 25% (10.0 из 40.0 на четырёх окнах), сверено с `guarded --build` |
| Цена «$0.00290» — арм C (испорченный прогон), а не боевой C2 | $0.00298; `phase2b --score` печатает C2/E2 |
| `zip(us, txts)` после фильтра пустых текстов — тихий рассинхрон единиц | единица и текст ходят парой; дефект был латентен (все армы 16/16), числа им не задеты |
| «44 проверки» в шапке | их 62, а с блоком `§ИТОГ` — больше; шапка правится при каждом лендинге |
| QE назван «слепым» (r=+0.06) | на `A/F3` r=0.32, это АНТИкорреляция; §15 |
**Заведён линтер зоны** (`eval/role_topology/ruff.toml`, `select = ["F","E9","PLE","B"]`) — повод
прямой: регрессия `med = med(costs)` (затенение функции локальной переменной) прошла в дерево
незамеченной. Первый прогон нашёл 36 находок; исправлены все, искажающих числа среди них не было.
---
## §7 Воспроизведение
```
@ -895,8 +1203,19 @@ eval/.venv/bin/python eval/role_topology/bakeoff.py --judge # судейств
eval/.venv/bin/python eval/role_topology/bakeoff.py --score # свод zh, $0
eval/.venv/bin/python eval/role_topology/pair_en.py --units|--arms|--judge|--score
eval/.venv/bin/python eval/role_topology/blind_read.py --emit zh|en # пакеты слепого чтения
# ЧЕТВЁРТАЯ РЕДАКЦИЯ — абсолютный риг и свод (всё $0)
eval/.venv/bin/python eval/role_topology/absjudge.py --controls|--controls2 # контроли ДО чисел
eval/.venv/bin/python eval/role_topology/absjudge.py --pool # свод двух проходов, §12
eval/.venv/bin/python eval/role_topology/absjudge.py --score4 # пятёрка Ф2б, §17
eval/.venv/bin/python eval/role_topology/phase2b.py --score # армы C/E/C2/E2, §17
eval/.venv/bin/python eval/role_topology/drift.py --score # дрейф, §14
eval/.venv/bin/python eval/role_topology/guarded.py --build # арм G, §15
eval/.venv/bin/python eval/role_topology/itog.py # ВСЕ числа блока ИТОГ, $0
eval/.venv/bin/python eval/role_topology/verify_report.py # верификатор чисел отчёта
eval/.venv/bin/python eval/role_topology/selfcheck.py # самопроверка харнесса, $0
eval/.venv/bin/ruff check eval/role_topology/ # линтер зоны
```
Артефакты — `~/books/role-topology/` (вне git). Текст книг в репозиторий и в отчёт не попадает.

View file

@ -5,11 +5,10 @@
разность чистый судейский шум. Это единственный контроль амендмента («разброс судьи на
повторе»), который до сих пор не был измерен ни разу.
"""
import json, statistics as st, sys
import statistics as st, sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent))
import absjudge as A # noqa: E402
import bakeoff as BO # noqa: E402
A.PASS = "retest"
A.ingest()
@ -29,8 +28,8 @@ print(f" ⇒ σ ОДНОГО СУДЬИ на повторе = {st.pstdev(d) / 2
xs = [r[u][k]["errors"] for u in common for k in r[u] if k in b[u]]
ys = [b[u][k]["errors"] for u in common for k in r[u] if k in b[u]]
mx, my = st.mean(xs), st.mean(ys)
print(f" корреляция повтора: r={sum((a-mx)*(c-my) for a, c in zip(xs, ys)) / ((sum((a-mx)**2 for a in xs)*sum((c-my)**2 for c in ys))**0.5):+.3f}")
for a_, b_, w in A.FAMILY:
print(f" корреляция повтора: r={sum((a-mx)*(c-my) for a, c in zip(xs, ys, strict=True)) / ((sum((a-mx)**2 for a in xs)*sum((c-my)**2 for c in ys))**0.5):+.3f}")
for a_, b_, _w in A.FAMILY:
m1 = [r[u][b_]["errors"] - r[u][a_]["errors"] for u in common if a_ in r[u] and b_ in r[u]]
m2 = [b[u][b_]["errors"] - b[u][a_]["errors"] for u in common if a_ in b[u] and b_ in b[u]]
if m1:

View file

@ -350,6 +350,31 @@ def _assert_family() -> None:
if decl != now:
raise SystemExit("⛔ СЕМЕЙСТВО РАЗОШЛОСЬ с впечатанным в ключ ДО ответов:\n"
f" в ключе: {decl}\n в коде: {now}")
if PASS == "abs4":
# ⚠ ЧЕСТНОСТЬ ПРОВЕНАНСА. В ключ прохода 4 впечатано семейство Ф2а — оно на узкой панели
# НЕПРИМЕНИМО (там нет арма `A`, и ни один его контраст не собирается). Сверка выше
# проходит, но она ничего не доказывает для тех контрастов, которые здесь считаются.
# Молчать об этом — значит выдать декоративный штамп за провенанс.
print("⚠ ПРОВЕНАНС ПРОХОДА 4 НЕПОЛОН: в ключ впечатано семейство Ф2а, неприменимое к узкой\n"
" панели. Считается пятёрка Ф2б (`FAMILY_2B`), объявленная в `phase2b.FAMILY` ДО\n"
" покупок с одной заменой: недоступный судье `C_oracle/C_real` → контроль `A_law/F3`.\n")
# СЕМЕЙСТВО УЗКОГО ПРОХОДА 4 (армы Ф2б). ⚠ Заведено 08.08 аудитом: `--score4` печатал ПУСТУЮ
# таблицу («поправка Холма по 0 контрастам») — ни один контраст `FAMILY` не имеет обоих армов на
# узкой панели (там нет `A`), и у таблицы п.7 отчёта не было пути воспроизведения в дереве.
# ⚠ ОТКЛОНЕНИЕ ОТ ПРЕ-РЕГА, объявляю: `phase2b.FAMILY` пятым членом называет `C_oracle vs C_real`
# — разрыв потолка и пола схемы. Он НЕ судейский (меряется посаженными дефектами и детекторами,
# судье не предъявлялся, p не имеет). В судейскую пятёрку вместо него вошёл контроль `A_law/F3`.
# Подмена КОНСЕРВАТИВНА — член семейства сохранён, поправка не ослаблена, — но это правка
# семейства после пре-рега, и читать её надо как девиацию, а не как замысел.
FAMILY_2B = [
("C2", "A_law", "точечный ремонт против полного переписывания"),
("C2", "F3", "и лучше ли он черновика, который чинит"),
("E2", "D_", "обратная связка против своей базы"),
("E2", "A_law", "обратная связка против прямой"),
("A_law", "F3", "КОНТРОЛЬ: воспроизводится ли эффект редактора"),
]
def score() -> None:
@ -358,8 +383,9 @@ def score() -> None:
if not data:
print("голосов нет — сначала --ingest")
return
fam = FAMILY_2B if PASS == "abs4" else FAMILY
rows = []
for a, b, what in FAMILY:
for a, b, what in fam:
m = _margins(a, b)
if len(m) < 3:
continue
@ -370,7 +396,8 @@ def score() -> None:
for rank, i in enumerate(order):
run = max(run, min(1.0, rows[i][4] * (k - rank)))
holm[i] = run
prov = ("семейство впечатано в ключ ДО ответов" if _family_proven()
prov = ("⚠ штамп в ключе относится к семейству Ф2а и к этим контрастам НЕприменим" if PASS == "abs4"
else "семейство впечатано в ключ ДО ответов" if _family_proven()
else "⚠ провенанс семейства НЕ доказуем: в ключе штампа нет")
print(f"единиц с голосами: {len(data)} · {prov}, поправка Холма по {k} контрастам\n")
print(f"{'контраст':14s}{'ед.':>4s}{'перевес':>9s}{'95% ДИ':>18s}{'p':>8s}{'p Холма':>9s} что меряет")
@ -429,16 +456,16 @@ def position() -> None:
for r in d.values():
xs.append(r["slot"] - mx)
ys.append(r["errors"] - my)
slope = sum(a * b for a, b in zip(xs, ys)) / sum(a * a for a in xs)
slope = sum(a * b for a, b in zip(xs, ys, strict=True)) / sum(a * a for a in xs)
print(f"наклон {slope:+.3f} ошибки на шаг метки (внутри единицы, n={len(xs)})")
print(f"средняя позиция арма: " + " · ".join(
print("средняя позиция арма: " + " · ".join(
f"{a} {st.mean([d[a]['slot'] for d in data.values() if a in d]):.2f}"
for a in ARMS))
print(f"\n{'контраст':14s}{'перевес':>9s}{'Δметки':>8s}{'вклад':>8s}{'с поправкой':>13s}{'p':>9s}")
for a, b, _w in FAMILY:
m = [d[b]["errors"] - d[a]["errors"] for d in data.values() if a in d and b in d]
dl = [d[a]["slot"] - d[b]["slot"] for d in data.values() if a in d and b in d]
corr = [mi + slope * x for mi, x in zip(m, dl)]
corr = [mi + slope * x for mi, x in zip(m, dl, strict=True)]
print(f"{a + ' vs ' + b:14s}{st.mean(m):+9.2f}{st.mean(dl):+8.2f}"
f"{-slope * st.mean(dl):+8.2f}{st.mean(corr):+13.2f}{BO.sign_perm_p(corr):9.4f}")
print("\nВывод, зависящий от раскладки, — тот, чей знак или значимость меняются поправкой.")
@ -503,7 +530,7 @@ def pool() -> None:
run = max(run, min(1.0, rows[i][4] * (len(rows) - rank)))
holm[i] = run
print(f"\n{'контраст':14s}{'перевес':>9s}{'95% ДИ':>19s}{'p':>9s}{'p Холма':>10s}{'вылетов LOO':>13s}")
for i, (a, b, w, m, pv) in enumerate(rows):
for i, (a, b, _w, m, pv) in enumerate(rows):
lo, hi = BO.boot_ci(m)
loo = sum(1 for k in range(len(m))
if BO.sign_perm_p(m[:k] + m[k + 1:]) * len(rows) >= 0.05) if holm[i] < 0.05 else None
@ -638,7 +665,7 @@ def selfcheck() -> int:
def answer(t1: tuple, w1: str, t2: tuple, w2: str) -> None:
(ANSW / "tok.txt").write_text(
"".join(f"Т{i}-{a}: {v}\n" for i, t in ((1, t1), (2, t2))
for a, v in zip(J.AXES, t)) .replace("Т1-ФОРМА", "Т1-ФОРМА")
for a, v in zip(J.AXES, t, strict=True)) .replace("Т1-ФОРМА", "Т1-ФОРМА")
+ f"Т1-ПОЧЕМУ: {w1}\nТ2-ПОЧЕМУ: {w2}\n", encoding="utf-8")
answer((1, 0, 0, 0), "", (0, 0, 0, 0), "")

View file

@ -272,8 +272,8 @@ def controls() -> None:
# транспозиция: признак того, что судья переставил числа вместо повторного чтения
tr = 0
tot = 0
for c, per in _margins().items():
for uid, v in per.items():
for _c, per in _margins().items():
for _uid, v in per.items():
if len(v) == 2:
tot += 1
tr += abs(v[0] - v[1]) < 1e-9

View file

@ -42,7 +42,6 @@ import random
import statistics
import sys
import time
from collections import Counter, defaultdict
from pathlib import Path
REPO = Path("/home/ubuntu/projects/textmachine")
@ -60,7 +59,7 @@ import editor_wire_probe as P # noqa: E402
import inject_probe as IP # noqa: E402
import judges as J # noqa: E402
import probe as Q # noqa: E402
from prices import CANDIDATES, cost # noqa: E402
from prices import CANDIDATES # noqa: E402
load_dotenv(REPO / "eval" / ".env")
OUT = Path.home() / "books" / "role-topology"
@ -601,7 +600,7 @@ def cmd_score() -> None:
for rank, i in enumerate(order):
running = max(running, ps[i][1] * (len(ps) - rank))
holm[i] = min(1.0, running)
for (name, p, n), h in zip(ps, holm):
for (name, p, n), h in zip(ps, holm, strict=True):
print(f" {name:16s} n={n:2d} p={p:.4f} Holm={h:.4f} "
f"{'проходит 0.05' if h < 0.05 else 'НЕ проходит 0.05'}")

View file

@ -46,7 +46,7 @@ import pymorphy3 # noqa: E402
import yaml # noqa: E402
from detect_word import decomposes as _decomposes # noqa: E402
from detect_word import translit_shape as _translit_shape # noqa: E402
from palladius import is_palladius_token, palladius_conformant # noqa: E402
from palladius import palladius_conformant # noqa: E402
_MORPH = pymorphy3.MorphAnalyzer()

View file

@ -64,7 +64,7 @@ INSTRUCTION = """Ты — редактор русского издательст
def shuffle_key(uid: str, arms: list[str]) -> list[str]:
"""Детерминированная перестановка от uid: воспроизводима и не зависит от порядка армов."""
h = hashlib.sha1(uid.encode()).digest() # noqa: S324
return [a for _, a in sorted(zip(h[:len(arms)], sorted(arms)))]
return [a for _, a in sorted(zip(h[:len(arms)], sorted(arms), strict=True))]
def emit(pack: str) -> None:

View file

@ -32,7 +32,7 @@ import re
import statistics as st
import sys
import time
from collections import Counter, defaultdict
from collections import defaultdict
from pathlib import Path
REPO = Path("/home/ubuntu/projects/textmachine")

View file

@ -89,8 +89,8 @@ def main() -> None:
sha = hashlib.sha256(body).hexdigest()[:12]
approx_in = sum(len(m["content"]) for m in msgs) // 3
print(f"запрос sha {sha} · ~{approx_in} токенов входа (оценка по знакам)")
print(f"арм A = вендор-дефолт (параметр НЕ шлётся) · арм B = reasoning_effort:'low'")
print(f"порядок ИНТЕРЛИВНЫЙ (A,B,A,B,…) — защита от временного дрейфа, quirks §3б\n")
print("арм A = вендор-дефолт (параметр НЕ шлётся) · арм B = reasoning_effort:'low'")
print("порядок ИНТЕРЛИВНЫЙ (A,B,A,B,…) — защита от временного дрейфа, quirks §3б\n")
P.RAW = OUT # см. комментарий у OUT: подмена только ПОСЛЕ сборки запроса
P.slug_check() # гардрейл CLAUDE.md: слаг сверяется живым /models в день запуска

View file

@ -128,7 +128,7 @@ def cmd_build() -> None:
a = [sum(json.loads(f.read_text(encoding="utf-8")).get("cost_usd") or 0.0
for f in OUT.glob(f"bo2-DRAFT-{u['uid']}*.json")) + cost_of("bo4-A", u["uid"])
for u in us]
print(f"АРМ G построен · $0 новых покупок\n")
print("АРМ G построен · $0 новых покупок\n")
print(f" окон флагнуто (куплен второй проход): {routed}/{len(us)}")
print(f" правок ОТКЛОНЕНО стражем (гейт увидел ухудшение): {kept}")
print(f" цена G среднее ${st.mean(costs):.5f} · медиана ${st.median(costs):.5f}")

View file

@ -36,10 +36,9 @@ from __future__ import annotations
import json
import os
import re
import statistics
import sys
import time
from collections import Counter, defaultdict
from collections import defaultdict
from pathlib import Path
REPO = Path("/home/ubuntu/projects/textmachine")
@ -221,7 +220,7 @@ def run_variance() -> None:
# Прямой замер: ложный перевес нулевой в 13 голосах из 13. Печатаются обе величины —
# дрейф калибровки важен для АБСОЛЮТНЫХ порогов, ложный перевес — для ПАРНЫХ вердиктов.
unan = tot = false_margin = votes_ok = 0
for w, rs in cells.items():
for _w, rs in cells.items():
for r in rs:
if r["В1-ВЕРНОСТЬ"] is None:
continue

View file

@ -12,7 +12,6 @@
from __future__ import annotations
import json
import os
import sys
from pathlib import Path
import requests

View file

@ -48,7 +48,6 @@ import battery as B # noqa: E402
import buy as BUY # noqa: E402
import editor_wire_probe as P # noqa: E402
import judges as J # noqa: E402
import probe as Q # noqa: E402
from bakeoff import boot_ci, client, uid_of # noqa: E402
import statistics # noqa: E402

View file

@ -64,12 +64,10 @@ sys.path.insert(0, str(REPO / "eval" / "role_topology"))
sys.path.insert(0, str(REPO / "eval" / "editor_harness"))
import bakeoff as BO # noqa: E402
import battery as BT # noqa: E402
import buy as BUY # noqa: E402
import align as AL # noqa: E402
import detect_word as DW # noqa: E402
import guarded as G # noqa: E402
from prices import cost # noqa: E402
OUT = Path.home() / "books" / "role-topology"
FIXER = "gpt-5.6-luna"
@ -401,17 +399,26 @@ def cmd_score() -> None:
Это и есть шаг после `--arms`.
"""
us = BO.units()
have = {a: [u for u in us if text_of(a, u["uid"]).strip()] for a in ("C", "E")}
have = {a: [u for u in us if text_of(a, u["uid"]).strip()] for a in ("C", "E", "C2", "E2")}
print(f"{'арм':6s}{'единиц':>8s}{'знаков':>9s}{'абзацев':>9s}{'канон':>8s}{'механика':>10s}")
for a, base in (("F3", None), ("A_law", None), ("D_", None), ("C", "F3"), ("E", "D_")):
txts = ([text_of(a, u["uid"]) for u in have[a]] if a in have
else [BO.text3_of(a, u) for u in us])
txts = [x for x in txts if x.strip()]
if not txts:
# ⚠ C2/E2 — БОЕВЫЕ армы Ф2б (фиксер с банком); C/E — первый, испорченный прогон без банка,
# оставлен для контраста «что покупает банк». ИТОГ цитирует C2/E2, поэтому они обязаны
# печататься здесь: до 08.08 таблица показывала только C/E, и число механики ИТОГа (5)
# не имело в дереве пути воспроизведения. Ревью 08.08.
for a in ("F3", "A_law", "D_", "C", "C2", "E", "E2"):
# ⚠ ЕДИНИЦА И ТЕКСТ ХОДЯТ ПАРОЙ. Прежде текст фильтровался по непустоте, а `us` — нет,
# и `zip(us, txts)` считал канон текста k-го арма против ИСХОДНИКА другой единицы, стоило
# хоть одному тексту оказаться пустым. Сейчас все армы полны 16/16, поэтому дефект латентен
# и напечатанные числа им не задеты — но это мина под любой ре-ран с отказом. Ревью 08.08.
pairs = [(u, text_of(a, u["uid"])) for u in have[a]] if a in have \
else [(u, BO.text3_of(a, u)) for u in us]
pairs = [(u, x) for u, x in pairs if x.strip()]
if not pairs:
print(f"{a:6s}{'нет':>8s}")
continue
txts = [x for _u, x in pairs]
s = k = 0
for u, x in zip(us, txts):
for u, x in pairs:
for zh, (_1, _2, r1, _3) in BO.IP.TERMS.items():
n = u["source"].count(zh)
if n:
@ -422,7 +429,7 @@ def cmd_score() -> None:
f"{st.median([len([q for q in x.split(chr(10)) if q.strip()]) for x in txts]):>9.0f}"
f"{(k / s if s else 0):>8.3f}{mech:>10d}")
print("\nЦЕНА (черновик/база + починка):")
for a, base in (("C", "F3"), ("E", "D_")):
for a, base in (("C", "F3"), ("C2", "F3"), ("E", "D_"), ("E2", "D_")):
fix = sum(json.loads(f.read_text(encoding="utf-8")).get("cost_usd") or 0.0
for f in OUT.glob(f"p2b-{a}-*-s*.json"))
n = len(have[a]) or 1

View file

@ -34,7 +34,6 @@
from __future__ import annotations
import json
import os
import re
import statistics
import sys
from pathlib import Path

View file

@ -28,7 +28,6 @@
"""
from __future__ import annotations
import json
import re
import statistics
import sys
from pathlib import Path

View file

@ -154,7 +154,7 @@ def main() -> None:
# ЧТО НАХОДЯТ РЕАЛЬНЫЕ ДЕТЕКТОРЫ — считается до и независимо от починки.
rec_k1 = rec_k2 = 0
for (txt, marks), u in zip(planted, us):
for (txt, marks), _u in zip(planted, us, strict=True):
hits = detect(txt, bank)
for m in marks:
if m["cls"] == "k1":
@ -169,7 +169,7 @@ def main() -> None:
timeout=300)
spent = 0.0
res = {"oracle": [0, 0], "real": [0, 0]} # [починено, предъявлено]
for ui, ((txt, marks), u) in enumerate(zip(planted, us)):
for ui, ((txt, marks), u) in enumerate(zip(planted, us, strict=True)):
hits = detect(txt, bank)
for m in marks:
# ORACLE: спан известен точно.

View file

@ -44,7 +44,7 @@ import bakeoff as BO # noqa: E402
import battery as BAT # noqa: E402
import detect_word as DW # noqa: E402
import repair_arm as RA # noqa: E402
from prices import CANDIDATES, cost # noqa: E402
from prices import CANDIDATES # noqa: E402
load_dotenv(REPO / "eval" / ".env")
OUT = Path.home() / "books" / "role-topology"

View file

@ -20,6 +20,7 @@ import json
import re
import statistics
import sys
from itertools import combinations
from pathlib import Path
REPO = Path("/home/ubuntu/projects/textmachine")
@ -344,6 +345,91 @@ def main() -> None: # noqa: PLR0915
except Exception as e: # noqa: BLE001
ck(f"дрейф проверяется гейтом ({type(e).__name__})", False, str(e)[:60])
# ══════════════════════════════════════════════════════════════════════════════════════
print("\n=== §ИТОГ — НЕСУЩИЕ ЧИСЛА БЛОКА РЕШЕНИЯ ===")
# ⚠ ЗАВЕДЕНО 08.08 ДВУМЯ АУДИТАМИ. До этого гейт сторожил таблицы §2 второй редакции, деньги
# и батарею — и НИ ОДНОГО числа ИТОГа: нога 2×2, контрасты Ф2б, покрытие канона и отборщики
# арма G стояли без стража, хотя именно на них принимается решение. Дефект того же класса,
# что глоб кассы Ф2б: охраняется не то, что решает.
try:
import absjudge as AJ # noqa: PLC0415
import itog as IT # noqa: PLC0415
st = statistics
a1, a2, common = IT._passes()
ck("ИТОГ: пул считается по 16 единицам обоих проходов", len(common) == 16, str(len(common)))
for arm, lbl in (("A", "A "), ("B", "B "), ("D_", "D_"), ("D", "D ")):
m = IT._pooled(a1, a2, common, arm, "F3")
ck(f"ИТОГ п.1 нога 2×2: {arm} против F3 = {st.mean(m):+.2f}",
num_near(text, lbl, f"{abs(st.mean(m)):.2f}"), f"{st.mean(m):+.2f}")
m = IT._pooled(a1, a2, common, "D", "A")
ck(f"ИТОГ п.4: D/A = {st.mean(m):+.2f}", num_in(text, f"{abs(st.mean(m)):.2f}"),
f"{st.mean(m):+.2f}")
us = BO.units()
for arm in ("F3", "A", "A_law", "B", "D", "D_"):
s = k = 0
for u in us:
x = BO.text3_of(arm, u)
for zh, (_v1, _v2, r1, _r2) in BO.IP.TERMS.items():
n = u["source"].count(zh)
if n:
s += n
k += min(len(re.findall(r1, x, re.I)), n)
ck(f"ИТОГ п.2 покрытие канона {arm} = {k / s:.3f}", num_in(text, f"{k / s:.3f}"),
f"{k / s:.3f}")
gain, routed, kept = IT._route()
got = sum(gain[u] for u in kept) / sum(gain.values())
ck(f"ИТОГ п.5: арм G забирает {got:.0%} выигрыша", num_in(text, f"{got * 100:.0f}"),
f"{got:.0%}")
rej = [u for u in routed if u not in kept]
ck(f"ИТОГ п.6: страж отклонил {len(rej)} правки со средним "
f"{st.mean([gain[u] for u in rej]):+.2f}",
num_in(text, f"{st.mean([gain[u] for u in rej]):.2f}") and num_in(text, str(len(rej))),
f"n={len(rej)}")
# Ф2б: пятёрка судейских контрастов прохода 4 с поправкой Холма
sv, AJ.PASS = AJ.PASS, "abs4"
try:
d4 = AJ._by_unit()
finally:
AJ.PASS = sv
fam = [("C2", "A_law"), ("C2", "F3"), ("E2", "D_"), ("E2", "A_law"), ("A_law", "F3")]
ms = [[d4[u][b]["errors"] - d4[u][a]["errors"] for u in d4 if a in d4[u] and b in d4[u]]
for a, b in fam]
holm = IT._holm([BO.sign_perm_p(m) for m in ms])
for (a, b), m, h in zip(fam, ms, holm, strict=True):
ck(f"ИТОГ п.7: {a} vs {b} = {st.mean(m):+.2f} (Холм {h:.4f})",
num_in(text, f"{abs(st.mean(m)):.2f}"), f"{st.mean(m):+.2f}")
ck("ИТОГ п.7: значимый контраст E2/A_law НАПЕЧАТАН в таблице отчёта",
num_near(text, "E2 vs A_law", "2.06"), "строки нет")
# §12: чем несущие контрасты пробовали убить — до 08.08 считалось ВНЕ дерева
chap = {u["uid"]: u["chapter"] for u in us}
chapters = sorted({chap[u] for u in common})
ck(f"§12: {len(common)} единиц происходят из {len(chapters)} глав (единицы НЕ независимы)",
num_in(text, str(len(chapters))), str(len(chapters)))
# ⚠ Холм считается СОВМЕСТНО по объявленному семейству из семи (три посчитанных контраста
# плюс четыре недобранных как p=1), а не по каждому отдельно: раздельный счёт даёт p×7
# каждому и расходится с числами отчёта. Ровно та же формула, что в `itog.p1_robust`.
core = [("A", "F3"), ("B", "F3"), ("D", "A")]
ms = [dict(zip(common, IT._pooled(a1, a2, common, a, b), strict=True)) for a, b in core]
ps = [BO.sign_perm_p([st.mean([m[u] for u in common if chap[u] == c]) for c in chapters])
for m in ms]
for (a, b), m, h in zip(core, ms,
IT._holm(ps + [1.0] * (len(AJ.FAMILY) - len(ps))), strict=False):
ck(f"§12 кластеризация по главе: {a}/{b} Холм {h:.4f} — выживает",
h < 0.05 and num_in(text, f"{h:.4f}"), f"{h:.4f}")
n2 = sum(1 for c in combinations(range(len(m)), 2)
if BO.sign_perm_p([x for i, x in enumerate(m.values()) if i not in c])
* len(AJ.FAMILY) >= 0.05)
ck(f"§12 leave-two-out: {a}/{b} вылетов {n2}/120", n2 == 0, str(n2))
lv = []
for nm in ("abs", "abs2", "abs3", "abs4"):
d = AJ._by_unit_pass(nm)
lv.append(st.mean([r["errors"] for v in d.values() for r in v.values()]))
ck(f"§11 строгость панелей растёт монотонно {''.join(f'{x:.2f}' for x in lv)}",
all(x < y for x, y in zip(lv, lv[1:], strict=False))
and all(num_in(text, f"{x:.2f}") for x in lv), " ".join(f"{x:.2f}" for x in lv))
except Exception as e: # noqa: BLE001
ck(f"числа ИТОГа проверяются гейтом ({type(e).__name__})", False, str(e)[:80])
print("\n=== ПОКРЫТИЕ ТРАТ КАССАМИ ===")
covered = ("bo2-", "bo4-", "jv2-", "bo3-", "jf-", "jr-", "en2-", "jve-", "jc-", "dr-")
unc = 0.0