Re-freeze the phase 1 harness after the first draft returned the Chinese source: add the echo gate with re-generation, and widen canon regexes

This commit is contained in:
Claude (backend session) 2026-08-08 15:23:27 +03:00
parent df519c7800
commit 9ca51da0a8
2 changed files with 58 additions and 16 deletions

View file

@ -133,18 +133,31 @@ def cmd_ask() -> None:
def _rx(dst: str) -> str:
"""Регекс канонной формы: слова длиннее 5 знаков усечены под словоизменение."""
"""Регекс канонной формы под русское словоизменение.
Правка ПОСЛЕ фриза Ф0 и ПОСЛЕ покупки терминолога (то есть $0 и на результат прогона не
влияет), объявляется как девиация. Первая версия усекала только слова от 6 знаков, и короткие
склоняемые слова канона («род Цинь») не находились в форме «рода Цинь» метрика покрытия
занижалась бы на всех армах одинаково, но занижалась.
"""
parts = []
for w in dst.split():
w = re.escape(w)
parts.append(w[:-2] + r"\w*" if len(w) >= 6 else w)
for raw in dst.split():
w = re.escape(raw)
if len(raw) >= 4:
parts.append(w[:-2] + r"\w*")
elif len(raw) == 3:
parts.append(w[:-1] + r"\w*")
else:
parts.append(w)
return r"\s+".join(parts)
# ⚠ РУЧНЫЕ ПРАВКИ КАНОНА. Пусто = терминолог принят как есть. Каждая строка — решение СЕССИИ,
# не владельца; основания печатаются `--canon` и едут в отчёт.
MANUAL: dict[str, tuple[str, str]] = {}
DROP: set[str] = set()
# Выброшено из банка: это общеязыковая лексика, а не термины книги. Канон на них сделал бы
# метрику покрытия замером словарного совпадения, а не терминологической дисциплины.
DROP = {"瞬间", "声音", "仿佛", "庭院"}
def cmd_canon() -> None:
@ -220,6 +233,13 @@ def selfcheck() -> int:
chk("регекс не ловит чужое слово", not re.search(_rx("апертура"), "аперитив", re.I))
chk("регекс держит многословную форму",
bool(re.search(_rx("море истинной ци"), "Море истинной ци", re.I)))
# Регрессии на реальные формы банка: короткое склоняемое слово и прилагательное.
for canon, form in (("род Цинь", "роду Цинь"), ("род Цинь", "рода Циня"),
("левый канцлер", "левого канцлера"), ("глава рода", "главе рода"),
("Цинь Фэн", "Цинь Фэну"), ("Су Цинсюэ", "Су Цинсюэ"),
("Гу Хэ", "Гу Хэ"), ("Фэн-лао", "Фэн-лао")):
chk(f"«{canon}» находится в форме «{form}»", bool(re.search(_rx(canon), form, re.I)))
chk("канон не ловит другой род", not re.search(_rx("род Цинь"), "рода Су", re.I))
b = PR.bank()
if b:
t = next(iter(b))

View file

@ -34,6 +34,9 @@ sys.path.insert(0, str(ZONE))
from dotenv import load_dotenv # noqa: E402
from openai import OpenAI # noqa: E402
sys.path.insert(0, str(REPO / "eval" / "role_topology"))
import bakeoff as BO # noqa: E402 гейт годности черновика
import material as M # noqa: E402
import money as MONEY # noqa: E402
import prompts as PR # noqa: E402
@ -81,24 +84,43 @@ def client(model: str) -> OpenAI:
def draft_of(uid: str) -> str:
f = OUT / f"tp1-scr-draft-{uid}.json"
return json.loads(f.read_text(encoding="utf-8")).get("content", "") if f.exists() else ""
"""ГОДНЫЙ черновик единицы: последняя попытка, прошедшая гейт. Пусто — годного нет."""
best = ""
for f in sorted(OUT.glob(f"tp1-scr-draft-{uid}*.json")):
c = json.loads(f.read_text(encoding="utf-8")).get("content", "")
if c and not BO.draft_reject_reason(c):
best = c
return best
def cmd_draft() -> None:
"""Черновик под редакторскую роль скрина. Один и тот же для ВСЕХ кандидатов — парный дизайн."""
"""Черновик под редакторскую роль скрина. Один и тот же для ВСЕХ кандидатов — парный дизайн.
РЕ-ГЕН ПРИ ЭХЕ добавлен ПОСЛЕ первой же покупки: единица `474f822806` вернулась ПОЛНЫМ
китайским исходником (`finish=stop`, ханьцзы 1785, кириллица 0.00) эхо-мина на плотном CJK,
описанная в quirks 00. Гейт годности и N ре-генов боевое лечение (ре-ген на flash в 7.6 раза
дешевле эскалации на pro), и цена ре-генов ЛОЖИТСЯ В ЛЕДЖЕР, а не прячется.
Функция гейта берётся из `bakeoff` та самая, что проверена `checks21.py` на историческом
артефакте; переписывать её здесь значило бы завести вторую, расходящуюся.
"""
led = MONEY.Guarded("Ф1", default_expect=0.004)
for u in units():
blk = PR.glossary_block(PR.terms_in(u["source"]))
msgs = PR.translator_msgs(u["source"], blk)
rec = MONEY.purchase(led, f"tp1-scr-draft-{u['uid']}", DRAFT_MODEL,
client(DRAFT_MODEL), call_kwargs(DRAFT_MODEL, msgs),
role="draft-for-screen", uid=u["uid"])
if rec.get("skipped"):
print("⛔ потолок Ф1 — стоп")
return
print(f" черновик {u['uid'][:6]} ({u['kind']}) finish={rec.get('finish')} "
f"{len(rec.get('content', '')):5d} зн ${rec.get('cost_usd', 0):.5f}")
for attempt in (1, 2, 3):
tag = f"tp1-scr-draft-{u['uid']}" + ("" if attempt == 1 else f"-r{attempt}")
rec = MONEY.purchase(led, tag, DRAFT_MODEL, client(DRAFT_MODEL),
call_kwargs(DRAFT_MODEL, msgs),
role="draft-for-screen", uid=u["uid"], attempt=attempt)
if rec.get("skipped"):
print("⛔ потолок Ф1 — стоп")
return
bad = BO.draft_reject_reason(rec.get("content", ""))
print(f" черновик {u['uid'][:6]} ({u['kind']}) попытка {attempt} "
f"finish={rec.get('finish')} {len(rec.get('content', '')):5d} зн "
f"${rec.get('cost_usd', 0):.5f}" + (f"{bad}ре-ген" if bad else ""))
if not bad:
break
print(f"потрачено Ф1 ${led.spent():.6f}")