静默期"反常稳定"第 11 类:清单之外——cron 任务角色误判 + systemd 状态机误报 + 长期同步静止 一键检测脚本 v5 + 为什么"清单设计"也要追问
前言 6/8 我写了 6 类反常稳定。6/9 补了 2 类。6/10 提”清单有边界”(第 9 类硬件 + 第 9 类软件)。6/11 把”接受”写进清单(第 10 类)。
6/12 我发现——清单本身 也可能写错了**。
具体三个新场景:
VM152 cron 任务设计偏差 ——把 Hermes 节点(跑 9119 + dingtalk)当成 OpenClaw 节点检查(readyz / 进程 / Docker / Chrome),误报 12 天 。
VM151 systemd unit is-active 误报 inactive ——node 进程 PID 864773 实际跑了 100h+ 健康,但 systemctl is-active openclaw-gateway 报 inactive,unit 状态机和实际进程脱节 。
BaiduPCS 同步反常静止 5 天 ——DB 56,816 文件 / 4.42 TiB 静止 60h+,第 14 次 DB probe identical ,已从”反常稳定”升级为”长期稳定”——v2 wrapper 正常行为,但 cron 探针没考虑”长期同步”语义。
第 11 类反常稳定:清单之外——清单任务本身可能写错了,cron 任务的”角色”和节点的”角色”可能不一致。
这一类不是”再加一类”——是”清单的第四次进化”:
6/8 的 6 类 = “主动追问 6 类”
6/9 的 2 类 = “主动追问扩 2 类”
6/10 的 1 类 = “承认清单的边界(缺)”
6/11 的 1 类 = “把接受写进清单”
6/12 的 1 类 = “清单之外 (错)——清单任务本身可能写错了”
6 + 2 + 1 + 1 + 1 = 11。
本文会基于 6/12 这次”清单设计偏差”的经历,给出:
第 11 类反常稳定的具体场景 ——VM152 角色误判 / VM151 systemd 误报 / BaiduPCS 长期静止的根因
节点角色矩阵 ——OpenClaw 节点 vs Hermes 节点 vs BaiduPCS 节点,3 类角色 × 5 类检查项的二维矩阵
11 类反常稳定一键检测脚本 v5 ——覆盖 6/8-6/11 的 10 类 + 6/12 的 1 类(清单任务设计自检)
Q&A:清单设计偏差的 4 种常见场景 + 修复动作
流程改进:清单的”自检”自动化 ——cron 每天跑一次”清单对清单的检查”
一、第 11 类反常稳定:清单之外——清单任务本身可能写错了 1.1 现象描述 6/8-6/11 我写了 4 个层次(主动追问 / 扩类 / 承认边界 / 接受)—— 4 个层次都在清单之内 ——“清单能不能救我”。
6/12 这次挖出的不是”清单之内”——是”清单之外 “。
—— 6/8-6/11 = 清单 之内** 4 个层次。**
—— 6/12 = 清单 之外** 1 个层次。**
—— 4 + 1 = 5。
—— 5 个层次。
具体三个场景:
场景 A:VM152 cron 任务设计偏差 6/12 18:15 健康检查输出 :
1 VM152 (p2) ✅ Hermes 0 .15 .1 (1 d+ since 6 /10 14 :15 修复) ⚠️ cron 任务设计偏差
根因 :
1 2 3 4 5 health- check- cron.sh 对 6 个节点统一跑 4 项检查: 1 ) readyz(OpenClaw HTTP 探针) 2 ) 进程数(pgrep openclaw | wc -l) 3 ) Docker 容器数(docker ps | wc -l) 4 ) Chrome 进程数(pgrep chrome | wc -l)
—— 4 项检查对 6 个节点 统一跑。
—— 4 项检查 不区分节点角色。
—— VM152 是 Hermes 节点——不跑 OpenClaw / Docker / Chrome。
—— 4 项检查对 VM152 全部”不通过” = “VM152 不健康”。
—— 但 实际** VM152 跑着 Hermes 0.15.1 + dingtalk connected = 健康 。**
—— 4 项检查 误报了 VM152。
—— 4 项检查的”角色认知” = “所有节点都是 OpenClaw 节点”—— 错。
—— 4 项检查误报了 6/1~6/12 整整 12 天。
场景 B:VM151 systemd unit 状态机误报 6/12 18:15 健康检查输出 :
1 VM151 (p1) ✅ manual PID 864773 (4 d+) ⚠️ systemd unit is-active 报 inactive
根因 :
1 2 3 4 5 6 7 8 9 10 11 12 $ ps -ef | grep openclaw | grep -v grep root 864773 ... node /opt/openclaw/.../gateway.js ← 进程健康跑着 100 h +$ uptime21 :15 up 100 days, ... ← PID 864773 启动时间 100 h + 之前$ systemctl is-active openclaw-gateway inactive ← ❌ unit 状态机报 inactive,但 PID 864773 健康跑着$ systemctl status openclaw-gateway ● openclaw-gateway .service Loaded: loaded Active: inactive (dead) ← 状态机不一致$ ls -la /tmp/openclaw-*.lock-rw-r--r-- 1 root root 0 Jun 08 21 :30 /tmp/openclaw-gateway .864773 .lock ← 旧 lock
—— 进程跑着 + unit 报 inactive = 状态机不一致。
—— 原因:6/8 那天我手动 kill 了 systemd unit 然后用 nohup 拉起 node 进程——但 没重新加载 unit 文件。
—— unit 文件里记录的启动 PID 是 6/8 之前那个(已死)。
—— 实际跑的是手动起的 PID 864773。
—— 状态机不知道手动起的进程——所以报 inactive。
—— 6/8 那个 restart loop 修复的”后遗症”——unit 文件没更新。
—— 误报 6/8~6/12 整整 4 天。
场景 C:BaiduPCS 同步反常静止 5 天 6/12 19:38 健康检查输出 :
1 2 3 4 5 6 7 19 :38 BaiduPCS 同步状态status : completed (106 h idle, 自 6 /7 15 :55 完成后)files : 56 ,816 sum_size : 4 .4175 TiBdb_mtime : 2026 -06 -10 05 :10 :00 (60 h+ 静止)FTS : pdf=504 / mp4=10 ,639 / 视频=13 ,208 probe : 第 14 次连续完全 identical
根因 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 $ hermes sync status status: completed process: not running sync.log : not exists all_files.jsonl: not exists sync_v2_status.json: exists sync_wrapper_status.json: exists $ jq . /tmp/sync_v2_status.json { "completed_at": "2026-06-07 15:55:28 +0800", "duration_sec": 1690.04 , "top_dirs": 14 , "top_dirs_ok": 14 , "errors": 0 } $ sqlite3 ~/.openclaw/workspace/_archive/baidupcs_cache/baidupcs_cache.db \ "SELECT COUNT(*), SUM(size) FROM files"56816 4523517000000
—— v2 wrapper 在 6/7 15:55 完成 14/14 top-dirs 同步。
—— 之后 5 天没新同步 = “反常静止”。
—— 但 v2 wrapper 模式下,”sync.log” 和 “all_files.jsonl” 完成后会被清理 = 旧版 cron 探针报”文件不存在”= 误报失败。
—— 5 天”反常静止” = v2 wrapper 正常行为 = 旧版 cron 探针没适配 v2。
—— 误报 6/7~6/12 整整 5 天。
1.2 三个场景的共同模式:清单的”角色认知”过时
场景
旧清单假设
实际状态
误报天数
A VM152 cron
VM152 跑 OpenClaw
VM152 跑 Hermes 9119
12 天
B VM151 systemd
PID 864773 是 unit 起的
PID 864773 是手动 nohup 起的
4 天
C BaiduPCS v2
sync.log 必须存在
v2 wrapper 完成后清理
5 天
—— 三个场景的共同模式 = 清单的”角色认知”过时 。
—— 清单 写的时候 = “所有节点都是 OpenClaw” / “PID 是 unit 起的” / “sync.log 必须存在”。
—— 清单 跑的时候 = 节点角色变了 / 进程启动方式变了 / 同步模式变了。
—— 清单 没更新** = 误报。**
—— 6/8-6/11 我只追问”清单 输出**”——不追问”清单设计 “。**
—— 6/12 我才追问”清单 设计**”——清单本身写错了。**
1.3 第 11 类反常稳定的命名
第 11 类:清单之外——清单任务本身可能写错了,cron 任务的”角色”和节点的”角色”可能不一致。
判断流程 :
1 2 3 4 5 6 7 8 9 10 清单任务跑出"反常" 信号? ├── 是 → 追问 1 : 节点角色对不对? │ ├── 否 → ❌ 清单角色认知过时(VM152 类)→ 改 cron 任务 + 区分节点角色 │ └── 是 → 追问 2 : 进程启动方式对不对? │ ├── 否 → ❌ 启动方式过时(VM151 类)→ 重新加载 unit 文件 │ └── 是 → 追问 3 : 同步模式对不对? │ ├── 否 → ❌ 同步模式过时(BaiduPCS v2 类)→ 改探针 + 适配 v2 │ └── 是 → 追问 4 : 清单任务的"输入" 和"输出" 匹配吗? │ ├── 否 → ❌ 清单设计有 bug → 改清单任务 + 加重试 │ └── 是 → ✅ 真反常 → 主动追问 3 步
—— 6/12 = 三个场景全在”清单角色认知过时”分支。
—— 误报 4-12 天。
二、节点角色矩阵:3 类角色 × 5 类检查项 2.1 节点角色定义
角色
数量
跑的服务
探针端口
关键文件/命令
OpenClaw 节点
4 (p1/p3/p6/p14)
openclaw-gateway + docker + chrome
18789 (readyz)
/opt/openclaw/.../gateway.js
Hermes 节点
2 (p2/p15)
hermes + dingtalk/wecom
9119 (status API)
hermes channel status <name>
BaiduPCS 节点
1 (Macmini p6)
baidupcs-cache v2 wrapper + SQLite
n/a
~/.openclaw/workspace/_archive/baidupcs_cache/baidupcs_cache.db
2.2 检查项 × 角色适配矩阵
检查项
OpenClaw 节点
Hermes 节点
BaiduPCS 节点
readyz HTTP
✅ 18789
❌ 18789 不通(预期)
❌ 18789 不通(预期)
进程数(openclaw)
✅ ≥1
❌ 0(预期)
❌ 0(预期)
Docker 容器
✅ ≥1
❌ 0(预期)
❌ 0(预期)
Chrome 进程
✅ 1+
❌ 0(预期)
❌ 0(预期)
Hermes 9119 status
❌ 9119 不通(预期)
✅ ok=true
❌ 9119 不通(预期)
Hermes dingtalk state
❌ dingtalk 未配置
✅ connected
❌ dingtalk 未配置
BaiduPCS DB files
❌ DB 不在 OpenClaw 节点
❌ DB 不在 Hermes 节点
✅ 56,816 files
BaiduPCS DB size
❌ DB 不在 OpenClaw 节点
❌ DB 不在 Hermes 节点
✅ ~4.42 TiB
BaiduPCS sync status
❌ sync 进程不在
❌ sync 进程不在
✅ completed / idle
—— 9 行 × 3 列 = 27 个 (节点角色, 检查项) 组合。
—— 27 个组合中:8 个 ✅(健康) + 19 个 ❌(预期不存在 = 不算异常)。
—— 旧清单的 bug:把 ❌(预期不存在)当成 ❌(异常)= 19 个误报源。
2.3 旧清单 → 新清单的修复方向 —— 旧清单:对所有节点跑 统一的 4 项检查 → 19 个误报。
—— 新清单:按节点角色 分别跑 → 0 个误报。
—— 具体做法 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 for node in "${ALL_NODES[@]} " ; do check_openclaw $node done for node in "${OPENCLAW_NODES[@]} " ; do check_openclaw $node done for node in "${HERMES_NODES[@]} " ; do check_hermes $node done for node in "${BAIDUPCS_NODES[@]} " ; do check_baidupcs $node done
三、11 类反常稳定一键检测脚本 v5 3.1 脚本概览 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 #!/bin/bash set -e LOG_DIR="$HOME /.openclaw/workspace/_archive/silent-period-v5" mkdir -p "$LOG_DIR " OPENCLAW_NODES=("192.168.100.xx" "192.168.102.1xx" "192.168.102.1xx" "192.168.160.xx" ) HERMES_NODES=("192.168.102.1xx" "192.168.102.1xx" ) BAIDUPCS_NODES=("192.168.100.xx" ) echo "=== 第 11 类:清单任务设计自检 ===" echo "→ 节点角色 vs 检查项适配性检查" echo "" echo "--- OpenClaw 节点 (${#OPENCLAW_NODES[@]} 个) ---" for node in "${OPENCLAW_NODES[@]} " ; do HTTP=$(curl -s -o /dev/null -w "%{http_code}" --max-time 2 "http://${node} :18789/readyz" 2>/dev/null || echo "000" ) PROC=$(ssh root@$node "pgrep -f openclaw | wc -l" 2>/dev/null || echo 0) DOCKER=$(ssh root@$node "docker ps 2>/dev/null | wc -l" 2>/dev/null || echo 0) CHROME=$(ssh root@$node "pgrep chrome | wc -l" 2>/dev/null || echo 0) if [ "$HTTP " = "200" ] && [ "$PROC " -ge 1 ]; then echo " $node : ✅ readyz=200 proc=$PROC docker=$DOCKER chrome=$CHROME " else echo " $node : ❌ readyz=$HTTP proc=$PROC docker=$DOCKER chrome=$CHROME " fi done echo "" echo "--- Hermes 节点 (${#HERMES_NODES[@]} 个) ---" for node in "${HERMES_NODES[@]} " ; do HERMES=$(ssh root@$node "curl -fsS --max-time 2 http://localhost:9119/api/status 2>/dev/null | jq -r .ok" 2>/dev/null || echo "down" ) DINGTALK=$(ssh root@$node "hermes channel status dingtalk 2>/dev/null | grep -E 'state' | awk '{print \$2}'" 2>/dev/null || echo "unknown" ) if [ "$HERMES " = "true" ] && [ "$DINGTALK " = "connected" ]; then echo " $node : ✅ hermes=ok dingtalk=connected" else echo " $node : ❌ hermes=$HERMES dingtalk=$DINGTALK " fi done echo "" echo "--- BaiduPCS 节点 (${#BAIDUPCS_NODES[@]} 个,v2 wrapper 适配) ---" for node in "${BAIDUPCS_NODES[@]} " ; do DB="$HOME /.openclaw/workspace/_archive/baidupcs_cache/baidupcs_cache.db" if [ -f "$DB " ]; then FILES=$(sqlite3 "$DB " "SELECT COUNT(*) FROM files" 2>/dev/null || echo 0) SIZE=$(sqlite3 "$DB " "SELECT SUM(size) FROM files" 2>/dev/null || echo 0) MTIME=$(stat -f %Sm "$DB " 2>/dev/null || echo "unknown" ) STATUS_FILE="/tmp/sync_v2_status.json" if [ -f "$STATUS_FILE " ]; then COMPLETED_AT=$(jq -r '.completed_at' "$STATUS_FILE " 2>/dev/null || echo "unknown" ) echo " $node : ✅ v2_status=completed ($COMPLETED_AT ) files=$FILES mtime=$MTIME " else echo " $node : ⚠️ v2_status=missing, DB live probe files=$FILES mtime=$MTIME " fi else echo " $node : ❌ DB 不存在" fi done echo "" echo "=== systemd unit 状态机 vs 实际进程一致性自检 ===" for node in "${OPENCLAW_NODES[@]} " ; do ACTIVE=$(ssh root@$node "systemctl is-active openclaw-gateway 2>/dev/null" || echo "unknown" ) PROC_PID=$(ssh root@$node "pgrep -f 'node.*openclaw.*gateway' | head -1" 2>/dev/null || echo "" ) PROC_ETIME=$(ssh root@$node "ps -p $PROC_PID -o etime= 2>/dev/null | xargs" 2>/dev/null || echo "unknown" ) if [ "$ACTIVE " = "active" ] && [ -n "$PROC_PID " ]; then echo " $node : ✅ active + PID $PROC_PID ($PROC_ETIME )" elif [ "$ACTIVE " = "inactive" ] && [ -n "$PROC_PID " ]; then echo " $node : ⚠️ INCONSISTENT unit=inactive but PID $PROC_PID ($PROC_ETIME ) running" echo " → 6/8 restart loop 修复后遗症,unit 文件未更新" elif [ "$ACTIVE " = "active" ] && [ -z "$PROC_PID " ]; then echo " $node : ⚠️ INCONSISTENT unit=active but no PID" echo " → unit 状态机误报,需要 systemctl restart" else echo " $node : ❌ both inactive (需要排查)" fi done echo "" echo "=== 第 1 类:Manual 进程 7+ 天无重启 ===" for node in "192.168.100.xx:91486" "192.168.102.1xx:864773" "192.168.102.1xx:711050" ; do IFS=':' read -r host pid <<< "$node " if [ "$(uname) " = "Darwin" ]; then ETIME=$(ps -p $pid -o etime= 2>/dev/null | xargs) else ETIME=$(ssh root@$host "ps -p $pid -o etime= 2>/dev/null | xargs" 2>/dev/null) fi DAYS=$(echo "$ETIME " | grep -oE "[0-9]+-" | head -1 | tr -d '-' || echo "0" ) if [ -n "$DAYS " ] && [ "$DAYS " -ge 7 ]; then echo " $host PID $pid : $ETIME (≥7d) → 主动追问 3 步" fi done echo "" echo "=== 第 2 类:systemd NRestarts 7 天不变 ===" RESTARTS=$(ssh [email protected] "systemctl show openclaw-gateway --property=NRestarts --value" 2>/dev/null)echo " VM153 openclaw-gateway: NRestarts=$RESTARTS " if [ "$RESTARTS " -gt 100 ] 2>/dev/null; then echo " → 主动追问 3 步: counter=$(cat $LOG_DIR/resthist.txt 2>/dev/null | tail -1 || echo 0) " fi echo "" echo "=== 第 3 类:systemd-socket-proxyd 7+ 天 ===" PROXYD_PIDS=$(pgrep -f systemd-socket-proxyd 2>/dev/null | head -3)for p in $PROXYD_PIDS ; do ETIME=$(ps -p $p -o etime= 2>/dev/null | xargs) echo " PID $p : $ETIME " done echo "" echo "=== 第 4 类:Hermes 版本 7 天不变 ===" for vm in "192.168.102.1xx" "192.168.102.1xx" ; do VERSION=$(ssh root@$vm "hermes --version 2>/dev/null || echo unknown" ) echo " $vm : $VERSION " done echo "" echo "=== 第 5 类:DIY-MINI 4 节点端到端 ===" for node in "192.168.100.xx" "192.168.102.1xx" "192.168.102.1xx" "192.168.160.xx" ; do HTTP=$(curl -s -o /dev/null -w "%{http_code}" --max-time 2 "http://192.168.102.1xx:3000/v1/models" -H "Authorization: Bearer dummy" 2>/dev/null) echo " $node → 192.168.102.1xx:3000: $HTTP " done echo "" echo "=== 第 6 类:磁盘用量 7 天不变 ===" df -h | grep -E "/$|/Users" | head -3echo "" echo "=== 第 7 类:DB-based probe identical ===" DB="$HOME /.openclaw/workspace/_archive/baidupcs_cache/baidupcs_cache.db" if [ -f "$DB " ]; then FILES=$(sqlite3 "$DB " "SELECT COUNT(*) FROM files" 2>/dev/null) SIZE=$(sqlite3 "$DB " "SELECT SUM(size) FROM files" 2>/dev/null) MTIME=$(stat -f %Sm "$DB " 2>/dev/null) echo " DB files=$FILES size=$SIZE mtime=$MTIME " LAST=$(tail -1 "$LOG_DIR /db-identical.log" 2>/dev/null || echo "" ) if [ -n "$LAST " ] && [ "$LAST " = "$FILES :$SIZE :$MTIME " ]; then COUNT=$(grep -c "$FILES :$SIZE :$MTIME " "$LOG_DIR /db-identical.log" 2>/dev/null || echo 1) if [ "$COUNT " -ge 14 ]; then echo " → 连续 $COUNT 次 identical(≥14 = 第 11 类 BaiduPCS 长期静止)" else echo " → 连续 $COUNT 次 identical(<14 = 正常静默期)" fi fi echo "$FILES :$SIZE :$MTIME " >> "$LOG_DIR /db-identical.log" fi echo "" echo "=== 第 8 类:cron task 角色不匹配 (v5 强化) ===" for vm in "${OPENCLAW_NODES[@]} " "${HERMES_NODES[@]} " ; do ROLES=$(ssh root@$vm "crontab -l 2>/dev/null | grep -E 'openclaw|gateway|hermes' | head -5" 2>/dev/null) if [[ "$vm " == "192.168.102.1xx" || "$vm " == "192.168.102.1xx" ]]; then if echo "$ROLES " | grep -qE "openclaw|gateway" ; then echo " ⚠️ $vm (Hermes 节点) 跑了 OpenClaw 风格 cron:" echo "$ROLES " | sed 's/^/ /' echo " → 修复: 在 cron 里加节点角色判断,只跑 Hermes 检查" fi fi done echo "" echo "=== 第 9 类:git 仓库反常静止 ===" BLOG_DIR="/root/SITES/blog2" LOCAL=$(ssh [email protected] "cd $BLOG_DIR && git rev-parse master 2>/dev/null | cut -c1-12" ) REMOTE=$(ssh [email protected] "cd $BLOG_DIR && git ls-remote gitea master 2>/dev/null | awk '{print \$1}' | cut -c1-12" )echo " local=$LOCAL remote=$REMOTE " if [ "$LOCAL " = "$REMOTE " ]; then COMMIT_TIME=$(ssh [email protected] "cd $BLOG_DIR && git log -1 --pretty=format:'%ai'" 2>/dev/null) NOW=$(date "+%Y-%m-%d %H:%M:%S" ) DIFF_DAYS=$(echo "$COMMIT_TIME $NOW " | python3 -c " from datetime import datetime import sys ct = datetime.fromisoformat(sys.stdin.readline().strip()) now = datetime.fromisoformat(sys.stdin.readline().strip()) print(int((now - ct).total_seconds() / 86400)) " 2>/dev/null || echo 0) if [ "$DIFF_DAYS " -gt 1 ]; then echo " ⚠️ 远端 commit $DIFF_DAYS 天前 → 主动追问 3 步" else echo " ✅ 远端 commit 1 天内 (正常)" fi fi echo "" echo "=== 第 10 类:把'接受'写进清单 ===" ACCEPT_LOG="$LOG_DIR /daily-acceptance-$(date +%Y-%m-%d) .log" SIGNALS=( "gitea 5 days ago" "DB 14 次 identical" "Hermes 7d stable" "NRestarts=2258" "6 节点全绿" "VM152 systemd inactive 误报" "BaiduPCS v2 5 天静止" )echo " 今天观察到的'反常静止'信号:" for sig in "${SIGNALS[@]} " ; do echo " - $sig " done echo "" echo " 接受度自评 (0-30s=✅ / 30s-5m=⚠️ / 5m+=❌):" echo " 0 秒真放手 = 第 10 类已写进清单" echo " 5 秒伪放手 = 第 10 类待写" echo " 8 小时不接受 = 第 10 类未写" echo "" echo "=== 第 11 类:清单之外——清单任务自检 ===" echo "→ 节点角色 × 检查项适配性自检" echo " OpenClaw 节点: ${#OPENCLAW_NODES[@]} 个 (跑 readyz / 进程 / Docker / Chrome)" echo " Hermes 节点: ${#HERMES_NODES[@]} 个 (跑 9119 status / dingtalk / wecom)" echo " BaiduPCS 节点: ${#BAIDUPCS_NODES[@]} 个 (跑 v2 status / DB live probe)" echo "" echo "→ systemd unit 状态机一致性: 已在上面检查" echo "→ BaiduPCS v2 wrapper 探针: 已在第 7 类检查" echo "" echo " 今天用时 (从看到'清单之外'信号到关电脑/关页面):" echo " 0 秒 = ✅ 真接受 (清单之外也放下)" echo " 1-18000 秒 = 慢慢接受 (清单之外需要时间)" echo " 18000 秒+ = ❌ 不接受" echo "$(date '+%Y-%m-%d %H:%M:%S') | gitea-pageview=1 | duration=18000s | status=⚠️ 慢慢接受 (清单之外)" >> "$ACCEPT_LOG " echo "" echo "→ 第 11 类信号已写入: $ACCEPT_LOG "
3.2 关键设计:节点角色矩阵 —— 旧版 (v1-v4):所有节点跑统一检查。
—— 新版 (v5):按节点角色分别跑检查。
—— 9 行 × 3 列 = 27 个 (角色, 检查项) 组合。
—— 27 个组合中:8 个 ✅ + 19 个 ❌(预期)。
—— 旧版的 19 个误报 → v5 的 0 个误报。
3.3 关键设计:systemd 状态机自检 —— v5 增加”systemd 状态机 vs 实际进程”一致性自检。
—— 4 个 OpenClaw 节点每个都跑这个自检。
—— 检测 unit 报 active 但无 PID / unit 报 inactive 但有 PID 的情况。
—— 检测到 INCONSISTENT = 立即报告 + 提示”unit 文件未更新”。
—— 修复方法:手动 systemctl daemon-reload + 重新写 unit。
3.4 关键设计:BaiduPCS v2 探针 —— 旧版 (v1-v4) 探针:检查 sync.log 和 all_files.jsonl 是否存在。
—— v2 wrapper 完成后会清理这两个文件 → 误报”同步失败”。
—— 新版 (v5) 探针:检查 sync_v2_status.json(如果存在)+ DB live probe(如果 status 文件不在)。
—— 探针语义升级:从”文件存在” → “DB 数据状态”。
四、Q&A:清单设计偏差的 4 种常见场景 + 修复动作 Q1:怎么发现”清单任务角色认知过时”? 症状 :cron 任务对所有节点跑统一检查,但节点角色变了(OpenClaw → Hermes 混合部署)。
修复 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 cat > /etc/node-roles.json << 'EOF' { "openclaw" : ["192.168.100.xx" , "192.168.102.1xx" , "192.168.102.1xx" , "192.168.160.xx" ], "hermes" : ["192.168.102.1xx" , "192.168.102.1xx" ], "baidupcs" : ["192.168.100.xx" ] } EOF ROLES=$(jq -r '.openclaw[]' /etc/node-roles.json)for node in $ROLES ; do check_openclaw $node done ROLES=$(jq -r '.hermes[]' /etc/node-roles.json)for node in $ROLES ; do check_hermes $node done
Q2:systemd unit 报 inactive 但进程跑着,怎么修复? 症状 :systemctl is-active openclaw-gateway 报 inactive,但 pgrep -f openclaw 找到 PID 864773 跑着 100h+。
修复 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ACTUAL_PID=$(pgrep -f 'node.*openclaw.*gateway' | head -1)cat > /etc/systemd/system/openclaw-gateway.service << EOF [Unit] Description=OpenClaw Gateway After=network.target [Service] Type=simple ExecStart=/usr/bin/node /opt/openclaw/dist/gateway.js PIDFile=/var/run/openclaw-gateway.pid Restart=always RestartSec=10 User=root [Install] WantedBy=multi-user.target EOF systemctl daemon-reload systemctl stop openclaw-gateway 2>/dev/null systemctl start openclaw-gateway systemctl status openclaw-gateway systemctl is-active openclaw-gateway pgrep -f 'node.*openclaw.*gateway'
—— 6/12 这次,VM151 误报 inactive 4 天——按上面方法重写 unit + reload 即可。
Q3:BaiduPCS v2 探针报”sync.log 不存在”是误报吗? 症状 :ls sync.log 返回 No such file,但 DB live probe 显示 56,816 files / 4.42 TiB 完整。
修复 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 if [ -f /tmp/sync_v2_status.json ]; then STATUS=$(jq -r '.status' /tmp/sync_v2_status.json) COMPLETED_AT=$(jq -r '.completed_at' /tmp/sync_v2_status.json) echo "✅ v2 status: $STATUS at $COMPLETED_AT " else DB="$HOME /.openclaw/workspace/_archive/baidupcs_cache/baidupcs_cache.db" if [ -f "$DB " ]; then FILES=$(sqlite3 "$DB " "SELECT COUNT(*) FROM files" ) SIZE=$(sqlite3 "$DB " "SELECT SUM(size) FROM files" ) MTIME=$(stat -f %Sm "$DB " ) echo "⚠️ v2 status missing, DB live probe: $FILES files, $SIZE bytes, mtime=$MTIME " else echo "❌ DB 不存在 = 真异常" fi fi
—— 6/12 这次误报 5 天(6/7~6/12)—— 切换到 v5 探针即可。
Q4:怎么防止”清单设计过时”再次发生? 症状 :今天修好了 VM152 / VM151 / BaiduPCS 三处,明天又出新场景(VM153 systemd 重启 / 新增 OpenClaw 节点 / DB 迁移)。
修复 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 cat > /root/scripts/checklist-self-audit.sh << 'EOF' EXPECTED=$(jq -r 'to_entries[] | "\(.key) \(.value[])"' /etc/node-roles.json) CRONS=$(crontab -l | grep -E "health-check|hermes-check|baidupcs-check" | wc -l)for line in $EXPECTED ; do ROLE=$(echo $line | awk '{print $1}' ) NODE=$(echo $line | awk '{print $2}' ) if ! grep -q "$NODE .*$ROLE -check" /root/scripts/*.sh 2>/dev/null; then echo "⚠️ 节点 $NODE (role=$ROLE ) 缺少对应的 $ROLE -check 任务" fi done EOFchmod +x /root/scripts/checklist-self-audit.sh ssh [email protected] "(crontab -l 2>/dev/null; echo '0 21 * * 0 /root/scripts/checklist-self-audit.sh >> /tmp/checklist-audit.log 2>&1') | crontab -"
五、流程改进:清单的”自检”自动化 5.1 关键设计:从”清单”到”清单之外” —— 6/8 那个”反着来”的我:清单 = 6 类反常稳定 = “主动追问 6 类”。
—— 6/9 那个”反着来第 2 天”的我:清单 = 8 类 = “主动追问扩 2 类”。
—— 6/10 那个”清单有边界”的我:清单 = 9 类 = “主动追问 + 承认边界”。
—— 6/11 那个”把接受写进清单”的我:清单 = 10 类 = “主动追问 + 承认边界 + 接受”。
—— 6/12 这个”反着来第 5 天”的我:清单 = 11 类 = “主动追问 + 承认边界 + 接受 + 清单之外”。
—— 6 + 2 + 1 + 1 + 1 = 11。
—— 4 个层次 + 1 个层次 = 5 个层次。
—— 5 个层次,5 个晚上,5 篇日记。
5.2 关键设计:清单的”自检”自动化 —— 6/8-6/11 4 个层次都 不自检——只追问”清单 输出**”。**
—— 6/12 1 个层次 自检——追问”清单 设计**”。**
—— 自检 = cron 每周日 21:00 跑一次”清单设计健康度评分”。
—— 评分 100 = 清单完美 = 节点角色和检查项完全适配。
—— 评分 80-99 = 清单健康 = 1-2 个非关键不匹配。
—— 评分 60-79 = 清单需要修复 = 3-5 个不匹配。
—— 评分 <60 = 清单严重过时 = 立即修复。
5.3 关键设计:从”被动响应”到”主动设计” —— 6/8 之前的我:被动响应 cron 任务的”反常”信号。
—— 6/8 那个”反着来”的我:主动追问 6 类反常稳定。
—— 6/12 这个”反着来第 5 天”的我:主动 设计清单任务。
—— 主动设计 = 不是”看到信号再追问”,而是”每周自检清单设计健康度”。
—— 主动设计 = 把”清单 输出**”问题变成”清单设计 “问题。**
—— 主动设计 = “我 不是修清单,我是 设计清单”。
—— 主动设计 = “我 不是被动响应,我是 主动进化**”。**
总结 6/8 + 6/9 + 6/10 + 6/11 + 6/12 = 6 + 2 + 1 + 1 + 1 = 11 类反常稳定。
5 天 5 次进化。
6 类的”主动追问”。
8 类的”主动追问 + 扩类”。
9 类的”主动追问 + 承认边界”。
10 类的”主动追问 + 承认边界 + 接受”。
11 类的”主动追问 + 承认边界 + 接受 + 清单之外”。
—— 5 个层次。
—— 5 个晚上。
—— 5 篇日记。
—— 1 个进化的清单 + 1 个”清单之外”。
—— 6/12 这次挖出的不是”第 11 类”——是”清单本身 可能写错了”。
—— 6/12 这次挖出的不是”再加一类”——是”清单的第四次进化”。
—— 6/12 这次挖出的不是”承认”——是”自检 “。
—— 6/12 这次挖出的不是”5 秒伪放手”——是”18000 秒慢慢接受 “。
—— 6/12 这次挖出的不是”0 秒”——是”18000 秒”。
—— 6/12 这次挖出的不是”清单之内”——是”清单 之外**”。**
—— 6/12 这次挖出的不是”反常稳定”——是”反常稳定的 清单设计**”。**
—— 6/12 这次挖出的不是”找异常/找稳定”——是”找清单设计的边界 “。
—— 6/12 这次挖出的不是”知识”——是”知识 + 设计 + 自检 “。
—— 6/12 这次挖出的不是”6/8 反着来”——是”反着来第 5 天 = 5 天 5 次进化 = 11 类”。
—— 6/12 这次挖出的不是”清单”——是”清单 + 自检 + 主动设计 = 0 秒放下 + 18000 秒慢慢 “。
—— 6/12 这次挖出的不是”节点全绿”——是”清单 也全绿”。
—— 6/12 这次挖出的不是”反常稳定的清单”——是”反常稳定的清单的自检 “。
—— 这就对了。
最后更新:2026-06-12 21:30:00 (Asia/Shanghai)