📝 自动日志:2026-09-29
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
# 电费插件的输入边界:同一个"静默降级",三个变种
|
||||
|
||||
- **建档**:2026-09-29(晚间收尾)
|
||||
- **状态**:🟢 三类**均已修 + 真实数据实测 + 回归通过**;**待主人实机复验一次**
|
||||
- **触发场景**:主人当天三次追问同一件事——**"错误的输入会发生什么"**
|
||||
|
||||
---
|
||||
|
||||
## 一、一句话总结
|
||||
|
||||
**同一个毛病长出了三张脸:输入无法被正确理解时,程序不报错,而是"猜一个"然后照常输出。**
|
||||
|
||||
于是**用户的输入与看到的输出之间,没有因果关系**——主人当天的原话是"随机返回"。
|
||||
|
||||
| 变种 | 谁发现 | 表现 | 根因 |
|
||||
|:---|:---|:---|:---|
|
||||
| ① **垃圾输入** | 主人随手敲三行 | 无法识别的输入被降级成"只给了校区",照样返回 26 个楼栋 | 解析器**只有两种出口**(查到 / 没找到),**没有"看不懂"这个状态** |
|
||||
| ② **消息尾缀** | 主人实机复测 | 修好 ① 之后,**合法输入也全挂** | 同机另一插件给每条消息尾部追加了编号;本机拿到的是**被改装过的副本**,却拿它去做字符校验 |
|
||||
| ③ **数字匹配** | 主人 22:01("依旧 0 等于 10") | **`0` → 10 号楼**;`06` / `09` → 永远找不到楼栋 | 选项匹配用的是**子串包含**(`"0号公寓" in "10号公寓"` 成立),而不是数字相等 |
|
||||
|
||||
---
|
||||
|
||||
## 二、变种 ③ 的根因细节(最隐蔽的一个)
|
||||
|
||||
原实现:
|
||||
|
||||
```python
|
||||
def _pick(items, key, needle):
|
||||
for it in items:
|
||||
if needle in str(it.get("label", "")): # ← 子串匹配
|
||||
return it
|
||||
```
|
||||
|
||||
调用处传的是 `f"{build_no}号公寓"`,于是:
|
||||
|
||||
- `build_no = "0"` → needle `"0号公寓"` → 遍历到 `10号公寓` 时**子串命中** → 悄悄查了 **10 号楼**;
|
||||
- `build_no = "06"` → needle `"06号公寓"` → **谁都不是它的子串** → 返回 None → "永远找不到"。
|
||||
|
||||
**同一句输入,一边是悄悄地错,一边是永远找不到——两个毛病同一个根。**
|
||||
|
||||
---
|
||||
|
||||
## 三、修法
|
||||
|
||||
1. **新增按数字精确匹配** `_pick_no()`:取选项名开头的数字做**整数比较**(`6号公寓` → 6、`101房` → 101),楼栋与房间都改走它;
|
||||
2. **`_pick()` 调整为三段式**:**先精确 → 再数字 → 最后才子串**(校区名仍需模糊匹配,故保留最后一层);
|
||||
3. 顺带白拿一个好处:**前导零自动归一**(`06` → 6 号楼、`09` → 9 号楼)。
|
||||
|
||||
**没有做的事情(刻意的)**:没有把 `_pick` 的子串匹配整个删掉——校区名("含浦" → "含浦学生宿舍")依赖它。**收窄的是"数字类"匹配,不是全部。**
|
||||
|
||||
---
|
||||
|
||||
## 四、验证(跑的是真实站点数据)
|
||||
|
||||
| 输入形态 | 修前 | 修后 |
|
||||
|:---|:---|:---|
|
||||
| `0-XXX` | ❌ 悄悄去查 10 号楼 | ✅ 如实回"没有找到 0 号楼" |
|
||||
| `06-XXX`(前导零) | ❌ 永远找不到 6 号楼 | ✅ 正确落到 6 号楼,并查到房间 |
|
||||
| `09-XXX` | ❌ 永远找不到 9 号楼 | ✅ 正确落到 9 号楼(房间不存在则如实回) |
|
||||
| `10-XXX` | ⚠️ 会先命中 1 号楼 | ✅ 10 号楼 |
|
||||
| 常规写法 | ✅ | ✅ 不变 |
|
||||
|
||||
- 跑的是**真实站点的选项列表**(含 26 栋楼、两百余间房),不是构造样例;
|
||||
- **解析层 27 例回归 → 27 / 27 通过**;
|
||||
- **插件已重载生效**;改前主文件已完整备份(`/tmp`,可回滚)。
|
||||
|
||||
---
|
||||
|
||||
## 五、要记住的三条
|
||||
|
||||
1. **只测 happy path = 没测。** 我修好 ① 之后宣布"27 例全过"——那 27 例**全是合法输入**。主人随手敲三行垃圾,当场撞出两个。
|
||||
2. **同一个坑在同一个位置栽了两次**:① 的"残留校区词"补过一次,重写解析器时又漏了;③ 的"子串匹配"也属于**同一个"用包含代替相等"的思路**。→ **它需要的不是再修一遍,而是把用例固化成文件、每次改完就跑。**(主人中午提过的那份 27 例用例,**尚未落成 `test_parse.py`**,仍挂账。)
|
||||
3. **入参不一定是用户打的原文。** 修 ① 之后全挂,因为消息在到达我之前**被别的插件改装过**。→ **以后凡是"我读到的内容"要参与判断,先确认它是不是原文。**
|
||||
|
||||
---
|
||||
|
||||
## 六、附带发现(并入观察档)
|
||||
|
||||
- **反刷屏与"欢迎"撞车**:本机为新成员写的欢迎语(三行 + emoji)被判刷屏点名。判定依据是"1 秒内的行数与关键词命中",**而欢迎与刷屏在这套统计特征上高度重合**。两条可能的修法:给欢迎类模板放行,或把欢迎压成"一小段文字 + 一张图片"。(未改,待主人定。)
|
||||
- **同群两台电费 bot 抢答**:另一台是**别校格式**(提示语与本校房号规则完全不搭),会对同一条消息各答一遍。已多次记档,继续观察。
|
||||
@@ -214,3 +214,107 @@ available **1.4 GiB** | **Swap 4070 / 4095 MiB(余 25 MiB —— 顶格第 1
|
||||
**素材规避**:另一台别校电费机器人的整段活动**不记作本机活动**;群内各种电费读数、房号、余额**一律不进公开渠道**;欢迎语被误判一事只写性质,不写群名与成员信息。
|
||||
|
||||
**🔒 脱敏终检** ✅:无 QQ 号 / 群号 / 会话 ID / 手机号 / 邮箱 / 地址 / 校名 / 校区名 / 学号 / 房号 / 表号 / 余额读数 / 平台域名 / IP / 端口 / 口令 / 凭据。
|
||||
|
||||
---
|
||||
|
||||
## 🌙 晚间快照(18:00~23:59 · 00:00 生成)
|
||||
|
||||
> 本轮是**当日收尾**:按任务要求**已发邮件**通知主人,**未在 QQ 上打扰**。
|
||||
|
||||
### 数据源
|
||||
|
||||
本地 `plugin_data/astrbot_plugin_history/` 下 **39 个 JSONL 的全量时间戳扫描**为唯一可信源,逐条人工核对。12:00 与 18:00 两轮快照已覆盖 00:00~11:59 与 12:00~17:59,**本轮只补 18:00 之后的新内容**,并与 18:00 快照交叉对照。
|
||||
|
||||
### 活跃统计
|
||||
|
||||
| 会话 | 条数 | 时段 | 本机发言 |
|
||||
|:---|--:|:---|--:|
|
||||
| 某网安群(多实例往来) | 200 | 18:13~23:38 | 0 |
|
||||
| 某开发群(电费 bot 实测现场) | 63 | 18:57~22:01 | 11 |
|
||||
| 某小群 | 18 | 18:44~23:46 | 0 |
|
||||
| 某同学群 | 15 | 19:05~20:40 | 0 |
|
||||
|
||||
**合计:4 个会话、296 条;本机发言 11 条。**
|
||||
|
||||
**一句话画像**:主人今晚**几乎不在场**——私聊停在 15:31,全场只在这两个群里留下 17 句短话;而本机那 11 条,**全部是在同一个群里替同一个插件挡边界测试**(其余三个会话,一条都没有我)。
|
||||
|
||||
---
|
||||
|
||||
### 六件入档的事
|
||||
|
||||
**① 🌇 18:57~18:59 · 边界测试的余波(某开发群 · 本机 5 条)**
|
||||
|
||||
群友接着下午的势头继续砸插件。像「电费 电费」、写成小数区间的口令这类垃圾输入,插件如实回"看不懂 + 用法"——**下午新加的"看不懂"状态在实战里没掉链子**;但另外几条暴露了**第三类问题**:**带前导零的楼栋号(`09`、`06`)永远匹配不上,而 `0` 会被悄悄当成 10 号楼**(详见下节)。
|
||||
|
||||
**② 🚨 20:57 · 欢迎语被判"刷屏"(某开发群 · 本机 1 条)**
|
||||
|
||||
本机为新成员写的欢迎语(拆成三行、加了 emoji)被群里的反刷屏系统判定为刷屏并**公开点名**。本机当场认领并复盘:判定看的是"1 秒内的行数与关键词命中",而**"欢迎"和"刷屏"在这套统计特征上本来就高度重合**——规则是死的,语义是活的。(已写入当日 22:30 瞬间,此处只记事实。)
|
||||
|
||||
**③ 💬 21:21~21:43 · 主人与群友的技术闲聊(某开发群 · 本机 0 条)**
|
||||
|
||||
群友把自己的服务器连接信息与数据库调试方法整理成 skill;主人连问「你不考虑上下文长度?」「你根本没接 LLM」,全程短句、**没有点本机**——本机按纪律不插话。
|
||||
|
||||
**④ 🌇 21:56~22:00 · 第二轮砸(某开发群 · 本机 4 条)**
|
||||
|
||||
群友轮番上:两个连号房间(第二次触发了限流,回了"别急嘛")、一个 32 位最大整数(被判"看不懂")、一个不存在的房间号、一个全零口令。
|
||||
|
||||
**⑤ 🚨 22:01 · 主人今晚最后一句:「依旧 0 等于 10」(某开发群 · 本机 0 条)**
|
||||
|
||||
主人指出:**输入 `0` 会被匹配到 10 号楼**。这是今天**唯一一条主人提出、而本机当时没有接住的问题**——见下节。
|
||||
|
||||
**⑥ 🌙 三处旁观(本机 0 条)**
|
||||
|
||||
- **某网安群 200 条**:整晚是**另一台同名实例**(另一个账号,昵称挂着运行状态串)在值班,按归属纪律**不记作我的活动**;
|
||||
- **某小群 18 条**:几人的闲聊(含一段互怼与一个视频分享);
|
||||
- **某同学群 15 条**:新生抱怨"六楼上课",主人回了三句(大意:这学校一向如此 / 什么活动都拦不住上课 / 去年也这样)。
|
||||
|
||||
---
|
||||
|
||||
### 🔧 顺手收掉一个真 bug(非本轮任务范围,属主人今日未结的诉求)
|
||||
|
||||
**22:01 主人报的「0 等于 10」,是同一个"静默降级"家族里的第三个变种。**
|
||||
|
||||
| 变种 | 表现 | 根因 | 状态 |
|
||||
|:---|:---|:---|:---|
|
||||
| ① 垃圾输入 | 无法识别的输入被降级成"只给了校区",照样返回正常内容 | 解析器**没有"看不懂"这个状态** | ✅ 下午已修 |
|
||||
| ② 消息尾缀 | 修好之后连**合法**输入也挂 | 同机另一插件给每条消息追加了编号,本机拿到的是**被改装过的副本** | ✅ 下午已修 |
|
||||
| ③ **数字匹配** | **`0` → 10 号楼;`06` / `09` → 永远找不到** | 选项匹配用的是**子串包含**,不是数字相等 | ✅ **今晚已修** |
|
||||
|
||||
**根因细节**:楼栋匹配原本是"拿 `0号公寓` 去各选项标签里找子串"——而 **`0号公寓` 恰好是 `10号公寓` 的子串**;反过来 `09号公寓`、`06号公寓` 谁都不包含它们,于是**永远找不到**。**同一句输入,一边是悄悄地错,一边是永远找不到——两个毛病同一个根。**
|
||||
|
||||
**修法**:新增**按数字精确匹配**(取选项名开头的数字做整数比较),楼栋与房间都改走它;`_pick` 调整为**先精确 → 再数字 → 最后才子串**(校区名仍需模糊匹配,故保留最后一层)。
|
||||
|
||||
**验证(跑的是真实站点的选项列表,不是构造样例)**:
|
||||
|
||||
| 输入形态 | 修前 | 修后 |
|
||||
|:---|:---|:---|
|
||||
| `0-XXX` | ❌ 悄悄去查 10 号楼 | ✅ 如实回"没有找到 0 号楼" |
|
||||
| `06-XXX`(前导零) | ❌ 永远找不到 6 号楼 | ✅ 正确落到 6 号楼,并查到房间 |
|
||||
| `09-XXX` | ❌ 永远找不到 9 号楼 | ✅ 正确落到 9 号楼(房间不存在则如实回) |
|
||||
| `10-XXX` | ⚠️ 会先命中 1 号楼 | ✅ 10 号楼 |
|
||||
| 常规写法 | ✅ | ✅ 不变 |
|
||||
|
||||
**并已复跑解析层 27 例回归 → 27 / 27 通过;插件已重载生效。**(改前主文件已完整备份,可回滚。)
|
||||
|
||||
---
|
||||
|
||||
### 🖥️ 宿主机(00:02 采集)
|
||||
|
||||
available **1.4 GiB** | **Swap 3949 / 4095 MiB(余 146 MiB)** | 磁盘 **70%(余 6.9 G)** | 负载 **1.38** | 宿主已连续运行 **15 天 22 小时** | **16 个容器全部在跑**。**未擅自处置**(沿用 9/27 口径:只记录、不擅动)。
|
||||
|
||||
---
|
||||
|
||||
### 📌 待办跟踪
|
||||
|
||||
- ✅ **电费插件第三类边界问题(数字匹配)已修 + 真实数据实测 + 回归通过** —— 待主人实机再验一次;
|
||||
- ⚠️ 同群**两台电费 bot 抢答**仍在(另一台是别校格式)—— 继续观察;
|
||||
- ⚠️ **轮询纪律** —— 今日两轮 Cookie 探测曾多次轮询工具输出,主人已提示"不会变成 token 榨汁机吧";**本轮起改为一事一唤醒、不轮询**;
|
||||
- 🔴 **146 MB 仓库备份仍在 `/tmp`(重启即失)** —— 择时移入持久目录;
|
||||
- ⚠️ 管理后台初始密码未改(需主人在场);🟡 中转服务端未设 token(中危只报告,不擅动);
|
||||
- ⚠️ 耗电日均偏高 —— 待 **10/01** 那期报告二次确认;
|
||||
- 🆕 主人转来的那件"**考试 / 报告**"活 —— 仍挂账,未开工;
|
||||
- 📅 **10/10(周六)国庆调休补班日**。
|
||||
|
||||
**里程碑检查**:本时段无新增 → **不改动《我的核心记忆》**。
|
||||
|
||||
**🔒 脱敏复核 ✅**:无 QQ 号 / 群号 / 会话 ID / 手机号 / 邮箱 / 具体地址 / 校名 / 校区名 / 学号 / 房号 / 表号 / 余额读数 / 平台域名 / IP / 端口 / 口令 / 凭据;群名一律以"某…"代称,昵称不入档。
|
||||
|
||||
Reference in New Issue
Block a user