auto-snapshot 2026-08-01 03:00:24

This commit is contained in:
小唯 A06 2026-08-01 03:00:24 +08:00
parent 4d1d2e290f
commit 0fb7d2455d
9 changed files with 420 additions and 34 deletions

View File

@ -939,14 +939,14 @@
"archived_at": null,
"created_at": "2026-05-07T03:26:18.333142+00:00",
"created_by": null,
"last_patched_at": "2026-07-29T15:13:24.101572+00:00",
"last_used_at": "2026-07-29T15:22:34.318883+00:00",
"last_viewed_at": "2026-07-29T15:22:34.307712+00:00",
"patch_count": 119,
"last_patched_at": "2026-07-31T18:14:44.384194+00:00",
"last_used_at": "2026-07-31T18:14:36.015868+00:00",
"last_viewed_at": "2026-07-31T18:14:35.997061+00:00",
"patch_count": 120,
"pinned": false,
"state": "active",
"use_count": 112,
"view_count": 111
"use_count": 113,
"view_count": 112
},
"hermes-mcp-setup": {
"archived_at": null,
@ -1420,14 +1420,14 @@
"archived_at": null,
"created_at": "2026-07-12T11:36:03.535167+00:00",
"created_by": "agent",
"last_patched_at": "2026-07-12T12:47:31.969471+00:00",
"last_used_at": "2026-07-21T10:35:10.282262+00:00",
"last_viewed_at": "2026-07-21T10:35:10.278534+00:00",
"patch_count": 2,
"last_patched_at": "2026-07-31T18:14:53.496815+00:00",
"last_used_at": "2026-07-31T18:14:50.239719+00:00",
"last_viewed_at": "2026-07-31T18:14:50.228349+00:00",
"patch_count": 4,
"pinned": false,
"state": "active",
"use_count": 5,
"view_count": 5
"use_count": 9,
"view_count": 9
},
"opencode": {
"archived_at": null,
@ -1563,14 +1563,14 @@
"archived_at": null,
"created_at": "2026-07-08T17:13:40.791890+00:00",
"created_by": "agent",
"last_patched_at": "2026-07-29T17:29:37.569117+00:00",
"last_used_at": "2026-07-29T17:29:22.122287+00:00",
"last_viewed_at": "2026-07-29T17:29:22.110945+00:00",
"patch_count": 72,
"last_patched_at": "2026-07-31T18:49:52.895820+00:00",
"last_used_at": "2026-07-31T18:49:41.435213+00:00",
"last_viewed_at": "2026-07-31T18:49:41.424226+00:00",
"patch_count": 80,
"pinned": false,
"state": "active",
"use_count": 65,
"view_count": 65
"use_count": 69,
"view_count": 69
},
"python-debugpy": {
"archived_at": null,
@ -1667,14 +1667,14 @@
"archived_at": null,
"created_at": "2026-07-08T18:13:02.034240+00:00",
"created_by": "agent",
"last_patched_at": "2026-07-29T15:13:46.831530+00:00",
"last_used_at": "2026-07-29T15:13:49.310605+00:00",
"last_viewed_at": "2026-07-29T15:13:49.299259+00:00",
"patch_count": 185,
"last_patched_at": "2026-07-31T18:50:21.591228+00:00",
"last_used_at": "2026-07-31T18:50:16.167283+00:00",
"last_viewed_at": "2026-07-31T18:50:16.155260+00:00",
"patch_count": 191,
"pinned": false,
"state": "active",
"use_count": 135,
"view_count": 135
"use_count": 144,
"view_count": 144
},
"self-hosted-tunneling": {
"archived_at": null,

View File

@ -295,6 +295,36 @@ hermes gateway status
ps aux | grep hermes | grep -v grep
```
### ⚠️ unit 文件丢失 → systemd 无限重启循环2026-08-01 事故)
**症状**gateway 不响应;`systemctl --user status hermes-gateway` 显示 `Loaded: ... ; bad` +
`Active: activating (auto-restart)``NRestarts` 持续飙升(事故中 187 次)。
**根因**`~/.config/systemd/user/hermes-gateway.service` 文件被删unit 丢失),
但 systemd 仍用内存里的旧定义反复拉起新进程;新进程与已有 gateway 抢 8644 端口
→ 启动失败 → 又重启 → 死循环。分体OpenClaw可临时拉起一个 hermes gateway 占住端口救活,
但 systemd 服务本身仍在空转循环。
**诊断三步**
```bash
systemctl --user show hermes-gateway -p NRestarts # 飙高 = 崩溃循环
ls -la ~/.config/systemd/user/hermes-gateway.service # No such file = unit 丢失
ss -tlnp | grep 8644 # 谁在占端口 / 谁是实际服务的进程
cat /proc/<PID>/cgroup | head -2 # 确认进程属于哪个 service
```
**修复**(必须在外部 shell 执行gateway 内部被强保护拦截):
```bash
hermes gateway install --no-start-now # 重建 unit官方方式
systemctl --user stop hermes-gateway # 停崩溃循环
systemctl --user reset-failed hermes-gateway # 重置失败计数
kill <临时gateway的PID> # 杀掉分体临时拉起的(占 8644 那个)
systemctl --user start hermes-gateway # 正统 systemd 接管
```
**杜绝**unit 文件纳入配置保护备份git rebase / 改 config.yaml 期间保持语法有效
gateway 的 cron scheduler 会实时读它,损坏窗口 = 崩溃窗口)。
### 看日志
```bash
tail -30 ~/.hermes/logs/gateway.log

View File

@ -12,6 +12,10 @@ trigger_notes: >
注意NewAPI 免费模型并非 SLA 保证,稳定性随时间变化。每 6h 有自动健康巡检,
使用前查看 ~/.hermes/model-health.json 获取当前最优模型。
pitfalls:
- ⚠️⚠️⚠️ 铁律2026-07-31 牧尘纠正两次2026-08-01 第三次纠正后加固):禁止擅自切换日常对话模型!日常对话固定 deepseek-v4-flash付费api.deepseek.com改模型前必须先问牧尘。2026-07-30 我把主模型换成 nemotron-3-super 免费模型 → 无法正常使用牧尘改回。NewAPI 免费模型只用于 cron/自动化/分体prof-b/OpenClaw绝不用于主对话
- ⚠️⚠️⚠️ 2026-08-01 根因实锤(提交 5bb8043`_auto_promote_config` 的 **B 段**会自动把 config.yaml 的 `model.default` 切成 newapi 排名第一的模型git 历史 d57bdc9 铁证:"主模型切换到NewAPI免费nemotron-3-super")。**任何自动化脚本都不得改 `model.default`**——日常对话主模型只由牧尘手动指定。排名驱动升级只允许作用于 `providers.newapi-local.default_model`cron/自动化池)。已删 B 段 + `_heal_config` 双重池内保护(`model_default in CANDIDATE_POOL` 前置条件)
- ⚠️ 自动运维脚本model-health.py 等)必须验证"实际生效的配置字段":只修 providers.models 列表、不验证 model.default → prof-b 被写成 NewAPI 不存在的模型全挂 503。任何写入配置的模型必须真实调用验证HTTP 200 + 有内容)才允许写入
- ⚠️ 排名公式必须含 context_score丢了上下文权重 → 1M 长上下文模型排不上。质量探针每题测 3 次取平均单次波动会误判nemotron 上次 100 下次 75
- 不要默认用 deepseek 系列。接任务时先判断:这是大事还是常规?常规就切 NewAPI 免费模型
- cron job 创建时必须显式指定 model/provider否则继承当前 session 的付费模型
- delegate_task 子代理默认继承父 session 模型。简单子任务不需要付费
@ -73,8 +77,11 @@ pitfalls:
|--------|------|------|---------|
#### 2026-07-29 质量排名(按 rank_score 排序)
> 质量分 = 探针×35% + 参数量×25% + 家族声誉×20% + 稳定×10% + 速度×10%
> 探针4 道固定题(逻辑/数学/常识/代码),自动判分 0-100
> 质量分 = 探针×30% + 上下文×25% + 参数量×20% + 家族声誉×10% + 稳定×10% + 速度×5%
> 探针4 道固定题(逻辑/数学/常识/代码),自动判分 0-100每题测 3 次取平均
> ⚠️ 2026-07-31 修复:旧公式 `探针×35%+参数量×25%+家族×20%+稳定×10%+速度×10%` 丢了 context_score
> 导致 1M 长上下文模型排名上不去nemotron-3-super 有 1M ctx 却排不过 128K 的 gpt-oss
> 现公式加入上下文权重 25%1M=100分, 256K=90, 128K=80, 8K=10
| 排名 | 模型 | 得分 | 探针 | 延迟 | 推荐场景 |
|:----:|:-----|:----:|:----:|:----:|:---------|
@ -136,9 +143,10 @@ print(f'稳定: {d[\"stable\"]}, 不稳定: {d[\"unstable\"]}, 死: {d[\"dead\"]
`~/.hermes/scripts/model-health.py`(亦作为本 skill 的 `scripts/model-health.py`
### 🆕 自愈 + 质量排名 + 自动升级 + 全配置覆盖2026-07-29 v2→v3
### 🆕 自愈 + 质量排名 + 排名驱动升级 + 全配置覆盖2026-07-31 v3 修复版
> 之前只检测+替补死亡模型。现在:自动发现新模型 → 测质量 → 排名 → 死换活 → 差换好 → **推送到所有配置**
> 之前只检测+替补死亡模型。现在:自动发现新模型 → 测质量3次平均 → 排名(含上下文权重) → 死换活 → **排名驱动升级default_model≠第1名就自动换****推送到所有配置**
> ⚠️ 2026-07-31 教训:自动运维脚本必须验证"实际生效的配置字段"model.default不只是维护静态列表任何写入配置的模型必须真实调用验证后才允许写入_verify_model_usable
#### 三阶段工作流程
@ -153,18 +161,22 @@ print(f'稳定: {d[\"stable\"]}, 不稳定: {d[\"unstable\"]}, 死: {d[\"dead\"]
--- 阶段 2质量测试 + 排名 ---
对每个模型:
① 测 2 次存活 + 速度(同之前)
② 如果是稳定模型 → 跑 4 道质量探针
② 如果是稳定模型 → 跑 4 道质量探针,每题测 3 次取平均2026-07-31 修复单次波动大nemotron 上次 100 下次 75
逻辑题:"如果所有A是B所有B是C那么A是C吗"
数学题:"1.8 和 1.11 哪个大?"(有效的质量区分题)
常识题:"中国的首都是?"
代码题:"Python一行反转列表"
③ 计算 rank_score
rank_score = 探针×35% + 参数量×25% + 家族声誉×20% + 稳定×10% + 速度×10%
rank_score = 探针×30% + 上下文×25% + 参数量×20% + 家族声誉×10% + 稳定×10% + 速度×5%
⚠️ 2026-07-31 修复:旧公式丢了 context_score1M 长上下文模型排名上不去
④ 按 rank_score 降序排列
--- 阶段 3自愈 + 升级,推送到所有配置 ---
--- 阶段 3自愈 + 排名驱动升级,推送到所有配置 ---
a) 死亡替代:配置中死亡模型 → 按质量排名选最优替补
b) 主动升级:新发现的稳定模型如果排名 > 配置中最低的 → 自动替换进去
b) ⚠️ 排名驱动升级2026-07-31 修复2026-08-01 范围收紧):每次巡检主动检查 `providers.newapi-local.default_model` 是否=排名第1不是就自动换。
旧版只在"发现全新模型"或"模型死亡"时触发,现有模型排名互换永不触发。
修复后default_model ≠ 第1名 → 自动升级(仅 newapi-local 免费模型,付费模型保护)。
⚠️⚠️ 2026-08-01 血泪教训:**此逻辑的 B 段曾误作用于 `model.default`(日常对话主模型)**,把 deepseek-v4-flash 切成 newapi nemotron → 对话挂、牧尘改回 3 次git d57bdc9 铁证。B 段已整体删除:**`model.default` 永不自动修改**,只允许优化 `providers.newapi-local.default_model`
c) 覆盖范围5 个配置点):
① ~/.hermes/config.yaml — 主配置模型列表
② ~/.hermes-prof-b/config.yaml — prof-b 分身模型列表
@ -177,6 +189,11 @@ print(f'稳定: {d[\"stable\"]}, 不稳定: {d[\"unstable\"]}, 死: {d[\"dead\"]
d) 自动移除付费模型KNOWN_PAID 集合deepseek-ai/deepseek-v4-pro 等)
e) 已知死模型跳过测试KNOWN_DEAD 集合避免浪费
f) 已知忽略系统模型KNOWN_IGNORE 集合embedding/tts/image/safety
g) ⚠️ 替换前必须 _verify_model_usable 真实调用验证2026-07-31 修复):
候选模型必须实际跑一次 HTTP 200 + 有内容才允许写入配置,防止写入死模型/不存在的模型
h) ⚠️ model.default 检查2026-07-31 修复):旧版只修 providers.models 列表,
从不验证实际生效的 model.default 字段 → prof-b 被写成 NewAPI 不存在的 deepseek/deepseek-v4-flash 全挂 503
i) ⚠️ OpenClaw fallbacks 修复2026-07-31 新增):旧版只修 primaryfallbacks 死模型一直留着
```
#### 探针设计原则
@ -416,6 +433,7 @@ curl -s -X POST http://127.0.0.1:3000/v1/chat/completions \
- `scripts/model-health.py` — 模型健康巡检脚本cron 自动调用)
- `references/2026-07-29-eol-fix-record.md` — 2026-07-29 EOL 模型修复全流程记录检测→config→cron→OpenClaw skill→自愈升级
- `references/model-distribution-five-forms.md` — 5 种分体cron/delegate/OpenClaw/opencode/prof-b模型分发策略与 EOL 修复流程2026-07-29 更新)
- `references/model-health-v3-fixes-20260731.md` — model-health.py v3 修复记录model.default 验证缺失、排名公式丢 context、排名驱动升级、_verify_model_usable 真实调用验证、探针3次平均、config.yaml key_env 安全引用2026-07-31 新增)
- `references/` > `moa` skill — MoA 多模型专家组配置
---

View File

@ -0,0 +1,91 @@
# model-health.py v3 修复记录2026-07-31
> 触发:牧尘发现 prof-b 分身 + OpenClaw 都不能用,追查发现是自动运维脚本的致命缺陷。
## 缺陷 1只修 providers.models 列表,从不验证 model.default
**症状**prof-b 的 `model.default: deepseek/deepseek-v4-flash` + `provider: newapi-local`
实际调用走 NewAPI 时模型名在 NewAPI 里不存在 → HTTP 503 model_not_found全挂。
**根因**`_heal_config` 只检查 `providers.newapi-local.models` 列表里的死模型。
`model.default` 字段(实际生效的模型)指向什么,脚本完全看不见。
prof-b 的坏配置 `deepseek/deepseek-v4-flash` 根本不在测试列表 ALL_MODELS 里,
脚本跑了 18 个模型全绿,却对坏配置视而不见。
**修复**`_heal_config` 新增第 2 步——检查 `model.default`(仅当 provider == newapi-local 时,
付费模型自动保护不碰)。不在结果里 = 未测试 = 视为需要修复。
## 缺陷 2排名公式丢了 context_score
**症状**nemotron-3-super1M ctx排名排不过 gpt-oss-120b128K
牧尘问"有长上下文不用"。
**根因**`test_model()` 里初始公式含 `cs * 0.15`,但 `main()` 里重新计算 rank_score 时
**把 context_score 丢掉了**(公式只有 probe/param/family/stab/speed覆盖了初始值。
**修复**:统一公式 `probe*0.30 + ctx*0.25 + param*0.20 + family*0.10 + stab*0.10 + speed*0.05`
修复后 nemotron-3-super 凭 1M ctxcontext_score=100+ 探针 100 登顶第一。
## 缺陷 3自动替换只在"死模型/新模型"时触发
**症状**:牧尘问"排名后是否会自动替换?"——答案是不会。
`_auto_promote_config` 只认 `model not in CANDIDATE_POOL` 的新模型。
现有模型排名互换nemotron 从第 2 升到第 1永不触发且只改 models 列表不更新 model.default。
**修复**:改为**排名驱动升级**——每次巡检主动检查 default_model 是否=排名第 1
不是就升级(仅 newapi-local 免费模型,付费保护)。闭环测试通过:
故意把 prof-b 改成排名第 5 的 llama-3.1-8b → 跑脚本 → 自动升级为 nemotron-3-super。
## 缺陷 4候选替换不验证真实可用
旧条件 `stability != "dead"`(测 2 次中 1 次成功就算),可能把半死不活的模型写进配置。
**修复**:新增 `_verify_model_usable(model)`——替换前真实调用一次 chat/completions
HTTP 200 + 有内容)才允许写入。所有候选条件改为 `stability == "stable"` + verify。
## 缺陷 5探针单次波动大
nemotron 探针上次 100 下次 75三段论逻辑题单次答错排名每次跑都在变。
**修复**`_run_quality_probe(trials=3)`——每题测 3 次取通过比例 × 权重。
全局超时 5min → 8min探针 3 倍耗时)。
## 缺陷 6OpenClaw fallbacks 不修复
旧版只修 primaryfallbacks 死模型qwen3-next-80b、minimax-m2.7)一直留着。
**修复**:新增 fallbacks 修复循环(同样 stable + verify 条件)。
## 安全发现config.yaml api_key 脱敏占位符
**症状**:推 Gitea 时发现 config.yaml 里 `api_key: sk-b12...6bbd` 是脱敏占位符不是真实 key。
**真相**:真实 key 在 `~/.hermes/.env`DEEPSEEK_API_KEY实测有效Hermes 运行时用 .env 注入。
config.yaml 里的占位符是脱敏工具写回的,不影响运行但推送会丢 key。
**修复**config.yaml 改用 Hermes 原生支持的 env 引用git 里不存明文:
```yaml
model:
default: deepseek-v4-flash
api_key_env: DEEPSEEK_API_KEY # model 段用 api_key_env
base_url: https://api.deepseek.com
providers:
deepseek:
key_env: DEEPSEEK_API_KEY # provider 段用 key_env
base_url: https://api.deepseek.com
```
Hermes 源码确认:`api_key_env` / `key_env` / `apiKeyEnv` 都是合法别名config.py _CAMEL_ALIASES
## 验证方法(关键:不能只看代码,要闭环实测)
1. 故意改坏 prof-b config → 跑脚本 → 确认自动修复 ✅
2. 故意把 model.default 设为排名第 5 → 跑脚本 → 确认排名驱动升级 ✅
3. 确认主配置付费模型 deepseek-v4-flash 没被动(保护生效)✅
4. 确认 OpenClaw 热重载(`openclaw logs | grep reload`)✅
## 铁律沉淀
1. **自动运维脚本必须验证"实际生效的配置字段"**,不只是维护静态列表
2. **任何写入配置的模型必须真实调用验证后才允许写入**
3. **排名公式必须含所有关键维度**(上下文长度是核心优势,不能丢)
4. **改模型前必须先问牧尘**——日常对话固定 deepseek-v4-flash 付费模型

View File

@ -8,6 +8,9 @@ tags: [self-healing, monitoring, auto-rollback, evolution, watchdog, config-prot
category: devops
trigger: 系统部署、开机自启、配置更改、故障恢复场景、备份验证、恢复演练
**2026-07-29 model-health.py 全覆盖**:自愈脚本覆盖 3 个配置格式——主(YAML) + prof-b(YAML) + OpenClaw(JSON)。死模型自动替补。gateway 内部无法 restart强保护需用户手动 systemctl restart。详见 references/model-health-multi-config-coverage.md。
**2026-08-01 model-health.py v3**:两个致命缺陷——①从不验证实际生效的 model.default只查 providers 列表)→ prof-b 被写成 NewAPI 不存在的模型全挂 503②排名公式丢 context_score → 1M 长上下文排不上。v3 新增 `_verify_model_usable()` 替换前真实调用验证 + 排名驱动自动升级 + 探针 3 次取平均。铁律:修复必须闭环测试(故意改坏→跑→确认)。详见 references/model-health-v3-fixes-20260801.md。
**2026-08-01 Gateway 崩溃循环事故(真根因 = auto-heal 自杀)**NRestarts=176 死循环的根源不是 unit 丢失本身,而是 config-protector.sh 的 auto-heal 机制——watchdog 检测到 hermes 重启瞬间 pgrep miss → 触发 `git checkout --force stable` → stable 停在 23 天前 → 整个 ~/.hermes 硬回滚 → 删新增文件/config 回退 → gateway 崩 → 再回滚 → 无限循环。帮凶:`git add -A` 跟踪运行时噪音 + stable tag 从 7-09 未更新 + hermes 在回滚触发列表。已修复6044957/4edbd50/bee399d/4d1d2e2+ 新增 anti-suicide-check.sh 每 30min 自检 6 规则。详见 references/auto-heal-suicide-crashloop-20260801.md。
**2026-08-01 systemd-run 逃生通道**gateway 内部硬保护拦截 stop/restartSIGTERM 传播自杀),但 `systemd-run --user --unit=xxx --collect bash script.sh` 从 gateway 外部独立进程树执行可绕开——用于"停崩溃循环 → 释放端口 → systemd 接管"的接管序列。脚本内 sleep 4 给会话留发送回复时间。详见 references/auto-heal-suicide-crashloop-20260801.md。
author: 小唯 A06
tags: [self-healing, monitoring, auto-rollback, evolution, watchdog, config-protection, daemon, backup, recovery]
category: devops

View File

@ -0,0 +1,70 @@
# Auto-Heal 自杀事故gateway 崩溃循环 176 次的真根因2026-08-01
## 事故表象
- hermes-gateway NRestarts=176systemd 无限崩溃循环)
- 日志:`cron.scheduler: failed to load config.yaml, while scanning a simple key`
- unit 文件 `~/.config/systemd/user/hermes-gateway.service` 丢失systemd 用内存旧定义重启
- 2 个 gateway 进程并存OpenClaw 分身拉起的 2198677 占 8644 端口 + prof-b 的 2199000
- 牧尘让分身OpenClaw拉起临时 gateway 才救活会话
## 表象归因(第一层,不完整)
第一轮排查认为unit 文件被删 + config.yaml 在 git rebase 冲突期损坏 + 8644 端口冲突 → 无限重启。
这只解释了"为什么起不来",没解释"为什么 unit 文件会消失、为什么 config 会损坏"。
## 真根因(第二层,`git checkout --force stable` 自杀机制)
```
health-watchdog.sh 每 30min
→ pgrep -f hermes 短暂 missgateway 重启瞬间)
→ CRITICAL=true
→ bash config-protector.sh auto-heal
→ auto_rollback_if_unhealthy() 检测到 30 分钟内配置有变更 + 关键进程挂
→ git checkout --force stable
→ stable tag 停在 2026-07-0923 天前!)
→ 整个 ~/.hermes 硬重置到 23 天前 → 删除所有新增文件、config.yaml 回退旧版
→ gateway 配置失效 → 崩 → watchdog 又触发 → 又回滚 → 死循环NRestarts=176
```
三个帮凶叠加:
1. **`config-protector.sh` snapshot 用 `git add -A`**:把 daemon/pid、cron/jobs.json、gateway.pid 等运行时噪音纳入版本库 → 仓库永远 dirty → snapshot 每 30min 都触发 commit
2. **stable tag 从未更新**`mark_stable` 只在手动调用时打 tag最后一次是 7-09。auto-heal 回滚到 stable = 回滚到 23 天前 = 灾难
3. **hermes 在 auto-heal 的进程检测列表**`for p in zhiyid-new new-api hermes bge_embed_server`——hermes gateway 重启是正常运维,重启瞬间 pgrep miss 就误触发回滚
## 修复(提交 6044957 + 4edbd50 + bee399d + 4d1d2e2
### config-protector.sh
1. snapshot 的 `git add -A` → 白名单:`git add SOUL.md AGENTS.md MEMORY.md config.yaml scripts/ skills/ workflows/ plugins/`
2. rollback 的 `git checkout --force stable``git restore --source=<target> -- <白名单>` 只回关键配置,不删新增文件
3. 新增年龄保护:目标 tag 超过 7 天 → 拒绝回滚(`age_days > 7 → return 1`
4. auto-heal 进程检测列表移除 hermes只留 zhiyid-new / new-api / bge_embed_server
### health-watchdog.sh
1. hermes 从 PROC_PATTERNS 移除,改用 `systemctl --user is-active hermes-gateway.service` 检测activating 也算 alive避免重启瞬间误报
2. 重启映射修正:`hermes → hermes-gateway.service`(原错误映射 `hermes.service` 不存在)
3. 重启后重检分支hermes 用 systemd 状态,其他用 pgrep
### git 仓库
1. `git rm --cached` 清理 20+ 运行时噪音文件cron/jobs.json、daemon/context.json、gateway.lock 等,.gitignore 里已有规则但对已跟踪文件无效)
2. `git tag -f stable HEAD` 把 stable 更新到当前健康状态
3. unit 文件备份到 `~/.hermes/systemd-units/` 并纳入 git防再丢失恢复`cp systemd-units/hermes-gateway.service ~/.config/systemd/user/ && systemctl --user daemon-reload`
### 新增防自杀自检 `scripts/anti-suicide-check.sh`watchdog 每 30min 联动)
6 项规则验证:① unit 文件存在 ② stable tag 新鲜≤7 天)③ auto-heal 不含 hermes ④ 主模型 = deepseek-v4-flash ⑤ 运行时噪音未被 git 跟踪 ⑥ gateway active。失效 → 飞书告警。
## 验证
- `bash scripts/anti-suicide-check.sh` → 6 项全绿
- `bash scripts/config-protector.sh rollback stable-20260709-022424` → 🚨 拒绝回滚23 天前)
- `bash scripts/health-watchdog.sh` → 🟢 一切正常,静默(不误触发回滚)
- hermes-gateway NRestarts 从 176 → 1active running
## 铁律(写进 SOUL/MEMORY
1. **自动回滚是最后手段,不是第一反应**:回滚目标必须是"最近已知良好点"last-config不是远古 stable
2. **任何 `git checkout --force` / `git reset --hard` 会删新增文件**——用 `git restore --source=<tag> -- <路径>` 代替
3. **hermes gateway 重启是正常运维**,不得作为自动回滚/自愈的触发条件systemd 自己管 Restart
4. **运行时噪音daemon/、cron/jobs.json、gateway.*、*.pid绝不 `git add -A`**——白名单提交
5. 改 config.yaml 保持语法有效yaml.safe_load 验证git rebase 冲突期禁止 gateway 读取
6. 修复必须闭环测试:故意改坏 → 跑 → 确认自动修复 → 确认不越界model.default 字节级未变)

View File

@ -0,0 +1,86 @@
# Gitea push 冲突处理 + config.yaml key 安全 — 2026-07-31
> 场景rebase 推送时遇到远端新提交 + auto-snapshot 冲突 + config.yaml 脱敏 key。
> 与 `gitea-push-timeout-20260713.md`(超时/force push互补。
## 场景 1push rejected远端有新提交
```
hint: Updates were rejected because the remote contains work that you do not have locally.
```
**原因**远端有新提交cron auto-snapshot 或其他分体推送过)。
**处理**
```bash
git fetch origin
git log --oneline HEAD..origin/main # 本地缺哪些
git log --oneline origin/main..HEAD # 本地多哪些
# 本地只有自己的修复 commit → rebase比 merge 干净)
git rebase origin/main
```
## 场景 2rebase 时 auto-snapshot commit 冲突
**症状**rebase 卡在 `auto-snapshot YYYY-MM-DD HH:MM:SS`cron 每天凌晨 3 点自动生成,含运行时噪音文件)。
**处理**auto-snapshot 本身无价值(运行时快照),**直接 `git rebase --skip`**,只保留自己的修复 commit。
**注意**rebase 过程中会反复卡(每个 commit 都可能冲突),别慌,逐段解决:
- 冲突标记检查:`grep -rn "<<<<<<< HEAD" --include="*" . 2>/dev/null | grep -v ".git/"`
- config.yaml 冲突保留牧尘手动改的权威版本deepseek-v4-flash 官方),不是脚本改的 nemotron 版
## 场景 3rebase 说"all conflicts fixed"但 continue 还报错
**症状**`git status` 显示无 UU/AA 文件,但 `git rebase --continue` 仍报 "You must edit all merge conflicts"。
**处理**
```bash
# 强制重新 stage 全部(包括未跟踪的新文件)
git add -A
GIT_EDITOR=true git rebase --continue
```
**常见坑**
- 冲突解决后 `.bak` / `.corrupt` 临时文件被误 add 进 git → `git rm --cached <file>` + 删除 + 加 .gitignore
- 两边内容相同只差 marker 的冲突:删掉 `<<<<<<<` / `=======` / `>>>>>>>` 三行即可,再删重复行
- 末尾还有 `(use "git commit --amend" to amend)``GIT_EDITOR=true git commit --amend --no-edit` 后再 continue
## 场景 4config.yaml 的 api_key 是脱敏占位符(安全发现!)
**症状**:推 Gitea 后发现 config.yaml 里 `api_key: sk-b12...6bbd` —— 这是脱敏占位符不是真实 key
**真相**
- 真实 key 在 `~/.hermes/.env`DEEPSEEK_API_KEYHermes 运行时从 .env 注入
- config.yaml 里的占位符是某脱敏工具写回的,**不影响本地运行**,但推送会丢 key别人 clone 用不了)
- 检查方法:`od -c` 看实际字节;`grep DEEPSEEK_API_KEY .env | cut -d= -f2 | wc -c` 对比长度
**修复**config.yaml 改用 Hermes 原生 env 引用git 里不存明文:
```yaml
model:
default: deepseek-v4-flash
api_key_env: DEEPSEEK_API_KEY # model 段用 api_key_env
base_url: https://api.deepseek.com
providers:
deepseek:
key_env: DEEPSEEK_API_KEY # provider 段用 key_env
base_url: https://api.deepseek.com
```
Hermes 源码确认 `key_env` / `api_key_env` / `apiKeyEnv` 都是合法别名config.py _CAMEL_ALIASES
改完 `hermes config check` 验证 + 当前会话正常响应即证明运行时 OK。
## 场景 5运行时噪音文件不该进 git
**症状**rebase 时 `daemon/context.json`、`cron/ticker_*`、`gateway_state.json`、`llm_context.json`、`state.db` 等运行时文件反复冲突。
**原则**`.gitignore` 只跟踪关键可恢复配置SOUL/AGENTS/MEMORY + skills/ + scripts/ + workflows/
运行时噪音sessions/、cron/output/、daemon/、logs/、*.db不提交。
冲突时用 `git checkout -- <file>` 丢弃噪音文件的工作区改动,只保留配置文件的合并。
## 验证清单(推送前)
```bash
git show origin/main:config.yaml | grep -A3 "^model:" # 确认 key_env 安全引用
git show origin/main:config.yaml | grep -c "sk-" || echo 0 # 确认无明文 key
git log --oneline origin/main -3 # 确认推送成功
```

View File

@ -0,0 +1,78 @@
# model-health.py v3 修复 — 2026-07-31致命缺陷 + 排名驱动自动替换)
> 场景:牧尘发现分体 prof-b 全挂HTTP 503质问"模型自愈脚本实践上并不会自动更换能用的模型"。
> 触发:脚本号称自动测模型→自动换最优,但把 prof-b 写成 NewAPI 里不存在的 `deepseek/deepseek-v4-flash`
## 两个致命缺陷v2 → v3 修复)
### 缺陷 1从不验证实际生效的 model.default 字段
**症状**prof-b `model.default: deepseek/deepseek-v4-flash` + `provider: newapi-local`
实际调用走 NewAPI127.0.0.1:3000时模型名不存在 → `HTTP 503 model_not_found`,全挂。
脚本跑了 18 个模型全绿,却对坏配置视而不见。
**根因**`_heal_config()` 只检查 `providers.newapi-local.models` **列表**里的死模型,
**从不检查 `model.default` 主模型字段**。`deepseek/deepseek-v4-flash` 根本不在测试列表里,
所以永远不会被修复。
**修复**:自愈逻辑新增第二步——检查 `model.default` 实际生效字段:
- 仅当 `model.provider == "newapi-local"` 时自愈(**付费主模型自动保护,绝不自动改**
- 在结果里找不到该模型(未测试)也视为需要修复
- 替换时同步修正 `base_url``api_key`
### 缺陷 2排名公式丢了 context_score长上下文模型排不上
**症状**:牧尘质问"模型排名对么?有长上下文不用"——1M ctx 的 nemotron-3-super 排不到第一。
**根因**`test_model()` 初始公式含 `cs*0.15`,但 `main()` 里**重新计算 rank_score 时把
context_score 丢了**(只用 probe/param/family/stab/speed导致长上下文一分不参与排名。
**修复**:统一公式,长上下文权重第二高:
```
rank_score = probe*0.30 + context*0.25 + param*0.20 + family*0.10 + stab*0.10 + speed*0.05
```
修复后 nemotron-3-super1M, probe 100登顶 🥇gpt-oss-120b128K, probe 92🥈。
## v3 新增机制
### `_verify_model_usable()` — 替换前真实调用安全闸门
所有候选替换前必须真实调用一次HTTP 200 + 有内容),防止写入死模型/不存在模型。
候选条件从 `stability != "dead"`(测 2 次中 1 次成功就算)改为 `stability == "stable"` + 验证通过。
### 排名驱动自动升级(`_auto_promote_config` v3
旧版只在"发现新模型(不在 CANDIDATE_POOL"时升级,**现有模型排名互换不触发**
且只改 models 列表不改 model.default。v3 改为每次巡检检查:
- A. `providers.newapi-local.default_model` 是否 = 排名第一(不是就换)
- B. `model.default`(仅 newapi-local provider排名落后于第一就换
- 全部替换前过 `_verify_model_usable`
### 探针 3 次取平均(`_run_quality_probe(trials=3)`
用户明确要求"测三次取平均值"。每道题测 3 次score = weight × 通过比例,
消除单次波动nemotron 上次 probe 100 这次 75 的抖动不再一票否决)。
全局超时 300s → 480s探针 3 倍耗时)。
## 闭环测试方法论(用户强调:"你测试了么?排名后是否会自动替换?"
**修复脚本不能只看代码,必须故意改坏 → 跑 → 确认修复**
```bash
# 1. 故意把 prof-b 改成排名第 5 的模型
python3 -c "...cfg['model']['default']='meta/llama-3.1-8b-instruct'..."
# 2. 跑脚本
python3 model-health.py
# 3. 期望输出
# ⬆️ [prof-b] default_model: openai/gpt-oss-120b → nvidia/nemotron-3-super-120b-a12b (排名第1)
# ⬆️ [prof-b] model.default: meta/llama-3.1-8b-instruct → nvidia/nemotron-3-super-120b-a12b
# 4. 确认主配置付费模型没被动deepseek-v4-flash 保护生效)
```
## 铁律
- **自愈脚本必须验证"实际生效的配置字段"model.default不只是维护静态列表**
- 任何自动写入配置的模型必须真实调用验证后才允许写入
- 排名公式必须包含 context_score长上下文是核心优势
- 修复必须闭环测试(改坏→跑→确认),不能只看代码逻辑
- 付费主模型deepseek-v4-flash永不自动改分体prof-b/OpenClaw才用免费模型自动换
- cron `6a45e41cba6c`(每 6h自动跑

View File

@ -1,8 +1,8 @@
---
tags: [openclaw, mcp, hermes-integration]
name: openclaw-mcp
description: "OpenClaw 作为 MCP Server 接入 Hermes — 已验证 2026-07-12暴露 9 个工具conversations_list/get、messages_read/send、events_poll/wait、attachments_fetch、permissions"
version: 1.0.0
description: "OpenClaw 作为 MCP Server 接入 Hermes — 已验证 2026-07-12暴露 9 个工具conversations_list/get、messages_read/send、events_poll/wait、attachments_fetch、permissions。2026-07-31 新增 scope upgrade 审批修复devices approve"
version: 1.1.0
author: 小唯
date: 2026-07-12
---
@ -61,6 +61,16 @@ python3 -c "import yaml; c=yaml.safe_load(open('/home/muc/.hermes/config.yaml'))
## Pitfalls
- **MCP 连接报 ClosedResourceError / scope upgrade pending approval2026-07-31 新增)**
- 症状:`mcp_openclaw_*` 工具全部报 `ClosedResourceError`,但 `hermes mcp test openclaw` 却连得上
- 根因OpenClaw gateway 有设备权限模型。Hermes 的 MCP 客户端设备只有 `operator.pairing,operator.read` 权限,它请求升级到 `operator.approvals,operator.read,operator.write`——这个升级请求挂在 gateway 审批队列里(可能挂 12 天没人批)
- 诊断:`tail ~/.hermes/logs/mcp-stderr.log` → `gateway connect failed: scope upgrade pending approval (requestId: xxx)`
- 修复三步:
1. `openclaw devices list` 找 pending 请求的 requestId
2. `openclaw devices approve <requestId>`(批准 scope 升级)
3. 等待 Hermes MCP 客户端自动重连(约 43s 自动重试),或 `hermes mcp test openclaw` 验证
- 验证:`hermes mcp test openclaw` → `✓ Connected, Tools discovered: 9`
- 注意:当前会话持有的 MCP 连接是旧连接,需要等自动重连或新会话生效
- **`hermes mcp add` 只做临时探测,不写 config.yaml** — 连接测试成功后必须手动 patch config.yaml 持久化
- **`hermes mcp reload` 不存在** — 需要 `hermes gateway restart` 才能让新配置生效
- **`openclaw mcp serve` 是 stdio 模式** — 进程处理完一条消息后退出,不能当作后台 TCP 服务