baa-conductor

git clone 

baa-conductor / coordination / tasks / done
im_wower  ·  2026-03-22

T-029-stability-regression.md

  1---
  2task_id: T-029
  3title: 多节点长时间稳定性回归
  4status: done
  5branch: feat/T-029-stability-regression
  6repo: /Users/george/code/baa-conductor
  7base_ref: main@926860a
  8depends_on:
  9  - T-028
 10write_scope:
 11  - docs/ops/**
 12  - docs/runtime/**
 13  - tests/e2e/**
 14  - scripts/smoke/**
 15  - scripts/failover/**
 16  - scripts/runtime/**
 17updated_at: 2026-03-22 05:35:00 CST
 18---
 19
 20# T-029 多节点长时间稳定性回归
 21
 22## 目标
 23
 24在真实 mini / mac / VPS / Cloudflare 环境上完成一轮长时间稳定性回归,确认主备、探活、控制面和 smoke 脚本在真实环境下可持续工作。
 25
 26## 本任务包含
 27
 28- 基于 `T-028` 已上线环境跑多轮 smoke / failover / 恢复
 29- 记录长时间运行期间的 `healthz`、`readyz`、`rolez`、`/v1/system/state`、`/v1/status`
 30- 至少覆盖一次 planned failover 和一次 switchback
 31- 把异常、抖动、人工干预点和最终结论写入回归报告
 32
 33## 本任务不包含
 34
 35- 重新部署 Cloudflare / VPS
 36- 重写 control-api / conductor / status-api 代码
 37- 修改 `baa-firefox` 仓库
 38
 39## 建议起始文件
 40
 41- `tests/e2e/smoke.test.mjs`
 42- `scripts/smoke/run-e2e.sh`
 43- `scripts/failover/rehearsal-check.sh`
 44- `scripts/runtime/check-node.sh`
 45- `docs/ops/README.md`
 46
 47## 交付物
 48
 49- 一份真实环境稳定性回归记录
 50- 一份 failover / switchback 实测结果
 51- 必要时更新后的 smoke / failover / on-node 文档
 52
 53## 验收
 54
 55- 能给出至少一轮真实环境 smoke 结果
 56- 能给出至少一次 failover 和一次 switchback 的结果
 57- `git diff --check`
 58
 59## 更新要求
 60
 61完成时更新 frontmatter 的:
 62
 63- `status`
 64- `base_ref`
 65- `updated_at`
 66
 67并补充下面这些内容:
 68
 69## files_changed
 70
 71- coordination/tasks/T-029-stability-regression.md
 72- docs/ops/README.md
 73- docs/ops/real-stability-regression-2026-03-22.md
 74- scripts/smoke/README.md
 75- scripts/smoke/live-regression.mjs
 76
 77## commands_run
 78
 79- `npx --yes pnpm install`
 80- `./scripts/failover/print-topology.sh --env /Users/george/.config/baa-conductor/ops.env`
 81- `./scripts/failover/rehearsal-check.sh --env /Users/george/.config/baa-conductor/ops.env --basic-auth "$DIRECT_BASIC_AUTH" --bearer-token "$CONTROL_API_OPS_ADMIN_TOKEN" --expect-leader mini`
 82- `node scripts/smoke/live-regression.mjs --env /Users/george/.config/baa-conductor/ops.env --control-secrets /Users/george/.config/baa-conductor/control-api-worker.secrets.env --basic-auth-file /Users/george/.config/baa-conductor/direct-node-basic-auth.env --expect-leader mini`
 83- `./scripts/runtime/check-node.sh --repo-dir /Users/george/code/baa-conductor-T028-v2 --node mini --service conductor --service status-api --install-dir /Users/george/Library/LaunchAgents --local-api-base http://100.71.210.78:4317 --local-api-allowed-hosts 100.71.210.78 --status-api-base http://100.71.210.78:4318 --status-api-host 100.71.210.78 --expected-rolez leader --check-loaded`
 84- `ssh george@100.112.239.13 'cd /Users/george/code/baa-conductor-T028-v2 && ./scripts/runtime/check-node.sh --repo-dir /Users/george/code/baa-conductor-T028-v2 --node mac --service conductor --service status-api --install-dir /Users/george/Library/LaunchAgents --local-api-base http://100.112.239.13:4317 --local-api-allowed-hosts 100.112.239.13 --status-api-base http://100.112.239.13:4318 --status-api-host 100.112.239.13 --expected-rolez standby --check-loaded'`
 85- `for i in 1 2 3 4 5 6 7; do node scripts/smoke/live-regression.mjs ... --expect-leader mini --compact; sleep 300; done`
 86- `ps -axo pid=,command= | grep '/apps/worker-runner/dist/index.js' | grep -v grep || true`
 87- `ssh george@100.112.239.13 "ps -axo pid=,command= | grep '/apps/worker-runner/dist/index.js' | grep -v grep || true"`
 88- `curl -X POST ... https://control-api.makefile.so/v1/system/drain`
 89- `curl -X POST ... https://control-api.makefile.so/v1/system/pause`
 90- `launchctl bootout "gui/$(id -u)" "$HOME/Library/LaunchAgents/so.makefile.baa-conductor.plist"`
 91- `./scripts/failover/rehearsal-check.sh --env /Users/george/.config/baa-conductor/ops.env --basic-auth "$DIRECT_BASIC_AUTH" --bearer-token "$CONTROL_API_OPS_ADMIN_TOKEN" --skip-node mini --expect-leader mac`
 92- `curl -X POST ... https://control-api.makefile.so/v1/system/resume`
 93- `ssh george@100.112.239.13 'launchctl bootout "gui/$(id -u)" "$HOME/Library/LaunchAgents/so.makefile.baa-conductor.plist"'`
 94- `cd /Users/george/code/baa-conductor-T028-v2 && ./scripts/runtime/reload-launchd.sh --service conductor --install-dir /Users/george/Library/LaunchAgents`
 95- `./scripts/failover/rehearsal-check.sh --env /Users/george/.config/baa-conductor/ops.env --basic-auth "$DIRECT_BASIC_AUTH" --bearer-token "$CONTROL_API_OPS_ADMIN_TOKEN" --skip-node mac --expect-leader mini`
 96- `ssh george@100.112.239.13 'cd /Users/george/code/baa-conductor-T028-v2 && ./scripts/runtime/reload-launchd.sh --service conductor --install-dir /Users/george/Library/LaunchAgents'`
 97- `dig @giancarlo.ns.cloudflare.com +short conductor.makefile.so`
 98- `echo | openssl s_client -servername conductor.makefile.so -connect 192.210.137.113:443 2>/dev/null | openssl x509 -noout -dates`
 99
100## result
101
102- 新增 `scripts/smoke/live-regression.mjs`,把 control-api、公网入口、直连入口、status-api 和鉴权结果收成一份真实环境快照;`scripts/smoke/README.md` 与 `docs/ops/README.md` 已补用法与报告入口。
103- 在 live `mini/mac/VPS/Cloudflare` 环境上完成了一轮基线 smoke、一轮 `30.3` 分钟持续观察、一次 planned failover 和一次 switchback,并把过程写入 `docs/ops/real-stability-regression-2026-03-22.md`104- steady-state 结论:control-api、公网 conductor、mini/mac 直连 conductor、Basic Auth、mini/mac on-node `check-node.sh` 都可以工作;final steady-state 已回到 `mini-main` leader、`mac-standby` standby、`mode=running`。
105- failover / switchback 都真实成功,但都观察到了短暂外部不一致窗口:停掉当前 leader 后,公网或恢复中的节点会先返回 `standby`,随后才稳定到新的 `leader`106- 本轮 smoke 没有完全通过:两台节点的 `status-api /v1/status` 全程都停在 `source=empty`, `mode=paused`, `leaderId=null`,与 control-api 真相不一致。
107
108## risks
109
110- live `status-api` 目前不是可靠真相源;它不能用来判断自动化是否真的在 `running`,也不能确认当前 leader、queueDepth 或 activeRuns。
111- mini/mac 两侧 launchd 安装副本仍然指向 `/Users/george/code/baa-conductor-T028-v2`,还没有整理到 canonical repo path `/Users/george/code/baa-conductor`112- switchback 不是“停 mac、起 mini”就完全结束;要恢复 canonical `mini leader + mac standby`,还需要额外显式 reload `mac` conductor。
113- authoritative DNS 仍是 DNS-only,Cloudflare proxy 没有重新开启;本轮没有尝试把 conductor hosts 切回橙云。
114- 本机非权威 DNS / 代理层对 `conductor.makefile.so`、`mac-conductor.makefile.so` 的解析与权威结果不一致,直接做 DNS/TLS 诊断时必须区分 authoritative 结果和本地 resolver 结果。
115- 在 planned failover 前,我有一次把 `GET /v1/system/state``POST /v1/system/pause` 并行发出,所以那次 `mode=paused` 读数不能单独拿来证明 `drain` 的独立效果;后续状态读取都改回串行。
116
117## next_handoff
118
119- 优先排查 live `status-api` 为什么持续返回 `source=empty`,并让 `/v1/status` 跟随 control-api 的真实 leader / mode / queue state。
120- 规划一次 runtime canonicalization,把 mini/mac 的 launchd、logs、runs、worktrees 路径从 `/Users/george/code/baa-conductor-T028-v2` 收口到 `/Users/george/code/baa-conductor`121- 如果要把 switchback 降为更可重复的运维流程,runbook 或脚本层需要显式补上“恢复 mac standby”的尾步骤。
122- 如果后续要重新启用 Cloudflare proxy,先把 DNS / TLS / zone SSL 模式的真实控制面整理清楚,再做单独演练,不要在当前 DNS-only 基线之上直接切橙云。
123
124开始时建议直接把 `status` 改为 `in_progress`125
126做完并推送后:
127
128- 如果等待整合,改为 `review`
129- 如果确认结束,改为 `done`