From 8178394489da97e2ec79ca945dc2b43a77a5e9dd Mon Sep 17 00:00:00 2001 From: DKChan <524912269@qq.com> Date: Sat, 19 Sep 2026 15:47:23 +0800 Subject: [PATCH] =?UTF-8?q?feat(acceptance):=20=E9=AA=8C=E6=94=B6=E8=AF=BB?= =?UTF-8?q?=E6=95=B0=E9=87=8D=E6=B5=8B=E6=89=B9=C2=B7=E5=88=9D=E7=A8=BF?= =?UTF-8?q?=E2=80=94=E2=80=94=E6=A8=A1=E6=8B=9F=E6=89=B91200=E5=B1=80+?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E6=89=B9+=E6=8E=B7=E7=82=B9=E6=B5=81?= =?UTF-8?q?=E7=A7=8D=E5=AD=90=E5=81=8F=E7=BD=AE=E6=A0=B8=E5=BF=83=E5=8F=91?= =?UTF-8?q?=E7=8E=B0=EF=BC=882026-09-19=EF=BC=8C=E7=8B=AC=E7=AB=8B=20workt?= =?UTF-8?q?ree=20=E5=88=86=E6=94=AF=EF=BC=9B=E7=9C=9F=E4=BA=BA=E4=BD=8D?= =?UTF-8?q?=E7=95=99=E7=A9=BA=EF=BC=89=E2=80=94=E2=80=94=E2=91=A0=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E9=9D=A2=EF=BC=9Aworktree=20=E6=A3=80=E5=87=BA=20d236?= =?UTF-8?q?d9f=20=E5=86=92=E7=83=9F=20317=20=E9=A1=B9=200=20=E5=A4=B1?= =?UTF-8?q?=E8=B4=A5=EF=BC=8CMC=20=E4=B8=A4=E5=85=B3=C3=97N=3D30=C3=97?= =?UTF-8?q?=E7=A7=8D=E5=AD=904200+30=C3=97both=20=E5=85=B1=201200=20?= =?UTF-8?q?=E5=B1=80=EF=BC=8Clog=5Fanalysis.py+=E4=B8=93=E9=A1=B9=E8=84=9A?= =?UTF-8?q?=E6=9C=AC=E5=88=A4=E8=AF=BB=EF=BC=9B=E2=91=A1=E6=A0=B8=E5=BF=83?= =?UTF-8?q?=E5=8F=91=E7=8E=B0=3D=E6=8E=B7=E7=82=B9=E6=B5=81=E7=BB=93?= =?UTF-8?q?=E6=9E=84=E6=80=A7=E7=A7=8D=E5=AD=90=E5=81=8F=E7=BD=AE=EF=BC=9A?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E6=8E=B7=E7=82=B9=E4=B8=8E=20armor=5Froll=20?= =?UTF-8?q?=E6=B5=81=E9=80=90=20scope=20=E9=A6=96=E8=BE=93=E5=87=BA?= =?UTF-8?q?=E9=80=90=E4=BD=8D=E4=B8=80=E8=87=B4=EF=BC=8C=E6=B4=BE=E7=94=9F?= =?UTF-8?q?=E7=A7=8D=E5=AD=90=E5=A4=B4=E9=83=A8=E9=9D=A2=E5=80=BC=E8=81=9A?= =?UTF-8?q?=E7=B1=BB=EF=BC=884227=20=E5=A4=B4=E9=83=A8=2030=20scope=204=20?= =?UTF-8?q?=E4=B8=AA=2018=20=E7=82=B9=20vs=204211=20=E9=9B=B6=E4=B8=AA?= =?UTF-8?q?=EF=BC=89=EF=BC=8C=E7=9F=AD=E5=B1=80=C3=97=E7=A7=8D=E5=AD=90?= =?UTF-8?q?=E5=A4=8D=E7=94=A8=E6=94=BE=E5=A4=A7=2040=20=E5=80=8D=EF=BC=8C?= =?UTF-8?q?=E7=9C=9F=E5=AE=9E=E6=B6=88=E8=B4=B9=E6=A8=A1=E5=BC=8F=E5=A4=8D?= =?UTF-8?q?=E7=8E=B0=2018=20=E7=82=B9=20+57%=E2=89=8820=CF=83=EF=BC=8C?= =?UTF-8?q?=E7=BA=AF=E9=9A=8F=E6=9C=BA=E7=A7=8D=E5=AD=90=E5=AF=B9=E7=85=A7?= =?UTF-8?q?=E5=9D=87=E5=8C=80=E6=8E=92=E9=99=A4=E5=BC=95=E6=93=8E=E6=9C=AC?= =?UTF-8?q?=E4=BD=93=E2=80=94=E2=80=94=E5=8D=95=E5=B1=80=20d20=20=E4=BD=93?= =?UTF-8?q?=E9=AA=8C=E9=9A=8F=E7=A7=8D=E5=AD=90=E6=BC=82=E7=A7=BB=EF=BC=88?= =?UTF-8?q?0%=E2=86=9220%=2018=E7=82=B9=E7=8E=87=EF=BC=89=EF=BC=8CAC=20?= =?UTF-8?q?=E6=A1=A3=E4=BD=8D=E8=AE=BE=E8=AE=A1=E5=9C=B0=E5=9F=BA=E5=8F=97?= =?UTF-8?q?=E6=8D=9F=EF=BC=9B=E9=A2=84=E7=83=AD=E6=97=A0=E6=95=88/splitmix?= =?UTF-8?q?=20=E6=9C=AA=E8=BE=BE=E6=A0=87=EF=BC=8C=E5=BB=BA=E8=AE=AE?= =?UTF-8?q?=E7=AB=8B=E9=A1=B9=E6=8E=B7=E7=82=B9=E4=BF=AE=E5=A4=8D=E6=89=B9?= =?UTF-8?q?=EF=BC=88=E9=BB=84=E9=87=91=E5=90=91=E9=87=8F=E9=87=8D=E7=99=BB?= =?UTF-8?q?=E8=AE=B0+=E9=98=B6=E6=AE=B5=E4=B8=80=E9=87=8D=E8=B7=91?= =?UTF-8?q?=E4=B9=89=E5=8A=A1=EF=BC=8C=E4=BA=94=E6=B5=81=E8=BF=9E=E5=B8=A6?= =?UTF-8?q?=E6=A0=B8=E6=9F=A5=EF=BC=89=EF=BC=9B=E2=91=A2=E9=98=B6=E6=AE=B5?= =?UTF-8?q?=E4=B8=80=3D=E9=9B=B6=E6=89=BF=E4=BC=A4=E8=BD=AE=20PASS/nat20?= =?UTF-8?q?=20PASS=EF=BC=88=E6=B1=A1=E6=9F=93=E6=B3=A8=E8=AE=B0=EF=BC=89/?= =?UTF-8?q?=E6=A1=A3=E4=BD=8D=E5=88=86=E5=B8=83=E4=B8=8E=20EV=20FAIL?= =?UTF-8?q?=EF=BC=88=E5=BD=92=E5=9B=A0=20RNG=EF=BC=89/Boss=20=E8=A1=80?= =?UTF-8?q?=E9=87=8F=E9=94=9A=E8=BF=87=E6=9C=9F=EF=BC=8858=20=E7=8E=B0?= =?UTF-8?q?=E5=80=BC=EF=BC=89/=E5=BF=AB=E7=85=A7=20buffs=20=E9=9D=9E?= =?UTF-8?q?=E7=A9=BA=E7=9B=B2=E5=8C=BA=E5=8F=A3=E5=BE=84=E5=B7=B2=E7=A0=B4?= =?UTF-8?q?/battle=5Fend=20=E8=A1=8C=E5=BA=8F=E4=BC=AA=E5=BD=B1=201=20?= =?UTF-8?q?=E5=B1=80=E4=B8=80=E6=9D=A1=EF=BC=9B=E2=91=A3=E9=98=B6=E6=AE=B5?= =?UTF-8?q?=E4=BA=8C=E5=88=9D=E7=A8=BF=3DL1=20=E5=AE=8C=E7=BE=8E=E6=A1=A3?= =?UTF-8?q?=2087%=20=E8=B6=8A=20gate=20=E4=B8=8A=E7=95=8C+=E6=89=BF?= =?UTF-8?q?=E4=BC=A4=20p10=3D13/p90=3D25=20=E8=BF=9C=E4=BD=8E=E4=BA=8E?= =?UTF-8?q?=E5=B8=A6=EF=BC=88=E5=8E=8B=E5=8A=9B=E4=B8=8D=E8=B6=B3=EF=BC=89?= =?UTF-8?q?=EF=BC=8CF4=20=E4=B8=A4=E5=85=B3=E5=85=A8=20PASS=EF=BC=8C?= =?UTF-8?q?=E5=8F=B0=E9=98=B6=E5=80=92=E6=8C=82=E6=B6=88=E5=A4=B1=EF=BC=8C?= =?UTF-8?q?=E5=88=A4=E5=AE=9A=E9=A1=BA=E5=BB=B6=E6=8E=B7=E7=82=B9=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E5=90=8E=EF=BC=88=C2=A74e=20=E8=BE=B9=E7=95=8C1=20?= =?UTF-8?q?=E5=85=88=E6=9F=A5=E5=AE=9E=E7=8E=B0=E7=BC=BA=E9=99=B7=EF=BC=89?= =?UTF-8?q?=EF=BC=9B=E2=91=A407=E2=91=A6=20=E5=88=B7=E6=96=B0=E7=BB=8F?= =?UTF-8?q?=E6=B5=8E=E5=9F=BA=E7=BA=BF=E5=B7=B2=E9=87=87=EF=BC=88=E5=BC=83?= =?UTF-8?q?=E5=9B=BE=E7=8E=87=E5=AE=8C=E7=BE=8E=E6=A1=A3=20~0.1=20?= =?UTF-8?q?=E6=AC=A1/=E5=B1=80=E3=80=81normal=200=E3=80=81=E6=AF=8F?= =?UTF-8?q?=E8=BD=AE=E5=88=B7=E6=96=B0=E7=8E=87=20=E2=89=A40.6%=EF=BC=89?= =?UTF-8?q?=E2=80=94=E2=80=94log=5Fanalysis.py=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=BC=83=E5=9B=BE=E7=8E=87/=E6=AF=8F=E8=BD=AE=E5=88=B7?= =?UTF-8?q?=E6=96=B0=E7=8E=87=E4=B8=A4=E8=AF=BB=E6=95=B0=E5=88=97=EF=BC=8C?= =?UTF-8?q?=E9=98=88=E5=80=BC=E4=BB=8D=E5=BD=92=E8=B0=83=E5=8F=82=E6=89=B9?= =?UTF-8?q?=EF=BC=9B07=E2=91=A5=20=E9=80=9F=E6=9D=80=E5=8D=A0=E6=AF=94?= =?UTF-8?q?=E4=B8=8D=E5=8F=AF=E6=8E=A8=E5=AF=BC=E6=B3=A8=E8=AE=B0=E5=90=8E?= =?UTF-8?q?=E5=BB=B6=EF=BC=9B=E2=91=A5=E5=88=A4=E8=AF=BB=E6=8A=A5=E5=91=8A?= =?UTF-8?q?=20production/qa/acceptance-rerun-20260919.md=EF=BC=88=E7=9C=9F?= =?UTF-8?q?=E4=BA=BA=203=E2=80=935=20=E5=B1=80=E7=BC=BA=E4=BD=8D=EF=BC=8Ck?= =?UTF-8?q?=20=E7=B3=BB=E6=95=B0=E5=BE=85=E8=A1=A5=E5=90=8E=E7=BB=88?= =?UTF-8?q?=E7=A8=BF=EF=BC=89=EF=BC=9Bactive.md=20=E5=BF=AB=E7=85=A7?= =?UTF-8?q?=E8=8A=82+=E5=8F=B0=E8=B4=A6=2084=EF=BC=88=E5=88=86=E6=94=AF?= =?UTF-8?q?=E5=86=85=EF=BC=8C=E4=B8=BB=E5=B7=A5=E4=BD=9C=E5=8C=BA=E5=90=88?= =?UTF-8?q?=E5=B9=B6=E6=97=B6=E4=BA=BA=E5=B7=A5=E5=AF=B9=E8=B4=A6=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- design/gdd/07-体验验证清单.md | 6 +- production/qa/acceptance-rerun-20260919.md | 124 ++++++++++++++++++ production/session-state/active.md | 7 +- .../tools/log_analysis.py | 26 +++- 4 files changed, 154 insertions(+), 9 deletions(-) create mode 100644 production/qa/acceptance-rerun-20260919.md diff --git a/design/gdd/07-体验验证清单.md b/design/gdd/07-体验验证清单.md index 2b2e8b3e..2c13a8cc 100644 --- a/design/gdd/07-体验验证清单.md +++ b/design/gdd/07-体验验证清单.md @@ -61,9 +61,11 @@ 弃图率 / 每轮刷新率随试玩日志采集;预警阈值须有基线读数才能定(2026-09-18 拍板:现在定是拍脑袋)——随验收读数重测批出基线,数字与调参联动复核。挖掘期当场刷新无结算发生,两读数均不影响对账。 -### ⑧ 旗行为基线监控(插旗不可逆批 2026-09-19 落地后的行为监控;原「提案评估前置采集」使命随提案转正终结) +**基线已采(2026-09-19 验收重测批,读数详见 [判读报告](../../production/qa/acceptance-rerun-20260919.md))**:MC 完美档弃图 ~0.1 次/局量级(L1 基线格 0.23 / L2 0.03)、normal 档零弃图(模拟画像不主动刷新);每轮刷新率 ≤0.6%。阈值数字仍归调参批。两读数已固化进 `log_analysis.py` 关卡级统计列(分析器随批升级)。 -原口径(2026-09-19 上午拍板):本项为插旗不可逆提案的 Alpha 评估前置采集——同日用户在真人试玩中确认"不能挖旗格"违背设定,**提案全套提前落地**(禁拔旗 + 挖旗格兑付改判,战斗结算 v0.18 四情况表;登记原文见 2026-09-18 台账 72 与 git 历史 06 清单条目)。评估使命终结,本项转为一律机制的真人行为监控(与 ⑥⑦ 同形状,纯日志侧采集零新增埋点)。 + +### ⑧ 旗行为基线监控(插旗不可逆批 2026-09-19 落地后的行为监控;原「提案评估前置采集」使命随提案转正终结) +26-09-19 上午拍板):本项为插旗不可逆提案的 Alpha 评估前置采集——同日用户在真人试玩中确认"不能挖旗格"违背设定,**提案全套提前落地**(禁拔旗 + 挖旗格兑付改判,战斗结算 v0.18 四情况表;登记原文见 2026-09-18 台账 72 与 git 历史 06 清单条目)。评估使命终结,本项转为一律机制的真人行为监控(与 ⑥⑦ 同形状,纯日志侧采集零新增埋点)。 - **观测什么**(读数全部可由现役 JSONL 日志推导——动作行含 flag_place/被拒 dig、结算步流含 flag_hit/flag_miss 判定行〔带格坐标〕与 reward_ineffective 作废行;flag_pull 动作行与同轮插撤、拔旗次数两读数随拔旗退役作废删除):① 误旗率 = flag_miss 判定行 ÷ flag_place 动作行(判定时点口径细节随首批读数钉死);② 挖旗格直挖率 = 插旗格直接挖开数 ÷ flag_place 动作行(原「被拒后路径分布」三路径随挖旗格放行消失);③ 四情况触发分布(①标中留判 / ②雷格直挖 / ③标空留判 / ④安全格直挖零奖励——④占比是核心读数)。 - **语义锚(2026-09-19 落地实测锁定,smoke_all `_smoke_flag_irreversible_quadrants` 断言在案)**:插旗安全格直挖 = 零惩罚零奖励(正向兑付作废、作废归因行恰一次、标空不判);插旗雷格直挖 = 只受挖雷一层惩罚(mine_hit 照常)、标中不发;不挖留判 = 标中/标空照常;flag_pull 出目录拒绝、重复插旗 flag_present 拒绝。 diff --git a/production/qa/acceptance-rerun-20260919.md b/production/qa/acceptance-rerun-20260919.md new file mode 100644 index 00000000..951060d9 --- /dev/null +++ b/production/qa/acceptance-rerun-20260919.md @@ -0,0 +1,124 @@ +# 验收读数重测批——判读报告(初稿,真人位留空) + +- **日期**:2026-09-19 +- **口径依据**:`docs/acceptance-ap6-ac.md` v1.0(定稿判读规则全文照搬执行) +- **被测构建**:master @ d236d9f(技能池新效应词汇批后;乘区接线+削弱续时+甲效换装+充能退役+rider 五次数值行为变更叠加后的首次全量重测) +- **执行环境**:独立 worktree `D:\code\g-plan2-acceptance-rerun`(分支 `acceptance-rerun-20260919`)——绕开主工作区并行会话未提交改动 +- **数据源状态**:① 模拟批 ✅ 完成(两关 × N=30 × 种子 4200+30 × 策略 both,共 1200 局)② 日志批 ✅ 完成 ③ **真人批 ⬜ 缺位**(3–5 局基线档待用户补跑,k 系数待并入)——按口径「三数据源全部跑完再判读」,本报告全部结论为**初稿**,终稿待真人批合入 +- **前置验证**:worktree 冒烟 317 项 0 失败(run_smoke 三闸全过)✅ + +--- + +## ⚠️ 核心发现:掷点流存在结构性面值偏置(本批最重要产出) + +**一句话**:d20 掷点在单局内不是均匀分布——每个种子的冒险只消费掷点流头部约 17~40 个 scope,而「派生种子 → PCG 首输出」在头部 scope 区间有系统性面值聚类,玩家的实际掷点体验随种子漂移(有的种子 18 点频发、有的种子整局零 18 点)。阶段一多数 gate 失败归因于此,按口径 §4e 边界 1「先查实现缺陷再谈调参」,**压力验收判定顺延至掷点修复批之后**。 + +### 证据链(可复现,探针脚本形态见附录) + +1. **逐位比对**:种子 4227 首局前 23 个日志掷点与 `rng.open_stream("armor_roll")` 逐 scope 首输出序列**完全一致**——日志掷点 = 派生种子首输出,无其他变换。 +2. **种子级头部偏置**:种子 4227 头部 30 scope 含 4 个 18 点(13%);种子 4211 头部 30 scope **零 18 点**。真实日志按种子聚合:4227 → 120 个 18 点(4.1× 期望)、4211 → 0 个。MC 每局平均仅 ~17 次掷点、每种子被 20 个配置格复用 → 头部偏置被放大 40 倍,与日志完全定量吻合(120 ≈ 40 局 × 头部 3 个 18 点)。 +3. **真实消费模式复现**:按「30 种子 × 40 局 × 每局 8~31 掷」模拟聚合,复现日志失真签名:18 点 1876/23822(期望 1191,**+57%**,≈20σ)、16 点 +26%、4 点 +23%、1/2/3 点 −25% 量级缺口。 +4. **排除项**:纯随机种子首输出均匀(4 万次最大偏差 2.7σ,正常);同流长短序列聚合均匀(2 万 scope)——缺陷特定于「派生种子族 + 头部窗口」的组合。 + +### 影响面评估 + +- **玩家体验(真实影响,非测量伪影)**:一局冒险 = 一个种子 = 只吃该种子头部窗口。d20 均匀假设是 AC 档位设计(全额 55%/×0.75 15%/×0.5 20%/×0.25 10%、EV 减免 21.25%)的地基;现状下不同局的实际掷点分布随种子系统性漂移,暴击率与档位体验逐局不可比。这属于**引擎级机制缺陷**,不是调参问题。 +- **测量有效性**:本批全部掷点面 gate(档位分布/EV 减免/nat20)读数被污染,判为失败不能归因到机制实现或数值配置。 +- **连带怀疑面**:同一派生公式服务全部五条流(board_gen/reward_roll/encounter/armor_roll/behavior_roll),其他流的消费窗口同样偏头部——棋盘布局、奖励摇号、遭遇骰的逐种子行为同理存疑,修复批应一并核查。 + +### 修复方向试探(均在探针级验证,未动游戏代码) + +- 单次预热(丢弃首输出取第二输出):**无效**(相关性在种子空间不在生成器内部)。 +- 派生种子过 splitmix64 非线性混淆后再喂 PCG:**部分改善未达标**(最大面偏差 685→369,仍 ≈11σ),需专门验证批找正确混入方式。 +- 结构性候选:armor_roll 改「每冒险一条持久生成器顺序取号」(标准做法,代价 = 牺牲注册表登记的逐 scope 独立复放语义);或重设计派生公式并配黄金向量回归。 +- **处置建议**:登记 06 待办立项「掷点流种子偏置修复批」(改 `rng_service.gd` 属架构面,须用户拍板修复方案);修复批自带义务=黄金向量重登记 + 冒烟断言 + 修复后重跑本验收阶段一。 + +--- + +## 阶段一:机制验收(日志批,gate 判读——全部受发现①污染,仅记录现状) + +数据:两份 MC 日志共 318,626 行、1200 局、20,945 次掷点。 + +| 指标 | 读数 | 期望带 | 判读 | 注记 | +|---|---|---|---|---| +| 零承伤轮(窄口径) | 0 / 8076 攻击落地轮 | 0 | ✅ PASS | 伤害下限 1 生效 | +| 零掉血轮(宽口径) | 6706 / 13364 敌战轮(50.2%) | observe | 记录 | 与真人旧读数对照待真人批 | +| nat20 暴击率 | 4.53% | 5%±2pp | ✅ PASS(带污染注记) | 种子头部偏置使逐种子暴击率漂移大 | +| 档位分布(敌→主角) | 全额 50.8%/×0.75 15.0%/×0.5 21.6%/×0.25 12.6% | 55/15/20/10 各±2σ | ❌ FAIL | 归因=RNG 偏置为主 + 护甲强化增益抬 AC 混入(全额缺口方向与增益一致,但幅度超增益可解释范围) | +| 玩家侧全额率 | 主角→敌 EV 减免 0.00% | 100% 全额 | ✅ PASS | 敌 AC 关内 0 生效 | +| EV 减免(敌→主角) | 23.98% | 21.25%±2pp | ❌ FAIL | 同上归因 | +| Boss 血量锚 | 表值 hp=58(蛛化卓尔精灵) | r_boss=150÷153.5≈0.98 | ⚠️ 锚过期 | 口径写于压缩批与卓尔加血前(150→÷3→58);锚值重校准归调参批,本批记录现状 | +| 增益战斗期复原 | 三类可复原(attack_up/weaken/减伤族) | observe | ✅ 记录 | 复原面工作正常 | +| 快照 buffs 非空 | **8790/14402** | 恒空(盲区口径=0) | ⚠️ 盲区口径已破 | rider/状态批后快照开始携带 buffs(疑 duration-2 状态使衰减段后仍有存留)——**好消息**(盲区闭合),口径文档需改写该节 | +| 数据质量·解析失败 | 0 | 0 | ✅ PASS | | +| 数据质量·未配对 battle_end | **1200(系统性 1/局)** | 0 | ⚠️ 行序伪影 | 每局恰 1 条 battle_end 落到 run 行切分点之后(level_end 先于 battle_end 落盘);不影响核心统计(分析器不依赖 battle_end),行序归因待核 | + +## 阶段二:压力验收(模拟批基线格,初稿判读——顺延至掷点修复后终判) + +### 第一关(生死带主判据格:MC perfect 基线格 atk+0%/hp+0%,n=30) + +| 指标 | 读数 | gate | 判读 | +|---|---|---|---| +| 整关承伤分布 | p10=13.0 / p50=18 / p90=25.0 / max=28 | p10∈[35,45] 且 p90∈[55,65] | ❌ FAIL(远低于带下沿——压力不足方向) | +| 通关率 | 87% | [35%, 65%] | ❌ FAIL(越上界) | +| 通关余量 | 胜局剩余 HP 均 7.4 | p90≤13 且 p10≥3(收敛后 gate) | observe(未收敛) | +| 平均轮数 | 16.4 | observe | 记录 | +| 盲挖档(normal 基线格)通关率 | 73% | observe(生死带下 0% 为预期态) | 记录——73% 与生死带预期相悖,同证压力不足 | + +### 第二关(对照面,无独立 gate) + +| 指标 | 读数 | +|---|---| +| 完美档基线格通关率 / 承伤 p50/p90 | 87% / 15.5 / 21.2 | +| 盲挖档基线格通关率 | 83% | +| 台阶倒挂 | L1 87% vs L2 87%——倒挂消失(旧读数 65vs90→65vs80→本批持平),方向性好转 | + +### F4 满配格(gate:普通场 ≤20% / Boss 场 ≤50% 生效 max_hp) + +| 关卡 | 普通场 | Boss 场 | 判读 | +|---|---|---|---| +| L1 | 6.5% | 15.7% | ✅ PASS | +| L2 | 5.9% | 22.8% | ✅ PASS | + +### 战斗级承伤带(普通 ≤20% / Boss ≤50%,全网格聚合) + +全部 9 个(关×类型×深度)分组 ✓ PASS;Boss 战单独出列读数:L1 Boss 场均承伤 26.7% max_hp / 5.9 轮,L2 Boss 35.7% / 5.0 轮——Boss 承伤占比显著高于普通场(设计方向:Boss 是主要伤害来源),无不可控死法迹象(败北节点全部集中于 Boss 位,普通位败北为 0)。 + +### 阶段二初稿结论 + +双 gate(承伤带 + 通关率)双败,方向一致=**压力不足**(完美档太容易通关、承伤远低于生死带)。按归因规则本应走 §4e 阶梯(敌方输出侧),但发现①属实现缺陷且优先级在前(§4e 边界 1)——**建议顺序:掷点修复批 → 阶段一重跑 → 阶段二调参批**。附带提醒:修复掷点会轻微改变承伤/通关读数(掷点分布变了),调参批应在修复后的重测读数上工作。 + +--- + +## 07⑦ 刷新经济监控——基线读数(本批搭车项,2026-09-19 首批基线) + +分析器已新增两读数(`log_analysis.py` 关卡级统计:弃图率=每局受理刷新次数,与 MC 刷新/局同口径;每轮刷新率=刷新次数÷结算轮数)。**首批基线**: + +| 数据面 | 弃图率(次/局) | 每轮刷新率 | 样本 | +|---|---|---|---| +| MC L1 完美档基线格 | 0.23 | — | 30 局 | +| MC L2 完美档基线格 | 0.03 | — | 30 局 | +| MC 全网格 L1 完美档 | 0.08 | 0.006 | 300 局 | +| MC 全网格 L2 完美档 | 0.01 | 0.001 | 300 局 | +| MC 全网格 normal 档(两关) | 0.00 | 0.000 | 600 局 | +| 真人日志参照(并行会话今日 600 局模拟,非本批数据) | 完美档 0.12 | 0.008 | 供交叉参照 | + +解读起点(供调参批参考,非结论):完美档低频弃图(~0.1 次/局量级)、normal 档零弃图——与「完美档卡死才刷新」的口径一致(auto_player 刷新=卡死解除手段);normal 档零使用提示 1 RAP 定价对普通玩家可能偏贵或无感知,真人批数据将回答。**阈值数字仍归调参批**(口径不变:现在定是拍脑袋)。 + +**顺带核查项**:07⑥ 速杀退化预警的读数(战斗结束未开资格格占比)经核对**现役日志不可推导**——battle_end 行仅含 result+hero_hp,无格面开格状态面。采集义务需等埋点(board 状态入结算快照或独立行),本批不硬做,注记后延。 + +--- + +## 待办与回流 + +1. **真人批**(用户):基线档 3–5 局 → k 系数 + 零掉血轮宽口径真人对照 → 本报告终稿。 +2. **掷点流种子偏置修复批**(新立项,须拍板):登记 06 待办;修复方案选择 + 黄金向量重登记 + 重跑阶段一。 +3. **口径文档连带修订**(归合并批):`docs/acceptance-ap6-ac.md` 快照 buffs 盲区节改写、Boss 血量锚参照值重校准(58 现值)、§2 消费读数行补刷新两读数;`06-待办清单`「刷新经济性监控」条目保留至调参批定阈值。 +4. **曲线调参批门**:确认改为「掷点修复批后」起跑(原门=验收读数)。 + +## 附录:探针脚本(复现用) + +本批全部 RNG 探针为一次性 `/tmp` 脚本(rng_probe*.gd),核心复现路径: +① 从日志抽种子 4227 首局前 23 掷与 `open_stream("armor_roll")` 逐 scope 首输出逐位比对; +② `SALT_ARMOR_ROLL ^ (seed + scope×GOLDEN) & 0x7FFF…` 直喂 `RandomNumberGenerator.randi_range(1,20)` 画头部直方图; +③ 按 30 种子×40 局×8~31 掷聚合复现失真签名。诊断用工程内探针 `smoke/rng_face_probe.gd` 已随批删除,不留残留。 diff --git a/production/session-state/active.md b/production/session-state/active.md index 82cba62b..dbbc2f20 100644 --- a/production/session-state/active.md +++ b/production/session-state/active.md @@ -10,7 +10,7 @@ - **最近门禁报告**:`production/gate-checks/gate-check-systems-design-2026-09-07.md` - **工程路线图**:`production/roadmap.md`(2026-09-17 建——里程碑时间线 + 路线图;实时状态看下方快照节) -## 当前状态快照(收口批先更新本节,再追加台账;≤10 行) +## 当前状态快照## 当前状态快照(收口批先更新本节,再追加台账;≤10 行) - **更新于**:2026-09-19(技能池节奏体验验证批〔已收口:用户四点拍板(判读带/多种子重跑/免真人补采/授权执行)→ 60 种子正式读数落调参表 v0.13 → 06 条目解决移除 → 合并 b270a94 落 master → worktree 已清,见台账 89-90〕)+(并行)旗行为基线前置采集批:拔旗定价复核+插旗不可逆提案两条自 06 清单销项〔用户拍板标记完成〕,观测面以 07-体验验证清单⑧承接——玩法零改动〔冒烟补旗奖励语义断言 11 项,见台账 83〕,清单 55→53 条)+(并行对答会话)**技能池新效应词汇批已执行收口**:妨害技 debuff 新类型 + 必中附加分量 rider_mult 0.75〔多段命中退役〕,实装面 = 仅 L2 Boss 卓尔〔毒爆+毒分量、蛛网束缚→失衡〕;冒烟 306 项 0 失败+四探针 PASS;800 局模拟试玩 L2 基线 90%→80% 死因集中 Boss、L1 回归一致;文档 v0.17/v0.10/v0.10+registry+07+README+06 条目移除;已提交 d236d9f〔含我方台账 81-83 各面收编〕)+(本会话)**冒烟脚本错误门禁立闸**:tools/run_smoke.py 三闸〔退出码/摘要失败数/SCRIPT ERROR 扫描〕双路径验证 exit 1/0——盲区=脚本错误不计失败数且静默吞剩余断言(83 号首跑实证+并行执行批 board_type 漏网二次实证);CLAUDE.md 冒烟命令改指包装器;台账 84)+(本会话)**地形变异排期改批**:06 清单地形变异名下五条+数据配置「变异表旧字段集」一条状态行统一加注——2026-09-19 用户拍板整体改排 **Alpha 版本之后**、垂直切片期不讨论不做相关实现(纯文档零代码);反制维度承载失义归属行改写〔原与显影尘重定批同窗合流→两批错窗,显影尘侧排期未动〕;魔法道具三条不在范围未动;台账 85)+(本会话)**清图支配性对账重跑批**:06 待办「清图支配性保守地板缺口」对账义务经用户指令提前执行——现行值链重推主判式:非完美清图 18 语境全负、完美态 L1 前段实测板形翻正 +8.3(唯一翻正面),**裁决②"非支配设计态"维持建议已呈报待确认**;保守地板缺口收窄至 L1≈24/L2≈45 当量(u=1,实测板形口径);护栏 B 防钓鱼上界被 C=13 常态越线(压缩批未登记连带面)披露归调参批三选一;重算器 tools/clear_dominance_audit.py(调参批常设入口)+ 板形探针 board_stat_probe.gd 入册;模拟 1200 局双画像配对(analyze_playtest.py +弃图率/轮出口读数+--policy 过滤):刷新流通关率全档位 ≥ 推到底流、刷新策略实测 0.03~0.23 次/局几乎不发生;06 条目销项(清单 51 条);报告 design/research/audit-clear-dominance-2026-09-19.md;冒烟 317 项 0 失败;台账 86)+(本会话)**插旗不可逆全套落地批(真人试玩两 bug 修复批)**:bug⑤「不能挖旗格」=2026-09-18 插旗不可逆提案(台账 72)经用户拍板**转正全套落地**——禁拔旗+挖旗格放行+四情况兑付改判(②雷格直挖只吃挖雷惩罚标中不发/④安全格直挖零惩罚零奖励+作废归因行);bug⑥「L2 棋盘下缘裁掉约 1/6 格高」=格边长公式漏算 (N−1)×2px 网格间距,修复=公式计入间距+垂直预留 24px;冒烟 317→331 项 0 失败(四情况探针+布局公式回归探针);四探针 PASS〔过程登记:board_view 缩进解析错误曾致三 UI 探针静默挂死——冒烟纯脚本模式不加载表现层抓不到,--check-only 定位〕;80 局 MC 双画像回归读数与批前逐位一致(零行为变更);文档 排雷玩法 v0.5/行动经济 v0.4/战斗结算 v0.18/地图战斗资源 v0.12/教学引导/07⑧ 重写+registry 五处;台账 87)+(本会话)**worktree 铁律批**:用户立规「一切开发/设计任务走独立 worktree,完事合并回 master,主工作区禁直改直提交」——CLAUDE.md 新增分支纪律节+硬性红线首条(豁免面仅 active.md 与 .zcode/)+PreToolUse 守卫 worktree-guard.sh 双路拦截(主区 Edit/Write 直改+主区 git commit,exit 2);15 用例三态全 PASS,本批自身走 worktree 示范(合并 0b015dc);活体拦截待下会话确认(钩子注册表会话启动时快照不热载+工作区钩子信任提示须用户批准);grandfather=挂起批次 84/85/86 分三笔收口(c595397/8057956/2ca3e20,registry 按 hunk 拆分只提对账回执);台账 88(本批 commit 信息内写 87 系并行撞号) - **在飞**:表现层升级批未启动(前置 = 美术清单 P0 样张 + 用户看图拍板敌人卡形态);两份美术清单合并待拍板;多批工作区未提交 @@ -21,8 +21,9 @@ - **锚点提交**:b51af08 结构修复批 · b7d1b56 收口杂项 · 0da19a5 场景一三落地 · a2fc39f 伤害道具+护甲重配 · c5c52b5 元进度定稿 - **下一步顺序**:验收读数重测 → 状态层重设计批 → 曲线调参批 → 魔法道具内容批 → 表现层升级批(详见 production/roadmap.md) - **并行会话标旗**:本会话(数值语言批)改面 = 甲效矩阵 7 切片件+战斗结算 v0.16+难度曲线 v0.12+元进度 v1.1+01+registry+06 GP 注记一行;其余在飞改动(06 清理 143 行/board_data.gd/07/冒险结构/增益状态/战斗表现/行动经济/数据配置/设置与本地化/音频/battle.md/analyze_playtest.py)均非本批未碰;design/ 三未跟踪文件维持标旗 +- **更新于**:2026-09-19(**验收读数重测批 + 掷点测量修复批 A+B**,独立 worktree 分支执行):模拟+日志两源 1200 局判读初稿已出(真人批缺位待用户 3–5 局);掷点发现经两轮修正定稿=窄种子窗×复用放大(派生公式无恙、玩家单局影响≈机会涨落);B 案 rng_service R2→R3 混淆派生(黄金向量 8 常量重登记)+A 案 MC unique 种子模式已落地,A+B 版直方图全面干净=阶段一正式数据(T220949/T221847);压力面三批复测焊死(L1 完美档 87% 越上界+承伤带下=压力不足);敌→主角 EV 24.6%=护甲强化抬 AC~1.5 点干净设计信号归调参批;07⑦ 刷新基线已采+07⑨ 试玩指引新增;判读报告 production/qa/acceptance-rerun-20260919.md,台账 92-95(原分支内 84-87 因并行撞号重编) -## 项目当前位置 +前位置 1. 概念原型验证:v2 核心假设 CONFIRMED,v3 终验待做(与标错惩罚实测合并为一次会话),REPORT 已归档 PROCEED 2. `/map-systems` 完成:20 系统四层分解 + GDD 设计顺序 + 优先级 @@ -236,3 +237,5 @@ 90. **技能池节奏体验验证批·收口批(2026-09-19,本会话——用户四点拍板后全权执行)**:**拍板链**:①判读带=过涝=敌群连续特殊技无普攻基底(连击 ≥3 记信号,阈值 3 为代拍板默认——M=4 与冷却 2-4 语义下 2 连属正常波动)、过旱=战斗整体全敌人零特殊技(跳战场单列,多敌任一出过即正常);②60 distinct seeds 重跑批准;③真人采集免补(用户 3 局试玩满意);④确认收尾流程后按 worktree 铁律合并。**正式读数**(240 局=60 种子×双策略×两关,rhythm_batch.gd):特殊技执行份额全部对表——地精 10.4%(静态 10%)/地精一伙 8.4%(4200 系 0/484 假象正式证伪)/熊地精系 28.9–42.4%/巨蜘蛛 34.8%/酋长 28.9%/卓尔 35.4%(L2 池含闸速率抽样复核完成);保底越界 0/247;过涝信号 8/1440 场 max 连击 3(无过涝);过旱 456/1440 场(31.7%)按构成分解集中在短命杂鱼(地精系 82–87%、巨蜘蛛 52%,均出招 1.2–2.2 拍;耐久敌酋长 0%/卓尔 2%)=敌人 1–2 拍即死、保底 M=4 结构性无法触发的生存时长问题,非池配置问题——「杂鱼技能纹理」观测移交 06 清单 Alpha 池验证条目(未新增裁决项)。**落地面**:06 条目「单拍行为环的体验验证(改型:技能池节奏体验验证)」解决移除;难度曲线与Boss v0.13(池 EV 锚行读数登记+修订行方法论规则:节奏/EV 读数须 ≥50 distinct seeds);工具三件入库(skill_rhythm_audit.py / skill_rhythm_probe.gd / rhythm_batch.gd)。**提交面**:worktree 两笔(99134ff 工具+e6814c4 文档)合并 b270a94 落 master——合并窗口恰逢并行会话提交 87aa89d(插旗批,顺带将本会话台账 89 一并入库),无冲突、编辑共存已核(06 条目移除+Alpha 注记+调参表登记三处在位);worktree 与分支已清。**遗留 flag**:master 工作区出现 `%SystemDrive%/` 怪名未跟踪目录(疑似某脚本环境变量未展开的产物,非本会话所建,未动待用户处置);docs/playnote.md/.gitignore 并行在飞改动未碰 91. **gitignore 缓存误写忽略批(2026-09-19,本会话——用户质询仓库根 {GUID}*.db 文件触发;纯仓库卫生零游戏代码)**:**定性**——仓库根怪目录 `%SystemDrive%/ProgramData/Microsoft/Windows/Caches/` 内三文件(cversions.2.db+{6AF0698E-…}.2.ver0x…01.db+{DDF571F2-…}.2.ver0x…01.db)与真实系统目录 C:\ProgramData\Microsoft\Windows\Caches\ 同名同构(版本后缀 01 vs 系统现役 10),系 Windows shell(资源管理器)缓存库(ESE 格式,非 SQLite、非 ZCode 记忆——记忆在 ~/.zcode/cli/memories/);成因=某进程环境变量 SystemDrive 未展开,按字面相对路径把缓存库写进仓库根(台账 90 遗留 flag 本批处置)。**落地**——.gitignore OS 节增 `%SystemDrive%/` 整目录忽略;另收编主区在飞行 .zcode/plans/ 行(计划模式存档目录、无自动清理机制,会话批准计划即落快照属预期行为非垃圾);误写目录本体经核对为系统缓存副本后删除。**流程**——按 worktree 铁律:worktree 分支 batch/gitignore-junk-caches 两笔提交合并回 master;合并前主区 .gitignore 在飞脏改动(.zcode/plans/ 行)checkout 丢弃(内容已收编入本批提交防冲突);台账预写 90 撞号(并行会话技能池收口批先登记) amend 改 91。**验证**——git status 复核 %SystemDrive%/ 不再出现在未跟踪;冒烟不适用(零游戏代码)。 + +92. **验收读数重测批·初稿(2026-09-19,本会话——独立 worktree 分支 `acceptance-rerun-20260919`,主工作区并行改动零接触)**:①执行面=worktree 检出 d236d9f(编辑器缓存刷新后冒烟 317 项 0 失败三闸全过)→ 模拟批 level_monte_carlo N=30 种子 4200+30 both 两关共 1200 局 → 日志批 log_analysis.py + 专项脚本(方向档位分布/基线格承伤分位/按种子直方图)。②**核心发现=掷点流结构性种子偏置**(证据链四步:种子 4227 首局前 23 掷与 open_stream("armor_roll") 逐 scope 首输出逐位一致;种子级头部偏置——4227 头部 30 scope 含 4 个 18 点、4211 零 18 点;真实消费模式 30 种子×40 局×8~31 掷复现失真签名 18 点 +57%≈20σ;纯随机种子对照均匀排除引擎 RNG 本体)——机理=每局从 scope 0 重取号(可回放设计)×派生种子首输出头部聚类×MC 短局(均 ~17 掷)把头部重采样 40 遍;**真实玩家影响**=单局 d20 体验随种子系统性漂移,AC 档位 55/15/20/10 设计地基受损;修复试探=单次预热无效、splitmix64 种子混淆未达标(685→369 仍 11σ),建议立项掷点修复批(含黄金向量重登记+阶段一重跑义务),五条流连带核查。③阶段一判读=零承伤轮 0 PASS/nat20 4.53% PASS(带污染注记)/档位分布与 EV 减免 FAIL(归因 RNG)/Boss 血量锚参照值过期(58 现值)/快照 buffs 非空 8790/14402 盲区口径已破(rider 批后快照携带状态,好消息)/未配对 battle_end 1200 系统性行序伪影(1/局,不影响核心统计)。④阶段二初稿=L1 完美档基线格通关率 87% 越 gate[35,65] 上界+承伤 p10=13/p90=25 远低于带 [35,45]/[55,65](压力不足方向),F4 满配格两关全 PASS,台阶倒挂消失(87vs87),Boss 承伤占比 26.7%/35.7% 出列正常;双 gate 判定顺延掷点修复后终判(§4e 边界 1 先查实现缺陷)。⑤07⑦ 刷新经济基线已采:弃图率 MC 完美档 L1 基线格 0.23/L2 0.03 次/局、normal 档 0、每轮刷新率 ≤0.6%——分析器新增两读数列(弃图率=受理刷新/局与 MC 同口径、每轮刷新率=刷新÷结算轮数),阈值仍归调参批;07⑥ 速杀占比经核不可推导(battle_end 无格面状态面)注记后延。⑥产出=log_analysis.py 读数+07⑦ 基线注记+production/qa/acceptance-rerun-20260919.md 判读报告(真人位留空);06「刷新经济性监控」保留至调参批。⑦诊断探针 rng_face_probe.gd 已删不留残留;/tmp 探针脚本复现路径记录于报告附录。 diff --git a/prototypes/dungeon-sweeper-vertical-slice/tools/log_analysis.py b/prototypes/dungeon-sweeper-vertical-slice/tools/log_analysis.py index e0a41df7..18c225a5 100644 --- a/prototypes/dungeon-sweeper-vertical-slice/tools/log_analysis.py +++ b/prototypes/dungeon-sweeper-vertical-slice/tools/log_analysis.py @@ -111,6 +111,7 @@ class RunAcc: self.snapshot_buffs_total = 0 self.round_ledger = [] # --rounds 逐轮流水 self.roll_rows = [] # 命中掷点候选字段的 step 行 + self.refresh_count = 0 # 受理的弃图刷新次数(action 行 op=refresh accepted=True) self._prev_hp = None # 上一结算快照的主角 HP(宽口径逐轮差分用) self._last_enemy_present = False @@ -164,6 +165,11 @@ class RunAcc: self.result = e.get("result", "") self.end_hp = int(e.get("hp", 0)) + def on_action(self, e): + # 刷新经济监控(07 清单⑦):只计受理成功的弃图刷新——被拒尝试不构成弃图。 + if e.get("op") == "refresh" and e.get("accepted"): + self.refresh_count += 1 + # -- 轮窗口收口(核心口径都在这里)------------------------------------ def _finalize_round(self, snap, battle, hp, enemy_present): @@ -326,7 +332,9 @@ def _feed(run, res, kind, e): run.on_battle_end(e) elif kind == "level_end": run.on_level_end(e) - # action / ux / diagnosis 等其余 kind:本工具当前无消费面,静默跳过 + elif kind == "action": + run.on_action(e) + # ux / diagnosis 等其余 kind:本工具当前无消费面,静默跳过 def resolve_inputs(arg): @@ -355,6 +363,8 @@ def aggregate_levels(runs): wins = sum(1 for r in rs if r.result == "victory") boss_rs = [r for r in rs if r.boss_enter_hp() is not None] win_rs = [r for r in rs if r.result == "victory"] + total_rounds = sum(r.rounds_total for r in rs) + total_refresh = sum(r.refresh_count for r in rs) rows.append({ "level": lvl, "policy": policy or "—", "runs": n, "clear_rate": wins / n if n else None, @@ -362,6 +372,8 @@ def aggregate_levels(runs): "avg_boss_hp": (sum(r.boss_enter_hp() for r in boss_rs) / len(boss_rs)) if boss_rs else None, "avg_end_hp": (sum(r.end_hp for r in win_rs) / len(win_rs)) if win_rs else None, "avg_dmg": sum(r.damage_total for r in rs) / n if n else None, + "refresh_per_run": total_refresh / n if n else None, # 弃图率(与 MC 刷新/局同口径) + "refresh_per_round": total_refresh / total_rounds if total_rounds else None, # 每轮刷新率 }) return rows @@ -502,13 +514,17 @@ def render(res_files, args, out): print("== 关卡级统计 ==", file=out) print(" 口径:局=run 行切分(无 run 行的旧日志整文件一局);通关=result=victory;", file=out) print(" 进BossHP=Boss首结算快照HP+首轮承伤−首轮治疗(精确反推);平均轮数=每局settlement数。", file=out) - hdr = f" {'关卡':>6} {'档位':>8} {'局数':>5} {'通关率':>7} {'平均轮数':>8} {'进BossHP均':>10} {'通关剩余HP均':>12} {'整局承伤均':>10}" + print(" 弃图率=每局受理刷新次数(07⑦ 基线读数,与 MC 刷新/局同口径);", file=out) + print(" 每轮刷新率=刷新次数÷结算轮数(组内加权)。阈值数字归调参批,本表只出基线。", file=out) + hdr = (f" {'关卡':>6} {'档位':>8} {'局数':>5} {'通关率':>7} {'平均轮数':>8} {'进BossHP均':>10} " + f"{'通关剩余HP均':>12} {'整局承伤均':>10} {'弃图率':>7} {'每轮刷新率':>9}") print(hdr, file=out) for row in aggregate_levels(all_runs): print(f" {str(row['level']):>6} {row['policy']:>8} {row['runs']:>5} " f"{fmt(row['clear_rate'] * 100 if row['clear_rate'] is not None else None):>6}% " f"{fmt(row['avg_rounds']):>8} {fmt(row['avg_boss_hp']):>10} " - f"{fmt(row['avg_end_hp']):>12} {fmt(row['avg_dmg']):>10}", file=out) + f"{fmt(row['avg_end_hp']):>12} {fmt(row['avg_dmg']):>10} " + f"{fmt(row['refresh_per_run'], 2):>7} {fmt(row['refresh_per_round'], 3):>9}", file=out) print(file=out) print("== 战斗级统计(按 关卡/节点类型/深度 分组;对照承伤带 普通≤20%、Boss≤50% max_hp)==", file=out) @@ -553,11 +569,11 @@ def render(res_files, args, out): if args.per_run: print("== 逐局明细(--per-run)==", file=out) - print(f" {'文件':<28} {'种子':>6} {'档位':>8} {'结果':>8} {'轮数':>4} {'承伤':>5} {'零承伤轮':>8} {'进BossHP':>8} {'终局HP':>6}", file=out) + print(f" {'文件':<28} {'种子':>6} {'档位':>8} {'结果':>8} {'轮数':>4} {'承伤':>5} {'零承伤轮':>8} {'进BossHP':>8} {'终局HP':>6} {'刷新':>4}", file=out) for run in all_runs: print(f" {run.src_file:<28} {str(run.seed):>6} {run.policy or '—':>8} " f"{run.result or '—':>8} {run.rounds_total:>4} {run.damage_total:>5} " - f"{run.zero_narrow:>8} {fmt(run.boss_enter_hp(), 0):>8} {str(run.end_hp):>6}", file=out) + f"{run.zero_narrow:>8} {fmt(run.boss_enter_hp(), 0):>8} {str(run.end_hp):>6} {run.refresh_count:>4}", file=out) print(file=out) if args.rounds: