Merge branch 'master' into codex/ddd
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
- [技术方案](./technical/README.md):动画、服务端、外部产品形态拆解。
|
||||
- [规划与优先级](./planning/README.md):当前阶段的迭代排序与落地优先级。
|
||||
- [参考目录](./reference/README.md):脚本/Function 速查入口。
|
||||
重点补充:RPG 创作与运行时脚本职责地图见 [RPG_CREATION_AND_RUNTIME_SCRIPT_RESPONSIBILITY_MAP_2026-04-28.md](./reference/RPG_CREATION_AND_RUNTIME_SCRIPT_RESPONSIBILITY_MAP_2026-04-28.md)。
|
||||
- [PRD](./prd):产品需求与阶段计划;新增 RPG 开场动画方案见 [AI_NATIVE_RPG_OPENING_ANIMATION_PRD_2026-04-25.md](./prd/AI_NATIVE_RPG_OPENING_ANIMATION_PRD_2026-04-25.md)。
|
||||
|
||||
## 推荐阅读顺序
|
||||
|
||||
@@ -17,6 +17,10 @@
|
||||
- [CUSTOM_WORLD_CREATOR_TOOL_AUDIT_2026-04-08.md](./CUSTOM_WORLD_CREATOR_TOOL_AUDIT_2026-04-08.md):自定义世界创作工具当前问题、体验断层和优化优先级审计。
|
||||
- [AGENT_TO_DRAFT_TO_WORLD_PIPELINE_AUDIT_2026-04-20.md](./AGENT_TO_DRAFT_TO_WORLD_PIPELINE_AUDIT_2026-04-20.md):Agent 聊天、草稿生成、作品库存储与进入世界之间的断点、多 pipeline、冗余与未实装项审计。
|
||||
- [CHARACTER_ASSET_PROMPT_CHAIN_AUDIT_2026-04-20.md](./CHARACTER_ASSET_PROMPT_CHAIN_AUDIT_2026-04-20.md):角色资产默认描述文本、正式图像/动作 prompt、共享模板与保留接口的分层与冗余审计。
|
||||
- [RPG_RUNTIME_DIRECT_DRAFT_PROFILE_AUDIT_2026-04-25.md](./RPG_RUNTIME_DIRECT_DRAFT_PROFILE_AUDIT_2026-04-25.md):RPG 运行时进入世界时改为直读 Agent session 草稿 profile 的链路检查。
|
||||
- [RPG_WORLD_DRAFT_EDIT_AUTOSAVE_OVERRIDE_AUDIT_2026-04-28.md](./RPG_WORLD_DRAFT_EDIT_AUTOSAVE_OVERRIDE_AUDIT_2026-04-28.md):RPG 世界草稿结果页编辑后被旧设定覆盖的前端本地态、session 真相源与自动保存链路审计。
|
||||
- [engineering/RPG_FRONTEND_SCRIPT_BACKEND_MIGRATION_AUDIT_2026-04-28.md](./engineering/RPG_FRONTEND_SCRIPT_BACKEND_MIGRATION_AUDIT_2026-04-28.md):RPG 前端脚本中仍应迁到 `server-rs` / SpacetimeDB 的开局、快照、story engine、战斗、NPC/背包规则与创作残留后门审计。
|
||||
- [engineering/RPG_FRONTEND_SCRIPT_BACKEND_MIGRATION_COMPLETION_CHECK_2026-04-28.md](./engineering/RPG_FRONTEND_SCRIPT_BACKEND_MIGRATION_COMPLETION_CHECK_2026-04-28.md):RPG 前端脚本后端迁移完成度复核,标明开局、快照、story engine / prompt context、`camp_travel_home_scene`、战斗、NPC、背包/锻造、结果页保存 normalize 与角色资产 prompt 主链均已收口。
|
||||
- [engineering/ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-20.md](./engineering/ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-20.md):对 `2026-04-19` 工程清理审计的当前仓库复核,区分已完成项、仍存边界问题和新的热点迁移。
|
||||
- [engineering/ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-19.md](./engineering/ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-19.md):未引用垃圾、旧入口残留、前后端双份真相与后端迁移项的专项审计。
|
||||
|
||||
|
||||
@@ -0,0 +1,233 @@
|
||||
# RPG 世界草稿编辑后被旧设定覆盖问题审计 2026-04-28
|
||||
|
||||
## 1. 问题摘要
|
||||
|
||||
当前 RPG 世界草稿结果页存在一条明显的“本地编辑态与 Agent session 真相源分叉”问题链:
|
||||
|
||||
1. 用户在结果页编辑世界设定时,前端只更新本地 `generatedCustomWorldProfile`。
|
||||
2. Agent 草稿会话里的 `draftProfile / resultPreview.preview` 并不会随着这次编辑同步更新。
|
||||
3. 自动保存触发时,系统又会优先重新拉取 session 最新快照,并以 session 返回的 profile 作为最终保存内容。
|
||||
4. 如果 session 里仍是编辑前旧设定,那么前端刚刚改过的内容就会被旧快照覆盖回来。
|
||||
|
||||
所以,这个问题表面看起来像“自动保存覆盖了我刚保存的内容”,本质上是:
|
||||
|
||||
- 结果页编辑写到了前端内存态;
|
||||
- 自动保存落库前又改为优先相信 session 真相;
|
||||
- 但 session 真相本身没有承接这次编辑。
|
||||
|
||||
## 2. 当前主链证据
|
||||
|
||||
### 2.1 结果页编辑只改前端本地 profile
|
||||
|
||||
`src/components/platform-entry/PlatformEntryFlowShellImpl.tsx:2637-2640`
|
||||
|
||||
- `RpgCreationResultView` 的 `onProfileChange` 只调用:
|
||||
- `sessionController.setGeneratedCustomWorldProfile(normalizeAgentBackedProfile(profile))`
|
||||
- 这里没有触发任何 `update_draft_card`、`sync_result_profile` 或其它后端写回动作。
|
||||
|
||||
这意味着结果页里的“保存修改”目前只是更新前端内存中的 `generatedCustomWorldProfile`。
|
||||
|
||||
### 2.2 结果页展示数据优先来自 session 预览
|
||||
|
||||
`src/services/rpg-creation/rpgCreationPreviewAdapter.ts:27-33`
|
||||
|
||||
- `buildCustomWorldProfileFromAgentSession()` 当前优先读取:
|
||||
- `session.resultPreview.preview`
|
||||
- 若没有,再回退到:
|
||||
- `session.draftProfile.legacyResultProfile`
|
||||
|
||||
也就是说,Agent 结果页最终重新打开、重新同步或重新计算时,主数据源仍是 session 快照,而不是用户刚改过的前端本地对象。
|
||||
|
||||
### 2.3 自动保存前会先刷新 session,并优先保存 session 返回的最新结果
|
||||
|
||||
`src/components/rpg-entry/useRpgCreationResultAutosave.ts:181-236`
|
||||
|
||||
- `syncAgentDraftResultProfile()` 在 session 与前端 profile 签名不一致时,不再把前端 profile 回写 session。
|
||||
- 它只会执行:
|
||||
- `syncAgentSessionSnapshot(activeAgentSessionId)`
|
||||
- 然后把拉回来的 session profile 重新塞回:
|
||||
- `setGeneratedCustomWorldProfile(latestProfile)`
|
||||
|
||||
`src/components/rpg-entry/useRpgCreationResultAutosave.ts:326-340`
|
||||
|
||||
- 自动保存延迟触发后,如果当前是 Agent 草稿结果页:
|
||||
1. 先调用 `syncAgentDraftResultProfile(profileToSave)`
|
||||
2. 再把 `syncedResult.profile ?? profileToSave` 作为最终要入库的 profile
|
||||
|
||||
也就是:
|
||||
|
||||
- 自动保存不是直接保存用户刚改的前端 profile;
|
||||
- 它会先“向 session 对齐”;
|
||||
- 对齐后优先保存 session 返回的新 profile。
|
||||
|
||||
如果 session 里还是旧设定,那么保存和界面都会一起回滚到旧设定。
|
||||
|
||||
## 3. 当前测试口径也在强化这条行为
|
||||
|
||||
### 3.1 单测明确要求“不触发 sync_result_profile,只保存 session 最新草稿”
|
||||
|
||||
`src/components/rpg-entry/useRpgEntryAgentDraftRestore.test.tsx:195-276`
|
||||
|
||||
这条测试验证的是:
|
||||
|
||||
1. 前端当前持有的是 `oldProfile`
|
||||
2. `syncAgentSessionSnapshot()` 返回的是 `latestSession`
|
||||
3. 自动保存最终必须保存 `latestSession.draftProfile`
|
||||
4. 并且明确断言不应触发 `sync_result_profile`
|
||||
|
||||
这说明现有实现不是偶然漏掉了 session 写回,而是被当前测试和实现共同锁定为:
|
||||
|
||||
- “自动保存只刷新 session,不回写前端结果页编辑态”
|
||||
|
||||
### 3.2 交互测试也要求“结果页自动保存优先保存 session 最新快照”
|
||||
|
||||
`src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx:2867-3006`
|
||||
|
||||
这条测试进一步验证:
|
||||
|
||||
1. 结果页最终保存的对象应来自 `syncedSession.resultPreview.preview`
|
||||
2. 不应触发 `sync_result_profile`
|
||||
|
||||
所以现在的覆盖行为不是单点 bug,而是当前结果页保存架构的直接产物。
|
||||
|
||||
## 4. 系统层面的根因拆解
|
||||
|
||||
### 4.1 双真相源并存
|
||||
|
||||
当前至少同时存在两份“看起来都像真相”的数据:
|
||||
|
||||
1. 前端结果页本地 `generatedCustomWorldProfile`
|
||||
2. Agent session 内的 `draftProfile / resultPreview.preview`
|
||||
|
||||
结果页编辑写前者,自动保存与恢复又优先读后者,所以只要两边没有同事务同步,就一定会出现覆盖风险。
|
||||
|
||||
### 4.2 编辑动作没有接入正式后端写回动作
|
||||
|
||||
仓库契约和 Rust 模块实际上已经存在两条正式动作:
|
||||
|
||||
- `update_draft_card`
|
||||
- `sync_result_profile`
|
||||
|
||||
证据:
|
||||
|
||||
- `packages/shared/src/contracts/rpgAgentActions.ts`
|
||||
- `server-rs/crates/spacetime-module/src/custom_world/mod.rs`
|
||||
|
||||
其中:
|
||||
|
||||
- `update_draft_card` 适合基于卡片/section 的结构化修改写回 `draftProfile`
|
||||
- `sync_result_profile` 适合把结果页完整 profile 回写 session 并重建 preview
|
||||
|
||||
但当前结果页 `onProfileChange` 没有接入这两条正式链路,导致“编辑成功”只停留在本地内存态。
|
||||
|
||||
### 4.3 自动保存策略与编辑链路不一致
|
||||
|
||||
自动保存的当前设计目标是正确的:
|
||||
|
||||
- 不再轻易把旧前端快照反向污染 session
|
||||
- 优先保存 session 最新快照,避免把陈旧 preview 写进作品库
|
||||
|
||||
但前提应该是:
|
||||
|
||||
- 结果页编辑本身已经先进入 session 真相源
|
||||
|
||||
现在前提不成立,于是自动保存的“防旧快照污染”策略,反过来变成了“用 session 旧值覆盖用户刚编辑的新值”。
|
||||
|
||||
### 4.4 结果页定位混乱
|
||||
|
||||
当前结果页同时承担了两种角色:
|
||||
|
||||
1. 预览/发布页
|
||||
2. 可深度编辑的草稿编辑器
|
||||
|
||||
但现有数据链路更偏向第 1 种:
|
||||
|
||||
- 数据来自 session preview
|
||||
- 自动保存优先对齐 session preview
|
||||
|
||||
而 UI 行为却提供了第 2 种能力:
|
||||
|
||||
- 用户可以直接改世界、角色、场景等内容
|
||||
|
||||
两种定位没有统一,最终表现就是“能编辑,但编辑不能稳定进入主真相源”。
|
||||
|
||||
## 5. 用户视角下的实际故障表现
|
||||
|
||||
从用户体感看,当前问题会表现为以下几种:
|
||||
|
||||
1. 刚改完字段,短暂显示新内容,随后自动回弹为旧内容。
|
||||
2. 页面提示“已自动保存”,但重新进入草稿页后仍然是旧设定。
|
||||
3. 某些字段改了能停留一会儿,触发自动保存或 session 刷新后又被覆盖。
|
||||
4. 用户会误以为“保存按钮坏了”或“自动保存有缓存问题”,但真实原因是保存目标和展示真相源不一致。
|
||||
|
||||
## 6. 影响范围
|
||||
|
||||
这个问题不只影响“世界简介文本”,而是整个结果页编辑体系:
|
||||
|
||||
1. 世界基础信息编辑
|
||||
2. 角色编辑
|
||||
3. 场景编辑
|
||||
4. 封面/派生内容依赖当前 profile 的场景
|
||||
5. 结果页返回、恢复、自动打开、发布前预览一致性
|
||||
|
||||
只要编辑发生在 `generatedCustomWorldProfile`,但没有进入 session 真相源,就都有同类风险。
|
||||
|
||||
## 7. 建议修复方向
|
||||
|
||||
### 7.1 第一优先级:统一结果页编辑的唯一真相源
|
||||
|
||||
推荐二选一,不要继续混用:
|
||||
|
||||
1. 结果页只做预览,不允许直接编辑复杂设定
|
||||
2. 结果页继续允许编辑,但每次保存必须先落到 session 真相源,再更新本地显示
|
||||
|
||||
按当前产品形态,更合理的是第 2 条。
|
||||
|
||||
### 7.2 如果保留结果页编辑,建议采用的正式链路
|
||||
|
||||
1. 世界/角色/场景编辑保存时,优先调用 Rust/SpacetimeDB 的正式动作写回 session。
|
||||
2. 能用 `update_draft_card` 的地方尽量走结构化 section 更新。
|
||||
3. 对无法被 card section 覆盖的完整 profile 级编辑,再评估是否保留 `sync_result_profile`,或新增更细粒度 reducer。
|
||||
4. session 写回完成后,再重新读取 session 并刷新结果页。
|
||||
5. 自动保存只负责“把已经写进 session 的最新真相同步到作品库”,不要再承担“猜测该保存前端还是 session”的职责。
|
||||
|
||||
### 7.3 自动保存策略需要降级为“作品库存档层”,不要兼任“session 真相协调层”
|
||||
|
||||
当前自动保存同时承担:
|
||||
|
||||
1. 防止旧前端快照污染 session
|
||||
2. 选择最终保存哪份 profile
|
||||
3. 刷新结果页显示
|
||||
|
||||
职责太重,也导致覆盖问题难以定位。
|
||||
|
||||
建议改为:
|
||||
|
||||
1. 编辑保存阶段:负责写 session
|
||||
2. 自动保存阶段:只负责把 session 已确认真相落作品库
|
||||
3. 结果页渲染阶段:只读 session 最新快照
|
||||
|
||||
### 7.4 需要补的测试口径
|
||||
|
||||
当前测试主要在保护“不要再触发 `sync_result_profile` 污染 session”。
|
||||
|
||||
后续修复后,至少要补以下测试:
|
||||
|
||||
1. 用户编辑世界基础字段后,session `draftProfile / resultPreview` 会同步更新。
|
||||
2. 自动保存不会把 session 旧值覆盖到刚编辑的新值上。
|
||||
3. 刷新页面或重新进入结果页后,看到的是编辑后的新设定。
|
||||
4. 进入世界、发布世界、继续扩展时,消费的是同一份最新 session 真相。
|
||||
|
||||
## 8. 结论
|
||||
|
||||
这次问题的核心结论是:
|
||||
|
||||
1. 你的判断“像是自动保存问题”是对的,但更准确地说,是“自动保存对齐 session 时,覆盖了未写回 session 的本地编辑态”。
|
||||
2. 当前结果页编辑没有接上正式的 session 写回链路,这是第一根断点。
|
||||
3. 当前自动保存被设计成优先信任 session 最新快照,这是第二根断点。
|
||||
4. 两个断点叠加后,就形成了“编辑后又自动变回原设定”的现象。
|
||||
|
||||
如果后续要真正修掉这个问题,重点不该是单独调 debounce 时间或加一个“防抖保存中”提示,而是:
|
||||
|
||||
- 把结果页编辑动作重新接回 Rust/SpacetimeDB 的 session 真相源;
|
||||
- 让自动保存只负责作品库存档,不再替代编辑写回链路做裁决。
|
||||
@@ -10,21 +10,25 @@
|
||||
这一版是第六批落地记录,聚焦删除无入口 `questDirector`、旧观察文案 helper、一次性硬编码同步脚本,并补齐后端运行时 function catalog 契约覆盖。
|
||||
3. [ENGINEERING_DEAD_CODE_CLEANUP_BATCH_E_2026-04-21.md](./ENGINEERING_DEAD_CODE_CLEANUP_BATCH_E_2026-04-21.md)
|
||||
这一版是第五批落地记录,聚焦旧命名 re-export、空路由骨架、旧发布服务、前端 prompt 镜像与无入口编辑器壳层的物理删除。
|
||||
4. [FRONTEND_LOGIC_BACKEND_MIGRATION_AUDIT_2026-04-21.md](./FRONTEND_LOGIC_BACKEND_MIGRATION_AUDIT_2026-04-21.md)
|
||||
4. [RPG_FRONTEND_SCRIPT_BACKEND_MIGRATION_AUDIT_2026-04-28.md](./RPG_FRONTEND_SCRIPT_BACKEND_MIGRATION_AUDIT_2026-04-28.md)
|
||||
这一版专项扫描 `src/` 下 RPG 开头脚本,明确运行时开局、快照、story engine、战斗后处理、NPC/背包规则和创作链残留后门中应迁到 `server-rs` 的逻辑。
|
||||
5. [RPG_FRONTEND_SCRIPT_BACKEND_MIGRATION_COMPLETION_CHECK_2026-04-28.md](./RPG_FRONTEND_SCRIPT_BACKEND_MIGRATION_COMPLETION_CHECK_2026-04-28.md)
|
||||
这一版复核 RPG 前端脚本后端迁移完成度,确认开局、快照、存档、story engine / prompt context、`camp_travel_home_scene`、NPC、背包/锻造、战斗后处理、结果页保存前 normalize 与角色资产 prompt 主链均已收口。
|
||||
6. [FRONTEND_LOGIC_BACKEND_MIGRATION_AUDIT_2026-04-21.md](./FRONTEND_LOGIC_BACKEND_MIGRATION_AUDIT_2026-04-21.md)
|
||||
这一版是本轮前端越界逻辑专项审计,专门汇总当前仍应继续迁到 `server-rs` 的运行时、鉴权、生成编排与本地真相残留。
|
||||
5. [ENGINEERING_DEAD_CODE_CLEANUP_BATCH_D_2026-04-21.md](./ENGINEERING_DEAD_CODE_CLEANUP_BATCH_D_2026-04-21.md)
|
||||
7. [ENGINEERING_DEAD_CODE_CLEANUP_BATCH_D_2026-04-21.md](./ENGINEERING_DEAD_CODE_CLEANUP_BATCH_D_2026-04-21.md)
|
||||
这一版是第四批落地记录,聚焦未接入业务的数据生成产物、测试专用 stub 与对应配置残留出清。
|
||||
6. [ENGINEERING_DEAD_CODE_CLEANUP_BATCH_C_2026-04-21.md](./ENGINEERING_DEAD_CODE_CLEANUP_BATCH_C_2026-04-21.md)
|
||||
8. [ENGINEERING_DEAD_CODE_CLEANUP_BATCH_C_2026-04-21.md](./ENGINEERING_DEAD_CODE_CLEANUP_BATCH_C_2026-04-21.md)
|
||||
这一版是第三批落地记录,聚焦鉴权真相收口,先移除前端保存自动登录用户名/密码的本地真相,并明确运行时快照前置写入为什么当前还不能硬砍。
|
||||
7. [ENGINEERING_DEAD_CODE_CLEANUP_BATCH_B_2026-04-21.md](./ENGINEERING_DEAD_CODE_CLEANUP_BATCH_B_2026-04-21.md)
|
||||
9. [ENGINEERING_DEAD_CODE_CLEANUP_BATCH_B_2026-04-21.md](./ENGINEERING_DEAD_CODE_CLEANUP_BATCH_B_2026-04-21.md)
|
||||
这一版是第二批落地记录,聚焦旧主流程壳层、旧 bootstrap 和旧 inventory / forge / equipment flow Hook 的正式出清。
|
||||
8. [ENGINEERING_DEAD_CODE_CLEANUP_BATCH_A_2026-04-21.md](./ENGINEERING_DEAD_CODE_CLEANUP_BATCH_A_2026-04-21.md)
|
||||
10. [ENGINEERING_DEAD_CODE_CLEANUP_BATCH_A_2026-04-21.md](./ENGINEERING_DEAD_CODE_CLEANUP_BATCH_A_2026-04-21.md)
|
||||
这一版是第一批落地记录,聚焦高置信度小型孤岛、prompt 壳子、stub 和无入口 modal 的首轮清理。
|
||||
9. [CURRENT_ENGINEERING_OPTIMIZATION_OPPORTUNITIES_2026-04-20.md](./CURRENT_ENGINEERING_OPTIMIZATION_OPPORTUNITIES_2026-04-20.md)
|
||||
11. [CURRENT_ENGINEERING_OPTIMIZATION_OPPORTUNITIES_2026-04-20.md](./CURRENT_ENGINEERING_OPTIMIZATION_OPPORTUNITIES_2026-04-20.md)
|
||||
这一版是面向当前仓库状态的优化点盘点,适合直接拿来排优先级和拆执行批次。
|
||||
10. [ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-20.md](./ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-20.md)
|
||||
12. [ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-20.md](./ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-20.md)
|
||||
这一版是对 `2026-04-19` 基线的当前仓库复核,明确哪些问题已经处理、哪些表述需要纠正、热点又迁移到了哪里。
|
||||
11. [ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-19.md](./ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-19.md)
|
||||
13. [ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-19.md](./ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-19.md)
|
||||
这一版保留原始问题快照和执行回填,适合回看“为什么会有这轮清理与边界收口”。
|
||||
## 融合结论
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+177
@@ -0,0 +1,177 @@
|
||||
# RPG 前端脚本后端迁移完成度核验(2026-04-28)
|
||||
|
||||
## 1. 核验结论
|
||||
|
||||
本次按 `RPG_FRONTEND_SCRIPT_BACKEND_MIGRATION_AUDIT_2026-04-28.md` 中列出的应迁后端项逐项检查当前代码。
|
||||
|
||||
结论:**应迁移项已全部迁移完成。**
|
||||
|
||||
当前状态:
|
||||
|
||||
1. `已完成`:10 项。
|
||||
2. `部分完成`:0 项。
|
||||
3. `未发现完全未启动`:0 项。
|
||||
|
||||
本轮重新核查的变化:
|
||||
|
||||
1. 上次残留的 `RPG 创作结果页` 保存前 profile normalize 已完成后端化。
|
||||
2. `camp_travel_home_scene` 已完成后端收口:正式点击统一走 `/api/runtime/story/actions/resolve`,目标场景、encounter preview、`scenesTraveled` 与快照持久化由 `server-rs` 裁决。
|
||||
|
||||
## 2. 核验口径
|
||||
|
||||
### 2.1 判定为已完成
|
||||
|
||||
满足以下条件才记为已完成:
|
||||
|
||||
1. 前端不再构造正式业务状态。
|
||||
2. 前端不再上传完整 `GameState` 作为后端写入依据。
|
||||
3. 前端不再用本地规则裁决价格、库存、掉落、复活、章节推进、结果页真相优先级。
|
||||
4. 前端只保留请求封装、UI 展示、表单草稿、loading/error、动画表现和按钮禁用展示。
|
||||
|
||||
### 2.2 判定为部分完成
|
||||
|
||||
满足以下任一情况记为部分完成:
|
||||
|
||||
1. 主链已经迁到 `server-rs`,但旧前端分支仍可被正式入口调用。
|
||||
2. 后端已经提供 view/action,但前端仍保留影响业务真相的 normalize、fallback 或 AI context 编排。
|
||||
3. 后端只覆盖部分状态机,前端仍负责另一部分正式状态推进。
|
||||
|
||||
## 3. 逐项结果
|
||||
|
||||
| 原审计项 | 当前状态 | 核验结论 |
|
||||
| --- | --- | --- |
|
||||
| `P0` 运行时开局 `GameState` 装配 | 已完成 | 正式开局状态由 `server-rs/crates/api-server/src/runtime_story/compat/bootstrap.rs` 创建并持久化;前端 `useRpgSessionBootstrap.ts` 只保留选择页占位态和 `beginRpgRuntimeStorySession(...)` 调用。 |
|
||||
| `P0` runtime story 网关客户端快照解析/补丁 | 已完成 | `rpgRuntimeStoryGateway.ts` 不再有 `buildRuntimeSnapshotRequest` / `bridgeServer*Snapshot`;`rpgRuntimeStoryClient.ts` 读取 `/state/:sessionId`,动作提交 `/actions/resolve`,不再上传完整 `snapshot.gameState/currentStory`。 |
|
||||
| `P0` 自动保存整份运行时快照 | 已完成 | `useRpgSessionPersistence.ts` / `rpgSnapshotClient.ts` 保存链路只提交 `sessionId/bottomTab` checkpoint;`runtime_save.rs` 从服务端已有快照刷新 checkpoint,并测试拒绝旧式完整快照上传。 |
|
||||
| `P0` story engine / chapter / world mutation / prompt context 编排 | 已完成 | 后端已有 `project_story_engine_after_action(...)` 与 `build_runtime_story_prompt_context(...)`,`/story/initial`、`/story/continue` 带 `sessionId` 时只从服务端 snapshot 投影 world / character / history / prompt context;`camp_travel_home_scene` 正式点击也已统一进入后端 resolver,不再由前端拼装场景迁移、encounter preview 或 runtimeStats。 |
|
||||
| `P0` 战斗胜负后处理、死亡复活、战斗后章节推进 | 已完成 | `battle_* / inventory_use` 正式点击统一走 `runServerRuntimeChoiceAction(...)` 与后端 `/actions/resolve`;`storyChoiceContinuation.ts` 对战斗 / 逃脱 / 物品动作加硬保护,不再裁决掉落、任务推进、死亡复活或战后 story;旧 `postBattleFlow.ts` 正式状态构造函数已删除。 |
|
||||
| `P1` NPC 交易/送礼价格数量库存校验 | 已完成 | 前端 `npcInteraction.ts` 已改为消费 `runtimeNpcInteraction` view 并只提交 `{ mode, itemId, quantity }`;后端 `npc_actions.rs` / `npc_support.rs` 负责价格、库存、货币、赠礼好感和原子更新。 |
|
||||
| `P1` 背包/装备/锻造可用性与配方视图 | 已完成 | 前端 `inventoryActions.ts` 读取 `loadRpgRuntimeInventoryView(...)`,根据后端 action/view 提交;后端 `view_model.rs` / `forge.rs` 生成背包、装备槽、配方、`canCraft/enabled/reason`。 |
|
||||
| `P1` RPG 创作 profile 生成 legacy AI 回退 | 已完成 | `rpgCreationGenerationClient.ts` 只调用 `/api/runtime/custom-world/profile`,不再动态 `import('../ai')` 或导出 `generateLegacyCustomWorldProfile`。 |
|
||||
| `P1` 创作结果页保存与 Agent session/result preview 真相优先级 | 已完成 | 后端已提供 `GET /api/runtime/custom-world/agent/sessions/:sessionId/result-view`,统一 `targetStage/profileSource/canAutosaveLibrary/canSyncResultProfile`,前端不再直接读取 `legacyResultProfile`;保存前 canonicalize 已迁到 `server-rs`,`normalizeRpgEntryAgentBackedProfile(...)` 现在只透传兼容旧导入。 |
|
||||
| `P1` 角色资产工坊默认 prompt 与缓存合并规则 | 已完成 | 默认 prompt、legacy prompt 过滤、逐动作缓存合并已在 `server-rs/crates/api-server/src/prompt/rpg/role_asset_studio.rs`;前端 modal 只调用 workflow API、保存用户草稿和发起生成/发布。 |
|
||||
|
||||
## 4. 已完成的具体收尾点
|
||||
|
||||
### 4.1 story engine / prompt context 主链与 `camp_travel_home_scene` 已完成后端收口
|
||||
|
||||
当前后端已经处理动作结算后的确定性 story projector:
|
||||
|
||||
1. `server-rs/crates/module-runtime-story-compat/src/story_engine.rs`
|
||||
2. `server-rs/crates/api-server/src/runtime_story/compat.rs`
|
||||
|
||||
本轮已补齐 prompt context 后端 projector:
|
||||
|
||||
1. `server-rs/crates/module-runtime-story-compat/src/prompt_context.rs`
|
||||
2. `server-rs/crates/api-server/src/runtime_story/compat.rs`
|
||||
3. `server-rs/crates/api-server/src/runtime_chat.rs`
|
||||
4. `server-rs/crates/api-server/src/runtime_chat_plain.rs`
|
||||
|
||||
完成状态:
|
||||
|
||||
1. 前端不再决定 `conversationSituation`、`conversationPressure`、NPC 对话上下文、party relationship notes、scene pressure 文本等正式 prompt context。
|
||||
2. 前端 story initial / continue 在有 `runtimeSessionId` 时只提交 `sessionId / clientVersion / choice / lastFunctionId / requestOptions` 等轻量字段。
|
||||
3. 后端从已持久化 runtime snapshot 投影 `worldType / playerCharacter / sceneHostileNpcs / storyHistory / context`,旧 payload 字段只保留兼容。
|
||||
4. 角色私聊、NPC 对话、NPC 单轮聊天、NPC 招募对话已支持 `sessionId`,有 session 时上下文同样以后端 snapshot 为准。
|
||||
5. 前端奖励领取、NPC 聊天闭合与旧 `deferredRuntimeState` 兼容分支不再写入 `storyEngineMemory`,章节、scene act、thread、world mutation 等正式叙事记忆只以后端快照为准。
|
||||
|
||||
本轮验收:
|
||||
|
||||
1. `cargo test -p module-runtime-story-compat prompt_context --manifest-path server-rs\Cargo.toml` 覆盖后端 prompt context projector 对场景、NPC 披露阶段、对话压力和关系态度的投影。
|
||||
2. `cargo test -p shared-contracts runtime_story_ai_request --manifest-path server-rs\Cargo.toml` 覆盖 story AI 请求可只携带 `sessionId` 的共享契约。
|
||||
3. `cargo test -p api-server runtime_story_initial_uses_server_snapshot_prompt_context_when_session_id_present --manifest-path server-rs\Cargo.toml` 覆盖 `/story/initial` 在 session 模式下以后端快照覆盖浏览器传入的 world / character / context。
|
||||
4. `npm run test -- src/services/ai.test.ts src/hooks/rpg-runtime-story/storyRequestCoordinator.test.ts src/hooks/rpg-runtime-story/useRpgRuntimeStoryController.test.tsx` 覆盖前端 story / chat 请求在 session 模式下只发送轻量 payload。
|
||||
5. `npm run test -- src/hooks/rpg-runtime-story/sessionActions.test.ts src/hooks/rpg-runtime-story/choiceActions.test.ts src/hooks/rpg-runtime-story/npcEncounterActions.test.ts` 覆盖前端旧 UI 分支不再回写后端拥有的 `storyEngineMemory`。
|
||||
|
||||
本轮收尾:
|
||||
|
||||
1. `packages/shared/src/contracts/rpgRuntimeStoryAction.ts` 已把 `camp_travel_home_scene` 纳入 `TASK5_RUNTIME_FUNCTION_IDS` / `SERVER_RUNTIME_FUNCTION_IDS`。
|
||||
2. `server-rs/crates/api-server/src/runtime_story/compat.rs` 的 `camp_travel_home_scene` resolver 已承接前端旧分支的正式状态职责:解析目标场景、写入 `currentScenePreset`、清理战斗/遭遇残留、递增 `scenesTraveled`、生成 encounter preview,并让后续故事和持久化继续走后端 snapshot 主链。
|
||||
3. 目标场景解析以后端为准:优先接收兼容 payload 中的 `targetSceneId`,其次使用内置角色主场景映射,自定义世界按角色与 landmark 绑定解析,再回退到当前场景前向连接或首个冒险场景。
|
||||
4. `src/hooks/rpg-runtime-story/choiceActions.ts` 不再调用 `runCampTravelHomeChoice(...)`,`camp_travel_home_scene` 即使命中旧展示 helper,也会按服务端 function id 统一进入 `runServerRuntimeChoiceAction(...)`。
|
||||
5. `src/hooks/rpg-runtime-story/storyChoiceRuntime.ts` 已删除 `runCampTravelHomeChoice(...)`,前端不再保留正式场景迁移构造函数。
|
||||
|
||||
已消除风险:
|
||||
|
||||
1. `camp_travel_home_scene` 不再由浏览器决定目标场景、运行时统计或 encounter preview。
|
||||
2. 正式离营状态已经满足“前端只提交 action,后端返回 hydrated snapshot”的边界。
|
||||
|
||||
本轮验收补充:
|
||||
|
||||
1. `cargo test -p api-server runtime_story_route_boundary_camp_travel_home_scene_is_server_owned --manifest-path server-rs\Cargo.toml` 覆盖点击后 hydrated snapshot 进入角色主场景、生成 encounter preview、递增 `scenesTraveled` 并持久化。
|
||||
2. `cargo test -p api-server runtime_story --manifest-path server-rs\Cargo.toml` 覆盖 runtime story 相关后端回归。
|
||||
3. `npm run test -- src/hooks/rpg-runtime-story/choiceActions.test.ts` 覆盖 `camp_travel_home_scene` 只调用后端 resolver,不触发旧本地旅行分支。
|
||||
4. `npm run test -- src/hooks/rpg-runtime-story/storyChoiceRuntime.test.ts src/services/rpg-runtime/rpgRuntimeStoryClient.test.ts` 覆盖服务端 runtime choice presentation 与 story client 轻量 payload。
|
||||
|
||||
### 4.2 本地战斗 continuation 已收口到后端
|
||||
|
||||
当前后端已经有战斗终局收口:
|
||||
|
||||
1. `server-rs/crates/module-runtime-story-compat/src/post_battle.rs`
|
||||
2. `server-rs/crates/module-runtime-story-compat/src/battle.rs`
|
||||
3. `server-rs/crates/api-server/src/runtime_story/compat.rs`
|
||||
|
||||
本轮已完成前端旧正式分支收口:
|
||||
|
||||
1. `src/hooks/rpg-runtime-story/choiceActions.ts` 不再保留 `shouldResolveCombatChoiceLocally(...)`,所有服务端 function id 都统一进入 `runServerRuntimeChoiceAction(...)`。
|
||||
2. `src/hooks/rpg-runtime-story/storyChoiceContinuation.ts` 对 `battle_* / inventory_use` 以及被分类为 `battle / escape` 的动作加硬保护,误入时只报错回退,不会写掉落、任务、复活或战后 story。
|
||||
3. `src/hooks/rpg-runtime-story/storyChoiceRuntime.ts` 删除本地敌对 NPC 掉落 reward helper,不再调用 `rollHostileNpcLoot(...)` / `addInventoryItems(...)` 构造正式战斗奖励。
|
||||
4. `src/hooks/rpg-runtime-story/postBattleFlow.ts` 与对应测试删除,前端不再保留 `buildPostBattleVictoryState(...)`、`buildPostBattleVictoryStory(...)`、`buildRevivedFirstSceneState(...)`、`buildDeathStory(...)` 作为正式状态构造入口。
|
||||
|
||||
已消除风险:
|
||||
|
||||
1. `battle_* / inventory_use` 不再因 `inBattle`、`currentBattleNpcId`、可见 story option 等状态回落到本地结算。
|
||||
2. 本地 continuation 不再调用敌对 NPC 掉落、背包合并、敌对 NPC 任务推进。
|
||||
3. 前端不再构造死亡复活状态、胜利后 story、deferred options 和章节推进。
|
||||
|
||||
本轮验收:
|
||||
|
||||
1. `choiceActions.test.ts` 覆盖 `battle_use_skill`、`battle_attack_basic` stale option、`inventory_use` 均只调用后端 resolver,不触发 `buildResolvedChoiceState(...)` / `playResolvedChoice(...)`。
|
||||
2. `storyChoiceRuntime.test.ts` 保留服务端 battle presentation 验收,确认胜利 / 失败最终采用服务端 hydrated snapshot。
|
||||
3. 搜索确认 `src/hooks/rpg-runtime-story` 不再包含 `shouldResolveCombatChoiceLocally`、`buildPostBattleVictory*`、`buildRevivedFirstSceneState`、`buildDeathStory`、`buildHostileNpcBattleReward`。
|
||||
|
||||
### 4.3 创作结果页保存前 normalize 已完成后端化
|
||||
|
||||
后端已经负责 Agent result-view:
|
||||
|
||||
1. `server-rs/crates/api-server/src/custom_world.rs`
|
||||
2. `packages/shared/src/contracts/rpgCreationResultView.ts`
|
||||
3. `src/services/rpg-creation/rpgCreationAgentClient.ts`
|
||||
|
||||
重新核查结果:
|
||||
|
||||
1. `src/components/rpg-entry/rpgEntryShared.ts`
|
||||
2. `src/components/rpg-entry/useRpgCreationResultAutosave.ts`
|
||||
3. `server-rs/crates/api-server/src/custom_world.rs`
|
||||
|
||||
当前完成状态:
|
||||
|
||||
1. `normalizeRpgEntryAgentBackedProfile(...)` 现在直接返回原始 `profile`,注释明确保存前 canonicalize 已迁到 `server-rs`。
|
||||
2. `stringifyRpgEntryAgentBackedProfile(...)` 现在只做 `JSON.stringify(profile)`,不再触发前端 normalize。
|
||||
3. `put_custom_world_library_profile(...)` 写入作品库前调用 `canonicalize_custom_world_library_profile_payload(payload.profile)`。
|
||||
4. `serialize_sync_result_profile_action_payload(...)` 会在 Agent `sync_result_profile` action payload 中对 `profile` 执行 `canonicalize_custom_world_profile_before_save(...)`。
|
||||
5. 后端测试 `sync_result_profile_payload_is_canonicalized_on_server` 与 `custom_world_library_profile_payload_is_canonicalized_on_server` 已覆盖保存前 canonicalize。
|
||||
|
||||
本项不再计为未迁移残留。
|
||||
|
||||
## 5. 已完成项的保留边界
|
||||
|
||||
以下前端残留可以保留,不视为未迁移:
|
||||
|
||||
1. `useRpgSessionBootstrap.ts` 的 `createSelectionGameState()`:只服务选择页占位,正式开局不使用它造运行时真相。
|
||||
2. `NpcModals.tsx` 的数量 stepper、价格展示和按钮禁用:只消费后端 view,不重新裁决价格或库存。
|
||||
3. `inventoryActions.ts` 的 `submitInventoryAction(...)`:只读取后端 action 的 `enabled/reason`,不本地计算规则。
|
||||
4. 角色资产工坊 modal 中的 prompt 输入框与缓存保存:这是用户正在编辑的 UI 草稿,默认 prompt 和合并规则已由后端 workflow 输出。
|
||||
5. `playServerBattlePresentation(...)`:只播放临时动画态,最终 `GameState/currentStory` 仍以服务端 snapshot 为准。
|
||||
|
||||
## 6. 后续建议
|
||||
|
||||
本轮核验范围内的应迁项已经收口。后续建议转为质量维护:
|
||||
|
||||
1. 继续把 function catalog / 旧文档里“本地规则结算”的历史描述逐批改成当前后端归属,避免误导后续开发。
|
||||
2. 新增 runtime function 时先补后端 resolver / view / contract,再让前端接展示入口,保持“前端不造正式状态”的边界。
|
||||
3. 对仍保留的前端本地 continuation 只允许处理非服务端 function id;凡进入 `SERVER_RUNTIME_FUNCTION_IDS` 的动作都应有 route 级测试。
|
||||
|
||||
## 7. 一句话结论
|
||||
|
||||
**当前迁移已经完成开局、快照、存档、story engine / prompt context 主链、`camp_travel_home_scene` 离营迁移、NPC、背包/锻造、战斗后处理、profile 生成、创作结果页 normalize 和角色资产 prompt 主链;本核验范围内不再保留前端正式状态裁决残留。**
|
||||
@@ -0,0 +1,33 @@
|
||||
# 平台入口隐藏大鱼吃小鱼创作入口设计
|
||||
|
||||
日期:`2026-04-28`
|
||||
|
||||
## 1. 变更背景
|
||||
|
||||
平台当前“选择创作类型”弹层同时暴露 RPG、大鱼吃小鱼、拼图三类入口。
|
||||
|
||||
本轮需求只要求在平台里隐藏“大鱼吃小鱼”的创作入口,不要求删除已有玩法实现、运行时路由、作品数据或后台能力。
|
||||
|
||||
## 2. 落地边界
|
||||
|
||||
- 只调整平台入口层展示,不修改大鱼吃小鱼已有前后端链路。
|
||||
- 不删除 `big-fish` 相关路由、服务、作品详情、运行时与数据结构。
|
||||
- 隐藏策略应收敛到统一配置层,避免首页、弹层、后续复用入口出现显示状态漂移。
|
||||
|
||||
## 3. 实现方案
|
||||
|
||||
1. 在 `src/components/platform-entry/platformEntryCreationTypes.ts` 的创作类型元数据中增加 `hidden` 字段。
|
||||
2. 将 `big-fish` 类型标记为 `hidden: true`。
|
||||
3. 平台创作类型弹层渲染前统一过滤 `hidden` 项。
|
||||
|
||||
这样可以保证:
|
||||
|
||||
- 平台用户看不到“大鱼吃小鱼”创作入口。
|
||||
- 若后续重新开放,只需改回配置,不必再拆 UI 逻辑。
|
||||
- 不影响既有直达路由、历史作品数据和开发中的玩法链路。
|
||||
|
||||
## 4. 验收点
|
||||
|
||||
- 平台“选择创作类型”弹层不再显示“大鱼吃小鱼”卡片。
|
||||
- RPG、拼图、“敬请期待”类卡片顺序与交互保持稳定。
|
||||
- 代码层不引入对 Big Fish 运行时或结果页的额外耦合修改。
|
||||
@@ -11,6 +11,7 @@
|
||||
- [CUSTOM_WORLD_SELF_OWNED_SETTING_LAYER_OPTIMIZATION_2026-04-08.md](./CUSTOM_WORLD_SELF_OWNED_SETTING_LAYER_OPTIMIZATION_2026-04-08.md):把模板依赖逐步迁成自定义世界自有设定层,并保证不破坏当前生成流程的优化方案。
|
||||
- [MOBILE_CREATION_NEW_WORK_COMPACT_LAYOUT_2026-04-24.md](./MOBILE_CREATION_NEW_WORK_COMPACT_LAYOUT_2026-04-24.md):移动端创作页新建作品模块最多占用首屏约 1/3 高度的紧凑布局设计。
|
||||
- [PLATFORM_CATEGORY_AND_CREATE_TAB_DESIGN_2026-04-24.md](./PLATFORM_CATEGORY_AND_CREATE_TAB_DESIGN_2026-04-24.md):平台入口新增分类 Tab、登录态导航裁剪与创作 Tab 视觉强化设计。
|
||||
- [PLATFORM_BIG_FISH_ENTRY_HIDE_2026-04-28.md](./PLATFORM_BIG_FISH_ENTRY_HIDE_2026-04-28.md):平台入口暂时隐藏大鱼吃小鱼创作卡片,但保留现有玩法链路。
|
||||
- [UNIFIED_MODAL_WINDOW_DESIGN_2026-04-25.md](./UNIFIED_MODAL_WINDOW_DESIGN_2026-04-25.md):统一平台风与 RPG 像素风模态窗口外壳、交互边界和迁移顺序。
|
||||
- [AI_NATIVE_RUNTIME_ITEM_SYSTEM_REDESIGN_2026-04-02.md](./AI_NATIVE_RUNTIME_ITEM_SYSTEM_REDESIGN_2026-04-02.md):运行时物品生成系统重设计。
|
||||
- [LEVEL_PROGRESS_AND_CHAPTER_NPC_AUTO_SCALING_DESIGN_2026-04-20.md](./LEVEL_PROGRESS_AND_CHAPTER_NPC_AUTO_SCALING_DESIGN_2026-04-20.md):等级成长、章节经验节奏与 NPC 自动定级设计。
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
# 大鱼吃小鱼草稿生成链路修复 2026-04-28
|
||||
|
||||
## 背景
|
||||
|
||||
大鱼吃小鱼玩法的结果页已经具备等级卡、主图工坊、动作工坊和背景工坊,但当前 `big_fish_compile_draft` 只是把锚点交给 `module-big-fish` 的 `compile_default_draft(...)` 做静态模板拼装。
|
||||
|
||||
这会导致两个直接问题:
|
||||
|
||||
1. 草稿编译虽然能成功进入结果页,但每一级实体只会拿到非常概括的模板文本,无法真正产出“实体名称、文字描述、形象描述、待机动作描述、移动动作描述”这一组首稿。
|
||||
2. 主图和动作工坊默认提示词没有绑定到一份足够细的草稿真相源,动作面板只能看到合并后的 `motionPromptSeed`,会表现成“草稿生成一带而过,所有内容都没有正常生成”。
|
||||
|
||||
## 本次修复口径
|
||||
|
||||
### 1. 每级等级蓝图必须补齐的文本字段
|
||||
|
||||
大鱼吃小鱼每一级 `level blueprint` 在保留原有字段的同时,新增并持久化下面这些文本真相:
|
||||
|
||||
1. `textDescription`
|
||||
- 当前等级实体的正文文字描述。
|
||||
- 用于结果页等级卡和后续重生成时的人类可读设定底稿。
|
||||
2. `visualDescription`
|
||||
- 当前等级实体的形象描述。
|
||||
- 主图工坊默认输入内容直接取这份字段。
|
||||
3. `idleMotionDescription`
|
||||
- 当前等级待机动作描述。
|
||||
- `idle_float` 动作工坊默认输入内容直接取这份字段。
|
||||
4. `moveMotionDescription`
|
||||
- 当前等级移动动作描述。
|
||||
- `move_swim` 动作工坊默认输入内容直接取这份字段。
|
||||
|
||||
### 2. 默认提示词流转规则
|
||||
|
||||
草稿生成、结果页工坊和正式资产生成统一按下面口径流转:
|
||||
|
||||
1. 草稿编译阶段先产出上述结构化文本字段。
|
||||
2. 主图工坊默认文案:
|
||||
- 优先显示 `visualDescription`
|
||||
- `visualPromptSeed` 作为主图正式生图提示词的冻结快照,可由 `visualDescription` 组合生成
|
||||
3. 动作工坊默认文案:
|
||||
- `idle_float` 优先显示 `idleMotionDescription`
|
||||
- `move_swim` 优先显示 `moveMotionDescription`
|
||||
- `motionPromptSeed` 继续保留为动作方向总提示词摘要,但具体动作正式生图必须显式拼入动作位对应描述
|
||||
4. 草稿阶段生成的正式主图、动作图和后续重生成,都只能读取同一份 `draft.levels[*]` 真相,前端不得本地拼接新的设定文案。
|
||||
|
||||
### 3. 编译策略
|
||||
|
||||
`big_fish_compile_draft` 需要升级为:
|
||||
|
||||
1. `api-server` 先调用 LLM 做结构化草稿编译。
|
||||
2. 若 LLM 成功,则把完整 `draft_json` 写回 SpacetimeDB。
|
||||
3. 若 LLM 不可用、返回非法 JSON 或字段缺失,则退回 `compile_default_draft(...)` 的 deterministic fallback。
|
||||
|
||||
这样可以同时保证:
|
||||
|
||||
1. 正常环境下草稿不再只是模板壳。
|
||||
2. 模型偶发失败时不会打断结果页主链。
|
||||
3. SpacetimeDB reducer 不承担外部网络调用,仍然符合后端边界。
|
||||
|
||||
## 落地范围
|
||||
|
||||
本次修复涉及:
|
||||
|
||||
1. `server-rs/crates/module-big-fish`
|
||||
2. `server-rs/crates/spacetime-module`
|
||||
3. `server-rs/crates/spacetime-client`
|
||||
4. `server-rs/crates/shared-contracts`
|
||||
5. `server-rs/crates/api-server`
|
||||
6. `packages/shared/src/contracts/bigFish.ts`
|
||||
7. `src/components/big-fish-result/BigFishResultView.tsx`
|
||||
|
||||
## 验收口径
|
||||
|
||||
修复后需要满足下面这些观察结果:
|
||||
|
||||
1. 点击“生成草稿”后,`draft.levels[*]` 不再只有空泛模板,而是每级都带名称、文字描述、形象描述、待机动作描述、移动动作描述。
|
||||
2. 打开主图工坊时,默认文本来自当前等级的 `visualDescription`。
|
||||
3. 打开待机动作工坊时,默认文本来自当前等级的 `idleMotionDescription`。
|
||||
4. 打开移动动作工坊时,默认文本来自当前等级的 `moveMotionDescription`。
|
||||
5. 资产槽位 `promptSnapshot` 与对应动作位 / 主图位的默认提示词一致。
|
||||
6. LLM 不可用时仍然能生成一版可用 fallback 草稿,而不是直接报错或写入空草稿。
|
||||
@@ -0,0 +1,27 @@
|
||||
# 拼图本地运行态通关排行榜误请求修复记录
|
||||
|
||||
## 问题现象
|
||||
|
||||
拼图关卡完成后,右下角会弹出错误提示,内容表现为拼图 `run` 不存在。
|
||||
|
||||
## 根因
|
||||
|
||||
当前拼图玩法仍有一条前端本地兜底链路:
|
||||
|
||||
1. 进入拼图测试或公开作品体验时,前端先创建 `local-puzzle-run-*` 形式的本地运行态。
|
||||
2. 这类 `run` 只存在于前端内存,不存在后端持久化记录。
|
||||
3. 通关副作用里却统一调用了后端 `submitPuzzleLeaderboard(runId, payload)`。
|
||||
4. 后端拿到本地 `runId` 后无法找到真实记录,于是返回“run 不存在”,最终在运行时右下角暴露成错误提示。
|
||||
|
||||
## 修复口径
|
||||
|
||||
本次不改后端接口,也不把本地兜底 run 强行持久化到后端,而是先把边界收口到前端:
|
||||
|
||||
1. 显式识别 `local-puzzle-run-*` 这类本地 run。
|
||||
2. 本地 run 通关后不再请求后端排行榜接口。
|
||||
3. 直接在前端本地生成只包含当前玩家成绩的排行榜数据,保证结算弹窗仍可展示成绩。
|
||||
4. 真实后端 run 仍继续走正式排行榜提交流程,不影响后续 Rust / SpacetimeDB 版本的统一收口。
|
||||
|
||||
## 经验结论
|
||||
|
||||
只要某条玩法链路还保留“本地 run / 本地快照”兜底,就不能在通关、副作用、排行榜、下一关等后置动作里默认把它当成后端真 run 使用。必须先做运行态来源分流,再决定是否调用依赖真实 runId 的接口。
|
||||
@@ -32,3 +32,5 @@
|
||||
- [AGENT_EMPTY_SESSION_DRAFT_VISIBILITY_2026-04-26.md](./AGENT_EMPTY_SESSION_DRAFT_VISIBILITY_2026-04-26.md):记录 Agent 空会话不应进入作品草稿列表的后端判定规则。
|
||||
- [BIG_FISH_PUBLISH_FEEDBACK_FIX_2026-04-26.md](./BIG_FISH_PUBLISH_FEEDBACK_FIX_2026-04-26.md):记录大鱼吃小鱼发布成功后结果页反馈与作品列表刷新的修复口径。
|
||||
- [BIG_FISH_WORKS_JSON_COMPAT_FIX_2026-04-28.md](./BIG_FISH_WORKS_JSON_COMPAT_FIX_2026-04-28.md):记录大鱼作品列表 `items_json` 字段升级后的向后兼容修复口径,避免旧 JSON 直接打崩 works 接口。
|
||||
- [BIG_FISH_DRAFT_GENERATION_CHAIN_FIX_2026-04-28.md](./BIG_FISH_DRAFT_GENERATION_CHAIN_FIX_2026-04-28.md):记录大鱼吃小鱼草稿生成从结构化内容产出到主图/动作默认提示词回填的修复口径。
|
||||
- [PUZZLE_LOCAL_RUN_LEADERBOARD_FIX_2026-04-28.md](./PUZZLE_LOCAL_RUN_LEADERBOARD_FIX_2026-04-28.md):记录拼图本地 run 通关后误请求后端排行榜、导致“run 不存在”报错的边界修复口径。
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
新系统必须满足:
|
||||
|
||||
1. 可解释:玩家能理解“为什么这个角色擅长这个”“为什么这个 NPC 会喜欢这种行为”“为什么这个怪物在这个世界里是这种威胁”。
|
||||
2. 可生成:自定义世界可以稳定生成新属性名称与定义。
|
||||
2. 可生成:自定义世界可以稳定生成新属性名称。
|
||||
3. 可校验:AI 输出不能直接裸写进运行时,必须经过本地验证。
|
||||
4. 可复用:同一套属性 schema 能进入角色、怪物、技能、Build、物品、对话 prompt。
|
||||
5. 可迁移:能从当前四维属性 / 标签 / 怪物 preset 平滑过渡。
|
||||
@@ -165,12 +165,6 @@ type WorldAttributeSchema = {
|
||||
slots: Array<{
|
||||
slotId: string;
|
||||
name: string;
|
||||
definition: string;
|
||||
positiveSignals: string[];
|
||||
negativeSignals: string[];
|
||||
combatUseText: string;
|
||||
socialUseText: string;
|
||||
explorationUseText: string;
|
||||
}>;
|
||||
};
|
||||
```
|
||||
@@ -178,12 +172,9 @@ type WorldAttributeSchema = {
|
||||
### 关键原则
|
||||
|
||||
1. `slotId` 是稳定技术标识,例如 `axis_a` ~ `axis_f`。
|
||||
2. `name` 是世界内真实显示名称,例如武侠里可能不是“力量”,而是“骨势”“身法”。
|
||||
3. `definition` 必须描述角色本质倾向,而不是派生战斗数值。
|
||||
4. 每个属性都必须能解释:
|
||||
- 战斗中的体现
|
||||
- 对话中的体现
|
||||
- 探索中的体现
|
||||
2. 本世界六维名称在创作、提示词输出、解析后保存的数据中只保留 `name`;其他定义、信号和用途说明字段不再进入 schema。
|
||||
3. `name` 是世界内真实显示名称,例如武侠里可能不是“力量”,而是“骨势”“身法”。
|
||||
4. 六个名称需要能支撑战斗、对话、探索的叙事理解,但这些说明由下游运行时按场景生成,不写入 schema。
|
||||
|
||||
### 禁止项
|
||||
|
||||
@@ -247,16 +238,9 @@ type AttributeSchemaGenerationInput = {
|
||||
|
||||
```ts
|
||||
type AttributeSchemaGenerationOutput = {
|
||||
schemaName: string;
|
||||
slots: Array<{
|
||||
slotId: string;
|
||||
name: string;
|
||||
definition: string;
|
||||
positiveSignals: string[];
|
||||
negativeSignals: string[];
|
||||
combatUseText: string;
|
||||
socialUseText: string;
|
||||
explorationUseText: string;
|
||||
}>;
|
||||
};
|
||||
```
|
||||
@@ -267,13 +251,9 @@ AI 输出后必须通过本地校验:
|
||||
|
||||
1. 属性数量必须等于 6。
|
||||
2. `name` 需唯一,长度建议 `2~4` 个中文字符。
|
||||
3. `definition` 不得出现“提升攻击力 / 提升防御力 / 提升生命值”这类派生描述。
|
||||
4. 每个属性都必须同时具备:
|
||||
- 一个战斗说明
|
||||
- 一个社交说明
|
||||
- 一个探索说明
|
||||
5. 任意两条属性定义关键词重叠度不能过高。
|
||||
6. 若校验失败:
|
||||
3. `name` 不得出现“生命 / 法力 / 护甲 / 攻击 / 防御 / 力量 / 敏捷 / 智力 / 精神”这类旧四维或派生资源词。
|
||||
4. 任意两个属性名称不能重复,也不能只做同义换皮。
|
||||
5. 若校验失败:
|
||||
- 预设世界回退到固化 schema
|
||||
- 自定义世界回退到模板世界 schema,并记录失败日志
|
||||
|
||||
@@ -283,25 +263,25 @@ AI 输出后必须通过本地校验:
|
||||
|
||||
### 武侠世界示例
|
||||
|
||||
| 属性名 | 定义 |
|
||||
| 槽位 | 属性名 |
|
||||
| --- | --- |
|
||||
| 骨势 | 扛压、顶冲、硬吃风险也不退的势头 |
|
||||
| 身法 | 腾挪、抢位、换线、把握出手节奏的能力 |
|
||||
| 眼脉 | 看破破绽、拆招、识局、看穿人心的能力 |
|
||||
| 心焰 | 决断、压迫、胆气、在局面中立住自身意志的能力 |
|
||||
| 尘缘 | 与人事、情面、承诺、牵引关系打交道的能力 |
|
||||
| 玄息 | 调息、稳态、久战、把自身维持在可用状态的能力 |
|
||||
| axis_a | 骨势 |
|
||||
| axis_b | 身法 |
|
||||
| axis_c | 眼脉 |
|
||||
| axis_d | 心焰 |
|
||||
| axis_e | 尘缘 |
|
||||
| axis_f | 玄息 |
|
||||
|
||||
### 仙侠世界示例
|
||||
|
||||
| 属性名 | 定义 |
|
||||
| 槽位 | 属性名 |
|
||||
| --- | --- |
|
||||
| 道骨 | 承载道压与高强度冲击的底子 |
|
||||
| 灵行 | 位移、御空、转场、抢占天时地利的能力 |
|
||||
| 识海 | 解析禁制、洞察因果、识破虚实的能力 |
|
||||
| 心契 | 与他者、器物、灵兽、誓约建立共鸣的能力 |
|
||||
| 劫纹 | 在高危变化中强行推进、改写局势的能力 |
|
||||
| 玄息 | 循环灵息、稳住心神、让自身持续在线的能力 |
|
||||
| axis_a | 道骨 |
|
||||
| axis_b | 灵行 |
|
||||
| axis_c | 识海 |
|
||||
| axis_d | 心契 |
|
||||
| axis_e | 劫纹 |
|
||||
| axis_f | 玄息 |
|
||||
|
||||
关键点:
|
||||
|
||||
@@ -692,10 +672,8 @@ AI 不可以直接生成:
|
||||
|
||||
```ts
|
||||
type PromptAttributeSummary = {
|
||||
schemaName: string;
|
||||
slots: Array<{
|
||||
name: string;
|
||||
definition: string;
|
||||
}>;
|
||||
actorTopAttributes: string[];
|
||||
targetTopAttributes?: string[];
|
||||
@@ -726,12 +704,6 @@ export type AttributeVector = Record<string, number>;
|
||||
export interface WorldAttributeSlot {
|
||||
slotId: string;
|
||||
name: string;
|
||||
definition: string;
|
||||
positiveSignals: string[];
|
||||
negativeSignals: string[];
|
||||
combatUseText: string;
|
||||
socialUseText: string;
|
||||
explorationUseText: string;
|
||||
}
|
||||
|
||||
export interface WorldAttributeSchema {
|
||||
@@ -1017,8 +989,8 @@ behaviorVectors: Array<{
|
||||
|
||||
对策:
|
||||
|
||||
1. 增加本地定义重叠校验
|
||||
2. 强制每个属性都写战斗 / 社交 / 探索三种说明
|
||||
1. 增加本地名称重复、旧词和同义换皮校验
|
||||
2. 提示词要求六个名称覆盖不同叙事气质,避免全部落在同一种行动倾向上
|
||||
3. 首版预设世界采用固化 schema,不在运行时漂移
|
||||
|
||||
### 风险 2:过度抽象,策划难以配置
|
||||
@@ -1029,8 +1001,8 @@ behaviorVectors: Array<{
|
||||
|
||||
对策:
|
||||
|
||||
1. 每个属性附带定义、正反信号、示例行为
|
||||
2. 编辑器永远显示 `name + definition`
|
||||
1. 编辑器只显示并编辑六个属性名称
|
||||
2. 解释文本由技能 / 标签 / 物品等下游按具体场景生成
|
||||
3. 所有技能 / 标签 / 物品的属性向量都显示人类可读解释
|
||||
|
||||
### 风险 3:旧系统迁移期间双轨并存混乱
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
|
||||
- `npc_help`
|
||||
脚本:`src/data/functionCatalog/npc/npcHelp.ts`
|
||||
说明:向 NPC 寻求补给、回复或支援的 function。奖励由本地规则稳定计算,避免帮助收益被模型临场漂移。
|
||||
说明:向 NPC 寻求补给、回复或支援的 function。正式奖励、资源变化与 one-shot 状态由后端 runtime action resolver 稳定计算,避免帮助收益被模型临场漂移。
|
||||
|
||||
- `npc_chat`
|
||||
脚本:`src/data/functionCatalog/npc/npcChat.ts`
|
||||
@@ -140,7 +140,7 @@
|
||||
|
||||
- `npc_quest_accept`
|
||||
脚本:`src/data/functionCatalog/npc/npcQuestAccept.ts`
|
||||
说明:正式接下 NPC 委托的 function。它把本地生成的任务写入 quest log,并让剧情承接“玩家已经答应处理这件事”。
|
||||
说明:正式接下 NPC 委托的 function。它把后端 pending quest offer 写入 quest log,并让剧情承接“玩家已经答应处理这件事”。
|
||||
|
||||
- `npc_quest_turn_in`
|
||||
脚本:`src/data/functionCatalog/npc/npcQuestTurnIn.ts`
|
||||
@@ -172,7 +172,7 @@
|
||||
|
||||
- `camp_travel_home_scene`
|
||||
脚本:`src/data/functionCatalog/flow/campTravelHomeScene.ts`
|
||||
说明:营地开场或同伴交流结束后,正式前往角色主场景的流程项。它负责定制化场景迁移和状态清理,不属于普通 state function。
|
||||
说明:营地开场或同伴交流结束后,正式前往角色主场景的流程项。前端脚本只保留按钮与视觉元信息,目标场景、状态清理、encounter preview、`scenesTraveled` 与快照持久化由后端 runtime action resolver 负责。
|
||||
|
||||
- `story_opening_camp_dialogue`
|
||||
脚本:`src/data/functionCatalog/flow/storyOpeningCampDialogue.ts`
|
||||
@@ -182,7 +182,7 @@
|
||||
|
||||
- `inventory_use`
|
||||
脚本:`src/data/functionCatalog/panel/inventoryUse.ts`
|
||||
说明:在背包面板里使用药品、灵力物或 build buff 物品的 function。它先由本地规则结算资源变化,再把结果记入故事历史。
|
||||
说明:在背包面板里使用药品、灵力物或 build buff 物品的 function。前端只提交物品动作,资源变化、数量扣减、build buff 与故事历史由后端 resolver 写入。
|
||||
|
||||
- `equipment_equip`
|
||||
脚本:`src/data/functionCatalog/panel/equipmentEquip.ts`
|
||||
@@ -190,7 +190,7 @@
|
||||
|
||||
- `equipment_unequip`
|
||||
脚本:`src/data/functionCatalog/panel/equipmentUnequip.ts`
|
||||
说明:从装备槽位卸下物品的 function。它确保卸装结果由本地规则严格处理,不会破坏背包数量和 loadout 一致性。
|
||||
说明:从装备槽位卸下物品的 function。后端 resolver 负责卸装结果、背包数量和 loadout 一致性。
|
||||
|
||||
- `forge_craft`
|
||||
脚本:`src/data/functionCatalog/panel/forgeCraft.ts`
|
||||
@@ -198,7 +198,7 @@
|
||||
|
||||
- `forge_dismantle`
|
||||
脚本:`src/data/functionCatalog/panel/forgeDismantle.ts`
|
||||
说明:在锻造面板中拆解物品回收材料的 function。拆解产出由本地锻造规则控制,避免与物品设计脱节。
|
||||
说明:在锻造面板中拆解物品回收材料的 function。拆解产出由后端锻造 resolver 控制,避免与物品设计脱节。
|
||||
|
||||
- `forge_reforge`
|
||||
脚本:`src/data/functionCatalog/panel/forgeReforge.ts`
|
||||
|
||||
@@ -4,11 +4,13 @@
|
||||
|
||||
- [BUSINESS_PROMPT_INVENTORY_2026-04-19.md](./BUSINESS_PROMPT_INVENTORY_2026-04-19.md):业务中现存提示词的总清单,覆盖后端主链、前端遗留、自定义世界、角色形象生成、场景背景生成与工具链 prompt。
|
||||
- [FUNCTION_SCRIPT_CATALOG_2026-04-04.md](./FUNCTION_SCRIPT_CATALOG_2026-04-04.md):Function 独立脚本目录与分类速查。
|
||||
- [RPG_CREATION_AND_RUNTIME_SCRIPT_RESPONSIBILITY_MAP_2026-04-28.md](./RPG_CREATION_AND_RUNTIME_SCRIPT_RESPONSIBILITY_MAP_2026-04-28.md):RPG 创作功能脚本与 RPG 运行时脚本的职责地图,覆盖前端入口、编排、表现、client、`server-rs` 与 SpacetimeDB 侧落点。
|
||||
- [TASK_GENERATION_TRACE_2026-04-08.md](./TASK_GENERATION_TRACE_2026-04-08.md):任务描述、达成条件与奖励生成链路梳理。
|
||||
- [CUSTOM_WORLD_TEMPLATE_DEPENDENCY_INVENTORY_2026-04-08.md](./CUSTOM_WORLD_TEMPLATE_DEPENDENCY_INVENTORY_2026-04-08.md):自定义世界当前仍依赖哪些模板世界设定的清单。
|
||||
|
||||
## 使用建议
|
||||
|
||||
- 需要快速定位 Function 脚本,而不是阅读长篇方案时,优先看这里。
|
||||
- 需要快速判断“RPG 创作链和 RPG 运行时链分别该改哪些脚本”时,优先看 RPG 脚本职责地图。
|
||||
- 需要判断“武侠 / 仙侠模板层”哪些还能删、哪些不能删时,优先看自定义世界模板依赖清单。
|
||||
- 如果要评估 Function 分层是否合理,再配合 `docs/audits/FUNCTION_DESIGN_AUDIT_2026-04-03.md` 一起看。
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,115 @@
|
||||
# RPG 脚本中文注释补充进度(2026-04-28)
|
||||
|
||||
## 1. 文档目的
|
||||
|
||||
这份文档用于记录当前仓库里 RPG 相关脚本的中文注释补充进度,避免后续“挨个补充”时重复扫描、重复改同一批文件,或者遗漏运行时主链上的关键脚本。
|
||||
|
||||
当前原则:
|
||||
|
||||
1. 先补职责最核心、状态流最复杂、后续最常被继续修改的脚本。
|
||||
2. 每一批都尽量按完整链路补,不只补单点文件。
|
||||
3. 注释以解释“为什么这样编排”“这一层负责什么边界”为主,不堆砌逐行翻译式废话。
|
||||
|
||||
---
|
||||
|
||||
## 2. 本轮已补充的脚本
|
||||
|
||||
### 2.1 RPG 运行时 session 主链
|
||||
|
||||
1. `src/hooks/rpg-session/useRpgRuntimeSession.ts`
|
||||
2. `src/hooks/rpg-session/useRpgSessionBootstrap.ts`
|
||||
3. `src/hooks/rpg-session/useRpgSessionPersistence.ts`
|
||||
|
||||
本轮重点:
|
||||
|
||||
1. 说明 session 装配器如何组合 bootstrap、story、combat、persistence。
|
||||
2. 说明自定义世界开局场景、首遇 NPC、初始装备与初始物品的装配原因。
|
||||
3. 说明自动存档、继续游戏、手动保存退出的状态边界。
|
||||
|
||||
### 2.2 RPG 运行时 story 主链
|
||||
|
||||
1. `src/hooks/rpg-runtime-story/useRpgRuntimeStory.ts`
|
||||
2. `src/hooks/rpg-runtime-story/useRpgRuntimeStoryController.ts`
|
||||
3. `src/hooks/rpg-runtime-story/useRpgRuntimeStoryFlow.ts`
|
||||
4. `src/hooks/rpg-runtime-story/useRpgRuntimeInteractionFlow.ts`
|
||||
5. `src/hooks/rpg-runtime-story/useRpgRuntimeStoryState.ts`
|
||||
6. `src/hooks/rpg-runtime-story/storyInteractionCoordinator.ts`
|
||||
7. `src/hooks/rpg-runtime-story/rpgRuntimeStoryGateway.ts`
|
||||
|
||||
本轮重点:
|
||||
|
||||
1. 说明 controller、flow、interaction、state 四层的职责切分。
|
||||
2. 说明 NPC 遭遇自动进入交互态、NPC 战斗快照桥接、地图旅行桥接的原因。
|
||||
3. 说明 story reset、story hydration、服务端动作结算的编排边界。
|
||||
|
||||
### 2.3 RPG 运行时 service / client 主链
|
||||
|
||||
1. `src/services/rpg-runtime/rpgRuntimeRequest.ts`
|
||||
2. `src/services/rpg-runtime/rpgRuntimeStoryClient.ts`
|
||||
3. `src/services/rpg-runtime/rpgSnapshotClient.ts`
|
||||
|
||||
本轮重点:
|
||||
|
||||
1. 说明 runtime 请求的统一重试策略。
|
||||
2. 说明服务端 `RuntimeStoryOptionView` 到前端 `StoryOption` 的适配原因。
|
||||
3. 说明远端快照读取、写入后为什么要先 rehydrate。
|
||||
|
||||
---
|
||||
|
||||
## 3. 建议的后续补充顺序
|
||||
|
||||
为了保持“按链路读得通”,下一轮建议继续按下面顺序推进:
|
||||
|
||||
### 3.1 运行时 story 子模块
|
||||
|
||||
1. `src/hooks/rpg-runtime-story/storyChoiceCoordinator.ts`
|
||||
2. `src/hooks/rpg-runtime-story/storyChoiceRuntime.ts`
|
||||
3. `src/hooks/rpg-runtime-story/storyRequestCoordinator.ts`
|
||||
4. `src/hooks/rpg-runtime-story/storyRequestRuntime.ts`
|
||||
5. `src/hooks/rpg-runtime-story/storyGenerationState.ts`
|
||||
6. `src/hooks/rpg-runtime-story/storyEncounterState.ts`
|
||||
7. `src/hooks/rpg-runtime-story/storyPresentation.ts`
|
||||
8. `src/hooks/rpg-runtime-story/sessionActions.ts`
|
||||
9. `src/hooks/rpg-runtime-story/progressionActions.ts`
|
||||
10. `src/hooks/rpg-runtime-story/npcInteraction.ts`
|
||||
11. `src/hooks/rpg-runtime-story/inventoryActions.ts`
|
||||
12. `src/hooks/rpg-runtime-story/goalFlow.ts`
|
||||
|
||||
原因:
|
||||
|
||||
1. 这些文件已经紧贴本轮完成的主编排层。
|
||||
2. 它们包含大量“局部规则 + 状态迁移 + UI 结果”的细节,最需要注释解释。
|
||||
|
||||
### 3.2 运行时 UI 与入口层
|
||||
|
||||
1. `src/components/rpg-runtime-shell/RpgRuntimeShell.tsx`
|
||||
2. `src/components/rpg-runtime-shell/RpgRuntimeStageRouter.tsx`
|
||||
3. `src/components/rpg-runtime-panels/RpgRuntimePanelRouter.tsx`
|
||||
4. `src/components/rpg-runtime-panels/RpgAdventurePanel.tsx`
|
||||
5. `src/hooks/rpg-session/useRpgSessionBootstrap.ts` 周边引用组件
|
||||
6. `src/components/rpg-entry/` 目录里的 RPG 运行时入口桥接脚本
|
||||
|
||||
原因:
|
||||
|
||||
1. 主链编排层补完后,再补表现层会更容易写出真正有用的注释。
|
||||
2. 入口层里有兼容 façade,需要明确标出“不要继续堆复杂逻辑”的边界。
|
||||
|
||||
### 3.3 RPG 创作链
|
||||
|
||||
1. `src/services/rpg-creation/` 目录主 client
|
||||
2. `src/components/rpg-creation-result/` 主动作脚本
|
||||
3. `src/components/rpg-creation-editor/` 主编辑链
|
||||
4. `src/components/rpg-creation-asset-studio/` 角色资产工坊链
|
||||
|
||||
原因:
|
||||
|
||||
1. 创作链文件也很多,但当前运行时主链更核心、更常改。
|
||||
2. 等运行时链注释连续后,再切创作链更不容易打断理解。
|
||||
|
||||
---
|
||||
|
||||
## 4. 本轮备注
|
||||
|
||||
1. 本轮以局部补丁方式补注释,没有整文件重写。
|
||||
2. 本轮没有改业务逻辑,只补中文注释和进度文档。
|
||||
3. 后续每补完一批,建议同步更新本文件,保持可追踪。
|
||||
@@ -192,6 +192,7 @@ npm run dev:rust
|
||||
1. 资源 URL 不再是 `/generated-big-fish/...`
|
||||
2. 而是 `/generated-big-fish-assets/...`
|
||||
3. 结果页状态显示为 `已生成`,而不是 `占位已生成`
|
||||
4. `Lv.x 主图` 与 `idle_float / move_swim` 正式图若下载结果为 PNG,后端会在写 OSS 前复用 RPG 角色主图透明背景 alpha 后处理;`生成背景` 不走该处理
|
||||
|
||||
### 7.2 Custom World 场景图
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
# 大鱼吃小鱼草稿进度与会话超时兜底修复 2026-04-28
|
||||
|
||||
## 背景
|
||||
|
||||
大鱼吃小鱼在 `2026-04-28` 完成草稿结构化升级后,结果页草稿已经不再是单纯模板壳,而是会生成等级文本、形象描述、动作描述与运行参数。
|
||||
|
||||
但当前链路仍暴露出两个直接体验问题:
|
||||
|
||||
1. 前端草稿进度页仍把大鱼吃小鱼展示成单个 `compile` 步骤,用户会感觉“整个生成过程只有一步,而且一直卡在第一步”。
|
||||
2. 前端在打开大鱼草稿或结果页时,会通过 `GET /api/runtime/big-fish/agent/sessions/:sessionId` 拉取完整会话;当 Maincloud 上游偶发抖动时,Rust `spacetime-client` 统一 10 秒超时会直接映射成 `502`,用户会看到反复报错。
|
||||
|
||||
## 修复口径
|
||||
|
||||
### 1. 草稿进度页改为多阶段感知
|
||||
|
||||
大鱼吃小鱼的 `big_fish_compile_draft` 仍然保持为一次后端 compile action,不拆成多个新的后端接口。
|
||||
|
||||
但前端进度读模型不再把它渲染成单步,而是拆成下面三段:
|
||||
|
||||
1. `整理玩法骨架`
|
||||
- 收拢玩法承诺、成长阶梯与风险节奏。
|
||||
2. `编译等级蓝图`
|
||||
- 生成每级角色描述、形象描述与动作描述。
|
||||
3. `校准场地与参数`
|
||||
- 整理背景蓝图与运行参数,准备结果页。
|
||||
|
||||
这样做的边界是:
|
||||
|
||||
1. 不把动作正式出图重新塞回 compile action。
|
||||
2. 只增强生成中的阶段反馈,不改动现有结果页资产工坊分工。
|
||||
3. 进度阶段属于前端展示语义,不要求后端额外维护细粒度 procedure 状态。
|
||||
|
||||
### 2. 会话读取增加短重试与超时语义收口
|
||||
|
||||
大鱼会话读取现在补充两层守卫:
|
||||
|
||||
1. `api-server` 在读取大鱼 session 时,对 `SpacetimeClientError::Timeout` 和 `SpacetimeClientError::ConnectDropped` 做一次短重试。
|
||||
2. 若最终仍然超时,则错误状态码从泛化 `502` 收口为更准确的 `504 Gateway Timeout`。
|
||||
|
||||
这样可以覆盖两类常见情况:
|
||||
|
||||
1. Maincloud 连接偶发抖动,第一次 procedure 超时但第二次马上恢复。
|
||||
2. 用户打开草稿页时碰到短暂断链,不再被立即判定成稳定的坏网关故障。
|
||||
|
||||
## 落地范围
|
||||
|
||||
1. `src/services/miniGameDraftGenerationProgress.ts`
|
||||
2. `src/services/miniGameDraftGenerationProgress.test.ts`
|
||||
3. `src/components/platform-entry/PlatformEntryFlowShellImpl.tsx`
|
||||
4. `server-rs/crates/api-server/src/big_fish.rs`
|
||||
|
||||
## 验收口径
|
||||
|
||||
1. 用户点击大鱼吃小鱼“生成草稿”后,进度页至少能看到三个结构化阶段,而不是单个 compile 步骤。
|
||||
2. 这三个阶段都只描述草稿编译,不出现“生成动作素材”之类结果页资产动作。
|
||||
3. `GET /api/runtime/big-fish/agent/sessions/:sessionId` 遇到短暂 SpacetimeDB 抖动时,会先做一次短重试。
|
||||
4. 如果最终仍超时,接口返回语义应体现为超时,而不是继续统一落成泛化 `502`。
|
||||
@@ -0,0 +1,82 @@
|
||||
# 大鱼吃小鱼角色主图透明背景后处理对齐说明 2026-04-28
|
||||
|
||||
## 背景
|
||||
|
||||
当前大鱼吃小鱼的等级主图与动作关键帧 prompt 已经明确要求“按 RPG 角色资产口径生成透明背景”,但正式图片链实际仍主要依赖供应商出图结果本身。
|
||||
|
||||
这会带来一个问题:
|
||||
|
||||
1. prompt 约束只能提高透明背景命中率,不能保证每次都没有残留底色。
|
||||
2. RPG 角色主图链已经在 Rust 后端落了一层 PNG alpha 后处理,大鱼链没有对齐,导致两条“角色主图口径”资产在最终成品一致性上仍有差异。
|
||||
|
||||
## 本次目标
|
||||
|
||||
把“大鱼吃小鱼生成的角色主图后处理流程”对齐到 RPG 角色主图链:
|
||||
|
||||
1. 等级主图正式图生成后,若下载结果为 PNG,则复用 RPG 现有透明背景 alpha 后处理。
|
||||
2. `idle_float` / `move_swim` 动作关键帧静态图同样复用这套处理。
|
||||
3. 场地背景图不走这套处理,避免误把 9:16 场景背景做成透明底。
|
||||
|
||||
## 落地方案
|
||||
|
||||
### 1. 复用 RPG 透明背景后处理能力
|
||||
|
||||
`server-rs/crates/api-server/src/character_visual_assets.rs`
|
||||
|
||||
冻结现有 `try_apply_background_alpha_to_png(...)` 为 `pub(crate)` 复用入口,继续由 RPG 主图链维护这套“绿底/白底/软边缘”透明背景清理逻辑。
|
||||
|
||||
### 2. Big Fish 正式图链按资产类型决定是否启用后处理
|
||||
|
||||
`server-rs/crates/api-server/src/big_fish.rs`
|
||||
|
||||
在 `BigFishFormalAssetContext` 中新增:
|
||||
|
||||
1. `apply_transparent_background_post_process`
|
||||
|
||||
映射规则如下:
|
||||
|
||||
1. `level_main_image`:`true`
|
||||
2. `level_motion`:`true`
|
||||
3. `stage_background`:`false`
|
||||
|
||||
### 3. 下载完成后、写 OSS 前执行统一处理
|
||||
|
||||
`download_big_fish_remote_image(...)` 新增布尔开关参数。
|
||||
|
||||
当满足以下条件时执行后处理:
|
||||
|
||||
1. 当前资产槽位需要透明背景后处理
|
||||
2. 上游下载结果 `mime_type == image/png`
|
||||
|
||||
执行顺序冻结为:
|
||||
|
||||
1. DashScope 出图
|
||||
2. 下载远端 PNG
|
||||
3. 复用 RPG `try_apply_background_alpha_to_png(...)`
|
||||
4. 再写入 Big Fish 正式 OSS 对象
|
||||
5. 确认 `asset_object`
|
||||
6. 绑定到 Big Fish 槽位
|
||||
|
||||
## 为什么这样做
|
||||
|
||||
1. 这次需求说的是“生成后处理流程和 RPG 角色主图一致”,因此不能只继续加强 prompt,必须把后处理链对齐。
|
||||
2. 直接复用 RPG 已有实现,比在 Big Fish 再复制一份抠图算法更稳,也更符合仓库“默认复用现有系统”的约束。
|
||||
3. 背景图是环境资产,不属于“角色主图口径”,如果也启用透明背景后处理,会造成错误裁底风险。
|
||||
|
||||
## 验收口径
|
||||
|
||||
1. 在 Big Fish 结果页点击 `生成并应用正式图 -> Lv.x 主图` 后,若 DashScope 返回 PNG,正式落库前会执行和 RPG 主图相同的透明背景 alpha 处理。
|
||||
2. 在 Big Fish 动作工坊点击 `生成并应用正式图` 后,`idle_float` / `move_swim` 的静态关键帧图同样执行该处理。
|
||||
3. `生成背景` 仍保持完整场景图,不走透明背景后处理。
|
||||
4. 编码检查通过,Rust `api-server` 定向编译通过。
|
||||
|
||||
## 影响范围
|
||||
|
||||
1. `server-rs/crates/api-server/src/character_visual_assets.rs`
|
||||
2. `server-rs/crates/api-server/src/big_fish.rs`
|
||||
|
||||
## 风险与边界
|
||||
|
||||
1. 当前后处理只在下载结果本身是 PNG 时生效;若供应商返回 JPEG/WebP,则仍按原始格式入库。
|
||||
2. 本次不新增新的 Big Fish 专属抠图算法,不改变 DashScope prompt 和 OSS 绑定协议。
|
||||
3. 本次不修改 SpacetimeDB schema,也不涉及 `migration.rs` 变更。
|
||||
@@ -0,0 +1,126 @@
|
||||
# 大鱼吃小鱼提示词脚本拆分 2026-04-28
|
||||
|
||||
## 背景
|
||||
|
||||
大鱼吃小鱼当前在 `server-rs/crates/api-server/src/big_fish.rs` 与 `server-rs/crates/api-server/src/big_fish_agent_turn.rs` 中同时承载了三类不同职责的提示词:
|
||||
|
||||
1. Agent 聊天阶段的草稿生成提示词。
|
||||
2. 结果页主图 / 生图提示词。
|
||||
3. 结果页动作关键帧提示词。
|
||||
|
||||
这会带来两个直接问题:
|
||||
|
||||
1. 聊天共创脚本和正式资产脚本混在路由业务文件中,后续继续调词时很容易顺手改到状态编排逻辑。
|
||||
2. 大鱼吃小鱼已经明确要求“草稿编译”和“结果页资产工坊”分离,如果提示词仍散落在业务实现里,后续很容易再次把动作资产逻辑误塞回 compile action。
|
||||
|
||||
## 本轮目标
|
||||
|
||||
把下面三类提示词显式拆到独立 prompt 脚本中:
|
||||
|
||||
1. 草稿生成提示词。
|
||||
2. 生图提示词。
|
||||
3. 动作提示词。
|
||||
|
||||
并保持以下边界不变:
|
||||
|
||||
1. 不改变 Big Fish 的会话表、草稿表、资产表结构。
|
||||
2. 不改变 compile action 只编译草稿、不串行生成资产的现有口径。
|
||||
3. 不改写当前中文提示词语义,只做脚本落位和调用收口。
|
||||
|
||||
## 落位方案
|
||||
|
||||
新增文件:
|
||||
|
||||
```text
|
||||
server-rs/crates/api-server/src/prompt/big_fish.rs
|
||||
```
|
||||
|
||||
该文件统一收口:
|
||||
|
||||
1. `BIG_FISH_AGENT_SYSTEM_PROMPT`
|
||||
2. `build_big_fish_agent_prompt(...)`
|
||||
3. `build_big_fish_level_main_image_prompt(...)`
|
||||
4. `build_big_fish_level_motion_prompt(...)`
|
||||
5. `build_big_fish_stage_background_prompt(...)`
|
||||
6. `BIG_FISH_DEFAULT_NEGATIVE_PROMPT`
|
||||
7. `BIG_FISH_TRANSPARENT_ASSET_NEGATIVE_PROMPT`
|
||||
|
||||
同时把 `prompt/mod.rs` 补齐为正式导出入口,和现有:
|
||||
|
||||
1. `puzzle_image.rs`
|
||||
2. `character_visual.rs`
|
||||
3. `character_animation.rs`
|
||||
4. `scene_background.rs`
|
||||
|
||||
保持同一层级。
|
||||
|
||||
## 调用边界
|
||||
|
||||
### 1. 草稿生成
|
||||
|
||||
`server-rs/crates/api-server/src/big_fish_agent_turn.rs`
|
||||
|
||||
改为只负责:
|
||||
|
||||
1. 调用公共 LLM turn 执行器。
|
||||
2. 解析 `replyText / progressPercent / nextAnchorPack`。
|
||||
3. 组装 finalize input。
|
||||
|
||||
不再内联维护大段 system prompt / output contract / chat prompt 拼接逻辑。
|
||||
|
||||
### 2. 生图与动作
|
||||
|
||||
`server-rs/crates/api-server/src/big_fish.rs`
|
||||
|
||||
改为只负责:
|
||||
|
||||
1. 读取当前 session 与 draft。
|
||||
2. 根据 `asset_kind` 构造正式资产上下文。
|
||||
3. 调用 DashScope 出图。
|
||||
4. 下载、后处理、持久化并写入资产绑定。
|
||||
|
||||
主图、动作关键帧、背景图的正式提示词脚本都从 `crate::prompt::big_fish` 引入,不再内联在路由业务脚本中。
|
||||
|
||||
## 为什么三类脚本要继续分开
|
||||
|
||||
### 草稿生成提示词
|
||||
|
||||
它的职责是把玩法灵感收束成:
|
||||
|
||||
1. 玩法承诺
|
||||
2. 生态视觉主题
|
||||
3. 成长阶梯
|
||||
4. 风险节奏
|
||||
|
||||
它面向的是 LLM 的结构化共创,不面向图片模型。
|
||||
|
||||
### 生图提示词
|
||||
|
||||
它的职责是把已经落库的等级蓝图翻译成“单体鱼形主图”的正式图片提示词。
|
||||
|
||||
它面向的是透明背景主体资产,需要强调:
|
||||
|
||||
1. 单体主体
|
||||
2. 透明背景
|
||||
3. 中心构图
|
||||
4. 不出现 UI / 场景 / 多主体
|
||||
|
||||
### 动作提示词
|
||||
|
||||
它的职责是把等级蓝图和动作槽位翻译成“静态关键帧预览图”的正式图片提示词。
|
||||
|
||||
它和主图区别在于:
|
||||
|
||||
1. 需要显式带入 `motion_key`
|
||||
2. 需要区分 `idle_float / move_swim`
|
||||
3. 需要强调动作方向和关键帧姿态
|
||||
|
||||
因此不能继续复用同一段文本拼接后靠 if 分支临时改句子。
|
||||
|
||||
## 本轮验收
|
||||
|
||||
1. 大鱼吃小鱼草稿生成提示词已从 `big_fish_agent_turn.rs` 抽离。
|
||||
2. 大鱼吃小鱼主图、动作、背景提示词已从 `big_fish.rs` 抽离。
|
||||
3. 路由业务文件只保留编排、鉴权、调用与错误映射职责。
|
||||
4. 新增 prompt 文件具备最小测试覆盖。
|
||||
5. `npm run check:encoding` 通过,确保新增中文文档与 Rust 注释未被写坏。
|
||||
@@ -0,0 +1,63 @@
|
||||
# 创作页公开广场与 Agent 恢复指针兜底修复 2026-04-28
|
||||
|
||||
## 1. 问题现象
|
||||
|
||||
浏览器控制台同时出现两类请求错误:
|
||||
|
||||
1. `GET /api/runtime/custom-world/agent/sessions/:sessionId` 返回 `404`。
|
||||
2. `GET /api/runtime/big-fish/gallery` 返回 `400`。
|
||||
|
||||
第一类错误发生在平台页尝试恢复 RPG / Custom World Agent 旧工作区时。旧 URL 或旧 sessionStorage 指针里可能只有 `customWorldSessionId`,没有本机保存的 `ownerUserId`,登录后前端仍会直接读取受保护 session,后端按 `owner_user_id + session_id` 查不到后返回 `404`。
|
||||
|
||||
第二类错误发生在首页读取大鱼吃小鱼公开广场时。公开广场是平台首屏的可选展示数据,即使 SpacetimeDB procedure 暂未就绪、连接短暂断开或旧环境缺少对应 procedure,也不应该阻断平台主界面。
|
||||
|
||||
## 2. 落地原则
|
||||
|
||||
1. URL 中的 `customWorldSessionId` 只用于深链恢复,不作为鉴权凭据。
|
||||
2. 受保护 Agent session 恢复必须能确认本机 `ownerUserId` 与当前登录用户一致。
|
||||
3. 未登录状态仍保留登录弹窗流程,不提前丢弃深链;登录完成后若仍无法确认归属,再清空恢复指针。
|
||||
4. Big Fish 公开广场只展示 `published` 作品;读取失败时允许空态降级,不把错误写成 UI 主错误。
|
||||
5. 私有作品列表、会话详情、发布、删除仍保持严格错误,不复用公开广场的软降级策略。
|
||||
|
||||
## 3. 本次修改
|
||||
|
||||
### 3.1 RPG Agent 恢复指针
|
||||
|
||||
`src/services/customWorldAgentUiState.ts` 读取 URL query 时,会尝试从 sessionStorage 中匹配同一个 `activeSessionId` 的 `ownerUserId`。
|
||||
|
||||
如果 URL 指针和本机存储匹配:
|
||||
|
||||
1. 返回 `activeSessionId`。
|
||||
2. 同时带回本机 `ownerUserId`。
|
||||
|
||||
如果 URL 指针没有对应本机归属:
|
||||
|
||||
1. 只返回 session 指针。
|
||||
2. 登录后 `useRpgCreationSessionController` 会清空指针。
|
||||
3. 不调用 `getRpgCreationSession()`,避免向后端发起必然 404 的失效恢复请求。
|
||||
|
||||
### 3.2 Big Fish 公开广场
|
||||
|
||||
前端 `listBigFishGallery()` 对 `400 / 404` 返回 `{ items: [] }`,让平台首页可以继续渲染空广场。
|
||||
|
||||
Rust `api-server` 的 `list_big_fish_gallery()` 对以下 SpacetimeDB 读取问题做服务端空态降级:
|
||||
|
||||
1. `SpacetimeClientError::Runtime(_)`
|
||||
2. `SpacetimeClientError::ConnectDropped`
|
||||
3. 明确指向 `list_big_fish_works` procedure 缺失或不可用的 procedure 错误
|
||||
|
||||
服务端会保留 `warn` 日志,便于部署环境继续排查 schema / publish 状态。`Timeout` 不降级,仍按网关超时暴露,避免长时间卡死被误认为正常空广场。
|
||||
|
||||
## 4. 验收标准
|
||||
|
||||
1. 已登录用户打开只带旧 `customWorldSessionId`、但本机没有匹配 `ownerUserId` 的页面时,不再请求 `GET /api/runtime/custom-world/agent/sessions/:sessionId`。
|
||||
2. 未登录用户打开带 `customWorldSessionId` 的深链时,仍先打开登录弹窗。
|
||||
3. Big Fish 公开广场返回 `400 / 404` 时,前端展示空列表,不把“读取大鱼吃小鱼广场失败”写入主错误态。
|
||||
4. 服务端遇到 Big Fish gallery 可降级 SpacetimeDB 错误时返回成功 envelope,`items` 为空,并记录 warn 日志。
|
||||
|
||||
## 5. 回归范围
|
||||
|
||||
1. `src/services/customWorldAgentUiState.test.ts`
|
||||
2. `src/components/rpg-entry/RpgEntryFlowShell.agent.interaction.test.tsx`
|
||||
3. `src/services/big-fish-gallery/bigFishGalleryClient.test.ts`
|
||||
4. `cargo test -p api-server big_fish_gallery`
|
||||
@@ -2,14 +2,27 @@
|
||||
|
||||
## 背景
|
||||
|
||||
RPG 在点击生成草稿后会离开聊天工作区,进入独立的生成进度页,并在该页展示生成链路的阶段、锚点与最终草稿内容。拼图与大鱼吃小鱼此前点击“生成结果页”后直接跳到结果页,正式图片、动作与背景仍分散在结果页工坊里逐个生成,导致用户无法看到“正在一次性准备完整草稿”的过程。
|
||||
RPG 在点击生成草稿后会离开聊天工作区,进入独立的生成进度页,并在该页展示生成链路的阶段、锚点与最终草稿内容。拼图与大鱼吃小鱼此前点击“生成结果页”后直接跳到结果页,缺少一个明确的“草稿编译中”过渡态。
|
||||
|
||||
但在 `2026-04-28` 的大鱼吃小鱼链路修正后,产品口径进一步收紧为:
|
||||
|
||||
1. 拼图仍然保留“生成草稿时一并补齐结果页主资产”的收口方式。
|
||||
2. 大鱼吃小鱼的“生成草稿”只负责把玩法锚点编译成结果页草稿。
|
||||
3. 大鱼吃小鱼的主图、动作、背景都留在结果页工坊按需生成,不再塞进草稿编译动作里串行执行。
|
||||
|
||||
这样做的原因是:
|
||||
|
||||
1. 大鱼吃小鱼草稿阶段的核心目标是先稳定产出等级蓝图、背景蓝图和运行参数,而不是在这一刻把整套资产都做完。
|
||||
2. 动作素材生成耗时最长,把它塞进草稿 action 会让用户长时间停留在首步等待态,形成“卡在第一步”的体感。
|
||||
3. 草稿阶段不需要配置动作,动作应当属于结果页资产精修阶段。
|
||||
|
||||
## 落地边界
|
||||
|
||||
- 前端只负责展示生成进度与触发已有后端动作,不新增 server-node 或 PostgreSQL 链路。
|
||||
- 后端继续沿用 `server-rs` + SpacetimeDB 的会话、草稿与资产写入能力;“一次性生成所有需要的东西”必须由 `server-rs` 的 compile action 承担,前端只发起一次 action 并展示进度页。
|
||||
- 拼图生成草稿链路必须包含:结果页草稿、候选图生成、正式图确认。
|
||||
- 大鱼吃小鱼生成草稿链路必须包含:玩法草稿、关卡主图、动作素材、场地背景。
|
||||
- 后端继续沿用 `server-rs` + `SpacetimeDB` 的会话、草稿与资产写入能力。
|
||||
- 拼图生成草稿链路仍包含:结果页草稿、候选图生成、正式图确认。
|
||||
- 大鱼吃小鱼生成草稿链路只包含:玩法草稿、等级蓝图、背景蓝图与运行参数编译。
|
||||
- 大鱼吃小鱼的主图、动作、背景都在结果页工坊单独触发,不再属于草稿编译阶段。
|
||||
- 生成过程中展示的“角色描述、角色图片、动作”等,统一映射为锚点、草稿蓝图与资产步骤,不把规则说明类文本写成默认 UI 文案。
|
||||
|
||||
## 交互设计
|
||||
@@ -17,8 +30,9 @@ RPG 在点击生成草稿后会离开聊天工作区,进入独立的生成进
|
||||
1. 用户在拼图或大鱼吃小鱼 Agent 工作区点击生成按钮。
|
||||
2. 页面立即切换到独立生成进度页,同时只向 `server-rs` 发起一次 compile action,返回按钮在生成中禁用,避免中途回退造成状态漂移。
|
||||
3. 进度页左侧展示阶段进度、步骤卡片与错误信息;右侧展示当前锚点与已成形的草稿结构。
|
||||
4. 全量生成成功后自动进入对应结果页,结果页直接展示已生成的资产。
|
||||
5. 生成失败时停留在进度页,用户可返回工作区补充设定,或点击重试重新执行完整草稿链路。
|
||||
4. 生成成功后自动进入对应结果页。
|
||||
5. 拼图结果页直接展示已生成的正式图;大鱼结果页则展示刚编译完成的玩法草稿,后续资产由结果页工坊继续生成。
|
||||
6. 生成失败时停留在进度页,用户可返回工作区补充设定,或点击重试重新执行完整草稿链路。
|
||||
|
||||
## 阶段映射
|
||||
|
||||
@@ -32,11 +46,14 @@ RPG 在点击生成草稿后会离开聊天工作区,进入独立的生成进
|
||||
### 大鱼吃小鱼
|
||||
|
||||
- `big_fish_compile_draft`:在 `server-rs` 内生成玩法草稿、关卡角色描述、背景蓝图与运行参数。
|
||||
- `big_fish_compile_draft`:同一次后端 action 内按每个关卡生成主角色/鱼群图片。
|
||||
- `big_fish_compile_draft`:同一次后端 action 内按每个关卡生成 `idle_float` 与 `move_swim` 动作素材。
|
||||
- `big_fish_compile_draft`:同一次后端 action 内生成玩法场地背景。
|
||||
- `ready`:进入大鱼吃小鱼结果页。
|
||||
|
||||
补充冻结:
|
||||
|
||||
- 大鱼吃小鱼草稿阶段不展示“生成动作素材”步骤。
|
||||
- `big_fish_generate_level_main_image`、`big_fish_generate_level_motion`、`big_fish_generate_stage_background` 继续保留为结果页中的独立资产动作。
|
||||
- 如果后续需要扩展大鱼草稿生成进度,也只能扩展“草稿结构编译”相关阶段,不能再把动作生成塞回 compile action。
|
||||
|
||||
## 前端流程收口
|
||||
|
||||
- 拼图与大鱼吃小鱼共用 `usePlatformCreationAgentFlowController` 管理会话、流式回复、忙碌态、错误态和草稿恢复,页面层不再重复手写两套 submit/action 流程。
|
||||
@@ -48,8 +65,10 @@ RPG 在点击生成草稿后会离开聊天工作区,进入独立的生成进
|
||||
## 验收点
|
||||
|
||||
- 拼图和大鱼吃小鱼点击生成草稿后不再直接停留在聊天工作区等待。
|
||||
- 生成中可看到独立进度页,且进度步骤随 action 完成逐步推进。
|
||||
- 拼图结果页打开时已有正式图;大鱼结果页打开时主图、动作和背景资产均已写入 `assetSlots`。
|
||||
- 前端点击生成草稿时不串行调用多个资产 action;多阶段业务编排收敛在 `server-rs`。
|
||||
- 生成中可看到独立进度页。
|
||||
- 拼图结果页打开时已有正式图。
|
||||
- 大鱼结果页打开时至少已有完整玩法草稿,不要求主图、动作和背景资产在草稿阶段写入 `assetSlots`。
|
||||
- 大鱼吃小鱼草稿生成进度中不再出现“生成动作素材”步骤。
|
||||
- 前端点击生成草稿时不串行调用多个大鱼资产 action;大鱼资产生成留在结果页独立触发。
|
||||
- 返回 Agent 工作区后,聊天区不出现“拼图结果页草稿已生成。”“本级主图已正式生成,可在结果页继续预览。”这类生成进度页状态消息。
|
||||
- 不新增 server-node 依赖,不复活 legacy public 静态资产路径。
|
||||
|
||||
@@ -4,6 +4,13 @@
|
||||
|
||||
## 文档列表
|
||||
|
||||
- [RPG_PROMPT_FRONTEND_REMOVAL_AND_SERVER_RS_MIGRATION_2026-04-28.md](./RPG_PROMPT_FRONTEND_REMOVAL_AND_SERVER_RS_MIGRATION_2026-04-28.md):冻结 RPG 提示词禁止存在前端的边界,明确前端只保留 API client,角色私聊/NPC 对话/剧情续写等 prompt 统一收口到 `server-rs`。
|
||||
- [RPG_CREATION_RESULT_VIEW_BACKEND_TRUTH_MIGRATION_2026-04-28.md](./RPG_CREATION_RESULT_VIEW_BACKEND_TRUTH_MIGRATION_2026-04-28.md):冻结 RPG 创作结果页保存、Agent session/result preview 真相优先级和结果页入口裁决迁移到后端 result-view 的落地边界。
|
||||
- [RPG_CREATION_PROFILE_GENERATION_BACKEND_MIGRATION_2026-04-28.md](./RPG_CREATION_PROFILE_GENERATION_BACKEND_MIGRATION_2026-04-28.md):记录 RPG 创作 profile 生成移除非浏览器 legacy AI 回退,统一通过 `server-rs` 的 `/api/runtime/custom-world/profile` 生成世界底稿。
|
||||
- [CREATION_PUBLIC_GALLERY_AND_AGENT_RESTORE_GUARD_FIX_2026-04-28.md](./CREATION_PUBLIC_GALLERY_AND_AGENT_RESTORE_GUARD_FIX_2026-04-28.md):记录 RPG Agent 旧 URL 恢复指针必须有本机用户归属才读取受保护 session,以及 Big Fish 公开广场读取失败按空广场降级的修复口径。
|
||||
- [BIG_FISH_DRAFT_PROGRESS_AND_SESSION_TIMEOUT_GUARD_FIX_2026-04-28.md](./BIG_FISH_DRAFT_PROGRESS_AND_SESSION_TIMEOUT_GUARD_FIX_2026-04-28.md):记录大鱼吃小鱼草稿进度页从单步 compile 改为多阶段感知展示,以及大鱼会话读取在 Maincloud 抖动时增加短重试与超时语义收口的修复口径。
|
||||
- [BIG_FISH_PROMPT_MODULE_EXTRACTION_2026-04-28.md](./BIG_FISH_PROMPT_MODULE_EXTRACTION_2026-04-28.md):记录大鱼吃小鱼草稿生成、生图、动作三类提示词从业务脚本中抽离到独立 `prompt/big_fish.rs` 模块的边界与职责划分。
|
||||
- [BIG_FISH_MAIN_IMAGE_TRANSPARENT_BACKGROUND_ALIGNMENT_2026-04-28.md](./BIG_FISH_MAIN_IMAGE_TRANSPARENT_BACKGROUND_ALIGNMENT_2026-04-28.md):记录大鱼吃小鱼等级主图与动作关键帧正式图在 Rust 后端复用 RPG 角色主图透明背景 alpha 后处理的对齐口径,并明确场地背景不走该处理。
|
||||
- [PUZZLE_RESULT_AUTOSAVE_AND_TAG_GATE_FIX_2026-04-28.md](./PUZZLE_RESULT_AUTOSAVE_AND_TAG_GATE_FIX_2026-04-28.md):记录拼图结果页名称与标签编辑自动保存、发布门槛统一到 `3~6` 标签,以及前端发布校验不再被旧 session blocker 卡死的修复口径。
|
||||
- [SPACETIMEDB_START_SH_EARLY_EXIT_DIAGNOSTICS_2026-04-27.md](./SPACETIMEDB_START_SH_EARLY_EXIT_DIAGNOSTICS_2026-04-27.md):记录发布包 `start.sh` 只输出“SpacetimeDB 进程在就绪前退出”时的诊断补强,启动失败或超时时自动回显 `logs/spacetimedb.log`、`server ping`、端口监听和 root-dir 相关进程。
|
||||
- [RPG_AND_AGENT_CHAT_TRUE_SSE_STREAMING_2026-04-26.md](./RPG_AND_AGENT_CHAT_TRUE_SSE_STREAMING_2026-04-26.md):记录 RPG 运行时 NPC 聊天、RPG/自定义世界 Agent 与大鱼 Agent 从“拼完整 SSE 字符串后一次性返回”改为 `mpsc + Sse<Event>` 真流式输出的后端落地口径。
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
# RPG 创作 profile 生成后端迁移(2026-04-28)
|
||||
|
||||
## 1. 背景
|
||||
|
||||
`docs/audits/engineering/RPG_FRONTEND_SCRIPT_BACKEND_MIGRATION_AUDIT_2026-04-28.md` 的 5.3 指出,`src/services/rpg-creation/rpgCreationGenerationClient.ts` 在非浏览器环境仍会动态 `import('../ai')`,让 RPG 创作 profile 生成继续保留前端 legacy AI 后门。
|
||||
|
||||
这与当前边界冲突:
|
||||
|
||||
1. 前端只负责表现和 API client。
|
||||
2. RPG 创作 prompt 与 LLM 编排只能在 `server-rs/crates/api-server/src/prompt/rpg/` 与 `api-server` 侧出现。
|
||||
3. 外部 LLM 调用不能进入 SpacetimeDB reducer,必须由 Axum / `platform-llm` 完成后再把确定结果交给后续持久化链。
|
||||
|
||||
## 2. 本轮落地
|
||||
|
||||
### 2.1 前端
|
||||
|
||||
`src/services/rpg-creation/rpgCreationGenerationClient.ts` 现在不再判断 `typeof window`,也不再动态导入 `src/services/ai.ts`。
|
||||
|
||||
无论浏览器、SSR 还是 Vitest node 环境,`generateRpgWorldProfile(...)` 都只调用:
|
||||
|
||||
```text
|
||||
POST /api/runtime/custom-world/profile
|
||||
```
|
||||
|
||||
测试如需离线运行,应 mock `requestJson`,不能恢复本地 AI 生成链。
|
||||
|
||||
### 2.2 后端
|
||||
|
||||
`server-rs/crates/api-server/src/app.rs` 新增:
|
||||
|
||||
```text
|
||||
POST /api/runtime/custom-world/profile
|
||||
```
|
||||
|
||||
handler 落在 `server-rs/crates/api-server/src/custom_world.rs`:
|
||||
|
||||
1. 校验 `settingText`。
|
||||
2. 要求 Bearer 鉴权。
|
||||
3. 要求 `platform-llm` 可用。
|
||||
4. 复用 `generate_custom_world_foundation_draft(...)` 生成 profile 草稿。
|
||||
5. 补齐结果页需要的 `id / settingText / templateWorldType / compatibilityTemplateWorldType / items / generationMode / generationStatus / creatorIntent`。
|
||||
6. 直接返回 `CustomWorldProfile` JSON,保持前端旧 client contract 不变。
|
||||
|
||||
本轮不新增 SpacetimeDB 表,不修改 `migration.rs`。
|
||||
|
||||
## 3. 验收
|
||||
|
||||
1. `src/services/rpg-creation/**` 不再出现 `import('../ai')`、`LegacyAiModule`、`loadLegacyAiModule`。
|
||||
2. `src/services/rpg-creation/index.ts` 不再导出 `generateLegacyCustomWorldProfile`。
|
||||
3. node 环境测试确认 profile 生成只走 `requestJson` mock。
|
||||
4. Rust `api-server` 测试确认 `/api/runtime/custom-world/profile` 未登录返回 `401`。
|
||||
@@ -0,0 +1,82 @@
|
||||
# RPG 创作结果页后端真相视图迁移方案(2026-04-28)
|
||||
|
||||
## 1. 本次落地边界
|
||||
|
||||
本次只迁移 `RPG_FRONTEND_SCRIPT_BACKEND_MIGRATION_AUDIT_2026-04-28.md` 中 5.4 对应链路:
|
||||
|
||||
1. 创作结果页自动保存前的 profile normalize 与 session 同步顺序。
|
||||
2. Agent session / result preview / legacyResultProfile 的真相优先级。
|
||||
3. 作品草稿点击后应进入 Agent workspace、生成过程页还是结果页的裁决。
|
||||
|
||||
不在本轮处理运行时 GameState、战斗、NPC、背包和锻造规则。
|
||||
|
||||
## 2. 后端读模型
|
||||
|
||||
新增稳定读模型:
|
||||
|
||||
```text
|
||||
GET /api/runtime/custom-world/agent/sessions/:sessionId/result-view
|
||||
```
|
||||
|
||||
响应字段:
|
||||
|
||||
1. `session`:最新 Agent session snapshot。
|
||||
2. `profile`:服务端按优先级选出的结果页 profile。
|
||||
3. `profileSource`:`result_preview` / `draft_profile` / `none`。
|
||||
4. `targetStage`:前端应打开的 stage。
|
||||
5. `generationViewSource` / `resultViewSource`:前端视图来源。
|
||||
6. `canAutosaveLibrary`:作品库自动保存是否可执行。
|
||||
7. `canSyncResultProfile`:结果页编辑是否允许回写 session。
|
||||
8. `recoveryAction`:缺失或失败时的恢复指令。
|
||||
|
||||
## 3. 真相优先级
|
||||
|
||||
服务端统一执行以下优先级,前端不再自己解释:
|
||||
|
||||
1. 首选 `session.resultPreview.preview`。
|
||||
2. 若没有 result preview,但 `draftProfile` 是已可打开结果页的完整 profile,则使用 `draftProfile`。
|
||||
3. `draftProfile.legacyResultProfile` 只作为后端兼容恢复来源,不再由前端直接读取。
|
||||
4. 没有可用 profile 时,服务端返回 `targetStage` 指示前端回生成过程页或 Agent workspace。
|
||||
|
||||
## 4. 保存链路
|
||||
|
||||
结果页编辑仍允许前端持有临时表单态,但保存必须按顺序:
|
||||
|
||||
1. 前端调用 `sync_result_profile` action,把编辑后的 profile 写回 Agent session。
|
||||
2. 前端读取 `result-view`,以服务端返回的 `profile` 刷新界面。
|
||||
3. 自动保存作品库只保存 `result-view.profile`,不再自己决定 session/profile 优先级。
|
||||
4. Agent 结果页保存成功后,作品库响应只刷新列表、详情与自动保存签名;当前编辑界面仍以 `result-view.profile` 为准,避免兼容响应缺少角色、地标等完整字段时覆盖正在编辑的结果页。
|
||||
|
||||
### 4.1 保存前 profile canonicalize
|
||||
|
||||
`creatorIntent -> settingText` 的保存前归一必须在后端执行:
|
||||
|
||||
1. `sync_result_profile` action 入站时,后端基于 `payload.profile.creatorIntent` 生成 canonical `settingText` 后再写入 Agent session 与 `resultPreview`。
|
||||
2. `PUT /api/runtime/custom-world-library/:profileId` 入站时,后端对 `payload.profile` 执行同一规则后再抽取 metadata 与写入作品库。
|
||||
3. 前端结果页、作品详情页、平台壳层只能保存用户当前编辑草稿,不再调用 `normalizeRpgEntryAgentBackedProfile(...)` 改写正式字段。
|
||||
4. 前端自动保存去重签名使用草稿 JSON 本身;保存成功后以服务端返回的 canonical entry/result-view 刷新界面。
|
||||
|
||||
该规则的唯一语义是:当 `creatorIntent` 含有有效锚点时,按“世界一句话 / 玩家开局 / 主题气质 / 核心冲突 / 关键关系 / 标志元素”的固定顺序生成 foundation text,并覆盖保存入库或 session 的 `settingText`。没有有效锚点时不改写用户草稿。
|
||||
|
||||
## 5. 前端职责
|
||||
|
||||
前端只保留:
|
||||
|
||||
1. 页面切换。
|
||||
2. loading / error / autosave 状态。
|
||||
3. 用户正在编辑的临时 profile。
|
||||
4. 调用后端 action 和 result-view。
|
||||
|
||||
前端禁止继续:
|
||||
|
||||
1. 直接读取 `draftProfile.legacyResultProfile`。
|
||||
2. 自行判断草稿应打开 Agent workspace、生成过程页还是结果页。
|
||||
3. 自动保存前只刷新 session 后用 session 旧快照覆盖本地编辑。
|
||||
|
||||
## 6. 验收
|
||||
|
||||
1. `rpgCreationPreviewAdapter` 不再读取 `legacyResultProfile`。
|
||||
2. `useRpgCreationResultAutosave` 对 Agent 草稿结果页会先执行 `sync_result_profile`,再读取后端 result-view。
|
||||
3. `useRpgEntryLibraryDetail` 根据 result-view 的 `targetStage` 切页。
|
||||
4. 测试覆盖编辑后不会被旧 session 覆盖、无 result preview 时由后端决定恢复入口。
|
||||
5. 测试覆盖 `sync_result_profile` 与作品库 upsert 入站时由后端 canonicalize `settingText`,前端 autosave 不再保存前 normalize。
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user