Files
jev-match-game/docs/design/adaptive-insertion.md
T

100 lines
5.1 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.
# 设计:自适应支线插入引擎
> 状态:设计定稿,待实现。关联:docs/story-framework.md §6(路由规则)、
> docs/script/adaptive-branches.md(支线剧本与三张总表)、ADR-0003(Jev 置信度自适应)。
> 读者:实现此功能的工程 agent。
## 1. 目标
每章结束后用 Jev 对用户行为轨迹打 7 维 score;对置信度不足的维度,在下一章的
固定挂点动态插入一段支线剧情,补充该维度的行为采样。插入必须:
- **玩家无感**:支线作为剧情独立成立,出口与主线严丝合缝;
- **测量有效**:支线选择点与主线选择点同等规格地落入事件流;
- **成本可控**:每章至多插入 1 条;Jev 故障时不插入(降级,不阻断主线)。
## 2. 触发时序
```
chapterEnd(第 N 章结束)
→ 汇总本 session 全部事件为 state
→ 一次 Jev 调用:7 个维度 score(并行,输出免费)
→ 提取每维 confidence
→ 插入决策(见 §3)→ 产出第 N+1 章的"插入计划"
→ 第 N+1 章开始,引擎带着插入计划运行
```
打分与画像报告页共用同一套 state 构建逻辑(`ReportPage.buildState` 提取为
`src/engine/scoring.ts`,报告页和插入决策都调它)。章末打分失败(Jev 故障/无 key)
→ 本章不插入任何支线,主线照常(console.warn 记录)。
## 3. 插入决策(对照支线册表 2 实现为代码)
输入:7 维 confidence、本周目已触发支线记录、目标章可用挂点。
1. 过滤:confidence < 0.6 的维度为候选;`risk` / `mate_preference` 无支线定义,跳过;
2. 排序:按「维度权重 × 置信度缺口 × 已测稀缺度」取首——
维度权重:attachment > values > conflict_style > emotional_stability > culture
(见支线册 §0.5);缺口 = 0.6 − confidence;稀缺度 = 该维度已被采样的选择点数越少越优先;
3. 选皮:该维度的支线 A(挂点 1)未用过→A,用过→B(挂点 2);A、B 都用尽仍低置信
→ 记录 `evidence_insufficient` 标记,不插入(交 Act 2);
4. 每章至多 1 条;挂点被占则顺延到该章另一挂点,两挂点都被占则不插入;
5. 时长红线:插入后该章预估时长 ≤ 45 分钟(支线 5-8 分钟 + 主线 25-35 分钟)。
## 4. 数据模型
支线包:`content/branches/{branchId}.json`(如 `b-att-a.json`),结构:
```jsonc
{
"id": "b-att-a",
"dimension": "attachment",
"anchor": { "chapter": "chapter2", "afterNode": "c2-d4f" }, // 挂点 1:§2-4 后
"startNodeId": "cb-att-a-01",
"nodes": [ /* 与章节 JSON 同 schema 的 StoryNode 数组 */ ],
// 支线选择点 pointId 用 CB-XXX-Y-ZZ 规则(支线册表 1),维度标签照支线册
}
```
引擎改动:
- `StoryEngine` 增加 `insertions: BranchPack[]`(本局生效的插入计划);
- 节点索引 `nodeIndex` 在装载插入计划时合并支线节点;
- **挂点重定向**:到达 `anchor.afterNode` 的 `next` 时,若该挂点有插入,
跳支线 `startNodeId`;支线最后一个节点的 `next` 在 JSON 里写为
特殊值 `"$resume"`,引擎解析为"回到挂点原 next";
- 支线节点参与现有全部机制:条件渲染(flags)、进度持久化、追问流。
## 5. 事件与测量
- 支线选择点事件正常 append,`pointId`(如 `CB-VAL-A-01`)即变量取值来源;
- 支线 flags(`cb_*`)进现有 flags 系统(`src/engine/flags.ts` 补映射,
消费方见支线册表 3——注意"回写只许面向未来场景"规则);
- 插入决策本身落一个 `kind: 'branch_inserted'` 事件(branchId、维度、触发置信度),
供画像层做路径标记(温简 weak 线的公平性问题同款思路)。
## 6. 状态与持久化
- `ProgressSnapshot` 增加 `activeBranchId?: string` 与 `insertions` 摘要,
刷新恢复时若正处于支线中,恢复到支线内断点;
- `replay()` 清空插入计划(新周目重新打分重新决策);
- 同一 session 已触发的支线不再重复触发(A→B 换皮由 §3.3 保证)。
## 7. 实施拆分(建议一棒完成)
1. `src/engine/scoring.ts`:7 维打分 + 置信度提取(从 ReportPage 抽出复用);
2. `src/engine/branching.ts`:插入决策纯函数(§3 全部规则,可单测);
3. 引擎装载/挂点重定向/`$resume` 解析/进度快照扩展;
4. `content/branches/`:把支线册 10 条变体 JSON 化(文案照
`docs/script/adaptive-branches.md`,pointId/变量照表 3);
5. `scripts/verify.ts` 新增断言:决策矩阵表驱动测试(7 种触发情形照表 2)、
挂点重定向与 `$resume` 汇合、支线事件落库、重复触发抑制、
Jev 故障不插入、replay 清空计划。
## 8. 未决问题(实现时可自行裁决,报备即可)
- 挂点锚点的精确 nodeId 以 JSON 现状为准(`afterNode` 需在实现时对照
chapter2/3.json 落定,支线册的 §2-4 后/§3-2 前是剧本坐标);
- 支线中的 narration 讲述点:本期支线册均为按钮式选择点,无 V 类点,
若后续支线加讲述点,追问流直接复用现有机制,无新增设计。