diff --git a/apps/ai-game-creator-shell/src-tauri/tests/runtime_prompt_bundle_build.rs b/apps/ai-game-creator-shell/src-tauri/tests/runtime_prompt_bundle_build.rs index 25024491f..28d5a71bc 100644 --- a/apps/ai-game-creator-shell/src-tauri/tests/runtime_prompt_bundle_build.rs +++ b/apps/ai-game-creator-shell/src-tauri/tests/runtime_prompt_bundle_build.rs @@ -28,10 +28,6 @@ const SECTION_FILES: &[(&str, &str)] = &[ ("supervisorPlaybook", "supervisor/playbook.md"), ("supervisorClaimGate", "supervisor/claim-gate.md"), ("supervisorRepair", "supervisor/repair.md"), - ("planCommon", "plan/common.md"), - ("planSupervisorIdentity", "plan/supervisor-identity.md"), - ("planSupervisorPlaybook", "plan/supervisor-playbook.md"), - ("projectPlanningRoleBrief", "roles/project-planning.md"), ( "providerIsolatedToolContract", "provider/isolated-tool-contract.md", @@ -144,14 +140,6 @@ fn valid_manifest() -> Value { "supervisorClaimGate", "supervisorRepair" ], - "supervisorPlan": [ - "$header", - "planCommon", - "isolatedAgentContract", - "planSupervisorIdentity", - "planSupervisorPlaybook", - "supervisorRepair" - ], "supervisorChat": { "identity": "supervisorIdentityContract", "finalReply": "supervisorFinalReplyContract" @@ -167,12 +155,7 @@ fn valid_manifest() -> Value { "editorUnavailable": "supervisorVisualWithoutEditor" } }, - "roleOverlays": [ - { - "agentId": "project-planning", - "sections": ["projectPlanningRoleBrief"] - } - ], + "roleOverlays": [], "providerFragments": { "isolatedToolContract": "providerIsolatedToolContract", "autonomousRunProfile": "providerAutonomousRunProfile", @@ -199,21 +182,6 @@ fn valid_manifest() -> Value { } ] }, - "planning": { - "id": "planning", - "label": "立项策划", - "role": "Project Planning", - "briefPathName": "project-planning.md", - "roles": [ - { - "id": "project-planning", - "role": "Project Planning", - "taskId": "project-planning", - "toolId": "agent.runtime.project-planning", - "briefPathName": "project-planning.md" - } - ] - }, "groups": [ { "id": "code", @@ -622,34 +590,73 @@ fn rejects_unused_registered_and_unregistered_markdown_sections() { .contains("未登记的 Markdown section")); } +// 基础 fixture 不携带 overlay(与生产 manifest 一致);本测试自带一份合法 overlay, +// 再逐项破坏它。overlay section 必须先落盘成普通文件——编译器先读完全部 section +// 文件才做语义校验。 +fn overlay_fixture() -> Fixture { + let mut fixture = Fixture::new(); + fs::create_dir_all(fixture.root().join("roles")).expect("create roles directory"); + fs::write( + fixture.root().join("roles/code-director-brief.md"), + "SECTION:codeDirectorRoleBrief\n", + ) + .expect("write overlay section"); + fixture.manifest["sections"]["codeDirectorRoleBrief"] = + json!("roles/code-director-brief.md"); + fixture.manifest["roleOverlays"] = json!([{ + "agentId": "code-director", + "sections": ["codeDirectorRoleBrief"] + }]); + fixture.write_manifest(); + fixture +} + +fn compile_overlay_after(mutator: impl FnOnce(&mut Value)) -> Result<(), String> { + let mut fixture = overlay_fixture(); + mutator(&mut fixture.manifest); + fixture.write_manifest(); + fixture.compile().map(|_| ()) +} + +fn assert_overlay_compile_error(mutator: impl FnOnce(&mut Value), expected: &str) { + let error = compile_overlay_after(mutator).expect_err("manifest must fail closed"); + assert!( + error.contains(expected), + "expected error containing {expected:?}, got {error:?}" + ); +} + #[test] fn rejects_invalid_role_overlays() { - assert_compile_error( + overlay_fixture() + .compile() + .expect("valid overlay manifest must compile"); + assert_overlay_compile_error( |manifest| manifest["roleOverlays"][0]["agentId"] = json!("unknown-agent"), "未知 agentId", ); - assert_compile_error( + assert_overlay_compile_error( |manifest| manifest["roleOverlays"][0]["sections"] = json!([]), "sections 不能为空", ); - assert_compile_error( + assert_overlay_compile_error( |manifest| manifest["roleOverlays"][0]["sections"] = json!(["missingSection"]), "未知 section", ); - assert_compile_error( + assert_overlay_compile_error( |manifest| { manifest["roleOverlays"][0]["sections"] = json!(["supervisorClaimGate"]); }, "Prompt section 跨语义所有者复用:supervisorClaimGate", ); - assert_compile_error( + assert_overlay_compile_error( |manifest| { manifest["roleOverlays"][0]["sections"] = - json!(["projectPlanningRoleBrief", "projectPlanningRoleBrief"]); + json!(["codeDirectorRoleBrief", "codeDirectorRoleBrief"]); }, "重复 section", ); - assert_compile_error( + assert_overlay_compile_error( |manifest| { let overlay = manifest["roleOverlays"][0].clone(); manifest["roleOverlays"] = json!([overlay.clone(), overlay]);