7.4 KiB
ADR-0007: 全游戏随机流统一评估(RNG Single Stream Evaluation)
Status
已裁决:方案丙(并流 + 全事件日志)——2026-09-27 用户裁决,随批落地。推荐案甲未被采纳,评估书正文保留原样作决策记录;丙的实施 = 统一随机流批(rng_service.gd 重写 + 七消费点迁移 + 单盐黄金向量重登记 + 事件日志会话制),验证与工单清单见文末「落地记录」。
背景:2026-09-27 用户在关卡节点图生成拍板点②两轮复裁终选「随机数统一用一个流」(全面执行),并拍板执行路径 = 先出本评估书再动手、节点图特性实施排队其后。本评估书按用户要求如实给出:现行机制事实、统一流的真实改动面、三个备选与推荐。裁决本 ADR 后按裁决执行。
Date
2026-09-27
Context
用户动因(如实记录)
用户质疑链全程:①问「增流是什么、文档没说明」→ ②质疑「借流复现口径变含糊」论断:「如果所有的随机数获取都是有完整记录的,那不是都可以一一复现吗?我觉得你的理论不对」→ ③收到机制澄清(复现=主种子+计数器按位重推导、非日志回放)与两条代价说明后,仍两轮终裁「统一用一个流」。动因解读:用户重视单一随机源的心智简洁,对"七条流"的分栏结构存疑(直觉=繁琐),并认为完整记录即可复现一切。
现行机制事实(全部带代码锚)
| 事实 | 锚点 |
|---|---|
| 唯一主种子:冒险开始恰一次注入,禁中途重播种(全零断言) | game/core/rng_service.gd:80-105 |
| 唯一派生公式族:derive(stream, scope) = mix64(SALT_s XOR (master + scope×GOLDEN)) | game/core/rng_service.gd:61-77 |
| 七条流 = 七个盐值常量(同一公式、同一主种子) | game/core/rng_service.gd:14-24 |
| 零旁路随机:randomize()/自建 RNG 硬性红线 | CLAUDE.md 硬性红线;rng_service.gd:4 |
| 每流独立计数器;快照观测面 counter() | rng_service.gd:36,140-142 |
| 复现 = 按(流,号位)重新推导,非日志回放 | registry rng_service/stream_seed_derivation 条目 |
| 计数器实际持久化:现行存档未写各流计数器(adventure_runner 摘要只落 master_seed) | game/core/adventure_runner.gd:59,83,217 |
| 黄金向量断言(R3 8 常量) | game/smoke/smoke_all.gd:34-36,3121+ |
| MC 逐局独立种子 | game/smoke/adventure_monte_carlo.gd:15,52 |
核心发现:字面目标「全游戏随机数派生自同一个源、可逐位复现、没有多套随机」——现行架构已经满足。七条流不是七个随机源,是同一主种子的七个盐值分栏(分栏只改派生种子,不改源)。真正剩下的唯一改动 = 把七条分栏计数器并为一个全局计数器(物理并流)。
七流消费点清单(并流迁移面)
| 流 | 消费点 | 取号时机 |
|---|---|---|
| board_gen | board_generator.gd:16、battle_orchestrator.gd:141 |
每张棋盘 |
| reward_roll | reward_economy.gd:61 |
每次装板批 |
| encounter | battle_orchestrator.gd:116 |
每次战斗实例化(数量骰) |
| armor_roll | damage_controller.gd:286(流名走配置 db.settlement.armor_roll_stream) |
每次命中掷点 |
| behavior_roll | 战斗结算开轮摇号(SkillLottery;子流 scope = spawn_index×1000000+序) | 每敌每轮 |
| variant_place | battle_orchestrator.gd:198 |
每板变异布置 |
| gp_drop | battle_orchestrator.gd:737 |
每战末掉落掷定 |
Alternatives Considered
方案甲:字面达成·维持分栏(node_map 作第八栏)
承认字面目标已满足(核心发现);节点图抽签按既有增流纪律接入第八栏。零迁移、位置语义(号位=第 N 次某类事件)完整保留、黄金向量与对拍口径不动。
方案乙:物理并流(用户终裁方向,如实评估)
单盐单全局计数器:derive(scope) = mix64(SALT_0 XOR (master + scope×GOLDEN)),scope = 全局顺序号。三个后果(均已向用户两轮呈报,此处落档):
- 号位失去事件语义——第 N 号只回答"全局第 N 次取数",不再回答"第 N 次什么"。玩家换条路(战斗次数变化)后,同一 N 号对应的事件种类漂移。
- 路线依赖——任何一处随机事件数量/顺序变化平移其后全部骰子;对拍工具"行数恒等纯次序位移"性质失效;"这局 Boss 为什么没中"类单点归因需全序重放。
- 连带改动面——七消费点迁移(上表 6 文件);armor_roll 流名配置语义失效(
db.settlement.armor_roll_stream并流后无意义);behavior_roll 子流位(spawn_index×STRIDE)重设计;快照契约登记面变更(7 计数器→1,实际存档未持久化计数器故代码迁移面小);R3 黄金向量 8 常量全量重生成;MC/对拍读数与旧基线断档(全部历史基线作废重测)。
方案丙:并流 + 全事件日志(用户的「完整记录」模型落地)
乙 + 每次取数落盘(流名/号位/用途/返回值),以此恢复单点定位能力。代价 = 乙全部代价 + 每次取数的写盘开销与日志体积;且日志回放与按位重推导并存 = 两套复现机制并存。
Recommendation
推荐甲:用户的核心诉求(单一随机源、完整可复现、无多套随机)现行架构字面满足;乙/丙是为一个已满足的目标支付真实的分析能力与一次性迁移成本。本 ADR 按用户裁决路径交付评估,若用户裁决维持乙,上表「连带改动面」即实施批工单,按乙执行,本特性排队其后——两个方向都已备好,裁决即动。
Consequences
- 裁决甲:节点图生成实施批按第八栏增流推进(改代码+金向量+冒烟断言三件套),本评估书归档为架构记录。
- 裁决乙:先开 rng 架构批(迁移工单如上),全量回归后节点图生成实施批接续;历史 MC 基线全部作废重测归曲线调参批。
- 裁决丙:同乙,另加日志面设计与写盘性能验收。
落地记录(统一随机流批 2026-09-27)
- 代码:rng_service.gd 重写(单盐 SINGLE_SALT=原 board_gen 盐 / 全局计数器 / 用途标签 open_stream(purpose) / derive_at(scope) 单参 / open_scope 与 BEHAVIOR_SUBSTREAM_STRIDE 退役 / 事件日志会话制 user://logs/rng_log_<主种子>.jsonl);消费点七处迁移(board_generator/reward_economy/battle_orchestrator×4/damage_probe/skill_rhythm_probe/smoke_all 向量与计数断言);behavior_roll 子流派生向量退役(逐敌顺序取号替代,单敌轨迹独立复放面随之退役——冒烟 ③ 测试同批退役,同种子全战斗对拍由 ② 承载)。
- 向量:统一流 8 常量重登记(scope 0-3 与旧 board_gen 向量逐位连续——单盐沿用其盐);registry stream_seed_derivation 全量改版。
- 测试:冒烟 557/0 三闸全过(nat20/极性路由/L2 max 三处种子硬编码测试改行为面扫描——并流后随机值面漂移的测试面重锚);四场景探针全绿(ui_input_probe 加「移位扩边」前置——板面种子漂移下前沿不足两格时沿已开区点击移位);MC 20 局逐局独立跑通,事件日志逐冒险落盘实证。
- 行为面基线:并流后全部历史 MC/verifier 基线作废,重测归曲线调参批(测量对账条款既有口径)。