From ac0b69875f5cb4e87ca2791a339552d822a66d11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Thu, 1 Oct 2026 18:17:30 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=A0=E9=99=A4=E5=B7=B2=E9=80=80=E5=BD=B9?= =?UTF-8?q?=20Supervisor=20=E7=9A=84=E6=8C=81=E4=B9=85=E8=BF=9B=E7=A8=8B?= =?UTF-8?q?=E5=8D=8F=E4=BD=9C=E6=B2=BB=E7=90=86=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - tests/command_runtime.rs:删除 `process_session_supervisor_collaboration_blocks_stdin_but_allows_poll_and_terminate_in_isolated_registry`——Supervisor 已于 2026-09-21 永久退役(项目对话收敛为 DirectProject 与 Design Agent,前端零引用),这条用例不再有现役调用方 - tests/mod.rs:同批删除它唯一的夹具 `process_session_supervisor_collaboration_governance_fixture`(256 行) - 保留 `process_session_agent_runtime_*_isolated_registry` 两条兄弟用例:它们走的是未退役的 `code-prototype` 路径,且仍是通用 process_session 收口的守门人 - 该用例也是分片偶发假红的来源:慢容器上 terminate 收口按设计翻成 needs-reconciliation(finalize_live_process_session 的 2 秒排水窗口),退役面不值得继续钉 - 验证:用例总数 3154 → 3153;两条兄弟用例通过;无新增编译告警;check:encoding、git diff --check 通过 --- .../src-tauri/src/tests/command_runtime.rs | 28 -- .../src-tauri/src/tests/mod.rs | 256 ------------------ 2 files changed, 284 deletions(-) diff --git a/apps/ai-game-creator-shell/src-tauri/src/tests/command_runtime.rs b/apps/ai-game-creator-shell/src-tauri/src/tests/command_runtime.rs index 5a2335bfd..c2299c288 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/tests/command_runtime.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/tests/command_runtime.rs @@ -4109,34 +4109,6 @@ fn process_session_agent_runtime_confirmed_lifecycle_runs_in_isolated_registry() assert!(status.success(), "isolated lifecycle test failed: {status}"); } -#[cfg(unix)] -#[test] -fn process_session_supervisor_collaboration_blocks_stdin_but_allows_poll_and_terminate_in_isolated_registry( -) { - const CHILD_MARKER: &str = - "GENARRATIVE_PROCESS_SESSION_SUPERVISOR_COLLABORATION_GOVERNANCE_CHILD"; - if std::env::var_os(CHILD_MARKER).is_some() { - tauri::async_runtime::block_on( - process_session_supervisor_collaboration_governance_fixture(), - ); - return; - } - let status = std::process::Command::new(std::env::current_exe().expect("current test binary")) - .env(CHILD_MARKER, "1") - .args([ - "--exact", - "tests::command_runtime::process_session_supervisor_collaboration_blocks_stdin_but_allows_poll_and_terminate_in_isolated_registry", - "--nocapture", - "--test-threads=1", - ]) - .status() - .expect("spawn isolated Supervisor process collaboration governance test"); - assert!( - status.success(), - "isolated Supervisor process collaboration governance test failed: {status}" - ); -} - #[cfg(target_os = "linux")] #[test] fn process_session_agent_runtime_start_audit_failure_terminates_target_in_isolated_registry() { diff --git a/apps/ai-game-creator-shell/src-tauri/src/tests/mod.rs b/apps/ai-game-creator-shell/src-tauri/src/tests/mod.rs index 7c0ea34e1..37aa5d9eb 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/tests/mod.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/tests/mod.rs @@ -4796,262 +4796,6 @@ async fn execute_approved_process_action_for_test( (pending, observation) } -#[cfg(unix)] -async fn process_session_supervisor_collaboration_governance_fixture() { - const READY_SENTINEL: &str = "SUPERVISOR_PROCESS_READY_PRIVATE"; - const POLL_SENTINEL: &str = "SUPERVISOR_PROCESS_POLL_PRIVATE"; - const BLOCKED_STDIN_SENTINEL: &str = "SUPERVISOR_PROCESS_BLOCKED_STDIN_PRIVATE"; - const AGENT_ID: &str = GAME_CREATOR_PROJECT_SUPERVISOR_AGENT_ID; - const RUN_ID: &str = "supervisor-process-collaboration-governance-run"; - clear_process_session_registry_for_tests(); - let root = unique_project_path(); - init_local_game_project_at( - &root, - "supervisor-process-collaboration-governance-project", - "Project Supervisor 持久进程治理项目", - ) - .expect("project init"); - let _cleanup = ProcessSessionIntegrationCleanup { - root: root.clone(), - agent_id: AGENT_ID, - run_id: RUN_ID, - }; - fs::write( - root.join("package.json"), - r#"{"private":true,"scripts":{"dev":"node supervisor-process-fixture.mjs"}}"#, - ) - .expect("write Supervisor process package"); - fs::write( - root.join("supervisor-process-fixture.mjs"), - format!( - r#"process.stdin.setEncoding('utf8'); -console.log('{READY_SENTINEL}'); -process.stdin.on('data', (chunk) => console.log(`ECHO:${{chunk.trim()}}`)); -setInterval(() => console.log('{POLL_SENTINEL}'), 50); -"# - ), - ) - .expect("write Supervisor process fixture"); - write_supervisor_collaboration_policy_at(&root, SupervisorCollaborationPolicy::default()) - .expect("write Supervisor collaboration policy"); - write_project_permission_policy_at( - &root, - ProjectPermissionPolicy { - denied_commands: Vec::new(), - confirm_commands: vec![ - "command.start".to_string(), - "command.stdin".to_string(), - "command.terminate".to_string(), - ], - agent_policies: BTreeMap::new(), - }, - ) - .expect("write process tool policy"); - let mut state = start_game_creator_agent_runtime_task_at( - &root, - AGENT_ID, - "在协作 delivery 前启动持久进程并验证后续治理边界", - RUN_ID, - "agent-chat", - "启动并治理持久进程", - vec!["进程可读取且可终止,协作后 stdin 被阻断".to_string()], - ) - .expect("start Supervisor process runtime"); - state.loop_iteration = 1; - - let (_, start_observation) = execute_approved_process_action_for_test( - &root, - &mut state, - AgentRuntimeToolAction { - tool: "command.start".to_string(), - reason: Some("在 delivery 前启动真实持久进程".to_string()), - input: serde_json::json!({ - "program": "npm", - "args": ["run", "dev"], - "cwd": ".", - "timeoutSeconds": 30 - }), - }, - AGENT_RUNTIME_ACTION_EXECUTION_MODE_CONFIRMATION, - ) - .await; - assert_eq!(start_observation.status, "ok", "{start_observation:?}"); - let start_detail: Value = serde_json::from_str( - start_observation - .detail - .as_deref() - .expect("start observation detail"), - ) - .expect("parse start observation detail"); - let process_id = start_detail["processId"] - .as_str() - .expect("start processId") - .to_string(); - let mut cursor = start_detail["nextCursor"] - .as_str() - .expect("start next cursor") - .to_string(); - - let mut ready_output = String::new(); - for index in 0..20 { - let (_, observation) = execute_approved_process_action_for_test( - &root, - &mut state, - AgentRuntimeToolAction { - tool: "command.poll".to_string(), - reason: Some(format!("等待 Supervisor fixture ready {index}")), - input: serde_json::json!({ - "processId": process_id, - "cursor": cursor, - "maxChars": 8_000, - "waitMs": 500 - }), - }, - AGENT_RUNTIME_ACTION_EXECUTION_MODE_AUTO, - ) - .await; - assert_eq!(observation.status, "ok", "{observation:?}"); - let detail: Value = serde_json::from_str( - observation - .detail - .as_deref() - .expect("ready poll observation detail"), - ) - .expect("parse ready poll detail"); - assert_eq!(detail["processId"], process_id); - ready_output.push_str(detail["output"].as_str().unwrap_or_default()); - cursor = detail["nextCursor"] - .as_str() - .expect("ready poll next cursor") - .to_string(); - if ready_output.contains(READY_SENTINEL) { - break; - } - } - assert!(ready_output.contains(READY_SENTINEL), "{ready_output}"); - - let delivery = new_static_delegate_delivery( - AGENT_ID, - &state.session_id, - RUN_ID, - "supervisor-process-collaboration-delegate-action", - "supervisor-process-collaboration-delivery", - "code-prototype", - "supervisor-process-collaboration-child-session", - "supervisor-process-collaboration-child-run", - ); - create_or_read_static_delegate_delivery_at(&root, &delivery) - .expect("create same-run durable static delivery"); - - let blocked_stdin = execute_game_creator_agent_runtime_tool_action( - &root, - AGENT_ID, - RUN_ID, - &state.current_task, - &AgentRuntimeToolAction { - tool: "command.stdin".to_string(), - reason: Some("协作后不得继续写入持久进程".to_string()), - input: serde_json::json!({ - "processId": process_id, - "data": BLOCKED_STDIN_SENTINEL, - "appendNewline": true, - "eof": false - }), - }, - ) - .await; - assert_eq!(blocked_stdin.status, "blocked", "{blocked_stdin:?}"); - assert!(blocked_stdin.summary.contains("协作编排")); - assert!(!serde_json::to_string(&blocked_stdin) - .expect("serialize blocked stdin observation") - .contains(BLOCKED_STDIN_SENTINEL)); - - let mut post_delivery_output = String::new(); - for index in 0..20 { - let (_, observation) = execute_approved_process_action_for_test( - &root, - &mut state, - AgentRuntimeToolAction { - tool: "command.poll".to_string(), - reason: Some(format!("协作后继续读取 Supervisor fixture {index}")), - input: serde_json::json!({ - "processId": process_id, - "cursor": cursor, - "maxChars": 8_000, - "waitMs": 500 - }), - }, - AGENT_RUNTIME_ACTION_EXECUTION_MODE_AUTO, - ) - .await; - assert_eq!(observation.status, "ok", "{observation:?}"); - let detail: Value = serde_json::from_str( - observation - .detail - .as_deref() - .expect("post-delivery poll detail"), - ) - .expect("parse post-delivery poll detail"); - assert_eq!(detail["processId"], process_id); - let output = detail["output"].as_str().unwrap_or_default(); - assert!(!output.contains(BLOCKED_STDIN_SENTINEL), "{output}"); - post_delivery_output.push_str(output); - cursor = detail["nextCursor"] - .as_str() - .expect("post-delivery poll next cursor") - .to_string(); - if post_delivery_output.contains(POLL_SENTINEL) { - break; - } - } - assert!( - post_delivery_output.contains(POLL_SENTINEL), - "{post_delivery_output}" - ); - assert!(!post_delivery_output.contains(BLOCKED_STDIN_SENTINEL)); - let transcript_path = root.join(format!( - ".agent/runtime/process-sessions/{process_id}.output.json" - )); - let transcript = fs::read_to_string(&transcript_path).expect("read process transcript"); - assert!(transcript.contains(READY_SENTINEL)); - assert!(!transcript.contains(BLOCKED_STDIN_SENTINEL)); - - let (_, terminate_observation) = execute_approved_process_action_for_test( - &root, - &mut state, - AgentRuntimeToolAction { - tool: "command.terminate".to_string(), - reason: Some("协作后只治理并终止既有持久进程".to_string()), - input: serde_json::json!({ - "processId": process_id, - "cursor": cursor - }), - }, - AGENT_RUNTIME_ACTION_EXECUTION_MODE_CONFIRMATION, - ) - .await; - assert_eq!( - terminate_observation.status, "ok", - "{terminate_observation:?}" - ); - let terminate_detail: Value = serde_json::from_str( - terminate_observation - .detail - .as_deref() - .expect("terminate observation detail"), - ) - .expect("parse terminate detail"); - assert_eq!(terminate_detail["processId"], process_id); - assert!(matches!( - terminate_detail["status"].as_str(), - Some("terminated" | "exited" | "timed-out" | "output-limit-exceeded") - )); - assert!(!has_active_process_sessions_at(&root).expect("process inactive after terminate")); - let terminal_transcript = - fs::read_to_string(&transcript_path).expect("read terminal process transcript"); - assert!(!terminal_transcript.contains(BLOCKED_STDIN_SENTINEL)); -} - #[cfg(target_os = "linux")] async fn process_session_agent_runtime_start_audit_failure_fixture() { const AGENT_ID: &str = "code-prototype";