1
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
2026-04-20 21:06:48 +08:00
parent 1c72066bab
commit 75944b1f1f
102 changed files with 9648 additions and 1540 deletions

View File

@@ -0,0 +1,174 @@
# 世界草稿自动资产可见性修复说明 2026-04-20
更新时间:`2026-04-20`
## 1. 问题现象
在世界草稿生成完成后,用户反馈:
1. 草稿里看不到角色主形象
2. 场景里看不到每一幕的背景图
这类反馈容易被误判成“自动资产没有生成”,但实际排查后发现,问题主要集中在**结果页展示链路**,同时叠加了一个**fallback 资源不可预览**的问题。
## 2. 链路排查结论
本轮检查后确认:
1. 服务端自动资产服务会把角色主形象写回 `draftProfile.playableNpcs[].imageSrc / generatedVisualAssetId`
2. 服务端自动资产服务会把幕背景图写回 `draftProfile.sceneChapters[].acts[].backgroundImageSrc / backgroundAssetId`
3. `agent draft -> result profile` 的适配层也会保留这些字段
真正的问题出在后续两个环节。
## 3. 根因
### 3.1 结果页可扮演角色卡优先用了运行时预览
结果页 `CustomWorldEntityCatalog` 的可扮演角色卡,之前优先显示:
1. `previewCharacter`
2. 再回退到 `role.imageSrc`
这会导致:
1. 草稿里已经有真实生成主图
2. 但界面仍优先渲染模板/运行时预览角色
3. 用户视觉上看不到最新生成主形象
### 3.2 场景页没有把多幕背景图真正展示出来
结果页 `场景` Tab 之前只展示:
1. 开局场景
2. 地点卡
但没有把:
`sceneChapterBlueprints[].acts[].backgroundImageSrc`
按可见结构渲染到结果页中。
因此即使后端已经生成并回写每一幕背景图,用户仍然只能看到“场景主图/地点图”,看不到“每一幕的图”。
### 3.3 fallback 自动资产写回的是 `.txt`
在没有 DashScope 图像能力时,`CustomWorldAgentAutoAssetService` 的 fallback 生成器之前会写:
1. 角色主形象:`master.txt`
2. 幕背景图:`scene.txt`
这虽然保证了字段被回写,但前端无法把 `.txt` 当图片展示,于是会进一步加重“好像没生成”的感知。
### 3.4 Agent 结果页入口优先读取 legacyResultProfile遮蔽了最新资产字段
世界草稿结果页不是直接读取当前 `draftProfile`,而是先经过:
1. `buildCustomWorldProfileFromAgentDraft`
2. `normalizeCustomWorldProfileRecord`
如果 `draftProfile.legacyResultProfile` 存在,旧逻辑会直接优先返回这份历史编译结果。
但自动资产服务在 Phase3/Phase4 后续补齐时,更新的是当前 `draftProfile` 中的:
1. `playableNpcs[].imageSrc / generatedVisualAssetId`
2. `storyNpcs[].imageSrc / generatedVisualAssetId`
3. `landmarks[].imageSrc`
4. `sceneChapters[].acts[].backgroundImageSrc / backgroundAssetId`
这会导致:
1. 服务端真实已经生成并回写了最新角色主图和分幕图
2. 结果页入口却仍然取到一份更早的 `legacyResultProfile`
3. 页面看到的是“旧草稿快照”,不是“当前带资产的草稿结果”
因此用户会表现为“完全看不到这轮刚生成出来的图片”。
## 4. 修复策略
### 4.1 结果页角色卡优先显示真实生成主图
`src/components/CustomWorldEntityCatalog.tsx` 中调整逻辑:
1.`role.imageSrc` 已存在,则优先显示该图片
2. 只有在缺失真实主图时,才回退到运行时角色预览
这样可扮演角色卡能直接展示当前草稿回写的角色主形象。
### 4.2 场景列表改为只展示场景卡,章节内容留在二级页
结合后续体验反馈,本轮又进一步收口了结果页结构:
1. `结果页 -> 场景列表` 不再直接展开章节与分幕内容
2. 场景列表卡片只负责展示:
- 场景名
- 场景摘要
- 场景图
3. 场景卡图片优先取该场景章节的首幕 `backgroundImageSrc`
4. 若首幕图缺失,再回退到场景主图 / 地标图
5. 章节标题、幕标题、幕目标等信息只在点击场景后的二级编辑页中查看
这样结果页列表保持清爽,但用户仍然能在列表里直接看到当前场景已生成的图片。
### 4.3 fallback 改为可显示 PNG
`server-node/src/services/customWorldAgentAutoAssetService.ts` 中调整 fallback
1. 不再写 `master.txt / scene.txt`
2. 改为写合法可显示的占位 `png`
3. prompt 信息单独写进 `manifest.json`
4. 角色主形象 fallback PNG 统一输出为 `1:1`
这样即使当前环境没有真实图像生成能力,草稿层也仍然会回写“前端能直接显示的图片资源”。
### 4.4 结果页读取 legacy profile 时强制合并当前草稿的最新资产字段
`src/services/customWorldAgentDraftResult.ts` 中补上合并逻辑:
1. 若存在 `legacyResultProfile`,继续保留它的完整运行时字段
2. 但会把当前 `draftProfile` 里最新回写的角色主图、地标图、分幕图再覆盖回结果页 profile
3. 这样结果页既不会丢失旧 runtime profile 的完整结构,也不会再被旧快照遮蔽最新图片资产
这一层修的是结果页真实入口,而不是仅修展示组件。
## 5. 影响范围
本次修复涉及:
1. `src/components/CustomWorldEntityCatalog.tsx`
2. `src/components/CustomWorldResultView.test.tsx`
3. `src/services/customWorldAgentDraftResult.test.ts`
4. `server-node/src/services/customWorldAgentAutoAssetService.ts`
5. `server-node/src/services/customWorldAgentAutoAssetService.test.ts`
6. `docs/technical/CUSTOM_WORLD_AUTO_ASSET_VISIBILITY_FIX_2026-04-20.md`
7. 历史 saved profile 资产同步脚本 / 数据修复动作
## 6. 验收标准
修复后需要满足:
1. 世界草稿结果页的可扮演角色卡能直接看到生成主形象
2. 世界草稿结果页的场景列表能直接看到场景图片,且优先展示首幕背景图
3. 场景章节与分幕内容只在场景二级页中展示
3. `agent draft -> result profile` 不会丢失角色主图与幕背景字段
4. fallback 环境下回写的仍是前端可显示图片,而不是文本文件
5. 角色主形象 fallback PNG 尺寸必须满足 `1:1`
6. 即使存在 `legacyResultProfile`,结果页也必须展示当前草稿最新同步的角色主图与幕背景图
## 6.1 历史保存档案补充结论
本轮在真实 PostgreSQL 数据中又确认了一类历史问题:
1. `agent session` 中的草稿资产字段可能已经补齐
2. 但较早时刻自动保存过的 `custom_world_profiles.payload_json` 仍停留在旧路径
3. 用户如果从作品库打开的是 saved profile就会继续看到旧图或空图
因此这次修复除了改默认生成与展示逻辑,还需要对受影响的历史 saved profile 做一次同步刷新。
## 7. 后续建议
后续继续迭代这条链路时,建议保持:
1. “资产已生成”必须和“用户已看见”同时验证,不能只验证字段回写
2. 结果页与草稿工作区都要把多幕背景视为正式资产,不要只停留在编辑弹层里
3. 所有 fallback 资源都应保持为 UI 可直接消费的媒体格式

View File

@@ -0,0 +1,149 @@
# 世界草稿生成失败与等待页卡住问题分析 2026-04-20
更新时间:`2026-04-20`
## 1. 问题背景
本次问题表现为:
1. 世界草稿生成过程中实际已经失败。
2. 前端等待页仍然停留在“编译草稿卡”步骤。
3. 用户感知为“卡住不动”,而不是“这一轮失败了,可以返回或重试”。
这个问题不是单点 bug而是由两类问题叠加造成
1. 前端进度映射把 `failed + progress=100` 误解释成“已经跑到最后一个步骤附近”,导致视觉上像卡在 `编译草稿卡`
2. 服务端 `draft_foundation` 主链把自动资产补齐也视为硬依赖,一旦角色主形象或场景幕背景图失败,就会把整版世界底稿一起打成失败。
## 2. 本次链路梳理结论
当前世界草稿生成主链路为:
```text
foundation_review
-> draft_foundation action
-> foundation draft service 生成世界底稿结构
-> auto asset service 补角色主图与幕背景图
-> draft compiler 编译 draftCards
-> session 进入 object_refining
-> 前端等待页切到结果或回工作区
```
其中真正的“必须成功”主链只有两段:
1. `foundation draft` 结构生成成功。
2. `draftCards` 编译成功。
角色主图与幕背景图属于增强链路,不应该阻断世界底稿首版落地。
## 3. 根因拆解
### 3.1 前端等待页状态映射问题
`src/services/customWorldAgentGenerationProgress.ts` 之前只对以下情况做了显式处理:
1. `completed`
2. 匹配某个 `phaseLabel`
3. 兜底按 `progress` 推断当前步骤
但没有对 `failed` 做单独分支。
于是当后端返回:
```text
status = failed
progress = 100
phaseLabel = 底稿生成失败
```
前端仍会按 `progress=100` 去推断步骤,结果高概率落在末尾附近,视觉上就像卡在:
```text
编译草稿卡
```
### 3.2 服务端把增强链路当成硬依赖
`server-node/src/services/customWorldAgentOrchestrator.ts` 中的 `processDraftFoundationOperation` 会在世界底稿生成后调用:
```ts
autoAssetService.populateDraftAssets(...)
```
`populateDraftAssets` 之前的行为是:
1. 角色主图生成失败直接 throw
2. 场景幕背景图生成失败直接 throw
于是自动资产失败会直接中断后续:
```text
draft compiler
session replaceDerivedState
checkpoint
assistant summary
operation completed
```
这会把“本来已经可以用的世界底稿”一并拖死。
## 4. 修复策略
### 4.1 前端修复
`src/services/customWorldAgentGenerationProgress.ts` 中新增显式失败步骤:
1. `failed` 状态不再走 `progress` 推断。
2. 失败时固定返回 `phaseId = failed`
3. 等待页保留已有步骤清单,但不再假装仍有某一步处于 active。
修复后,等待页会明确展示:
1. 当前状态已失败
2. 失败文案与失败详情
3. 用户可以返回工作区或重新生成
### 4.2 服务端修复
`server-node/src/services/customWorldAgentAutoAssetService.ts` 中把自动资产改成“尽力而为”:
1. 角色主形象生成失败时不再 throw而是记录 warning。
2. 幕背景图生成失败时不再 throw而是记录 warning。
3. 主链继续编译 `draftCards`,并让 `assetCoverage` 明确标记哪些资产仍缺失。
`server-node/src/services/customWorldAgentOrchestrator.ts` 中:
1. 如果草稿主链成功,只是资产补齐未完成,则 operation 仍记为 `completed`
2. `phaseDetail` 增加“有若干项资产补齐待后续处理”的说明。
3. assistant summary 也同步说明“这不影响继续精修世界底稿”。
4. 真正失败时,优先保留当前失败阶段的 `phaseLabel/phaseDetail`,避免统一抹平成模糊的“底稿生成失败”。
## 5. 影响范围
本次修改影响以下模块:
1. `src/services/customWorldAgentGenerationProgress.ts`
2. `src/services/customWorldAgentGenerationProgress.test.ts`
3. `server-node/src/services/customWorldAgentAutoAssetService.ts`
4. `server-node/src/services/customWorldAgentAutoAssetService.test.ts`
5. `server-node/src/services/customWorldAgentOrchestrator.ts`
6. `server-node/src/services/customWorldAgentPhase3.test.ts`
## 6. 验收标准
修复后需要满足:
1. 世界草稿主链失败时,等待页明确显示失败,而不是视觉上卡在 `编译草稿卡`
2. 自动资产生成失败时,世界底稿和草稿卡仍然要能生成完成。
3. session 能进入 `object_refining`,用户可以先继续精修结构内容。
4. `assetCoverage` 能反映未补齐的角色图/场景图缺口。
5. 助手消息和 operation 文案都能把“主链完成,增强链路待补”表达清楚。
## 7. 后续建议
后续若继续增强这条链路,建议保持以下原则:
1. 世界结构生成、草稿卡编译属于主链,必须最稳。
2. 角色图、动作、场景图、长尾补齐都属于增强链路,应允许降级。
3. 所有等待页都要有显式失败态映射,禁止仅靠 `progress` 推断最终阶段。
4. 操作失败时优先保留最后一个真实阶段标签,方便定位到底是结构生成失败、资产生成失败,还是写回失败。

View File

@@ -0,0 +1,115 @@
# 自定义世界 Phase4 数量字段语义对齐说明 2026-04-20
更新时间:`2026-04-20`
## 1. 背景
在排查世界草稿生成等待页问题后,继续执行 `server-node` 相关测试时,发现 Phase4 仍有两处失败:
1. `generate_characters` 后草稿作品卡的角色数量没有按预期增长。
2. `generate_landmarks` 的 HTTP 用例对地点数量使用了过时的固定基线。
这两个问题本质上都和“数量字段语义不一致”有关。
## 2. 当前产品语义
创作中心草稿卡在前端展示的是:
```text
角色 X
地点 Y
```
这里的“角色”从产品感知上表示:
**当前草稿中已经长出来、可继续精修的全部角色对象数量。**
而不是:
**仅 playable / 仅主角位角色数量。**
对应地,“地点”表示:
**当前草稿中已经存在的地点对象数量。**
## 3. 之前的偏差
### 3.1 角色数量偏差
`server-node/src/services/customWorldWorkSummaryService.ts` 在草稿态里原先只统计:
```ts
draftProfile.playableNpcs.length
```
但 Phase4 `generate_characters` 的实现是把新增角色插入:
```ts
draftProfile.storyNpcs
```
所以会出现:
1. 角色卡确实新增了
2. `storyNpcs` 也确实变多了
3. 创作中心草稿卡上的“角色数”却没有同步增加
这会让产品表现和数据真实状态不一致。
### 3.2 地点数量断言偏差
`server-node/src/app.test.ts``generate_landmarks` HTTP 用例里,之前写死了:
```ts
assert.ok((sessionPayload.draftProfile?.landmarks?.length ?? 0) >= 6);
```
但当前基础草稿阶段的地点基线已经调整为:
```ts
FOUNDATION_DRAFT_LANDMARK_COUNT = 2
```
所以 Phase4 的正确断言应该是:
```text
在当前会话已有地点基线上,再新增 2 个地点
```
而不是继续沿用旧版本里“基础草稿默认至少 4 个地点”的固定假设。
## 4. 本次修正
### 4.1 草稿摘要角色数
草稿态 `playableNpcCount` 在工作摘要里继续沿用既有字段名,但统计语义调整为:
```text
全部草稿角色数量 = playableNpcs + storyNpcs 去重后的总数
```
原因:
1. 前端现有 contract 和展示字段已经复用 `playableNpcCount`
2. 这次目标是最小修复,不额外扩 contract
3. 草稿态 UI 标签本身展示的是“角色”,不是“可扮演角色”
因此这次保留字段名,修正其在草稿态的统计语义。
### 4.2 Phase4 地点断言
`generate_landmarks` 的 HTTP 用例改为基于当前会话的 `draftProfile.landmarks.length` 做增量校验:
```text
新增后数量 >= 基线数量 + 2
```
这样可以避免未来基础草稿默认地点数再次调整时Phase4 用例继续被写死基线误伤。
## 5. 约束建议
后续涉及草稿作品卡数量字段时,统一遵守:
1. 草稿态“角色”展示全部草稿角色数,不只统计 playable。
2. 已发布态如果 UI 明确写“可扮演角色”,再单独按 playable 统计。
3. 所有数量断言优先使用“当前基线 + 增量”的写法,不要硬编码旧阶段默认数量。

View File

@@ -77,7 +77,7 @@ src/prompts/
- `customWorldSceneNpcPrompts.ts`
- 世界编辑器场景 NPC 生成 prompt
- `characterAssetPrompts.ts`
- 角色主图 / 动作试片 / 角色关联场景 prompt
- 角色主图 / 动作试片正式生成 prompt
- `eightAnchorPrompts.ts`
- 八锚点状态推断、模式规则与正式单轮共创 prompt
- `src/prompts/customWorldPrompts.ts`
@@ -85,7 +85,7 @@ src/prompts/
- `src/prompts/qwenSpriteSheetToolPrompts.ts`
- 精灵图工具主词 / 分镜词 / 修帧词 / 负面词
- `src/prompts/customWorldRolePromptDefaults.ts`
- 角色资产工作台默认 prompt 种子
- 角色资产工作台默认 prompt 种子唯一主源
- `src/prompts/customWorldEntityActionPrompts.ts`
- 编辑器技能动作 prompt
- `packages/shared/src/prompts/qwenSprite.ts`

View File

@@ -6,6 +6,10 @@
- [REPO_NOISE_CLEANUP_BASELINE_2026-04-19.md](./REPO_NOISE_CLEANUP_BASELINE_2026-04-19.md):落实工程清理审计第一阶段后的仓库噪音清理范围、忽略规则闭合点与后续约束。
- [PROMPT_DIRECTORY_MANAGEMENT_2026-04-19.md](./PROMPT_DIRECTORY_MANAGEMENT_2026-04-19.md):后端提示词收口到 `server-node/src/prompts/` 的目录方案、兼容策略与后续新增规则。
- [CUSTOM_WORLD_DRAFT_GENERATION_FAILURE_ANALYSIS_AND_FIX_2026-04-20.md](./CUSTOM_WORLD_DRAFT_GENERATION_FAILURE_ANALYSIS_AND_FIX_2026-04-20.md):世界草稿生成失败后等待页误显示为“卡在编译草稿卡”的根因拆解、主链与增强链路边界,以及本次修复策略。
- [CUSTOM_WORLD_AUTO_ASSET_VISIBILITY_FIX_2026-04-20.md](./CUSTOM_WORLD_AUTO_ASSET_VISIBILITY_FIX_2026-04-20.md):世界草稿里“资产已生成但结果页看不到”的根因拆解,包含角色主形象展示、分幕背景露出和 fallback 资源格式修复。
- [CUSTOM_WORLD_PHASE4_COUNT_SEMANTICS_ALIGNMENT_2026-04-20.md](./CUSTOM_WORLD_PHASE4_COUNT_SEMANTICS_ALIGNMENT_2026-04-20.md)Phase4 新增角色/地点后草稿作品卡数量统计与测试断言的语义对齐说明。
- [TXT_MODE_VISUAL_NOVEL_MIGRATION_EXECUTION_PLAN_2026-04-20.md](./TXT_MODE_VISUAL_NOVEL_MIGRATION_EXECUTION_PLAN_2026-04-20.md):把外部仓库 TXT 模式完整迁入当前项目的冻结边界、模块映射、分阶段计划与验收清单。
- [NODE_SERVER_KNOWLEDGE_GRAPH_2026-04-08.md](./NODE_SERVER_KNOWLEDGE_GRAPH_2026-04-08.md):当前 Node 运行时后端的技术栈、入口、鉴权、存储与接口知识图谱。
- [EXPRESS_BACKEND_INTEGRATION_FREEZE_2026-04-09.md](./EXPRESS_BACKEND_INTEGRATION_FREEZE_2026-04-09.md)Express 后端当前 contract 冻结版本、热点文件编辑规则与集成窗口清单。
- [EXPRESS_BACKEND_WORKSTREAM_AUDIT_2026-04-09.md](./EXPRESS_BACKEND_WORKSTREAM_AUDIT_2026-04-09.md):按并行工作流文档逐项核对后的完成度审计与剩余收口点。

View File

@@ -69,6 +69,11 @@
7. 角色槽位会把第一槽位写回 `primaryNpcId`,其余槽位顺序压缩写回 `encounterNpcIds`
8. 每幕已补上“幕预览”入口,点击后会以独立全屏层启动当前幕运行时预览
9. 保存场景时会把幕配置同步写回 `CustomWorldProfile.sceneChapterBlueprints`
10. 世界档案里的场景详情页已移除“场景图片”和“场景内 NPC”字段相关兼容字段改为从多幕配置自动同步回 `imageSrc / sceneNpcIds`
补充一条等待页体验收口:
10. 世界草稿生成等待页的第二模块标题已从“当前锚点信息”收口为“当前世界信息”,不再显示辅助说明小字,也不再在该模块头部提供“回到工作区”按钮,避免等待态出现重复返回入口
## 2.5 运行时基础层
@@ -82,6 +87,7 @@
6. 幕编辑中的 3 个角色槽位已进一步收敛成贴在背景图上的站位式角色预览,交互与幕预览保持同一位置语义,只显示角色形象与名称
7. 幕预览运行时已补 custom world NPC 的视觉兜底链路,优先使用 `visual / imageSrc` 渲染,避免角色形象或动画空白
8. 当前幕小预览已调整为左侧玩家、右侧敌对/相遇角色的构图NPC 站位采用一前两后
前排主角色与玩家角色保持同一 y 轴后排两个角色改为同一列、x 轴对齐并上下分布,且后排整体 y 轴中点与前排主角色一致
9. 新增幕默认只带 1 个主角色,后续槽位由创作者按需补充
10. 小预览里的名字已移动到角色头顶,角色渲染不再带方形底板,避免遮挡场景背景
@@ -95,6 +101,9 @@
4.`5` 轮会由后端 prompt 强约束生成“铺垫式收束”回复,不再继续生成下一轮聊天建议
5.`5` 轮返回后,前端会自动清掉 `npcChatState`,隐藏输入框,并给出 `继续` 的后续推进入口
6. Adventure 面板会显示当前幕标题与有限聊天剩余轮数
7. 当前幕主角色在本地战斗胜利后,会重新回到 NPC 聊天态,而不是直接掉回普通剧情续写
8. 战后重新开启的聊天会把“战斗结果摘要 + 最近战斗日志”一起写入 `npc_chat` 上下文,保证 NPC 能承接刚刚那场交锋继续说话
9. 若该主角色当前好感仍小于 `0`,战后重新开启的聊天仍按 `5` 轮有限聊天处理,轮数从战后这次重开重新计算
## 3. 当前仍未完成

File diff suppressed because it is too large Load Diff