# 2026-05-04 Agent健身房复盘
一句话概括:**这次发现的不是已经自动修复的问题,而是 5 类以后会反复浪费时间的操作摩擦 / 工具缺口。**
| 优先级 | 发现的问题 | 真实含义 | 计划怎么解决 |
| --- | --- | --- | --- |
| 1 | 推文日报每次失败都要重新确认环境 | 真实卡点不是抓取逻辑,而是 roster 缺失、provider DNS、Odyssey 写权限、记忆路径展开这些前置条件;不预检就会把环境问题误判成限流或无内容。 | 做 `twitter_fetcher_preflight_doctor.py`,抓取前检查仓库、账号名单、key、DNS、目标目录和 `CODEX_HOME`,失败时只写 fallback 诊断包。 |
| 2 | 外部平台任务经常卡在登录态、会员和权限 | Get笔记已经装好并授权但被 `not_member` 挡住,ElevenLabs/知乎也分别受登录、MFA、反爬和内容完整性影响;需要先判断平台是否 READY。 | 做 `external_platform_readiness_doctor.py`,按平台输出 READY / 需要用户操作 / 会员阻塞 / 反爬阻塞,并给出交接下一步。 |
| 3 | Viva 语境解释靠临时手测推动 | 同一天里连续处理了上下文窗口、多义词、占位 fallback、API key 来源、句中角色等问题;没有固定 case 集,下一次 prompt 小改还会靠肉眼判断。 | 把 5 个 bad case 固化成 tooltip regression bench,检查当前义、句中角色、禁用占位文案、同词重复定位和 helper 配置来源。 |
| 4 | Agent健身房产物生成后缺少自检 | 出现过 plist 磁盘/已加载时间不一致、主子进程 token 统计易漏、中文本地化破坏 `审批.sh` 的真实 bug;这些会直接影响早上 review 的可信度。 | 做 Night Gym package doctor,检查 schedule、子分析完成、token 合计、manifest/example 完整性、中文命名和审批脚本 dry-run。 |
| 5 | 通知监听类 LaunchAgent 容易误触发 | 番茄 watcher 把 `without presenting` 当成番茄结束,后续又发现 `log stream` 启动失败会引发二次异常;类似 watcher 都需要样例回放和运行态检查。 | 做 Pomodoro LaunchAgent doctor,统一检查 plist、进程唯一性、log stream、通知样例回放、state 文件和历史残留 label。 |
## 下一步
| 顺序 | 先做什么 | 为什么 |
| --- | --- | --- |
| 1 | 先做推文日报预检脚本 | 这是当前还未恢复的自动化链路;做完后每晚失败会直接给 root cause,不再重复追仓库、DNS 和权限。 |
| 2 | 再做外部平台 readiness 统一口径 | Get笔记、ElevenLabs、知乎都证明了登录/会员/反爬要先判定,否则 agent 会把不可代办步骤当成技术实现问题。 |
| 3 | 把 Viva tooltip 的 5 个 case 固化 | 它能把 prompt 小改从“看起来更好”变成可复跑的产品质量门禁。 |
| 4 | 补 Night Gym 自检 | 这是保证以后早间复盘可读、可审批、可追成本的基础设施。 |
| 5 | 最后补 watcher doctor | 误触发已经修掉,但把诊断沉淀下来可以复用到其他通知监听/遮罩类任务。 |
## 一、候选详情
### 1.1 推文日报抓取预检诊断工具
- 类型:`diagnostic-tool`
- 风险:`low`
- 概要:该主题有效,不是噪音。相关片段显示每日推文日报的失败反复集中在运行前提:仓库文件缺失、repo-local roster 缺失、双 provider DNS 失败、目标目录不可写,以及自动化记忆路径未正确展开。预检工具可以在真正抓取前给出分层诊断和 fallback 路径,避免把环境问题误判为没有推文、provider 限流或脚本逻辑错误。
计划改动:
- 新增工具入口 `scripts/twitter_fetcher_preflight_doctor.py`:支持 `--repo <path>`、`--target-date YYYY-MM-DD`、`--json-out <path>`、`--markdown-out <path>`。输入来源包括 repo-local `.claude/skills/config.json`、`skills/twitter-fetcher/*` 工作树/HEAD 状态、环境变量 `TWITTERAPI_IO_KEY`/`SOCIALDATA_API_KEY`、目标输出目录、自动化记忆路径 `$CODEX_HOME/automations/automation/memory.md`。
- 核心检查步骤按阻塞链排序:1) `git status --short` 检查 `skills/twitter-fetcher` 是否被删,必要时用 `git show HEAD:...` 读取 canonical 接口;2) 解析 `.claude/skills/config.json`,确认 `skills.twitter-fetcher.users` 非空并回传账号数;3) 检查 provider key 是否存在;4) 对 `api.socialdata.tools` 和 `api.twitterapi.io` 做 DNS/socket 预检;5) 对 `~/Downloads/twitter_output`、Odyssey research 目录和 repo `.codex_tmp/` 做写入测试;6) 展开并校验 `CODEX_HOME`,避免落到 `/automations`。
- 成功/失败信号标准化:输出 JSON 包含 `overall_status=pass|warn|fail`、`checks[]`、`blocking_reasons[]`、`next_action`。成功信号是脚本存在或可从 HEAD 回看、roster 非空、至少一个 provider DNS/key 可用、目标目录可写;失败信号包括 `missing_fetcher_files`、`missing_roster`、`provider_dns_failed`、`target_not_writable`、`codex_home_unexpanded`,exit code 用 `0=pass`、`1=warn/fallback`、`2=blocking fail`。
### 1.2 外部平台登录与权限就绪检查
- 类型:`diagnostic-tool`
- 风险:`medium`
- 概要:这个主题有效:多个片段都不是单纯功能实现问题,而是外部平台账号、登录态、API 鉴权、会员权益和反爬策略未就绪导致的阻塞。把这些前置条件做成可复用 doctor,可以在进入抓取、安装 skill、生成内容前先判断是 READY、需要用户登录,还是被会员/平台策略挡住。
计划改动:
- 新增诊断工具入口:在 Night Gym 工具集中加 `scripts/external_platform_readiness_doctor.py`,命令形态为 `python scripts/external_platform_readiness_doctor.py --platform getnote|elevenlabs|zhihu --task read|write|clone|scrape --target <url_or_api>`;也可沉淀为 Codex skill `~/.codex/skills/external-platform-readiness/SKILL.md`,让后续外部平台任务先调用 doctor。
- 输入来源:读取 `~/.codex/secret.env` 中的 API key/client id、平台配置清单 `~/.codex/external-platforms.json`、当前内嵌浏览器 profile 的登录态检查 URL、以及任务目标 URL/API;禁止读取或记录短信验证码、密码、MFA 内容,只记录是否出现凭证门槛。
- 核心检查步骤与信号:依次检查凭证是否存在、API 鉴权 smoke test、会员/plan entitlement、浏览器登录态、反爬/风控页、目标内容完整性。成功信号为 `READY` 加可读/可写/可生成能力;失败信号分为 `USER_ACTION_REQUIRED`、`AUTH_MISSING`、`ENTITLEMENT_BLOCKED`、`ANTI_BOT_BLOCKED`、`PARTIAL_CONTENT_ONLY`。
### 1.3 Viva语境解释回归评测台
- 类型:`tool-upgrade`
- 风险:`low`
- 概要:该主题有效:片段显示 Viva tooltip 的语境解释问题不是单一 bad case,而是上下文窗口规则、多义词释义、占位 fallback、API key 来源和缓存共同影响用户感知。建议把当时的临时 5 case 表格测试固化为可重复运行的回归评测台,后续每次改 helper prompt、fallback 或上下文提取逻辑都能先跑一遍。
计划改动:
- 在 Viva 插件仓库新增 `helper/tests/fixtures/tooltip_regression_cases.jsonl`:沉淀至少 5 个语境释义 case,字段包含 `expression`、`sentence`、`parent_text`、`selection_offset`、`expected_sense_zh`、`required_role_zh`、`forbidden_phrases`,覆盖 `trillion`、`charge`、同词重复、数字表达、专名/短语修饰功能。
- 新增 `helper/tools/run_tooltip_regression.py`:从 fixture 读取输入,优先调用与插件一致的 helper 入口;支持 `--helper-url` 调常驻 `Anki导入助手`,支持 `--local` 直接跑 `helper/anki_concept_helper.py`;输出 `out/tooltip_regression/latest.json` 和 Markdown 表格,并对 API key 只做存在性检查和脱敏日志。
- 扩展 `helper/tests/test_anki_concept_helper.py` 或新增 `helper/tests/test_tooltip_regression.py`:断言 `tooltipExplanationZh` 不能是占位句,必须包含目标表达在句中的语义和句法/功能角色;同时加入父容器内同词重复的 `selection_offset` 测试,防止 fallback `indexOf(expression)` 命中第一次出现的同词。
### 1.4 Agent健身房运行与候选包自检
- 类型:`diagnostic-tool`
- 风险:`low`
- 概要:这个主题有明确价值,不是噪音:片段同时覆盖了 Night Gym 的定时运行漂移、fan-out 子进程成本统计、候选包本地化/命名要求、后处理脚本破坏 JSON 的真实 bug,以及早间复盘模板质量门禁。适合沉淀成一个 read-only doctor,在每晚运行结束后先判断运行是否真实完成、候选包是否完整可审批、成本是否被低估,再把修复建议输出给早间复盘。
计划改动:
- 工具入口:在 Night Gym 根目录新增 `scripts/night_gym_package_doctor.py`,命令形态为 `python scripts/night_gym_package_doctor.py --run-dir /Users/bytedance/.codex/night-gym/runs/YYYY-MM-DD --plist ~/Library/LaunchAgents/Agent健身房.plist --json`;在每次主流程生成 `out/manifest.json` 后自动运行,并把结果写入 `out/诊断报告.json` 与 `out/诊断报告.md`。
- 输入来源:读取磁盘 LaunchAgent plist、`launchctl print gui/$UID/Agent健身房` 的 loaded job 状态、run 目录里的 `master.log`、`out/sub/*.log`、`out/sub/*.json`、`out/manifest.json`、`out/MORNING_REVIEW.md`、`out/approve.sh`,以及必要时的 Codex session usage/rate_limits 记录。
- 核心检查步骤与成功/失败信号:检查磁盘 plist 与 loaded 触发时间/命令/输出目录是否一致,成功信号为 `schedule_consistent`,失败信号为 `plist_loaded_drift`;检查主进程和所有子 agent 的 `tokens used` 是否被合并,成功为 `usage_complete`,失败为 `subagent_usage_missing`;检查每个候选都有 `SUBAGENT_DONE`、合法 JSON、required fields、中文标题/文件名、示例 markdown,成功为 `package_complete`,失败为 `missing_sub_json`、`invalid_json`、`non_localized_filename`;检查 `approve.sh` 可在临时 manifest 上 dry-run,不破坏 JSON,成功为 `approval_script_ok`,失败为 `approval_script_breaks_json`。
### 1.5 番茄通知监听诊断工具
- 类型:`diagnostic-tool`
- 风险:`low`
- 概要:这个主题有明确价值:片段里出现了真实的番茄未结束却触发事件,并且根因是 macOS 通知日志中 `without presenting` 被粗糙关键词匹配误判。它适合沉淀成一个可复用 doctor,把 LaunchAgent 状态、watcher 进程、log stream、通知样例回放和历史残留记录一起检查,避免每次靠临时排查。
计划改动:
- 在 `/Users/bytedance/Documents/product-bu/scripts/pomodoro_launchagent_doctor.py` 增加诊断工具入口,支持 `--service-label`、`--plist`、`--watcher-script`、`--log-sample`、`--live-seconds` 参数;默认读取 `~/Library/LaunchAgents` 下的番茄 watcher plist 和近端 `log stream` 输出。
- 核心检查步骤固定为:解析 plist 语法和 ProgramArguments;用 `launchctl print gui/$UID/<label>` 判断服务是否 running;用 `pgrep -af` 检查 watcher 与 TickTick `log stream` 是否重复;回放通知日志样例,确认只允许 `category:"pomoEmpty"` 或等价强信号触发,拒绝 `without presenting`、`pomoRelax`、普通任务提醒。
- 成功/失败信号要结构化输出:成功时打印 `status: ok`、active PID、唯一 log stream PID、匹配样例结果;失败时打印 `status: fail`、问题类型如 `duplicate_watchers`、`weak_presenting_match`、`log_stream_start_error`、`stale_launchctl_disabled_record`,并给出下一步修复命令或文件位置。
## 二、证据摘要
### 2.1 推文日报抓取预检诊断工具
- `019df081-31c8-7ed3-825f-a508581743b3` / `~/Documents/Codex/2026-04-21-https-github-com-haopenglau-skills/repo`:使用当前工作区仓库里的 twitter-fetcher 流程抓取配置文件 .claude/skills/config.json 中 twitter-fetcher.users 的账号列表,使用其中的 SOCIALDATA_API_KEY 或 TWITTERAPI_IO_KEY 访问 socialdata.tools。
- `019df081-31c8-7ed3-825f-a508581743b3` / `~/Documents/Codex/2026-04-21-https-github-com-haopenglau-skills/repo`:当前仓库现态和上次记忆一致:工作树里没有 `twitter-fetcher` 目录,当前 `.claude/skills/config.json` 也没有 `skills.twitter-fetcher.users`。
- `019df081-31c8-7ed3-825f-a508581743b3` / `~/Documents/Codex/2026-04-21-https-github-com-haopenglau-skills/repo`:`api.socialdata.tools` 和 `api.twitterapi.io` 都继续报 DNS 解析失败;目标 Odyssey 目录 `~/Library/Mobile Documents/com~apple~CloudDocs/odyssey/0 收集箱/research` 也仍然不可写。
### 2.2 外部平台登录与权限就绪检查
- `019df25e-942f-70c0-98d1-49f8b9579510` / `~/Documents/info-bu`:API 前提:Get笔记 OpenAPI 需要会员,并且请求要带 Authorization 和 X-Client-ID。结论:应该从 getnote-openclaw 仓库迁移成 Codex Skill,并补上 Codex 侧的鉴权配置。
- `019df25e-942f-70c0-98d1-49f8b9579510` / `~/Documents/info-bu`:浏览器里现在是手机号验证码登录弹窗。手机号和短信验证码属于敏感凭证/身份信息,这一步需要你在打开的页面里自己填并登录。
- `019df25e-942f-70c0-98d1-49f8b9579510` / `~/Documents/info-bu`:冒烟验证结果:API 鉴权已经能打到 Get笔记,但返回 10201 / not_member,也就是当前账号没有 OpenAPI 会员权限。
### 2.3 Viva语境解释回归评测台
- `019df1d4-5513-72b0-aed4-5f095dd13771` / `~/Documents/product-bu`:现在我那个插件做那个语境内该单词的解释的时候,它找的语境窗口是多大的?这个规则是什么?因为我发现这里有bad case。
- `019df1d4-5513-72b0-aed4-5f095dd13771` / `~/Documents/product-bu`:上下文不是按“前后 N 个词/字符”取,而是按“当前句子”取,再统一截到 300 字符。这个 bad case 更像是“句子级窗口够短但模型/候选词典义被多义词带偏”。
- `019df1d4-5513-72b0-aed4-5f095dd13771` / `~/Documents/product-bu`:“结合原句理解 trillion 的具体意思。”不是模型生成的内容,是扩展在 helper 没返回有效释义时自己补出来的占位文案。这个占位会误导用户。
### 2.4 Agent健身房运行与候选包自检
- `019decee-0f1f-7113-a8e7-5a6e148bc793` / `~/Documents/learning-bu`:磁盘上的 plist 现在写的是 `04:00`,但 `launchctl print` 里当前已加载的触发器还是 `01:00`。所以昨晚实际按 `01:00` 跑了。
- `019decee-0f1f-7113-a8e7-5a6e148bc793` / `~/Documents/learning-bu`:主进程日志明确写了 `tokens used 123,873`。但 Night Gym 还 fan-out 了 5 个子 Codex 实例;我继续把子实例各自的 `tokens used` 也取出来。
- `019decee-0f1f-7113-a8e7-5a6e148bc793` / `~/Documents/learning-bu`:发现一个后处理 bug:`审批.sh` 里对 `候选清单.json` 的替换破坏了 Python 字符串引号。我现在修成直接重写一个稳定的中文审批脚本。
### 2.5 番茄通知监听诊断工具
- `019df1dc-82c5-7160-b149-1ea604b959b5` / `~/Documents/product-bu`:我的番茄还没结束,这个就触发了,排查下
- `019df1dc-82c5-7160-b149-1ea604b959b5` / `~/Documents/product-bu`:脚本用关键词 `Presenting` 判断番茄结束,但 macOS 的普通 TickTick 通知日志里会出现 `without presenting`,所以普通任务提醒也被误判成“番茄结束”。
- `019df1dc-82c5-7160-b149-1ea604b959b5` / `~/Documents/product-bu`:只有一个 watcher 进程和一个 TickTick `log stream` 子进程在跑,没有重复监听;plist 语法正常,服务状态是 running。