From 158fae5879fea955a0339de1f6d8a7906882098f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Tue, 6 Oct 2026 19:23:29 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=8F=E7=BA=A2=E4=B9=A6=E6=B3=A8=E5=86=8C?= =?UTF-8?q?=E8=A1=A8=E4=BF=9D=E5=AD=98=E8=A1=A5=E4=B8=8A=E5=B9=B6=E5=8F=91?= =?UTF-8?q?=E7=AA=97=E5=8F=A3=E7=9A=84=E6=8E=A5=E5=8F=97=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - registry::save 在读与写之间加注释:保存由用户手动触发、明知 code agent 在改,接受后写覆盖先写 - 说明不做 CAS 的原因:把 expected_hash 下沉进共享 save 会改所有导出目标的写契约 --- .../src-tauri/src/export/draft/xhs_minitool/registry.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/ai-game-creator-shell/src-tauri/src/export/draft/xhs_minitool/registry.rs b/apps/ai-game-creator-shell/src-tauri/src/export/draft/xhs_minitool/registry.rs index 6453ccd13..9a00a6027 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/export/draft/xhs_minitool/registry.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/export/draft/xhs_minitool/registry.rs @@ -44,6 +44,13 @@ pub(crate) fn save( base_hash: &str, ) -> Result { let path = registry_path(root); + // 读 `load_or_create` 与下面的 `write_registry` 之间没有锁,两步不是原子的:并发写(用户保存 + // 撞上 code agent 改同一个 `.export/xhs-minitool.json`)存在「后写覆盖先写」的窗口。 + // + // 这里明确接受这个窗口,不加 compare-and-swap:保存一律由用户手动触发(点保存 / 停手后的 + // 自动落盘 / 点打包前的 flush),用户本来就知道 code agent 在同一项目里改文件;真撞上时重新 + // 读一次注册表就能看到最新内容,不需要写入门禁级别的并发保证。把 `base_hash` 比较下沉进共享的 + // `crate::export::save`(原子重读 + 比较 + rename)会改掉所有导出目标的写契约,成本高于收益。 let current = load_or_create(&path, &XHSMiniToolExportRegistry::default())?; let form = form.normalized(); if !current.created && current.content_hash != base_hash {