fix(models): 默认模型改用「压缩包 sha256」匹配(转换产物非字节级确定)

实测发现:同一份 zip 连续转换三次得到三个不同的产物 sha256(大小都是 1,152,464
字节,差异集中在 BIN chunk 的十几字节),说明 Assimp 的 GLB 导出不是字节级确定的。
因此原先把「转换产物 sha256」当作默认模型匹配键的设计是错的——换一次转换就失效。

- default-model.ts / default-model-source.ts:种子拆成 sourceSha256(上传压缩包的
  sha256,稳定,主匹配键)与 fileSha256(产物 sha256,仅作记录)
- models.service.ts:resolveDefaultModelId 依次按 压缩包 sha256 → 产物 sha256 →
  名称 匹配,都落空才回落到 VRM 优先规则并告警
- ModelDto 增加 sourceSha256(非压缩包上传为 null)
- scripts/import-default-model.mjs:写种子时用 sourceSha256;顺带修掉位置参数解析
  (文件当第一个参数时识别不出,会打印用法)
- 契约与文档同步:data-models §4.1、model-formats §1.1 记录该确定性结论;
  README / DSH / tasks/005 的「按产物 sha256 匹配」表述已更正

另附:把模型格式能力的实测矩阵写进 Release 说明(原生只支持 glTF 系;
PMX→FBX 失败;VRM→GLB 丢 VRM 扩展;humanoid 骨骼命名覆盖率)。

验证:125 项单测通过;清理掉两个"文件只在本机临时目录"的模型(避免 sha256 去重
导致后续上传不落盘);种子按压缩包 sha256 命中后 defaultModelId 正确解析。
This commit is contained in:
2026-09-15 19:36:37 +08:00
parent e4351c5062
commit ccced34dd6
12 changed files with 164 additions and 48 deletions
+2 -1
View File
@@ -243,7 +243,8 @@ CONTRACTS_DIR=/contracts # 可选,读取实时契约版本
`FBX-DOM no Objects dictionary found`),实际入库为 GLB。
- **默认模型**:转换成功且 `autoDefault` 不为 false(默认 true)→ `is_primary=1` +
`status=published`,并把身份写进源码种子;`GET /api/catalog/export` 的
`defaultModelId` 解析顺序为 `DEFAULT_MODEL_ID` → 源码种子(按产物 sha256 匹配)
`defaultModelId` 解析顺序为 `DEFAULT_MODEL_ID` → 源码种子(按**上传压缩包**的 sha256 匹配;
产物 sha256 每次转换都变,只作记录)
→ 已发布且 is_primary 的 VRM → 任意已发布 VRM → id 最小的已发布模型。
- **溯源**:压缩包原件存为 `model-archive` 资产,记入 `models.source_asset_id`
(迁移 `AddModelConversionFields1789450000000`);`models.conversion_note` 记转换说明。