#!/usr/bin/env python3 """Ф0.3 — ПРОВЕРКА ИСПОЛНЕНИЕМ четырёх починок, заказанных эксп-21 §8. $0. Промт эксп-22 объявляет их обязательными ДО первой покупки. Список §8 писался как «что надо сделать», и часть пунктов эксп-21 закрыл сам, не вычеркнув из списка. Поэтому здесь не чтение кода, а ЗАПУСК: каждый пункт проверяется на входе с известным ответом, а где возможно — на том самом артефакте, из-за которого пункт появился. §8-1 гейт ре-гена черновика обязан ловить и целевую письменность (был принят и оплачен английский выход с долей латиницы 0.79); §8-2 карта раскладки слепого чтения лежит ВНЕ каталога пакетов; §8-3 обоснование судьи персистируется, и голос с ненулевой осью без цитаты отвергается; §8-4 три докстринга, названные лживыми, больше не противоречат исполняемому коду. Ненулевой код возврата = покупать нельзя. """ from __future__ import annotations import io import json import re import sys from contextlib import redirect_stdout from pathlib import Path REPO = Path("/home/ubuntu/projects/textmachine") ZONE = REPO / "eval" / "role_topology" sys.path.insert(0, str(ZONE)) RAW21 = Path.home() / "books" / "role-topology" BAD = 0 def chk(name: str, ok: bool, detail: str = "") -> None: global BAD # noqa: PLW0603 BAD += not ok print(f"[{'OK ' if ok else 'ПРОВАЛ'}] {name}" + (f" {detail}" if detail else "")) def c1_draft_gate() -> None: """Гейт письменности: пустой · эхо исходника · не целевой язык · годный.""" import bakeoff as BO # noqa: PLC0415 chk("§8-1 пустой выход отвергнут", bool(BO.draft_reject_reason(" "))) chk("§8-1 эхо исходника отвергнуто", BO.draft_reject_reason("第一章 蛊真人转世重生,方源看着眼前的青茅山,心中冷笑" * 8) == "эхо исходника") chk("§8-1 английский выход отвергнут", BO.draft_reject_reason("The young man looked at the mountain and smiled coldly. " * 8) == "выход не на целевом языке") chk("§8-1 русский выход принят", BO.draft_reject_reason("Юноша посмотрел на гору и холодно усмехнулся. " * 8) == "") # Регрессия на ТОМ САМОМ артефакте: он оплачен и принят прежним гейтом. f = RAW21 / "bo2-DRAFT-34749d6ccc-r2.json" if f.exists(): why = BO.draft_reject_reason(json.loads(f.read_text(encoding="utf-8"))["content"]) chk("§8-1 исторический артефакт (латиница) отвергается", why != "", f"вердикт: {why!r}") else: chk("§8-1 исторический артефакт доступен", False, f"нет {f}") def c2_blind_map() -> None: """Карта раскладки не должна лежать в каталоге, который отдают читателю.""" import blind_read as BR # noqa: PLC0415 chk("§8-2 карта вне каталога пакетов", BR.KEYS.resolve() != BR.PACKETS.resolve(), f"пакеты {BR.PACKETS.name} · карта {BR.KEYS.name}") maps = list(BR.KEYS.glob("*-MAP.json")) if BR.KEYS.exists() else [] stray = list(BR.PACKETS.glob("*MAP*")) if BR.PACKETS.exists() else [] chk("§8-2 карт в каталоге пакетов нет", not stray, f"карт в ключах: {len(maps)}") def c3_judge_reasons() -> None: """Ненулевая ось без цитаты обязана быть отвергнута, и отказ обязан снимать прежний голос.""" import absjudge as AJ # noqa: PLC0415 buf = io.StringIO() with redirect_stdout(buf): rc = AJ.selfcheck() out = buf.getvalue() chk("§8-3 selfcheck рига без провалов", rc == 0, f"провалов {rc}") for probe in ("ненулевая ось без цитаты отвергнута", "голое имя оси без цитаты отвергнуто", "отказ СНЯЛ прежний годный голос"): chk(f"§8-3 регрессия «{probe}»", f"[OK ] {probe}" in out) # Персист: у боевых голосов эксп-21 обоснование обязано быть непустым там, где ось ненулевая. votes = list((RAW21 / "aj-abs4-votes").glob("*.json")) if votes: bad = 0 tot = 0 for f in votes: for r in json.loads(f.read_text(encoding="utf-8")).values(): tot += 1 if sum(r.get(a, 0) for a in ("ВЕРНОСТЬ", "ТЕРМИН", "ЯЗЫК", "ФОРМА")) and \ not (r.get("why") or "").strip(): bad += 1 chk("§8-3 боевые голоса несут обоснование", bad == 0, f"{tot - bad}/{tot} клеток с текстом") def c4_docstrings() -> None: """Три докстринга, названные лживыми. Проверяем ПРОТИВОРЕЧИЕ КОДУ, а не наличие слов.""" bo = (ZONE / "bakeoff.py").read_text(encoding="utf-8") ju = (ZONE / "judges.py").read_text(encoding="utf-8") doc_bo = bo.split('"""')[1] if '"""' in bo else "" doc_ju = ju.split('"""')[1] if '"""' in ju else "" # (а) «черновик стоит $0» — код черновик ПОКУПАЕТ (`run_draft`) и кладёт цену в экономику. chk("§8-4 докстринг bakeoff не утверждает «черновик стоит $0»", not re.search(r"черновик\s+стоит\s+\$0", doc_bo)) chk("§8-4 код черновик действительно покупает", "def run_draft" in bo and "bo2-DRAFT-" in bo) # (б) «вердикт при ≥2 повторах из 3» — REPS_PER_ORDER=1, правило вердикта другое. import bakeoff as BO # noqa: PLC0415 claims_2of3 = bool(re.search(r"≥\s*2\s+(?:повтор\w*\s+)?из\s+3", doc_bo)) chk("§8-4 докстринг bakeoff не обещает правило «≥2 из 3»", not claims_2of3, f"REPS_PER_ORDER={BO.REPS_PER_ORDER}") # (в) состав судей в докстринге judges.py обязан совпадать с кортежем JUDGES. import judges as J # noqa: PLC0415 named = [m for m in J.JUDGES if m in doc_ju] chk("§8-4 докстринг judges называет ровно действующий состав", len(named) == len(J.JUDGES) and "grok-4.3` выпал" in doc_ju, f"{', '.join(J.JUDGES)}") def main() -> int: print("Ф0.3 — ПОЧИНКИ ЭКСП-21 §8, ПРОВЕРКА ИСПОЛНЕНИЕМ\n") c1_draft_gate() c2_blind_map() c3_judge_reasons() c4_docstrings() print(f"\n{'ВСЕ ЧЕТЫРЕ ПУНКТА ЗАКРЫТЫ' if not BAD else f'ОТКРЫТО ПУНКТОВ: {BAD} — ПОКУПКИ ЗАПРЕЩЕНЫ'}") return BAD if __name__ == "__main__": sys.exit(1 if main() else 0)