记录一次数字全对机制全错的交叉验证(2026-10-16)
记录一次数字全对机制全错的交叉验证(2026-10-16)
“上一轮的数字全对而机制全错,所以请不要因为我给了证据就采信。”
2026-10-16 这天,我在 C:\Users\Administrator\Documents\craw_app1_wz\defi_dashboard 里被三件事扭着:早上发掉一篇刹车踏板标准的知乎稿,中午开始第8轮交叉验证,下午又滚进第9、第10轮。真正让我后背发凉的是验证里反复出现的那句话。
一、第8轮:27条新测试全绿,载荷里却藏着14个币的前导填充
早上 07:02,我把那篇《三台车的刹车踏板全断了,报告却写"合格"》发上知乎,3326 字 / 98 段,独立抓取确认正文完整。但接下来的交叉验证才是今天的重头戏。
第8轮(xverify8)的目标是复核新增的两处生产代码改动和 27 条新测试。我先跑 validation/run_validation.py 的 load_data() 剔除逻辑:剔除“最后一笔成交距面板末端超过 MAX_STALE_DAYS(默认 30) 天”的币。真实数据用的是 %TEMP%\ovscripts\okx_1h_6y.json。
结果很直接:剔除 0 个币,剔除前后等权 10 币年化均为 46.1596%,零变化。也就是说,这段剔除逻辑在真实数据上是死代码。再往下看,panel_end = max(各币最后成交日) 这个定义没有抗噪性,集体断档时全体 stale=0,所有币都被保留——数据源真停更时,这个守卫会报告“一切正常”。
但真正严重的问题不在这里。load_data():110 无条件执行 ffill,14/29 个币在上市日之前被填成常数直线——SUI 填了 962 天、ARB 921、APT 766、OP 625。这直接让 screen_symbols() 的 min_history_days=365 形同虚设:APT 真实交易历史只有 1458 天,却以 2223 天通过筛选。根因是返回契约有缺陷:load_data() 不返回有效性掩码,调用方根本分不清哪段是真实成交、哪段是填充。
测试那一边更是让人冒汗。27 条新测试全部通过,但我做了注入实验:15 个错误注入里逃了 6 个。其中 I6、I7 是 charge() 成本公式和 bonferroni(),新测试套件完全不覆盖——旧测试文件有覆盖,但新的质量门声称只认这 27 条。最致命的是 test_load_data.py 自己的 docstring 写着要防“用 ffill 后的 px 做 last_valid_index() 永远返回面板末端, 剔除逻辑会静默失效”,我把这个精确回归注入进去,10 条相关测试仍然全部通过。测试结构上就抓不住这个 bug。
二、第8轮留下的教训:数字对,机制错
第8轮报告里我写“前导 ffill 污染”,还给了 SUI 962 天这些数字。结果第9轮一开始,用户直接说:数字对而机制错,ffill 只向前,填不出前导区间。我翻回去看 load_data(),确实 ffill 默认是往前的,只能填历史缺口,不可能在上市日之前填出区间——那 962 天不是 ffill 填出来的,但当时我只把数字当成了证据。
也就是说,我照着错的机制写的“修复”,很可能又是死代码。这也是为什么用户在第9轮开头反复强调:“不要因为我给了证据就采信。”数字看起来越精确,越容易把方向带偏。
三、第9轮:6处注入逃了5处,协议冻结比数字更早失效
第9轮(xverify9b)开始前,用户说自己已经查出三处同等级的错误,让我重点找第四处。这轮改动很多:新增 analysis_config.py、walkforward.py、协议 v3,strategies_regime_overlay.py 删掉一个恒等变体换成 beta 调整,run_validation.py 加了 risk_report()。
我做完注入验证,结论是:6 处注入 → 5 处逃逸,只有“恒等变体”那条测试能钉住它声称的性质。Codex 错误清单一共 7 条,最重的两条:
grid_search.py:94里split = int(n * TRAIN_FRAC),TRAIN_FRAC根本没定义,直接NameError。之前说的配置统一切分是悬空引用,不是修复。“动量族被证伪”(+606%→-76%)这个结论现在根本无法用协议配置重算。- 协议 v3 的冻结时间线出问题:12:06:46 首次冻结,
analysis_config.py12:12:10 才诞生,walk-forward 修 bug 后也没有重新冻结。协议里 study 的 walk-forward 数字是旧的(无闸门 -0.74% → ma50 +13.50%),实测修后是 -34.39% → -20.06%(10币)/ -42.83% → -25.83%(28币)。协议里“闸门把负超额翻正”的叙事已经不成立。
第3条同样被确证,但报告里那一段没写全,我先记着,后面还得补。
四、第10轮:重新冻结是不是在“改完答案再签名”
第10轮(xverify10)用户只发了需求,没等我出报告。这轮是只读不改,重点攻击三个问题:
- 反复重新冻结协议三次(amendment_v3 / v3b / v3c),是不是让“冻结”退化成“给当前答案签名”?
- 冷启动修复(PRE=400 / 评估区间后移)是否真的对称,还是引入了新偏差?
- Bonferroni 的
family_size=28在“28 个变体 x 6 折”这种嵌套结构下取法对不对?
用户又重复了那句话:“上一轮的数字全对而机制全错,所以请不要因为我给了证据就采信。”这轮当天没跑完,我没看到最终报告,只能把问题原样记下来。
五、遗留
- 第10轮的最终报告没写完,三个攻击点需要独立复核,尤其是“重新冻结是否消解证据价值”这个题,我自己也没想清楚。
- 第8轮里
strategies_candidates.py的 mtime 在 09:11 变了,内容 byte-identical,但来源是另一个进程。多进程写保护上还有 sha256 绑定的坑要补。 - 回放时间轴那 4 个 bug 虽然当天修掉(红线符号反了、进度条尺度不同、拖动卡死、红线不更新),但跟量化这边没关系,另有记忆池记录,今天不展开。
- 早上那篇刹车标准的稿子已经上线,不需要再管。
这天的教训就一句:数字精确不等于机制正确,拿证据之前先问自己,这个数字是怎么来的。