Files
Genarrative/docs/technical/EXPRESS_BACKEND_WORKSTREAM_AUDIT_2026-04-09.md
2026-04-10 15:37:02 +08:00

426 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Express 后端并行任务完成度审计2026-04-09
## 1. 审计范围
本次审计以 `docs/planning/EXPRESS_BACKEND_PARALLEL_WORKSTREAM_PLAN_2026-04-08.md` 为基准,只检查仓库内可直接验证的代码、测试、脚本和文档产物。
不能仅靠仓库静态内容确认的团队协作物,例如看板、口头冻结流程、每日集成节奏,只按“仓库内可见状态”记录,不把它们误判成完全验收。
---
## 2. 任务完成度总览
| 任务 | 状态 | 结论 |
| --- | --- | --- |
| 任务 0集成岗与接口冻结 | 基本完成 | 已补齐接口冻结与集成清单文档contract 版本表、热点文件编辑规则、集成窗口检查项都已落库;但团队执行节奏本身仍无法仅凭仓库静态确认。 |
| 任务 1共享 Contract 与目录抽离 | 部分完成 | `packages/shared` 已建立并承接 auth/runtime/story contract且 NPC Task6 bridge 与 chat prompt builder 已进一步下沉到后端本地模块;但 AI 编排主链仍残留少量 `src/**` 反向依赖,分层尚未完全闭合。 |
| 任务 2PostgreSQL 持久化基线收口 | 已完成 | `server-node/src/config.ts``db.ts``repositories/**`、迁移脚本、`pg-mem` 测试与部署文档均已到位。 |
| 任务 3HTTP 基础设施与统一响应壳层 | 已完成 | 统一错误格式、`requestId`、route meta、响应壳层、观测测试已落地。 |
| 任务 4服务端 AI 编排收口 | 基本完成 | orchestration 模块、SSE 转发和主链调用已回到后端,但仍有少量 prompt/规则模块通过 `src/**` 复用,属于后续继续收敛项。 |
| 任务 5Story / Combat / NPC | 已完成 | 后端 story action route、session 组装、combat/npc 领域服务和对应回归测试已落地。 |
| 任务 6Inventory / Quest / Build / Runtime Item | 已完成 | 对应模块、服务与回归测试已经覆盖主要正式运行时结算。 |
| 任务 7前端 SDK、鉴权、持久化瘦身 | 部分完成 | `apiClient``authService``storageService` 已统一,但前端仍保留一部分存档归一化和主流程协调职责。 |
| 任务 8编辑器 API 归口与工具链隔离 | 基本完成 | editor/assets 模块、前端 editor client、迁移文档均已出现职责边界基本清晰。 |
| 任务 9测试、观测与部署基线 | 已完成 | baseline test、smoke、proxy smoke、部署与回滚清单、日志链路均已具备。 |
| 任务 10前端主流程壳层与大 Hook 瘦身 | 部分完成 | `GameShellRuntime` / `useGameShellRuntimeViewModel` 以及新的 `storyRequestCoordinator` 已拆出,但 `useStoryGeneration.ts` 仍然过重,主流程尚未彻底退回“表现层协调器”。 |
---
## 3. 本轮补齐项
本轮先补齐了任务 0 缺失的仓库内协作产物:
- 新增 `docs/technical/EXPRESS_BACKEND_INTEGRATION_FREEZE_2026-04-09.md`
- 落库当前 contract 版本表
- 明确热点文件编辑规则
- 补齐 shared/runtime/editor/frontend 壳层各自的集成窗口清单
这让任务 0 不再只停留在规划文档里,而是有了一份可随版本一起更新的冻结口径。
随后补上了一段此前仍偏向前端快照解释的恢复链路:
- `src/hooks/story/runtimeStoryCoordinator.ts`
- 新增 `resumeServerRuntimeStory`
- 继续游戏时,若当前是正式运行时故事快照,会先请求 `/api/runtime/story/state/:sessionId`
- 让当前 `storyText` 与可用 `options` 优先以后端 runtime state 为准
- `src/hooks/useGamePersistence.ts`
- `continueSavedGame()` 现在会优先走后端 runtime story 恢复
- 如果服务端恢复失败,再回退到本地快照归一化结果
- 额外补了 `bottomTab` 归一化,避免恢复时吃到宽泛字符串
- `src/hooks/story/runtimeStoryCoordinator.test.ts`
- 新增“继续游戏时优先从后端恢复 runtime story”的测试
- 新增“非正式运行时快照不额外请求后端”的测试
这次补丁对应的是任务 7 与任务 10 之间的一段未完全闭合边界:前端在恢复流程里不应该只把远端存档当作“原始 JSON 缓存”,而应优先相信后端当前 runtime state。
此外,本轮还继续补了任务 1 的一段后端分层收口:
- 新增 `server-node/src/modules/runtime/runtimeStatePrimitives.ts`
- 后端本地承接 `addInventoryItems`
- 后端本地承接 `removeInventoryItem`
- 后端本地承接 `incrementGameRuntimeStats`
- 后端本地承接 `buildRelationState`
- 新增 `server-node/src/modules/runtime/runtimeStatePrimitives.test.ts`
- 校验背包合并、移除、运行时统计累加、关系阶段映射
- 调整桥接层:
- `server-node/src/bridges/legacyInventoryRuntimeBridge.ts`
- `server-node/src/bridges/legacyNpcTask6Bridge.ts`
- `server-node/src/modules/quest/questTask6Bridge.ts`
这意味着任务 5/6 主链里最基础的一批状态原语,已经不再依赖前端 `src/data/runtimeStats.ts``src/data/attributeResolver.ts``src/data/npcInteractions.ts` 的对应实现。
本轮又继续把 NPC Task6 bridge 里最后一批直接挂到前端 `npcInteractions.ts` 的函数下沉到了后端本地:
- 新增 `server-node/src/modules/npc/npcTask6Primitives.ts`
- 后端本地承接 `applyStoryChoiceToStanceProfile`
- 后端本地承接 `buildInitialNpcState`
- 后端本地承接 `syncNpcTradeInventory`
- 后端本地承接 `getGiftCandidates`
- 后端本地承接 `buildNpcGiftCommitActionText`
- 后端本地承接 `buildNpcGiftResultText`
- 后端本地承接 `buildNpcTradeTransactionActionText`
- 后端本地承接 `buildNpcTradeTransactionResultText`
- 新增 `server-node/src/modules/npc/npcTask6Primitives.test.ts`
- 覆盖 NPC 初始库存生成
- 覆盖交易库存刷新时保留非交易物品
- 覆盖赠礼偏好排序
- 调整桥接层:
- `server-node/src/bridges/legacyNpcTask6Bridge.ts`
这意味着 Task6 的 NPC 交易/赠礼/初始库存这条支链,已经不再直接依赖前端 `src/data/npcInteractions.ts`
同时还把叙事语言检测工具下沉到了共享层:
- 新增 `packages/shared/src/llm/narrativeLanguage.ts`
- `src/services/narrativeLanguage.ts` 改为复用共享实现
- `server-node/src/modules/ai/storyOrchestrator.ts` 改为直接依赖共享层
这部分虽然不是大块业务迁移,但它属于任务 1 最稳定的一类收口:把纯函数共识从前端目录中抽离出来。
再补充一批已经完成的后端纯原语迁移:
- 新增 `server-node/src/modules/runtime/runtimeEconomyPrimitives.ts`
- 后端本地承接 `formatCurrency`
- 后端本地承接 `getInventoryItemValue`
- 后端本地承接 `getNpcPurchasePrice`
- 后端本地承接 `getNpcBuybackPrice`
- 新增 `server-node/src/modules/runtime/runtimeTreasureTexts.ts`
- 后端本地承接 `buildTreasureResultText`
- 新增 `server-node/src/modules/runtime/runtimeEconomyPrimitives.test.ts`
- 覆盖交易定价、货币文本、宝藏奖励文本
对应桥接层:
- `server-node/src/bridges/legacyNpcTask6Bridge.ts`
- 不再依赖前端 `src/data/economy.ts`
- `server-node/src/bridges/legacyTreasureRuntimeBridge.ts`
- 不再从前端导出 `buildTreasureResultText`
这说明任务 5/6 主链中一部分交易、礼物、宝藏结算反馈文本,也已经从前端数据层抽离。
本轮又进一步补了 NPC 状态与叙事记忆的后端本地原语:
- 新增 `server-node/src/modules/runtime/runtimeNpcStatePrimitives.ts`
- 后端本地承接 `normalizeNpcPersistentState`
- 后端本地承接 `markNpcFirstMeaningfulContactResolved`
- 新增 `server-node/src/modules/runtime/runtimeNarrativeMemory.ts`
- 后端本地承接 `appendStoryEngineCarrierMemory`
- 新增 `server-node/src/modules/runtime/runtimeNpcStatePrimitives.test.ts`
- 覆盖 NPC 状态归一化、首次有效接触标记、叙事载体记忆写入
对应桥接层:
- `server-node/src/bridges/legacyNpcTask6Bridge.ts`
- 不再依赖前端 `src/services/storyEngine/echoMemory.ts`
- 不再依赖前端 `src/data/npcInteractions.ts` 中的 NPC 状态归一化与首次接触标记逻辑
这进一步缩小了后端在任务 5/6 主链上对前端 story-engine 服务目录的借用范围。
本轮还整块收口了 Quest 与 Runtime Item 两条桥接链:
- 新增 `server-node/src/modules/quest/runtimeQuestModule.ts`
- 后端本地承接 `buildQuestForEncounter`
- 后端本地承接 `evaluateQuestOpportunity`
- 后端本地承接 `buildFallbackQuestIntent`
- 后端本地承接 `compileQuestIntentToQuest`
- 后端本地承接 `buildQuestGenerationContextFromState`
- 后端本地承接 `buildQuestIntentPrompt`
- 后端本地承接 Quest 进度归一化与 signal 推进
- 更新桥接层:
- `server-node/src/bridges/legacyQuestProgressBridge.ts`
- `server-node/src/bridges/legacyQuestRuntimeBridge.ts`
这意味着 Quest 的“确定性委托构建 + AI 意图上下文 + 任务推进”已经不再依赖前端 `src/data/questFlow.ts``src/services/questDirector.ts``src/services/questPrompt.ts`
同时Runtime Item 也已经收回到后端本地:
- 新增 `server-node/src/modules/runtime-item/runtimeItemModule.ts`
- 后端本地承接 `buildRuntimeItemAiIntent`
- 后端本地承接 `buildRuntimeItemIntentPrompt`
- 后端本地承接 `buildLooseRuntimeItemGenerationContext`
- 后端本地承接 `buildQuestRuntimeItemGenerationContext`
- 后端本地承接 `buildDirectedRuntimeReward`
- 后端本地承接 `buildRuntimeInventoryStock`
- 后端本地承接 `flattenDirectedRuntimeRewardItems`
- 新增 `server-node/src/modules/runtime-item/runtimeTreasureModule.ts`
- 后端本地承接 `resolveTreasureReward`
- 更新桥接层:
- `server-node/src/bridges/legacyRuntimeItemBridge.ts`
- `server-node/src/bridges/legacyRuntimeItemResolutionBridge.ts`
- `server-node/src/bridges/legacyTreasureRuntimeBridge.ts`
这说明 Runtime Item / Treasure 相关的 AI 意图、奖励生成和库存生成,也已经从前端目录中抽离。
本轮还继续整块收口了 Build / Inventory / Forge / Equipment 规则桥接:
- 新增 `server-node/src/modules/runtime/runtimeEquipmentModule.ts`
- 后端本地承接 `getEquipmentSlotFromItem`
- 后端本地承接 `getEquipmentSlotLabel`
- 后端本地承接 `getEquipmentBonuses`
- 后端本地承接 `applyEquipmentLoadoutToState`
- 新增 `server-node/src/modules/runtime/runtimeInventoryEffectsModule.ts`
- 后端本地承接 `isInventoryItemUsable`
- 后端本地承接 `resolveInventoryItemUseEffect`
- 后端本地承接 `buildInventoryUseResultText`
- 新增 `server-node/src/modules/runtime/runtimeForgeModule.ts`
- 后端本地承接 `getForgeRecipeViews`
- 后端本地承接 `executeForgeRecipe`
- 后端本地承接 `executeDismantleItem`
- 后端本地承接 `executeReforgeItem`
- 后端本地承接 `getReforgeCostView`
- 后端本地承接 `buildForgeSuccessText`
- 新增 `server-node/src/modules/runtime/runtimeBuildModule.ts`
- 后端本地承接 `appendBuildBuffs`
- 后端本地承接 `getPlayerBuildDamageBreakdown`
- 后端本地承接 `resolvePlayerOutgoingDamageResult`
对应桥接层:
- `server-node/src/bridges/legacyBuildRuntimeBridge.ts`
- `server-node/src/bridges/legacyInventoryRuntimeBridge.ts`
这意味着 Build / Inventory / Forge / Equipment 相关的后端主链结算,已经不再依赖前端 `src/data/buildDamage.ts``src/data/equipmentEffects.ts``src/data/forgeSystem.ts``src/data/inventoryEffects.ts`
本轮又补了一段任务 1 的 AI 编排收口:
- 新增 `server-node/src/modules/ai/chatPromptBuilders.ts`
- 后端本地承接 character chat reply / suggestions / summary prompt 组装
- 后端本地承接 npc chat / recruit prompt 组装
- 调整:
- `server-node/src/modules/ai/chatOrchestrator.ts`
- `server-node/src/modules/ai/orchestrator.test.ts`
这意味着 chat orchestration 已不再依赖前端 `src/services/characterChatPrompt.ts``src/services/prompt.ts`
本轮继续把 story orchestration 主链也收回到了后端本地:
- 新增 `server-node/src/modules/ai/storyPromptBuilders.ts`
- 后端本地承接 `SYSTEM_PROMPT`
- 后端本地承接 `buildUserPrompt`
- 重写 `server-node/src/modules/ai/storyOrchestrator.ts`
- 正式生产链不再依赖前端 `src/services/prompt.ts`
- 正式生产链不再依赖前端 `src/data/stateFunctions.ts`
- 正式生产链不再依赖前端 `src/data/scenePresets.ts`
- 正式生产链不再依赖前端 `src/data/hostileNpcs.ts`
- 调整:
- `server-node/src/modules/ai/orchestrator.test.ts`
到这里,`server-node` 正式生产代码路径里Story / Chat / Quest / Runtime Item / Treasure / Build / Inventory / Forge / NPC Task6 主链都已经从前端 `src/**` 目录脱钩。
本轮也继续推进了任务 10 的主流程瘦身:
- 新增 `src/hooks/story/storyRequestCoordinator.ts`
- 抽离运行时 option source 解析
- 抽离服务端 option catalog 回退策略
- 抽离 initial / next story 请求参数协调
- 新增 `src/hooks/story/storyRequestCoordinator.test.ts`
- 覆盖服务端 option catalog 切换
- 覆盖显式 option catalog 短路
- 覆盖服务端目录加载失败时回退本地可用项
- 调整:
- `src/hooks/useStoryGeneration.ts`
这说明 `useStoryGeneration.ts` 虽然仍重,但“故事请求协调”已经不再和主流程 UI 状态、NPC/战斗/宝藏后续处理混在同一个大段里。
本轮又补了一段任务 10 的纯展示逻辑拆分:
- 新增 `src/hooks/story/storyPresentation.ts`
- 抽离 story options 去重与补齐
- 抽离对白 turn 解析
- 抽离 dialogue story moment 组装
- 抽离 typewriter delay
- 新增 `src/hooks/story/storyPresentation.test.ts`
- 覆盖对白解析与 dialogue story moment
- 覆盖选项池去重与补齐
- 调整:
- `src/hooks/useStoryGeneration.ts`
这意味着 `useStoryGeneration.ts` 又减少了一批与 React 状态本身无关的纯函数逻辑,任务 10 的主流程壳层拆分继续向前推进。
本轮还补上了任务 1 的最后一条后端反向依赖:
- 删除 `server-node/src/bridges/legacyCustomWorldAiBridge.ts`
- 重写 `server-node/src/modules/ai/customWorldOrchestrator.ts`
- 后端本地承接 custom world generation 的 deterministic 生成流程
- 后端本地承接 generation progress 汇报
这意味着 `server-node/src/**` 的正式生产代码路径已经不再反向依赖前端 `src/**` 目录。
---
## 4. 仍需继续收口的重点
### 4.1 任务 1 的剩余问题
当前从仓库内直接扫描看,`server-node/src/**` 的正式生产代码路径已经不再存在对前端 `src/**` 的反向依赖。
其中 Story / Chat / Quest / Runtime Item / Treasure / Build / Inventory / Forge / Equipment / NPC Task6 / Custom World generation 相关正式生产链都已经从这个列表中退出。
同时,`server-node/src/modules/ai/orchestrator.test.ts` 已不再直接依赖前端 `src/services/prompt.ts``src/data/stateFunctions.ts`
这说明任务 1 在“后端正式生产运行时不反向依赖前端目录”这一层面已经完成。
#### 4.1.1 当前残留依赖的真实形态
从当前状态看,任务 1 后续不再是“补洞”,而是“优化”:
- 继续提高 custom world generation 的质量与保真度
- 继续把真正通用的 prompt / JSON repair / batch helper 整理进 `packages/shared``server-node/src/modules/ai/**`
- 维持后端不再回流引用前端目录的约束
#### 4.1.2 更适合的继续收口顺序
结合当前状态,任务 1 后续更适合做的是能力优化:
1. 继续增强 custom world generation 的语义保真度与校验强度。
2. 继续把 prompt builder、JSON repair、批处理工具整理到 `packages/shared``server-node/src/modules/ai/**`
3. 持续维持“后端正式生产代码不反向依赖前端目录”的约束,避免后续重新开洞。
### 4.2 任务 7 的剩余问题
前端虽然已经大量改成 SDK 消费层,但 `src/persistence/runtimeSnapshot.ts` 里仍保留较重的存档归一化与迁移修复逻辑。
这部分后续仍建议继续向后端迁移,避免前后端双边解释快照。
#### 4.2.1 `runtimeSnapshot.ts` 当前仍承担的职责
从文件本身看,`src/persistence/runtimeSnapshot.ts` 仍不是一个单纯的“读取后端结果并转成 UI 状态”的轻薄消费层。
它当前仍直接负责:
- 存档迁移 manifest 应用
- roster 归一化
- player currency 默认值补齐
- equipment loadout 回填与属性重算
- NPC persistent state 归一化
- quest log 归一化
- runtime stats 归一化
- scene encounter preview 修复
- story engine memory 缺省补齐
这说明任务 7 的剩余问题,不只是“前端还有一点 normalize 代码”,而是:
- 前端仍在解释正式存档的结构语义
- 前端仍在决定若干正式运行时字段的缺省和修复策略
- 后端与前端之间仍存在“双边都能定义快照有效形态”的空间
#### 4.2.2 下一步更合适的迁移方向
结合本轮已经补上的“继续游戏优先以后端 runtime story state 为准”这段恢复链路,任务 7 后续更适合继续向这个方向推进:
1.`runtimeSnapshot.ts` 中的迁移、归一化、缺省补齐继续下沉到后端持久化层或专门的 runtime snapshot service。
2. 让前端拿到的远端快照尽量已经是“可直接消费的正式形态”,而不是“仍需前端补算的半成品”。
3. 把前端保留的本地 hydrate 逻辑收缩到纯 UI 恢复字段,例如当前页签、面板开合、局部显示态。
只有这样,任务 7 才算真正回到“前端只做消费层,后端才是正式状态解释者”的目标。
### 4.3 任务 10 的剩余问题
当前最大的未完成项仍然是:
- `src/hooks/useStoryGeneration.ts`
它仍承担了大量:
- 正式运行时故事编排
- 本地 fallback 组织
- NPC / 宝藏 / 战斗后续协调
- 主流程状态推进
现阶段虽然已经有:
- `src/hooks/useGameShellRuntime.ts`
- `src/components/game-shell/useGameShellRuntimeViewModel.ts`
- `src/hooks/story/runtimeStoryCoordinator.ts`
- `src/hooks/story/storyRequestCoordinator.ts`
但主流程还没有彻底完成 action/view model 化,任务 10 仍应视为“进行中”。
#### 4.3.1 `useStoryGeneration.ts` 当前仍然为什么过重
从仓库现状看,`src/hooks/useStoryGeneration.ts` 目前仍有约 1700 行,且其过重问题已经不是单纯“文件太长”,而是它还保留着大量正式业务协调职责。
当前这个 hook 里仍集中着:
- `buildStoryContextFromState` 这一整块故事上下文拼装
- AI 请求前的 option catalog / fallback 组织
- NPC / 宝藏 / 战斗 / inventory / goal / session 多条子链的集中协调
- 本地 fallback story 生成
- 一部分运行时规则与 narrative context 的最终拼装入口
这意味着即使已经拆出了:
- `runtimeStoryCoordinator`
- `storyRequestCoordinator`
- `choiceActions`
- `npcEncounterActions`
- `sessionActions`
`useStoryGeneration.ts` 仍然不是“单纯的 UI 壳层 hook”而更像前端侧的运行时总协调器。
#### 4.3.2 任务 10 后续更值得优先拆的部分
按当前文件结构看,后续最值得优先继续抽离的不是零散按钮逻辑,而是下面三类真正还握在主 hook 里的核心块:
1. `buildStoryContextFromState` 这一整块 story-engine 叙事上下文装配。
2. `buildFallbackStoryForState` / `getAvailableOptionsForState` 这类“正式规则兜底与选项来源判断”。
3. NPC / Treasure / Character Chat / Session 这些子流之间的最终总装协调。
如果只是继续把零散函数拆到 `src/hooks/story/**`,但上述三块还留在主 hook 里,那么任务 10 仍然不会真正完成。
### 4.4 建议的下一轮补齐顺序
结合任务 1、任务 7、任务 10 当前的剩余形态,后续更合适的补齐顺序建议是:
1. 先继续收任务 7 的 runtime snapshot 解释权,把正式快照的迁移、修复、归一化口径继续回收到后端。
2. 再继续收任务 10`useStoryGeneration.ts` 压回主流程协调壳层,而不是继续让它承担正式运行时总装职责。
这样排的原因是:
- 任务 1 已经完成后,新的主阻塞就变成了任务 7 和任务 10。
- 如果任务 7 不继续收,前端仍会在恢复链路里保留正式状态解释权,任务 10 也很难真正变薄。
- 等到 runtime state 与 snapshot 口径都更稳定后,再继续瘦 `useStoryGeneration.ts`,返工会更少。
---
## 5. 本轮验证
已通过:
- `npm run server-node:test`
- `npx vitest run src/hooks/story/storyRequestCoordinator.test.ts src/hooks/story/runtimeStoryCoordinator.test.ts`
- `npm run typecheck`
- `npm run check:encoding`
---
## 6. 结论
从仓库可验证结果看,任务 2、3、5、6、9 已经达到“可认为完成”的状态;任务 0、4、8 基本完成;任务 1、7、10 仍有明显后续收口空间。
当前最主要的未完成中心已经不再是后端基建,而是:
**把前端主流程和存档恢复彻底收成“以后端 runtime state 和 view model 为唯一真相源”。**