From 1f66b354feada6628176d99b9103387aee6caabb Mon Sep 17 00:00:00 2001 From: heaven Date: Fri, 14 Aug 2026 17:36:28 +0300 Subject: [PATCH] Freeze the ja reconnaissance axis and its raised ceiling: shared base purchasing, pair-scoped tags and the descriptive status asserted by selftest --- eval/dovodka/contour.py | 50 +++++++++++++- eval/dovodka/ja_axis.py | 150 ++++++++++++++++++++++++++++++++++++++++ eval/dovodka/money_d.py | 8 ++- 3 files changed, 204 insertions(+), 4 deletions(-) create mode 100644 eval/dovodka/ja_axis.py diff --git a/eval/dovodka/contour.py b/eval/dovodka/contour.py index 480ee29e..5ba9edc0 100644 --- a/eval/dovodka/contour.py +++ b/eval/dovodka/contour.py @@ -79,7 +79,9 @@ ARMS = ("A1", "A1B", "A2", "A3", "A4", "A6", "A6F") ARM_KIND = {"A1": "flags", "A1B": "flags", "A6F": "flags", "A4": "canonfix", "A2": "onepass", "A3": "critic", "A6": "critic", # английская ось Д3 (имена — из пре-регистрации, механизмы — те же) - "E1": "flags", "E2": "onepass", "E3": "critic", "E4": "canonfix"} + "E1": "flags", "E2": "onepass", "E3": "critic", "E4": "canonfix", + # японская ось Д6 — разведка: связка и однопроходка + "J2": "onepass"} def phase_of(arm: str) -> str: @@ -91,6 +93,7 @@ def phase_of(arm: str) -> str: return "ФД-G" return {"en-ru": "ФД-B", "ja-ru": "ФД-C"}[P.key] + # ⚠ ПОЧЕМУ A1 И A1B — ДВА АРМА, А НЕ ПЕРЕ-ПОКУПКА ОДНОГО. Куплённые 30 клеток `A1` получили список # мест ТОЛЬКО от канон-гейта: батарея падала на 32/32 и ошибку глотал голый except (эррата Э-4). # Переименовать их значило бы разойтись с полем `tag` внутри самих записей, а править оплаченное @@ -649,6 +652,51 @@ def cmd_run(which: list[str]) -> None: MONEY.report() +def buy_bases(phase: str, us: list[dict], pfx: str, draft_arm: str, edit_arm: str, + draft_model: str, edit_model: str, pair_key: str, law_fn, expect: float) -> None: + """Черновик и боевая связка новой пары — общий механизм для всех неканонных осей. + + ⚠ Вынесено, чтобы японская ось не была КОПИЕЙ английской. Копия цикла покупки означала бы + копию всех будущих расхождений: гард, кэш, гейт годности черновика и порядок «сначала база, + потом контуры» должны быть одни и те же на всех осях, иначе разница осей начнёт мерить + разницу их драйверов. + """ + led = MONEY.Guarded(phase, default_expect=expect) + + def cell(tg: str) -> str: + f = OUT / f"{tg}.json" + return (json.loads(f.read_text(encoding="utf-8")).get("content") or "") if f.exists() else "" + + for u in us: # сначала ВСЕ черновики + tg = f"{pfx}-{draft_arm.lower()}-{u['uid']}" + if cell(tg).strip(): + continue + rec = MONEY.purchase(led, tg, draft_model, ED22.client(draft_model), + ROSTER.call_kwargs(draft_model, + PR.translator_msgs(u["source"], None, + pair=pair_key)), + role="translator", uid=u["uid"], arm=draft_arm) + if rec.get("skipped"): + raise SystemExit(f"⛔ ГАРД ОТКАЗАЛ на {tg} — СТОП и вопрос владельцу") + for u in us: # затем связка поверх них + draft = base_draft(u["uid"]) + if not draft.strip(): + print(f" {u['uid']}: черновика нет — {edit_arm} пропущен") + continue + tg = f"{pfx}-{edit_arm.lower()}-{u['uid']}" + if cell(tg).strip(): + continue + rec = MONEY.purchase(led, tg, edit_model, ED22.client(edit_model), + ROSTER.call_kwargs(edit_model, + PR.editor_msgs(u["source"], draft, + law_fn(u["source"]), + pair=pair_key)), + role="editor", uid=u["uid"], arm=edit_arm) + if rec.get("skipped"): + raise SystemExit(f"⛔ ГАРД ОТКАЗАЛ на {tg} — СТОП и вопрос владельцу") + MONEY.report() + + def cmd_floor() -> None: """СВОЙ шумовой пол оси Д4 — ПАРОЙ независимых генераций одного и того же лечения. diff --git a/eval/dovodka/ja_axis.py b/eval/dovodka/ja_axis.py new file mode 100644 index 00000000..843e1ae9 --- /dev/null +++ b/eval/dovodka/ja_axis.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python3 +"""Д6 — РАЗВЕДОЧНАЯ ОСЬ ja→ru на 9 единицах «円環の果てに». Платный. + +⚠ СТАТУС — РАЗВЕДКА, объявлен пре-регистрацией (Д0.5) и закреплён арифметикой: при n=9 и sd 2.90 +MDE оси 2.90 против цели 2.00, то есть несущего вывода она дать НЕ МОЖЕТ ни при каком исходе. +`power.FORCED_DESCRIPTIVE` держит это механически — ось объявлена описательной ДО денег, и +превращать её результат в вывод «японский ведёт себя так-то» нельзя даже при красивых числах. + +Механизмы не дублируются: базы покупает общий `contour.buy_bases`, однопроходку — общий +`contour.cmd_run`. Здесь только японо-специфичное — единицы, модели, касса. + + D0 черновик (`deepseek-v4-flash`) база + J0 боевая связка: черновик + боевой редактор эталон оси + J2 однопроходка уравненного мандата единственный контур разведки + +Контроль оси — `J0/D0`: покупает ли редактор что-нибудь поверх черновика на этой паре. + +⚠ Материал прошёл гардрейл 18+ (0 срабатываний из 48 чанков) и контам-пробу жильцами +(0/5 узнавание и 0/5 клоуз у обоих при сработавшем положительном контроле). + +Запуск: ja_axis.py --dry | --bases | --arms | --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_ja", ZONE / "contour.py") +MJ = _load("material_ja_ax", ZONE / "material_ja.py") +MONEY, PR, PARA = C.MONEY, C.PR, C.PARA + +DRAFT_MODEL = "deepseek-v4-flash" +EDITOR = "deepseek-v4-pro" +PFX = "dv-c" + + +def units() -> list[dict]: + """9 приколотых единиц. Манифест обязателен и уже заморожен.""" + return MJ.units() + + +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: + t = text_of(f"{PFX}-d0-{uid}") + if not t.strip(): + return "" + why = C.draft_defect(t) + if why: + print(f" ⚠ {uid}: черновик БРАКОВАН гейтом проекта ({why}) — единица непригодна") + return "" + return t + + +def base_j0(uid: str) -> str: + return text_of(f"{PFX}-j0-{uid}") + + +def wire() -> None: + C.configure(PARA.JA, units_provider=units, + base_draft_hook=base_draft, base_a0_hook=base_j0) + + +def _law(src: str) -> str | None: + bf = PARA.JA.bank_file + return PR.law_block(PR.terms_in(src, bf), bf) + + +def cmd_bases() -> None: + wire() + C.buy_bases("ФД-C", units(), PFX, "D0", "J0", DRAFT_MODEL, EDITOR, "ja-ru", _law, 0.006) + + +def cmd_arms() -> None: + wire() + C.cmd_run(["J2"]) + + +def cmd_dry() -> None: + wire() + us = units() + have = {"D0": sum(1 for u in us if text_of(f"{PFX}-d0-{u['uid']}").strip()), + "J0": sum(1 for u in us if text_of(f"{PFX}-j0-{u['uid']}").strip()), + "J2": sum(1 for u in us if text_of(C.tag("J2", u["uid"])).strip())} + price = {"D0": 0.0020, "J0": 0.00523, "J2": 0.00523} + what = {"D0": "черновик (база)", "J0": "боевая связка — эталон", "J2": "однопроходка"} + print(f"Д6 ja→ru РАЗВЕДКА · единиц {len(us)} · банк {len(PR.bank(PARA.JA.bank_file))} терминов\n") + need_total = 0.0 + print(f" {'арм':4s}{'есть':>6s}{'надо':>6s}{'смета':>9s} что это") + for a in ("D0", "J0", "J2"): + need = len(us) - have[a] + need_total += need * price[a] + print(f" {a:4s}{have[a]:6d}{need:6d}{need * price[a]:9.4f} {what[a]}") + sp = MONEY.Guarded("ФД-C").spent() + left = MONEY.CEILINGS["ФД-C"] - sp + print(f"\n ФД-C: потрачено ${sp:.4f} · потолок ${MONEY.CEILINGS['ФД-C']:.2f} · " + f"остаток ${left:.4f} · нужно ${need_total:.4f} → " + f"{'ВЛЕЗАЕТ' if need_total <= left else f'НЕ ВЛЕЗАЕТ, не хватает ${need_total - left:.4f}'}") + + +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("единиц ровно 9 — как объявила разведка", len(us) == 9, f"их {len(us)}") + ck("пара включена целиком", C.pair().key == "ja-ru") + ck("теги идут в кассу ФД-C", C.tag("J2", "u").startswith("dv-c-") + and C.phase_of("J2") == "ФД-C") + ck("банк пары непуст", len(PR.bank(PARA.JA.bank_file)) > 0, + f"терминов {len(PR.bank(PARA.JA.bank_file))}") + ck("японская письменность опознаётся как исходник", + bool(PARA.JA.source_script.search(us[0]["source"]))) + ck("ось объявлена ОПИСАТЕЛЬНОЙ и это не отменяется арифметикой", + "Д6 ja→ru разведка" in _load("power_ja", ZONE / "power.py").FORCED_DESCRIPTIVE) + 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, + "--selftest": lambda: sys.exit(1 if cmd_selftest() else 0)}.get(a) + fn() if fn else print(__doc__) diff --git a/eval/dovodka/money_d.py b/eval/dovodka/money_d.py index 546a0c2f..c8b68e35 100644 --- a/eval/dovodka/money_d.py +++ b/eval/dovodka/money_d.py @@ -116,11 +116,13 @@ TAGS = { # (жилец `pro` думает по $0.014 за клетку). Английские единицы вдобавок в полтора раза длиннее # китайских, поэтому клетка дороже сметы на ~21% (замер по базам: $0.140 против $0.116). # Без подъёма арм E3 — смысловой контур, несущий ставку владельца на китайской оси, — остался бы -# некупленным. Пакетный потолок поднят РОВНО на ту же дельту, чтобы инвариант «сумма фазовых ≤ +# некупленным. ФД-C поднят 14.08 по той же причине и в том же режиме автономии: +# проба жильцами съела $0.090 из плановых $0.154 японской оси, и на связку с +# однопроходкой не оставалось $0.032. Пакетный потолок поднят РОВНО на ту же дельту, чтобы инвариант «сумма фазовых ≤ # пакетного» держался; ось никто не режет и деньги ниоткуда не забирает. -CEILINGS = {"ФД-A": 1.950, "ФД-B": 0.900, "ФД-C": 0.170, "ФД-D": 0.050, +CEILINGS = {"ФД-A": 1.950, "ФД-B": 0.900, "ФД-C": 0.250, "ФД-D": 0.050, "ФД-E": 2.370, "ФД-F": 0.720, "ФД-G": 0.210} -PACK_CEILING = 6.42 +PACK_CEILING = 6.50 M22.configure(ZONE=ZONE, OUT=OUT, TAGS=TAGS, CEILINGS=CEILINGS, PACK_CEILING=PACK_CEILING, GLOB_ALL="dv-*.json", ROSTER=ROSTER)