fix(tier2): run_gates 缺 driver 时默认 business-sim play_spec(修服务态假性不收敛根因)

★ 收敛根因实证(cp-smoke-006/007 真跑 + 007 现成游戏带 driver 重跑):服务态 play_spec=None →
游戏永不被真玩 → F_wiring(calls=0 expected=[])挂 + 富游戏三门拿不到观测=None(不是 False=没法评估)→
agent 看到 verdict=fix 却在"修一个不存在的问题"→ 反复 thrash 到 budget_exhausted。**游戏本身是好的**
(007 boot/render/live 全绿、暴露 resource.addCoins/consumeIngredient call-ID、latch 终态、bindInput 路由)。

铁证:用默认 business-sim play_spec 对 007 现成游戏重跑门 → decision=accept / L1.passed=True /
九门全绿 / 富游戏三门(tripleLink/economy/latch)全绿。即 M3 单写 + 设计阶段【已经】产出过门富游戏,
"不收敛"纯是控制面没传 driver 的假象。

修:run_gates 在 play_spec 缺 driver 时 setdefault DEFAULT_BUSINESS_SIM_PLAY_SPEC(driver 按参数驱动、
不靠逐像素坐标,对任何契约合规 business-sim 游戏通用;bakery feie-005 / coffee 007 同款过门),显式
play_spec 仍优先。一处修复同时惠及 agent 自己的 run_gates 工具(thrash 根)与控制面评门。richGame 仍据数据表自派生。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
zizi 2026-06-24 12:43:27 +00:00
parent 99a6afe08c
commit 21472811be

View File

@ -763,6 +763,29 @@ def derive_l3_egregious(verdict: dict | None) -> dict:
return {"egregious": egregious, "reasons": reasons, "notes": notes, "suggestFatal": egregious}
# ── 默认 business-sim 真玩规格(2026-06-24 收敛根因实证后补)─────────────────────────────
# 实证(cp-smoke-006/007 真跑 + 007 现成游戏带本 spec 重跑):tier2 富游戏(经营模拟)契约是【通用】的——
# 游戏暴露 resource.addCoins / resource.consumeIngredient call-ID、latch 终态 phase、bindInput 路由注入输入;
# harness 的 driver.type="business-sim" 按【参数】(steps/winThreshold/bankruptSteps/streakLose)驱动,不靠逐像素
# 坐标。所以同一份 driver 对【任何契约合规的 business-sim 游戏】都通用(bakery feie-005 / coffee 007 同款过门)。
# 此前服务态 play_spec=None → 无 driver → 游戏永不被真玩 → F_wiring(calls=0)挂 + 富游戏门拿不到观测=None →
# agent 看到 verdict=fix 却"修不动一个不存在的问题"→ 反复 thrash 到 budget_exhausted(006/007 假性不收敛根因)。
# 补默认:run_gates 在 play_spec 缺 driver 时 setdefault 本规格(显式 play_spec 仍优先),让 agent 自己的
# run_gates 工具 + 控制面评门都拿到 driver/期望调用/断言 → 真玩 → 门真评。richGame(合成链)仍由下方据数据表自派生。
DEFAULT_BUSINESS_SIM_PLAY_SPEC = {
"driver": {"type": "business-sim", "steps": 80, "stepMs": 280,
"winThreshold": 100, "bankruptSteps": 60, "streakLose": 3},
"expectLatch": True,
"latchTerminals": ["win", "lose", "gameover"],
"economy": {"winThreshold": 100, "bankruptPath": True},
"expectedEngineCallPrefixes": ["resource.addCoins", "resource.consumeIngredient"],
"assertAfterPlay": [
{"path": "coins", "op": "increased", "why": "完单后金币上升(正循环真有进展)"},
{"path": "phase", "op": "in", "value": ["play", "win"], "why": "真玩中或赢,非卡死"},
],
}
def run_gates(game_id: str, play_spec: dict | None = None, *,
port: int = 4330, cdp_port: int = 9322, timeout_s: int = 300) -> dict:
"""真浏览器真玩 L1 九门 + 富游戏三门,返回 tier2-verdict 形状(judge 纯代码,零 LLM)。
@ -786,6 +809,11 @@ def run_gates(game_id: str, play_spec: dict | None = None, *,
ev_dir = wd / "evidence"
ev_dir.mkdir(parents=True, exist_ok=True)
spec = dict(play_spec or {})
# 缺 driver(服务态 play_spec=None / agent 工具没带)→ setdefault 默认 business-sim 规格(driver/期望调用/断言/
# 经济/latch),显式 play_spec 的同名键仍优先。这是 006/007 假性不收敛的修复:没 driver 游戏永不被真玩。
if not spec.get("driver"):
for _k, _v in DEFAULT_BUSINESS_SIM_PLAY_SPEC.items():
spec.setdefault(_k, _v)
# 结构层(源工程校验+构建)由上游 build 段产出:bundle 非空即结构 OK(harness 本身只判可运行层,经 spec 透传)。
bundle = wd / "bundle.iife.js"
spec.setdefault("structureOk", bundle.exists() and bundle.stat().st_size > 0)