From 55377f9e51a0656d7c9ea5d8c6507d9ba686f859 Mon Sep 17 00:00:00 2001 From: Linghong Date: Tue, 8 Sep 2026 11:11:31 +0000 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20prompt=20bundle=20?= =?UTF-8?q?=E9=9B=86=E6=88=90=E6=B5=8B=E8=AF=95=E5=A4=B9=E5=85=B7=E6=AE=8B?= =?UTF-8?q?=E7=95=99=20V1=20planning=20=E5=BD=A2=E7=8A=B6=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=20CI=20=E5=A4=B1=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 基础夹具 manifest 同步删除 supervisorPlan 组合、planning 目录条目与四个已删 section 登记 roleOverlays 校验测试改为自带合法 overlay 夹具后逐项破坏,与生产 manifest 的空 overlay 形状对齐 --- .../tests/runtime_prompt_bundle_build.rs | 87 ++++++++++--------- 1 file changed, 47 insertions(+), 40 deletions(-) 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]);