59/60/61/65 按决定不修复,改为在代码里写清取舍

- worker.rs:说明 last_error_message 是落库且前端直接展示的摘要,只取 provider message,不塞内部 reason/taskStatus(#59)
- platform-tripo error.rs:说明 ADR 0001 要求平台层不带出 SDK 错误模型,Io/Serde 只保留文本(#60)
- platform-tripo mapping.rs:说明 Tripo 文档把 generated_image_url 列为 text_to_model 固定字段,按 ADR 0001 失败关闭保留必填(#61)
- platform-tripo image_to_model/client.rs:说明 PublicUrl 只做非空白校验的边界条件与将来接外部地址时的校验位置(#65)
This commit is contained in:
2026-09-23 18:04:29 +08:00
parent 985955205c
commit 6b1114356c
4 changed files with 24 additions and 0 deletions
@@ -71,6 +71,11 @@ pub(crate) async fn process_model3d_job(
run_model3d_job(state, caller, job, request, provider_deadline),
)
.await
// 这里返回的字符串会成为 job 的 `last_error_message`,并原样回给前端(见
// `editor_generation_queue_state` 的 `error` 字段),所以刻意只取 provider 错误体里
// 人类可读的 message:用户可见文案不带内部 reason / taskStatus 枚举。
// 评审 #59 提过把结构化 details 一并写进去,按决定不改 —— 那会改掉已落库与前端展示的
// 文案口径;排障要定位 provider 侧任务时看 job 的 provider task idcheckpoint)。
.map_err(|error| error.body_text())
}
@@ -113,6 +113,13 @@ pub enum TripoError {
field: &'static str,
message: String,
},
/// SDK 自身报出的错误(本地 IO、反序列化等),只保留文本。
///
/// 按 ADR 0001「不把 `tripo3d-sdk` 的错误模型带出平台边界」,这里不保留
/// `std::io::Error` / serde 错误的类型,也不实现 `Error::source()`:调用方拿到的是
/// 平台层归一化后的错误,而不是第三方错误链。评审 #60 提过拆 `SdkIo` / `SdkSerde`
/// 变体或加 `source` 字段,按决定不改 —— 那是公共错误枚举的 breaking 变更,
/// 收益只到排障细分一层。
Sdk {
message: String,
},
@@ -425,6 +432,8 @@ impl From<tripo3d_sdk::Error> for TripoError {
// 等待超时是瞬时的:重试一次可能就等到了。
retryable: true,
},
// Io 与 Serde 拍平成同一个文本变体:上游 SDK 对这两种错误只保证 Display 文本,
// 平台层也不再向上区分(理由见 `Sdk` 变体的注释,评审 #60)。
tripo3d_sdk::Error::Io(error) => Self::Sdk {
message: error.to_string(),
},
@@ -98,6 +98,10 @@ fn map_output(
TripoTaskType::TextToModel => Ok(TripoTaskOutput::TextToModel(TripoTextToModelResult {
model_url,
rendered_image_url,
// Tripo API 文档把 generated_image_url 列为 text_to_model 输出的固定字段,
// 真实 provider smoke 也确认它总是存在(见技术方案《Tripo 3D模型Provider集成》)。
// 因此按 ADR 0001「结果缺必填字段即以 output schema error 失败关闭」保留必填:
// 真缺失说明上游偏离了文档,属于要暴露的异常,不做静默兜底(评审 #61,按决定不改)。
generated_image_url: required_url(
task_id,
"generated_image_url",
@@ -12,6 +12,12 @@ use super::validation::validate_image_to_model_params;
///
/// 平台层只接受站内引用,所以调用方只会产出这两种形态:先上传拿 `file_token`
/// 或给出公网可读地址。不提供裸字符串变体,避免 SDK 把字符串按前缀推断成 task_id。
///
/// `PublicUrl` 只做非空白校验、不做 scheme / host 白名单:Tripo API 文档允许 `url` 指向任意
/// 公网可读地址,本地再收窄会误伤文档允许的形态。当前生产路径全部走 `upload_image` →
/// `FileToken``PublicUrl` 只由冒烟示例构造,没有不可信输入的现役入口;将来若把外部传入的
/// 地址接到这条路径,应在构造侧按 `TripoUrl::parse` 的口径校验 scheme 并拒绝 userinfo /
/// 内网主机(评审 #65,按决定不在本层加校验)。
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum TripoImageInput {
FileToken(String),