完美像素持久化阶段由服务端显式告知客户端
上一版用 error instanceof ApiClientError 判定「结果已知」,即「服务端响应过就等于 没落库」。这个等式不成立:持久化非事务,complete_editor_canvas_generation 走 CAS 写入,冲突时经 map_editor_project_error 变成 409,403/404/400 同理。带响应的 4xx 同样可能发生在 OSS 对象、asset object、project resource 和账号素材全部落库之后。 完美像素要跑满 30 秒,用户在这期间改画布推进 revision 并不罕见。 否决了两个替代方案:所有 POST 后失败都当未知(每次常见校验失败多两次读取,且给 不可能产生素材的场景附上「请核对素材库」的不适用提示);按状态码分类(409 确实只 来自写操作,但 403/404 和 5xx 在持久化前后都会出现,等于把猜测写进代码)。 改为服务端显式告知。AppError 新增 with_detail_field,在已有 details 上补字段而不是 整体替换,保留下游写入的 provider/message。snap_editor_image_to_pixel_art 在第一次 OSS PUT 之后的四条失败路径置 resultPersistenceStarted。客户端只对完全无响应和带该 标记的失败做对账。 配套:对账成功分支补上 hasCanvasGenerationDialogById 检查——权威快照里占位消失也 可能是用户删的,契约要求此时不应用快照不写历史,成功路径早有这道检查而对账路径漏了。 对账同时刷新素材库,否则只 GET 项目却让用户核对素材库,他看到的是旧列表。 服务端 guard 把标记钉为 4 处并要求只出现在 persist_editor_generated_image_owned 之后;客户端新增三条用例覆盖带标记对账、未带标记不对账、用户删除占位。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -5972,3 +5972,13 @@
|
||||
- 验证:新增三条用例分别覆盖「未知但实际成功→按快照收口并写历史」「未知且占位存活→只同步快照、标失败、文案要求先核对」「`ApiClientError` 已知失败→不发对账 GET、不动快照」。既有用例 `keeps a failed perfect-pixel placeholder` 原本用裸 `Error` 表达「服务端识别不到网格」,语义不准且会误入对账路径,改为 `ApiClientError`。测试 harness 新增 `dialog-error` 输出,否则对账文案不可观测。
|
||||
- 补充(同日):对账只对真正发出过 POST 的失败生效。占位创建、源图解析和 `flushProjectPersistence` 都在 POST 之前,它们失败时请求根本没发出,此时给出「素材库可能已存在派生图」是反向谎报,与本条要修的谎报是镜像关系;用 `perfectPixelPostAttempted` 标记划界,同时省掉一次无意义的权威读取。占位存活分支也不再调用 `applyProjectSnapshot`:传给该 hook 的是 `ImageCanvasEditorView` 的 `applyGeneratedProjectSnapshot`,其 action 默认值为 `generate-image`,不传 action 会写一条类型错误且受撤销保护的历史,而权威快照此刻与本地一致(占位都在),套用只会覆盖用户在请求期间的未保存编辑。这次 GET 的用途是判定,不是同步。
|
||||
- 关联文档:`docs/technical/【前端架构】图片画布编辑器MVP接入方案-2026-06-11.md`。
|
||||
|
||||
## 2026-08-01 完美像素持久化阶段由服务端显式告知客户端
|
||||
|
||||
- 背景:上一版对账用 `error instanceof ApiClientError` 判定「结果已知」,即「服务端响应过就等于没落库」。这个等式不成立——持久化非事务,`complete_editor_canvas_generation` 走 CAS 写入,冲突时 `spacetime-module` 抛「图片画布版本冲突」,经 `map_editor_project_error` 变成 `409`;`403 / 404 / 400` 同理。也就是说带响应的 4xx 同样可能发生在 OSS 对象、asset object、project resource 和账号素材全部落库之后。完美像素要跑满 30 秒,用户在这期间改动画布把 revision 推进并不罕见,因此该场景触发频率高于最初估计。
|
||||
- 否决的两个方案:把所有 POST 后失败都当未知(每次常见校验失败多两次读取,且给不可能产生素材的场景附上「请核对素材库」的不适用提示);按状态码分类(`409` 确实只来自写操作,但 `403 / 404` 和 `5xx` 在持久化前后都会出现,分不干净,等于把猜测写进代码)。
|
||||
- 决策:由服务端显式告知。`AppError` 新增 `with_detail_field`,在已有 details 上补字段而不是像 `with_details` 那样整体替换,保留下游写入的 provider / message——客户端要靠 message 定位、靠新字段决策。`snap_editor_image_to_pixel_art` 在第一次 OSS PUT 之后的四条失败路径(账号素材持久化失败、项目资源缺失、账号素材缺失、画布回填失败)置 `resultPersistenceStarted: true`。客户端只对「完全无响应」和「带该标记」的失败做对账,常见的纯校验 `400`、排队 `503`、预算 `504` 既不多打读取也不附加提示。
|
||||
- 配套修复:对账成功分支补上 `hasCanvasGenerationDialogById` 检查——权威快照里占位消失有两种原因,服务端消费掉或用户在请求期间删除,后者契约要求不应用完成快照、不写历史,成功路径同一处早有这道检查而对账路径漏了。对账同时刷新素材库(新增可选 `refreshAssetLibrary` 贯穿 `ImageCanvasEditorView` → surface → workflow),否则只 GET 项目却让用户核对素材库,他看到的仍是旧列表,不满足契约的「项目 / 素材快照」。占位存活分支刻意不调 `applyProjectSnapshot`:传入的是 `applyGeneratedProjectSnapshot`,其 action 默认值为 `generate-image`,不传 action 会写一条类型错误且受撤销保护的历史,而权威快照此刻与本地一致,套用只会覆盖未保存编辑。
|
||||
- 验证:服务端 `assert_function_occurrence_count` 把标记钉为 4 处,并用顺序断言要求它只出现在 `persist_editor_generated_image_owned` 之后——漏标一处或误标在校验阶段都会失败。客户端新增用例覆盖「带标记的 409 触发对账并刷新素材库」「未带标记的 400 不对账、文案保持服务端原文」「用户删除占位则不应用快照不写历史」。
|
||||
- 未覆盖:刷新页面后停在 `generating` 的占位仍无自动收口,需先给 dialog 增加「无 durable job 的 inline 链路」标记,单独立项。客户端 120 秒超时相对服务端 30 秒预算是四倍冗余,未调整。
|
||||
- 关联文档:`docs/technical/【前端架构】图片画布编辑器MVP接入方案-2026-06-11.md`。
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user