test(cheap-gen): 死圈修复外科修复回路确定性集成测试(fix①-A × fix②-check 成环)
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>
This commit is contained in:
parent
8f700c4b42
commit
29da237307
70
cheap-worker/tests/test_deadloop_fix_loop.py
Normal file
70
cheap-worker/tests/test_deadloop_fix_loop.py
Normal file
@ -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"]))
|
||||
Loading…
x
Reference in New Issue
Block a user