113 lines
5.3 KiB
Python
113 lines
5.3 KiB
Python
#!/usr/bin/env python3
|
||
"""Сверка НЕСУЩИХ ЧИСЕЛ отчёта `docs/experiments/20-editor-role.md` с сырьём.
|
||
|
||
Зачем отдельным скриптом: числа в отчёт попадают через мою же аналитику, и опечатка или устаревшая
|
||
цифра после пере-съёмки арма визуально неотличимы от факта. Здесь каждое заявленное число
|
||
пере-выводится из персистированных артефактов заново и сравнивается с тем, что написано в тексте.
|
||
|
||
Запуск: eval/.venv/bin/python eval/editor_harness/verify_report.py
|
||
Ненулевой код возврата = отчёт разошёлся с сырьём и его нельзя лендить.
|
||
"""
|
||
from __future__ import annotations
|
||
import difflib
|
||
import json
|
||
import statistics
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
REPO = Path("/home/ubuntu/projects/textmachine")
|
||
sys.path.insert(0, str(REPO / "eval" / "bank_arbitration"))
|
||
RAW = Path.home() / "books" / "gu-zhenren" / "editor-harness"
|
||
|
||
import editor_wire_probe as P # noqa: E402
|
||
|
||
FAILS = 0
|
||
|
||
|
||
def g(tag: str):
|
||
f = RAW / f"{tag}.json"
|
||
return json.loads(f.read_text(encoding="utf-8")) if f.exists() else None
|
||
|
||
|
||
def ck(claim: str, ok: bool, got: str = "") -> None:
|
||
global FAILS
|
||
if not ok:
|
||
FAILS += 1
|
||
print(f"[{'OK ' if ok else 'ПРОВАЛ'}] {claim}" + ("" if ok else f" — сырьё даёт {got}"))
|
||
|
||
|
||
def cjk(s: str) -> int:
|
||
return sum(1 for ch in s if 0x3400 <= ord(ch) <= 0x9FFF)
|
||
|
||
|
||
def out_text(tag: str) -> str | None:
|
||
a = RAW / f"{tag}.applied.json"
|
||
if a.exists():
|
||
return json.loads(a.read_text(encoding="utf-8"))["text"]
|
||
r = g(tag)
|
||
return r["content"] if r else None
|
||
|
||
|
||
def main() -> None:
|
||
# §3.1 — отношение цены дифф/full по моделям и режимам
|
||
for ms, pre, claim in (("dp", "eh", 2.83), ("gl", "eh", 0.64), ("gl", "eht", 0.86),
|
||
("gr", "eh", 0.60), ("gr", "eht", 0.66),
|
||
("lu", "eh", 1.01), ("lu", "eht", 0.89)):
|
||
f = [g(f"{pre}-{ms}-full-w{k}") for k in range(6)]
|
||
d = [g(f"{pre}-{ms}-diff-harness-w{k}") for k in range(6)]
|
||
if any(x is None for x in f + d):
|
||
ck(f"§3.1 {ms}/{pre}", False, "нет артефактов")
|
||
continue
|
||
r = statistics.median(d[k]["cost_usd"] / f[k]["cost_usd"] for k in range(6))
|
||
ck(f"§3.1 {ms}/{pre} отношение дифф/full = {claim}", abs(r - claim) < 0.015, f"{r:.3f}")
|
||
|
||
# §3.3 — цена починки и полнота снятия дефектов
|
||
for ms, claim in (("dp", 0.000625), ("lu", 0.000173)):
|
||
f = RAW / f"repair-{ms}.json"
|
||
if not f.exists():
|
||
ck(f"§3.3 {ms}", False, "нет repair-*.json")
|
||
continue
|
||
rows = json.loads(f.read_text(encoding="utf-8"))
|
||
med = statistics.median(x["cost"] for x in rows)
|
||
ck(f"§3.3 {ms} цена одной починки = {claim}", abs(med - claim) < 1e-6, f"{med:.6f}")
|
||
snyat = sum(1 for x in rows if not x["still"])
|
||
ck(f"§3.3 {ms} дефект снят 12/12", snyat == 12, str(snyat))
|
||
inf = [x for x in rows if not x["degenerate"]]
|
||
strict = sum(1 for x in inf if not x["still"] and x["restored"])
|
||
ck(f"§3.3 {ms} восстановлен строго 7/8", (strict, len(inf)) == (7, 8),
|
||
f"{strict}/{len(inf)}")
|
||
|
||
# §4 — доля слов черновика, доживших до выхода
|
||
for ms, c, claim in (("dp", "full", 0.65), ("gl", "full", 0.83),
|
||
("dp", "diff-harness", 0.98)):
|
||
vals = []
|
||
for k in range(6):
|
||
o = g(f"eh-{ms}-{c}-w{k}")
|
||
if not o:
|
||
continue
|
||
dw = P.draft_of(k).split()
|
||
ow = (out_text(f"eh-{ms}-{c}-w{k}") or "").split()
|
||
sm = difflib.SequenceMatcher(None, dw, ow, autojunk=False)
|
||
vals.append(sum(b.size for b in sm.get_matching_blocks()) / len(dw))
|
||
ck(f"§4 {ms}/{c} слов дожило {claim:.0%}",
|
||
bool(vals) and abs(statistics.median(vals) - claim) < 0.015,
|
||
f"{statistics.median(vals):.3f}" if vals else "нет данных")
|
||
|
||
# §5.4 — утечка исходника в выход у luna
|
||
for c, w_claim, n_claim in (("full", 3, 19), ("diff-harness", 3, 16)):
|
||
outs = [cjk(out_text(f"eh-lu-{c}-w{k}") or "") for k in range(6)]
|
||
ck(f"§5.4 luna/{c}: окон с утечкой {w_claim}, знаков {n_claim}",
|
||
sum(1 for x in outs if x) == w_claim and sum(outs) == n_claim,
|
||
f"{sum(1 for x in outs if x)} окон, {sum(outs)} знаков")
|
||
|
||
# deepseek обязан быть чист по обоим контрактам — это утверждение отчёта
|
||
for c in ("full", "diff-harness"):
|
||
outs = [cjk(out_text(f"eh-dp-{c}-w{k}") or "") for k in range(6)]
|
||
ck(f"§5.4 deepseek/{c}: утечки нет", sum(outs) == 0, f"{sum(outs)} знаков")
|
||
|
||
print(f"\n{'ВСЕ ЧИСЛА ОТЧЁТА СХОДЯТСЯ' if not FAILS else f'РАСХОЖДЕНИЙ: {FAILS}'}")
|
||
sys.exit(1 if FAILS else 0)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|