Files
gplan-2/design/dev/architecture/adr-0007-rng-single-stream.md
T

7.4 KiB
Raw Blame History

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 = 全局顺序号。三个后果(均已向用户两轮呈报,此处落档):

  1. 号位失去事件语义——第 N 号只回答"全局第 N 次取数",不再回答"第 N 次什么"。玩家换条路(战斗次数变化)后,同一 N 号对应的事件种类漂移。
  2. 路线依赖——任何一处随机事件数量/顺序变化平移其后全部骰子;对拍工具"行数恒等纯次序位移"性质失效;"这局 Boss 为什么没中"类单点归因需全序重放。
  3. 连带改动面——七消费点迁移(上表 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 基线作废,重测归曲线调参批(测量对账条款既有口径)。