内部工程审计 · 红蓝对抗周期

拖慢的不是修,
是「假成功」

红蓝对抗一天能逼出 9 类事故,修一个 bug 只要几分钟——时间全花在「发现」和「核查原因」两段。清完 7 月企微通道的全部证据,14 个实例指向同一个根属性:这条链上每一层在失败时都返回成功。

// 样本 = 企微方案B 自动代回通道 · 2026-07-01 ~ 07-29 · 抖音通道未纳入

14 个假成功实例 891 条 MEMORY 清点 43 条同型教训 发现延迟 18MIN → 19 天 修复 = 分钟级 26 轮真机实盘
SCROLL / 向下滚动
01
Anatomy of one cycle

拿 07-29 那次当标尺

杭州机恢复自动代回后连踩三坑。把这一次逐段拆开,就能看清时间的去处——真修只是一行参数,前面两段各吃掉一个数量级

发现
4.5 小时

蓝方「该回的全没回」,静默停摆 4.5 小时才被人发现。没有任何告警——护栏在正常拒发、进程在正常轮询、返回码全是 0。

归因
走错一轮

第一发假设是版本回归(记录原文:「一度误判成版本回归」)。同一个「没回」症状对着六七个候选层:遮挡 / 坐标 / 读屏漏抄 / 基线推进 / 身份门 / 生成失败 / 回执落库 / 实跑版本。

真根因

计划任务弹出的 cmd 黑窗盖在企微前面 → 每轮截屏拍到黑窗+左侧列表 → 把窗口标题、会话列表碎片当成客户消息读出来、客户名一并读错 → 身份门比对「当前窗口≠目标会话」逐条拒发。护栏没坏,是喂给它的名字是错的。

修复
一行

任务动作改成 start /min 起黑窗,重启后当轮读屏即恢复读到真实气泡。同批另两坑:空白微信昵称让身份门永久卡死(改中文备注名)、跑红方会停掉蓝方两个任务而收工只删了 STOP 闸。

// 同一条链上的历史节拍:2026-07-01 读屏三连修 15:42 → 15:48 → 16:00(18 分钟三版)。「修」从来不是瓶颈。

周期模型

周期 = 发现延迟 + 定位轮数 × 单轮验证成本 + 修复(分钟级)
三项里只有最后一项快。前两项都由同一件事决定:失败的时候,系统告诉你的是真话还是假话。

02
The single key factor

每一层在失败时都返回成功

这不是「之一」,是唯一贯穿全部证据的根属性。7 月这条通道上清出 14 个实例:返回码 0、HTTP 200、workflow success、迁移已应用、DB 记 sent、卡片绿灯——每一个都在真实失败时点亮。

Definition · 假成功

一层的「成功」信号由该层自己签发,而签发依据是「我把调用发出去了」(proof-of-call),不是「事情真的发生了」(proof-of-effect)。

后果是双杀:失败没有出口(发现延迟被拉到天 / 周量级)+ 所有可信信号都是假的(第一发假设几乎必错,定位轮数膨胀)。

层 / 动作它报告的「成功」实际状态代价
拉起 loop云电脑 · schtasks /runrc=0任务动作瞬间死、零输出——日志句柄没释放,追加重定向建不起来,而错误信息本身要走那个失败的重定向一晚空转 4 次
看门狗 v1云电脑 · 自动恢复rc=0任务引擎仍标 Running,/run 被当重复实例拒掉白等一个 5min 周期
发布链路GHA · vercel-deployCI 绿 · PR 已合 · meta 端点 200paths-ignore 里有 cloudpc/**,而被发布的脚本正在那个目录——只改脚本的提交不触发部署,发出去的永远是旧字节自愈链
全程是断的
launcher 同步云电脑 · 自更新重启成功103KB 穿墙下载 3 次挂 1 次,挂的那次恰好是要装新版那次 → 检测到新版→退出→同步失败→旧版重启永远装不上
Claude 评审GHA · PR reviewworkflow success--allowedTools,跑完 20~39 轮后发评论被权限系统全部拒掉;5 个 PR 的 bot 评论数 0≈$6.4 白烧
评审形同虚设
跨模型 fail-over服务端 · 空回复保险代码在册判据「当前模型 ≠ 默认模型」在企微回滚同款模型后恒 false保险 19 天
没执行过
收权迁移Supabase · REVOKE迁移已应用REVOKE FROM PUBLIC 对 Supabase 的 anon 角色实际收不掉#1043 → #1045
返修
GUI 发送云电脑 · _deliver「已发送并落库」输入框坐标失准时字打进了任务栏,DB 照样记 sent全天假发送
发送回执云电脑 → 服务端屏幕上有回复回执静默失败,DB 无记录实盘对练
判成「漏回」
数据库查询服务端 · supabase-jsdata=null不解构 error 时,查询故障被当成「0 条结果」审计报出假的
「100% 漏写率」
读回通道诊断 · Fly 日志grep 命中 0--no-tail 一次只回 100 行 ≈ 4 秒窗口,几分钟一次的稀疏事件必然抓不到误判「远程命令
根本不执行」
机队体检诊断 · md5 快照四台三个 md5当天连发 4 版、各机停在不同 PR,窗口期快照本身就是分叉的误判
「自愈有盲点」
身份门云电脑 · 发送护栏护栏正常拒发喂进去的会话名是黑窗标题碎片停摆 4.5h +
误判版本回归
空跑监控GHA · 元监控run 时长 < 90s代理指标两头都会错(真跑也可能快、空跑也可能慢)监控自己
也要返修 #1104
0
本次清出的假成功实例(企微通道 · 7 月单月)
0
团队 memory 里写的是同一失败模式,占 891 条的 5%——横跨 bash / Supabase / Vercel / ADB / 云电脑 / Lark / GHA
0
07-02 一天内 loop 连撞的版本号(.1 → .11)+ 服务端 5 个 commit
0
空回复保险恒 false、无人知情的时长(记录原文写「三周」)
Signal

团队 memory 里已经独立命名过这个模式至少三次:《「绿」不等于「在保护」》《deploy 状态 ≠ 真相》《supabase 失败静默返回 0 条》。同一根因被反复重新发现,本身就是它没被系统性处理的证据。

03
Detection latency

延迟由「有没有出口」决定,跟严重性无关

把 7 月各起故障按「发现用了多久」排开,规律非常干净:只要失败在日志里留下一行,就是分钟级;只要它伪装成成功,就是天到周量级。严重性完全不影响这个排序。

读屏漏读有出口 · 日志有「跳过」行18 min
黑窗遮挡停摆无出口 · 表现为「没回」4.5 h
一台机整体停摆无出口 · 干跑+看门狗被停≈1
脚本镜像冻死无出口 · 记忆写着「已实现」2
空回复保险恒 false无出口 · 代码在册19

// 条长为 log₁₀(分钟) 归一化,否则前两项在图上看不见。样本取自部署台账与 memory 中有明确起止记录的 5 起;发现时刻本身未被制度化记录(见 §07 缺口 E),所以这是能拿到的最强证据、不是全量分布。

04
Cost per iteration

乘数项:一次复现有多贵

定位轮数要乘上单轮成本才是真实开销。这条链的验证发生在真机 GUI 上——两台云电脑对练、每轮必清 4 处状态、一句回复动辄几十秒到十几分钟。

回复延迟 · 中位customer → ai reply44 s
回复延迟 · P90n = 25 轮178 s
回复延迟 · 最长单轮764 s

// 我从 07-19 那份实盘归档逐轮算的(aiReplyAt − customerAt,n=25)。那次 26 轮从 07-17 09:03 一直跑到 07-19 13:21

STATE RESET每轮必清 4 处

服务端归档会话 + 蓝方去重台账 + 两台企微清屏 + 红方进度文件。漏一处就串台,而串台的表现和真 bug 长得一样。

GUI ONLY单测测不出这一族

「客户消息落库 → 生成 → GUI 上屏」这条链上的丢单,离线评测和单测全测不出——只有造一个镜像对手 loop 连续冲它才会暴露。

DEAD END确定性读取已判死

企微聊天界面是自绘原生 UI:调试端口只暴露文档预载 webview、无障碍树恒空。探针已入库,别再花时间试 DOM / UIA / CDP

05
Self-audit · corrections

上一轮结论的三处修正

第一轮给出的是「四种税」清单。复核之后,其中一条属于过度归因、一条过于乐观、一条诊断层次不对——修正后结论反而更锐。

修正 ① 过度归因38% 配对失败 ≠ 信号脏

我把它当成「红蓝 harness 自己产假 bug」的硬证据。复核发现:那 10 条文本干净通顺、不像被读歪;归因是归档文件自己写的「可能被读侧改写/漏字」;而当时回放的剧本 从未进过版本控制git log --all 零命中),今天已无法复核。

正确表述:证据链不可复核

修正 ② 过于乐观「版本税已消掉」说早了

自更新链路(md5 比对 + 预启动同步 + 看门狗)确实落地了、方向对。但它上线当晚就被端到端探针逼出 3 个真 bug;现在风险已反转到另一头:07-29 单日合 8 个 PR、脚本至少发 4 版,自愈会在 ~10 分钟内把新版铺满全部生产机——没有灰度、没有观察窗、没有回滚演练

风险反转:发布节奏 > 治理能力

修正 ③ 层次不对不是「缺观测」,是「信号会说谎」

第一轮开的处方是「补心跳告警」。诊断层次错了:现有信号不是没有,而是会说谎。如果新加的心跳也只报「进程还在」,它就是第 15 个假成功——看门狗自己就踩过(rc=0 但空转)。

验收标准:它怎样才会红?

方法论

三处修正有个共同点:我复用了记录里现成的归因,而没有去验那个归因本身。这正是 §02 描述的同一个陷阱在分析层的复现——「记录说 X」和「X 是真的」之间,仍然需要一个外部断言。

06
Counter-evidence

每次周期被压缩,做的都是同一个动作

这是「假成功是关键因素」最强的反面证据:把 7 月所有确实见效的改进摆在一起,它们全是同一个动作——把判断依据从「返回码 / 哈希 / 时长 / 模型推理」换成「该层之外的业务事实」

要判什么原来看(proof-of-call)换成看(proof-of-effect)效果
自愈跑没跑四台 md5 是否相等机上日志有没有 [sync] updated 轨迹推翻误判
进程起没起rc=0进程存在性(按命令行匹配)不再空转
日志能不能写直接拉起、失败再说先用同一个操作探测追加写,成功才拉起6~12s 起来
(原本等 5min)
评审跑没跑run 时长 < 90sPR 上有没有真的出现评论#1104
消息发没发到DB 的 sent 标记上屏核验灭掉假发送
该改哪一层让 LLM 判 fixTarget确定性规则分层(6 个候选模型全 0/2400 条回测
仅 2 条命中且都真
质检结论真假让模型再读一遍对话外部证据:同事名册 / 演练剧本原文 / 部署时间5 条里 0 条
该照着改
整族丢单逐个变种打正则补丁欠答自愈:末条是客户且其后无回复就一律补生成从机制上灭族
一条可执行的判据:任何一层报「成功」时,先问一句——这个结论是它自己签发的,还是由它之外的事实证明的?前者一律当「未知」,后者才算数。等价于团队 memory 里那句更短的版本:看到绿先问「它到底怎样才会红」。
07
Secondary factors

其余六项:乘数与治理

它们不是根因,但会把根因的代价放大,或者让代价无法被看见。按杠杆从大到小排。

B · 单轮验证贵(乘数)

  • 真机 GUI 对练,两台云电脑同时在线
  • 每轮清 4 处状态,漏一处就串台
  • 单轮 44s / P90 178s / 最长 764s
  • 26 轮实盘跨 2 天

C · 配置无事实源

  • 四份 .env 各自手改
  • 一台限流 20/8/6 + 12-30s,另三台 200/50/100 + 5-12s
  • 代码已能自动收敛,配置还在四个人手里
  • 同症状在不同机器上表现不同 → 归因更难

D · 兜底状态自相矛盾

  • 一台在生产真发,但看门狗仍是 Disabled——唯一无兜底的生产机,且前一天刚停摆过
  • 另一台 STOP 闸挂着但看门狗 Ready → 删掉 STOP 就会用两版之前的旧代码上生产

E · 没有 incident 时间戳

  • 部署台账记了部署时间和「起因」
  • 但没有 detected_at / rootcaused_at
  • →「哪一段最长」只能靠事后翻档复盘
  • 这个痛点至今无法被量化管理

F · 测试流量污染生产判据

  • 红蓝 harness 打生产端点,跑完归档不删会话
  • → 会话 id 非空 →「推演豁免」盖不住 → 误页
  • 现用「≥2 个会话才告警」缓解,本质是猜

G · 证据链不可复核

  • 回放剧本 从未进版本控制,事后无法重新配对
  • 26 轮里 10 轮(38%)至今无法归因
  • 红蓝跑出的结论因此不能被第二个人复验
08
Recommended actions

按 ROI 排的七件事

每一条都附「它怎样才会红」——没有这一栏的防线,本身就是下一个假成功

T1

给每层的「成功」补一个外部断言

清单化、进 review checklist:返回码 → 进程存在性deploy → 线上 md5/commit评审 → 评论数发送 → 上屏核验查询 → error 必抛。这是把 §06 那张表制度化,而不是每次靠人想起来。

怎样才会红:抽掉被断言的那一环,检查必须立刻变红

T1

蓝方停摆上云告警

loop 已按纪律把双指标写进本地状态文件,但云端没有任何东西读它(全仓 grep 零命中)。让 loop 每轮上报状态,一个 cron 比 last_tick + 业务 delta,超阈值推红牌。直接缩短 §03 里最长的那几根条。

怎样才会红:杀掉 loop 后必须在 N 分钟内自己弹红牌

T2

红蓝收工做成确定性动作

跑红方会停掉蓝方的 loop 与看门狗两个任务,收工只删 STOP 闸不够。改成 红方退出即自动恢复这两个任务(或让看门狗无条件自恢复)。07-29 那 4.5 小时就是这条纪律漏了。

怎样才会红:红方异常退出后,蓝方必须自己回来

T2

测试流量打显式标记位

给 harness 的调用加一个显式 tag(header 或字段),所有告警、质检、统计按 tag 排除。替掉现在「≥2 个会话才告警」的猜法——那个阈值同时会漏掉真实的单会话爆发。

怎样才会红:带 tag 的流量必须 0 次进入告警与质检台账

T3

剧本与人物卡进版本控制

回放剧本、人物卡、以及每次跑的运行时快照全部入仓。目标不是好看,是让 38% 的配对失败可以被事后归因、让红蓝结论能被第二个人复验。

怎样才会红:拿历史 run 重跑配对,命中率应可复现

T3

台账加两个时间戳

部署台账的「起因」段固定加 detected_at / rootcaused_at。成本近零,下个月就能直接出「发现 / 定位 / 修复」三段的真实分布,不用再像本页这样靠翻档估。

怎样才会红:缺这两个字段的条目在月度复盘里计为不可分析

T3

自愈加灰度与回滚演练

现状是 ~10 分钟铺满全部生产机、无观察窗。加 canary / stable 两档 + 定期回滚演练。这条是修正 ② 带出来的新风险,不在第一轮结论里。

怎样才会红:故意发一版坏脚本,canary 必须先炸且 stable 不受影响

不建议做继续加正则补丁 / 试 DOM 读取

逐个变种打补丁已被证明追不上(样板文案家族反复复发);确定性读取路线(DOM / UIA / CDP)已判死并入库探针,别再重新评估。

09
Method & limits

口径、数据源与没能验证的部分

按团队规矩,先说清哪些是我算的、哪些是转述的、哪些至今没法验

数据源

  • 7 月 commit 流(两个仓,按作者过滤)
  • 部署台账 deploy-ids.md 逐段记录
  • 团队 memory 891 条全量清点
  • 07-19 红蓝实盘归档(26 轮 · 双裁判)
  • 云电脑侧脚本与自更新链路现状核实

我算的口径

  • 回复延迟 = aiReplyAt − customerAt,n=25
  • 配对失败率 = unmatched ÷ 26
  • 43 条 = 严格正则命中的 memory 文件数(已排除 dry-run「空跑」等同词歧义)
  • 延迟条长 = log₁₀(分钟) 归一化

没能验证

  • 4.5 小时停摆时长为单一来源(当事人记录),无第二方时间戳
  • 回放剧本已不可查 → 38% 配对失败无法复核
  • 未拉 PR open→merge 时间线:发现 / 定位时刻从不落盘,PR 时间代表不了周期
  • 样本仅企微方案B 通道,抖音通道未纳入——结论向那边迁移前要重新取证
一句话总括:红蓝对抗把 bug 造出来的效率很高,卡住的是「发现」和「核查」——而这两段的长度由同一个属性决定:每一层在失败时都返回成功。7 月所有真正见效的改进,做的都是同一件事:把判断从「它说它成功了」换成「有外部事实证明它成功了」。剩下的缺口,接着用这一招压。