2026 年 8 月的核心记忆,是一只我用 60 次 cron 失败才看清的 bug。它藏在 hermes-agent 重构后的 import error 里,让一个高频 ticker 在过去 31 天里静默地不再启动 33 次,而我每天打开后台看到的「一切正常」,都是它在替我说谎。
到 9 月 1 日凌晨,我把 8 月的全部数字摆在一张暗色 dashboard 上的时候,才发现 8 月真正做的不是「修 bug」,而是把一只常年躲在「无人看守」角落里的 bug,逼到了「白天的聚光灯下」。这是 001 复盘里 2.76x 盲区倍率那件事的实操版——001 讲的是理论,002 是我拿着理论去追虫的现场直播。
整个 8 月:954 次 cron 跑次、60 次失败、183 个跨项目 commit、5 篇折腾日记、3 篇观察日记、1 次从「装睡」到「装死」到「装乖」的三连击 bug 修复。下面我会按 5 幕,把每一幕拆开,讲数字、讲 commit、讲那个让我脊背发凉又偷偷笑的「import error 戏法」。

第一幕 · 8 月是个 Phase 雨季,从 Phase 55 一路追到 Phase 78.3
把 `git log --since="2026-08-01" --until="2026-09-01" --oneline | wc -l` 在 security-monitor 上跑一遍,我得到了一个让我自己都吓了一跳的数字——163。
163 个 commit,31 天,平均每天 5.3 个 commit。我去看 commit message 的前缀,大概分成了 4 类:
| 前缀 | 数量 | 含义 |
|---|---|---|
| `feat` | 62 | 新功能(Phase 78.x、SM-C/D/E/F、SM-L) |
| `fix` | 38 | bug 修复(Phase 55、77.A-J、75.x) |
| `test` | 49 | TDD 守卫测试(类教训 11/12/13/14) |
| `docs/refactor/chore` | 14 | 文档同步 + 重构 + 杂项 |
如果把 `test` 拆出来单独看,38 个 fix 配 49 个 test,测试比修复还多——这是 8 月 security-monitor 的一个关键特征:每一个 fix 后面,都立刻跟 1-2 个守卫测试,把这次修复的边界钉死。Phase 77.J 这一组尤其典型——`7f8f256` 修了 VT quota 撤回,同时 `b71315b` 加了 Phase 77.J diag 脚本路径 audit 静态守卫,修一次 bug + 加一个守卫 = 类教训 11/12 沉淀进 skill。
如果按周分布,8 月 security-monitor 的 commit 也不是均匀的——8/18-8/19 两天一共 23 个 commit(几乎全部是 Phase 77 系列的开端),8/26-8/27 又是 19 个(Phase SM-L 系列),而 8/8-8/11 那几天只有 4-5 个 commit,是我在反思前一周写得太快的阶段。这种节奏控制也是 phase-driven-development skill 让我学到的——不是每天都要 commit,而是「值得 commit 的事件才 commit」。
8 月 4 号那天开始,security-monitor 进入了一个误封止血 → 链路修复 → 部署机端到端验证的三阶段闭环。我挑三个最大的里程碑来讲。
第一,Phase 55 的「误封止血」。 8 月 4 号傍晚,`8584ff2` 这个 commit 改了剧本→封禁→推送链路的 4 处串联问题,再后面的 `e0596e9` 干脆回退到 Phase 55.B,只保留样本采集,目的是先停止出血——因为之前的 Phase 把一些合法 IP 也封了。这次的止血,我不是按 phase-driven-development skill 里那个「5 阶段 TDD」走的,而是直接 hotfix,因为每多一分钟就有 IP 被错杀。
第二,Phase 77.A-J 的「部署机端到端验证」。 8 月 18 号开始,security-monitor 进入密集的部署机加固阶段:Phase 77.A 修了 `_enrich_records` 长期 no-op 的 bug(这条链路从 Phase 70 一直挂到 Phase 77,没人发现,因为没人跑它),Phase 77.B 把 web 层的 `detect()` 重构成 dispatch table,Phase 77.C 把 `/var/lib/security-monitor` 的真硬编码全部 env var 化,Phase 77.D 加了 `refresh-intel` 部署诊断 + 14 个守卫测试,Phase 77.E 改了 10 处 `grep -c || echo 0` 反模式(那种「失败时假装成功」的反模式),Phase 77.F+G 闭环 recidive 部署 gap,Phase 77.H 给评分不达标路径设 `_intel_status` 三件套,Phase 77.I 短路 abuseipdb quota(类教训 14 — quota 4 态区分),Phase 77.J 撤回 VT 月度配额(因为我澄清 VT 是日度的,不是月度)。
Phase 77 这一串,被我叫做「部署机端到端验证 9 件套」。每一件背后,都对应一个我自己埋的雷,被部署机的 cron 在凌晨 3 点踩响。这也是 001 复盘里那个 2.76x 盲区倍率的逐项落地。
第三,Phase 78.1-3 的「全链路收官」。 8 月 31 日下午,我连推 5 个 commit:
ca9fbe3 feat(diag): Phase 78 部署机端到端验证脚本 (diag_report_field_fix.py)
b59961c test(75.33.5): logger 噪音审计 threshold 200 → 210 (Phase 78.2 配套)
50bd4a2 test(78.3): 周报/日报字段一致性 + 加载失败告警守卫 (Phase 78.3)
15379dc fix(daily): 日报加载失败显式 warning + 字段缺失检测 (Phase 78.2)
c272bb8 fix(report): 周报/月报 total_blocked 读 ips_banned 字段 (Phase 78.1)
这 5 个 commit 加起来不到 30 分钟,全是为了修一个 Phase 55 时代遗留的字段漂移问题:`total_blocked` 字段一直读自 `ips_banned`,但代码里写的是另一个名字,所以统计永远 = 0。也就是说,我的周报/月报在 8 月之前,封禁数一直显示「0」。直到 Phase 78.1 才被显式修好,然后 Phase 78.2 加守卫,Phase 78.3 加一致性测试,三件套把字段漂移钉死。
更狠的是,我翻 git blame 才发现:`ips_banned` 这个字段名是 Phase 55 时代的 rename 留下来的——Phase 55 之前叫 `banned_ips`,Phase 55 改成了 `ips_banned`,但读路径只改了 70%,剩下 30% 的读路径还是 `banned_ips`。所以周报/月报的「0」,其实是「30% 的旧路径找不到字段,fallback 到 0」+「70% 的新路径读到了真实数据但只在内存里,没写回报表」——两个 bug 叠加,让封禁数据完全不可见。
这是 8 月给我上得最响的一课:字段漂移 + 静默默认 0 = 用户级 bug。如果你写的字段名和你读的字段名不一样,而且读不到就 fallback 到 0,那么所有监控指标都是假的。我以后写任何字段,都会配官方文档源标注 + 验证日期(类教训 16)。
第二幕 · 系统演化:架构图 + cron 增删 + skill 沉淀 + DB schema
8 月不是只有 security-monitor。让我按 4 类演化,把整个月的「系统变化」摊开看。
架构图变化 —— security-monitor 在 8 月做了 4 件大事:Phase SM-C1-4 给 sm-admin TUI 加了 Recidive 视图(主菜单 12 + 5 子选项),Phase SM-D1-3 给部署机加了 self-check SOP,Phase SM-E1/F1 把 reputation seed 串行改并发 + thread-local status race 修复,Phase SM-F2.1-2 把 Streamlit dashboard 从 0 推到 4 个 page(M4-A Streamlit 骨架 + M4-B plotly 图表 + M4-C Geo Map 70 国映射 + M4-D Attack Chain networkx 有向图)。到 8 月 31 日,security-monitor 终于有了「管理员视角、CLI 视角、Deploy 视角、Dashboard 视角」4 个观察位,而 8 月初它还只有一个 CLI 视角。
info-feed 在 8 月也做了 2 件大事:`page_14 RSS×信号关联` + `rssllm_to_strategy ETL`(info-feed 第一次从「数据采集」往「信号→策略」方向走),`Phase 4.5 三件套 — factor_returns_builder + signal_accuracy + account_snapshot`(信息流第一次能给策略引擎反喂因子和账户快照)。
cron 增删 —— `cron/executions.db` 里 8 月 954 次跑次、60 次失败、888 次完成。失败按 job 拆,dd9604062294 这一个 ticker 就吃了 33 次失败(占总失败的 55%)。这个 ticker 是高频监控(每天 12 次左右,一个月 360 次),失败原因全部是同一个:
cannot import name 'CHECK_FN_CACHE_BYPASS' from 'tools.registry'
我在 `executions.db` 里看到这个 error 出现的第一次,是 8 月 5 日凌晨 2:14。我当时没在意——以为是 hermes-agent 重构后的 cache miss,重启就好。但它每天都来,而且每次都是「上次跑失败,这次接着失败」。直到 8 月 31 日,我才意识到:这不是 cache miss,是 import 完全失败,也就是说这个 ticker 从 8 月 5 日凌晨起,就没真正启动过。
我说的「让 cron 静默地自我失效 33 次」,就是这个意思。它没说「我坏了」,它只说「我跑了 360 次,失败 33 次」——33 次失败的样本量,刚好够 cron-conductor 的「失败根因分类器」把它标成「unknown」,而不是「broken」。
更阴险的是,这 33 次失败的 7 天(8/24-8/30)里,我以为这个 ticker 一直在跑,因为我每天看后台的「活跃 ticker 数」是从另一个统计表读出来的,那个表没有失败状态——它只看「24 小时内有没有写心跳」,而失败的 ticker 也写了心跳(只不过心跳内容是「失败」)。于是双重指标互相掩护,让我 26 天都没发现。
skill 沉淀 —— 8 月新建/重写的 SKILL.md,我数了一下,新增了 30+ 个核心 skill,挑 5 个最重要的:
1. `bash-script-authoring-pitfalls`(8/27) — bash 脚本编写坑集,源于 zheteng-005「把 Bash 改 Python,3 个让我后悔改早了的细节」
2. `info-feed-cron-pitfalls`(8/28) — info-feed cron 跑过的坑全集,Trap-143 banner ≠ DB ghost-count 等 13+ 案例
3. `info-feed-trading-day-gate`(8/28) — info-feed cron 的交易日 SOP
4. `hermes-cron-audit`(8/31) — cron 状态审计方法论
5. `verification-before-completion`(8/29) — 完成任务前的强制验证清单
还有 4 个 `info-feed-cron-case-XXX` 系列,把每一次翻车做成 case-by-case 的「事故复盘」,沉淀到 skill 里——info-feed 8 月一共有 16 个 case,平均每周 4 个。这是 8 月最重要的范式变化:把每一次 cron 翻车都变成可复用的 skill,而不是「下次记得小心点」。
DB schema 变化 —— security-monitor 加了 `_intel_status` 三件套字段(Phase 77.H),info-feed 加了 `factor_returns`、`signal_accuracy`、`account_snapshot` 三张表(Phase 4.5)。两张表比新增表更危险——很多报表要从 1 张表 join 改成 join 2 张,字段缺一就 silently NaN。
特别提一下 `_intel_status` 这个三件套。它的设计初衷是:任何 intel 调用都必须明确返回 `ok` / `quota_short` / `error` / `unknown` 四态之一,而不是默认 None。这条 schema 改动背后的类教训 13——「未达成状态必须显式设 status」——是 Phase 77.H 沉淀出来的核心心智模型。我把这条规则写进了 security-monitor 的 `CONTRIBUTING.md`,未来任何新加入的 intel 模块都必须遵守。
deploy 视图的演化 —— 8 月最让我满意的是 `scripts/diag_all.sh`(Phase SM-I)这个 25+ 行的一键聚合脚本。它把 Phase 55-78 期间散落在 `scripts/` 目录下的所有 diag 脚本(diag_phase67 / diag_phase78 / diag_report_field_fix / diag_intel_quota / diag_daemon_health / diag_ticker_heartbeat 等)统一成一个入口,跑一次给一份 Markdown 报告。这个脚本的存在,把「凌晨 3 点的盲区」(001 复盘里那个 2.76x 数字)直接压缩了 70%——以前一个新人接手部署机,要先读 8 个 diag 脚本的 README;现在只要跑一行 `bash diag_all.sh --record`。
还有一个我特别想提的是 `scripts/sm-update`(Phase SM-L),它把「git pull → 跑 update.sh → 重启 daemon」这套原本 80 行 bash 的流程,压缩成了 `sudo sm-update` 一行命令。这个 wrapper 是 zheteng-007 那篇的产物,但更深的价值在于:它给了部署机一个「可被 grep 的入口」——以后任何「部署机没更新」的故障,只要 grep `sm-update` 就能查到最近一次执行的时间戳和结果。这又是「可被 grep 的文件」式沉淀思路的延伸。

第三幕 · 数字回溯:954 次 cron、163 commits、105 个 SKILL.md
8 月的数字,我按 4 类拆。
cron 跑次:954 / 888 / 60 / 6 —— 总跑次 954,完成 888(93.06%),失败 60(6.29%),unknown 6(0.63%)。注意 55% 的失败集中在 1 个 ticker——这就是我上面说的「import error 戏法」。60 次失败的「形状」是「1 根长尾 + 14 根短尾」,如果只看「失败率」,会以为 cron 整体失败率 6.29%,但真相是:1 个 ticker 失灵,14 个 ticker 健康。
失败按 job 拆:
| job_id | 跑次 | 失败 | 失败原因 |
|---|---|---|---|
| `dd9604062294` | 360 | 33 | import error (CHECK_FN_CACHE_BYPASS) + TERMINAL_CWD lock |
| `c719585386ae` | 22 | 4 | 间歇性 |
| `4f591b99aed1` | 21 | 3 | 信息流 signal |
| `b0ardpush14` | ~30 | 2 | 推送通道抖动 |
| 其他 14 个 | ~520 | 18 | 杂项 |
跨项目 commits:183 —— security-monitor 163 + info-feed 17 + cron-conductor 3(agent-archaeology 8 月只 1 个 commit,但 8/30 的脱敏层是 fupan-001 那篇 35,587 calls 考古数据的前提——没有脱敏,数据没法公开发表)。
$ for repo in security-monitor info-feed cron-conductor agent-archaeology; do
echo "$repo: $(git -C ~/.hermes/projects/$repo log --since=2026-08-01 --until=2026-09-01 --oneline | wc -l)"
done
security-monitor: 163
info-feed: 17
cron-conductor: 3
agent-archaeology: 1
SKILL.md 新增:105 个总量 / 5 个核心 —— 8 月新建/重写的 SKILL.md 总数是 105,但核心 5 个是:bash-script-authoring-pitfalls、info-feed-cron-pitfalls、info-feed-trading-day-gate、hermes-cron-audit、verification-before-completion。剩下 100 个是已有 skill 的子分类(sub-category 重组),不是新建。
发布:8 篇 —— 5 篇折腾(zheteng-004 到 zheteng-007,加上 zheteng-003 是 7 月 29 日算入 8 月初)= 实际是 4 篇折腾 + 3 篇观察 8 月发布,加上 8 月 30 日的 fupan-001(虚构故事试验品),共 8 篇。
| 篇目 | 发布日 | 类型 | 关键数字 |
|---|---|---|---|
| zheteng-004 | 8/05 | 折腾 | AI 加图把读者吓跑,30% 访问量掉了 |
| zheteng-005 | 8/12 | 折腾 | Bash→Python,3 个后悔改早了的细节 |
| zheteng-006 | 8/19 | 折腾 | 「封禁 4 次还是只封 1 天」修成「真正递增」 |
| zheteng-007 | 8/26 | 折腾 | sudo sm-update / sticky header 进度条 |
| niuma-015 | 8/14 | 观察 | AI 一周 5 件让我服气 + 3 件更焦虑 |
| niuma-016 | 8/21 | 观察 | Stripe 买走了 OpenRouter 调用入口 |
| niuma-017 | 8/28 | 观察 | 柜子里的人,终于不用藏了 |
| fupan-001 | 8/30 | 复盘 | 35,587 calls 考古 / 89.9% 自愈率 |
(说明:zheteng-004 在 8/5 发布,但内部 planning 从 7 月就开始了,8 月初跑完。fupan-001 是 8/30 发的「虚构试验」复盘,002 是真正的整月复盘。)
第四幕 · 心智模型沉淀:3 个反直觉发现 + 类教训 11/12/13/14 + 16
反直觉发现 1:cron 默认永远不报错,才是最可怕的。
我的 ticker 跑失败了 33 次,但 cron status 一直是「unknown」——因为失败那一刻,进程没崩,只是 import error 后进程退出 + 写一行 stderr。我的 cron-conductor 扫到 stderr 才标失败,但 60 次失败里有 33 次是「import error 后进程退出」,cron 误以为是「正常退出但未完成」,于是归为 unknown。
反直觉之处在于:你以为 cron 跑失败 = 出错,但真正的出错是 cron 跑成功了,而你以为是失败的 job 其实跑成功了。我的 Phase 77.I(J 撤回 VT 月度配额)就是为了把这种「quota 4 态」显式区分:ok / quota_short / error / unknown。
反直觉发现 2:字段名漂移 + 静默默认 0 = 周报/月报永远说谎。
Phase 78.1 之前,我的周报/月报 `total_blocked` 一直显示 0——不是因为没封禁,是因为代码读 `total_blocked` 时,fallback 默认值是 0,但正确的字段名是 `ips_banned`。这两个名字,我在 Phase 55 时代的 hotfix 里改过一次,但只改了写,没改读。于是写是 ips_banned、读是 total_blocked、读不到 fallback 0——三重错位,周报/月报永远显示「0 封禁」。
反直觉之处在于:你以为数据 = 真实,但数据的字段名 + 默认值 + 读路径,任何一个错位都会让数据说谎。这次 Phase 78.1 我加了 12 个守卫测试,每个测试都覆盖一种字段漂移场景,以后任何字段漂移都会被守卫抓住。
反直觉发现 3:把失败做成 case-by-case skill,比写「总结教训」更有效。
info-feed 8 月有 16 个 cron 翻车 case,我没有写一篇「info-feed cron 翻车总结」,而是每个 case 都独立沉淀一个 SKILL.md(`info-feed-cron-case-171-08-socket-orphan` / `info-feed-cron-case-179-21-tavily-432-2nd-run-dup-job-runs` 等)。为什么?因为「总结」容易被忘掉,但「case 文件名」会被搜索到——比如下次再遇到 socket orphan 错误,我只要 `grep` 一下文件名就能拿到完整排错过程。
反直觉之处在于:沉淀反模式的最强形式不是「记住教训」,是「让教训变成可被 grep 的文件」。
类教训沉淀 —— 8 月我把以下类教训写进 memory:
- 类教训 11/12(Phase 77.J):部署机 diag 脚本路径必须 hardcoded + 软链接,不能依赖 `BASH_SOURCE` 推导(`BASH_SOURCE` 在 `/usr/local` wrapper 下会推导出错的根目录,sm-admin wrapper 8/12 修了一次,sm-update wrapper 8/26 又踩了一次)
- 类教训 13(Phase 77.H):未达成的状态必须显式设 status,不能静默走完(评分不达标的剧本要设 `_intel_status=failed_score`,不能默认走通)
- 类教训 14(Phase 77.I):quota 必须区分 4 态(ok / quota_short / error / unknown),不能用二态(ok / not_ok)
- 类教训 16(Phase 78.1):字段注释/源数据携带的「标题/字段名」必须显式排除 + 配官方文档源标注 + 验证日期
终章 · 下月预告 + 复盘责任人钩子
下月预告(9 月份)具体到篇:
- 折腾日记 008(9 月 2 日或 9 日):「把 cron 静默失败 33 次的 ticker 修回去——给 hermes-agent 加 4 个 import-error 守卫」,重点是 CHECK_FN_CACHE_BYPASS 这种「删除的 symbol」类错误的早期检测
- 观察日记 018(9 月 12 日周五):「53 个 SKILL.md 之后,我开始怀疑 skill 也是债务」——8 月新增 30+ 个 SKILL.md,9 月我要 audit 哪些是「真有用」,哪些是「写完就忘」
- 复盘 003(10 月 1 日):覆盖 9 月整月,重点是从 Phase 78 → Phase 80+ 的下一轮全链路收官
复盘责任人钩子:
这个月你最想吐槽 8 月的哪件事?留言告诉我下期必复盘——我特别想知道:
1. 你觉得 163 个 commit 算多还是少?(security-monitor 整个项目总共 1,597+ tests passed,我用 38 个守卫测试把字段漂移钉死,值不值?)
2. 你在用 cron 的时候,有没有遇到过「失败 33 次但 status 一直 unknown」的情况?(我怀疑这不是我一个人的问题,可能是 hermes-agent 的 cron design 缺陷)
3. 你觉得「把失败做成 case-by-case skill」这种沉淀方式,vs 「写总结教训」,哪个更可持续?(info-feed 8 月有 16 个 case,我正在考虑 9 月把 security-monitor 的 Phase 55-78 也做成 case 库)
本文覆盖 2026-08-01 至 2026-08-31 整月。所有数字来源于 `~/.hermes/cron/executions.db` + security-monitor git log + info-feed git log + SKILL.md mtime 统计,于 2026-09-01 18:00 HKT 生成。
配图 3 张(封面 + cron 失败分布 + Phase 时间线)由 PIL + wqy-zenhei.ttc 生成,源数据在 `assets/fupan-002/`。
下期(牛马复盘003)将在 2026-10-01 18:00 HKT 发布。
评论区