记录 AGC 快照换号重传修复未落地:根因与迁移约束写入共享记忆,文档回退到现行状态
Project CI / AI game creator shell Rust crates (pull_request) Successful in 1m2s
Project CI / Backend tests (pull_request) Failing after 17s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m41s
Project CI / Frontend tests (pull_request) Successful in 2m18s
Project CI / Repository checks (pull_request) Failing after 13s
Project CI / AI game creator shell web tests (pull_request) Successful in 1m22s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 8m47s
Project CI / Native shell tests (pull_request) Successful in 6m21s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 9m8s

- decision-log 改写 2026-09-24 条目:只固化根因与「数据与 IO 往后端挪」必须保留的三条约束,注明客户端索引分桶实现保留在分支 fix/api-timeout(3be8e40bc)且 PR #505 已关闭
- decision-log 补充分层结论:本次改动只碰本地持久化格式与 native-only 诊断视图字段,未涉及客户端与服务端的路由、DTO、对象键与清单结构,即不涉及协议层
- pitfalls 同条目把处理口径改为暂缓落地,验证口径改为按分支状态描述
- 主规范索引描述回退为整份只保存一个账号基线、换号后冷启动全量对比,并指向 issue #504 与 decision-log
- 快照里程碑文档回退索引口径,验收项 13 标为随架构迁移重新定义
This commit is contained in:
2026-09-24 12:05:10 +08:00
parent 3be8e40bc2
commit 771965ea40
4 changed files with 13 additions and 14 deletions
@@ -1642,7 +1642,7 @@ Direct 回合的所有权属于进程内项目身份锁,不属于当前页面
- 触发入口为项目生命周期登记、已登记项目的周期定时器及窗口关闭事件(`CloseRequested`)。它们共用同一个进程内同步器,同一项目的同步串行执行,周期触发在已有同步进行时直接让位,不排队堆积。
- 应用退出(`RunEvent::Exit`)不重复发起同步;退出路径只负责在有界预算(15 秒)内等待在途同步收尾,让关窗触发的那一次同步有机会写完索引再退出。超过预算不能声明最后状态已经上传。
- 客户端扫描、差异对比、索引持久化与上传编排都在 Tauri Rust 进程(`src-tauri/src/project_snapshot/`);WebView 只读状态,不参与差异计算。
- 本地索引是增量对比的唯一依据:`<AppData>/project-snapshots/<projectId>/index.json`(schema v2)**按账号分桶**保存各账号上次成功同步的相对路径、校验和、字节数和修改时间。远端对象键第一段就是 `userId`,所以基线只对写入它的账号成立——换号不会再让别的账号的基线失效,也不会被别的账号覆盖;只有该账号在本机确实没有基线(首次同步该项目)时才全量上传。v1 的单账号索引在读取时按它记录的 `userId` 迁移进对应桶,格式升级本身不额外触发一次重传。项目根使用现有 manifest 的稳定 `project_id` 作为远端身份,路径不再作为身份。
- 本地索引是增量对比的唯一依据:`<AppData>/project-snapshots/<projectId>/index.json` 保存上次成功同步的相对路径、校验和、字节数和修改时间。项目根使用现有 manifest 的稳定 `project_id` 作为远端身份,路径不再作为身份。索引整份只保存一个账号的基线,换号后按冷启动全量对比(已知问题与迁移约束见 issue #504 与 `docs/project-memory/shared-memory/decision-log.md` 2026-09-24 条目)。
- 可观测性按产品口径收敛到本机日志:同步结果、失败分类、延后与跳过计数只写入 AppData 诊断日志(`project_snapshot.sync.*` 前缀),客户端界面不暴露上传状态、时间线或入口按钮。`read_local_project_snapshot_state` 与 `sync_local_project_snapshot` 两条命令仅作为 native-only 的排障与联调入口登记,不在渲染层调用。
- 远端写入经 `api-server`,客户端只持平台登录态 Access Token。两条登录态路由:`POST /api/agc/project-snapshots/files`(单文件,正文为原始字节,元数据走查询串)与 `POST /api/agc/project-snapshots/manifest`(本次同步后的完整清单)。
- 对象键与清单由服务端决定:文件键为 `agc/project-snapshots/v2/{channel}/{userId}/{projectId}/files/{sizeBytes}-{checksumDigest}/{relPath}`,清单键为 `agc/project-snapshots/v2/{channel}/{userId}/{projectId}/manifest.json`;`channel` 是本部署渠道(`GENARRATIVE_AGC_PROJECT_SNAPSHOT_CHANNEL`,缺省沿用 `GENARRATIVE_CLIENT_DOWNLOAD_CHANNEL`),同一 bucket 因此天然按渠道分区,开发与正式部署互不可见对方项目。键里带字节数与摘要,因此"对象已存在且长度一致"可以作为内容一致的判据;路径按原始大小写保留,不走 `put_object` 的低位规范化。`agc` 前缀(含历史无渠道的 `agc/project-snapshots/v1/`)继续是服务端专用私有前缀,通用对象键解析与客户端直传票据都不覆盖它。后台“项目工程”按渠道查询与下载,渠道名非法时失败关闭,历史 v1 对象不再列出。