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

21 KiB
Raw Blame History

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.tsdb.tsrepositories/**、迁移脚本、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、鉴权、持久化瘦身 部分完成 apiClientauthServicestorageService 已统一,但前端仍保留一部分存档归一化和主流程协调职责。
任务 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.tssrc/data/attributeResolver.tssrc/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.tssrc/services/questDirector.tssrc/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.tssrc/data/equipmentEffects.tssrc/data/forgeSystem.tssrc/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.tssrc/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.tssrc/data/stateFunctions.ts

这说明任务 1 在“后端正式生产运行时不反向依赖前端目录”这一层面已经完成。

4.1.1 当前残留依赖的真实形态

从当前状态看,任务 1 后续不再是“补洞”,而是“优化”:

  • 继续提高 custom world generation 的质量与保真度
  • 继续把真正通用的 prompt / JSON repair / batch helper 整理进 packages/sharedserver-node/src/modules/ai/**
  • 维持后端不再回流引用前端目录的约束

4.1.2 更适合的继续收口顺序

结合当前状态,任务 1 后续更适合做的是能力优化:

  1. 继续增强 custom world generation 的语义保真度与校验强度。
  2. 继续把 prompt builder、JSON repair、批处理工具整理到 packages/sharedserver-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. 再继续收任务 10useStoryGeneration.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 为唯一真相源”。