3D 允许 projectId 为空的文档与共享记忆同步

- 实施计划(API 契约):交付验收补上「只给 assetFolderId 合法」这一条。
- 里程碑(API 契约):落点口径写成「两个都给合法、只给 assetFolderId(无画布工程)同样合法」。
- 实施计划(前端入口):发送门禁改成「两个落点至少给一个」,projectId 可空、缺失时不发该字段,没有工程时结果只落素材库。
- 共享记忆 decision-log:在 G5 条目的「代价与取舍」里把「3D 仍要求 projectId」改成「同日按用户决定改为与其它工具一致」,并追加一条收尾说明(门禁常量改名、canvasCompletion 只随 projectId 下发、无工程时的读回边界)。
- 验证:node scripts/check-doc-index.mjs(221 份 Markdown 通过)、npm run check:encoding、git diff --check 通过。
This commit is contained in:
2026-09-23 16:42:15 +08:00
parent a4132616d8
commit 347d066fc5
4 changed files with 5 additions and 4 deletions
@@ -9420,7 +9420,8 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在
- 背景:G5 复核(对照图片 / 图标 / 音效 / 角色动作等所有画布生成工具的前后端)发现 3D 仍有三处自成一派:① 服务端要求「`projectId` 与 `assetFolderId` 恰好一个」,而其它工具两个都能给,且前端画布链路**始终**同时发 `projectId` + `assetFolderId`(当前素材夹) + `assetLabel`,落库时项目资源行与素材行两条都写;② 3D 前端提交只发 `projectId`,于是 3D 结果永远不进素材库,同一张画布上的其它生成工具却都会进;③ 结果里的落点引用还是 tagged enum(`{ kind: "projectResource" | "assetLibrary" }`),与请求侧的平坦落点形状不一致;素材库行也没有 `model3d` 分支,一旦真落了素材行,缩略图会拿 `objectKey`(模型 `.glb`)去换签名地址。
- 决策:① 服务端校验放宽为「至少一个落点」:两个都不给 400 点名 `projectId`,`canvasCompletion` 与「没有 `projectId`」同现 400 点名 `canvasCompletion`,两个都给合法;预检对给出的每个落点逐个定点查,出错时字段名只在「只给一个」时点名该字段,两个都给无法归因就回落到 `target`。② `Model3dGenerationTargetRef` 从 tagged enum 改成与请求落点同形的平坦可选字段 `resourceId?` / `assetId?`:哪个落点写了行就带哪个 ID,两个都写就都带。③ 前端 `buildModel3dSubmissionPlan` 接收当前素材夹与素材名,与其它工具一样同时发 `projectId` + `assetFolderId` + `assetLabel`(缺省名回落本次结果标题),`useModel3dGenerationTask` 从画布生成链路拿到 `assetFolderId`;结果消费沿用既有画布路径(`applyGeneratedProjectSnapshot` 顺带刷新素材库),不再需要 3D 专用刷新。④ 素材库行加 `model3d` 分支:缩略图按预览图(`asset.src`)渲染,`objectKey`(模型本体)不参与图片签名,与画布 3D 卡片的 `objectKey={null}` 口径一致。
- 原因:**同一件事在各工具间必须同形**——落点是「结果放哪儿」的同一语义,3D 没有理由单独要求二选一;其它工具「画布 + 素材库同时落」既是现状也是用户预期(同一画布上的产出应当都能在素材库里找到)。结果引用跟着请求形状走,消费方不需要为同一个概念准备两套类型。素材库行的隐患属于「不接就永远发现不了」的类型:后端投影已经把 `imageSrc` 指向预览、`objectKey` 指向模型本体(`project_editor_client_media_src`),前端再拿 `objectKey` 签名就会去加载 `.glb`。
- 代价与取舍:3D 现在会像其它画布工具一样,每次都往素材库写一条素材行(落点是当前素材夹,默认 `project` → owner 默认素材夹),素材库体积与写入量随 3D 使用增加,这是与其它工具一致的既有代价。素材库行只做预览图渲染与拖入画布,行内不开 3D 查看器,要看模型仍需拖到画布后点「3D 预览」。3D **仍要求 `projectId`**(画布链路必须已保存工程,否则提示「请先保存当前画布工程」),这一点与「`projectId` 可空、只落素材库」的其它工具仍有差异,属于有意保留:3D 入口只在有画布的编辑器里,没有画布就没有 3D 查看入口。本分支未合并,无外部调用方,结果引用形状变化不需要兼容层。
- 代价与取舍:3D 现在会像其它画布工具一样,每次都往素材库写一条素材行(落点是当前素材夹,默认 `project` → owner 默认素材夹),素材库体积与写入量随 3D 使用增加,这是与其它工具一致的既有代价。素材库行只做预览图渲染与拖入画布,行内不开 3D 查看器,要看模型仍需拖到画布后点「3D 预览」。3D **起初仍要求 `projectId`**(初稿理由是「3D 入口只在有画布的编辑器里」);同日按用户决定改为与其它工具完全一致——`projectId` 可空、只给 `assetFolderId` 时结果只落素材库,前端门禁由「必须有工程」改成「两个落点至少给一个」。本分支未合并,无外部调用方,结果引用形状变化不需要兼容层。
- 2026-09-23 追加(同一需求收尾):`projectId` 也改成可空。前端 `buildModel3dSubmissionPlan` 的发送门禁从「必须有画布工程」(`MODEL3D_PROJECT_REQUIRED_MESSAGE`,已删除)改成「两个落点至少给一个」(`MODEL3D_TARGET_REQUIRED_MESSAGE`),placement 只带实际存在的字段、`canvasCompletion` 只随 `projectId` 下发;Rust 请求结构体的文档注释同步去掉「二选一」旧表述并重新生成绑定。没有工程时结果只落素材库(与其它画布工具在无工程时一致:不套用项目快照、也没有本地图层回流)。
- 影响面:`server-rs/crates/shared-contracts/src/model3d/common/generation_target_ref.rs`(tagged enum → 平坦结构,`packages/shared/src/contracts/model3d/common/Model3dGenerationTargetRef.ts` 随之变宽)、`server-rs/crates/api-server/src/tripo3d/{validation.rs,target.rs,job.rs,worker.rs}`、`server-rs/crates/shared-contracts/tests/model3d_api_request_contract.rs`、`src/components/image-editor/model3d-generation/{Model3dGenerationSubmission.ts,useModel3dGenerationTask.ts}`、`src/components/image-editor/useImageCanvasGenerationSubmissionWorkflow.ts`、`src/components/image-editor/ImageCanvasAssetRowView.tsx`、技术方案 / 里程碑 / 实施计划三份 3D 文档与共享记忆。
- 验证方式:`cargo test -p api-server tripo3d::`(56 passed,含 `target_accepts_both_locators_but_requires_at_least_one`、`flat_locator_maps_to_point_lookup_without_rewriting_ids`、`unavailable_field_names_the_given_locators`、`completed_result_is_strict_per_endpoint_and_free_of_provider_facts`)、`cargo test -p shared-contracts`、`npm run contracts:model3d:generate`、`npx vitest run src/components/image-editor/model3d-generation src/components/image-editor/ImageCanvasAssetRowView.test.tsx`(67 passed)、`npm run typecheck`、`npm run check:encoding`、`npm run check:rustfmt`、`node scripts/check-doc-index.mjs`、`git diff --check`。
- 关联文档:[技术方案 Tripo 3D生成API集成](../../technical/【技术方案】Tripo 3D生成API集成-2026-09-21.md)、[里程碑 Tripo生成API契约与数据模型](../plans/【里程碑】Tripo生成API契约与数据模型-2026-09-21.md)、[实施计划 Tripo生成前端入口](../plans/【实施计划】Tripo生成前端入口-2026-09-21.md)、[实施计划 Tripo生成结果前端预览接入](../plans/【实施计划】Tripo生成结果前端预览接入-2026-09-21.md)。