textmachine/eval/editor_tier/judge.py

173 lines
7.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""СУДЕЙСТВО ПАКА «СИЛЬНЫЙ ТИР». $0 сам по себе; расходует агент-запуски (кап 60).
Риг не пере-изобретается: `absjudge` эксп-21 настраивается через `configure`, как это делал
эксп-22. Пак-специфика здесь — только два прохода и их армы.
ПРОХОД `tier` — панель сильного тира: T1..Tn против R0 над ТОЙ ЖЕ якорной базой, 16 единиц
эксп-22. Отвечает: остаётся ли `deepseek-v4-pro` рекомендацией при полной панели.
ПРОХОД `border`— граница `glm-5`: R0 против R2 на 32 единицах (16 эксп-22 + 16 новых). Отвечает:
разводится ли контраст 2.12 от порога при удвоении n.
⚠ Порог различимости фиксируется ОДИН — шумовой пол СВОЕГО прохода. Двусмысленность эксп-22, где
пред-объявленный (2.03) и фактический (2.47) пороги дали для `glm-5` разный ответ, закрыта здесь
заранее, а не после замера.
"""
from __future__ import annotations
import json
import sys
from pathlib import Path
REPO = Path("/home/ubuntu/projects/textmachine")
ZONE = Path(__file__).resolve().parent
sys.path.insert(0, str(REPO / "eval" / "tenant_panel"))
sys.path.insert(0, str(REPO / "eval" / "role_topology"))
import absjudge as AJ # noqa: E402
def _load(name: str, path: Path):
import importlib.util # noqa: PLC0415
spec = importlib.util.spec_from_file_location(name, path)
mod = importlib.util.module_from_spec(spec)
sys.modules[name] = mod
spec.loader.exec_module(mod)
return mod
PAN = _load("panel_et", ZONE / "panel.py")
MONEY, MAT, P22 = PAN.MONEY, PAN.MAT, PAN.P22
OUT = MONEY.OUT
KEYS = OUT / "blind-keys"
RUNS = OUT / "agent-runs.json"
CAP = 60
PASSES = ("tier", "border")
def arm_map(pass_: str) -> dict[str, str]:
if pass_ == "tier":
return {"R0": PAN.BATTLE, **{f"T{i}": m for i, m in enumerate(PAN.survivors(), start=1)}}
return {"R0": PAN.BATTLE, "R2": PAN.BORDER}
def arms(pass_: str) -> tuple[str, ...]:
return tuple(arm_map(pass_))
def family(pass_: str) -> list[tuple[str, str, str]]:
"""Семейство объявляется ДО выпуска и впечатывается в ключ."""
if pass_ == "tier":
return [(a, "R0", f"редактор сильного тира {a} против боевого над ТОЙ ЖЕ базой")
for a in arms(pass_) if a != "R0"]
return [("R2", "R0", "пограничный glm-5 против боевого, n удвоено до 32")]
def units(pass_: str) -> list[dict]:
"""Единицы прохода. У `border` их 32: 16 эксп-22 плюс 16 новых этого пака."""
if pass_ == "tier":
return P22.M.units_zh()
return P22.M.units_zh() + MAT.units_new()
def text_of(pass_: str):
new_uids = {u["uid"] for u in MAT.units_new()}
def hook(arm: str, u: dict) -> str:
if pass_ == "border":
# единица новая → тексты фазы B; единица эксп-22 → его же клетки
if u["uid"] in new_uids:
return PAN.text_b(arm, u["uid"])
return P22.edit_text(PAN.BATTLE if arm == "R0" else PAN.BORDER, u["uid"]) \
if arm == "R0" else _ed22(u["uid"])
return PAN.text_c(arm, u["uid"])
return hook
def _ed22(uid: str) -> str:
"""Клетка R2 эксп-22 — это `glm-5` над якорной базой в его фазе Ф3."""
import editors as ED # noqa: PLC0415
return ED.text_of("R2", uid)
def floor_of(pass_: str):
"""Пол СВОЕГО прохода — две независимые генерации самого дешёвого арма панели.
⚠ Для `border` пол берётся ОТТУДА ЖЕ и это объявлено: армы обоих проходов — редакторы над
одной якорной базой, судит одна и та же популяция, поэтому шум одного вызова у них общий.
Покупать второй такой же пол значило бы платить за то же число дважды.
"""
def hook(u: dict):
return PAN.floor_pair(u["uid"])
return hook
def decoy_base(slots: dict) -> str:
for a in ("R0", "T1", "R2"):
if a in slots and (slots[a] or "").strip():
return a
return next(iter(slots))
def setup(pass_: str) -> None:
AJ.configure(OUT=OUT, KEYS=KEYS, PASS=pass_, ARMS=arms(pass_), ARMS_2B=(),
FAMILY=family(pass_), TEXT_HOOK=text_of(pass_),
UNITS_HOOK=lambda: units(pass_), FLOOR_HOOK=floor_of(pass_),
DECOY_HOOK=decoy_base, SRC_LANG="китайском")
KEYS.mkdir(parents=True, exist_ok=True)
def runs_used() -> list[dict]:
return json.loads(RUNS.read_text(encoding="utf-8")) if RUNS.exists() else []
def log_run(pass_: str, tokens: list[str], note: str = "") -> int:
rs = runs_used()
n = len(rs) + 1
rs.append(dict(n=n, pass_=pass_, tokens=tokens, note=note))
RUNS.write_text(json.dumps(rs, ensure_ascii=False, indent=1), encoding="utf-8")
jf = KEYS / f"{pass_}-JUDGES.json"
m = json.loads(jf.read_text(encoding="utf-8")) if jf.exists() else {}
for t in tokens:
m[t] = f"agent-{n:02d}"
jf.write_text(json.dumps(m, ensure_ascii=False, indent=1), encoding="utf-8")
if n > CAP:
raise SystemExit(f"⛔ КАП АГЕНТ-ЗАПУСКОВ ПРОБИТ: {n} > {CAP}")
return n
def per_run(pass_: str) -> int:
return max(1, 20 // max(1, len(arm_map(pass_)) + 3))
def cmd_plan(pass_: str) -> None:
setup(pass_)
us, amap = units(pass_), arm_map(pass_)
print(f"проход {pass_} · единиц {len(us)} · армов {len(amap)}")
for a, m in amap.items():
print(f" {a:4s}{m}")
print("семейство (в ключ ДО ответов):")
for a, b, w in family(pass_):
print(f" {a:4s} vs {b:4s} {w}")
have = sum(1 for u in us for a in amap if (text_of(pass_)(a, u) or "").strip())
print(f"текстов готово {have} из {len(us) * len(amap)} · "
f"агент-запусков {len(runs_used())} из {CAP}")
if __name__ == "__main__":
a = sys.argv[1:] or ["--plan", "tier"]
if a[0] == "--plan":
cmd_plan(a[1] if len(a) > 1 else "tier")
elif a[0] == "--emit":
setup(a[1])
AJ.emit()
elif a[0] == "--ingest":
setup(a[1])
AJ.ingest()
elif a[0] == "--score":
setup(a[1])
AJ.controls()
print()
AJ.score()
else:
print(__doc__)