From c1dba090499278fc972127240cf9c6a52470ead0 Mon Sep 17 00:00:00 2001 From: Linghong Date: Thu, 20 Aug 2026 13:00:09 +0000 Subject: [PATCH] =?UTF-8?q?=E8=AE=A9=20static-smoke=20=E5=A4=B9=E5=85=B7?= =?UTF-8?q?=E6=BB=A1=E8=B6=B3=E6=94=B6=E7=B4=A7=E5=90=8E=E7=9A=84=E5=85=A5?= =?UTF-8?q?=E5=8F=A3=E5=90=88=E5=90=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 9a7a79951 给 finish_agent_runtime_project_verification_locked 加了一道复核:记录 game.static_smoke 通过时,按当前磁盘内容重跑 validate_game_html_smoke。五个夹具 仍停在收紧前的形状——它们各自只为视觉门、模块可达性或 owner 产物判据构造入口页, 没有目标说明、主循环或输入监听,于是伪造的 smoke 通过一律被拒,用例从未绿过。 生产代码不动:draft_validation.rs 与 master 逐字一致,project_gates.rs 里那段复核 逻辑也和 master 相同。只把夹具补到合同要求的形状: - 数值常量作用域、内联/外部模块图集三处改用仓库已有的 with_static_smoke_contract 包一层,被探测的常量引用与模块结构原样保留; - 终态投影用例的入口页原本只有一个空实现回调,空回调本身触发另一条判据,去掉后 同样包上合同层,写入次数不变、revision 断言不受影响; - owner 产物用例是真实新项目,入口是无画布占位页。它在断言过「占位页过不了真实 smoke」之后才需要一份过期 smoke 凭证,故在 owner 产物之前先落一份合规入口, verified_revision 仍取最后一次 owner 产物; - 自主 manifest 用例只写了 package.json,直接用普通文件写入落一份合规入口,不触碰 revision 记账。 顺带修一处仿造 gate:清 static_smoke_verified_revision 时必须同时清入口摘要, 两者是一对,否则 gate 自身的一致性校验会先于被测行为拒收。 Co-Authored-By: Claude Opus 5 --- .../autonomous_completion_contract_tests.rs | 25 ++++++++++++++++--- .../planning_strategy/autonomous_build.rs | 9 +++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/autonomous_completion_contract_tests.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/autonomous_completion_contract_tests.rs index fd05506d7..bda8a298f 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/autonomous_completion_contract_tests.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/autonomous_completion_contract_tests.rs @@ -7044,7 +7044,9 @@ fn canvas_visual_gate_resolves_numeric_constants_by_symbol_scope() { &queue_autonomous_manifest_child_fixture(&root, &parent_state, "code-prototype"), ); let html = ""; - advance_game_index_revision(&root, &code_state, html); + // 夹具只为数值常量作用域判据构造,缺完整 static-smoke 合同要的目标说明、 + // 主循环与输入监听;补上这层再落盘,被探测的常量引用形状不变。 + advance_game_index_revision(&root, &code_state, &with_static_smoke_contract(html)); mark_verification_passed(&root, &code_state, "game.static_smoke"); assert!(autonomous_game_build_completion_blocker_at_locked(&root, &code_state).is_none()); } @@ -7123,7 +7125,7 @@ fn cli_code_prototype_accepts_linked_inline_and_external_modules_for_canvas_atla advance_game_index_revision( &root, &code_state, - "", + &with_static_smoke_contract(""), ); mark_verification_passed(&root, &code_state, "game.static_smoke"); assert!( @@ -7139,7 +7141,9 @@ fn cli_code_prototype_accepts_linked_inline_and_external_modules_for_canvas_atla advance_game_index_revision( &root, &code_state, - "", + &with_static_smoke_contract( + "", + ), ); mark_verification_passed(&root, &code_state, "game.static_smoke"); assert!( @@ -8105,6 +8109,12 @@ fn autonomous_owner_artifact_runtime_validation_unblocks_real_new_project_withou append_game_creator_agent_runtime_task(&root, &state) .expect("persist running design foundation child"); + // 上面刚断言过占位入口过不了真实 smoke。后面要伪造一次 static-smoke 通过来制造 + // 「过期凭证」,而收口时会按当前磁盘内容复核入口页——占位页必然被拒。先把入口 + // 换成合规页面,再走 owner 产物;verified_revision 仍取最后一次 owner 产物, + // 后续 revision 断言不受影响。 + advance_game_index_revision(&root, &state, cropped_spritesheet_game_html()); + advance_owner_artifact_revision( &root, &state, @@ -8410,7 +8420,11 @@ fn autonomous_gui_cli_code_prototype_terminal_projection_requires_own_static_smo let mutation_revision = advance_game_index_revision( &root, &state, - "", + // 同一份入口后面要被记为 static-smoke 通过,落盘时就得满足完整合同; + // 此处只写一次、revision 不变,前面对 mutation/verified revision 的断言不受影响。 + &with_static_smoke_contract( + "", + ), ); mark_verification_passed(&root, &state, "project.verify"); let project_verified_gate = read_game_creator_agent_runtime_verification_gate( @@ -8495,6 +8509,9 @@ fn autonomous_gui_cli_code_prototype_terminal_projection_requires_own_static_smo legacy_gate.last_verification_status = Some(AGENT_RUNTIME_VERIFICATION_STATUS_PASSED.to_string()); legacy_gate.static_smoke_verified_revision = None; + // 入口摘要与 revision 是一对:仿造 legacy gate 时必须一起清,否则 gate + // 自身的一致性校验会先于被测行为拒收。 + legacy_gate.static_smoke_verified_game_index_sha256 = None; write_game_creator_agent_runtime_verification_gate(&root, &legacy_gate) .expect("persist legacy project.verify-only completed code gate"); let root_blocker = autonomous_game_build_completion_blocker_at_locked(&root, &parent_state) diff --git a/apps/ai-game-creator-shell/src-tauri/src/tests/runtime_actions/planning_strategy/autonomous_build.rs b/apps/ai-game-creator-shell/src-tauri/src/tests/runtime_actions/planning_strategy/autonomous_build.rs index ab4b8b7dc..89082ecec 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/tests/runtime_actions/planning_strategy/autonomous_build.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/tests/runtime_actions/planning_strategy/autonomous_build.rs @@ -1063,6 +1063,15 @@ async fn autonomous_manifest_code_prototype_requires_its_own_static_smoke_after_ .collect::>() ); + // 收口 static-smoke 时会按磁盘内容复核 game/index.html。该夹具只写了 + // package.json,入口仍是初始化留下的无画布占位页,复核必然拒收。落一份满足 + // 完整合同的入口;纯文件写入不触碰 revision 记账,上面对 mutation / verified + // revision 的断言不受影响。 + fs::write( + root.join("game/index.html"), + "

目标:移动角色收集全部目标并获得胜利;碰到危险即失败,按 R 重新开始。

", + ) + .expect("write a smoke-contract compliant game entry before the static smoke credential"); persist_project_verification_for_test( &root, "code-prototype",