From b84c9d4e45e47156ed84c55768ccb717d03cc335 Mon Sep 17 00:00:00 2001 From: Linghong Date: Sat, 5 Sep 2026 12:17:04 +0000 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=AD=96=E5=88=92V2=E4=B8=8D?= =?UTF-8?q?=E5=8F=AF=E5=8F=98=E6=96=87=E4=BB=B6=E5=A4=B1=E8=B4=A5=E6=AE=8B?= =?UTF-8?q?=E7=95=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 失败时清理已创建的空文件或截断文件 保留已有文件的幂等与内容冲突校验 --- .../runtime_protocol/planning_policy_v2.rs | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/planning_policy_v2.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/planning_policy_v2.rs index 90fcf28f1..58edceff3 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/planning_policy_v2.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/planning_policy_v2.rs @@ -839,13 +839,24 @@ fn create_v2_immutable_file(root: &Path, relative: &str, bytes: &[u8]) -> Result .open(&path) { Ok(mut file) => { - harden_new_game_creator_private_path(&path, false, "Planning V2 文件")?; - file.write_all(bytes) - .and_then(|_| file.sync_data()) - .map_err(|error| { - format!("写入 Planning V2 文件失败:{}: {error}", path.display()) - })?; - Ok(()) + // `create_new` has already made the final path visible. Every + // subsequent step must therefore be transactional from the + // caller's perspective: a failed ACL repair, partial write, or + // failed sync must not leave an empty/truncated immutable file + // that would permanently block a retry. + let result = (|| { + harden_new_game_creator_private_path(&path, false, "Planning V2 文件")?; + file.write_all(bytes) + .and_then(|_| file.sync_data()) + .map_err(|error| { + format!("写入 Planning V2 文件失败:{}: {error}", path.display()) + })?; + Ok(()) + })(); + if result.is_err() { + let _ = fs::remove_file(&path); + } + result } Err(error) if error.kind() == std::io::ErrorKind::AlreadyExists => { prepare_game_creator_private_path_for_read(&path, false, "Planning V2 文件")?;