diff --git a/docs/experiments/22-tenant-panel.md b/docs/experiments/22-tenant-panel.md index fab0c8b9..20d82f64 100644 --- a/docs/experiments/22-tenant-panel.md +++ b/docs/experiments/22-tenant-panel.md @@ -209,3 +209,177 @@ OpenAI (Cloudflare 403), xAI (308→403; Wayback свежее эксп-21 не `eval/tenant_panel/` целиком (`material.py` · `checks21.py` · `roster.py` · `money.py` · `prompts.py` · `bank.py` · `contam.py` · `screen.py`) + эта секция отчёта. Дальнейшие фазы получают свои секции и свои фриз-коммиты; amend фриза запрещён, девиации объявляются в отчёте. + +--- + +## §1 Ф0 — ИСПОЛНЕНО + +### 1.1 Контаминация среза: чисто на двух моделях при живом положительном контроле + +Проба узнавания + клоуза, 5 отрывков на книгу, две модели (`tp0-cont-*`, $0.005709): + +``` +книга модель узнано клоуз вердикт (порог: узнавание ≥3/5) +slice22 gpt-5.6-luna 0/5 0/5 следов нет +slice22 deepseek-v4-flash 0/5 0/5 следов нет +gu-zhenren gpt-5.6-luna 1/5 0/5 следов нет +gu-zhenren deepseek-v4-flash 3/5 3/5 НЕПРИГОДЕН +jinpingmei gpt-5.6-luna 4/5 4/5 НЕПРИГОДЕН +jinpingmei deepseek-v4-flash 5/5 5/5 НЕПРИГОДЕН +``` + +**Материал среза чист по объявленному порогу**, и проба при этом работает: положительный контроль +опознан 4/5 и 5/5. + +**Находка, которой у эксп-21 не было: КОНТАМИНАЦИЯ ЗАВИСИТ ОТ МОДЕЛИ.** На 蛊真人 `luna` даёт 1/5 +(«следов нет»), а `deepseek-v4-flash` — 3/5 узнавания И 3/5 клоуза, то есть знает конкретику. +Эксп-21 мерил ОДНОЙ моделью и оставил это открытым пунктом (§4 п.9); здесь видно, что одна модель +занижает оценку — и занижает её как раз для той модели, которая населяет черновую роль. Практика: +пробу контаминации гонять на ЖИЛЬЦАХ, а не на удобной дешёвой модели. + +### 1.2 Банк среза + +Терминолог-прогон (`gpt-5.6-luna`, $0.002444) по 26 частотным кандидатам майнинга → 26 строк +`термин ⇥ перевод`. Ручная правка сессии: **выброшены четыре** (`瞬间` «мгновенно», `声音` «голос`, +`仿佛` «словно», `庭院` «двор») — это общеязыковая лексика, канон на неё превратил бы метрику +покрытия в замер словарного совпадения. Остальные 22 приняты как есть, ручных ПОДМЕН нет. + +Банк: **22 термина, знаменатель 1124 упоминания на 16 единицах** (у эксп-21 — 8 терминов, +228 упоминаний). Помечен `signed: false` — ручной канон сессии, **НЕ подпись владельца** (D39.47). + +⚠ Девиация: регексы канонных форм расширены под русское словоизменение ПОСЛЕ фриза Ф0 и ПОСЛЕ +покупки терминолога (то есть $0 и на результат прогона не влияет). Причина — короткие склоняемые +слова («род Цинь») не находились в форме «рода Цинь»: метрика занижалась бы у всех армов +одинаково, но занижалась. Регрессии на реальные формы банка — в `bank.py --selfcheck`. + +### 1.3 Sol-пакет (а) выпущен + +20 пакетов (`~/books/tenant-panel/sol/`), парный протокол, слепые метки, ОБА порядка, две +контрольные пары с посаженной деградацией, инструкция владельцу отдельным файлом. Контрасты и +основание отбора — в шапке `sol.py`: `A/F` (заказан промтом), `B/F` (тот же заголовочный вопрос, +разрыв судей 1.90) и `A_law/A` — единственный контраст, где судьи расходятся **знаком** +(+0.91 против −0.20), а расхождение знака меняет вердикт, а не точность. + +## §2 Ф1 — ПРОФИЛЬ-СКРИН: ЧТО ПОКАЗАЛ И ЧТО ПОЧИНИЛ + +### 2.1 Таблица по КАЖДОМУ кандидату — и вошедшему, и нет + +``` +модель вердикт $/ед transl $/ед edit ханьцзы размышл причины +deepseek-v4-flash прошёл 0.00089 0.00264 14 21.4% +deepseek-v4-pro прошёл 0.00384 0.00545 6 15.7% +gpt-5.6-luna прошёл 0.00367 0.00437 16 5.0% +gemini-3.1-flash-lite прошёл 0.00398 0.00490 12 0.0% +glm-4.7 прошёл 0.00656 0.00853 6 0.0% +glm-5 прошёл 0.00959 0.01303 4 0.0% +grok-4.3 прошёл 0.00984 0.01452 0 20.9% +kimi-k2.6 ПРОВАЛ 0.05661 0.06773 0 100.0% Г1 (3 клетки) · Г5 обе роли · Г6 пустой выход +mistral-large-latest ПРОВАЛ 0.02016 0.02661 0 0.0% Г5 цена translator $0.0202 > $0.02 +gemini-3.6-flash ПРОВАЛ 0.07320 0.06354 0 0.0% Г5 цена обеих ролей +``` + +**Скрин убил 3 из 11** — против 2 из 12 у эксп-21, и убил по СОДЕРЖАТЕЛЬНЫМ порогам, а не по +удобству состава. + +⚠ **`mistral-large-latest` провалился с запасом в 1%** ($0.02016 против порога $0.02). Порог +объявлен до замера и не двигается, но честная форма вердикта — «на границе», а не «дорог». + +⚠ **`kimi-k2.6` — единственный, кто отдал ПУСТОЙ выход**: 3 клетки из 4 пришли `finish=length` +с нулевым `content` при 100% доли размышления, каждая по $0.065–0.070. Это ровно тот класс, +который уже стоил проекту волны (quirks §10), и он воспроизвёлся на новом вендоре. + +### 2.2 Три починки, найденные ИСПОЛНЕНИЕМ по ходу Ф1 + +| Что сломалось | Как поймано | Правка | +|---|---|---| +| **эхо-мина на ПЕРВОЙ же покупке**: черновик единицы `474f822806` вернулся полным китайским исходником (`finish=stop`, ханьцзы 1785, кириллица 0.00) | вскрытие единицы глазами сразу после покупки | в скрин добавлен боевой гейт годности + N ре-генов; цена ре-гена ложится в леджер | +| **касса считала цену по таблице эксп-21**: `buy.priced` звал `role_topology/prices.cost`, где новых моделей нет — прогон упал `KeyError: kimi-k2.6` на середине | падение прогона | прайс-таблица пака подставлена в кассу явно; заведена проверка «цена считается для ВСЕХ моделей ростера»; сверка уже купленных записей новой таблицей — **0 расхождений** | +| **детектор markdown ловил разделитель сцены**: `***` (стандартный русский типографский разделитель) считался протёкшей разметкой ⇒ ПРОВАЛ получали `glm-5` и `gemini-3.1-flash-lite` | вскрытие клеток перед выводом (D39.61) | детектор приведён к БОЕВОМУ (`checks/sanitizer.go` + D33.2: декоративный разделитель не заголовок); порог «нарушений более чем в одной клетке» НЕ менялся — менялось, что считается нарушением | + +⚠ Третья правка сделана ПОСЛЕ того, как первые вердикты были видны. Это признак подгонки, и +защита от него одна: правка меняет ДЕТЕКТОР, а не ПОРОГ; она приводит его к боевому гейту, а не +к желаемому составу; и она проверена регрессиями на девяти входах с известным ответом +(`***`, `* * *`, `# # #`, `## ***`, `**жирный**`, `### Глава 1`, …). + +### 2.3 Провод-факты для quirks + +* **`gemini-3.1-pro-preview` отдаёт HTTP 503 «This model is currently experiencing high demand» + сериями.** Четыре вызова подряд — четыре 503 за 3–5 секунд, $0; через минуту тот же слаг + ответил с первой попытки. Страница статуса Google инцидентов не показывала. ⇒ адаптер обязан + иметь отступ на 5xx, иначе клетка теряется по причине, которая замером не является. +* **`kimi-k2.6` без ручки эффорта выжигает бюджет**: 3 клетки из 4 `finish=length`, `content` + пуст, 100% выхода — размышление. Ручки управления размышлением у Kimi в quirks не описано. +* **`gemini-3.6-flash` дороже в роли ПЕРЕВОДЧИКА ($0.0732), чем в роли РЕДАКТОРА ($0.0635)** — + при том, что редакторский вход длиннее вдвое. То есть размышление у него растёт на задаче + перевода с нуля, а не на объёме входа. +* **DeepSeek объявил на прайс-странице повышение цен** («We plan to raise the overall pricing for + DeepSeek API services in the near future, with a significant increase expected»). Проекция + себестоимости книги в ИТОГе едет с этой оговоркой. + +--- + +## §0-Ф2 ПРЕ-РЕГ ФАЗЫ 2 (зафризен своим коммитом ДО покупок Ф2) + +**Панель (6 клеток = якорь + 5 жильцов, потолок промта «до 5 + якорь»).** Правило состава +объявлено в §0.6 и применено механически: прошедших скрин кандидатов черновой роли шесть, слотов +пять, поэтому сохранена ЦЕНОВАЯ ОСЬ — обязательны якорь, самый дешёвый и самый дорогой прошедшие, +середина добирается по возрастанию цены. + +``` +D0 deepseek-v4-flash $0.00089/ед ЯКОРЬ (боевой черновик) +D1 gpt-5.6-luna $0.00367/ед самый дешёвый прошедший +D2 deepseek-v4-pro $0.00384/ед +D3 gemini-3.1-flash-lite $0.00398/ед +D4 glm-4.7 $0.00656/ед +D5 grok-4.3 $0.00984/ед самый дорогой прошедший +``` + +**Снят правилом:** `glm-5` ($0.00959/ед, скрин ПРОШЁЛ) — шестой по цене из шести, вытеснен +границей «до 5 жильцов». Он не выбывает из пака: в Ф3 он входит как ратифицированный резерв. +Ценовая ось панели — **11× от края до края**, то есть вопрос «покупает ли дорогой черновик +качество» на ней задаваем. + +**Что покупается:** черновик каждого жильца на 16 zh + 6 en единицах (с банкнотой на zh; пара en +идёт БЕЗ блока — подписанного глоссария для книги Kristoff не существует, девиация унаследована +от эксп-21) + боевой редактор `A_law`-конфига (`deepseek-v4-pro`, full-regen + закон-блок) поверх +КАЖДОГО черновика + шумовой пол. + +**ШУМОВОЙ ПОЛ.** Якорный арм гоняется ДВАЖДЫ end-to-end (`p1`, `p2`) на тех же 16 zh-единицах: +свой черновик и своя редактура в каждом прогоне. Истинная разница — ноль по построению, поэтому +измеренный разброс есть шум ПАЙПЛАЙНА (генерация черновика + генерация редактуры + судья), а не +только редактора: у эксп-21 пол мерил повтор редактора над замороженным черновиком и потому был +нижней границей. Пол применяется к Ф2 И Ф3; перевес ниже пола печатается вердиктом +**«ниже порога различимости»** — это статус «не разрешено ригом», запрета печатать числа нет. + +⚠ Пол кладётся ОТДЕЛЬНОЙ парой `p1`/`p2`, а не «боевая клетка + её повтор»: иначе одна половина +пола побайтно совпала бы с армом `E0` в том же судейском пакете, судья увидел бы один текст +дважды, а контроль «близнец» сработал бы на боевом арме. + +**СЕМЕЙСТВО КОНТРАСТОВ Ф2 (zh и en раздельно), объявляется ЗДЕСЬ и впечатывается в ключ судейского +прохода ДО первого ответа:** + +``` +E1 vs E0 · E2 vs E0 · E3 vs E0 · E4 vs E0 · E5 vs E0 — финал поверх черновика жильца против + финала поверх якоря (5 гипотез) +E0 vs D0 — КОНТРОЛЬ: покупает ли боевой редактор + поверх якорного черновика +``` +Поправка Холма — по шести. Контрасты `D_i vs D_0` (черновик как ТЕКСТ) и разложение по осям +объявляются **описательными**: поправку не несут и решений не определяют. Основание такого сужения +— продуктовое: решение владельца принимается по ФИНАЛУ (что уедет в книгу), а не по черновику; +эксп-21 §9 показал, чем кончается семейство, объявленное задним числом. + +**КРИТЕРИИ (объявляются ДО покупок, как требует промт).** +* «X бьёт Y» засчитывается, если перевес **больше шумового пола** (порог различимости = 2.8·SE + пола при 80% мощности) И `p` Холма < 0.05 по объявленному семейству. +* Перевес ниже пола печатается как **«ниже порога различимости»** с числом, а не замалчивается. +* **Правило ничьей (ратифицировано D39.117): при неразличимости рекомендация = самый дешёвый + жилец.** Это правило ОТЧЁТА, а не ожидание результата. +* Детерминированные оси (эхо, батарея, покрытие канона, цена) читаются НЕЗАВИСИМО от судьи: они + шума не имеют, и расхождение с судейским порядком — находка (строка 152 бэклога). + +**СМЕТА Ф2 по фактическим ценам скрина: $1.4533** (черновики 132 вызова + редактуры 132 + пол 32) +при потолке $2.00. Не влезет — стоп и пинг, не резать молча. + +**АГЕНТ-ЗАПУСКИ Ф2:** 16 (zh, по одной единице на сессию: 6 черновиков + 6 редактур + декой + +пара пола = 14 текстов) + 3 (en, по две единицы: 6 черновиков + 6 редактур + декой = 13 текстов). diff --git a/eval/tenant_panel/editors.py b/eval/tenant_panel/editors.py index 065e4732..676c379b 100644 --- a/eval/tenant_panel/editors.py +++ b/eval/tenant_panel/editors.py @@ -57,18 +57,31 @@ def client(model: str) -> OpenAI: return OpenAI(api_key=os.environ[env], base_url=base, timeout=900) -def panel() -> list[str]: - """R0 = боевой редактор · затем обязательный кандидат · затем прошедшие скрин по цене. +RESERVE = "glm-5" # ратифицированный резерв D39.22 = арм B эксп-21 - Порядок фиксирован, потому что имена армов (R0, R1, …) впечатываются в ключ судейского - прохода: сдвиг порядка после выпуска заданий сделал бы семейство неповторимым. + +def panel() -> list[str]: + """Состав панели Ф3 по ОБЪЯВЛЕННОМУ (во фризе Ф3, ДО покупок) правилу. + + R0 боевой редактор — база всех контрастов; + R1 обязательный кандидат промта (гипотеза эксп-04 «gemini-pro — аутлаер прозы»); + R2 резерв эксп-21 `glm-5` — ПРЕЕМСТВЕННОСТЬ: только он позволяет пере-снять контраст + `A_law/B` на неконтаминированном материале, а без него эксп-22 не связан с эксп-21 ничем; + R3 самый ДЕШЁВЫЙ прошедший редактор — отвечает «хватает ли дешёвого»; + R4 самый ДОРОГОЙ прошедший — отвечает «покупает ли дорогой качество». + + Порядок фиксирован: имена армов R0..R4 впечатываются в ключ судейского прохода, и сдвиг + порядка после выпуска заданий сделал бы семейство неповторимым. """ res = P2.screen_result() - out = [BATTLE, MANDATORY] + out = [BATTLE, MANDATORY, RESERVE] ok = [m for m, r in res.items() if r["verdict"] == "прошёл" and m not in out and r.get("price_editor") is not None] ok.sort(key=lambda m: res[m]["price_editor"]) - return (out + ok)[:MAX_EDITORS] + for m in ([ok[0]] if ok else []) + ([ok[-1]] if len(ok) > 1 else []): + if m not in out: + out.append(m) + return out[:MAX_EDITORS] def base_text(uid: str) -> str: diff --git a/eval/tenant_panel/panel.py b/eval/tenant_panel/panel.py index 643abf73..47102cf1 100644 --- a/eval/tenant_panel/panel.py +++ b/eval/tenant_panel/panel.py @@ -84,11 +84,11 @@ def tenants() -> list[str]: ok.sort(key=lambda m: res[m]["price_translator"]) if ANCHOR in ok: ok.remove(ANCHOR) - if len(ok) <= MAX_TENANTS - 1: + if len(ok) <= MAX_TENANTS: return [ANCHOR, *ok] keep = [ok[0], ok[-1]] for m in ok[1:-1]: - if len(keep) >= MAX_TENANTS - 1: + if len(keep) >= MAX_TENANTS: break keep.append(m) return [ANCHOR, *sorted(keep, key=lambda m: res[m]["price_translator"])]