This commit is contained in:
417
docs/audits/AGENT_TO_DRAFT_TO_WORLD_PIPELINE_AUDIT_2026-04-20.md
Normal file
417
docs/audits/AGENT_TO_DRAFT_TO_WORLD_PIPELINE_AUDIT_2026-04-20.md
Normal file
@@ -0,0 +1,417 @@
|
||||
# Agent 聊天到草稿生成到进入游戏世界链路审计
|
||||
|
||||
更新时间:`2026-04-20`
|
||||
|
||||
## 0. 审计目标
|
||||
|
||||
本次审计只看一条链:
|
||||
|
||||
`Agent 聊天 -> 世界草稿生成 -> 结果页/作品库 -> 进入游戏世界`
|
||||
|
||||
聚焦回答四类问题:
|
||||
|
||||
1. 哪些数据在链路中断掉了
|
||||
2. 哪些地方在代码里同时存在多条 pipeline
|
||||
3. 哪些字段、功能、组件已经变成冗余或主链弱消费
|
||||
4. 哪些能力在 contract、PRD 或代码结构里已经定义,但并没有真正实装到当前游戏主流程
|
||||
|
||||
---
|
||||
|
||||
## 1. 结论先行
|
||||
|
||||
当前系统还没有形成“Agent 会话是唯一真相源、发布后再进入世界”的单一主链,而是处在多条 pipeline 并存、多个桥接层临时粘合的状态。
|
||||
|
||||
最关键的结论有 8 条:
|
||||
|
||||
1. 当前至少并存 `5` 条相关 pipeline,其中真正影响可玩流程的主链至少有 `3` 条。
|
||||
2. 最大的数据断点是:`CustomWorldAgentSessionSnapshot.draftProfile` 不直接进入 runtime,前端 `buildCustomWorldProfileFromAgentDraft()` 会先把它本地编译成 legacy `CustomWorldProfile`,后面的结果页、自动保存、进入世界都只认这个 legacy profile。
|
||||
3. 服务端内部也存在一次“先编成 legacy runtime profile,再转回 foundation draft”的双重编译,`draftProfile.legacyResultProfile` 是这个桥接层留下来的强耦合字段。
|
||||
4. `packages/shared/src/contracts/customWorldAgent.ts`、`server-node/src/routes/customWorldAgent.ts`、`server-node/src/services/customWorldAgentOrchestrator.ts` 三层定义不一致,`publish_world / generate_scene_assets / sync_scene_assets / expand_long_tail / lock_cards / unlock_cards / regenerate_scope` 等关键动作没有形成真实可用链路。
|
||||
5. `CustomWorldResultView.tsx` 仍保留“直接对 legacy profile 生成角色/地点、直接编辑 profile”的旧流程,会绕过 Agent session,是当前最明显的并行 pipeline 和冗余功能源。
|
||||
6. “进入世界”和“发布世界”目前是两套平行逻辑。Agent 草稿结果页可以自动保存并直接进入世界,但 `publish_world` action 仍不可用,`qualityFindings / blocker` 校验也没有真正接入。
|
||||
7. `listCustomWorldWorks()` 与 `CustomWorldWorkSummaryService` 已能聚合 Agent 草稿和已发布 profile,但平台 `create` tab 仍主要展示 `myEntries`,Agent draft session 不能自然回到主入口,恢复创作主要依赖 `activeSessionId`。
|
||||
8. Agent 工作区主 UI 只接了头部、进度、线程、输入框、操作横幅等极简子集,PRD 里规划的锁定条、草稿抽屉、详情面板、澄清面板、快捷动作、发布校验结果等大部分还没有真正进入当前游戏主流程。
|
||||
|
||||
---
|
||||
|
||||
## 2. 目标链路
|
||||
|
||||
按 `docs/prd/AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PRD_2026-04-12.md` 和 `docs/prd/AI_NATIVE_AGENT_FIRST_EIGHT_ANCHOR_CO_CREATION_FLOW_PRD_2026-04-16.md`,目标链路应当是:
|
||||
|
||||
```text
|
||||
Agent 对话
|
||||
-> Express 后端维护结构化 eight-anchor / creatorIntent / lockState / draftSnapshot
|
||||
-> foundation draft
|
||||
-> 角色资产工坊 / 场景资产工坊
|
||||
-> sync 回 Agent session draft
|
||||
-> expand long tail
|
||||
-> publish_world
|
||||
-> 服务端执行 quality / blocker 校验
|
||||
-> 服务端编译最终 CustomWorldProfile
|
||||
-> 持久化到世界库
|
||||
-> 进入世界
|
||||
```
|
||||
|
||||
这条目标链路有 4 个硬约束:
|
||||
|
||||
1. Express 后端才是真实状态源,前端只负责展示和输入,不负责结构化草稿编译。
|
||||
2. 未发布的 Agent 草稿不应该直接污染正式世界库,主入口里应该通过“继续创作”恢复。
|
||||
3. 进入世界前应先经过 `publish_world`,并由发布校验阻止缺角色资产、缺场景资产、缺主线第一幕等 blocker。
|
||||
4. 结果页不再是旧自定义世界编辑器的平移副本,而应更接近“最终预览 / 发布确认 / 进入世界”的收口层。
|
||||
|
||||
---
|
||||
|
||||
## 3. 当前真实链路
|
||||
|
||||
## 3.1 Agent 会话草稿链
|
||||
|
||||
当前新链路实际是:
|
||||
|
||||
```text
|
||||
PreGameSelectionFlow.tsx
|
||||
-> /api/runtime/custom-world/agent/sessions
|
||||
-> CustomWorldAgentSessionStore
|
||||
-> CustomWorldAgentOrchestrator
|
||||
-> CustomWorldAgentFoundationDraftService
|
||||
-> CustomWorldAgentAutoAssetService
|
||||
-> session.draftProfile / draftCards / assetCoverage
|
||||
-> 前端 buildCustomWorldProfileFromAgentDraft()
|
||||
-> generatedCustomWorldProfile
|
||||
-> upsertCustomWorldProfile()
|
||||
-> handleCustomWorldSelect(profile)
|
||||
-> runtime
|
||||
```
|
||||
|
||||
关键特点:
|
||||
|
||||
1. Agent session 不是 runtime 直接消费的对象。
|
||||
2. Agent 草稿完成后,会在前端先转成 `CustomWorldProfile`。
|
||||
3. 结果页阶段会自动调用 `upsertCustomWorldProfile()`,把当前 profile 写进 `custom-world-library`。
|
||||
4. “进入世界”按钮直接把这个 profile 送给 `handleCustomWorldSelect(...)`,不需要 `publish_world`。
|
||||
|
||||
主要证据:
|
||||
|
||||
- `src/components/game-shell/PreGameSelectionFlow.tsx`
|
||||
- `src/services/customWorldAgentDraftResult.ts`
|
||||
- `src/hooks/useGameFlow.ts`
|
||||
|
||||
## 3.2 旧自定义世界 session 链
|
||||
|
||||
旧链路仍然完整存在:
|
||||
|
||||
```text
|
||||
aiService.generateCustomWorldProfile()
|
||||
-> /api/runtime/custom-world/sessions
|
||||
-> answerCustomWorldSessionQuestion()
|
||||
-> /generate/stream
|
||||
-> generateCustomWorldProfile()
|
||||
-> CustomWorldProfile
|
||||
-> 结果页 / 作品库 / 进入世界
|
||||
```
|
||||
|
||||
关键特点:
|
||||
|
||||
1. `src/services/aiService.ts` 里的 `generateCustomWorldProfile()` 仍然会创建旧 `custom-world/sessions`。
|
||||
2. 前端会先根据 `world_hook / player_premise / opening_situation / core_conflict` 自动补默认回答,再触发流式生成。
|
||||
3. 这条链已经与 Agent 八锚点链并行存在,且依然可用。
|
||||
|
||||
主要证据:
|
||||
|
||||
- `src/services/aiService.ts`
|
||||
- `server-node/src/routes/runtimeRoutes.ts`
|
||||
- `server-node/src/services/customWorldSessionStore.ts`
|
||||
|
||||
## 3.3 已保存 profile / 作品库链
|
||||
|
||||
当前作品库链是:
|
||||
|
||||
```text
|
||||
custom-world-library
|
||||
-> upsert / delete / publish / unpublish
|
||||
-> PlatformHomeView / saved profile detail
|
||||
-> CustomWorldResultView
|
||||
-> handleCustomWorldSelect(profile)
|
||||
```
|
||||
|
||||
关键特点:
|
||||
|
||||
1. 这条链直接消费 `CustomWorldProfile`,不依赖 Agent session。
|
||||
2. Agent 结果页自动保存后,也会落入这条链。
|
||||
3. `publish/unpublish` 作用在作品库 profile 上,而不是 Agent session 上。
|
||||
|
||||
主要证据:
|
||||
|
||||
- `server-node/src/routes/runtimeRoutes.ts`
|
||||
- `src/components/game-shell/PlatformHomeView.tsx`
|
||||
- `src/components/game-shell/PreGameSelectionFlow.tsx`
|
||||
|
||||
## 3.4 结果页 legacy profile 直改链
|
||||
|
||||
`CustomWorldResultView.tsx` 仍保留旧能力:
|
||||
|
||||
1. `generateCustomWorldPlayableNpc({ profile })`
|
||||
2. `generateCustomWorldStoryNpc({ profile })`
|
||||
3. `generateCustomWorldLandmark({ profile })`
|
||||
4. `CustomWorldEntityEditorModal`
|
||||
|
||||
这意味着结果页不仅是预览层,还是一套独立的“legacy profile 直改工作台”。这一套能力不会回写 Agent session 的结构化状态,也不会走 Agent action route。
|
||||
|
||||
主要证据:
|
||||
|
||||
- `src/components/CustomWorldResultView.tsx`
|
||||
- `src/services/aiService.ts`
|
||||
|
||||
## 3.5 创作中心 works 聚合链
|
||||
|
||||
后端已经能聚合两类作品:
|
||||
|
||||
1. `sourceType: 'agent_session'`
|
||||
2. `sourceType: 'published_profile'`
|
||||
|
||||
但主平台 `create` tab 现在仍主要展示 `myEntries`,没有把 `CustomWorldCreationHub.tsx` 作为主入口接上。
|
||||
|
||||
这导致:
|
||||
|
||||
1. works 聚合链存在
|
||||
2. create tab 真实消费的是另一条链
|
||||
3. Agent draft session 的继续创作入口没有真正收口到主平台
|
||||
|
||||
主要证据:
|
||||
|
||||
- `server-node/src/services/customWorldWorkSummaryService.ts`
|
||||
- `src/components/custom-world-home/CustomWorldCreationHub.tsx`
|
||||
- `src/components/game-shell/PlatformHomeView.tsx`
|
||||
|
||||
---
|
||||
|
||||
## 4. 数据断点
|
||||
|
||||
| 断点 | 当前现状 | 影响 | 主要证据 |
|
||||
| --- | --- | --- | --- |
|
||||
| Agent session -> runtime | `buildCustomWorldProfileFromAgentDraft()` 在前端把 `session.draftProfile` 编译成 legacy `CustomWorldProfile`,后续结果页、自动保存、进入世界都只认 profile | 后端不再是最终唯一真相源,前端承担了结构化编译与字段裁决,容易产生字段丢失、语义漂移、状态失真 | `src/components/game-shell/PreGameSelectionFlow.tsx`、`src/services/customWorldAgentDraftResult.ts` |
|
||||
| foundation draft 内部双重编译 | `CustomWorldAgentFoundationDraftService` 会先 `buildCompiledCustomWorldProfile(...)`,再 `convertRuntimeProfileToFoundationDraft(...)`,并把结果塞进 `legacyResultProfile` | Agent draft 不是原生生成,而是绕了一次 legacy profile,再回 draft;后续桥接层依赖这个字段继续工作 | `server-node/src/services/customWorldAgentFoundationDraftService.ts` |
|
||||
| 创作态元数据进入最终 profile | 前端桥接时会把 `anchorContent / creatorIntent / anchorPack / lockState` 一并塞进 legacy profile;同时固定写入 `generationMode: 'fast'`、`generationStatus: 'key_only'` | 创作态数据污染运行时 profile 存储;`generationMode / generationStatus` 还会覆盖真实阶段语义 | `src/services/customWorldAgentDraftResult.ts` |
|
||||
| Agent session 元数据在结果页后被截断 | `draftCards / pendingClarifications / suggestedActions / qualityFindings / checkpoints / operations` 大多停留在 session 层;结果页与 runtime 只继续消费 profile | 进入结果页后,Agent 会话层的大量结构化上下文被切断,发布门槛、锁定、局部重生成等信息无法自然继承 | `packages/shared/src/contracts/customWorldAgent.ts`、`server-node/src/services/customWorldAgentSessionStore.ts`、`src/components/custom-world-agent/CustomWorldAgentWorkspace.tsx` |
|
||||
| works 聚合 -> 平台 create tab | 后端 `listCustomWorldWorkSummaries(...)` 能返回 draft 与 published,但 create tab 仍只渲染 `myEntries` | Agent draft session 无法稳定出现在主入口“我的创作”里,恢复创作入口割裂 | `server-node/src/services/customWorldWorkSummaryService.ts`、`src/components/game-shell/PlatformHomeView.tsx` |
|
||||
| 发布状态 -> 可玩状态 | 结果页会自动 `upsertCustomWorldProfile()` 并允许直接 `onEnterWorld`;但 `publish_world` action 仍不可用 | “可玩”与“已发布”没有统一门槛,发布校验无法阻止未完成草稿进入世界 | `src/components/game-shell/PreGameSelectionFlow.tsx`、`server-node/src/services/customWorldAgentOrchestrator.ts` |
|
||||
|
||||
---
|
||||
|
||||
## 5. 多条 Pipeline
|
||||
|
||||
## 5.1 主链级 pipeline
|
||||
|
||||
| pipeline | 真相源 | 当前是否在主流程可达 | 问题 |
|
||||
| --- | --- | --- | --- |
|
||||
| Agent 会话草稿链 | `CustomWorldAgentSessionStore` + `draftProfile` | 是 | 后半段通过前端桥接成 legacy profile,未形成端到端单一真相源 |
|
||||
| 旧 custom-world session 链 | `CustomWorldSessionStore` | 是 | 与 Agent 八锚点链重复,且前端仍在补默认回答 |
|
||||
| 已保存 / 已发布 profile 链 | `custom-world-library` 中的 `CustomWorldProfile` | 是 | 与 Agent draft session 发布链平行存在 |
|
||||
| 结果页 legacy profile 直改链 | 结果页本地 `profile` | 是 | 绕过 Agent session,属于并行编辑器 |
|
||||
| works 创作中心链 | `listCustomWorldWorks()` 聚合数据 | 否,主平台未接主入口 | 后端已有聚合,但 UI 没真正切过去 |
|
||||
|
||||
## 5.2 资产子链 pipeline
|
||||
|
||||
资产相关还存在“自动补齐”和“人工工坊写回”并存:
|
||||
|
||||
1. `draft_foundation` 后,`CustomWorldAgentAutoAssetService` 会自动补角色主图和幕背景图。
|
||||
2. 角色资产又存在 `generate_role_assets -> sync_role_assets` 的手动工坊写回链。
|
||||
3. 场景资产在 contract 层定义了 `generate_scene_assets / sync_scene_assets`,但主 action 链未打通。
|
||||
|
||||
这导致当前资产链不是一条统一 pipeline,而是:
|
||||
|
||||
```text
|
||||
自动补角色 / 自动补幕背景
|
||||
并存
|
||||
手动角色工坊 -> sync_role_assets
|
||||
缺失
|
||||
手动场景工坊 -> sync_scene_assets
|
||||
```
|
||||
|
||||
主要证据:
|
||||
|
||||
- `server-node/src/services/customWorldAgentAutoAssetService.ts`
|
||||
- `server-node/src/services/customWorldAgentRoleAssetStateService.ts`
|
||||
- `packages/shared/src/contracts/customWorldAgent.ts`
|
||||
- `server-node/src/services/customWorldAgentOrchestrator.ts`
|
||||
|
||||
---
|
||||
|
||||
## 6. 冗余字段与主链悬空字段
|
||||
|
||||
这里区分两类:
|
||||
|
||||
1. 已经明显承担桥接残留职责的冗余字段
|
||||
2. 在 contract / session 里存在,但当前主流程几乎不消费的悬空字段
|
||||
|
||||
| 字段 | 类型 | 当前状态 | 判断 |
|
||||
| --- | --- | --- | --- |
|
||||
| `draftProfile.legacyResultProfile` | 桥接残留字段 | foundation draft 服务端先生成 legacy runtime profile,再把它塞回 draft,前端桥接又优先读它 | 明显冗余,属于临时兼容字段,不应长期成为主链依赖 |
|
||||
| `generationMode: 'fast'` | 固定写死字段 | `buildCustomWorldProfileFromAgentDraft()` 固定写入 | 不是草稿真实状态,更像桥接层补丁 |
|
||||
| `generationStatus: 'key_only'` | 固定写死字段 | `buildCustomWorldProfileFromAgentDraft()` 固定写入 | 同上,会掩盖真实生成阶段 |
|
||||
| `anchorContent / creatorIntent / anchorPack / lockState` 被直接塞进 legacy profile | 创作态元数据 | 会跟随自动保存一起写进作品库 profile,但 runtime 并不以这些字段为正式运行时输入 | 当前更像创作态元数据泄漏进运行时 profile |
|
||||
| `qualityFindings` | session / contract 字段 | contract、session store、测试里存在,但没形成生成、渲染、发布阻断闭环 | 当前主链悬空 |
|
||||
| `checkpoints` | session 字段 | session store 会记录,但主工作区和结果页没有真实展示入口 | 当前主链悬空 |
|
||||
| `suggestedActions` | session 字段 | session 会生成,但当前正式工作区没有对应消费面;旧 `QuickActions` 面板已在 `2026-04-21` 判定退出当前版本主链并物理删除 | 当前主链悬空 |
|
||||
| `pendingClarifications` | session 字段 | session 有数据,但当前正式工作区没有对应消费面;旧澄清面板已在 `2026-04-21` 判定退出当前版本主链并物理删除 | 当前主链悬空 |
|
||||
| `operations` 历史 | session 字段 | 主工作区只展示当前 `activeOperation` 横幅,不展示完整历史 | 当前主链弱消费 |
|
||||
| `roleAssetSummaryLabel / cover* / counts` 等 works 字段 | works 聚合字段 | 后端能返回,但主平台 create tab 没走 `works` 入口 | 当前主链弱消费 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 冗余功能与冗余组件
|
||||
|
||||
## 7.1 冗余功能
|
||||
|
||||
| 功能 | 当前状态 | 问题 |
|
||||
| --- | --- | --- |
|
||||
| 结果页直接生成 playable/story/landmark | `CustomWorldResultView.tsx` 仍可直接调用 AI 生成 | 与 Agent 对象精修链重复,且不会同步回 session |
|
||||
| 结果页直接编辑 `CustomWorldProfile` | `CustomWorldEntityEditorModal` 仍挂在结果页 | 把结果页继续维持成旧编辑器,而不是 Agent 流程的收口层 |
|
||||
| 旧 `custom-world/sessions` 世界生成 | `2026-04-20` 审计时仍完整可用;`2026-04-21` 已完成物理删除 | 与 Agent 八锚点世界创建重复;当前遗留问题已转为文档口径清理 |
|
||||
| 作品库 `publish/unpublish` 与 Agent `publish_world` | 两套“发布”概念并行 | 一套作用于 library profile,一套想作用于 Agent session,但后者还未打通 |
|
||||
| 结果页自动保存 | `generatedCustomWorldProfile` 变化时自动 `upsertCustomWorldProfile()` | 让“草稿保存”“作品库存档”“正式发布”语义混在一起 |
|
||||
|
||||
## 7.2 冗余或已退出当前版本主链的组件
|
||||
|
||||
`src/components/custom-world-agent/CustomWorldAgentWorkspace.tsx` 当前只真正接了:
|
||||
|
||||
1. `CustomWorldAgentHeader`
|
||||
2. `EightAnchorProgressBar`
|
||||
3. `CustomWorldAgentOperationBanner`
|
||||
4. `CustomWorldAgentThread`
|
||||
5. `CustomWorldAgentComposer`
|
||||
|
||||
在 `2026-04-21` 清理前,同目录下还存在一组未接线旧组件:
|
||||
|
||||
1. `CustomWorldAgentLockBar.tsx`
|
||||
2. `CustomWorldAgentDraftDrawer.tsx`
|
||||
3. `CustomWorldAgentDraftDetailPanel.tsx`
|
||||
4. `CustomWorldAgentQuickActions.tsx`
|
||||
5. `CustomWorldAgentSummaryPanel.tsx`
|
||||
6. `CustomWorldAgentIntentSummaryPanel.tsx`
|
||||
7. `CustomWorldAgentClarificationPanel.tsx`
|
||||
8. `CustomWorldGenerateEntityModal.tsx`
|
||||
|
||||
其中:
|
||||
|
||||
1. `CustomWorldAgentDraftDrawer.tsx` 已在批次 A 清理中删除
|
||||
2. `CustomWorldAgentLockBar.tsx`
|
||||
3. `CustomWorldAgentDraftDetailPanel.tsx`
|
||||
4. `CustomWorldAgentQuickActions.tsx`
|
||||
5. `CustomWorldAgentSummaryPanel.tsx`
|
||||
6. `CustomWorldAgentIntentSummaryPanel.tsx`
|
||||
7. `CustomWorldAgentClarificationPanel.tsx`
|
||||
8. `CustomWorldGenerateEntityModal.tsx`
|
||||
|
||||
已在批次 D 清理中判定为退出当前版本主链,并完成物理删除。
|
||||
|
||||
因此这里的审计结论需要更新为:
|
||||
|
||||
1. 它们不再属于“待接线组件”
|
||||
2. 它们属于已确认退场的旧副面板链
|
||||
3. 当前版本如果还要补 `suggestedActions / pendingClarifications / draftCards` 的消费面,应基于新的主链设计重新定义,而不是默认把旧面板接回来
|
||||
|
||||
另外,`src/components/custom-world-home/CustomWorldCreationHub.tsx` 也已存在,但平台 `create` tab 还没有把它接成主入口。
|
||||
|
||||
---
|
||||
|
||||
## 8. 当前没有真正实装到游戏主流程中的项
|
||||
|
||||
| 能力 | 设计 / 定义位置 | 当前状态 |
|
||||
| --- | --- | --- |
|
||||
| `publish_world` 真正发布链 | contract、PRD、route、orchestrator | route 能接,orchestrator 直接 `throw badRequest('publish_world is not available in phase5')` |
|
||||
| `generate_scene_assets` | contract、PRD | contract 定义了,但 action route 未接,主链无执行实现 |
|
||||
| `sync_scene_assets` | contract、PRD | contract 定义了,但 action route 未接,主链无执行实现 |
|
||||
| `expand_long_tail` | contract、PRD | contract 定义了,但主 action 链未接 |
|
||||
| `lock_cards / unlock_cards` | contract、PRD | contract 定义了,但 route / UI / orchestrator 主链未接 |
|
||||
| `regenerate_scope` | contract、PRD | contract 定义了,但 route / UI / orchestrator 主链未接 |
|
||||
| `qualityFindings` 与 blocker 发布门禁 | contract、PRD、技术进度文档 | 字段存在,但没有真实的生成、展示、阻止发布闭环 |
|
||||
| 场景资产工坊从 Agent workspace 打开并写回 | PRD | 主工作区未接详情面板与场景资产 action |
|
||||
| 通过 works 统一恢复 Agent draft / 已发布作品 | works service + creation hub | 后端已有聚合,主平台入口未收口 |
|
||||
| 发布前只允许预览、发布后再进入世界 | PRD | 当前 Agent 草稿结果页可自动保存并直接进入世界 |
|
||||
|
||||
补充说明:
|
||||
|
||||
`docs/technical/SCENE_MULTI_ACT_CREATOR_IMPLEMENTATION_PROGRESS_2026-04-20.md` 已明确写到,发布期 `qualityFindings / blocker` 正式接入仍未完成,这与当前代码状态一致。
|
||||
|
||||
---
|
||||
|
||||
## 9. 优先级建议
|
||||
|
||||
## P0:先收一条真正的单一主链
|
||||
|
||||
建议明确把下面这条定为唯一正式主链:
|
||||
|
||||
```text
|
||||
Agent session
|
||||
-> 服务端 draft snapshot
|
||||
-> 服务端质量检查 / 发布动作
|
||||
-> 服务端编译 final CustomWorldProfile
|
||||
-> 世界库
|
||||
-> runtime
|
||||
```
|
||||
|
||||
对应动作:
|
||||
|
||||
1. 结果页不再承担“主编辑器”职责,至少对 Agent draft 结果页关闭 legacy profile 直改能力。
|
||||
2. 用服务端 preview / compile 接口替代前端 `buildCustomWorldProfileFromAgentDraft()` 的最终裁决职责。
|
||||
3. `publish_world` 打通后,再决定是否允许“发布后立即进入世界”。
|
||||
|
||||
## P0:把“进入世界”和“发布世界”重新绑回同一门槛
|
||||
|
||||
建议收口为:
|
||||
|
||||
1. 未发布 Agent 草稿只能继续创作或查看预览。
|
||||
2. 只有 `publish_world` 成功后,才产出正式 `CustomWorldProfile` 并允许主入口进入世界。
|
||||
3. `qualityFindings / blocker` 必须在 foundation draft 完成、资产写回后、publish 前持续重跑。
|
||||
|
||||
## P1:继续做旧 world session 链的文档收口
|
||||
|
||||
`2026-04-21` 更新:
|
||||
|
||||
旧 `custom-world/sessions` 链已经完成物理删除。
|
||||
|
||||
因此这里不再是“保留还是淘汰”的开放问题,而是:
|
||||
|
||||
1. 继续清理由这条旧链残留在审计、PRD、知识图谱中的过时口径
|
||||
2. 把当前正式主链与仍保留的兼容层边界写清楚
|
||||
|
||||
## P1:把 works 创作中心接回主平台
|
||||
|
||||
建议:
|
||||
|
||||
1. 平台 `create` tab 改成消费 `listCustomWorldWorks()`。
|
||||
2. 草稿 session 通过“继续创作”恢复。
|
||||
3. 已发布 profile 通过“进入世界”或“查看详情”进入。
|
||||
4. `myEntries` 退回为作品库子集,而不是 create tab 的唯一数据源。
|
||||
|
||||
## P1:为悬空 session 字段重新定义最小闭环
|
||||
|
||||
`2026-04-21` 更新:
|
||||
|
||||
原文这里建议把旧 `QuickActions / DraftDrawer / DraftDetailPanel / ClarificationPanel` 接回主工作区。
|
||||
|
||||
但这些旧副面板已经在当前版本收口判断中被明确认定为:
|
||||
|
||||
1. 不属于现行主链
|
||||
2. 不再作为当前版本默认待落地项
|
||||
3. 已完成物理删除
|
||||
|
||||
因此当前更准确的建议应该是:
|
||||
|
||||
1. 如果 `suggestedActions / pendingClarifications / draftCards` 仍要进入正式主流程,需要先重新定义符合当前极简工作区的消费方式
|
||||
2. 不应再以“把旧副面板接回来”作为默认方案
|
||||
3. 在没有新主链设计前,这些字段继续标记为“主链悬空”
|
||||
|
||||
## P2:等主链收口后再清桥接字段
|
||||
|
||||
下面这些字段不建议现在立刻删,但应在主链收口后尽快移除:
|
||||
|
||||
1. `draftProfile.legacyResultProfile`
|
||||
2. 前端桥接里固定写死的 `generationMode / generationStatus`
|
||||
3. 仅为兼容旧编辑器而塞进 legacy profile 的创作态元数据
|
||||
|
||||
---
|
||||
|
||||
## 10. 一句话总评
|
||||
|
||||
当前“Agent 聊天 -> 草稿生成 -> 进入世界”已经能跑通一条可玩链,但它还不是 PRD 要求的“后端单一真相源 + 发布门禁收口”的正式链路,而是 `Agent session`、`legacy profile`、`旧 session`、`作品库` 四层并存、靠前端桥接和结果页兼容能力临时拼起来的过渡态。
|
||||
332
docs/audits/CHARACTER_ASSET_PROMPT_CHAIN_AUDIT_2026-04-20.md
Normal file
332
docs/audits/CHARACTER_ASSET_PROMPT_CHAIN_AUDIT_2026-04-20.md
Normal file
@@ -0,0 +1,332 @@
|
||||
# 角色资产 Prompt 链路审计(2026-04-20)
|
||||
|
||||
更新时间:`2026-04-20`
|
||||
|
||||
## 0. 本次审计回答什么问题
|
||||
|
||||
本次只回答角色资产相关的 4 个问题:
|
||||
|
||||
1. `characterAssetPrompts.ts` 里的 `visualPromptText` 和 `animationPromptText`,是不是“生成角色形象 / 动作形象的默认描述”。
|
||||
2. 生成角色形象的系统提示词在哪个文件,生成默认角色形象描述文本的提示词在哪个文件。
|
||||
3. 生成角色动作的系统提示词在哪个文件,生成默认角色动作描述文本的提示词在哪个文件。
|
||||
4. 当前链路里是否存在冗余流程、保留接口或无效代码。
|
||||
|
||||
---
|
||||
|
||||
## 1. 先说结论
|
||||
|
||||
结论不是“只有一套 prompt”,而是:
|
||||
|
||||
**当前角色资产链路仍然有两层 prompt,但“默认描述文本”已经统一成单一主源。**
|
||||
|
||||
### 1.1 默认描述文本层
|
||||
|
||||
这层的目标是:
|
||||
|
||||
**先给资产工坊里的输入框一个默认可编辑文本。**
|
||||
|
||||
这层不直接拿去生成图片或动作视频。
|
||||
|
||||
当前实际主链来源:
|
||||
|
||||
- `src/prompts/customWorldRolePromptDefaults.ts`
|
||||
|
||||
它会把角色已有字段映射成:
|
||||
|
||||
- `visualPromptText`
|
||||
- `animationPromptText`
|
||||
- `scenePromptText`
|
||||
|
||||
其中:
|
||||
|
||||
- `visualPromptText` 优先取 `visualDescription`
|
||||
- `animationPromptText` 优先取 `actionDescription`
|
||||
- `scenePromptText` 优先取 `sceneVisualDescription`
|
||||
|
||||
这层是**默认描述文本**,不是正式图像模型 prompt。
|
||||
|
||||
### 1.2 正式模型 prompt 层
|
||||
|
||||
这层的目标是:
|
||||
|
||||
**把“默认描述文本”进一步编译成正式给图像模型 / 动作模型的完整 prompt。**
|
||||
|
||||
当前主链来源:
|
||||
|
||||
- `server-node/src/prompts/characterAssetPrompts.ts`
|
||||
- `packages/shared/src/prompts/qwenSprite.ts`
|
||||
|
||||
也就是说:
|
||||
|
||||
1. 前端先有一段短文本
|
||||
2. 后端再用正式 prompt builder 把它扩成模型真正使用的完整 prompt
|
||||
|
||||
---
|
||||
|
||||
## 2. 角色形象生成链路
|
||||
|
||||
## 2.1 生成角色形象的系统提示词在哪
|
||||
|
||||
如果这里问的是“正式生成角色主图时,真正控制模型输出方向的 prompt 主源在哪”,答案是:
|
||||
|
||||
- `server-node/src/prompts/characterAssetPrompts.ts`
|
||||
- `packages/shared/src/prompts/qwenSprite.ts`
|
||||
|
||||
更准确说:
|
||||
|
||||
1. `buildNpcVisualPrompt`
|
||||
- 文件:`server-node/src/prompts/characterAssetPrompts.ts`
|
||||
- 作用:把短描述文本和角色摘要合并
|
||||
2. `buildMasterPrompt`
|
||||
- 文件:`packages/shared/src/prompts/qwenSprite.ts`
|
||||
- 作用:提供正式的角色主图 prompt 骨架
|
||||
|
||||
最终角色形象正式生成请求使用的是:
|
||||
|
||||
- `buildNpcVisualPrompt(...)`
|
||||
|
||||
调用位置:
|
||||
|
||||
- `server-node/src/modules/assets/characterAssetRoutes.ts`
|
||||
|
||||
即:
|
||||
|
||||
**角色主图正式生成的系统提示词主链,不在前端默认值文件,而在后端 `characterAssetPrompts.ts` + 共享 `qwenSprite.ts`。**
|
||||
|
||||
## 2.2 生成默认角色形象描述文本的提示词在哪
|
||||
|
||||
当前资产工坊默认输入框实际使用:
|
||||
|
||||
- `src/prompts/customWorldRolePromptDefaults.ts`
|
||||
|
||||
这不是 LLM system prompt,而是本地字段映射规则。
|
||||
|
||||
换句话说,当前页面上的默认“形象描述”主要来自:
|
||||
|
||||
- `role.visualDescription`
|
||||
- 或回退到 `role.description`
|
||||
|
||||
---
|
||||
|
||||
## 3. 角色动作生成链路
|
||||
|
||||
## 3.1 生成角色动作的系统提示词在哪
|
||||
|
||||
当前正式动作生成主链在:
|
||||
|
||||
- `server-node/src/prompts/characterAssetPrompts.ts`
|
||||
- `packages/shared/src/prompts/qwenSprite.ts`
|
||||
|
||||
其中分两类:
|
||||
|
||||
1. `buildArkCharacterAnimationPrompt`
|
||||
- 当前图生视频动作链路主入口
|
||||
2. `buildNpcAnimationPrompt`
|
||||
- 通用动作视频 prompt builder
|
||||
3. `buildImageSequencePrompt`
|
||||
- 连续帧方案动作 prompt builder
|
||||
4. `buildVideoActionPrompt`
|
||||
- 共享动作模板骨架,在 `packages/shared/src/prompts/qwenSprite.ts`
|
||||
|
||||
当前主动作链路更偏向:
|
||||
|
||||
- `buildArkCharacterAnimationPrompt`
|
||||
|
||||
调用位置:
|
||||
|
||||
- `server-node/src/modules/assets/characterAssetRoutes.ts`
|
||||
|
||||
## 3.2 生成默认角色动作描述文本的提示词在哪
|
||||
|
||||
当前资产工坊真实默认“动作描述”来源:
|
||||
|
||||
- `src/prompts/customWorldRolePromptDefaults.ts`
|
||||
|
||||
规则是:
|
||||
|
||||
- 优先 `actionDescription`
|
||||
- 回退 `combatStyle`
|
||||
|
||||
这仍然是**默认描述文本层**,不是最终动作模型 prompt。
|
||||
|
||||
---
|
||||
|
||||
## 4. `characterAssetPrompts.ts` 里的 `visualPromptText` / `animationPromptText` 到底是什么
|
||||
|
||||
这两个字段容易混淆,因为它们名字里带 `Prompt`。
|
||||
|
||||
但当前工程里它们更准确的定位是:
|
||||
|
||||
**“默认描述文本 bundle 字段名”,不是最终图像模型请求体里的最终 prompt 名称。**
|
||||
|
||||
也就是:
|
||||
|
||||
- `visualPromptText`
|
||||
- 在 UI 里更像“角色形象描述默认文本”
|
||||
- 之后会再被编译进正式图像 prompt
|
||||
- `animationPromptText`
|
||||
- 在 UI 里更像“角色动作描述默认文本”
|
||||
- 之后会再被编译进正式动作 prompt
|
||||
|
||||
所以对你的问题可以直接回答为:
|
||||
|
||||
**是,它们在当前语义上确实可以看作“默认角色形象 / 动作描述文本”。**
|
||||
|
||||
但需要补一句:
|
||||
|
||||
**它们不是最终一步的正式模型系统提示词,而是正式模型 prompt 的上游输入。**
|
||||
|
||||
---
|
||||
|
||||
## 5. 当前真实调用链
|
||||
|
||||
## 5.1 当前资产工坊页面初始默认值主链
|
||||
|
||||
当前真实主链:
|
||||
|
||||
1. 角色对象已有字段进入前端
|
||||
2. `src/prompts/customWorldRolePromptDefaults.ts`
|
||||
3. `CustomWorldRoleAssetStudioModal.tsx`
|
||||
4. 输入框初始值:
|
||||
- `visualPromptText`
|
||||
- `animationPromptText`
|
||||
|
||||
这条链:
|
||||
|
||||
- 快
|
||||
- 本地可控
|
||||
- 不依赖额外一次 LLM 调用
|
||||
|
||||
## 5.2 当前正式角色主图生成主链
|
||||
|
||||
1. 前端把输入框里的 `visualPromptText` 提交到后端
|
||||
2. `server-node/src/prompts/characterAssetPrompts.ts`
|
||||
- `buildNpcVisualPrompt`
|
||||
3. `packages/shared/src/prompts/qwenSprite.ts`
|
||||
- `buildMasterPrompt`
|
||||
4. 图像模型正式生成
|
||||
|
||||
## 5.3 当前正式角色动作生成主链
|
||||
|
||||
1. 前端把输入框里的 `animationPromptText` 提交到后端
|
||||
2. `server-node/src/prompts/characterAssetPrompts.ts`
|
||||
- `buildArkCharacterAnimationPrompt`
|
||||
- 或 `buildNpcAnimationPrompt`
|
||||
- 或 `buildImageSequencePrompt`
|
||||
3. `packages/shared/src/prompts/qwenSprite.ts`
|
||||
- `buildVideoActionPrompt`
|
||||
4. 动作模型正式生成
|
||||
|
||||
---
|
||||
|
||||
## 6. 冗余流程与当前问题
|
||||
|
||||
## 6.1 默认描述文本双链已收口
|
||||
|
||||
此前默认描述文本同时存在:
|
||||
|
||||
1. 前端本地字段映射
|
||||
2. 后端 bundle 编译接口
|
||||
|
||||
本轮已经统一为:
|
||||
|
||||
- `src/prompts/customWorldRolePromptDefaults.ts`
|
||||
|
||||
也就是:
|
||||
|
||||
**默认描述文本现在只有一条真实主源。**
|
||||
|
||||
对应变化:
|
||||
|
||||
1. 不再保留后端独立的默认 bundle 编译接口。
|
||||
2. 不再保留前端对应的 bundle 生成 API 壳层。
|
||||
3. `server-node/src/prompts/characterAssetPrompts.ts` 只保留正式模型 prompt builder。
|
||||
|
||||
判断:
|
||||
|
||||
**默认描述文本层的双份真相已经被消除。**
|
||||
|
||||
## 6.2 `scenePromptText` 结构存在,但当前资产工坊没有完整承接
|
||||
|
||||
当前这套链路里:
|
||||
|
||||
- `customWorldRolePromptDefaults.ts` 会返回 `scenePromptText`
|
||||
- `characterAssetPrompts.ts` 也会返回 `scenePromptText`
|
||||
|
||||
但当前资产工坊 UI 里并没有完整对应输入框链路。
|
||||
|
||||
这说明:
|
||||
|
||||
**场景描述文本在结构层存在,但在当前角色资产工坊里没有形成完整的用户可编辑闭环。**
|
||||
|
||||
## 6.3 共享模板与工具模板存在相似实现,但职责不同
|
||||
|
||||
仓库里同时有:
|
||||
|
||||
- `packages/shared/src/prompts/qwenSprite.ts`
|
||||
- `src/prompts/qwenSpriteSheetToolPrompts.ts`
|
||||
|
||||
它们都提供类似的主图 / 动作模板能力。
|
||||
|
||||
但当前定位不同:
|
||||
|
||||
- `packages/shared/src/prompts/qwenSprite.ts`
|
||||
- 正式角色资产主链共享模板
|
||||
- `src/prompts/qwenSpriteSheetToolPrompts.ts`
|
||||
- Qwen 工具链 prompt
|
||||
|
||||
它们不是同一条业务主链里的重复实现,但确实容易让人误读为“双份正式模板”。
|
||||
|
||||
判断:
|
||||
|
||||
**这是“职责上可解释,但认知上高混淆”的并行模板,不建议现在直接删,但需要文档明确边界。**
|
||||
|
||||
## 6.4 当前没有证据说明正式主图 / 动作 prompt builder 是无效代码
|
||||
|
||||
以下 builder 当前都有正式调用点:
|
||||
|
||||
- `buildNpcVisualPrompt`
|
||||
- `buildNpcVisualNegativePrompt`
|
||||
- `buildArkCharacterAnimationPrompt`
|
||||
- `buildNpcAnimationPrompt`
|
||||
- `buildImageSequencePrompt`
|
||||
|
||||
因此它们不能算“无效代码”。
|
||||
|
||||
真正已经被清理掉的保留链路,是此前未接入主 UI 的默认 bundle 接口:
|
||||
|
||||
- `CHARACTER_PROMPT_BUNDLE_SYSTEM_PROMPT`
|
||||
- `buildCharacterPromptBundleUserPrompt`
|
||||
- `/api/assets/character-prompts/generate`
|
||||
|
||||
这套链路已经不再保留在当前仓库主线中。
|
||||
|
||||
---
|
||||
|
||||
## 7. 本次建议
|
||||
|
||||
如果后续要继续收口,建议按顺序处理:
|
||||
|
||||
1. 继续以前端本地映射作为默认描述文本唯一主源。
|
||||
2. 对 `scenePromptText` 做完整承接,不要继续停留在结构存在但 UI 不消费的状态。
|
||||
3. 继续保留 `packages/shared/src/prompts/qwenSprite.ts` 与工具链 prompt 分层,但在文档里强制写清“正式主链 / 工具链”边界。
|
||||
|
||||
---
|
||||
|
||||
## 8. 本次审计覆盖文件
|
||||
|
||||
- `server-node/src/prompts/characterAssetPrompts.ts`
|
||||
- `packages/shared/src/prompts/qwenSprite.ts`
|
||||
- `server-node/src/modules/assets/characterAssetRoutes.ts`
|
||||
- `src/prompts/customWorldRolePromptDefaults.ts`
|
||||
- `src/components/CustomWorldRoleAssetStudioModal.tsx`
|
||||
- `src/components/asset-studio/characterAssetWorkflowPersistence.ts`
|
||||
- `src/prompts/qwenSpriteSheetToolPrompts.ts`
|
||||
|
||||
---
|
||||
|
||||
## 9. 一句话版结论
|
||||
|
||||
一句话总结就是:
|
||||
|
||||
**当前角色资产系统把“默认描述文本”和“正式模型 prompt”拆成了两层,这是合理的;默认描述文本层已经统一为前端本地映射单一主源,当前剩余主要问题不再是双主源,而是 `scenePromptText` 仍未形成完整 UI 闭环。**
|
||||
444
docs/audits/CUSTOM_WORLD_CREATOR_TOOL_AUDIT_2026-04-08.md
Normal file
444
docs/audits/CUSTOM_WORLD_CREATOR_TOOL_AUDIT_2026-04-08.md
Normal file
@@ -0,0 +1,444 @@
|
||||
# 自定义世界创作工具问题审计与优化建议
|
||||
|
||||
更新时间:`2026-04-08`
|
||||
|
||||
## 0. 结论先说
|
||||
|
||||
当前自定义世界创作工具已经有了比较强的生成骨架、锚点结构和结果编辑能力,但整体仍处在一个很明显的“半收口状态”:
|
||||
|
||||
**设计目标已经走到“创作者工作台”,数据结构已经支持“锚点化输入”,但实际体验仍然更像“大文本生成器 + 大型结果总表编辑器”。**
|
||||
|
||||
如果用一句话概括当前问题,就是:
|
||||
|
||||
**高杠杆创作入口还不够强,低杠杆编辑负担还偏重,局部重生成与后端收口也还没有真正闭环。**
|
||||
|
||||
---
|
||||
|
||||
## 1. 审计范围
|
||||
|
||||
本次审计主要对照了三类信息:
|
||||
|
||||
1. 目标设计与 PRD
|
||||
- `docs/prd/AI_NATIVE_CUSTOM_WORLD_CREATION_FLOW_OPTIMIZATION_PRD_2026-04-06.md`
|
||||
- `docs/design/CUSTOM_WORLD_CREATOR_INPUT_AND_AI_BOUNDARY_DESIGN_2026-04-06.md`
|
||||
- `docs/design/CUSTOM_WORLD_SELF_OWNED_SETTING_LAYER_OPTIMIZATION_2026-04-08.md`
|
||||
- `docs/design/CUSTOM_WORLD_TEMPLATE_DECOUPLING_AND_CROSS_GENRE_GENERALIZATION_DESIGN_2026-04-08.md`
|
||||
|
||||
2. 当前前端主流程与工作台
|
||||
- `src/components/SelectionCustomizationModals.tsx`
|
||||
- `src/components/game-shell/PreGameSelectionFlow.tsx`
|
||||
- `src/components/CustomWorldGenerationView.tsx`
|
||||
- `src/components/CustomWorldResultView.tsx`
|
||||
- `src/components/CustomWorldEntityCatalog.tsx`
|
||||
- `src/components/CustomWorldEntityEditorModal.tsx`
|
||||
|
||||
3. 当前生成链与后端会话层
|
||||
- `src/services/ai.ts`
|
||||
- `src/services/aiService.ts`
|
||||
- `src/services/customWorldCreatorIntent.ts`
|
||||
- `src/services/customWorld.ts`
|
||||
- `server-node/src/services/customWorldSessionStore.ts`
|
||||
- `server-node/src/services/customWorldGenerationService.ts`
|
||||
- `server-node/src/bridges/legacyAiRuntimeBridge.ts`
|
||||
|
||||
---
|
||||
|
||||
## 2. 当前主要问题
|
||||
|
||||
## 2.1 输入层和意图结构已经脱节
|
||||
|
||||
当前数据结构已经支持:
|
||||
|
||||
- 世界一句话
|
||||
- 主题关键词
|
||||
- 气质约束
|
||||
- 玩家身份
|
||||
- 开局处境
|
||||
- 核心冲突
|
||||
- 关键势力
|
||||
- 关键角色
|
||||
- 关键地点
|
||||
- 标志性要素
|
||||
- 禁止事项
|
||||
|
||||
但实际入口 `src/components/SelectionCustomizationModals.tsx` 里,创作者弹窗仍然基本只有:
|
||||
|
||||
- 生成模式
|
||||
- 一块大 textarea
|
||||
|
||||
这导致两个直接后果:
|
||||
|
||||
1. 设计里已经想清楚的“高杠杆锚点输入”,还没有真正变成主入口。
|
||||
2. `CustomWorldCreatorIntent` 虽然已经能表达卡片化输入,但 UI 并没有把它转成真正可用的创作工作台。
|
||||
|
||||
目前 `card` 模式更多还停留在类型和测试层,没有成为真实用户路径。
|
||||
|
||||
可优化点:
|
||||
|
||||
- 把当前创建弹窗升级成“快速文本模式 / 创作卡片模式”双入口。
|
||||
- 快速文本模式保留,但提交后应自动拆出建议锚点,而不是直接把整段文本原封不动送进生成链。
|
||||
- 卡片模式先只做最关键的 `5~6` 张卡,不要一开始把所有高级字段都铺开。
|
||||
- 允许空卡提交,但明确区分“已锁定锚点”和“允许 AI 自由补全”的内容。
|
||||
|
||||
---
|
||||
|
||||
## 2.2 澄清机制已经存在,但没有真正服务创作者
|
||||
|
||||
`server-node/src/services/customWorldSessionStore.ts` 已经支持:
|
||||
|
||||
- 根据输入缺口生成澄清问题
|
||||
- 世界核心不足时追问
|
||||
- 玩家身份缺失时追问
|
||||
- 开局处境缺失时追问
|
||||
- 核心冲突缺失时追问
|
||||
|
||||
但 `src/services/aiService.ts` 当前做法是:
|
||||
|
||||
- 创建 session
|
||||
- 读取问题
|
||||
- 直接用 fallback 文案自动回答
|
||||
- 然后继续生成
|
||||
|
||||
这意味着:
|
||||
|
||||
**系统表面上已经有“先澄清再生成”的能力,但实际体验里,创作者并没有真正参与这一步。**
|
||||
|
||||
结果就是:
|
||||
|
||||
- 低信息量输入并没有被真正补强
|
||||
- 澄清问题变成了内部兜底,而不是创作协作
|
||||
- 很容易继续生成出“完整但不够像用户想要的世界”
|
||||
|
||||
可优化点:
|
||||
|
||||
- 把 session question 真正接到前端,作为生成前的二次确认步骤。
|
||||
- 每次只问 `1~3` 个最关键问题,不要把它做成问卷。
|
||||
- 支持“一键使用系统建议”,但必须让创作者可见,而不是静默自动填充。
|
||||
- 把回答结果回写到 `creatorIntent`,而不是只作为一次性会话答案。
|
||||
|
||||
---
|
||||
|
||||
## 2.3 新建完成后的工作台闭环没有成立
|
||||
|
||||
设计文档里,自定义世界应该是:
|
||||
|
||||
`输入 -> 生成 -> 结果页确认/编辑 -> 保存并进入世界`
|
||||
|
||||
但当前 `src/components/game-shell/PreGameSelectionFlow.tsx` 里,新建世界生成成功后会:
|
||||
|
||||
- 直接保存到世界库
|
||||
- 清空 `generatedCustomWorldProfile`
|
||||
- 返回世界列表页
|
||||
|
||||
而不是进入 `custom-world-result` 结果工作台。
|
||||
|
||||
这会带来几个问题:
|
||||
|
||||
1. 新建后的第一时间确认感不够强。
|
||||
2. 快速模式生成出的“关键对象预览”没有自然承接页。
|
||||
3. 用户生成完后,如果想继续看结果、继续补全、继续编辑,还要再从世界列表里点一次“编辑”。
|
||||
|
||||
这条链路会让“创作中”与“已保存”之间的体验断开。
|
||||
|
||||
可优化点:
|
||||
|
||||
- 新建完成后默认进入结果工作台,而不是直接跳回世界列表。
|
||||
- 保存动作留在结果页显式触发。
|
||||
- 可以增加“自动保存草稿,但仍停留在结果页”的策略,兼顾安全感和连贯性。
|
||||
- 世界列表更适合作为“已归档内容入口”,不适合作为新建完成页。
|
||||
|
||||
---
|
||||
|
||||
## 2.4 结果页仍然偏“数据总表”,低杠杆编辑负担偏重
|
||||
|
||||
当前结果页已经有 `世界 / 锚点 / 可扮演角色 / 场景角色 / 场景` 五个页签,这是正确方向。
|
||||
|
||||
但问题在于,进入编辑器后暴露出来的字段仍然太“底层”了,例如:
|
||||
|
||||
- `backstoryReveal`
|
||||
- 技能列表
|
||||
- 初始物品
|
||||
- 场景 NPC 分配
|
||||
- 场景连接关系
|
||||
|
||||
这些字段对少数深度编辑场景有用,但不应该成为默认主编辑内容。
|
||||
|
||||
当前 `src/components/CustomWorldEntityEditorModal.tsx` 已经变成一个非常重的综合编辑器,里面同时承担:
|
||||
|
||||
- 角色完整档案编辑
|
||||
- 形象编辑入口
|
||||
- AI 资产生成入口
|
||||
- 背景章节编辑
|
||||
- 技能与初始物品编辑
|
||||
- 场景内 NPC 分配
|
||||
- 场景连接维护
|
||||
|
||||
这会带来三层问题:
|
||||
|
||||
1. 创作者负担过重
|
||||
- 很多字段属于“系统编译层”,不属于“创作决策层”。
|
||||
|
||||
2. 移动端负担过重
|
||||
- 大量长表单、长弹窗和多级编辑,对手机创作并不友好。
|
||||
|
||||
3. 工程复杂度过高
|
||||
- 前端工作台承担了太多不同层级的编辑职责。
|
||||
|
||||
可优化点:
|
||||
|
||||
- 默认只暴露高杠杆编辑:
|
||||
- 世界核心命题
|
||||
- 主题与气质
|
||||
- 玩家身份与开局
|
||||
- 关键势力
|
||||
- 关键角色
|
||||
- 关键地点
|
||||
- 标志性要素
|
||||
- 把技能、初始物品、章节 reveal、连接网络等移到“高级模式”或“系统层编辑”。
|
||||
- 结果页结构从“按对象字段堆表单”改成“按创作价值组织”。
|
||||
- 移动端优先改成分段式面板或底部工作台,不要把长表单都塞进同一个大 modal。
|
||||
|
||||
---
|
||||
|
||||
## 2.5 锁定与局部重生成机制还不完整
|
||||
|
||||
当前已经有两套看起来相关的能力:
|
||||
|
||||
1. `creatorIntent` 里的 `locked`
|
||||
2. `lockState` 里的角色 / 地点 / 势力锁定字段
|
||||
|
||||
但实际重生成时,`src/components/game-shell/PreGameSelectionFlow.tsx` 里的合并逻辑只真正处理了:
|
||||
|
||||
- 已锁定角色
|
||||
- 已锁定地点
|
||||
|
||||
而且还是按“名称匹配”保留,不是按稳定 id 或字段级锁定来处理。
|
||||
|
||||
这带来的问题很明显:
|
||||
|
||||
1. 角色或地点一旦重命名,锁定可能失效。
|
||||
2. 势力、冲突、世界概述等高价值内容没有真正进入局部重生成保护范围。
|
||||
3. 当前“锁定能力”更像一个早期过渡实现,还没有形成统一的重生成规则。
|
||||
|
||||
同时,结果页的“重新生成”提示文案仍然是“整世界覆盖式”的语义,这也会进一步削弱用户对重生成的信任感。
|
||||
|
||||
可优化点:
|
||||
|
||||
- 把锁定语义统一收口到后端,以 `lockState` 为唯一事实来源。
|
||||
- 锁定粒度改成:
|
||||
- 世界字段锁定
|
||||
- 势力锁定
|
||||
- 关键角色锁定
|
||||
- 关键地点锁定
|
||||
- 长尾内容可重生成
|
||||
- 局部重生成至少拆成几类:
|
||||
- 仅补长尾角色
|
||||
- 仅补长尾场景
|
||||
- 仅重做场景网络
|
||||
- 仅重做支持性 NPC
|
||||
- 合并逻辑不要再靠名称匹配,改成稳定 id 或锚点映射。
|
||||
|
||||
---
|
||||
|
||||
## 2.6 快速模式还不够“快”,生成页也还不够“创作者视角”
|
||||
|
||||
当前快速模式的主要区别,是把数量降成:
|
||||
|
||||
- 可扮演角色 `3`
|
||||
- 场景角色 `8`
|
||||
- 场景 `4`
|
||||
|
||||
但主生成链本身仍然会继续跑:
|
||||
|
||||
- framework
|
||||
- theme pack
|
||||
- story graph
|
||||
- role narrative
|
||||
- role dossier
|
||||
- narrative profile
|
||||
- finalization
|
||||
|
||||
也就是说:
|
||||
|
||||
**现在的 fast 更像“缩数量版 full”,还不是“先出关键锚点与关键对象的创作预览模式”。**
|
||||
|
||||
同时,`src/components/CustomWorldGenerationView.tsx` 当前展示的重点仍然是:
|
||||
|
||||
- 当前批次
|
||||
- 预计等待
|
||||
- 计时
|
||||
- 模型阶段
|
||||
|
||||
而不是创作者真正关心的:
|
||||
|
||||
- 关键角色有没有成型
|
||||
- 核心冲突有没有稳定
|
||||
- 哪些锚点已经锁定
|
||||
- 当前正在补的是关键对象还是长尾内容
|
||||
|
||||
可优化点:
|
||||
|
||||
- 快速模式改成真正的“关键锚点预览模式”:
|
||||
- 先只生成关键角色、关键地点、核心冲突摘要
|
||||
- 暂不补全所有长尾档案
|
||||
- 生成页改成“创作者视角进度”:
|
||||
- 世界灵魂已确定
|
||||
- 关键角色已成型
|
||||
- 关键地点已落地
|
||||
- 长尾扩展准备开始
|
||||
- 把技术批次隐藏到二级信息里,默认只展示创作状态。
|
||||
|
||||
---
|
||||
|
||||
## 2.7 自定义世界底层仍然没有完全脱离模板世界依赖
|
||||
|
||||
这部分设计文档和参考清单已经说得比较清楚,代码里也能看到对应痕迹:
|
||||
|
||||
- `templateWorldType`
|
||||
- `WUXIA / XIANXIA` 兼容字段
|
||||
- 规则层 fallback
|
||||
- 视觉参考池 fallback
|
||||
- 角色骨架与怪物池 fallback
|
||||
|
||||
当前问题不在于“还没完全去模板化”本身,而在于:
|
||||
|
||||
**这层依赖仍然深入到了生成、运行时规则、表现词汇和参考资源,不只是一个兼容字段。**
|
||||
|
||||
这会限制:
|
||||
|
||||
1. 跨题材表达稳定性
|
||||
2. 自定义世界的自有设定层独立性
|
||||
3. 后续真正做到“任何题材都能稳定跑”
|
||||
|
||||
可优化点:
|
||||
|
||||
- 继续按现有设计稿,把模板依赖逐步迁成:
|
||||
- 语义锚层
|
||||
- 规则层
|
||||
- 表现层
|
||||
- 原型参考层
|
||||
- 兼容迁移层
|
||||
- 在迁移完成前,保留兼容字段,但让新逻辑优先读取 `ownedSettingLayers`。
|
||||
- 明确哪些是“兼容桥”,哪些还是“真实主依赖”,避免继续混用。
|
||||
|
||||
---
|
||||
|
||||
## 2.8 前后端边界仍处于过渡态,和项目约束还有距离
|
||||
|
||||
当前自定义世界已经有了:
|
||||
|
||||
- Node 路由
|
||||
- session
|
||||
- 流式生成
|
||||
- 世界库存储接口
|
||||
|
||||
这是对的。
|
||||
|
||||
但问题是,`server-node/src/services/customWorldGenerationService.ts` 仍然通过 `server-node/src/bridges/legacyAiRuntimeBridge.ts` 去桥接 `src/services/ai.ts`。
|
||||
|
||||
这说明:
|
||||
|
||||
**核心生成逻辑虽然已经被路由包起来了,但真正的生成实现还没有完全成为 Express 侧自己的领域服务。**
|
||||
|
||||
同时,前端仍然承担了不少流程语义:
|
||||
|
||||
- 锁定内容合并
|
||||
- 重生成确认
|
||||
- 结果页覆盖提示
|
||||
- 工作台状态切换
|
||||
|
||||
这和当前仓库“前端只负责表现,逻辑与数据尽量收口到 Express 后端”的方向还有距离。
|
||||
|
||||
可优化点:
|
||||
|
||||
- 把自定义世界生成链正式下沉到 `server-node` 领域服务。
|
||||
- 把锁定、局部重生成、澄清会话、结果归档规则都放到后端。
|
||||
- 前端只负责:
|
||||
- 输入展示
|
||||
- 进度展示
|
||||
- 结果工作台展示
|
||||
- 明确的用户确认动作
|
||||
|
||||
---
|
||||
|
||||
## 2.9 移动端工作台仍有明显压迫感
|
||||
|
||||
项目文档已经明确要求移动端优先,但当前自定义世界工作台里仍有几个典型问题:
|
||||
|
||||
- 大量长 modal
|
||||
- 多段长表单
|
||||
- `window.confirm / window.alert` 原生弹框较多
|
||||
- 结果页与编辑器中同时承载太多操作密度
|
||||
|
||||
这些在桌面端还能勉强接受,但在手机上会很容易变成:
|
||||
|
||||
- 滚动层级混乱
|
||||
- 退出成本高
|
||||
- 修改焦点不明确
|
||||
- 确认感不稳定
|
||||
|
||||
可优化点:
|
||||
|
||||
- 移动端改成底部工作台 / 分步面板 / 可折叠分区。
|
||||
- 用项目内统一确认弹层替换 `window.confirm / window.alert`。
|
||||
- 让“保存”“继续补全”“局部重生成”这些关键动作固定在底部安全区附近。
|
||||
- 把搜索、批量删除、创建动作做成更轻的操作条,而不是持续挤压正文区。
|
||||
|
||||
---
|
||||
|
||||
## 3. 优先级建议
|
||||
|
||||
### P0:先修主链路闭环
|
||||
|
||||
- 补卡片化输入入口,至少把关键锚点输入真正开放出来。
|
||||
- 把澄清问题正式接入创作者流程,不再静默自动兜底。
|
||||
- 修正“新建完成后直接回世界列表”的流程,生成后默认进入结果工作台。
|
||||
- 统一锁定与局部重生成规则,先让“创作者不怕重生成”成立。
|
||||
|
||||
### P1:再降低工作台负担
|
||||
|
||||
- 结果页默认只展示高杠杆编辑。
|
||||
- 低杠杆字段进入高级模式。
|
||||
- 快速模式改成真正的关键对象预览模式。
|
||||
- 生成页改成创作者视角进度,而不是模型批次视角。
|
||||
|
||||
### P2:最后做架构收口与去模板化
|
||||
|
||||
- 把生成链、锁定规则、会话澄清彻底收回 Express 后端。
|
||||
- 持续推进 `ownedSettingLayers` 成为真实主设定层。
|
||||
- 逐步去掉自定义世界对模板世界的深依赖。
|
||||
- 针对移动端重做工作台的操作密度和确认路径。
|
||||
|
||||
---
|
||||
|
||||
## 4. 推荐落地顺序
|
||||
|
||||
如果只按“最小投入、最大体验收益”排序,建议按下面四步做:
|
||||
|
||||
1. 先改输入与结果闭环
|
||||
- 卡片化最小入口
|
||||
- 澄清问题接入
|
||||
- 新建后进入结果页
|
||||
|
||||
2. 再改锁定与局部重生成
|
||||
- 用稳定 id
|
||||
- 用统一 lockState
|
||||
- 增加局部重生成类型
|
||||
|
||||
3. 再改结果工作台结构
|
||||
- 默认高杠杆
|
||||
- 高级模式收纳低杠杆字段
|
||||
- 移动端拆分长表单
|
||||
|
||||
4. 最后做后端收口与去模板化
|
||||
- 服务端领域化
|
||||
- 设定层自有化
|
||||
- 跨题材泛化
|
||||
|
||||
---
|
||||
|
||||
## 5. 一句话判断
|
||||
|
||||
当前自定义世界创作工具最需要的,不是再继续补更多字段或更多生成步骤,而是:
|
||||
|
||||
**把“创作者先决定灵魂锚点,系统再稳定展开世界”这条主逻辑真正落到 UI、流程和后端边界上。**
|
||||
621
docs/audits/CUSTOM_WORLD_PROFILE_MAPPING_AUDIT_2026-04-18.md
Normal file
621
docs/audits/CUSTOM_WORLD_PROFILE_MAPPING_AUDIT_2026-04-18.md
Normal file
@@ -0,0 +1,621 @@
|
||||
# 世界 Profile 到预设内容与实时生成规则映射审计
|
||||
|
||||
更新时间:`2026-04-18`
|
||||
|
||||
## 0. 审计目标
|
||||
|
||||
本次审计只回答一个问题:
|
||||
|
||||
**当前仓库里的世界 profile 设定,是否已经完整、合理地映射到游戏的预设内容与实时生成内容规则中。**
|
||||
|
||||
这里的“世界 profile”包含两层:
|
||||
|
||||
1. `CustomWorldProfile` 顶层世界数据
|
||||
2. `ownedSettingLayers` 派生设定层
|
||||
|
||||
这里的“预设内容”包含:
|
||||
|
||||
1. 角色运行时预设
|
||||
2. 场景预设
|
||||
3. 默认视觉与怪物匹配
|
||||
4. 初始装备 / 初始背包 / 经济与术语表现
|
||||
|
||||
这里的“实时生成规则”包含:
|
||||
|
||||
1. 主剧情 prompt
|
||||
2. NPC 对话 / 招募 / 私聊 prompt
|
||||
3. 任务生成
|
||||
4. 运行时物品生成
|
||||
5. 故事线程、可见性、叙事 QA 与推进规则
|
||||
|
||||
---
|
||||
|
||||
## 1. 结论先行
|
||||
|
||||
结论不是“完全映射”,而是:
|
||||
|
||||
**已完成基础映射,但没有达到“完全且合理”的程度。**
|
||||
|
||||
当前状态更准确地说是:
|
||||
|
||||
1. `世界基础骨架 -> 角色 / 场景 / 属性 / prompt` 这条主链已经打通。
|
||||
2. `叙事层 -> 主剧情/NPC 可见性规则` 已经有比较扎实的接入。
|
||||
3. `规则层 -> UI术语 / 经济 / 属性` 已经接入。
|
||||
4. 但 `模板兼容层` 仍然过强,跨题材世界会被粗暴压回 `WUXIA/XIANXIA`。
|
||||
5. 但 `后端运行时任务/物品模块` 只拿到了瘦身版 profile,没有真正吃到完整世界叙事层。
|
||||
6. 但 `世界级 items / faction / conflict` 仍然更多是文本种子,而不是可操作的游戏内容对象。
|
||||
|
||||
如果按结果判断:
|
||||
|
||||
1. **预设内容映射:部分完整,约 70%。**
|
||||
2. **实时生成规则映射:前端剧情主链较完整,后端运行时子链不完整,整体约 60%。**
|
||||
3. **跨题材合理性:明显不足。**
|
||||
|
||||
---
|
||||
|
||||
## 2. 本次审计覆盖的核心文件
|
||||
|
||||
类型与编译链:
|
||||
|
||||
- `src/types/customWorld.ts`
|
||||
- `src/services/customWorld.ts`
|
||||
- `src/services/customWorldBuilder.ts`
|
||||
- `src/services/customWorldOwnedSettingLayers.ts`
|
||||
- `src/services/customWorldTheme.ts`
|
||||
|
||||
预设内容落地:
|
||||
|
||||
- `src/data/characterPresets.ts`
|
||||
- `src/data/scenePresets.ts`
|
||||
- `src/data/customWorldCharacterLoadout.ts`
|
||||
- `src/data/customWorldRuntime.ts`
|
||||
- `src/data/customWorldVisuals.ts`
|
||||
- `src/data/customWorldNpcMonsters.ts`
|
||||
- `src/data/worldAttributeSchemas.ts`
|
||||
- `src/data/economy.ts`
|
||||
- `src/services/customWorldPresentation.ts`
|
||||
|
||||
实时生成规则:
|
||||
|
||||
- `src/hooks/story/storyContextBuilder.ts`
|
||||
- `src/services/prompt.ts`
|
||||
- `src/services/characterChatPrompt.ts`
|
||||
- `src/services/questPrompt.ts`
|
||||
- `src/services/questDirector.ts`
|
||||
- `src/services/runtimeItemAiPrompt.ts`
|
||||
- `src/data/runtimeItemNarrative.ts`
|
||||
- `src/services/storyEngine/themePack.ts`
|
||||
- `src/services/storyEngine/worldStoryGraph.ts`
|
||||
- `src/services/storyEngine/actorNarrativeProfile.ts`
|
||||
- `src/services/storyEngine/knowledgeGraph.ts`
|
||||
- `src/services/storyEngine/threadContract.ts`
|
||||
- `src/services/storyEngine/visibilityEngine.ts`
|
||||
- `src/services/storyEngine/authorialConstraintPack.ts`
|
||||
- `src/hooks/story/progressionActions.ts`
|
||||
|
||||
后端运行时链:
|
||||
|
||||
- `server-node/src/modules/ai/customWorldOrchestrator.ts`
|
||||
- `server-node/src/modules/runtime-item/runtimeItemModule.ts`
|
||||
- `server-node/src/modules/quest/runtimeQuestModule.ts`
|
||||
- `server-node/src/modules/runtime/runtimeSnapshotHydration.ts`
|
||||
|
||||
---
|
||||
|
||||
## 3. 映射总表
|
||||
|
||||
| 设定层/字段 | 映射到预设内容 | 映射到实时生成规则 | 判断 |
|
||||
| --- | --- | --- | --- |
|
||||
| `name/subtitle/summary/tone/playerGoal` | 已映射到角色 opening、场景提示、视觉匹配、程序化物品关键词 | 已映射到主剧情 prompt、任务 prompt、物品 prompt、ThemePack/StoryGraph 派生 | 基本成立 |
|
||||
| `templateWorldType/compatibilityTemplateWorldType` | 强影响角色模板、场景图参考池、怪物池、兼容 schema | 影响 ThemePack fallback 与部分运行时回退 | 已接入,但合理性不足 |
|
||||
| `majorFactions/coreConflicts` | 主要进入 ThemePack / StoryGraph / tension state,未落成具体 faction 实体 | 影响 authorial constraints、线程图谱、任务与剧情语义 | 有映射,但偏文本种子 |
|
||||
| `camp` | 已映射为开局 camp scene、camp 图、camp 连接 | 通过世界参考文本和开局内容进入 prompt | 成立 |
|
||||
| `attributeSchema` | 已映射到角色/NPC 属性、战斗面板、属性展示 | 已映射到 prompt 属性描述与运行时计算 | 成立 |
|
||||
| `ownedSettingLayers.ruleProfile.resourceLabels` | 已映射到 UI 血量/法力/货币等术语 | 主要通过 UI/经济层体现,prompt 侧间接使用 | 成立 |
|
||||
| `ownedSettingLayers.ruleProfile.economyProfile.initialCurrency` | 已映射到初始货币与快照恢复 | 对运行时奖励规则影响弱,更多是初始化 | 成立但范围有限 |
|
||||
| `playableNpcs` | 已映射到可玩角色预设、技能变体、初始物品、home scene | 已映射到剧情 prompt、私聊 prompt、叙事档案 | 成立 |
|
||||
| `storyNpcs` | 已映射到场景 NPC、怪物判定、角色运行时预设 | 已映射到遭遇 prompt、任务发布者、叙事可见性 | 成立 |
|
||||
| `landmarks` | 已映射到 scene presets、连接网络、场景视觉、treasure hints | 已映射到世界参考文本、scene residues、故事线程关联 | 成立 |
|
||||
| `items` | 生成主链默认清空,世界级 item 几乎未形成正式内容层 | `knowledgeFacts` 可支持 item,但主链无内容可用 | 映射明显不足 |
|
||||
| `themePack/expressionProfile` | 已映射到视觉/命名/技能名/场景语义 | 已映射到 prompt 基调、reveal 风格、故事图谱 | 成立 |
|
||||
| `referenceProfile.roleArchetypes` | 已映射到角色模板骨架选择 | 运行时规则直接消费较少 | 部分成立 |
|
||||
| `referenceProfile.sceneBuckets` | 已映射到场景默认图匹配 | 运行时 prompt 直接消费较少 | 部分成立 |
|
||||
| `referenceProfile.creatureArchetypes` | 已映射到怪物 preset 池筛选 | 运行时规则间接消费 | 部分成立 |
|
||||
| `storyGraph` | 预设层主要影响 narrative residues 与 faction tension | 已映射到 active threads、constraints、visibility、chapter/campaign | 成立 |
|
||||
| `narrativeProfile` | 已映射到 scene NPC 简介和遭遇资料 | 已映射到 prompt 可见性、任务/物品关系生成 | 成立 |
|
||||
| `knowledgeFacts` | 不直接生成预设内容 | 已映射到 visibility slice 与 prompt 裁剪 | 成立 |
|
||||
| `threadContracts` | 不直接生成预设内容 | 已映射到 story signal / thread update / QA | 成立 |
|
||||
| `creatorIntent/anchorPack/lockState/anchorContent` | 主要留在创作工作区与结果页整理 | 几乎不直接进入正式游戏运行时 | 创作层有用,运行时映射弱 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 已经成立的映射链
|
||||
|
||||
## 4.1 世界基础骨架已经能稳定进入角色、场景与剧情主链
|
||||
|
||||
`CustomWorldProfile` 的基础字段已经不是“只存档不消费”的状态。
|
||||
|
||||
它们已经实际进入:
|
||||
|
||||
1. 角色开局文案与 opening 动机
|
||||
2. 角色技能变体
|
||||
3. 场景预设名称、描述、连接、treasure hints
|
||||
4. 主剧情 prompt 中的世界补充档案
|
||||
5. 私聊 / 任务 / 运行时物品 prompt 的世界摘要
|
||||
|
||||
这说明:
|
||||
|
||||
**世界 profile 的基础文本层已经真正进入游戏主链。**
|
||||
|
||||
---
|
||||
|
||||
## 4.2 规则层已经落到真实游戏表现
|
||||
|
||||
`ownedSettingLayers.ruleProfile` 目前已真实影响:
|
||||
|
||||
1. `attributeSchema`
|
||||
- 角色/NPC 属性计算
|
||||
- prompt 中的属性描述
|
||||
- 面板展示
|
||||
2. `resourceLabels`
|
||||
- HP/MP/伤害/冷却/货币等 UI 术语
|
||||
3. `economyProfile.initialCurrency`
|
||||
- 自定义世界初始货币
|
||||
- 快照恢复时的默认初始化
|
||||
|
||||
这部分不是空壳。
|
||||
|
||||
**规则层已经从 profile 进入真实结算和 UI。**
|
||||
|
||||
---
|
||||
|
||||
## 4.3 叙事层已经进入 prompt 可见性与推进规则
|
||||
|
||||
`themePack -> storyGraph -> narrativeProfile -> knowledgeFacts -> visibilitySlice`
|
||||
这条链已经是当前自定义世界最完整的一条映射链。
|
||||
|
||||
它已经支撑:
|
||||
|
||||
1. NPC 首遇/低披露 prompt 裁剪
|
||||
2. 当前线程可见性控制
|
||||
3. 当前压力、错位、禁区、已解锁章节等信息分层
|
||||
4. 章节/战役/约束/QA 的继续推进
|
||||
|
||||
这说明:
|
||||
|
||||
**世界 profile 里的叙事层不只是展示文本,而是真的在控制“模型这轮能知道什么、不能知道什么”。**
|
||||
|
||||
---
|
||||
|
||||
## 5. 关键问题
|
||||
|
||||
## 5.1 高优先级问题:模板兼容层仍然是二元锚点,跨题材世界会被错误压缩
|
||||
|
||||
当前主生成链仍要求模型输出:
|
||||
|
||||
- `templateWorldType: WUXIA | XIANXIA`
|
||||
|
||||
而兼容解析也会把世界最终压回:
|
||||
|
||||
1. `arcane -> XIANXIA`
|
||||
2. 其它几乎全部回到 `WUXIA`
|
||||
|
||||
这会直接影响:
|
||||
|
||||
1. 角色模板骨架选择
|
||||
2. 场景默认图参考池
|
||||
3. 怪物 preset 池
|
||||
4. 兼容性 fallback
|
||||
|
||||
问题不在“有兼容字段”,而在于:
|
||||
|
||||
**当前兼容字段仍然过度参与真实内容映射。**
|
||||
|
||||
对现代金融、科幻 AI 战争、校园、都市、调查等题材来说,这种二元压缩并不合理。
|
||||
|
||||
仓库日志里已经出现了典型样本:
|
||||
|
||||
1. 股市世界被要求产出 `XIANXIA`
|
||||
2. AI 战争世界也被要求产出 `XIANXIA`
|
||||
3. 魔法科技融合世界被要求产出 `WUXIA`
|
||||
|
||||
这意味着:
|
||||
|
||||
**世界 profile 虽然支持跨题材文本输入,但底层预设内容映射仍带着明显的“武侠/仙侠残余偏置”。**
|
||||
|
||||
相关文件:
|
||||
|
||||
- `server-node/src/modules/ai/customWorldOrchestrator.ts`
|
||||
- `src/services/customWorldTheme.ts`
|
||||
- `src/data/customWorldVisuals.ts`
|
||||
- `src/data/customWorldNpcMonsters.ts`
|
||||
- `src/data/characterPresets.ts`
|
||||
|
||||
判断:
|
||||
|
||||
**这是当前“合理映射”最大缺口。**
|
||||
|
||||
---
|
||||
|
||||
## 5.2 高优先级问题:后端运行时任务/物品模块只消费了瘦身版 world profile
|
||||
|
||||
前端剧情主链里,`customWorldProfile` 会带着:
|
||||
|
||||
1. `themePack`
|
||||
2. `storyGraph`
|
||||
3. `knowledgeFacts`
|
||||
4. `threadContracts`
|
||||
5. `ownedSettingLayers`
|
||||
|
||||
但后端运行时模块里:
|
||||
|
||||
1. `runtimeItemModule` 的 `customWorldProfile` 只有 `{ name, summary }`
|
||||
2. `runtimeQuestModule` 的 `customWorldProfile` 也只有 `{ name, summary }`
|
||||
|
||||
这直接导致后端运行时生成无法真正读取:
|
||||
|
||||
1. 世界线程图谱
|
||||
2. 世界可见性事实
|
||||
3. 参考原型层
|
||||
4. 规则层
|
||||
5. 表达层
|
||||
|
||||
结果是:
|
||||
|
||||
1. 主剧情/NPC prompt 已经较强依赖世界叙事层
|
||||
2. 但后端任务/物品生成还只是吃世界摘要
|
||||
|
||||
这会把系统拆成两种强度不同的世界消费链:
|
||||
|
||||
1. 前端剧情链较“懂世界”
|
||||
2. 后端运行时奖励链较“不懂世界”
|
||||
|
||||
相关文件:
|
||||
|
||||
- `src/hooks/story/storyContextBuilder.ts`
|
||||
- `src/services/runtimeItemAiPrompt.ts`
|
||||
- `src/services/questPrompt.ts`
|
||||
- `server-node/src/modules/runtime-item/runtimeItemModule.ts`
|
||||
- `server-node/src/modules/quest/runtimeQuestModule.ts`
|
||||
|
||||
判断:
|
||||
|
||||
**世界 profile 到实时生成规则的映射,在后端链路上是不完整的。**
|
||||
|
||||
---
|
||||
|
||||
## 5.3 高优先级问题:世界级 `items` 没有真正接进主生成链
|
||||
|
||||
类型里存在:
|
||||
|
||||
- `CustomWorldProfile.items`
|
||||
|
||||
构建器也支持:
|
||||
|
||||
1. item 归一化
|
||||
2. `attributeResonance`
|
||||
3. item knowledge facts
|
||||
|
||||
但真正的世界生成主链里:
|
||||
|
||||
1. orchestrator prompt 明确要求不要预生成物品档案
|
||||
2. `attachRuntimeGenerationMetadata(...)` 会把 `items` 直接压成空数组
|
||||
|
||||
这会带来两个结果:
|
||||
|
||||
1. 世界 profile 的“世界级物品层”几乎为空
|
||||
2. 运行时背包、掉落、交易更多依赖程序化生成和角色初始物品
|
||||
|
||||
于是目前的物品系统更像:
|
||||
|
||||
1. 有角色初始物品
|
||||
2. 有运行时程序化物品
|
||||
3. 但没有稳定的“世界物品图谱”
|
||||
|
||||
这意味着:
|
||||
|
||||
**世界 profile 在物品层没有形成完整映射。**
|
||||
|
||||
相关文件:
|
||||
|
||||
- `server-node/src/modules/ai/customWorldOrchestrator.ts`
|
||||
- `src/services/customWorldBuilder.ts`
|
||||
- `src/data/customWorldRuntime.ts`
|
||||
- `src/data/customWorldCharacterLoadout.ts`
|
||||
- `src/services/storyEngine/knowledgeGraph.ts`
|
||||
|
||||
判断:
|
||||
|
||||
**这是“预设内容”和“实时生成规则”共同缺失的一块。**
|
||||
|
||||
---
|
||||
|
||||
## 5.4 中优先级问题:`majorFactions/coreConflicts` 仍然是文本种子,不是可操作游戏对象
|
||||
|
||||
当前 `majorFactions` 与 `coreConflicts` 已经被大量消费,但主要消费方式是:
|
||||
|
||||
1. 拼进 `ThemePack`
|
||||
2. 派生 `WorldStoryGraph`
|
||||
3. 派生 `AuthorialConstraintPack`
|
||||
4. 派生 `FactionTensionState`
|
||||
|
||||
问题在于它们还没有形成:
|
||||
|
||||
1. 可索引 faction 实体
|
||||
2. faction 与 NPC 的显式归属关系
|
||||
3. faction 与场景/商店/敌对阵营的显式绑定
|
||||
4. 冲突与任务/势力状态的强约束关系
|
||||
|
||||
当前更多是:
|
||||
|
||||
**“文本里提到过 -> 图谱做字符串匹配 -> 运行时拿去写 prompt”**
|
||||
|
||||
而不是:
|
||||
|
||||
**“世界里真的存在这些派系与冲突对象,并驱动交互规则”**
|
||||
|
||||
相关文件:
|
||||
|
||||
- `src/services/storyEngine/themePack.ts`
|
||||
- `src/services/storyEngine/worldStoryGraph.ts`
|
||||
- `src/services/storyEngine/factionTensionState.ts`
|
||||
|
||||
判断:
|
||||
|
||||
**已有映射,但离“完全落地”为具体游戏内容对象还有明显距离。**
|
||||
|
||||
---
|
||||
|
||||
## 5.5 中优先级问题:场景预设会额外注入模板怪物,弱化 landmark 的原始设定控制力
|
||||
|
||||
`buildCustomScenePresets(profile)` 在每个 landmark scene 中,除了把 `landmark.sceneNpcIds` 指向的角色放进去,还会:
|
||||
|
||||
1. 从怪物 preset 池按 scene index 截两只怪
|
||||
2. 直接拼进 `combinedNpcs`
|
||||
|
||||
这意味着即使 profile 本身没有明确要求某个 landmark 出现这些敌对实体,运行时场景仍会被额外补入模板怪物。
|
||||
|
||||
这会导致:
|
||||
|
||||
1. 场景内容不完全由 `landmark + storyNpcs` 决定
|
||||
2. 地标设定与实际可战斗内容之间存在偏移
|
||||
3. 跨题材世界会更容易被模板怪物池拖偏
|
||||
|
||||
相关文件:
|
||||
|
||||
- `src/data/scenePresets.ts`
|
||||
- `src/data/customWorldNpcMonsters.ts`
|
||||
|
||||
判断:
|
||||
|
||||
**landmark 到实际场景实体池的映射,不是完全忠实映射,而是“设定 + 模板补丁”。**
|
||||
|
||||
---
|
||||
|
||||
## 5.6 中优先级问题:后端运行时物品线程并不是真正世界线程
|
||||
|
||||
前端剧情链里的 `activeThreadIds` 来自:
|
||||
|
||||
1. `storyEngineMemory`
|
||||
2. `storyGraph`
|
||||
3. `knowledgeFacts`
|
||||
4. `visibilitySlice`
|
||||
|
||||
但后端 `runtimeItemModule` 的 loose context 里,`activeThreadIds` 只是:
|
||||
|
||||
1. `thread:${encounter.id}`
|
||||
2. 或 `thread:${scene.id}`
|
||||
|
||||
这不是世界线程图谱,而是临时合成 id。
|
||||
|
||||
结果是:
|
||||
|
||||
1. 名义上后端物品模块也有“active threads”
|
||||
2. 实际上它拿到的并不是 `WorldStoryGraph` 中的真实线程
|
||||
|
||||
这会让运行时物品的“为什么现在出现”更像局部上下文推断,而不是来自世界故事结构。
|
||||
|
||||
相关文件:
|
||||
|
||||
- `server-node/src/modules/runtime-item/runtimeItemModule.ts`
|
||||
|
||||
判断:
|
||||
|
||||
**这是实时生成规则层的结构性弱映射。**
|
||||
|
||||
---
|
||||
|
||||
## 5.7 中优先级问题:`referenceProfile.roleArchetypes` 只从 playableNpcs 派生,storyNpcs 覆盖不够
|
||||
|
||||
当前 `roleArchetypes` 的编译来源是:
|
||||
|
||||
1. `profile.playableNpcs.slice(0, 6)`
|
||||
|
||||
而不是:
|
||||
|
||||
1. `playableNpcs + storyNpcs` 的综合原型池
|
||||
|
||||
这导致两个问题:
|
||||
|
||||
1. 世界里的长尾 story NPC 原型没有进入 reference archetype 编译
|
||||
2. 某些场景角色/怪物/平民的模板骨架选择更多依赖启发式 fallback
|
||||
|
||||
这会让:
|
||||
|
||||
1. 可玩角色映射较稳定
|
||||
2. 长尾场景角色映射不够稳定
|
||||
|
||||
相关文件:
|
||||
|
||||
- `src/services/customWorldOwnedSettingLayers.ts`
|
||||
- `src/services/customWorldReferenceSignals.ts`
|
||||
- `src/data/characterPresets.ts`
|
||||
|
||||
判断:
|
||||
|
||||
**参考层映射存在明显“主角优先、长尾不足”的偏差。**
|
||||
|
||||
---
|
||||
|
||||
## 5.8 低优先级问题:创作元数据并未进入正式游戏运行时
|
||||
|
||||
`creatorIntent / anchorPack / lockState / anchorContent` 当前主要服务于:
|
||||
|
||||
1. 创作工作区
|
||||
2. Agent session
|
||||
3. 结果页和编辑器
|
||||
|
||||
它们对正式运行时的直接作用主要是:
|
||||
|
||||
1. 参与 `ownedSettingLayers` 的编译
|
||||
|
||||
但不会直接变成:
|
||||
|
||||
1. 正式战斗规则
|
||||
2. 场景交互规则
|
||||
3. faction 状态
|
||||
4. 任务目标约束
|
||||
|
||||
这不一定是 bug,但如果把“世界 profile 设定”理解为所有 profile 元数据,那么:
|
||||
|
||||
**创作层数据目前并没有完整进入游戏运行时。**
|
||||
|
||||
---
|
||||
|
||||
## 6. 分层判断
|
||||
|
||||
## 6.1 预设内容映射判断
|
||||
|
||||
### 已经合理接入的部分
|
||||
|
||||
1. 可玩角色
|
||||
2. 场景角色
|
||||
3. 地标场景
|
||||
4. 属性 schema
|
||||
5. 资源术语
|
||||
6. 初始货币
|
||||
7. camp 开局归处
|
||||
8. 默认场景图匹配
|
||||
|
||||
### 仍然不足的部分
|
||||
|
||||
1. 世界级 items
|
||||
2. faction 实体化
|
||||
3. 冲突到任务/场景状态的强绑定
|
||||
4. 跨题材世界的模板偏置问题
|
||||
5. 地标与怪物注入之间的忠实性
|
||||
|
||||
结论:
|
||||
|
||||
**预设内容层是“能跑且已有骨架”,但还不是“设定完全落地”。**
|
||||
|
||||
---
|
||||
|
||||
## 6.2 实时生成规则映射判断
|
||||
|
||||
### 已经合理接入的部分
|
||||
|
||||
1. 主剧情 prompt
|
||||
2. NPC 可见性控制
|
||||
3. 私聊与对话 prompt
|
||||
4. 叙事线程图谱
|
||||
5. 事实图谱
|
||||
6. 作者性约束与 QA
|
||||
|
||||
### 仍然不足的部分
|
||||
|
||||
1. 后端任务模块 world profile 过瘦
|
||||
2. 后端物品模块 world profile 过瘦
|
||||
3. 后端物品线程是伪线程
|
||||
4. 世界级 item 图谱为空
|
||||
5. faction/conflict 仍偏语义层,不够规则化
|
||||
|
||||
结论:
|
||||
|
||||
**实时生成规则层呈现出“前端剧情链强、后端奖励链弱”的不均衡状态。**
|
||||
|
||||
---
|
||||
|
||||
## 7. 最终判定
|
||||
|
||||
如果问题是:
|
||||
|
||||
**“世界 profile 设定是否已经完全地、合理地映射到游戏的预设内容、实时生成内容规则中?”**
|
||||
|
||||
我的结论是:
|
||||
|
||||
**没有。**
|
||||
|
||||
更准确地说:
|
||||
|
||||
1. 已经完成了主干映射。
|
||||
2. 但还没有完成全量映射。
|
||||
3. 也还没有完成跨题材下的合理映射。
|
||||
|
||||
当前系统最准确的状态是:
|
||||
|
||||
**世界 profile 已经成为真实驱动源之一,但还没有成为所有预设内容与实时规则的一致单一真相源。**
|
||||
|
||||
---
|
||||
|
||||
## 8. 建议的修复优先级
|
||||
|
||||
## P1:先补“真实消费不完整”的链路
|
||||
|
||||
1. 让后端 `runtimeItemModule` / `runtimeQuestModule` 接收完整 `customWorldProfile` 子集
|
||||
2. 至少补进:
|
||||
- `ownedSettingLayers`
|
||||
- `storyGraph`
|
||||
- `knowledgeFacts`
|
||||
- `themePack`
|
||||
- `majorFactions/coreConflicts`
|
||||
|
||||
---
|
||||
|
||||
## P1:把 `templateWorldType` 退回兼容字段,而不是主导字段
|
||||
|
||||
1. 生成期保留兼容输出
|
||||
2. 运行时优先读取:
|
||||
- `ownedSettingLayers`
|
||||
- `themeMode`
|
||||
- `referenceProfile`
|
||||
3. 不再让 `WUXIA/XIANXIA` 主导现代/科幻/海洋/裂界世界的视觉与怪物选择
|
||||
|
||||
---
|
||||
|
||||
## P1:补世界级 item 层
|
||||
|
||||
1. 允许世界生成阶段产出一批世界级 items seed
|
||||
2. 让 `knowledgeFacts / runtime item / quest reward / treasure hint` 能挂到这些 seed 上
|
||||
3. 形成“世界物件图谱”,而不是只有角色初始物品和程序化临时物品
|
||||
|
||||
---
|
||||
|
||||
## P2:把 faction/conflict 从文本种子升级成结构对象
|
||||
|
||||
1. faction 实体
|
||||
2. faction -> NPC 归属
|
||||
3. faction -> 场景控制
|
||||
4. conflict -> 任务/线程/场景压力绑定
|
||||
|
||||
---
|
||||
|
||||
## P2:去掉地标场景里的固定模板怪物补丁式注入
|
||||
|
||||
1. 优先使用 landmark 自己的敌对角色设计
|
||||
2. 模板怪物只作为缺口补位
|
||||
3. 补位也要受 landmark/theme/thread 约束
|
||||
|
||||
---
|
||||
|
||||
## P3:扩充 reference archetype 的来源
|
||||
|
||||
1. role archetypes 不只从 playableNpcs 编
|
||||
2. storyNpcs 也应参与 archetype 归纳
|
||||
3. 为平民、敌对、怪物、势力成员建立更细 archetype
|
||||
|
||||
---
|
||||
|
||||
## 9. 一句话总评
|
||||
|
||||
**当前世界 profile 已经能驱动游戏,但还没有彻底收束成“所有预设内容与实时生成规则都优先读取它”的单一真相源。主链可用,边链仍散,跨题材合理性仍偏弱。**
|
||||
437
docs/audits/FUNCTION_DESIGN_AUDIT_2026-04-03.md
Normal file
437
docs/audits/FUNCTION_DESIGN_AUDIT_2026-04-03.md
Normal file
@@ -0,0 +1,437 @@
|
||||
# 当前 Function 设计审计(2026-04-03)
|
||||
|
||||
## 审计范围
|
||||
|
||||
本次审计重点阅读并对照了这些位置:
|
||||
|
||||
- `docs/experience/ADVENTURE_RUNTIME_DEV_EXPERIENCE.md`
|
||||
- `docs/experience/PROJECT_WORK_EXPERIENCE_PLAYBOOK.md`
|
||||
- `docs/experience/PROJECT_DEVELOPMENT_EXPERIENCE.md`
|
||||
- `docs/audits/engineering/README.md`
|
||||
- `src/data/stateFunctions.ts`
|
||||
- `src/data/npcInteractions.ts`
|
||||
- `src/data/treasureInteractions.ts`
|
||||
- `src/hooks/useStoryGeneration.ts`
|
||||
- `src/hooks/story/npcEncounterActions.ts`
|
||||
- `src/hooks/story/npcInteraction.ts`
|
||||
- `src/hooks/story/progressionActions.ts`
|
||||
- `src/hooks/story/storyGenerationState.ts`
|
||||
- `src/services/ai.ts`
|
||||
- `src/services/prompt.ts`
|
||||
- `src/components/AdventurePanel.tsx`
|
||||
- `src/components/StateFunctionEditor.tsx`
|
||||
|
||||
## 先说结论
|
||||
|
||||
当前运行时的“function”不是单一体系,而是至少分成了 4 层:
|
||||
|
||||
1. `stateFunctions.ts` 里的基础战斗 / 空闲 function。
|
||||
2. `npcInteractions.ts` 里的 NPC 交互 function。
|
||||
3. `treasureInteractions.ts` 里的宝藏交互 function。
|
||||
4. `useStoryGeneration.ts` / `npcInteraction.ts` / 背包装备锻造里额外加出来的“流程控制型 functionId”。
|
||||
|
||||
“选完选项触发 function 后没有触发剧情推理”这类现象,当前主要有 3 种来源:
|
||||
|
||||
1. **按设计先走本地分流,不会在第一次点击时立刻推理。**
|
||||
2. **剧情推理其实已经完成,但被“继续冒险”这道 UI 中转门挡住了。**
|
||||
3. **真正的可见性 bug:`story_continue_adventure` 的文案常量已经乱码,导致 UI 提示失效,用户很容易误判为没继续推理。**
|
||||
|
||||
---
|
||||
|
||||
## 1. 当前 function 体系分层
|
||||
|
||||
### 1.1 基础状态 function:`src/data/stateFunctions.ts`
|
||||
|
||||
这一层才是严格意义上的“状态 function 注册表”,由 `resolveFunctionOption` 统一解析。
|
||||
|
||||
当前运行时实际启用 12 个:
|
||||
|
||||
- 战斗类 7 个:
|
||||
- `battle_all_in_crush`
|
||||
- `battle_guard_break`
|
||||
- `battle_probe_pressure`
|
||||
- `battle_feint_step`
|
||||
- `battle_recover_breath`
|
||||
- `battle_finisher_window`
|
||||
- `battle_escape_breakout`
|
||||
- 空闲类 5 个:
|
||||
- `idle_explore_forward`
|
||||
- `idle_travel_next_scene`
|
||||
- `idle_rest_focus`
|
||||
- `idle_observe_signs`
|
||||
- `idle_call_out`
|
||||
|
||||
关键设计点:
|
||||
|
||||
- 定义源头是 `BATTLE_FUNCTIONS` / `IDLE_FUNCTIONS`。
|
||||
- 最终运行时集合由 `buildStateFunctionDefinitions` 产出。
|
||||
- 可执行过滤走 `getExecutableFunctions`。
|
||||
- 文案和视觉包装走 `resolveFunctionOption`。
|
||||
- 默认选项池走 `getDefaultFunctionIdsForContext`。
|
||||
|
||||
注意:
|
||||
|
||||
- `idle_follow_clue` 仍然留在源码和 prompt 描述里,但在 `applyRuntimeFunctionAdjustments` 中被直接过滤掉,不会进入运行时 function 集合。
|
||||
- `src/components/game-shell/useSceneTransitionModel.ts` 里仍然保留了 `idle_follow_clue` 的转场映射,这说明当前 function 清单并不完全一致。
|
||||
|
||||
### 1.2 NPC 交互 function:`src/data/npcInteractions.ts`
|
||||
|
||||
这一层不是通过 `resolveFunctionOption` 生成的,而是 `buildNpcEncounterStoryMoment` 直接拼出 `StoryOption`,并挂上 `interaction.kind = 'npc'`。
|
||||
|
||||
按功能类型看,当前会出现这些 `functionId`:
|
||||
|
||||
- `npc_preview_talk`
|
||||
- `npc_trade`
|
||||
- `npc_fight`
|
||||
- `npc_spar`
|
||||
- `npc_help`
|
||||
- `npc_chat`(可重复出现 2 个以上,代表不同聊天话题)
|
||||
- `npc_gift`
|
||||
- `npc_recruit`
|
||||
- `npc_quest_accept`
|
||||
- `npc_quest_turn_in`
|
||||
- `npc_leave`
|
||||
|
||||
关键设计点:
|
||||
|
||||
- 这一层的 function 是“眼前 NPC 交互目录”,不是基础状态机目录。
|
||||
- 真正执行分流不在 `stateFunctions.ts`,而在 `handleNpcInteraction` / `resolveNpcInteractionDecision`。
|
||||
- prompt 层通过 `availableOptions` 把这些 function 当作“固定可选项列表”交给模型,要求模型保留数量和 `functionId`。
|
||||
|
||||
### 1.3 宝藏交互 function:`src/data/treasureInteractions.ts`
|
||||
|
||||
这一层同样不是 `resolveFunctionOption` 体系,而是直接构造带 `interaction.kind = 'treasure'` 的选项。
|
||||
|
||||
当前有 3 个:
|
||||
|
||||
- `treasure_secure`
|
||||
- `treasure_inspect`
|
||||
- `treasure_leave`
|
||||
|
||||
执行时由 `useTreasureFlow.ts` 接管,最终再回到 `commitGeneratedState` 继续剧情推理。
|
||||
|
||||
### 1.4 流程控制 / 面板动作 functionId
|
||||
|
||||
这类 `functionId` 会进入 `lastFunctionId` 或 `commitGeneratedState`,但不在 `stateFunctions.ts` 注册表里:
|
||||
|
||||
- 流程控制:
|
||||
- `story_continue_adventure`
|
||||
- `camp_travel_home_scene`
|
||||
- `story_opening_camp_dialogue`
|
||||
- 面板动作:
|
||||
- `inventory_use`
|
||||
- `equipment_equip`
|
||||
- `equipment_unequip`
|
||||
- `forge_craft`
|
||||
- `forge_dismantle`
|
||||
- `forge_reforge`
|
||||
|
||||
这说明当前项目里“functionId”已经同时承担了 3 个角色:
|
||||
|
||||
- 运行时基础状态动作 ID
|
||||
- NPC / 宝藏交互动作 ID
|
||||
- 流程 / 面板事件 ID
|
||||
|
||||
这能跑,但可追踪性已经开始分裂。
|
||||
|
||||
---
|
||||
|
||||
## 2. 当前剧情推理触发链路
|
||||
|
||||
### 2.1 会立刻触发剧情推理的主链
|
||||
|
||||
这类点击后会直接走 AI 续推:
|
||||
|
||||
- 普通战斗 / 空闲 function
|
||||
- `handleChoice`
|
||||
- `buildResolvedChoiceState`
|
||||
- `playResolvedChoice`
|
||||
- `generateNextStep`
|
||||
- 这些 NPC 交互
|
||||
- `npc_preview_talk`
|
||||
- `npc_help`
|
||||
- `npc_chat`
|
||||
- `npc_fight`
|
||||
- `npc_spar`
|
||||
- `npc_quest_accept`
|
||||
- `npc_quest_turn_in`
|
||||
- `npc_leave`
|
||||
- 宝藏交互确认后
|
||||
- `treasure_secure`
|
||||
- `treasure_inspect`
|
||||
- `treasure_leave`
|
||||
- 面板动作确认后
|
||||
- `inventory_use`
|
||||
- `equipment_equip`
|
||||
- `equipment_unequip`
|
||||
- `forge_*`
|
||||
|
||||
共性是:
|
||||
|
||||
- 要么直接在 `handleChoice` 里调用 `generateNextStep`。
|
||||
- 要么先走 `commitGeneratedState` / `commitGeneratedStateWithEncounterEntry`,再统一调用 `generateStoryForState`。
|
||||
|
||||
### 2.2 第一次点击不会立刻触发剧情推理的分流
|
||||
|
||||
这类最容易被误判成“function 触发了,但剧情没继续”:
|
||||
|
||||
- `npc_trade`
|
||||
- `npc_gift`
|
||||
- `npc_recruit`(队伍满时必进 modal;队伍未满时会先进招募对话流)
|
||||
|
||||
原因不是漏调,而是当前设计明确先走:
|
||||
|
||||
- `resolveNpcInteractionDecision`
|
||||
- `trade_modal`
|
||||
- `gift_modal`
|
||||
- `recruit_modal`
|
||||
- `recruit_immediate`
|
||||
|
||||
也就是说:
|
||||
|
||||
- 第一次点击只是**打开模态框 / 进入招募流程**。
|
||||
- 真正推进剧情推理,要等到:
|
||||
- `confirmTrade`
|
||||
- `confirmGift`
|
||||
- `confirmRecruit`
|
||||
- `executeRecruitment`
|
||||
|
||||
如果产品预期是“用户每点一次选项就必须立即看到剧情继续”,这一层现在不满足。
|
||||
|
||||
### 2.3 `npc_chat` 是“先推理,再延迟展示选项”
|
||||
|
||||
`npc_chat` 不是普通的“生成下一幕 + 立刻给选项”,而是单独走这条链:
|
||||
|
||||
1. `commitNpcChatState` 先流式生成聊天正文。
|
||||
2. 聊天结束后,再调用一次 `generateNextStep`。
|
||||
3. 新一轮冒险选项不直接显示,而是塞进 `deferredOptions`。
|
||||
4. 当前界面只先显示一个 `story_continue_adventure`。
|
||||
5. 用户再点一次,才把 `deferredOptions` 放出来。
|
||||
|
||||
所以这里常见的误判是:
|
||||
|
||||
- **剧情推理其实已经做完了。**
|
||||
- 只是 UI 先让用户“继续冒险”一次,才把新选项展示出来。
|
||||
|
||||
---
|
||||
|
||||
## 3. 本次排查发现的重点问题
|
||||
|
||||
### 3.1 真正最像“没触发剧情推理”的地方:模态框型 NPC function
|
||||
|
||||
定位:
|
||||
|
||||
- `src/hooks/story/npcEncounterActions.ts:427-449`
|
||||
- `src/hooks/story/storyGenerationState.ts:41-80`
|
||||
- `src/hooks/story/npcInteraction.ts:427-585`
|
||||
|
||||
现象:
|
||||
|
||||
- 点击 `npc_trade` / `npc_gift` / `npc_recruit` 后,故事文本区通常不会立刻变化。
|
||||
- 当前故事也不会马上追加一段新的 `storyText`。
|
||||
|
||||
原因:
|
||||
|
||||
- 这些 function 的第一次点击只做本地 UI 分流。
|
||||
- 直到用户在 modal 里确认,才会真正调用 `commitGeneratedState` 继续推理。
|
||||
|
||||
判断:
|
||||
|
||||
- **这不是单纯 bug,而是当前设计本身如此。**
|
||||
- 但如果玩家从“选项即剧情推进”的心智出发,会非常像“点了没反应”。
|
||||
|
||||
建议优先级:高。
|
||||
|
||||
### 3.2 最关键的实际 bug:`story_continue_adventure` 文案乱码,导致“已推理但未显式提示”
|
||||
|
||||
定位:
|
||||
|
||||
- `src/hooks/useStoryGeneration.ts:92-96`
|
||||
- `src/hooks/story/npcEncounterActions.ts:281-400`
|
||||
- `src/components/AdventurePanel.tsx:534`
|
||||
- `src/components/AdventurePanel.tsx:860`
|
||||
- `src/components/AdventurePanel.tsx:879`
|
||||
|
||||
现象:
|
||||
|
||||
- `npc_chat` 完成后,系统本应展示一个“继续冒险”按钮,提示“剧情推理完成,继续后显示新的冒险选项”。
|
||||
- 但当前 `CONTINUE_ADVENTURE_ACTION_TEXT` 常量已经写成了乱码:`缁х画鍐掗櫓`。
|
||||
- `AdventurePanel` 又是靠 `option.actionText === '继续冒险'` 来识别这个特殊按钮。
|
||||
|
||||
直接后果:
|
||||
|
||||
- 特殊提示 UI 不会出现。
|
||||
- 玩家只会看到一个普通且乱码的单选项。
|
||||
- 实际上 `deferredOptions` 已经算好了,但用户极容易误会为“剧情没有继续推理”。
|
||||
|
||||
判断:
|
||||
|
||||
- **这是本次排查里最明确的实现级 bug。**
|
||||
- 它不会阻止底层推理发生,但会严重破坏“推理已完成”的可见性。
|
||||
|
||||
建议优先级:最高。
|
||||
|
||||
### 3.3 `StateFunctionEditor` 覆盖不到真正最容易出问题的 function
|
||||
|
||||
定位:
|
||||
|
||||
- `src/components/StateFunctionEditor.tsx:13-21`
|
||||
- `src/components/StateFunctionEditor.tsx:488`
|
||||
- `src/components/StateFunctionEditor.tsx:772-838`
|
||||
- `src/components/StateFunctionEditor.tsx:992-1211`
|
||||
|
||||
现象:
|
||||
|
||||
- 编辑器预览只接了 `buildStateFunctionDefinitions` / `getAllStateFunctionDefinitions` / `resolveFunctionOption`。
|
||||
- 也就是它只能预览 `stateFunctions.ts` 那 12 个基础 function。
|
||||
|
||||
覆盖不到的关键分支:
|
||||
|
||||
- `npc_*`
|
||||
- `treasure_*`
|
||||
- `npc_preview_talk`
|
||||
- `story_continue_adventure`
|
||||
- modal 分流
|
||||
- `npc_chat` 的 `deferredOptions`
|
||||
|
||||
判断:
|
||||
|
||||
- 这不是运行时 bug,但它解释了为什么这类问题很难在编辑器里提前暴露。
|
||||
- 当前“Function 编辑器”并没有覆盖到最复杂、最容易让用户感知为异常的 function 链路。
|
||||
|
||||
建议优先级:高。
|
||||
|
||||
### 3.4 function 清单存在“源码有、运行时无、别处还在引用”的分裂
|
||||
|
||||
定位:
|
||||
|
||||
- `src/data/stateFunctions.ts:350`
|
||||
- `src/data/stateFunctions.ts:429-441`
|
||||
- `src/components/game-shell/useSceneTransitionModel.ts:19-25`
|
||||
|
||||
现象:
|
||||
|
||||
- `idle_follow_clue` 仍在定义表、提示词描述、若干 `switch` 分支中存在。
|
||||
- 但最终在 `applyRuntimeFunctionAdjustments` 被过滤掉,不会进入运行时 function 集合。
|
||||
- `useSceneTransitionModel` 里却还保留着它的转场模式映射。
|
||||
|
||||
判断:
|
||||
|
||||
- 这不是“没触发剧情推理”的直接原因。
|
||||
- 但会让维护者误判当前真实 function 清单,也会增加后续继续扩 function 时的混乱。
|
||||
|
||||
建议优先级:中。
|
||||
|
||||
### 3.5 自动化测试几乎没有覆盖“最容易让人误会没推理”的链路
|
||||
|
||||
定位:
|
||||
|
||||
- 当前已有测试主要是 `src/hooks/story/storyGenerationState.test.ts`
|
||||
|
||||
已覆盖:
|
||||
|
||||
- `trade_modal`
|
||||
- `recruit_modal`
|
||||
- 地图切场景
|
||||
|
||||
未覆盖:
|
||||
|
||||
- `npc_chat` 的 `deferredOptions -> story_continue_adventure -> 真正显示新选项`
|
||||
- `npc_trade` / `npc_gift` / `npc_recruit` 确认后是否一定调用 `commitGeneratedState`
|
||||
- `story_continue_adventure` 文案与 UI 特判是否一致
|
||||
- `npc_preview_talk -> enterNpcInteraction -> generateStoryForState`
|
||||
- 宝藏分支确认后是否稳定续推
|
||||
|
||||
判断:
|
||||
|
||||
- 这类问题之所以能长期存在,一个核心原因就是**最关键的续推分支没有测试兜底**。
|
||||
|
||||
建议优先级:高。
|
||||
|
||||
---
|
||||
|
||||
## 4. 按“首次点击是否立即触发剧情推理”整理
|
||||
|
||||
### 4.1 首次点击就会继续推理
|
||||
|
||||
- `battle_*`
|
||||
- `idle_*`
|
||||
- `npc_preview_talk`
|
||||
- `npc_help`
|
||||
- `npc_chat`
|
||||
- `npc_fight`
|
||||
- `npc_spar`
|
||||
- `npc_quest_accept`
|
||||
- `npc_quest_turn_in`
|
||||
- `npc_leave`
|
||||
- `treasure_*`
|
||||
- `inventory_use`
|
||||
- `equipment_*`
|
||||
- `forge_*`
|
||||
|
||||
### 4.2 首次点击不会立刻继续推理
|
||||
|
||||
- `npc_trade`
|
||||
- `npc_gift`
|
||||
- `npc_recruit`(至少会先进入确认 / 对话流)
|
||||
- `story_continue_adventure`
|
||||
|
||||
这里要特别分清:
|
||||
|
||||
- `npc_trade` / `npc_gift` / `npc_recruit` 是**先分流,后确认,确认后再推理**。
|
||||
- `story_continue_adventure` 是**推理已经完成,只是先把结果选项延后展示**。
|
||||
|
||||
---
|
||||
|
||||
## 5. 建议的修正顺序
|
||||
|
||||
### P0
|
||||
|
||||
- 修掉 `CONTINUE_ADVENTURE_ACTION_TEXT` 的乱码。
|
||||
- `AdventurePanel` 不要再靠 `actionText === '继续冒险'` 判定特殊按钮,改成按 `functionId === 'story_continue_adventure'` 判定。
|
||||
|
||||
### P1
|
||||
|
||||
- 明确产品规则:
|
||||
- `npc_trade` / `npc_gift` / `npc_recruit` 第一次点击是否就应该写入一条“进入交易 / 送礼 / 招募确认”的剧情反馈。
|
||||
- 如果答案是“应该”,那这些 modal 型 function 需要补一层轻量 story feedback,而不是只弹框。
|
||||
|
||||
### P1
|
||||
|
||||
- 给 `npc_chat` 补自动化测试:
|
||||
- 聊天后必须出现 `story_continue_adventure`
|
||||
- 第二次点击后必须能展示 `deferredOptions`
|
||||
|
||||
### P1
|
||||
|
||||
- 给 `npc_trade` / `npc_gift` / `npc_recruit` 补自动化测试:
|
||||
- 第一次点击只分流
|
||||
- 确认后一定触发 `commitGeneratedState`
|
||||
- 后续一定能拿到新的 `StoryMoment`
|
||||
|
||||
### P2
|
||||
|
||||
- 扩展 `StateFunctionEditor` 或补新的“交互 function 预览器”,把 `npc_*` / `treasure_*` / `story_continue_adventure` 也纳入可预演范围。
|
||||
|
||||
### P2
|
||||
|
||||
- 清理 `idle_follow_clue` 这类“半退场”的 function,保证:
|
||||
- 运行时集合
|
||||
- prompt 描述
|
||||
- 编辑器
|
||||
- 转场映射
|
||||
- 测试
|
||||
|
||||
保持一致。
|
||||
|
||||
---
|
||||
|
||||
## 最后结论
|
||||
|
||||
当前最值得优先处理的,不是再继续加新的 function,而是先把这 3 个点收拢:
|
||||
|
||||
1. **把“首次点击只分流、不推理”的 function 明确标出来。**
|
||||
2. **把 `npc_chat -> story_continue_adventure -> deferredOptions` 这条延迟展示链做清楚。**
|
||||
3. **先修掉 `story_continue_adventure` 的乱码和基于文案的 UI 判断。**
|
||||
|
||||
如果不先处理这几个点,用户会持续把“按设计延迟”与“真实漏调剧情推理”混在一起感知,后面 function 越多,这类问题会越难排查。
|
||||
@@ -0,0 +1,163 @@
|
||||
# Function 需求完整性核查(2026-04-14)
|
||||
|
||||
## 1. 核查范围
|
||||
|
||||
本次核查按当前线程上下文,聚焦 function 体系相关文档与实现,不扩大到整个项目全部 PRD。
|
||||
|
||||
本次实际对照了这些文档:
|
||||
|
||||
- `docs/audits/FUNCTION_DESIGN_AUDIT_2026-04-03.md`
|
||||
- `docs/reference/FUNCTION_SCRIPT_CATALOG_2026-04-04.md`
|
||||
- `docs/experience/ADVENTURE_RUNTIME_DEV_EXPERIENCE.md`
|
||||
- `docs/audits/engineering/README.md`
|
||||
|
||||
本次实际核对了这些实现入口:
|
||||
|
||||
- `src/data/functionCatalog/**`
|
||||
- `src/data/stateFunctions.ts`
|
||||
- `src/data/npcInteractions.ts`
|
||||
- `src/components/AdventurePanel.tsx`
|
||||
- `src/hooks/story/choiceActions.ts`
|
||||
- `src/hooks/story/npcEncounterActions.ts`
|
||||
- `src/hooks/story/npcInteraction.ts`
|
||||
- `src/services/runtimeStoryService.ts`
|
||||
- `server-node/src/modules/story/**`
|
||||
- `server-node/src/modules/inventory/**`
|
||||
- `server-node/src/modules/runtime-item/**`
|
||||
- `server-node/src/modules/quest/**`
|
||||
|
||||
## 2. 核查结论
|
||||
|
||||
结论先说:
|
||||
|
||||
- function 主链路需求已经基本落地,不需要再继续“为了完整而过度迭代”。
|
||||
- 当前最主要的缺口不是再发明一套新 function 流程,而是把已有链路补齐回归测试,确保后续不会回退。
|
||||
- 本轮核查后,已把两条仍缺直接测试兜底的核心链路补上。
|
||||
|
||||
## 3. 已确认已经落地的需求
|
||||
|
||||
### 3.1 function 目录化与分层收口
|
||||
|
||||
已实现:
|
||||
|
||||
- `state / npc / treasure / flow / panel` 五类 function 已统一收口到 `src/data/functionCatalog/`
|
||||
- `src/data/functionCatalog/index.ts` 已提供统一导出
|
||||
- `SERVER_RUNTIME_FUNCTION_IDS` 也已和 catalog 文档映射对齐
|
||||
|
||||
判断:
|
||||
|
||||
- 这部分需求已完成,不需要继续重做结构。
|
||||
|
||||
### 3.2 `story_continue_adventure` 延迟展示链路
|
||||
|
||||
已实现:
|
||||
|
||||
- `npc_chat` 在 `npcEncounterActions.ts` 中先生成聊天正文,再把后续选项写入 `deferredOptions`
|
||||
- `choiceActions.ts` 在点击 `story_continue_adventure` 时会直接恢复 `deferredOptions`
|
||||
- `AdventurePanel.tsx` 已按 `functionId` 而不是 `actionText` 识别该特殊按钮
|
||||
|
||||
判断:
|
||||
|
||||
- 这条主功能链路已经真正存在,不属于“文档写了、实现没跟上”。
|
||||
|
||||
### 3.3 modal 型 function 的首次点击分流
|
||||
|
||||
已实现:
|
||||
|
||||
- `npc_trade`
|
||||
- `npc_gift`
|
||||
- `npc_recruit`
|
||||
|
||||
这些 function 当前都明确是“首次点击先分流,再在确认后进入真正执行链”。
|
||||
|
||||
当前实现路径:
|
||||
|
||||
- 首次点击:
|
||||
- `choiceActions.ts`
|
||||
- `storyGenerationState.ts`
|
||||
- `npcInteraction.ts`
|
||||
- 确认后:
|
||||
- `trade / gift / quest` 进入 server runtime action
|
||||
- `recruit` 进入本地招募对白与本地状态提交链
|
||||
|
||||
判断:
|
||||
|
||||
- 这不是未实现,而是当前架构设计如此。
|
||||
- 文档里“确认后要继续推进剧情/结算”的要求已经满足。
|
||||
|
||||
### 3.4 Task6 function 的服务端化
|
||||
|
||||
已实现:
|
||||
|
||||
- `inventory_use`
|
||||
- `equipment_equip`
|
||||
- `equipment_unequip`
|
||||
- `forge_craft`
|
||||
- `forge_dismantle`
|
||||
- `forge_reforge`
|
||||
- `npc_trade`
|
||||
- `npc_gift`
|
||||
- `npc_quest_accept`
|
||||
- `npc_quest_turn_in`
|
||||
- `treasure_secure`
|
||||
- `treasure_inspect`
|
||||
- `treasure_leave`
|
||||
|
||||
这些 function 已经在前端 `runtimeStoryService.ts`、服务端 `story runtime / inventory / runtime-item / quest` 模块里形成闭环。
|
||||
|
||||
判断:
|
||||
|
||||
- 这部分不需要再回退到前端本地重写。
|
||||
|
||||
## 4. 本轮发现的真实缺口
|
||||
|
||||
本轮真正仍未完整落地的,不是功能行为本身,而是下面两条回归保护:
|
||||
|
||||
### 4.1 `npc_chat -> story_continue_adventure -> deferredOptions`
|
||||
|
||||
问题:
|
||||
|
||||
- 文档明确要求这条链路要清楚、可验证。
|
||||
- 代码已经有,但之前没有直接测试“点击继续冒险后必须展示 deferredOptions”。
|
||||
|
||||
本轮已补:
|
||||
|
||||
- `src/hooks/story/choiceActions.test.ts`
|
||||
- 新增 `reveals deferred adventure options when story_continue_adventure is selected`
|
||||
|
||||
### 4.2 `AdventurePanel` 对 continue option 的识别方式
|
||||
|
||||
问题:
|
||||
|
||||
- 文档明确要求不要再靠文案识别 continue option。
|
||||
- 实现已经改成按 `functionId` 识别,但之前没有组件层测试锁住。
|
||||
|
||||
本轮已补:
|
||||
|
||||
- `src/components/AdventurePanel.test.tsx`
|
||||
- 验证 `story_continue_adventure` 即使 actionText 改掉,仍然显示延迟选项提示
|
||||
- 验证仅 actionText 相同但 functionId 不同,不会误触发提示
|
||||
|
||||
## 5. 本轮新增测试
|
||||
|
||||
本轮新增:
|
||||
|
||||
- `src/components/AdventurePanel.test.tsx`
|
||||
- `src/hooks/story/choiceActions.test.ts`
|
||||
- 新增 deferred options 恢复用例
|
||||
|
||||
## 6. 验收结论
|
||||
|
||||
按当前 function 相关文档要求判断:
|
||||
|
||||
- 核心运行时需求:已实现
|
||||
- 延迟展示链路:已实现
|
||||
- modal 分流架构:已实现
|
||||
- Task6 服务端承接:已实现
|
||||
- 回归测试盲区:本轮已补齐关键缺口
|
||||
|
||||
最终建议:
|
||||
|
||||
- 这块现在不应该继续过度迭代。
|
||||
- 后续应以“新增需求再增量补测试”为主,而不是再次重构 function 主链路。
|
||||
- 除非后续 PRD 明确要求“modal 首次点击也必须立刻生成一段剧情反馈”,否则不建议为了形式统一再强行改写当前分流模型。
|
||||
212
docs/audits/FUNCTION_RUNTIME_FULL_TEST_AUDIT_2026-04-16.md
Normal file
212
docs/audits/FUNCTION_RUNTIME_FULL_TEST_AUDIT_2026-04-16.md
Normal file
@@ -0,0 +1,212 @@
|
||||
# Function 运行时完整测试审计(2026-04-16)
|
||||
|
||||
## 1. 本次目标
|
||||
|
||||
本次不是泛泛地跑一遍前端页面,而是围绕“游戏运行中的 function 主链路”做系统化核查,重点确认下面 4 件事:
|
||||
|
||||
- 当前运行时 function 集合是否还能正确构建、过滤、排序和解析。
|
||||
- function 命中的前端承接链路是否仍然稳定。
|
||||
- 已服务端化的 runtime action function 是否还能闭环执行。
|
||||
- 工程门禁是否处于可持续回归的状态。
|
||||
|
||||
## 2. 本次实际覆盖范围
|
||||
|
||||
本轮重点覆盖了这些实现入口:
|
||||
|
||||
- `src/data/stateFunctions.ts`
|
||||
- `src/data/functionCatalog/**`
|
||||
- `src/data/npcInteractions.ts`
|
||||
- `src/hooks/story/**`
|
||||
- `src/services/runtimeStoryService.ts`
|
||||
- `src/hooks/useGameFlow.ts`
|
||||
- `server-node/src/modules/story/**`
|
||||
- `server-node/src/modules/inventory/**`
|
||||
- `server-node/src/modules/runtime-item/**`
|
||||
- `server-node/src/modules/quest/**`
|
||||
- `scripts/smoke-server-node.ts`
|
||||
|
||||
## 3. 实际执行的测试与检查
|
||||
|
||||
### 3.1 前端 Vitest 全量测试
|
||||
|
||||
执行命令:
|
||||
|
||||
```bash
|
||||
npm.cmd test
|
||||
```
|
||||
|
||||
结果:
|
||||
|
||||
- `110` 个测试文件全部通过
|
||||
- `276` 条测试全部通过
|
||||
|
||||
其中与 function 主链路直接相关、并已确认通过的测试包括:
|
||||
|
||||
- `src/data/stateFunctions.test.ts`
|
||||
- `src/data/functionCatalog/functionCatalog.test.ts`
|
||||
- `src/data/npcInteractions.test.ts`
|
||||
- `src/hooks/story/choiceActions.test.ts`
|
||||
- `src/hooks/story/storyGenerationState.test.ts`
|
||||
- `src/hooks/story/runtimeStoryCoordinator.test.ts`
|
||||
- `src/components/AdventurePanel.test.tsx`
|
||||
- `src/services/runtimeStoryService.test.ts`
|
||||
|
||||
补充说明:
|
||||
|
||||
- 运行 `hostileNpcPresets.test.ts` 时会看到 “network disabled in test” 的日志。
|
||||
- 这不是本轮失败项,测试已验证在 LLM 不可达时会正确走 deterministic fallback。
|
||||
|
||||
### 3.2 内容数据校验
|
||||
|
||||
执行命令:
|
||||
|
||||
```bash
|
||||
npm.cmd run check:content
|
||||
```
|
||||
|
||||
结果:
|
||||
|
||||
- `check:data` 通过
|
||||
- `check:overrides` 通过
|
||||
- `check:smoke` 通过
|
||||
- 输出为:`Content validation passed. scenes=24 monsters=16 characters=5 functions=12`
|
||||
|
||||
结论:
|
||||
|
||||
- 当前基础内容数据、override 与 smoke 内容校验没有发现新的 function 数据层问题。
|
||||
|
||||
### 3.3 服务端测试
|
||||
|
||||
执行命令:
|
||||
|
||||
```bash
|
||||
npm.cmd run server-node:test
|
||||
```
|
||||
|
||||
结果:
|
||||
|
||||
- `108` 条服务端测试全部通过
|
||||
|
||||
本轮已确认通过的 function 相关服务端能力包括:
|
||||
|
||||
- `inventory_use`
|
||||
- `equipment_equip`
|
||||
- `npc_trade`
|
||||
- `npc_gift`
|
||||
- `npc_quest_accept`
|
||||
- `npc_quest_turn_in`
|
||||
- `treasure_inspect`
|
||||
- 战斗结算与 quest signal 推进
|
||||
|
||||
结论:
|
||||
|
||||
- 已服务端化的 runtime function 承接链路当前单测层面是稳定的。
|
||||
|
||||
### 3.4 服务端 smoke
|
||||
|
||||
执行命令:
|
||||
|
||||
```bash
|
||||
npm.cmd run server-node:smoke
|
||||
```
|
||||
|
||||
结果:
|
||||
|
||||
- 失败
|
||||
- 报错:
|
||||
|
||||
```text
|
||||
TypeError: Cannot read properties of undefined (reading 'enabled')
|
||||
```
|
||||
|
||||
### 3.5 TypeScript 类型检查
|
||||
|
||||
执行命令:
|
||||
|
||||
```bash
|
||||
npm.cmd run typecheck
|
||||
```
|
||||
|
||||
结果:
|
||||
|
||||
- 失败
|
||||
- 失败位置:
|
||||
- `src/hooks/useGameFlow.ts:339`
|
||||
|
||||
### 3.6 生产构建
|
||||
|
||||
执行命令:
|
||||
|
||||
```bash
|
||||
npm.cmd run build
|
||||
```
|
||||
|
||||
结果:
|
||||
|
||||
- 通过
|
||||
|
||||
结论:
|
||||
|
||||
- 当前代码可构建,但并不代表类型门禁与 smoke 门禁同样健康。
|
||||
|
||||
## 4. 本轮确认的问题
|
||||
|
||||
## P1:`server-node:smoke` 已失效,无法完成服务端运行时冒烟验证
|
||||
|
||||
- 现象:
|
||||
- `npm.cmd run server-node:smoke` 无法启动临时 Express 服务,直接在 `createSmsVerificationService` 处报错。
|
||||
- 直接原因:
|
||||
- [`scripts/smoke-server-node.ts`](../../scripts/smoke-server-node.ts) 里的 `createSmokeConfig()` 只构造了 `llm`、`dashScope` 等字段,没有补齐后续新增的 `smsAuth`、`wechatAuth`、`authSession` 配置块。
|
||||
- [`server-node/src/config.ts`](../../server-node/src/config.ts) 中 `AppConfig` 已把这些字段定义为必需项。
|
||||
- [`server-node/src/services/smsVerificationService.ts`](../../server-node/src/services/smsVerificationService.ts) 在 `createSmsVerificationService` 中直接读取 `config.smsAuth.enabled`,因此 smoke 配置一进入 `createAppContext` 就会崩。
|
||||
- 影响:
|
||||
- 本地无法再用 smoke 脚本验证“服务端真实启动 + 认证 + runtime save/settings 回路”。
|
||||
- 这会让 function 服务端化之后的真实接线路径少掉一层最接近运行时的保护。
|
||||
- 判断:
|
||||
- 这是本轮最明确、最稳定复现的真实 bug。
|
||||
|
||||
## P1:`typecheck` 门禁已破,`useGameFlow` 的 starter inventory 合并存在类型漂移
|
||||
|
||||
- 现象:
|
||||
- `npm.cmd run typecheck` 在 [`src/hooks/useGameFlow.ts`](../../src/hooks/useGameFlow.ts) 第 `339` 行失败。
|
||||
- 直接原因:
|
||||
- 同文件中的 `mergeStarterInventoryItems<T extends { category: string; name: string }>` 会优先从显式 starter item 推断出一个“字段更严格”的 `T`。
|
||||
- 但 fallback 侧传入的是 [`InventoryItem`](../../src/types/items.ts) 数组,而 `InventoryItem.description`、`equipmentSlotId`、`runtimeMetadata` 等字段本身是可选的。
|
||||
- 于是 `explicitItems` 与 `fallbackItems` 在泛型推断后不再兼容,类型门禁被打穿。
|
||||
- 影响:
|
||||
- 当前 starter inventory 初始化链路虽然能跑、也能通过构建,但已经失去 TypeScript 对结构一致性的保护。
|
||||
- 这类问题后续很容易演变成“自定义世界显式初始物品”和“默认初始物品”在字段形态上继续分叉。
|
||||
- 判断:
|
||||
- 这是一个真实的工程 bug,优先级高于纯测试文案问题。
|
||||
|
||||
## 5. 本轮已确认通过的结论
|
||||
|
||||
- state function 运行时构建、过滤、优先级、选项解析当前测试全绿。
|
||||
- function catalog 文档映射、helper option、trade/gift/recruit modal helper 当前测试全绿。
|
||||
- 前端 function 主链路相关测试在最新工作区状态下已全部通过。
|
||||
- 服务端 runtime story action、inventory、runtime-item、quest 承接链路当前测试全绿。
|
||||
- 内容数据层校验通过。
|
||||
- 生产构建通过。
|
||||
|
||||
## 6. 结论
|
||||
|
||||
如果只看“游戏运行中的 function 主链路”,当前结论是:
|
||||
|
||||
- 前端 function 运行时逻辑:通过
|
||||
- 服务端 function action 承接:通过
|
||||
- 内容数据与 function 基础目录:通过
|
||||
- 工程回归门禁:不完整
|
||||
|
||||
当前最需要处理的不是再扩 function 范围,而是先修复这两个门禁缺口:
|
||||
|
||||
1. 修好 `server-node:smoke` 的配置构造,让服务端冒烟恢复可用。
|
||||
2. 修好 `useGameFlow` 的 starter inventory 类型漂移,让 `typecheck` 回到绿色基线。
|
||||
|
||||
## 7. 备注
|
||||
|
||||
本轮没有做两类事情:
|
||||
|
||||
- 没有接入真实外部 LLM 做在线回归,本轮依赖的是本地测试里已有的 fallback 断言。
|
||||
- 没有人手逐个点击整局游戏所有 function 的视觉回放,本轮重点是自动化测试、服务端测试、内容校验与 smoke 门禁。
|
||||
|
||||
因此,本审计可以说明“当前 function 系统的自动化测试层状况”,但不等于“所有视觉演出与在线模型联动都已人工验证完毕”。
|
||||
128
docs/audits/FUNCTION_TEST_AUDIT_2026-04-14.md
Normal file
128
docs/audits/FUNCTION_TEST_AUDIT_2026-04-14.md
Normal file
@@ -0,0 +1,128 @@
|
||||
# Function 测试审计(2026-04-14)
|
||||
|
||||
补充更新:
|
||||
|
||||
- 本文记录的 2 个 bug 已在同日完成代码修复。
|
||||
- 对应测试已经从“稳定复现旧行为”切换为“验证修复后行为”。
|
||||
|
||||
## 1. 本次新增测试
|
||||
|
||||
本轮新增了两组 function 相关测试:
|
||||
|
||||
- `src/data/stateFunctions.test.ts`
|
||||
- 覆盖 state function 的运行时过滤、优先级、选项解析、排序逻辑。
|
||||
- `src/data/functionCatalog/functionCatalog.test.ts`
|
||||
- 覆盖 function 文档映射、flow helper、NPC helper modal 初始化逻辑。
|
||||
|
||||
这两组测试都直接挂在现有 `vitest` 体系里,没有新建独立测试框架。
|
||||
|
||||
## 2. 本次执行结果
|
||||
|
||||
本轮实际执行了以下测试:
|
||||
|
||||
```bash
|
||||
npx vitest run src/data/stateFunctions.test.ts src/data/functionCatalog/functionCatalog.test.ts
|
||||
npx vitest run src/data/npcInteractions.test.ts src/hooks/story/storyGenerationState.test.ts src/services/runtimeStoryService.test.ts
|
||||
```
|
||||
|
||||
执行结果:
|
||||
|
||||
- 新增测试:`2` 个文件,`12` 条测试,全部通过。
|
||||
- 复跑已有 function 相关测试:`3` 个文件,`17` 条测试,全部通过。
|
||||
- 修复回归测试:`5` 个文件,`30` 条测试,全部通过。
|
||||
- 编码检查:`1516` 个文件全部通过。
|
||||
|
||||
说明:
|
||||
|
||||
- 本轮不是“测试全绿就代表没有问题”。
|
||||
- 最初定位出的 2 个问题,已经在后续修复回合里转成了回归测试。
|
||||
|
||||
## 3. 历史 bug 与修复结果
|
||||
|
||||
### 3.1 `battle_recover_breath`
|
||||
|
||||
- 所在位置:`src/data/stateFunctions.ts`
|
||||
- 状态:已修复
|
||||
- 原始问题表现:
|
||||
- 当 `inBattle = true`,但当前没有存活敌人时,`battle_recover_breath` 仍会留在可执行 function 列表中。
|
||||
- 直接原因:
|
||||
- `matchesCategory` 对 `recovery` 分类只判断了是否处于战斗态,没有像 `battle` / `escape` 分类那样额外校验 `hasAliveMonsters(context.monsters)`。
|
||||
- 修复方式:
|
||||
- 已在 `matchesCategory` 的 `recovery` 分支中,为战斗恢复类 function 补上 `hasAliveMonsters(context.monsters)` 判断。
|
||||
- 修复前影响:
|
||||
- 在“敌人已死但战斗态尚未清理干净”的边界帧里,界面仍可能出现战斗恢复类选项。
|
||||
- 这会让 function 池和真实战斗状态产生残留错位。
|
||||
- 当前验证方式:
|
||||
- `inBattle = true`
|
||||
- `monsters = [{ hp: 0, ... }]`
|
||||
- 调用 `getExecutableFunctions(context)`
|
||||
- 现在返回结果应为空,不再包含 `battle_recover_breath`
|
||||
- 对应用例:
|
||||
- `src/data/stateFunctions.test.ts`
|
||||
- 用例名:`removes battle_recover_breath when combat has no living monsters`
|
||||
|
||||
### 3.2 `npc_trade`
|
||||
|
||||
- 所在位置:`src/data/functionCatalog/npc/npcTrade.ts`
|
||||
- 状态:已修复
|
||||
- 原始问题表现:
|
||||
- trade modal 初始化时,`selectedPlayerItemId` 直接取 `state.playerInventory[0]?.id`。
|
||||
- 如果玩家背包第一项数量为 `0`,modal 默认会选中一件不可出售物品。
|
||||
- 直接原因:
|
||||
- `buildNpcTradeModalState` 没有过滤 `quantity <= 0` 的物品,也没有寻找第一个可交易物品。
|
||||
- 修复方式:
|
||||
- 已改为优先选择 `quantity > 0` 的可交易物品。
|
||||
- 同时对 NPC 库存和玩家背包都使用同一条筛选规则,避免默认选中空物品。
|
||||
- 修复前影响:
|
||||
- 交易面板第一次打开时,默认状态可能就是不可确认的。
|
||||
- 用户需要手动切换到第二件物品,才会进入可提交状态。
|
||||
- 当前验证方式:
|
||||
- `playerInventory[0].quantity = 0`
|
||||
- `playerInventory[1].quantity > 0`
|
||||
- 调用 `buildNpcTradeModalState(...)`
|
||||
- 现在 `selectedPlayerItemId` 应该自动落到第一件可交易物品
|
||||
- 对应用例:
|
||||
- `src/data/functionCatalog/functionCatalog.test.ts`
|
||||
- 用例名:`prefers the first tradable player item when zero-quantity items exist`
|
||||
- `src/hooks/story/storyGenerationState.test.ts`
|
||||
- 用例名:`skips zero-quantity player items when opening the trade modal`
|
||||
|
||||
## 4. 本轮已验证通过的 function 能力
|
||||
|
||||
以下内容本轮已通过测试验证,没有发现新的明显问题:
|
||||
|
||||
- state function runtime 构建:
|
||||
- `idle_follow_clue` 已正确从运行时候选池移除。
|
||||
- `idle_explore_forward` 的运行时文案覆盖仍然生效。
|
||||
- state function 选项行为:
|
||||
- 高压战斗下 `battle_recover_breath` 会被正确提权。
|
||||
- 营地场景会正确隐藏 `idle_explore_forward`。
|
||||
- `idle_travel_next_scene` 会强制使用运行时建议 actionText。
|
||||
- `battle_all_in_crush` 会保留外部传入的自定义 actionText。
|
||||
- story option 排序仍保持“前 2 个 model 锁定 + 后续按 priority 排序”。
|
||||
- flow helper:
|
||||
- `story_continue_adventure`
|
||||
- `camp_travel_home_scene`
|
||||
- NPC helper:
|
||||
- `npc_preview_talk`
|
||||
- `npc_gift`
|
||||
- `npc_recruit`
|
||||
- 文档映射:
|
||||
- 当前 `SERVER_RUNTIME_FUNCTION_IDS` 全部都能在 function catalog 文档中找到对应条目。
|
||||
- 本轮扫描到的 function `source` 路径全部存在,没有出现失效引用。
|
||||
|
||||
## 5. 本轮修复动作
|
||||
|
||||
- `battle_recover_breath`
|
||||
- 已补充战斗恢复类 function 的存活敌人校验,避免战斗边界帧残留非法选项。
|
||||
- `npc_trade`
|
||||
- 已把 trade modal 默认选中逻辑改为优先寻找可交易物品,不再直接吃数组第一项。
|
||||
- 回归测试
|
||||
- 原先记录旧行为的测试已翻转为修复后预期,并额外补了一条 `storyGenerationState` 接入层测试。
|
||||
|
||||
## 6. 备注
|
||||
|
||||
这次测试资产的意义分两步:
|
||||
|
||||
- 第一步先把 bug 稳定复现出来,避免问题只停留在口头描述。
|
||||
- 第二步在修复后把断言翻转成“正确行为”,让它们正式成为回归测试。
|
||||
133
docs/audits/ITEM_AND_BUILD_PRD_AUDIT_2026-04-05.md
Normal file
133
docs/audits/ITEM_AND_BUILD_PRD_AUDIT_2026-04-05.md
Normal file
@@ -0,0 +1,133 @@
|
||||
# 物品生成系统与 Build 标签系统 PRD 落地审计
|
||||
|
||||
审计时间:2026-04-05
|
||||
|
||||
审计范围:
|
||||
|
||||
- `docs/prd/AI_NATIVE_RUNTIME_ITEM_GENERATION_DESIGN.md`
|
||||
- `docs/prd/RUNTIME_ITEM_GENERATION_CURRENT_SYSTEM_DESIGN.md`
|
||||
- `docs/prd/BUILD_SYSTEM_ATTRIBUTE_SIMILARITY_PRD_2026-04-02.md`
|
||||
- `docs/design/EQUIPMENT_BUILD_AND_FORGE_LOOP_SYSTEM_DESIGN.md`
|
||||
|
||||
## 结论速览
|
||||
|
||||
### 1. 物品生成系统
|
||||
|
||||
当前状态可以判定为:**主链已补齐落地**。
|
||||
|
||||
已经落地的是:
|
||||
|
||||
- 有独立的运行时上下文层、导演层、本地编译层、叙事回写层。
|
||||
- 宝藏、怪物掉落、通用 NPC 商店已经能走统一的 runtime item director。
|
||||
- 永久 build 标签物品、限时 build buff 物品、少量数值物品三种骨架都已经能编译出来,并接进现有背包 / 装备 / build 结算。
|
||||
|
||||
本轮已补齐的是:
|
||||
|
||||
- 新增了 runtime item AI 意图导演与 prompt,并接入 NPC 帮助奖励主链,失败时自动回退到本地导演。
|
||||
- NPC 交易库存改成按玩家当前 build 生成,并通过 `tradeStockSignature` 只在 build 变化时刷新。
|
||||
- NPC 帮助奖励、委托奖励已经统一接入 runtime item director。
|
||||
- 怪物掉落已经改成“基础掉落 + 语义掉落”双层叠加。
|
||||
|
||||
### 2. Build 标签系统
|
||||
|
||||
当前状态可以判定为:**核心已按 PRD 落地,且实现范围比 PRD 更大**。
|
||||
|
||||
已经落地的是:
|
||||
|
||||
- `BuildTagDefinition.attributeAffinity` 已扩展。
|
||||
- `buildDamage.ts` 已改成“标签分别匹配角色属性画像”的加法模型,不再做标签两两网络效应。
|
||||
- Buff / 角色固有 / 武器 / 护甲 / 饰品 / 套装标签都能进入最终倍率。
|
||||
- Character 面板已经切到“属性适配度”展示,并能拆出单标签的属性贡献明细。
|
||||
- 有针对新公式的测试覆盖。
|
||||
|
||||
还存在的尾项主要是:
|
||||
|
||||
- 实现用的是“世界属性 schema 六轴模型”,不是 PRD 文字里的固定四维属性。
|
||||
- 旧的标签相似度辅助能力没有完全清干净,重铸仍在用 `getSimilarBuildTags` 做候选标签替换。
|
||||
|
||||
## 物品生成系统审计
|
||||
|
||||
| PRD 项 | 当前实现 | 判定 | 代码证据 |
|
||||
| --- | --- | --- | --- |
|
||||
| 上下文采样层 | 已有 `buildRuntimeItemGenerationContext` / `buildQuestRuntimeItemGenerationContext`,会收集场景、遭遇、关联 NPC、最近剧情、玩家 build 标签与 build gap。 | 已落地 | `src/data/runtimeItemContext.ts:157-188`、`src/data/runtimeItemContext.ts:191-252` |
|
||||
| AI 意图层 | 已新增 `runtimeItemAiDirector` / `runtimeItemAiPrompt`,`buildRuntimeItemAiPromptInput` 已进入真实 prompt 组装;NPC 帮助奖励主链会先请求 AI 物品意图,再回落到本地意图导演。 | 已补齐 | `src/services/runtimeItemAiPrompt.ts`、`src/services/runtimeItemAiDirector.ts`、`src/data/runtimeItemDirector.ts`、`src/hooks/story/npcEncounterActions.ts` |
|
||||
| 本地编译层 | 已按 channel / slot / permanence 做 rarity 与预算编译,并产出 `statProfile`、`useProfile.buildBuffs`、`buildProfile`、`runtimeMetadata`。 | 已落地 | `src/data/runtimeItemCompiler.ts:77-101`、`src/data/runtimeItemCompiler.ts:122-206`、`src/data/runtimeItemCompiler.ts:245-276` |
|
||||
| 叙事回写层 | 会把锚点、来源理由、build 倾向回写进物品名和描述。 | 已落地 | `src/data/runtimeItemNarrative.ts:171-189` |
|
||||
| 永久标签 / 限时标签 / 少量数值三类物品 | 永久物品走 `buildProfile`,限时物品走 `useProfile.buildBuffs`,并可附带少量数值。 | 已落地 | `src/data/runtimeItemCompiler.ts:104-155`、`src/data/runtimeItemCompiler.ts:157-206` |
|
||||
| 宝藏入口 | 宝藏奖励已经走 `buildRuntimeItemGenerationContext + buildDirectedRuntimeReward`,并把结果写回 story hint。 | 已落地 | `src/data/treasureInteractions.ts:52-89`、`src/hooks/useTreasureFlow.ts:45-75` |
|
||||
| NPC 交易入口 | 通用 NPC 商店已改成按玩家当前 build 生成;初始 NPC 状态、交易模态打开时刷新、场景预览读取都会带上完整 `GameState`,并用 `tradeStockSignature` 避免无意义重刷。角色型 NPC 仍保留既有角色装备/背包模板。 | 已补齐 | `src/data/npcInteractions.ts`、`src/hooks/story/npcInteraction.ts`、`src/hooks/useStoryGeneration.ts`、`src/components/NpcModals.tsx` |
|
||||
| NPC 帮助 / 关系奖励 | `npc_reward` 已真正接入主链。帮助奖励现在会生成带 `runtimeMetadata` 的 runtime item,并保留数值恢复、冷却缩减与 story hint。 | 已补齐 | `src/data/npcInteractions.ts`、`src/hooks/story/npcEncounterActions.ts` |
|
||||
| 委托奖励入口 | Quest reward 已改为走 runtime director,支持 `buildQuestRuntimeItemGenerationContext`,领取时发放的是 runtime item。主 NPC 接任务流程也已切到 `generateQuestForNpcEncounter`。 | 已补齐 | `src/data/questFlow.ts`、`src/hooks/story/npcEncounterActions.ts`、`src/services/questDirector.ts` |
|
||||
| 怪物掉落双层设计 | 普通世界掉落已改成预设 `lootTable` 基础掉落与 `monster_drop` runtime 语义掉落并存,不再互相覆盖。 | 已补齐 | `src/data/hostileNpcPresets.ts`、`src/data/hostileNpcPresets.test.ts` |
|
||||
|
||||
### 物品系统的具体判断
|
||||
|
||||
#### 已经明显符合 PRD 的部分
|
||||
|
||||
1. 系统分层已经形成。
|
||||
`runtimeItemContext -> runtimeItemDirector -> runtimeItemCompiler -> runtimeItemNarrative` 这条链已经非常接近 PRD 里“上下文采样 / AI 意图 / 本地编译 / 叙事回写”的结构。
|
||||
|
||||
2. build 导向优先于纯数值。
|
||||
`buildRuntimeItemContext` 会先算 `playerBuildTags` 和 `playerBuildGaps`,导演层再优先把 gap tag 与现有 build tag 拼进 `targetBuildDirection`,编译层才决定数值预算。
|
||||
|
||||
3. 奖励已经进入真实玩法结算。
|
||||
runtime item 生成出的 `buildProfile` 会进入装备 build 结算,`useProfile.buildBuffs` 会在使用物品时写入 `activeBuildBuffs`。
|
||||
|
||||
#### 本轮补齐后的说明
|
||||
|
||||
1. 运行时物品意图已经进入真实主链。
|
||||
当前至少在 NPC 帮助奖励链路中,已经先走 AI 意图导演,再走本地编译与叙事回写;如果模型不可用,会回退到既有启发式导演,保证玩法不断。
|
||||
|
||||
2. 交易库存已经真正读取玩家当前构筑。
|
||||
通用交易 NPC 的库存会基于玩家当前 build、装备标签和 build gap 生成,而不是继续依赖 NPC 自身偏好标签。
|
||||
|
||||
3. 帮助奖励、委托奖励、怪物掉落都已并入统一 runtime director。
|
||||
现在三条链路都能产出带 relation anchor / source reason / runtime metadata 的 runtime item。
|
||||
|
||||
## Build 标签系统审计
|
||||
|
||||
| PRD 项 | 当前实现 | 判定 | 代码证据 |
|
||||
| --- | --- | --- | --- |
|
||||
| `BuildTagDefinition.attributeAffinity` 扩展 | 类型已扩展,标签注册表也会为每个标签注入 affinity。 | 已落地 | `src/types/build.ts:6-13`、`src/data/buildTags.ts:66-69` |
|
||||
| 静态标签亲和度表 | 已有 `buildTagAttributeAffinity.ts`,提供标签到属性轴的静态 affinity 表。 | 已落地 | `src/data/buildTagAttributeAffinity.ts:127-183` |
|
||||
| 从“标签互相影响”改为“标签分别匹配角色属性” | `buildDamage.ts` 已按单标签计算 `fitScore`、`bonusDelta` 和属性贡献,最后做加法累积,不再做 pair/cluster 乘法网络。 | 已落地 | `src/data/buildDamage.ts:236-318` |
|
||||
| 来源系数 | Buff / 角色 / 武器 / 护甲 / 饰品 / 套装都有独立 source coefficient,和 PRD 基本一致。 | 已落地 | `src/data/buildDamage.ts:95-114` |
|
||||
| 最终伤害接入 | `resolvePlayerOutgoingDamage` / `resolveCompanionOutgoingDamage` / `resolveMonsterOutgoingDamage` 都已接 `buildDamageMultiplier`。 | 已落地 | `src/data/buildDamage.ts:498-542` |
|
||||
| 展示层从“标签协同”改成“属性适配度” | Character 面板已经按标签展示 bonus、来源、主导属性,并能打开明细弹窗。 | 已落地 | `src/components/CharacterPanel.tsx:205-247`、`src/components/CharacterPanel.tsx:497-539` |
|
||||
| 验收测试 | 已覆盖单标签可拆分、删一个标签不重算其余标签、不同属性角色用同一套装倍率不同、Buff/套装来源正常进入等场景。 | 已落地 | `src/data/buildDamage.test.ts:125-313` |
|
||||
| 四维属性口径 | PRD 写的是四维固定属性;实现已经提升为 world schema 六轴模型。目标一致,但口径不再一一对应。 | 已落地,但实现已外延扩展 | `src/types/attributes.ts:3-15`、`src/data/worldAttributeSchemas.ts:4-155` |
|
||||
| 旧标签相似度清理 | 核心伤害结算已不再依赖旧矩阵,但 `getSimilarBuildTags` 仍存在,重铸继续用它挑候选标签,`generate:build-tags` 脚本也还保留。 | 收尾未完成 | `src/data/buildTags.ts:183-215`、`src/data/forgeSystem.ts:371-399`、`package.json:21-24` |
|
||||
|
||||
### Build 系统的具体判断
|
||||
|
||||
#### 已经符合 PRD 核心目标的部分
|
||||
|
||||
1. 可解释性已经建立。
|
||||
现在每个标签都有自己的 `fitScore`、`attributeContributions` 和 `attributeModifierDeltas`,玩家可以看到“这个标签为什么强、强在哪条属性轴上”。
|
||||
|
||||
2. 新增标签不会反向扰动旧标签贡献。
|
||||
`buildDamage.test.ts` 已专门验证“删掉一个标签,只会移除它自己的 row,不会重算其他 row”。
|
||||
|
||||
3. 套装标签、Buff 标签、装备标签都能统一进入同一公式。
|
||||
这点和 PRD 的来源规则一致,且测试已经覆盖。
|
||||
|
||||
#### 需要注意但不构成核心未落地的问题
|
||||
|
||||
1. 实现已经超出 PRD 的四维设计。
|
||||
现在不是固定 `strength / agility / intelligence / spirit` 四维,而是通过 `WorldAttributeSchema` 映射成武侠/仙侠/自定义世界都能共用的语义属性轴。这更适合当前仓库的世界化属性系统,但也意味着 PRD 文案需要同步。
|
||||
|
||||
2. 旧相似度能力没有完全退场。
|
||||
核心伤害结算已经不用标签两两矩阵,但锻造重铸仍然会根据标签相似度挑换洗标签,所以“旧体系相关命名/脚本”还没彻底收尾。
|
||||
|
||||
## 综合判断
|
||||
|
||||
如果按“是否已经把 PRD 的主战场落到代码里”来判断:
|
||||
|
||||
- **Build 标签系统:可以认为已经落地。**
|
||||
- **物品生成系统:可以认为主链已经落地,之前审计出的缺口已在本轮补齐。**
|
||||
|
||||
如果接下来继续做收尾,更建议做的是:
|
||||
|
||||
1. 把 runtime item AI 意图层继续扩到宝藏、怪物掉落、委托奖励以外的更多同步入口,减少启发式 fallback 的覆盖面。
|
||||
2. 给 Build 系统补一版文档同步,明确当前实现已经从 PRD 四维模型升级为世界属性 schema 模型,并清理剩余旧相似度脚本/命名。
|
||||
3. 评估 `origin: 'ai_compiled'` 的语义是否还要细分成“AI 意图 + 本地编译”与“纯本地 fallback”两档,方便后续观测与埋点。
|
||||
27
docs/audits/README.md
Normal file
27
docs/audits/README.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# 审计与复盘
|
||||
|
||||
这一组文档聚焦“当前状态是否健康、问题在哪里、和目标设计差多少”。
|
||||
|
||||
## 系列总览
|
||||
|
||||
- [engineering/README.md](./engineering/README.md):当前工程优化审查与历史结论聚合入口。
|
||||
- [text/README.md](./text/README.md):文本、英文残留、乱码审计系列的融合入口。
|
||||
|
||||
## 专项审计
|
||||
|
||||
- [FUNCTION_DESIGN_AUDIT_2026-04-03.md](./FUNCTION_DESIGN_AUDIT_2026-04-03.md):Function 体系分层、职责边界和当前结构问题。
|
||||
- [FUNCTION_REQUIREMENT_COMPLETENESS_AUDIT_2026-04-14.md](./FUNCTION_REQUIREMENT_COMPLETENESS_AUDIT_2026-04-14.md):Function 相关文档需求与当前实现对齐核查。
|
||||
- [FUNCTION_TEST_AUDIT_2026-04-14.md](./FUNCTION_TEST_AUDIT_2026-04-14.md):Function 运行时测试补充、已确认 bug 与当前验证结果。
|
||||
- [FUNCTION_RUNTIME_FULL_TEST_AUDIT_2026-04-16.md](./FUNCTION_RUNTIME_FULL_TEST_AUDIT_2026-04-16.md):Function 运行时完整测试、服务端承接验证与当前门禁缺口。
|
||||
- [ITEM_AND_BUILD_PRD_AUDIT_2026-04-05.md](./ITEM_AND_BUILD_PRD_AUDIT_2026-04-05.md):物品生成与 Build 标签系统对 PRD 的落地情况。
|
||||
- [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、共享模板与保留接口的分层与冗余审计。
|
||||
- [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):未引用垃圾、旧入口残留、前后端双份真相与后端迁移项的专项审计。
|
||||
|
||||
## 推荐使用方式
|
||||
|
||||
1. 先读系列总览,确认“最新结论在哪一份”。
|
||||
2. 再按需要进入具体日期文档,查看当时的证据和上下文。
|
||||
3. 做方案设计前,优先把对应审计文档看完,避免重复踩已知问题。
|
||||
@@ -0,0 +1,29 @@
|
||||
# RPG 运行时直读世界草稿 Profile 检查 2026-04-25
|
||||
|
||||
## 结论
|
||||
|
||||
RPG 运行时进入游戏时不应再通过 `resultPreview.preview` 或 legacy runtime profile 做中间转换,主数据源统一为 Agent session 的 `draftProfile`。
|
||||
|
||||
本次检查确认:
|
||||
|
||||
1. Rust 侧 `custom_world_foundation_draft` 已直接产出 `draftProfile`。
|
||||
2. 前端原先 `buildCustomWorldProfileFromAgentSession()` 仍只读取 `session.resultPreview.preview`,这会绕过草稿 profile 中已经存在的角色形象、关系、压力等字段。
|
||||
3. 角色选择页与游戏内角色本身可以消费 `CustomWorldProfile.playableNpcs[].imageSrc`,断点在“session -> profile”的入口,而不是角色选择页。
|
||||
4. “进入世界”按钮原先还会先执行 `sync_result_profile`,把当前结果页旧快照再同步回 session;如果结果页 profile 没有最新角色图,会在进入角色选择页前覆盖掉 `draftProfile` 中的正确形象。
|
||||
|
||||
## 已修正
|
||||
|
||||
- `buildCustomWorldProfileFromAgentSession()` 改为直接归一化 `session.draftProfile`。
|
||||
- `resultPreview` 只保留为发布质量、blocker、预览外壳信息,不再作为进入游戏 profile 的数据源。
|
||||
- Agent 草稿结果进入游戏时直接使用最新 `agentSessionProfile`,不再把当前结果页 profile 回写成新的运行时 profile。
|
||||
- 前端 `normalizeCustomWorldProfileRecord()` 补齐 rs 草稿角色字段兼容:
|
||||
- `publicMask/publicIdentity` -> `description/visualDescription/personality` fallback
|
||||
- `currentPressure/hiddenHook` -> `backstory/actionDescription/sceneVisualDescription` fallback
|
||||
- `relationToPlayer` -> `motivation/relationshipHooks` fallback
|
||||
- `imageSrc/generatedVisualAssetId/generatedAnimationSetId/animationMap` 保持直通
|
||||
|
||||
## 后续约束
|
||||
|
||||
- 新 RPG 运行时链路只允许读取 `draftProfile`。
|
||||
- 不再为进入游戏构造额外 legacy profile,也不再把 `resultPreview.preview` 当作运行时真相源。
|
||||
- 如果草稿中新增角色、场景、物品字段,应优先扩展 `draftProfile` 的归一化读取,而不是增加中间转换结构。
|
||||
@@ -0,0 +1,369 @@
|
||||
# 当前工程优化点盘点(2026-04-20)
|
||||
|
||||
更新时间:`2026-04-20`
|
||||
|
||||
## 0. 盘点目标
|
||||
|
||||
这份文档用于回答一个更直接的问题:
|
||||
|
||||
**基于当前仓库状态,接下来最值得投入工程时间的优化点是什么。**
|
||||
|
||||
本轮只做文档盘点,不直接修改业务代码;结论同时参考了当前工作区现状。
|
||||
需要注意,仓库当前存在一批未提交改动,尤其集中在 `custom world`、`assets`、`platform shell` 相关模块,所以本文更强调“优先级与切入方式”,而不是要求做大范围整仓改写。
|
||||
|
||||
---
|
||||
|
||||
## 1. 当前快照
|
||||
|
||||
## 1.1 本轮复核方式
|
||||
|
||||
本轮主要复核了以下内容:
|
||||
|
||||
1. 现有工程优化审计文档与目录索引
|
||||
2. `package.json`、`vite.config.ts`、`.eslintrc.cjs` 等门禁脚本
|
||||
3. 当前前端、后端、脚本目录的大文件热点
|
||||
4. 运行时、鉴权、自定义世界、资产链路的边界实现
|
||||
5. 当前 `typecheck / lint / build` 状态
|
||||
|
||||
---
|
||||
|
||||
## 1.2 当前门禁结果
|
||||
|
||||
| 项目 | 结果 | 当前判断 |
|
||||
| --- | --- | --- |
|
||||
| `npm run typecheck` | 失败 | 当前第一优先级问题,类型基线已失真 |
|
||||
| `npm run lint:eslint` | 失败 | `136` 个 error、`4` 个 warning,且 `95` 个可自动修复 |
|
||||
| `npm run build` | 通过 | 发布链路未红,但体积压力仍明显存在 |
|
||||
|
||||
### 关键说明
|
||||
|
||||
当前状态和 `2026-04-10` 那轮“build warning 直接拦截”的状态不同:
|
||||
|
||||
1. **构建现在可以通过。**
|
||||
2. **真正变成第一阻塞项的是 `typecheck` 与 `lint`。**
|
||||
3. **构建虽然通过,但主包、功能包、CSS 体积依然偏重,说明性能类优化仍然值得做。**
|
||||
|
||||
---
|
||||
|
||||
## 1.3 当前热点文件快照
|
||||
|
||||
本轮按源码目录统计的大文件热点如下:
|
||||
|
||||
| 文件 | 当前行数 | 判断 |
|
||||
| --- | --- | --- |
|
||||
| `src/components/CustomWorldEntityEditorModal.tsx` | `6122` | 当前前端最大热点 |
|
||||
| `server-node/src/app.test.ts` | `3568` | 后端测试聚合度过高 |
|
||||
| `server-node/src/modules/assets/characterAssetRoutes.ts` | `2802` | 资产路由职责过重 |
|
||||
| `src/services/ai.ts` | `2432` | 浏览器侧 AI 编排仍然偏重 |
|
||||
| `server-node/src/modules/story/storyActionRoutes.test.ts` | `2402` | 运行时路由测试聚合度过高 |
|
||||
| `src/data/npcInteractions.ts` | `2274` | NPC 规则数据仍然集中 |
|
||||
| `src/prompts/storyPromptBuilders.ts` | `1728` | prompt 构造成为新的复杂度中心 |
|
||||
| `server-node/src/modules/custom-world/runtimeProfile.ts` | `1623` | custom world runtime 编译热点 |
|
||||
| `src/hooks/story/npcEncounterActions.ts` | `1582` | NPC 行动流仍然偏重 |
|
||||
| `src/components/game-shell/PlatformHomeView.tsx` | `1474` | 平台首页壳层继续膨胀 |
|
||||
| `src/components/game-shell/PreGameSelectionFlow.tsx` | `1418` | 前置选择流程职责过多 |
|
||||
| `src/services/customWorld.ts` | `1383` | 自定义世界服务虽然收缩,但仍偏大 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 结论先行
|
||||
|
||||
当前仓库的优化重点,已经不是“继续清旧 Vite 插件链路”或者“继续讨论前后端是否要分离”。
|
||||
|
||||
更准确地说,当前最值得做的优化点已经收敛成四类:
|
||||
|
||||
1. **先恢复可信的工程基线。**
|
||||
`typecheck` 与 `lint` 当前都是红线,继续扩功能会放大返工成本。
|
||||
2. **拆掉正在持续膨胀的新热点。**
|
||||
热点已经从早期运行时主链,迁移到 `custom world`、`asset routes`、`platform shell`、`prompt builders`。
|
||||
3. **继续把前端退出“运行时真相”和“鉴权真相”。**
|
||||
当前前端仍保留本地快照镜像与自动登录凭证持久化。
|
||||
4. **补一轮入口归档,减少疑似孤岛模块和大测试聚合文件。**
|
||||
这部分不一定最急,但会持续拉低仓库可维护性。
|
||||
|
||||
一句话判断:
|
||||
|
||||
**当前最值得投入的不是横向加功能,而是把质量门禁重新拉绿,再把 custom world / asset / platform 这批新复杂度中心拆开。**
|
||||
|
||||
---
|
||||
|
||||
## 3. 优化点清单
|
||||
|
||||
## 3.1 P0:先恢复类型基线
|
||||
|
||||
这是当前最优先的工程优化点。
|
||||
|
||||
### 证据
|
||||
|
||||
`npm run typecheck` 当前失败,主要问题集中在两类:
|
||||
|
||||
1. `CustomWorldCampScene` 结构漂移
|
||||
- `src/components/CustomWorldEntityEditorModal.test.tsx`
|
||||
- `src/data/customWorldLibrary.ts`
|
||||
- `src/services/customWorld.ts`
|
||||
- `src/services/customWorldCamp.ts`
|
||||
2. 局部实现与类型定义不同步
|
||||
- `src/components/auth/AccountModal.test.tsx` 的测试数据缺少新增字段
|
||||
- `src/components/game-canvas/GameCanvasShared.tsx` 引用了未定义的 `DEFAULT_IMAGE_STYLE`
|
||||
|
||||
### 影响
|
||||
|
||||
1. 类型系统已经不能提供可信回归信号。
|
||||
2. 自定义世界链路当前正在迭代,如果继续在红线状态叠加修改,后续会反复出现“改 A 崩 B”的情况。
|
||||
3. 测试 fixture 与正式类型脱节,会让测试文件逐渐失去文档价值。
|
||||
|
||||
### 建议
|
||||
|
||||
1. 先补一个统一的 `CustomWorldCampScene` 构造/归一化入口,禁止在多个文件里手写不完整字面量。
|
||||
2. 把 `auth`、`custom world` 的测试 fixture 改成工厂函数,避免字段新增后多处漏改。
|
||||
3. 单独清掉 `GameCanvasShared.tsx` 这类“编译即失败”的确定性问题,优先恢复 `typecheck` 绿色基线。
|
||||
|
||||
---
|
||||
|
||||
## 3.2 P0:恢复 lint 可信度,区分机械问题和真实问题
|
||||
|
||||
这项和类型基线同级。
|
||||
|
||||
### 证据
|
||||
|
||||
`npm run lint:eslint` 当前结果是:
|
||||
|
||||
- `136` 个 error
|
||||
- `4` 个 warning
|
||||
- 其中 `95` 个问题可自动修复
|
||||
|
||||
当前 lint 问题明显分成两层:
|
||||
|
||||
1. 机械问题
|
||||
- import 排序
|
||||
- export 排序
|
||||
- 未使用导入
|
||||
2. 真实问题
|
||||
- `server-node/src/modules/inventory/inventoryStoryActionService.ts` 出现 React Hook 规则错误
|
||||
- `server-node/src/migrate.ts` 仍触发 `no-console`
|
||||
- `packages/shared/src/http.ts` 触发 `@typescript-eslint/ban-types`
|
||||
- 若干文件存在真正未使用变量、转义和规则误配问题
|
||||
|
||||
### 影响
|
||||
|
||||
1. 当前 lint 信号噪音仍然较高,不利于 review。
|
||||
2. 真实问题会被大量机械问题掩盖。
|
||||
3. 团队会更倾向于跳过 lint,而不是信任 lint。
|
||||
|
||||
### 建议
|
||||
|
||||
1. 先跑一轮仅机械修复的清理批次,优先吃掉 import sort、unused imports 这类低风险项。
|
||||
2. 再单独处理 Hook 误用、共享契约类型、脚本规则豁免这类语义问题。
|
||||
3. 之后把“自动可修复问题”与“必须人工处理的问题”拆成两个门禁视角,减少下次再次堆积。
|
||||
|
||||
---
|
||||
|
||||
## 3.3 P1:拆 custom world / asset / platform 新热点
|
||||
|
||||
这是当前最有性价比的结构性优化点。
|
||||
|
||||
### 证据
|
||||
|
||||
当前复杂度最高的业务热点,已经集中在这些模块:
|
||||
|
||||
1. `src/components/CustomWorldEntityEditorModal.tsx`
|
||||
2. `server-node/src/modules/assets/characterAssetRoutes.ts`
|
||||
3. `src/services/ai.ts`
|
||||
4. `src/prompts/storyPromptBuilders.ts`
|
||||
5. `server-node/src/modules/custom-world/runtimeProfile.ts`
|
||||
6. `src/components/game-shell/PlatformHomeView.tsx`
|
||||
7. `src/components/game-shell/PreGameSelectionFlow.tsx`
|
||||
8. `src/hooks/story/npcEncounterActions.ts`
|
||||
|
||||
### 问题本质
|
||||
|
||||
这些文件并不是单纯“代码多”,而是同时承载了多类职责:
|
||||
|
||||
1. UI 状态
|
||||
2. 领域规则
|
||||
3. 请求编排
|
||||
4. 文本构造
|
||||
5. 运行时映射
|
||||
6. 面板切换与流程控制
|
||||
|
||||
### 建议
|
||||
|
||||
1. `CustomWorldEntityEditorModal.tsx`
|
||||
- 先按“实体列表/表单区/资源区/高级设置/预览区”拆组件
|
||||
- 再把数据准备与提交编排抽成 hook
|
||||
2. `characterAssetRoutes.ts`
|
||||
- 拆成 route、prompt payload、job orchestration、产物发布、错误响应五层
|
||||
3. `PlatformHomeView.tsx` 与 `PreGameSelectionFlow.tsx`
|
||||
- 把页面壳层、数据加载、卡片渲染、弹层控制拆开
|
||||
4. `storyPromptBuilders.ts` 与 `runtimeProfile.ts`
|
||||
- 把“模板片段”“上下文归一化”“规则裁剪”“最终拼接”分层
|
||||
|
||||
---
|
||||
|
||||
## 3.4 P1:继续控制构建产物体积
|
||||
|
||||
构建虽通过,但体积已经给出明显信号。
|
||||
|
||||
### 当前证据
|
||||
|
||||
本轮 `npm run build` 输出里,几个值得关注的点是:
|
||||
|
||||
1. `dist/assets/AuthenticatedApp-*.js`:`794.77 kB`
|
||||
2. `dist/assets/index-*.js`:`197.44 kB`
|
||||
3. `dist/assets/CustomWorldResultView-*.js`:`163.38 kB`
|
||||
4. `dist/assets/ai-*.js`:`131.73 kB`
|
||||
5. `dist/assets/PreGameSelectionFlow-*.js`:`96.39 kB`
|
||||
6. `dist/assets/index-*.css`:`201.44 kB`
|
||||
|
||||
### 影响
|
||||
|
||||
1. 虽然还没触发新的 build gate 红线,但首屏、缓存和移动端体验会继续承压。
|
||||
2. `AuthenticatedApp` 主包偏大,说明平台壳层仍然装入了过多首屏不必需能力。
|
||||
3. CSS 体积继续上涨,说明样式正在跨模块相互堆叠。
|
||||
|
||||
### 建议
|
||||
|
||||
1. 继续把 custom world、asset studio、平台详情页、角色资产工具从主壳层路径中抽离。
|
||||
2. 审查 `ai.ts`、`custom world result view`、`pregame selection` 是否还能再延迟加载。
|
||||
3. 对全局样式做一次按模块归属清理,减少公共样式无限增长。
|
||||
|
||||
---
|
||||
|
||||
## 3.5 P1:继续收紧前端与后端边界
|
||||
|
||||
这项已经不是“要不要做”的问题,而是“还剩多少尾巴没收完”。
|
||||
|
||||
### 当前证据
|
||||
|
||||
1. `src/services/apiClient.ts`
|
||||
- 当前仍把 `access token`
|
||||
- 自动登录用户名
|
||||
- 自动登录密码
|
||||
写入 `window.localStorage`
|
||||
2. `src/hooks/story/runtimeStoryCoordinator.ts`
|
||||
- 当前仍会在调用后端运行时前先 `putSaveSnapshot(...)`
|
||||
- 响应后继续 `rehydrateSavedSnapshot(...)`
|
||||
3. `src/hooks/story/npcEncounterActions.ts`
|
||||
- 当前仍从前端动作流触发 `generateQuestForNpcEncounter(...)`
|
||||
- 说明 NPC 任务“换单/重抽”分支尚未完全后端化
|
||||
|
||||
### 影响
|
||||
|
||||
1. 前端仍保留了一部分运行时真相与鉴权真相。
|
||||
2. 自动登录凭证持久化在边界和安全上都不理想。
|
||||
3. 运行时快照前置写入,会让“前端镜像状态”和“后端会话状态”继续纠缠。
|
||||
|
||||
### 建议
|
||||
|
||||
1. 优先移除自动登录用户名/密码本地持久化,收敛到服务端 session / refresh 机制。
|
||||
2. 把运行时快照改为“展示缓存”而不是“提交前真相源”。
|
||||
3. 把 NPC 任务更换动作补齐到后端 runtime/session 边界,不再由前端直接发起生成决策。
|
||||
|
||||
---
|
||||
|
||||
## 3.6 P2:做一次疑似孤岛模块与旧入口归档
|
||||
|
||||
这项不一定最紧急,但现在做会明显降低后续维护噪音。
|
||||
|
||||
### 当前现象
|
||||
|
||||
从当前入口关系看,以下模块值得做一次正式复核:
|
||||
|
||||
1. `src/components/GameShell.tsx`
|
||||
2. `src/components/custom-world-home/CustomWorldCreationHub.tsx`
|
||||
3. `src/components/custom-world-home/CustomWorldCreationLauncherModal.tsx`
|
||||
4. `src/components/custom-world-agent/CustomWorldAgentLauncherModal.tsx`
|
||||
5. `src/components/custom-world-agent/CustomWorldAgentDraftDrawer.tsx`
|
||||
6. `src/hooks/story/storyBootstrap.ts`
|
||||
7. `src/hooks/useEquipmentFlow.ts`
|
||||
8. `src/hooks/useForgeFlow.ts`
|
||||
9. `src/hooks/useInventoryFlow.ts`
|
||||
10. `src/services/typewriter.ts`
|
||||
|
||||
### 当前判断
|
||||
|
||||
这批模块不一定全部是垃圾代码,但至少说明一件事:
|
||||
|
||||
**仓库里仍然存在一批“不是正式入口、也没有清晰归档标签”的过渡实现。**
|
||||
|
||||
### 建议
|
||||
|
||||
把这类模块统一分成三类:
|
||||
|
||||
1. 正式保留并接回入口
|
||||
2. 明确标记为实验稿
|
||||
3. 直接归档或删除
|
||||
|
||||
这样可以减少后续开发时的误判成本。
|
||||
|
||||
---
|
||||
|
||||
## 3.7 P2:拆测试聚合文件,恢复测试的定位能力
|
||||
|
||||
当前测试文件也已经出现“大一统热点”。
|
||||
|
||||
### 证据
|
||||
|
||||
1. `server-node/src/app.test.ts`:`3568` 行
|
||||
2. `server-node/src/modules/story/storyActionRoutes.test.ts`:`2402` 行
|
||||
3. `server-node/src/modules/assets/characterAssetRoutes.test.ts`:`1235` 行
|
||||
4. `src/hooks/story/npcEncounterActions.test.ts`:`1199` 行
|
||||
|
||||
### 影响
|
||||
|
||||
1. 失败定位成本高。
|
||||
2. fixture 复用差,字段一变容易整片测试跟着漂移。
|
||||
3. 测试文件本身开始变成新的维护热点。
|
||||
|
||||
### 建议
|
||||
|
||||
1. 按领域动作拆测试文件,而不是继续堆到单一总测文件中。
|
||||
2. 补 fixture builder / factory,减少字面量散落。
|
||||
3. 对 `runtime / auth / custom world / assets` 这几条链路增加更明确的契约测试分层。
|
||||
|
||||
---
|
||||
|
||||
## 4. 推荐执行顺序
|
||||
|
||||
如果只按工程收益排序,建议按下面的顺序推进:
|
||||
|
||||
1. 先修 `typecheck`
|
||||
2. 再把 `lint` 分成机械修复和语义修复两轮
|
||||
3. 然后拆 `custom world / asset / platform` 热点
|
||||
4. 再继续收前端运行时与鉴权边界
|
||||
5. 最后处理孤岛模块归档和测试拆分
|
||||
|
||||
---
|
||||
|
||||
## 5. 当前不建议优先做的事
|
||||
|
||||
1. 不建议在 `typecheck` 和 `lint` 仍为红线时继续横向扩功能。
|
||||
2. 不建议直接在 `CustomWorldEntityEditorModal.tsx`、`characterAssetRoutes.ts`、`PlatformHomeView.tsx` 里继续堆新逻辑。
|
||||
3. 不建议把 bundle 体积问题简单理解为“先放宽阈值”,当前更适合继续拆职责和延迟加载。
|
||||
4. 不建议在未确认入口关系前随手删除可疑旧模块,先做归档分类更稳。
|
||||
|
||||
---
|
||||
|
||||
## 6. 本文依据
|
||||
|
||||
文档依据:
|
||||
|
||||
1. `docs/audits/engineering/README.md`
|
||||
2. `docs/technical/CURRENT_BACKEND_IMPLEMENTATION_BASELINE_2026-04-25.md`
|
||||
3. `docs/audits/engineering/ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-20.md`
|
||||
4. `docs/experience/PROJECT_WORK_EXPERIENCE_PLAYBOOK.md`
|
||||
|
||||
当前仓库复核依据:
|
||||
|
||||
1. `package.json`
|
||||
2. `.eslintrc.cjs`
|
||||
3. `vite.config.ts`
|
||||
4. `scripts/build-gate.mjs`
|
||||
5. `src/App.tsx`
|
||||
6. `src/services/apiClient.ts`
|
||||
7. `src/hooks/story/runtimeStoryCoordinator.ts`
|
||||
8. `src/hooks/story/npcEncounterActions.ts`
|
||||
9. 当前源码大文件体量扫描结果
|
||||
10. `npm run typecheck`
|
||||
11. `npm run lint:eslint`
|
||||
12. `npm run build`
|
||||
@@ -0,0 +1,606 @@
|
||||
# 工程清理与后端边界审计(2026-04-19)
|
||||
|
||||
更新时间:`2026-04-20`
|
||||
|
||||
## 0.1 执行回填(2026-04-19)
|
||||
|
||||
本文审计项 `3.2` 与 `4.4` 已于 `2026-04-19` 当日完成首轮处置:
|
||||
|
||||
1. 已删除 `scripts/dev-server/localApiPlugins.ts`
|
||||
2. 已删除 `scripts/dev-server/characterAssetStudioPlugins.ts`
|
||||
3. 已删除 `scripts/dev-server/qwenSpriteSheetToolPlugins.ts`
|
||||
4. `scripts/dev-server/` 目录仅保留迁移说明,不再保留旧 Vite 本地 API 实现代码
|
||||
5. 当前正式入口统一为 `scripts/dev-node.mjs + vite proxy + server-node/src/modules/**`
|
||||
|
||||
本文其余段落保留为本次审计时的原始问题快照,用于解释为什么要做这轮删除。
|
||||
|
||||
## 0.2 执行回填(2026-04-19,仓库噪音产物)
|
||||
|
||||
本文审计项 `3.1` 已于 `2026-04-19` 当日完成首轮处置:
|
||||
|
||||
1. 已从版本库删除以下根目录历史扫描/截图产物:
|
||||
- `npc-editor-dom.html`
|
||||
- `npc-editor-shot.png`
|
||||
- `temp-write-check.txt`
|
||||
- `tmp_character_presets_scan.txt`
|
||||
- `tmp_jsx_text_scan.txt`
|
||||
- `tmp_runtime_text_scan.txt`
|
||||
- `tmp_text_candidates.txt`
|
||||
- `tmp_text_candidates_refined.txt`
|
||||
- `tmp_visible_props_scan.txt`
|
||||
- `tmp_volc_seedance_doc.html`
|
||||
2. 已从版本库删除 `scripts/__pycache__/generate-build-tag-similarity.cpython-313.pyc`。
|
||||
3. 已清理本地工作区中的 `.codex-*.log`、`.preview.*`、`npc-editor-console.log` 与 `temp-build-goal-check/`,清理前对应体量约为:
|
||||
- 根目录噪音文件 `60` 个,约 `49.94 MB`
|
||||
- `temp-build-goal-check/` 共 `15620` 个条目,约 `158.85 MB`
|
||||
4. 已补齐 `.gitignore`、`.prettierignore` 与 `.eslintrc.cjs` 的忽略口径,显式覆盖 `tmp_*`、`tmp/`、`npc-editor-*`、`temp-write-check.txt`、`temp-build-goal-check/`、`__pycache__/`。
|
||||
5. `scripts/dev-server/localApiPlugins.ts` 之外的后端边界收口项不在本轮噪音清理范围内,后续继续按本文第二至第四阶段推进。
|
||||
|
||||
## 0.3 执行回填(2026-04-19,运行时边界第一轮收口)
|
||||
|
||||
本文审计项 `4.1` 与 `5.1` 已于 `2026-04-19` 当日完成一轮工程收口:
|
||||
|
||||
1. `RuntimeStoryOptionView` 现在由后端直接附带 `interaction` 元数据。
|
||||
2. `server-node/src/modules/story/runtimeSession.ts` 已成为 runtime option interaction 的唯一构建位置。
|
||||
3. `src/services/runtimeStoryService.ts` 不再根据 `currentEncounter + functionId` 在前端本地重建一份 interaction 映射。
|
||||
4. `/api/custom-world/scene-image` 已补齐服务端 prompt 兜底组装能力,允许前端只提交 `profile + landmark + userPrompt` 上下文。
|
||||
5. `src/services/aiService.ts` 的场景图 SDK 已改为直接调用后端接口,不再为了该链路动态加载 `src/services/ai.ts`。
|
||||
|
||||
## 0.4 执行回填(2026-04-19,自定义世界后端边界第二轮收口)
|
||||
|
||||
本文审计项 `5.2` 与“第三阶段第 4 条:清理 `server-node -> src/**` 的反向依赖”已于 `2026-04-19` 当日完成第二轮工程收口:
|
||||
|
||||
1. `server-node/src/modules/custom-world/` 已新增服务端自持 runtime 模块,承接:
|
||||
- `creator intent` 归一化
|
||||
- `anchorPack / lockState` 推导
|
||||
- custom world framework/profile compile 与 normalize
|
||||
2. `server-node/src/modules/ai/customWorldOrchestrator.ts` 与 `server-node/src/services/customWorldAgentFoundationDraftService.ts` 已不再运行时依赖:
|
||||
- `src/services/customWorld.js`
|
||||
- `src/services/customWorldBuilder.js`
|
||||
- `src/services/customWorldCreatorIntent.js`
|
||||
- `src/types.js`
|
||||
3. `server-node/src/prompts/customWorldPrompts.ts` 已成为后端自持的 custom world prompt source,`scene image` 与 `foundation draft` 相关 builder 不再从前端 `src/prompts/customWorldPrompts.ts` 反向 import。
|
||||
4. 本轮只迁移 prompt source 位置,没有改动任何 custom world 提示词正文,也没有改动功能需求。
|
||||
|
||||
## 0.5 执行回填(2026-04-20,NPC 待接委托正式接取收口)
|
||||
|
||||
本文审计项 `5.3` 已于 `2026-04-20` 完成一轮补充收口:
|
||||
|
||||
1. `src/hooks/story/npcEncounterActions.ts` 中“聊天里的待接委托正式接取”已不再由前端本地直接写入:
|
||||
- `quests`
|
||||
- `runtimeStats.questsAccepted`
|
||||
- `npcChatState.pendingQuestOffer`
|
||||
2. `server-node/src/modules/quest/questStoryActionService.ts` 现在会优先读取服务端快照里已保存的 `pendingQuestOffer.quest`,按当前聊天态中已经展示给玩家的那份委托完成正式接取。
|
||||
3. `server-node/src/modules/story/storyActionService.ts` 已补齐待接委托接取后的聊天态投影:
|
||||
- 保留 NPC 对话展示模式
|
||||
- 清空 `pendingQuestOffer`
|
||||
- 回到既有的三条自由追问建议
|
||||
4. 本轮没有新增任何 runtime functionId,也没有改动任务生成提示词或任务需求,只是把既有“接任务”正式结算权收回到后端。
|
||||
|
||||
## 0.6 执行回填(2026-04-20,NPC 聊天任务草案与浏览器 LLM fallback 收口)
|
||||
|
||||
本文审计项 `5.1` 与 `5.3` 已于 `2026-04-20` 完成一轮补充收口:
|
||||
|
||||
1. `server-node/src/modules/ai/chatOrchestrator.ts` 现在会基于 `NPC chat turn` 的运行时上下文,在后端判断是否触发 `pendingQuestOffer`,并把 quest draft 与引导文案一并回填给前端。
|
||||
2. `src/hooks/story/npcEncounterActions.ts` 不再在 NPC 单轮聊天完成后本地调用 `generateQuestForNpcEncounter(...)` 再决定是否挂出待接委托。
|
||||
3. `src/services/questDirector.ts` 浏览器端在后端失败时不再退回本地 LLM 生成 quest draft,而是直接走 deterministic fallback compile。
|
||||
4. `src/services/runtimeItemAiDirector.ts` 浏览器端在后端失败时不再退回本地 LLM 生成 runtime item intent,而是直接返回 deterministic fallback intents。
|
||||
5. 本轮仍未改动任何业务提示词正文,也没有改动 quest / runtime item 的需求能力面,只是继续清理浏览器里的正式 AI orchestration 残留。
|
||||
|
||||
## 0. 审计目标
|
||||
|
||||
本次审计只回答四类问题:
|
||||
|
||||
1. 项目里哪些内容已经是高置信度的垃圾、临时产物或无入口代码。
|
||||
2. 哪些实现属于双份真相、重复映射或旧链路残留。
|
||||
3. 哪些前端代码仍然承担了应迁移到 Express 后端的职责。
|
||||
4. 哪些文件已经大到会持续拖累迭代效率,需要优先拆分。
|
||||
|
||||
---
|
||||
|
||||
## 1. 结论先行
|
||||
|
||||
当前仓库的主要问题不是“有一些小工具没人用”,而是四类结构性噪音同时存在:
|
||||
|
||||
1. **仓库噪音产物仍然很多。**
|
||||
根目录残留了大量 `.codex-*.log`、`tmp_*`、旧截图/HTML,以及 `temp-build-goal-check/` 这类大体量检查产物,已经不是单个文件层面的脏数据,而是在持续污染工程视野。
|
||||
2. **旧入口和新入口并存,形成了明显的冗余链路。**
|
||||
`scripts/dev-server/localApiPlugins.ts` 已经退出当前正式开发入口,但仍保留了 LLM proxy、JSON 写盘、资产发布等整套旧 Vite 本地 API 机制。
|
||||
3. **前端仍然承载了过多运行时规则与 AI 编排。**
|
||||
`src/services/ai.ts`、`src/services/customWorld.ts`、`src/hooks/story/npcEncounterActions.ts` 这类文件,仍在浏览器里承担 prompt 组装、规则判定、奖励结算、剧情推进等职责。
|
||||
4. **后端边界还没有真正闭合。**
|
||||
`server-node` 虽然已经承接了大量路由和运行时动作,但仍直接 import `src/services/customWorld*.ts` 和 `src/types.ts`,说明后端领域层还没有完全从前端目录中独立出来。
|
||||
|
||||
一句话判断:
|
||||
|
||||
**这轮优先级不该再是继续堆功能,而是先清仓库噪音与无入口孤岛,再把前后端双份真相收口,最后拆新的巨型热点文件。**
|
||||
|
||||
---
|
||||
|
||||
## 2. 本次审计方法与口径
|
||||
|
||||
### 2.1 方法
|
||||
|
||||
本次审计结合了四类证据:
|
||||
|
||||
1. 文档基线:
|
||||
- `docs/audits/engineering/README.md`
|
||||
- `docs/technical/CURRENT_BACKEND_IMPLEMENTATION_BASELINE_2026-04-25.md`
|
||||
- `scripts/dev-server/README.md`
|
||||
2. 当前入口核对:
|
||||
- `src/main.tsx`
|
||||
- `src/routing/appRoutes.tsx`
|
||||
- `src/App.tsx`
|
||||
- `package.json`
|
||||
- `server-node/package.json`
|
||||
3. 静态依赖扫描:
|
||||
- 对 `src/`、`server-node/src/`、`packages/shared/src/`、`scripts/` 共 `650` 个 TS/JS 文件做本地依赖图扫描。
|
||||
4. 定向 grep:
|
||||
- 核对旧 dev 插件入口、后端跨层 import、localStorage 使用、运行时快照双写、重复映射代码。
|
||||
|
||||
### 2.2 口径说明
|
||||
|
||||
为避免误判,本次审计明确排除了两类对象:
|
||||
|
||||
1. **包脚本入口**:例如 `scripts/build-gate.mjs`、`scripts/check-encoding.mjs`、`server-node/build.mjs` 这类由 `package.json` 直接执行的脚本,不因“无 import”而判为垃圾。
|
||||
2. **字符串路径消费的资源**:例如 `src/data/itemOverrides.json`、`src/data/monsterOverrides.json` 会被校验脚本和 editor route 以文件路径读取,不按“无 import”处理。
|
||||
|
||||
另外,当前工作区存在未提交改动,因此本次结论以**已纳入当前主链且能确认未接线/重复/越界的内容**为主,不把明显的当日 WIP 文件计入垃圾结论。
|
||||
|
||||
---
|
||||
|
||||
## 3. 高置信度垃圾、临时产物与无入口代码
|
||||
|
||||
## 3.1 仓库噪音产物已经到了需要集中清理的程度
|
||||
|
||||
### 证据
|
||||
|
||||
| 项目 | 当前证据 | 判断 |
|
||||
| ------------------------ | ------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- |
|
||||
| 根目录日志/临时文件 | 根目录命中 `60` 个 `.codex-*.log`、`.preview.*`、`tmp_*`、`npc-editor-*`、`temp-write-check.txt`,合计约 `52.36 MB` | 已经不是偶发临时文件,而是长期堆积的开发残留 |
|
||||
| `temp-build-goal-check/` | 当前包含 `15099` 个文件,合计约 `166.56 MB` | 大体量检查产物,应该移出主工程视野 |
|
||||
| Python 缓存 | 当前存在 `scripts/__pycache__/` | 纯缓存产物,不应长期留在仓库工作区中 |
|
||||
|
||||
### 影响
|
||||
|
||||
1. 根目录信噪比明显下降,真实工程文件被大量一次性产物淹没。
|
||||
2. `temp-build-goal-check/` 虽然已被 `.gitignore` 和 `vite.config.ts` 的 watch 忽略模式覆盖,但 `.eslintrc.cjs` 的 `ignorePatterns` 里没有对应口径,仍存在工具口径不一致问题。
|
||||
3. 这类目录会持续干扰检索、review、lint 判断和本地扫描速度。
|
||||
|
||||
### 建议
|
||||
|
||||
1. 把根目录临时日志、扫描 txt/html、旧截图统一迁到单独的 `tmp/` 或本地缓存目录,默认不留在仓库根目录。
|
||||
2. 把 `temp-build-goal-check/` 改成真正的外置检查产物目录,或者在 lint/脚本口径上一起排除。
|
||||
3. 清理 `scripts/__pycache__/`,并统一补上 Python 缓存忽略规则。
|
||||
|
||||
---
|
||||
|
||||
## 3.2 旧 Vite 本地 API 插件链已经退出主入口,但仍保留整套旧实现
|
||||
|
||||
### 证据
|
||||
|
||||
1. `scripts/dev-server/README.md` 已明确写明:`scripts/dev-server/**` 不再是当前开发入口,只保留为迁移参考。
|
||||
2. `scripts/dev-server/localApiPlugins.ts` 当前仍有 `1664` 行。
|
||||
3. 仓库内已经找不到 `localApiPlugins` 的实际代码入口引用,当前只剩文档引用。
|
||||
4. 该文件内部仍然同时定义和拼装:
|
||||
- `createLlmProxyPlugin`
|
||||
- `createJsonFileEditorPlugin`
|
||||
- `createCustomWorldSceneImagePlugin`
|
||||
- `createCharacterVisualPublishPlugin`
|
||||
- `createCharacterAnimationPublishPlugin`
|
||||
- `createCharacterAssetStudioPlugins`
|
||||
- `createQwenSpriteSheetToolPlugins`
|
||||
|
||||
### 判断
|
||||
|
||||
这不是“一个小工具暂时没用”,而是**整条旧 editor/assets 本地 API 链路仍然完整保留在仓库里**。它在工程上已经属于高置信度的历史残留。
|
||||
|
||||
### 建议
|
||||
|
||||
1. 如果只保留迁移证据,建议把 `scripts/dev-server/localApiPlugins.ts` 和相关说明迁到 `docs/reference/` 或单独的 `archive/` 目录。
|
||||
2. 如果确实还要保留参考代码,至少要在文件顶部加更强的“只读参考、禁止继续扩展”标识,并从主工程扫描面上进一步隔离。
|
||||
3. 不建议继续在这条旧链路里新增任何 `/api/*` 能力。
|
||||
|
||||
---
|
||||
|
||||
## 3.3 当前存在一批“无运行时入口”或“仅测试引用”的孤岛模块
|
||||
|
||||
### 高置信度无入口/仅测试引用清单
|
||||
|
||||
| 模块 | 证据 | 判断 |
|
||||
| --------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
|
||||
| `src/components/GameShell.tsx` | 文件体量 `761` 行;当前 `src/App.tsx` 只接入 `components/game-shell/GameShellRuntime.tsx`;仓库内无其它 import | 旧版壳层残留 |
|
||||
| `src/components/custom-world-home/CustomWorldCreationHub.tsx` | 仅被 `CustomWorldCreationHub.test.tsx` 和 `CustomWorldCreationHub.interaction.test.tsx` 引用;`src/routing/appRoutes.tsx` 只有 `game` 和 `qwen-sprite-tool` 两条路由 | 已做出 UI,但未进入正式入口 |
|
||||
| `src/components/custom-world-home/CustomWorldCreationLauncherModal.tsx` | 当前无运行时引用 | 同属未接线入口壳层 |
|
||||
| `src/components/custom-world-agent/*` 中 `9` 个子模块 | 当前合计约 `826` 行;典型文件包括 `CustomWorldAgentLauncherModal.tsx`、`CustomWorldAgentDraftDrawer.tsx`、`CustomWorldAgentLockBar.tsx`、`CustomWorldAgentQuickActions.tsx`、`CustomWorldAgentSummaryPanel.tsx`;部分文件完全无引用,部分仅被测试引用 | 处于“做了一部分 UI,但未进入主链”的孤岛状态 |
|
||||
| `src/hooks/story/storyBootstrap.ts` | `250` 行,仓库内只定义不消费 | 已被新流程替代的可能性高 |
|
||||
| `src/hooks/useEquipmentFlow.ts` / `useForgeFlow.ts` / `useInventoryFlow.ts` | 合计约 `393` 行,当前无运行时引用 | 旧流转层残留 |
|
||||
| `src/editor/shared/cloneValue.ts` / `EditorEmptyState.tsx` / `EditorSelectionCard.tsx` / `useJsonSave.ts` | 当前无运行时引用 | editor 旧共享层碎片 |
|
||||
| `src/services/customWorldPresentation.stub.ts` | 当前无引用,且文件本身就是 stub | 高置信度占位残留 |
|
||||
| `src/services/typewriter.ts` | 当前无引用,仅提供一个 `getTypewriterDelay` | 已被其它链路内联实现替代 |
|
||||
| `src/data/buildTagSimilarity.generated.ts` | 当前 `823` 行,仅能被生成脚本自身检索到,没有消费方 | 生成产物未接入任何业务链路 |
|
||||
| `src/data/customWorldCharacterLoadout.stub.ts` | 当前无引用,且实现只返回空数组 | 占位残留 |
|
||||
| `src/components/DeveloperTeamModal.tsx` / `src/components/LazySkillEffectPreview.tsx` | 当前无运行时引用 | 小体量零散孤岛 |
|
||||
|
||||
### 判断
|
||||
|
||||
这批文件不一定都应该“立刻删除”,但它们已经满足两个至少其一:
|
||||
|
||||
1. 当前正式入口完全不消费。
|
||||
2. 只剩测试在消费,本体没有真实运行时位置。
|
||||
|
||||
所以它们至少都应该进入以下三选一处理:
|
||||
|
||||
1. 立即归档/删除。
|
||||
2. 明确接回正式入口。
|
||||
3. 改名或迁目录,标明“实验稿/参考稿/未接线”身份。
|
||||
|
||||
### 特别提醒
|
||||
|
||||
`src/components/custom-world-home/` 和 `src/components/custom-world-agent/` 这两组文件里,存在**已经有一定 UI 完成度、但没有进入真实路由/流程**的情况。
|
||||
这类文件最危险的点不是体量,而是会让后来者误以为“这块功能已经在主链上”。
|
||||
|
||||
---
|
||||
|
||||
## 4. 冗余实现与双份真相
|
||||
|
||||
## 4.1 Story option interaction 映射在前后端各维护了一份
|
||||
|
||||
### 证据
|
||||
|
||||
1. 前端 `src/services/runtimeStoryService.ts` 的 `buildRuntimeOptionInteraction` 维护了 `npcActionMap`、`treasureActionMap`。
|
||||
2. 后端 `server-node/src/modules/story/storyActionService.ts` 的 `buildStoryOptionInteraction` 维护了几乎同构的一份 `npcActionMap`、`treasureActionMap`。
|
||||
|
||||
### 风险
|
||||
|
||||
1. 任何一个 functionId 增删改,前后端都要同步。
|
||||
2. 一边先改、一边漏改时,表现层和运行时层会出现静默漂移。
|
||||
|
||||
### 建议
|
||||
|
||||
把 interaction/view model 映射收口到后端,前端只消费后端返回的结构,不再根据 `functionId` 本地重建一遍交互语义。
|
||||
|
||||
---
|
||||
|
||||
## 4.2 浏览历史已经有后端接口,但前端仍维护本地真相与迁移状态
|
||||
|
||||
### 证据
|
||||
|
||||
1. `src/components/game-shell/PreGameSelectionFlow.tsx` 中,`appendBrowseHistoryEntry` 先调用 `writePlatformBrowseHistory` 写本地,再调用 `upsertProfileBrowseHistory` 写后端。
|
||||
2. 同文件启动阶段又会先读 `readPlatformBrowseHistory`,再根据 `hasPendingPlatformBrowseHistoryMigration` 把本地历史同步回后端。
|
||||
3. 后端 `server-node/src/routes/runtimeRoutes.ts` 已经提供了 `/profile/browse-history` 路由,而前端 `src/services/storageService.ts` 也已有对应 API SDK。
|
||||
|
||||
### 判断
|
||||
|
||||
当前浏览历史并不是单纯的“本地缓存”,而是**本地存储 + 远端持久化 + 迁移标记**三套状态并存。
|
||||
|
||||
### 建议
|
||||
|
||||
1. 后端结果作为唯一真相源。
|
||||
2. 前端如果要保留缓存,只保留一个明确的 cache wrapper,不再把它做成独立状态系统。
|
||||
3. `markPlatformBrowseHistoryMigrated` 这种迁移标记应尽量在后端一次性收口,而不是长期停留在正式前端逻辑里。
|
||||
|
||||
---
|
||||
|
||||
## 4.3 运行时快照依然由前端先落本地,再与后端会话互相回填
|
||||
|
||||
### 证据
|
||||
|
||||
1. `src/hooks/story/runtimeStoryCoordinator.ts` 在读状态和提交 action 前都会先调用 `putSaveSnapshot`。
|
||||
2. 同文件以及 `src/services/runtimeStoryService.ts` 又会在响应后多次 `rehydrateSavedSnapshot`。
|
||||
3. 这意味着浏览器仍然在“后端 action 之前”先写一份自己的快照解释。
|
||||
|
||||
### 判断
|
||||
|
||||
这条链路说明当前运行时还处在**前端快照解释权没有完全退出**的过渡状态。
|
||||
|
||||
### 建议
|
||||
|
||||
1. 前端逐步退化为 view model 消费层。
|
||||
2. 运行时快照、版本迁移、恢复解释权继续往后端收口。
|
||||
3. 前端保留最小必要的离线展示缓存,但不再成为正式运行时状态真相来源。
|
||||
|
||||
---
|
||||
|
||||
## 4.4 旧 Vite 本地 API 与正式 Express 路由仍然形成重复能力面
|
||||
|
||||
### 证据
|
||||
|
||||
1. `scripts/dev-server/localApiPlugins.ts` 里仍有 JSON 编辑、场景图生成、角色视觉发布、角色动作发布等插件。
|
||||
2. 当前正式路径已经迁到:
|
||||
- `server-node/src/modules/editor/**`
|
||||
- `server-node/src/modules/assets/**`
|
||||
3. `scripts/dev-server/README.md` 已明确说明旧链路只保留为迁移参考。
|
||||
|
||||
### 判断
|
||||
|
||||
这属于典型的**旧能力未删除,新能力已落地,双链路长期并存**。
|
||||
|
||||
### 建议
|
||||
|
||||
尽快把旧 Vite 本地 API 参考实现移出主工程扫描面,避免后续继续被误用或被误认为正式入口。
|
||||
|
||||
---
|
||||
|
||||
## 5. 需要迁移到后端的代码
|
||||
|
||||
## 5.1 `src/services/ai.ts` 仍然承担了过多正式运行时职责
|
||||
|
||||
### 当前职责
|
||||
|
||||
`src/services/ai.ts` 当前约 `2632` 行,仍然同时承担:
|
||||
|
||||
1. function 可用性与 option 构造相关逻辑。
|
||||
2. NPC 对话 / 招募 prompt 构造。
|
||||
3. 自定义世界生成 prompt 与 JSON 修复请求。
|
||||
4. 直接调用 `requestPlainTextCompletion` / `streamPlainTextCompletion`。
|
||||
5. 浏览器内 fallback 与响应解析。
|
||||
|
||||
### 判断
|
||||
|
||||
这不是单纯的“前端请求 SDK”,而是**前端仍在承担正式运行时 AI orchestration**。
|
||||
|
||||
### 建议迁移方向
|
||||
|
||||
1. prompt 组装、模型调用、超时重试、JSON repair 继续收口到 `server-node/src/modules/ai/**`。
|
||||
2. 前端只保留轻量 SDK 和展示态拼装。
|
||||
3. fallback 如果必须保留,也应明确区分“开发兜底”与“正式运行时”。
|
||||
|
||||
---
|
||||
|
||||
## 5.2 `src/services/customWorld.ts` 仍然是前端侧的大型规则中心
|
||||
|
||||
### 当前职责
|
||||
|
||||
`src/services/customWorld.ts` 当前约 `2413` 行,仍然承担:
|
||||
|
||||
1. 世界框架与角色/地标 outline 归一化。
|
||||
2. 世界属性 schema 生成。
|
||||
3. `ownedSettingLayers` 归一化。
|
||||
4. 最终世界 profile 校验。
|
||||
5. fallback story graph/theme pack 生成。
|
||||
|
||||
### 当前越界证据
|
||||
|
||||
后端目前直接从以下文件 import 这些能力:
|
||||
|
||||
1. `server-node/src/modules/ai/customWorldOrchestrator.ts`
|
||||
2. `server-node/src/services/customWorldAgentFoundationDraftService.ts`
|
||||
|
||||
它们仍直接引用:
|
||||
|
||||
1. `src/services/customWorld.js`
|
||||
2. `src/services/customWorldBuilder.js`
|
||||
3. `src/services/customWorldCreatorIntent.js`
|
||||
4. `src/types.js`
|
||||
|
||||
### 判断
|
||||
|
||||
这说明自定义世界的核心领域规则仍然以**前端目录为事实源**,后端只是在反向复用。
|
||||
|
||||
### 建议迁移方向
|
||||
|
||||
1. `types/schema/contracts` 抽到 `packages/shared`。
|
||||
2. 规则编译、校验、fallback 与 AI 编排迁到 `server-node`。
|
||||
3. 前端只保留编辑器表现层和字段草稿态。
|
||||
|
||||
---
|
||||
|
||||
## 5.3 `src/hooks/story/npcEncounterActions.ts` 仍在浏览器里做任务、奖励、战斗与招募结算
|
||||
|
||||
### 当前职责
|
||||
|
||||
`src/hooks/story/npcEncounterActions.ts` 当前约 `1623` 行,仍然直接编排:
|
||||
|
||||
1. `quest_accept` / `quest_turn_in`
|
||||
2. 招募、切磋、离开、帮助奖励
|
||||
3. 掉落/背包写入
|
||||
4. HP / MP / cooldown 奖励变化
|
||||
5. NPC 亲和度变化
|
||||
6. 战斗场景切换与遭遇状态推进
|
||||
|
||||
### 判断
|
||||
|
||||
这条链已经明显超出“前端表现协调层”的边界,仍属于**正式运行时规则在前端执行**。
|
||||
|
||||
### 建议迁移方向
|
||||
|
||||
1. quest 信号推进 -> `server-node/src/modules/quest/**`
|
||||
2. 奖励与背包变更 -> `server-node/src/modules/inventory/**`
|
||||
3. 招募/关系变化 -> `server-node/src/modules/npc/**`
|
||||
4. 战斗结算 -> `server-node/src/modules/combat/**`
|
||||
|
||||
前端应该只保留选项触发、加载态、动画态和最终结果展示。
|
||||
|
||||
---
|
||||
|
||||
## 5.4 `src/services/apiClient.ts` 仍保留了本地 token 与自动登录凭证存储
|
||||
|
||||
### 证据
|
||||
|
||||
`src/services/apiClient.ts` 当前仍把以下内容放在 `window.localStorage`:
|
||||
|
||||
1. access token
|
||||
2. 自动登录用户名
|
||||
3. 自动登录密码
|
||||
|
||||
### 判断
|
||||
|
||||
这既是安全面问题,也是边界问题。
|
||||
在“后端负责鉴权、前端只做表现”的目标下,正式凭证体系不应长期依赖浏览器本地保存账号密码。
|
||||
|
||||
### 建议迁移方向
|
||||
|
||||
1. 正式态优先走服务端 session / HttpOnly cookie。
|
||||
2. 自动登录不要继续保存明文用户名/密码。
|
||||
3. 前端仅保留最小必要的登录态感知,不保留额外认证真相。
|
||||
|
||||
---
|
||||
|
||||
## 6. 需要优先优化和拆分的代码
|
||||
|
||||
## 6.1 `src/components/CustomWorldEntityEditorModal.tsx`
|
||||
|
||||
### 当前状态
|
||||
|
||||
文件体量约 `4487` 行,已同时吞下:
|
||||
|
||||
1. 世界营地编辑
|
||||
2. playable NPC 编辑
|
||||
3. story NPC 编辑
|
||||
4. 地标与世界地图布局
|
||||
5. 场景图生成
|
||||
6. 技能编辑
|
||||
7. 初始物品编辑
|
||||
8. 资产工作台串联
|
||||
9. 多层 modal 开关与保存逻辑
|
||||
|
||||
### 判断
|
||||
|
||||
这是当前前端最明显的“巨型工作台单体文件”。
|
||||
|
||||
### 建议拆分方向
|
||||
|
||||
1. 按实体拆:营地 / playable NPC / story NPC / 地标。
|
||||
2. 按能力拆:基础信息 / 关系 / 技能 / 初始物品 / 视觉资产。
|
||||
3. 把 AI 生成与资产工作流进一步外置成独立 coordinator。
|
||||
|
||||
---
|
||||
|
||||
## 6.2 `server-node/src/modules/assets/characterAssetRoutes.ts`
|
||||
|
||||
### 当前状态
|
||||
|
||||
文件体量约 `3579` 行,已同时承担:
|
||||
|
||||
1. route 注册
|
||||
2. 请求解析
|
||||
3. LLM prompt bundle 生成
|
||||
4. JSON 解析与修复
|
||||
5. 文件系统写盘
|
||||
6. visual publish
|
||||
7. animation publish
|
||||
8. 资产目录管理
|
||||
|
||||
### 直接证据
|
||||
|
||||
文件内同时存在:
|
||||
|
||||
1. `mkdir` / `writeFile`
|
||||
2. `UpstreamLlmClient`
|
||||
3. `parseJsonResponseText`
|
||||
4. 多条 publish 路径
|
||||
5. 大量本地文件落盘逻辑
|
||||
|
||||
### 建议拆分方向
|
||||
|
||||
1. route 层
|
||||
2. prompt bundle service
|
||||
3. file publish service
|
||||
4. animation persistence service
|
||||
5. asset metadata service
|
||||
|
||||
---
|
||||
|
||||
## 6.3 `src/services/ai.ts`
|
||||
|
||||
### 当前状态
|
||||
|
||||
文件体量约 `2632` 行,同时承载运行时 story、自定义世界、NPC 对话、招募等多条链路。
|
||||
|
||||
### 建议
|
||||
|
||||
即使短期内不能全部迁后端,也应该先按职责拆成:
|
||||
|
||||
1. runtime story client
|
||||
2. npc dialogue client
|
||||
3. recruit dialogue client
|
||||
4. custom world generation client
|
||||
5. parser / fallback / error helpers
|
||||
|
||||
---
|
||||
|
||||
## 6.4 `src/services/customWorld.ts`
|
||||
|
||||
### 当前状态
|
||||
|
||||
文件体量约 `2413` 行,已经变成世界生成、校验、归一化、fallback 的综合体。
|
||||
|
||||
### 建议
|
||||
|
||||
至少拆成:
|
||||
|
||||
1. 世界框架与 outline schema
|
||||
2. profile normalize / validate
|
||||
3. role / landmark 编译器
|
||||
4. fallback builder
|
||||
5. world rule helpers
|
||||
|
||||
---
|
||||
|
||||
## 6.5 `src/hooks/story/npcEncounterActions.ts`
|
||||
|
||||
### 当前状态
|
||||
|
||||
文件体量约 `1623` 行,已经不是单纯 hook,而是前端运行时 action resolver。
|
||||
|
||||
### 建议
|
||||
|
||||
按动作域拆开:
|
||||
|
||||
1. npc chat / recruit
|
||||
2. npc help / affinity
|
||||
3. quest accept / turn-in
|
||||
4. battle entry / exit
|
||||
5. async streaming / typewriter / presentation glue
|
||||
|
||||
---
|
||||
|
||||
## 7. 推荐执行顺序
|
||||
|
||||
### 第一阶段:先清仓库噪音和旧入口残留
|
||||
|
||||
1. 清根目录日志、扫描文件、旧截图、`__pycache__`
|
||||
2. 迁出 `temp-build-goal-check/`
|
||||
3. 明确处置 `scripts/dev-server/localApiPlugins.ts`
|
||||
|
||||
### 第二阶段:再处理无入口孤岛模块
|
||||
|
||||
1. 逐个确认 `GameShell.tsx`、custom-world-home、custom-world-agent、旧 flow hooks 是要接回还是归档
|
||||
2. 对确认不再使用的 stub / helper / generated dead file 直接清理
|
||||
|
||||
### 第三阶段:把双份真相收口
|
||||
|
||||
1. runtime option interaction 映射只保留一份
|
||||
2. 浏览历史以后端为真相源
|
||||
3. 运行时快照解释权继续后移
|
||||
4. 清理 `server-node -> src/**` 的反向依赖
|
||||
|
||||
### 第四阶段:最后拆巨型热点文件
|
||||
|
||||
1. `CustomWorldEntityEditorModal.tsx`
|
||||
2. `characterAssetRoutes.ts`
|
||||
3. `ai.ts`
|
||||
4. `customWorld.ts`
|
||||
5. `npcEncounterActions.ts`
|
||||
|
||||
---
|
||||
|
||||
## 8. 本文依据
|
||||
|
||||
文档依据:
|
||||
|
||||
1. `docs/audits/engineering/README.md`
|
||||
2. `docs/technical/CURRENT_BACKEND_IMPLEMENTATION_BASELINE_2026-04-25.md`
|
||||
3. `scripts/dev-server/README.md`
|
||||
|
||||
当前仓库扫描依据:
|
||||
|
||||
1. `src/main.tsx`
|
||||
2. `src/routing/appRoutes.tsx`
|
||||
3. `src/App.tsx`
|
||||
4. `package.json`
|
||||
5. `server-node/package.json`
|
||||
6. `vite.config.ts`
|
||||
7. `.eslintrc.cjs`
|
||||
8. `git grep` 对关键模块引用、后端跨层 import、localStorage、旧 dev 插件入口的扫描结果
|
||||
@@ -0,0 +1,382 @@
|
||||
# 工程清理与后端边界复核审计(2026-04-20)
|
||||
|
||||
更新时间:`2026-04-20`
|
||||
|
||||
## 0. 审计目标
|
||||
|
||||
这份文档不是重复 `2026-04-19` 的原始扫描,而是基于当前仓库状态做一轮复核,重点回答三个问题:
|
||||
|
||||
1. 昨天审计里已经提出的问题,哪些今天已经真正落地。
|
||||
2. 哪些结论在当前代码里仍然成立,哪些表述需要纠正。
|
||||
3. 当前工程热点和边界问题有没有发生迁移。
|
||||
|
||||
---
|
||||
|
||||
## 1. 结论先行
|
||||
|
||||
和 `2026-04-19` 那份基线相比,当前仓库已经有一批明确进展:
|
||||
|
||||
1. **旧 Vite 本地 API 链路已经真正出清。**
|
||||
`scripts/dev-server/` 当前只剩一份 `README.md`,旧的 `localApiPlugins.ts`、角色资产插件、精灵表插件都不在仓库里了。
|
||||
2. **根目录噪音产物已经清理完成。**
|
||||
当前根目录临时日志/扫描产物扫描结果为空,`temp-build-goal-check/` 也不存在。
|
||||
3. **`server-node -> src/**` 反向依赖已经收掉。**
|
||||
当前复核没有再发现 `server-node/src/**` 直接 import 前端 `src/**` 的情况。
|
||||
4. **runtime option interaction 已经收口成后端单一真相。**
|
||||
这部分现在由 `server-node/src/modules/story/runtimeSession.ts` 统一构造,前端 `src/services/runtimeStoryService.ts` 不再本地再建一份映射表。
|
||||
|
||||
但这不代表边界问题已经结束,当前剩余问题主要集中在三块:
|
||||
|
||||
1. **前端仍保留运行时镜像与登录凭证本地真相。**
|
||||
`runtimeStoryCoordinator.ts` 仍会先写本地快照,`apiClient.ts` 仍把 token/自动登录凭证放在 `localStorage`。
|
||||
2. **NPC 聊天任务链路还没有完全后端化。**
|
||||
“聊天后挂出待接委托”已经移到后端,但“更换待接委托”这条分支仍由前端 `npcEncounterActions.ts` 触发 `generateQuestForNpcEncounter(...)`。
|
||||
3. **未接线孤岛和热点文件问题仍然明显。**
|
||||
一批 UI/Hook/Prompt 残留模块还没有正式入口;同时热点已经从已删除的旧插件链路,转移到 `CustomWorldEntityEditorModal.tsx`、`storyPromptBuilders.ts`、`runtimeProfile.ts`、`PreGameSelectionFlow.tsx`、`PlatformHomeView.tsx` 等新中心。
|
||||
|
||||
一句话判断:
|
||||
|
||||
**当前仓库已经完成“清垃圾、拆旧入口、切断后端反向依赖”的第一阶段,但还没有完成“前端退出运行时真相”和“未接线孤岛归档”的第二阶段。**
|
||||
|
||||
---
|
||||
|
||||
## 2. 已完成项复核
|
||||
|
||||
## 2.1 旧 dev-server 链路已经不是“逻辑上废弃”,而是“代码上删除”
|
||||
|
||||
### 当前证据
|
||||
|
||||
| 项目 | 当前状态 | 结论 |
|
||||
| --- | --- | --- |
|
||||
| `scripts/dev-server/` | 当前只剩 `README.md` 一份说明文件 | 旧 Vite 本地 API 链路已从仓库代码层出清 |
|
||||
| `scripts/dev-server/README.md` | 已明确声明当前正式入口为 `scripts/dev-node.mjs + server-node/src/modules/**` | 文档与代码状态一致 |
|
||||
|
||||
### 结论
|
||||
|
||||
`2026-04-19` 文档里关于旧本地 API 插件链路的清理结论,在当前仓库里已经可以确认成立,不再只是“计划删除”。
|
||||
|
||||
---
|
||||
|
||||
## 2.2 根目录噪音产物已经从当前工作区移除
|
||||
|
||||
### 当前证据
|
||||
|
||||
| 项目 | 当前状态 | 结论 |
|
||||
| --- | --- | --- |
|
||||
| 根目录历史日志/扫描产物 | 本轮扫描结果为空 | 之前的 `.codex-*.log`、`tmp_*`、旧截图/HTML 不再占据当前工作区 |
|
||||
| `temp-build-goal-check/` | 当前不存在 | 大体量检查产物已移出当前仓库视野 |
|
||||
|
||||
### 结论
|
||||
|
||||
`2026-04-19` 文档中关于“仓库噪音产物”的问题,在当前工作区层面已经完成首轮治理。
|
||||
这部分不再是当前工程第一优先级。
|
||||
|
||||
---
|
||||
|
||||
## 2.3 `server-node -> src/**` 反向依赖已清零
|
||||
|
||||
### 当前证据
|
||||
|
||||
本轮用脚本复核 `server-node/src/**` 中所有 `import` 后,当前结果为:
|
||||
|
||||
`NO_DIRECT_SERVER_TO_FRONTEND_SRC_IMPORTS`
|
||||
|
||||
同时,仓库里已经看不到类似下面这类旧反向依赖:
|
||||
|
||||
1. `server-node -> src/services/customWorld.js`
|
||||
2. `server-node -> src/services/customWorldBuilder.js`
|
||||
3. `server-node -> src/services/customWorldCreatorIntent.js`
|
||||
4. `server-node -> src/types.js`
|
||||
|
||||
### 结论
|
||||
|
||||
`2026-04-19` 文档里“清理 `server-node -> src/**` 反向依赖”的阶段性目标,在当前仓库里已经真正落地。
|
||||
|
||||
---
|
||||
|
||||
## 2.4 runtime option interaction 已经收口到后端
|
||||
|
||||
### 当前证据
|
||||
|
||||
1. `server-node/src/modules/story/runtimeSession.ts` 当前仍保留 `buildOptionInteraction(...)`,负责构造:
|
||||
- `npcActionMap`
|
||||
- `treasureActionMap`
|
||||
2. `src/services/runtimeStoryService.ts` 当前只做:
|
||||
- 直接读取 `option.interaction`
|
||||
- 把后端返回的 interaction 投影成 `StoryOption`
|
||||
3. 前端文件里已经找不到旧的 `buildRuntimeOptionInteraction` / `npcActionMap` / `treasureActionMap` 实现。
|
||||
|
||||
### 结论
|
||||
|
||||
这项收口已经成立,当前不会再出现“前后端各维护一份 interaction 映射表”的旧问题。
|
||||
|
||||
---
|
||||
|
||||
## 2.5 浏览器端的 quest/runtime item 本地 LLM fallback 已移除
|
||||
|
||||
### 当前证据
|
||||
|
||||
1. `src/services/questDirector.ts`
|
||||
- 浏览器路径先请求 `/api/runtime/quests/generate`
|
||||
- 后端失败时只走 deterministic fallback compile
|
||||
2. `src/services/runtimeItemAiDirector.ts`
|
||||
- 浏览器路径先请求 `/api/runtime/items/runtime-intent`
|
||||
- 后端失败时只返回 deterministic fallback intents
|
||||
3. 这两个文件虽然仍保留 `requestChatMessageContent(...)` 分支,但那是非浏览器分支,不再是浏览器端正式兜底链路。
|
||||
|
||||
### 结论
|
||||
|
||||
`2026-04-19` 文档里关于“浏览器本地 LLM fallback”这部分,当前应更新为:
|
||||
|
||||
**浏览器端本地 LLM fallback 已移除,但这两个模块仍然是双环境混合实现,还没有彻底后端化。**
|
||||
|
||||
---
|
||||
|
||||
## 3. 需要纠正的旧文档表述
|
||||
|
||||
## 3.1 NPC 任务链路不是“全部后端化”,而是“挂单已后移、换单仍前触发”
|
||||
|
||||
### 需要纠正的点
|
||||
|
||||
`2026-04-19` 文档中的回填里有一条表述是:
|
||||
|
||||
“`src/hooks/story/npcEncounterActions.ts` 不再在 NPC 单轮聊天完成后本地调用 `generateQuestForNpcEncounter(...)` 再决定是否挂出待接委托。”
|
||||
|
||||
### 当前代码状态
|
||||
|
||||
这句话对“聊天后挂出待接委托”这条主链是成立的,因为当前后端 `server-node/src/modules/ai/chatOrchestrator.ts` 已经会回填 `pendingQuestOffer`。
|
||||
|
||||
但它对整条 NPC 任务链路来说并不完整,因为当前前端仍保留这条分支:
|
||||
|
||||
1. `src/hooks/story/npcEncounterActions.ts`
|
||||
2. `replacePendingNpcQuestOffer()`
|
||||
3. `generateQuestForNpcEncounter(...)`
|
||||
|
||||
也就是:
|
||||
|
||||
**待接委托的“正式挂出”已后端化,但“更换委托”仍然由前端动作流发起。**
|
||||
|
||||
### 当前应改成的结论
|
||||
|
||||
更准确的描述应该是:
|
||||
|
||||
1. NPC 单轮聊天里“是否挂出待接委托”的决定权已收回后端。
|
||||
2. 但待接委托的“换单/重抽”分支仍通过前端 `npcEncounterActions.ts -> questDirector.ts` 发起。
|
||||
|
||||
---
|
||||
|
||||
## 4. 当前仍然成立的遗留问题
|
||||
|
||||
## 4.1 未接线/仅测试引用孤岛模块仍然明显
|
||||
|
||||
本轮依赖图复核后,当前仍能确认一批高置信度孤岛模块:
|
||||
|
||||
| 模块 | 当前状态 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `src/components/GameShell.tsx` | `765` 行,无运行时引用 | 旧版壳层残留仍在 |
|
||||
| `src/components/custom-world-home/CustomWorldCreationHub.tsx` | `161` 行,仅测试引用 | UI 已有完成度,但仍未进入正式入口 |
|
||||
| `src/components/custom-world-home/CustomWorldCreationLauncherModal.tsx` | `147` 行,无运行时引用 | 未接线入口壳层 |
|
||||
| `src/components/custom-world-agent/CustomWorldAgentLauncherModal.tsx` | `91` 行,无运行时引用 | agent UI 孤岛仍在 |
|
||||
| `src/components/custom-world-agent/CustomWorldAgentDraftDrawer.tsx` | `116` 行,无运行时引用 | agent UI 孤岛仍在 |
|
||||
| `src/hooks/story/storyBootstrap.ts` | `250` 行,无运行时引用 | 旧 bootstrap hook 仍未归档 |
|
||||
| `src/hooks/useEquipmentFlow.ts` | `134` 行,无运行时引用 | 旧 flow hook 残留 |
|
||||
| `src/hooks/useForgeFlow.ts` | `159` 行,无运行时引用 | 旧 flow hook 残留 |
|
||||
| `src/hooks/useInventoryFlow.ts` | `100` 行,无运行时引用 | 旧 flow hook 残留 |
|
||||
| `src/services/customWorldPresentation.stub.ts` | `55` 行,无运行时引用 | 占位 stub 仍在 |
|
||||
| `src/services/typewriter.ts` | `7` 行,无运行时引用 | 小型 helper 残留 |
|
||||
| `src/prompts/customWorldOrchestratorPrompts.ts` | `9` 行,无运行时引用 | prompt source 已迁走后留下的孤岛 |
|
||||
| `src/prompts/storyOrchestratorPrompts.ts` | `6` 行,无运行时引用 | prompt source 已迁走后留下的孤岛 |
|
||||
| `src/data/buildTagSimilarity.generated.ts` | `823` 行,无运行时引用 | 生成产物未接入正式业务链路 |
|
||||
|
||||
### 说明
|
||||
|
||||
`src/data/itemOverrides.json`、`src/data/monsterOverrides.json` 这类文件虽然没有 import 引用,但会被脚本和 editor route 以路径消费,所以不计入垃圾判断。
|
||||
|
||||
### 结论
|
||||
|
||||
仓库已经完成“删旧插件”,但还没有完成“清未接线孤岛”。
|
||||
当前这批模块应该进入明确处置表:
|
||||
|
||||
1. 直接归档/删除
|
||||
2. 正式接回入口
|
||||
3. 改名/迁目录,标记为实验稿
|
||||
|
||||
---
|
||||
|
||||
## 4.2 前端仍保留运行时镜像真相
|
||||
|
||||
### 当前证据
|
||||
|
||||
1. `src/hooks/story/runtimeStoryCoordinator.ts`
|
||||
- 仍会在读状态和提交动作前先 `putSaveSnapshot(...)`
|
||||
- 仍会在响应后多次 `rehydrateSavedSnapshot(...)`
|
||||
2. `src/services/runtimeStoryService.ts`
|
||||
- 仍对响应快照做 `rehydrateSavedSnapshot(...)`
|
||||
|
||||
### 结论
|
||||
|
||||
当前运行时已经不是“前端主算”,但仍然是:
|
||||
|
||||
**前端先写一份本地镜像,再和后端会话互相回填。**
|
||||
|
||||
这说明前端还没有完全退出正式运行时状态解释层。
|
||||
|
||||
---
|
||||
|
||||
## 4.3 前端仍保留本地登录凭证真相
|
||||
|
||||
### 当前证据
|
||||
|
||||
`src/services/apiClient.ts` 当前仍把以下内容写入 `window.localStorage`:
|
||||
|
||||
1. `ACCESS_TOKEN_KEY`
|
||||
2. `AUTO_AUTH_USERNAME_KEY`
|
||||
3. `AUTO_AUTH_PASSWORD_KEY`
|
||||
|
||||
对应代码仍包括:
|
||||
|
||||
1. `window.localStorage.getItem(...)`
|
||||
2. `window.localStorage.setItem(...)`
|
||||
3. `window.localStorage.removeItem(...)`
|
||||
|
||||
### 结论
|
||||
|
||||
这一点和“前端只做表现、后端负责鉴权”的目标仍然不一致。
|
||||
尤其是自动登录用户名/密码继续存本地,风险和边界问题都还在。
|
||||
|
||||
---
|
||||
|
||||
## 4.4 quest/runtime item 仍是双环境混合实现
|
||||
|
||||
### 当前证据
|
||||
|
||||
1. `src/services/questDirector.ts`
|
||||
- 浏览器路径走 `requestJson('/api/runtime/quests/generate')`
|
||||
- 非浏览器路径仍有 `requestChatMessageContent(...)`
|
||||
2. `src/services/runtimeItemAiDirector.ts`
|
||||
- 浏览器路径走 `requestJson('/api/runtime/items/runtime-intent')`
|
||||
- 非浏览器路径仍有 `requestChatMessageContent(...)`
|
||||
3. `src/hooks/story/npcEncounterActions.ts`
|
||||
- 当前仍 import `generateQuestForNpcEncounter`
|
||||
- `replacePendingNpcQuestOffer()` 仍会调用它
|
||||
|
||||
### 结论
|
||||
|
||||
浏览器兜底已经收掉,但模块职责仍然是混合的:
|
||||
|
||||
1. 同一个文件同时承担前端 SDK 和非浏览器编排逻辑
|
||||
2. NPC 换单动作仍由前端发起服务调用
|
||||
|
||||
这部分还不能算真正后端化完成。
|
||||
|
||||
---
|
||||
|
||||
## 4.5 `src/services/ai.ts` 仍然是浏览器端正式 AI orchestration 热点
|
||||
|
||||
### 当前证据
|
||||
|
||||
`src/services/ai.ts` 当前约 `2608` 行,仍直接使用:
|
||||
|
||||
1. `requestChatMessageContent`
|
||||
2. `requestPlainTextCompletion`
|
||||
3. `streamPlainTextCompletion`
|
||||
|
||||
### 结论
|
||||
|
||||
这说明浏览器侧的大型 AI orchestration 仍然没有真正退出主工程。
|
||||
虽然部分链路已经迁走,但整体边界还没有收完。
|
||||
|
||||
---
|
||||
|
||||
## 5. 当前热点已经发生迁移
|
||||
|
||||
## 5.1 当前主要大文件快照
|
||||
|
||||
| 文件 | 当前行数 | 判断 |
|
||||
| --- | --- | --- |
|
||||
| `src/components/CustomWorldEntityEditorModal.tsx` | `4898` | 仍是前端最大热点 |
|
||||
| `server-node/src/modules/assets/characterAssetRoutes.ts` | `3181` | 仍是后端资产链路最大热点 |
|
||||
| `src/services/ai.ts` | `2608` | 浏览器 AI orchestration 热点仍在 |
|
||||
| `src/data/npcInteractions.ts` | `2409` | 仍是大型规则数据中心 |
|
||||
| `server-node/src/services/customWorldAgentFoundationDraftService.ts` | `1902` | custom world agent 后端热点上升 |
|
||||
| `src/prompts/storyPromptBuilders.ts` | `1882` | prompt source 已成为新的前端热点 |
|
||||
| `server-node/src/modules/custom-world/runtimeProfile.ts` | `1735` | custom world runtime 编译中心已转到后端 |
|
||||
| `src/components/game-shell/PreGameSelectionFlow.tsx` | `1547` | 平台/入口流程热点上升 |
|
||||
| `src/components/game-shell/PlatformHomeView.tsx` | `1522` | 平台首页热点上升 |
|
||||
| `src/services/customWorld.ts` | `1489` | 仍然大,但已明显缩小 |
|
||||
| `src/hooks/story/npcEncounterActions.ts` | `1434` | 仍然是前端 action 热点 |
|
||||
|
||||
---
|
||||
|
||||
## 5.2 热点变化判断
|
||||
|
||||
和 `2026-04-19` 相比,当前热点不是单纯“没变”,而是出现了明显迁移:
|
||||
|
||||
1. `characterAssetRoutes.ts` 从 `3579` 行降到 `3181` 行,说明资产路由已经有过一轮拆分,但仍然偏大。
|
||||
2. `src/services/customWorld.ts` 从 `2413` 行降到 `1489` 行,说明自定义世界规则已拆出一部分。
|
||||
3. `src/hooks/story/npcEncounterActions.ts` 从 `1623` 行降到 `1434` 行,说明 NPC 运行时逻辑也有收口。
|
||||
4. 新的复杂度中心开始转移到:
|
||||
- `src/prompts/storyPromptBuilders.ts`
|
||||
- `server-node/src/modules/custom-world/runtimeProfile.ts`
|
||||
- `src/components/game-shell/PreGameSelectionFlow.tsx`
|
||||
- `src/components/game-shell/PlatformHomeView.tsx`
|
||||
|
||||
### 结论
|
||||
|
||||
当前问题已经不再是“原来的热点完全没动”,而是:
|
||||
|
||||
**部分旧热点正在缩小,但复杂度正在向 prompt source、custom world runtime profile、平台入口壳层继续迁移。**
|
||||
|
||||
---
|
||||
|
||||
## 6. 最新建议执行顺序
|
||||
|
||||
### 第一阶段:先清理当前仍明确无入口的孤岛
|
||||
|
||||
1. 处理 `GameShell.tsx`
|
||||
2. 处理 `custom-world-home/*`
|
||||
3. 处理 `custom-world-agent/*`
|
||||
4. 处理 `storyBootstrap.ts`、`useEquipmentFlow.ts`、`useForgeFlow.ts`、`useInventoryFlow.ts`
|
||||
5. 处理已脱钩的 `src/prompts/*OrchestratorPrompts.ts`
|
||||
|
||||
### 第二阶段:再收运行时和鉴权真相
|
||||
|
||||
1. 收掉 `runtimeStoryCoordinator.ts` 的本地快照前置写入
|
||||
2. 收掉 `apiClient.ts` 中的自动登录用户名/密码本地持久化
|
||||
3. 优先把 token/session 统一到服务端鉴权边界
|
||||
|
||||
### 第三阶段:补完 NPC 任务链路的后端化
|
||||
|
||||
1. 把“更换待接委托”从 `npcEncounterActions.ts -> questDirector.ts` 继续迁到后端
|
||||
2. 把 `questDirector.ts` / `runtimeItemAiDirector.ts` 拆成明确的后端服务与前端 SDK 两层
|
||||
|
||||
### 第四阶段:最后拆新热点
|
||||
|
||||
1. `CustomWorldEntityEditorModal.tsx`
|
||||
2. `characterAssetRoutes.ts`
|
||||
3. `storyPromptBuilders.ts`
|
||||
4. `runtimeProfile.ts`
|
||||
5. `PreGameSelectionFlow.tsx`
|
||||
6. `PlatformHomeView.tsx`
|
||||
|
||||
---
|
||||
|
||||
## 7. 本文依据
|
||||
|
||||
文档依据:
|
||||
|
||||
1. `docs/audits/engineering/ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-19.md`
|
||||
2. `docs/audits/engineering/README.md`
|
||||
3. `docs/technical/CURRENT_BACKEND_IMPLEMENTATION_BASELINE_2026-04-25.md`
|
||||
|
||||
当前仓库复核依据:
|
||||
|
||||
1. `scripts/dev-server/README.md`
|
||||
2. `server-node/src/modules/story/runtimeSession.ts`
|
||||
3. `src/services/runtimeStoryService.ts`
|
||||
4. `src/hooks/story/runtimeStoryCoordinator.ts`
|
||||
5. `src/hooks/story/npcEncounterActions.ts`
|
||||
6. `src/services/questDirector.ts`
|
||||
7. `src/services/runtimeItemAiDirector.ts`
|
||||
8. `src/services/apiClient.ts`
|
||||
9. 当前依赖图扫描结果与当前大文件体量扫描结果
|
||||
@@ -0,0 +1,141 @@
|
||||
# 工程死分支清理执行记录 A(2026-04-21)
|
||||
|
||||
更新时间:`2026-04-21`
|
||||
|
||||
## 0. 本批次目标
|
||||
|
||||
这份记录对应:
|
||||
|
||||
- `docs/planning/ENGINEERING_DEAD_CODE_AND_HIDDEN_BRANCH_CLEANUP_PLAN_2026-04-21.md`
|
||||
- 其中的 `P0 + 批次 A`
|
||||
|
||||
本批次只做一件事:
|
||||
|
||||
**先清理高置信度、低耦合、无正式入口的小型孤岛与残留壳子。**
|
||||
|
||||
这批对象有一个共同特征:
|
||||
|
||||
1. 当前没有正式运行时引用
|
||||
2. 没有当前主链计划要接回
|
||||
3. 删除后有明确替代路径,或者本身只是历史占位
|
||||
|
||||
因此这批次不碰运行时真相链、不碰鉴权链、不碰任务物品主链,只先做低风险去噪。
|
||||
|
||||
---
|
||||
|
||||
## 1. 本批次已处理对象
|
||||
|
||||
## 1.1 已删除文件
|
||||
|
||||
| 文件 | 判定 | 删除原因 | 替代路径 / 当前真相源 | 验证口径 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/services/customWorldPresentation.stub.ts` | 无引用占位 stub | 文件本身就是占位实现,且正式逻辑已由 `customWorldPresentation.ts` 承接 | `src/services/customWorldPresentation.ts` | 符号级检索确认正式调用方都指向正式实现 |
|
||||
| `src/services/typewriter.ts` | 无引用 helper 残留 | 独立 helper 已失效,正式链路已在 `storyPresentation.ts` / `storyRenderingHelpers.ts` 等处内联或迁移 | `src/hooks/story/storyPresentation.ts`、`src/hooks/story/storyRenderingHelpers.ts` | `getTypewriterDelay` 调用点未指向该文件 |
|
||||
| `src/prompts/customWorldOrchestratorPrompts.ts` | 前端孤岛 prompt 壳 | 当前无正式 import,正式主编排 prompt 已收口到后端 prompt 目录,前端 `ai.ts` 也保留自己的现行实现 | `server-node/src/prompts/customWorldOrchestratorPrompts.ts`、`src/services/ai.ts` | 全仓检索仅剩文档引用,无代码消费 |
|
||||
| `src/prompts/storyOrchestratorPrompts.ts` | 前端孤岛 prompt 壳 | 当前无正式 import,剧情语言修复 prompt 已由后端 prompt 目录承接,前端当前执行路径不依赖该文件 | `server-node/src/prompts/storyOrchestratorPrompts.ts`、`src/services/ai.ts` | 全仓检索仅剩文档引用,无代码消费 |
|
||||
| `src/components/custom-world-home/CustomWorldCreationLauncherModal.tsx` | 无入口 UI 壳层 | 最近两轮工程审计都确认无运行时引用,当前平台主流程未接这条入口 | 当前平台正式入口链 | 文件级检索确认无组件 import |
|
||||
| `src/components/custom-world-agent/CustomWorldAgentLauncherModal.tsx` | 无入口 UI 壳层 | Agent 创作主流程已切到当前工作区链路,这个旧 modal 没有接线价值 | 当前 Agent 工作区主链 | 文件级检索确认无组件 import |
|
||||
| `src/components/custom-world-agent/CustomWorldAgentDraftDrawer.tsx` | 无入口 UI 壳层 | 只有孤立 UI 实现,没有正式调用链,也不在当前结果页 / 工作区主链中 | 当前 Agent 工作区与结果页正式链 | 文件级检索确认无组件 import |
|
||||
|
||||
---
|
||||
|
||||
## 2. 本批次为什么先删这 7 个
|
||||
|
||||
这批文件适合先处理,不是因为它们最大,而是因为它们最清晰:
|
||||
|
||||
1. **没有正式入口。**
|
||||
本轮检索没有发现主工程 import。
|
||||
2. **删除后不会形成职责空洞。**
|
||||
要么已有正式替代路径,要么本身只是历史占位。
|
||||
3. **不会误伤当前重点链路。**
|
||||
这批不涉及运行时快照、鉴权、任务、物品、AI 正式编排主链。
|
||||
4. **可以最快降低目录噪音。**
|
||||
先把真假并存的壳子删掉,后面做批次 B/C/D 时判断成本会更低。
|
||||
|
||||
---
|
||||
|
||||
## 3. 本批次暂不处理对象
|
||||
|
||||
以下对象虽然已进入首轮台账,但本批次暂不删除:
|
||||
|
||||
1. `src/components/GameShell.tsx`
|
||||
2. `src/components/custom-world-home/CustomWorldCreationHub.tsx`
|
||||
3. `src/hooks/story/storyBootstrap.ts`
|
||||
4. `src/hooks/useEquipmentFlow.ts`
|
||||
5. `src/hooks/useForgeFlow.ts`
|
||||
6. `src/hooks/useInventoryFlow.ts`
|
||||
7. `src/data/buildTagSimilarity.generated.ts`
|
||||
|
||||
暂缓原因分别是:
|
||||
|
||||
1. 仍属于旧主流程 / 旧 flow 级别对象,删除前要先核对更多历史依赖和替代路径
|
||||
2. 部分对象仍有测试引用或更大的上下文耦合
|
||||
3. `buildTagSimilarity.generated.ts` 虽无正式业务 import,但属于生成产物,处理前还要确认脚本链与文档链
|
||||
|
||||
这批对象更适合进入:
|
||||
|
||||
1. `批次 B:旧 flow / 旧 shell / 旧 hook`
|
||||
2. 或独立的数据产物复核批次
|
||||
|
||||
---
|
||||
|
||||
## 4. 本批次同步更新的文档
|
||||
|
||||
本批次除了删文件,还同步做了文档回填:
|
||||
|
||||
1. 新增本执行记录,说明本批删了什么、为什么删、哪些对象暂缓
|
||||
2. 更新 `docs/audits/engineering/README.md`,把这份执行记录加入当前审计入口
|
||||
|
||||
这样做的目的,是避免再次出现:
|
||||
|
||||
1. 代码删了
|
||||
2. 但审计入口还是旧状态
|
||||
3. 后续开发又从旧清单里重复判断一遍
|
||||
|
||||
---
|
||||
|
||||
## 5. 验证方式
|
||||
|
||||
本批次验证采用两层口径:
|
||||
|
||||
## 5.1 删除前验证
|
||||
|
||||
1. 文件级检索确认无正式 import
|
||||
2. 符号级检索确认关键导出没有被主链消费
|
||||
3. 结合 `2026-04-20` 工程审计交叉确认这些对象已被标记为高置信度孤岛
|
||||
|
||||
## 5.2 删除后验证
|
||||
|
||||
建议至少执行:
|
||||
|
||||
1. `npm run check:encoding`
|
||||
2. `npm run build`
|
||||
|
||||
说明:
|
||||
|
||||
- 当前仓库已知 `typecheck` 与 `lint` 仍处于红线阶段,因此本批不把它们作为“由本批引入的新失败”判断口径
|
||||
- 本批主要验证目标是:删除小残留后,不产生新的导入断裂和构建断裂
|
||||
|
||||
---
|
||||
|
||||
## 6. 本批次结果判断
|
||||
|
||||
本批次完成后,工程至少获得了 3 个直接收益:
|
||||
|
||||
1. `src/prompts/`、`src/services/`、`src/components/custom-world-*` 中少了一批无入口孤岛
|
||||
2. 当前目录里“看起来像正式入口,其实已经废弃”的误导性对象减少
|
||||
3. 后续可以把精力集中到真正高价值的批次 B/C/D,而不是继续被小残留分散判断成本
|
||||
|
||||
---
|
||||
|
||||
## 7. 下一批建议
|
||||
|
||||
建议严格按计划继续往下推进:
|
||||
|
||||
1. 批次 B:`GameShell`、`storyBootstrap`、`useEquipmentFlow`、`useForgeFlow`、`useInventoryFlow`
|
||||
2. 批次 C:`runtimeStoryCoordinator`、`runtimeStoryService`、`apiClient`
|
||||
3. 批次 D:`npcEncounterActions`、`questDirector`、`runtimeItemAiDirector`、`ai.ts`
|
||||
|
||||
一句话总结本批次:
|
||||
|
||||
**先把最确定的死分支和占位壳子清掉,让主工程少一些假入口、假主源、假能力,再进入更重的主链收口。**
|
||||
@@ -0,0 +1,145 @@
|
||||
# 工程死分支清理执行记录 B(2026-04-21)
|
||||
|
||||
更新时间:`2026-04-21`
|
||||
|
||||
## 0. 本批次目标
|
||||
|
||||
这份记录对应清洗计划中的:
|
||||
|
||||
- `批次 B:旧 flow / 旧 shell / 旧 hook`
|
||||
|
||||
本批次聚焦的不是小型 stub,而是:
|
||||
|
||||
**已经退出正式主流程、但仍占着高辨识度命名和旧职责心智的壳层与流程 Hook。**
|
||||
|
||||
这类文件如果继续留在仓库里,问题比小 helper 更大,因为它们会持续制造误判:
|
||||
|
||||
1. 新人会以为它们还是正式入口
|
||||
2. 后续开发会误判“应该往这里接逻辑”
|
||||
3. review 时会多出一层“旧主链是不是还活着”的判断成本
|
||||
|
||||
---
|
||||
|
||||
## 1. 本批次已处理对象
|
||||
|
||||
## 1.1 已删除文件
|
||||
|
||||
| 文件 | 判定 | 删除原因 | 替代路径 / 当前真相源 | 验证口径 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/GameShell.tsx` | 旧主流程壳层残留 | 当前正式壳层已由 `src/components/game-shell/GameShellRuntime.tsx` 承接,旧文件无正式 import | `src/components/game-shell/GameShellRuntime.tsx`、`src/hooks/useGameShellRuntime.ts` | 全仓检索未发现对旧 `GameShell` 组件的正式消费 |
|
||||
| `src/hooks/story/storyBootstrap.ts` | 旧启动流程 Hook 残留 | 当前主剧情启动链已不再调用该 Hook,继续保留只会误导人以为它还是故事初始化入口 | 当前 story runtime / coordinator 链 | 全仓检索未发现 `useStoryBootstrap` 消费方 |
|
||||
| `src/hooks/useEquipmentFlow.ts` | 旧装备流程 Hook 残留 | 当前正式背包与装备链未消费该 Hook,属于旧流程实现残留 | 当前 inventory / runtime 正式链 | 符号级检索仅命中定义文件自身 |
|
||||
| `src/hooks/useForgeFlow.ts` | 旧锻造流程 Hook 残留 | 当前正式锻造入口未通过该 Hook 进入主链,保留会制造旧流程错觉 | 当前 inventory / runtime 正式链 | 符号级检索仅命中定义文件自身 |
|
||||
| `src/hooks/useInventoryFlow.ts` | 旧背包使用流程 Hook 残留 | 当前主流程未消费该 Hook,属于旧状态推进实现残留 | 当前 inventory / runtime 正式链 | 符号级检索仅命中定义文件自身 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 为什么这批要紧跟批次 A 处理
|
||||
|
||||
批次 A 清掉的是“小型假入口”。
|
||||
|
||||
批次 B 清掉的是“高辨识度旧主链”。
|
||||
|
||||
这批必须紧跟着做,原因是:
|
||||
|
||||
1. 它们虽然比 stub 更大,但引用关系同样清楚
|
||||
2. 它们的误导性比小残留更强
|
||||
3. 不先处理这批,后面做批次 C/D 时,很容易继续有人拿旧 flow Hook 当候选接线点
|
||||
|
||||
一句话讲:
|
||||
|
||||
**批次 A 是去噪,批次 B 是拔掉旧路牌。**
|
||||
|
||||
---
|
||||
|
||||
## 3. 本批次删除后的结构变化
|
||||
|
||||
本批次完成后,仓库里的流程心智会更清楚:
|
||||
|
||||
1. 游戏壳层正式入口继续收敛到 `src/components/game-shell/**`
|
||||
2. 旧 `GameShell.tsx` 不再和 `GameShellRuntime.tsx` 并存
|
||||
3. 旧的装备 / 锻造 / 背包单独 flow Hook 不再伪装成还在生效的正式实现
|
||||
4. 旧 `storyBootstrap` 不再和当前 story runtime 链并存
|
||||
|
||||
这会直接减少两类误判:
|
||||
|
||||
1. “是不是还有旧主流程没迁完”
|
||||
2. “我是不是应该把新逻辑继续补进这些旧 Hook”
|
||||
|
||||
---
|
||||
|
||||
## 4. 本批次暂不处理对象
|
||||
|
||||
虽然批次 B 已经处理了旧 shell / old flow / old bootstrap,但以下对象仍暂缓:
|
||||
|
||||
1. `src/components/custom-world-home/CustomWorldCreationHub.tsx`
|
||||
2. `src/data/buildTagSimilarity.generated.ts`
|
||||
3. 批次 C 的运行时真相链:
|
||||
- `src/hooks/story/runtimeStoryCoordinator.ts`
|
||||
- `src/services/runtimeStoryService.ts`
|
||||
- `src/services/apiClient.ts`
|
||||
4. 批次 D 的混合执行层:
|
||||
- `src/hooks/story/npcEncounterActions.ts`
|
||||
- `src/services/questDirector.ts`
|
||||
- `src/services/runtimeItemAiDirector.ts`
|
||||
- `src/services/ai.ts`
|
||||
|
||||
暂缓原因很明确:
|
||||
|
||||
1. 这些对象要么仍在当前正式链上
|
||||
2. 要么涉及运行时真相与鉴权边界
|
||||
3. 不能按“无引用旧壳”同一口径直接删除
|
||||
|
||||
---
|
||||
|
||||
## 5. 本批次验证方式
|
||||
|
||||
## 5.1 删除前验证
|
||||
|
||||
1. 全仓检索 `GameShell` 旧组件消费方,确认当前正式壳层已切到 `game-shell/` 目录
|
||||
2. 全仓检索 `useStoryBootstrap`
|
||||
3. 全仓检索旧装备 / 锻造 / 背包 flow Hook 导出的 handler 名称
|
||||
4. 交叉确认当前正式主链入口已存在替代实现
|
||||
|
||||
## 5.2 删除后验证
|
||||
|
||||
建议至少执行:
|
||||
|
||||
1. `npm run check:encoding`
|
||||
2. `npm run build`
|
||||
|
||||
如果这两项通过,说明:
|
||||
|
||||
1. 删除没有引入新的导入断裂
|
||||
2. 主工程构建链仍然成立
|
||||
|
||||
---
|
||||
|
||||
## 6. 本批次结果判断
|
||||
|
||||
本批次完成后,工程获得的直接收益是:
|
||||
|
||||
1. 旧主流程壳层不再和现行壳层并存
|
||||
2. 旧流程 Hook 不再占据 `src/hooks/` 的主路径注意力
|
||||
3. 当前正式入口和历史残留的边界更清楚
|
||||
4. 后续开发更不容易把新逻辑接回旧流程壳子
|
||||
|
||||
---
|
||||
|
||||
## 7. 下一批建议
|
||||
|
||||
建议下一步进入真正有结构价值的收口:
|
||||
|
||||
1. `批次 C:运行时真相收口`
|
||||
- `runtimeStoryCoordinator`
|
||||
- `runtimeStoryService`
|
||||
- `apiClient`
|
||||
2. `批次 D:任务 / 物品 / AI 混合执行层收口`
|
||||
- `npcEncounterActions`
|
||||
- `questDirector`
|
||||
- `runtimeItemAiDirector`
|
||||
- `ai.ts`
|
||||
|
||||
一句话总结本批次:
|
||||
|
||||
**这一步不是在“删几个没用 Hook”,而是在把已经退场的旧主流程壳层和旧 flow 路牌从主工程里真正拔掉,让现行架构不再和历史壳子并排站着。**
|
||||
@@ -0,0 +1,241 @@
|
||||
# 工程死分支清理执行记录 C(2026-04-21)
|
||||
|
||||
更新时间:`2026-04-21`
|
||||
|
||||
## 0. 本批次目标
|
||||
|
||||
这份记录对应清洗计划中的:
|
||||
|
||||
- `批次 C:运行时真相收口`
|
||||
|
||||
但这次不是“一口气把运行时真相链全删干净”,而是先做其中最明确、风险最低、最不该继续拖的那一段:
|
||||
|
||||
1. **收掉前端本地自动登录用户名 / 密码真相**
|
||||
2. **把登录恢复改成优先依赖服务端 session / refresh**
|
||||
|
||||
同时,这一批也明确记录了一件事:
|
||||
|
||||
**运行时快照前置写入链当前还不能直接砍。**
|
||||
|
||||
原因不是“不想动”,而是服务端当前 `runtime story` 动作入口仍然以远端快照作为执行基线。
|
||||
在后端 contract 没先改好之前,前端不能假装自己已经退出这条链。
|
||||
|
||||
---
|
||||
|
||||
## 1. 本批次已处理对象
|
||||
|
||||
## 1.1 已收口的鉴权链
|
||||
|
||||
| 文件 | 处理动作 | 本批结论 |
|
||||
| --- | --- | --- |
|
||||
| `src/services/apiClient.ts` | 删除本地自动登录用户名 / 密码存取逻辑 | 前端不再保存 auto auth 账号密码 |
|
||||
| `src/services/authService.ts` | 去掉对本地游客凭证的读写依赖 | 自动游客登录改为仅本次生成凭证,不再长期落本地 |
|
||||
| `src/components/auth/AuthGate.tsx` | 去掉“必须先有本地 access token 才尝试恢复”的前置假设 | 登录恢复改为优先尝试服务端 `getCurrentAuthUser()` / refresh session |
|
||||
| `src/services/authService.test.ts` | 改写游客自动登录相关断言 | 验证改为“生成临时凭证并完成登录”,而不是“落本地账号密码” |
|
||||
| `src/components/auth/AuthGate.test.tsx` | 改写登录恢复 mock | 验证改为“先尝试服务端会话恢复,再决定是否走游客兜底” |
|
||||
|
||||
---
|
||||
|
||||
## 2. 本批次为什么先做这段
|
||||
|
||||
这批优先级高,是因为它同时满足 4 条:
|
||||
|
||||
1. **风险明确。**
|
||||
浏览器保存自动登录用户名 / 密码,本身就不符合“前端只做表现、后端负责鉴权真相”的方向。
|
||||
2. **替代路径已经存在。**
|
||||
后端已经有 refresh session cookie 与 `getCurrentAuthUser()`,不是没有可替代能力。
|
||||
3. **改动边界清楚。**
|
||||
这一段主要落在前端鉴权恢复逻辑和测试,不会直接波及运行时战斗、任务、物品、剧情主链。
|
||||
4. **收益直接。**
|
||||
一旦收掉,前端就少了一份最不该长期保留的高风险真相。
|
||||
|
||||
一句话讲:
|
||||
|
||||
**这一步先把“浏览器记住游客账号密码再重登”这条假真相链拔掉。**
|
||||
|
||||
---
|
||||
|
||||
## 3. 本批次明确没做的事
|
||||
|
||||
## 3.1 没有直接删除 `runtimeStoryCoordinator.ts` 里的前置 `putSaveSnapshot(...)`
|
||||
|
||||
这不是漏做,而是明确暂缓。
|
||||
|
||||
当前复核结果是:
|
||||
|
||||
1. `server-node/src/modules/story/storyActionService.ts`
|
||||
2. `server-node/src/routes/runtimeRoutes.ts`
|
||||
3. `server-node/src/repositories/runtimeRepository.ts`
|
||||
|
||||
这条后端链当前仍然通过远端快照读取运行时状态,再执行:
|
||||
|
||||
1. `getRuntimeStoryState`
|
||||
2. `resolveRuntimeStoryAction`
|
||||
|
||||
也就是说,当前真实情况不是“前端多写了一份完全没用的镜像”,而是:
|
||||
|
||||
**前端在提交动作前先把当前状态写回远端快照,后端再基于这份快照执行业务动作。**
|
||||
|
||||
在这个 contract 没先升级为“前端只发 action,后端自己持有完整 session 真相”之前,前端不能直接把这一步砍掉。
|
||||
|
||||
否则会出现:
|
||||
|
||||
1. 动作请求仍在走
|
||||
2. 但服务端读取到的执行基线不完整
|
||||
3. 最后不是收口真相,而是把主链打断
|
||||
|
||||
## 3.2 没有删除 `runtimeStoryService.ts` / `runtimeStoryCoordinator.ts` 的快照再水合逻辑
|
||||
|
||||
这一步本轮也做了复核,结论是:
|
||||
|
||||
1. 我曾尝试把 `runtimeStoryCoordinator.ts` 中对服务端返回快照的重复再水合去掉
|
||||
2. 但对应的 `runtimeStoryCoordinator` 测试立即暴露出:当前后端返回的快照在部分战斗场景下还不是完整水合态
|
||||
3. 说明前端当前这层再水合仍然有现实职责,不是纯多余代码
|
||||
|
||||
所以这一步本批明确结论是:
|
||||
|
||||
**暂不删除,等后端快照 contract 先补完整后再做。**
|
||||
|
||||
---
|
||||
|
||||
## 4. 本批次验证结果
|
||||
|
||||
本批次已完成的定向验证:
|
||||
|
||||
1. `npx vitest run src/services/authService.test.ts`
|
||||
2. `npx vitest run src/components/auth/AuthGate.test.tsx`
|
||||
3. `npx vitest run src/hooks/story/runtimeStoryCoordinator.test.ts`
|
||||
4. `npm run check:encoding`
|
||||
|
||||
结果:
|
||||
|
||||
1. `authService` 测试通过
|
||||
2. `AuthGate` 测试通过
|
||||
3. `runtimeStoryCoordinator` 测试通过
|
||||
4. 编码检查通过
|
||||
|
||||
另外执行了:
|
||||
|
||||
1. `npm run build`
|
||||
|
||||
结果:
|
||||
|
||||
构建产物生成成功,但 `build-gate` 仍因主包 chunk warning 拦截失败。
|
||||
当前失败点仍是已知的主包体积问题:
|
||||
|
||||
- `AuthenticatedApp-*.js` 超过当前 warning 门槛
|
||||
|
||||
这属于仓库当前既有工程问题,不是本批次引入的新断裂。
|
||||
|
||||
## 4.1 2026-04-21 补充修正:会话探测 401 自触发循环
|
||||
|
||||
在这批收口完成后,前端又暴露出一条更细的鉴权恢复回路问题:
|
||||
|
||||
1. `AuthGate` 启动时会调用 `getCurrentAuthUser()` 探测现有会话
|
||||
2. `/api/auth/me` 返回 `401` 时,`apiClient.ts` 会默认广播一次 `AUTH_STATE_EVENT`
|
||||
3. `AuthGate` 自己又监听这个事件并重新 `hydrate()`
|
||||
4. 最终形成 `hydrate -> /auth/me 401 -> emit -> hydrate` 的自触发循环
|
||||
|
||||
这条链的问题不在“是否允许 401”,而在:
|
||||
|
||||
**会话探测请求把“未登录态探测”错误地当成了“全局登录态变更”。**
|
||||
|
||||
因此这里补了一条更细粒度的约束:
|
||||
|
||||
1. `apiClient.ts` 新增 `notifyAuthStateChange` 选项,默认仍保持原有广播行为
|
||||
2. `getCurrentAuthUser()` 作为会话探测请求,显式关闭这类 401 广播
|
||||
3. 真实登录、登出、刷新成功后,仍保留全局鉴权变更通知
|
||||
|
||||
这样修完后:
|
||||
|
||||
1. `AuthGate` 仍会优先尝试服务端会话恢复
|
||||
2. 无会话时会正常落回未登录分支
|
||||
3. 不会因为探测型 401 把自己重新唤醒并刷爆控制台
|
||||
|
||||
## 4.2 2026-04-22 补充修正:公开认证入口误触发 refresh
|
||||
|
||||
在登录弹窗链路继续联调时,又暴露出一条更细的请求边界问题:
|
||||
|
||||
1. 用户处于未登录态,浏览器本地没有 access token
|
||||
2. 点击“获取验证码”会调用 `sendPhoneLoginCode()`
|
||||
3. `authService.ts` 复用了通用 `requestJson(...)`
|
||||
4. `apiClient.ts` 在“无本地 token 且未显式关闭 refresh”时,会先尝试 `POST /api/auth/refresh`
|
||||
5. 若当前浏览器本来也没有 refresh session cookie,就会先打出一条 `401 Unauthorized`
|
||||
6. 最终表现成:验证码接口真正发送前,前端控制台先报一次 `/api/auth/refresh 401`
|
||||
|
||||
这条链的问题不在“验证码接口失败”,而在:
|
||||
|
||||
**登录前公开认证入口被错误当成了需要先补票的受保护请求。**
|
||||
|
||||
因此这里再补一条明确约束:
|
||||
|
||||
1. `sendPhoneLoginCode()`
|
||||
2. `loginWithPhoneCode()`
|
||||
3. `authEntry()`
|
||||
4. `getAuthLoginOptions()`
|
||||
5. `startWechatLogin()`
|
||||
|
||||
以上这些“获取登录态之前”的公开认证入口,统一显式传入:
|
||||
|
||||
1. `skipAuth: true`
|
||||
2. `skipRefresh: true`
|
||||
|
||||
这样修完后:
|
||||
|
||||
1. 未登录用户点击“获取验证码”不会先打 `/api/auth/refresh`
|
||||
2. 公开认证入口不会误带旧 token,也不会制造无意义的 401 噪音
|
||||
3. 真正需要 refresh 的仍然只有已拿到登录态后的受保护请求
|
||||
|
||||
本次补修的定向验证:
|
||||
|
||||
1. `npx vitest run src/services/authService.test.ts`
|
||||
2. `npm run check:encoding`
|
||||
|
||||
---
|
||||
|
||||
## 5. 本批次完成后的实际收益
|
||||
|
||||
这一步完成后,工程在鉴权边界上有了两个明确改善:
|
||||
|
||||
1. **前端不再保存自动登录用户名 / 密码。**
|
||||
浏览器只保留 access token,本地高风险游客凭证真相已经收掉。
|
||||
2. **登录恢复逻辑更接近服务端为真相源。**
|
||||
`AuthGate` 不再假设“没有本地 token 就一定还没登录”,而是优先尝试服务端会话恢复。
|
||||
|
||||
这意味着前端鉴权链已经从:
|
||||
|
||||
```text
|
||||
本地用户名/密码 -> 再次 entry -> 拿 token
|
||||
```
|
||||
|
||||
进一步收到了:
|
||||
|
||||
```text
|
||||
refresh session / 当前会话 -> 恢复用户
|
||||
兜底时才创建一次游客凭证
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 本批次后续建议
|
||||
|
||||
要继续完成批次 C,下一步不该直接在前端硬删,而应该先补后端 contract:
|
||||
|
||||
1. 让 `runtime story` 动作链逐步摆脱“前端先写远端快照”的依赖
|
||||
2. 让服务端自己持有更完整的运行时 session 真相
|
||||
3. 等后端返回快照已经稳定水合后,再删前端的重复再水合
|
||||
|
||||
换句话说,批次 C 的后半段应该拆成:
|
||||
|
||||
1. **C-1:鉴权真相收口**
|
||||
本批已完成
|
||||
2. **C-2:运行时快照 contract 后端化**
|
||||
需要先改后端
|
||||
3. **C-3:前端镜像写入与重复水合退场**
|
||||
依赖 C-2
|
||||
|
||||
---
|
||||
|
||||
## 7. 一句话总结
|
||||
|
||||
**批次 C 这一轮已经先把“浏览器长期保存游客账号密码”这条最不该存在的鉴权假真相链收掉了;而运行时快照前置写入这条链经过复核确认仍受后端 contract 约束,不能在服务端未先补齐前硬砍。**
|
||||
@@ -0,0 +1,56 @@
|
||||
# 工程死分支清理执行记录 D(2026-04-21)
|
||||
|
||||
更新时间:`2026-04-21`
|
||||
|
||||
## 0. 本批次目标
|
||||
|
||||
本批次继续清理上一轮复核后剩余的低风险数据产物与测试占位:
|
||||
|
||||
1. 未接入业务的生成产物
|
||||
2. 只为测试替换真实实现的空 stub
|
||||
3. 支撑这些残留的配置与脚本
|
||||
|
||||
---
|
||||
|
||||
## 1. 已删除对象
|
||||
|
||||
| 文件 | 判定 | 删除原因 | 替代路径 / 当前真相源 |
|
||||
| --- | --- | --- | --- |
|
||||
| `src/data/buildTagSimilarity.generated.ts` | 未接入业务的生成产物 | 运行时代码不 import;Build 相似度当前由 `buildTags.ts` 中的属性亲和度逻辑计算 | `src/data/buildTags.ts` |
|
||||
| `scripts/generate-build-tag-similarity.py` | 已无输出目标的生成脚本 | 只负责生成已删除的矩阵文件,继续保留会误导后续开发恢复旧主源 | `src/data/buildTags.ts` 的手工审表逻辑 |
|
||||
| `src/data/customWorldCharacterLoadout.stub.ts` | 测试专用空 stub | 只通过 `vitest.config.ts` alias 替换真实实现;真实实现已经稳定存在 | `src/data/customWorldCharacterLoadout.ts` |
|
||||
|
||||
---
|
||||
|
||||
## 2. 同步更新
|
||||
|
||||
本批次同步移除了:
|
||||
|
||||
1. `vitest.config.ts` 中指向 `customWorldCharacterLoadout.stub.ts` 的 alias
|
||||
2. `BUILD_SYSTEM_ATTRIBUTE_SIMILARITY_PRD_2026-04-02.md` 中把旧 generated 矩阵描述为当前文件的表述
|
||||
3. 清理计划里对 `buildTagSimilarity.generated.ts` 的未处理状态说明
|
||||
|
||||
---
|
||||
|
||||
## 3. 验证口径
|
||||
|
||||
删除前已确认:
|
||||
|
||||
1. `buildTagSimilarity.generated.ts` 无运行时代码引用
|
||||
2. `customWorldCharacterLoadout.stub.ts` 只被 `vitest.config.ts` alias 引用
|
||||
3. 真实 `customWorldCharacterLoadout.ts` 仍被 `characterPresets.ts` 与 `npcInteractions.ts` 使用,不能删除
|
||||
|
||||
删除后建议验证:
|
||||
|
||||
1. `npm run check:encoding`
|
||||
2. 与自定义世界开局物品相关的测试
|
||||
|
||||
---
|
||||
|
||||
## 4. 当前结论
|
||||
|
||||
本批次完成后,剩余清理对象已经不再适合按“无引用直接删”推进。后续如果继续清,需要先改 contract 或主链职责:
|
||||
|
||||
1. 运行时快照真相链
|
||||
2. 任务 / 物品 / AI 混合执行层
|
||||
3. 大型主流程组件继续拆分,而不是直接删除
|
||||
@@ -0,0 +1,117 @@
|
||||
# 工程死分支清理执行记录 E(2026-04-21)
|
||||
|
||||
更新时间:`2026-04-21`
|
||||
|
||||
## 0. 本批次目标
|
||||
|
||||
本批次承接批次 D,继续清掉已经退出 RPG 游戏创作主流程、RPG 运行时玩法主流程、平台基本功能主流程的历史壳层。
|
||||
|
||||
本批次不处理仍需后端 contract 先收口的对象,例如:
|
||||
|
||||
1. `src/services/questDirector.ts`
|
||||
2. `src/services/runtimeItemAiDirector.ts`
|
||||
3. `src/hooks/rpg-runtime-story/runtimeStoryCoordinator.ts`
|
||||
4. `src/services/apiClient.ts`
|
||||
|
||||
这些对象仍属于“前端越界逻辑继续后端化”的后续批次,不按无引用文件直接删除。
|
||||
|
||||
---
|
||||
|
||||
## 1. 删除判定口径
|
||||
|
||||
本批只删除满足下面条件之一的对象:
|
||||
|
||||
1. 无运行时入口、无脚本入口、无当前路由挂载。
|
||||
2. 已有现行正式实现,旧文件只剩 re-export / facade / 兼容命名。
|
||||
3. 只被测试验证旧壳自身,且该测试不再服务当前主流程门禁。
|
||||
4. 文档已明确该对象处于“后续只允许收缩、不再接新逻辑”的兼容残留状态。
|
||||
|
||||
---
|
||||
|
||||
## 2. 本批次已处理对象
|
||||
|
||||
| 文件 | 判定 | 删除原因 | 替代路径 / 当前真相源 |
|
||||
| --- | --- | --- | --- |
|
||||
| `server-node/src/routes/rpgCreationAgentRoutes.ts` | 旧命名 re-export | 当前后端正式路由直接使用 `customWorldAgent.ts` | `server-node/src/routes/customWorldAgent.ts` |
|
||||
| `server-node/src/routes/rpgWorldGalleryRoutes.ts` | 空路由骨架 | 世界广场实际列表和详情已经进入世界库路由 | `server-node/src/routes/rpg-entry/rpgWorldLibraryRoutes.ts` |
|
||||
| `server-node/src/services/RpgAgentOrchestrator.ts` | 旧命名 re-export | 当前正式上下文直接使用 `CustomWorldAgentOrchestrator` | `server-node/src/services/customWorldAgentOrchestrator.ts` |
|
||||
| `server-node/src/services/RpgAgentSessionStore.ts` | 旧命名 re-export | 当前正式上下文直接使用 `CustomWorldAgentSessionStore` | `server-node/src/services/customWorldAgentSessionStore.ts` |
|
||||
| `server-node/src/services/customWorldWorkSummaryService.ts` | 旧兼容入口 | 测试和路由已改为直接使用 RPG 命名服务 | `server-node/src/services/RpgWorldWorkSummaryService.ts` |
|
||||
| `server-node/src/services/customWorldAgentPublishGateService.ts` | 旧发布门禁实现 | 当前 action executor 与作品库发布链已统一走 PublishingService | `server-node/src/services/customWorldAgentPublishingService.ts` |
|
||||
| `server-node/src/services/customWorldAgentPublishService.ts` | 旧发布实现 | 当前发布链不再编译旧 legacy result profile | `server-node/src/services/customWorldAgentPublishingService.ts` |
|
||||
| `server-node/src/modules/custom-world/runtime-profile/runtimeProfileCompiler.ts` | 旧 facade | runtime profile 已拆到目录模块并由 `index.ts` / `runtimeProfile.ts` 承接 | `server-node/src/modules/custom-world/runtime-profile/index.ts` |
|
||||
| `server-node/src/bridges/legacyBuildRuntimeBridge.ts` | 无引用旧桥 | 后端 runtime build / equipment 已直接在正式模块内使用 | `server-node/src/modules/runtime/**` |
|
||||
| `server-node/src/bridges/legacyRuntimeItemResolutionBridge.ts` | 旧桥 | runtime item 解析服务一并删除,正式运行时使用 `runtimeItemModule.ts` | `server-node/src/modules/runtime-item/runtimeItemModule.ts` |
|
||||
| `server-node/src/modules/runtime-item/runtimeItemResolutionService.ts` | 无正式入口 wrapper | 只被 barrel 和自身测试引用,未挂入 Express 运行时主链 | `server-node/src/modules/runtime-item/runtimeItemModule.ts` |
|
||||
| `server-node/src/modules/**/index.ts` | 无引用 barrel | 这些 barrel 没有被当前后端入口消费,反而制造“公共模块入口仍存在”的错觉 | 直接 import 具体正式模块 |
|
||||
| `server-node/src/routes/rpg-*/index.ts` | 无引用 barrel | 当前 Express app 直接 import 具体 route 文件 | `server-node/src/app.ts` 中的具体路由 |
|
||||
| `server-node/src/repositories/rpg-*/index.ts` | 无引用 barrel | 当前上下文直接 import 具体 repository | `server-node/src/server.ts` 中的具体仓储 |
|
||||
| `src/components/DeveloperTeamModal.tsx` | 无入口 UI | 平台主流程没有打开该弹窗的入口 | 无替代 UI,删除历史壳 |
|
||||
| `src/components/LazySkillEffectPreview.tsx` | 无入口 lazy 壳 | 正式技能预览直接使用 `SkillEffectPreview` | `src/components/SkillEffectPreview.tsx` |
|
||||
| `src/components/npcVisualEditorModel.ts` | 旧 NPC 形象写回模型 | 当前 RPG 创作编辑器使用 `CustomWorldNpcVisualEditor` 与结果页新入口 | `src/components/CustomWorldNpcVisualEditor.tsx`、`src/components/rpg-creation-editor/**` |
|
||||
| `src/components/npcVisualEditorPersistence.ts` | 旧 NPC 形象写回持久层 | 只被旧持久化测试引用,正式编辑入口已迁移 | `src/components/rpg-creation-editor/**` |
|
||||
| `src/components/rpg-creation-*/index.ts` | 无引用 barrel | 当前入口直接 import 具体 facade 文件,barrel 没有主流程消费 | 直接 import `RpgCreation*` 具体文件 |
|
||||
| `src/components/rpg-creation-editor/CustomWorldSceneChapterEditorSection.tsx` | 旧 facade | 当前编辑器 section 直接在 `RpgCreationEntityEditorShared.tsx` 中分发 | `src/components/rpg-creation-editor/RpgCreationEntityEditorShared.tsx` |
|
||||
| `src/data/editorValidation.ts` | 旧预设编辑器校验 | 当前主流程和内容门禁不再调用 | `scripts/validate-overrides.ts`、后端 editor API |
|
||||
| `src/editor/shared/EditorNotice.tsx` | 无入口共享 UI | 只被同批删除的 FormFields 使用 | 无替代 UI,删除历史编辑器壳 |
|
||||
| `src/editor/shared/FormFields.tsx` | 无入口共享 UI | 旧编辑器共享表单未接主流程 | 当前 RPG 编辑器组件内聚在 `rpg-creation-editor/**` |
|
||||
| `src/editor/shared/SectionCard.tsx` | 无入口共享 UI | 旧编辑器卡片未接主流程 | 当前 RPG 编辑器组件内聚在 `rpg-creation-editor/**` |
|
||||
| `src/hooks/rpg-runtime-story/npcEncounterActions.ts` | 旧 wrapper | 正式实现已在 `useRpgRuntimeNpcInteraction.ts`,测试已改到正式文件 | `src/hooks/rpg-runtime-story/useRpgRuntimeNpcInteraction.ts` |
|
||||
| `src/hooks/rpg-runtime-story/openingAdventure.ts` | 旧前端开局特殊流程 | 开局营地对白已由后端 `RpgRuntimeStoryActionDomain` 和当前 story context 承接 | `server-node/src/modules/rpg-runtime-story/RpgRuntimeStoryActionDomain.ts` |
|
||||
| `src/hooks/rpg-runtime-story/storyCampCompanion.ts` | 旧前端营地同伴 helper | 只剩旧开局流程和自身测试引用,正式开局上下文已迁到当前 runtime story 链 | 后端 runtime story action domain 与 `storyContextBuilder.ts` |
|
||||
| `src/hooks/rpg-runtime-story/storyRenderingHelpers.ts` | 无入口旧渲染 helper | 当前正式 story presentation 不再 import | `src/hooks/rpg-runtime-story/storyPresentation.ts` |
|
||||
| `src/prompts/questPrompts.ts` | 前端 prompt 残留 | Quest prompt 真相已迁到后端 | `server-node/src/prompts/questPrompts.ts` |
|
||||
| `src/prompts/runtimeItemPrompts.ts` | 前端 prompt 残留 | Runtime item prompt 真相已迁到后端 | `server-node/src/prompts/runtimeItemPrompts.ts` |
|
||||
| `src/services/questPrompt.ts` | 前端 prompt re-export | 只指向同批删除的前端 prompt | `server-node/src/prompts/questPrompts.ts` |
|
||||
| `src/services/runtimeItemAiPrompt.ts` | 前端 prompt re-export | 只指向同批删除的前端 prompt | `server-node/src/prompts/runtimeItemPrompts.ts` |
|
||||
| `src/services/storyEngine/contentDependencyGraph.ts` | 实验性孤岛 | 只被自身测试引用,没有主流程消费 | 后续如需要重新设计到后端 story graph 服务 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 同步调整
|
||||
|
||||
1. `customWorldAgentPhase2/3/4` 测试改为直接实例化 `RpgWorldWorkSummaryService`。
|
||||
2. `customWorldWorkSummaryService.integration.test.ts` 改为直接覆盖 `RpgWorldWorkSummaryService`。
|
||||
3. `npcEncounterActions.test.ts` 改为直接覆盖 `useRpgRuntimeNpcInteraction.ts`,不再通过旧 wrapper。
|
||||
4. `story_opening_camp_dialogue` 的 function catalog 执行路径改为后端 runtime action domain,不再指向已删除旧前端文件。
|
||||
5. NPC function catalog 中 `npc_chat / npc_help / npc_leave / npc_fight / npc_spar / npc_preview_talk` 的 executor 路牌改到现行 `useRpgRuntimeNpcInteraction.ts`。
|
||||
|
||||
---
|
||||
|
||||
## 4. 本批次暂缓对象
|
||||
|
||||
以下对象仍然保留,原因是它们不是“无引用死代码”,而是需要下一轮按 contract 或主链职责迁移:
|
||||
|
||||
1. `src/services/questDirector.ts`
|
||||
2. `src/services/runtimeItemAiDirector.ts`
|
||||
3. `src/services/ai.ts`
|
||||
4. `src/data/sceneObservation.ts`
|
||||
5. `server-node/ecosystem.config.cjs`
|
||||
6. `server-node/src/scripts/syncCustomWorldSavedProfileAssets.ts`
|
||||
|
||||
其中 `ecosystem.config.cjs` 被部署脚本直接使用;`sceneObservation.ts` 被内容 smoke 脚本验证;`syncCustomWorldSavedProfileAssets.ts` 是一次性运维脚本,后续要单独按运维脚本治理口径确认是否归档。
|
||||
|
||||
---
|
||||
|
||||
## 5. 验证口径
|
||||
|
||||
本批删除后建议验证:
|
||||
|
||||
1. `npm run check:encoding`
|
||||
2. `npx tsx --test server-node/src/services/customWorldWorkSummaryService.integration.test.ts`
|
||||
3. `npx vitest run src/hooks/rpg-runtime-story/npcEncounterActions.test.ts`
|
||||
4. `npm run server-node:build`
|
||||
5. `npm run build`
|
||||
|
||||
如果 `npm run build` 仍被既有 chunk warning 拦截,需要单独记录为既有门禁问题,不归因到本批删除。
|
||||
|
||||
---
|
||||
|
||||
## 6. 当前结论
|
||||
|
||||
本批次进一步删除了“旧命名入口、旧 facade、旧 prompt 前端镜像、无入口编辑器壳层”这批容易误导后续开发的文件。
|
||||
|
||||
后续清理不应继续按“静态无引用”直接推进,而应进入两类工作:
|
||||
|
||||
1. 运行时 / 任务 / 物品 / AI 的后端 contract 收口。
|
||||
2. RPG 创作编辑器与运行时热点文件的职责拆分。
|
||||
@@ -0,0 +1,91 @@
|
||||
# 工程死分支清理执行记录 F(2026-04-21)
|
||||
|
||||
更新时间:`2026-04-21`
|
||||
|
||||
## 0. 本批次目标
|
||||
|
||||
本批次承接批次 E 的验证结果,继续处理删除后暴露出的最后一组高置信残留:
|
||||
|
||||
1. 已经没有任何代码入口引用的前端任务生成 director。
|
||||
2. 只被内容 smoke 牵住、但不再是正式运行时入口的旧观察文案 helper。
|
||||
3. 带有固定用户、固定 session、固定 profile 的一次性历史同步脚本。
|
||||
4. 清理后暴露出的 function catalog 契约覆盖缺口。
|
||||
|
||||
本批次仍然不按文件名直接删除 `legacy` 命名对象。经核对,`server-node/src/bridges/legacyInventoryRuntimeBridge.ts`、`legacyNpcTask6Bridge.ts`、`legacyQuestProgressBridge.ts`、`legacyQuestRuntimeBridge.ts`、`legacyRuntimeItemBridge.ts`、`legacyTreasureRuntimeBridge.ts` 仍被后端战斗、背包、任务、宝藏主链直接引用,不能按历史命名硬删。
|
||||
|
||||
---
|
||||
|
||||
## 1. 删除判定口径
|
||||
|
||||
本批删除对象必须同时满足:
|
||||
|
||||
1. 修正 `.js -> .ts` 后端源码解析、前端懒加载入口解析后,仍不可从正式入口到达。
|
||||
2. 全仓库代码引用扫描没有正式入口引用。
|
||||
3. 如只被 smoke 或测试牵住,先把 smoke / 测试改到当前正式主链,再删除旧对象。
|
||||
4. 删除后通过对应门禁验证,没有新增悬空 import。
|
||||
|
||||
---
|
||||
|
||||
## 2. 本批次已处理对象
|
||||
|
||||
| 文件 | 判定 | 删除 / 调整原因 | 替代路径 / 当前真相源 |
|
||||
| --- | --- | --- | --- |
|
||||
| `src/services/questDirector.ts` | 无代码入口残留 | 正式 quest 生成已由后端 `/api/runtime/quests/generate` 与 `questService.ts` 承接,前端当前没有任何 import | `server-node/src/services/questService.ts`、`server-node/src/modules/quest/runtimeQuestModule.ts` |
|
||||
| `src/data/sceneObservation.ts` | 旧观察文案 helper | 只被 `scripts/smoke-content.ts` 引用,正式观察动作已走 `idle_observe_signs` function 与运行时 story continuation | `src/data/functionCatalog/state/idleObserveSigns.ts`、`src/hooks/rpg-runtime-story/storyChoiceContinuation.ts` |
|
||||
| `server-node/src/scripts/syncCustomWorldSavedProfileAssets.ts` | 一次性硬编码运维脚本 | 脚本内固定用户、session、profile,只服务历史补丁,没有 CLI 参数和当前运维入口 | 无替代;如未来需要,按参数化运维脚本重新设计 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 同步调整
|
||||
|
||||
1. `scripts/smoke-content.ts` 不再 import 旧 `sceneObservation.ts`,改为通过 `resolveFunctionOption('idle_observe_signs', ...)` 验证当前正式 function 目录。
|
||||
2. `packages/shared/src/contracts/rpgRuntimeContracts.test.ts` 不再验证已移除的旧 `story` façade,改为直接验证当前拆分契约。
|
||||
3. `src/data/functionCatalog/` 补齐仍在后端运行时契约中的 function 文档:
|
||||
- `battle_attack_basic`
|
||||
- `battle_use_skill`
|
||||
- `npc_chat_quest_offer_view`
|
||||
- `npc_chat_quest_offer_replace`
|
||||
- `npc_chat_quest_offer_abandon`
|
||||
4. `battle_attack_basic` 与 `battle_use_skill` 只作为后端契约文档登记,不进入 `STATE_FUNCTION_DEFINITIONS`,避免前端本地候选池生成缺少 `runtimePayload.skillId` 的假技能 option。
|
||||
|
||||
---
|
||||
|
||||
## 4. 本批次暂缓对象
|
||||
|
||||
以下对象经本批复核后继续保留:
|
||||
|
||||
1. `server-node/src/services/customWorldAgentRepositoryTestHelpers.ts`
|
||||
2. `server-node/src/services/customWorldAgentTestHelpers.ts`
|
||||
3. `server-node/src/testFixtures/runtimeCharacter.ts`
|
||||
4. `server-node/src/testHttp.ts`
|
||||
|
||||
这些文件不属于正式运行时入口,但当前被后端测试、smoke 与路由边界门禁使用。它们不是 RPG 创作 / 运行时玩法主流程代码,但仍是平台基本质量门禁的一部分,不能在“删除冗余业务代码”批次里直接硬删。
|
||||
|
||||
另保留:
|
||||
|
||||
1. `src/services/runtimeItemAiDirector.ts`
|
||||
2. `src/services/ai.ts`
|
||||
3. `src/services/apiClient.ts`
|
||||
|
||||
这些文件仍被当前主链或前端 SDK 入口引用,后续如继续压缩,必须先完成对应 contract / SDK 拆分,不按无引用规则删除。
|
||||
|
||||
---
|
||||
|
||||
## 5. 验证结果
|
||||
|
||||
本批已通过:
|
||||
|
||||
1. `npx vitest run src/data/functionCatalog/functionCatalog.test.ts packages/shared/src/contracts/rpgRuntimeContracts.test.ts`
|
||||
2. `npx tsx scripts/smoke-content.ts`
|
||||
3. `npm run check:encoding`
|
||||
|
||||
并额外确认:
|
||||
|
||||
1. 全仓库代码中不再引用 `sceneObservation`、`questDirector`、`syncCustomWorldSavedProfileAssets`。
|
||||
2. `buildStateFunctionDefinitions()` 中不会出现 `battle_attack_basic` / `battle_use_skill`,这两个 function 只由后端运行时 option 池下发。
|
||||
|
||||
---
|
||||
|
||||
## 6. 当前结论
|
||||
|
||||
本批次后,静态入口扫描中剩余的高置信“不可达源码”已经收敛为测试辅助、测试夹具和 smoke helper。继续删除前需要先重构测试基础设施或迁移剩余前端 SDK,而不应再按文件名或历史命名直接硬删。
|
||||
@@ -0,0 +1,553 @@
|
||||
# 前端应迁后端逻辑审计(2026-04-21)
|
||||
|
||||
更新时间:`2026-04-21`
|
||||
|
||||
## 0. 审计目标
|
||||
|
||||
这份文档只回答一个问题:
|
||||
|
||||
**当前前端代码里,哪些逻辑已经明显越过“前端只做表现,Express 后端负责逻辑、数据与存储”的边界,应该继续迁到后端。**
|
||||
|
||||
本轮不改业务代码,只做:
|
||||
|
||||
1. 基于当前仓库状态给出高置信度候选点
|
||||
2. 标明代码证据
|
||||
3. 给出迁移优先级
|
||||
4. 说明迁移后前端应该保留什么、移走什么
|
||||
|
||||
---
|
||||
|
||||
## 1. 结论先行
|
||||
|
||||
结合当前代码与已有边界文档,前端里仍有 7 类逻辑应该继续后移:
|
||||
|
||||
1. **运行时快照前置写入与本地镜像解释**
|
||||
2. **鉴权 token 的浏览器本地真相**
|
||||
3. **平台浏览历史的本地真相与迁移状态**
|
||||
4. **NPC 待接委托“换单”仍由前端直接触发正式生成**
|
||||
5. **quest/runtime item 的双环境混合编排**
|
||||
6. **浏览器侧大型 AI orchestration 与 prompt/repair/fallback 主链**
|
||||
7. **NPC 招募对白之后的正式结算链路**
|
||||
|
||||
一句话判断:
|
||||
|
||||
**当前前端已经不是最早那种“大量主算”的状态,但仍然保留了运行时镜像、生成编排和部分正式真相。后端边界还需要再收一轮,前端才算真正退回表现层。**
|
||||
|
||||
---
|
||||
|
||||
## 2. 审计依据
|
||||
|
||||
### 2.1 文档依据
|
||||
|
||||
1. `docs/experience/PROJECT_WORK_EXPERIENCE_PLAYBOOK.md`
|
||||
2. `docs/technical/CURRENT_BACKEND_IMPLEMENTATION_BASELINE_2026-04-25.md`
|
||||
3. `docs/technical/RUNTIME_STORY_BACKEND_BOUNDARY_MIGRATION_2026-04-19.md`
|
||||
4. `docs/audits/engineering/ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-20.md`
|
||||
5. `docs/audits/engineering/CURRENT_ENGINEERING_OPTIMIZATION_OPPORTUNITIES_2026-04-20.md`
|
||||
|
||||
### 2.2 当前代码依据
|
||||
|
||||
1. `src/hooks/story/runtimeStoryCoordinator.ts`
|
||||
2. `src/services/apiClient.ts`
|
||||
3. `src/services/platformBrowseHistory.ts`
|
||||
4. `src/components/game-shell/PreGameSelectionFlow.tsx`
|
||||
5. `src/hooks/story/npcEncounterActions.ts`
|
||||
6. `src/services/questDirector.ts`
|
||||
7. `src/services/runtimeItemAiDirector.ts`
|
||||
8. `src/services/ai.ts`
|
||||
|
||||
---
|
||||
|
||||
## 3. 当前高置信度应后移逻辑
|
||||
|
||||
## 3.0 本轮已完成后移
|
||||
|
||||
以下链路已在本轮或上一轮连续落地中完成后移,不再属于“仍残留在前端”的正式主链:
|
||||
|
||||
1. access token 浏览器本地真相
|
||||
2. browse history 本地真相
|
||||
3. runtime story 前置 `PUT /runtime/save/snapshot`
|
||||
4. NPC 待接委托 `replace / abandon / accept`
|
||||
5. custom world profile 正式浏览器入口
|
||||
6. `questDirector` / `runtimeItemAiDirector` 浏览器正式编排
|
||||
7. NPC 招募正式结算
|
||||
|
||||
其中 NPC 招募已从“前端本地改 companions / roster / npcStates / storyHistory”收回到后端 runtime action。
|
||||
|
||||
## 3.1 运行时快照前置写入仍在前端
|
||||
|
||||
### 代码证据
|
||||
|
||||
`src/hooks/story/runtimeStoryCoordinator.ts` 当前仍存在以下链路:
|
||||
|
||||
1. `syncRuntimeSnapshot(...)`
|
||||
2. `syncRuntimeSnapshot(...)` 内部直接调用 `putSaveSnapshot(...)`
|
||||
3. `loadServerRuntimeOptionCatalog(...)` 在请求 `getRuntimeStoryState(...)` 之前先写本地快照
|
||||
4. `resolveServerRuntimeChoice(...)` 在请求 `resolveRuntimeStoryAction(...)` 之前先写本地快照
|
||||
|
||||
对应位置:
|
||||
|
||||
1. `src/hooks/story/runtimeStoryCoordinator.ts:21`
|
||||
2. `src/hooks/story/runtimeStoryCoordinator.ts:25`
|
||||
3. `src/hooks/story/runtimeStoryCoordinator.ts:36`
|
||||
4. `src/hooks/story/runtimeStoryCoordinator.ts:99`
|
||||
|
||||
### 当前问题
|
||||
|
||||
这意味着运行时正式动作发起前,前端仍会先落一份自己的快照真相,再去请求后端。
|
||||
|
||||
这条链的问题不是“有没有缓存”,而是:
|
||||
|
||||
1. 前端仍在承担正式提交前的状态镜像
|
||||
2. 快照解释权没有完全收回到后端
|
||||
3. 运行时主链仍处于“本地镜像 + 服务端会话”并存状态
|
||||
|
||||
### 迁移建议
|
||||
|
||||
后端继续承接:
|
||||
|
||||
1. 运行时快照写入
|
||||
2. 快照版本解释
|
||||
3. 动作提交前的状态一致性校验
|
||||
|
||||
前端只保留:
|
||||
|
||||
1. 当前展示用的 view model
|
||||
2. 可选的只读恢复缓存
|
||||
3. 纯表现态的 loading / transition / animation state
|
||||
|
||||
### 优先级
|
||||
|
||||
`P0`
|
||||
|
||||
---
|
||||
|
||||
## 3.2 鉴权 token 仍由前端 localStorage 持有真相
|
||||
|
||||
### 代码证据
|
||||
|
||||
`src/services/apiClient.ts` 当前仍直接访问 `window.localStorage` 保存 access token:
|
||||
|
||||
1. `getStoredAccessToken()`
|
||||
2. `setStoredAccessToken(...)`
|
||||
3. `clearStoredAccessToken(...)`
|
||||
4. `withAuthorizationHeaders(...)` 直接从本地 token 组装请求头
|
||||
|
||||
对应位置:
|
||||
|
||||
1. `src/services/apiClient.ts:333`
|
||||
2. `src/services/apiClient.ts:341`
|
||||
3. `src/services/apiClient.ts:362`
|
||||
4. `src/services/apiClient.ts:382`
|
||||
|
||||
### 当前问题
|
||||
|
||||
第三批清理已经收掉了“自动登录用户名/密码”本地真相,但 access token 仍然由浏览器长期持有。
|
||||
|
||||
这在当前项目边界下仍有两个问题:
|
||||
|
||||
1. 正式鉴权真相仍没有完全收回后端 session 边界
|
||||
2. 前端 SDK 仍然负担 token 生命周期的关键部分
|
||||
|
||||
### 迁移建议
|
||||
|
||||
后端继续承接:
|
||||
|
||||
1. session / refresh / cookie 真相
|
||||
2. 鉴权状态续期
|
||||
3. token 更新与失效策略
|
||||
|
||||
前端只保留:
|
||||
|
||||
1. 当前是否已登录的展示态
|
||||
2. 统一的请求封装
|
||||
3. 401 后的 UI 响应
|
||||
|
||||
### 优先级
|
||||
|
||||
`P0`
|
||||
|
||||
---
|
||||
|
||||
## 3.3 平台浏览历史仍是“前端本地历史 + 后端回填”的双真相
|
||||
|
||||
### 代码证据
|
||||
|
||||
`src/services/platformBrowseHistory.ts` 当前仍维护一整套本地历史真相:
|
||||
|
||||
1. `readPlatformBrowseHistory(...)`
|
||||
2. `writePlatformBrowseHistory(...)`
|
||||
3. `hasPendingPlatformBrowseHistoryMigration(...)`
|
||||
4. `markPlatformBrowseHistoryMigrated(...)`
|
||||
|
||||
对应位置:
|
||||
|
||||
1. `src/services/platformBrowseHistory.ts:77`
|
||||
2. `src/services/platformBrowseHistory.ts:103`
|
||||
3. `src/services/platformBrowseHistory.ts:151`
|
||||
4. `src/services/platformBrowseHistory.ts:164`
|
||||
|
||||
`src/components/game-shell/PreGameSelectionFlow.tsx` 当前仍显式做:
|
||||
|
||||
1. 先 `writePlatformBrowseHistory(...)`
|
||||
2. 再调用 `upsertProfileBrowseHistory(...)`
|
||||
3. 同步成功后 `markPlatformBrowseHistoryMigrated(...)`
|
||||
4. 启动阶段读取 `readPlatformBrowseHistory(...)`
|
||||
5. 根据 `hasPendingPlatformBrowseHistoryMigration(...)` 决定是否补同步
|
||||
|
||||
对应位置:
|
||||
|
||||
1. `src/components/game-shell/PreGameSelectionFlow.tsx:383`
|
||||
2. `src/components/game-shell/PreGameSelectionFlow.tsx:392`
|
||||
3. `src/components/game-shell/PreGameSelectionFlow.tsx:394`
|
||||
4. `src/components/game-shell/PreGameSelectionFlow.tsx:433`
|
||||
5. `src/components/game-shell/PreGameSelectionFlow.tsx:466`
|
||||
|
||||
### 当前问题
|
||||
|
||||
这条链已经不是单纯缓存,而是:
|
||||
|
||||
1. 本地历史存储
|
||||
2. 本地同步标记
|
||||
3. 后端历史持久化
|
||||
|
||||
三套状态同时存在。
|
||||
|
||||
### 迁移建议
|
||||
|
||||
后端继续承接:
|
||||
|
||||
1. 浏览历史唯一持久化真相
|
||||
2. 历史去重、排序、截断
|
||||
3. 迁移完成标记
|
||||
|
||||
前端只保留:
|
||||
|
||||
1. 展示缓存
|
||||
2. 弱网下的临时 optimistic UI
|
||||
3. 刷新后重新拉取远端结果
|
||||
|
||||
### 优先级
|
||||
|
||||
`P1`
|
||||
|
||||
---
|
||||
|
||||
## 3.4 NPC 待接委托“换单”仍由前端直接发起正式生成
|
||||
|
||||
### 代码证据
|
||||
|
||||
`src/hooks/story/npcEncounterActions.ts` 当前仍保留:
|
||||
|
||||
1. `replacePendingNpcQuestOffer = async () => { ... }`
|
||||
2. 内部直接调用 `generateQuestForNpcEncounter(...)`
|
||||
|
||||
对应位置:
|
||||
|
||||
1. `src/hooks/story/npcEncounterActions.ts:1561`
|
||||
2. `src/hooks/story/npcEncounterActions.ts:1595`
|
||||
|
||||
### 当前问题
|
||||
|
||||
聊天后是否挂出待接委托已经后移,但“换一份委托”这条分支仍然是:
|
||||
|
||||
1. 前端组装上下文
|
||||
2. 前端决定调用生成
|
||||
3. 前端直接把结果写回当前 story UI
|
||||
|
||||
这仍属于正式运行时任务编排没有收干净。
|
||||
|
||||
### 迁移建议
|
||||
|
||||
后端继续承接:
|
||||
|
||||
1. NPC 待接委托换单决策
|
||||
2. 是否允许换单
|
||||
3. 换单后的任务草案生成
|
||||
4. 对应聊天态快照回填
|
||||
|
||||
前端只保留:
|
||||
|
||||
1. 点击“换一份委托”
|
||||
2. loading / error 展示
|
||||
3. 消费后端返回的新 pending quest offer
|
||||
|
||||
### 优先级
|
||||
|
||||
`P0`
|
||||
|
||||
---
|
||||
|
||||
## 3.5 questDirector 仍是前端 SDK 与生成编排混合体
|
||||
|
||||
### 代码证据
|
||||
|
||||
`src/services/questDirector.ts` 当前同时承担:
|
||||
|
||||
1. `generateQuestForNpcEncounter(...)`
|
||||
2. 浏览器路径 `requestJson('/api/runtime/quests/generate')`
|
||||
3. 非浏览器路径 `requestChatMessageContent(...)`
|
||||
4. 本地 `compileQuestIntentToQuest(...)` fallback
|
||||
|
||||
对应位置:
|
||||
|
||||
1. `src/services/questDirector.ts:213`
|
||||
2. `src/services/questDirector.ts:242`
|
||||
3. `src/services/questDirector.ts:267`
|
||||
4. `src/services/questDirector.ts:256`
|
||||
5. `src/services/questDirector.ts:281`
|
||||
6. `src/services/questDirector.ts:293`
|
||||
|
||||
### 当前问题
|
||||
|
||||
这类文件虽然浏览器正式路径已经优先走后端,但职责仍混在一起:
|
||||
|
||||
1. 前端 SDK
|
||||
2. Quest prompt 编排
|
||||
3. Quest intent 解析
|
||||
4. deterministic fallback compile
|
||||
|
||||
这会导致边界长期模糊,也让前端仍像“半个服务端”。
|
||||
|
||||
### 迁移建议
|
||||
|
||||
后端继续承接:
|
||||
|
||||
1. quest intent 生成
|
||||
2. prompt 组装
|
||||
3. JSON 解析
|
||||
4. fallback compile
|
||||
|
||||
前端只保留:
|
||||
|
||||
1. `requestGenerateQuest(...)` 这类轻量 SDK
|
||||
2. 请求参数组装
|
||||
3. 结果消费
|
||||
|
||||
### 优先级
|
||||
|
||||
`P1`
|
||||
|
||||
---
|
||||
|
||||
## 3.6 runtimeItemAiDirector 仍是前端 SDK 与意图生成混合体
|
||||
|
||||
### 代码证据
|
||||
|
||||
`src/services/runtimeItemAiDirector.ts` 当前同时承担:
|
||||
|
||||
1. `generateRuntimeItemAiIntents(...)`
|
||||
2. 浏览器路径 `requestJson('/api/runtime/items/runtime-intent')`
|
||||
3. 非浏览器路径 `requestChatMessageContent(...)`
|
||||
4. 本地 `buildRuntimeItemAiIntent(...)` fallback
|
||||
|
||||
对应位置:
|
||||
|
||||
1. `src/services/runtimeItemAiDirector.ts:84`
|
||||
2. `src/services/runtimeItemAiDirector.ts:94`
|
||||
3. `src/services/runtimeItemAiDirector.ts:118`
|
||||
|
||||
### 当前问题
|
||||
|
||||
它和 `questDirector` 是同类问题:
|
||||
|
||||
1. 正式浏览器路径已经走后端
|
||||
2. 但前端文件仍然承担完整生成逻辑认知
|
||||
3. 文件职责仍然是双环境混合
|
||||
|
||||
### 迁移建议
|
||||
|
||||
后端继续承接:
|
||||
|
||||
1. runtime item intent prompt
|
||||
2. 模型调用
|
||||
3. 结果解析与 fallback
|
||||
|
||||
前端只保留:
|
||||
|
||||
1. 轻量请求 SDK
|
||||
2. 结果到 UI 的映射
|
||||
|
||||
### 优先级
|
||||
|
||||
`P1`
|
||||
|
||||
---
|
||||
|
||||
## 3.7 `src/services/ai.ts` 仍是浏览器侧正式 AI orchestration 热点
|
||||
|
||||
### 代码证据
|
||||
|
||||
当前 `src/services/ai.ts` 仍直接承担以下正式链路:
|
||||
|
||||
1. `requestChatMessageContent(...)`
|
||||
2. `requestPlainTextCompletionFromClient(...)`
|
||||
3. `streamPlainTextCompletionFromClient(...)`
|
||||
4. `generateCustomWorldProfile(...)`
|
||||
5. `generateInitialStory(...)`
|
||||
6. `generateNextStep(...)`
|
||||
7. `streamNpcChatDialogue(...)`
|
||||
8. `streamNpcRecruitDialogue(...)`
|
||||
|
||||
对应位置:
|
||||
|
||||
1. `src/services/ai.ts:1732`
|
||||
2. `src/services/ai.ts:1868`
|
||||
3. `src/services/ai.ts:2038`
|
||||
4. `src/services/ai.ts:2339`
|
||||
5. `src/services/ai.ts:2447`
|
||||
6. `src/services/ai.ts:2487`
|
||||
7. `src/services/ai.ts:2529`
|
||||
8. `src/services/ai.ts:2570`
|
||||
|
||||
并且文件内仍保留:
|
||||
|
||||
1. JSON repair
|
||||
2. prompt 组装
|
||||
3. response normalize
|
||||
4. fallback/offline 响应
|
||||
5. 角色聊天建议与摘要生成
|
||||
|
||||
### 当前问题
|
||||
|
||||
这说明浏览器端并不只是“请求一个后端接口”,而是还在承担:
|
||||
|
||||
1. prompt source
|
||||
2. 生成策略
|
||||
3. 错误修复
|
||||
4. fallback 编排
|
||||
5. 多类业务场景的正式 AI 出口
|
||||
|
||||
这与“前端只做表现”存在明确冲突。
|
||||
|
||||
### 迁移建议
|
||||
|
||||
后端继续承接:
|
||||
|
||||
1. story / npc / recruit / custom-world 的 prompt 编排
|
||||
2. JSON repair
|
||||
3. fallback 策略
|
||||
4. streaming orchestration
|
||||
5. 模型调用与日志
|
||||
|
||||
前端只保留:
|
||||
|
||||
1. 轻量 AI SDK
|
||||
2. SSE 文本流展示
|
||||
3. UI fallback 呈现
|
||||
|
||||
### 优先级
|
||||
|
||||
`P0`
|
||||
|
||||
---
|
||||
|
||||
## 3.8 NPC 招募对白之后的正式结算链路已完成后移
|
||||
|
||||
### 本轮前状态
|
||||
|
||||
迁移前,`src/hooks/story/npcInteraction.ts` 中的 `buildRecruitmentOutcome / executeRecruitment / startRecruitmentSequence` 仍在前端本地正式结算:
|
||||
|
||||
1. 改 `npcStates`
|
||||
2. 改 `companions`
|
||||
3. 改 `roster`
|
||||
4. 清 `currentEncounter / inBattle / sceneHostileNpcs`
|
||||
5. 直接写 `storyHistory`
|
||||
6. 再触发后续剧情推进
|
||||
|
||||
这与“前端只做表现,所有正式逻辑、数据都放到 Express 后端”直接冲突。
|
||||
|
||||
### 本轮后状态
|
||||
|
||||
本轮已完成:
|
||||
|
||||
1. `server-node/src/modules/story/runtimeSession.ts`
|
||||
- 正式承接完整 `companions`
|
||||
- 正式承接 `roster`
|
||||
2. `server-node/src/modules/npc/npcInteractionService.ts`
|
||||
- `npc_recruit` 已支持正常入队
|
||||
- `npc_recruit` 已支持满员换队招募
|
||||
3. `src/hooks/story/npcInteraction.ts`
|
||||
- 前端只保留招募对白流式展示
|
||||
- 正式招募结算改为调用后端 runtime action
|
||||
|
||||
### 当前判断
|
||||
|
||||
这一项已不再属于前端残留正式逻辑。
|
||||
|
||||
---
|
||||
|
||||
## 4. 可以暂时保留在前端的部分
|
||||
|
||||
下面这些内容即使和上述模块同文件出现,也不属于必须后移的对象:
|
||||
|
||||
1. 面板开关、loading、error、streaming 文本展示
|
||||
2. 动画时间线、过场状态、临时 UI 回显
|
||||
3. 表单草稿、筛选词、排序选项
|
||||
4. 只影响表现、不影响正式真相的 view model 拼接
|
||||
|
||||
迁移时要注意:
|
||||
|
||||
**不是把所有前端代码都往后端搬,而是把“正式状态解释、规则裁决、生成编排、持久化真相”搬走。**
|
||||
|
||||
---
|
||||
|
||||
## 5. 推荐迁移顺序
|
||||
|
||||
## 5.1 第一阶段
|
||||
|
||||
先收最危险的正式真相:
|
||||
|
||||
1. `runtimeStoryCoordinator.ts`
|
||||
2. `apiClient.ts`
|
||||
3. `npcEncounterActions.ts` 里的 quest replace 分支
|
||||
|
||||
原因:
|
||||
|
||||
1. 这三处最直接影响运行时真相和动作主链
|
||||
2. 不先收这些,前端仍然不是纯表现层
|
||||
|
||||
## 5.2 第二阶段
|
||||
|
||||
再拆双环境混合服务:
|
||||
|
||||
1. `questDirector.ts`
|
||||
2. `runtimeItemAiDirector.ts`
|
||||
3. `platformBrowseHistory.ts`
|
||||
|
||||
原因:
|
||||
|
||||
1. 这几处已经有后端承接基础
|
||||
2. 迁移成本相对可控
|
||||
|
||||
## 5.3 第三阶段
|
||||
|
||||
最后继续压缩浏览器 AI orchestration:
|
||||
|
||||
1. `src/services/ai.ts`
|
||||
2. 相关 prompt builder / repair helper / offline fallback
|
||||
|
||||
原因:
|
||||
|
||||
1. 这部分体量大
|
||||
2. 链路多
|
||||
3. 更适合在前两阶段把 contract 稳住后集中拆
|
||||
|
||||
---
|
||||
|
||||
## 6. 建议产出物
|
||||
|
||||
如果后续按这份文档继续落地,建议每一批都至少同步产出:
|
||||
|
||||
1. 一份落地文档,说明迁移了哪条链
|
||||
2. 一组 contract/route 变更说明
|
||||
3. 一组前端 SDK 收缩说明
|
||||
4. 一组防回退测试
|
||||
|
||||
---
|
||||
|
||||
## 7. 一句话结论
|
||||
|
||||
当前前端最需要继续后移的,不是零散小工具,而是:
|
||||
|
||||
**运行时快照前置写入、鉴权 token、本地浏览历史真相、NPC 委托换单、quest/runtime item 双环境混合编排,以及 `src/services/ai.ts` 里仍然留在浏览器的正式 AI orchestration。**
|
||||
@@ -0,0 +1,173 @@
|
||||
# 怪物-NPC 脚本统一整改审计
|
||||
|
||||
日期:2026-04-06
|
||||
|
||||
## 核心结论
|
||||
|
||||
当前工程仍然没有真正落实“怪物就是初始好感度为负数的 NPC”这一原则。
|
||||
|
||||
现状不是“NPC 脚本里支持 hostile 状态”,而是同时存在两条并行链路:
|
||||
|
||||
1. `npc / encounter / npcStates / npcInteraction`
|
||||
2. `monster / hostileNpc / sceneMonsters / sceneHostileNpcs / hostileNpcPresets`
|
||||
|
||||
这会直接导致:
|
||||
|
||||
- 同一个敌对实体同时拥有 NPC 身份和 monster 身份。
|
||||
- 场景、战斗、渲染、提示词都在维护两套入口。
|
||||
- 后续修 bug 时,任何位置、死亡、血条、入场、掉落问题都要同时查两条链路。
|
||||
|
||||
本次文档的目标不是立刻改代码,而是先把应该删除的分叉脚本、应该降级成素材层的文件、以及必须合并的字段全部列清楚,作为后续统一改造的依据。
|
||||
|
||||
## 当前违背原则的根因
|
||||
|
||||
### 1. 场景数据仍然把“怪物”和“NPC”当成两类实体
|
||||
|
||||
当前场景层同时维护:
|
||||
|
||||
- `ScenePreset.monsterIds`
|
||||
- `SceneNpc[]`
|
||||
- `ScenePresetInfo.hostileNpcIds`
|
||||
- `SceneNpc.monsterPresetId / hostileNpcPresetId`
|
||||
|
||||
这意味着场景里一个敌对单位既可以来自 `monsterIds`,也可以来自 `npcs`,甚至会被脚本再生成为 hostile scene npc。
|
||||
|
||||
### 2. 运行时仍然存在“怪物专用实体状态”
|
||||
|
||||
当前运行时仍然同时维护:
|
||||
|
||||
- `GameState.sceneMonsters`
|
||||
- `GameState.sceneHostileNpcs`
|
||||
- `SceneHostileNpc / SceneMonster`
|
||||
|
||||
这和“怪物本质上只是 hostile NPC”是冲突的。真正统一后,运行时只应该保留一套“场景 NPC / 战斗 NPC”状态。
|
||||
|
||||
### 3. 战斗脚本仍然把怪物当独立 actor
|
||||
|
||||
战斗层目前不是“NPC 战斗,只是 hostile 的那部分会出手”,而是显式写了:
|
||||
|
||||
- `TurnActor = 'player' | 'companion' | 'monster'`
|
||||
- `getClosestMonster`
|
||||
- `resetCombatPresentation(monsters, ...)`
|
||||
- `sceneMonsters` 全链路结算
|
||||
|
||||
这会强制后面所有视觉、掉落、提示词、AI 上下文都跟着叫 monster。
|
||||
|
||||
### 4. 渲染层仍然有 monster 专属显示入口
|
||||
|
||||
画布层当前仍然依赖:
|
||||
|
||||
- `sceneMonsters`
|
||||
- `sceneHostileNpcs`
|
||||
- `monsterPresetId`
|
||||
- `HostileNpcAnimator`
|
||||
|
||||
也就是“敌对 NPC 是否按 NPC 脚本渲染”这件事,到最终显示层仍然没有统一。
|
||||
|
||||
## 一级删除清单
|
||||
|
||||
下面这些文件属于“业务流程分叉脚本”,不是单纯资源适配层。后续统一时应优先删除或并入 NPC 主链路。
|
||||
|
||||
| 文件 | 当前分叉角色 | 处理建议 |
|
||||
| --- | --- | --- |
|
||||
| `src/data/monsters.ts` | 对 `hostileNpcs.ts` 的别名出口 | 直接删除,禁止继续保留 monster 专属入口名。 |
|
||||
| `src/data/hostileNpcs.ts` | 负责 monster 创建、编队、距离、朝向、变化、落位 | 按 hostile NPC 运行时工具重写并并入 NPC 体系;原文件名不应继续保留。 |
|
||||
| `src/data/sceneEncounterPreviews.ts` | 单独构造 hostile encounter group、auto battle、hostile preview | 删除 monster 专线逻辑,改为“负好感 NPC 预览/入场/转战斗”。 |
|
||||
| `src/hooks/combat/battlePlan.ts` | 使用 `monster` actor、`sceneMonsters`、`getClosestMonster` | 改成统一的 hostile NPC combatant 规划脚本;monster actor 概念应移除。 |
|
||||
| `src/hooks/combat/playback.ts` | 使用 `sceneMonsters` 播放怪物战斗演出 | 改成统一 NPC 战斗回放;不再区分 monster 播放器。 |
|
||||
| `src/components/game-canvas/GameCanvasRuntime.tsx` | 运行时按 `sceneMonsters / sceneHostileNpcs` 双数据源选敌方实体 | 删除双源兜底,统一成单一 hostile NPC 列表。 |
|
||||
| `src/components/game-canvas/GameCanvasEntityLayer.tsx` | 敌方实体按 monsterPreset 分支渲染 | 改成同一套 NPC 实体渲染,视觉差异仅由 visual preset 决定。 |
|
||||
| `src/components/game-canvas/GameCanvasShared.tsx` | 定义 `sceneMonsters / sceneHostileNpcs` props 与 monster 专属计算 | 删除这些字段与 helper,改成统一 NPC 画布协议。 |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | 独立怪物预设编辑面板 | 并回 NPC hostile visual preset 面板,或删除该独立编辑器入口。 |
|
||||
| `src/components/preset-editor/MonsterPresetTab.tsx` | 独立怪物预设页签 | 与上面一并删除或并入 NPC preset 编辑器。 |
|
||||
| `src/components/preset-editor/ScenePresetPanel.tsx` | 仍然单独编辑 `monsterIds` | 删除 `monsterIds` 编辑项,只保留场景 NPC 列表。 |
|
||||
|
||||
## 二级归并清单
|
||||
|
||||
下面这些文件不一定需要物理删除,但它们当前仍然在放大 monster / NPC 分轨,必须在统一改造时一起收口。
|
||||
|
||||
| 文件 | 当前问题 | 处理建议 |
|
||||
| --- | --- | --- |
|
||||
| `src/data/scenePresets.ts` | 通过 `monsterIds` 再生 hostile scene npc,并区分 `getSceneHostileNpcs / getSceneFriendlyNpcs` | 保留场景数据文件本身,但删除 `monsterIds` 体系,让敌对角色直接存在于 `npcs` 中。 |
|
||||
| `src/data/customWorldNpcMonsters.ts` | 用单独脚本推导“怪物型 NPC”预设 | 可保留为 hostile visual preset 选择器,但不能再生成第二套实体语义。 |
|
||||
| `src/data/hostileNpcPresets.ts` | 目前既是视觉预设库,也是独立 hostile 流程的数据源 | 降级为 hostile visual/combat preset 库;不再拥有独立实体生命周期。 |
|
||||
| `src/components/HostileNpcAnimator.tsx` | 当前名字和调用语义都在暗示“独立怪物实体” | 可以保留为贴图播放器,但应改为 hostile NPC 的视觉适配组件,而不是独立物种脚本。 |
|
||||
| `src/components/AdventureEntityModal.tsx` | 详情弹窗仍会优先查 monster preset / hostileNpcPreset | 统一读取 NPC 档案;视觉差异只通过 hostile preset 补充。 |
|
||||
| `src/components/SkillEffectPreview.tsx` | 预览器直接使用 `sceneMonsters` 和 `createSceneMonstersFromIds` | 改成统一 hostile NPC 预览态。 |
|
||||
| `src/components/StateFunctionEditor.tsx` | 编辑器里仍然直接造 monster battle preview | 改成 hostile NPC preview。 |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | 仍然暴露 `monsterPresetId` 字段 | 改成更明确的 hostile visual preset 字段,避免“怪物类型”和“NPC 类型”双语义。 |
|
||||
| `src/hooks/story/npcEncounterActions.ts` | 虽然入口叫 npc,但内部仍然写 `sceneMonsters / sceneHostileNpcs` | 改成统一 hostile NPC 战斗状态字段。 |
|
||||
| `src/hooks/story/choiceActions.ts` | 仍然有 `buildHostileNpcBattleReward` 和 `getResolvedSceneHostileNpcs` 这一层额外概念 | 统一到 hostile NPC 结算工具,不再把“敌对 NPC”和“monster”混称。 |
|
||||
| `src/hooks/useStoryGeneration.ts` | 给 AI/剧情层传入 `sceneMonsters` 或 `sceneHostileNpcs` | 改成统一的 hostile NPC 上下文切片。 |
|
||||
| `src/services/prompt.ts` | 仍然从 `monsterIds` 和 `createSceneMonstersFromIds` 组 prompt | 改成从场景 NPC 列表中筛出 hostile NPC。 |
|
||||
| `src/services/questDirector.ts` | 仍然依赖 `monsterPresetId` 推导当前敌对目标 | 统一改为基于负好感或 hostile 标记的 NPC。 |
|
||||
| `src/services/ai.ts` | 仍然混用 `monsterIds`、sceneNpc 的 hostile 判定 | 与场景统一后改成只读 NPC 列表。 |
|
||||
| `src/services/questTypes.ts` | 仍然把 `hostileNpcIds / monsterIds` 当作 scene 快照字段 | 删除 `monsterIds`,保留 hostile NPC 语义。 |
|
||||
|
||||
## 可保留但必须降级为“素材/配置层”的内容
|
||||
|
||||
下面这些内容不一定要消失,但不能继续作为独立业务链路存在:
|
||||
|
||||
| 文件/内容 | 可以保留的原因 | 必须收口的边界 |
|
||||
| --- | --- | --- |
|
||||
| `src/components/HostileNpcAnimator.tsx` | 怪物贴图是特殊资源,需要专门 sprite sheet 播放器 | 只负责画图,不再决定实体类型、战斗身份、交互入口。 |
|
||||
| `src/data/hostileNpcPresets.ts` | hostile visual/combat preset 仍然有价值 | 只能作为 hostile NPC 的 visual/combat preset 库,不再驱动另一套“monster 实体”。 |
|
||||
| `src/data/hostileNpcOverrides.json` | 资源级 override 仍可继续用 | 不能再配套出独立 hostile 流程。 |
|
||||
| `src/data/monsterOverrides.json` | 如果只是素材映射,可迁移到 hostile visual preset override | 不应继续以 monster 专属命名长期存在。 |
|
||||
| `src/data/customWorldNpcMonsters.ts` | 自定义世界里确实需要从文本匹配 hostile visual preset | 只能产出“NPC 使用哪个 hostile visual preset”,不能产出独立 monster 身份。 |
|
||||
|
||||
## 字段级必须合并的内容
|
||||
|
||||
后续改代码时,至少要把下面这些字段和类型一起收口:
|
||||
|
||||
| 当前字段/类型 | 问题 | 合并方向 |
|
||||
| --- | --- | --- |
|
||||
| `ScenePreset.monsterIds` | 场景里额外保存一份怪物池 | 删除,只保留 `npcs`。 |
|
||||
| `ScenePresetInfo.hostileNpcIds` | 历史遗留双字段 | 直接由 `npcs.filter(initialAffinity < 0 或 hostile)` 推导。 |
|
||||
| `Encounter.monsterPresetId` | 把 hostile NPC 再次物种化 | 改成 hostile visual preset 字段,或并入统一 visualRef。 |
|
||||
| `Encounter.hostileNpcPresetId` | 与 `monsterPresetId` 语义重叠 | 与上面合并为一个字段。 |
|
||||
| `GameState.sceneMonsters` | 把敌对 NPC 单独塞进 monster 容器 | 改成统一 `sceneNpcCombatants` 或等价单一列表。 |
|
||||
| `GameState.sceneHostileNpcs` | 历史兼容层,导致双数据源 | 删除。 |
|
||||
| `SceneHostileNpc / SceneMonster` | 类型名直接固化了分轨 | 改成统一的 hostile NPC / scene combat NPC 类型。 |
|
||||
| `SceneHostileNpcChange / SceneMonsterChange` | 继续复制同一套变更结构 | 合并成统一 NPC scene change。 |
|
||||
| `SceneNpc.monsterPresetId / hostileNpcPresetId` | 同一实体上挂两套 preset 入口 | 收敛为一个 hostile visual/combat preset 字段。 |
|
||||
|
||||
## 本轮最优先的删除顺序
|
||||
|
||||
建议后续真正改代码时,按下面顺序删并,风险最低:
|
||||
|
||||
1. 先删字段入口:`monsterIds / sceneHostileNpcs / hostileNpcPresetId`
|
||||
2. 再删运行时双轨:`src/data/monsters.ts`、`src/data/hostileNpcs.ts`、`src/data/sceneEncounterPreviews.ts`
|
||||
3. 再删战斗双轨:`battlePlan.ts`、`playback.ts` 里的 `monster` actor 与 `sceneMonsters`
|
||||
4. 再删画布双轨:`GameCanvasRuntime.tsx`、`GameCanvasEntityLayer.tsx`、`GameCanvasShared.tsx`
|
||||
5. 最后清编辑器和提示词:`MonsterPresetPanel.tsx`、`MonsterPresetTab.tsx`、`prompt.ts`、`questDirector.ts`
|
||||
|
||||
## 改造后的目标形态
|
||||
|
||||
统一后应只剩下这一套语义:
|
||||
|
||||
- 场景中所有可见角色都放在 `npcs`
|
||||
- 怪物 = `initialAffinity < 0` 或 `hostile = true` 的 NPC
|
||||
- hostile 的视觉差异只来自 hostile visual preset
|
||||
- 战斗中所有敌方单位都属于 hostile NPC combatant
|
||||
- AI、任务、渲染、详情、掉落都只读同一套 NPC 数据
|
||||
|
||||
如果后面代码里还出现下面这些关键词,基本都说明分轨没有删干净:
|
||||
|
||||
- `sceneMonsters`
|
||||
- `sceneHostileNpcs`
|
||||
- `monsterIds`
|
||||
- `hostileNpcPresetId`
|
||||
- `createSceneMonstersFromIds`
|
||||
- `getClosestMonster`
|
||||
- `TurnActor = 'monster'`
|
||||
|
||||
## 这份文档的使用方式
|
||||
|
||||
后续正式开始改造时,建议把文件分成三批执行:
|
||||
|
||||
1. “直接删掉”的入口脚本
|
||||
2. “改名并并回 NPC 主链路”的桥接脚本
|
||||
3. “仅保留素材职责”的 renderer / preset 文件
|
||||
|
||||
不要继续接受“名字叫 NPC,但内部仍然先转成 monster 再跑”的中间态。
|
||||
46
docs/audits/engineering/README.md
Normal file
46
docs/audits/engineering/README.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# 工程优化审查总览
|
||||
|
||||
这一组只保留仍能指导当前 Rust / SpacetimeDB 主线的工程审查入口。早期连续扫描的有效结论已经合并到本 README 的“融合结论”,不再保留逐日旧稿。
|
||||
|
||||
## 当前推荐入口
|
||||
|
||||
1. [SERVER_NODE_FREEZE_AND_DEPRECATION_2026-04-24.md](./SERVER_NODE_FREEZE_AND_DEPRECATION_2026-04-24.md)
|
||||
这一版是旧 Node 后端冻结、第一批物理删除与后续批次边界记录,明确当前工程只保留 Rust / SpacetimeDB 主线入口。
|
||||
2. [ENGINEERING_DEAD_CODE_CLEANUP_BATCH_F_2026-04-21.md](./ENGINEERING_DEAD_CODE_CLEANUP_BATCH_F_2026-04-21.md)
|
||||
这一版是第六批落地记录,聚焦删除无入口 `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)
|
||||
这一版是本轮前端越界逻辑专项审计,专门汇总当前仍应继续迁到 `server-rs` 的运行时、鉴权、生成编排与本地真相残留。
|
||||
5. [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)
|
||||
这一版是第三批落地记录,聚焦鉴权真相收口,先移除前端保存自动登录用户名/密码的本地真相,并明确运行时快照前置写入为什么当前还不能硬砍。
|
||||
7. [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)
|
||||
这一版是第一批落地记录,聚焦高置信度小型孤岛、prompt 壳子、stub 和无入口 modal 的首轮清理。
|
||||
9. [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)
|
||||
这一版是对 `2026-04-19` 基线的当前仓库复核,明确哪些问题已经处理、哪些表述需要纠正、热点又迁移到了哪里。
|
||||
11. [ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-19.md](./ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-19.md)
|
||||
这一版保留原始问题快照和执行回填,适合回看“为什么会有这轮清理与边界收口”。
|
||||
## 融合结论
|
||||
|
||||
- 最新专项审计已经把“前端哪些逻辑还该后移到后端”收敛到 6 类:运行时快照、本地 token、本地浏览历史、NPC 委托换单、quest/runtime item 混合编排、浏览器 AI orchestration。
|
||||
- 工程大清洗已经开始进入实际执行阶段,首批高置信度小型孤岛和残留壳子已开始清理。
|
||||
- 第二批已经开始清理旧主流程壳层与旧 flow Hook,当前主工程的“现行入口”和“历史入口”边界正在变得更清楚。
|
||||
- 第三批已经先完成鉴权真相收口的一段,前端不再保存自动登录用户名/密码;运行时快照链仍需先补后端 contract,再继续往前删。
|
||||
- 第四批已经继续收掉未接入业务的数据生成产物、测试专用 stub 与对应脚本/配置残留,主工程里的“假数据主源”进一步减少。
|
||||
- 第五批已经继续收掉旧命名 re-export、空路由骨架、旧发布 service、前端 prompt 镜像与无入口编辑器壳层,主工程里的“假入口”和“假 prompt 主源”进一步减少。
|
||||
- 第六批已经继续收掉无入口 `questDirector`、旧观察文案 helper、一次性硬编码同步脚本,并修复 function catalog 对后端运行时契约的覆盖缺口。
|
||||
- 当前仓库已经完成“旧 dev 插件链路删除、根目录噪音清理、`server-node -> src/**` 反向依赖切断”这批第一阶段任务。
|
||||
- 当前如果想直接判断“今天先优化什么”,优先看 `CURRENT_ENGINEERING_OPTIMIZATION_OPPORTUNITIES_2026-04-20.md`。
|
||||
- 当前的新重点已经进一步收敛到三类:未接线孤岛模块、前端残留的运行时/鉴权真相、热点向 prompt/runtime profile/平台入口壳层迁移。
|
||||
- 早期三轮工程扫描的结论已经聚合为一条长期规则:工程化不能只看目录和拆分动作,必须覆盖真实主链、质量门禁、绿色基线、关键模块豁免和 build warning。
|
||||
- `2026-04-19` 这一轮把问题压实到了四类:仓库噪音、旧 dev 入口残留、前端越界运行时逻辑、巨型热点文件。
|
||||
- `2026-04-20` 这一轮进一步确认:前两类已经阶段性完成,当前真正剩下的是边界尾巴和新热点迁移。
|
||||
- 如果是要看当前清理和边界收口的最新状态,优先看 `ENGINEERING_CLEANUP_AND_BACKEND_BOUNDARY_AUDIT_2026-04-20.md`。
|
||||
- 如果是要看“当前可执行的优化点清单”,优先看 `CURRENT_ENGINEERING_OPTIMIZATION_OPPORTUNITIES_2026-04-20.md`。
|
||||
- 如果是要做长期重构方案,从 `2026-04-19`、`2026-04-20` 与当前 dead-code batch 记录开始即可。
|
||||
@@ -0,0 +1,129 @@
|
||||
# server-node 冻结隔离说明(2026-04-24)
|
||||
|
||||
## 1. 当前状态
|
||||
|
||||
`server-node/` 已进入冻结隔离状态,不再作为可运行、可扩展、可引用的后端工程使用。
|
||||
|
||||
冻结原因:项目后端主线已经切到 `server-rs/` 的 Rust + SpacetimeDB 多 crate 方案,继续保留可执行的 `server-node/` 入口会误导后续开发,并增加提示词资产、AI 工作流与运行态逻辑的迁移漂移风险。
|
||||
|
||||
## 2. 冻结边界
|
||||
|
||||
1. 禁止新增任何以 `server-node/` 为目标的运行脚本、开发入口、CI 入口或工程依赖。
|
||||
2. 禁止新增从前端、Rust 后端、脚本或配置主动调用 `server-node/` 的逻辑。
|
||||
3. 禁止在 `server-node/` 内继续新增业务能力;后续能力必须落到 `server-rs/` 对应 crate。
|
||||
4. 历史文档、审计文档、迁移基线中允许保留 `server-node/` 作为旧系统来源说明,但不得把它描述成当前推荐实现。
|
||||
5. 第一批物理删除后,提示词资产与提示词相关工作流继续按迁移核对项追踪,不再恢复旧工程目录。
|
||||
|
||||
## 3. 删除前迁移核对项
|
||||
|
||||
以下资产曾作为删除前核对项。第一批物理删除后,旧实现不再从工作区直接读取;如需继续核对能力缺口,只允许通过历史提交、迁移文档或 `server-rs/` 已迁移实现追溯:
|
||||
|
||||
1. `server-node/src/prompts/customWorldEntityPrompts.ts`:自定义世界实体生成 prompt。
|
||||
2. `server-node/src/prompts/customWorldSceneNpcPrompts.ts`:自定义世界场景 NPC prompt。
|
||||
3. `server-node/src/prompts/questPrompts.ts`:任务意图识别 prompt。
|
||||
4. `server-node/src/prompts/runtimeItemPrompts.ts`:运行时物品意图识别 prompt。
|
||||
5. `server-node/src/prompts/customWorldOrchestratorPrompts.ts`:旧 Custom World JSON 生成与修复 prompt。
|
||||
6. `src/services/ai.ts` 与 `src/prompts/customWorldPrompts.ts` 中仍由前端承载的 AI orchestration / prompt 编排。
|
||||
|
||||
## 4. 工程防线
|
||||
|
||||
1. 第一批物理删除后,根目录 `package.json` 不再保留 `server-node:*`、`dev:node`、`check:server-node-freeze` 等旧入口。
|
||||
2. Vite 与本地开发脚本默认只指向 Rust `api-server`,不再保留 Node/Rust 后端切换开关。
|
||||
3. 历史文档允许保留旧 `server-node` 字样,但新增工程入口、脚本、依赖、运行说明不得再指向旧 Node 后端。
|
||||
4. 若后续需要恢复旧能力,只能迁移到 `server-rs/` 对应 crate 或 Axum facade,不恢复 `server-node/` 工程目录。
|
||||
|
||||
## 5. 后续处理顺序
|
||||
|
||||
1. 继续核对提示词资产与 prompt 工作流是否已完整落到 Rust 主线。
|
||||
2. 继续把前端残留业务编排迁入 `server-rs/`。
|
||||
3. 清理技术索引中容易误导当前入口的 Node / Express 文案。
|
||||
4. 保留历史审计材料,但不得把旧 Node 后端描述为当前推荐实现。
|
||||
|
||||
## 6. 已确认迁移项
|
||||
|
||||
### 6.1 场景幕背景图提示词
|
||||
|
||||
2026-04-25 已把旧 Node 自动资产链路中的场景幕背景图提示词包装迁移到 Rust 主线:
|
||||
|
||||
1. 旧来源:`server-node/src/services/customWorldAgentAutoAssetService.ts` 的 `buildSceneActPrompt(...)`。
|
||||
2. 新主源:`server-rs/crates/api-server/src/custom_world.rs` 的 `build_scene_act_background_image_prompt(...)`。
|
||||
3. 使用位置:`generate_draft_foundation_act_backgrounds(...)` 收集 `sceneChapterBlueprints[].acts[]` 后,先构造幕背景图专用提示词,再调用 `generate_custom_world_scene_image_for_profile(...)`。
|
||||
4. 保留语义:世界名、场景名、幕标题、幕摘要、幕目标、过渡钩子、主角色、辅助角色、世界气质、背景描述,以及“只生成环境背景,不出现角色立绘、站位 UI、对白框、按钮或文字”的约束。
|
||||
5. 迁移边界:`server-node/` 仅作为历史来源说明,不再参与运行;后续调整统一修改 Rust 主源。
|
||||
|
||||
## 7. 第一批安全删除记录(2026-04-25)
|
||||
|
||||
本批次开始把冻结隔离升级为物理删除。执行依据是项目后端主线已固定为 `server-rs/` 的 Rust + SpacetimeDB 多 crate 方案,旧 `server-node/` 不再作为可运行、可扩展、可引用的工程目录保留。
|
||||
|
||||
### 7.1 删除范围
|
||||
|
||||
1. 删除 `server-node/` 目录本体,旧实现只允许通过历史提交、迁移文档和已迁移到 `server-rs/` 的代码追溯。
|
||||
2. 删除旧 Node 后端专用入口:`scripts/dev-node.mjs`、`scripts/server-node-frozen.mjs`、`scripts/check-server-node-freeze.mjs`、`scripts/server-node-freeze-baseline.json`、`scripts/smoke-server-node.ts`、`scripts/smoke-same-origin-stack.ts`、`scripts/m7-api-compare.ts`、`scripts/deploy.sh`、`scripts/update.sh`、`view-llm-logs.ps1`。
|
||||
3. 根目录 `package.json` 删除 `server-node:*`、`dev:node`、`m7:api-compare` 与 `check:server-node-freeze` 等旧入口,并移除 `express`、`@types/express` 依赖。
|
||||
4. `npm run dev` 改为启动 Rust 本地栈;Vite 默认只代理到 Rust `api-server`,不再保留 `GENARRATIVE_BACKEND_STACK` 的 Node/Rust 双栈切换口。
|
||||
5. 清理 `.gitignore` 中只服务 `server-node/` 的忽略规则,并同步 `README.md`、`.env.example`、`server-rs/README.md` 与 `scripts/dev-server/README.md`。
|
||||
|
||||
### 7.2 暂不处理范围
|
||||
|
||||
1. 历史 PRD、审计、迁移基线中的 `server-node` 文案暂时保留为历史记录,不在第一批中大规模改写。
|
||||
2. `backend-rewrite-tasklist/` 中以旧 Node 后端为对照的迁移材料暂时保留,作为后续核对 Rust 主线能力缺口的历史审计输入。
|
||||
3. `src/services/ai.ts` 与 `src/prompts/customWorldPrompts.ts` 的前端残留编排不属于本批 Node 后端删除范围;后续继续按“前端只负责表现,业务逻辑进入 `server-rs/`”单独收口。
|
||||
|
||||
### 7.3 后续批次建议
|
||||
|
||||
1. 技术文档索引中的 Node / Express 后端条目只保留为历史资料,不再作为当前入口或推荐方案。
|
||||
2. 后续如继续整理历史文档,只把仍描述 `Express / PostgreSQL` 为当前目标架构的文字修正为“历史阶段口径”。
|
||||
3. 继续把前端残留业务逻辑迁入 `server-rs`;涉及 SpacetimeDB 的设计、实现、脚本和绑定继续显式使用相关 skill。
|
||||
|
||||
### 7.4 本轮安全核对结果
|
||||
|
||||
2026-04-25 本轮开始分批删除时,已确认第一批工程入口层面满足以下条件:
|
||||
|
||||
1. 工作区根目录下已不存在 `server-node/` 物理目录。
|
||||
2. `scripts/` 下已不存在旧 Node 后端专用运行、冻结、smoke、API 对比脚本。
|
||||
3. 根目录 `package.json` 不再包含 `server-node:*`、`dev:node`、`m7:api-compare` 与 `check:server-node-freeze` 入口。
|
||||
4. `package.json` 与 `package-lock.json` 不再包含 `express`、`@types/express`、`pg`、`postgres` 依赖包。
|
||||
5. `README.md`、`scripts/dev-server/README.md`、`server-rs/README.md`、`vite.config.ts`、`scripts/*.mjs`、`src/`、`packages/` 与 `server-rs/` 未发现仍主动启动或调用 `server-node` 的当前工程入口。
|
||||
|
||||
### 7.5 第二批删除边界
|
||||
|
||||
第二批不再删除可运行工程代码,而是清理“容易误导当前实现口径”的历史文档索引:
|
||||
|
||||
1. 只修正文档中仍把 `server-node`、Express 或 PostgreSQL 描述为当前推荐后端的句子。
|
||||
2. 保留审计、PRD、迁移基线中作为历史事实、旧实现来源、能力对照的 `server-node` 引用。
|
||||
3. 不大规模重写包含中文剧情、需求、审计结论的历史文档,避免把真实历史上下文抹平。
|
||||
4. 若发现某个历史文档仍指导新开发继续写 Node 后端,先把该文档改为“历史阶段口径”,再继续工程处理。
|
||||
|
||||
## 8. 开发命令与脚本复核(2026-04-26)
|
||||
|
||||
本轮按“`server-node/` 已完全移除”的状态复核当前开发入口、脚本和工程配置,确认不再保留旧 Node 后端或 Express 运行路径。
|
||||
|
||||
### 8.1 已复核范围
|
||||
|
||||
1. 根目录 `package.json` 与 `package-lock.json`。
|
||||
2. 根目录 `README.md`、`.env.example`、`.gitignore` 与 `vite.config.ts`。
|
||||
3. `scripts/`、`.github/`、`jenkins/` 与 `server-rs/` 下的已跟踪文本文件。
|
||||
|
||||
### 8.2 复核结论
|
||||
|
||||
1. `package.json` 中不存在 `server-node:*`、`dev:node`、`m7:api-compare`、`check:server-node-freeze` 等旧入口。
|
||||
2. `scripts/` 下不存在 `dev-node.mjs`、`smoke-server-node.ts`、`m7-api-compare.ts`、`smoke-same-origin-stack.ts` 等旧 Node 后端脚本。
|
||||
3. `package.json` 与 `package-lock.json` 中不存在 `express`、`@types/express`、`pg`、`postgres` 依赖。
|
||||
4. 当前开发入口继续固定为 `npm run dev`、`npm run dev:web`、`npm run api-server:maincloud` 与 Rust / SpacetimeDB 相关脚本,不恢复旧 Node 后端切换开关。
|
||||
|
||||
## 9. Caddy 本地服务入口移除(2026-04-26)
|
||||
|
||||
`serve:caddy` 仅服务旧的 dist 本地代理验证链路,不再属于当前 Rust / SpacetimeDB 主开发入口。本轮删除该入口和配套文件,避免开发命令继续暴露第二套本地服务方式。
|
||||
|
||||
### 9.1 删除范围
|
||||
|
||||
1. 根目录 `package.json` 删除 `serve:caddy`。
|
||||
2. 删除 `scripts/run-caddy-dev.mjs`。
|
||||
3. 删除 `tools/Caddyfile.dev`。
|
||||
4. `.env.example` 删除 `CADDY_API_UPSTREAM` 样例变量。
|
||||
|
||||
### 9.2 后续口径
|
||||
|
||||
1. 本地完整联调继续使用 `npm run dev`。
|
||||
2. 单独前端联调继续使用 `npm run dev:web` 并通过 Vite 代理到 Rust `api-server`。
|
||||
3. 生产包预览继续使用 Vite `preview`,不恢复 Caddy 专用开发入口。
|
||||
91
docs/audits/text/CHINESE_MOJIBAKE_INVENTORY.md
Normal file
91
docs/audits/text/CHINESE_MOJIBAKE_INVENTORY.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# 中文乱码位置清单
|
||||
|
||||
更新时间:`2026-03-24`
|
||||
|
||||
## 说明
|
||||
|
||||
- 本文档用于记录仓库内已确认或高置信度疑似存在中文乱码的位置。
|
||||
- 当前这份文档是重建版本;原有的 [`docs/audits/text/CHINESE_MOJIBAKE_INVENTORY.md`](/E:/Repos/Genarrative/docs/audits/text/CHINESE_MOJIBAKE_INVENTORY.md) 本身也已经乱码,因此已整体替换。
|
||||
- 本次整理依据:
|
||||
- 仓库内旧清单中的完整文件/行号信息
|
||||
- 本轮人工复核时再次直接看到的明显乱码位置
|
||||
- 由于仓库内同时存在“文件内容已写坏”和“终端/工具显示失真”两类情况,下面清单优先保留高置信位置,便于后续逐项修复。
|
||||
|
||||
## 扫描范围
|
||||
|
||||
- 已纳入:`src/`、`docs/`、根目录文档与元数据文件
|
||||
- 已排除:`.git/`、`node_modules/`、`dist/`、纯图片资源目录
|
||||
|
||||
## 高置信位置
|
||||
|
||||
### 文档与元数据
|
||||
|
||||
- [`docs/experience/AGENT_UI_CHANGELOG.md`](/E:/Repos/Genarrative/docs/experience/AGENT_UI_CHANGELOG.md):1, 3, 7, 9, 11-18, 24, 26-28, 32-33, 37, 39, 41-43, 47, 49, 51, 53-66, 68, 72, 74, 77-79, 83, 87, 89-90, 94, 96, 98-100, 104, 106-112, 116
|
||||
- [`UI_CODING_STANDARD.md`](/E:/Repos/Genarrative/UI_CODING_STANDARD.md):3, 91, 104, 108, 112, 156, 158, 160-166
|
||||
- [`metadata.json`](/E:/Repos/Genarrative/metadata.json):2-3
|
||||
|
||||
### 组件层
|
||||
|
||||
- [`src/components/AdventurePanel.tsx`](/E:/Repos/Genarrative/src/components/AdventurePanel.tsx):57, 65
|
||||
- [`src/components/CharacterPanel.tsx`](/E:/Repos/Genarrative/src/components/CharacterPanel.tsx):37, 65-66, 91-95, 102-103
|
||||
- [`src/components/GameCanvas.tsx`](/E:/Repos/Genarrative/src/components/GameCanvas.tsx):240, 462
|
||||
- [`src/components/GameShell.tsx`](/E:/Repos/Genarrative/src/components/GameShell.tsx):108, 116, 124, 138, 171, 181
|
||||
- [`src/components/InventoryPanel.tsx`](/E:/Repos/Genarrative/src/components/InventoryPanel.tsx):55, 58, 82-83, 181-184, 189, 191
|
||||
- [`src/components/MapModal.tsx`](/E:/Repos/Genarrative/src/components/MapModal.tsx):105, 108, 136
|
||||
- [`src/components/MedievalNpcAnimator.tsx`](/E:/Repos/Genarrative/src/components/MedievalNpcAnimator.tsx):124
|
||||
- [`src/components/NpcVisualEditor.tsx`](/E:/Repos/Genarrative/src/components/NpcVisualEditor.tsx):65, 69-71, 403, 440, 444, 446, 464, 467, 470, 482, 569, 571, 585, 610, 628, 662, 690, 694-695, 697, 722, 751, 759, 775, 777, 781, 824
|
||||
- [`src/components/PresetEditor.tsx`](/E:/Repos/Genarrative/src/components/PresetEditor.tsx):34-37, 43-44, 94, 96, 349, 470, 472, 480, 482, 512, 516, 519, 525, 568, 612, 618, 637, 639, 643, 645, 652, 661, 677, 740, 769, 771, 779, 781, 806, 809, 820, 831, 835, 837, 840, 848, 871, 894, 916, 918, 930, 932, 950, 953, 956, 960, 962, 990, 1004, 1006, 1012, 1018, 1024, 1030, 1036, 1064, 1120, 1122, 1130, 1132, 1150, 1153, 1156, 1172-1175, 1180, 1182, 1186, 1188, 1199, 1203-1204, 1208, 1240, 1242
|
||||
|
||||
### 数据层
|
||||
|
||||
- [`src/data/characterPresets.ts`](/E:/Repos/Genarrative/src/data/characterPresets.ts):97, 102, 104, 107, 129, 132-133, 142, 144, 170, 276, 302, 470, 496, 531, 540, 566, 699-700, 729, 972
|
||||
- [`src/data/medievalNpcVisuals.ts`](/E:/Repos/Genarrative/src/data/medievalNpcVisuals.ts):103, 115, 117, 119, 136, 154, 156, 161, 167, 174, 177, 189, 226, 235-236, 241, 244-245, 249-254, 256-257, 260, 262, 274, 278, 288, 451-453, 565, 568, 577, 592
|
||||
- [`src/data/monsterPresets.ts`](/E:/Repos/Genarrative/src/data/monsterPresets.ts):41-42, 54, 60-61, 79-80, 92, 98-99, 117-118, 136-137, 155-156, 171-173, 185, 191-192, 204, 210-211, 229-230, 242, 248-249, 261, 267-268, 280, 286-287, 304-305, 323-324, 335
|
||||
- [`src/data/monsters.ts`](/E:/Repos/Genarrative/src/data/monsters.ts):112
|
||||
- [`src/data/npcInteractions.ts`](/E:/Repos/Genarrative/src/data/npcInteractions.ts):68-71, 80, 82-83, 161, 165, 173, 182, 188-190, 196, 198, 205, 231, 241, 245, 255-260, 272, 296, 319-320, 372, 444-445, 449, 451, 453, 507, 569-570, 578-579, 587-588, 597, 605-606, 615, 617-618, 626-627, 634, 641-643, 652, 661, 665, 670, 672, 676
|
||||
- [`src/data/scenePresets.ts`](/E:/Repos/Genarrative/src/data/scenePresets.ts):115, 120, 122, 128, 133, 135, 141, 146, 148, 154, 159, 161, 167, 172, 174, 180, 185, 187, 192-193, 198, 200, 205-206, 211, 213, 219, 224, 226, 232, 237, 239, 245, 250, 252, 258, 263, 265, 274, 279, 281, 287, 292, 294, 299-300, 305, 307, 313, 318, 320, 326, 331, 333, 339, 344, 346, 352, 357, 359, 364-365, 370, 372, 377-378, 383, 385, 390-391, 396, 398, 404, 409, 411, 417, 422, 424, 509, 523, 525
|
||||
- [`src/data/stateFunctions.ts`](/E:/Repos/Genarrative/src/data/stateFunctions.ts):72-73, 80, 95-96, 103, 117-118, 125, 139-140, 147, 161-162, 169, 186-187, 194, 209-210, 217, 237-238, 255-256, 273-274, 294, 311-312, 329-330, 420, 430-431, 433-435, 437-438, 440-442, 444-445, 447, 449, 451-452, 454-456, 458, 460-461, 464, 466, 468, 484-485, 487, 489, 491, 493, 601, 618
|
||||
|
||||
### Hooks 与服务层
|
||||
|
||||
- [`src/hooks/useCombatFlow.ts`](/E:/Repos/Genarrative/src/hooks/useCombatFlow.ts):54, 56-58, 566
|
||||
- [`src/services/ai.ts`](/E:/Repos/Genarrative/src/services/ai.ts):200-201, 209-210, 234-235, 269-270, 309, 311, 317, 338, 341, 358, 382
|
||||
- [`src/services/prompt.ts`](/E:/Repos/Genarrative/src/services/prompt.ts):7-8, 10, 13-15, 19-20, 25-40, 43, 55, 61-62, 64, 66, 74-76, 78-79, 83-84, 87-90, 96, 103-104, 112, 115, 157, 159, 161-162, 164-165, 167-168, 170, 172-173
|
||||
|
||||
### 其他源码
|
||||
|
||||
- [`src/uiAssets.ts`](/E:/Repos/Genarrative/src/uiAssets.ts):54, 115, 122, 129, 142, 173, 180
|
||||
|
||||
## 本轮人工复核补充
|
||||
|
||||
以下位置是在本轮实现过程中直接再次看到的明显乱码文本,建议优先复查:
|
||||
|
||||
- [`src/hooks/useCombatFlow.ts`](/E:/Repos/Genarrative/src/hooks/useCombatFlow.ts):1094, 1554, 1556-1557
|
||||
|
||||
## 处理优先级建议
|
||||
|
||||
### 第一批
|
||||
|
||||
- `src/components/GameShell.tsx`
|
||||
- `src/components/InventoryPanel.tsx`
|
||||
- `src/components/CharacterPanel.tsx`
|
||||
- `src/data/characterPresets.ts`
|
||||
- `src/data/npcInteractions.ts`
|
||||
- `src/data/scenePresets.ts`
|
||||
- `src/services/prompt.ts`
|
||||
|
||||
### 第二批
|
||||
|
||||
- `src/components/PresetEditor.tsx`
|
||||
- `src/components/NpcVisualEditor.tsx`
|
||||
- `src/data/monsterPresets.ts`
|
||||
- `src/data/stateFunctions.ts`
|
||||
- `docs/experience/AGENT_UI_CHANGELOG.md`
|
||||
- `UI_CODING_STANDARD.md`
|
||||
|
||||
## 备注
|
||||
|
||||
- 当前文档的目标是“先把位置收拢清楚”,不是直接修复乱码。
|
||||
- 如果你下一步要我继续,我可以基于这份清单继续做两件事之一:
|
||||
- 逐文件修复中文乱码
|
||||
- 先做一个“乱码修复优先级 + 替换建议”文档
|
||||
236
docs/audits/text/CURRENT_GAME_STORY_SOURCE_REVIEW_2026-04-07.md
Normal file
236
docs/audits/text/CURRENT_GAME_STORY_SOURCE_REVIEW_2026-04-07.md
Normal file
@@ -0,0 +1,236 @@
|
||||
# 当前游戏剧情原文整理与质量评测
|
||||
|
||||
日期:`2026-04-07`
|
||||
|
||||
## 总结先说
|
||||
- 当前游戏的剧情骨架已经能让玩家在武侠、仙侠两个世界里感到“我正在追一件事”,整体判断为:**部分达到预期**。
|
||||
- 强项在于:场景残痕、地图推进、NPC 保留、线程结构已经开始互相咬合。
|
||||
- 短板也很明确:强回收、强情感爆点、真正能改写后续理解的长线后果还没有完全跑起来。
|
||||
|
||||
## 方法
|
||||
- 先把当前仓库里的可扮演角色、场景、场景 NPC、宝藏残痕原文整理出来。
|
||||
- 再用现有 story engine 模块补出 ThemePack、WorldStoryGraph、ActorNarrativeProfile、KnowledgeGraph、ThreadContract、QA Report 和 Release Gate。
|
||||
- 最后按“玩家真实会感受到什么剧情”重组样章,并对照 PRD 的经典 RPG 体验目标做评测。
|
||||
|
||||
## 武侠世界
|
||||
|
||||
### 说明
|
||||
- “原文”部分整理的是当前仓库角色、场景、NPC 和残痕里已经存在的中文文本。
|
||||
- “引擎整理”部分是根据这些原文,经过 story engine 的主题包、线程图谱、角色叙事档案和 QA 规则重新编译出的结构化结果。
|
||||
|
||||
### 项目内原始剧情文本整理
|
||||
### 可扮演角色原文
|
||||
- 剑之公主 / 王庭剑姬
|
||||
角色原文:以迅疾剑技和正面压制见长,适合喜欢凌厉推进的玩家。
|
||||
背景原文:王庭旁支出身,自幼被当作执剑者培养。一次宫变让她失去旧有庇护,也背上了亲手追回王室誓剑与真相的责任。
|
||||
表层来意:以迅疾剑技和正面压制见长,适合喜欢凌厉推进的玩家。
|
||||
- 神箭游侠 / 流风弓卫
|
||||
角色原文:擅长远距离压制与精准射击,节奏灵活,机动性很强。
|
||||
背景原文:曾是边境游骑与斥候,被一场伏击逼得离开旧军阵。如今他只信自己亲眼见过的风向与箭路,却仍背着守住边境故土的旧誓。
|
||||
表层来意:擅长远距离压制与精准射击,节奏灵活,机动性很强。
|
||||
- 双刃旅者 / 疾影斥候
|
||||
角色原文:速度快、侵略性强,适合喜欢持续推进和连段压迫的玩家。
|
||||
背景原文:她在暗巷与帮派追杀中长大,学会靠速度、直觉和先手活下去。表面上轻快利落,心里却一直在追查那封改变命运的密信去向。
|
||||
表层来意:速度快、侵略性强,适合喜欢持续推进和连段压迫的玩家。
|
||||
|
||||
### 场景角色原文
|
||||
- 神箭游侠 / 流风弓卫
|
||||
角色原文:擅长远距离压制与精准射击,节奏灵活,机动性很强。
|
||||
保留线索:曾是边境游骑与斥候,被一场伏击逼得离开旧军…
|
||||
- 青鳞毒蛇 / 敌对角色
|
||||
角色原文:身形细长,吐信极快,最喜欢守在草木掩映和石缝交错之地。
|
||||
保留线索:青鳞毒蛇长期出没于竹林古道。身形细长,吐信…
|
||||
- 枯藤伏虫 / 敌对角色
|
||||
角色原文:像一截会蠕动的枯藤,贴地潜行,适合在林地和湿地里伏击。
|
||||
保留线索:枯藤伏虫长期出没于竹林古道。像一截会蠕动的…
|
||||
- 樵夫老周 / 樵夫
|
||||
角色原文:常在竹海边缘砍柴,对附近路数和兽踪了如指掌。
|
||||
保留线索:樵夫老周长期出没于竹林古道。常在竹海边缘砍…
|
||||
- 玄甲战锋 / 重装先锋
|
||||
角色原文:攻守兼备,推进稳健,适合喜欢扎实前排风格的玩家。
|
||||
保留线索:他长期担任重装前锋,习惯站在最危险的位置替…
|
||||
- 石背蜗怪 / 敌对角色
|
||||
角色原文:驮着厚重石壳缓慢爬行,常盘踞在石阶、桥边与潮湿山路上。
|
||||
保留线索:石背蜗怪长期出没于山门石阶。驮着厚重石壳缓…
|
||||
|
||||
### 场景原文整理
|
||||
- 竹林古道
|
||||
场景原文:风过竹叶如刀鸣,窄道蜿蜒向深处,最适合藏伏毒物和游侠。
|
||||
第一残痕:竹根旁半埋的刀鞘
|
||||
场景角色:神箭游侠(流风弓卫)、青鳞毒蛇(敌对角色)、枯藤伏虫(敌对角色)
|
||||
- 山门石阶
|
||||
场景原文:青石阶层层向上,旧山门半开半掩,守山人与伏兽都能藏得很稳。
|
||||
第一残痕:裂缝里的铜钥
|
||||
场景角色:玄甲战锋(重装先锋)、石背蜗怪(敌对角色)、岩甲蛛兽(敌对角色)
|
||||
- 雨夜长街
|
||||
场景原文:长街积水映灯,屋檐下尽是藏身空隙,最易碰见追踪者与夜行客。
|
||||
第一残痕:灯檐下浸湿的布包
|
||||
场景角色:双刃旅者(疾影斥候)、夜牙潜兽(敌对角色)、孢爆菇灵(敌对角色)
|
||||
- 荒村断垣
|
||||
场景原文:残墙和空屋挤成一团,风里总像夹着旧哭声与游荡脚步。
|
||||
第一残痕:断墙后压着的木匣
|
||||
场景角色:断骨祟灵(敌对角色)、孢爆菇灵(敌对角色)、守村妇人(遗民)
|
||||
- 古桥渡口
|
||||
场景原文:桥面潮湿,渡口雾重,来往之人不多,但每个身影都藏着故事。
|
||||
第一残痕:桥柱缝里的油纸包
|
||||
场景角色:双刃旅者(疾影斥候)、石背蜗怪(敌对角色)、夜牙潜兽(敌对角色)
|
||||
|
||||
### 引擎整理出的明线
|
||||
- 旧宫旧案仍在牵动江湖局势:旧宫旧案仍在牵动江湖局势,焦点常落在竹林古道。
|
||||
- 护送线:边关与地宫残痕正在把旧事重新拖回台前,焦点常落在山门石阶。
|
||||
- 回收线:当前武侠世界不是单点冒险,而是一张由边关军需、渡口风声、地宫旧痕和宫苑旧案交叉拉紧的追查网络。,焦点常落在雨夜长街。
|
||||
- 分歧对峙线:沿着场景残痕和人物试探,一步步追清边关与宫苑旧案背后的真相,焦点常落在荒村断垣。
|
||||
|
||||
### 引擎整理出的暗线
|
||||
- 神箭游侠的隐线:神箭游侠并不只是流风弓卫,他与旧宫旧案仍在牵动江湖局势之间还有一段未被说破的牵连。
|
||||
- 青鳞毒蛇的隐线:青鳞毒蛇并不只是敌对角色,他与护送线之间还有一段未被说破的牵连。
|
||||
- 枯藤伏虫的隐线:枯藤伏虫并不只是敌对角色,他与回收线之间还有一段未被说破的牵连。
|
||||
- 樵夫老周的隐线:樵夫老周并不只是樵夫,他与分歧对峙线之间还有一段未被说破的牵连。
|
||||
- 玄甲战锋的隐线:玄甲战锋并不只是重装先锋,他与旧宫旧案仍在牵动江湖局势之间还有一段未被说破的牵连。
|
||||
|
||||
### 场景旧痕
|
||||
- 竹林古道留下的旧痕:表层残痕是“风过竹叶如刀鸣,窄道蜿蜒向深处,最适合藏伏毒物和游侠。”;压着的真相是“神箭游侠并不只是流风弓卫,他与旧宫旧案仍在牵动江湖局势之间还有一段未被说破的牵连。”
|
||||
- 山门石阶留下的旧痕:表层残痕是“青石阶层层向上,旧山门半开半掩,守山人与伏兽都能藏得很稳。”;压着的真相是“青鳞毒蛇并不只是敌对角色,他与护送线之间还有一段未被说破的牵连。”
|
||||
- 雨夜长街留下的旧痕:表层残痕是“长街积水映灯,屋檐下尽是藏身空隙,最易碰见追踪者与夜行客。”;压着的真相是“枯藤伏虫并不只是敌对角色,他与回收线之间还有一段未被说破的牵连。”
|
||||
- 荒村断垣留下的旧痕:表层残痕是“残墙和空屋挤成一团,风里总像夹着旧哭声与游荡脚步。”;压着的真相是“樵夫老周并不只是樵夫,他与分歧对峙线之间还有一段未被说破的牵连。”
|
||||
- 古桥渡口留下的旧痕:表层残痕是“桥面潮湿,渡口雾重,来往之人不多,但每个身影都藏着故事。”;压着的真相是“玄甲战锋并不只是重装先锋,他与旧宫旧案仍在牵动江湖局势之间还有一段未被说破的牵连。”
|
||||
|
||||
### 玩家在游戏中真实感受到的剧情样章
|
||||
你来到这个武侠世界,是为追查失落王庭誓剑流入江湖的踪迹。此行最重要的目标,是在诸门派与野心家之前找回誓剑,并逼出宫变幕后之人。 第一眼看到的不是纯说明,而是 边关营地 里的环境压迫:营火与旌旗都带着风沙味,士卒、斥候和异兽都可能在这里短暂停留。
|
||||
走进边关营地时,玩家实际感受到的核心不是“到了新地图”,而是“营火与旌旗都带着风沙味,士卒、斥候和异兽都可能在这里短暂停留。”。这句场景原文会立刻把体验拉回到“旧宫旧案仍在牵动江湖局势”这条明线。神箭游侠表面只是流风弓卫,但他的公开面是“擅长远距离压制与精准射击,节奏灵活,机动性很强。”,真正压在肩上的却是“找出贩卖军情的人,并截回被转移的军械账册”。而像“废营帐里的箭囊”这样的场景残痕,会把玩家往“这里一定还藏着别的事”那种感觉里继续推。如果继续追下去,边关营地背后会逐渐显出“神箭游侠并不只是流风弓卫,他与旧宫旧案仍在牵动江湖局势之间还有一段未被说破的牵连。”这层旧伤。
|
||||
走进雨夜长街时,玩家实际感受到的核心不是“到了新地图”,而是“长街积水映灯,屋檐下尽是藏身空隙,最易碰见追踪者与夜行客。”。这句场景原文会立刻把体验拉回到“护送线”这条明线。双刃旅者表面只是疾影斥候,但他的公开面是“速度快、侵略性强,适合喜欢持续推进和连段压迫的玩家。”,真正压在肩上的却是“夺回密信,查清究竟是谁把你推上了被追杀的路”。而像“灯檐下浸湿的布包”这样的场景残痕,会把玩家往“这里一定还藏着别的事”那种感觉里继续推。如果继续追下去,雨夜长街背后会逐渐显出“青鳞毒蛇并不只是敌对角色,他与护送线之间还有一段未被说破的牵连。”这层旧伤。
|
||||
走进古桥渡口时,玩家实际感受到的核心不是“到了新地图”,而是“桥面潮湿,渡口雾重,来往之人不多,但每个身影都藏着故事。”。这句场景原文会立刻把体验拉回到“回收线”这条明线。双刃旅者表面只是疾影斥候,但他的公开面是“速度快、侵略性强,适合喜欢持续推进和连段压迫的玩家。”,真正压在肩上的却是“夺回密信,查清究竟是谁把你推上了被追杀的路”。而像“桥柱缝里的油纸包”这样的场景残痕,会把玩家往“这里一定还藏着别的事”那种感觉里继续推。如果继续追下去,古桥渡口背后会逐渐显出“枯藤伏虫并不只是敌对角色,他与回收线之间还有一段未被说破的牵连。”这层旧伤。
|
||||
因此,武侠世界目前最容易让玩家产生真实剧情感的地方,不是某一句高光台词,而是“场景描述 -> 人物保留 -> 残痕线索 -> 线程压力”这条连续链路。它已经能让玩家觉得自己在追一件还没完全揭开的事,但离“经典 RPG 式的强收束和强情感爆点”还差最后一层回响回收。
|
||||
|
||||
### 质量评测
|
||||
整体判断:**部分达成预期**
|
||||
|
||||
### 维度评测
|
||||
- 角色记忆点:达成。当前可扮演角色的人设、背景、开局动机和首遇目标已经能形成第一轮代入,玩家能记住“谁在上路、为什么上路”。
|
||||
- 低关系也有戏:达成。低好感或首遇 NPC 不再只是“更冷淡”,而是能从当前压力、错位说辞和反应钩子里带出暗线存在感。
|
||||
- 世界互文与旧史厚度:达成。场景、NPC、旧痕和线程已经能互相指向同一批旧事,不再只是各自独立的设定块。
|
||||
- 空间与残痕叙事:达成。地点不是纯背景图,场景描述、宝藏线索和 narrative residue 已经能共同承担“空间会说话”的职责。
|
||||
- 选择后果与主线抓手:部分达成。当前任务抓手和线程合约已经存在,但真正影响关系、理解和后续回响的后果层还没有被完全跑满。
|
||||
- 长线回响与收束:未达成。从 QA 结果看,当前版本最明显的短板仍是“已经埋下的线,后面有没有被稳定回收”。这一步决定它能不能真正跨到经典 RPG 质感。
|
||||
|
||||
### 客观检查
|
||||
- Narrative QA:4 条明线 / 1 条问题。
|
||||
- Release Gate:warn。当前版本可继续观察,但仍有若干 narrative 风险。
|
||||
- Simulation:共跑了 3 条 simulation,ending family 1 类,单次最高 QA 问题 1 条。
|
||||
|
||||
### 当前主要问题
|
||||
- 有线程合约尚未在 chronicle 中留下足够的回收痕迹。
|
||||
|
||||
## 仙侠世界
|
||||
|
||||
### 说明
|
||||
- “原文”部分整理的是当前仓库角色、场景、NPC 和残痕里已经存在的中文文本。
|
||||
- “引擎整理”部分是根据这些原文,经过 story engine 的主题包、线程图谱、角色叙事档案和 QA 规则重新编译出的结构化结果。
|
||||
|
||||
### 项目内原始剧情文本整理
|
||||
### 可扮演角色原文
|
||||
- 剑之公主 / 王庭剑姬
|
||||
角色原文:以迅疾剑技和正面压制见长,适合喜欢凌厉推进的玩家。
|
||||
背景原文:王庭旁支出身,自幼被当作执剑者培养。一次宫变让她失去旧有庇护,也背上了亲手追回王室誓剑与真相的责任。
|
||||
表层来意:以迅疾剑技和正面压制见长,适合喜欢凌厉推进的玩家。
|
||||
- 神箭游侠 / 流风弓卫
|
||||
角色原文:擅长远距离压制与精准射击,节奏灵活,机动性很强。
|
||||
背景原文:曾是边境游骑与斥候,被一场伏击逼得离开旧军阵。如今他只信自己亲眼见过的风向与箭路,却仍背着守住边境故土的旧誓。
|
||||
表层来意:擅长远距离压制与精准射击,节奏灵活,机动性很强。
|
||||
- 双刃旅者 / 疾影斥候
|
||||
角色原文:速度快、侵略性强,适合喜欢持续推进和连段压迫的玩家。
|
||||
背景原文:她在暗巷与帮派追杀中长大,学会靠速度、直觉和先手活下去。表面上轻快利落,心里却一直在追查那封改变命运的密信去向。
|
||||
表层来意:速度快、侵略性强,适合喜欢持续推进和连段压迫的玩家。
|
||||
|
||||
### 场景角色原文
|
||||
- 神箭游侠 / 流风弓卫
|
||||
角色原文:擅长远距离压制与精准射击,节奏灵活,机动性很强。
|
||||
保留线索:曾是边境游骑与斥候,被一场伏击逼得离开旧军…
|
||||
- 玄甲战锋 / 重装先锋
|
||||
角色原文:攻守兼备,推进稳健,适合喜欢扎实前排风格的玩家。
|
||||
保留线索:他长期担任重装前锋,习惯站在最危险的位置替…
|
||||
- 秘匣书妖 / 敌对角色
|
||||
角色原文:像会自行翻页的秘典与宝匣,常在仙门、遗迹与禁制附近浮游。
|
||||
保留线索:秘匣书妖长期出没于云海仙门。像会自行翻页的…
|
||||
- 噬雾飞蛾 / 敌对角色
|
||||
角色原文:借雾气遮身,飞行轨迹诡谲,喜欢围着灵光和人影打转。
|
||||
保留线索:噬雾飞蛾长期出没于云海仙门。借雾气遮身,飞…
|
||||
- 守门灵官 / 门官
|
||||
角色原文:站在门阙侧旁观来者,像在等一份迟迟未到的回报。
|
||||
保留线索:守门灵官长期出没于云海仙门。站在门阙侧旁观…
|
||||
- 幽烬灵蝠 / 敌对角色
|
||||
角色原文:翅翼缭绕灰烬般的灵火,常成群出没于洞天、崖壁与灵脉附近。
|
||||
保留线索:幽烬灵蝠长期出没于悬空仙岛。翅翼缭绕灰烬般…
|
||||
|
||||
### 场景原文整理
|
||||
- 云海仙门
|
||||
场景原文:云阶在脚下翻涌,门阙后方灵光不断,来客与守门异物都极显眼。
|
||||
第一残痕:云阶尽头的灵符匣
|
||||
场景角色:神箭游侠(流风弓卫)、玄甲战锋(重装先锋)、秘匣书妖(敌对角色)
|
||||
- 悬空仙岛
|
||||
场景原文:浮岛边缘风大云急,灵禽与飞蛾总绕着岛沿的光带盘旋。
|
||||
第一残痕:浮岛边缘的灵羽匣
|
||||
场景角色:幽烬灵蝠(敌对角色)、噬雾飞蛾(敌对角色)、云栖散修(散修)
|
||||
- 天宫长廊
|
||||
场景原文:廊柱之间回响着空灵风声,禁制和书妖都喜欢寄在这类高处回廊里。
|
||||
第一残痕:廊柱暗槽里的玉简
|
||||
场景角色:剑之公主(王庭剑姬)、玄甲战锋(重装先锋)、秘匣书妖(敌对角色)
|
||||
- 灵药花圃
|
||||
场景原文:灵草灵花层层叠开,香气诱人,却也最容易养出食灵的怪物。
|
||||
第一残痕:药圃深处的灵壶
|
||||
场景角色:噬灵妖花(敌对角色)、血瞳妖眼(敌对角色)、药圃执事(药师)
|
||||
- 寒玉洞天
|
||||
场景原文:洞壁结着寒玉光泽,地面湿滑,水灵和阴性异物都爱停在这里。
|
||||
第一残痕:寒玉裂隙里的灵髓
|
||||
场景角色:青腐泥灵(敌对角色)、幽烬灵蝠(敌对角色)、澄潮灵母(敌对角色)
|
||||
|
||||
### 引擎整理出的明线
|
||||
- 灵脉与封印正在失衡:灵脉与封印正在失衡,焦点常落在云海仙门。
|
||||
- 追索线:宗门旧案与秘境争夺彼此缠住了当下局势,焦点常落在悬空仙岛。
|
||||
- 封印失衡线:当前仙侠世界由宗门秩序、秘境余波、灵脉封印和古仙残迹共同推着故事前进,玩家每深入一层,都会撞上新的旧事回响。,焦点常落在天宫长廊。
|
||||
- 宗门旧案线:顺着灵痕、残识和人物保留,一层层摸清宗门旧案与秘境失衡的根源,焦点常落在灵药花圃。
|
||||
|
||||
### 引擎整理出的暗线
|
||||
- 神箭游侠的隐线:神箭游侠并不只是流风弓卫,他与灵脉与封印正在失衡之间还有一段未被说破的牵连。
|
||||
- 玄甲战锋的隐线:玄甲战锋并不只是重装先锋,他与追索线之间还有一段未被说破的牵连。
|
||||
- 秘匣书妖的隐线:秘匣书妖并不只是敌对角色,他与封印失衡线之间还有一段未被说破的牵连。
|
||||
- 噬雾飞蛾的隐线:噬雾飞蛾并不只是敌对角色,他与宗门旧案线之间还有一段未被说破的牵连。
|
||||
- 守门灵官的隐线:守门灵官并不只是门官,他与灵脉与封印正在失衡之间还有一段未被说破的牵连。
|
||||
|
||||
### 场景旧痕
|
||||
- 云海仙门留下的旧痕:表层残痕是“云阶在脚下翻涌,门阙后方灵光不断,来客与守门异物都极显眼。”;压着的真相是“神箭游侠并不只是流风弓卫,他与灵脉与封印正在失衡之间还有一段未被说破的牵连。”
|
||||
- 悬空仙岛留下的旧痕:表层残痕是“浮岛边缘风大云急,灵禽与飞蛾总绕着岛沿的光带盘旋。”;压着的真相是“玄甲战锋并不只是重装先锋,他与追索线之间还有一段未被说破的牵连。”
|
||||
- 天宫长廊留下的旧痕:表层残痕是“廊柱之间回响着空灵风声,禁制和书妖都喜欢寄在这类高处回廊里。”;压着的真相是“秘匣书妖并不只是敌对角色,他与封印失衡线之间还有一段未被说破的牵连。”
|
||||
- 灵药花圃留下的旧痕:表层残痕是“灵草灵花层层叠开,香气诱人,却也最容易养出食灵的怪物。”;压着的真相是“噬雾飞蛾并不只是敌对角色,他与宗门旧案线之间还有一段未被说破的牵连。”
|
||||
- 寒玉洞天留下的旧痕:表层残痕是“洞壁结着寒玉光泽,地面湿滑,水灵和阴性异物都爱停在这里。”;压着的真相是“守门灵官并不只是门官,他与灵脉与封印正在失衡之间还有一段未被说破的牵连。”
|
||||
|
||||
### 玩家在游戏中真实感受到的剧情样章
|
||||
你来到这个仙侠世界,是因为王庭圣印坠入了云海裂隙。此行最重要的目标,是寻回圣印,截断那些企图借它开启天门禁制的野心。 第一眼看到的不是纯说明,而是 星舟甲板 里的环境压迫:甲板横在高天之上,风压和星光都很强,飞行异物最爱在这里盘旋。
|
||||
走进星舟甲板时,玩家实际感受到的核心不是“到了新地图”,而是“甲板横在高天之上,风压和星光都很强,飞行异物最爱在这里盘旋。”。这句场景原文会立刻把体验拉回到“灵脉与封印正在失衡”这条明线。神箭游侠表面只是流风弓卫,但他的公开面是“擅长远距离压制与精准射击,节奏灵活,机动性很强。”,真正压在肩上的却是“找回星图核心,查清是谁击落了你的船队”。而像“舵台后的星图匣”这样的场景残痕,会把玩家往“这里一定还藏着别的事”那种感觉里继续推。如果继续追下去,星舟甲板背后会逐渐显出“神箭游侠并不只是流风弓卫,他与灵脉与封印正在失衡之间还有一段未被说破的牵连。”这层旧伤。
|
||||
走进悬空仙岛时,玩家实际感受到的核心不是“到了新地图”,而是“浮岛边缘风大云急,灵禽与飞蛾总绕着岛沿的光带盘旋。”。这句场景原文会立刻把体验拉回到“追索线”这条明线。云栖散修表面只是散修,但他的公开面是“常坐在浮岛边缘打坐,对天风和禁制的变化很敏感。”,真正压在肩上的却是“在悬空仙岛守住自己不愿失去的那一层秩序。”。而像“浮岛边缘的灵羽匣”这样的场景残痕,会把玩家往“这里一定还藏着别的事”那种感觉里继续推。如果继续追下去,悬空仙岛背后会逐渐显出“玄甲战锋并不只是重装先锋,他与追索线之间还有一段未被说破的牵连。”这层旧伤。
|
||||
走进月湖仙洲时,玩家实际感受到的核心不是“到了新地图”,而是“湖光像铺开的镜面,水灵、章灵与花影都可能从月色里浮出来。”。这句场景原文会立刻把体验拉回到“封印失衡线”这条明线。双刃旅者表面只是疾影斥候,但他的公开面是“速度快、侵略性强,适合喜欢持续推进和连段压迫的玩家。”,真正压在肩上的却是“找到残阵核心,并弄明白信里提到的“第二个你”究竟是谁”。而像“湖岸边漂来的玉匣”这样的场景残痕,会把玩家往“这里一定还藏着别的事”那种感觉里继续推。如果继续追下去,月湖仙洲背后会逐渐显出“秘匣书妖并不只是敌对角色,他与封印失衡线之间还有一段未被说破的牵连。”这层旧伤。
|
||||
因此,仙侠世界目前最容易让玩家产生真实剧情感的地方,不是某一句高光台词,而是“场景描述 -> 人物保留 -> 残痕线索 -> 线程压力”这条连续链路。它已经能让玩家觉得自己在追一件还没完全揭开的事,但离“经典 RPG 式的强收束和强情感爆点”还差最后一层回响回收。
|
||||
|
||||
### 质量评测
|
||||
整体判断:**部分达成预期**
|
||||
|
||||
### 维度评测
|
||||
- 角色记忆点:达成。当前可扮演角色的人设、背景、开局动机和首遇目标已经能形成第一轮代入,玩家能记住“谁在上路、为什么上路”。
|
||||
- 低关系也有戏:达成。低好感或首遇 NPC 不再只是“更冷淡”,而是能从当前压力、错位说辞和反应钩子里带出暗线存在感。
|
||||
- 世界互文与旧史厚度:达成。场景、NPC、旧痕和线程已经能互相指向同一批旧事,不再只是各自独立的设定块。
|
||||
- 空间与残痕叙事:达成。地点不是纯背景图,场景描述、宝藏线索和 narrative residue 已经能共同承担“空间会说话”的职责。
|
||||
- 选择后果与主线抓手:部分达成。当前任务抓手和线程合约已经存在,但真正影响关系、理解和后续回响的后果层还没有被完全跑满。
|
||||
- 长线回响与收束:未达成。从 QA 结果看,当前版本最明显的短板仍是“已经埋下的线,后面有没有被稳定回收”。这一步决定它能不能真正跨到经典 RPG 质感。
|
||||
|
||||
### 客观检查
|
||||
- Narrative QA:4 条明线 / 1 条问题。
|
||||
- Release Gate:warn。当前版本可继续观察,但仍有若干 narrative 风险。
|
||||
- Simulation:共跑了 3 条 simulation,ending family 1 类,单次最高 QA 问题 1 条。
|
||||
|
||||
### 当前主要问题
|
||||
- 有线程合约尚未在 chronicle 中留下足够的回收痕迹。
|
||||
|
||||
## 最终结论
|
||||
- 如果目标只是“让玩家进入游戏后立刻感觉世界里有事正在发生”,当前文本资产已经够用,且部分环节已经明显跑起来了。
|
||||
- 如果目标是“对标经典单机 RPG 的强角色回响、强关系后果、强主线收束”,当前版本还只能算走到了一半,最该补的是 payoff 和长线回响。
|
||||
- 也就是说:**当前剧情原文的底座已经部分达到预期,但还没到可以完全放心交给玩家沉浸式吃剧情的程度。**
|
||||
@@ -0,0 +1,276 @@
|
||||
# 游戏 UI / 预设 / 编辑器 / npcInteraction / prompt 文本深度审计
|
||||
|
||||
日期:`2026-04-02`
|
||||
|
||||
## 说明
|
||||
|
||||
- 本文档基于当前仓库源码再次深搜,不直接沿用旧审计结论。
|
||||
- 审计目标:找出“可能出现在游戏 UI、预设、编辑器 UI、生成链路中的文本”里,仍然存在的:
|
||||
- `中文乱码`
|
||||
- `英文直出`
|
||||
- `中英混用`
|
||||
- 本轮重点加查:
|
||||
- `src/data/npcInteractions.ts`
|
||||
- `src/services/prompt.ts`
|
||||
- `src/services/characterChatPrompt.ts`
|
||||
- `src/services/questPrompt.ts`
|
||||
- 说明口径:
|
||||
- “会显示给玩家/编辑器使用者”的文本,按高优先级记录。
|
||||
- “内部英文枚举/键名,但可能泄露到 prompt、编辑器或预览”的内容,也单独记录。
|
||||
- 已经转成中文且当前复查无明显问题的区域,会标记为“复查通过”。
|
||||
|
||||
## 结论摘要
|
||||
|
||||
- 当前最严重的文本污染源不是单一 UI,而是两条链路同时存在问题:
|
||||
- 运行时弹窗 / 实体详情 / NPC 交易招募弹窗
|
||||
- `prompt` 生成链路
|
||||
- `src/services/prompt.ts` 是当前最重灾区,既有大面积中文乱码,也混有英文结构词,会直接影响 AI 生成质量。
|
||||
- `src/data/npcInteractions.ts` 里“话题 actionText / detailText”大体已是正常中文,但商人来源匹配、库存种子物品类别/名称仍有明显乱码,而且阶段枚举仍是英文值。
|
||||
- 预设编辑器仍然是英文和乱码高密度区,尤其是:
|
||||
- `CharacterPresetPanel.tsx`
|
||||
- `MonsterPresetPanel.tsx`
|
||||
- `SceneNpcPresetPanel.tsx`
|
||||
- `ScenePresetPanel.tsx`
|
||||
- `StateFunctionEditor.tsx`
|
||||
- 自定义世界 NPC/场景编辑器、NPC 视觉编辑器大体已转中文,但还残留 `NPC`、`AI`、`Shift` 等中英混用。
|
||||
|
||||
## 一、游戏主流程 UI 与运行时面板
|
||||
|
||||
### 1.1 复查通过
|
||||
|
||||
| 文件 | 行号 | 当前状态 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `src/components/game-shell/PreGameSelectionFlow.tsx` | `47-49` | 通过 | 开场联系方式已改成 `QQ群`、`微信` |
|
||||
| `src/components/game-shell/GameShellRuntime.tsx` | `147` | 通过 | 场景名兜底已改成 `当前区域` |
|
||||
| `src/components/adventure-panel/AdventurePanelOverlays.tsx` | `137-158` | 通过 | 任务目标眉标、宝藏踪迹、切磋会话等主文案已是中文 |
|
||||
|
||||
### 1.2 仍有问题
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/game-shell/PreGameSelectionFlow.tsx` | `81`、`89` | 中英混用 | `正在生成核心NPC...` | `NPC` 仍在中文进度文案里直出 |
|
||||
| `src/components/game-shell/GameShellOverlays.tsx` | `151` | 中文乱码 | `闃熶紞` / `鑳屽寘` | 队伍/背包弹层标题已写坏 |
|
||||
| `src/components/game-shell/GameShellRuntime.tsx` | `200-201` | 英文直出 | `GENARRATIVE` | 运行时头部品牌字样仍为英文 |
|
||||
| `src/components/adventure-panel/AdventurePanelOverlays.tsx` | `140` | 中英混用 | `未知敌对 NPC` | 已非乱码,但仍混入 `NPC` |
|
||||
|
||||
## 二、实体详情、NPC 交互弹窗、交易/招募 UI
|
||||
|
||||
### 2.1 `AdventureEntityModal.tsx`
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/AdventureEntityModal.tsx` | `111` | 中文乱码 | `鏁屽 NPC` | hostile badge 已坏,同时混入 `NPC` |
|
||||
| `src/components/AdventureEntityModal.tsx` | `113`、`137-146` | 英文直出 | `NPC`、`Player`、`Companion` | 标题/副标题兜底值仍为英文 |
|
||||
| `src/components/AdventureEntityModal.tsx` | `221`、`264`、`272`、`283`、`296`、`306` | 英文直出 | `Portrait`、`Status`、`Relation`、`Attributes`、`Encounter`、`Inventory` | 六个主区块标题都未本地化 |
|
||||
| `src/components/AdventureEntityModal.tsx` | `266-267` | 英文直出 | `HP`、`MP` | 状态条标签未本地化 |
|
||||
| `src/components/AdventureEntityModal.tsx` | `274-275` | 英文直出 | `Affinity`、`Recruited: Yes/No` | 关系区块仍是英文 |
|
||||
| `src/components/AdventureEntityModal.tsx` | `298-301` | 英文直出 | `Name`、`Context`、`Type`、`Battle mode` | 遭遇信息区块仍是英文 |
|
||||
|
||||
### 2.2 `NpcModals.tsx`
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/NpcModals.tsx` | `251-252` | 英文直出 | `NPC inventory` / `Your inventory` / `items` | 交易栏标题和数量单位仍是英文 |
|
||||
| `src/components/NpcModals.tsx` | `272` | 英文直出 | `This NPC has nothing to sell right now.` / `You have nothing to sell right now.` | 空状态未本地化 |
|
||||
| `src/components/NpcModals.tsx` | `290` | 英文直出 | `Purchase total` / `Sale total` | 交易总价标题未本地化 |
|
||||
| `src/components/NpcModals.tsx` | `297` | 中文乱码 | 大段价格不足提示 | 购买资金不足提示整段已坏 |
|
||||
| `src/components/NpcModals.tsx` | `303` | 中文乱码 | 大段默认说明 | 未选中物品时的说明区整段已坏 |
|
||||
| `src/components/NpcModals.tsx` | `350-399` | 英文直出 | `Item details`、`NPC item`、`Stock`、`Value`、`Purchase price`、`Buyback price`、`Slot`、`Not equippable`、`Usable immediately`、`Tags`、`None` | 物品详情弹窗几乎整屏英文 |
|
||||
| `src/components/NpcModals.tsx` | `404` | 中文乱码 + 中英混用 | 含 `MP` 的恢复说明 | 物品使用效果提示已坏 |
|
||||
| `src/components/NpcModals.tsx` | `465` | 中文乱码 | 好感变动提示 | 交易结果反馈文案已坏 |
|
||||
| `src/components/NpcModals.tsx` | `500-501` | 英文直出 | `Manage companion slot`、`Select a current companion to rotate out before recruiting this NPC.` | 招募替换同伴弹窗未本地化 |
|
||||
|
||||
## 三、预设编辑器与编辑器 UI
|
||||
|
||||
### 3.1 复查通过或基本通过
|
||||
|
||||
| 文件 | 行号 | 当前状态 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `src/components/CustomWorldEntityEditorModal.tsx` | `242` | 通过 | 图片路径占位文案已中文化,不再暴露 `URL` |
|
||||
| `src/components/NpcVisualEditor.tsx` | `463` | 基本通过 | 空状态是中文,但仍混入 `NPC` |
|
||||
| `src/components/CustomWorldNpcVisualEditor.tsx` | `88-91`、`552-765` | 基本通过 | 主体编辑项、装备类型、素材、姿态等基本都为中文 |
|
||||
|
||||
### 3.2 标签、枚举、面板标题问题
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/preset-editor/shared.ts` | `43` | 英文直出 | `NPC` | 预设编辑器顶层页签仍用英文 |
|
||||
| `src/components/preset-editor/shared.ts` | `62-67` | 英文枚举外露 | `idle`、`move`、`attack`、`die` | 怪物动画候选仍是英文值 |
|
||||
| `src/components/preset-editor/shared.ts` | `69-74` | 英文枚举外露 | `steady`、`burst`、`mobility`、`finisher`、`projectile` | 技能风格候选仍是英文值 |
|
||||
| `src/components/NpcVisualEditor.tsx` | `702-708` | 中英混用 | `NPC 视觉编辑器` | 中文标题中混入 `NPC` |
|
||||
| `src/components/NpcVisualEditor.tsx` | `718` | 中英混用 | `当前 NPC` | 选择器标签混入 `NPC` |
|
||||
| `src/components/NpcVisualEditor.tsx` | `976-977` | 中英混用 | `拖动标记微调 NPC 的预览布局。移动时按住 Shift...` | 混入 `NPC`、`Shift` |
|
||||
| `src/components/CustomWorldEntityEditorModal.tsx` | `482-483` | 中英混用 | `AI生成NPC形象`、`NPC 形象 AI 生成功能仍在开发中。` | 模态标题与副标题仍大量混用英文术语 |
|
||||
| `src/components/CustomWorldEntityEditorModal.tsx` | `635-636` | 中英混用 | `新增 NPC`、`编辑 NPC` | 主标题和副标题混入 `NPC` |
|
||||
| `src/components/CustomWorldEntityEditorModal.tsx` | `734`、`762-763` | 中英混用 | `AI生成`、`AI生成场景`、`场景图片 AI 生成功能仍在开发中。` | 场景生成入口仍混入 `AI` |
|
||||
| `src/components/CustomWorldEntityEditorModal.tsx` | `792-793` | 中英混用 | `npc-...`、`自定义NPC...` | 新建 NPC 默认 ID/名称混有英文前缀与 `NPC` |
|
||||
|
||||
### 3.3 `CharacterPresetPanel.tsx`
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/preset-editor/CharacterPresetPanel.tsx` | `262`、`264`、`277` | 中文乱码 | `瑙掕壊`、`淇濆瓨瑙掕壊瑕嗙洊` | 选择卡标题、下拉标签、保存按钮均已坏 |
|
||||
| `src/components/preset-editor/CharacterPresetPanel.tsx` | `320`、`326` | 中文乱码 | `鍔ㄧ敾`、`闁煎啿...` | 动画/世界标签已坏 |
|
||||
| `src/components/preset-editor/CharacterPresetPanel.tsx` | `418`、`427` | 中文乱码 | `涓栫晫`、`棰勮鎬墿` | 技能预览区字段标签已坏 |
|
||||
| `src/components/preset-editor/CharacterPresetPanel.tsx` | `313-314`、`402-403` | 通过 | `角色详情`、`技能预览` | 主体段落标题已是正常中文 |
|
||||
|
||||
### 3.4 `MonsterPresetPanel.tsx`
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | `49-50` | 英文直出 | `Saved monster overrides...`、`Failed to save monster overrides.` | 保存反馈未本地化 |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | `58-59` | 中文乱码 | 空状态整段提示 | 无怪物时的空态文案已坏 |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | `124-126` | 英文直出 | `Section`、`Editor section.`、`Field` | 左侧选择卡是占位英文 |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | `135` | 中文乱码 | `闂?` | 世界与名字之间的分隔符已坏 |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | `139` | 英文直出 | `Save Monster Overrides` | 保存按钮未本地化 |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | `158-159` | 英文直出 | `Monster Override Preview`、`Editor section.` | 右侧预览卡标题/说明未本地化 |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | `165`、`218`、`223`、`228`、`240`、`248`、`256` | 英文直出 | `Field`、`Name`、`Intro Action` | 多个字段标签仍是英文或占位文案 |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | `335` | 中文乱码 | 一段动画配置标签乱码 | 帧数相关字段标题已坏 |
|
||||
|
||||
### 3.5 `SceneNpcPresetPanel.tsx`
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `159` | 英文直出 | `No NPC presets are available.` | 空状态未本地化 |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `177-193` | 英文直出 | `NPC Library`、`Browse and select an NPC preset.`、`NPC ID`、`Save NPC Overrides` | 选择区整块未本地化 |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `221-238` | 英文直出 | `Skill Preview`、`Skill`、`World` | 技能预览区未本地化 |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `258-259` | 中文乱码 | 空状态/说明整段乱码 | 预览区已有损坏文本 |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `264-268` | 英文直出 | `Visual Preview`、`Hostile NPCs use monster presets...`、`Narrative NPCs can preview...` | 视觉预览说明未本地化 |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `310-357` | 英文直出 | `NPC Details`、`NPC ID`、`Name`、`Role`、`Avatar`、`Linked Character ID`、`Monster Preset ID`、`Initial Affinity`、`Description` | 详情字段整体未本地化 |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `363` | 中文乱码 | 预览说明大段乱码 | NPC 预览描述区已坏 |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `371-375` | 英文直出 | `Visual Editor`、`Hostile NPCs cannot use the visual editor...` | 可视编辑器说明未本地化 |
|
||||
|
||||
### 3.6 `ScenePresetPanel.tsx`
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/preset-editor/ScenePresetPanel.tsx` | `105-108` | 英文直出 | `Treasure Ahead`、`Treasure` | 宝藏预览实体名/头像仍是英文 |
|
||||
| `src/components/preset-editor/ScenePresetPanel.tsx` | `132-133` | 英文直出 | `Scene Library`、`Browse and select a scene preset.` | 左侧选择区未本地化 |
|
||||
| `src/components/preset-editor/ScenePresetPanel.tsx` | `162` | 英文直出 | `Save` | 保存按钮未本地化 |
|
||||
| `src/components/preset-editor/ScenePresetPanel.tsx` | `170-181` | 英文直出 | `Scene Preview`、`Preview Mode`、`Monster Preview`、`NPC Preview`、`Treasure Preview`、`Empty` | 预览模式整组未本地化 |
|
||||
| `src/components/preset-editor/ScenePresetPanel.tsx` | `207-226` | 英文直出 | `Hostile NPCs`、`NPCs`、`Treasure Hint`、`None` | 场景摘要卡未本地化 |
|
||||
| `src/components/preset-editor/ScenePresetPanel.tsx` | `233-299` | 英文直出 | `Scene Details`、`Scene ID`、`World`、`Name`、`Description`、`Image Source`、`Forward Scene`、`Unset`、`Connected Scene IDs`、`Monster IDs`、`Treasure Hints`、`NPCs In Scene` | 详情编辑区整块未本地化 |
|
||||
|
||||
### 3.7 `StateFunctionEditor.tsx` 与共享请求层
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/StateFunctionEditor.tsx` | `1060-1064` | 英文直出 | `Failed to save option behavior overrides`、`Option behavior overrides saved.` | 保存结果提示未本地化 |
|
||||
| `src/components/StateFunctionEditor.tsx` | `1138` | 中英混用 | `GameState` | 预览说明里仍混入英文类型名 |
|
||||
| `src/components/StateFunctionEditor.tsx` | `1143` | 中英混用 | `敌对NPC资源` | `NPC` 混入字段标签 |
|
||||
| `src/components/StateFunctionEditor.tsx` | `1185` | 英文枚举外露 | `AnimationState` 原始值 | 玩家动作下拉会直接显示英文枚举值 |
|
||||
| `src/components/StateFunctionEditor.tsx` | `1190` | 英文占位符外露 | `{monster}` | 占位提示面向编辑器用户直接可见 |
|
||||
| `src/components/StateFunctionEditor.tsx` | `1191` | 英文枚举外露 | `idle`、`move`、`attack` | 怪物动画下拉仍使用英文值 |
|
||||
| `src/components/StateFunctionEditor.tsx` | `1213-1217` | 基本通过 | `稳扎稳打`、`爆发`、`机动` 等 | 技能权重显示标签已是中文,但底层 key 仍是英文 |
|
||||
| `src/editor/shared/jsonClient.ts` | `29`、`43` | 英文直出 | `Request failed`、`Save failed` | 通用网络错误兜底未本地化,所有编辑器接口都可能透出 |
|
||||
|
||||
## 四、`npcInteractions.ts` 重点复查
|
||||
|
||||
### 4.1 复查通过
|
||||
|
||||
| 文件 | 行号 | 当前状态 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `src/data/npcInteractions.ts` | `507-657` | 通过 | `actionText` / `detailText` 话题库主体已是中文,适合作为后续清理基线 |
|
||||
|
||||
### 4.2 仍有问题
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/data/npcInteractions.ts` | `299-343` | 中文乱码 | `绋€鏈夊搧`、`鏉愭枡`、`琛屽晢鎶ょ`、`绮剧偧閾?`、`闃叉按琛屽泭`、`娌抽浘缃楃洏`、`鍏界毊`、`鐚庨拱缇藉潬`、`鎷撴湰鏂囧唽`、`娈嬬己鍦板浘`、`姝﹀櫒`、`鍒跺紡浣╁垁`、`鎶ょ敳`、`鎶よ噦`、`鏃у竷鍗?`、`闅忚韩鏃х墿` | 商人来源匹配、商品分类、商品名存在明显乱码,会直接流入交易 UI |
|
||||
| `src/data/npcInteractions.ts` | `401-424` | 英文枚举外露 | `deep`、`honest`、`partial`、`guarded`、`warm`、`cooperative`、`neutral`、`distant`、`candid`、`true_but_incomplete`、`half_truth`、`situational_only` | 阶段/回答模式仍使用英文值,虽不一定直接给玩家看,但已进入 prompt 上下文 |
|
||||
| `src/data/npcInteractions.ts` | `428-500` | 基本通过 | `已经愿意逐步谈到真实来历...` 等 | 描述层已是中文,可作为未来替换英文枚举时的文案来源 |
|
||||
| `src/data/npcInteractions.ts` | `1199`、`1209`、`1243` | 中英混用 | `向该NPC送礼`、`邀请该NPC加入队伍`、`离开当前 NPC,重新回到探索状态。` | 选项和说明里仍混入 `NPC` |
|
||||
| `src/data/npcInteractions.ts` | `1250` | 中英混用 | `当前好感为 ...` 同句包含 `NPC` | 遭遇总结文本仍有术语混入 |
|
||||
|
||||
## 五、`prompt` 链路重点复查
|
||||
|
||||
### 5.1 `src/services/prompt.ts`
|
||||
|
||||
这是当前最需要优先清理的文件。问题不是一两处,而是“结构性污染”:
|
||||
|
||||
- 前段中文描述已混入乱码。
|
||||
- 中段人物/遭遇/场景/状态描述大面积乱码。
|
||||
- 后段选项约束、战斗/观察/营地对话指令大面积乱码。
|
||||
- 同时混有 `functionId`、`actionText`、`npc|treasure|none` 等英文结构词。
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/services/prompt.ts` | `145`、`151` | 中文乱码 | `锛堣嚜瀹氫箟...`、`鑷畾涔変笘鐣?...` | 自定义世界描述区已坏 |
|
||||
| `src/services/prompt.ts` | `170-171`、`198-216` | 中文乱码 | 冒险开场理由、表层钩子、眼前顾虑、目标等整段乱码 | 角色开场信息会直接污染生成上下文 |
|
||||
| `src/services/prompt.ts` | `226-233` | 中文乱码 + 英文枚举外露 | `NPC`、`deep`、`warm`、`answerMode` 等 | NPC 会话阶段控制段同时存在乱码和英文枚举 |
|
||||
| `src/services/prompt.ts` | `378-451` | 中文乱码 + 中英混用 | 遭遇实体、敌对 `NPC`、玩家状态、场景说明等整段乱码 | 玩家、NPC、怪物、场景等核心提示都已受污染 |
|
||||
| `src/services/prompt.ts` | `547-568` | 中文乱码 + 英文结构词外露 | `functionId`、`actionText`、`function` | 选项约束与动作重写规则段落已坏 |
|
||||
| `src/services/prompt.ts` | `859-910` | 中文乱码 + 中英混用 | 空闲/遭遇函数说明、观察线索、开场营地跟进等整段乱码 | 后半段生成规则几乎不可维护 |
|
||||
|
||||
### 5.2 `src/services/characterChatPrompt.ts`
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/services/characterChatPrompt.ts` | `42-54` | 英文直出 | `You are a companion character...`、`Generate exactly 3 player reply suggestions.`、`Summarize the evolving relationship...` | 系统 prompt 整段为英文 |
|
||||
| `src/services/characterChatPrompt.ts` | `57-59` | 英文直出 | `Wuxia`、`Xianxia`、`Custom World` | 世界描述仍为英文 |
|
||||
| `src/services/characterChatPrompt.ts` | `64`、`69-71`、`74-75` | 英文直出 | `Custom world reference`、`female`、`male`、`unknown`、`left`、`right` | 性别、朝向、扩展说明均为英文 |
|
||||
| `src/services/characterChatPrompt.ts` | `99-112` | 英文直出 | `Recent story: none.`、`Earlier story summary`、`Most recent 3 story rounds` | 历史摘要模板为英文 |
|
||||
| `src/services/characterChatPrompt.ts` | `123-155` | 英文直出 | `damage`、`mana`、`cooldown`、`arrival reason`、`current goal`、`world schema`、`top attributes` | 角色信息拼接模板整体为英文 |
|
||||
|
||||
### 5.3 `src/services/questPrompt.ts`
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/services/questPrompt.ts` | `28-31` | 英文直出 | `issued by`、`No live quests` | 当前任务摘要模板为英文 |
|
||||
| `src/services/questPrompt.ts` | `35-37` | 英文直出 | `Active companions`、`Roster companions` | 同伴摘要模板为英文 |
|
||||
| `src/services/questPrompt.ts` | `41-52` | 英文直出 | `Player`、`HP`、`Mana`、`Inventory snapshot` | 玩家状态模板为英文 |
|
||||
| `src/services/questPrompt.ts` | `67-95` | 英文直出 | `You are the quest director...` 等整段 | 任务意图系统 prompt 全英文 |
|
||||
| `src/services/questPrompt.ts` | `107-123` | 英文直出 | `World`、`Issuer NPC`、`Encounter kind`、`Recent story moments` 等 | 最终拼接 prompt 仍是英文框架 |
|
||||
|
||||
### 5.4 `src/services/aiFallbacks.ts`
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/services/aiFallbacks.ts` | `5-17` | 英文直出 | `Player: ...`、`That question is not casual...`、`I accept...` | 离线 NPC 对话与招募兜底仍是英文 |
|
||||
| `src/services/aiFallbacks.ts` | `28-35` | 英文直出 | `I will answer in my own way`、`I still remember...` | 离线角色私聊回复兜底为英文 |
|
||||
| `src/services/aiFallbacks.ts` | `40-42` | 英文直出 | 三条候选回复 | 私聊建议兜底为英文 |
|
||||
| `src/services/aiFallbacks.ts` | `52-57` | 英文直出 | `Player`、`Recent exchange`、`warmer toward the player` | 私聊摘要兜底为英文 |
|
||||
|
||||
## 六、其他会外溢到 UI / 预览 / 生成链路的文本源
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/hooks/useStoryGeneration.ts` | `578-580` | 通过 | `前往...`、`离开营地...` | 旅行选项已中文化 |
|
||||
| `src/hooks/useStoryGeneration.ts` | `599`、`602` | 英文直出 | `approaches from a short distance away...`、`steps into view...` | 初始同伴结果文本仍是英文 |
|
||||
| `src/hooks/useStoryGeneration.ts` | `814` | 英文直出 | `Continue the camp exchange and organize the most natural next actions.` | 营地跟进生成指令仍是英文 |
|
||||
| `src/data/scenePresets.ts` | `195`、`297` | 英文枚举外露 | `trade`、`fight`、`spar`、`help`、`chat`、`recruit`、`gift` | 场景函数列表仍是英文 ID |
|
||||
| `src/data/stateFunctions.ts` | `33` | 英文枚举外露 | `idle|move|attack` | 怪物动画枚举仍是英文 |
|
||||
| `src/data/stateFunctions.ts` | `130`、`152`、`174`、`196`、`221`、`244` | 英文枚举外露 | `steady`、`burst`、`mobility`、`finisher`、`projectile` | 技能权重 key 仍为英文 |
|
||||
| `src/data/characterPresets.ts` | `60-76` | 英文枚举外露 | `blunt`、`wary`、`evasive`、`measured`、`gentle`、`teasing`、`dry`、`steady`、`direct`、`fragmented`、`deflecting` | 对话风格推断值仍为英文,已进入 `npcInteractions` / `prompt` 描述链路 |
|
||||
|
||||
## 七、优先级建议
|
||||
|
||||
### P0:先修,否则会持续污染生成结果或直接破坏主界面
|
||||
|
||||
1. `src/services/prompt.ts`
|
||||
2. `src/components/NpcModals.tsx`
|
||||
3. `src/components/AdventureEntityModal.tsx`
|
||||
4. `src/data/npcInteractions.ts` 的商店库存种子乱码段
|
||||
5. `src/components/game-shell/GameShellOverlays.tsx` 的标题乱码
|
||||
|
||||
### P1:紧接着修,编辑器体验当前已经明显受损
|
||||
|
||||
1. `src/components/preset-editor/MonsterPresetPanel.tsx`
|
||||
2. `src/components/preset-editor/SceneNpcPresetPanel.tsx`
|
||||
3. `src/components/preset-editor/ScenePresetPanel.tsx`
|
||||
4. `src/components/preset-editor/CharacterPresetPanel.tsx`
|
||||
5. `src/components/StateFunctionEditor.tsx`
|
||||
6. `src/editor/shared/jsonClient.ts`
|
||||
|
||||
### P2:统一术语与风格,减少中英混用
|
||||
|
||||
1. 全局统一 `NPC`、`HP`、`MP`、`AI`、`Shift` 是否保留英文缩写
|
||||
2. 将 `npcInteractions.ts` / `characterPresets.ts` / `stateFunctions.ts` 的英文枚举与键名整理为“内部值 + 中文展示层”
|
||||
3. 补齐 `aiFallbacks.ts`、`characterChatPrompt.ts`、`questPrompt.ts` 的中文 prompt / fallback 版本
|
||||
|
||||
## 八、建议的修复顺序
|
||||
|
||||
1. 先修 `prompt` 和 `npcInteractions`,因为这两处会同时污染 AI 输出和运行时文本。
|
||||
2. 再修 `NpcModals`、`AdventureEntityModal`、`GameShellOverlays`,优先恢复玩家可见界面。
|
||||
3. 再批量处理四个预设编辑器面板和 `StateFunctionEditor`,最后统一共享请求层兜底文案。
|
||||
|
||||
273
docs/audits/text/GAME_UI_PRESET_EDITOR_TEXT_AUDIT_2026-04-02.md
Normal file
273
docs/audits/text/GAME_UI_PRESET_EDITOR_TEXT_AUDIT_2026-04-02.md
Normal file
@@ -0,0 +1,273 @@
|
||||
# 游戏 UI / 预设 / 编辑器文本二次审计(扩展重查版)
|
||||
|
||||
日期:`2026-04-02`
|
||||
|
||||
说明:
|
||||
|
||||
- 本文档用于替换同名上一版审计。上一版确实漏掉了不少内容,尤其是:
|
||||
- `AdventurePanel` 里的任务概览与奖励文案
|
||||
- `npcInteractions.ts` 里的 `actionText` / `detailText`
|
||||
- 自定义世界编辑器、NPC 视觉编辑器里的英文兜底和混合术语
|
||||
- 预设编辑器里多组仍未本地化的标题、字段名、保存反馈
|
||||
- 本次以当前仓库实际内容为准,不沿用旧结论;已经修掉的内容不再重复计入。
|
||||
|
||||
## 审计范围
|
||||
|
||||
- 扫描目录:
|
||||
- `src/components/`
|
||||
- `src/data/`
|
||||
- `src/hooks/`
|
||||
- `src/services/`
|
||||
- `src/routing/`
|
||||
- `src/editor/`
|
||||
- 关注对象:
|
||||
- 玩家在主流程、冒险面板、弹窗里会看到的文本
|
||||
- 预设编辑器、自定义世界编辑器、NPC 视觉编辑器中会直接显示的文本
|
||||
- 会透传到 UI、弹窗、编辑器预览中的数据层文本源
|
||||
- 标记类型:
|
||||
- `英文直出`:面向玩家 / 编辑器用户的英文文本仍直接显示
|
||||
- `中英混用`:中文 UI 中混入 `NPC`、`HP`、`MP`、`AI`、`URL`、`Shift` 等术语
|
||||
- `异常显示`:明显乱码、截断、异常问号替代、分隔符损坏
|
||||
|
||||
## 结论摘要
|
||||
|
||||
- 游戏主流程里仍有明显英文残留:`QQ Group`、`WeChat`、`GENARRATIVE`、`Current Area`。
|
||||
- 游戏内任务 / 冒险面板仍有一批英文任务眉标和按钮辅助文案:`BOUNTY TARGET`、`CACHE TRACE`、`SPAR SESSION`、`Inspect reward item ...`、`Unknown monster`。
|
||||
- `GameShellOverlays.tsx` 仍有整组 loading fallback 出现异常编码。
|
||||
- 预设编辑器目前仍是问题最密集区域之一,`CharacterPresetPanel`、`MonsterPresetPanel`、`SceneNpcPresetPanel`、`ScenePresetPanel`、`StateFunctionEditor` 里都有明显英文直出或半成品占位。
|
||||
- 数据层里仍有大量会透出到 UI / 编辑器的英文值,重点在:
|
||||
- `npcInteractions.ts`
|
||||
- `useStoryGeneration.ts`
|
||||
- `storyGenerationState.ts`
|
||||
- `npcEncounterActions.ts`
|
||||
- `sceneObservation.ts`
|
||||
- `characterPresets.ts`
|
||||
- `stateFunctions.ts`
|
||||
|
||||
## 一、游戏主流程 UI
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 / 字段 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/game-shell/PreGameSelectionFlow.tsx` | `48-49` | 英文直出 | `QQ Group`、`WeChat` | 开场页联系方式标签仍是英文 |
|
||||
| `src/components/game-shell/PreGameSelectionFlow.tsx` | `351` | 中英混用 | `contact.label === 'QQ Group' ? 'QQ群' : '微信'` | 逻辑分支仍依赖英文标签 |
|
||||
| `src/components/game-shell/GameShellOverlays.tsx` | `123` | 异常显示 | `姝e湪鍔犺浇鍐掗櫓璇︽儏...` | 冒险详情 loading fallback 乱码 |
|
||||
| `src/components/game-shell/GameShellOverlays.tsx` | `162` | 异常显示 | `姝e湪鍔犺浇闃熶紞闈㈡澘` | 队伍面板 loading fallback 乱码 |
|
||||
| `src/components/game-shell/GameShellOverlays.tsx` | `187` | 异常显示 | `姝e湪鍔犺浇鑳屽寘闈㈡澘` | 背包面板 loading fallback 乱码 |
|
||||
| `src/components/game-shell/GameShellOverlays.tsx` | `214` | 异常显示 | `姝e湪鍔犺浇闃熶紞钀ュ湴...` | 营地弹窗 loading fallback 乱码 |
|
||||
| `src/components/game-shell/GameShellOverlays.tsx` | `229` | 异常显示 | `姝e湪鍔犺浇鍦板浘...` | 地图 loading fallback 乱码 |
|
||||
| `src/components/game-shell/GameShellOverlays.tsx` | `248` | 异常显示 | `姝e湪鍔犺浇瑙掕壊鑱婂ぉ...` | 角色聊天 loading fallback 乱码 |
|
||||
| `src/components/game-shell/GameShellOverlays.tsx` | `261` | 异常显示 | `姝e湪鍔犺浇 NPC 浜や簰...` | NPC 交互 loading fallback 同时混入 `NPC` |
|
||||
| `src/components/game-shell/GameShellRuntime.tsx` | `146` | 英文直出 | `Current Area` | 当前场景名缺失时的兜底文案仍是英文 |
|
||||
| `src/components/game-shell/GameShellRuntime.tsx` | `200` | 英文直出 | `GENARRATIVE` | 顶部 logo 文案仍是英文 |
|
||||
| `src/components/GameShell.tsx` | `311` | 英文直出 | `Current Area` | 旧壳组件里同样保留英文兜底 |
|
||||
| `src/components/GameShell.tsx` | `365` | 英文直出 | `GENARRATIVE` | 旧壳组件里同样保留英文 logo |
|
||||
| `src/components/DeveloperTeamModal.tsx` | `44` | 英文直出 | `aria-label="Close developer team modal"` | 开发团队弹窗关闭按钮辅助文案未本地化 |
|
||||
|
||||
## 二、游戏内面板 / 弹窗
|
||||
|
||||
### 2.1 冒险与任务面板
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 / 字段 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/AdventurePanel.tsx` | `197-198` | 异常显示 | `适合进攻型构`、`适合防御型构` | 描述文本疑似被截断,正常语义应是“构筑” |
|
||||
| `src/components/AdventurePanel.tsx` | `206` | 异常显示 | `item.name + ' 奖励物品<E789A9>?';` | 奖励物品描述兜底尾部异常 |
|
||||
| `src/components/AdventurePanel.tsx` | `216` | 异常显示 | ``${hours}小时 ...<2E>?...秒`` | 时长格式字符串出现异常字符 |
|
||||
| `src/components/AdventurePanel.tsx` | `219` | 异常显示 | ``${minutes}<7D>?...秒`` | 分钟格式字符串同样异常 |
|
||||
| `src/components/AdventurePanel.tsx` | `248` | 英文直出 | ``aria-label={`Inspect reward item ${item.name}`}`` | 奖励物品按钮辅助文案是英文 |
|
||||
| `src/components/AdventurePanel.tsx` | `279` | 英文直出 | `BOUNTY TARGET` | 任务眉标未本地化 |
|
||||
| `src/components/AdventurePanel.tsx` | `283` | 英文直出 | `Unknown monster` | 目标怪物兜底文案是英文 |
|
||||
| `src/components/AdventurePanel.tsx` | `290` | 英文直出 | `CACHE TRACE` | 宝藏任务眉标未本地化 |
|
||||
| `src/components/AdventurePanel.tsx` | `295` | 英文直出 | `Inspect the hidden reward site` | 宝藏任务副文案未本地化 |
|
||||
| `src/components/AdventurePanel.tsx` | `302` | 英文直出 | `SPAR SESSION` | 切磋任务眉标未本地化 |
|
||||
|
||||
### 2.2 NPC / 实体 / 交易相关弹窗
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 / 字段 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/AdventureEntityModal.tsx` | `895` | 中英混用 | `label="HP"` | 实体状态估计面板直接显示 `HP` |
|
||||
| `src/components/AdventureEntityModal.tsx` | `901` | 中英混用 | `label="MP"` | 实体状态估计面板直接显示 `MP` |
|
||||
| `src/components/NpcModals.tsx` | `252` | 中英混用 | `NPC 商品列表` / `你的背包列表` | 交易列表标题混入 `NPC` |
|
||||
| `src/components/NpcModals.tsx` | `273` | 中英混用 | `这个 NPC 当前没有可售商品。` | 空状态文案混入 `NPC` |
|
||||
| `src/components/NpcModals.tsx` | `356` | 中英混用 | `NPC 商品` | 详情弹窗标题混入 `NPC` |
|
||||
| `src/components/NpcModals.tsx` | `408` | 中英混用 | `效果预览:HP +... / MP +... / 冷却 -...` | 数值预览里直接保留 `HP`、`MP` |
|
||||
|
||||
### 2.3 自定义世界结果页
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 / 字段 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/CustomWorldResultView.tsx` | `58` | 中英混用 | `新增 NPC` | 结果页新增操作标签混入 `NPC` |
|
||||
|
||||
## 三、自定义世界 / NPC 视觉编辑
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 / 字段 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/CustomWorldEntityEditorModal.tsx` | `242` | 英文直出 | `URL` | 图片地址输入提示词未本地化 |
|
||||
| `src/components/CustomWorldEntityEditorModal.tsx` | `464` | 英文直出 | `MedievalFantasyCharacters` | 形象编辑副标题里直接暴露素材包英文名 |
|
||||
| `src/components/CustomWorldEntityEditorModal.tsx` | `482-483` | 中英混用 | `AI生成NPC形象`、`NPC 形象 AI 生成功能仍在开发中。` | 同时混入 `AI`、`NPC` |
|
||||
| `src/components/CustomWorldEntityEditorModal.tsx` | `635-636` | 中英混用 | `新增 NPC`、`编辑 NPC:...` | NPC 档案编辑标题混入英文缩写 |
|
||||
| `src/components/CustomWorldEntityEditorModal.tsx` | `663` | 中英混用 | `修改形象` | 本行本身无问题,但上下文仍指向 `NPC` 视觉编辑入口 |
|
||||
| `src/components/CustomWorldEntityEditorModal.tsx` | `734` | 中英混用 | `AI生成` | 按钮文案混入 `AI` |
|
||||
| `src/components/CustomWorldEntityEditorModal.tsx` | `762-763` | 中英混用 | `AI生成场景`、`场景图片 AI 生成功能仍在开发中。` | 场景生成弹窗混入 `AI` |
|
||||
| `src/components/CustomWorldNpcVisualEditor.tsx` | `393` | 中英混用 | `AI生成` | 自定义 NPC 视觉编辑器按钮混入 `AI` |
|
||||
| `src/components/NpcVisualEditor.tsx` | `263-267` | 英文直出 | `Failed to load NPC visual overrides`、`Failed to load NPC layout config` | 编辑器首屏可见的加载失败兜底为英文 |
|
||||
| `src/components/NpcVisualEditor.tsx` | `284-308` | 英文直出 | `response was invalid, using bundled defaults` 等 | 多组降级提示未本地化 |
|
||||
| `src/components/NpcVisualEditor.tsx` | `463` | 中英混用 | `请先选择一个 NPC 进行编辑` | 空态文案混入 `NPC` |
|
||||
| `src/components/NpcVisualEditor.tsx` | `539` | 英文直出 | `Save failed` | 保存失败提示仍是英文 |
|
||||
| `src/components/NpcVisualEditor.tsx` | `702-708` | 中英混用 | `NPC 视觉编辑器`、`选择并编辑 NPC 的外观...` | 页面标题与简介多次混入 `NPC` |
|
||||
| `src/components/NpcVisualEditor.tsx` | `718` | 中英混用 | `当前 NPC` | 当前对象字段名混入 `NPC` |
|
||||
| `src/components/NpcVisualEditor.tsx` | `976-977` | 中英混用 | `拖动标记微调 NPC 的预览布局。移动时按住 Shift...` | 帮助提示同时混入 `NPC` 与 `Shift` |
|
||||
| `src/components/NpcVisualEditor.tsx` | `1033-1052` | 英文直出 | `Unknown headgear`、`No headgear`、`Unknown main hand`、`No main hand`、`Unknown off hand`、`No off hand` | 预览状态说明仍是英文 |
|
||||
|
||||
## 四、预设编辑器
|
||||
|
||||
### 4.1 共享配置与选项枚举
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 / 字段 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/preset-editor/shared.ts` | `43` | 中英混用 | `label: 'NPC'` | 预设编辑器顶部 tab 仍直接显示 `NPC` |
|
||||
| `src/components/preset-editor/shared.ts` | `63-66` | 英文直出 | `idle`、`move`、`attack`、`die` | 怪物动画可选项是原始英文值 |
|
||||
| `src/components/preset-editor/shared.ts` | `70-74` | 英文直出 | `steady`、`burst`、`mobility`、`finisher`、`projectile` | 技能风格可选项是原始英文值 |
|
||||
|
||||
### 4.2 角色预设面板
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 / 字段 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/preset-editor/CharacterPresetPanel.tsx` | `91-92` | 英文直出 | `Saved character preset overrides...`、`Failed to save character preset overrides.` | 保存反馈未本地化 |
|
||||
| `src/components/preset-editor/CharacterPresetPanel.tsx` | `264-279` | 英文直出 | `Characters`、`Browse the character roster...`、`Field`、`Save Character Overrides` | 左侧选择卡与保存栏均为英文 |
|
||||
| `src/components/preset-editor/CharacterPresetPanel.tsx` | `315-322` | 英文直出 | `Character Details`、`Field` | 详情卡标题和字段名未本地化 |
|
||||
| `src/components/preset-editor/CharacterPresetPanel.tsx` | `404-430` | 英文直出 | `Skill Preview`、`Preview ranged skills...`、`Preview Monster` | 技能预览区英文直出 |
|
||||
| `src/components/preset-editor/CharacterPresetPanel.tsx` | `450-467` | 英文直出 | `Skill Setup`、`Add Skill` | 技能配置区仍是英文 |
|
||||
| `src/components/preset-editor/CharacterPresetPanel.tsx` | `498-558` | 英文直出 | 大量 `label="Field"` | 多数字段仍显示占位词 `Field` |
|
||||
| `src/components/preset-editor/CharacterPresetPanel.tsx` | `605` | 英文直出 | `Start Frame` | 动画字段未本地化 |
|
||||
| `src/components/preset-editor/CharacterPresetPanel.tsx` | `629`、`729` | 英文直出 | `Section`、`Editor section.` | 两个分区仍是半成品英文占位 |
|
||||
| `src/components/preset-editor/CharacterPresetPanel.tsx` | `697-698` | 英文直出 | `Attributes`、`Adjust the core character attributes.` | 属性面板未本地化 |
|
||||
| `src/components/preset-editor/CharacterPresetPanel.tsx` | `755` | 英文直出 | `Unset` | 场景绑定下拉空值项为英文 |
|
||||
|
||||
### 4.3 怪物预设面板
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 / 字段 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | `49-50` | 英文直出 | `Saved monster overrides...`、`Failed to save monster overrides.` | 保存反馈未本地化 |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | `124-139` | 英文直出 | `Section`、`Editor section.`、`Field`、`Save Monster Overrides` | 左侧选择区和保存栏未本地化 |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | `135` | 异常显示 | ``${WORLD_LABELS[monster.worldType]} 闂?${optionMonster.name}`` | 选择列表分隔符损坏 |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | `158-159` | 英文直出 | `Monster Override Preview`、`Editor section.` | 预览区标题仍是英文 |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | `192-201` | 英文直出 | `Attack Range`、`Speed`、`HP`、`Max HP` | 预览摘要未本地化 |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | `212-234` | 英文直出 | `Monster ID`、`Name`、`Intro Action` | 核心字段名仍是英文 |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | `343` | 英文直出 | `FPS` | 动画字段未本地化 |
|
||||
| `src/components/preset-editor/MonsterPresetPanel.tsx` | `207`、`275`、`307` | 英文直出 | `Section`、`Editor section.` | 多个分区标题仍为占位英文 |
|
||||
|
||||
### 4.4 场景 NPC 预设面板
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 / 字段 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `127-128` | 英文直出 | `Saved NPC overrides.`、`Failed to save NPC overrides.` | 保存反馈未本地化 |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `159` | 英文直出 | `No NPC presets are available.` | 空态文案未本地化 |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `177-193` | 英文直出 | `NPC Library`、`Browse and select an NPC preset.`、`NPC ID`、`Save NPC Overrides` | 左侧选择区英文直出 |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `221-237` | 英文直出 | `Skill Preview`、`Preview ranged skills from the linked character.`、`Skill`、`World` | 技能预览区未本地化 |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `258` | 异常显示 | `闂?NPC` | 空态或提示文案已损坏 |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `264-268` | 英文直出 | `Visual Preview`、`Hostile NPCs use monster presets...` | 视觉预览区标题与说明均未本地化 |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `310-371` | 英文直出 | `NPC Details`、`Name`、`Role`、`Avatar`、`Linked Character ID`、`Monster Preset ID`、`Initial Affinity`、`Description`、`Visual Editor` | 详情区字段名大面积英文直出 |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `374-375` | 英文直出 | `Hostile NPCs cannot use the visual editor...`、`Narrative NPC visual overrides can be previewed here.` | 视觉编辑区说明未本地化 |
|
||||
| `src/components/preset-editor/SceneNpcPresetPanel.tsx` | `382-384` | 异常显示 | 三整段乱码说明 + `NPC` | 视觉编辑区空态说明已严重损坏 |
|
||||
|
||||
### 4.5 场景预设面板
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 / 字段 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/preset-editor/ScenePresetPanel.tsx` | `52-53` | 英文直出 | `Saved scene overrides.`、`Failed to save scene overrides.` | 保存反馈未本地化 |
|
||||
| `src/components/preset-editor/ScenePresetPanel.tsx` | `62` | 英文直出 | `No scene presets are available.` | 空态文案未本地化 |
|
||||
| `src/components/preset-editor/ScenePresetPanel.tsx` | `105-107` | 英文直出 | `Treasure Ahead`、`Treasure` | 宝藏预览实体名仍是英文 |
|
||||
| `src/components/preset-editor/ScenePresetPanel.tsx` | `132-171` | 英文直出 | `Scene Library`、`Browse and select a scene preset.`、`Save`、`Scene Preview`、`Preview monsters, NPCs, and treasure...` | 场景面板主框架仍多处英文 |
|
||||
| `src/components/preset-editor/ScenePresetPanel.tsx` | `175-181` | 英文直出 | `Preview Mode`、`Monster Preview`、`NPC Preview`、`Treasure Preview` | 预览模式切换未本地化 |
|
||||
| `src/components/preset-editor/ScenePresetPanel.tsx` | `207-226` | 英文直出 | `Hostile NPCs`、`NPCs`、`None` | 预览摘要区未本地化 |
|
||||
| `src/components/preset-editor/ScenePresetPanel.tsx` | `233-290` | 英文直出 | `Scene Details`、`Edit the selected scene preset.`、`Scene ID`、`World`、`Name`、`Description`、`Image Source`、`Forward Scene`、`Connected Scene IDs`、`Monster IDs`、`Treasure Hints` | 详情编辑区字段名几乎全部英文 |
|
||||
| `src/components/preset-editor/ScenePresetPanel.tsx` | `271` | 英文直出 | `Unset` | 下拉空值项为英文 |
|
||||
| `src/components/preset-editor/ScenePresetPanel.tsx` | `299` | 英文直出 | `NPCs In Scene` | 分区标题未本地化 |
|
||||
|
||||
### 4.6 状态函数编辑器
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 / 字段 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/components/StateFunctionEditor.tsx` | `310-325` | 英文直出 | `Preview`、`Treasure` | 预览 NPC / 宝藏 context 里保留英文 |
|
||||
| `src/components/StateFunctionEditor.tsx` | `1062-1064` | 英文直出 | `Option behavior overrides saved.`、`Failed to save option behavior overrides` | 保存反馈未本地化 |
|
||||
| `src/components/StateFunctionEditor.tsx` | `1128` | 英文直出 | `无模板` 之外的模板选择逻辑仍有英文结构 | 该区主体中文,但下游模板 ID / 类型依旧偏英文 |
|
||||
| `src/components/StateFunctionEditor.tsx` | `1185` | 英文直出 | `AnimationState` 原始值直接作为选项标签 | 动画值会直接显示英文枚举 |
|
||||
| `src/components/StateFunctionEditor.tsx` | `1190` | 英文直出 | `placeholder="可使用 {monster} 占位符"` | 占位符本身暴露英文 key |
|
||||
| `src/components/StateFunctionEditor.tsx` | `1191` | 英文直出 | `idle`、`move`、`attack` | 怪物动画下拉仍使用英文值 |
|
||||
|
||||
## 五、数据层 / 运行时文本源
|
||||
|
||||
### 5.1 直接驱动交互按钮、详情文案、结果文本的源头
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 / 字段 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/data/npcInteractions.ts` | `444-580` | 重点补录 | 大量 `actionText` / `detailText` | 这是本轮补录重点,属于 NPC 交互选项直接展示源,需要逐条审校 |
|
||||
| `src/data/npcInteractions.ts` | `327-349` | 英文直出 | `deep`、`honest`、`partial`、`guarded`、`warm`、`cooperative`、`neutral`、`distant`、`candid`、`true_but_incomplete`、`half_truth`、`situational_only` | 这些关系 / 说话风格值虽然是逻辑枚举,但后续很容易在编辑器、调试面板、覆盖配置中直接暴露 |
|
||||
| `src/hooks/useStoryGeneration.ts` | `576-578` | 英文直出 | `Travel to ...`、`Leave camp and head toward ...` | 旅行选项和详情文案未本地化 |
|
||||
| `src/hooks/useStoryGeneration.ts` | `654-659` | 英文直出 | `Speak with ...`、`Focus on the person in front of you first...` | 开场对话选项未本地化 |
|
||||
| `src/hooks/useStoryGeneration.ts` | `827`、`1297` | 英文直出 | `Exchange an opening judgment with ... at camp` | 营地开场交互 actionText 未本地化 |
|
||||
| `src/hooks/useStoryGeneration.ts` | `1097` | 英文直出 | `Begin the adventure` | 初始 actionText 未本地化 |
|
||||
| `src/hooks/useStoryGeneration.ts` | `1374`、`1794` | 英文直出 | `Unknown AI error` | AI 兜底错误提示仍是英文 |
|
||||
| `src/hooks/story/storyGenerationState.ts` | `137-141` | 英文直出 | `You leave ...`、`Travel to ...` | 旅行结果与 actionText 未本地化 |
|
||||
| `src/hooks/story/npcEncounterActions.ts` | `277` | 英文直出 | `Victory reward: ${lootText}.` | 战斗胜利奖励结算文本未本地化 |
|
||||
| `src/hooks/story/npcEncounterActions.ts` | `389` | 英文直出 | `NPC dialogue AI is unavailable.` | NPC 对话 AI 失败兜底是英文 |
|
||||
| `src/hooks/story/characterChat.ts` | `68` | 英文直出 | `Player` | 聊天摘要拼接里保留英文说话人名 |
|
||||
| `src/hooks/story/characterChat.ts` | `84` | 英文直出 | `Tell me more clearly what you mean.` | 建议起句未本地化 |
|
||||
| `src/hooks/story/characterChat.ts` | `283` | 英文直出 | `Unknown AI error` | 私聊错误兜底未本地化 |
|
||||
| `src/data/sceneObservation.ts` | `9-34` | 英文直出 | `You pause to listen...`、`Possible NPCs...`、`Possible hostile NPCs...`、`Possible treasure clues...`、`Boss clue...` | 观察环境的整组文本源仍是英文 |
|
||||
|
||||
### 5.2 会透出到编辑器 / 预览 / 覆盖系统的预设值
|
||||
|
||||
| 文件 | 行号 | 类型 | 当前文本 / 字段 | 说明 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `src/data/scenePresets.ts` | `141` | 中英混用 | `role: '敌对NPC'` | 场景 NPC 角色名混入 `NPC` |
|
||||
| `src/data/scenePresets.ts` | `194`、`294` | 英文直出 | `['trade', 'fight', 'spar', 'help', 'chat', 'recruit', 'gift']` | 场景 NPC 功能数组是英文原始值,编辑器容易直出 |
|
||||
| `src/data/stateFunctions.ts` | `33` | 英文直出 | `monsterAnimation?: 'idle' | 'move' | 'attack'` | 动画值原始英文会进入状态函数编辑器 |
|
||||
| `src/data/stateFunctions.ts` | `130`、`152`、`174`、`196`、`221`、`244` | 英文直出 | `steady`、`burst`、`mobility`、`finisher`、`projectile` | 技能权重 key 为英文原始值 |
|
||||
| `src/data/stateFunctions.ts` | `372`、`445`、`569`、`575-576` | 中英混用 | 描述里多次直接写 `NPC` | 虽然主体中文,但会透出到说明文字 |
|
||||
| `src/data/characterPresets.ts` | `54-70` | 英文直出 | `blunt`、`wary`、`evasive`、`measured`、`gentle`、`teasing`、`dry`、`steady`、`direct`、`fragmented`、`deflecting` | 对话风格推断返回值全为英文 |
|
||||
| `src/data/characterPresets.ts` | `362-382`、`519-539`、`738-758`、`833-853`、`1018-1041` | 英文直出 | `assetFolder`、`folder`、`prefix` 中大量英文,如 `Sword Princess`、`idle`、`Double Jump`、`Wall Slide`、`Attack` | 这些值会被预设编辑器动画区直接展示或编辑 |
|
||||
| `src/data/characterPresets.ts` | `387-389`、`544-546`、`763-765`、`858-860`、`1046-1048` | 英文直出 | `guardStyle`、`warmStyle`、`truthStyle` 使用英文值 | 会透出到预设编辑器 / 调试视图 |
|
||||
| `src/data/characterPresets.ts` | `410-501`、`575-720`、`794-1000`、`1069-1197` | 英文直出 | `style`、`delivery`、`phase`、`anchor`、`motion` 使用 `steady`、`mobility`、`ranged`、`travel`、`target`、`projectile` 等英文值 | 角色技能配置层大面积保留英文元数据 |
|
||||
| `src/data/monsterPresets.ts` | `384-817` | 英文直出 | 多处 `common`、`uncommon`、`rare`、`epic` | 怪物稀有度原始值为英文,若编辑器未做映射会直接暴露 |
|
||||
| `src/editor/shared/jsonClient.ts` | `29-43` | 英文直出 | `Request failed`、`Save failed` | 编辑器通用 JSON 客户端默认错误文案未本地化 |
|
||||
|
||||
## 六、本轮已复查、暂未记录明确问题的文件
|
||||
|
||||
以下文件本轮重新检查过,但当前内容里没有继续记录“英文直出 / 异常显示”的明确条目,暂可视为本轮通过:
|
||||
|
||||
- `src/routing/appRoutes.tsx`
|
||||
- `src/components/game-shell/CharacterSelectionFlow.tsx`
|
||||
- `src/components/game-shell/GameShellStoryPanels.tsx`
|
||||
- `src/components/CharacterPanel.tsx`
|
||||
- `src/components/InventoryPanel.tsx`
|
||||
- `src/components/MapModal.tsx`
|
||||
- `src/components/CharacterChatModal.tsx`
|
||||
- `src/components/SelectionCustomizationModals.tsx`
|
||||
- `src/components/adventure-panel/AdventurePanelOverlays.tsx`
|
||||
- `src/data/sceneEncounterPreviews.ts`
|
||||
- `src/data/customWorldVisuals.ts`
|
||||
- `src/services/customWorldBuilder.ts`
|
||||
|
||||
## 建议修复顺序
|
||||
|
||||
1. 先修主流程直接暴露给玩家的文本:
|
||||
- `PreGameSelectionFlow.tsx`
|
||||
- `GameShellOverlays.tsx`
|
||||
- `GameShellRuntime.tsx`
|
||||
- `GameShell.tsx`
|
||||
- `AdventurePanel.tsx`
|
||||
2. 再修编辑器里最容易误导内容生产的面板:
|
||||
- `CharacterPresetPanel.tsx`
|
||||
- `MonsterPresetPanel.tsx`
|
||||
- `SceneNpcPresetPanel.tsx`
|
||||
- `ScenePresetPanel.tsx`
|
||||
- `StateFunctionEditor.tsx`
|
||||
3. 最后统一清理数据层文本源和枚举映射:
|
||||
- `npcInteractions.ts`
|
||||
- `useStoryGeneration.ts`
|
||||
- `storyGenerationState.ts`
|
||||
- `npcEncounterActions.ts`
|
||||
- `sceneObservation.ts`
|
||||
- `characterPresets.ts`
|
||||
- `stateFunctions.ts`
|
||||
18
docs/audits/text/README.md
Normal file
18
docs/audits/text/README.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# 文本与乱码审计总览
|
||||
|
||||
这一组只保留当前仍需要执行的文本与乱码审计入口。早期逐日扫描已经聚合到当前结论,不再保留旧稿链路。
|
||||
|
||||
## 当前推荐入口
|
||||
|
||||
1. [CHINESE_MOJIBAKE_INVENTORY.md](./CHINESE_MOJIBAKE_INVENTORY.md)
|
||||
偏全局库存清单,适合先确认问题分布范围。
|
||||
2. [GAME_UI_PRESET_EDITOR_NPC_PROMPT_TEXT_AUDIT_2026-04-02_DEEP_SCAN.md](./GAME_UI_PRESET_EDITOR_NPC_PROMPT_TEXT_AUDIT_2026-04-02_DEEP_SCAN.md)
|
||||
这是当前最完整的深度审计版本,已经扩到 `prompt`、`npcInteractions`、运行时弹窗与编辑器深层文本。
|
||||
3. [GAME_UI_PRESET_EDITOR_TEXT_AUDIT_2026-04-02.md](./GAME_UI_PRESET_EDITOR_TEXT_AUDIT_2026-04-02.md)
|
||||
适合看“扩展重查版”的 UI / 预设 / 编辑器问题面。
|
||||
|
||||
## 融合结论
|
||||
|
||||
- 早期几轮扫描已经完成使命,核心结论是:不要把乱码当成普通文案改写,先确认真实编码;文本修复要优先处理会进入玩家体验和 AI 生成链路的内容。
|
||||
- `2026-04-02` 两份文档开始把重点收敛到真正会影响玩家体验和 AI 生成质量的链路。
|
||||
- 现在做文本修复时,不必从最早一份开始逐篇读;优先看 `CHINESE_MOJIBAKE_INVENTORY` 和 `2026-04-02` 两份即可。
|
||||
Reference in New Issue
Block a user