n=5 收敛环的确定性内核(不含大模型,只证工具能组合成环):scaffold 合规起点 → 注入一处 裸 Math.random(模拟模型自造回退)→ check 经真 node tools.mjs 报「红线 + 确切行号 + edit_file 补救指向」→ edit_file 精修那一行 → check 红线消失、整体回 ok=True。 证的正是死圈出口:过去=产物带违规 + 只有整文件覆盖 write_file + 报错无行号 → agent 整文件 重写、漏 path、连撞熔断;现在=报错点名到行 + 给 edit_file → 一行精修即出圈。「大模型会不会 照做」交真环境 n=5 收敛环。1 测过(scaffold→inject→check→edit→check),exit=0。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
71 lines
3.4 KiB
Python
71 lines
3.4 KiB
Python
"""test_deadloop_fix_loop.py — 死圈修复外科修复回路的【确定性】集成测试(2026-07-08)。
|
|
|
|
这是 n=5 收敛环的确定性内核(不含大模型,只证工具能组合成环):
|
|
scaffold(合规起点) → 注入一处裸 Math.random 违规(模拟模型自造回退) → check 经真 node tools.mjs
|
|
报「红线 + 确切行号 + edit_file 补救指向」 → edit_file 精修那一行 → check 红线消失。
|
|
|
|
它把 fix①-A(增量 edit 工具)与 fix②-check(报错带行号 + edit_file 指向)串起来验:
|
|
过去死圈 = 产物带违规、只有整文件覆盖的 write_file、报错还没行号 → agent 只能整文件重写、漏 path、
|
|
连撞熔断。现在 = 报错点名到行 + 给 edit_file、agent 一行精修即出圈。本测证这条回路在工具层真能闭合;
|
|
「大模型会不会照做」交真环境 n=5 收敛环(见 [[cheap-gen-deadloop-fix]])。
|
|
|
|
用真 games/ 下临时 game_dir(amgen-editloop*)+ 真 node tools.mjs check,teardown 清理,不碰真产物。
|
|
跑:cheap-worker/.venv/bin/python -m pytest cheap-worker/tests/test_deadloop_fix_loop.py -q
|
|
"""
|
|
|
|
import shutil
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parents[1])) # → cheap-worker/
|
|
import cheap_run # noqa: E402
|
|
import pytest # noqa: E402
|
|
|
|
_GID = "editloop001"
|
|
_LOGIC_REL = f"game-runtime/games/amgen-{_GID}/src/game-logic.js"
|
|
_ANCHOR = "export function createGame({ plugins, bundle, viewport }) {"
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _cleanup():
|
|
try:
|
|
yield
|
|
finally:
|
|
shutil.rmtree(cheap_run.game_dir(_GID), ignore_errors=True)
|
|
|
|
|
|
def test_check_edit_check_loop_surgical_fix():
|
|
# 1) scaffold 合规起点(点圆得分模板)
|
|
sc = cheap_run.scaffold(_GID)
|
|
assert sc["ok"], sc
|
|
logic_abs = cheap_run.game_dir(_GID) / "src" / "game-logic.js"
|
|
|
|
# 2) 注入一处裸 Math.random 违规:在 createGame 体首新增一行(新增而非替换——修回后文件仍异于模板、
|
|
# 不撞"与 _template 完全相同"门,回路终点是真过门态而非退回模板)。
|
|
src = logic_abs.read_text(encoding="utf-8")
|
|
assert src.count(_ANCHOR) == 1, "模板 createGame 锚点应唯一"
|
|
injected = src.replace(_ANCHOR, _ANCHOR + "\n const _probe = Math.random(); // 集成测试注入违规", 1)
|
|
w = cheap_run.write_file(_GID, _LOGIC_REL, injected)
|
|
assert w["ok"], w
|
|
|
|
# 3) check 应 FAIL,且报红线 + 确切行号 + edit_file 补救指向(这正是 agent 出圈要读到的)
|
|
c1 = cheap_run.check(_GID)
|
|
assert not c1["ok"], f"注入违规后 check 应 FAIL:{c1['output']}"
|
|
out = c1["output"]
|
|
assert "红线" in out and "Math" in out, f"应报 Math.random 红线:{out}"
|
|
assert "第" in out and "行" in out, f"红线应带确切行号:{out}"
|
|
assert "edit_file" in out, f"红线应给 edit_file 补救指向:{out}"
|
|
|
|
# 4) edit_file 精修那一行:Math.random() → 常量(消红线、作用域安全)
|
|
e = cheap_run.edit_file(_GID, _LOGIC_REL, "const _probe = Math.random();", "const _probe = 0.5;")
|
|
assert e["ok"], e
|
|
|
|
# 5) check 红线消失,回路成环(且整体回到过门态——注入行已修、文件仍异于模板)
|
|
c2 = cheap_run.check(_GID)
|
|
assert "红线" not in c2["output"], f"精修后红线应消失:{c2['output']}"
|
|
assert c2["ok"], f"精修后应整体过门(回到 ok=True):{c2['output']}"
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(pytest.main([__file__, "-q"]))
|