Re-freeze phase 1 tail: raise its ceiling to the owner-approved figure and align the markdown gate with the production sanitizer
This commit is contained in:
parent
930a3792c3
commit
05e2d57fd7
4 changed files with 102 additions and 23 deletions
|
|
@ -113,8 +113,8 @@ def floor_of(pass_: str):
|
|||
def hook(u: dict):
|
||||
if pass_ not in ("p2zh", "p3"):
|
||||
return None
|
||||
a = P2.edit_text(P2.ANCHOR, u["uid"])
|
||||
b = P2.edit_text(P2.ANCHOR, u["uid"], floor=True)
|
||||
a = P2.edit_text(P2.ANCHOR, u["uid"], floor=1)
|
||||
b = P2.edit_text(P2.ANCHOR, u["uid"], floor=2)
|
||||
return (a, b) if a.strip() and b.strip() else None
|
||||
return hook
|
||||
|
||||
|
|
@ -164,6 +164,57 @@ def cmd_plan(pass_: str) -> None:
|
|||
print(f"агент-запусков израсходовано {len(runs_used())} из {CAP}")
|
||||
|
||||
|
||||
# Сколько единиц отдаётся ОДНОЙ судейской сессии. Кап промта — «пакет до ~20 текстов»; здесь
|
||||
# считается по фактическому числу меток прохода, а не на глаз.
|
||||
def per_run(pass_: str) -> int:
|
||||
n_arms = len(arm_map(pass_)) + 3 # + декой и пара пола
|
||||
return max(1, 20 // max(1, n_arms))
|
||||
|
||||
|
||||
def cmd_dispatch(pass_: str) -> None:
|
||||
"""Группы заданий на агент-запуски + дословный промт судьи. Ничего не запускает сам."""
|
||||
setup(pass_)
|
||||
tasks = sorted((OUT / f"aj-{pass_}-tasks").glob("*.txt"))
|
||||
if not tasks:
|
||||
print("заданий нет — сначала --emit")
|
||||
return
|
||||
k = per_run(pass_)
|
||||
groups = [tasks[i:i + k] for i in range(0, len(tasks), k)]
|
||||
used = len(runs_used())
|
||||
print(f"проход {pass_}: заданий {len(tasks)} · по {k} на сессию · сессий {len(groups)}")
|
||||
print(f"агент-запусков израсходовано {used}, останется {CAP - used - len(groups)} из {CAP}")
|
||||
if used + len(groups) > CAP:
|
||||
print("⛔ КАП НЕ ВМЕЩАЕТ ПРОХОД — стоп и пинг, не резать молча")
|
||||
return
|
||||
print("\nПРОМТ СУДЬИ (дословно, один на сессию; список файлов подставляется):\n")
|
||||
print(JUDGE_PROMPT.format(files="<файлы сессии>", answers=OUT / f"aj-{pass_}"))
|
||||
print("\nГРУППЫ:")
|
||||
for i, g in enumerate(groups, 1):
|
||||
print(f" сессия {i}: " + " ".join(str(p) for p in g))
|
||||
|
||||
|
||||
JUDGE_PROMPT = """Ты — литературный редактор-эксперт в роли СУДЬИ. Работай сам, не делегируй \
|
||||
задачу другим агентам: раздача пакетов разным исполнителям смешивает их пороги строгости и \
|
||||
делает числа несравнимыми.
|
||||
|
||||
Файлы заданий: {files}
|
||||
|
||||
Для КАЖДОГО файла: прочитай его целиком и выполни ровно то, что в нём написано — оцени каждый \
|
||||
помеченный вариант ОТДЕЛЬНО против исходника, посчитай ошибки по четырём осям и запиши ответ \
|
||||
файлом ровно по тому пути, который назван внутри задания (каталог {answers}).
|
||||
|
||||
Жёсткие правила:
|
||||
* обоснование ПОЧЕМУ обязательно для каждой НЕНУЛЕВОЙ оси и обязано содержать цитату в кавычках; \
|
||||
число без цитаты не принимается разбором и на диск не попадает;
|
||||
* ноль по оси обоснования не требует;
|
||||
* НЕ открывай ничего, кроме файлов заданий: ни ключей раскладки, ни кода, ни соседних каталогов. \
|
||||
Метки Т1..Тn слепые намеренно;
|
||||
* порядок меток ничего не значит и перемешан;
|
||||
* не сравнивай варианты между собой — только каждый против исходника.
|
||||
|
||||
Верни одной строкой: сколько файлов заданий обработано и куда записаны ответы."""
|
||||
|
||||
|
||||
def main() -> None:
|
||||
a = sys.argv[1:]
|
||||
if not a:
|
||||
|
|
|
|||
|
|
@ -48,7 +48,11 @@ TAGS = {
|
|||
"Ф2": ("tp2-draft-*.json", "tp2-edit-*.json", "tp2-floor-*.json"),
|
||||
"Ф3": ("tp3-ed-*.json",),
|
||||
}
|
||||
CEILINGS = {"Ф0": 0.40, "Ф1": 1.00, "Ф2": 2.00, "Ф3": 1.60}
|
||||
# ⚠ ПОТОЛОК Ф1 ПОДНЯТ 08.08 С $1.00 ДО $1.05 СЛОВОМ ВЛАДЕЛЬЦА, объявлено ДО траты. Причина:
|
||||
# проекционный гард остановил скрин перед `gemini-3.1-pro-preview` — ОБЯЗАТЕЛЬНЫМ кандидатом Ф3
|
||||
# по промту. Его цена — единственная неизвестная в смете Ф3 (оценка $0.80 из $1.60), и без замера
|
||||
# половина фазы стояла бы на прайс-странице вместо провода. Пакетный потолок $5.00 не двигался.
|
||||
CEILINGS = {"Ф0": 0.40, "Ф1": 1.05, "Ф2": 2.00, "Ф3": 1.60}
|
||||
PACK_CEILING = 5.00
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -98,16 +98,20 @@ def units_all() -> list[tuple[dict, bool]]:
|
|||
return [(u, False) for u in M.units_zh()] + [(u, True) for u in M.units_en()]
|
||||
|
||||
|
||||
def tag_draft(model: str, uid: str, attempt: int = 1, floor: bool = False) -> str:
|
||||
base = "tp2-floor" if floor else "tp2-draft"
|
||||
# ⚠ ПОЛ КЛАДЁТСЯ ОТДЕЛЬНОЙ ПАРОЙ, а не «боевая клетка + повтор». Иначе одна половина пола
|
||||
# побайтно совпала бы с армом `E0` в том же судейском пакете: судья увидел бы один текст дважды,
|
||||
# а контроль «близнец» сработал бы на боевом арме. Эксп-21 обошёл это тем, что его пол лежал на
|
||||
# ДРУГОМ входе (§build_unit), — здесь то же достигается двумя независимыми прогонами `p1`/`p2`.
|
||||
def tag_draft(model: str, uid: str, attempt: int = 1, floor: int = 0) -> str:
|
||||
base = f"tp2-floor-p{floor}" if floor else "tp2-draft"
|
||||
return f"{base}-D-{model}-{uid}" + ("" if attempt == 1 else f"-r{attempt}")
|
||||
|
||||
|
||||
def tag_edit(model: str, uid: str, floor: bool = False) -> str:
|
||||
return f"{'tp2-floor' if floor else 'tp2-edit'}-E-{model}-{uid}"
|
||||
def tag_edit(model: str, uid: str, floor: int = 0) -> str:
|
||||
return f"{f'tp2-floor-p{floor}' if floor else 'tp2-edit'}-E-{model}-{uid}"
|
||||
|
||||
|
||||
def draft_text(model: str, uid: str, floor: bool = False) -> str:
|
||||
def draft_text(model: str, uid: str, floor: int = 0) -> str:
|
||||
"""ГОДНЫЙ черновик: последняя попытка, прошедшая гейт. Пусто — годного нет."""
|
||||
pre = tag_draft(model, uid, floor=floor)
|
||||
best = ""
|
||||
|
|
@ -118,12 +122,12 @@ def draft_text(model: str, uid: str, floor: bool = False) -> str:
|
|||
return best
|
||||
|
||||
|
||||
def edit_text(model: str, uid: str, floor: bool = False) -> str:
|
||||
def edit_text(model: str, uid: str, floor: int = 0) -> str:
|
||||
f = OUT / f"{tag_edit(model, uid, floor)}.json"
|
||||
return json.loads(f.read_text(encoding="utf-8")).get("content", "") if f.exists() else ""
|
||||
|
||||
|
||||
def buy_draft(led, model: str, u: dict, en: bool, floor: bool = False) -> dict:
|
||||
def buy_draft(led, model: str, u: dict, en: bool, floor: int = 0) -> dict:
|
||||
blk = None if en else PR.glossary_block(PR.terms_in(u["source"]))
|
||||
msgs = PR.translator_msgs(u["source"], blk, en=en)
|
||||
rec = {}
|
||||
|
|
@ -137,7 +141,7 @@ def buy_draft(led, model: str, u: dict, en: bool, floor: bool = False) -> dict:
|
|||
return rec
|
||||
|
||||
|
||||
def buy_edit(led, model: str, u: dict, en: bool, floor: bool = False) -> dict:
|
||||
def buy_edit(led, model: str, u: dict, en: bool, floor: int = 0) -> dict:
|
||||
draft = draft_text(model, u["uid"], floor)
|
||||
if not draft:
|
||||
return dict(skipped=False, content="", no_draft=True)
|
||||
|
|
@ -207,21 +211,30 @@ def cmd_edit() -> None:
|
|||
|
||||
|
||||
def cmd_floor() -> None:
|
||||
"""Вторая генерация ЯКОРНОГО арма end-to-end на тех же zh-единицах."""
|
||||
"""ШУМОВОЙ ПОЛ: ДВА независимых прогона якорного арма end-to-end на тех же zh-единицах.
|
||||
|
||||
Истинная разница между `p1` и `p2` — ноль по построению, поэтому измеренный разброс и есть
|
||||
шум пайплайна (генерация черновика + генерация редактуры + судья). Он применяется к Ф2 И Ф3:
|
||||
перевес ниже пола печатается вердиктом «ниже порога различимости».
|
||||
"""
|
||||
led = MONEY.Guarded("Ф2", default_expect=0.01)
|
||||
for p in (1, 2):
|
||||
for u in M.units_zh():
|
||||
d = buy_draft(led, ANCHOR, u, False, floor=True)
|
||||
d = buy_draft(led, ANCHOR, u, False, floor=p)
|
||||
if d.get("skipped"):
|
||||
print("⛔ потолок Ф2 — стоп")
|
||||
return
|
||||
e = buy_edit(led, ANCHOR, u, False, floor=True)
|
||||
print(f" пол {u['uid'][:6]} черновик {len(d.get('content', '')):5d} зн · "
|
||||
e = buy_edit(led, ANCHOR, u, False, floor=p)
|
||||
if e.get("skipped"):
|
||||
print("⛔ потолок Ф2 — стоп")
|
||||
return
|
||||
print(f" пол p{p} {u['uid'][:6]} черновик {len(d.get('content', '')):5d} зн · "
|
||||
f"редактура {len(e.get('content', '')):5d} зн")
|
||||
time.sleep(0.15)
|
||||
print(f"потрачено Ф2 ${led.spent():.6f}")
|
||||
|
||||
|
||||
def draft_cost(model: str, uid: str, floor: bool = False) -> float:
|
||||
def draft_cost(model: str, uid: str, floor: int = 0) -> float:
|
||||
"""Цена черновика = ВСЕ попытки: ре-ген оплачен, значит он в цене роли."""
|
||||
pre = tag_draft(model, uid, floor=floor)
|
||||
return sum(json.loads(f.read_text(encoding="utf-8")).get("cost_usd", 0.0)
|
||||
|
|
|
|||
|
|
@ -55,7 +55,18 @@ CYR_MIN = 0.5 # Г4: доля
|
|||
ECHO_MAX = 0.15 # Г2: боевой порог disposition.go
|
||||
|
||||
_RE_HAN = re.compile(r"[㐀-鿿]")
|
||||
_RE_MD = re.compile(r"^\s{0,3}#{1,6}\s|\*\*", re.M)
|
||||
# ⚠ ДЕТЕКТОР MARKDOWN ИСПРАВЛЕН ПО ВСКРЫТИЮ КЛЕТОК (правило D39.61: перед сравнительным выводом
|
||||
# открыть единицы). Первая версия (унаследована из скрина эксп-21) ловила ЛЮБОЕ `**` и потому
|
||||
# помечала как «протёкшую разметку» строку `***` — стандартный русский типографский разделитель
|
||||
# сцены, которым модель верно передала смену сцены в исходнике. Из-за этого ПРОВАЛ получали
|
||||
# `glm-5` (ратифицированный резервный редактор) и `gemini-3.1-flash-lite` — то есть дефект
|
||||
# детектора менял состав панели.
|
||||
# Здесь детектор приведён к БОЕВОМУ (`checks/sanitizer.go:320` + D33.2): ATX-заголовок = решётки,
|
||||
# пробел и БУКВА/ЦИФРА (декоративный разделитель решётками боевой гейт тоже не считает), плюс
|
||||
# настоящий жирный спан `**текст**`, который боевой санитайзер не ловит, но в прозе он мусор.
|
||||
# Порог «нарушений более чем в одной клетке» НЕ менялся — менялось только то, что считается
|
||||
# нарушением.
|
||||
_RE_MD = re.compile(r"^\s{0,3}#{1,6}\s+[^\W\d_]|\*\*(?=\S)(?:(?!\*\*).)+\*\*", re.M)
|
||||
_RE_PREAMBLE = re.compile(r"^\s*(вот|ниже|here is|here's)\b[^\n:]{0,80}:", re.I)
|
||||
_RE_REFUSAL = re.compile(
|
||||
r"не могу|не буду|отказ|прости(те)?, но|cannot (assist|help|comply)|i'm sorry", re.I)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue