refactor/整理现有的string-typed资源类型 #388

Merged
k88936 merged 80 commits from feat/agc-organize-assetkind into master 2026-09-19 03:51:33 +08:00
Member

close #368

close #368
k88936 self-assigned this 2026-09-16 18:40:17 +08:00
k88936 added this to the 陶泥儿gameAgent project 2026-09-16 18:40:17 +08:00
k88936 added 34 commits 2026-09-16 18:40:17 +08:00
Direct Codex 引用 ui-design-doc 时生成带文档的 JS 文件

生成成功或失败信息追加到当前 prompt

补充成功、失败与 ui-prototype 隔离测试
新增 ui-design-doc 与 application/json 常量

创建、桥接、工作流和持久化统一使用严格资产类型
共享契约新增 ui-design-doc 分类及中英文映射

前端编辑器与资源桥接严格识别文档资产

更新技术方案、实施计划和长期决策记录
将 ui-design-doc 资源纳入选中资源的 UI 编辑器按钮判定

保留 ui-prototype 图片资源的编辑器桥接入口
将项目开发 UI 编辑器回程测试 fixture 更新为 ui-design-doc
前端入口、资源桥接与引用预览统一使用共享常量

Rust 持久化与测试复用共享契约常量

补齐 UI 编辑器入口 fixture 的新资产类型
移除 UI 文档引用新增测试
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 4m30s
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 4m59s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 4m24s
Project CI / Backend tests (pull_request) Failing after 11s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m50s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Failing after 4m28s
Project CI / Repository checks (pull_request) Failing after 13s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m7s
Project CI / AI game creator shell web tests (pull_request) Failing after 3m22s
Project CI / Frontend tests (pull_request) Failing after 3m51s
Project CI / Native shell tests (pull_request) Successful in 7m4s
70a2246e8b
删除 Direct Codex UI 文档 fixture 与专门测试用例

保留生产引用逻辑和现有业务测试
新增资源 kind 枚举化主规范与边界。

新增词汇审计、Rust 绑定、写入清理三个里程碑。

新增 shell-only 资源 kind 扫描 todo 清单。

通过文档索引、编码与 diff 检查。
记录 manifest kind 的 Rust 写入边界与 TypeScript 消费方。

区分资源 kind 与 source/generation/workflow 等字符串领域。

标注 font、audio、sound-effect、background-music 及旧值的生产状态。

通过文档索引、编码与 diff 检查。
补充 Rust manifest 构造器逐处迁移清单。

补充 shell TypeScript 裸 assetKind 消费方清单。

区分图集、工作流和 manifest kind 的处理边界。
限定首个代码切片为 Rust enum 与 ts-rs 生成边界。

明确不修改 manifest 字段和其他资源字符串领域。

列出绑定、serde round-trip 与定向验证门禁。
新增 GameCreationAppAssetKind 及 Unknown 解析边界
通过 ts-rs 生成 shell 专属 TypeScript 联合类型
补充未知值上下文日志与 Rust/绑定生成测试
将 manifest 条目 kind 改为 Rust 枚举并把未知值收口为 Unknown
修正字体上传与图集切片的正式资源 kind
保持 source.kind 与 generationKind 等其他字符串字段不变
验证旧值读取为 Unknown 且序列化为 unknown
明确不执行 alias 迁移
新增消费 Rust 生成绑定的未知值解析模块
迁移资源引用与画布引用入口并补充日志测试
更新逐项迁移清单与实施计划
UI 原型与文档链接改用生成枚举边界
删除 ui-prototype 的主动 alias 使用并更新测试清单
为 AssetKindVisitor 增加 visit_string 转发。

补充 JSON 转义 kind 的反序列化回归测试。
按 ts-rs 生成的单引号联合成员校验绑定内容。
仅在测试构建中导入 GameCreationAppAssetKind,避免正式构建产生未使用警告。
生产校验与测试 fixture 改用 GameCreationAppAssetKind::UiDesign。

保留 ui-prototype 作为本地文件路径标识。
工作流源图校验与 fixture 统一使用 UiDesign。

更新失败提示中的 manifest kind 名称。
将 manifest 资源 kind 字符串 fixture 迁移为 Character 枚举。
将图集切片、角色动画和规格资源 fixture 改用对应 AssetKind 变体。
恢复校验和测试筛选统一识别 Icon 资源 kind。

部分登记探测限定在图集切片路径,避免误判普通图标。
在 server-rs workspace 集中声明 ts-rs 版本。

shared-contracts 通过 workspace 依赖引用可选 ts-rs。
按 Font 与 Unknown 返回值修正上传类型断言。

使用枚举字符串视图校验 canonical kind 集合。
引用资源时直接解析已存在的 subtype,移除无效 category 回退。
将字体、角色和资源图 fixture 改为 AssetKind 枚举。

将资源 kind 回传到字符串字段时显式使用 to_string。
资源编辑请求中的 sourceSubtype 统一从 AssetKind 显式转换字符串。
转义后的 ui-design 应解析为 UiDesign 枚举。
将有效分类投影用例的资源 kind 改为 UiDesign 枚举与 ui-design 断言。

移除遗留 ui 字符串 fixture,使 AGC 壳测试恢复编译。
正则改为匹配 parseGameCreationAppAssetKind(selectedResource.subtype) 的新调用形状。
回退资源 kind 绑定断言的误改
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust smoke (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Has been cancelled
2a75a2d2c8
ts-rs 导出内容是双引号,测试重新生成后再校验,恢复双引号断言。
Author
Member
  • 1. 资源引用按钮曾用 selectedResource.category 作为 subtype 的回退。canvas category 不是资源 kind,该分支只会解析成 unknown;已改为直接解析 selectedResource.subtype。提交 97e2b2690

  • 2. GameCreationAppAssetKind 的反序列化只实现 visit_str,带 JSON 转义的 kind 字符串会直接报错。已补 visit_string 转发并新增回归用例。提交 3caefd67155d0c99e2

  • 3. binding.rsGameCreationAppAssetKind 导入只在测试里用到。已加 #[cfg(test)],正式构建不再报未使用导入。提交 d07ea186f

  • 4. UI 原型桥接与 UI 工作流的 kind 校验仍在比较 ui-prototype,而 manifest 写入侧已用正式枚举。已统一为 GameCreationAppAssetKind::UiDesign / ui-design,路径常量保持原样。提交 a19319d81c2da8e184

  • 5. 图集切片读取侧校验与测试筛选仍比较旧字面量,导致平台图集切片登记无法短路、测试断言失真。已改为 GameCreationAppAssetKind::Icon 叠加 assets/art-spritesheet-slices/ 路径判定。提交 8b007c637

  • 6. 资源桥接、Codex 资源引用与 direct tool bridge 的测试 fixture 仍用字符串构造 kind。已改为 CharacterIconCharacterAnimationSpecUiDesign 等枚举成员。提交 30edfee00f0a62c63021dbbb4c3

  • 7. ts-rs 直连版本号未走 workspace 依赖。已在 server-rs workspace 统一声明并从 shared-contracts 引用。提交 040f64648

  • 8. sourceSubtype / source_subtype 等字符串字段接收枚举时类型不匹配。已显式 to_string(),不改字段语义。提交 46dfa2cff3907a8bf7

  • 9. 上传资源 kind 测试仍断言旧的 document / asset,且把枚举传给字符串集合。已改为 font / unknownkind.as_str()。提交 39e33f7a5

  • 10. 资源引用入口的源码正则仍匹配旧的 subtype || category 形状。已更新为匹配 parseGameCreationAppAssetKind(selectedResource.subtype, ...),对应用例已单跑通过。提交 512f669f5

  • 11. review 第 9 条(绑定测试应断言单引号)经核实是误报:exports_ui_editor_types 会先用 ts-rs 把绑定就地重写成双引号原始格式再读取,单引号断言会让该测试失败。已回退,恢复双引号断言并验证通过。提交 2a75a2d2c

  • 12. review 关于 ts(export_to) 会被当成目录、生成到 GameCreationAppAssetKind.ts/GameCreationAppAssetKind.ts 的推断经核实不成立:实际落点就是 apps/ai-game-creator-shell/src/contracts/generated/GameCreationAppAssetKind.ts,与提交文件一致。

  • 13. 图集切片读取侧与写入侧词汇不一致。现状:写入侧切片的 manifest kind 已是正式成员,读取侧却仍在比较平台/工作流标识(art-spritesheet-slice),判定恒不成立,切片美术列表会返回空、切片链路失效。修复:切片登记与读取统一按 GameCreationAppAssetKind::Icon,切片与普通图标靠 assets/art-spritesheet-slices/ 路径前缀区分。提交 a61b0cce8

  • 14. 陶泥儿美术资产身份比对错用了字符串。现状:direct_taonier_art_asset_identity"art-spritesheet" / "game-background" 去比枚举字段,除已是 canonical 的 icon-spec 外全部恒不匹配,整包校验与恢复校验会失败。修复:函数签名改成 expected_kind: GameCreationAppAssetKind,调用点与 fixture 统一传 IconSpec / Scene / IconSpritesheet;同一提交里直连游戏工程产物的 game-entry / game-script / game-style / game-package / game-lockfile / game-build-config / game-source 也收敛为正式成员 Code。提交 a61b0cce8

  • 15. 非 canonical manifest kind 字面量审计。现状:真正的问题不是「字面量多」,而是写入边界没有把平台请求词汇转成正式成员,读取侧还拿平台词汇去比枚举字段。修复:assets.rs 画板导出推断直接返回枚举并删掉兜底归一;commands.rs 登记边界按上下文解析 kind;canvas_generation.rs 新增 platform_art_asset_manifest_kind,把 ui-prototype / art-spritesheet / game-background / game-art 等平台词汇显式映射为正式成员;manifest.rs 的必填视觉资产校验此前拿 ui-prototype / art-spritesheet 去比枚举字段(真实 bug,恒不匹配),已改为 IconSpec / UiDesign / IconSpritesheetproject_gates.rsautonomous_policy.rsrecovery_scan.rsdirect_tool_bridge.rsui_editor/* 与测试 fixture 同步收敛。原文举的 tool_policy_snapshot.rs 不成立:该文件只列工具名,没有 kind 列表。剩余字面量都在平台请求字段与 JSON 载荷里,不再进 manifest。提交 a61b0cce8

  • 16. GameCreationAppAssetManifestEntry.kindString 改成枚举是公开 Rust 类型的破坏性变更。现状:分支里已经按类型收紧落地,没有 String 版本;本次不写历史兼容代码、不做数据迁移、不写兼容测试,写入侧只接受枚举成员,未知输入仍按读边界收口 Unknown。修复/说明:把这次破坏性变更写进实施计划的「已落地 / 明确不修改」两节;版本策略与对外变更说明由你决定,我没有自行宣布任何兼容或迁移策略。提交 7eee89ded

  • 17. source_subtype 与资源 kind 字段语义混用(原文:会把 art-imagesvgtextproject-versionagent-result-derivative 传进 kind)。现状:非正式成员会被收口成 Unknown,项目版本与 Agent 回执在冒充 manifest kind。修复:新增 ResourceEditSourceKindManifest(GameCreationAppAssetKind) / ProjectVersion / AgentResultText),快照字段改收该枚举;前端 sourceSubtype 只传正式枚举成员,非 manifest 来源传 null;栅格源归一化只认正式成员(删掉 task-artifact 特判,未知按 Image 收口);账本、HTTP 载荷与提示词边界用 as_str(),写回 manifest 用 manifest_kind()。提交 f185d21f5f9bc2d917

  • 18. 你说的「没看到这个文件」——它是 apps/ai-game-creator-shell/src/contracts/assetKind.ts(资源 kind 的前端契约入口,不在 view/ 目录里,平时不会翻到)。现状:GAME_CREATION_APP_ASSET_KINDS 是手写字面量列表,与生成的 union 各写一份,且已包含生成侧才有的 font / unknown,两边会再次分叉。修复:改成 GAME_CREATION_APP_ASSET_KIND_MEMBERS: Record<GameCreationAppAssetKind, true> 常量表,集合与新增的 isGameCreationAppAssetKind 类型守卫都由它派生;生成 union 增删成员时 TS 会直接编译报错,列表没法再悄悄漂移。提交 f9bc2d917

  • 19. BindingChange / BindingDTO 不是凭空出现的名字:它们是 apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/binding.rs 里真实的内部结构(LLM 组件绑定响应体)。原文的问题是那个手写测试 exports_ui_editor_types:它用 ts-rs 把这两个结构导出到已退役的 src/features/ui-editor/types/,并顺手把 src/contracts/generated/GameCreationAppAssetKind.ts 就地重写成生成器原始格式——测试自己重写文件,既发现不了漂移又污染工作树。修复:删掉该测试与那套额外的类型导出(退役类型不再导出,前端消费方已删),生成只走 cargo test export_bindings;枚举自带 #[ts(export, export_to = .../src/contracts/generated/)];生成的 src/contracts/generated/ 加入 .prettierignore 与 eslint ignorePatterns,让 ts-rs 原始格式保持幂等、跑完不污染工作树。提交 b96cd4b7c

  • 20. 顺带修掉 apps/ai-game-creator-shell/tests/assetKindCanonicalMapping.test.ts 两条在改动前就已经恒失败的用例:解析 Rust canonical 目录的正则只认裸字符串字面量,认不出 GAME_CREATION_APP_UI_DESIGN_DOC_ASSET_KIND 这类常量引用,于是「两侧 canonical kind 目录一致」永远少一项;现在解析前先把 pub const *_ASSET_KIND: &str = "..." 展开成字面量,并删掉测试体里游离的 'font', 表达式。提交 f9bc2d917

- [x] 1. 资源引用按钮曾用 `selectedResource.category` 作为 `subtype` 的回退。canvas category 不是资源 kind,该分支只会解析成 `unknown`;已改为直接解析 `selectedResource.subtype`。提交 `97e2b2690`。 - [x] 2. `GameCreationAppAssetKind` 的反序列化只实现 `visit_str`,带 JSON 转义的 kind 字符串会直接报错。已补 `visit_string` 转发并新增回归用例。提交 `3caefd671`、`55d0c99e2`。 - [x] 3. `binding.rs` 的 `GameCreationAppAssetKind` 导入只在测试里用到。已加 `#[cfg(test)]`,正式构建不再报未使用导入。提交 `d07ea186f`。 - [x] 4. UI 原型桥接与 UI 工作流的 kind 校验仍在比较 `ui-prototype`,而 manifest 写入侧已用正式枚举。已统一为 `GameCreationAppAssetKind::UiDesign` / `ui-design`,路径常量保持原样。提交 `a19319d81`、`c2da8e184`。 - [x] 5. 图集切片读取侧校验与测试筛选仍比较旧字面量,导致平台图集切片登记无法短路、测试断言失真。已改为 `GameCreationAppAssetKind::Icon` 叠加 `assets/art-spritesheet-slices/` 路径判定。提交 `8b007c637`。 - [x] 6. 资源桥接、Codex 资源引用与 direct tool bridge 的测试 fixture 仍用字符串构造 `kind`。已改为 `Character`、`Icon`、`CharacterAnimation`、`Spec`、`UiDesign` 等枚举成员。提交 `30edfee00`、`f0a62c630`、`21dbbb4c3`。 - [x] 7. `ts-rs` 直连版本号未走 workspace 依赖。已在 `server-rs` workspace 统一声明并从 `shared-contracts` 引用。提交 `040f64648`。 - [x] 8. `sourceSubtype` / `source_subtype` 等字符串字段接收枚举时类型不匹配。已显式 `to_string()`,不改字段语义。提交 `46dfa2cff`、`3907a8bf7`。 - [x] 9. 上传资源 kind 测试仍断言旧的 `document` / `asset`,且把枚举传给字符串集合。已改为 `font` / `unknown` 与 `kind.as_str()`。提交 `39e33f7a5`。 - [x] 10. 资源引用入口的源码正则仍匹配旧的 `subtype || category` 形状。已更新为匹配 `parseGameCreationAppAssetKind(selectedResource.subtype, ...)`,对应用例已单跑通过。提交 `512f669f5`。 - [x] 11. review 第 9 条(绑定测试应断言单引号)经核实是误报:`exports_ui_editor_types` 会先用 ts-rs 把绑定就地重写成双引号原始格式再读取,单引号断言会让该测试失败。已回退,恢复双引号断言并验证通过。提交 `2a75a2d2c`。 - [x] 12. review 关于 `ts(export_to)` 会被当成目录、生成到 `GameCreationAppAssetKind.ts/GameCreationAppAssetKind.ts` 的推断经核实不成立:实际落点就是 `apps/ai-game-creator-shell/src/contracts/generated/GameCreationAppAssetKind.ts`,与提交文件一致。 - [x] 13. 图集切片读取侧与写入侧词汇不一致。现状:写入侧切片的 manifest kind 已是正式成员,读取侧却仍在比较平台/工作流标识(`art-spritesheet-slice`),判定恒不成立,切片美术列表会返回空、切片链路失效。修复:切片登记与读取统一按 `GameCreationAppAssetKind::Icon`,切片与普通图标靠 `assets/art-spritesheet-slices/` 路径前缀区分。提交 `a61b0cce8`。 - [x] 14. 陶泥儿美术资产身份比对错用了字符串。现状:`direct_taonier_art_asset_identity` 拿 `"art-spritesheet"` / `"game-background"` 去比枚举字段,除已是 canonical 的 `icon-spec` 外全部恒不匹配,整包校验与恢复校验会失败。修复:函数签名改成 `expected_kind: GameCreationAppAssetKind`,调用点与 fixture 统一传 `IconSpec` / `Scene` / `IconSpritesheet`;同一提交里直连游戏工程产物的 `game-entry` / `game-script` / `game-style` / `game-package` / `game-lockfile` / `game-build-config` / `game-source` 也收敛为正式成员 `Code`。提交 `a61b0cce8`。 - [x] 15. 非 canonical manifest kind 字面量审计。现状:真正的问题不是「字面量多」,而是写入边界没有把平台请求词汇转成正式成员,读取侧还拿平台词汇去比枚举字段。修复:`assets.rs` 画板导出推断直接返回枚举并删掉兜底归一;`commands.rs` 登记边界按上下文解析 kind;`canvas_generation.rs` 新增 `platform_art_asset_manifest_kind`,把 `ui-prototype` / `art-spritesheet` / `game-background` / `game-art` 等平台词汇显式映射为正式成员;`manifest.rs` 的必填视觉资产校验此前拿 `ui-prototype` / `art-spritesheet` 去比枚举字段(真实 bug,恒不匹配),已改为 `IconSpec` / `UiDesign` / `IconSpritesheet`;`project_gates.rs`、`autonomous_policy.rs`、`recovery_scan.rs`、`direct_tool_bridge.rs`、`ui_editor/*` 与测试 fixture 同步收敛。原文举的 `tool_policy_snapshot.rs` 不成立:该文件只列工具名,没有 kind 列表。剩余字面量都在平台请求字段与 JSON 载荷里,不再进 manifest。提交 `a61b0cce8`。 - [x] 16. `GameCreationAppAssetManifestEntry.kind` 由 `String` 改成枚举是公开 Rust 类型的破坏性变更。现状:分支里已经按类型收紧落地,没有 `String` 版本;本次不写历史兼容代码、不做数据迁移、不写兼容测试,写入侧只接受枚举成员,未知输入仍按读边界收口 `Unknown`。修复/说明:把这次破坏性变更写进实施计划的「已落地 / 明确不修改」两节;版本策略与对外变更说明由你决定,我没有自行宣布任何兼容或迁移策略。提交 `7eee89ded`。 - [x] 17. `source_subtype` 与资源 kind 字段语义混用(原文:会把 `art-image`、`svg`、`text`、`project-version`、`agent-result-derivative` 传进 kind)。现状:非正式成员会被收口成 `Unknown`,项目版本与 Agent 回执在冒充 manifest kind。修复:新增 `ResourceEditSourceKind`(`Manifest(GameCreationAppAssetKind)` / `ProjectVersion` / `AgentResultText`),快照字段改收该枚举;前端 `sourceSubtype` 只传正式枚举成员,非 manifest 来源传 `null`;栅格源归一化只认正式成员(删掉 `task-artifact` 特判,未知按 `Image` 收口);账本、HTTP 载荷与提示词边界用 `as_str()`,写回 manifest 用 `manifest_kind()`。提交 `f185d21f5`、`f9bc2d917`。 - [x] 18. 你说的「没看到这个文件」——它是 `apps/ai-game-creator-shell/src/contracts/assetKind.ts`(资源 kind 的前端契约入口,不在 `view/` 目录里,平时不会翻到)。现状:`GAME_CREATION_APP_ASSET_KINDS` 是手写字面量列表,与生成的 union 各写一份,且已包含生成侧才有的 `font` / `unknown`,两边会再次分叉。修复:改成 `GAME_CREATION_APP_ASSET_KIND_MEMBERS: Record<GameCreationAppAssetKind, true>` 常量表,集合与新增的 `isGameCreationAppAssetKind` 类型守卫都由它派生;生成 union 增删成员时 TS 会直接编译报错,列表没法再悄悄漂移。提交 `f9bc2d917`。 - [x] 19. `BindingChange` / `BindingDTO` 不是凭空出现的名字:它们是 `apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/binding.rs` 里真实的内部结构(LLM 组件绑定响应体)。原文的问题是那个手写测试 `exports_ui_editor_types`:它用 ts-rs 把这两个结构导出到已退役的 `src/features/ui-editor/types/`,并顺手把 `src/contracts/generated/GameCreationAppAssetKind.ts` 就地重写成生成器原始格式——测试自己重写文件,既发现不了漂移又污染工作树。修复:删掉该测试与那套额外的类型导出(退役类型不再导出,前端消费方已删),生成只走 `cargo test export_bindings`;枚举自带 `#[ts(export, export_to = .../src/contracts/generated/)]`;生成的 `src/contracts/generated/` 加入 `.prettierignore` 与 eslint `ignorePatterns`,让 ts-rs 原始格式保持幂等、跑完不污染工作树。提交 `b96cd4b7c`。 - [x] 20. 顺带修掉 `apps/ai-game-creator-shell/tests/assetKindCanonicalMapping.test.ts` 两条在改动前就已经恒失败的用例:解析 Rust canonical 目录的正则只认裸字符串字面量,认不出 `GAME_CREATION_APP_UI_DESIGN_DOC_ASSET_KIND` 这类常量引用,于是「两侧 canonical kind 目录一致」永远少一项;现在解析前先把 `pub const *_ASSET_KIND: &str = "..."` 展开成字面量,并删掉测试体里游离的 `'font',` 表达式。提交 `f9bc2d917`。
k88936 added 5 commits 2026-09-16 19:38:58 +08:00
- assets.rs:`register_local_asset_at` / `register_local_asset_entry` 改为接收 `GameCreationAppAssetKind`,画板导入与画板同步在边界解析 kind
- assets.rs:`infer_canvas_export_asset_kind` 直接返回枚举成员,去掉仅供兜底的 canonical 归一
- commands.rs:资源登记按 `asset.register` 上下文解析 kind,字体导入写 `Font`,本地文件类型表与平台导入归一改用枚举
- direct_runtime.rs:直连游戏工程产物统一写 `Code`,图集切片读取按 `Icon` 叠加切片路径判定,陶泥儿美术身份改收枚举
- canvas_generation.rs:新增 `platform_art_asset_manifest_kind` 收口平台美术请求词汇,切片登记 category 改用 `Icon.as_str()`
- manifest.rs:必填视觉资产校验改用 `IconSpec` / `UiDesign` / `IconSpritesheet`,修正此前与写入侧对不上的比对
- project_gates.rs、autonomous_policy.rs、recovery_scan.rs、direct_tool_bridge.rs、ui_editor workflow/persistence/resource_bridge:读取侧与 fixture 改用正式枚举成员
- tests:资源相关 fixture 与断言改用正式枚举成员
- resource_editor.rs:新增 `ResourceEditSourceKind`,把源身份拆成 `Manifest(GameCreationAppAssetKind)` / `ProjectVersion` / `AgentResultText`
- resource_editor.rs:`ResourceEditSourceSnapshot.asset_kind` 由 `String` 收紧为该枚举,项目版本与 Agent 回执不再冒充 manifest kind
- resource_editor.rs:`infer_resource_edit_source_asset_kind` 直接返回枚举成员,`art-image` / `svg` / `text` 收口为 `Image` / `Image` / `Document`
- resource_editor.rs:栅格源归一化只接受正式枚举成员,`task-artifact` 特判删除,未知值按 `Image` 收口
- resource_editor.rs:账本、HTTP 载荷与提示词边界改用 `as_str()`,manifest 写回改用 `manifest_kind()`
- resource_editor.rs:`source_subtype` 字段补充「只接受 manifest 正式 kind」的文档说明,测试 fixture 同步改用枚举成员
- asset_kind.rs:`GameCreationAppAssetKind` 自带 `#[ts(export, export_to = ../apps/ai-game-creator-shell/src/contracts/generated/)]`,`cargo test export_bindings` 即可复现生成文件
- binding.rs:删除手写的 `exports_ui_editor_types` 测试,不再由测试就地重写生成文件或重建退役类型
- binding.rs:`BindingChange` / `BindingDTO` 去掉 `TS` derive 与 `ts(export_to)`,只作为内部结构使用,不再导出退役的前端绑定
- binding.rs:清理仅为该测试存在的 `ts_rs` / `GameCreationAppAssetKind` 导入
- .prettierignore、.eslintrc.cjs:忽略 `src/contracts/generated/`,保留 ts-rs 原始格式使生成幂等且不污染工作树
- GameCreationAppAssetKind.ts:按生成器原始格式更新(与上述路径一致,无内容漂移)
- assetKind.ts:新增 `GAME_CREATION_APP_ASSET_KIND_MEMBERS: Record<GameCreationAppAssetKind, true>`,生成 union 增删成员时会直接编译报错
- assetKind.ts:`GAME_CREATION_APP_ASSET_KINDS` 由该表派生,不再手写第二份字面量列表
- assetKind.ts:新增 `isGameCreationAppAssetKind` 类型守卫,`parseGameCreationAppAssetKind` 复用它
- view/project-development/index.tsx:资源引用的 `sourceSubtype` 只传正式 kind 成员,任务产物等非 manifest 来源传 `null`
- tests/assetKindCanonicalMapping.test.ts:两侧 kind 目录比对前先展开 Rust 常量引用(`ui-design-doc` 是常量),修正此前恒失败的两条;删除测试体里游离的 `'font',` 表达式
同步 AGC 资源 kind 枚举化的实施计划、里程碑与扫描清单
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 5m22s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 5m16s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 5m4s
Project CI / Backend tests (pull_request) Failing after 10s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m39s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 4m40s
Project CI / Repository checks (pull_request) Failing after 11s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m1s
Project CI / AI game creator shell web tests (pull_request) Successful in 3m3s
Project CI / Frontend tests (pull_request) Successful in 4m35s
Project CI / Native shell tests (pull_request) Successful in 6m44s
7eee89ded3
- 实施计划:记录已落地内容(kind 由 `String` 收紧为枚举的破坏性变更、写入与读取统一正式成员、资源编辑源身份词汇表、`cargo test export_bindings` 生成路径、TS 穷举派生)
- 实施计划:修正「明确不修改」与验证命令,去掉与当前代码不符的表述
- 里程碑:验收标准除旧 alias 读边界一项外全部勾选,并补记 ts-rs 生成与退役类型导出两项证据
- 扫描清单:把「当前未决项」逐条落成结论(`asset`、`art-spritesheet*`、`game-*`、`ui*`、`Unknown` trace、生成路径),只保留 CI verify 接入一项待办
k88936 added 1 commit 2026-09-16 22:08:26 +08:00
合并 origin/master 并收敛 DirectProject 引用渲染到 canonical user item
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 7m17s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 7m15s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 7m45s
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Failing after 7m59s
Project CI / Backend tests (pull_request) Failing after 10s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m8s
Project CI / Repository checks (pull_request) Failing after 9s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m48s
Project CI / AI game creator shell web tests (pull_request) Successful in 6m24s
Project CI / Frontend tests (pull_request) Successful in 15m29s
Project CI / Native shell tests (pull_request) Successful in 19m38s
a4296a4bdd
- .eslintrc.cjs 冲突取双方 ignore 并集,保留 contracts/generated/** 与 project-workspace/generated/**。
- 实施计划文档冲突保留双方内容:2026-09-15 资源 kind 枚举化权威口径与 master 新增计划段并存。
- resourceReferences.ts 冲突合并双方 import:kind 解析入口与 canonical DirectCodexUserItem 类型同时保留。
- project-development.suite.ts 冲突合并双方 import:UI 设计文档 kind/mediaType 常量与 ProjectSupervisorView 同时保留。
- decision-log.md 冲突取双方条目,并补记 DirectProject 引用渲染收敛到 canonical user item 的决策。
- 接受 master 退役 agent/direct_codex_references.rs,把 UI 设计文档引用生成代码上下文的 prompt 注入迁入 agent/direct_codex_user_item/wire.rs。
- assets.rs 资源登记 kind 参数收紧为 GameCreationAppAssetKind,相应测试 fixture 改用正式枚举成员。
- 同步 project-memory 实施计划、里程碑与扫描清单中的模块路径。
k88936 added 9 commits 2026-09-17 13:07:38 +08:00
- ResourceReferenceInput 缩略图:删掉 `kind === 'ui'` 判断与只服务它的 `kind` 变量,UI 设计文档仍由 `mediaType === 'application/json'` 识别。
- 理由:manifest kind 由 Rust 枚举序列化,只会是 canonical 成员或 `unknown`,该分支永远无法命中。
- assetKind.ts:非字符串输入不再走 `String(raw)` 字符串化,改为记录 `rawType` 并直接收口为 `unknown`。
- assetKind.test.ts:新增非字符串输入用例,钉住新的日志形状。
- Cargo.toml:`[build-dependencies]` 的 shared-contracts 去掉 `features = ["ts-bindings"]`,只保留 `[dependencies]` 那份。
- build.rs 只用 `GameCreationAppAgentGroup` 与 `new_game_creation_app_seed_tasks`,不需要 ts-rs 导出,没必要让构建脚本图额外编译 ts-rs。
- direct_tools_mcp.rs:`agc_list_registered_assets` 的 kind 过滤示例把旧值 `art-spritesheet-slice` 换成 canonical 的 `icon-spritesheet`。
- 理由:manifest kind 收紧为枚举后,旧值在过滤前已收口为 `unknown`,按示例传参只会得到空结果。
- packages/shared:新增 `GAME_CREATION_APP_UI_DESIGN_ASSET_KIND`(`ui-design`)并让 canonical kind 列表与分类表引用它,避免散落裸字符串。
- project-development/index.tsx:`openResourceUiEditor` 与 `selectedResourceOpensUiEditor` 的原型判断由旧值 `ui-prototype` 改为该常量,恢复原型图的「UI 编辑器」入口。
- resourceProjectionModel.ts:`isPendingUiPrototype` 同步改用该常量,恢复待视觉验收标注。
- project-development.suite.ts:候选界面图 fixture 改用 canonical kind,并补一条原型图打开 UI 编辑器桥接的回归用例(去掉修正即转红)。
- uiDesignResourceBridge.ts:原型 kind 比较由裸字符串 `'ui-design'` 改为 `GAME_CREATION_APP_UI_DESIGN_ASSET_KIND`,与 manifest kind 契约保持同一处定义。
- direct_runtime/mod.rs:`direct_game_sources_referenced_taonier_assets` 的 manifest 兜底由 `art-spritesheet | art-spritesheet-slice | game-background` 改为 `IconSpritesheet | Icon | Scene`,恢复对项目自定义图集与背景的收录。
- direct_runtime/mod.rs:同处与 `direct_registered_taonier_runtime_image_paths` 的「切片不得绕过严格校验」排除条件改用 `GameCreationAppAssetKind::Icon`,并顺手把 `icon-spec` 比较改为枚举成员。
- 理由:kind 收紧为枚举后 `as_str()` 只会返回 canonical 名,旧字面量恒不命中,兜底筛选与切片排除同时失效。
- ui_editor/resource_bridge.rs:`next_ui_design_path` 提升为 `pub(crate)` 并补注释,作为两个写入侧唯一的「UI 设计 N」命名规则。
- commands.rs:`create_ui_design_resource` 不再按已登记文档数直接取名,改为复用该规则,resourceId 与文件名同一编号。
- tests/project.rs:新增已存在 `ui/UI 设计 1.json` 时仍能创建并落到编号 2 的回归用例。
清理项目视觉资产判断里已不可达的旧 kind 字面量
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 4m58s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 4m44s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 4m26s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m3s
Project CI / Backend tests (pull_request) Failing after 10s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 4m0s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m50s
Project CI / Repository checks (pull_request) Failing after 14s
Project CI / Frontend tests (pull_request) Successful in 6m3s
Project CI / AI game creator shell web tests (pull_request) Successful in 6m3s
Project CI / Native shell tests (pull_request) Successful in 11m11s
56c4faa8ee
- projectAssetSummaries.ts:`isProjectVisualAsset` 去掉 `sprite` / `ui` / `background` 三个旧 kind 判断。
- 理由:manifest kind 由 Rust 枚举序列化,只会是 canonical 成员或 `unknown`,这三个旧字面量在 TS 侧永远无法命中;图像与视频资产仍由 mediaType 分支覆盖。
Author
Member

本分支把 manifest 的 kindString 收紧成 Rust 枚举 GameCreationAppAssetKindserver-rs/crates/shared-contracts/src/game_creation_app/asset_kind.rs),
TS 侧经 ts-rs 生成同名 union;from_str_lossy精确匹配、无 trim/无别名表,不认识的值一律落 Unknown,回写时序列化成 "unknown"
技术方案 docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md(2026-09-15 节)写明**"不为旧本地 manifest 提供 migration、alias 兼容或静默转换"
所以「旧 manifest 里的 "UI" / "ui-prototype" / "art-spritesheet" 读不到」这一族现象是
既定口径**,我按"不是缺陷"处理;但其中会引起运行中门禁失败静默丢数据的,我单独标出来请你决定。
另外 review 里的示例补丁不一定可用,第 6 条我实际核对后推翻了它给的修法。

一、原 review 清单(保持原文件顺序,编号即条目号)

  • 1. ResourceReferenceInput.tsx:1316-1317 缩略图里残留 kind === 'ui' —— 已修复(faab31812

    • 原实现:资源引用缩略图的判断写成 kind === 'ui' || mediaType === GAME_CREATION_APP_UI_DESIGN_DOC_MEDIA_TYPE,靠前者把 UI 设计 JSON 当文本预览。
    • 问题:成立。kind 现在由 Rust 枚举序列化,只会是 canonical 成员或 unknown,上层又经 parseGameCreationAppAssetKind 收口,'ui' 恒不命中,是死分支。
    • 已做:删掉 kind === 'ui' 与只为它取值的 kind 变量;UI 设计文档仍由 mediaType === application/json 命中,行为不变。
  • 5. uiDesignResourceBridge.ts:93-96 裸字符串 'ui-design' —— 已修复(9dccf5318

    • 原实现:TS 侧直接写 asset.kind === 'ui-design'
    • 问题:成立(可维护性)。该 kind 在 packages/shared 里已有唯一定义,再手写一份裸字符串会与 Rust 枚举静默漂移。
    • 已做:改用共享常量 GAME_CREATION_APP_UI_DESIGN_ASSET_KIND(该常量在 f21638161 中新增,供 TS 侧统一引用)。
  • 6. asset_kind.rs:88-89 from_str_lossy 不 trim / 不 lowercase —— 不修(真问题,但给的修法不对)

    • 当前实现:match value { "image" => Self::Image, ... _ => Self::Unknown },纯字面量、大小写敏感、不 trim;parse_with_contextUnknown 时打 warn。
    • 判定:部分成立,而且 review 给的补丁修不好它自己举的例子。 canonical_game_creation_app_asset_kindtrim().to_lowercase() 加别名表;只加 lowercase 时 "UI" 会归一成 "ui",而 "ui" 仍不是 canonical 值(canonical 是 ui-design),照样落 Unknown。要修 "UI",需要的是别名表,不是 lowercase。
    • 若要改(破坏性,需你决定):(a) 维持现状,把 Unknown 当"不在本客户端词汇表"的显式信号;(b) 只做 trim+lowercase 纯归一化(风险最小,但修不了 "UI");(c) 让 from_str_lossy 复用 canonical_game_creation_app_asset_kind,等于恢复旧兼容并推翻既定口径。选哪个都要同步改技术方案。
  • 7. asset_kind.rs:53-54 Font 与 canonical 列表分叉 —— 不修(真问题,需口径决策)

    • 当前实现:Rust 枚举有 Fontas_str() == "font");但 TS 的 GAME_CREATION_APP_CANONICAL_ASSET_KINDS(17 项)不含 fontcanonical_game_creation_app_asset_kind("font") 仍按别名映射到 document;而 AGC 上传路径 assets.rs::uploaded_asset_kind 对字体文件(font/*ttf/otf/woff/woff2)真的会写出 GameCreationAppAssetKind::Font
    • 判定:成立,且比 review 说的更硬——是本分支自己造的分叉:写侧落 font,读侧 canonical 口径却是 document,TS canonical 集合里也没有 font。(分类结果目前仍正确,因为 font → document;坏的是"落盘值集合"与"canonical 集合"不一致。)
    • 若要改(涉及契约):二选一并成对改——要么把 font 提升为 canonical(补 TS 列表、分类表、assetKindCanonicalMapping.test.ts 交叉钉住),要么删掉 Font 成员让上传继续写 document
  • 8. src/contracts/assetKind.ts:55 非字符串入参被 String(raw) 字符串化 —— 已修复(d333f783f

    • 原实现:先 String(raw) 再记 rawKind,于是 null / undefined / 对象会打成 "null" / "undefined" / "[object Object]",与"真的未知字符串"无法区分。
    • 问题:成立
    • 已做:非字符串直接收口 unknown 并单独记 rawType 日志,补了 assetKind.test.ts 用例钉住新日志形状。
  • 9. src-tauri/Cargo.toml:17 [build-dependencies] 打开 ts-bindings —— 已修复(a5ee45aa4

    • 原实现:[build-dependencies]shared-contractsfeatures = ["ts-bindings"],而 build.rs 只用 GameCreationAppAgentGroupnew_game_creation_app_seed_tasks,用不到 ts-rs。
    • 问题:成立:多出的 feature 让构建脚本依赖图额外编译 ts-rs,等于在正式依赖图之外多一次导出入口。
    • 已做:只去掉 build-dep 上的 feature,[dependencies] 保留;已核验 cargo check --locked 通过,且 cargo test -p shared-contracts --features ts-bindings 仍能重新生成同一份绑定(无 diff)。
  • 10. direct_tool_bridge.rs:1247-1248 + direct_tools_mcp.rs 示例 —— 部分修复(示例已修 d454d3fa4

    • 当前实现:asset.listkind 入参经 parse_with_context 收口成枚举,再 kind.is_none_or(|kind| asset.kind == kind) 过滤;未知值落 Unknown,于是"过滤出 0 条"而不是报错。
    • 判定:示例文案部分成立(旧值 art-spritesheet-slice 在收口后恒不命中,已改成 canonical 的 icon-spritesheet);"未知值应报错"部分属行为变更,留给你。
    • 若要改:在 kind 收口处对 Unknown 直接 Err("asset.list.kind 不是已知 kind:…"),同步 MCP schema 描述,并补一条工具侧用例。注意 Unknown 本身是合法枚举成员,要区分"调用方传错值"与"真想查 unknown 资产"。
  • 11. direct_runtime/mod.rs:2741-2745 切片路径与兜底的旧字面量 —— 已修复(41930b858

    • 原实现:direct_registered_taonier_runtime_image_pathsasset.kind != "icon-spec"asset.kind == "art-spritesheet-slice" 这类旧字面量比较。
    • 问题:成立。kind 变枚举后 as_str() 只产出 canonical 名,旧字面量恒不命中,"切片必须走严格 manifest/receipt 校验、不得被弱兜底重新收录"的排除条件失效。补充事实:这在改枚举前(kind: String)是真的有效的,不是本来就死的代码。
    • 已做:改为枚举成员比较(IconSpecIcon),保留切片路径前缀条件。
  • 12. view/project-development/index.tsx:7473 原型图判断仍是 'ui-prototype' —— 已修复(f21638161

    • 原实现:工具栏 selectedResourceOpensUiEditoropenResourceUiEditorsubtype === 'ui-prototype' 判原型图,而同文件 ensureUiDesignResourceForPrototype 已要求 'ui-design'
    • 问题:成立且用户可见:canonical 原型 kind 是 ui-design,旧判断恒 false,原型图的「UI 编辑器」按钮不再出现。
    • 已做:改用新常量 GAME_CREATION_APP_UI_DESIGN_ASSET_KINDresourceProjectionModel.ts::isPendingUiPrototype 同步;fixture 改 canonical;补了回归用例「opens the UI editor bridge from a canonical ui-design prototype image」(去掉修正即转红,已实测),appSurface 全绿。
  • 14. commands.rs:2203-2206 新建 UI 设计资源编号撞车 —— 已修复(d23c80837

    • 原实现:create_ui_design_resource 用"已登记的 UI 设计文档数 + 1"取名/编号(ui/UI 设计 N.jsonresourceId: ui:N),而统计只算 canonical ui-design-doc
    • 问题:成立:命中不了旧 "UI" 存量时编号从 1 重开,与已有文件撞名,命令报「UI 设计资源路径已存在」。
    • 已做:复用 ui_editor::resource_bridge::next_ui_design_path(提升为 pub(crate))做无冲突扫描,resourceId 与文件名取同一编号;补「已存在 ui/UI 设计 1.json 时落到编号 2」用例。
    • 注意边界:这条修的是"命名规则不再写两份 + 不再撞名",不是把旧 "UI" 纳入统计(旧存量仍不参与编号,只是不会再撞车)。
  • 15. assets.rs:922-927 画板同步的 assetKind 未 canonical 化 —— 不修(真问题,属口径)

    • 当前实现:画板资源同步直接 GameCreationAppAssetKind::parse_with_context(value, "canvas.asset_sync");而同类平台入口 commands.rs::imported_platform_asset_kind canonical_game_creation_app_asset_kind(kind) from_str_lossy(有测试钉着 Some("UI") == UiDesign)。
    • 判定:方向成立:同一份"平台外部词汇"在两个入口被两种口径处理。旧值(ui-prototype / game-background / UI / art-spritesheet)经 imported_platform_asset_kind 会收口成 canonical,经这条路会落 Unknown,分类随后掉到 unclassified(改枚举前这里能派生出 ui-interaction / scene)。
    • 为什么没动:它和"要不要为外部/存量词汇保留 canonical 收口"是同一个口径问题(与第 6、17 条同源)。单点改会让两个平台入口一致、却和"反序列化不收口"形成更细的不一致,建议口径一次定完再动。改法:把 assets.rs 这条路改为走 imported_platform_asset_kind,或抽一个 platform_asset_kind_from_external 公共函数。
  • 18. direct_runtime/mod.rs:2743-2745 兄弟筛选仍用旧字面量 —— 已修复(41930b858,与第 11 条同一提交)

    • 原实现:direct_registered_taonier_runtime_image_paths 的切片排除、direct_game_sources_referenced_taonier_assetsmatches!(kind.as_str(), "art-spritesheet" | "art-spritesheet-slice" | "game-background") 兜底都还是旧字面量。
    • 问题:成立:canonical 化后这些比较恒不命中,项目自定义图集/背景的兜底变死代码,切片还可能被更弱的像素兜底重新收录。
    • 已做:兜底改为 IconSpritesheet | Icon | Sceneicon-spec 比较与切片排除一并换成枚举成员;agent::direct_runtime 模块 95 条用例通过。

二、附:本轮额外发现(不在原 review.txt 内)

  • 19. project-summary/projectAssetSummaries.ts::isProjectVisualAsset 残留旧 kind 字面量 —— 已修复(56c4faa8e

    • 原实现:kind === 'sprite' || kind === 'ui' || kind === 'background' 参与「项目视觉资产」判定(/art 摘要用它筛资产)。
    • 判定:成立,与第 1 条同类的死分支。Rust 侧 GameCreationAppAssetManifestEntry.kind 已是枚举、from_str_lossy 精确匹配,落盘值只能是 canonical 成员或 unknown,TS 拿不到 sprite / ui / background
    • 已做:删掉这三个字面量(图像/视频仍由 mediaType 分支覆盖);它们本来就是死代码,删除不改变行为。
  • 20. direct_runtime/mod.rs 切片路径前缀判断冗余(review 在第 11 条顺带提到)—— 不修(可读性,非缺陷)

    • 当前实现:direct_registered_taonier_slice_paths 先用 asset.local_path == slice.path 做身份匹配,再叠一个 starts_with("assets/art-spritesheet-slices/")
    • 判定:现象成立但无害(我核对过:切片来自固定路径的切片清单,validated_art_slices 产出的路径带该前缀,所以第二次判断恒真)。
    • 建议:保留当防御性冗余、或删掉靠路径相等唯一识别,都行;属可选清理,本轮不动。
本分支把 manifest 的 `kind` 从 `String` 收紧成 Rust 枚举 `GameCreationAppAssetKind`(`server-rs/crates/shared-contracts/src/game_creation_app/asset_kind.rs`), TS 侧经 ts-rs 生成同名 union;`from_str_lossy` 是**精确匹配、无 trim/无别名表**,不认识的值一律落 `Unknown`,回写时序列化成 `"unknown"`。 技术方案 `docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md`(2026-09-15 节)写明**"不为旧本地 manifest 提供 migration、alias 兼容或静默转换"**。 所以「旧 manifest 里的 `"UI"` / `"ui-prototype"` / `"art-spritesheet"` 读不到」这一族现象是**既定口径**,我按"不是缺陷"处理;但其中会引起**运行中门禁失败**或**静默丢数据**的,我单独标出来请你决定。 另外 review 里的示例补丁不一定可用,第 6 条我实际核对后推翻了它给的修法。 ## 一、原 review 清单(保持原文件顺序,编号即条目号) - [x] 1. `ResourceReferenceInput.tsx:1316-1317` 缩略图里残留 `kind === 'ui'` —— 已修复(`faab31812`) - 原实现:资源引用缩略图的判断写成 `kind === 'ui' || mediaType === GAME_CREATION_APP_UI_DESIGN_DOC_MEDIA_TYPE`,靠前者把 UI 设计 JSON 当文本预览。 - 问题:**成立**。kind 现在由 Rust 枚举序列化,只会是 canonical 成员或 `unknown`,上层又经 `parseGameCreationAppAssetKind` 收口,`'ui'` 恒不命中,是死分支。 - 已做:删掉 `kind === 'ui'` 与只为它取值的 `kind` 变量;UI 设计文档仍由 `mediaType === application/json` 命中,行为不变。 - [x] 5. `uiDesignResourceBridge.ts:93-96` 裸字符串 `'ui-design'` —— 已修复(`9dccf5318`) - 原实现:TS 侧直接写 `asset.kind === 'ui-design'`。 - 问题:**成立**(可维护性)。该 kind 在 `packages/shared` 里已有唯一定义,再手写一份裸字符串会与 Rust 枚举静默漂移。 - 已做:改用共享常量 `GAME_CREATION_APP_UI_DESIGN_ASSET_KIND`(该常量在 `f21638161` 中新增,供 TS 侧统一引用)。 - [x] 6. `asset_kind.rs:88-89` `from_str_lossy` 不 trim / 不 lowercase —— 不修(真问题,但给的修法不对) - 当前实现:`match value { "image" => Self::Image, ... _ => Self::Unknown }`,纯字面量、大小写敏感、不 trim;`parse_with_context` 落 `Unknown` 时打 warn。 - 判定:**部分成立,而且 review 给的补丁修不好它自己举的例子。** `canonical_game_creation_app_asset_kind` 是 `trim().to_lowercase()` **加别名表**;只加 lowercase 时 `"UI"` 会归一成 `"ui"`,而 `"ui"` 仍不是 canonical 值(canonical 是 `ui-design`),照样落 `Unknown`。要修 `"UI"`,需要的是别名表,不是 lowercase。 - 若要改(破坏性,需你决定):(a) 维持现状,把 `Unknown` 当"不在本客户端词汇表"的显式信号;(b) 只做 trim+lowercase 纯归一化(风险最小,但修不了 `"UI"`);(c) 让 `from_str_lossy` 复用 `canonical_game_creation_app_asset_kind`,等于恢复旧兼容并推翻既定口径。选哪个都要同步改技术方案。 - [x] 7. `asset_kind.rs:53-54` `Font` 与 canonical 列表分叉 —— 不修(真问题,需口径决策) - 当前实现:Rust 枚举有 `Font`(`as_str() == "font"`);但 TS 的 `GAME_CREATION_APP_CANONICAL_ASSET_KINDS`(17 项)**不含 `font`**,`canonical_game_creation_app_asset_kind("font")` 仍按别名映射到 `document`;而 AGC 上传路径 `assets.rs::uploaded_asset_kind` 对字体文件(`font/*`、`ttf/otf/woff/woff2`)真的会写出 `GameCreationAppAssetKind::Font`。 - 判定:**成立,且比 review 说的更硬**——是本分支自己造的分叉:写侧落 `font`,读侧 canonical 口径却是 `document`,TS canonical 集合里也没有 `font`。(分类结果目前仍正确,因为 `font → document`;坏的是"落盘值集合"与"canonical 集合"不一致。) - 若要改(涉及契约):二选一并成对改——要么把 `font` 提升为 canonical(补 TS 列表、分类表、`assetKindCanonicalMapping.test.ts` 交叉钉住),要么删掉 `Font` 成员让上传继续写 `document`。 - [x] 8. `src/contracts/assetKind.ts:55` 非字符串入参被 `String(raw)` 字符串化 —— 已修复(`d333f783f`) - 原实现:先 `String(raw)` 再记 `rawKind`,于是 `null` / `undefined` / 对象会打成 `"null"` / `"undefined"` / `"[object Object]"`,与"真的未知字符串"无法区分。 - 问题:**成立**。 - 已做:非字符串直接收口 `unknown` 并单独记 `rawType` 日志,补了 `assetKind.test.ts` 用例钉住新日志形状。 - [x] 9. `src-tauri/Cargo.toml:17` `[build-dependencies]` 打开 `ts-bindings` —— 已修复(`a5ee45aa4`) - 原实现:`[build-dependencies]` 的 `shared-contracts` 带 `features = ["ts-bindings"]`,而 `build.rs` 只用 `GameCreationAppAgentGroup` 与 `new_game_creation_app_seed_tasks`,用不到 ts-rs。 - 问题:**成立**:多出的 feature 让构建脚本依赖图额外编译 ts-rs,等于在正式依赖图之外多一次导出入口。 - 已做:只去掉 build-dep 上的 feature,`[dependencies]` 保留;已核验 `cargo check --locked` 通过,且 `cargo test -p shared-contracts --features ts-bindings` 仍能重新生成同一份绑定(无 diff)。 - [x] 10. `direct_tool_bridge.rs:1247-1248` + `direct_tools_mcp.rs` 示例 —— **部分修复**(示例已修 `d454d3fa4`) - 当前实现:`asset.list` 把 `kind` 入参经 `parse_with_context` 收口成枚举,再 `kind.is_none_or(|kind| asset.kind == kind)` 过滤;未知值落 `Unknown`,于是"过滤出 0 条"而不是报错。 - 判定:**示例文案部分成立**(旧值 `art-spritesheet-slice` 在收口后恒不命中,已改成 canonical 的 `icon-spritesheet`);**"未知值应报错"部分属行为变更**,留给你。 - 若要改:在 `kind` 收口处对 `Unknown` 直接 `Err("asset.list.kind 不是已知 kind:…")`,同步 MCP schema 描述,并补一条工具侧用例。注意 `Unknown` 本身是合法枚举成员,要区分"调用方传错值"与"真想查 unknown 资产"。 - [x] 11. `direct_runtime/mod.rs:2741-2745` 切片路径与兜底的旧字面量 —— 已修复(`41930b858`) - 原实现:`direct_registered_taonier_runtime_image_paths` 用 `asset.kind != "icon-spec"`、`asset.kind == "art-spritesheet-slice"` 这类旧字面量比较。 - 问题:**成立**。kind 变枚举后 `as_str()` 只产出 canonical 名,旧字面量恒不命中,"切片必须走严格 manifest/receipt 校验、不得被弱兜底重新收录"的排除条件失效。补充事实:**这在改枚举前(`kind: String`)是真的有效的**,不是本来就死的代码。 - 已做:改为枚举成员比较(`IconSpec`、`Icon`),保留切片路径前缀条件。 - [x] 12. `view/project-development/index.tsx:7473` 原型图判断仍是 `'ui-prototype'` —— 已修复(`f21638161`) - 原实现:工具栏 `selectedResourceOpensUiEditor` 与 `openResourceUiEditor` 用 `subtype === 'ui-prototype'` 判原型图,而同文件 `ensureUiDesignResourceForPrototype` 已要求 `'ui-design'`。 - 问题:**成立且用户可见**:canonical 原型 kind 是 `ui-design`,旧判断恒 false,原型图的「UI 编辑器」按钮不再出现。 - 已做:改用新常量 `GAME_CREATION_APP_UI_DESIGN_ASSET_KIND`;`resourceProjectionModel.ts::isPendingUiPrototype` 同步;fixture 改 canonical;补了回归用例「opens the UI editor bridge from a canonical ui-design prototype image」(去掉修正即转红,已实测),`appSurface` 全绿。 - [x] 14. `commands.rs:2203-2206` 新建 UI 设计资源编号撞车 —— 已修复(`d23c80837`) - 原实现:`create_ui_design_resource` 用"已登记的 UI 设计文档数 + 1"取名/编号(`ui/UI 设计 N.json`、`resourceId: ui:N`),而统计只算 canonical `ui-design-doc`。 - 问题:**成立**:命中不了旧 `"UI"` 存量时编号从 1 重开,与已有文件撞名,命令报「UI 设计资源路径已存在」。 - 已做:复用 `ui_editor::resource_bridge::next_ui_design_path`(提升为 `pub(crate)`)做无冲突扫描,`resourceId` 与文件名取同一编号;补「已存在 `ui/UI 设计 1.json` 时落到编号 2」用例。 - 注意边界:这条修的是"命名规则不再写两份 + 不再撞名",**不是**把旧 `"UI"` 纳入统计(旧存量仍不参与编号,只是不会再撞车)。 - [x] 15. `assets.rs:922-927` 画板同步的 `assetKind` 未 canonical 化 —— 不修(真问题,属口径) - 当前实现:画板资源同步直接 `GameCreationAppAssetKind::parse_with_context(value, "canvas.asset_sync")`;而同类平台入口 `commands.rs::imported_platform_asset_kind` 是**先** `canonical_game_creation_app_asset_kind(kind)` **再** `from_str_lossy`(有测试钉着 `Some("UI") == UiDesign`)。 - 判定:**方向成立**:同一份"平台外部词汇"在两个入口被两种口径处理。旧值(`ui-prototype` / `game-background` / `UI` / `art-spritesheet`)经 `imported_platform_asset_kind` 会收口成 canonical,经这条路会落 `Unknown`,分类随后掉到 `unclassified`(改枚举前这里能派生出 `ui-interaction` / `scene`)。 - 为什么没动:它和"要不要为外部/存量词汇保留 canonical 收口"是同一个口径问题(与第 6、17 条同源)。单点改会让两个平台入口一致、却和"反序列化不收口"形成更细的不一致,建议口径一次定完再动。改法:把 `assets.rs` 这条路改为走 `imported_platform_asset_kind`,或抽一个 `platform_asset_kind_from_external` 公共函数。 - [x] 18. `direct_runtime/mod.rs:2743-2745` 兄弟筛选仍用旧字面量 —— 已修复(`41930b858`,与第 11 条同一提交) - 原实现:`direct_registered_taonier_runtime_image_paths` 的切片排除、`direct_game_sources_referenced_taonier_assets` 的 `matches!(kind.as_str(), "art-spritesheet" | "art-spritesheet-slice" | "game-background")` 兜底都还是旧字面量。 - 问题:**成立**:canonical 化后这些比较恒不命中,项目自定义图集/背景的兜底变死代码,切片还可能被更弱的像素兜底重新收录。 - 已做:兜底改为 `IconSpritesheet | Icon | Scene`,`icon-spec` 比较与切片排除一并换成枚举成员;`agent::direct_runtime` 模块 95 条用例通过。 ## 二、附:本轮额外发现(不在原 review.txt 内) - [x] 19. `project-summary/projectAssetSummaries.ts::isProjectVisualAsset` 残留旧 kind 字面量 —— 已修复(`56c4faa8e`) - 原实现:`kind === 'sprite' || kind === 'ui' || kind === 'background'` 参与「项目视觉资产」判定(`/art` 摘要用它筛资产)。 - 判定:**成立**,与第 1 条同类的死分支。Rust 侧 `GameCreationAppAssetManifestEntry.kind` 已是枚举、`from_str_lossy` 精确匹配,落盘值只能是 canonical 成员或 `unknown`,TS 拿不到 `sprite` / `ui` / `background`。 - 已做:删掉这三个字面量(图像/视频仍由 `mediaType` 分支覆盖);它们本来就是死代码,删除不改变行为。 - [ ] 20. `direct_runtime/mod.rs` 切片路径前缀判断冗余(review 在第 11 条顺带提到)—— 不修(可读性,非缺陷) - 当前实现:`direct_registered_taonier_slice_paths` 先用 `asset.local_path == slice.path` 做身份匹配,再叠一个 `starts_with("assets/art-spritesheet-slices/")`。 - 判定:**现象成立但无害**(我核对过:切片来自固定路径的切片清单,`validated_art_slices` 产出的路径带该前缀,所以第二次判断恒真)。 - 建议:保留当防御性冗余、或删掉靠路径相等唯一识别,都行;属可选清理,本轮不动。
k88936 added 4 commits 2026-09-17 13:53:16 +08:00
- manifest.rs:读 manifest 时若存在 `unknown` kind,从原始 JSON 回捞 `assets[].kind` 原值,连同资产 ID、路径写进应用日志;同一原值每进程只记一次,避免刷屏。
- recovery_tests.rs:新增用例钉住回捞范围(只报非 canonical 值,跳过 canonical 与字面 `unknown`;结构异常返回空表)。
- commands.rs:`imported_platform_asset_kind` 收口平台 `assetKind` 时,非 canonical 原值一并留痕,供后续定位平台侧 legacy 写入点。
- shared-contracts/Cargo.toml:`ts-bindings` 不再顺带打开 `kind-observability`,改由 AGC 壳显式声明,日志开关不再随绑定需求被动启停。
- 口径:kind 保持严格解析(无 trim/lowercase、无别名表、无迁移),认不出的值一律收口 `unknown` 并留痕,不做 fallback。
- game_creation_app.rs:`GAME_CREATION_APP_CANONICAL_ASSET_KINDS` 加入 `font`(17 → 18 项),分类表补 `font → document`,删除 `"font" => "document"` 别名。
- gameCreationApp.ts:TS 侧同步加入 `font`、删除别名表条目、补 `font: 'document'` 分类,并同步别名表注释。
- 测试:两侧用例改为断言 `font` 是 canonical 成员(大小写仍不敏感)、栏目仍是 document。
- 理由:字体上传写入侧直接落 `font`,再把它当别名会让「落盘值集合」与「canonical 集合」分叉;严格解析下写入侧的值必须本身就是 canonical。
- direct_tool_bridge.rs:`kind` 收口后既不是 canonical、也不是字面 `unknown` 时直接返回工具错误并带上原值,不再静默过滤出空列表。
- direct_tool_bridge.rs:新增用例,钉住"项目访问前就报错"与"字面 `unknown` 仍是合法过滤值"。
- direct_tools_mcp.rs:schema 描述改为必须是 canonical kind、非 canonical 值会被拒绝。
Merge remote-tracking branch 'origin/master' into feat/agc-organize-assetkind
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 6m6s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 3m19s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 6m23s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 6m9s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 5m55s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m36s
Project CI / Repository checks (pull_request) Successful in 5m36s
Project CI / Frontend tests (pull_request) Failing after 7m10s
Project CI / Backend tests (pull_request) Successful in 13m10s
Project CI / Native shell tests (pull_request) Successful in 11m34s
Project CI / AI game creator shell web tests (pull_request) Successful in 5m38s
e6092dda6f
# Conflicts:
#	docs/project-memory/shared-memory/decision-log.md
k88936 marked the pull request as ready for review 2026-09-17 13:55:39 +08:00
k88936 requested review from suzmii 2026-09-17 13:55:49 +08:00
k88936 added 12 commits 2026-09-17 18:47:55 +08:00
- asset_kind.rs:新增声明宏,由一张 kind 表派生出枚举、线上值 as_str、ALL、严格解析与 ts-rs 绑定,仓库里不再有第二份 kind 列表。
- asset_kind.rs:from_str_lossy 改名 from_str_or_unknown 并去掉 trim / lowercase 归一,parse_with_context 只做严格等值匹配,认不出的原值不查别名、不迁移。
- asset_kind.rs:留痕改为可注册回调 set_non_canonical_asset_kind_reporter,把原始串与调用上下文交给壳层日志,未注册时静默。
- game_creation_app.rs:删除手写 GAME_CREATION_APP_CANONICAL_ASSET_KINDS 与 canonical_game_creation_app_asset_kind 别名表(含 font → document 特例),分类映射表按枚举成员穷举。
- shared-contracts/Cargo.toml:删除 kind-observability feature 与 tracing 依赖,留痕不再靠 tracing。
- api-server/editor_project.rs:图片编辑白名单注释改成「API 兼容面」,不再自称 kind 别名表。
- main.rs:新增 register_non_canonical_asset_kind_reporter(),把 shared-contracts 的原始串与上下文落到 app_log!,按 (原始串, 上下文) 去重;main() 启动时注册。
- commands.rs:imported_platform_asset_kind 改为直接 parse_with_context,不再先经别名表收口;用例改为断言 UI / ui / mystery / game-art / ui-prototype 等非 canonical 值一律落 unknown。
- assets.rs:画板/上传等用例的 kind 断言改用 GameCreationAppAssetKind::ALL 穷举口径。
- project/manifest.rs:读 manifest 的留痕去重键由「只有原始 kind」改成「原始 kind + 资产身份」,避免第二个写旧值的资产被静默吞掉。
- project/manifest.rs:from_str_lossy 调用点改名 from_str_or_unknown。
- agent/generation/canvas_generation.rs:画板 assetKind 的兜底分支改为 parse_with_context,非 canonical 值留痕收口为 unknown。
- project/version_resource_replacement.rs:subtypeEqual 改为 canonical kind 直接比较,去掉中间归一。
- packages/shared/src/contracts/gameCreationApp.ts:删除手写 GAME_CREATION_APP_CANONICAL_ASSET_KINDS、GameCreationAppCanonicalAssetKind、GAME_CREATION_APP_LEGACY_ASSET_KINDS 与 canonicalGameCreationAppAssetKind(),改为 re-export ts-rs 生成的 union。
- packages/shared/src/contracts/gameCreationApp.ts:新增穷举 GAME_CREATION_APP_ASSET_KIND_MEMBERS / GAME_CREATION_APP_ASSET_KINDS、isGameCreationAppAssetKind 与严格解析 parseGameCreationAppAssetKind(认不出的原值 console.warn 留痕并返回 unknown)。
- packages/shared/src/contracts/gameCreationApp.ts:分类映射表与 gameCreationAppAssetCategoryForKind 改按生成 union 穷举,unknown 落 unclassified。
- packages/shared/src/contracts/generated/GameCreationAppAssetKind.ts:ts-rs 生成物从壳内私有目录搬到 packages/shared(跨端契约目录)。
- apps/ai-game-creator-shell/src/contracts/assetKind.ts:删除这份壳内重复实现,消费方改从 packages/shared 导入。
- apps/ai-game-creator-shell/src/features/project-workspace/resourceReferences.ts / features/ui-editor/uiDesignResourceBridge.ts / view/project-development/index.tsx:导入点改到 packages/shared 的同一份 parser 与常量。
- apps/ai-game-creator-shell/tests/assetKindCanonicalMapping.test.ts:删除「正则解析 Rust 源码比对两份手写表」的守卫用例,跨语言一致性改由生成 union 在编译期保证。
- .prettierignore / .eslintrc.cjs:忽略规则跟着生成目录一起搬到 packages/shared/src/contracts/generated。
- projectArtifactSummaries.ts:inferProjectFileAssetDraft 的 json 分支由 data 改为 document、判不出扩展名时由 asset 改为 unknown,与 Rust 侧 uploaded_asset_kind 同口径——/asset-register 的 kind 会原样进 register_local_asset 的严格解析,写非 canonical 值只会被判成认不出并留痕。
- packages/shared/src/contracts/gameCreationApp.test.ts:新增严格解析用例(认不出的原值 console.warn 留痕、返回 unknown),分类映射与自愈用例改用 canonical ui-design / icon,并断言 kind:'ui' 收口成 unknown 后落 unclassified。
- tests/resourceTypePanel.test.tsx / tests/resourceClassificationPanel.test.tsx:自愈用例的 fixture kind 由 ui 改为 ui-design,让「显示口径 ≠ 落盘口径」这条判据继续真的被验证。
- tests/projectResourceLiveIntegration.test.tsx:fixture kind 改为 ui-design;用例按 canonical UI 设计图带「(待视觉验收)」的标签定位按钮,并把用例名与注释改回真实口径。
- tests/resourceCardPreviewRealManifest.test.ts:真机 61 条资产的取证结论改为严格口径——57 条 ui 与 game-entry 停在待归类,明确栏目只由落盘 category 决定;自愈断言改用 ui-design。
- tests/appSurface/home.suite.ts / project-development.suite.ts:fixture 里的 art-spritesheet / game-background / animation / ui-prototype / ui 改为 canonical icon-spritesheet / scene / character-animation / ui-design / icon。
- tests/projectResourceProjectionModel.test.ts / projectResourceLiveUpdateModel.test.ts:fixture kind 由 game-entry / asset 改为 code / image。
- docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md:新增 2026-09-17 权威节,写明唯一词汇表、严格解析、app_log! 留痕与生成目录搬家。
- docs/prd/【AI游戏创作】项目开发工作台PRD-2026-07-20.md:删掉「alias 表大小写不敏感」的旧口径,改为严格等值解析 + 原始串留痕,并把跨端守卫改为编译期绑定。
- docs/project-memory/shared-memory/decision-log.md:新增 2026-09-17 条目记录四项决策与验证命令。
- docs/project-memory/shared-memory/pitfalls.md:新增 ts-rs 生成目录搬家后必须同步忽略规则的坑;旧别名表相关条目补上现行口径,避免后人照旧重加别名表。
- docs/project-memory/plans/ / todos/:把 kind-observability、壳内生成目录、已删除的交叉守卫用例等过期描述改成当前口径。
- assets.rs:新增 `registration_asset_kind()`,空白入参落中性 `image`、非空认不出严格收口成 `Unknown` 并留痕;`import_canvas_asset_at` 改走该函数。
- commands.rs:`imported_platform_asset_kind` 与 `register_local_asset` 一并委托给 `registration_asset_kind()`,删掉两处各写一遍的 trim/严格解析分支。
- agent/generation/canvas_generation.rs:切片残留登记判据改为只看 `assets/art-spritesheet-slices/` 路径——历史切片刻的 kind 是非 canonical 值,严格解析后收口成 `unknown`,再带 kind 判据会漏掉半成品登记并静默跳过回填;补平台词汇映射用例钉住别名与未映射值落点。
- project/resource_editor.rs:栅格归一化的源 subtype 收口到图片族成员(音频/视频/文档/字体等一律按图片登记),Agent 回执派生物写回 `Document` 而不再主动写 `Unknown`;补派生 kind 用例。
- ui_editor/workflow.rs:新增 `same_sprite_asset_identity()`,比较 sprite 身份时忽略随 kind 派生的 `metadata.asset_type`,避免对既有 State 重跑工作流误报资源冲突。
- packages/shared/src/contracts/gameCreationApp.ts:新增 `isGameCreationAppUiDesignDocAsset(asset)`,`kind` 严格解析后再比文档 kind、`mediaType` 比 `application/json`,这是该判据的唯一定义。
- packages/shared/src/contracts/gameCreationApp.test.ts:补用例钉住判据——只满足一半(kind 对 / mediaType 不符、mediaType 对 / kind 不是文档)与 legacy kind(`UI`、`ui`、带空格、大写)一律返回 false。
- apps/ai-game-creator-shell/src/view/project-development/index.tsx:桥接结果校验与「自动打开 ui-workflow 完成资源」两处改用共享判据,删掉本地 kind/mediaType 双条件。
- apps/ai-game-creator-shell/src/features/ui-editor/uiDesignResourceBridge.ts:`findLinkedUiDesignResource` 的过滤条件改用共享判据。
- apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx:缩略图文档分支改用共享判据(原来只看 mediaType,kind 不同也能命中)。
- apps/ai-game-creator-shell/tests/appSurface/project-development.suite.ts:`ensure_ui_design_resource_for_prototype` 的 mock 从返回 `null` 改为返回真实形状的桥接结果(asset + manifest + committedProjectRevision + created),并新增 `data-resource-view-state === 'resources.ui-editor'` 断言,让用例真的覆盖它名字里的成功路径而不是被组件吞进错误分支。
- server-rs/crates/shared-contracts/src/game_creation_app/asset_kind.rs:删掉公开的 `from_str_or_unknown()`(`from_str_lossy` 的残留命名),严格匹配降级为私有 `match_canonical()`;`parse_with_context()` 成为唯一公开解析入口,`FromStr`、serde 与所有边界一律走它,认不出 canonical 值只有这一处收口并留痕。
- server-rs/crates/shared-contracts/src/game_creation_app/asset_kind.rs:词汇表用例改走唯一入口,并断言每个非 canonical 变体都留痕。
- apps/ai-game-creator-shell/src-tauri/src/project/manifest.rs:读侧回捞 legacy kind 时不再调用第二个解析函数,直接用唯一词汇表 `ALL` 判真值(`unknown` 本身是成员,自然跳过)。
- docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md:2026-09-17 节改为唯一解析入口 `parse_with_context()`(内部私有 `match_canonical()`,`from_str_lossy` / 公开 `from_str_or_unknown` 均已删除),并新增登记边界同口径、登记内容 kind 必须与内容相符、切片残留判据只看路径、sprite 身份不含展示串、TS 判据只留一份与「严格口径已知代价、不迁移」六条。
- docs/project-memory/shared-memory/decision-log.md:同一节补上单一解析入口、登记边界 kind 口径、判据不许散落、已知代价不补救四条决策,并把验证命令更新为实际跑过的定向用例。
合并资源规范与画布 JSON 功能
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 7m2s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 7m4s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 7m20s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 7m21s
Project CI / Backend tests (pull_request) Failing after 14s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m52s
Project CI / Repository checks (pull_request) Failing after 11s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 3m5s
Project CI / Frontend tests (pull_request) Failing after 5m26s
Project CI / AI game creator shell web tests (pull_request) Failing after 4m11s
Project CI / Native shell tests (pull_request) Successful in 10m40s
64879cfcdd
合并 canonical 资源 kind 校验与按类型提示词上限。\n保留 UI JSON 预览识别、严格 UI 文档持久化和画布编辑入口。\n修复合并后 Rust 资源 kind 测试夹具并补齐定向回归用例。
k88936 added 3 commits 2026-09-18 00:56:29 +08:00
按 manifest 来源与资产身份去重
避免不同项目相同 ID 互相抑制日志
工具白名单与 schema 改用 GameCreationAppAssetKind
canonical 输入在生成适配边界映射旧账本值
拒绝栅格资源 subtype 静默降级
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust smoke (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Has been cancelled
72cd0747a4
非图片族和未知 sourceSubtype 改为明确报错
补充栅格正规化回归测试并同步规范
k88936 added 1 commit 2026-09-18 01:51:40 +08:00
合并资源编辑与当前主线改动
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust smoke (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
c2ab9674a0
保留资源 kind 强类型与栅格 subtype 严格校验

合并抠图模式、幂等账本、恢复轮询和 PNG 透明通道校验

修正共享资源枚举在 Cocos 登记与抠图桥接中的类型传递

保留双方模板库、项目快照、发布和 Provider 重试改动
k88936 added 1 commit 2026-09-18 01:55:27 +08:00
Merge remote-tracking branch 'origin/master' into feat/agc-organize-assetkind
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Failing after 5m34s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 5m33s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Failing after 5m47s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m56s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 4m20s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m27s
Project CI / Repository checks (pull_request) Successful in 5m58s
Project CI / Frontend tests (pull_request) Successful in 6m49s
Project CI / Native shell tests (pull_request) Successful in 10m59s
Project CI / Backend tests (pull_request) Successful in 12m9s
Project CI / AI game creator shell web tests (pull_request) Successful in 5m5s
fc5cea43ac
k88936 added 2 commits 2026-09-18 10:43:16 +08:00
测试现在直接从 AGENT_RUNTIME_CANVAS_ASSET_KINDS 派生期望值,避免再次漂移。
Merge remote-tracking branch 'origin/master' into feat/agc-organize-assetkind
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 6m43s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 6m28s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m18s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 6m5s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m47s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 5m42s
Project CI / Repository checks (pull_request) Successful in 6m2s
Project CI / Frontend tests (pull_request) Successful in 8m48s
Project CI / Native shell tests (pull_request) Successful in 9m37s
Project CI / Backend tests (pull_request) Successful in 10m34s
Project CI / AI game creator shell web tests (pull_request) Successful in 5m29s
03d7bca9a5
k88936 requested review from lhk229 2026-09-18 10:59:00 +08:00
Member

本轮 review 结论:当前不建议合并,发现以下问题:

P1:存量 legacy kind 图片快速编辑会被服务端拒绝

apps/ai-game-creator-shell/src-tauri/src/project/resource_editor.rs:1406-1418 将旧 manifest kind(如 uiart-spritesheetgame-background)解析为 Unknown,随后在 :1936assetKind: "unknown" 发给服务端。服务端 server-rs/crates/api-server/src/editor_project.rs:4123-4148 的静态图片白名单不包含 unknown,因此存量图片执行快速编辑会返回 400。

需要明确:不要把客户端收口后的 unknown 当作 API 的来源类型发送,或同步补齐服务端/API 的兼容口径,并补充存量 legacy kind 的回归测试。

P1:旧 UI 设计 JSON 资产失去编辑能力

存量 UI 设计资产仍可能是 UI / ui,但 apps/ai-game-creator-shell/src-tauri/src/ui_editor/persistence.rs:314-323 现在要求 kind == "ui-design-doc"。因此卡片入口可能仍显示,load/save/generate 进入后却会报“目标资源不是 UI 设计 JSON 资产”;桥接流程还可能新建一份重复文档,旧文档被孤立。

需要保留已有合法 UI State 的加载/保存能力,或提供明确的一次性迁移,并覆盖旧项目回归场景。

P2:任意 manifest 写入会不可逆改写旧 kind

GameCreationAppAssetKind 的未知值解析为 Unknown,整体写 manifest 时再序列化为 "unknown"server-rs/crates/shared-contracts/src/game_creation_app/asset_kind.rs:110-118apps/ai-game-creator-shell/src-tauri/src/project/manifest.rs:2178)。修改标签、任务或其他 manifest 字段后,原始 legacy kind 会丢失,后续也无法再做可靠迁移。

建议写入侧保留原始值,或在首次读取时保存可恢复的迁移清单。

本地验证:shared-contracts 28/28、TS 契约 22/22、encoding、rustfmt、diff check 通过;PR CI run 2472 全部成功。AGC typecheck 在本地受缺失依赖(@tauri-apps/plugin-updaterthreereact-window)影响,未能完成。

本轮 review 结论:当前不建议合并,发现以下问题: ### P1:存量 legacy kind 图片快速编辑会被服务端拒绝 `apps/ai-game-creator-shell/src-tauri/src/project/resource_editor.rs:1406-1418` 将旧 manifest kind(如 `ui`、`art-spritesheet`、`game-background`)解析为 `Unknown`,随后在 `:1936` 以 `assetKind: "unknown"` 发给服务端。服务端 `server-rs/crates/api-server/src/editor_project.rs:4123-4148` 的静态图片白名单不包含 `unknown`,因此存量图片执行快速编辑会返回 400。 需要明确:不要把客户端收口后的 `unknown` 当作 API 的来源类型发送,或同步补齐服务端/API 的兼容口径,并补充存量 legacy kind 的回归测试。 ### P1:旧 UI 设计 JSON 资产失去编辑能力 存量 UI 设计资产仍可能是 `UI` / `ui`,但 `apps/ai-game-creator-shell/src-tauri/src/ui_editor/persistence.rs:314-323` 现在要求 `kind == "ui-design-doc"`。因此卡片入口可能仍显示,load/save/generate 进入后却会报“目标资源不是 UI 设计 JSON 资产”;桥接流程还可能新建一份重复文档,旧文档被孤立。 需要保留已有合法 UI State 的加载/保存能力,或提供明确的一次性迁移,并覆盖旧项目回归场景。 ### P2:任意 manifest 写入会不可逆改写旧 kind `GameCreationAppAssetKind` 的未知值解析为 `Unknown`,整体写 manifest 时再序列化为 `"unknown"`(`server-rs/crates/shared-contracts/src/game_creation_app/asset_kind.rs:110-118`、`apps/ai-game-creator-shell/src-tauri/src/project/manifest.rs:2178`)。修改标签、任务或其他 manifest 字段后,原始 legacy kind 会丢失,后续也无法再做可靠迁移。 建议写入侧保留原始值,或在首次读取时保存可恢复的迁移清单。 本地验证:shared-contracts 28/28、TS 契约 22/22、encoding、rustfmt、diff check 通过;PR CI run 2472 全部成功。AGC typecheck 在本地受缺失依赖(`@tauri-apps/plugin-updater`、`three`、`react-window`)影响,未能完成。
Author
Member

都是关于旧数据的风险,可以接受, 而且最好在周一上线前就统一

都是关于旧数据的风险,可以接受, 而且最好在周一上线前就统一
Author
Member

审查基线
• 固定点:origin/master = b137f1759(Merge PR #417),分支 feat/agc-organize-assetkind,merge-base a2e6f205d。
• 范围:git diff origin/master...HEAD — 84 个文件,+3205 / −1267,72 个提交;HEAD = 03d7bca9a(把 master 合并回来的 merge)。
• 本次审查是静态审查(未执行测试/构建),结论基于 diff 与仓库文档、决策日志的交叉核对。
• 规格来源(两族,均为本分支新增文档):docs/project-memory/plans/ 下 7 份 ——
【技术方案】AGC资源kind枚举化Rust权威边界-2026-09-15.md、【里程碑】AGC资源kind枚举化共享契约与TS绑定-2026-09-15.md、【里程碑】AGC资源kind枚举化词汇审
计与绑定架构-2026-09-15.md、【实施计划】AGC资源kind纵深化Rust绑定与内部收口-2026-09-15.md、【待办】AGC资源kind枚举化扫描清单-2026-09-15.md、【实施计
划】UI设计文档引用代码上下文-2026-09-14.md、【里程碑】UI设计文档引用代码上下文-2026-09-14.md;另有
docs/project-memory/shared-memory/decision-log.md、pitfalls.md。
• 规范来源:AGENTS.md、UI_CODING_STANDARD.md、docs【协作规范】*、docs/project-memory/shared-memory/team-conventions.md,外加内置代码坏味基线。

规范轴(Standards)
文档口径不一致(硬性文案冲突)

• apps/ai-game-creator-shell/src-tauri/src/assets.rs:480:函数文档仍写「判不出内容类型时返回中性的 asset」,而同一提交把函数内注释(第 287–288 行
hunk)改成了 unknown ,代码(:537)也返回 Unknown。同一提交内同一事实两处写法不同,且文档引用了已退役的 asset 值(AGENTS.md「四不写」第 3
条同类问题)。
• assets.rs:470–478 整段新注释(「不用 uploaded 这类来源词」「更不能把 ui 当默认类型」「别名表」、「读时自愈」)是在解释已删除的别名表与 uploaded/ui
旧值,属墓碑式说明;这些信息已在 decision-log.md 顶部条目与 pitfalls.md 记录,注释里的重复副本会随代码漂移。

生成物与工程策略(判断项)

• packages/shared/src/contracts/generated/GameCreationAppAssetKind.ts 新入库(生成文件,含「Do not edit」),但本次未新增 .gitattributes,且
.prettierignore 新增 generated 让它静默跳过格式检查;仓库 .gitignore:320 已有 .generated. 规则,命名相近易混。生成能力用 #[cfg(feature =
"ts-bindings")]
门禁(server-rs/crates/shared-contracts/Cargo.toml、asset_kind.rs:51–61)是对的,但「生成物如何入库/如何校验」缺少成文约定(.codex/skills/genarrative
-spacetimedb 那类 skill 未覆盖)。
• 生成门禁可发现性:导出由 ts-rs 的 export_bindings_* 测试触发(asset_kind.rs:52–61 的 export/export_to),仓库与文档均未记录具体命令(实际为 cargo
test export_bindings),漂移风险缺少说明(轻微)。

重复知识与类型退化(判断项)

• apps/ai-game-creator-shell/src/features/project-summary/projectAssetSummaries.ts:101–127:isProjectAudioAsset / isProjectVisualAsset 仍手写 kind
字面量(audio/sound-effect/background-music/image/icon/character-animation),且先 asset.kind.toLowerCase() 使比较退化为普通 string —— 新 union
的编译期穷举保护在这里失效(写错字面量不会报错)。同一套「图片/音频族」判据在 Rust 侧 ui_editor/resource_editor.rs(matches! 8 项)另有一份实现,构成
Duplicated Code / Primitive Obsession。

写入口径自相矛盾(判断项)

• asset_kind.rs:48–49 明确「正常资源写入路径不应主动选择 Unknown」,但 assets.rs:537(内容判型兜底)与 :552(空白入参回退 Image、非空认不出回退
Unknown)正是写入路径主动落 Unknown。口径需要二选一:要么放宽 Unknown 的语义说明,要么让写入侧在无法判型时改用明确的中性值。

迁移收尾(既有问题,非本次引入)

• apps/ai-game-creator-shell/src/view/project-development/index.tsx:392 仍比较 asset.kind ===
'art-spritesheet'(已退役值,比较恒假死分支)。本次未改动该文件,但属同一词汇收敛范围,建议顺带清理。

规格轴(Spec)

  1. 「删别名表」与里程碑文档边界冲突(最重)

• 【里程碑】AGC资源kind枚举化词汇审计与绑定架构-2026-09-15.md:26「不实现旧 manifest migration、alias 表或 fallback
清理」,:40「(该表属读边界,本次未新增也未扩展,留给独立词汇收敛切片)」;而本次直接删除了
GAME_CREATION_APP_LEGACY_ASSET_KINDS、canonicalGameCreationAppAssetKind() 及 Rust 同名实现。
• 代价已在 decision-log.md:12
记录(「已知代价,不补救……不得把别名表加回解析路径」),但上级里程碑/实施计划未同步:【实施计划】AGC资源kind纵深化Rust绑定与内部收口-2026-09-15.md
仍是 Status: planned、37 个验收框全未勾选,【里程碑】词汇审计 验收项仍写「未扩展/留给独立切片」。按 AGENTS.md「工程修改要同步更新对应
docs/」,这是文档同步缺口。
• 行为后果需评审确认:服务端保留了兼容白名单(server-rs/crates/api-server/src/editor_project.rs:4139–4140、:20766 「实测 art-spritesheet / ui 曾整片
400」,本次仅改注释语义),而 shell 读侧不再归一 —— 存量/平台登记的 art-spritesheet、ui-prototype、font 资产从「图标素材 / UI 交互 /
文档」退化为「待归类」(GameCreationAppAssetKind.ts 与 packages/shared/src/contracts/gameCreationApp.ts:519–598 的 unknown 收口)。

  1. resourceProjectionModel.ts 判据被放宽,语义超出里程碑

• 变更:asset.kind === 'ui-prototype' → === GAME_CREATION_APP_UI_DESIGN_ASSET_KIND(ui-design,resourceProjectionModel.ts:411–413)。
• 影响面在 :421–433:这会把标签改成「(待视觉验收)」、来源标成「画板 · 候选界面图」。旧实现只命中原型导入资产,新实现命中所有 ui-design
资产(CANVAS_ASSET_KINDS 含 UiDesign,画板生成 UI 设计也在此列),只要 design-foundation 未完成就会被标注。里程碑只要求「manifest kind 统一为
ui-design」,没有要求放宽该运行门禁,需要确认是否有意为之。

  1. projectAssetSummaries.ts:121–126 删除 sprite/ui/background 后无补偿

• 与 1 同源:这些旧值语义上确实不再是 canonical,但删除后此类存量资产在项目摘要里既不算美术也不算音频,直接从汇总消失(此前经别名归到
image/ui-design)。里程碑没有交代存量摘要在「不迁移」下的预期表现(建议在文档中显式声明为可接受代价)。

  1. 未做而未在文档登记的缺口

• 【实施计划】...纵深化Rust绑定与内部收口-2026-09-15.md 第 34–37 项(别名表清理、font 移除 default/category、UNKNOWN_RESOURCE_PROJECTION_KIND、TS
kind 映射收口)已在代码中落实且测试覆盖(decision-log.md、pitfalls.md 有记录、pitfalls.md 有 4 条真机回归清单),但计划/里程碑的验收框与 Status
全部停留在未开始状态,验收证据无法从文档侧核对。

  1. UI 设计文档引用链路(未发现偏差)

• apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/wire.rs 新增的 render_ui_design_code_context 与里程碑一致:仅认 ui-design-doc

  • application/json(:80–84)、逐引用顺序处理、单条失败只追加错误不阻断(:45–53、:55–59 注释),ui-prototype 图片不触发代码生成,符合里程碑 4/5 项。

一并需要处理的工作区状态
• 未提交更改:package-lock.json(仓库以 pnpm 为主,pnpm-lock.yaml 同时存在,疑似误改)与 .env(AGENTS.md 绝对约束禁止提交;请确认不该被 git
add)。未跟踪的 .output.txt 是本会话临时产物,已删除。

汇总
• 规范轴:7 条(其中 1 条硬性文案冲突、其余为判断项),最重为 assets.rs:480 与同提交 unknown 口径不一致 + 大段墓碑注释。
• 规格轴:5 条,最重为「删除别名表」与里程碑明文边界冲突、且里程碑文档未同步(代价虽已记入 decision-log.md,但存量资产在 shell
侧退化为「待归类」的影响面需要显式确认)。

审查基线 • 固定点:origin/master = b137f1759(Merge PR #417),分支 feat/agc-organize-assetkind,merge-base a2e6f205d。 • 范围:git diff origin/master...HEAD — 84 个文件,+3205 / −1267,72 个提交;HEAD = 03d7bca9a(把 master 合并回来的 merge)。 • 本次审查是静态审查(未执行测试/构建),结论基于 diff 与仓库文档、决策日志的交叉核对。 • 规格来源(两族,均为本分支新增文档):docs/project-memory/plans/ 下 7 份 —— 【技术方案】AGC资源kind枚举化Rust权威边界-2026-09-15.md、【里程碑】AGC资源kind枚举化共享契约与TS绑定-2026-09-15.md、【里程碑】AGC资源kind枚举化词汇审 计与绑定架构-2026-09-15.md、【实施计划】AGC资源kind纵深化Rust绑定与内部收口-2026-09-15.md、【待办】AGC资源kind枚举化扫描清单-2026-09-15.md、【实施计 划】UI设计文档引用代码上下文-2026-09-14.md、【里程碑】UI设计文档引用代码上下文-2026-09-14.md;另有 docs/project-memory/shared-memory/decision-log.md、pitfalls.md。 • 规范来源:AGENTS.md、UI_CODING_STANDARD.md、docs【协作规范】*、docs/project-memory/shared-memory/team-conventions.md,外加内置代码坏味基线。 规范轴(Standards) 文档口径不一致(硬性文案冲突) • apps/ai-game-creator-shell/src-tauri/src/assets.rs:480:函数文档仍写「判不出内容类型时返回中性的 asset」,而同一提交把函数内注释(第 287–288 行 hunk)改成了 ` `unknown` `,代码(:537)也返回 Unknown。同一提交内同一事实两处写法不同,且文档引用了已退役的 asset 值(AGENTS.md「四不写」第 3 条同类问题)。 • assets.rs:470–478 整段新注释(「不用 uploaded 这类来源词」「更不能把 ui 当默认类型」「别名表」、「读时自愈」)是在解释已删除的别名表与 uploaded/ui 旧值,属墓碑式说明;这些信息已在 decision-log.md 顶部条目与 pitfalls.md 记录,注释里的重复副本会随代码漂移。 生成物与工程策略(判断项) • packages/shared/src/contracts/generated/GameCreationAppAssetKind.ts 新入库(生成文件,含「Do not edit」),但本次未新增 .gitattributes,且 .prettierignore 新增 generated 让它静默跳过格式检查;仓库 .gitignore:320 已有 *.generated.* 规则,命名相近易混。生成能力用 #[cfg(feature = "ts-bindings")] 门禁(server-rs/crates/shared-contracts/Cargo.toml、asset_kind.rs:51–61)是对的,但「生成物如何入库/如何校验」缺少成文约定(.codex/skills/genarrative -spacetimedb 那类 skill 未覆盖)。 • 生成门禁可发现性:导出由 ts-rs 的 export_bindings_* 测试触发(asset_kind.rs:52–61 的 export/export_to),仓库与文档均未记录具体命令(实际为 cargo test export_bindings),漂移风险缺少说明(轻微)。 重复知识与类型退化(判断项) • apps/ai-game-creator-shell/src/features/project-summary/projectAssetSummaries.ts:101–127:isProjectAudioAsset / isProjectVisualAsset 仍手写 kind 字面量(audio/sound-effect/background-music/image/icon/character-animation),且先 asset.kind.toLowerCase() 使比较退化为普通 string —— 新 union 的编译期穷举保护在这里失效(写错字面量不会报错)。同一套「图片/音频族」判据在 Rust 侧 ui_editor/resource_editor.rs(matches! 8 项)另有一份实现,构成 Duplicated Code / Primitive Obsession。 写入口径自相矛盾(判断项) • asset_kind.rs:48–49 明确「正常资源写入路径不应主动选择 Unknown」,但 assets.rs:537(内容判型兜底)与 :552(空白入参回退 Image、非空认不出回退 Unknown)正是写入路径主动落 Unknown。口径需要二选一:要么放宽 Unknown 的语义说明,要么让写入侧在无法判型时改用明确的中性值。 迁移收尾(既有问题,非本次引入) • apps/ai-game-creator-shell/src/view/project-development/index.tsx:392 仍比较 asset.kind === 'art-spritesheet'(已退役值,比较恒假死分支)。本次未改动该文件,但属同一词汇收敛范围,建议顺带清理。 规格轴(Spec) 1. 「删别名表」与里程碑文档边界冲突(最重) • 【里程碑】AGC资源kind枚举化词汇审计与绑定架构-2026-09-15.md:26「不实现旧 manifest migration、alias 表或 fallback 清理」,:40「(该表属读边界,本次未新增也未扩展,留给独立词汇收敛切片)」;而本次直接删除了 GAME_CREATION_APP_LEGACY_ASSET_KINDS、canonicalGameCreationAppAssetKind() 及 Rust 同名实现。 • 代价已在 decision-log.md:12 记录(「已知代价,不补救……不得把别名表加回解析路径」),但上级里程碑/实施计划未同步:【实施计划】AGC资源kind纵深化Rust绑定与内部收口-2026-09-15.md 仍是 Status: planned、37 个验收框全未勾选,【里程碑】词汇审计 验收项仍写「未扩展/留给独立切片」。按 AGENTS.md「工程修改要同步更新对应 docs/」,这是文档同步缺口。 • 行为后果需评审确认:服务端保留了兼容白名单(server-rs/crates/api-server/src/editor_project.rs:4139–4140、:20766 「实测 art-spritesheet / ui 曾整片 400」,本次仅改注释语义),而 shell 读侧不再归一 —— 存量/平台登记的 art-spritesheet、ui-prototype、font 资产从「图标素材 / UI 交互 / 文档」退化为「待归类」(GameCreationAppAssetKind.ts 与 packages/shared/src/contracts/gameCreationApp.ts:519–598 的 unknown 收口)。 2. resourceProjectionModel.ts 判据被放宽,语义超出里程碑 • 变更:asset.kind === 'ui-prototype' → === GAME_CREATION_APP_UI_DESIGN_ASSET_KIND(ui-design,resourceProjectionModel.ts:411–413)。 • 影响面在 :421–433:这会把标签改成「(待视觉验收)」、来源标成「画板 · 候选界面图」。旧实现只命中原型导入资产,新实现命中所有 ui-design 资产(CANVAS_ASSET_KINDS 含 UiDesign,画板生成 UI 设计也在此列),只要 design-foundation 未完成就会被标注。里程碑只要求「manifest kind 统一为 ui-design」,没有要求放宽该运行门禁,需要确认是否有意为之。 3. projectAssetSummaries.ts:121–126 删除 sprite/ui/background 后无补偿 • 与 1 同源:这些旧值语义上确实不再是 canonical,但删除后此类存量资产在项目摘要里既不算美术也不算音频,直接从汇总消失(此前经别名归到 image/ui-design)。里程碑没有交代存量摘要在「不迁移」下的预期表现(建议在文档中显式声明为可接受代价)。 4. 未做而未在文档登记的缺口 • 【实施计划】...纵深化Rust绑定与内部收口-2026-09-15.md 第 34–37 项(别名表清理、font 移除 default/category、UNKNOWN_RESOURCE_PROJECTION_KIND、TS kind 映射收口)已在代码中落实且测试覆盖(decision-log.md、pitfalls.md 有记录、pitfalls.md 有 4 条真机回归清单),但计划/里程碑的验收框与 Status 全部停留在未开始状态,验收证据无法从文档侧核对。 5. UI 设计文档引用链路(未发现偏差) • apps/ai-game-creator-shell/src-tauri/src/agent/direct_codex_user_item/wire.rs 新增的 render_ui_design_code_context 与里程碑一致:仅认 ui-design-doc + application/json(:80–84)、逐引用顺序处理、单条失败只追加错误不阻断(:45–53、:55–59 注释),ui-prototype 图片不触发代码生成,符合里程碑 4/5 项。 一并需要处理的工作区状态 • 未提交更改:package-lock.json(仓库以 pnpm 为主,pnpm-lock.yaml 同时存在,疑似误改)与 .env(AGENTS.md 绝对约束禁止提交;请确认不该被 git add)。未跟踪的 .output.txt 是本会话临时产物,已删除。 汇总 • 规范轴:7 条(其中 1 条硬性文案冲突、其余为判断项),最重为 assets.rs:480 与同提交 unknown 口径不一致 + 大段墓碑注释。 • 规格轴:5 条,最重为「删除别名表」与里程碑明文边界冲突、且里程碑文档未同步(代价虽已记入 decision-log.md,但存量资产在 shell 侧退化为「待归类」的影响面需要显式确认)。
Author
Member
#!/usr/bin/env python3
"""Migrate legacy GameCreationApp manifest asset kinds.

This is intentionally a personal, stand-alone helper.  It only edits
``assets[*].kind`` in a manifest JSON file; it never changes project source
files or any other manifest field.

The default mode is a dry run.  Pass ``--write`` to create a timestamped
backup and atomically replace the manifest.  Unknown values stop the run by
default; use ``--unknown-kind unknown`` only after reviewing the report.
"""

from __future__ import annotations

import argparse
import collections
import datetime as dt
import json
import os
from pathlib import Path
import shutil
import stat
import tempfile
from typing import Any


CANONICAL_KINDS = frozenset(
    {
        "image",
        "scene",
        "character",
        "character-animation",
        "icon",
        "icon-spritesheet",
        "icon-spec",
        "ui-design",
        "ui-design-doc",
        "publication-material",
        "spec",
        "video",
        "audio",
        "sound-effect",
        "background-music",
        "font",
        "document",
        "code",
        "unknown",
    }
)

# Exact legacy spellings whose case carried meaning.  The historical UI editor
# document writer emitted uppercase "UI" for application/json documents; the
# old case-insensitive alias code incorrectly collapsed it to ui-design.
EXACT_LEGACY_KIND_MAP = {
    "UI": "ui-design-doc",
}

# These are the remaining legacy values accepted by the pre-enum
# implementation.  Their spelling is normalized with strip().lower().
LEGACY_KIND_MAP = {
    "game-background": "scene",
    "character-art": "character",
    "ui-prototype": "ui-design",
    "ui": "ui-design",
    "art-spritesheet": "icon-spritesheet",
    "art-spritesheet-slice": "icon",
    "illustration": "image",
    "game-art": "image",
    "game-entry": "code",
    "game-script": "code",
    "game-style": "code",
    "animation": "character-animation",
    "asset": "image",
    # "font" is now a first-class canonical kind.  Keeping it as font
    # preserves the asset's semantics; the old alias table had to use
    # document only because that enum did not yet contain font.
    "font": "font",
    # Older upload registration used this generic kind.  The old canonical
    # fallback treated it as image, so keep that observable behavior.
    "uploaded": "image",
}


class MigrationError(Exception):
    """A user-fixable manifest or command-line problem."""


def resolve_manifest_path(raw_path: str) -> Path:
    candidate = Path(raw_path).expanduser()
    if candidate.is_dir():
        candidate = candidate / ".agent" / "manifest.json"
    if not candidate.exists():
        raise MigrationError(f"manifest not found: {candidate}")
    if candidate.is_symlink():
        raise MigrationError(f"refusing to operate on a symlink: {candidate}")
    if not candidate.is_file():
        raise MigrationError(f"not a regular file: {candidate}")
    return candidate.resolve()


def load_manifest(path: Path) -> tuple[dict[str, Any], str]:
    try:
        raw_text = path.read_text(encoding="utf-8-sig")
    except OSError as exc:
        raise MigrationError(f"cannot read {path}: {exc}") from exc
    try:
        value = json.loads(raw_text)
    except json.JSONDecodeError as exc:
        raise MigrationError(f"invalid JSON in {path}: {exc}") from exc
    if not isinstance(value, dict):
        raise MigrationError("manifest root must be a JSON object")
    assets = value.get("assets")
    if not isinstance(assets, list):
        raise MigrationError("manifest.assets must be a JSON array")
    for index, asset in enumerate(assets):
        if not isinstance(asset, dict):
            raise MigrationError(f"manifest.assets[{index}] must be an object")
        if "kind" not in asset:
            raise MigrationError(f"manifest.assets[{index}] has no kind field")
        if not isinstance(asset["kind"], str):
            raise MigrationError(
                f"manifest.assets[{index}].kind must be a string, "
                f"got {type(asset['kind']).__name__}"
            )
    return value, raw_text


def migrate_manifest(
    manifest: dict[str, Any], *, unknown_kind: str | None
) -> tuple[list[dict[str, str]], collections.Counter[tuple[str, str]]]:
    changes: list[dict[str, str]] = []
    counts: collections.Counter[tuple[str, str]] = collections.Counter()
    for index, asset in enumerate(manifest["assets"]):
        raw_kind = asset["kind"]
        stripped = raw_kind.strip()
        normalized = stripped.lower()
        if stripped in EXACT_LEGACY_KIND_MAP:
            new_kind = EXACT_LEGACY_KIND_MAP[stripped]
        elif normalized in CANONICAL_KINDS:
            new_kind = normalized
        else:
            new_kind = LEGACY_KIND_MAP.get(normalized)
            if new_kind is None:
                if unknown_kind is None:
                    asset_id = asset.get("id", f"assets[{index}]")
                    raise MigrationError(
                        f"unrecognized asset kind {raw_kind!r} at {asset_id!r}; "
                        "review it and rerun with --unknown-kind unknown if appropriate"
                    )
                new_kind = unknown_kind
        if new_kind not in CANONICAL_KINDS:
            raise MigrationError(f"internal error: invalid target kind {new_kind!r}")
        if raw_kind != new_kind:
            asset_id = str(asset.get("id", f"assets[{index}]"))
            local_path = str(asset.get("localPath", ""))
            changes.append(
                {
                    "asset_id": asset_id,
                    "local_path": local_path,
                    "old_kind": raw_kind,
                    "new_kind": new_kind,
                }
            )
            counts[(raw_kind, new_kind)] += 1
            asset["kind"] = new_kind
    return changes, counts


def format_json(manifest: dict[str, Any], original_text: str) -> str:
    # Keep the existing newline convention and final-newline behavior.  JSON
    # object insertion order is preserved by Python, so unrelated fields are
    # not reordered.
    newline = "\r\n" if "\r\n" in original_text else "\n"
    final_newline = "\n" if original_text.endswith(("\n", "\r")) else ""
    rendered = json.dumps(manifest, ensure_ascii=False, indent=2, allow_nan=False)
    if newline != "\n":
        rendered = rendered.replace("\n", newline)
    return rendered + final_newline


def make_backup(path: Path) -> Path:
    stamp = dt.datetime.now().strftime("%Y%m%d-%H%M%S")
    base = path.with_name(f"{path.name}.bak-{stamp}")
    backup = base
    suffix = 1
    while backup.exists():
        backup = path.with_name(f"{base.name}-{suffix}")
        suffix += 1
    shutil.copy2(path, backup)
    return backup


def atomic_write(path: Path, content: str) -> None:
    mode = stat.S_IMODE(path.stat().st_mode)
    fd, temp_name = tempfile.mkstemp(prefix=f".{path.name}.", suffix=".tmp", dir=path.parent)
    temp_path = Path(temp_name)
    try:
        os.chmod(temp_path, mode)
        with os.fdopen(fd, "w", encoding="utf-8", newline="") as handle:
            handle.write(content)
            handle.flush()
            os.fsync(handle.fileno())
        os.replace(temp_path, path)
        try:
            dir_fd = os.open(path.parent, os.O_DIRECTORY)
        except OSError:
            dir_fd = None
        if dir_fd is not None:
            try:
                os.fsync(dir_fd)
            finally:
                os.close(dir_fd)
    except BaseException:
        try:
            temp_path.unlink()
        except FileNotFoundError:
            pass
        raise


def print_report(path: Path, changes: list[dict[str, str]], counts: collections.Counter[tuple[str, str]]) -> None:
    print(f"Manifest: {path}")
    if not changes:
        print("No asset kind changes needed; file was not written.")
        return
    print(f"Asset kind changes: {len(changes)}")
    for (old_kind, new_kind), count in sorted(counts.items()):
        print(f"  {old_kind!r} -> {new_kind!r}: {count}")
    print("\nEntries:")
    for change in changes:
        location = change["local_path"] or change["asset_id"]
        print(
            f"  {change['asset_id']}: {change['old_kind']!r} -> "
            f"{change['new_kind']!r} ({location})"
        )


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        description="Migrate legacy GameCreationApp manifest asset kinds."
    )
    parser.add_argument(
        "path",
        nargs="?",
        default="/root/agc",
        help="manifest.json path or project root (default: /root/agc)",
    )
    parser.add_argument(
        "--write",
        action="store_true",
        help="create a backup and atomically write the migrated manifest",
    )
    parser.add_argument(
        "--unknown-kind",
        choices=("unknown",),
        default=None,
        help="explicitly map otherwise unrecognized values to unknown",
    )
    return parser.parse_args()


def main() -> int:
    args = parse_args()
    try:
        path = resolve_manifest_path(args.path)
        manifest, original_text = load_manifest(path)
        changes, counts = migrate_manifest(manifest, unknown_kind=args.unknown_kind)
        print_report(path, changes, counts)
        if not changes or not args.write:
            if changes and not args.write:
                print("\nDry run only; pass --write after reviewing the mapping.")
            return 0
        backup = make_backup(path)
        atomic_write(path, format_json(manifest, original_text))
        print(f"\nWrote migrated manifest. Backup: {backup}")
        # Re-read the result and ensure every asset kind is canonical.  This
        # catches accidental partial writes or a future edit to the map.
        written, _ = load_manifest(path)
        remaining = [
            (asset.get("id", f"assets[{index}]"), asset.get("kind"))
            for index, asset in enumerate(written["assets"])
            if asset.get("kind") not in CANONICAL_KINDS
        ]
        if remaining:
            raise MigrationError(f"post-write validation found non-canonical kinds: {remaining}")
        print("Post-write validation: all asset kinds are canonical.")
        return 0
    except MigrationError as exc:
        print(f"error: {exc}", file=os.sys.stderr)
        return 2
    except OSError as exc:
        print(f"error: filesystem operation failed: {exc}", file=os.sys.stderr)
        return 2


if __name__ == "__main__":
    raise SystemExit(main())

``` #!/usr/bin/env python3 """Migrate legacy GameCreationApp manifest asset kinds. This is intentionally a personal, stand-alone helper. It only edits ``assets[*].kind`` in a manifest JSON file; it never changes project source files or any other manifest field. The default mode is a dry run. Pass ``--write`` to create a timestamped backup and atomically replace the manifest. Unknown values stop the run by default; use ``--unknown-kind unknown`` only after reviewing the report. """ from __future__ import annotations import argparse import collections import datetime as dt import json import os from pathlib import Path import shutil import stat import tempfile from typing import Any CANONICAL_KINDS = frozenset( { "image", "scene", "character", "character-animation", "icon", "icon-spritesheet", "icon-spec", "ui-design", "ui-design-doc", "publication-material", "spec", "video", "audio", "sound-effect", "background-music", "font", "document", "code", "unknown", } ) # Exact legacy spellings whose case carried meaning. The historical UI editor # document writer emitted uppercase "UI" for application/json documents; the # old case-insensitive alias code incorrectly collapsed it to ui-design. EXACT_LEGACY_KIND_MAP = { "UI": "ui-design-doc", } # These are the remaining legacy values accepted by the pre-enum # implementation. Their spelling is normalized with strip().lower(). LEGACY_KIND_MAP = { "game-background": "scene", "character-art": "character", "ui-prototype": "ui-design", "ui": "ui-design", "art-spritesheet": "icon-spritesheet", "art-spritesheet-slice": "icon", "illustration": "image", "game-art": "image", "game-entry": "code", "game-script": "code", "game-style": "code", "animation": "character-animation", "asset": "image", # "font" is now a first-class canonical kind. Keeping it as font # preserves the asset's semantics; the old alias table had to use # document only because that enum did not yet contain font. "font": "font", # Older upload registration used this generic kind. The old canonical # fallback treated it as image, so keep that observable behavior. "uploaded": "image", } class MigrationError(Exception): """A user-fixable manifest or command-line problem.""" def resolve_manifest_path(raw_path: str) -> Path: candidate = Path(raw_path).expanduser() if candidate.is_dir(): candidate = candidate / ".agent" / "manifest.json" if not candidate.exists(): raise MigrationError(f"manifest not found: {candidate}") if candidate.is_symlink(): raise MigrationError(f"refusing to operate on a symlink: {candidate}") if not candidate.is_file(): raise MigrationError(f"not a regular file: {candidate}") return candidate.resolve() def load_manifest(path: Path) -> tuple[dict[str, Any], str]: try: raw_text = path.read_text(encoding="utf-8-sig") except OSError as exc: raise MigrationError(f"cannot read {path}: {exc}") from exc try: value = json.loads(raw_text) except json.JSONDecodeError as exc: raise MigrationError(f"invalid JSON in {path}: {exc}") from exc if not isinstance(value, dict): raise MigrationError("manifest root must be a JSON object") assets = value.get("assets") if not isinstance(assets, list): raise MigrationError("manifest.assets must be a JSON array") for index, asset in enumerate(assets): if not isinstance(asset, dict): raise MigrationError(f"manifest.assets[{index}] must be an object") if "kind" not in asset: raise MigrationError(f"manifest.assets[{index}] has no kind field") if not isinstance(asset["kind"], str): raise MigrationError( f"manifest.assets[{index}].kind must be a string, " f"got {type(asset['kind']).__name__}" ) return value, raw_text def migrate_manifest( manifest: dict[str, Any], *, unknown_kind: str | None ) -> tuple[list[dict[str, str]], collections.Counter[tuple[str, str]]]: changes: list[dict[str, str]] = [] counts: collections.Counter[tuple[str, str]] = collections.Counter() for index, asset in enumerate(manifest["assets"]): raw_kind = asset["kind"] stripped = raw_kind.strip() normalized = stripped.lower() if stripped in EXACT_LEGACY_KIND_MAP: new_kind = EXACT_LEGACY_KIND_MAP[stripped] elif normalized in CANONICAL_KINDS: new_kind = normalized else: new_kind = LEGACY_KIND_MAP.get(normalized) if new_kind is None: if unknown_kind is None: asset_id = asset.get("id", f"assets[{index}]") raise MigrationError( f"unrecognized asset kind {raw_kind!r} at {asset_id!r}; " "review it and rerun with --unknown-kind unknown if appropriate" ) new_kind = unknown_kind if new_kind not in CANONICAL_KINDS: raise MigrationError(f"internal error: invalid target kind {new_kind!r}") if raw_kind != new_kind: asset_id = str(asset.get("id", f"assets[{index}]")) local_path = str(asset.get("localPath", "")) changes.append( { "asset_id": asset_id, "local_path": local_path, "old_kind": raw_kind, "new_kind": new_kind, } ) counts[(raw_kind, new_kind)] += 1 asset["kind"] = new_kind return changes, counts def format_json(manifest: dict[str, Any], original_text: str) -> str: # Keep the existing newline convention and final-newline behavior. JSON # object insertion order is preserved by Python, so unrelated fields are # not reordered. newline = "\r\n" if "\r\n" in original_text else "\n" final_newline = "\n" if original_text.endswith(("\n", "\r")) else "" rendered = json.dumps(manifest, ensure_ascii=False, indent=2, allow_nan=False) if newline != "\n": rendered = rendered.replace("\n", newline) return rendered + final_newline def make_backup(path: Path) -> Path: stamp = dt.datetime.now().strftime("%Y%m%d-%H%M%S") base = path.with_name(f"{path.name}.bak-{stamp}") backup = base suffix = 1 while backup.exists(): backup = path.with_name(f"{base.name}-{suffix}") suffix += 1 shutil.copy2(path, backup) return backup def atomic_write(path: Path, content: str) -> None: mode = stat.S_IMODE(path.stat().st_mode) fd, temp_name = tempfile.mkstemp(prefix=f".{path.name}.", suffix=".tmp", dir=path.parent) temp_path = Path(temp_name) try: os.chmod(temp_path, mode) with os.fdopen(fd, "w", encoding="utf-8", newline="") as handle: handle.write(content) handle.flush() os.fsync(handle.fileno()) os.replace(temp_path, path) try: dir_fd = os.open(path.parent, os.O_DIRECTORY) except OSError: dir_fd = None if dir_fd is not None: try: os.fsync(dir_fd) finally: os.close(dir_fd) except BaseException: try: temp_path.unlink() except FileNotFoundError: pass raise def print_report(path: Path, changes: list[dict[str, str]], counts: collections.Counter[tuple[str, str]]) -> None: print(f"Manifest: {path}") if not changes: print("No asset kind changes needed; file was not written.") return print(f"Asset kind changes: {len(changes)}") for (old_kind, new_kind), count in sorted(counts.items()): print(f" {old_kind!r} -> {new_kind!r}: {count}") print("\nEntries:") for change in changes: location = change["local_path"] or change["asset_id"] print( f" {change['asset_id']}: {change['old_kind']!r} -> " f"{change['new_kind']!r} ({location})" ) def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser( description="Migrate legacy GameCreationApp manifest asset kinds." ) parser.add_argument( "path", nargs="?", default="/root/agc", help="manifest.json path or project root (default: /root/agc)", ) parser.add_argument( "--write", action="store_true", help="create a backup and atomically write the migrated manifest", ) parser.add_argument( "--unknown-kind", choices=("unknown",), default=None, help="explicitly map otherwise unrecognized values to unknown", ) return parser.parse_args() def main() -> int: args = parse_args() try: path = resolve_manifest_path(args.path) manifest, original_text = load_manifest(path) changes, counts = migrate_manifest(manifest, unknown_kind=args.unknown_kind) print_report(path, changes, counts) if not changes or not args.write: if changes and not args.write: print("\nDry run only; pass --write after reviewing the mapping.") return 0 backup = make_backup(path) atomic_write(path, format_json(manifest, original_text)) print(f"\nWrote migrated manifest. Backup: {backup}") # Re-read the result and ensure every asset kind is canonical. This # catches accidental partial writes or a future edit to the map. written, _ = load_manifest(path) remaining = [ (asset.get("id", f"assets[{index}]"), asset.get("kind")) for index, asset in enumerate(written["assets"]) if asset.get("kind") not in CANONICAL_KINDS ] if remaining: raise MigrationError(f"post-write validation found non-canonical kinds: {remaining}") print("Post-write validation: all asset kinds are canonical.") return 0 except MigrationError as exc: print(f"error: {exc}", file=os.sys.stderr) return 2 except OSError as exc: print(f"error: filesystem operation failed: {exc}", file=os.sys.stderr) return 2 if __name__ == "__main__": raise SystemExit(main()) ```
Author
Member
  1. resourceProjectionModel.ts 判据被放宽,语义超出里程碑 <- agent操作UI编辑器路线会重写
2. resourceProjectionModel.ts 判据被放宽,语义超出里程碑 <- agent操作UI编辑器路线会重写
k88936 added 2 commits 2026-09-18 17:13:05 +08:00
- 将 manifest 与本地导入回执的资源 kind 改为 ts-rs 生成绑定

- 集中音频与视觉资源族判据并复用 Rust 枚举方法

- 放宽 Unknown 未解析语义并清理上传类型墓碑注释

- 标记共享生成绑定并同步项目决策与实施计划
删除资源 kind 兼容白名单
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 4m4s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust smoke (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Has been cancelled
0d5940433d
服务端图片快速编辑改用共享枚举静态图片判定

移除退役 kind 的兼容放行与冗余回归测试

清理客户端恒假 art-spritesheet 判断并统一远端 kind 解析

同步 AGC kind 里程碑、实施计划与决策记录
k88936 added 2 commits 2026-09-19 01:51:20 +08:00
canvas生成与运行时统一使用共享GameCreationAppAssetKind

删除平台kind兼容映射与退役kind拒绝测试

更新资源kind审计里程碑与绑定文档
合并主线并保留资源kind枚举收口
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust smoke (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
18252e24b8
合并 origin/master 的 AGC 画布参考与项目能力更新

解决 canvas 生成恢复与任务模型冲突并继续使用共享 GameCreationAppAssetKind

保留 run_id、generationKind 与外部协议字符串的独立边界
k88936 added 1 commit 2026-09-19 01:54:26 +08:00
Merge remote-tracking branch 'origin/master' into feat/agc-organize-assetkind
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Failing after 3m23s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Failing after 3m1s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Failing after 2m41s
Project CI / AI game creator shell Rust smoke (pull_request) Failing after 2m20s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Failing after 2m38s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 3m25s
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
af38de9fd1
k88936 added 1 commit 2026-09-19 02:41:30 +08:00
修复 AGC 资源 kind 枚举化后的编译与字符串回退
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Failing after 7m9s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Failing after 7m20s
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Failing after 7m24s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 8m10s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 1m39s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m54s
Project CI / Repository checks (pull_request) Failing after 4m43s
Project CI / Frontend tests (pull_request) Failing after 4m51s
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
5d20f5bfeb
- canvas_generation:参考素材合同四个 helper 改收 GameCreationAppAssetKind,删除 ui-prototype/game-background/art-spritesheet 字符串比较

- direct_runtime:删除 game-background / art-spritesheet 的参考合同字符串映射,直接传枚举

- resource_editor:音效/BGM 编辑类型判据改为比较 ResourceEditSourceKind::Manifest(BackgroundMusic),不再拼字符串 haystack

- assets/commands:画板导入 kind 解析上移到 Tauri 命令边界,import_canvas_asset_at 只接收枚举

- 测试与批量标签脚手架:kind 参数由字符串改为 GameCreationAppAssetKind,恢复编译期穷举保护

- 技术方案:登记边界同口径改为描述命令边界解析
k88936 added 2 commits 2026-09-19 03:25:22 +08:00
- agent/runtime_tools/media.rs:asset_kind 只在入参未声明(空白)时落通道默认值,显式认不出的值保持 Unknown 交给下游失败关闭。
- tests/project.rs:规范图 / 图集用例的入参改传 canonical kind(icon-spec / icon-spritesheet),用例名与断言同步。
修复 AGC 前端资源 kind 判据与用例的 canonical 残留
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Successful in 7m1s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Successful in 7m6s
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Successful in 7m14s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Successful in 7m52s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 1m31s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 1m50s
Project CI / Repository checks (pull_request) Successful in 4m44s
Project CI / Frontend tests (pull_request) Successful in 6m20s
Project CI / Backend tests (pull_request) Successful in 8m27s
Project CI / Native shell tests (pull_request) Successful in 8m15s
Project CI / AI game creator shell web tests (pull_request) Successful in 3m10s
47f7cb2bf1
- resource-canvas/resourceCanvasAssetGenerationReferenceModel.ts:「图集不接受用户参考」判据改用 canonical icon-spritesheet,删除残留平台词的字符串清单。
- view/project-development/index.tsx:美术摘要的图片产出判据显式排除 ui-design,候选 UI 原型图不再顶掉「仅完成计划」。
- tests/appSurface/project-development.suite.ts:generateCall 支持按素材名定位,规范 / 图集 / UI 设计图入口断言改用 canonical kind。
- tests/appSurface/project-assets.suite.ts:/asset-register 与开发面板用例改用 canonical kind,面板默认值按 unknown 断言。
- tests/resourceCanvasAssetGenerationReferences.test.tsx:夹具与提交断言改用 icon-spritesheet / ui-design。
- docs/technical/【AGC】栏目画布底部工具栏入口矩阵-2026-09-13.md:载荷表与规范通道说明改用 canonical kind,并写明平台请求词汇只留在 source.generationKind。
- docs/project-memory/shared-memory/pitfalls.md:记录前端 kind 判据与 fixture 必须一起按 canonical 成员重写。
k88936 merged commit 5383af4cc5 into master 2026-09-19 03:51:33 +08:00
Sign in to join this conversation.