Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 563dac9238 | |||
| fbd493029d |
@@ -860,14 +860,11 @@ pub(crate) fn acquire_project_write_lock_failure(
|
||||
}
|
||||
}
|
||||
}
|
||||
if crate::agent::autonomous_game_build_root_run_active_at(root)
|
||||
&& project_write_lock_is_owned_by_current_process(&path)
|
||||
{
|
||||
// The autonomous game-build lane intentionally permits
|
||||
// parallel specialist actions. If the durable lock belongs
|
||||
// to this very process, contention is an in-process overlap,
|
||||
// not another application editing the project. Return an
|
||||
// advisory guard and leave the real lock untouched.
|
||||
if project_write_lock_is_owned_by_current_process(&path) {
|
||||
// A project lock is the client-use lock. Nested calls in
|
||||
// the same client process must reuse that ownership instead
|
||||
// of waiting on their own durable marker. Cross-process
|
||||
// contenders still take the normal retryable path.
|
||||
return Ok(ProjectWriteLock {
|
||||
path,
|
||||
content: String::new(),
|
||||
|
||||
@@ -5611,12 +5611,14 @@ fn local_project_checkpoint_diff_restore_and_index_are_recorded() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn project_write_lock_rejects_parallel_writer_and_releases_on_drop() {
|
||||
fn project_write_lock_reuses_same_process_owner_and_releases_on_drop() {
|
||||
let root = unique_project_path();
|
||||
let first = acquire_project_write_lock(&root, "file.write").expect("first lock");
|
||||
|
||||
let error = acquire_project_write_lock(&root, "file.delete").expect_err("second lock fails");
|
||||
assert!(error.contains("项目正在被其他写操作占用"));
|
||||
let nested = acquire_project_write_lock(&root, "file.delete")
|
||||
.expect("same process must reuse the client project lock");
|
||||
drop(nested);
|
||||
assert!(root.join(PROJECT_WRITE_LOCK_PATH).exists());
|
||||
|
||||
drop(first);
|
||||
acquire_project_write_lock(&root, "file.delete").expect("lock released");
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# 【实施计划】项目客户端占用锁收敛-2026-09-14
|
||||
|
||||
Version: 1
|
||||
Status: in-progress
|
||||
Date: 2026-09-14
|
||||
Milestone: `【里程碑】项目客户端占用锁收敛-2026-09-14.md`
|
||||
|
||||
## 代码边界
|
||||
|
||||
- `apps/ai-game-creator-shell/src-tauri/src/project/write_lock.rs`
|
||||
- `apps/ai-game-creator-shell/src-tauri/src/runner/project_owner.rs`
|
||||
- `apps/ai-game-creator-shell/src-tauri/src/runner/protocol.rs`
|
||||
- 锁恢复、Runtime 写入和 Runner owner 定向测试
|
||||
|
||||
## 修改顺序
|
||||
|
||||
1. 统一同进程嵌套调用的项目锁语义,禁止自等待。
|
||||
2. 盘点并迁移 Runner 的项目级 owner 文件到统一锁,保留诊断投影与跨 boot 恢复。
|
||||
3. 删除重复项目级锁路径及其专属调用,保留底层原子写和 Git 锁。
|
||||
4. 补齐同进程重入、跨进程占用、崩溃恢复和锁释放测试。
|
||||
|
||||
## 验证命令
|
||||
|
||||
- `cargo fmt --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml -- --check`
|
||||
- `cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml project_write_lock_reuses_same_process_owner_and_releases_on_drop --no-default-features`
|
||||
- Runner owner 与 response stream 相关定向测试
|
||||
- `npm run check:encoding`
|
||||
- `git diff --check`
|
||||
|
||||
## 风险与回滚点
|
||||
|
||||
- Runner 与 GUI 可能是不同进程;统一锁前必须验证同一客户端不会互相阻塞。
|
||||
- 旧 `.agent/runtime/execution-owner.lock` 残留需要按 PID/启动身份安全回收,不能直接删除。
|
||||
- 若跨 boot 恢复或 GUI/Runner 联动回归,回滚统一路径迁移,保留已验证的同进程重入修复。
|
||||
@@ -0,0 +1,28 @@
|
||||
# 【里程碑】项目客户端占用锁收敛-2026-09-14
|
||||
|
||||
Version: 1
|
||||
Status: in-progress
|
||||
Date: 2026-09-14
|
||||
Parent Spec: `docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md`
|
||||
|
||||
## 目标
|
||||
|
||||
项目只保留一个面向客户端占用的项目级跨进程锁,防止多个客户端同时打开同一项目;同一客户端进程内的嵌套调用复用既有项目锁,不因自身持锁进入等待。
|
||||
|
||||
## 边界
|
||||
|
||||
- 项目客户端占用锁与项目写入调用的职责统一,跨进程竞争仍返回占用语义。
|
||||
- Agent DB、session lane、manifest 原子写和 Git 自身的底层一致性机制不在本里程碑删除范围内。
|
||||
- 不改变项目 revision、权限、幂等、恢复和数据格式合同。
|
||||
|
||||
## 验收标准
|
||||
|
||||
- 同一进程内嵌套取得项目锁立即返回 advisory guard,不等待、不删除真实持有者锁。
|
||||
- 不同进程持有项目锁时仍保持占用失败与残留回收判据。
|
||||
- 客户端项目占用入口与 Runtime 写入入口不会各自维护第二个项目级锁文件。
|
||||
- 锁释放后下一客户端可重新取得锁。
|
||||
- 定向 Rust 锁测试、`cargo fmt --check`、`npm run check:encoding`、`git diff --check` 通过。
|
||||
|
||||
## 未决事项
|
||||
|
||||
- Runner 的 `execution-owner.lock` 如何迁移到统一客户端占用锁,需要补充跨进程启动、恢复和诊断测试后再落地。
|
||||
@@ -1363,3 +1363,8 @@ DirectProject 使用 `approvalPolicy=never`,避免每次原生调用再经过
|
||||
- **成功后行为**:重读 manifest,**不切换版本**(没有新版本可切),**不自动重载 / 重启运行中的预览**(PRD §3.2 末条),不做运行时资源重映射。可见变化只有资源卡「当前使用」高亮移到替换素材、`@` 面板「当前版本素材」更新。
|
||||
- **已知代价(用户已确认接受)**:**替换历史不可回溯**——替换前身份只剩那条审计与 manifest 的 `.previous` 副本;需要"某版本历史上换过什么"时要另立切片(PRD §3.2 / §5.3 保留为未来合同正是为此)。
|
||||
- **验证**:绑定改写通道定向 7 条(`project/manifest/version_binding_rewrite_tests.rs`)+ 替换定向 8 条 + `shared-contracts` 20 条。**变异验证**:① 去掉「未放行版本整条相等」→ 两周转红;② 放行集合改成整个版本数组 → 「未放行版本」转红;③ 去掉长度检查 → 「不增不删」转红;④ 准入删掉 category → 硬门禁与候选两条转红;另有 ⑤ 改回"原地改既有版本但绕过放行口"→ 被「项目版本记录写入后不可修改、删除或重排」拦下。前端 13 条(模型 9 + 真链路 4)。AGC 全量 1231 passed / 4 skipped / 0 failed;共享美术画布组件 1385 passed;`npm run ai-game-creator-shell:typecheck`(含 check-config)、`cargo check --locked --all-targets`、`npm run check:encoding`、`git diff --check` 全绿。`/api/external/v1`、SpacetimeDB schema、`packages/shared` 与 `shared-contracts` 的 wire DTO、manifest 结构、布局 sidecar schema 均未改动。
|
||||
|
||||
## 2026-09-14 项目客户端占用锁收敛
|
||||
|
||||
项目锁职责收敛为“客户端占用项目”这一事实:同一客户端进程内的嵌套项目写入调用复用已有项目锁并返回 advisory guard,不再等待自身持有的 `.agent/project.lock`;跨进程竞争继续沿用现有占用、残留回收和权限分类。Runner 的 `.agent/runtime/execution-owner.lock` 迁移到统一项目占用锁仍属于进行中的里程碑,完成前不改变其恢复诊断合同。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user