From 29da2373072b3ba86e4960824d0fbbf17973de05 Mon Sep 17 00:00:00 2001 From: lili Date: Wed, 8 Jul 2026 02:28:51 -0700 Subject: [PATCH] =?UTF-8?q?test(cheap-gen):=20=E6=AD=BB=E5=9C=88=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E5=A4=96=E7=A7=91=E4=BF=AE=E5=A4=8D=E5=9B=9E=E8=B7=AF?= =?UTF-8?q?=E7=A1=AE=E5=AE=9A=E6=80=A7=E9=9B=86=E6=88=90=E6=B5=8B=E8=AF=95?= =?UTF-8?q?(fix=E2=91=A0-A=20=C3=97=20fix=E2=91=A1-check=20=E6=88=90?= =?UTF-8?q?=E7=8E=AF)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- cheap-worker/tests/test_deadloop_fix_loop.py | 70 ++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 cheap-worker/tests/test_deadloop_fix_loop.py diff --git a/cheap-worker/tests/test_deadloop_fix_loop.py b/cheap-worker/tests/test_deadloop_fix_loop.py new file mode 100644 index 00000000..59b973f6 --- /dev/null +++ b/cheap-worker/tests/test_deadloop_fix_loop.py @@ -0,0 +1,70 @@ +"""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"]))