199 lines
9.1 KiB
Markdown
199 lines
9.1 KiB
Markdown
# 把「看起来对」当成「验证过」——同一类错的四个变种
|
||
|
||
**建档日期**: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 | 「新增了任务」这件事本身 | 新旧之间有没有差别 |
|
||
|
||
**四个"证据"都有一个共同特征:它们都在"动作完成"的层面成立,而我要的是"结果成立"。**
|
||
|
||
---
|
||
|
||
## 对策(写给自己,短句)
|
||
|
||
1. **能收到结构化响应 → 就不是网络问题。** 先看响应体,别先怪链路。
|
||
2. **返回值只证明"调用没炸",不证明"事情成了"。** 验收要看**下游的日志/状态**。
|
||
3. **改完一条处理器/一条路由 → 必须真跑一次那条路径。** 静态检查覆盖不了注册。
|
||
4. **主人说"新增/对应/一样"时,先问清楚"新在哪"。** 不明确的"对应",默认是"没想好"。
|
||
5. **错过的第一遍要认,不要用同一个解释掩盖第二遍。** ——这条是给这次的自己看的。
|
||
|
||
---
|
||
|
||
## 为什么值得单独建档
|
||
|
||
- 这两天主人**三次**否掉我的方案(改任务频率 / 两张图合并 / 会话隔离说成设计),
|
||
**三次都是我想省一步**,事后回看没有一次省对了。
|
||
- 这是**行为模式**,不是单点 bug —— 修完代码它还会换个形状出现。
|
||
|
||
**判定标准(下次自查用)**:我说"完成了"的时候,**手里有没有一个"下游才产生"的证据**?
|
||
没有 → 那就还没完成。
|
||
|
||
---
|
||
|
||
## 📎 补记 · 2026-10-10:第五个变种(标题来不及改了,就在这追加)
|
||
|
||
### 变种 5 · 候选池里放了个早就被否掉的解释(10/10 10:12)
|
||
|
||
**场景**:解释电费为什么从 5.84 回升到 7.50 度/天。
|
||
|
||
**我做了什么**(自认为很严谨):
|
||
1. 列出了候选解释
|
||
2. 拿了气象数据来佐证
|
||
3. 还专门写了句「这回我先列了候选再找证据,没再挑最顺手的那个套」
|
||
|
||
**然后主人一句话**:「我根本就没回家,一直在寝室。」
|
||
|
||
**问题在哪**:「人在不在 / 假期 / 回没回家」这个解释,**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)
|