From 2cd2b9704b8e94399a5243bc3164e8fbc62e75ca Mon Sep 17 00:00:00 2001 From: kdletters <61648117+kdletters@users.noreply.github.com> Date: Thu, 28 May 2026 15:13:20 +0800 Subject: [PATCH] fix puzzle generation failure stage --- .hermes/shared-memory/pitfalls.md | 8 ++++ .../crates/spacetime-module/src/puzzle.rs | 37 ++++++++++++++++++- .../PlatformEntryFlowShellImpl.tsx | 6 +-- ...gEntryFlowShell.agent.interaction.test.tsx | 18 ++++----- 4 files changed, 56 insertions(+), 13 deletions(-) diff --git a/.hermes/shared-memory/pitfalls.md b/.hermes/shared-memory/pitfalls.md index 23371fc5..3dea8cd4 100644 --- a/.hermes/shared-memory/pitfalls.md +++ b/.hermes/shared-memory/pitfalls.md @@ -918,6 +918,14 @@ - 验证:运行 `npm run test -- src\services\assetReadUrlService.test.ts src\hooks\useResolvedAssetReadUrl.test.tsx src\components\puzzle-result\PuzzleResultView.test.tsx`,再触发一次真实生成确认 Network 中先请求 `/api/assets/read-url`,图片 `src` 为未追加 `_v` 的签名 URL。 - 关联:`src/services/assetReadUrlService.ts`、`src/components/ResolvedAssetImage.tsx`、`docs/technical/PUZZLE_IMAGE_ASSET_PROXY_FIX_2026-04-27.md`。 +## 拼图图片生成失败后不要停在 ImageRefining + +- 现象:拼图图片生成失败后,会话仍停留在 `PuzzleAgentStage::ImageRefining`,用户从作品架或生成页恢复时容易被当成生成中/精修中状态,重试入口和失败承接不清晰。 +- 原因:`mark_puzzle_draft_generation_failed_tx` 只把 `PuzzleResultDraft.generation_status` 标成 `failed`,但 session stage 仍沿用旧的 `row.stage`;如果失败前已进入 `ImageRefining`,失败回写不会把会话带回结果草稿态。 +- 处理:失败回写后按失败草稿重新解析 session stage:已发布保持 `Published`,仍满足发布门禁则为 `ReadyToPublish`,否则回到 `DraftReady`;前端生成页文案用“拼图图片生成进度 / 重新生成图片”,避免把失败态误导成还在生成整份草稿。 +- 验证:运行 `cargo check -p spacetime-module --manifest-path server-rs/Cargo.toml`、`npm run check:encoding`,以及拼图生成页恢复相关 `RpgEntryFlowShell.agent.interaction.test.tsx` 定向用例。 +- 关联:`server-rs/crates/spacetime-module/src/puzzle.rs`、`src/components/platform-entry/PlatformEntryFlowShellImpl.tsx`。 + ## 本地短信登录页签突然消失 - 现象:登录弹窗只剩密码登录,短信登录页签看起来像被删掉,但 `LoginScreen` 中手机号验证码表单仍存在。 diff --git a/server-rs/crates/spacetime-module/src/puzzle.rs b/server-rs/crates/spacetime-module/src/puzzle.rs index 1b7c42e5..c5ed877c 100644 --- a/server-rs/crates/spacetime-module/src/puzzle.rs +++ b/server-rs/crates/spacetime-module/src/puzzle.rs @@ -1042,6 +1042,7 @@ fn mark_puzzle_draft_generation_failed_tx( )) } }; + let next_stage = resolve_failed_puzzle_agent_stage(row.stage, &draft); upsert_puzzle_draft_work_profile( ctx, &row.session_id, @@ -1059,7 +1060,7 @@ fn mark_puzzle_draft_generation_failed_tx( seed_text: row.seed_text.clone(), current_turn: row.current_turn, progress_percent: row.progress_percent.max(88), - stage: row.stage, + stage: next_stage, anchor_pack_json: row.anchor_pack_json.clone(), draft_json: Some(serialize_json(&draft)), last_assistant_reply: Some(input.error_message), @@ -1078,6 +1079,21 @@ fn mark_puzzle_draft_generation_failed_tx( ) } +fn resolve_failed_puzzle_agent_stage( + current_stage: PuzzleAgentStage, + draft: &PuzzleResultDraft, +) -> PuzzleAgentStage { + if current_stage == PuzzleAgentStage::Published { + return PuzzleAgentStage::Published; + } + + if build_result_preview(draft, Some("陶泥儿主")).publish_ready { + PuzzleAgentStage::ReadyToPublish + } else { + PuzzleAgentStage::DraftReady + } +} + fn save_puzzle_form_draft_tx( ctx: &TxContext, input: PuzzleFormDraftSaveInput, @@ -3862,6 +3878,25 @@ mod tests { assert_eq!(draft.work_title, "我的猫街合集"); } + #[test] + fn failed_generation_returns_result_draft_stage_instead_of_refining() { + let anchor_pack = infer_anchor_pack("画面描述:一只猫在雨夜灯牌下回头。", None); + let draft = compile_result_draft_from_seed( + &anchor_pack, + &[], + Some("画面描述:一只猫在雨夜灯牌下回头。"), + ); + + assert_eq!( + resolve_failed_puzzle_agent_stage(PuzzleAgentStage::ImageRefining, &draft), + PuzzleAgentStage::DraftReady + ); + assert_eq!( + resolve_failed_puzzle_agent_stage(PuzzleAgentStage::Published, &draft), + PuzzleAgentStage::Published + ); + } + #[test] fn puzzle_recommendation_score_prefers_same_author_weight() { let left = PuzzleWorkProfile { diff --git a/src/components/platform-entry/PlatformEntryFlowShellImpl.tsx b/src/components/platform-entry/PlatformEntryFlowShellImpl.tsx index c025338f..9b9a11f0 100644 --- a/src/components/platform-entry/PlatformEntryFlowShellImpl.tsx +++ b/src/components/platform-entry/PlatformEntryFlowShellImpl.tsx @@ -16653,11 +16653,11 @@ export function PlatformEntryFlowShellImpl({ onInterrupt={undefined} backLabel="返回创作中心" settingActionLabel={null} - retryLabel="重新生成草稿" + retryLabel="重新生成图片" settingTitle="当前拼图信息" settingDescription={null} - progressTitle="拼图草稿生成进度" - activeBadgeLabel="草稿生成中" + progressTitle="拼图图片生成进度" + activeBadgeLabel="图片生成中" idleBadgeLabel="等待返回工作区" hideBatchModule /> diff --git a/src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx b/src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx index 50cb1c8a..5a1303e5 100644 --- a/src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx +++ b/src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx @@ -4273,7 +4273,7 @@ test('running puzzle form generation creates a new puzzle draft on same template ); expect( await screen.findByRole('progressbar', { - name: '拼图草稿生成进度', + name: '拼图图片生成进度', }), ).toBeTruthy(); @@ -4309,7 +4309,7 @@ test('running puzzle form generation creates a new puzzle draft on same template expect( await screen.findByRole('progressbar', { - name: '拼图草稿生成进度', + name: '拼图图片生成进度', }), ).toBeTruthy(); await user.click(screen.getByRole('button', { name: '返回创作中心' })); @@ -4389,7 +4389,7 @@ test('running puzzle draft opens generation progress from draft tab', async () = ); expect( await screen.findByRole('progressbar', { - name: '拼图草稿生成进度', + name: '拼图图片生成进度', }), ).toBeTruthy(); @@ -4403,7 +4403,7 @@ test('running puzzle draft opens generation progress from draft tab', async () = expect( await screen.findByRole('progressbar', { - name: '拼图草稿生成进度', + name: '拼图图片生成进度', }), ).toBeTruthy(); expect(screen.queryByText('拼图结果页')).toBeNull(); @@ -5390,7 +5390,7 @@ test('embedded puzzle form recovers when compile request times out after backend }); expect(screen.queryByText('执行拼图操作失败。')).toBeNull(); expect(screen.queryByText('请求超时:90000ms')).toBeNull(); - expect(screen.queryByText('拼图草稿生成进度')).toBeNull(); + expect(screen.queryByText('拼图图片生成进度')).toBeNull(); expect(startLocalPuzzleRun).toHaveBeenCalledTimes(1); }); @@ -7416,13 +7416,13 @@ test('persisted generating puzzle draft opens generation progress after refresh' }); expect( await screen.findByRole('progressbar', { - name: '拼图草稿生成进度', + name: '拼图图片生成进度', }), ).toBeTruthy(); expect( Number( screen - .getByRole('progressbar', { name: '拼图草稿生成进度' }) + .getByRole('progressbar', { name: '拼图图片生成进度' }) .getAttribute('aria-valuenow'), ), ).toBe(0); @@ -7481,7 +7481,7 @@ test('persisted generating puzzle draft keeps session polling on the same sessio expect( await screen.findByRole('progressbar', { - name: '拼图草稿生成进度', + name: '拼图图片生成进度', }), ).toBeTruthy(); @@ -7529,7 +7529,7 @@ test('puzzle compile timeout shows failure dialog when reread session is still g expect(within(dialog).getByRole('button', { name: '复制报错' })).toBeTruthy(); expect( await screen.findByRole('progressbar', { - name: '拼图草稿生成进度', + name: '拼图图片生成进度', }), ).toBeTruthy(); });