孤儿账本只在正向终态清除,legacy 迁移判据对齐 exact retry
一、孤儿过早清账。上一条把孤儿改成「读到任何结论就清账本」,但 pending / conflict 不是结论。浏览器关掉不会中止服务端处理——api-server 的处理与持久化 预算合计可达 90 秒,重开项目时单次 GET 没看见 resource 只说明「还不知道」。 此刻清账,服务端稍后落库便再无对账凭据,用户永远等不到「结果已进素材库」的 提示。改为只在 applied / dialog-missing 两个正向终态清账;pending / conflict 与读失败一律保留给下次加载重读,残留由保留期与条数上限兜住。 二、legacy 迁移漏 failed。判据按状态白名单列举 generating / pending-confirmation,漏掉 failed + perfectPixelOperation——那是旧严格保存 失败的合法持久化形状,retryPerfectPixelOperation 明确接受它,「重试同一完美 像素操作」按钮正是在这个形状下出现。漏迁后下一次保存剥成 marker,再加载即 failed + invalid,重试按钮消失,用户只剩删掉重做,而那正是新 identity。判据 改用 isUnresolvedCanvasGenerationDialogRecord 取反,与 hydrate 判定收口态同 一个函数,两处不会漂移。 通用要求:涉及「这条 operation 还需不需要账本」的判断一律问「它收口了没有」, 不要列举状态——状态白名单会随语义变化静默漏项,本条就是实例。 同步更正专题文档三处残留矛盾:窗口起算点仍写作「稳定请求快照写入时」;仍称 「不会让布局校验失败升级成硬阻断」(应限定为解除客户端侧拒发,端到端 409 依赖仍在);「删除后不再对账」(应限定为结果不再自动回填画布)。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -6439,3 +6439,15 @@
|
||||
- 影响范围:`useImageCanvasProjectPersistence.ts` 的 `applyProjectSnapshot`。不修改服务端、SpacetimeDB schema 或对外契约。
|
||||
- 验证方式:新增「legacy 内联账本在加载后被迁入本机,且剥离内联快照后仍能凭本机账本往返回有效的 `pending-confirmation` 占位」用例,已实证:回退迁移后报 `expected +0 to be 1`。运行 `npx vitest run src/components/image-editor src/components/platform-entry`、`npm run typecheck`、`npm run lint:eslint`、`npm run check:encoding`。
|
||||
- 关联文档:`docs/technical/【前端架构】图片画布编辑器MVP接入方案-2026-06-11.md`(已同步 legacy 迁移要求与 Undo 已知限制)。
|
||||
|
||||
## 2026-08-05 孤儿账本只在正向终态清除;legacy 迁移判据对齐 exact retry
|
||||
|
||||
- 缺陷一(孤儿过早清账):上一条把孤儿改成「读到任何结论就清账本」,但 `pending` / `conflict` 不是结论。浏览器关掉不会中止服务端处理——api-server 的处理与持久化预算合计可达 90 秒,远端 procedure 也可能还在跑;重开项目时单次 GET 没看见 resource 只说明「还不知道」。此刻清账,服务端稍后落库便再无对账凭据,用户永远等不到「结果已进素材库」的提示,同时又多开一个 identity 的口子。
|
||||
- 决策一:只有 `applied` / `dialog-missing` 这两个**正向终态**才清账本;`pending` / `conflict` 与读失败一律保留,留给下次加载重读。残留由 7 天保留期与 32 条上限兜住,代价是极少数永不落库的条目每个会话多一次 GET——比丢失凭据便宜得多。
|
||||
- 缺陷二(legacy 迁移漏 `failed`):迁移判据按状态白名单列举了 `generating` / `pending-confirmation`,漏掉 `failed + perfectPixelOperation`。那是旧严格保存失败的合法持久化形状(请求已备好、POST 从未发出),`retryPerfectPixelOperation` 明确接受该状态,面板上的「重试同一完美像素操作」也正是在这个形状下出现。漏迁的后果与缺陷本体一致:下一次保存剥成 marker 后再加载即 `failed + invalid`,重试按钮消失,用户只剩删掉重做——而那正是新 identity,正是 exact retry 存在的意义所在。
|
||||
- 决策二:迁移判据改用 `isUnresolvedCanvasGenerationDialogRecord` 取反,与 `hydrateCanvasGenerationDialog` 判定收口态用的是同一个函数,两处不会漂移。**通用要求**:涉及「这条 operation 还需不需要账本」的判断一律问「它收口了没有」,不要列举状态——状态白名单会随着新增状态或语义变化而静默漏项,本条就是实例。
|
||||
- exact retry 的价值必须记清楚,它不是「省一次操作」:原样重放同一 identity 时服务端幂等生效(稳定 task / object / resource / asset ID 由 `owner + project + dialogId` 派生,请求带 fingerprint),同内容重放返回 `AlreadyApplied` 而不是再造一份。删掉它意味着对账查不出结论时用户只能新建 identity,旧的若其实成功就会重复。曾评估过「直接删除该功能以减少用户困扰」,权衡后保留——困扰来自文案与状态不清晰,可以单独治理,而幂等保证一旦删掉无法用文案补回。
|
||||
- 同步更正的文档:专题文档三处残留矛盾——`submittedAt / reconcileUntil` 仍称「从稳定请求快照写入时建立」(应为 pre-POST flush 之后、POST 之前)、仍称「不会让布局校验失败升级成硬阻断」(应限定为解除了客户端侧拒发,端到端 409 依赖仍在)、以及「删除后不再对账」(应限定为结果不再自动回填画布,对账本身继续进行)。
|
||||
- 影响范围:`useImageCanvasGenerationWorkflow.ts` 的恢复 effect 孤儿分支、`useImageCanvasProjectPersistence.ts` 的 legacy 迁移判据。不修改服务端、SpacetimeDB schema 或对外契约。
|
||||
- 验证方式:孤儿用例翻转为「单次读仍无法判定时保留账本、不提示、不刷新素材库」;新增「legacy `failed + operation` 被迁入本机」用例。两条均已实证:回退修复后各报 `expected +0 to be 1`。运行 `npx vitest run src/components/image-editor src/components/platform-entry`、`npm run typecheck`、`npm run lint:eslint`、`npm run check:encoding`。
|
||||
- 关联文档:`docs/technical/【前端架构】图片画布编辑器MVP接入方案-2026-06-11.md`。
|
||||
|
||||
Reference in New Issue
Block a user