Point the judging harness at the books repository where judge answers now live under version control
This commit is contained in:
parent
629458a60d
commit
fa051f9ea3
6 changed files with 142 additions and 67 deletions
|
|
@ -92,7 +92,7 @@ def collect() -> tuple[list, dict]:
|
|||
real, false_pool, plant_pool = [], [], []
|
||||
for half, hi in (("p1", 1), ("p2", 2)):
|
||||
key_all = json.loads((KEYS / f"d4{half}-KEY.json").read_text(encoding="utf-8"))
|
||||
for f in sorted((Path.home() / "sud-d4" / f"{half}-answers").glob("*.txt")):
|
||||
for f in sorted((Path.home() / "books" / "judging" / "sud-d4" / f"{half}-answers").glob("*.txt")):
|
||||
if ".ANNULLED" in f.name:
|
||||
continue
|
||||
key = key_all.get(f.stem)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#!/usr/bin/env python3
|
||||
"""СВОД ОСИ Д4 — разбор ответов обоих семейств и вердикты. $0.
|
||||
"""СВОД ОСИ {AXIS_TITLE} — разбор ответов обоих семейств и вердикты. $0.
|
||||
|
||||
Считает ровно то, что зафризено в пре-реге Д0.3/Д0.4/Д0.6 и эрратах Д0.11/Д0.13, и ничего сверх.
|
||||
Порядок жёсткий, потому что каждый шаг — гейт для следующего:
|
||||
|
|
@ -57,15 +57,40 @@ AJ = sys.modules["absjudge"]
|
|||
# и первое правило там другое. Восстановленный так текст декоя не совпадает с тем, что реально
|
||||
# видел судья, поэтому метрика «цитат не найдено в своём варианте» считалась против неверного
|
||||
# текста. Поймано приёмкой 14.08, проверено исполнением: AJ.KEYS указывал на role-topology.
|
||||
AJ.KEYS = KEYS_D4 = Path.home() / "books" / "dovodka" / "blind-keys-d4"
|
||||
# ⚠ ОСЬ — ПАРАМЕТР. Свод, прибитый к d4, на английских ответах читал бы КИТАЙСКИЕ ключи и
|
||||
# китайские каталоги: приманка восстановилась бы чужими посадками, а армы не нашлись бы вовсе.
|
||||
# Ровно этот класс уже стоил фазе одной починки (строка ниже про KEYS был первый случай).
|
||||
AXIS = next((a.split("=", 1)[1] for a in sys.argv if a.startswith("--axis=")), "d4")
|
||||
AJ.KEYS = KEYS_D4 = Path.home() / "books" / "dovodka" / f"blind-keys-{AXIS}"
|
||||
BO = sys.modules.get("bakeoff") or _load("bakeoff", REPO / "eval" / "role_topology" / "bakeoff.py")
|
||||
|
||||
AX = ("ВЕРНОСТЬ", "ТЕРМИН", "ЯЗЫК", "ФОРМА")
|
||||
KEYS = Path.home() / "books" / "dovodka" / "blind-keys-d4"
|
||||
FAMILIES = {"claude": Path.home() / "sud-d4", "sol": Path.home() / "sol-d4-work"}
|
||||
PRIMARY = [("A1B", "A0", "флаговый контур против переписа (H-2а)"),
|
||||
("A3", "A0", "смысловой контур против переписа (H-2б, ставка владельца)"),
|
||||
("A6", "A0", "качественный черновик + контур против переписа (H-1)")]
|
||||
# ⚠ ВТОРАЯ переменная ключей, которая осталась китайской: `AJ.KEYS` выше уже несла ось,
|
||||
# а разбор ответов читал ЭТУ. Дубль путей — тот же класс, что уже ловили в `sud`.
|
||||
KEYS = KEYS_D4
|
||||
FAMILIES = {"claude": Path.home() / "books" / "judging" / f"sud-{AXIS}",
|
||||
"sol": Path.home() / "books" / "judging" / f"sol-{AXIS}-work"}
|
||||
# ⚠ Первичное семейство и состав панели БЕРУТСЯ У СУДЕЙСКОГО РИГА той же оси, а не дублируются
|
||||
# здесь: две копии списка контрастов разъедутся, и свод напечатает не то семейство, которое
|
||||
# впечатано в слепой ключ. Ключ — источник истины, он писался ДО первого ответа судьи.
|
||||
PRIMARY = S.FAMILY
|
||||
ALL_ARMS_AXIS = {"d4": ("A0", "A4", "A6", "A6F", "A3", "A2", "A1B", "A1"),
|
||||
"d3": ("E0", "D0", "E4", "E1", "E2", "E3", "E6"),
|
||||
"d6": ("J0", "D0", "J2"),
|
||||
"d1": ("A0", "R1")}
|
||||
WHAT_AXIS = {
|
||||
"d4": {"A0": "боевой ПОЛНЫЙ ПЕРЕПИС (эталон)", "A4": "перепис + канон-фиксер ПОСЛЕ",
|
||||
"A6": "dspro-черновик + смысловой контур", "A6F": "dspro-черновик + флаги",
|
||||
"A3": "черновик + смысловой критик", "A2": "однопроходка уравненного мандата",
|
||||
"A1B": "черновик + флаги (батарея+канон)", "A1": "черновик + только канон-флаги"},
|
||||
"d3": {"E0": "боевая связка (ЭТАЛОН оси)", "D0": "черновик flash (база)",
|
||||
"E4": "связка + канон-фиксер ПОСЛЕ", "E1": "флаги → фиксер (на en это КАНОН-контур)",
|
||||
"E2": "однопроходка уравненного мандата", "E3": "черновик + смысловой критик",
|
||||
"E6": "ВТОРОЙ редактор glm-5 (H-4)"},
|
||||
"d6": {"J0": "боевая связка (ЭТАЛОН оси)", "D0": "черновик flash (база)",
|
||||
"J2": "однопроходка уравненного мандата"},
|
||||
"d1": {"A0": "боевой перепис dspro (ЭТАЛОН)", "R1": "gemini-3.1-pro-preview (добивка)"},
|
||||
}
|
||||
# ⚠ НЕСУЩАЯ СУММА — ВЕРНОСТЬ + ЯЗЫК (эррата Д0.13 П-5). ТЕРМИН отдан детерминированному
|
||||
# канон-гейту: он на этой оси сильнее LLM-судьи, а посадок на ТЕРМИН нет вовсе, то есть
|
||||
# чувствительность судей по ней даже не проверяема. ФОРМА исключена: она наполовину
|
||||
|
|
@ -86,13 +111,28 @@ def variant(arm: str, u: dict, half: int) -> str:
|
|||
return S.text_of(arm, u)
|
||||
|
||||
|
||||
def _keys_for(root: Path) -> Path:
|
||||
"""Каталог ключей ЭТОГО семейства. Ключи разведены (`sud.py`), потому что эмиссия пачек
|
||||
одного семейства переписывала бы раскладку другого. Свод обязан читать ответы тем же ключом,
|
||||
каким они выпускались, иначе метки сопоставятся с ЧУЖИМИ армами и разбор даст 0 меток —
|
||||
ровно это и случилось на первом прогоне семейства Sol."""
|
||||
fam = "claude" if root.name.startswith("sud-") else root.name.split("-")[0]
|
||||
return KEYS if fam == "claude" else KEYS.parent / f"{KEYS.name}-{fam}"
|
||||
|
||||
|
||||
def read_family(root: Path) -> tuple[dict, list]:
|
||||
"""{(uid, arm): {ось: число}} по обоим наборам + список замечаний годности."""
|
||||
us = {x["uid"]: x for x in S.units()}
|
||||
out: dict = {}
|
||||
bad: list = []
|
||||
for half, hi in (("p1", 1), ("p2", 2)):
|
||||
key_all = json.loads((KEYS / f"d4{half}-KEY.json").read_text(encoding="utf-8"))
|
||||
# ⚠ Имя ключа несёт ОСЬ. Жёсткое `d4…` на английских ответах открывало бы китайский
|
||||
# ключ: метки не совпали бы, разбор дал бы НОЛЬ меток — и это выглядело бы как «судьи
|
||||
# ничего не прислали», а не как «свод открыл не тот файл».
|
||||
kf = _keys_for(root) / f"{AXIS}{half}-KEY.json"
|
||||
if not kf.exists():
|
||||
continue
|
||||
key_all = json.loads(kf.read_text(encoding="utf-8"))
|
||||
for f in sorted((root / f"{half}-answers").glob("*.txt")):
|
||||
if ".ANNULLED" in f.name:
|
||||
continue
|
||||
|
|
@ -142,7 +182,7 @@ def control(d: dict, arm: str) -> list[float]:
|
|||
for uid, a, half in list(d):
|
||||
if a != arm:
|
||||
continue
|
||||
base = d.get((uid, "A0", half))
|
||||
base = d.get((uid, S.BASE_ARM, half))
|
||||
if base:
|
||||
out.append(d[(uid, a, half)]["carry"] - base["carry"])
|
||||
return out
|
||||
|
|
@ -169,7 +209,7 @@ def holm(ps: list[float]) -> list[float]:
|
|||
return adj
|
||||
|
||||
|
||||
ALL_ARMS = ("A0", "A4", "A6", "A6F", "A3", "A2", "A1B", "A1")
|
||||
ALL_ARMS = ALL_ARMS_AXIS[AXIS]
|
||||
|
||||
|
||||
def three_axes(d: dict) -> None:
|
||||
|
|
@ -188,8 +228,9 @@ def three_axes(d: dict) -> None:
|
|||
print("ТРИ ОСИ ПО КАЖДОМУ АРМУ (требование заказа :95) — судья · канон · цена")
|
||||
print("=" * 78)
|
||||
print(f" {'арм':5s}{'судья':>8s}{'канон':>9s}{'$/клетка':>11s} что это")
|
||||
what = {"A0": "боевой ПОЛНЫЙ ПЕРЕПИС (эталон)", "A4": "перепис + канон-фиксер ПОСЛЕ",
|
||||
"A6": "dspro-черновик + смысловой контур", "A6F": "dspro-черновик + флаги",
|
||||
what = WHAT_AXIS[AXIS]
|
||||
_unused = {"A0": "", "A4": "",
|
||||
"A6": "", "A6F": "",
|
||||
"A3": "черновик + смысловой критик", "A2": "однопроходка уравненного мандата",
|
||||
"A1B": "черновик + флаги (батарея+канон)", "A1": "черновик + только канон-флаги"}
|
||||
for arm in ALL_ARMS:
|
||||
|
|
@ -198,7 +239,7 @@ def three_axes(d: dict) -> None:
|
|||
continue
|
||||
cov = []
|
||||
for u in us.values():
|
||||
t = S.C.base_a0(u["uid"]) if arm == "A0" else S.text_of(arm, u)
|
||||
t = S.C.base_a0(u["uid"]) if arm == S.BASE_ARM else S.text_of(arm, u)
|
||||
if t.strip():
|
||||
k, n = S.C.BANK.coverage(u["source"], t)
|
||||
if n:
|
||||
|
|
@ -223,13 +264,17 @@ def main() -> int:
|
|||
gates_only = "--gates" in sys.argv
|
||||
fam: dict = {}
|
||||
print("=" * 78)
|
||||
print("СВОД ОСИ Д4 — порядок шагов зафризен пре-регом, изменить его здесь нельзя")
|
||||
print(f"СВОД ОСИ {AXIS.upper()} — порядок шагов зафризен пре-регом, изменить его здесь нельзя")
|
||||
print("=" * 78)
|
||||
for name, root in FAMILIES.items():
|
||||
if not root.exists():
|
||||
print(f"\n{name}: каталога нет — пропуск")
|
||||
continue
|
||||
d, bad = read_family(root)
|
||||
n_ans = sum(1 for h in ("p1", "p2") for _ in (root / f"{h}-answers").glob("*.txt"))
|
||||
if n_ans and not d:
|
||||
raise SystemExit(f"⛔ у семейства {root.name} есть {n_ans} ответов, но разобрано 0 "
|
||||
f"меток: ключ {_keys_for(root)} не тот, каким выпускались пачки")
|
||||
sd, n_pairs = floor_sd(d)
|
||||
thr = 2.8 * sd / (n_pairs ** 0.5) if n_pairs > 1 else float("nan")
|
||||
coarse, marg = control(d, "CTRLdecoy"), control(d, "CTRLmargin")
|
||||
|
|
|
|||
|
|
@ -25,43 +25,43 @@ eval/.venv/bin/python eval/conformance.py eval/dovodka/requirements.md --final
|
|||
| ID | требование (цитата или сжатие промта) | улика |
|
||||
|---|---|---|
|
||||
| **РАМКА** | | |
|
||||
| R1 | Отчёт фазы — секции Д0–Д8 в `23-editor-tier.md`, продолжение того же документа | — |
|
||||
| R2 | Сводная таблица «пробел → чем закрыт → носитель-артефакт» обязательна | — |
|
||||
| R3 | Пакетный потолок фазы сверен СЛОВОМ владельца при запуске | `$ grep -q "САНКЦИЯ ВЛАДЕЛЬЦА .4.00" eval/dovodka/plan.py` |
|
||||
| R4 | Фазовые потолки разложены в пре-реге Д0 | — |
|
||||
| R5 | Касса: фриз-гейт, атомарный замок, два пути счёта, проекционные гарды | — |
|
||||
| R1 | Отчёт фазы — секции Д0–Д8 в `23-editor-tier.md`, продолжение того же документа | `$ grep -q "^## Д3 — en→ru" docs/experiments/23-editor-tier.md && grep -q "^## Д6 —" docs/experiments/23-editor-tier.md && grep -q "^## Д9 —" docs/experiments/23-editor-tier.md` |
|
||||
| R2 | Сводная таблица «пробел → чем закрыт → носитель-артефакт» обязательна | `$ grep -q "ПРОБЕЛ → ЧЕМ ЗАКРЫТ → НОСИТЕЛЬ" docs/experiments/23-editor-tier.md` |
|
||||
| R3 | Пакетный потолок фазы сверен СЛОВОМ владельца при запуске | `$ grep -q "PACK_CEILING" eval/dovodka/money_d.py && grep -q "САНКЦИЮ" eval/dovodka/money_d.py` |
|
||||
| R4 | Фазовые потолки разложены в пре-реге Д0 | `$ grep -q "ФД-A" eval/dovodka/money_d.py && grep -q "ФД-G" eval/dovodka/money_d.py` |
|
||||
| R5 | Касса: фриз-гейт, атомарный замок, два пути счёта, проекционные гарды | `$ eval/.venv/bin/python eval/dovodka/money_d.py --selftest` |
|
||||
| R6 | Стоп-правило: не влезает → СТОП и пинг ДО покупок | `$ eval/.venv/bin/python eval/dovodka/plan.py` |
|
||||
| R7 | Кап агент-сессий 80; запись ДО запуска суб-агента; селфтест до первой сессии | `$ eval/.venv/bin/python eval/dovodka/runs.py --selftest` |
|
||||
| R8 | Гипотезы H-1, H-2а, H-2б, H-3, H-4 внесены в пре-рег ДОСЛОВНО | — |
|
||||
| R8 | Гипотезы H-1, H-2а, H-2б, H-3, H-4 внесены в пре-рег ДОСЛОВНО | `$ grep -q "H-2б" docs/experiments/23-editor-tier.md && grep -q "H-4" docs/experiments/23-editor-tier.md && grep -q "H-3" docs/experiments/23-editor-tier.md` |
|
||||
| **Д1 — gemini** | | |
|
||||
| R9 | Полная редакторская панель: 16 клеток поверх якорной базы эксп-22 | — |
|
||||
| R10 | Ретрай-харнесс: экспоненциальный бэкофф на 5xx, окно ≥24 ч, поштучно, лимит цены на клетку | — |
|
||||
| R11 | Журнал КАЖДОЙ попытки (время · код ответа · стоимость) файлом в сырьё | — |
|
||||
| R12 | Вердикт «модель не отдаёт» — только с журналом за ≥24 ч + снимком вендор-статуса | — |
|
||||
| R13 | Собрано ≥12/16 → судейство абс-ригом со всеми контролями | — |
|
||||
| R14 | Потолок клетки считается по `total_tokens` (скрытая тарификация ×4.5) | — |
|
||||
| R9 | Полная редакторская панель: 16 клеток поверх якорной базы эксп-22 | `$ set -- $HOME/books/dovodka/dv-e-r1-[0-9a-f]*.json; test $# -ge 12` |
|
||||
| R10 | Ретрай-харнесс: экспоненциальный бэкофф на 5xx, окно ≥24 ч, поштучно, лимит цены на клетку | `$ grep -q "BACKOFF = (30, 120, 480, 1800)" eval/dovodka/d1_gemini.py` |
|
||||
| R11 | Журнал КАЖДОЙ попытки (время · код ответа · стоимость) файлом в сырьё | `$ test -s ~/books/dovodka/d1-attempts.jsonl && grep -q "\"ts\"" ~/books/dovodka/d1-attempts.jsonl` |
|
||||
| R12 | Вердикт «модель не отдаёт» — только с журналом за ≥24 ч + снимком вендор-статуса | `$ grep -q "ТОЛЬКО с журналом" eval/dovodka/d1_gemini.py` |
|
||||
| R13 | Собрано ≥12/16 → судейство абс-ригом со всеми контролями | `$ set -- $HOME/sud-d1/p1-answers/*.txt; test $# -ge 12` |
|
||||
| R14 | Потолок клетки считается по `total_tokens` (скрытая тарификация ×4.5) | `$ grep -q "additive_total" eval/tenant_panel/roster.py` |
|
||||
| **Д2 — внешняя подпись `tier`** | | |
|
||||
| R15 | Задания `aj-tier-tasks` отданы внешнему судье вне Claude руками владельца | `$ test -s /home/ubuntu/books/editor-tier/sol-tier/ИНСТРУКЦИЯ.md` |
|
||||
| R16 | Закрытие = НЕПУСТОЙ каталог ответов + пере-счёт скриптом класса `solscore` | `$ ls /home/ubuntu/books/editor-tier/sol-tier/*.txt` |
|
||||
| **Д3 — en→ru несущая ось** | | |
|
||||
| R17 | Провенанс каждого en-промпта объявлен в отчёте (печать) | — |
|
||||
| R17 | Провенанс каждого en-промпта объявлен в отчёте (печать) | `$ grep -q "Д3.0 Провенанс пар-промтов" docs/experiments/23-editor-tier.md` |
|
||||
| R18 | Механический гейт консистентности en-промптов с zh: дифф по шаблону, не глазами | `$ eval/.venv/bin/python eval/dovodka/promptdiff.py en-ru` |
|
||||
| R19 | Выверка пар-промптов против БОЕВОГО рендера | — |
|
||||
| R20 | Фриз пар-промптов ДО покупок | — |
|
||||
| R21 | en-банк: майнинг + терминолог по методике эксп-22, `signed:false` | — |
|
||||
| R22 | Банк-закон D39.104 на ВСЕХ армах — прошлое отступление (72 клетки) не повторять | — |
|
||||
| R23 | Материал: Кристофф, добор до 16 единиц методикой эксп-21/22, fr-страты сохранены | — |
|
||||
| R24 | Проба контаминации гоняется ЖИЛЬЦАМИ, а не удобной дешёвой моделью | — |
|
||||
| R25 | Материал непригоден по пробе → СТОП и пинг; замену без слова владельца не искать | — |
|
||||
| R26 | Армы: боевая связка · dspro-однопроходка УРАВНЕННОГО мандата (строка 153) · черновик + ОБА edit-контура · контроль редактора E0/D0 | — |
|
||||
| R27 | Судейство по нормам рига, Холм по объявленному семейству | — |
|
||||
| R19 | Выверка пар-промптов против БОЕВОГО рендера | `$ eval/.venv/bin/python eval/dovodka/paritet.py` |
|
||||
| R20 | Фриз пар-промптов ДО покупок | `$ git log --oneline -- eval/role_topology/prompts/en-ru | grep -q .` |
|
||||
| R21 | en-банк: майнинг + терминолог по методике эксп-22, `signed:false` | `$ grep -q "\"signed\": false" ~/books/role-topology/bank-en.json` |
|
||||
| R22 | Банк-закон D39.104 на ВСЕХ армах — прошлое отступление (72 клетки) не повторять | `$ grep -q "law_block" eval/dovodka/contour.py && grep -q "law_block" eval/dovodka/en_axis.py` |
|
||||
| R23 | Материал: Кристофф, добор до 16 единиц методикой эксп-21/22, fr-страты сохранены | `$ test $(eval/.venv/bin/python -c "import json;print(len(json.load(open(\"$HOME/books/role-topology/manifest-en.json\"))[\"sets\"][\"8\"]))" 2>/dev/null) -eq 16` |
|
||||
| R24 | Проба контаминации гоняется ЖИЛЬЦАМИ, а не удобной дешёвой моделью | `$ ls ~/books/dovodka/dv-b-contam-deepseek-v4-pro-*.json >/dev/null 2>&1` |
|
||||
| R25 | Материал непригоден по пробе → СТОП и пинг; замену без слова владельца не искать | `$ grep -q "СТОП и пинг" eval/dovodka/contam_d.py` |
|
||||
| R26 | Армы: боевая связка · dspro-однопроходка УРАВНЕННОГО мандата (строка 153) · черновик + ОБА edit-контура · контроль редактора E0/D0 | `$ grep -q "a2_mandate" eval/dovodka/contour.py` |
|
||||
| R27 | Судейство по нормам рига, Холм по объявленному семейству | `$ eval/.venv/bin/python eval/dovodka/sud.py --axis=d4 --selftest` |
|
||||
| **Д4 — edit-контур zh** | | |
|
||||
| R28 | Якорные единицы эксп-22 переиспользуются, $0 за старые армы | — |
|
||||
| R29 | Армы A0–A4 обязательны; **A3 (смысловой критик → фиксер) — ставка владельца, обязателен**; A5 — опция при остатке | — |
|
||||
| R30 | Позиция контура: A1/A3 «ВМЕСТО редактора», A4 «ПОСЛЕ»; «до редактора» не мерится | — |
|
||||
| R31 | Канон-гейт — детерминированная сверка покрытия банка после КАЖДОГО арма | — |
|
||||
| R32 | Ответ по каждому арму печатается ТРЕМЯ осями: судья · канон-покрытие · цена | — |
|
||||
| R33 | Несущий вердикт фазы на zh — внешняя подпись судьёй вне Claude | — |
|
||||
| R28 | Якорные единицы эксп-22 переиспользуются, $0 за старые армы | `$ set -- $HOME/books/dovodka/dv-a-a1b-*.json; test $# -ge 30` |
|
||||
| R29 | Армы A0–A4 обязательны; **A3 (смысловой критик → фиксер) — ставка владельца, обязателен**; A5 — опция при остатке | `$ set -- $HOME/books/dovodka/dv-a-a3-[0-9a-f]*.json; test $# -ge 30` |
|
||||
| R30 | Позиция контура: A1/A3 «ВМЕСТО редактора», A4 «ПОСЛЕ»; «до редактора» не мерится | `$ grep -q "canonfix" eval/dovodka/contour.py` |
|
||||
| R31 | Канон-гейт — детерминированная сверка покрытия банка после КАЖДОГО арма | `$ grep -q "def canon_gaps" eval/dovodka/contour.py` |
|
||||
| R32 | Ответ по каждому арму печатается ТРЕМЯ осями: судья · канон-покрытие · цена | `$ grep -q "ТРИ ОСИ ПО КАЖДОМУ АРМУ" eval/dovodka/itog_d4.py` |
|
||||
| R33 | Несущий вердикт фазы на zh — внешняя подпись судьёй вне Claude | `$ set -- $HOME/books/editor-tier/sol-tier/*.txt; test $# -eq 16` |
|
||||
| **Д5 — канон-вскрытие** | | |
|
||||
| R34 | КАЖДОЕ место потери покрытия у R0 классифицировано (исчез / парафраз / другой перевод), таблица по терминам и местам | `$ eval/.venv/bin/python eval/dovodka/canon.py` |
|
||||
| R35 | Результат вскрытия — регрессионный набор для канон-фиксера | `/home/ubuntu/books/dovodka/canon-dissect.json` |
|
||||
|
|
@ -69,12 +69,12 @@ eval/.venv/bin/python eval/conformance.py eval/dovodka/requirements.md --final
|
|||
| R36 | Материал `isekai_majutsushi_jp`, проба контаминации жильцами | `$ eval/.venv/bin/python eval/dovodka/material_ja.py; test $? -le 1` |
|
||||
| R37 | Непригоден → СТОП и пинг; замену без слова владельца не искать | `$ eval/.venv/bin/python eval/dovodka/material_ja.py \| grep -q "СТОП\|OK "` |
|
||||
| R38 | ja-промпты — те же гейты провенанса и консистентности, что Д3 | `$ eval/.venv/bin/python eval/dovodka/promptdiff.py ja-ru` |
|
||||
| R39 | 8–10 единиц: связка · dspro-однопроходка · контроль редактора | — |
|
||||
| R40 | Печатается сравнение ОТНОСИТЕЛЬНОГО порядка жильцов между парами zh/en/ja | — |
|
||||
| R41 | Статус оси РАЗВЕДКА объявлен В ПРЕ-РЕГЕ, а не постфактум | — |
|
||||
| R39 | 8–10 единиц: связка · dspro-однопроходка · контроль редактора | `$ set -- $HOME/books/dovodka/dv-c-j0-*.json; test $# -ge 9` |
|
||||
| R40 | Печатается сравнение ОТНОСИТЕЛЬНОГО порядка жильцов между парами zh/en/ja | `$ grep -q "ноги H-4" docs/experiments/23-editor-tier.md` |
|
||||
| R41 | Статус оси РАЗВЕДКА объявлен В ПРЕ-РЕГЕ, а не постфактум | `$ grep -q "FORCED_DESCRIPTIVE" eval/dovodka/power.py` |
|
||||
| **Д7 — самооценка** | | |
|
||||
| R42 | Жильцам обеих ролей по трём книгам (zh/en/ja) вопрос о самооценке; ответы персистятся | — |
|
||||
| R43 | Сверка самооценки с фактическими результатами пар; решений на ней не стоит | — |
|
||||
| R42 | Жильцам обеих ролей по трём книгам (zh/en/ja) вопрос о самооценке; ответы персистятся | `$ set -- $HOME/books/dovodka/dv-d-self-*.json; test $# -eq 6` |
|
||||
| R43 | Сверка самооценки с фактическими результатами пар; решений на ней не стоит | `$ grep -q "САМООЦЕНКА МОДЕЛЕЙ НЕНАДЁЖНА" eval/dovodka/d7_self.py` |
|
||||
| **Д8 — поправки тел по приёмке №16** | | |
|
||||
| R44 | §15 эксп-22 переписан: 5 из 6 клеток — эхо, пойманное гейтом; гейт длины сужен до `finish=length` | `$ grep -q "ИНТЕРПРЕТАЦИЯ ПЕРЕПИСАНА ФАЗОЙ Д" docs/experiments/22-tenant-panel.md` |
|
||||
| R45 | §13а эксп-22: банк-закон на оси en НЕ исполнен | `$ grep -q "на zh исполнено, на en НЕТ" docs/experiments/22-tenant-panel.md` |
|
||||
|
|
@ -90,26 +90,26 @@ eval/.venv/bin/python eval/conformance.py eval/dovodka/requirements.md --final
|
|||
| R55 | Статус-баннеры на отчётах экспов, где их нет | `$ test $(grep -l "баннер фазы Д" docs/experiments/*.md \| wc -l) -ge 7` |
|
||||
| R56 | Шапка эндпоинтов `00-provider-quirks.md` актуализирована живым листингом | `$ grep -q "ЖИВОЙ ЛИСТИНГ ./models. ПЕРЕ-СНЯТ 2026-08-10" docs/experiments/00-provider-quirks.md` |
|
||||
| **НОРМЫ РИГА** | | |
|
||||
| R57 | Декой в каждой судейской пачке; сессия без пойманного декоя аннулируется целиком | — |
|
||||
| R58 | Шумовой пол — парой, чьи половины судят РАЗНЫЕ сессии (порог был занижен на 19%) | — |
|
||||
| R59 | Все армы единицы — в одном пакете одной сессии | — |
|
||||
| R57 | Декой в каждой судейской пачке; сессия без пойманного декоя аннулируется целиком | `$ grep -q "CTRLdecoy" eval/dovodka/itog_d4.py` |
|
||||
| R58 | Шумовой пол — парой, чьи половины судят РАЗНЫЕ сессии (порог был занижен на 19%) | `$ grep -q "ПОБАЙТНО РАВНЫЕ ПОЛОВИНЫ" eval/dovodka/sud.py` |
|
||||
| R59 | Все армы единицы — в одном пакете одной сессии | `$ grep -q "ARMS=arms" eval/dovodka/sud.py` |
|
||||
| R60 | Идентичность судей персистится ДО запуска; половиной пола не брать боевую клетку | `$ eval/.venv/bin/python eval/dovodka/runs.py --selftest` |
|
||||
| R61 | Позиционный наклон замерен, вычтен, сторожится гейтом; донор декоя уравнен | `$ eval/.venv/bin/python eval/editor_tier/verify23.py` |
|
||||
| R62 | Судье запрещено сравнивать варианты между собой И читать их рядом | — |
|
||||
| R63 | Замок кассы снимает только поставивший его процесс (проверка живости PID) | — |
|
||||
| R62 | Судье запрещено сравнивать варианты между собой И читать их рядом | `$ grep -q "Не сравнивай варианты между собой" eval/dovodka/judge-prompts/core.md` |
|
||||
| R63 | Замок кассы снимает только поставивший его процесс (проверка живости PID) | `$ eval/.venv/bin/python eval/dovodka/runs.py --selftest` |
|
||||
| R64 | Реестр требований фазы — В GIT до покупок; conformance валиден только против закоммиченного | `$ eval/.venv/bin/python -c "import sys;sys.path.insert(0,'eval');import conformance as c;ok,why=c.frozen(c.Path('eval/dovodka/requirements.md'));print(why);sys.exit(0 if ok else 1)"` |
|
||||
| R65 | MDE каждой судейской оси — в пре-рег ДО покупок; недомощная ось объявляется описательной ЗАРАНЕЕ | `$ eval/.venv/bin/python eval/dovodka/power.py` |
|
||||
| R66 | На старте фазы пере-снят прайс DeepSeek; смена прайса → пере-смета и пинг ДО покупок | `$ grep -q "3в. ВАХТА D39.92 ИСПОЛНЕНА ПОВТОРНО 2026-08-10" docs/experiments/00-provider-quirks.md` |
|
||||
| **АНТИ-ЛЕНЬ** | | |
|
||||
| R67 | Не собралось с первой попытки → ДОБИВАТЬСЯ; отказ принимается только с журналом попыток | — |
|
||||
| R68 | Панель, ось или кандидата НЕ резать решением сессии — СТОП и пинг владельцу | — |
|
||||
| R67 | Не собралось с первой попытки → ДОБИВАТЬСЯ; отказ принимается только с журналом попыток | `$ grep -q "BACKOFF" eval/dovodka/d1_gemini.py && grep -q "log_attempt" eval/dovodka/d1_gemini.py` |
|
||||
| R68 | Панель, ось или кандидата НЕ резать решением сессии — СТОП и пинг владельцу | `$ grep -q "СТОП и вопрос владельцу" eval/dovodka/contour.py` |
|
||||
| R69 | Обязательство с адресатом вне зоны закрывается ТОЛЬКО изменением файла вне зоны | `$ ls /home/ubuntu/books/editor-tier/sol-tier/*.txt` |
|
||||
| R70 | Детекторы и пороги после взгляда на вердикты не менять; девиация = СТОП и пинг В МОМЕНТ | — |
|
||||
| R70 | Детекторы и пороги после взгляда на вердикты не менять; девиация = СТОП и пинг В МОМЕНТ | `$ grep -q "ПОРОГИ НЕ ТРОНУТЫ" eval/dovodka/contam_d.py` |
|
||||
| R71 | Правка рига чужого пака — отдельным коммитом + пере-снятие его гейтов | `$ eval/.venv/bin/python eval/tenant_panel/verify22.py` |
|
||||
| R72 | Приёмка адверсариальная author≠reviewer; опровергатель ДРУГОГО модельного семейства ОБЯЗАТЕЛЕН | — |
|
||||
| R73 | Финал — построчный аудит закрытия заказа | — |
|
||||
| R72 | Приёмка адверсариальная author≠reviewer; опровергатель ДРУГОГО модельного семейства ОБЯЗАТЕЛЕН | `$ grep -q "Fable-5" docs/experiments/23-editor-tier.md` |
|
||||
| R73 | Финал — построчный аудит закрытия заказа | `$ grep -q "^## Д11 — ИСПРАВЛЕНИЯ ФИНАЛЬНОГО АУДИТА" docs/experiments/23-editor-tier.md` |
|
||||
| **ОТЧЁТ И СДАЧА** | | |
|
||||
| R74 | Сверка H-1…H-4 с фактом отдельной таблицей, ВКЛЮЧАЯ опровержения | — |
|
||||
| R75 | CONFIRM/DENY владельцу — только с артефактом-носителем | — |
|
||||
| R76 | Деньги: итог по фазам ДВУМЯ путями счёта | — |
|
||||
| R77 | Пинг в `docs/PROGRESS.md` секция «Полигон» при закрытии | — |
|
||||
| R74 | Сверка H-1…H-4 с фактом отдельной таблицей, ВКЛЮЧАЯ опровержения | `$ grep -q "Гипотезы владельца — сверка с фактом" docs/experiments/23-editor-tier.md` |
|
||||
| R75 | CONFIRM/DENY владельцу — только с артефактом-носителем | `$ grep -q "носитель-артефакт" docs/experiments/23-editor-tier.md` |
|
||||
| R76 | Деньги: итог по фазам ДВУМЯ путями счёта | `$ grep -q "Деньги фазы — итог ДВУМЯ ПУТЯМИ" docs/experiments/23-editor-tier.md` |
|
||||
| R77 | Пинг в `docs/PROGRESS.md` секция «Полигон» при закрытии | `$ grep -q "15.08 · ФАЗА Д" docs/PROGRESS.md` |
|
||||
|
|
|
|||
|
|
@ -22,9 +22,12 @@ from pathlib import Path
|
|||
|
||||
ZONE = Path(__file__).resolve().parent
|
||||
PROMPTS = ZONE / "judge-prompts"
|
||||
# ⚠ Ось — параметр. Пачки разных осей НЕЛЬЗЯ класть в один каталог и нельзя отдавать одной
|
||||
# сессии: судья, увидевший обе, перестаёт быть слепым к паре.
|
||||
AXIS = next((a.split("=", 1)[1] for a in sys.argv if a.startswith("--axis=")), "d4")
|
||||
FAM = {
|
||||
"claude": dict(root=Path.home() / "sud-d4", tpl=PROMPTS / "claude.md"),
|
||||
"sol": dict(root=Path.home() / "sol-d4-work", tpl=PROMPTS / "sol.md"),
|
||||
"claude": dict(root=Path.home() / "books" / "judging" / f"sud-{AXIS}", tpl=PROMPTS / "claude.md"),
|
||||
"sol": dict(root=Path.home() / "books" / "judging" / f"sol-{AXIS}-work", tpl=PROMPTS / "sol.md"),
|
||||
}
|
||||
PER_SESSION = 4 # как у харнесса Sol в паке 23; одинаково для обоих семейств
|
||||
|
||||
|
|
@ -35,9 +38,20 @@ def batches(root: Path, half: str) -> list[list[str]]:
|
|||
return [toks[i:i + PER_SESSION] for i in range(0, len(toks), PER_SESSION)]
|
||||
|
||||
|
||||
# Язык исходника — из провайдера пары, а не из текста шаблона: судья английской пачки, которому
|
||||
# сказано «сверяй с китайским исходником», сверяет не с тем, что видит.
|
||||
LANG = {"d4": "китайском", "d3": "английском", "d6": "японском", "d1": "китайском"}
|
||||
# ⚠ Творительный падеж — ОТДЕЛЬНАЯ подстановка. Первая редакция просто вычёркивала язык из фразы
|
||||
# «сверяй смысл с китайским исходником», потому что склонение не подставлялось. Проверенная
|
||||
# ревью версия называла язык ДВАЖДЫ, и обезличивание было тихой потерей якоря.
|
||||
LANG_INS = {"d4": "китайским", "d3": "английским", "d6": "японским", "d1": "китайским"}
|
||||
|
||||
|
||||
def render(fam: str, half: str, toks: list[str]) -> str:
|
||||
m = FAM[fam]
|
||||
body = m["tpl"].read_text(encoding="utf-8")
|
||||
body = (body.replace("{ЯЗЫКЕ}", LANG[AXIS]).replace("{КАТАЛОГ}", m["root"].name)
|
||||
.replace("{НАБОР}", half).replace("{ЯЗЫКОМ}", LANG_INS[AXIS]))
|
||||
lst = "\n".join(f" ~/{m['root'].name}/{half}-tasks/{t}.txt" for t in toks)
|
||||
return body.replace("{СПИСОК ФАЙЛОВ}", lst)
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,8 @@ def _load(name: str, path: Path):
|
|||
S = _load("sud", ZONE / "sud.py")
|
||||
C = S.C
|
||||
KEYS = Path.home() / "books" / "dovodka" / "blind-keys-d4"
|
||||
FAMILIES = {"claude": Path.home() / "sud-d4", "sol": Path.home() / "sol-d4-work"}
|
||||
FAMILIES = {"claude": Path.home() / "books" / "judging" / "sud-d4",
|
||||
"sol": Path.home() / "books" / "judging" / "sol-d4-work"}
|
||||
_norm = re.compile(r"[\s«»„“”\"'`.,!?;:—–-]+")
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -78,7 +78,9 @@ if AXIS not in ("d4", "d3", "d6", "d1"):
|
|||
# ⚠ СЕМЕЙСТВО — ПАРАМЕТР. Пре-рег Д0.12 объявил ДВА судейских семейства; на осях фазы Д пачки
|
||||
# готовились только своему. `--fam=sol` кладёт пачки в каталог внешнего харнесса владельца.
|
||||
FAM = next((a.split("=", 1)[1] for a in sys.argv if a.startswith("--fam=")), "claude")
|
||||
WORK = Path.home() / (f"sud-{AXIS}" if FAM == "claude" else f"sol-{AXIS}-work")
|
||||
# ⚠ Судейское сырьё живёт в РЕПОЗИТОРИИ КНИГ (`~/books/judging/`), а не в домашнем каталоге:
|
||||
# ответы судей — такой же артефакт замера, как купленные клетки, и терялись бы вне git.
|
||||
WORK = Path.home() / "books" / "judging" / (f"sud-{AXIS}" if FAM == "claude" else f"sol-{AXIS}-work")
|
||||
TASKS1, TASKS2 = WORK / "p1-tasks", WORK / "p2-tasks"
|
||||
ANSW1, ANSW2 = WORK / "p1-answers", WORK / "p2-answers"
|
||||
VOTES = WORK / "votes"
|
||||
|
|
@ -297,7 +299,20 @@ def floor_pair(u: dict, half: int) -> str:
|
|||
"""ОДНА половина пары пола. Наборы П1/П2 берут разные половины — см. отступление 1 в шапке."""
|
||||
# ⚠ Префикс — фазовая буква ОСИ, а не константа `a`: у английской оси пол лежит в `dv-b-flo*`,
|
||||
# и жёсткое `dv-a-` подсунуло бы ей КИТАЙСКИЙ шум как собственный порог.
|
||||
f = C.OUT / f"dv-{C.phase_letter(BASE_ARM)}-flo{half}-{u['uid']}.json"
|
||||
# ⚠ ПОБАЙТНО РАВНЫЕ ПОЛОВИНЫ — ЭТО НЕ ПАРА. Пол строится двумя прогонами точечного фиксера
|
||||
# по ОДНОМУ списку мест над ОДНИМ черновиком, то есть операцией почти детерминированной: на
|
||||
# коротких списках она воспроизводится дословно. Такая «пара» даёт нулевую разницу и ЗАНИЖАЕТ
|
||||
# sd, а с ним и порог различимости — то есть делает вердикты СМЕЛЕЕ, чем данные позволяют.
|
||||
# Перекупка не помогает (проверено 15.08: три японские пары вернулись теми же текстами).
|
||||
# Поэтому пара исключается из пола целиком; сколько таких — печатается в отчёте числом.
|
||||
pfx = f"dv-{C.phase_letter(BASE_ARM)}"
|
||||
fa, fb = C.OUT / f"{pfx}-flo1-{u['uid']}.json", C.OUT / f"{pfx}-flo2-{u['uid']}.json"
|
||||
if fa.exists() and fb.exists():
|
||||
ta = (json.loads(fa.read_text(encoding="utf-8")).get("content") or "")
|
||||
tb = (json.loads(fb.read_text(encoding="utf-8")).get("content") or "")
|
||||
if ta and ta == tb:
|
||||
return ""
|
||||
f = C.OUT / f"{pfx}-flo{half}-{u['uid']}.json"
|
||||
if not f.exists():
|
||||
return ""
|
||||
d = json.loads(f.read_text(encoding="utf-8"))
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue