Re-freeze phase 1 tail again: retry transient provider 5xx with backoff after four capacity refusals cost the mandatory candidate its screen cells

This commit is contained in:
Claude (backend session) 2026-08-08 18:12:18 +03:00
parent 05e2d57fd7
commit d123526cd5
2 changed files with 23 additions and 3 deletions

View file

@ -18,6 +18,7 @@ from __future__ import annotations
import json
import os
import subprocess
import time
import sys
from functools import lru_cache
from pathlib import Path
@ -134,15 +135,33 @@ def _refuse_unfrozen() -> None:
raise SystemExit("⛔ вызывающий файл не определён")
# Транзиентные отказы провода, которые лечатся ожиданием, а не диагнозом. Поймано исполнением
# 08.08: `gemini-3.1-pro-preview` отдал HTTP 503 «This model is currently experiencing high
# demand» на ЧЕТЫРЁХ вызовах подряд ($0, клетки потеряны), а через минуту тот же слаг ответил с
# первой попытки; страница статуса Google при этом инцидентов не показывала. Без отступа
# обязательный кандидат Ф3 выпал бы из замера по причине, которая замером не является.
_TRANSIENT = ("503", "502", "504", "overloaded", "high demand", "timeout", "Timeout",
"RemoteProtocolError", "APIConnectionError")
def purchase(led: Guarded, tag: str, model: str, client, kw: dict, **extra) -> dict:
"""Один платный вызов. Кэш → фриз-гейт → проекционный гард → покупка."""
"""Один платный вызов. Кэш → фриз-гейт → проекционный гард → покупка (+ отступ на 5xx)."""
f = OUT / f"{tag}.json"
if f.exists():
return json.loads(f.read_text(encoding="utf-8"))
if not any(tag.startswith(p.split("*")[0]) for p in TAGS[led.phase]):
raise SystemExit(f"⛔ тег {tag!r} не покрыт глобом кассы {led.phase} — впиши в TAGS")
_refuse_unfrozen()
return BUY.purchase(led, tag, model, client, kw, **extra)
rec = {}
for k in range(4):
rec = BUY.purchase(led, tag, model, client, kw, **extra)
err = rec.get("error", "") if rec.get("finish") == "error" else ""
if not err or not any(t in err for t in _TRANSIENT):
return rec
wait = 15 * (k + 1)
print(f" транзиентный отказ ({err[:60]}) — отступ {wait} с")
time.sleep(wait)
return rec
def report() -> None:

View file

@ -55,7 +55,8 @@ OUT = MONEY.OUT
ANCHOR = "deepseek-v4-flash" # боевой черновик — якорь панели
EDITOR = "deepseek-v4-pro" # боевой редактор, конфиг `A_law` (full-regen + закон-блок)
MAX_TENANTS = 5 # потолок промта: до 5 жильцов + якорь
MAX_TENANTS = 5 # промт: «до 5 жильцов черновика + `deepseek-v4-flash`
# (якорь)» ⇒ пять СВЕРХ якоря, панель ≤6 клеток
RETRIES = 3