#!/usr/bin/env python3 """АРМ G С ЗАКАЗАННЫМ РОУТЕРОМ: QE-скорер вместо детерминированного гейта. $0 (модель локальная). ⚠ Заведён 07.08 после того, как адверсариальное ревью показало: обоснование `guarded.py` («QE-ранкера в зоне нет, выдумывать его полигон не вправе») ЛОЖНО. Ранкер есть — `qe_bench.QE` на `metricx-24-hybrid-large`, венв `~/.venvs/tm-qe`, шесть файлов калибровок на диске с 06.08. Я подменил заказанный роутер, не проверив собственную посылку. Здесь заказ исполняется буквой. Промт стр.116: «QE/гейты скорят ВСЕ окна → стиль-пасс ТОЛЬКО флагнутым, редактура принимается, только если внешний гейт видит УЛУЧШЕНИЕ (guarded APE, max(draft, edited))». Здесь и роутинг, и страж идут по ОДНОЙ величине — предсказанной QE ошибке, — а не по разным, как в `guarded.py`, где страж смотрел на механику, а редактор оптимизировал язык. ⚠ ШКАЛА ПЕРЕВЁРНУТА: MetricX предсказывает ВЕЛИЧИНУ ОШИБКИ, больше — хуже. Запуск: --score посчитать QE по всем армам на всех единицах (кэшируется на диск), $0 --build собрать арм G_qe и напечатать цену и качество, $0 """ from __future__ import annotations import json import statistics as st import sys from pathlib import Path REPO = Path("/home/ubuntu/projects/textmachine") sys.path.insert(0, str(REPO / "eval" / "role_topology")) import bakeoff as BO # noqa: E402 OUT = Path.home() / "books" / "role-topology" CACHE = OUT / "qe-arms.json" ARMS = ("F3", "A", "A_law", "B", "D", "D_") def cmd_score() -> None: sys.path.insert(0, str(REPO / "eval" / "role_topology")) from qe_bench import QE # noqa: PLC0415 cache = json.loads(CACHE.read_text(encoding="utf-8")) if CACHE.exists() else {} qe = QE() for u in BO.units(): for arm in ARMS: k = f"{arm}|{u['uid']}" if k in cache: continue cache[k] = qe.score(u["source"], BO.text3_of(arm, u)) CACHE.write_text(json.dumps(cache, ensure_ascii=False), encoding="utf-8") print(f" {k} {cache[k]:.3f}", flush=True) print(f"готово · {len(cache)} оценок → {CACHE}") def cmd_build() -> None: cache = json.loads(CACHE.read_text(encoding="utf-8")) us = BO.units() q = lambda a, u: cache[f"{a}|{u['uid']}"] # noqa: E731 med = st.median([q("F3", u) for u in us]) print(f"QE черновика: медиана {med:.3f} · разброс " f"{min(q('F3', u) for u in us):.2f}…{max(q('F3', u) for u in us):.2f}") print(f"\n{'арм':7s}{'QE медиана':>12s}{'лучше черновика':>18s}") for a in ARMS: v = [q(a, u) for u in us] better = sum(1 for u in us if q(a, u) < q("F3", u)) print(f"{a:7s}{st.median(v):12.3f}{better:>14d}/16") # РОУТИНГ: стиль-пасс только окнам, чей QE хуже медианы; СТРАЖ: принять, только если QE упал for thr_name, thr in (("медиана", med), ("верхняя треть", sorted(q("F3", u) for u in us)[10])): routed = [u for u in us if q("F3", u) > thr] acc = [u for u in routed if q("A", u) < q("F3", u)] print(f"\nпорог = {thr_name} ({thr:.3f}): флагнуто {len(routed)}/16 · " f"страж принял {len(acc)}/{len(routed)}") yield_ = {u["uid"]: ("A" if u in acc else "F3") for u in us} (OUT / f"arm-Gqe-{thr_name.split()[0]}.json").write_text( json.dumps(dict(threshold=thr, routed=len(routed), accepted=len(acc), pick=yield_), ensure_ascii=False), encoding="utf-8") if __name__ == "__main__": a = sys.argv[1:] or ["--build"] {"--score": cmd_score, "--build": cmd_build}.get(a[0], lambda: print(__doc__))()