diff --git a/design/research/MC成本调研与规制方案-2026-10-03.md b/design/research/MC成本调研与规制方案-2026-10-03.md new file mode 100644 index 00000000..e87e50e3 --- /dev/null +++ b/design/research/MC成本调研与规制方案-2026-10-03.md @@ -0,0 +1,225 @@ +# MC 成本失控调研与规制方案(2026-10-03) + +> 性质:纯调研会话产物——全程零测试、零 MC、零冒烟、零改码;对既有锚文件仅做只读统计(非模拟)。 +> 数据来源:`design/qa/test-perf-report-2026-10-02.md`(单局耗时实测)、sim-data 三份读数 md(2026-10-03)、三批 loop 计划书(.zcode/plans)、git 提交链、外部统计基准(§附)。 +> 任务书四问:①成本结构 ②重跑审计 ③N 标准 ④规制案文——按序对应 §1–§4,拍板点在 §5。 + +--- + +## 0. 结论速览 + +1. **耗时构成**:MC 是纯同步 CPU 计算(零渲染、零帧等待、零 await),单局耗时 ∝ 战斗轮数(每轮约 100ms 恒定)。perfect 档轮数中位 77 vs normal 13(约 6 倍)——「perfect 占 87% 墙钟」是动作总量问题,不是单步慢。 +2. **一天账本**:2026-10-03 三批共 5 次采集 ≈ 130–145 分钟墙钟,其中**约六成(75–90 分钟)属可避免**:81000 满档跑单一 k 值(超需约 5 倍)、批②缺陷修复后整套重跑 192 局(读数缺陷不伤轨迹,旧数据本可重构续用)。 +3. **N 无成文标准是直接根因**:N=60/400 系 agent 计划书起草惯例(批①计划书自设「≥50 distinct seeds」),无用户裁定背书、无成本约束条款——现有规则只锁「什么时候可以跑」,没锁「跑多少、跑多贵」。 +4. **N 三用途最小充分值**(外部统计公式反推,非自拟):对拍断言=0 新跑(同种子确定性复放);结构回归=N=60(80% 功效检出 ≥25pp 位移);带值判定=N=100–170(95% CI ±9.8/±7.5pp,15pp 判定带半宽);N=400 满档仅里程碑放行级需要。**normal 档便宜可独立满档(8 分钟),贵的是 perfect 档**。 +5. **可加速面实存且零轨迹风险**:①进程级分片并行(种子逐局独立,K 进程 ÷K 墙钟,加一个游标偏移参数约 5 行)②playtest_logger 每行 `flush()`(`playtest_logger.gd:184`)改为批量刷(MC 批不消费 fulllog,纯开销)。两者都不改 RNG 序,可逐位对拍验收。 + +--- + +## 1. 成本结构核证 + +### 1.1 单局耗时(实测,2026-10-02 性能报告 §1 #12) + +| 档 | 实测 | 折算 | +|---|---|---| +| normal | N=50 共 ~60s → **1.21s/局** | 满档 N=400 ≈ 8.1 分钟 | +| perfect | N=50 共 ~423s → **8.47s/局**(7 倍) | 满档 N=400 ≈ 56.5 分钟 | +| 双策略满档 | — | **≈65 分钟**(81000 用户口径 ~80 分钟,并行会话负载差异) | +| N=60 双策略一组 | — | **≈9.7 分钟**(60×1.21 + 60×8.47 ≈ 581s) | + +### 1.2 耗时去向的代码证据 + +- **采集器是薄驱动**:`game/smoke/adventure_monte_carlo.gd:18-114`——SceneTree `_initialize` 一次性同步跑完 n 局,全程无 await、无帧依赖、无渲染等待;种子=`seed0+cursor` 逐局独立(`:15,82`),`_run_cursor` 跨策略全局连续不重置。 +- **驱动链全同步**:`game/smoke/level_autoplay.gd:115-174`(run_adventure)→ `_drive_level:89-105` → `_autoplay_battle:404-450`——每动作 `_decide_act` → `settle_batch` 同步结算;轮 guard 60、动作 guard 400/轮(`:416-425`)。 +- **每动作全量重推理是 CPU 大头**:`game/smoke/auto_player.gd:115-150` `_deduce`——while-changed 不动点,每次迭代重建约束集两次(`:122` cons、`:134` cons2)+ O(C²) 子集对枚举(`:135-137`),每步决策(move/dig/flag 每一手)全量重跑;约束集构建遍历全部已开数字格×8 邻(`:155-178`)。 +- **耗时 ∝ 动作总量的直接证据**(81000 锚 800 局只读统计,本会话):normal 中位 battles=4、rounds=13/局;perfect 中位 battles=13、rounds=**77**/局——轮数比 ~6 倍,单轮成本恒定(1.21/13≈93ms vs 8.47/77≈110ms)。perfect 语义=零盲挖全探索+通关 3 关,动作总量天然大。 +- **I/O 面有一处纯开销**:`game/presentation/playtest_logger.gd:184` `_append` 每行 `_file.store_line` + **`_file.flush()`**——每动作/每结算行/每 step 行全量 JSONL 落盘并即刷(2026-09-12 用户要求的真人合规口径);MC 批的 fulllog **不留盘不消费**(sim-data/README「fulllog 全量日志不留盘」),故逐行 flush 在 MC 语境=纯开销。量级未实测(本会话禁跑),属一次性 A/B 可量化项。logger 系纯观察层(`playtest_logger.gd:5-6`「核心零日志感知」),关刷零轨迹影响。 +- **字段采集不是大头**:RUNSUM 行 ~1KB/局,含 reward_events/序列数组等,相对 1.2–8.5s 的计算量可忽略。 + +### 1.3 可加速面清单 + +| 面 | 做法 | 轨迹影响 | 收益 | 证据 | +|---|---|---|---|---| +| **A. 进程级分片并行** | 种子逐局独立且局间零共享 → K 个 Godot 进程各跑游标区间,stdout 纯 JSONL 拼接合并;现工具无游标偏移参数(`_run_cursor` 恒 0 起),加第 7 参 ~5 行 | 零(种子不变逐位同轨迹) | 满档 65min → K=4 约 17min / K=8 约 9min | `adventure_monte_carlo.gd:15,82` | +| **B. logger flush 开关** | MC 批关逐行 flush(或批量刷) | 零(观察层,零 RNG 消费) | 未量化,一次性 N=50 A/B 可测 | `playtest_logger.gd:184` | +| C. 求解器增量化/缓存 | 约束集增量维护 | **有风险**——决策序必须逐位不变,任何优化须对现行锚逐位对拍验收 | 不明确 | `auto_player.gd:115-150` | +| D. 引擎帧率/时间缩放 | — | — | **不适用**:整链无帧等待,`--fixed-fps`/time_scale 无效 | 全链零 await | + +### 1.4 不可加速面 + +动作总量本身=测量语义(perfect 档定义就是上界全探索);砍体量=改测量口径,非性能问题。 + +### 1.5 顺带发现:锚文件捕获口径不统一 + +- 81000 锚=原样 stdout 捕获(850 行=800 行 `RUNSUM ` 前缀 JSON+50 行头/进度行);n60 四锚=去前缀纯 JSONL(120 行)。 +- `analyze.py:214` 对每行直接 `json.loads`——只吃纯 JSONL 形态,喂 81000 会炸(与 README 既有「完成度%段对现行锚未验证」警示同源)。 +- 进度行含耗时(`adventure_monte_carlo.gd:109-110` 每 20 局打印),n60 锚因滤掉进度行**丢失了耗时账**(批②「耗时无实测」的技术原因)。 + +--- + +## 2. 重跑模式审计(2026-10-03 三批五次采集) + +### 2.1 事件台账 + +| # | 事件 | 触发理由 | N | 谁决定 | 耗时(推算) | 归类 | +|---|---|---|---|---|---|---| +| 1 | 81000 满档锚(迭代 9 出口批 T19/T20,5369c47) | ①taken 字段当日入库(84df55c)旧锚无该字段,k 终值需新锚;②出度重建后结构位移存档(只测不判) | 400/档(满档惯例继承自迭代 10 四代锚) | agent 按惯例起草、批内执行;用户事前未裁 N,**事后质询改判**「k 应等 M-4 数值批顺带」 | ~65–80 分钟 | **规则漏洞导致的滥用**(N 无约束+时机无约束;k 补算 N=60 即稳,结构位移按 80% 功效也只需 ~85–100/档,超配约 5 倍) | +| 2 | 批① T8 off+on(a6a2bf8) | 同调机制轴新增改轨迹 → off 对拍锚换代(T7 出池必改奖励序列,T6 检查点用户追认)+on 分层读数 | 60/档·模式(计划书提案「≥50 distinct seeds」自设下限,U0 批计划书默许) | agent 提案、计划书批准 | ~19 分钟 | **合理取证**(机制加入必须新锚,对拍硬断言正当) | +| 3 | 批① T10 off 复跑(同上,输出未留盘) | 出口重闸:off 锚同种子逐位复现=机制关着零扰动终检 | 60 | 计划书重闸条款 | ~9.7 分钟 | **合理取证**(但 N 超配:逐位断言检出力与 N 无关——机制漏开时 RNG 流整体位移、每条种子必漂,N≤20 足矣,~7 分钟可省) | +| 4 | 批② T5 首轮 off+on(d79afd2 主体) | 计划书 T5 授权:off 对拍 off_n60 逐位 + on 新锚一次 | 60/档·策略 | 计划书提案、U0 批准 | ~19 分钟 | **合理取证** | +| 5 | 批② T5 缺陷修复后双锚重跑 | pool_stock 读数路径缺陷(`_settle` 先清账本、run_adventure 直读=满库假象,43/120 行自检暴露)→ 修复后按「双锚重跑」现场决策执行;中途被停(on 侧 72 行) | 60×2 | **agent 现场自决**(计划书无「修复后重跑」预授权) | ~15–20 分钟(192 局) | **规则漏洞导致的滥用**(三缺口叠加,见 §2.2) | + +### 2.2 批②重跑的三个规则缺口(读数 md 自认「流程浪费」,sim-data/读数_m4iter11b §口径注记 3) + +1. **无采集前 pilot**:缺陷由 43/120 行自检暴露——若先跑 N=5 pilot 校验字段,缺陷在 10 局内暴露,240 局不会白跑。 +2. **无「读数缺陷 ≠ 轨迹失效」判读规则**:修复仅动摘要组装,零 gameplay/RNG 触碰(读数 md §口径注记 2 静态核证)+ off 对批①锚逐位 PASS 佐证——已采数据本就有效,pool_stock 从 `reward_events` 事件流推算重构即可(**最终收口正是这么做的**,重跑从结果上完全多余)。 +3. **无会话内预算/停机点**:第二轮重跑无任何闸拦,「调整一下就重跑」畅行到用户人工叫停。 + +### 2.3 一天总量核算 + +| 项 | 墙钟(推算) | 可避免部分 | +|---|---|---| +| 81000 满档 | 65–80 min | ~49–64 min(按用途最高需要 N=100 计 ~16 min) | +| 批① T8 | ~19 min | 0(正当) | +| 批① T10 | ~9.7 min | ~6.5 min(N=20 足矣) | +| 批② T5 四次 | ~35 min | ~15–20 min(重跑两次) | +| **合计** | **~130–145 min** | **~75–90 min ≈ 六成** | + +--- + +## 3. N 标准调研(按用途分级,外部统计公式反推) + +### 3.1 用途①:对拍断言(同种子逐位)——**N=0 新跑** + +- 依据:种子=seed0+cursor 逐局独立确定性(`adventure_monte_carlo.gd:82`);同种子 ⇒ 全程逐步可回放(`level_autoplay.gd:26`);核心 RNG 单点(CLAUDE.md RNG 单点红线)。同代码同种子=逐位同轨迹 → 留盘锚常驻即比,**零新跑**。 +- 已兑现先例:批② T0 复用批① off_n60 不重跑(batch2 计划书 F9「码态相同不重跑」);批② off 对拍 120 行逐位 PASS。 +- 需要新跑的唯一情形=代码轨迹变了(此时对拍语义升级为「改前锚 vs 改后锚读数位移」,见 §4 增量复用)。 +- 复验形态(出口闸逐位复现)用**种子子集 N≤20** 即可:断言是确定性的,扰动存在时 RNG 流整体位移、每条种子几乎必漂——检出力与 N 无关,N 只需覆盖「子集确实来自锚文件」。 +- 依据外部锚:确定性复放为工程事实(非统计推断),无需样本量公式。 + +### 3.2 用途②:结构性回归读数——**N=60/策略** + +- 依据:两比例比较样本量公式(Fleiss 型,外部锚 [BMJ Paediatrics Open](https://bmjpaedsopen.bmj.com)/标准教材:n/组 = (z_α/2+z_β)²·[p₁q₁+p₂q₂]/(p₁−p₂)²,α=0.05 双侧、80% 功效 z_β=0.84): + - 检出 50%→10%(灾难性破坏,Δ=40pp):n≈17–20/组 + - 检出 50%→25%(重大位移,Δ=25pp):n≈55–58/组 +- 结论:**N=60 恰好覆盖 ≥25pp 级结构位移的 80% 功效检出**——正是「出池/重建/机制加入」级事件的量级;更小位移在 N=60 下判读不可靠,必须如实标「只测不判/窗口不足」(现行读数 md 纪律与此吻合:N=60 vs 400 窗差 ±~10pp 自标)。 +- 佐证(已知背景):种子窗波动 ±~10pp(81000 读数 §三引 numfix 报告注)。 + +### 3.3 用途③:带值判定——**按判定带宽度反推** + +- 依据:单比例样本量公式(外部锚 [LibreTexts 7.4](https://stats.libretexts.org/Courses/Citrus_College/Introductory_Statistics_OER_-_Exercise_Questions_Each_Section_Included/07%3A_Confidence_Interval_for_One_Sample/7.04%3A_Confidence_Interval_and_Sample_Size_for_the_Proportion)、[NIST 手册 7.2.4.2](https://www.itl.nist.gov/div898/handbook/prc/section2/prc242.htm):E = z·√(p(1−p)/n) ⇒ **n = z²·p(1−p)/E²**,最保守 p=0.5 时 n=z²/(4E²);z=1.645@90%、1.96@95%)。 +- 现行判定带 D≤15pp(难度曲线与Boss 带值四带甲案)→ 半带宽 7.5pp。读数离带边的可靠裁决距离=CI 半宽: + +| 目标 CI | E(半宽) | 所需 N/档 | perfect 档耗时 | 用途定位 | +|---|---|---|---|---| +| 90% | ±10pp | **68** | ~9.6 min | 粗判(离带边 ≥10pp 才下结论) | +| 95% | ±10pp | **97** | ~13.7 min | 常规带判 | +| 95% | ±7.5pp | **171** | ~24 min | 15pp 带全宽裁决 | +| 95% | ±5pp | **385** | ~54 min | 贴带边精确裁决(**现行 N=400 惯例的真实含义**) | + +- **N=400 只在「贴带边裁决+里程碑放行」场景必要**——日常数值验证根本用不到满档。 +- 判读纪律配套:读数离带边 不推翻现行规则(两入口铁规/无数值改动禁跑/缓存层语义/读数只锚一次),只补「跑多少、跑多贵、何时免跑」维度。 + +### 4a. CLAUDE.md「测试执行两入口铁规」——MC 触发细则节后追加一条硬红线 + +```markdown +- **MC 成本与样本量细则(2026-10-03 补立,承接 MC 触发细则)**:MC 采集一律按用途选 N(分级表与耗时上限见 + `sim-data/README.md`「N 分级标准表」节),禁按惯例继承、禁计划书自拟;超出「对拍=0/复验≤20/结构回归=60/ + 带值粗判=100/全带=170」档位(含满档 400)须用户逐次明示发令。单次开发会话 MC 总耗时上限 **20 分钟** + (≈一组 N=60 双策略),超限停机呈报;为单一比值/中位数/单字段取证(如 k 系数)禁用满档——N=60 即稳 + (81000 教训)。任何 ≥60 局采集前必先跑 N=5/档 pilot 校验 RUNSUM 字段完整与口径自检(≈1 分钟),通过才放 + 全量(批② T5 43 行自检暴露缺陷教训前置化)。**读数缺陷 ≠ 轨迹失效**:采集器/读数路径修复若零 gameplay/RNG + 触碰(静态核证+off 对拍佐证),已采数据仍有效——优先事件流重构补算,禁整套重跑;仅轨迹失效才取新锚。 + **增量复用规则**:①零数值改动=零 MC(现行规则重申);②采集器增字段零 gameplay=零重跑,新字段随下次正当 + 触发顺带采集;③轨迹性改动(表值/机制/池构成)=改前锚已留盘即用(禁为「改前」补跑),改后取新锚一次判读 + 位移;④同批同码态锚只取一次,「调整一下就重跑」禁止;⑤出口闸逐位复验用锚内种子子集(N≤20)即可。采集链 + 性能改造(分片并行/日志 flush 开关)属零轨迹影响面,一次性批立项并对现行锚逐位对拍验收后方可使用。 +``` + +### 4b. sim-data/README.md 追加「N 分级标准表」节(§工具与格式 前插入) + +```markdown +## N 分级标准表(2026-10-03 立规——按用途定 N 与耗时上限,禁惯例继承禁计划书自拟) + +依据:单比例样本量 n=z²p(1−p)/E² 与两比例功效公式(外部统计基准,出处见 +design/research/MC成本调研与规制方案-2026-10-03.md §3/§附);单局费率 normal 1.21s / perfect 8.47s +(2026-10-02 性能报告实测,on 态同量级按 1.5× 上界预留)。 + +| 用途 | N/档 | 双策略耗时 | 判读力 | 触发权 | +|---|---|---|---|---| +| 对拍断言(同种子逐位) | 0(复用留盘锚);复验子集 ≤20 | 0 / ≈3 分钟 | 确定性——扰动即全体种子漂移,检出力与 N 无关 | 任务书授权 | +| 结构回归读数 | 60 | ≈10 分钟 | 80% 功效检出 ≥25pp 位移;<25pp 只测不判 | 任务书授权 | +| 带值判定·粗 | 100 | ≈16 分钟 | 95% CI ±9.8pp(离带边 ≥10pp 才下结论) | 任务书授权 | +| 带值判定·全带(15pp 带半宽) | 170 | ≈27 分钟 | 95% CI ±7.5pp | 任务书授权 | +| 贴带边裁决/里程碑放行 | 400(满档) | ≈65 分钟 | 95% CI ±4.9pp | 用户明示发令 | +| 采集 pilot(强制前置) | 5 | ≈1 分钟 | 字段/口径自检,非统计读数 | ≥60 局采集必附 | +| normal 独立满档 | 400(仅 normal) | ≈8 分钟 | 零事件 95% 上界 0.75%(规则三) | 任务书授权 | + +配套纪律:会话预算 ≤20 分钟(细则见 CLAUDE.md MC 成本细则);读数离带边