textmachine/eval/dovodka/prereg-4axes/PREREG.md

39 KiB
Raw Blame History

ПРЕ-РЕГИСТРАЦИЯ СТЕНДА — контролируемая проба редактора по четырём осям

Дата: 02.09.2026. Ветка polygon. Сессия-исполнитель textmachine-2f. Закон: eval/dovodka/PLAN-01-09.md (фриз ДОКУМЕНТА — коммит dc602e9). Промт исполнителя: eval/dovodka/PROMPT-PROBE-4AXES.md.

Настоящий коммит — ФРИЗ №1: СТЕНД, и он ложится ДО первой платной клетки. dc602e9 заморозил дизайн, модели, правило решения, потолок, рамку и сид; здесь замораживается всё остальное, что после первой покупки править уже нельзя: конфиги, скрипты, sha256 и правило кассы. ФРИЗ №2 — пин сигнатуры Δprompt_tokens, снятой пред-полётом (план §4: полосу нельзя было задать заранее). Оба объявляются владельцу вслух.

Машинная копия всего перечисленного — prereg.json рядом (её читает chetyre.py --manifest). Замороженные копии конфигов и промптов — stand/. Они лежат в зоне полигона, потому что физически конфиги живут в каталоге книги, а books/отдельный репозиторий, и «фриз коммитом» там неисполним по канону (план §5.5).


1. РАМКА ВЫБОРКИ — пинится первой, иначе «20 юнитов» читаются как ОТБОР

что значение
главы книги 2642 (17 глав)
нумерация в движке 117 в колонке chapter БД ⚠ движок не умеет смещение глав
файл среза ~/books/gu-zhenren/probe-4axes/guzhenren-ch26-42.gb18030.txt
sha256 среза 1ebcc9efb0fa5006548eba8599b58d4d5a44a201562271d0ff9f1eb9b803fccf
размер 97 408 Б GB18030 · CRLF · 17 заголовков · 47 519 знаков без переводов строк
резалка eval/dovodka/narezka.py --from 26 --to 42 (вход UTF-8, GB18030 на выходе)
n юнитов 20
каталог новый ~/books/gu-zhenren/probe-4axes/ — не coldrun-v16 (там три оплаченных edit-юнита)
отбора нет все юниты диапазона в порядке движка; юнит пред-полёта ВХОДИТ в n

Как снято n, командой ($0, до первой покупки):

$ ~/books/gu-zhenren/probe-4axes/bin/tmctl manifest --config ~/books/gu-zhenren/probe-4axes/book.yaml
chapters=17 units=20 chunks=35
source: 97408 bytes (sha256 1ebcc9efb0fa) · encoding gb18030 · zh→ru

МИНА НУМЕРАЦИИ СЛАБЕЕ, ЧЕМ БОЯЛСЯ ПЛАН — и это тоже улика, а не мнение. План писал, что соответствие «главы книги 2642 ≡ главы среза 117» держится ТОЛЬКО записью в пре-реге. На деле у движка есть СВОЙ носитель: чанкер разбирает китайский номер 第二十六节 и печатает в манифесте заголовки «Глава 26» … «Глава 42» при позиционных number 1…17. То есть соответствие восстанавливается из артефакта прогона, а не только из этого документа. Команда:

$ python -c "import json;m=json.load(open('.../guzhenren-probe4.db.manifest.json'));
             print([(c['number'],c['heading'],c['units_total']) for c in m['chapters']])"
(1,'Глава 26',1) (2,'Глава 27',1) (3,'Глава 28',2) … (17,'Глава 42',1)   Σ units = 20

Три главы (28, 37, 38) дают по два юнита, остальные по одному — отсюда 20, а не 17.

ОТСТУПЛЕНИЕ ОТ ОЖИДАНИЯ ПЛАНА, названное до покупки: план ждал ~24 юнита по пропорции холодного прогона (14 на 10 глав). Фактически 20. Это не нарушение — §6 плана прямо говорит, что вариант задаётся ДИАПАЗОНОМ ГЛАВ, а «24» есть ожидание, а не цель. Следствие для мощности объявляется здесь, а не после чисел: при σ=1.2 MDE растёт с ×2.02 (n=24) до ×2.16 (n=20).

2. СИД И ПОРЯДОК

Сид 20260902. Порядок рук внутри юнита — eval/dovodka/poryadok.py, перестановка на sha256 (не random: он не обещает стабильности между версиями Python). Контракт: четыре руки креста — перестановкой, glm-off ВСЕГДА пятый, чтобы при денежном гарде терялся референс, а не пара, на которой стоит E1. Выпавший порядок всех 20 юнитов — в prereg.json (порядок_рук).

3. КРЕСТ И МОДЕЛИ — фиксированы

рука промпт stages[edit].reasoning модель что уходит на провод
p7-off editor-p7.md (июльский) "off" deepseek-v4-pro ключа reasoning_effort НЕТ ⇒ вендор-дефолт
p7-low тот же "low" deepseek-v4-pro reasoning_effort:"low"
p9-off editor-p9.md (сегодняшний) "off" deepseek-v4-pro ключа нет
p9-low тот же "low" deepseek-v4-pro low
glm-off editor-p9.md "off" glm-5 extra_body {thinking:{type:disabled}}референс, НЕ фактор креста

Черновик deepseek-v4-flash@low, хоп эскалации deepseek-v4-pro, терминолог и классификатор deepseek-v4-flash@lowконстанты во всех пяти руках. Судья не вызывается.

Провод проверен по коду, не по памяти: capability.go:236-239 — ветка ReasoningNone пишет reasoning_effort только если значение не пусто и не "off"; у deepseek-v4-pro в models.yaml блока capabilities.reasoning нет вовсе ⇒ off = ключ не отправлен, low = отправлен буквально. У glm-5 control: extra_body_disable, off_extra_body: {thinking:{type:disabled}}у неё off это НАСТОЯЩЕЕ выключение размышления.

Различие двух промптов — ровно одна строка (проверено diff): в editor-p9.md к правилу о повторах добавлена оговорка про авторский рефрен. Метка prompt_version у обоих одна (v3-discourse-reflow), поэтому ось берётся по SHA, а не по метке.

4. SHA256 — всё, что после этого коммита не правится

Полный список — prereg.json (sha256). Несущие:

1ebcc9efb0fa5006548eba8599b58d4d5a44a201562271d0ff9f1eb9b803fccf  срез глав 26-42
5ed4ee7ed5bc6c48102798a55567fb6752da3309caff8005f8167f8133e792fc  бинарь tmctl (main @ bd2077b)
21b7735009c25679abc42e018692d3fde93beb3146b157603b5d49acda81ee01  models.yaml (побайтно один в обоих деревьях)
2b84dee34b0861637a055fee60372d2553f85ffa4c1b535c1e781f5167e8c3a1  editor-p7.md  (P₇, июльский)
1ad4544e564a9b4049231e79e961a9cbb85bc39de07c5ce72cdbc8d92cc68999  editor-p9.md  (P₉, сегодняшний)
3d2a7123bafc22cc6f9f93c62d2fb4cce3bb4d311437f14cbec6411fe4b1221b  pairs/zh-ru.yaml

Бинарь НЕ ТОТ, что вёз холодный прогон (e6f872df…, main @ 065d8ac). Между ними уехали volume.go (+118), terminologist.go (+102), snapshotdiff.go (новый), rebill.go, status.go; в stagerun.go изменился ТОЛЬКО текст ошибки снапшот-гарда (проверено git diff — формула max_tokens не тронута), а snapshot.go, ledger.go и models.yaml не тронуты вовсе. Пере-сборка из 065d8ac потребовала бы checkout в чужом рабочем дереве — запрещено каноном. Расхождение названо здесь, а не скрыто.

5. КОЭФФИЦИЕНТ ВОССТАНОВЛЕНИЯ РАЗМЫШЛЕНИЯ

R̂ = completion_tokens 0.3644 · len(сырой response_text попытки)0.3644 токена/знак, запинено. Границы (из плана §3, названы до покупки): CJK в выходе ломает оценку и завышает ; при R̂ < ~700 относительная ошибка 2070% и о величине таких клеток вывод не делается; берётся СЫРАЯ строка попытки, не sanitized_export; типичная ошибка ~3%, худшая клетка 5.3%. У референса glm-5 R̂ = 0 ПО ПОСТРОЕНИЮ, а не по формуле.

Дыра прибора подтверждена на данных: в базе холодного прогона sum(reasoning_tokens>0) = 0 при 68 строках; положительный контроль — 38 строк с непустым completion_tokens.

6. ДЕНЬГИ — правило запинено ДО чисел

  • Санкция владельца: $9.50 в ПИКОВЫХ терминах. Сессией не поднимается. Гард ⇒ стоп и вопрос.

  • Пояс базового прогона: --ceiling-usd 0.60.

  • Потолок руки i = base_факт + w_i · (9.50 base_факт), веса пропорциональны ожидаемой цене клетки (§6 плана: ∅ $0.09, low $0.05, референс $0.02):

    рука w смысл
    p7-off, p9-off 0.3000 каждая дороже всех: без ручки думают больше
    p7-low, p9-low 0.1667 каждая
    glm-off 0.0667 референс, теряется первым

    Сумма весов 1.0000, поэтому base + Σ(потолок_i base) = $9.50 РОВНО при любом фактическом base. Это и есть механизм, которого у леджера нет: он считает потолок по book_id, а spend лежит ВНУТРИ проектной базы, и каждая из пяти копий несёт базовый расход под тем же book_id.

  • Агрегат ведётся вручную после КАЖДОГО юнита: израсходовано = база + Σ(копия база).

  • --ceiling-usd сравнивается с накопленным расходом книги, а не с расходом прогона (cmd/tmctl/main.go:260) ⇒ в него кладётся «база + доля», а не «доля».

  • --ceiling-usd перекрывает только book_usd; day_usd берётся из book.yaml (stagerun.go:496) ⇒ дневной потолок задан в каждой руке как book_usd + $1.00.

ПОРОГ, ОБЪЯВЛЕННЫЙ ДО ПРЕД-ПОЛЁТА, чтобы не выбирать его после чисел. Цена клетки low — единственное число сметы без источника (движковых редакторских вызовов на low не существует). В репозитории есть независимый замер, которого план не использовал: docs/experiments/23-editor-tier.md:7139, арм RNL 30.08 на low$0.056695 за вызов, то есть ближе к «худшему» сценарию плана ($0.065), чем к центральному ($0.04). ⇒ Решение: пред-полётная клетка low ≤ $0.065 — иду дальше (это худший сценарий §6 плана, потолок его покрывает ценой потери 12 юнитов, что план называет штатным исходом). > $0.065 — СТОП и вопрос владельцу, потому что выше в замороженной смете сценария нет.

7. ОПРЕДЕЛЕНИЕ «ДОСТАВЛЕНО» — объявляется ДО чисел, вместе с проверкой устойчивости

delivered меряется на отгружаемом тексте (checkpoints.response_text по chunk_status.final_hash; final_hash может быть синтетическим tm-sanitized-v1:<sha> и тоже лежит в checkpoints — проверено).

  • delivered = 0 ⟺ диспозиция skipped, ИЛИ final_hash не резолвится, ИЛИ отгружаемый текст не проходит $0-предикат: доля кириллицы среди букв < 0.99 либо в тексте есть CJK.
  • иначе delivered = длина отгружаемого текста в знаках.

Почему НЕ «flagged ⇒ 0»: в холодном прогоне 1 из 3 редакторских юнитов — sanitizer_stripped (CJK-утечка, санитайзер её вырезал, текст ОТГРУЖЕН, 6048 знаков). По правилу «flagged ⇒ 0» гард «>20% пустых ⇒ прибор отказывает» сработал бы от санитайзера, а не от предмета замера. Флаги при этом не теряются — они целиком идут в E5, разделённые по механизму (санитайзер / CJK / обрыв по длине). Строгий вариант (flagged ⇒ 0) считается ВСЕГДА и печатается рядом как заранее объявленная проверка устойчивости.

8. ПРАВИЛО РЕШЕНИЯ — из §4 плана, здесь не пересматривается

p<0.05 двусторонне ⇒ эффект есть, величина = медиана Ходжеса–Лемана с 95% ДИ. Иначе ⇒ «НИЖЕ РАЗРЕШЕНИЯ ЗАМЕРА», и это НЕ «эффекта нет». Полоса [0.8; 1.25] — описательная, решения не несёт. Нули (ничьи от цензуры) СОХРАНЯЮТСЯ: zero_method='pratt' (умолчание wilcox их выбрасывает — проверено исполнением на scipy 1.18.0). ДИ Ходжеса–Лемана написан руками: у wilcoxon в этой версии интервала нет (проверено — у результата только statistic/pvalue/count/index). Цензура на потолке — симметрично, по §4; величина под цензурой печатается со знаком «≥».

9. ОТСТУПЛЕНИЯ ОТ ЗАМОРОЖЕННОЙ ПРОЦЕДУРЫ — предъявляются, а не правятся молча

План §10 требует: «если исполнение покажет, что что-то из замороженного неверно — это НАХОДКА, которая записывается и предъявляется». Ниже — все, найденные ДО первой покупки.

# § что в плане что на самом деле что делаю
1 §9.2 конфиги рук в $B/arms/ LoadPair ищет пар-слой в <каталог PIPELINE-файла>/pairs/ (config/pipeline.go:821), а отсутствие файла = (nil, nil) тихо (config/pair.go:55-64). ⚠ ПЕРВОНАЧАЛЬНАЯ ФОРМУЛИРОВКА ЭТОЙ СТРОКИ БЫЛА ПРЕУВЕЛИЧЕНА И СНЯТА — см. §9-КВАТЕР конфиги рук лежат в $B/ рядом с единственным $B/pairs/; в $B/arms/ только .book.yaml и .db — решение остаётся, но обосновано отсутствием дрейфа двух копий, а не опасностью
2 §9.3 --ceiling-usd 1.20 на базовый прогон правило §9.0 п.1 — «чуть выше ожидания ЧЕРНОВОЙ волны»; ожидание, пере-снятое с леджера: не-edit расход $0.436110$0.214865 = $0.221245 на 28 174 знака ⇒ ×1.6866 = $0.373 + эскалация ≈ $0.45. Зазор при поясе 1.20 = $0.75; резервация одной edit-клетки ≈ 16000·3.96/1e6 + 5000·1.32/1e6 ≈ $0.070 (⚠ расчёт, не замер: потолок вывода pro = флор 16000) ⇒ в зазор влезает порядка десяти редакторских юнитов, а купленная в базе редактура необратима пояс 0.60. Асимметрия в правильную сторону: перелёт стоит перекупки, недолёт — бесплатного resume (код 4, черновики целы). ⚠ Первая же резервация черновика замерена Ш1: $0.012052 — оценка вчетверо выше фактической цены чанка ($0.0034 по холодному прогону), потому что леджер букирует пик
3 §9.3 rc=$? после | tee в сниппете плана нет set -o pipefail, а без него $? возвращает код tee ⇒ проверка [ $rc -eq 4 ] не сработает никогда. Проверено исполнением: без pipefail $? = 0, с pipefail = 4, ${PIPESTATUS[0]} = 4 в обоих случаях ${PIPESTATUS[0]} (правда независимо от pipefail)
4 §9.3 останов цикла по grep -q 'VOLUME CEILING:' строка печатается при res.Volume != nil, то есть на КАЖДОМ прогоне с --max-units (cmd/tmctl/render.go:130) ⇒ break 2 рвал бы цикл после первой же клетки цикл ограничен N=20 из пре-рега, а не выводом; строка «never been delivered» лишь ПЕЧАТАЕТСЯ как признак «рука закончена». Останавливают цикл: код 4, код 3, неожиданный код, рассинхрон рук и агрегат $9.50
5 §9.3 --config $B/arms/$arm.yaml при том, что §9.2 зовёт $arm.yaml копией pipeline translate грузит book.yaml пять book.yaml рук, различающиеся ровно тремя полями (pipeline, project_db, ceilings)
6 §9.1 day_usd не упомянут --ceiling-usd его не перекрывает; наследованный из образца day_usd: 1.00 остановил бы руку посреди пачки day_usd = book_usd + $1.00 в каждой руке
7 §5.3 «мина вооружается ТУМБЛЕРОМ, а уровни эффорта её не вооружают» 00-provider-quirks.md:123: «effort:"low" ПЕРЕ-ВООРУЖАЕТ эхо-мину… защита деградирует НЕПРЕРЫВНО с эффортом»; :132 — off 4/20 против low 3/20, на N=20 неразличимо формулировка снята как неверная; критерий E5 плана опасность уже несёт, поэтому дизайн не меняется
8 §4 ковариатная модель log R̂ ~ effort + prompt + log(len_draft) + (1|unit) как проверка устойчивости E1/E3 не может быть проверкой устойчивости E1/E3: len_draft — величина УНИТ-УРОВНЕВАЯ (все четыре руки редактируют ОДИН черновик — это и есть блокировка трудности), а в сбалансированном внутри-юнитном дизайне юнит-уровневая ковариата НЕ МЕНЯЕТ оценок усилия и промпта ПО ПОСТРОЕНИЮ. Сам наклон длины при этом оценим — он считается отдельно считаю руками обе величины, которые она дала бы: (1) МНК контраста по log(len_draft) — внутри-юнитная устойчивость; (2) МНК среднего по юниту log R̂ по log(len_draft) — это и есть коэффициент длины в сбалансированном дизайне. statsmodels не установлен; ⚠ причина НЕ «нет сети» (сеть есть, колесо под cp314 существует — проверено), а вырожденность модели плюс риск правки общего venv при живых параллельных сессиях
9 §9.6 «n = сколько получится» tmctl manifest бесплатен и даёт units_total до первой покупки n = 20 запинено здесь

| 10 | §9.3 | у рук флага --verify-bank нет | флаг оставлен и в руках намеренно: в копиях банк уже предъявлен базовым прогоном, hasUnpresentedCluster вернёт false (mining.go:222-230), и движок напечатает «every cluster already presented — continuing». Это $0-улика состояния банка и страховка: если рука вдруг соберёт НОВЫЙ кластер, она встанет кодом 3 громко, а не поедет с другим банком молча | флаг подаётся всем пяти рукам; отступление названо здесь |

9-КВАТЕР. МОЯ СОБСТВЕННАЯ ОШИБКА, СНЯТАЯ ИСПОЛНЕНИЕМ ДО ФРИЗА

Класс: чтение кода — своё и агента-контролёра — принято за факт о мире. Ровно тот класс, которым предыдущая сессия ошиблась одиннадцать раз (§8 плана). Записано здесь, потому что фриз не должен нести преувеличенную находку.

Что я утверждала: «руки в $B/arms/ без своего pairs/ ТИХО потеряли бы калибровку нарезки, это сдвинуло бы segmentationSnap ⇒ черновой снапшот ⇒ перекупка всех черновиков ×5».

Что показало исполнение (два независимо достаточных опровержения, оба за $0):

  1. Без каталога pairs/ прогон ПАДАЕТ ГРОМКО, а не молча. prompts_root откатывается на несуществующий каталог, и загрузчик отказывает ещё до всякой нарезки:
    tmctl: config .../nopairs/pipeline.yaml:
      - gates.terminology is enabled but its role prompt is missing — expected .../prompts/zh-ru/terminologist.md
      - gates.terminology.classify_types is on but its prompt is missing — expected .../prompts/zh-ru/classifier.md
    RC=10                                   (отказ, $0, ни одного вызова)
    
  2. Даже с пар-слоем БЕЗ блока segmentation снапшот НЕ ДВИГАЕТСЯ. Дженерик-умолчания в internal/config/pipeline.go:895-905 — это 1797 / 3200 / 1.1978 / 0.3852, то есть ровно те же числа, что несёт pairs/zh-ru.yaml. Прогон с вырезанным блоком дал снапшот 8d5721f6559624d9… — побайтно тот же, что и полный конфиг.

Что остаётся верным: механизм тихого отката у LoadPair реален, и для пары, чья калибровка ОТЛИЧАЕТСЯ от дженерик-умолчаний, ловушка сработала бы. Для zh-ru — нет. Решение держать все пять конфигов рук рядом с одним pairs/ остаётся в силе, но его довод теперь честный: оно исключает расхождение двух копий пар-слоя, а не спасает от перекупки, которой здесь не было.

9-ТЕР. ТРИ РЕШЕНИЯ ПРИБОРА, ОБЪЯВЛЕННЫЕ ДО ЧИСЕЛ

Найдены верификацией собственной работы (агент-контролёр + мои пере-проверки), исправлены ДО фриза.

(а) E5 меряет эхо по СЫРОМУ ответу попытки 0, а не по отгружаемому тексту. Первая редакция прибора считала CJK по отгружаемому — а санитайзер эхо ВЫРЕЗАЕТ, и эндпойнт, блокирующий любую рекомендацию, был слеп ровно к своему предмету. Улика, снята командой на базе холодного прогона:

ЮНИТ     флаг                  CJK в отгруженном | CJK в СЫРОМ ответе попытки 0
 (1,0)   sanitizer_stripped            0          |    10
 (1,1)   —                             0          |     0
 (2,0)   —                             0          |     0

Колонка по отгруженному остаётся ВТОРОЙ: она отвечает на другой вопрос — что увидел читатель. Это важно вдвойне, потому что 00-provider-quirks.md:121 прямо говорит: эхо-безопасность РЕДАКТОРСКОЙ роли на pro@low по плотному CJK не мерена ни разу (пять чистых хопов 31.08 — роль ПЕРЕВОДЧИКА). ⇒ этот замер и есть первый такой контроль в проекте, и слепой E5 обнулил бы его.

(б) ⚠ ПЕРЕКОС ПОРЯДКА ПРИ ЗАПИНЕННОМ СИДЕ — посчитан до чисел, сид НЕ трогается. Выпавшая перестановка на n=20 несимметрична:

первой клеткой юнита:  p7-low 10 · p9-low 6 · p9-off 3 · p7-off 1
пара P7: low раньше off в 15 юнитах из 20      пара P9: 9 из 20

Первая клетка юнита не бьёт префикс-кэш и потому дороже примерно на 6000·($1.32$0.044)/1e6 ≈ $0.0077. ⇒ E2 у пары P7 систематически наклонён ПРОТИВ low. Сид — часть пре-рега и не меняется; вместо этого E2 печатается в ЧЕТЫРЁХ заранее объявленных вариантах: попытка 0 × фактическая цена (основной) · итог юнита × фактическая цена · попытка 0 × строгое delivered · попытка 0 × кэш-независимая цена (весь вход по полной ставке — снимает перекос целиком). На E1 это не влияет вовсе: от кэша не зависит.

(в) ⚠ ДЛИНА ВХОДА ЮНИТА СОБИРАЕТСЯ ИЗ ЧАНКОВ ПО МАНИФЕСТУ. Юнит редактуры и чанк черновика — разные единицы: в этом стенде 20 юнитов на 35 чанков, и у 15 юнитов из 20 chunk_count > 1. Ключ (глава, индекс) у них СОВПАДАЕТ, поэтому «взять первый чанк» не дало бы ни ошибки, ни пустоты — только занижённую ковариату у трёх четвертей выборки. Прибор суммирует first_chunk_idx … first_chunk_idx+chunk_count1; неполный юнит становится None, а не полусуммой. Проверено прямым тестом функции (сценарий 0 контроля).

9-БИС. ПРОВОДНАЯ УЛИКА ЕСТЬ — план утверждал обратное

План §3 «Дыра 2»: «У движка нет проводного артефакта — стадийный лог эффорт не печатает… Оба свидетеля косвенные; побайтной улики у движка нет». Это неверно, и опровержение бесплатно.

internal/obs/logging.go:72 LogLLMExchange пишет сырое тело запроса и ответа на уровне DEBUG, когда включены LOG_LLM_BODIES=1 И LOG_LEVEL=debug. Вызывается из internal/llm/httpllm.go:415 — это и есть OpenAI-совместимый путь, по которому едут и deepseek, и zai. Тело режется до 32 768 Б с сохранением ОБОИХ концов — это и делает улику доступной: Go маршалит map с сортировкой ключей, и reasoning_effort ложится ПОСЛЕ длинного messages, то есть в ХВОСТ тела, который обрезание сохраняет. Логируются ТОЛЬКО тела — никогда URL и никогда заголовки, поэтому ключ утечь не может (комментарий там же, :70).

Пред-полёт идёт с включённым каналом, и в пре-рег ложится побайтная улика: у рук low в теле стоит "reasoning_effort":"low", у рук этого ключа НЕТ, у референса стоит "thinking":{"type":"disabled"}. Это прямо исполняет требование промта §7.1 «прочитай вслух тело запроса каждой руки». Пачка идёт уже БЕЗ канала — он нужен один раз, а объём логов не бесплатен.

⚠ Новой экспозиции текста это не создаёт: логи ложатся в $B/logs/ внутри каталога книги, где сам текст книги уже лежит.

Второе бесплатное подтверждение, которое дал сам движок. На manifest конфига glm-off он напечатал предупреждение, а на четырёх руках креста — нет:

level=WARN msg="a stage sends the SOURCE text to a model whose wire SUPPRESSES thinking —
the ratified echo zone (D19.1 point 2: reasoning-off + dense CJK is a property of the model
class, not a vendor quirk)... it costs a paid call per hit" stages=edit→glm-5 source_lang=zh

То есть движок сам различает: у glm-5 при off размышление ВЫКЛЮЧЕНО, а у deepseek-v4-pro при off — нет (ключ просто не отправляется, thinking остаётся включённым). Ровно то различие, на котором стоит дизайн, — предъявлено движком, а не конспектом.

10. ЧТО ФРИЗ НЕ ПОКРЫВАЕТ

Сигнатуру Δprompt_tokens — её нельзя было задать заранее (единственное известное значение 79 снято на английской паре и на риге). Пред-полёт её замеряет, ФРИЗ №2 её пинит, и только после этого она становится гейтом с допуском ±2 токена и правилом «>20% юнитов вне допуска ⇒ проба аннулируется».

11. ПРИБОР ПРОВЕРЕН ИСПОЛНЕНИЕМ, А НЕ САМООТЧЁТОМ

eval/dovodka/proverka_pribora.py строит синтетические проектные базы той же схемы с ЗАРАНЕЕ ИЗВЕСТНЫМ ответом и прогоняет по ним настоящий chetyre.py. Прямой тест функции + девять сценариев, всё зелёное:

0. сборка длины входа юнита из чанков → 350 / 7 / 24 / None   (наивная дала бы 100 — МОЛЧА)
1. эффект ×2 заложен  → прибор нашёл, Ходжес-Леман ×0.512 против истины ×0.500   (код 0)
2. эффекта нет        → «НИЖЕ РАЗРЕШЕНИЯ ЗАМЕРА», не «эффекта нет»              (код 0)
3. рука вся пустая    → ⛔ ПРИБОР ОТКАЗЫВАЕТ                                     (код 2)
4. ось схлопнулась    → ⛔ ПРИБОР ОТКАЗЫВАЕТ, назвав prompt_sha256               (код 2)
5. треть ∅ цензурирована → посчитал и объявил величину нижней границей           (код 0)
6. 19 строк-повторов на клетку → взял НАСТОЯЩИЙ вызов, ×0.462 против истины ×0.500 (код 0)
7. сигнатура сломана у 40% юнитов → ⛔ ПРОБА АННУЛИРОВАНА                        (код 2)
8. эхо ЗА САНИТАЙЗЕРОМ → E5 видит CJK@сырой=4 при CJK@отгруженном=0              (код 0)
9. баз нет вовсе      → ⛔ ПРИБОР ОТКАЗЫВАЕТ, а не печатает нули                 (код 2)

⚠ Сценарии 3, 4, 7 и 9 ждут от прибора ОТКАЗА — это не подгонка под зелень, а проверка того, что прибор умеет говорить «нет».

⚠ Сценарий 6 проверяет защиту, которой в первой редакции прибора НЕ БЫЛО, и она куплена чтением данных, а не догадкой: интерливинг гоняет каждую руку 20 раз с --max-units 1, и каждый прогон дописывает в request_log строку-ПОВТОР уже оплаченной клетки — tm_hit=1, все токены и цена НУЛЕВЫЕ, но request_hash тот же, то есть она соединяется с тем же чекпойнтом и несёт attempt=0. Проверено на базе холодного прогона: 29 таких строк из 68, у всех нули. Прибор выбирает настоящий вызов явно (tm_hit=0), а не по порядку id.

Команда: ./eval/.venv/bin/python eval/dovodka/proverka_pribora.py

Цикл интерливинга eval/dovodka/pachka.sh проверен тем же способом — на ПОДДЕЛЬНОМ tmctl, который печатает то же, что настоящий, и продвигает БД руки. Проверялись не успешные ветки (они очевидны), а отказные:

подделка что обязан сделать цикл получено
рука p9-low не продвигается (оборванный вызов без чекпойнта) заметить рассинхрон и встать «РУКА p9-low РАЗЪЕХАЛАСЬ: 0 вместо 1», код 5
движок вернул код 4 стоп и вопрос владельцу, добор запрещён код 4
движок вернул код 3 в РУКЕ (банк уже предъявлен базой — так быть не должно) стоп код 3
копия несёт НЕ базовый расход (сделана не из того бэкапа) не начинать: агрегат соврал бы «КОПИЯ p9-low НЕСЁТ $0.61 ВМЕСТО БАЗОВЫХ $0.45», код 1
рука купила ДРУГОЙ юнит при том же ЧИСЛЕ юнитов заметить по НАБОРУ КЛЮЧЕЙ «эта рука 51:0 · эталон 1:0», код 5

⚠ Инвариант синхронности рук существует потому, что блокировка трудности держится на «k-я клетка — ОДИН И ТОТ ЖЕ юнит у всех пяти рук». Оборванный вызов сдвинул бы одну руку на юнит назад, и дальше руки сравнивали бы РАЗНЫЕ чанки — молча, без единой ошибки. Проверка после каждой клетки: сверяются НАБОРЫ КЛЮЧЕЙ chapter:chunk_idx всех пяти рук, а не только их число — счётчик совпал бы и у рук, купивших разные юниты. База для агрегата берётся из ФАЙЛА БЭКАПА, из которого сделаны копии, а не с живой базовой БД: иначе любое касание базы сдвинуло бы вычитаемое молча.

12. ЧЕГО В ЗАМЕРЕ НЕТ НАМЕРЕННО

Судейства качества (качество при сниженном усилии — вне скоупа; только $0-гейты и ось безопасности E5) · калибровки ставки платформы · правок models.yaml, capabilities, Go, боевого pipeline-c1.yaml · смены модели, черновика, дифф-контракта · флага --resnapshotникогда.