Add generationStatus and match3d/runtime fixes

Introduce persistent generationStatus to work summaries (puzzle & match3d) and propagate generation recovery rules across docs and frontend/backends so "generating" is restored from server-side work summary rather than ephemeral front-end notices. Update API server image/asset handling (improve match3d material sheet green/alpha decontamination and promote generatedItemAssets background fields) and add runtime improvements: alpha-based hotspot hit-testing, tray insertion/three-match animation behavior, and session re-read on client-side VectorEngine timeouts/lock-screen interruptions. Many docs, tests and related frontend modules updated/added to reflect these contract and behavior changes.
This commit is contained in:
2026-05-16 22:59:02 +08:00
parent bb60ca91ef
commit a45e358e83
42 changed files with 3872 additions and 443 deletions

View File

@@ -22,6 +22,14 @@
- 验证:拼图入口测试仍可通过,且新组件可通过不同页面复用而不需要复制上传卡实现。
- 关联:`src/components/common/CreativeImageInputPanel.tsx``src/components/puzzle-agent/PuzzleAgentWorkspace.tsx`
## 拼图参考图生成草稿报 VectorEngine 编辑接口超时先查降级链路
- 现象:上传参考图并开启 AI 重绘生成拼图草稿时,页面报 `VectorEngine` 编辑接口超时,生成过程显示未到前端长超时上限但草稿失败。
- 原因:参考图 AI 重绘优先走 `/v1/images/edits` multipart旧逻辑在编辑接口超时后直接失败没有改走支持弱参考图的 `/v1/images/generations`
- 处理:`api-server` 只在编辑接口超时类错误时降级到 `/v1/images/generations`,把同一参考图压成 Data URL 后放进 `image` 数组;鉴权、参数、参考图格式等非超时错误仍原样返回。
- 验证:`cargo test -p api-server puzzle_vector_engine --manifest-path server-rs/Cargo.toml` 覆盖超时映射、降级条件和生成请求体携带参考图。
- 关联:`server-rs/crates/api-server/src/puzzle.rs``docs/【玩法创作】平台入口与玩法链路-2026-05-15.md`
## 汪汪声浪重新开放时不要再回到独立配置阶段
- 现象:汪汪声浪入口如果继续切换到独立配置阶段,会和拼图、抓大鹅的创作页内嵌结构不一致,用户会感觉入口跳页。
@@ -262,6 +270,14 @@
- 验证:`npm run test -- src/components/puzzle-result/PuzzleResultView.test.tsx`,以及自动试玩入口测试 `npm run test -- src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx -t "puzzle draft generation auto starts trial"`
- 关联:`docs/【玩法创作】平台入口与玩法链路-2026-05-15.md``docs/【项目基线】当前产品与工程约束-2026-05-15.md``docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`
## 拼图某关生成完成后不要抢占其它关卡编辑面板
- 现象:用户在第 2 关图片生成中继续编辑第 3 关时,第 2 关生成完成回包到达后,结果页关卡详情面板会突然关闭、切回或弹出第 2 关,打断当前输入。
- 原因:生成完成回包只包含后端已知关卡快照,可能不包含本地正在编辑或刚新增的关卡;如果 `activeLevelId` 按回包原始 `levels` 校验,就会把当前本地关卡误判为不存在并清空面板状态。
- 处理:`PuzzleResultView` 收到新 draft 时先通过 `mergeDraftEditStateWithIncomingState(...)` 得到合并后的本地编辑态,再用合并态维护 `activeLevelId``generationRuntimeByLevelId`。生成完成只更新对应关卡素材,不主动打开或切换详情面板。
- 验证:`npm run test -- src/components/puzzle-result/PuzzleResultView.test.tsx -t "keeps the current level dialog open"`
- 关联:`src/components/puzzle-result/PuzzleResultView.tsx``docs/【玩法创作】平台入口与玩法链路-2026-05-15.md`
## 自动草稿成功但缺音乐或 UI 先查后端吞错
- 现象:拼图或抓大鹅生成页提示完成,但草稿页仍显示“暂无音乐”,拼图 UI 仍是默认预览,试玩局内也没有生成音乐或 UI 背景。
@@ -270,6 +286,14 @@
- 验证:`cargo test -p api-server puzzle_initial_draft_assets_must_include_music_and_ui_background match3d_background_music_ready_requires_audio_src match3d_background_music_title_is_required_for_auto_draft --manifest-path server-rs\Cargo.toml`,并重启 `npm run api-server` 后检查 `/healthz`
- 关联:`docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md``docs/【玩法创作】平台入口与玩法链路-2026-05-15.md`
## 草稿生成中态不能只靠前端 notice
- 现象:用户在拼图或抓大鹅生成中退出产品或刷新页面后,作品架上的等待遮罩消失,生成中的草稿看起来像普通草稿。
- 原因:生成中态只停留在前端内存 notice后端 work summary 没有稳定下发 `generationStatus`,刷新后无法重建。
- 处理:作品架和平台入口壳层统一以后端 work summary 的 `generationStatus` 恢复生成中态;前端 notice 只做当前会话的即时反馈。拼图编译草稿时要把 `generating` 写回可持久化的 work profile抓大鹅则用素材和背景完整性回推生成态。
- 验证:刷新或重新进入后仍能看到等待遮罩;`src/components/custom-world-home/creationWorkShelf.test.ts`、拼图 / 抓大鹅 works 合约测试和后端编排测试覆盖恢复。
- 关联:`docs/【玩法创作】平台入口与玩法链路-2026-05-15.md``docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`
## 拼图草稿生成 180 秒后 502/504 先查 VectorEngine 超时与前端重试
- 现象:点击“生成拼图游戏草稿”后,`POST /api/runtime/puzzle/agent/sessions/{sessionId}/actions` 等待约 180 秒返回 `502 Bad Gateway``504 Gateway Timeout`;钱包流水里同一 session 可能出现连续两组 `puzzle_initial_image` 扣费后退款。
@@ -278,6 +302,14 @@
- 验证:运行 `npm run test -- src/services/creation-agent/creationAgentClientFactory.test.ts src/services/apiClient.test.ts``cargo test -p api-server puzzle_vector_engine --manifest-path server-rs/Cargo.toml`,真实联调重启 `npm run api-server` 后检查 `/healthz`
- 关联:`docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md``docs/【玩法创作】平台入口与玩法链路-2026-05-15.md`
## 拼图草稿锁屏后报 VectorEngine 超时先复读 session
- 现象:电脑锁屏、息屏或浏览器后台挂起后,拼图生成页显示 VectorEngine `images/edits` 超时,但页面计时只显示不到 90 秒;稍后草稿或后端 session 里可能已经有生成好的关卡图。
- 原因前端页面生命周期或网络连接先中断HTTP action promise 进入失败分支;后端实际长耗时生图和回写可能仍在继续。若前端直接按失败收尾,会把“前端断连”误报成“服务端生成失败”,且重新打开生成页时若用 `Date.now()` 重建状态,会让已耗时看起来被重置。
- 处理:拼图 action 失败后先 `getPuzzleAgentSession(sessionId)` 复读最新 session只要读到 `draft.coverImageSrc`、首关 `coverImageSrc` 或首关候选图,就把 session 规范成 ready、冻结 `finishedAtMs`、刷新作品架并继续自动试玩/结果页链路。生成页从草稿架恢复时用作品 `updatedAt` 还原 `startedAtMs`,完成/失败态不要继续累加耗时。
- 验证:`npm run test -- src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx -t "embedded puzzle form recovers"``npm run test -- src/services/miniGameDraftGenerationProgress.test.ts``npm run typecheck`
- 关联:`src/components/platform-entry/PlatformEntryFlowShellImpl.tsx``src/services/miniGameDraftGenerationProgress.ts``docs/【玩法创作】平台入口与玩法链路-2026-05-15.md`
## 本地脚本调 VectorEngine 生图卡住先区分 fetch 首部超时
- 现象:用 Node `fetch` 直接请求 `POST /v1/images/generations`,已经设置较长的 AbortController 超时,但仍在约 180 到 300 秒后抛 `AbortError``TypeError: fetch failed``UND_ERR_HEADERS_TIMEOUT`;同一 prompt 改用原生 `https.request` 可以在较短时间内成功返回图片。
@@ -724,8 +756,8 @@
- 现象草稿恢复、结果页素材配置、UI 预览或试玩时仍显示默认背景 / 默认容器,但 work profile 的首个 `generatedItemAssets[].backgroundAsset` 里已经有生成的背景和容器图。
- 原因UI 背景和容器资产没有独立表字段,后端持久化常落在 `generatedItemAssets[].backgroundAsset`;如果 session 映射、结果页 profile、推荐运行态详情补读后不提升到顶层 `generatedBackgroundAsset``backgroundImageSrc`,后续组件会误判“没有生成 UI 资产”。
- 处理Agent session 返回前要用持久化 work profile 资产回填 draft前端进入结果页、构建草稿 profile、推荐 / 公开作品启动运行态前,都要把 `generatedItemAssets[].backgroundAsset` 提升为顶层背景字段。容器图在运行态和 UI 预览复用同一套居中 `object-contain` 样式,移动端宽度接近屏宽,只有缺失或加载失败时才使用透明参考图兜底。
- 验证:`cargo test -p api-server match3d_agent_session_response_hydrates_persisted_ui_assets --manifest-path server-rs/Cargo.toml``npm run test -- src/components/match3d-result/Match3DResultView.test.tsx src/components/match3d-runtime/Match3DRuntimeShell.test.tsx`
- 处理Agent session 返回前要用持久化 work profile 资产回填 draft草稿编译后的 `draft_json` 也必须携带 `generated_item_assets_json` 快照,且 HTTP facade 在 work detail 回读为空时不得清空 draft 内已有 UI 资产。前端进入结果页、构建草稿 profile、作品架 / 广场列表刷新、生成完成自动试玩、结果页手动试玩、推荐 / 公开作品启动运行态前,都要把 `generatedItemAssets[].backgroundAsset` 提升为顶层背景字段。容器图在运行态和 UI 预览复用同一套居中 `object-contain` 样式,移动端宽度略大于屏宽并保持原图比例,只有缺失或加载失败时才使用透明参考图兜底。
- 验证:`cargo test -p api-server match3d_agent_session_response --manifest-path server-rs/Cargo.toml``cargo test -p spacetime-client match3d --manifest-path server-rs/Cargo.toml``cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml``npm run test -- src/components/match3d-result/Match3DResultView.test.tsx src/components/match3d-runtime/Match3DRuntimeShell.test.tsx`
## 抓大鹅重启时不要清空 generated 图片签名缓存
@@ -819,7 +851,7 @@
- 现象:抓大鹅生成的物品视角图裁剪后仍带白边,或者整块纯绿色绿幕背景没有被透明化,运行态看到绿色方块。
- 原因:素材 sheet 可能是“每格内部绿幕、整张图外圈近白底”,内部绿幕不一定连通到 sheet 外边缘;旧 flood fill 只从外边缘找背景会漏掉这种绿幕块。白底抗锯齿如果不纳入抠像和边缘去污染,也会随裁剪输出成一圈白边。即使顺序已是先整张 sheet 去绿再裁剪,较厚的半透明或混色软绿边仍可能低于高置信绿幕阈值,被当作前景带进独立 PNG。
- 处理:`api-server``slice_match3d_material_sheet` 必须先在整张 sheet 上做透明背景后处理:外边缘连通绿幕/近白底清 alpha非连通但高置信纯绿块也清 alpha沿整张 sheet 透明背景继续吃掉软绿边;每个视角单图还要以扩大的 PNG 边界带为种子,把连通的浅绿 / 近白抗锯齿边直接改为透明,再按剩余可见主体收紧裁边,同时保护不够纯的绿色主体像素。不要改成先裁剪单格再去绿。
- 处理:`api-server``slice_match3d_material_sheet` 必须先在整张 sheet 上做透明背景后处理:外边缘连通绿幕/近白底清 alpha非连通但高置信纯绿块也清 alpha沿整张 sheet 透明背景继续吃掉软绿边;每个视角单图还要以扩大的 PNG 边界带为种子,把连通的浅绿 / 近白抗锯齿边直接改为透明,并对贴透明背景的弱绿 / 暗绿轮廓像素做去绿污染处理,再按剩余可见主体收紧裁边,同时保护不够纯的绿色主体像素。不要改成先裁剪单格再去绿。
- 验证:`cargo test -p api-server match3d_material_sheet_slicing --manifest-path server-rs\Cargo.toml` 覆盖非连通绿幕、白边、贴边主体保留和固定 5x5 切图。
- 关联:`docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md``docs/【玩法创作】平台入口与玩法链路-2026-05-15.md`
@@ -865,11 +897,11 @@
## 拼图 UI 背景只有 objectKey 时不要回退默认 UI
- 现象:拼图草稿页、试玩和正式运行态都显示默认 UI或者只在结果页看到生成图进入试玩后又回到默认背景。
- 原因:`uiBackgroundImageSrc` 可能为空而真实生成结果只写了 `uiBackgroundImageObjectKey`;如果前端和运行态只读 `src`,或者本地试玩 / 正式 run 没把 `objectKey` 一起传递,就会丢掉已有背景。
- 处理:统一通过一个解析入口把 `uiBackgroundImageSrc || uiBackgroundImageObjectKey` 归一到可展示路径;本地试玩和正式运行态都要保留 `uiBackgroundImageObjectKey`,并在 `uiBackgroundImageSrc` 为空时换签读取。
- 验证:结果页 UI Tab、`startLocalPuzzleRun``PuzzleRuntimeShell` 都应在仅有 `objectKey` 时显示生成背景,不再回落默认 UI。
- 关联:`src/services/puzzle-runtime/puzzleUiBackgroundSource.ts``src/components/puzzle-result/PuzzleResultView.tsx``src/services/puzzle-runtime/puzzleLocalRuntime.ts``src/components/puzzle-runtime/PuzzleRuntimeShell.tsx``server-rs/crates/module-puzzle/src/application.rs`
- 现象:拼图草稿页、试玩和正式运行态都显示默认 UI或者只在结果页看到生成图进入试玩后又回到默认背景;也可能第一关应用了生成 UI 背景,第二关开始回到默认 UI 背景
- 原因:`uiBackgroundImageSrc` 可能为空而真实生成结果只写了 `uiBackgroundImageObjectKey`;如果前端和运行态只读 `src`,或者本地试玩 / 正式 run 没把 `objectKey` 一起传递,就会丢掉已有背景。多关卡作品里 UI 背景是作品运行态背景,不是只属于第一关的关卡图;如果后续关卡字段为空但运行态只读当前关卡字段,也会回退默认 UI。
- 处理:统一通过一个解析入口把 `uiBackgroundImageSrc || uiBackgroundImageObjectKey` 归一到可展示路径;本地试玩和正式运行态都要保留 `uiBackgroundImageObjectKey`,并在 `uiBackgroundImageSrc` 为空时换签读取。直达指定关卡或推进同作品后续关卡时,按“目标关卡 UI 背景 > 同作品首个可用 UI 背景 > 当前运行态快照背景 > 默认 UI”解析。
- 验证:结果页 UI Tab、`startLocalPuzzleRun``PuzzleRuntimeShell` `module-puzzle` 同作品下一关推进都应在仅有 `objectKey` 或后续关卡缺字段时显示生成背景,不再回落默认 UI。
- 关联:`src/services/puzzle-runtime/puzzleUiBackgroundSource.ts``src/components/puzzle-result/PuzzleResultView.tsx``src/services/puzzle-runtime/puzzleLocalRuntime.ts``src/components/puzzle-runtime/PuzzleRuntimeShell.tsx``server-rs/crates/module-puzzle/src/application.rs``server-rs/crates/spacetime-module/src/puzzle.rs`
## 拼图 UI 背景提示词或作品元信息异常先查首关命名契约
@@ -918,3 +950,19 @@
- 处理:前端标题和选中标签从 `imageSrc` 路径末尾推导,例如 `image.png`;时间解析兼容 ISO 与 `1713686400.000000Z`;创作页主图、历史列表图和结果页参考图继续用 `ResolvedAssetImage`,提交给后端时仍保留原始 `imageSrc`
- 验证:`npm run test -- src/components/puzzle-agent/PuzzleAgentWorkspace.interaction.test.tsx src/components/puzzle-result/PuzzleResultView.test.tsx`,并执行 `npm run check:encoding`
- 关联:`docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md``docs/【玩法创作】平台入口与玩法链路-2026-05-15.md``docs/【项目基线】当前产品与工程约束-2026-05-15.md``docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`
## 抓大鹅透明 PNG 不能只按圆形粗筛命中
- 现象:抓大鹅物体看起来点中了透明边角或 `object-contain` 留白,但局内仍被判定为可点击。
- 原因:仅用中心圆半径做粗筛,会把图片透明角和留白一起算进热区;`itemSize` 缩小后,空白更明显。
- 处理:先用圆形半径做粗筛,再按当前展示图的 alpha 像素做精筛;透明像素、`object-contain` 留白和缩放后的空白区都不能命中。若 alpha 读取失败,再回退粗筛保留可点能力。
- 验证:`npm run test -- src/components/match3d-runtime/match3dHotspot.test.ts`
- 关联:`src/components/match3d-runtime/match3dHotspot.ts``src/components/match3d-runtime/Match3DRuntimeShell.tsx``docs/【玩法创作】平台入口与玩法链路-2026-05-15.md`
## 抓大鹅物品栏插入要按同类后插并在三消后前压补位
- 现象:抓大鹅运行态点击物品后,底部物品栏只是简单追加到第一个空位,导致同类物品顺序被打乱;三件同类凑齐后只是瞬时清空,没有“左右向中间合成再一起消失”的过渡感,后面的物品也不会在视觉上前压补位。
- 原因:前端和后端都曾按“第一个空槽”入槽,没保留同类末尾插入的托盘布局规则;清除后也只做了静态快照更新,没有单独的合成覆盖层和补位动画层。
- 处理:托盘插入统一改成“先找同类最后一个物品,插到它后面;没有同类就追加到末尾”,并在前端为同类三消增加覆盖层动画:三个物品在飞入结束后向托盘中点收拢并淡出,随后后面的托盘物品做前压补位。后端确认逻辑只清当前点击类型的三连,清除后再压缩槽位。
- 验证:`npm run test -- src/services/match3d-runtime/match3dTrayLayout.test.ts src/components/match3d-runtime/match3dHotspot.test.ts src/components/match3d-runtime/Match3DRuntimeShell.test.tsx``cargo test -p module-match3d --manifest-path server-rs/Cargo.toml``npm run typecheck`
- 关联:`src/services/match3d-runtime/match3dTrayLayout.ts``src/services/match3d-runtime/match3dLocalRuntime.ts``src/components/match3d-runtime/Match3DRuntimeShell.tsx``server-rs/crates/module-match3d/src/application.rs`