实现资源画布布局持久化 #116
Reference in New Issue
Block a user
Delete Branch "codex/canvas-layout-persistence"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
冻结资源画布布局数据与 CAS 合同
实现双模式本地 sidecar 安全读写
接入二维拖动、默认排版和跨重启恢复
补齐并发冲突、安全边界和界面测试
同步技术文档与共享决策
结论:请求更改。
评审固定在 base
5479559c86e4881d51b80a3e60e4c64dac328d0e、head61f1306fee380d426eb9c5daeff47670f633542a、merge-based29240b954c7f1acf70bd3023443f68a778e65e1。[P1] 先解决与当前目标分支的内容冲突。
git merge-tree与 Gitea 均确认apps/ai-game-creator-shell/src/view/project-development/index.tsx、docs/project-memory/shared-memory/decision-log.md冲突。前者不能简单保留 PR 版本:base 已把 loopback 预览收口到LocalGamePreviewFrame,rebase/merge 时需要同时保留该收口与本 PR 的布局能力。当前状态无法合并,也无法验证合并后的真实行为。[P1] 不要让资源集合变化取消本窗口正在进行的布局写入。
useProjectResourceCanvasLayout.ts:163-170的初始化 effect 同时依赖resources、fallback、resourceSignature和捕获resources的persistLayout;manifest、附件或 Agent 结果更新会在120-123递增 token 并清掉 saving,使旧保存回包在91-92被静默忽略,同时重新读取旧 revision。若新增资源又触发自动协调写入,它可能先赢 CAS 并落盘“旧坐标 + 新资源”,刚完成的用户拖动随后冲突但因 token 过期无人处理。无 Tauri bridge 时同一路径还会直接用 fallback 重置当前会话拖动。请拆开 project/mode 首次读取与资源协调,并串行化本窗口写入;资源数组身份不能取消已发出的保存。[P1] 默认排版在合同允许的 4096 项上会冻结主线程。
resourceCanvasLayoutModel.ts:72-114每探测一个 slot 都线性扫描已有位置,162-175又对每个新资源从头执行;同一 section 从空布局协调 N 项时接近 O(N^3)。在本 head 上,type 模式 4096 项实测约 9.5 秒,而该函数会在 render fallback 和读取回包中同步运行。请使用占用集合/行列索引或空间索引,将上限规模降到可接受复杂度,并加入接近 4096 项的性能回归测试;dependency 同层布局也需要覆盖。[P1] stale 布局锁的回收会破坏“同 revision 双写最多一个成功”的核心合同。
resource_layout.rs:42-53,96-104只按 mtime 判 stale,未检查 token 中 owner PID 是否仍存活;而 stale 检查与remove_file也不是同一原子认领。两个竞争者可同时判定旧锁 stale:一方删除旧锁并创建新锁后,另一方仍可删除这把新锁,最终双方都进入 read-check-write。请加入活 owner 保护,并让 stale reclaim 对被检查的同一锁实例做安全认领,补同步竞争测试。[P2] 无效项目路径不应先产生目录副作用。
resource_layout.rs:278-280在读取.agent/manifest.json/确认 projectId 前先 acquire lock,而58-61会create_dir_all。因此任意不存在或非项目的绝对projectPath虽最终报 manifest 错误,却已经创建<path>/.agent/workbench/resource-layouts/。请先只读确认有效项目,锁内再复核身份,并补 invalid/nonexistent root 零副作用测试。验证记录:当前 head 的 Repository checks、Frontend tests、Backend tests、Native shell tests 均通过;定向资源布局模型测试与 Rust resource_layout 测试通过,
git diff --check通过。现有测试未覆盖上述合并、上限复杂度、资源更新与保存竞争、stale reclaim 竞争和无效 root 副作用。结论:仍需请求更改。
本轮重新固定 base
d4075c3423e0dd8c52deb90c9dc36130602ef1a7、headb2cc21646cf989a0acab529feaeaa18a12ac04a1,当前 merge-base 已等于 base,Gitea 显示可合并且四项 CI 全绿。上轮提出的分支冲突、资源变化取消在途保存、4096 项布局性能、stale 锁回收和无效项目路径副作用均已修复。[P1] 自动资源协调 CAS 冲突时会静默丢弃其后排队的用户拖动。
useProjectResourceCanvasLayout.ts:314-333对任何 conflict 都清空当前 scope 的全部 manual intent;但 active intent 为resources且资源协调仍可自动重试时,331-333不会设置“请重新拖动”提示。可复现场景:资源同步 revision 1 在途,用户把资源 A 拖到x=100,首写 conflict 返回权威x=400/revision=2,自动资源重试随后成功;最终卡片回到x=400,但notice === ''。丢弃冲突前手动意图符合当前合同,静默丢弃不符合;只要本次 conflict 清除了任意 manual intent,就必须提示用户重新拖动,并补“resource sync 在途 + manual 排队 + conflict + retry success”的 Hook 测试。[P2] “按类型”默认布局仍未实现 PRD 冻结的资源子类型排序。PRD §5.2.4 要求按“资源子类型、媒体类型和名称”稳定排序;但
resourceCanvasLayoutModel.ts:25-31的ResourceCanvasItem没有 subtype,178-195只比较mediaType/label/id,而project-development/index.tsx:317-343又没有把manifest.assets[].kind传入布局模型。因此同为image/png的ui-prototype、art-spritesheet等资源会按名称混排。请为各资源来源提供稳定 subtype(资产至少使用asset.kind)并加入“相同 MIME、不同 subtype”测试;如果产品不再要求子类型排序,则应先同步修正 PRD 和实现状态声明。[P2] Rust
u64revision 与 TypeScriptnumber的 IPC 精度边界仍未闭合。shared-contracts接受完整u64,resource_layout.rs:342-359未限制 JS safe integer,而前端用number回传expectedRevision。例如 sidecar revision9007199254740993到 JS 会变成9007199254740992,之后只能持续 conflict;u64::MAX回传时甚至超出 Rustu64反序列化范围。现有checked_add和纯 Rust 的u64::MAX测试没有经过 JSON/Tauri 边界。请改用字符串 revision,或把持久化、读取校验和递增上限统一限制为Number.MAX_SAFE_INTEGER,并补跨 JSON 合同测试。验证记录:本地 AGC typecheck 通过;资源布局模型和 Hook 测试 12/12 通过;AppSurface 322/322 通过;当前 4096 项实测 type 约 23 ms、dependency 约 2 ms;
git diff --check通过。Rust 定向测试在本机最终链接阶段遇到 clang bus error,未产生源码诊断;远端 Backend tests 已成功。复核通过,批准合并。
评审固定在 base
d4075c3423e0dd8c52deb90c9dc36130602ef1a7、head39f7b06297cf306c14af6c46de6b5fba250de52a,merge-base 等于 base,merge-tree 干净。上轮剩余三项均已关闭:
asset.kind,其它来源使用稳定 subtype,并纳入排序与资源签名。Number.MAX_SAFE_INTEGER,达到上限或超限时失败关闭且不覆盖原文件。验证记录:四项 Gitea CI 全绿;本地 AGC typecheck 通过;资源布局合同/模型/Hook 测试 18/18 通过;AppSurface 323/323 通过;shared-contracts revision 测试 2/2 通过;Tauri resource_layout 测试 11/11 通过;
git diff --check通过。未发现新的可操作阻塞项。