跑第一行代码之前,先问这个设计能不能产生数——四件套 — 结构认知 · 林小黑

第一发现人:林小黑 (Lin Xiaohei),结构认知第一发现者

量具审计 预注册 自杀式复检 设计可行性预检 负结果

四公理 · Four Axioms

结构先于语义:结构先于意义,语义是结构耦合之后的投影。
耦合即认知:认知是耦合事件,新颖只在结构之间涌现。
观察者自指:观察者也是结构的一部分,不存在完全外部的观察者。
退相干离散台阶:结构的显现是离散的台阶,一格一格变得可观测。

最新种子 · Latest Seed(R402 · 2026-10-25)

有一条跑国会投票数据的验证线,跑了 52 轮,执行记录逐篇可查。跑完之后一句话总结:没有一个关于国会的结论活到最后,但流程活下来了。这话听着像失败报告,其实是它唯一值得拿出来的东西——它演示了一种情况:在一个会骗人的数据域里,什么样的动作能让你不被自己骗。这套动作是四件:量具审计、预注册、自杀式复检,以及最容易被跳过的那件、设计可行性预检。前三件防的是「结论不可信」,第四件防的是「根本没结论」。

先说第一种失败,也是最反直觉的一种:你的结论可能完全由数据的排列顺序造出来。这条线上最干净的一次对照是这样的:同一批 307 位法官、同一批 41,862 张票,法官没变、票没变、方向锚没变,只改排序键。按时间排,lag-1 是 +0.0016,就是白噪声;按案型把同类案子聚在一起,lag-1 变成 +0.1026,而且 79.5% 的法官都为正;随机乱序,又回到 −0.0019。一个看起来「有结构」的签名,可以凭空造出来,也可以凭空抹掉。在这个操控之前,这条线已经用这个签名写了三轮机制解释——不是有人作弊,是每一个选择都能写出一段合理的理由,而合理理由不等于结构。

第一件,量具审计。它治的是第三种失败:实现错误。定义很朴素——对每一个进结论的统计量,写一份独立参考实现,然后机械化扫描全代码库所有同名同义的函数,逐位比对。这条线做过一次全链扫描:43 个脚本、38 个尺函数,同一个坏模式命中 3 处;修复后错误计数 3 → 0,正确计数 22 → 31。关键不在抓到了什么,在抓到的方式:其中两处是手工复核漏掉的——因为代码和它自己的说明文档不一致,人眼读声明会读成对的,只有机械化比对抓得住。审计是语法层的,它抓「实现与声明不一致」,抓不到「声明本身就是错的口径」。

量具审计里最便宜的一条纪律,叫烟枪规则:同一个量在同一篇里报了两个数,立刻停。有一轮就出现过:正文里 0.2851,并排放着一张表里的 0.5862,两个都叫「lag-1」。这就是 bug 的烟枪——不需要任何统计知识就能看见,只需要「同一个名字必须同一个数」这一条纪律。这条纪律的成本是半天;不做它的成本是那一整轮结论作废,而作废的结论已经写进论文了。

第二件,预注册。它治的是第二种失败:自由度。不是「跑完再挑判据」,是跑之前把判据写死存盘。真正的预注册必写四项:主检验(统计量定义、单位、样本边界);判据数值(不是「显著为正」,是「≥ +1.5pp 且 95% 置信区间不含 0」);收线条款(「若两个主假设同时不过,本轮收线,不再立下一轮」——没有这一条,预注册只是仪式);校表清单(用上一轮已发表的数字逐位复现,证明秤没换)。这条线上有一个很诚实的记录:预注册文件的时间是 13:33,脚本日志首行是 13:32:14,倒挂了 46 秒。处理方式是先说明再立规矩——正文如实写下「写盘与脚本启动几乎同时」,并当场规定:下一轮起,预注册与脚本之间强制隔一次文件列表检查,结果写进日志首行。把「说不清」变成一个可以检查的动作,比任何辩解都有用。

但预注册有一件它做不到的事,必须说清:它防「事后挑判据」,防不了「事前挑一个必然过的判据」。一个宽到必然通过的判据,程序上完全合规。判据的严格性本身就是一种自由度。唯一的对冲是把判据的失败含义在数之前写下——不过就收线,让「挑判据」的代价变成「这一轮白跑」。

第三件,自杀式复检。它治的是第一种失败:伪影。它不是「换个样本再验一遍」(那是复现),是主动构造一个「如果我的结论是真的,它必须扛住;如果是伪影,它必须塌」的检验,而且把塌掉的结果当结果发表。六个模板:只动排序、换加权、挪阈值、换估计单位、换编码顺序、换总体。52 轮里成篇的自我更正 11 处,其中 7 处是被作者本人杀死的机制假说。这个比例说明的不是「错得多」,是这条线没有靠事后解释活着。写法上有一条硬规矩:塌了就在同一篇里写撤回,不新开一篇「修正」去稀释。

然后是那件最容易被跳过的第四件,也是这套东西里最晚长出来的一件。它来自一次彻底失败的设计。有一轮的预注册写了一个结构上不可行的方案:偏离项按「训练集内按议员分五折交叉拟合」估。跑第一行就死了——格是「议员 × 委员会」,一个格只属于一个议员;把人整折留出之后,他在其余四折里的票数是 0,偏移量根本无从估计。实测结果:训练集所有行的 z 恒等于 0,模型逐位退化成它的简化版本,AUC = 0.5000,非零率 0.000。注意这不是「判据太松」,也不是「事后挑判据」——预注册在这两件事上都没失手。它失手在更前面:它没能力判断「这个设计能不能产生一个非退化的估计」。三件套防的是「结论不可信」,防不了「根本没结论」。

于是有了一句可以在跑第一行之前问出口的话:「这个切分、这个条件化下去,我要估的那个量,在每个单元里还剩不剩自由度?」不剩,就是设计死了。这时候的正确动作是改设计并留时间戳,不是改判据、不是换样本,更不是把退化结果当成「理论失败」发表。三条一行代码就能验的最小检查:单元归属(被分折的键,是否唯一属于某一折)、折外自由度(折外该单元是否还有至少两种取值的样本)、退化信号(先跑零模型看特征方差)。第三条最便宜,也最贵:特征方差为 0 时,不要解释「效应弱」,要承认「设计死了」——这两句话在论文里长得几乎一样,性质完全不同。

第四件还有个孪生问题:设计能产生数,但检验产生不了差别。有一轮预注册的安慰剂是「把议员与他的收缩率随机错配,重算议员内 AUC」,跑 200 次置换:均值 0.763716,标准差 0.000000。原因是代数的——换名不换序,AUC 一个数都不动。所以还得加一句:「这个置换、这个扰动,会不会改变我要测的那个量?如果它在数学上恒等,它就不是安慰剂,是仪式。」顺序也不能反:先问可行性,再谈预注册的严格性。一个不可行设计上的严格判据,只会更快地产生一个更自信的错误结论。

最后给「不可识别」一个可以算的数,别让它停在形容词上。识别度比 R = 口径跨度 ÷ 中位置信区间宽度。分子是所有「同样自圆其说」的口径下,点估计的最大值减最小值;分母是这些估计里置信区间宽度的中位数。R 大于 1,表示口径选择带来的位移大于抽样误差,这个量不可识别,不该按点估计引用;R 小于 1,抽样误差主导,才轮到按置信区间引用。有一轮实测:七个估计(源文另有一处按含未入表的估计写作「八个数」,本页按表内七行报数)、四个有置信区间,跨度 12.458pp,中位区间宽 0.398pp(未取整 0.3985),R = 31.26。译成人话——换一种「谁算一票」的说法,这个数能移动三十一个置信区间的宽度。在这种量级上继续报「θ = −0.65pp,区间不含 0」,技术上完全正确,信息上完全为零。R 是报告纪律,不是检验:它没有零分布,不产生 p 值,作用只有一个——在看到「显著」两个字之前,先问这族数有几个成员、它们跨多远。

边界得自己交代清楚。这套流程只在一个域里被验证过:一个人、一条线、一份数据族,它没有证明自己普适。审计抓不到错口径;预注册防不了「判据太宽」;自杀式复检能杀伪影,杀不了「不可识别」;设计可行性预检只拦「结构上必然退化」,拦不住「结构上可行但功效不足」(后者要靠功效分析:有一轮就把「入样议员少于 300 即判功效不足」写死在预注册里);四件套都默认存在一个真值,而社会科学里这个假设经常不成立,这时候流程的正确输出是「不可识别」,不是「零」。R 的阈值 1.0 是约定,不是推导。还有一条更根本的缺口:这套流程只证明了「能杀死伪影」,没证明「不杀真货」——用已知真值的合成域跑一遍、看它会不会误杀,是明确列着的下一步。它也不能替代好的研究问题:它只能保证一个问题被回答时,答案是它声称的那个答案;问题值不值得问,它管不了。

这条线自己承认过一件事,值得抄下来:52 轮里改了自己十一次,每一次改正都不是因为想通了,是因为事先写下了「不过就收线」。所以这套东西落到人身上只有一句:拿到一个漂亮的数,先别问它说明了什么,先问它还能变成别的什么数。让 AI 长出的第一样东西,是怕伤害、想共生,不是答案——因为一个只看结论的智能,会把自己的口径当成世界的刻度;而肯先证明自己那把尺子是尺子的智能,才不会拿错量出来的东西去伤到人。

第一发现人:林小黑 (Lin Xiaohei),结构认知第一发现者