From 9bad7121b55cc1c7bd5ec4772e7771e7b0e52d65 Mon Sep 17 00:00:00 2001 From: Linghong Date: Tue, 18 Aug 2026 08:35:27 +0000 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20Native=20shell=20tests=20?= =?UTF-8?q?=E6=97=A2=E5=AD=98=E7=BA=A2=EF=BC=9A=E5=A7=94=E6=B4=BE=E7=94=A8?= =?UTF-8?q?=E4=BE=8B=E6=94=B9=E8=B0=83=20=5Fat=5Flocked?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CI task 3784 的 Native shell tests 报 2121 passed / 3 failed,三条同因: agent.delegate -> failed, "无法取得一致项目快照" 项目正在被其他写操作占用:$PROJECT_ROOT/.agent/project.lock - autonomous_direct_child_collaboration_mutations_require_the_current_root - autonomous_delegate_descendant_inherits_and_enforces_the_current_root_guard - standard_delegate_collaboration_mutations_remain_compatible 根因是又一次「把动作挪到调用链更前面,改变的不是严格度而是作用范围」。 bc1fe7d8f 写这几个用例时,观察点是「测试先持项目写锁、再调 observe_agent_runtime_agent_delegate」,当时无害:老薄壳压根不碰项目锁,它调的 start_..._with_link_at 只对 planning 身份取锁,其余身份走 ..._with_project_lock_at(..., None)。 152cc40c7(完成 M1C-2b 策划澄清与预算接线)为了让 planning 子 session 的投影按 project -> session 取锁,把锁的所有权上提,拆出 observe_agent_runtime_agent_delegate_at_locked,并让同名薄壳在入口无条件取项目写锁。 而 .agent/project.lock 是 create_new(true) 的文件锁、不可重入:调用方已持锁再进薄壳 就死等满 2000x5ms 预算再失败。确定性红,不是抖动——本机复现逐字一致。 这不是生产漏洞。生产侧调 agent.delegate 的只有 action_execution.rs:436 和 pending_recovery.rs:162,两处都持锁后调 _at_locked;取锁的薄壳如今零生产调用方, 只剩测试在用(main_loop_tests、autonomous_completion_contract_tests 那些都不持锁, 所以一直是绿的)。所以改测试面,生产代码零行改动。 - delegation.rs 四处(2515/2584/2678/2740)改调 _at_locked 并传入已持有的 &project_lock。这不是迁就实现:_at_locked 才是生产唯一的调用形状,改完这三个用例 覆盖的是真实路径。首处留注释说明为何必须绕开同名薄壳——否则下次「顺手统一」回去 会复发,而症状是 10s 静默卡顿,很难往锁不可重入上想 - runtime_tools.rs 补一条 #[cfg(test)] pub(crate) 再导出。生产侧靠 pub(in crate::agent) 的 glob 即可见,测试模块在 crate::agent 之外需单独放行; 沿用旁边 #[cfg(test)] pub(crate) use delivery::{...} 的既有写法,不动生产可见面 验证:tests::collaboration::delegation 改前 22 passed / 3 failed(18.68s),改后 25 passed / 0 failed(5.54s)。少掉的 13 秒正是三条各自空等 10s 锁预算的量——那三次 等待没再发生,不是断言被放宽。cargo fmt --check 干净。 另记一条前提更正:AGC shell crate 是有 CI 的。project-ci.yml 的 native-shell-tests job 跑 npm run check:native-shells,本次覆盖 2124 条。此前「这个 crate 在 CI 里从不 编译也不测试」的判断是错的。 Co-Authored-By: Claude Opus 5 --- .../src-tauri/src/agent/runtime_tools.rs | 2 ++ .../src/tests/collaboration/delegation.rs | 18 ++++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_tools.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_tools.rs index a40e23674..7954fea9d 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_tools.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_tools.rs @@ -34,6 +34,8 @@ pub(in crate::agent) use project_ops::*; pub(in crate::agent) use run_status::*; pub(in crate::agent) use task_ops::*; +#[cfg(test)] +pub(crate) use delegation::observe_agent_runtime_agent_delegate_at_locked; #[cfg(test)] pub(crate) use delivery::{ build_static_delegate_result_for_child_at, wake_waiting_static_delegate_parent_run_for_test_at, diff --git a/apps/ai-game-creator-shell/src-tauri/src/tests/collaboration/delegation.rs b/apps/ai-game-creator-shell/src-tauri/src/tests/collaboration/delegation.rs index 13ce2dca3..7e321f4c9 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/tests/collaboration/delegation.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/tests/collaboration/delegation.rs @@ -2501,12 +2501,18 @@ fn autonomous_direct_child_collaboration_mutations_require_the_current_root() { ); let action_id = "stale-direct-child-delegate"; + // 本文件这四处「先持项目写锁、再调 agent.delegate」的用例走 `_at_locked`,不走同名薄壳。 + // 薄壳在 M1C-2b(`152cc40c7`)里被改成入口自取项目写锁——把锁的所有权上提,是为了让 + // planning 子 session 的投影按 project -> session 的顺序取锁。而 `.agent/project.lock` 是 + // `create_new(true)` 的文件锁、不可重入:调用方已持锁再进薄壳,会死等满 10s 预算然后报 + // 「无法取得一致项目快照」。生产侧两个调用方(`action_execution.rs`、`pending_recovery.rs`) + // 也都是持锁后调 `_at_locked`,薄壳如今已无生产调用方;用 `_at_locked` 钉的才是真实形状。 let project_lock = acquire_game_creator_agent_runtime_project_write_lock_with_wait( &root, "test.stale-direct-child-delegate", ) .expect("acquire delegate project lock"); - let stale_delegate = observe_agent_runtime_agent_delegate( + let stale_delegate = observe_agent_runtime_agent_delegate_at_locked( &root, child_agent_id, &child_run_id, @@ -2516,6 +2522,7 @@ fn autonomous_direct_child_collaboration_mutations_require_the_current_root() { "task": "旧根 child 不得创建委派", "runId": "stale-direct-child-target" }), + &project_lock, ); drop(project_lock); assert_eq!(stale_delegate.status, "failed", "{stale_delegate:?}"); @@ -2574,7 +2581,7 @@ fn autonomous_delegate_descendant_inherits_and_enforces_the_current_root_guard() "test.current-descendant-delegate", ) .expect("acquire current descendant delegate project lock"); - let delegated = observe_agent_runtime_agent_delegate( + let delegated = observe_agent_runtime_agent_delegate_at_locked( &root, ready_agent_id, &ready_run_id, @@ -2584,6 +2591,7 @@ fn autonomous_delegate_descendant_inherits_and_enforces_the_current_root_guard() "task": "在当前自主根下执行只读质量检查", "runId": descendant_run_id }), + &project_lock, ); drop(project_lock); assert_eq!(delegated.status, "ok", "{delegated:?}"); @@ -2667,7 +2675,7 @@ fn autonomous_delegate_descendant_inherits_and_enforces_the_current_root_guard() "test.stale-descendant-delegate", ) .expect("acquire descendant delegate project lock"); - let stale_delegate = observe_agent_runtime_agent_delegate( + let stale_delegate = observe_agent_runtime_agent_delegate_at_locked( &root, descendant_agent_id, descendant_run_id, @@ -2677,6 +2685,7 @@ fn autonomous_delegate_descendant_inherits_and_enforces_the_current_root_guard() "task": "旧根 descendant 不得继续派生", "runId": "stale-descendant-target" }), + &project_lock, ); drop(project_lock); assert_eq!(stale_delegate.status, "failed", "{stale_delegate:?}"); @@ -2728,7 +2737,7 @@ fn standard_delegate_collaboration_mutations_remain_compatible() { "test.standard-delegate", ) .expect("acquire standard delegate project lock"); - let delegated = observe_agent_runtime_agent_delegate( + let delegated = observe_agent_runtime_agent_delegate_at_locked( &root, parent_agent_id, parent_run_id, @@ -2738,6 +2747,7 @@ fn standard_delegate_collaboration_mutations_remain_compatible() { "task": "标准 Run 的兼容委派", "runId": "standard-delegate-child" }), + &project_lock, ); drop(project_lock); assert_eq!(delegated.status, "ok", "{delegated:?}");