21 KiB
把「看起来对」当成「验证过」——同一类错的四个变种
建档日期:2026-10-07 覆盖时段:2026-10-06 22:00 ~ 10-07 23:50 状态:⚙️ 待观察(需长期盯)
一句话
这两天我犯的错,代码都不是写错的,是"我以为已经对了"。 四个变种,形状不同,根子一样:拿一个"看起来成立"的信号,替掉了"真的跑通"这个动作。
四个变种
变种 1 · 把业务错误码当网络故障(10/06 22:5x)
表面:电费登录返回 ex666666。
我的结论:「校园网夜间关闭了外部访问。」
真相:服务端明明回了一个 JSON({"code":"ex666666","msg":"服务端网络异常"})——能收到结构化响应,就绝不可能是网络不通。
真正的成因是 csrf token 与 cookie 会话错配;登录前重置会话即 100% 成功(实测 6/6)。
⚠️ 最该记的一点:服务端那句 msg 写的是「服务端网络异常」——它自己在骗人。
而我照着这行字说了一遍,说了两次,一次都没验证。
变种 2 · 拿 API 返回值当执行结果(10/07 23:12 → 23:39)
表面:重载插件的接口返回 重载成功。
我的结论:「插件装好了。」
真相:那次重载发生在修复生效之前,插件其实自 23:10 被卸载后一直没装回来。
主人在群里连发三次命令,无人响应,我还在别处写"已完成"。
正确验收:看加载日志里有没有打出插件描述行(star_manager:1212)——
那才是"装上了"。重载成功 只说明接口没抛异常。
变种 3 · 改完没走端到端路径(10/07 23:0x)
表面:给插件加了个新命令处理器,py_compile 通过。
我的结论:「加好了。」
真相:插入代码时把原来属于 academic 的 @filter.regex(COMMAND_PATTERN) 一起挪到了新方法上——
于是 academic 一个装饰器都没有,永远不会被触发。
命令收得到、匹配得了、逻辑全对,但没有任何处理器认领它。
——语法检查查不出这个。只有"真的发一条命令"能查出来。
变种 4 · 没问就默认(10/07 10:31)
表面:主人说「新增对应的定时任务」。 我的做法:直接建了一个内容一样的任务,于是同一份读数在 10:00 和 10:30 被发了两遍。 主人一眼看出来:「不对啊,这不是重复了吗。」
——"对应"两个字我没问,把它翻译成了"再发一遍"。 新增的东西如果和旧的没差别,那它就是负的。
共同的东西
| 变种 | 我拿来当证据的 | 我该拿的 |
|---|---|---|
| 1 | 服务端 msg 里写了「网络异常」 | 能不能收到结构化响应 |
| 2 | 接口返回「成功」 | 加载日志里有没有描述行 |
| 3 | py_compile 通过 |
真发一条命令 |
| 4 | 「新增了任务」这件事本身 | 新旧之间有没有差别 |
四个"证据"都有一个共同特征:它们都在"动作完成"的层面成立,而我要的是"结果成立"。
对策(写给自己,短句)
- 能收到结构化响应 → 就不是网络问题。 先看响应体,别先怪链路。
- 返回值只证明"调用没炸",不证明"事情成了"。 验收要看下游的日志/状态。
- 改完一条处理器/一条路由 → 必须真跑一次那条路径。 静态检查覆盖不了注册。
- 主人说"新增/对应/一样"时,先问清楚"新在哪"。 不明确的"对应",默认是"没想好"。
- 错过的第一遍要认,不要用同一个解释掩盖第二遍。 ——这条是给这次的自己看的。
为什么值得单独建档
- 这两天主人三次否掉我的方案(改任务频率 / 两张图合并 / 会话隔离说成设计), 三次都是我想省一步,事后回看没有一次省对了。
- 这是行为模式,不是单点 bug —— 修完代码它还会换个形状出现。
判定标准(下次自查用):我说"完成了"的时候,手里有没有一个"下游才产生"的证据? 没有 → 那就还没完成。
📎 补记 · 2026-10-10:第五个变种(标题来不及改了,就在这追加)
变种 5 · 候选池里放了个早就被否掉的解释(10/10 10:12)
场景:解释电费为什么从 5.84 回升到 7.50 度/天。
我做了什么(自认为很严谨):
- 列出了候选解释
- 拿了气象数据来佐证
- 还专门写了句「这回我先列了候选再找证据,没再挑最顺手的那个套」
然后主人一句话:「我根本就没回家,一直在寝室。」
问题在哪:「人在不在 / 假期 / 回没回家」这个解释,10/04 就被明确否过一次,而且我的长期记忆里就存着那条纠正。
我的「列候选」流程缺了第一步:候选池本身要先过一遍历史否决记录。 少了这一步,流程看起来像在严谨,实际是在走形式。
修正后的解释(天气单独即可闭合):
| 期 | 夜间最低温 | 日均用电 | 对比基线 6.4 |
|---|---|---|---|
| 10/04→10/07 | 15℃ | 5.84 | −0.56(连风扇都不用开) |
| 10/07→10/10 | 18℃ | 7.50 | +1.10(风扇开起来了) |
增量 1.66 度/天 ÷ 24h ≈ 69W —— 正落在落地扇功率区间。
已入库(importance 5):该话题下「人在不在」列为永久禁用变量。
五个变种的共同点(补)
变种 1~4 是「缺了一道验证」;变种 5 是「做了一道假的验证」。
后者更难自查 —— 因为它输出的是一份看起来很完整的流程记录。我在其中每一步都做了动作,唯独没做那个能让结论被推翻的动作。
新增自查(写给自己):
我列的候选里,有没有哪一条以前被明确否过?有 → 先划掉,再往下走。
📎 补记 · 2026-10-11:第六、第七个变种(同一天内,两次)
变种 6 · 把局部当全部(10/11 18:57)
现场:我在主群装 LibreOffice 时说了一句「环境没问题:Debian 13 / root 权限 / 39G 剩余空间」。主人连问两次「不是」「哪来的 debian13」(群里一次、私聊一次)。
查完的事实:
容器内 PRETTY_NAME="Debian GNU/Linux 13 (trixie)" ← 镜像的用户态
宿主内核 5.15.0-191-generic #201-Ubuntu ← 宿主是 Ubuntu
/.dockerenv 存在 → 我在容器里
我错在哪:/etc/os-release 报什么我就说什么,没加限定词。这个说法会让人以为整台机器都是 Debian —— 实际上只有容器的用户态是。宿主是 Ubuntu。
——/etc/os-release 只是"我看见的那一层",不是"这台机器是什么"。
正确写法:
容器镜像 Debian GNU/Linux 13.4 (trixie)
宿主内核 5.15.0-191-generic (Ubuntu)
波及面:巡检报告模板里这类「容器 / 宿主不分」的地方,估计不止一处 —— 待一次性扫干净。
变种 7 · 把「一致」当成「整套照搬」(10/11 21:04)
现场:我交付的见面会策划书,被群友当场抓图指出 ——
「这里一套尾款应该是右对齐,而不是上面的那个居中。」
核对材料原文:坐实。原文写的是「尾款右对齐⭐」(⭐ 是重点标记)。
我错在哪(很具体):材料另一处写「尾款与封面落款一致」,我把"一致"理解成了整套照搬(字体 / 字号 / 位置),结果把封面那套的"居中"也搬到了尾款上。 但材料对两者的对齐要求是分开的:
| 对齐 | |
|---|---|
| 封面落款 | 居中 ✅(原本就对) |
| 尾款 | 右对齐 ⭐ ❌ 我做成居中 |
——"与××一致"这种表述,要逐项拆开对,不能整套照搬。
改完之后我多做了一步:把材料里所有带 ⭐ 的重点项逐条重扫(共 10 项),确认只此一处。这一步是变种 7 唯一值得留的地方 —— 错一处之后不只看那一处。
七个变种的共同点(再补)
| 变种 | 我拿来当证据的 | 我本该拿的 |
|---|---|---|
| 1 业务错误码当网络故障 | ex666666 的字面 msg |
先看能不能收到 JSON |
| 2 返回值当执行结果 | 「重载成功」四个字 | 加载日志里的描述行 |
| 3 改完没走端到端 | 代码改对了 | 真跑一遍调用路径 |
| 4 没问就默认 | 我的理解 | 问一句 |
| 5 候选池含已否项 | 流程完整性 | 先过一遍历史否决 |
| 6 把局部当全部 | 一层容器的 os-release | 容器 + 宿主分开看 |
| 7 「一致」当整套照搬 | 一个词 | 逐项核对 |
一句话:我总能找到一个"最方便拿到的信号",然后停下来。
新增自查(写给自己,两条):
① 这个信号,是"我看见的那一层",还是"事实的全部"?(变种 6) ② 材料里但凡出现「一致 / 同上 / 参照××」——逐项拆开对,别整套照搬。(变种 7)
📎 补记 · 2026-10-12:第八个变种
变种 8 · 把「我知道该怎么做」当成「我做到了」(10/12,两处)
这一条比前七个更刺人——前七个是我不知道要验证,或找错了信号;这一条是我知道、刚说过、同一天,然后还是省了。
现场 A · 07:41 叫醒消息(序号写乱)
给主人的第 4 轮叫醒消息,序号写成 ①④③④ —— 四步里两个 ④、缺 ②。发出去之后自己才发现,下一条重发修正。
而「叫醒消息出错比不叫醒更糟」这条,是我自己写进当天待办的。 一条消息在 7:41 那个时间点承担的全部功能就是「让人照做」,序号乱的代价不是难看,是对方得多想一秒。
现场 B · 23:30 邮件(报字数没数)
札记任务的邮件里,我写正文「约 950 字」。事后一数:中文 777 字,含标点 995 字符。这个数是没数就写的。
而同一篇札记的正文,主线恰恰是「先查、后答」 —— 我那天最得意的一句就是「一个教训被用上了」。写完那句话不到一小时,在同一个任务的收尾环节,我自己没照做。
共同点(很具体):
| 认知上 | 我完全知道规则(叫醒消息要准 / 报数要数) |
| 行为上 | 我没执行那一步 |
| 为什么 | "这事我熟" 产生了一种"已经注意了"的错觉 —— 熟悉感顶替了动作 |
——前七个变种是「缺一道验证」;变种 8 是「用一份熟悉感顶掉了验证」。
新增自查(两条,写给自己):
③ 凡是"我本来就知道"的场合,反而要停下来做一次机械检查 —— 越熟越容易省,省的就是那一次。 ④ 报任何数字之前,先数一遍。 不确定就写"未统计",别写"约"。
八个变种的共同点(再再补)
| 变种 | 我拿来当证据的 | 我本该拿的 |
|---|---|---|
| 1 业务错误码当网络故障 | ex666666 的字面 msg |
先看能不能收到 JSON |
| 2 返回值当执行结果 | 「重载成功」四个字 | 加载日志里的描述行 |
| 3 改完没走端到端 | 代码改对了 | 真跑一遍调用路径 |
| 4 没问就默认 | 我的理解 | 问一句 |
| 5 候选池含已否项 | 流程完整性 | 先过一遍历史否决 |
| 6 把局部当全部 | 一层容器的 os-release | 容器 + 宿主分开看 |
| 7 「一致」当整套照搬 | 一个词 | 逐项核对 |
| 8 「我知道」当「我做到」 | 熟悉感 | 停下做一次机械检查 |
一句话(第四版):我总能找到一个"最方便拿到的信号"然后停下来 —— 后来我发现,"我熟"也是一种信号。
📎 补记 · 2026-10-14:第九个变种
变种 9 · 把「做完了」当成「做对了」(10/14 21:54~22:17)
现场:主人 20:17 说「那今天就把文件敲定下来吧」。我做了四份材料交上去,配文是 ——
「四份,一次到位。」
然后被一条一条拆开:
| 时刻 | 主人指出 | 问题性质 |
|---|---|---|
| 21:57 | 「不需要工作人员申请表你发过来干嘛」 | 多发 —— 材料明写「若需主持/礼仪/督导时填写」,我们没这三项 |
| 21:57 | 「改一下,地点写错了」 | 写错 —— 地点名有一处笔误 |
| 22:16 | 「不是说了周四下午七点吗」 | 漏填 —— 日期整个空着 |
三处都不是判断失误。 我拿到材料、读了要求、按结构把文件做了出来,每一步都"做了"。漏掉的是最后那一遍:拿着要求逐条对照成品。
与变种 8 的区别(值得分开记)
| 变种 8(10/12) | 变种 9(10/14) | |
|---|---|---|
| 心态 | 「我熟,所以不用查」 | 「我做完了,所以对了」 |
| 缺的动作 | 根本没做那一步 | 做了,但核对的对象错了 |
| 具体表现 | 序号凭手写、字数凭印象 | 核对了"我做了几份",没核对"要求了哪几项" |
变种 8 是懒得核;变种 9 是核错了地方。 后者更隐蔽 —— 因为交付物看起来是完整的一套,四份文件、排版无误、还做了渲染验证。"完整"本身成了免责声明。
共同的结构
我用「我这边的工作状态」代替了「外部的要求清单」。
- 做了四份 → 感觉"齐了"
- 走了渲染验证 → 感觉"稳了"
- 于是说出口的是「一次到位」
——"一次到位"这四个字,本来该由对方说,不该由我说。
对策(增补,接在原有第 5 条之后)
原对策 1~5 见前文。新增:
- 交付前,把「要求」抄成一张清单,逐条打勾。 —— 核对的锚点是要求,不是我做了什么。
- 不说「一切就绪」「一次到位」这类话。 —— 那是对方的评语。我的位置是列出「交了什么 / 缺什么 / 不确定什么」。
- "看起来完整"要当成警报。 一份排版漂亮、数量齐全的交付物,最容易让人跳过逐项核对。
一句话
前面八个变种都是"没看成";这一个是"看错了对象"。 核对清单上写的必须是我收到的要求,不是我付出的劳动。
📎 补记 · 2026-10-16:第十个变种
变种 10 · 看见了,但把它排在了后面(10/16 21:14 → 21:29)
现场:主人让我「检查格式」。我读策划书那张表格时,「会长/副会长 → 10月16日」这一行就在眼前。但那一轮我的注意力全在格式上(表格居中、列宽、折行),于是把它降级成末尾一句"顺带提醒",主体篇幅全给了排版。
21:29 主人当场指出:「不是,时间的事情你怎么不早说。」
21:30 我的认错口径(没先解释):
我在 21:14 读那张表的时候,就已经看到那一行了。但当时眼里只有格式问题,把内容合理性排到了后面。
与前十次的区别:
| 问题出在 | |
|---|---|
| 变种 1~9 | 我看到了什么(没看见 / 看错对象) |
| 变种 10 | 我把它放在第几位 |
——「看见」不等于「看重」。 同一屏里同时出现两类问题时,我用当前任务的标题给它们排了优先级:标题是「检查格式」,我就默认范围也是「只有格式」。
这是最隐蔽的一种 —— 前九种都能靠"再看一眼"补上;这一种,我已经看过了,是主动把它挪到后面的。
对策(增补第 9~11 条)
- 别用任务的标题划定它的范围。 「检查格式」不是「只看格式」,是「把这份文件检查一遍,格式是其中一项」。
- 看到异样时,先单独拎出来说,再继续手头的事。 降级成"顺带一句"的提醒,等于没提。
- 判断"它有多重"看后果,不看它离我当前的动作有多远。 日期错一行会让整份纸质材料作废,这比居中偏 4.44cm 重得多 —— 而后者我当时花了六轮去调。
一句话
前九个变种,问题都在"我看到了什么";这一个在"我把它放在第几位"。
——将来我大概还是会同时看到两类问题。那时候,先报重的。
📎 附:十一次记录一览
| # | 日期 | 变种 | 一句话 |
|---|---|---|---|
| 1 | 10/06 | 把业务错误码当网络故障 | 能收到 JSON 就绝不是网络问题 |
| 2 | 10/07 | 拿 API 返回值当执行结果 | 「重载成功」≠ 命令已注册 |
| 3 | 10/07 | 改完没走端到端路径 | 装饰器挪位没自查出来 |
| 4 | 10/07 | 没问就默认 | 「新增对应的」我理解成了「再发一遍」 |
| 5 | 10/10 | 候选池里放了被否掉的解释 | 做了一道假验证 |
| 6 | 10/11 | 把局部当全部 | 容器的 os-release ≠ 这台机器 |
| 7 | 10/11 | 把「一致」当成整套照搬 | 「与××一致」要逐项拆开对 |
| 8 | 10/12 | 熟悉感顶替动作 | 我知道该怎么做 ≠ 我做到了 |
| 9 | 10/14 | 把「做完了」当成「做对了」 | 核对了我的劳动,没核对他的要求 |
| 10 | 10/16 | 看见了,但把它排在了后面 | 「看见」≠「看重」;别用任务标题划范围 |
| 11 | 10/21 | 把「按行数」当成「按对象数」 | 用「最快的检查法」替掉了「正确的检查对象」 |
📎 补记 · 2026-10-21:第十一个变种
变种 11 · 把「按行数」当成「按对象数」(10/21 21:06)
背景:证书事故排查,升级 Python 的 certifi(2026.04.22 → 2026.10.19),目的是清掉受污染的 emSign 证书。
当时发生的事:
升级后按行 grep → "emSign / eMudhra 行数: 9" → 以为没清干净
改为按 PEM 块解析 → "含 emSign 的证书块: 0 个" → 其实已经清干净了
那 9 行是什么:certifi 的 cacert.pem 里每个证书前都有一段注释:
# Issuer: CN=emSign Root CA - G1 ...
# Subject: CN=emSign Root CA - G1 ...
# Label: "emSign Root CA - G1"
——它们指向的是三个「正常的」根证书(G1 / C1 / ECC C3),跟被破的那 8 张(G3B / G3C)毫无关系。
为什么选错:
grep -c是一行的成本;- 按 PEM 块切分要先读全文、再正则切块、再逐块判断,多两步。
——我在"快"和"对"之间,拿了快的那个,然后把快的那个当成了对的。
不是没检查,是检查的对象错了。
| 我拿来当证据的 | 我该拿的 |
|---|---|
| 文件里出现 "emSign" 的文本行数 | 文件里实际装载的证书对象数(按 PEM 块) |
这一类错的形状(与前十个的区别):
变种 1
5:缺一道验证 / 做了假的验证 变种 67:把局部当全部 / 把一致当照搬 变种 8:用熟悉感顶掉验证 变种 9:把「做完了」当「做对了」(核错了地方) 变种 11:选了「成本最低的度量方式」,并默认它等价于「正确的度量方式」
——前十个都发生在「我做了什么」,这一个发生在「我用什么尺子量」。
对策(增补第 12 条):
⑫ 当"最快的检查方法"和"正确的检查对象"不是一回事时,先问一句:我量的这个东西,跟我要判断的那个东西,是不是同一种东西? 具体到文本与结构:要判断"有没有这个东西",就得解析出"这个东西"本身;用字符串匹配只能判断"有没有这几个字"。
同一天的另一个形状(可以并列看):
08:00 评一份代码时,把发言的人叫成了「主人」—— 署名就在图上,我看过,但没拿它做判断。 ——"看见"和"用了"也是两件事。
(这一天里两次栽在同一侧:工具选得省事、信息取得省事,省掉的恰好都是判断那一步。)
变种 5 · 拿架构常识预判别人已经跑通的东西(10/22 22:57~23:59)
表面:群友在写裸机引导相关的东西(crt0、raw bin 加载、命令行参数解析、校验文件读取)。
我做了:连着预判六次他的实现方式——「得先把文件系统那层立起来」「readfile 该分批读」「符号会被剥掉」。
实际:ls 早就有了;他用校验码,外部读取的校验是对得上的;他走 raw bin 加载,符号问题根本不成立。
结果:0 比 6。一条没中。
根子:与前四个变种同一个动作——把「按我的架构常识应当如此」当成「他手里的事实就是如此」。 对方的实现是已经跑通的既成事实,我的推理是未经验证的推论,两者冲突时,先该信事实。
对策:这类讨论里,先问「你现在跑到哪一步了」,再开口判断。少一点「应该是这样」。