十四个开关 · 路线图2026-09-07六个洞 + 第十至十四份 · 产业表开始往下走

补洞与新开关

九份全部建成之后,剩下的事分成两半:这九份自己还漏着的六个洞, 以及要不要有第十份、如果有该是谁。两半的判据不一样——前一半看的是「闸门能不能骗过去」, 后一半看的还是那条老判据:如果 1950 年有人证明它不可能存在,今天少的不是一点速度,是一整个行业。

六条里已经补掉四条(①②④⑤,同一天)。两件值得单说: ① 在补的过程中当场抓到六处问题,其中一处是页面上的数本身就是错的, 而旧闸门那条断言在空转——验的是一个恒真的等式; ④ 则根本不是这一页原来写的「哑雷」,它已经炸了—— dist/ 里 11 个页面的 <body> 全是空的,只是浏览器替它兜住了。

这一页上关于代码的每一条都是现查的。①②④⑤ 补完之后的状态:
npm run check → 250 条断言 · 0 失败(补之前 75 条)
12 个页面 · 97 个键 · 159 处引用
IntersectionObserver → 7(补之前 0) ·  dist 每页 <body> → 19~20 KB(补之前 0)
dist 每页 og 标签 → 12 条(补之前 0) ·  分享卡片 → 13 张 1200×630
浏览器那关 → 37 条断言 · 42 个键闭环  ·  LICENSE → MIT + CC BY 4.0
第十至十二份已建成 —— 一致性哈希(4 处)+ 拍卖与匹配(2 处)+ 分布式一致性(1 处), + FM-index(2 处)+ PageRank(1 处),被打回的总数 27 → 37。⇒ 上半那三个类别缺口全填了

上半 · 这九份自己漏着的

六个洞,按值钱程度排

前两条是真正重要的:①是正确性,②是这个项目最独特的资产没有入口—— 都已补。后四条是工程卫生,④⑤ 也补了。六条全补完了,同一天。

闸门第二关是字符串匹配,不是数值核对

scripts/check.mjs + check-browser.mjs · 2026-09-07 两半都补完
已补

旧闸门里,页面 JS 改坏了、运行时算出别的数,它照样绿——只要正文那句话还写着原来那个数。

当时的毛病,两条 synced() 做的是 src.includes('109 倍'):验的是「正文里写着这个字符串」, 不是「页面运行时算出这个数」。第二条更阴——硬串很脆, '0.45m ~ 0.60m''∛机器精度' 这类排版一改就失配, 而一条断言消失只是少一行绿,不会红
做法 正文里的每个数改成槽位:<b data-fact="dh.gap">65536 倍</b>, 由页面自己那份实现在运行时填,同时挂到 window.__facts。 闸门按键 → 值核对,并检查没有孤儿槽位(加了 data-fact 却没人验)。 两个方向都做过反向测试:改错数字 → 红;加槽位不验 → 红。
结果 主闸门 75 → 137 条断言,零依赖,几秒钟跑完。 后半也做完了npm run check:browser 真开一个浏览器, 读 window.__facts,把「运行时算出来的数」和「页面上写着的数」对上—— 37 条断言、42 个键在真浏览器里闭环。⇒ lib 值 == 静态初值 == 运行时值,三者相等。 它单独一个 CI job,主闸门保持零依赖
第五关开起来抓到的第一个东西

05 卡尔曼那页在浏览器里抛 getS is not defined——registerFacts() 整个异常, 两个 fact 从来没登记上,而静态闸门一直是绿的:它只看得见初值。 这正是这一关存在的理由,而它抓到的第一个受害者是我自己前一天写的代码。 顺带它还把「页面报错就红」变成了一条断言 —— 在这之前,九个页面里任何一个 JS 抛异常都只能靠肉眼发现。

补的过程中当场抓到六处,其中一处是页面上的数本身就错了。

抓到什么性质
03 正文「差 47000 倍」是错的,真值 65536(= 2¹⁶)。 而旧断言 near(2¹⁶, 65536, 1) 恒真——标签挂着 47000,验的却是个恒等式, synced 再确认页面上写着这个串 闸门空转新的一类
02 正文公式 255q + 2√(255q) < 16 解出来是 3.8%,页面写 3.6%。 3.6% 对应的是 Z ≈ 2.211(「74 个码字全成功」那个分位数);闸门里则手抄了 x = 9.2 当「解」 公式和它自己的数不自洽
09 正文那七个数(区间 + 六个值 + 0.15m)页面运行时根本不算,是一次性实验手抄的; 闸门只卡了 0.35 < r < 0.70 这条两边都能过的松带子 手抄 + 松带子
04 三处漂移:33.5→33.7、19.5→19.6、7.8→8.0。 旧断言是 near(ratio, 33.5, 2.5) 这种容差带,正文那个数从来没被真比过 实现漂了,正文没跟
05 67 米 → 68 米,同上 同上
08 1906 ms / 31.0 倍 / 2.0 倍 三个数之前没有任何东西在验, 只有字符串核对。现在真跑了——数是对的 无人验(结果无恙)
最该记住的一条

设计文档里那 21 处订正分 A 类(结论错)和 B 类(测量脏)。03 这一处是第三类:闸门自己空转。 断言写得像在验,实际验的是一个恒等式。它比 B 类更隐蔽——B 类至少给出一个看起来正常的错数字, 而这一类连看都没看。

还留在弱一档的

这些 lib/ 没算,仍然只有字符串核对(闸门里都标了 ⚠): 04 摇镜三档(1.91 / 1.39 / 1.01)、05 隧道三个数(11.8 / 314 / 34)和四配置 σ 比、07 的 0.076、06 的「d = 4」。

那二十一处订正,应该是首页第一入口

design/corrections.html · 2026-09-07 已补 · 现在是二十七处
已补

九份演示网上有替代品(没这么较真,但有)。「我预期错了,这是被打回的记录」——没有。

做法 独立成页:每一处摊开成「我以为 / 实测是 / 为什么会错」,并标出是哪一道关抓到的。 首页顶部第一个链接,页脚也指过去。原来的两类之外多了一类,是补第 ① 条时抓出来的:
靠什么抓
A 类 13 处结论错了拍的定性判断被真数打翻,错得显眼 先写下预期再实测——不写下来就没有「被打回」这回事
B 类 8 处测量本身不干净给出的是一个看起来完全正常的错数字 同一件事用两份独立实现各算一遍
C 类 6 处检查在空转断言写得像在验,实际什么都没看 把手抄的数换成槽位,由实现在运行时填
顺带收掉的一个洞

index.html 以前完全不在闸门视野里(check.mjs 只读 switches/),已经漂了四处: 闸门条数还写着 75、04 卡片 33.5×/19.5×、05 的 67 米、09 的 0.45m ~ 0.60m、页脚「二十一处」。 ⇒ fact 机制改成全局键模型:一个键一个值,出现在哪个页面都必须一致, 覆盖 12 个页面、43 个键、67 处引用。最后一节验首页写着的断言条数 —— 加或删一条断言就得改 index.html,否则闸门红。这是故意的。

分享层是空的

13 个页面 · 2026-09-07 已补
已补

九份都做成了 Artifact 形状、明摆着是给人转发的,转出去却只有一条光秃秃的链接

做法 13 个页面各写一句 <meta name="description">,build 从 <title> 和它派生出 og:title / og:description / og:type / og:site_name / og:locale 和 twitter 那三条。⚠ 首页以前是原样复制的(它自带骨架标签),那样它拿不到 og—— 现在剥掉骨架走同一条路,13 个页面一视同仁。设了 SITE_URL 还会补上 og:urlcanonical
⚠ 顺带堵掉一个陷阱 <meta>挂不了 data-fact 槽位 ⇒ 描述里一旦写进实测值, 它就成了下一处会漂而且没人验的数。所以闸门加了一条: 描述里出现任何一个 fact 值就红。十三句描述因此都是定性的。
那张图也有了 npm run shots 用同一个浏览器给每页截一张 1200×630 存进 assets/og/, build 拷进 dist/og/ 并挂上 og:image,卡片升成 summary_large_image截的就是页面顶部那一屏——eyebrow + 标题 + 一句 thesis + 总闸 + 活着的演示, 本来就是为「一眼看懂」设计的,页面改了重截一次就同步,不会变成又一处手工维护的东西。 ⚠ 闸门只验它在不在、尺寸对不对,验不了内容新不新

build.mjs 的切割点

scripts/build.mjs · 2026-09-07 已补
已补

⚠ 这一页原来把它写成「加第十份时会踩的哑雷」。说轻了——它已经炸了。

实况 body.replace(/^…(?=<div class="wrap">)/, '$1')把匹配到的前缀换成它自己,于是 head 等于整个 bodybody.slice(head.length) 切出来是空串。 dist/ 里 11 个页面的内容全在 <head> 里,<body> 是空的。
为什么没人发现 浏览器会自动纠错:在 <head> 里遇到 <div> 就隐式关掉 head、开 body, 把内容重新挂对地方,所以站点看着完全正常。 而 CI 唯一那条检查只看首行有没有 doctype,照样绿。 ⇒ 它和第 ① 条抓到的 C 类是同一种病:一个看着在验的检查,验的不是它声称的那件事。
做法 显式匹配切割点,build 里当场断言三条:切出来的 <body> 不少于 500 字符、 <title> 必须落在 head 那一半、找不到容器直接抛错 (加第十份换个类名会立刻失败,而不是静默塞进 head)。CI 另加一条独立复查。

20 处 requestAnimationFrame,0 处 IntersectionObserver

七个页面 · 2026-09-07 已补
已补

画布滚出视口照跑,同页离屏的动画没有任何东西会停下它——读底下那四张卡的时候,画布全在屏幕外。

做法 七个带 rAF 循环的页面(02 和 09 本来就没有)各加一个 IntersectionObserver: 观察本页所有画布,一张都看不见就停循环,回到视口再接上。 只关动画,不碰任何数字——fact 都是加载时就算好的。

没有 LICENSE,index.html 有个没写下来的例外

仓库根 · 2026-09-07 已补
已补
许可证:拆开 代码lib/ scripts/ .github/)走 MIT内容(九份页面、设计文档、被打回的记录、分享卡片)走 CC BY 4.0。 拆的理由写在 LICENSE 头一段:那九份的价值不在代码上,在那些被实测打回的结论上—— 代码希望被随便拿去用,结论希望被引用时说一声出处。 末尾附了一句请求(不是许可条件):引用页面上的数,请连它的条件一起引, 单拎一个数字出来正是这个项目从头到尾在反对的事。
那个例外:直接消掉,不是记下来 index.html 原来是唯一带骨架标签的源文件,build 得特判它、CI 那条检查对它开口子。 现在它也是 Artifact 形状了,13 个源文件走同一条路,没有例外了—— build 里那段剥骨架的正则也一并删掉。

下半 · 第十份该是谁

缺口在类别上,不在题材上

九份在题材上覆盖得不错。但它们全是同一种论证形状: 同一个问题,换掉一行,计算代价爆炸。有三整类产业级算法,这个形状套不上——所以一个都没进来。

缺的类别它的「关掉之后」是什么现有九份为什么覆盖不到
激励 / 机制设计拍卖 · 匹配 不是算得慢,是参与者开始撒谎,市场散架 九份里没有一个有「多个各有自己利益的参与者」
分布式一致性 / 容错Paxos · Raft · 2PC✓ 第 12 份 不是慢,是两个人同时以为自己是对的 九份的尺子全是「多少次 / 多少字节」,没有「多少次分歧」—— 现在有了
索引 / 数据结构B 树 · 倒排 · FM-index✓ 第 13 份 不是算法变慢,是数据规模的天花板整个塌下来 尺子该是内存字节和磁盘页数,九份一把都没用过

候选池

创造了新产业的算法

按经济体量排。⚠ 量级一栏是公开口径的数量级,不是实测数字—— 这一页上唯一一处不能用闸门验的数据,标出来。绿底三行是下面详写的三个。

算法它凭空造出来的产业量级一行开关
A 广义二价拍卖 GSP / VCGVickrey 1961 → AdWords 2002 搜索与展示广告——把注意力变成了一个可以清算的市场 ~3000 亿
美元/年
二价换一价 → 出价互相试探、震荡,收入和效率一起掉
B PageRank / 幂迭代Page & Brin 1998✓ 第 14 份 网页搜索本身——是 A 的前提 同上 特征向量迭代换回词频排序 → 前十全是灌水页
C ★ 一致性哈希Karger 1997 CDN 与云缓存——Akamai 1998 就是照着这篇论文开的公司 云基础设施
的一层
hash%N 换成环上取后继
D Paxos / Raft + 两阶段提交Lamport 1998 · Ongaro 2014 云数据库、几乎所有多副本存储 同上 关掉多数派确认 → 分区时两个 leader 同时写,钱花两遍
E B 树 + 基于代价的查询优化器1970s 关系数据库产业 千亿级/年 走索引换全表扫描:磁盘页 logBN → N/页
F 收缩层次 CH / A*Hart 1968 · Geisberger 2008 导航、网约车、即时配送、物流调度 千亿级/年 关掉 CH 退回 Dijkstra:洲际路网上 settle 的节点数从几百跳到千万
G 注意力 / Transformer2017 现在这一波 已经很大
且在长
换回 RNN 的顺序依赖:每样本串行步数 O(1) → O(n)
H ★ BWT + FM-index2000 → BWA / Bowtie 2009 基因组测序服务业——「千元基因组」里,比对这一半是算法给的,不是化学给的 数百亿/年 后向搜索换回逐位置扫描
I ★ 稳定匹配 Gale–Shapley1962 · 2012 诺贝尔经济学奖 住院医师分配、校位分配、器官交换 不以营收计
但是真人的一生
延迟接受换成先到先得 → 屏幕上当场冒出想互换的配对
J 概率数据结构Bloom 1970 · HyperLogLog 2007 大数据与实时分析这一层 中等 精确去重 10⁹ 个 id:几 GB → 12 KB,尺子是内存
K SHA + Merkle 树Merkle 1979 加密资产(争议大) 万亿级市值 去掉 Merkle 证明:验一笔交易要下整条链,log n → n

如果只加一份

三个候选,照六个字段填一遍

规矩没变:关掉的必须是一行不是一个概念、永远两把尺子、每一个都要给反例。 填不满这六格的题材就不该做——下面三个都填得满。

C

一致性哈希

Karger et al. 1997 · 2026-09-07 已建成 · switches/10-chash.html
已建成

关掉它,每加一台缓存机器,整个互联网都要回源一次

关掉哪一行 server = hash(key) % N 换成「把节点和键都散在一个环上,键顺时针找第一个节点」。一个表达式。 键的分布、哈希函数、节点数滑块全不动。

关掉

节点数从 8 拖到 9 的那一瞬间,左边网格里 87.5% 的格子同时变红—— 这些键全部换了机器,缓存全失效,全部回源。

打开

同一个动作,右边只有 11.1% 变红,而且变红的全是相邻的一段弧—— 新节点只从它的后继手里接走了自己那一段。

尺子 A机器无关

加一个节点时被重映射的键的比例 ⚠ 这一栏原来写的 87.5% 是错的(把 N 当成了旧的节点数),实测见下

取模N/(N+1) = 89.0% 一致性哈希11.8% 7.5 ×
尺子 B体感

扩容那一刻的回源带宽尖峰 · 这次扩容要不要停服

取模源站被打爆 · 得挑凌晨 一致性哈希照常滚动上线
啊哈瞬间

这条闭式解不需要跑就能证,而它是一家公司的全部立论: Akamai 1998 年成立,招股书里那个技术就是前一年这篇论文。 一个取模换成一个环,撑起了今天整个 CDN 行业。

建成之后 · 三处预期被实测打回 ① 取模「87.5%」→ 89.0%(闭式解是 N/(N+1),我把 N 当成了旧台数)。 ② 「1/(N+1) 是理论下界」→ 它是期望,不是下界:N=16 实测 5.7% 低于 5.9%。 站得住的是一句更强的话——搬家的键恒等于新机器接管的键,一个都不多(逐键数过,搬去别处的是 0 个)。 ③ 「取模负载几乎完美」→ 它是 √(N/K),N=64 时 3.65%。 外加一处测量脏:用 N=8 量 1/√V 律,8 个样本算变异系数量出的是噪声,换 N=64 才干净。
⇒ 页面上真正的头条不是 89% 对 11.8%,是 取模搬的里面有 77.8% 是白搬—— 老机器之间互搬,没有任何理由。
它什么时候不赢

节点少的时候环上分布很不均,朴素一致性哈希的负载方差比取模还差—— 得靠虚拟节点补回来。让用户把「每节点虚拟点数」从 1 拖到 200,看着负载柱状图从参差不齐变平。 这个反例最好,因为它说清了这个算法真正的前提:它买的是「变化时的稳定」,代价是「静态时的均匀」。

I

拍卖与匹配

Vickrey 1961 · Gale–Shapley 1962 · 2026-09-07 已建成 · switches/11-mechanism.html
已建成

关掉它,市场不是变慢,是所有人开始撒谎

关掉哪一行 成交价从「第二高价」改成「你自己的出价」(拍卖那半), 或者把延迟接受的「暂时持有、可被更好的申请挤掉」改成「先到先得、一旦接受不再反悔」(匹配那半)。 参与者的真实估值、到达顺序全不动。

关掉

一价拍卖里出价开始互相试探、来回震荡,没人再报真话; 先到先得的匹配里,屏幕上当场冒出一堆互相想换的配对——两边都觉得跟对方换更好,但换不了。

打开

二价下照实报价成了每个人的最优策略,出价曲线一夜之间躺平; 延迟接受跑完之后,阻塞对为 0——这是可以逐对枚举验证的,不是宣称。

尺子 A机器无关

阻塞对的个数(枚举全部配对可验) · 出价偏离真实估值的幅度

先到先得阻塞对 > 0 延迟接受阻塞对 = 0
尺子 B体感

这套规则真的在管什么

全美住院医师分配 · 校位分配 · 肾脏交换链
啊哈瞬间

前九份都是「人和机器」,这一份是人和人。08 拥塞那份已经摸到了这条边 (「AIMD 是一份社会契约,不是一条物理定律」),但那份里作弊者只是个开关,没有真的均衡。 而且大多数人对二价的直觉是错的——「报低一点更划算」会被实测当场打脸,第 6 条规矩天然满足。

建成之后 · 两处预期被实测打回 ① 这一页原来写「一价出价互相试探、震荡,收入和效率一起掉」——两样都没掉: 收入 0.6664 对 0.6667(收入等价定理),效率都是 100%(同比例压价保序)。 ② 「出价会震荡」是学习过程的现象,不是机制的性质。
⇒ 论点因此换掉了:二价买的不是钱,是「不用猜」—— 二价的最优出价永远是 1.000 × v,一价从 0.484 × v(2 人)爬到 0.947 × v(20 人), 对手多一个就得重算一次。和 08「关掉 AIMD 吞吐一点没变,塌的是公平」是同一种形状。
它什么时候不赢

⚠ 这一条必须说,否则整份演示就是在骗人:二价的「说真话最优」只在单物品下成立。 真实的搜索广告是多个广告位的 GSP,它不是 VCG,均衡里照样要压价。 另外延迟接受只对提出申请的那一方最优,另一方拿到的是它可能得到的最差稳定解—— 「谁提亲」这个看似无关的选择,决定了利益归谁。

H

BWT 与 FM-index

Burrows–Wheeler 1994 · 2026-09-07 已建成 · switches/13-fmindex.html
已建成

关掉它,「千元基因组」里便宜下来的那一半根本没发生——测序仪读得再快,也没人比对得完。

关掉哪一行 把 FM-index 的后向搜索(每次一个字符,两次 rank 查询,把候选区间往里收) 换成在 3×10⁹ 个碱基上逐位置比对。同一条 read,同一个参考基因组。

关掉

一条 100bp 的 read 要扫过整条染色体。一次 30× 全基因组有十亿条 read, 进度条上的预计完成时间以计。

打开

同一条 read 一百来步就定位完了——步数只和 read 长度有关, 和基因组多大完全无关。而且那个索引比原基因组还小

尺子 A机器无关

定位一条 100bp read 所需的字符比较次数 · 以及索引占多少字节

逐位置扫描正比于 3×10⁹ 后向搜索约 100 步 · 索引 < 原文
尺子 B体感

一次 30× 全基因组比对的机时

关掉以周计 打开以小时计
啊哈瞬间

一个为压缩而生的变换,顺手成了一个索引。BWT 1994 年被造出来是为了让文本更好压 (bzip2 就是它),六年后有人发现那个压缩过的东西本身可以直接被搜索,不用解开。 测序成本这些年掉了六个数量级,通常全算在化学头上——有一半在这里。

它什么时候不赢

后向搜索只认精确匹配。错一个碱基,区间当场空掉。 Illumina 那种 0.1% 错误率还能靠回溯硬撑,换成纳米孔那种 5%~10% 错误率的长读长, 这个策略直接失效——所以现代长读长比对器回到了 minimizer 加动态规划的种子延伸路线。 它买的是「精确匹配下的对数时间」,这个前提一旦不成立,优势归零。

建议的动手顺序

按「先补正确性,再补传播,最后才加内容」排。第十份是可选的—— 六个洞补完,这九份就已经比现在结实一档。第一条已经划掉了。

  1. ①②③④⑤ ✓ 已完成 主闸门 75 → 137 条,键→值核对覆盖 13 个页面;二十七处订正独立成页并挂上首页; build 的空 <body> 修好并加了断言;七个页面离屏停动画。 ⇒ 这九份现在比一天前结实一档。
  2. ⑥ LICENSE ✓ 已完成 MIT(代码)+ CC BY 4.0(内容),拆开的理由写在 LICENSE 头一段。 顺带把 index.html 那个「唯一带骨架标签的源文件」例外直接消掉了—— 消掉例外比记下例外好
  3. ① 的后半:puppeteer 那一关 ✓ 已完成 npm run check:browser:37 条断言、42 个键在真浏览器里闭环,外加「页面报错就红」。 依赖只装在这一支,主闸门仍然零依赖、几秒钟跑完,CI 里两个 job 分开。 ⚠ 它开起来抓到的第一个东西,是我前一天写的代码(见 ① 那条)。 同一个浏览器顺手把 ③ 差的那 13 张 og:image 也截了。
  4. ⇒ 六个洞全补完,只剩第十份 这一页原来列的六条,加上 ① 的后半,同一天全做完了。 下面这条是唯一还开着的,而它是加东西,不是补洞。
  5. 第十份:一致性哈希 ✓ 已建成 switches/10-chash.html:65 536 个键按哈希顺序铺成一张图, 加一台机器,取模那边 89.0% 变色、环那边 11.8%。 三处预期被实测打回,全部留在页面上。 ⇒ 第十一份也建成了,见下。
  6. 第十一份:拍卖与匹配 ✓ 已建成 switches/11-mechanism.html前十份关掉的都是「机器算得动」,这一份关掉的是「人肯说真话」。 ⚠ 它把自己的论点也推翻了一次——关掉二价,收入一分没少(收入等价定理)、效率一点没掉, 塌的是「你必须知道多少东西才出得了价」。 ⇒ 第十二份也建成了,见下。
  7. 第十二份:分布式一致性 ✓ 已建成 switches/12-consensus.html:一行开关 —— 提交前要不要等 q 台确认。 关掉之后 39.9% 的已提交条目是分叉的(同一个位置两个值); 分歧恒为 0 当且仅当 2q > N,枚举 55 对子集验过,一对不相交的都没有 —— 一致性靠数数保证,不靠通信。 ⚠ 它又抓到一处 B 类:我第一次用「集群可用率」量代价,量出 100%,把代价整个盖住。 ⇒ 上半那三个类别缺口全填了;再往下就该从产业表里挑(B PageRank、D 两阶段提交、E B 树、F 最短路、H FM-index…)。

⚠ 一个反面提醒:G 和 07 撞格子

注意力 / Transformer 虽然是十个候选里最热的,但它和 07 梯度那份撞位置—— 两份都会落到「AI 为什么可能」这一句上,而 07 已经占了。

真要做,切入点必须换成并行性而不是算力:关掉的是「一次能看全序列」, 换回 RNN 的顺序依赖,尺子 A 是每个样本的串行步数(O(1) 对 O(n)), 体感是「GPU 喂不满」。这和 07 那份的「梯度要算多少次前向」是两件不同的事, 说不清这个区别就不该做