textmachine/eval/dovodka/en_axis.py

237 lines
12 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
"""Д3 — НЕСУЩАЯ ОСЬ en→ru на 16 единицах Кристоффа. Платный.
Зачем отдельным файлом. Механизмы контуров не дублируются: покупку ведёт `contour.cmd_run`,
переведённый на пару вызовом `contour.configure`. Здесь живёт только то, что у английской оси
СВОЁ, — базы и их источник.
⚠ ПОЧЕМУ БАЗЫ ПОКУПАЮТСЯ ЗАНОВО, А НЕ БЕРУТСЯ ИЗ ЭКСП-21. В `~/books/role-topology` лежат 75
оплаченных английских клеток (15 единиц × DRAFT/A/B/D/D_), и соблазн взять их базой велик. Нельзя:
они куплены 10.08, а пар-пакет `prompts/en-ru/` переписан и заморожен 1314.08 ДО покупок фазы Д.
Взяв старые клетки, мы получили бы арм `E0` на старых промтах и контуры поверх него на новых —
разница армов мерила бы смену промтов, а не топологию. Это конфаундер эксп-19 в чистом виде.
Старое сырьё остаётся сырьём эксп-21 и здесь не читается вообще.
Имена армов — из пре-регистрации (`23-editor-tier.md`, Д0.5), механизмы — общие с китайской осью:
D0 черновик (`deepseek-v4-flash`) база, не арм
E0 боевая связка: черновик + боевой редактор эталон оси
E1 черновик + детерминированные флаги → фиксер вид «flags»
E2 однопроходка уравненного мандата вид «onepass»
E3 черновик + смысловой критик → фиксер вид «critic»
E4 E0 + канон-фиксер ПОСЛЕ вид «canonfix»
E6 ВТОРОЙ редактор (`glm-5`) поверх той же базы касса ФД-G
Первичный контраст — `E0/D0` (H-3: покупает ли редактор что-нибудь поверх черновика). Он и
покупается первым: если денег не хватит на всю ось, несущая гипотеза всё равно будет закрыта,
а описательные армы объявлены некупленными — вслух, а не молчанием.
Запуск: en_axis.py --dry смета и что уже куплено, $0
en_axis.py --bases купить D0 и E0 (первичный контраст)
en_axis.py --arms купить E1 E2 E3 E4
en_axis.py --e6 купить E6 (касса ФД-G)
en_axis.py --selftest
"""
from __future__ import annotations
import importlib.util
import json
import sys
from pathlib import Path
REPO = Path("/home/ubuntu/projects/textmachine")
ZONE = Path(__file__).resolve().parent
for d in ("dovodka", "editor_tier", "tenant_panel", "role_topology", "bank_arbitration"):
sys.path.insert(0, str(REPO / "eval" / d))
def _load(name: str, path: Path):
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
C = _load("contour_en", ZONE / "contour.py")
PE = _load("pair_en_ax", REPO / "eval" / "role_topology" / "pair_en.py")
MONEY, PR, ROSTER, ED22, PARA = C.MONEY, C.PR, C.ROSTER, C.ED22, C.PARA
N_PER_STRATUM = 8 # 16 единиц — ровно то, что объявила мощность оси
DRAFT_MODEL = "deepseek-v4-flash" # тот же жилец-черновик, что на китайской оси
EDITOR = "deepseek-v4-pro" # боевой редактор
EDITOR2 = "glm-5" # второй редактор, H-4
def units() -> list[dict]:
"""16 приколотых единиц. Манифест обязателен: чтение никогда не переотбирает."""
return PE.units(N_PER_STRATUM)
def text_of(tg: str) -> str:
f = MONEY.OUT / f"{tg}.json"
if not f.exists():
return ""
return json.loads(f.read_text(encoding="utf-8")).get("content") or ""
def base_draft(uid: str) -> str:
"""D0 — якорный черновик оси. ⚠ Гейт годности тот же, что на китайской ветке."""
t = text_of(f"dv-b-d0-{uid}")
if not t.strip():
return ""
why = C.draft_defect(t)
if why:
print(f"{uid}: черновик БРАКОВАН гейтом проекта ({why}) — единица непригодна")
return ""
return t
def base_e0(uid: str) -> str:
"""E0 — боевая связка, эталон оси (роль A0 китайской)."""
return text_of(f"dv-b-e0-{uid}")
def wire() -> None:
"""Единственная точка включения пары. Всё остальное — механизмы контура."""
C.configure(PARA.EN, units_provider=units,
base_draft_hook=base_draft, base_a0_hook=base_e0)
def _law(src: str) -> str | None:
bf = PARA.EN.bank_file
return PR.law_block(PR.terms_in(src, bf), bf)
def cmd_bases() -> None:
"""D0 и E0 — первичный контраст оси. Покупаются ПЕРВЫМИ."""
wire()
led = MONEY.Guarded("ФД-B", default_expect=0.006)
for u in units():
uid, src = u["uid"], u["source"]
tg = f"dv-b-d0-{uid}"
if not text_of(tg).strip():
rec = MONEY.purchase(led, tg, DRAFT_MODEL, ED22.client(DRAFT_MODEL),
ROSTER.call_kwargs(DRAFT_MODEL,
PR.translator_msgs(src, None, pair="en-ru")),
role="translator", uid=uid, arm="D0")
if rec.get("skipped"):
raise SystemExit(f"⛔ ГАРД ОТКАЗАЛ на {tg} — СТОП и вопрос владельцу")
for u in units():
uid, src = u["uid"], u["source"]
draft = base_draft(uid)
if not draft.strip():
print(f" {uid}: черновика нет — E0 пропущен")
continue
tg = f"dv-b-e0-{uid}"
if text_of(tg).strip():
continue
rec = MONEY.purchase(led, tg, EDITOR, ED22.client(EDITOR),
ROSTER.call_kwargs(EDITOR,
PR.editor_msgs(src, draft, _law(src),
pair="en-ru")),
role="editor", uid=uid, arm="E0")
if rec.get("skipped"):
raise SystemExit(f"⛔ ГАРД ОТКАЗАЛ на {tg} — СТОП и вопрос владельцу")
MONEY.report()
def cmd_e6() -> None:
"""E6 — ВТОРОЙ редактор поверх той же базы. Касса ФД-G, а не ФД-B."""
wire()
led = MONEY.Guarded("ФД-G", default_expect=0.013)
for u in units():
uid, src = u["uid"], u["source"]
draft = base_draft(uid)
if not draft.strip():
continue
tg = f"dv-g-e6-{uid}"
if text_of(tg).strip():
continue
rec = MONEY.purchase(led, tg, EDITOR2, ED22.client(EDITOR2),
ROSTER.call_kwargs(EDITOR2,
PR.editor_msgs(src, draft, _law(src),
pair="en-ru")),
role="editor3", uid=uid, arm="E6")
if rec.get("skipped"):
raise SystemExit(f"⛔ ГАРД ОТКАЗАЛ на {tg} — СТОП и вопрос владельцу")
MONEY.report()
def cmd_arms() -> None:
wire()
C.cmd_run(["E1", "E2", "E3", "E4"])
def cmd_dry() -> None:
"""Смета и наличие. $0. Цены — измеренные медианы фазы, а не догадки."""
wire()
us = units()
have = {a: sum(1 for u in us if text_of(C.tag(a, u["uid"])).strip())
for a in ("E1", "E2", "E3", "E4", "E6")}
have["D0"] = sum(1 for u in us if text_of(f"dv-b-d0-{u['uid']}").strip())
have["E0"] = sum(1 for u in us if text_of(f"dv-b-e0-{u['uid']}").strip())
price = {"D0": 0.0020, "E0": 0.00523, "E1": 0.00314, "E2": 0.00523,
"E3": 0.01120 + 0.00314, "E4": 0.00314, "E6": 0.01249}
what = {"D0": "черновик (база, не арм)", "E0": "боевая связка — ЭТАЛОН оси",
"E1": "флаги → фиксер", "E2": "однопроходка уравненного мандата",
"E3": "смысловой критик → фиксер", "E4": "E0 + канон-фиксер",
"E6": "второй редактор glm-5 (касса ФД-G)"}
print(f"Д3 en→ru · единиц {len(us)} · банк {len(PR.bank(PARA.EN.bank_file))} терминов\n")
print(f" {'арм':4s}{'есть':>6s}{'надо':>6s}{'$/клетка':>10s}{'смета':>9s} что это")
tot_b = tot_g = 0.0
for a in ("D0", "E0", "E1", "E2", "E3", "E4", "E6"):
need = len(us) - have[a]
cost = need * price[a]
if a == "E6":
tot_g += cost
else:
tot_b += cost
print(f" {a:4s}{have[a]:6d}{need:6d}{price[a]:10.5f}{cost:9.4f} {what[a]}")
for ph, need in (("ФД-B", tot_b), ("ФД-G", tot_g)):
sp = MONEY.Guarded(ph).spent()
ceil = MONEY.CEILINGS[ph]
left = ceil - sp
mark = "ВЛЕЗАЕТ" if need <= left else f"НЕ ВЛЕЗАЕТ, не хватает ${need - left:.4f}"
print(f"\n {ph}: потрачено ${sp:.4f} · потолок ${ceil:.2f} · остаток ${left:.4f} · "
f"нужно ${need:.4f}{mark}")
print("\n⚠ Цены — медианы, снятые на китайских единицах (~1100 знаков). Английские длиннее "
"(~1600), поэтому фактическая цена выше сметы; порядок покупки это учитывает: "
"первичный контраст E0/D0 берётся ПЕРВЫМ.")
def cmd_selftest() -> int:
bad = 0
def ck(n: str, ok: bool, d: str = "") -> None:
nonlocal bad
bad += not ok
print(f"[{'OK ' if ok else 'ПРОВАЛ'}] {n}" + (f" {d}" if d else ""))
wire()
us = units()
ck("единиц ровно 16 — как объявила мощность оси", len(us) == 16, f"их {len(us)}")
ck("страты равны (французский слой против без него)",
sum(1 for u in us if u["stratum"] == "fr") == 8)
ck("пара включена целиком", C.pair().key == "en-ru")
ck("теги оси попадают в глоб кассы ФД-B",
all(C.tag(a, "u").startswith("dv-b-") for a in ("E1", "E2", "E3", "E4")))
ck("E6 идёт в ФД-G, а не в ФД-B",
C.tag("E6", "u").startswith("dv-g-") and C.phase_of("E6") == "ФД-G")
ck("банк пары непуст (иначе канон-ось пуста и E4 неотличим от E0)",
len(PR.bank(PARA.EN.bank_file)) > 0)
# ⚠ Старое сырьё эксп-21 НЕ должно подхватываться: оно на других промтах.
old = list((Path.home() / "books" / "role-topology").glob("en2-*.json"))
ck("сырьё эксп-21 существует, но осью НЕ читается", bool(old)
and not any(str(MONEY.OUT) in str(f) for f in old), f"клеток эксп-21 {len(old)}")
ck("базы берутся из клеток ФАЗЫ", C.BASE_DRAFT_HOOK is base_draft
and C.BASE_A0_HOOK is base_e0)
print(f"\n{'ОСЬ ГОТОВА К ПОКУПКЕ' if not bad else f'ПРОВАЛОВ: {bad}'}")
return bad
if __name__ == "__main__":
a = sys.argv[1] if len(sys.argv) > 1 else "--dry"
fn = {"--dry": cmd_dry, "--bases": cmd_bases, "--arms": cmd_arms, "--e6": cmd_e6,
"--selftest": lambda: sys.exit(1 if cmd_selftest() else 0)}.get(a)
fn() if fn else print(__doc__)