#!/usr/bin/env python3 """Разброс СУДЬИ на повторе одной и той же клетки — последняя незакрытая дыра методики. Проблема. Во всех раундах судейства каждая пара текстов судилась ровно один раз на раскладку. Значит любое расхождение между армами нельзя отделить от собственного шума судьи: если он на ОДНОМ И ТОМ ЖЕ входе отвечает по-разному, то «связка 6:4» может целиком лежать внутри его дисперсии. Отчёт это признаёт («разброс судьи на повторе одной клетки не мерен ни разу»), но не измеряет. Здесь: те же пакеты, та же ориентация, N независимых голосов. Меряется доля клеток, где все N голосов совпали. Это ВЕРХНЯЯ граница разрешающей способности всей судейской методики: разница между армами меньше собственного разброса судьи не может считаться сигналом. Температура намеренно та же, что в основном судействе, — меряется разброс РЕАЛЬНОГО инструмента, а не гипотетического детерминированного. """ from __future__ import annotations import json import re import sys import time from collections import Counter from pathlib import Path REPO = Path("/home/ubuntu/projects/textmachine") HERE = Path(__file__).resolve().parent sys.path.insert(0, str(REPO / "eval" / "editor_contract")) sys.path.insert(0, str(REPO / "eval" / "bank_arbitration")) sys.path.insert(0, str(HERE)) import probe as Q # noqa: E402 import judge_crossmodel as J # noqa: E402 PACK = Path.home() / "books" / "gu-zhenren" / "editor-harness" / "judge-reflow" REPS = 3 def main(model: str, ms: str) -> None: nothink = Q.MODELS[model][5] in ("disable", "effort_none") votes = {} spent = 0.0 for k in range(6): p = PACK / f"packet-{ms}-w{k}.md" if not p.exists(): continue body = p.read_text(encoding="utf-8") for r in range(1, REPS + 1): rec = Q.call(model, [{"role": "system", "content": J.RUBRIC}, {"role": "user", "content": body}], f"jv-{ms}-w{k}-r{r}", nothink) spent += rec["cost_usd"] votes.setdefault(k, []).append(J.parse(rec["content"])) time.sleep(0.2) print(f"\nРАЗБРОС СУДЬИ {model} на {REPS} повторах одного входа (модель материала {ms})\n") print(f"{'ось':11s}{'клеток':>8s}{'единогласно':>13s}{'доля':>8s}") print("-" * 42) total_cells = total_unan = 0 for ax in J.AXES: unan = cells = 0 for k, vs in votes.items(): picks = [v.get(ax) for v in vs if v.get(ax)] if len(picks) < REPS: continue cells += 1 unan += int(len(set(picks)) == 1) if cells: print(f"{ax:11s}{cells:8d}{unan:13d}{unan / cells:8.0%}") total_cells += cells total_unan += unan if total_cells: print(f"\nИТОГО единогласно {total_unan}/{total_cells} = {total_unan / total_cells:.0%}") print("⇒ разница между армами МЕНЬШЕ этого разброса сигналом считаться не может.") print(f"потрачено ${spent:.6f}") for k, vs in sorted(votes.items()): c = Counter(v.get("общий") for v in vs) print(f" w{k} общий вердикт по повторам: {dict(c)}") if __name__ == "__main__": main(sys.argv[1] if len(sys.argv) > 1 else "deepseek-v4-pro", sys.argv[2] if len(sys.argv) > 2 else "dp")