textmachine/eval/editor_contract/score_final.py

254 lines
15 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
"""Счёт четырёх фальсификаций СТРОГО по критериям, замороженным в 19-editor-contract-q4b §3.
Критерии не мои и после прогона не меняются:
L — §2.7 падает, если медианное отношение цены дифф/full ≤1.0. Плюс ОБЯЗАТЕЛЬНЫЙ эхо-контроль:
ненулевая доля ханьцзы в выходе делает `low` непригодным независимо от цены.
G — §2.1 падает, если формат-комплаенс (applied/ops_total) на боевой единице <0.90.
E — §2.7 падает, если на английской цели отношение цены ≤1.0. Точность перевода НЕ скорится.
N — §2.2 падает, если доля NO_CHANGE на fidelity-only промпте >0.
Средние исходы печатаются как «неопределённо». Ничего не абсорбируется молча: недостающие
клетки печатаются поимённо, а не выпадают из знаменателя.
"""
from __future__ import annotations
import json
import statistics
import sys
from pathlib import Path
RAW = Path.home() / "books" / "gu-zhenren" / "bank-arbitration"
def rec(tag: str):
f = RAW / f"{tag}.json"
return json.loads(f.read_text(encoding="utf-8")) if f.exists() else None
def app(tag: str):
f = RAW / f"{tag}.applied.json"
return json.loads(f.read_text(encoding="utf-8")) if f.exists() else None
def hanzi_share(s: str) -> float:
if not s:
return 0.0
h = sum(1 for c in s if 0x3400 <= ord(c) <= 0x9FFF)
return h / len(s)
def money_block(tags: list[str], label: str) -> dict:
rs = [r for r in (rec(t) for t in tags) if r]
if not rs:
return {}
return {"label": label, "n": len(rs),
"usd": sum(r["cost_usd"] for r in rs),
"out": sum(r["completion_tokens"] for r in rs),
"finish": {r["finish"] for r in rs}}
def pair_ratios(dtag, ftag, cells) -> tuple[list[tuple], list[str]]:
"""[(клетка, отношение цены дифф/full)] + пропуски поимённо.
⚠ Возвращается ИМЕННО пара с клеткой: ранняя версия отдавала голый список отношений, и
группировка по окнам делалась `zip` с пере-фильтрованным списком клеток — при любом пропуске
отношения съезжали на чужие окна, а медиана считалась бы по перепутанным данным.
"""
out, missing = [], []
for c in cells:
d, f = rec(dtag(c)), rec(ftag(c))
if not d or not f:
missing.append(f"{dtag(c)}|{ftag(c)}")
continue
out.append((c, d["cost_usd"] / f["cost_usd"]))
return out, missing
def compliance(tags: list[str]) -> tuple[int, int, dict, list[str]]:
ops = ap = 0
reasons = {"notfound": 0, "ambiguous": 0, "overlap": 0, "empty": 0,
"malformed": 0, "no_change": 0}
missing = []
for t in tags:
a = app(t)
if not a:
missing.append(t)
continue
ops += a["ops_total"]
ap += a["applied"]
reasons["notfound"] += a["rejected_notfound"]
reasons["ambiguous"] += a["rejected_ambiguous"]
reasons["overlap"] += a["rejected_overlap"]
reasons["empty"] += a["rejected_empty"]
reasons["malformed"] += a["malformed"]
reasons["no_change"] += a["no_change"]
return ops, ap, reasons, missing
def verdict(name: str, falls: bool | None, detail: str) -> None:
mark = {True: "ВЫВОД §ПАДАЕТ", False: "вывод устоял", None: "НЕОПРЕДЕЛЁННО"}[falls]
print(f"{name}: {mark}{detail}")
def arm_L():
print("\n=== АРМ L: «дифф дороже» — артефакт несъёмного thinking? (reasoning_effort=low) ===")
cells = [(k, r) for k in range(6) for r in (1, 2, 3)]
pairs, missing = pair_ratios(lambda c: f"fp-LD-w{c[0]}-r{c[1]}",
lambda c: f"fp-LF-w{c[0]}-r{c[1]}", cells)
if missing:
print(f" ⚠ нет пары для {len(missing)} клеток: {', '.join(missing[:6])}")
if not pairs:
return verdict("L", None, "нет ни одной полной пары")
# медиана ПО ОКНАМ: сперва медиана розыгрышей внутри окна, затем медиана окон
ratios = [r for _, r in pairs]
by_win = {}
for (k, _rep), ratio in pairs:
by_win.setdefault(k, []).append(ratio)
win_med = {k: statistics.median(v) for k, v in sorted(by_win.items())}
med = statistics.median(win_med.values())
print(" отношение цены дифф/full по окнам: "
+ " ".join(f"w{k}={v:.2f}" for k, v in win_med.items()))
print(f" медиана окон = {med:.3f} (всех клеток {len(ratios)}, медиана клеток "
f"{statistics.median(ratios):.3f})")
d = money_block([f"fp-LD-w{k}-r{r}" for k, r in cells], "дифф low")
f = money_block([f"fp-LF-w{k}-r{r}" for k, r in cells], "full low")
for b in (d, f):
if b:
print(f" {b['label']}: n={b['n']} ${b['usd']:.6f} выход {b['out']} ток. finish={b['finish']}")
# ЭХО-КОНТРОЛЬ. Пре-рег §3 сказан буквально: «ненулевое эхо делает low непригодным».
# ⚠ ИСПРАВЛЕНО по адверсариальному ревью 05.08. Прежний комментарий утверждал, что все
# найденные знаки — «цитаты в сносках»; это было ЛОЖНО и опиралось на разбор ОДНОГО случая
# из двух. Сырьё: `fp-LD-w4-r1` (修行) — дословный SEARCH-якорь по сноске САМОГО черновика,
# REPLACE пуст, операция сноску удаляет ⇒ модель знаков не порождала; `fp-LF-w3-r2` (潜能) —
# сносок в выходе нет вообще, знаки стоят внутри повествования («символом жизненной潜能»),
# а черновик в этом месте несёт корректное «жизненного потенциала» ⇒ это ПОРОЖДЁННАЯ
# моделью микро-утечка исходника. Порог 5% ниже боевого гейта (`disposition.go`
# cjkEchoThreshold = 0.15) и на два порядка выше наблюдённого; явление quirks §4 (выход
# исходником целиком, доля 0.830.999) не наблюдалось. Low-специфичность НЕ показана:
# на дефолтном эффорте ханьцзы тоже есть (ec-D1 2/18, ec-D2 1/18 — та же сноска черновика).
from collections import Counter
chars, per_call = Counter(), {}
for k, r in cells:
for t in (f"fp-LD-w{k}-r{r}", f"fp-LF-w{k}-r{r}"):
rr = rec(t)
if not rr:
continue
hz = [c for c in rr["content"] if 0x3400 <= ord(c) <= 0x9FFF]
if hz:
chars.update(hz)
per_call[t] = hanzi_share(rr["content"])
literal_nonzero = bool(per_call)
worst = max(per_call.values()) if per_call else 0.0
print(f" эхо-контроль, БУКВА пре-рега (ханьцзы > 0): "
f"{'есть' if literal_nonzero else 'нет'} — вызовов с ханьцзы {len(per_call)}, "
f"всего знаков {sum(chars.values())}, худшая доля {worst:.4%}")
if chars:
print(f" какие знаки: {dict(chars)} ⇒ разбор глазами обязателен")
if worst >= 0.05:
print(" ⛔ ЭХО-МИНА: доля исходника в выходе ≥5% — это не цитата")
verdict("L", None, "цена нерелевантна: `low` пере-вооружил эхо-мину ⇒ режим непригоден")
else:
if literal_nonzero:
print(" ⚠ ДЕВИАЦИЯ ОТ БУКВЫ пре-рега: порог 5% вместо «ненулевого». Разбор сырья: "
"часть знаков — SEARCH-якорь по сноске ЧЕРНОВИКА (модель их не порождала), "
"часть — настоящая микро-утечка исходника в повествование. Сплошного эха "
"(quirks §4, доля 0.83+) нет. По БУКВЕ пре-рега рекомендация «редактору low» "
"закрыта независимо от цены; на медианный вердикт ниже это не влияет")
# ⚠ НЕ печатаем «вывод устоял»: по адверсариальному ревью 05.08 (отчёт 19 §6.2) арм L —
# НЕ исполненная фальсификация. Его посылка («ручка low на pro работает», quirks §3б)
# не выдержала пере-счёта: решающее правило n=3/3 воспроизводится НУЛЕВЫМ вмешательством,
# на побайтно одном входе дефолт и low пересекаются (MW p=0.589). Число верно, статус — нет.
print(f" ⇒ L: НЕ ФАЛЬСИФИКАЦИЯ — отличимость `low` от дефолта не установлена (§6.2). "
f"Медиана {med:.3f} > 1.0 засчитывается как ВТОРАЯ РЕПЛИКАЦИЯ вывода «дифф дороже», "
f"а не как выдержанная проверка гипотезы про несъёмный thinking")
ops, ap, reasons, miss = compliance([f"fp-LD-w{k}-r{r}" for k, r in cells])
if ops:
print(f" побочно, комплаенс диффа на low: {ap}/{ops} = {ap / ops:.3f}; {reasons}")
def arm_N():
print("\n=== АРМ N: покупается ли do-nothing узким fidelity-промптом? ===")
tags = [f"fp-N-w{k}-r{r}" for k in range(6) for r in (1, 2, 3)]
ops, ap, reasons, missing = compliance(tags)
present = len(tags) - len(missing)
if missing:
print(f" ⚠ нет выхода для {len(missing)}: {', '.join(missing[:6])}")
if not present:
return verdict("N", None, "нет данных")
nc = reasons["no_change"]
print(f" вызовов {present}/{len(tags)} · операций {ops} · применено {ap} "
f"· NO_CHANGE {nc} · малформед {reasons['malformed']}")
print(f" комплаенс {ap / ops:.3f}" if ops else " операций 0")
b = money_block(tags, "fidelity-дифф")
if b:
print(f" {b['label']}: ${b['usd']:.6f} выход {b['out']} ток. finish={b['finish']}")
verdict("N", nc > 0, f"NO_CHANGE {nc} из {present} вызовов (в §2 было 0 из 36)")
def arm_G():
print("\n=== АРМ G: держится ли комплаенс на БОЕВОЙ единице (~3200 ру-ток.)? ===")
cells = [(u, r) for u in range(2) for r in (1, 2, 3)]
dtags = [f"fp-GD-u{u}-r{r}" for u, r in cells]
ops, ap, reasons, missing = compliance(dtags)
if missing:
print(f" ⚠ нет apply для {len(missing)}: {', '.join(missing)}")
if not ops:
return verdict("G", None, "операций 0 — считать нечего")
comp = ap / ops
print(f" операций {ops} · применено {ap} · комплаенс {comp:.3f}")
print(f" причины reject: {reasons}")
gpairs, miss2 = pair_ratios(lambda c: f"fp-GD-u{c[0]}-r{c[1]}",
lambda c: f"fp-GF-u{c[0]}-r{c[1]}", cells)
ratios = [r for _, r in gpairs]
if ratios:
print(f" отношение цены дифф/full на длинной единице: медиана "
f"{statistics.median(ratios):.3f} ({len(ratios)} пар)")
for b in (money_block(dtags, "дифф длинный"),
money_block([f"fp-GF-u{u}-r{r}" for u, r in cells], "full длинный")):
if b:
print(f" {b['label']}: n={b['n']} ${b['usd']:.6f} выход {b['out']} ток. finish={b['finish']}")
verdict("G", comp < 0.90, f"комплаенс {comp:.3f} против порога 0.90")
def arm_E():
print("\n=== АРМ E: «дифф дороже» — артефакт РУССКОЙ фертильности? (английская цель) ===")
cells = [(k, r) for k in range(6) for r in (1, 2)]
epairs, missing = pair_ratios(lambda c: f"fp-ED-w{c[0]}-r{c[1]}",
lambda c: f"fp-EF-w{c[0]}-r{c[1]}", cells)
ratios = [r for _, r in epairs]
if missing:
print(f" ⚠ нет пары для {len(missing)}: {', '.join(missing[:6])}")
if not ratios:
return verdict("E", None, "нет ни одной полной пары")
med = statistics.median(ratios)
print(f" отношение цены дифф/full: медиана {med:.3f} по {len(ratios)} парам "
f"({' '.join(f'{r:.2f}' for r in ratios)})")
dt = [f"fp-ED-w{k}-r{r}" for k, r in cells]
ops, ap, reasons, miss = compliance(dt)
if ops:
print(f" формат-комплаенс на английском: {ap}/{ops} = {ap / ops:.3f}; {reasons}")
for b in (money_block(dt, "дифф en"),
money_block([f"fp-EF-w{k}-r{r}" for k, r in cells], "full en")):
if b:
print(f" {b['label']}: n={b['n']} ${b['usd']:.6f} выход {b['out']} ток. finish={b['finish']}")
print(" ⚠ точность перевода этим армом НЕ измеряется: en-голда в проекте нет (пре-рег §3)")
verdict("E", med <= 1.0, f"медиана {med:.3f} против порога 1.0")
def main():
spent = sum(json.loads(f.read_text(encoding="utf-8"))["cost_usd"]
for f in RAW.glob("fp-*.json") if not f.name.endswith(".applied.json"))
for fn in (arm_L, arm_N, arm_G, arm_E):
try:
fn()
except Exception as e: # noqa: BLE001 — арм не должен ронять счёт остальных
print(f" ⛔ счёт арма упал: {type(e).__name__}: {e}")
print(f"\nПОТРАЧЕНО на фальсификации: ${spent:.6f} (потолок пре-рега $0.50)")
if __name__ == "__main__":
main()
sys.exit(0)