图生 3D 图片输入的失败语义同步到文档

- 实施计划写明预检失败的状态码口径:400 只覆盖跨 owner / 未登记 / 已删除 / kind 不符,403 / 409 / 5xx 保留原状态码,缺对象键 502
- 决策记录新增同日条目,说明收窄收敛范围与缺对象键改判 502 的原因、代价与验证方式
This commit is contained in:
2026-09-23 14:59:52 +08:00
parent 11d1324857
commit 1fa413a352
2 changed files with 12 additions and 2 deletions
@@ -9393,3 +9393,13 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在
- 影响面:`server-rs/crates/shared-contracts/src/model3d/{text_to_model/request.rs,image_to_model/request.rs,common/mod.rs}`(删除 `common/generation_target.rs`)、`server-rs/crates/api-server/src/tripo3d/{job.rs,validation.rs,target.rs,routes.rs,worker.rs}``server-rs/crates/api-server/src/editor_project.rs`(删除 Standard 的 `result` 透传)、`packages/shared/src/contracts/model3d/`(删除 `common/Model3dGenerationTarget.ts` 与 barrel 导出)、`src/components/image-editor/model3d-generation/{Model3dGenerationSubmission.ts,useModel3dGenerationTask.test.tsx}``src/services/image-editor/editorProjectClient.ts`、技术方案 / 里程碑 / 实施计划与共享记忆。
- 验证方式:`cargo test -p shared-contracts``cargo test -p api-server`1193 passed)、`cargo test -p api-server tripo3d::`55 passed,含 `target_requires_exactly_one_flat_locator``flat_locator_maps_to_point_lookup_without_rewriting_ids``flat_target_is_normalized_before_enqueue`)、`npx vitest run src/components/image-editor/model3d-generation src/components/image-editor/model3d-preview`63 passed)、`npm run typecheck``npm run contracts:model3d:generate``npm run check:encoding``npm run check:rustfmt``git diff --check`
- 关联文档:[技术方案 Tripo 3D生成API集成](../../technical/【技术方案】Tripo 3D生成API集成-2026-09-21.md)、[实施计划 Tripo生成API契约与数据模型](../plans/【实施计划】Tripo生成API契约与数据模型-2026-09-21.md)。
## 2026-09-23 图生 3D 的图片输入失败语义:只收敛「引用不可用」,缺对象键改判 502
- 背景:`tripo3d/image_source.rs` 原先用 `is_client_error()` 把 resolver 的所有 4xx 都收敛成 `400 model3d-image-source-unavailable`(文案「图片输入必须是当前账号已登记的画布资源或素材。」),同时把「记录已解析、属于调用方、但没有对象键」也归进同一句 400。逐条核对后确认前者会把 `403``require_editor_generation_runtime_service_identity``map_editor_project_error` 的「无权」)与 `409`(版本冲突 / 幂等)说成用户引用写错,后者则把一个「DB 行存在但格式异常」的运维信号说成客户端问题。
- 决策:① 收敛范围收窄为 `400` / `404`,其余状态码(含 `403``409`、5xx)一律按原状态码与原文案上报;② 「记录已解析但缺对象键」单独判 `502 model3d-image-source-object-key-missing`(带 `field: source`),口径与 `editor_project::validate_editor_reference_id_for_owner``preflight_editor_icon_spec_reference_metadata``BAD_GATEWAY` 一致;③ 预检失败仍然不扣费、不入队。
- 原因:**错误语义要指向用户能改的东西**——`403` 是服务身份配置问题、`409` 是并发写入、缺对象键是数据完整性,三者都不是「你的图片没登记」。原实现的模块注释本身写着「只有基础设施失败保留原状态码」,但代码用 `is_client_error()` 覆盖了 `403` / `409`,注释与实现互相矛盾,按注释收口才自洽。
- 代价与取舍:`502``400` 的差异对外可见(前端会把 5xx 当可重试的服务端错误、把 400 当参数错误),这是有意的;token 与 ID 都不出响应体。缺对象键的场景按「上游数据异常」处理,客户端重试不会自愈,需要人工修数据行。
- 影响面:`server-rs/crates/api-server/src/tripo3d/image_source.rs`(收敛分支、新增 `image_source_object_key_missing`、模块文档与定向用例)、[实施计划 Tripo生成Worker执行链路与API路由](../plans/【实施计划】Tripo生成Worker执行链路与API路由-2026-09-21.md)。
- 验证方式:`cargo test --locked -p api-server tripo3d::image_source`4 passed,含 `image_source_resolution_only_collapses_unavailable_references` 覆盖 400 / 404 收敛与 403 / 409 / 500 保留、`image_source_resolution_reports_missing_object_key_as_server_side_failure` 断言 502 与 reason)、`rustfmt --check`
- 关联文档:[技术方案 Tripo 3D生成API集成](../../technical/【技术方案】Tripo 3D生成API集成-2026-09-21.md)、[实施计划 Tripo生成Worker执行链路与API路由](../plans/【实施计划】Tripo生成Worker执行链路与API路由-2026-09-21.md)。