4.2 假选择的检测
两个不同选项在同一状态下推进出的状态逐字段相等,就是一对假选择。本节用完整 BFS 精确枚举 9895423 个可达 (节点,状态) 对,检出 3 对静态假与 10 对状态级假;其中 d_fg_3 的一对在全部 1036900 个可用状态下都相等,静态判据会漏掉它。再用三个合成规格证明检测器会开火。
category
两个不同选项在同一状态下推进出的状态逐字段相等,就是一对假选择。本节用完整 BFS 精确枚举 9895423 个可达 (节点,状态) 对,检出 3 对静态假与 10 对状态级假;其中 d_fg_3 的一对在全部 1036900 个可用状态下都相等,静态判据会漏掉它。再用三个合成规格证明检测器会开火。
后果可见性量的是:一个选项写下的状态差量,要隔几步才被下游的条件读到。本节把 115 个选项逐个算成整数距离——34 个立即可见、37 个延迟、28 个写进状态却永不被读到,另有 16 个根本没有差量;平均 2.42 步、最远 12 步。全程结构 BFS,不出现浮点,也不预测玩家感受。
回归的精确含义是「基线可达、改动后不可达」。本节用 BFS 精确口径枚举基线可达的 5 个结局,掐断真相的唯一入边后静态死条件分析报出回归;再把灯守的阈值门从 0 扫到 101,用 Y*=100 定位它由可达变不可达的临界点,软告警恒 exit 0。
20000 条路径逐边计数,把「分支被走得均不均匀」变成整数:分支覆盖率 1000‰、进入次数中位 4173、偏斜度 gini 373‰、头部集中度 29‰。再用偏置强度 b 从 0 扫到 1000 看相变——覆盖先掉、偏斜先抬、稀有结局先消失,软告警恒 exit 0。
结局熵有四个数,混在一起就错。本节把上界 2321 毫比特、单路径 0 毫比特、路径采样 1714 毫比特、状态枚举 1888 毫比特分开报,并讲清「上界不是实测值」——一条路径只到一个结局,它的熵恒为 0。全部整数、毫比特取整,seed=20261016 可复现。
覆盖率给一个总数,缺口给一张名单。本节对随机采样 N=100 条路径逐边计数,定位那条从未被走过的边——门条件为 bell_rung 的真相结局入口,源节点访问了 100 次却没选中它;再用采样规模与种子的参数扰动给出软告警口径,低于 850‰ 只记 WARN、恒 exit 0。
分支覆盖率是一个整数千分比:走过的对话边 × 1000 整除全部对话边。本节先声明两层分母口径(去重边 56 与选项 115),再把单条确定性路径、采样 N 条、BFS 穷举三个来源放进同一张表,量出边、节点、场景三层覆盖,并给出 446‰ 与 1000‰ 的口径来源。
一张 48 节点、115 个选项的故事图,一条确定性路径只走 25 条边(446‰),远低于 850‰ 的目标。本节把随机、贪心、穷举三种采样策略放进同一路径预算对照,量出各自覆盖多少条对话边、到达几个结局,并解释为什么穷举是覆盖率的基准而不是一种采样。
本卷交付四类东西:真源与内核、度量工具链(S/P/W/B 共九件脚本)、可复算产物、六项代理指标口径。给出接手五步与「本套不做」清单——真人玩家测试、真实配音成本等需真实业务环境,命令行不可复现,逐处标 X,并列出后续可做的三个方向(多规格回归 / 度量反演 / 真人数据接入)。
让穷举、执行、度量三种消费跑同一份规格并断言彼此不矛盾:BFS 穷举的可达集(9895423 个状态)包含全部采样路径,同一条选择序列在 Python / TS / 浏览器三处推进出逐位相同的状态摘要 4162796975。含 Playwright 无头真玩。
三卷共用一份真源。本节把「装起来能不能用」拆成四组共 17 条断言:真源字段齐、卷一结构过、卷二引擎三处消费一致(跨语言锚点摘要 4162796975 逐位相等)、卷三六项代理指标量得出。每条都给出本机实跑值与可重跑命令,任一 FAIL 即非零退出。
命令行量不出玩家情绪,本卷七条指标全是 proxy。本节把「不能声称什么」写成可执行的 lint:八类禁声称(更感人、更好玩、玩家满意度、更优秀、玩家实际、读起来、绝对达标、提升 N 倍)、五条正面清单,以及 12 条候选结论的逐条判定与改写。指标能声称的只有相对变化与结构量。
同一张指标表里的数不能随便比:量纲不同的指标不能相加,七条指标合成不出一个总分;同一份规格加删一条选项,覆盖率就从 446 漂到 438 / 454;熵对样本量敏感,n=50 缺最稀有结局反而算出更高的熵。本节用三个可复现实验把可比性的边界钉死。
全卷七条代理指标第一次被收成一张总表:分支覆盖率、结局分布熵、张力曲线 MAE、好感度曲线 MAE、一致性残差、节奏密度偏差、整数不变量残差,每条给全定义、量纲、真源字段、实测值与首见小节。脚本从规格重算六条并与各章产物逐条对账,落 out/nm_15_1_metric_catalog.json。
指标变了不等于指标变坏了。本节把 14.2 的增量按三级分类:OK(没变)、DRIFT(变了但未越声明阈值)、CROSS(越过阈值才判得动方向)。再以 B 层把两处规格参数连续扫一遍,扫出相变点,全程只发软告警、始终 exit 0——扰动不该让构建硬失败。
上一节算出了影响面,这一节把「改动前 / 改动后」做成一张回归对照表:分支覆盖率、结局分布熵、张力 MAE、一致性残差各一列,增量各一行,并对着写在 metrics 里的声明阈值逐格判越阈。五处改动全是「变了但未越阈」,表同时落成 JSON 与 CSV,供后续每次演化重跑比对。
改一处规格,哪些路径与指标会变?本节用集合差回答:拿卷二 4.3 的 500 条采样序列当基线,在改动后的规格上重放,逐项量被阻断路径数、终局状态集差、结局集差与边/节点/场景/节拍集差。五处小改动各自给出实测数字,并说明为什么影响面不能靠重跑穷举来算。
解集有多大是一回事,稳不稳是另一回事。本节用两条轴量反推的稳健性:把目标曲线的 b10 从 5 挪到 4,在可枚举的预算上精确求新旧解集的交集与 Jaccard 千分;再把 MAE 阈值从 0 毫扫到 2000 毫看解集规模的相变。结论是解集近稳但规模巨大,曲线达标推不出唯一标注。
给定一条目标张力曲线,反过来能求出哪些节拍标注?本节把「MAE 不超阈值」化成 sum 绝对值不超过 16 的整数约束,用逐位 DP 精确计数:达标解集有 6072047140 个,占全空间 5 的 16 次方的 39.8 千分。随机搜索 200000 次的经验命中率与精确比例吻合,而收紧到 62 毫时随机搜索一次都命不中。
曲线偏离目标时,怎么把它落到具体的节拍下标与场景?本节用残差向量做定位,造三个漂移场景:在路径上的单点、两个异常点,以及离路径的隐藏点。实测发现路径口径看不见没经过的节拍——b10 从 5 降到 4 时路径 MAE 仍为 0 毫,全曲线 MAE 才抬到 62 毫。可观测性决定了可识别性。