修复无限画布恢复与幂等链路
Project CI / Repository checks (pull_request) Successful in 1m0s
Project CI / Frontend tests (pull_request) Successful in 2m57s
Project CI / Backend tests (pull_request) Successful in 3m48s
Project CI / Native shell tests (pull_request) Failing after 11m11s

补齐 refine 草稿跨重启唯一恢复与生命周期门禁

完善 Provider durable handoff、认证恢复和旧密钥服务确认

修复资源事务前向恢复与异步导入迟到写入

补充前后端回归测试并同步权威文档与项目记忆
This commit is contained in:
2026-08-12 10:21:18 +08:00
parent 912df59c2b
commit daaef0917f
13 changed files with 2115 additions and 230 deletions
@@ -4548,6 +4548,7 @@
- 原因:把 Pointer 事件接线、宿主生命周期胶水和可复用 history 算法放在同一组件中,误以为没有复制整个画布目录就已经满足共享源码边界。
- 处理:两宿主直接消费共享 `useCanvasHistory`;共享 snapshot 统一覆盖 viewport、selection、图层位置和 width/height,宿主只声明本地媒体是否允许安全移除/重做。Tauri 仍可保留 Pointer capture/epoch/host callback 接线,但选择、平移、缩放、变换、renderer 和 history 状态机不得在宿主重写。
- 验证:主站 history 定向测试覆盖 resize undo/redo;Tauri 新建、导入、编辑、撤销重做和 durable commit 用例必须在同一共享 hook 下通过。
## 编辑器生成不能把传输重试、参考图截断和客户端 provenance 当成独立小问题(2026-08-05)
- 现象:生成 POST 首次已经入队但响应丢失时,客户端自动重试产生第二个任务;第 6 张或更多参考图仍显示在 UI / 元数据里,却没有送给 provider;直接构造请求还能把任意资源 ID 写成最终素材引用。
@@ -4649,11 +4650,11 @@
## Tauri 生成与资源编辑恢复不能依赖 UI 快照、旧 Key 指纹或队列首项(2026-08-11)
- 现象:应用重启后,任务视频或项目版本的编辑 operation 无法恢复;轮换 Developer API Key 后已有 operation 被误判为配置变化;目录中放入大量无关文件还能绕过 pending 扫描上限。一条远端已明确失败的老 operation 会持续占据队列首项,挡住后续已受理或已下载任务;manifest 已写而 project revision 未写时,又可能被误标为 committed。durable committed 后遗留 staging 可能因一次删除失败而被误报为提交失败,也可能在正式媒体或 manifest 身份已经漂移时被直接删除;manifest 已有派生子版本而 journal 缺失,或旧 journal 没有 revision 身份时,也可能被猜成已经提交。派生视频再次编辑时若把 `assetObjectId` 当远端引用,生成会失败或指向错误身份。
- 原因:早期账本只保存显示层资源 ID,恢复时又依赖当前页面资源对象;配置指纹混入 Key;扫描计数只在识别出 pending JSON 后递增;本地登记 ID 与 External generation 接受的稳定 `objectKey` 没有分层。恢复 UI 只选排序后第一项,而账本又没有远端终态失败/归档阶段;资产提交没有一份同时证明文件、manifest 和 revision 的 durable journal,提交后的清理也没有区分可证明的 staging 与需要保留的对账证据;旧 version journal 只保存 base/target 数值,不能证明完整 project revision before/after 身份。
- 处理:新账本冻结完整源快照,旧账本从权威 manifest、完成任务和版本记录有界恢复;服务身份用 `service-origin-v1` 哈希规范化 External base URL,确认 UI 只展示去除路径与凭据的服务 origin。对素材画布生成账本,当前 Key 不能验证旧 Key-bound 指纹时,确认前保持零网络动作,由用户显式确认当前服务后才继续原 GET 或精确重放冻结 POST;对全类型资源编辑,同类旧指纹保留原 operation 进入对账,不自动接管或重放。扫描在读取每个目录条目时先计数,任何文件都消耗预算。提交前复验源摘要,远端请求只使用账本已确认的稳定 `objectKey`,恢复始终复用原 operation 和请求字节。
- 队列与事务:独立恢复面板必须展示后端权威队列的所有 operation,读取失败不能伪装为空。`remote-failed` 不再重放,只能显式标为 `archived` 并保留账本;`reconciliation-required` 不能归档。派生 asset 使用 `prepared -> media-installed -> manifest-written -> revision-written -> committed` journal,只对可证明状态前向恢复;文件/摘要、manifest before/after 或 revision before/after 不匹配时进入人工对账。committed 后只有 staging 与正式媒体摘要一致、manifest 按 ID 或路径唯一精确匹配 journal asset 时才尽力清理;删除 I/O 失败保持 durable committed,身份或媒体漂移保留 staging 并进入对账。version journal 同样冻结 project revision before/after 身份;manifest 已有子版本但 journal 缺失,或旧 journal 面对已推进 revision 无法补证时都失败关闭。
- 验证:覆盖任务视频/版本旧账本恢复、所有目录条目上限、Key 轮换与旧 Key 无法验证时的显式确认、401/403/404 保留 operation、远端明确失败只归档且零新网络/扣费、三条乱序恢复队列、项目切换迟到结果、asset transaction 各崩溃阶段、committed 后 staging 清理成功/删除 I/O 失败/媒体或 manifest 漂移保留、源摘要漂移拒绝、committed 视频二次派生,以及 manifest 子版本缺 journal、旧 version journal 无法证明 revision 推进与 version journal exactly-once。
- 现象:应用重启后,任务视频、项目版本或 refine 草稿无法恢复;轮换 Developer API Key 后已有 operation 被误判为配置变化,已受理任务一次 401/403 还可能永久进入对账;文本 Provider 已成功但尚未 staging 时崩溃会重复调用。目录中放入大量无关文件还能绕过 pending 扫描上限。一条远端已明确失败的老 operation 会持续占据队列首项,挡住后续已受理或已下载任务;manifest 已写而 project revision 未写时,又可能被误标为 committed,或者 journal 已证明提交后因项目继续合法修改而无法补 ledger。durable committed 后遗留 staging 可能因一次删除失败而被误报为提交失败,也可能在正式媒体或 manifest 身份已经漂移时被直接删除;manifest 已有派生子版本而 journal 缺失,或旧 journal 没有 revision 身份时,也可能被猜成已经提交。派生视频再次编辑时若把 `assetObjectId` 当远端引用,生成会失败或指向错误身份。
- 原因:早期账本只保存显示层资源 ID,恢复时又依赖当前页面资源对象;refine `draftId` 只在组件 Map;配置指纹混入 Key 并把认证错误写成状态机终态;Provider 正文从内存直接进入解析/staging;扫描计数只在识别出 pending JSON 后递增;本地登记 ID 与 External generation 接受的稳定 `objectKey` 没有分层。恢复 UI 只选排序后第一项,而账本又没有远端终态失败/归档阶段;资产提交恢复把整个历史 after manifest 当作永久相等条件,没有区分目标事务事实与后续合法提交;旧 version journal 只保存 base/target 数值,不能证明完整 project revision before/after 身份。
- 处理:新账本冻结完整源快照,旧账本从权威 manifest、完成任务和版本记录有界恢复;refine 从正式 sidecar 按项目、意图、源素材和 active 状态唯一发现。服务身份用 `service-origin-v1` 哈希规范化 External base URL,确认 UI 只展示去除路径与凭据的服务 origin;旧 Key-bound 指纹由快照绑定的显式挑战迁移,确认前零网络动作,已受理任务换 Key 后只 GET 原 operation。Provider 调用前先持久化 request-issued,成功正文再写 durable handoff 后解析/staging;issued 无 handoff 只能对账。扫描在读取每个目录条目时先计数,任何文件都消耗预算。提交前复验源摘要,远端请求只使用账本已确认的稳定 `objectKey`,恢复始终复用原 operation 和请求字节。
- 队列与事务:独立恢复面板必须展示后端权威队列的所有 operation,读取失败不能伪装为空。`remote-failed` 不再重放,只能显式标为 `archived` 并保留账本;`reconciliation-required` 不能归档。派生 asset 使用 `prepared -> media-installed -> manifest-written -> revision-written -> committed` journal,只对可证明状态前向恢复;尚未证明目标写入时严格核对 before/after,已证明目标 asset/media 与 target revision 后允许 manifest/revision 被后续合法提交继续推进,并补齐同一 ledger。committed 后只有 staging 与正式媒体摘要一致、manifest 按 ID 或路径唯一精确匹配 journal asset 时才尽力清理;删除 I/O 失败保持 durable committed,身份或媒体漂移保留 staging 并进入对账。version journal 同样冻结 project revision before/after 身份;manifest 已有子版本但 journal 缺失,或旧 journal 面对已推进 revision 无法补证时都失败关闭。
- 验证:覆盖跨进程唯一 refine 草稿发现和多候选失败关闭、文本 Provider 成功到 staging 崩溃后零重复调用、任务视频/版本旧账本恢复、所有目录条目上限、Key 轮换与旧 Key 无法验证时的显式确认、Accepted 后 401/403 再换 Key 只 GET 原 operation、远端明确失败只归档且零新网络/扣费、三条乱序恢复队列、项目切换迟到结果、asset transaction 各崩溃阶段、revision 后项目继续合法修改仍补齐 ledger、committed 后 staging 清理成功/删除 I/O 失败/媒体或 manifest 漂移保留、源摘要漂移拒绝、committed 视频二次派生,以及 manifest 子版本缺 journal、旧 version journal 无法证明 revision 推进与 version journal exactly-once。
## 无限画布延迟草稿与零位移不能制造新状态(2026-08-11)