平台工程

云端定时内容生产连环坑复盘:全绿不等于已发

一句话:无人值守流水线的验收标准是业务产物(main 上的提交/线上的页面),不是 CI 状态——「全绿」完全可以是兜底分支伪装出来的失败。

事实记录(不可修改区)

排障过程

按发现顺序,每个坑修一轮、暴露下一个:

  1. schedule 不触发:workflow state=active、cron 正确、同仓库 deploy.yml 的 schedule 正常——排除配置问题,属 GitHub 对新 schedule 的已知不可靠行为。手动 dispatch 绕过,自然触发留观。
  2. OIDC 402→缺权限:claude-code-action@v1 硬性要求 id-token: write,补一行。
  3. 未装 GitHub App:action 默认走 App 的 OIDC 换 token;传 github_token: ${{ github.token }} 跳过(本任务只需在 runner 里写一个文件,GITHUB_TOKEN 足够)。
  4. 白名单闷杀搜索:curl … | grep … 这类组合命令要求每一段都在 allowedTools 内,只放行 curl 等于全拒。扩容常用只读文本工具(node/jq/grep/sed/head/python3 等)后 Claude 才第一次真正搜到料。
  5. 脏工作区丢提交:npm run build 自检顺手改写了 public/*/index.html(缓存戳脚本),后续 git pull --rebase 拒绝执行——期刊已生成、已 commit,却没能 push,白烧一次 API。push 前加 git checkout -- . 丢弃构建副产。
  6. 余额 402:报错只存在 runner 本地的执行输出 JSON 里,workflow 日志只有 is_error: true。加了「打印执行输出末尾」诊断步骤后一眼定位:402 Insufficient credits, balance $-0.05。充值后跑通。

结果分析

方法论沉淀(均为首次发现,暂时性结论)

⚠️ 全绿≠已发律(首次发现)

核心:带「不发」兜底分支的流水线,失败会伪装成成功——Claude 没产出文件时 verify 步骤走 exit 0,Actions 全绿,但什么都没发。验收和巡检必须盯业务产物,不看 CI 徽章。

来源:07-04 两次「成功」运行实际都是空手而归,徽章全绿。

操作规则:

  1. 巡检口诀:看 main 有没有当日 news(快讯) 提交 / 线上页面日期,不看 Actions 状态;
  2. 兜底分支不要静默 exit 0,至少 echo 出显著告警(有条件就发通知);
  3. 「宁缺毋滥」闸门(见前档)与本律是一对:闸门允许不发,本律要求不发必须可见

⚠️ 手动跑通会掩盖自动路径(对「人先跑通一遍」的边界修正,首次发现)

核心:前档主张「人先手动跑通再交给定时器」,本次暴露其盲区——手动发布让当日产物已存在,自动路径的幂等检查直接跳过,于是自动路径从未被执行过,而所有人都以为它验证过了。缺陷(OIDC/App/白名单/脏工作区)全部潜伏到第一次真实执行才连环引爆。

来源:07-03 那次 workflow 运行 8 秒「成功」,实为跳过;6 个坑全部在 07-04 首次真实执行时暴露。

操作规则:验证等级分三层分开记账,缺一不可:

  1. 手动跑通(人在环,验证流程设计);
  2. 自动路径真实执行(在产物不存在的条件下手动 dispatch 一次,验证权限/环境/脚本);
  3. 定时器自然触发(验证调度本身)。 本案例三层分别于 07-02、07-05 达成,第三层至今未达成。

⚠️ 黑盒 action 先接可观测性(首次发现)

核心:claude-code-action 的真实报错(API 402、denial 明细)只写在 runner 本地的 claude-execution-output.json,workflow 日志只给 is_error: true。盲修了三轮才想起把它打出来,一打出来 10 秒定位。

操作规则:接入任何黑盒 action,第一个 commit 就加 if: always() 的诊断步骤把其执行输出暴露到日志——排障顺序应是「先能看见,再动手修」。

⚠️ 换便宜模型≠更省(成本=单价×用量,首次发现)

核心:Sonnet 5 单价约为 Fable 5 的 1/3,首跑却花 $7.26 > $4.04——搜索行为更发散(爬 DuckDuckGo/Bing 结果页、for 循环批量查询),178 轮 vs 40 轮,用量放大 4 倍以上,把单价优势整个吃掉。

操作规则:

  1. agent 型任务换模型必须实测总成本,不能只看牌价;
  2. 给 agent 明确停止条件(「凑足 5-8 条立即收工」)和硬上限(--max-turns);
  3. 权限白名单拒绝会诱发换姿势重试,放大用量(本次 16 次拒绝)——白名单要么放够,要么在 prompt 里明说哪些路径走不通,别让它自己撞。

⭐⭐ 追记(2026-07-12):「schedule 不可靠」获二次验证

坑① 在另一仓库(typhoon-eye,台风数据每 15 分钟定时抓取)再次实证:每小时 4 班仅被放行约 1 班、整点连丢 4 班,GitHub 状态页全程 operational。该规律升 ⭐⭐ 二次验证,系统性兜底方案(外部 cron dispatch watchdog 型任务)见 B站Toy同步事故复盘_版本指纹与外部cron兜底_v1

下次改进

关联文档

类型/平台工程主题/自动化生产主题/踩坑