init with react+axum+spacetimedb
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
2026-04-26 18:06:23 +08:00
commit cbc27bad4a
20199 changed files with 883714 additions and 0 deletions

View 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``作品库` 四层并存、靠前端桥接和结果页兼容能力临时拼起来的过渡态。

View 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 闭环。**

View 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、流程和后端边界上。**

View 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 已经能驱动游戏,但还没有彻底收束成“所有预设内容与实时生成规则都优先读取它”的单一真相源。主链可用,边链仍散,跨题材合理性仍偏弱。**

View 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 越多,这类问题会越难排查。

View File

@@ -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 首次点击也必须立刻生成一段剧情反馈”,否则不建议为了形式统一再强行改写当前分流模型。

View 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 系统的自动化测试层状况”,但不等于“所有视觉演出与在线模型联动都已人工验证完毕”。

View 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 稳定复现出来,避免问题只停留在口头描述。
- 第二步在修复后把断言翻转成“正确行为”,让它们正式成为回归测试。

View 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
View 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. 做方案设计前,优先把对应审计文档看完,避免重复踩已知问题。

View File

@@ -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` 的归一化读取,而不是增加中间转换结构。

View File

@@ -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`

View File

@@ -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-20NPC 待接委托正式接取收口)
本文审计项 `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-20NPC 聊天任务草案与浏览器 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 插件入口的扫描结果

View File

@@ -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. 当前依赖图扫描结果与当前大文件体量扫描结果

View File

@@ -0,0 +1,141 @@
# 工程死分支清理执行记录 A2026-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`
一句话总结本批次:
**先把最确定的死分支和占位壳子清掉,让主工程少一些假入口、假主源、假能力,再进入更重的主链收口。**

View File

@@ -0,0 +1,145 @@
# 工程死分支清理执行记录 B2026-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 路牌从主工程里真正拔掉,让现行架构不再和历史壳子并排站着。**

View File

@@ -0,0 +1,241 @@
# 工程死分支清理执行记录 C2026-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 约束,不能在服务端未先补齐前硬砍。**

View File

@@ -0,0 +1,56 @@
# 工程死分支清理执行记录 D2026-04-21
更新时间:`2026-04-21`
## 0. 本批次目标
本批次继续清理上一轮复核后剩余的低风险数据产物与测试占位:
1. 未接入业务的生成产物
2. 只为测试替换真实实现的空 stub
3. 支撑这些残留的配置与脚本
---
## 1. 已删除对象
| 文件 | 判定 | 删除原因 | 替代路径 / 当前真相源 |
| --- | --- | --- | --- |
| `src/data/buildTagSimilarity.generated.ts` | 未接入业务的生成产物 | 运行时代码不 importBuild 相似度当前由 `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. 大型主流程组件继续拆分,而不是直接删除

View File

@@ -0,0 +1,117 @@
# 工程死分支清理执行记录 E2026-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 创作编辑器与运行时热点文件的职责拆分。

View File

@@ -0,0 +1,91 @@
# 工程死分支清理执行记录 F2026-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而不应再按文件名或历史命名直接硬删。

View File

@@ -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。**

View File

@@ -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 再跑”的中间态。

View 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 记录开始即可。

View File

@@ -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 专用开发入口。

View 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`
## 备注
- 当前文档的目标是“先把位置收拢清楚”,不是直接修复乱码。
- 如果你下一步要我继续,我可以基于这份清单继续做两件事之一:
- 逐文件修复中文乱码
- 先做一个“乱码修复优先级 + 替换建议”文档

View 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 QA4 条明线 / 1 条问题。
- Release Gatewarn。当前版本可继续观察但仍有若干 narrative 风险。
- Simulation共跑了 3 条 simulationending family 1 类,单次最高 QA 问题 1 条。
### 当前主要问题
- 有线程合约尚未在 chronicle 中留下足够的回收痕迹。
## 仙侠世界
### 说明
- “原文”部分整理的是当前仓库角色、场景、NPC 和残痕里已经存在的中文文本。
- “引擎整理”部分是根据这些原文,经过 story engine 的主题包、线程图谱、角色叙事档案和 QA 规则重新编译出的结构化结果。
### 项目内原始剧情文本整理
### 可扮演角色原文
- 剑之公主 / 王庭剑姬
角色原文:以迅疾剑技和正面压制见长,适合喜欢凌厉推进的玩家。
背景原文:王庭旁支出身,自幼被当作执剑者培养。一次宫变让她失去旧有庇护,也背上了亲手追回王室誓剑与真相的责任。
表层来意:以迅疾剑技和正面压制见长,适合喜欢凌厉推进的玩家。
- 神箭游侠 / 流风弓卫
角色原文:擅长远距离压制与精准射击,节奏灵活,机动性很强。
背景原文:曾是边境游骑与斥候,被一场伏击逼得离开旧军阵。如今他只信自己亲眼见过的风向与箭路,却仍背着守住边境故土的旧誓。
表层来意:擅长远距离压制与精准射击,节奏灵活,机动性很强。
- 双刃旅者 / 疾影斥候
角色原文:速度快、侵略性强,适合喜欢持续推进和连段压迫的玩家。
背景原文:她在暗巷与帮派追杀中长大,学会靠速度、直觉和先手活下去。表面上轻快利落,心里却一直在追查那封改变命运的密信去向。
表层来意:速度快、侵略性强,适合喜欢持续推进和连段压迫的玩家。
### 场景角色原文
- 神箭游侠 / 流风弓卫
角色原文:擅长远距离压制与精准射击,节奏灵活,机动性很强。
保留线索:曾是边境游骑与斥候,被一场伏击逼得离开旧军…
- 玄甲战锋 / 重装先锋
角色原文:攻守兼备,推进稳健,适合喜欢扎实前排风格的玩家。
保留线索:他长期担任重装前锋,习惯站在最危险的位置替…
- 秘匣书妖 / 敌对角色
角色原文:像会自行翻页的秘典与宝匣,常在仙门、遗迹与禁制附近浮游。
保留线索:秘匣书妖长期出没于云海仙门。像会自行翻页的…
- 噬雾飞蛾 / 敌对角色
角色原文:借雾气遮身,飞行轨迹诡谲,喜欢围着灵光和人影打转。
保留线索:噬雾飞蛾长期出没于云海仙门。借雾气遮身,飞…
- 守门灵官 / 门官
角色原文:站在门阙侧旁观来者,像在等一份迟迟未到的回报。
保留线索:守门灵官长期出没于云海仙门。站在门阙侧旁观…
- 幽烬灵蝠 / 敌对角色
角色原文:翅翼缭绕灰烬般的灵火,常成群出没于洞天、崖壁与灵脉附近。
保留线索:幽烬灵蝠长期出没于悬空仙岛。翅翼缭绕灰烬般…
### 场景原文整理
- 云海仙门
场景原文:云阶在脚下翻涌,门阙后方灵光不断,来客与守门异物都极显眼。
第一残痕:云阶尽头的灵符匣
场景角色:神箭游侠(流风弓卫)、玄甲战锋(重装先锋)、秘匣书妖(敌对角色)
- 悬空仙岛
场景原文:浮岛边缘风大云急,灵禽与飞蛾总绕着岛沿的光带盘旋。
第一残痕:浮岛边缘的灵羽匣
场景角色:幽烬灵蝠(敌对角色)、噬雾飞蛾(敌对角色)、云栖散修(散修)
- 天宫长廊
场景原文:廊柱之间回响着空灵风声,禁制和书妖都喜欢寄在这类高处回廊里。
第一残痕:廊柱暗槽里的玉简
场景角色:剑之公主(王庭剑姬)、玄甲战锋(重装先锋)、秘匣书妖(敌对角色)
- 灵药花圃
场景原文:灵草灵花层层叠开,香气诱人,却也最容易养出食灵的怪物。
第一残痕:药圃深处的灵壶
场景角色:噬灵妖花(敌对角色)、血瞳妖眼(敌对角色)、药圃执事(药师)
- 寒玉洞天
场景原文:洞壁结着寒玉光泽,地面湿滑,水灵和阴性异物都爱停在这里。
第一残痕:寒玉裂隙里的灵髓
场景角色:青腐泥灵(敌对角色)、幽烬灵蝠(敌对角色)、澄潮灵母(敌对角色)
### 引擎整理出的明线
- 灵脉与封印正在失衡:灵脉与封印正在失衡,焦点常落在云海仙门。
- 追索线:宗门旧案与秘境争夺彼此缠住了当下局势,焦点常落在悬空仙岛。
- 封印失衡线:当前仙侠世界由宗门秩序、秘境余波、灵脉封印和古仙残迹共同推着故事前进,玩家每深入一层,都会撞上新的旧事回响。,焦点常落在天宫长廊。
- 宗门旧案线:顺着灵痕、残识和人物保留,一层层摸清宗门旧案与秘境失衡的根源,焦点常落在灵药花圃。
### 引擎整理出的暗线
- 神箭游侠的隐线:神箭游侠并不只是流风弓卫,他与灵脉与封印正在失衡之间还有一段未被说破的牵连。
- 玄甲战锋的隐线:玄甲战锋并不只是重装先锋,他与追索线之间还有一段未被说破的牵连。
- 秘匣书妖的隐线:秘匣书妖并不只是敌对角色,他与封印失衡线之间还有一段未被说破的牵连。
- 噬雾飞蛾的隐线:噬雾飞蛾并不只是敌对角色,他与宗门旧案线之间还有一段未被说破的牵连。
- 守门灵官的隐线:守门灵官并不只是门官,他与灵脉与封印正在失衡之间还有一段未被说破的牵连。
### 场景旧痕
- 云海仙门留下的旧痕:表层残痕是“云阶在脚下翻涌,门阙后方灵光不断,来客与守门异物都极显眼。”;压着的真相是“神箭游侠并不只是流风弓卫,他与灵脉与封印正在失衡之间还有一段未被说破的牵连。”
- 悬空仙岛留下的旧痕:表层残痕是“浮岛边缘风大云急,灵禽与飞蛾总绕着岛沿的光带盘旋。”;压着的真相是“玄甲战锋并不只是重装先锋,他与追索线之间还有一段未被说破的牵连。”
- 天宫长廊留下的旧痕:表层残痕是“廊柱之间回响着空灵风声,禁制和书妖都喜欢寄在这类高处回廊里。”;压着的真相是“秘匣书妖并不只是敌对角色,他与封印失衡线之间还有一段未被说破的牵连。”
- 灵药花圃留下的旧痕:表层残痕是“灵草灵花层层叠开,香气诱人,却也最容易养出食灵的怪物。”;压着的真相是“噬雾飞蛾并不只是敌对角色,他与宗门旧案线之间还有一段未被说破的牵连。”
- 寒玉洞天留下的旧痕:表层残痕是“洞壁结着寒玉光泽,地面湿滑,水灵和阴性异物都爱停在这里。”;压着的真相是“守门灵官并不只是门官,他与灵脉与封印正在失衡之间还有一段未被说破的牵连。”
### 玩家在游戏中真实感受到的剧情样章
你来到这个仙侠世界,是因为王庭圣印坠入了云海裂隙。此行最重要的目标,是寻回圣印,截断那些企图借它开启天门禁制的野心。 第一眼看到的不是纯说明,而是 星舟甲板 里的环境压迫:甲板横在高天之上,风压和星光都很强,飞行异物最爱在这里盘旋。
走进星舟甲板时,玩家实际感受到的核心不是“到了新地图”,而是“甲板横在高天之上,风压和星光都很强,飞行异物最爱在这里盘旋。”。这句场景原文会立刻把体验拉回到“灵脉与封印正在失衡”这条明线。神箭游侠表面只是流风弓卫,但他的公开面是“擅长远距离压制与精准射击,节奏灵活,机动性很强。”,真正压在肩上的却是“找回星图核心,查清是谁击落了你的船队”。而像“舵台后的星图匣”这样的场景残痕,会把玩家往“这里一定还藏着别的事”那种感觉里继续推。如果继续追下去,星舟甲板背后会逐渐显出“神箭游侠并不只是流风弓卫,他与灵脉与封印正在失衡之间还有一段未被说破的牵连。”这层旧伤。
走进悬空仙岛时,玩家实际感受到的核心不是“到了新地图”,而是“浮岛边缘风大云急,灵禽与飞蛾总绕着岛沿的光带盘旋。”。这句场景原文会立刻把体验拉回到“追索线”这条明线。云栖散修表面只是散修,但他的公开面是“常坐在浮岛边缘打坐,对天风和禁制的变化很敏感。”,真正压在肩上的却是“在悬空仙岛守住自己不愿失去的那一层秩序。”。而像“浮岛边缘的灵羽匣”这样的场景残痕,会把玩家往“这里一定还藏着别的事”那种感觉里继续推。如果继续追下去,悬空仙岛背后会逐渐显出“玄甲战锋并不只是重装先锋,他与追索线之间还有一段未被说破的牵连。”这层旧伤。
走进月湖仙洲时,玩家实际感受到的核心不是“到了新地图”,而是“湖光像铺开的镜面,水灵、章灵与花影都可能从月色里浮出来。”。这句场景原文会立刻把体验拉回到“封印失衡线”这条明线。双刃旅者表面只是疾影斥候,但他的公开面是“速度快、侵略性强,适合喜欢持续推进和连段压迫的玩家。”,真正压在肩上的却是“找到残阵核心,并弄明白信里提到的“第二个你”究竟是谁”。而像“湖岸边漂来的玉匣”这样的场景残痕,会把玩家往“这里一定还藏着别的事”那种感觉里继续推。如果继续追下去,月湖仙洲背后会逐渐显出“秘匣书妖并不只是敌对角色,他与封印失衡线之间还有一段未被说破的牵连。”这层旧伤。
因此,仙侠世界目前最容易让玩家产生真实剧情感的地方,不是某一句高光台词,而是“场景描述 -> 人物保留 -> 残痕线索 -> 线程压力”这条连续链路。它已经能让玩家觉得自己在追一件还没完全揭开的事,但离“经典 RPG 式的强收束和强情感爆点”还差最后一层回响回收。
### 质量评测
整体判断:**部分达成预期**
### 维度评测
- 角色记忆点:达成。当前可扮演角色的人设、背景、开局动机和首遇目标已经能形成第一轮代入,玩家能记住“谁在上路、为什么上路”。
- 低关系也有戏:达成。低好感或首遇 NPC 不再只是“更冷淡”,而是能从当前压力、错位说辞和反应钩子里带出暗线存在感。
- 世界互文与旧史厚度达成。场景、NPC、旧痕和线程已经能互相指向同一批旧事不再只是各自独立的设定块。
- 空间与残痕叙事:达成。地点不是纯背景图,场景描述、宝藏线索和 narrative residue 已经能共同承担“空间会说话”的职责。
- 选择后果与主线抓手:部分达成。当前任务抓手和线程合约已经存在,但真正影响关系、理解和后续回响的后果层还没有被完全跑满。
- 长线回响与收束:未达成。从 QA 结果看,当前版本最明显的短板仍是“已经埋下的线,后面有没有被稳定回收”。这一步决定它能不能真正跨到经典 RPG 质感。
### 客观检查
- Narrative QA4 条明线 / 1 条问题。
- Release Gatewarn。当前版本可继续观察但仍有若干 narrative 风险。
- Simulation共跑了 3 条 simulationending family 1 类,单次最高 QA 问题 1 条。
### 当前主要问题
- 有线程合约尚未在 chronicle 中留下足够的回收痕迹。
## 最终结论
- 如果目标只是“让玩家进入游戏后立刻感觉世界里有事正在发生”,当前文本资产已经够用,且部分环节已经明显跑起来了。
- 如果目标是“对标经典单机 RPG 的强角色回响、强关系后果、强主线收束”,当前版本还只能算走到了一半,最该补的是 payoff 和长线回响。
- 也就是说:**当前剧情原文的底座已经部分达到预期,但还没到可以完全放心交给玩家沉浸式吃剧情的程度。**

View File

@@ -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`,最后统一共享请求层兜底文案。

View 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`

View 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` 两份即可。