# M4 module-npc 与 module-combat 联合编排基线(2026-04-21) 更新时间:`2026-04-22` ## 0. 文档目标 本文件只冻结一件事: **在不污染 `module-npc` 纯领域边界的前提下,把 `npc_fight / npc_spar` 从“只返回 `BattlePending` 语义”推进到“可在 `spacetime-module` 聚合层同步创建 `battle_state`”的最小联合编排口径。** 这不是完整 `resolve_story_action` 设计,也不是完整战斗奖励编译、经验预算和剧情续写迁移。 --- ## 1. 本轮落地范围 本轮只落实下面 4 件事: 1. 明确 `module-npc` 继续只负责 NPC 交互语义,不直接依赖 `module-combat`。 2. 在 `spacetime-module` 聚合层新增 `resolve_npc_battle_interaction_and_return` procedure。 3. 让该 procedure 在同一事务内完成: - `resolve_npc_interaction` - `battle_state` 初始化写入 4. 返回统一结果,供后续 `spacetime-client` / Axum facade 直接消费。 --- ## 2. 为什么不把 battle 初始化塞进 module-npc 原因很直接: 1. `module-npc` 当前职责是 `npc_state / relation_state / stance_profile / interaction contract`。 2. `battle_state` 属于 `module-combat` 真相,不应倒灌进 NPC 领域 crate。 3. 如果把玩家 HP / MP、战斗生命、故事会话 ID 这些字段直接塞进 `ResolveNpcInteractionInput`,会把 `module-npc` 再次膨胀成跨子域入口。 因此本轮明确冻结为: 1. `module-npc` - 继续只返回 `BattlePending + battle_mode` 2. `spacetime-module` - 负责把 NPC 交互结果编排成真正的 `battle_state` --- ## 3. 新增 procedure 口径 ### 3.1 名称 新增: 1. `resolve_npc_battle_interaction_and_return` ### 3.2 输入 首版输入冻结为: 1. `npc_interaction` - 原样复用 `ResolveNpcInteractionInput` - 当前只允许 `npc_fight / npc_spar` 2. `story_session_id` 3. `actor_user_id` 4. `battle_state_id` - 允许为空 - 为空时按 `updated_at_micros` 自动派生 5. `player_hp` 6. `player_max_hp` 7. `player_mana` 8. `player_max_mana` 9. `target_hp` 10. `target_max_hp` 11. `experience_reward` - 由上游作为已编译好的确定奖励透传 - 当前允许为 `0` 12. `reward_items` - 类型固定为 `Vec` - 只承接已经编译好的战利品快照,不在 procedure 内现场生成 ### 3.3 输出 当前返回: 1. `interaction` - `module-npc::NpcInteractionResult` 2. `battle_state` - `module-combat::BattleStateSnapshot` 也就是说,这个 procedure 明确是一个**聚合返回口径**,不是新的底层领域真相。 --- ## 4. 当前事务流程 单次调用按下面顺序执行: 1. 校验 `story_session_id / actor_user_id` 2. 校验 `interaction_function_id` 必须是: - `npc_fight` - `npc_spar` 3. 先执行 `resolve_npc_interaction_record` - 写入最新 `npc_state` - 拿到 `NpcInteractionResult` 4. 从 `NpcInteractionResult.battle_mode` 映射出 `BattleMode` 5. 组装 `BattleStateInput` - 透传 `experience_reward` - 透传 `reward_items` 6. 复用 `module-combat` 的 `validate_battle_state_input` 7. 插入 `battle_state` 8. 返回: - `interaction` - `battle_state` --- ## 5. 当前刻意未做 本轮明确不做下面这些扩张: 1. 不在这个 procedure 里直接发经验 2. 不在这个 procedure 里直接记 `chapter_progression` 3. 不在这个 procedure 里直接写 `story_event` 4. 不在这个 procedure 里现场计算掉落或经验预算 5. 不在这个 procedure 里直接执行 `inventory_slot` 发物 5. 不在这个 procedure 里直接接 `resolve_combat_action` 6. 不在这个 procedure 里推导敌方等级、强度、掉落预算 也就是说,这一层当前只解决: **NPC 宣告开战后,如何立刻把 battle 真相表连同已编译奖励真相一起建立起来。** --- ## 6. 与现有文档的关系 本文件是对下面两份基线文档的补充,而不是替代: 1. `M4_MODULE_NPC_SPACETIMEDB_BASELINE_2026-04-21.md` - 继续定义 NPC 领域 contract 2. `M4_MODULE_COMBAT_SPACETIMEDB_BASELINE_2026-04-21.md` - 继续定义 battle_state 与单行为战斗推进规则 新增编排只发生在 `spacetime-module` 聚合层。 --- ## 7. 下一步建议 在这条最小联合编排稳定后,后续按下面顺序推进最稳: 1. 把 Node 侧 `monster_drop` / hostile reward 编译逻辑收口到 Rust 聚合层。 2. 再把章节自动定级、敌对经验预算和 `chapter_progression` 所需章节上下文收口进 battle 初始化编译器。 3. 最后把这条链收口进完整 `resolve_story_action`。