Files

116 lines
7.6 KiB
Markdown
Raw Permalink 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.
# 设计:自适应支线插入引擎
> 状态:已实现(2026-10-03),`pnpm verify` 包含主线与自适应支线验证。关联: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. 选皮:变体与挂点**按章绑定**(第 2 章=变体 A/挂点 1,第 3 章=变体 B/挂点 2),
不跨章搬运(与支线册 §0「变体皮肤规则」一致——变体场景与该章主线进度耦合)。
同维度重复低置信:第 2 章插 A、第 3 章插 B(强制换皮);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 类点,
若后续支线加讲述点,追问流直接复用现有机制,无新增设计。
## 9. 实现裁决与验证
- 挂点按剧情坐标落定:A 在 `chapter2/c2-branch-anchor`(C2-03 三条后续汇合后、观星台前),B 在 `chapter3/c3-d1b`(台基下、登台前)。原示例 `c2-d4f` 位于路线裁断前,不作挂点。
- A/B 绑定章节,不跨挂点搬运。第三章首次补测某维度也使用 B;当前章槽已占用则不叠加,下一章重新打分决定。
- 优先级采用权重 5/4/3/2/1 × `(0.6-confidence)` × `1/(1+独立测点数)`;choice/narration 为有效测点,追问与路由事件不重复计数。主线时长默认保守取 35 分钟,支线按上限 8 分钟估算。
- 文化兜底检查刚完成章的主线解谜是否已有事件,不检查目标章尚未发生的解谜,否则文化支线会永远无法触发。
- 支线册少量时序措辞做了衔接修正:官牙发生在安门内登台前;漏刻不预先引用尚未复原的星图;分药后的 D 路径同样遵循 `wenjian_health=weak` 留营规则。测量维度和变量枚举不变。
- `advance()` 返回 Promise,调用方须 await;章末防重复提交,HTTP 请求 15 秒超时。无 key 的自动 Mock 不参与插入决策,显式注入 Mock 可用于测试。
- 快照保存支线 ID 摘要与活动支线;恢复先合并节点索引,再定位断点。路由事件先于快照落盘,恢复时可从本 session 事件补回计划。重玩清除索引与计划,不改旧事件。
- 共 17 个支线选择点(两问解谜各计一个测点)。计时点记录耗时和超时,解谜记录两问答案、提示档数、是否解出,选择事件保存实际条件渲染后的文案。风声音效、缝宽演出和阅读/改选遥测未实现;当前 UI 点选即提交,不伪造这些信号。
- `pnpm exec tsx scripts/build-adaptive-branches.ts` 从定稿支线册重生成十个静态包;运行时不解析 Markdown。
- `scripts/verify-adaptive.ts` 覆盖决策矩阵、全部选项与超时/跳过、温简双状态、逐节点恢复、五维三章 A→B、事件/flags、重复点击与刷新、无 key/无效评分/网络故障、replay 会话隔离,由 `scripts/verify.ts` 统一执行。