Make the output budget an axis parameter and gate cell validity so truncated empty cells are quarantined and rebought instead of judged as arms

This commit is contained in:
heaven 2026-08-14 18:28:25 +03:00
parent e64d921e48
commit 548d1ce6dd
3 changed files with 78 additions and 9 deletions

View file

@ -134,6 +134,12 @@ EXCLUDED = {
# и включается ЦЕЛИКОМ: риг, банк, бриф, письменность, теги и источник единиц разом. # и включается ЦЕЛИКОМ: риг, банк, бриф, письменность, теги и источник единиц разом.
_PAIR = None _PAIR = None
_UNITS = None _UNITS = None
# ⚠ БЮДЖЕТ ВЫВОДА — ПАРАМЕТР ОСИ. Умолчание рига 16000 хватает китайским единицам, но не японским:
# у DeepSeek размышление тарифицируется и считается ВНУТРИ бюджета, а японский текст плотнее на
# знак и даёт более длинный русский перевод. Замер 14.08: 3 клетки из 27 вернулись ПУСТЫМИ с
# `finish=length`, деньги списаны, содержимого нет. Клетка при этом СУЩЕСТВУЕТ файлом, поэтому
# счёт «9/9» выглядел полным — считались файлы, а не годное содержимое.
_MAX_OUT = 16000
def pair(): def pair():
@ -143,9 +149,12 @@ def pair():
return _PAIR return _PAIR
def configure(p, units_provider=None, base_draft_hook=None, base_a0_hook=None) -> None: def configure(p, units_provider=None, base_draft_hook=None, base_a0_hook=None,
max_out: int | None = None) -> None:
"""Перевести контур на пару `p`. Для zh — проверенный no-op (селфтест это стережёт).""" """Перевести контур на пару `p`. Для zh — проверенный no-op (селфтест это стережёт)."""
global _PAIR, _UNITS, BASE_DRAFT_HOOK, BASE_A0_HOOK global _PAIR, _UNITS, BASE_DRAFT_HOOK, BASE_A0_HOOK, _MAX_OUT
if max_out:
_MAX_OUT = max_out
BASE_DRAFT_HOOK, BASE_A0_HOOK = base_draft_hook, base_a0_hook BASE_DRAFT_HOOK, BASE_A0_HOOK = base_draft_hook, base_a0_hook
_PAIR, _UNITS = p, units_provider _PAIR, _UNITS = p, units_provider
B.configure_pair(SOURCE_VALUES_HOOK=p.values_in_source, B.configure_pair(SOURCE_VALUES_HOOK=p.values_in_source,
@ -570,7 +579,7 @@ def _buy(led, tg: str, msgs: list[dict], **extra) -> dict:
вопрос владельцу**. Здесь она наконец механизирована. вопрос владельцу**. Здесь она наконец механизирована.
""" """
rec = MONEY.purchase(led, tg, FIXER, ED22.client(FIXER), rec = MONEY.purchase(led, tg, FIXER, ED22.client(FIXER),
ROSTER.call_kwargs(FIXER, msgs), **extra) ROSTER.call_kwargs(FIXER, msgs, max_out=_MAX_OUT), **extra)
if rec.get("skipped"): if rec.get("skipped"):
raise SystemExit( raise SystemExit(
f"⛔ ГАРД ОТКАЗАЛ на клетке {tg} — прогон ОСТАНОВЛЕН.\n" f"⛔ ГАРД ОТКАЗАЛ на клетке {tg} — прогон ОСТАНОВЛЕН.\n"
@ -656,6 +665,25 @@ def cmd_run(which: list[str]) -> None:
MONEY.report() MONEY.report()
def quarantine_length(tags: list[str]) -> int:
"""Увести клетки `finish=length` с пустым содержимым в карантин `.LENGTH.json`.
Не удалять: деньги за них списаны и обязаны остаться видимыми кассе (глоб считает
`dv-*.json`, и карантинное имя под него по-прежнему попадает). Удаление спрятало бы трату.
"""
n = 0
for tg in tags:
f = OUT / f"{tg}.json"
if not f.exists():
continue
rec = json.loads(f.read_text(encoding="utf-8"))
if rec.get("finish") == "length" and not (rec.get("content") or "").strip():
f.rename(OUT / f"{tg}.LENGTH.json")
print(f" {tg}: пустая клетка (finish=length) → карантин")
n += 1
return n
def buy_bases(phase: str, us: list[dict], pfx: str, draft_arm: str, edit_arm: str, 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: draft_model: str, edit_model: str, pair_key: str, law_fn, expect: float) -> None:
"""Черновик и боевая связка новой пары — общий механизм для всех неканонных осей. """Черновик и боевая связка новой пары — общий механизм для всех неканонных осей.
@ -678,7 +706,8 @@ def buy_bases(phase: str, us: list[dict], pfx: str, draft_arm: str, edit_arm: st
rec = MONEY.purchase(led, tg, draft_model, ED22.client(draft_model), rec = MONEY.purchase(led, tg, draft_model, ED22.client(draft_model),
ROSTER.call_kwargs(draft_model, ROSTER.call_kwargs(draft_model,
PR.translator_msgs(u["source"], None, PR.translator_msgs(u["source"], None,
pair=pair_key)), pair=pair_key),
max_out=_MAX_OUT),
role="translator", uid=u["uid"], arm=draft_arm) role="translator", uid=u["uid"], arm=draft_arm)
if rec.get("skipped"): if rec.get("skipped"):
raise SystemExit(f"⛔ ГАРД ОТКАЗАЛ на {tg} — СТОП и вопрос владельцу") raise SystemExit(f"⛔ ГАРД ОТКАЗАЛ на {tg} — СТОП и вопрос владельцу")
@ -694,7 +723,8 @@ def buy_bases(phase: str, us: list[dict], pfx: str, draft_arm: str, edit_arm: st
ROSTER.call_kwargs(edit_model, ROSTER.call_kwargs(edit_model,
PR.editor_msgs(u["source"], draft, PR.editor_msgs(u["source"], draft,
law_fn(u["source"]), law_fn(u["source"]),
pair=pair_key)), pair=pair_key),
max_out=_MAX_OUT),
role="editor", uid=u["uid"], arm=edit_arm) role="editor", uid=u["uid"], arm=edit_arm)
if rec.get("skipped"): if rec.get("skipped"):
raise SystemExit(f"⛔ ГАРД ОТКАЗАЛ на {tg} — СТОП и вопрос владельцу") raise SystemExit(f"⛔ ГАРД ОТКАЗАЛ на {tg} — СТОП и вопрос владельцу")

View file

@ -61,6 +61,9 @@ N_PER_STRATUM = 8 # 16 единиц — ровно то, ч
DRAFT_MODEL = "deepseek-v4-flash" # тот же жилец-черновик, что на китайской оси DRAFT_MODEL = "deepseek-v4-flash" # тот же жилец-черновик, что на китайской оси
EDITOR = "deepseek-v4-pro" # боевой редактор EDITOR = "deepseek-v4-pro" # боевой редактор
EDITOR2 = "glm-5" # второй редактор, H-4 EDITOR2 = "glm-5" # второй редактор, H-4
# ⚠ Английские единицы длиннее китайских (1600 знаков против 1100), и перевод длиннее — умолчания
# рига 16000 может не хватить так же, как не хватило японской оси (3 пустых клетки из 27).
MAX_OUT = 32000
def units() -> list[dict]: def units() -> list[dict]:
@ -95,7 +98,7 @@ def base_e0(uid: str) -> str:
def wire() -> None: def wire() -> None:
"""Единственная точка включения пары. Всё остальное — механизмы контура.""" """Единственная точка включения пары. Всё остальное — механизмы контура."""
C.configure(PARA.EN, units_provider=units, C.configure(PARA.EN, units_provider=units,
base_draft_hook=base_draft, base_a0_hook=base_e0) base_draft_hook=base_draft, base_a0_hook=base_e0, max_out=MAX_OUT)
def _law(src: str) -> str | None: def _law(src: str) -> str | None:
@ -184,6 +187,17 @@ def cmd_floor() -> None:
C.cmd_floor() C.cmd_floor()
def cmd_refill() -> None:
"""Карантин пустых клеток оси и повторная покупка с поднятым бюджетом вывода."""
wire()
tags = ([f"dv-b-{a}-{u['uid']}" for u in units() for a in ("d0", "e0")]
+ [C.tag(a, u["uid"]) for u in units() for a in ("E1", "E2", "E3", "E4")]
+ [C.tag("E3", u["uid"], "crit") for u in units()]
+ [C.tag("E6", u["uid"]) for u in units()])
n = C.quarantine_length(tags)
print(f"в карантин ушло клеток: {n}")
def cmd_dry() -> None: def cmd_dry() -> None:
"""Смета и наличие. $0. Цены — измеренные медианы фазы, а не догадки.""" """Смета и наличие. $0. Цены — измеренные медианы фазы, а не догадки."""
wire() wire()
@ -247,12 +261,19 @@ def cmd_selftest() -> int:
and not any(str(MONEY.OUT) in str(f) for f in old), f"клеток эксп-21 {len(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 ck("базы берутся из клеток ФАЗЫ", C.BASE_DRAFT_HOOK is base_draft
and C.BASE_A0_HOOK is base_e0) and C.BASE_A0_HOOK is base_e0)
got = [(a, u["uid"]) for u in us for a in ("E1", "E2", "E4")
if (MONEY.OUT / f"{C.tag(a, u['uid'])}.json").exists()]
empty = [f"{a}-{uid}" for a, uid in got if not text_of(C.tag(a, uid)).strip()]
empty += [f"D0-{u['uid']}" for u in us if not text_of(f"dv-b-d0-{u['uid']}").strip()]
empty += [f"E0-{u['uid']}" for u in us if not text_of(f"dv-b-e0-{u['uid']}").strip()]
ck("купленные клетки НЕПУСТЫ (файл ≠ годное содержимое)", not empty,
f"пустых {len(empty)}: {empty[:3]}")
print(f"\n{'ОСЬ ГОТОВА К ПОКУПКЕ' if not bad else f'ПРОВАЛОВ: {bad}'}") print(f"\n{'ОСЬ ГОТОВА К ПОКУПКЕ' if not bad else f'ПРОВАЛОВ: {bad}'}")
return bad return bad
if __name__ == "__main__": if __name__ == "__main__":
a = sys.argv[1] if len(sys.argv) > 1 else "--dry" a = sys.argv[1] if len(sys.argv) > 1 else "--dry"
fn = {"--dry": cmd_dry, "--bases": cmd_bases, "--arms": cmd_arms, "--floor": cmd_floor, "--e6": cmd_e6, fn = {"--dry": cmd_dry, "--bases": cmd_bases, "--arms": cmd_arms, "--floor": cmd_floor, "--refill": cmd_refill, "--e6": cmd_e6,
"--selftest": lambda: sys.exit(1 if cmd_selftest() else 0)}.get(a) "--selftest": lambda: sys.exit(1 if cmd_selftest() else 0)}.get(a)
fn() if fn else print(__doc__) fn() if fn else print(__doc__)

View file

@ -48,6 +48,9 @@ MONEY, PR, PARA = C.MONEY, C.PR, C.PARA
DRAFT_MODEL = "deepseek-v4-flash" DRAFT_MODEL = "deepseek-v4-flash"
EDITOR = "deepseek-v4-pro" EDITOR = "deepseek-v4-pro"
PFX = "dv-c" PFX = "dv-c"
# ⚠ Японский плотнее китайского на знак, а размышление DeepSeek тарифицируется ВНУТРИ бюджета:
# при умолчании рига 16000 три клетки из 27 вернулись пустыми с `finish=length`.
MAX_OUT = 32000
def units() -> list[dict]: def units() -> list[dict]:
@ -79,7 +82,7 @@ def base_j0(uid: str) -> str:
def wire() -> None: def wire() -> None:
C.configure(PARA.JA, units_provider=units, C.configure(PARA.JA, units_provider=units,
base_draft_hook=base_draft, base_a0_hook=base_j0) base_draft_hook=base_draft, base_a0_hook=base_j0, max_out=MAX_OUT)
def _law(src: str) -> str | None: def _law(src: str) -> str | None:
@ -97,6 +100,17 @@ def cmd_arms() -> None:
C.cmd_run(["J2"]) C.cmd_run(["J2"])
def cmd_refill() -> None:
"""Карантин пустых клеток и повторная покупка с поднятым бюджетом вывода."""
wire()
tags = [f"{PFX}-{a}-{u['uid']}" for u in units() for a in ("d0", "j0", "j2")]
n = C.quarantine_length(tags)
print(f"в карантин ушло клеток: {n}")
if n:
cmd_bases()
cmd_arms()
def cmd_floor() -> None: def cmd_floor() -> None:
"""Свой шумовой пол оси — парой независимых генераций одного лечения. """Свой шумовой пол оси — парой независимых генераций одного лечения.
@ -150,12 +164,16 @@ def cmd_selftest() -> int:
bool(PARA.JA.source_script.search(us[0]["source"]))) bool(PARA.JA.source_script.search(us[0]["source"])))
ck("ось объявлена ОПИСАТЕЛЬНОЙ и это не отменяется арифметикой", ck("ось объявлена ОПИСАТЕЛЬНОЙ и это не отменяется арифметикой",
"Д6 ja→ru разведка" in _load("power_ja", ZONE / "power.py").FORCED_DESCRIPTIVE) "Д6 ja→ru разведка" in _load("power_ja", ZONE / "power.py").FORCED_DESCRIPTIVE)
empty = [f"{a}-{u['uid']}" for u in us for a, t in
(("D0", f"{PFX}-d0-{u['uid']}"), ("J0", f"{PFX}-j0-{u['uid']}"),
("J2", C.tag("J2", u["uid"]))) if not text_of(t).strip()]
ck("клетки НЕПУСТЫ (файл ≠ годное содержимое)", not empty, f"пустых {len(empty)}: {empty[:3]}")
print(f"\n{'РАЗВЕДКА ГОТОВА' if not bad else f'ПРОВАЛОВ: {bad}'}") print(f"\n{'РАЗВЕДКА ГОТОВА' if not bad else f'ПРОВАЛОВ: {bad}'}")
return bad return bad
if __name__ == "__main__": if __name__ == "__main__":
a = sys.argv[1] if len(sys.argv) > 1 else "--dry" a = sys.argv[1] if len(sys.argv) > 1 else "--dry"
fn = {"--dry": cmd_dry, "--bases": cmd_bases, "--arms": cmd_arms, "--floor": cmd_floor, fn = {"--dry": cmd_dry, "--bases": cmd_bases, "--arms": cmd_arms, "--floor": cmd_floor, "--refill": cmd_refill,
"--selftest": lambda: sys.exit(1 if cmd_selftest() else 0)}.get(a) "--selftest": lambda: sys.exit(1 if cmd_selftest() else 0)}.get(a)
fn() if fn else print(__doc__) fn() if fn else print(__doc__)