---
name: hermes-pitfalls-learned
description: >-
  宝锐生物工作台中踩过的Hermes Agent开发陷阱与解决方案。
  涵盖：file://协议下的fetch/CORS问题、HTML文件生成安全规范、
  归档同步机制、价格档案流程、文件操作保护、对话效率优化、
  合同审核规范、飞书API接入、MCP数据管道、实时API服务器。
  铁律：所有KPI数字必须真实，绝对不准估算。
  Hermes运维：更新升级、Gateway多Profile冲突、MEMORY.md精简。
  当涉及文件生成、HTML开发、数据同步、归档检测、合同审核、
  飞书API、MCP、MQL查询、客诉看板、审批阻塞、工作台页面、Hermes更新升级时触发。
triggers:
  - 生成HTML文件前
  - 操作客户管理目录下的文件
  - 遇到file://协议相关问题
  - 归档/文件检测不工作
  - 新建拜访卡/市场调研卡/来访接待报告
  - 文件丢失或被覆盖
  - 长时间会话效率下降
  - 审核合同/声明/协议
  - 飞书API接入/拉取数据/MCP
  - 飞书项目/销售管理/客户项目管理/售后管理
  - MQL查询/工作项查询
  - 客诉看板/审批阻塞
  - 飞书Gateway故障：Agent error、消息不响应、WebSocket断连
  - 模型/Provider切换后飞书消息异常
  - Hermes更新升级后Gateway无法启动/端口冲突
  - 多Profile Gateway资源冲突
  - MEMORY.md超限/需要精简
  - state.db损坏/数据库修复
  - CloudBase部署/CDN缓存/JSON文件同步
  - Cloudflare Tunnel断连/不稳定
  - Gateway飞书会话爆炸/无响应
  - 模型Provider配置错误导致404
---



# Hermes Agent 开发踩坑记录与规范（宝锐工作台定制）

## 🔴 铁律一：所有数据必须真实，严禁估算

> 用户："你可千万不要给我瞎估算，这里的信息全部要真实的"

**绝对禁止**：
- 用目标占比分摊销售额到部门或个人
- 用任何比例系数推算KPI实际值
- 在数据不可追溯时填入任何数字
- 标注"估算"、"≈"、"预计"的数字当做真实值展示

**正确做法**：
- 只有数据可精确追溯到原始记录时才填入
- 无法确认时留空或标"待确认"
- 始终标注数据来源（ERP已审计/MCP实时/批量导出）
- 每页显示数据来源徽章（🟢实时/🟡批量/🔴ERP）

> 以下为具体技术陷阱。

> 参考：xugj520.cn《Hermes Agent 避坑指南：25个开发者绕不开的致命坑》
> 对应条目: #16长任务失忆 #10工具调用失效 #17 Token爆炸 #15记忆策略

## Pitfall 1: file:// 协议下 fetch() 全部失败

**症状**：从 `file:///Users/.../xxx.html` 打开的页面中所有 `fetch()` 返回404或CORS错误。

**根因**：`file://` 协议下 `fetch('/路径')` 解析为 `file:///路径`（文件系统），非HTTP请求。且 `file://` → `http://` 被浏览器CORS拦截。

**解决方案**：大数据内嵌HTML；轻量数据用 `httpBase` 拼接；文件清单用Python扫描→JSON→页面fetch。

## Pitfall 2: 文件被误删 / symlink断链

**症状**：生成的HTML文件失踪，`ls` 显示 "broken symbolic link"。

**解决方案**：写入前 `~/.hermes/scripts/safe_write.sh <filepath>` 自动备份（保留5版）；Symlink仅用于命名兼容。

## Pitfall 3: MEMORY.md 超限

**症状**：MEMORY.md 超过2200字符，Agent写入受限。

**解决方案**：定期精简，只保留稳定业务事实；过程性知识放skills。完整精简方案和 Hermes 体检流程见 `references/hermes-health-check.md`。

## Pitfall 4: HTML生成中JS语法错误高频

**症状**：`node --check` 报错，页面空白。

**解决方案**：用 `write_file` 写完整HTML（不用patch拼接）；写完必须 `node --check`。

## Pitfall 5: 归档检测不工作

**症状**：访前准备中心文件状态始终"待生成"。

**当前方案**：Python扫描→`file_manifest.json`→页面fetch+模糊匹配。`custShort`算法：去括号→去后缀→迭代剥离。

## Pitfall 6: 长时间会话效率下降

**应对**：`max_turns: 60`, `temperature: 0.3`, `tool_use_enforcement: strict`，50轮+拆分到子Agent。

## Pitfall 7: 合同/声明文件审核

**触发**：文件放入 `~/Desktop/hermes输入/合同审核/`。

**流程**：提取全文→四级风险标注(🔴P0/🟡P1/🟢P2)→逐条修改建议→修订版docx。输出到 `~/Desktop/Hermes输出-工作类/合同/`。

**常见检查点**：价格锁死无调价出口、知识产权归属模糊、授权范围过度、保密期过短、争议管辖不利。

## Pitfall 8: 飞书API接入路径

**核心区分**：tenant_access_token只访问应用文件夹；user_access_token（OAuth授权）继承用户全部权限。

**飞书项目**：独立API体系(project.feishu.cn)，通过MCP Server接入（非REST API）。

## Pitfall 9: MCP数据管道模式

**管道**：`飞书项目MCP → Python(curl) → JSON → 工作台fetch()`。
**脚本位置**：`~/Desktop/Hermes输出-工作类/数据/mcp_*.py`。
**Token**：硬编码在脚本中（X-Mcp-Token是长期token）。

## Pitfall 10: 审批流转前必须确认实际阻塞节点

**症状**：`list_todo`显示"大区/部门经理审核"，尝试批量流转失败。

**根因**：`list_todo.node_name`是流程标签，不等于当前实际阻塞节点。

**正确方案**：逐条`get_node_detail`→过滤`status:"in_progress"`→确认当前用户是owner→`transition_node(action:"confirm")`。

## Pitfall 11: MQL语法和list_todo陷阱

**MQL**：project_key为独立参数；FROM格式`` `空间`.`类型` ``；不支持`SELECT *`；OFFSET分页可靠无重复。

**list_todo陷阱**：`node_name`是角色标签非当前活跃节点。业务线分类：含「课题组」=生命科学，其余=诊断原料。

## Pitfall 12: 飞书项目URL中 work_item_type 必须用 `story` 非 `sj`

**症状**：生成的URL `xsguanli/sj/detail/xxx` 点开显示"无对应工作项"。

**根因**：导出模板用 `sj`（商机缩写），前端路由用 `story`（type key）。

**修复**：所有URL `sj/detail` → `story/detail`。URL模板：`https://project.feishu.cn/{simple_name}/story/detail/{id}`。

## Pitfall 13: 销售订单字段通过关系和角色补全

**可用MQL**：单据编号/货号#/金额/单价/销售数量。需补全：客户(relation遍历) + 销售员(role_members)。

**性能**：客户补全仅对近90天明细逐条查，历史用聚合。

## Pitfall 14: MQL字段名是中文显示名（2026-07-09）

**症状**：`SELECT work_item_id`→返回字段名"工作项id"，代码`fields.get('work_item_id')`永远为空。

**根因**：MCP返回字段名是中文显示名，非API key。

**修复**：parse_items中标准化映射：`工作项id→work_item_id, 名称→name, 单据编号→order_no, 货号#→product_code`。

**完整字段映射表**：见 `references/mql-field-mappings.md`。

## Pitfall 15: MQL创建者字段≠销售员（2026-07-09）

**症状**：所有销售订单创建者指向同一人（自动化机器人），KPI按人汇总无效。

**根因**：`创建者`返回飞书系统记录创建人，真实销售员在`get_workitem_brief→role_members→销售员`。

**⚠️ 关键原则**：**绝对不准估算**。KPI的所有数字必须是真实数据，禁止用目标占比分摊或任何近似计算。H2月度实际额只有在客户→部门映射完成后才能填入，在此之前字段应为0。

## Pitfall 16: list_related_workitem间歇超时（2026-07-09）

**修复**：超时设30s（非15s），加3次重试，建`{wid: customer}`缓存避免重复查询。客户名补全失败时不应阻塞整体管道——继续输出已拉取的订单，客户列留空待下次补全。

## Pitfall 17: MQL WHERE + 大OFFSET超时（2026-07-09）

**症状**：`SELECT ... WHERE 创建时间 >= "2026-07-01" LIMIT 50 OFFSET 250` 超时。

**根因**：MCP服务器对WHERE+大OFFSET组合查询慢。

**正确方案**：先在销售管道中拉取全量订单并聚合到 `daily_sales_mcp.json` 的 `daily_summary` 中。KPI管道从 `daily_summary` 读取月度总额，避免重复调MCP做WHERE查询。

## Pitfall 18: 实时API服务器模式（2026-07-09）

**方案**：`api_server.py` 代替静态文件服务器。端口8765同时提供静态文件+API端点，后者实时调用MCP。

```bash
cd ~/Desktop/Hermes输出-工作类 && python3 api_server.py
```

**API端点**：
| 路径 | 数据 | 延迟 |
|------|------|------|
| `/api/activities` | 最新100条活动 | 2-5s |
| `/api/complaints` | 客诉列表 | 2-3s |
| `/api/sales` | 今日销售单 | 2-5s |
| `/api/ping` | 健康检查 | <1ms |

**页面集成**：`fetch('/api/xxx').catch(() => fetch('/数据/xxx.json'))` 实现实时+缓存双通道。

## Pitfall 19: 飞书项目URL work_item_type必须用`story`（2026-07-09）

**症状**：`xsguanli/sj/detail/{id}` 点击显示"无对应工作项"。

**根因**：导出模板用`sj`(商机)，但前端路由用 type key `story`。

**正确URL模板**：`https://project.feishu.cn/{simple_name}/story/detail/{work_item_id}`。验证：`meegle url decode --url "..."`。

## Pitfall 20: 功能交付不完整导致用户挫败（2026-07-09）

**症状**：用户说"你真的把我要的功能更新了吗？排序没有、按月季度分组没有"。添加了 `dateKey` 但没有同步配置 `sumKeys` 和聚合列渲染逻辑。

**根因**：只完成了基础设施（参数传递），没完成端到端功能（用户可见的效果）。`HermesTable.render({dateKey:'date'})` 只加了日期筛选栏，聚合模式需要 `sumKeys` + `renderCols` 动态交换才能正确显示。

**铁律**：用户说"要做A+B+C"，验收标准是A+B+C全部能用，不是"框架支持A+B+C但没调通"。

**自查清单**（每次改完页面后）：
1. `node --check` JS语法 ✅
2. 打开浏览器点每个按钮 → 确认有响应
3. 切换周期（日/周/月/季/年）→ 确认数据正确聚合
4. 点列头排序 → 确认升/降/取消三态切换
5. 搜关键词 → 确认筛选结果正确
6. CSV导出 → 确认文件可打开
1. 写入前备份：`~/.hermes/scripts/safe_write.sh <filepath>`
2. 写入后验证：`ls -la` + HTTP HEAD
3. 不创建symlink链

### HTML卡片规范
1. 顶栏：48px白底，BIORI BIOTECH
2. 配色：`--pri:#1a73e8` 白蓝科技风
3. JS语法：`node --check` 必过
4. 编辑栏：右下角 ✏️编辑/💾保存/↩恢复 float bar
5. contentEditable + localStorage 持久化

## Pitfall 21: `<table>` 容器塞 HermesTable `<div>` 卡片全部空白（2026-07-09）

**症状**：明细视图有框架没数据，表格永远空白。控制台无报错。

**根因**：HermesTable 产生 `<div class="ht-card">`，放入 `<table>` 容器时，浏览器HTML解析器把 `<div>` 弹出 table 结构外，DOM 里实际是空壳。

```html
<!-- ❌ 错误：所有内容被浏览器弹出 -->
<div class="card"><table id="myTable"></table></div>
<!-- ✅ 正确：HermesTable用div -->
<div class="card"><div id="myTable"></div></div>
```

**批量修复**：所有 `actTable/testTable/ordTable/compTable/blkTable` 容器必须用 `<div>`。

## Pitfall 22: JSON嵌套格式与代码假设不一致（2026-07-09）

**症状**：`(TESTS.daily[day]||[]).forEach is not a function` 或 `cannot read property 'type' of undefined`

**根因**：测试单 JSON 是 `daily[date]={count,amount,details:[]}` 非 flat数组；活动API缺 `type` 字段。

**修复**：
```javascript
// 测试单
((TESTS.daily[day]||{}).details||[]).forEach(function(t){t.date=day;all.push(t)});
// 活动类型推断
atype = '拜访';
if(/线上|电话/.test(desc)) atype='线上跟进';
else if(/测试|送样/.test(desc)) atype='测试跟进';
```

## Pitfall 23: HermesTable 加载遮罩永不消失（2026-07-09）

**症状**：页面一直显示"加载中…" spinner，数据实际上已返回。

**修复（三重保障）**：
1. `refresh()` 开头立即 `ld.style.display='none'`
2. 8秒超时自动隐藏
3. 全函数 `try/catch` 包裹，失败时显示 ⚠️

## Pitfall 24: 功能交付前必须端到端验证（2026-07-09）

**教训**：用户说"你真的把我要的功能更新了吗？排序没有、按月季度分组没有"——只加了 `dateKey` 参数但没配 `sumKeys` 和聚合列渲染。

**自查清单**：每次改完页面 → 1) JS语法 2) 每个按钮有响应 3) 周期切换正确 4) 排序三态 5) 搜索筛选 6) CSV导出

## Pitfall 25: IMA参考页面设计模式（2026-07-10）

用户提供的 `宝锐销售工作台-ima.html` 展示了偏好设计：

| 特征 | IMA方案 | 应用到工作台 |
|------|--------|------------|
| 顶栏 | 深蓝渐变+角色切换 | 可选暗色顶栏 |
| 卡片 | 左侧彩色边框 | 用于KPI卡片 |
| 面板 | 6维度2列网格 | 活动/测试/订单/售后/案例/待办 |
| 表格 | 裸innerHTML | 极简渲染，不用重型组件 |
| 数据 | 硬编码嵌入 | 改用MCP实时+JSON |
| 规章 | 每个面板底部引用规程编号 | 加 info-bar |

**核心原则**：渲染优先级 — 裸innerHTML > HermesTable > Smart.Table。用户在乎数据准确和加载速度，不care组件华丽度。

## Pitfall 26: MCP活动类型错误——查了story不是活动（2026-07-10）

**症状**：MCP返回7月24条story，Excel导出332行活动，差12倍。

**根因**：`销售管理.story` = 商机，不是活动。飞书项目的"活动"是独立type `销售管理.活动`，type_key=`65ae1e5d44338dbe7c39a29a`。

**发现方法**：`list_workitem_types` 列出13种类型，含"活动"。

**修复**：`SELECT ... FROM \`销售管理\`.\`活动\``，URL格式 `xsguanli/65ae1e5d44338dbe7c39a29a/detail/{id}`

## Pitfall 27: 客诉无法按人分权——需客户清单交叉匹配（2026-07-10）

**症状**：客诉只有 `id/name/days/url`，无owner字段。选销售员后无法过滤。

**解决方案**：客户清单Excel → `{客户名: 销售员}` 映射。客诉名称含客户名，前缀匹配。24/24全部成功。

## Pitfall 28: 销售员视图全面板精准过滤（2026-07-10）

选销售员后必须全部面板精准到人：活动(`a.sales`)、销售(`s.salesperson` ERP列[1])、测试(`t.sales`)、客诉(客户清单匹配)、KPI(`people[name]`)。

## Pitfall 30: macOS screencapture 对 Chrome 窗口失败（2026-07-11）

**症状**：`screencapture -l <Chrome WindowID>` 返回 "could not create image from window"。

**根因**：macOS 26.5 的 screencapture 无法截取 Chrome 窗口。System Events 辅助功能也需手动授权。

**替代方案**：
1. Chrome AppleScript + `execute javascript` 获取 innerText（需先开启：Chrome → 查看 → 开发者 → 允许 Apple 事件中的 JavaScript）
2. `computer_use` 工具（需 `cua-driver` 安装，但国内网络下载 GitHub release 超时）
3. 用户手动截图/导出

## Pitfall 31: HTML页面修改后用户看不到更新（2026-07-11）

**症状**：文件已通过 `write_file`/`patch` 更新，`curl` 确认服务器返回新内容，但用户浏览器显示旧版。

**根因**：浏览器强缓存。`meta http-equiv` 标签对已缓存的页面无效。

**修复（四重保障）**：
1. `meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate"` + `Pragma: no-cache` + `Expires: 0`
2. 每次修改后给URL加唯一 `?t=...` 参数强制重新加载
3. 重启 HTTP 服务器清除服务端缓存
4. 告知用户 Cmd+Shift+R 或无痕窗口打开

**最可靠的验证方式**：`curl -s http://127.0.0.1:8765/工具/xxx.html | grep -c "新特征字符串"` 确认服务器已更新，然后用户无痕窗口打开。

## Pitfall 32: `computer_use` 安装在国内超时（2026-07-11）

**症状**：`hermes computer-use install` 下载 GitHub release（cua-driver-rs）超时。

**替代方案**：使用 Chrome AppleScript 直接控制浏览器（见 Pitfall 30）。核心脚本：
```bash
osascript -e 'tell application "Google Chrome"
  open location "URL"
end tell'
# 重新注册
hermes gateway start
```

**验证**：`hermes gateway status` 不再显示 `stale` 警告，且 PID 已更新。

## Pitfall 46: model.api_key 与 providers.<name>.api_key 不一致导致 Gateway Agent 全部报错（2026-07-19）

**症状**：CLI 会话一切正常，但飞书/微信 Gateway 每条消息都报 "Agent error"（或 "Sorry, I encountered an unexpected error"），即使 `/reset` 后也不行。Gateway 状态显示正常（feishu connected），且消息能被 Gateway 接收，但 Agent 处理时崩溃。

**根因**：`config.yaml` 中 `model.api_key` 和 `providers.<provider>.api_key` 是两个独立的值，可能不同步：
- CLI Agent 使用 `model.api_key`
- Gateway 的 api_server（监听 `127.0.0.1:8642`）使用 `providers.<provider>.api_key`

切换模型或手动修改配置时容易只更新一处而遗漏另一处。当 provider 级别的 key 失效或过期时，Gateway 每次调用 DeepSeek（或其他 provider）都返回 `Invalid API key`，导致所有会话崩溃。

**诊断**：
```bash
# ✅ 正确：shell-first 模式
tmux new-session -d -s turing -x 160 -y 50          # 1. 启动 shell
tmux send-keys -t turing "hermes --provider kimi-coding --model kimi-k2 --toolsets terminal,file,browser" Enter  # 2. 注入命令
sleep 10                                              # 3. 等待初始化完成

# 2. 注册为 Hermes provider（Ollama 提供 OpenAI 兼容的 /v1 端点）
hermes config set providers.local.api_key "ollama"
hermes config set providers.local.base_url "http://localhost:11434/v1"
hermes config set providers.local.default_model "qwen3:4b-16k"

# 1. 注册获取免费 API Key（1000次/月）
# 打开 https://app.tavily.com → Google/GitHub 登录 → Dashboard → 复制 Key（格式：tvly-...）

# 注册 https://brave.com/search/api/ → 获取 Key → 写入 .env
echo "BRAVE_SEARCH_API_KEY=BSA-your-key" >> ~/.hermes/.env
hermes tools enable web
```

**注意**：
- `hermes tools enable web` 后需要 `/reset` 新会话才能加载 web_search 工具
- Tavily Key 以 `tvly-` 开头（Dev Key）或 `tvly-dev-` 开头
- 工具生效后 `web_search` 和 `web_extract` 两个工具均可用
- 中国境内访问 Tavily API 正常，无需代理

## Pitfall 63: CloudBase 部署后页面数据加载失败——JSON 文件未部署（2026-07-26）\n\n**症状**：CloudBase 工作台页面在 HTTPS 域名下登录成功，但数据加载显示 `⚠️ 加载失败：customers，请检查文件路径 ../数据/...`。本地 localhost:8765 正常。\n\n**根因（三层）**：\n1. **JSON 数据文件未部署到 CloudBase**：页面的回退路径 `../数据/pricing/_key_customers.json` 在 CloudBase 上 404\n2. **HTTPS 页面禁止 HTTP 请求**（浏览器混合内容策略）：`http://127.0.0.1:8765` 被浏览器拦截\n3. **Cloudflare Tunnel 不稳定**：Tunnel 断连时 API 也无响应，三重失败叠加\n\n**修复**：\n\n```bash\n# 1. 部署全部数据文件到 CloudBase（1398 个文件）\ncd /Users/liuxinyuan/Desktop/Hermes输出-工作类\ntcb hosting deploy 数据/ 数据 -e bier-sales-d0gatbvlx288724e9\n\n# 2. 部署 logo.png 等静态资源\ntcb hosting deploy 工具/logo.png /logo.png -e bier-sales-d0gatbvlx288724e9\n\n# 3. 验证关键文件可访问\ncurl -s -o /dev/null -w \"%{http_code}\" \\\n  \"https://bier-sales-d0gatbvlx288724e9-1458438710.tcloudbaseapp.com/数据/pricing/_key_customers.json\"\n# 应返回 200\n```\n\n**部署后页面仍不更新的原因**：CloudBase CDN 缓存（5-10 分钟刷新）。验证方法：\n```bash\n# 用 tcb hosting download 确认 Origin 已更新（绕过 CDN）\ntcb hosting download /index.html /tmp/check.html -e bier-sales-d0gatbvlx288724e9\ngrep -c '新特征' /tmp/check.html\n\n# CDN 缓存刷新后，浏览器无痕窗口验证\n```\n\n**防坑清单**（每次改页面后）：\n- [ ] 修改了 HTML → 部署 `/index.html`（注意 cloudPath 必须带 `/`）\n- [ ] 新增了数据文件 → 部署 `数据/` 目录\n- [ ] 验证 Origin 文件 → `tcb hosting download`\n- [ ] 等 CDN 刷新 → 浏览器无痕窗口 + `?v=timestamp` 参数验证\n\n## Pitfall 64: Cloudflare Tunnel 稳定性 + 离线登录双保险（2026-07-26）\n\n**症状**：Cloudflare `trycloudflare.com` Tunnel 频繁断连：\n- 重启时 URL 变化（随机子域名）\n- QUIC 协议在中国网络环境下被墙，回退 HTTP/2 后延迟增加\n- `hermes update` 的 Gateway 重启会 SIGTERM 所有后台进程（包括 cloudflared）\n- 多个 cloudflared 进程冲突（pkill 不彻底 → 新旧进程争端口）\n\n**根因**：`trycloudflare.com` 是免费临时 Tunnel，无固定域名，每次重启 URL 都变。且 Hermes update 的进程清理波及所有子进程。\n\n**修复策略**：\n\n### 1. tmux 隔离启动（不受 Gateway 重启影响）\n```bash\n# 彻底清理所有 cloudflared 进程\npkill -9 -f cloudflared\nsleep 2\n\n# tmux 隔离启动（会话名 tunnel）\ntmux kill-session -t tunnel 2>/dev/null\ntmux new-session -d -s tunnel 'cloudflared tunnel --url http://localhost:8765 2>&1'\nsleep 10\n\n# 获取新 URL\ntmux capture-pane -t tunnel -p | grep -o 'https://[a-z-]*\\.trycloudflare\\.com' | tail -1\n```\n\n### 2. 页面离线登录（不依赖 Tunnel）\n在 `doLogin()` 中添加 OFFLINE_USERS 硬编码回退：\n```javascript\nvar OFFLINE_USERS = {\n  'admin': {name:'超级管理员', role:'admin', dept:'诊断原料销售部'},\n  'liuxinyuan@biori.com': {name:'刘新元', role:'admin', dept:'诊断原料销售部'}\n};\nvar OFFLINE_PWD = 'biori2026';\n\n// tryLogin 的最后一个 catch 中：\nif (i >= apiUrls.length) {\n  var u = OFFLINE_USERS[email.toLowerCase()];\n  if (u && pwd === OFFLINE_PWD) { finishLogin(u); return; }\n  // ...否则显示通用错误\n}\n```\n\n### 3. 数据加载 JSON 优先（不依赖 Tunnel）\n将 loadData() 的 fetch 顺序从\"API 优先\"改为\"JSON 优先\"：\n```javascript\nif (fallbackUrl) {\n  return tryFetch(fallbackUrl).catch(function() {\n    if (apiUrl) return tryFetch(apiBase + apiUrl);\n    throw new Error(key);\n  });\n}\n```\n\n**三重保障体系**：\n```\n登录：API (Tunnel/localhost) → 失败 → 离线凭据\n数据：CloudBase CDN JSON → 失败 → Tunnel API\n```\n\n**Tunnel URL 同步**：Tunnel 重启后需更新 HTML 中的 4 处旧 URL → 部署到 CloudBase → 等 CDN 刷新（5-10 分钟）。完整操作见 `references/hermes-health-check.md`。

## Pitfall 65: Gateway 飞书会话 1000+ 消息未 /reset 导致 API 超时（2026-07-28）

**症状**：飞书回复极短（3-7 字符），Gateway 日志 `APIConnectionError` 全 3 次重试失败。`hermes gateway restart` 超时（60s+），kill 旧进程后手动 start 才成功。

**根因**：同一飞书会话累积 1000+ 条消息未 `/reset`。每次 API 调用都要发送全部上下文（1000+ 条消息 = 数万 token），请求体过大导致 DeepSeek 连接超时。

**诊断**：
```bash
# 如果 DROP 报 "database disk image is malformed" → 放弃此路径，核心表已损坏
```

### 路径 B：.clone 导出/导入——本次场景失败
```bash
cp ~/.hermes/state.db ~/.hermes/state.db.bak
sqlite3 ~/.hermes/state.db ".clone /tmp/state_repaired.db"
# FTS 表可能重复创建，索引可能不存在
# 部署数据文件（1398 个 JSON/CSV）到 CloudBase
cd ~/Desktop/Hermes输出-工作类
tcb hosting deploy 数据/ 数据 -e bier-sales-d0gatbvlx288724e9
```

## Pitfall 67: 端口被 Tailscale Serve 占用——8765 不通（2026-07-27）

**症状**：`python3 销售工作台服务.py 8765` 反复失败 `OSError: [Errno 48] Address already in use`。`lsof -i :8765` 有时不显示进程，但 `netstat -anv | grep 8765` 显示 `io.tailscale.ipn` 绑定。换成 8766 立即正常。

**根因**：**Tailscale Serve** 之前配置了 `tailscale serve --https=8765 / http://127.0.0.1:8000`，在 8765 端口做了代理。即使用 `kill` 杀进程，Tailscale 也会重新绑定。

**诊断**：
```bash
# 确认 Tailscale Serve 配置
tailscale serve status

## Pitfall 1: file:// 协议下 fetch() 全部失败

**症状**：从 `file:///Users/.../xxx.html` 打开的页面中所有 `fetch()` 返回404或CORS错误。

**根因**：`file://` 协议下 `fetch('/路径')` 解析为 `file:///路径`（文件系统），非HTTP请求。且 `file://` → `http://` 被浏览器CORS拦截。

**解决方案**：大数据内嵌HTML；轻量数据用 `httpBase` 拼接；文件清单用Python扫描→JSON→页面fetch。


## Pitfall 2: 文件被误删 / symlink断链

**症状**：生成的HTML文件失踪，`ls` 显示 "broken symbolic link"。

**解决方案**：写入前 `~/.hermes/scripts/safe_write.sh <filepath>` 自动备份（保留5版）；Symlink仅用于命名兼容。


## Pitfall 3: MEMORY.md 超限

**症状**：MEMORY.md 超过2200字符，Agent写入受限。

**解决方案**：定期精简，只保留稳定业务事实；过程性知识放skills。完整精简方案和 Hermes 体检流程见 `references/hermes-health-check.md`。


## Pitfall 4: HTML生成中JS语法错误高频

**症状**：`node --check` 报错，页面空白。

**解决方案**：用 `write_file` 写完整HTML（不用patch拼接）；写完必须 `node --check`。


## Pitfall 5: 归档检测不工作

**症状**：访前准备中心文件状态始终"待生成"。

**当前方案**：Python扫描→`file_manifest.json`→页面fetch+模糊匹配。`custShort`算法：去括号→去后缀→迭代剥离。


## Pitfall 6: 长时间会话效率下降

**应对**：`max_turns: 60`, `temperature: 0.3`, `tool_use_enforcement: strict`，50轮+拆分到子Agent。


## Pitfall 7: 合同/声明文件审核

**触发**：文件放入 `~/Desktop/hermes输入/合同审核/`。

**流程**：提取全文→四级风险标注(🔴P0/🟡P1/🟢P2)→逐条修改建议→修订版docx。输出到 `~/Desktop/Hermes输出-工作类/合同/`。

**常见检查点**：价格锁死无调价出口、知识产权归属模糊、授权范围过度、保密期过短、争议管辖不利。


## Pitfall 16: list_related_workitem间歇超时（2026-07-09）

**修复**：超时设30s（非15s），加3次重试，建`{wid: customer}`缓存避免重复查询。客户名补全失败时不应阻塞整体管道——继续输出已拉取的订单，客户列留空待下次补全。


## Pitfall 20: 功能交付不完整导致用户挫败（2026-07-09）

**症状**：用户说"你真的把我要的功能更新了吗？排序没有、按月季度分组没有"。添加了 `dateKey` 但没有同步配置 `sumKeys` 和聚合列渲染逻辑。

**根因**：只完成了基础设施（参数传递），没完成端到端功能（用户可见的效果）。`HermesTable.render({dateKey:'date'})` 只加了日期筛选栏，聚合模式需要 `sumKeys` + `renderCols` 动态交换才能正确显示。

**铁律**：用户说"要做A+B+C"，验收标准是A+B+C全部能用，不是"框架支持A+B+C但没调通"。

**自查清单**（每次改完页面后）：
1. `node --check` JS语法 ✅
2. 打开浏览器点每个按钮 → 确认有响应
3. 切换周期（日/周/月/季/年）→ 确认数据正确聚合
4. 点列头排序 → 确认升/降/取消三态切换
5. 搜关键词 → 确认筛选结果正确
6. CSV导出 → 确认文件可打开
1. 写入前备份：`~/.hermes/scripts/safe_write.sh <filepath>`
2. 写入后验证：`ls -la` + HTTP HEAD
3. 不创建symlink链

### HTML卡片规范
1. 顶栏：48px白底，BIORI BIOTECH
2. 配色：`--pri:#1a73e8` 白蓝科技风
3. JS语法：`node --check` 必过
4. 编辑栏：右下角 ✏️编辑/💾保存/↩恢复 float bar
5. contentEditable + localStorage 持久化


## Pitfall 24: 功能交付前必须端到端验证（2026-07-09）

**教训**：用户说"你真的把我要的功能更新了吗？排序没有、按月季度分组没有"——只加了 `dateKey` 参数但没配 `sumKeys` 和聚合列渲染。

**自查清单**：每次改完页面 → 1) JS语法 2) 每个按钮有响应 3) 周期切换正确 4) 排序三态 5) 搜索筛选 6) CSV导出


## Pitfall 30: macOS screencapture 对 Chrome 窗口失败（2026-07-11）

**症状**：`screencapture -l <Chrome WindowID>` 返回 "could not create image from window"。

**根因**：macOS 26.5 的 screencapture 无法截取 Chrome 窗口。System Events 辅助功能也需手动授权。

**替代方案**：
1. Chrome AppleScript + `execute javascript` 获取 innerText（需先开启：Chrome → 查看 → 开发者 → 允许 Apple 事件中的 JavaScript）
2. `computer_use` 工具（需 `cua-driver` 安装，但国内网络下载 GitHub release 超时）
3. 用户手动截图/导出


## Pitfall 67: 端口被 Tailscale Serve 占用——8765 不通（2026-07-27）

**症状**：`python3 销售工作台服务.py 8765` 反复失败 `OSError: [Errno 48] Address already in use`。`lsof -i :8765` 有时不显示进程，但 `netstat -anv | grep 8765` 显示 `io.tailscale.ipn` 绑定。换成 8766 立即正常。

**根因**：**Tailscale Serve** 之前配置了 `tailscale serve --https=8765 / http://127.0.0.1:8000`，在 8765 端口做了代理。即使用 `kill` 杀进程，Tailscale 也会重新绑定。

**诊断**：
```bash
# 确认 Tailscale Serve 配置
tailscale serve status

## 详细资料（按需查阅）

> 以下文件不在本 SKILL.md 内，需要时再读；正文只保留每次都会用到的部分。

- **`references/archive-changelog.md`** — 含 11 节：1. 比较两个 key 是否一致、1. 确认 Ollama 运行并列出模型、3. 验证 API、2. 写入 .env、3. 验证 Key 有效性、4. 启用 web 工具集
- **`references/auth-permission.md`** — 含 1 节：重启（推荐 tmux 隔离，避免被 hermes update 的 Gateway 重启波及 SIGTERM）：
- **`references/data-pipeline.md`** — 含 6 节：❌ 错误: 按产品years字段分摊、✅ 正确: 从原始订单按年汇总、方案A（推荐）：生成内嵌数据时同时添加 customer 字段、步骤1：同步 config.yaml 中 provider key 为有效的 model key、3. 检查 JSONL 备份、前提：~/.hermes/sessio…
- **`references/details.md`** — 含 37 节：等待加载后提取内容、查看断连频率、方案B：JS 侧兼容、一次性任务、指定工具集、直接用 restart 通常可以绕过 bootstrap 错误
- **`references/feishu-api.md`** — 含 15 节：查看最近一次成功接收消息的时间、停掉现有 gateway 进程、2. 查看 state.db 中该飞书会话的 model 列是否为 null、3. 看 Gateway 日志中是否有连续的 "Agent error"、步骤2：设置环境变量（Gateway Agent 的 resolve_provide…

### 既有参考文件（原正文未引用，此处补齐索引）

- **`references/contract-review-checklist.md`** — 合同审核速查清单
- **`references/contract-review-workflow.md`** — 合同审核工作流（给法务/销售管理）
- **`references/data-source-labeling.md`** — 宝锐工作台数据来源标注规范
- **`references/feishu-api-integration.md`** — 飞书 API 接入指南（宝锐定制 · 2026-07-08 实测）
- **`references/feishu-integration.md`** — 飞书集成参考
- **`references/feishu-mcp-catalog.md`** — 飞书项目MCP工具速查
- **`references/feishu-mcp-guide.md`** — 飞书项目 MCP 接入完整指南
- **`references/feishu-mcp-integration.md`** — 飞书项目 MCP 集成完整指南
- **`references/feishu-mcp-urls.md`** — 飞书项目URL构造速查
- **`references/feishu-project-mcp.md`** — 飞书项目 MCP 接入手册
- **`references/feishu-project-setup.md`** — 飞书项目 (Meegle) 接入流程
- **`references/feishu-session-bloat-and-statedb-repair.md`** — 飞书会话膨胀 + state.db 损坏修复（2026-07-28）
- **`references/gateway-model-empty-config.md`** — Gateway Model Provider 空配置排查（2026-07-28）
- **`references/gateway-model-switch-fix.md`** — Gateway 模型切换后飞书全部 Agent error 的修复
- **`references/gateway-stability-pattern.md`** — Gateway 稳定性故障模式分类（2026-08-01）
- **`references/pptx-template-workflow.md`** — python-pptx 使用公司模板生成 PPT
- **`references/tailscale-port-conflict.md`** — Tailscale Serve/Funnel 端口冲突（2026-07-28）

# 重启（推荐 tmux 隔离，避免被 hermes update 的 Gateway 重启波及 SIGTERM）：
tmux new-session -d -s workbench -x 120 -y 10 \
  'cd /Users/liuxinyuan/Desktop/Hermes输出-工作类 && python3 脚本/销售工作台服务.py 8765'

## Pitfall 14: MQL字段名是中文显示名（2026-07-09）

**症状**：`SELECT work_item_id`→返回字段名"工作项id"，代码`fields.get('work_item_id')`永远为空。

**根因**：MCP返回字段名是中文显示名，非API key。

**修复**：parse_items中标准化映射：`工作项id→work_item_id, 名称→name, 单据编号→order_no, 货号#→product_code`。

**完整字段映射表**：见 `references/mql-field-mappings.md`。


## Pitfall 15: MQL创建者字段≠销售员（2026-07-09）

**症状**：所有销售订单创建者指向同一人（自动化机器人），KPI按人汇总无效。

**根因**：`创建者`返回飞书系统记录创建人，真实销售员在`get_workitem_brief→role_members→销售员`。

**⚠️ 关键原则**：**绝对不准估算**。KPI的所有数字必须是真实数据，禁止用目标占比分摊或任何近似计算。H2月度实际额只有在客户→部门映射完成后才能填入，在此之前字段应为0。


## Pitfall 26: MCP活动类型错误——查了story不是活动（2026-07-10）

**症状**：MCP返回7月24条story，Excel导出332行活动，差12倍。

**根因**：`销售管理.story` = 商机，不是活动。飞书项目的"活动"是独立type `销售管理.活动`，type_key=`65ae1e5d44338dbe7c39a29a`。

**发现方法**：`list_workitem_types` 列出13种类型，含"活动"。

**修复**：`SELECT ... FROM \`销售管理\`.\`活动\``，URL格式 `xsguanli/65ae1e5d44338dbe7c39a29a/detail/{id}`

## Pitfall 10: 审批流转前必须确认实际阻塞节点

**症状**：`list_todo`显示"大区/部门经理审核"，尝试批量流转失败。

**根因**：`list_todo.node_name`是流程标签，不等于当前实际阻塞节点。

**正确方案**：逐条`get_node_detail`→过滤`status:"in_progress"`→确认当前用户是owner→`transition_node(action:"confirm")`。


## Pitfall 11: MQL语法和list_todo陷阱

**MQL**：project_key为独立参数；FROM格式`` `空间`.`类型` ``；不支持`SELECT *`；OFFSET分页可靠无重复。

**list_todo陷阱**：`node_name`是角色标签非当前活跃节点。业务线分类：含「课题组」=生命科学，其余=诊断原料。


## Pitfall 12: 飞书项目URL中 work_item_type 必须用 `story` 非 `sj`

**症状**：生成的URL `xsguanli/sj/detail/xxx` 点开显示"无对应工作项"。

**根因**：导出模板用 `sj`（商机缩写），前端路由用 `story`（type key）。

**修复**：所有URL `sj/detail` → `story/detail`。URL模板：`https://project.feishu.cn/{simple_name}/story/detail/{id}`。


## Pitfall 17: MQL WHERE + 大OFFSET超时（2026-07-09）

**症状**：`SELECT ... WHERE 创建时间 >= "2026-07-01" LIMIT 50 OFFSET 250` 超时。

**根因**：MCP服务器对WHERE+大OFFSET组合查询慢。

**正确方案**：先在销售管道中拉取全量订单并聚合到 `daily_sales_mcp.json` 的 `daily_summary` 中。KPI管道从 `daily_summary` 读取月度总额，避免重复调MCP做WHERE查询。


## Pitfall 19: 飞书项目URL work_item_type必须用`story`（2026-07-09）

**症状**：`xsguanli/sj/detail/{id}` 点击显示"无对应工作项"。

**根因**：导出模板用`sj`(商机)，但前端路由用 type key `story`。

**正确URL模板**：`https://project.feishu.cn/{simple_name}/story/detail/{work_item_id}`。验证：`meegle url decode --url "..."`。


## Pitfall 27: 客诉无法按人分权——需客户清单交叉匹配（2026-07-10）

**症状**：客诉只有 `id/name/days/url`，无owner字段。选销售员后无法过滤。

**解决方案**：客户清单Excel → `{客户名: 销售员}` 映射。客诉名称含客户名，前缀匹配。24/24全部成功。


## Pitfall 46: model.api_key 与 providers.<name>.api_key 不一致导致 Gateway Agent 全部报错（2026-07-19）

**症状**：CLI 会话一切正常，但飞书/微信 Gateway 每条消息都报 "Agent error"（或 "Sorry, I encountered an unexpected error"），即使 `/reset` 后也不行。Gateway 状态显示正常（feishu connected），且消息能被 Gateway 接收，但 Agent 处理时崩溃。

**根因**：`config.yaml` 中 `model.api_key` 和 `providers.<provider>.api_key` 是两个独立的值，可能不同步：
- CLI Agent 使用 `model.api_key`
- Gateway 的 api_server（监听 `127.0.0.1:8642`）使用 `providers.<provider>.api_key`

切换模型或手动修改配置时容易只更新一处而遗漏另一处。当 provider 级别的 key 失效或过期时，Gateway 每次调用 DeepSeek（或其他 provider）都返回 `Invalid API key`，导致所有会话崩溃。

**诊断**：
```bash
# ✅ 正确：shell-first 模式
tmux new-session -d -s turing -x 160 -y 50          # 1. 启动 shell
tmux send-keys -t turing "hermes --provider kimi-coding --model kimi-k2 --toolsets terminal,file,browser" Enter  # 2. 注入命令
sleep 10                                              # 3. 等待初始化完成

# 2. 注册为 Hermes provider（Ollama 提供 OpenAI 兼容的 /v1 端点）
hermes config set providers.local.api_key "ollama"
hermes config set providers.local.base_url "http://localhost:11434/v1"
hermes config set providers.local.default_model "qwen3:4b-16k"

# 1. 注册获取免费 API Key（1000次/月）
# 打开 https://app.tavily.com → Google/GitHub 登录 → Dashboard → 复制 Key（格式：tvly-...）

# 注册 https://brave.com/search/api/ → 获取 Key → 写入 .env
echo "BRAVE_SEARCH_API_KEY=BSA-your-key" >> ~/.hermes/.env
hermes tools enable web
```

**注意**：
- `hermes tools enable web` 后需要 `/reset` 新会话才能加载 web_search 工具
- Tavily Key 以 `tvly-` 开头（Dev Key）或 `tvly-dev-` 开头
- 工具生效后 `web_search` 和 `web_extract` 两个工具均可用
- 中国境内访问 Tavily API 正常，无需代理


## Pitfall 65: Gateway 飞书会话 1000+ 消息未 /reset 导致 API 超时（2026-07-28）

**症状**：飞书回复极短（3-7 字符），Gateway 日志 `APIConnectionError` 全 3 次重试失败。`hermes gateway restart` 超时（60s+），kill 旧进程后手动 start 才成功。

**根因**：同一飞书会话累积 1000+ 条消息未 `/reset`。每次 API 调用都要发送全部上下文（1000+ 条消息 = 数万 token），请求体过大导致 DeepSeek 连接超时。

**诊断**：
```bash
# 如果 DROP 报 "database disk image is malformed" → 放弃此路径，核心表已损坏
```

### 路径 B：.clone 导出/导入——本次场景失败
```bash
cp ~/.hermes/state.db ~/.hermes/state.db.bak
sqlite3 ~/.hermes/state.db ".clone /tmp/state_repaired.db"
# FTS 表可能重复创建，索引可能不存在
# 部署数据文件（1398 个 JSON/CSV）到 CloudBase
cd ~/Desktop/Hermes输出-工作类
tcb hosting deploy 数据/ 数据 -e bier-sales-d0gatbvlx288724e9
```

## Pitfall 21: `<table>` 容器塞 HermesTable `<div>` 卡片全部空白（2026-07-09）

**症状**：明细视图有框架没数据，表格永远空白。控制台无报错。

**根因**：HermesTable 产生 `<div class="ht-card">`，放入 `<table>` 容器时，浏览器HTML解析器把 `<div>` 弹出 table 结构外，DOM 里实际是空壳。

```html
<!-- ❌ 错误：所有内容被浏览器弹出 -->
<div class="card"><table id="myTable"></table></div>
<!-- ✅ 正确：HermesTable用div -->
<div class="card"><div id="myTable"></div></div>
```

**批量修复**：所有 `actTable/testTable/ordTable/compTable/blkTable` 容器必须用 `<div>`。


## Pitfall 23: HermesTable 加载遮罩永不消失（2026-07-09）

**症状**：页面一直显示"加载中…" spinner，数据实际上已返回。

**修复（三重保障）**：
1. `refresh()` 开头立即 `ld.style.display='none'`
2. 8秒超时自动隐藏
3. 全函数 `try/catch` 包裹，失败时显示 ⚠️


## Pitfall 28: 销售员视图全面板精准过滤（2026-07-10）

选销售员后必须全部面板精准到人：活动(`a.sales`)、销售(`s.salesperson` ERP列[1])、测试(`t.sales`)、客诉(客户清单匹配)、KPI(`people[name]`)。


## Pitfall 31: HTML页面修改后用户看不到更新（2026-07-11）

**症状**：文件已通过 `write_file`/`patch` 更新，`curl` 确认服务器返回新内容，但用户浏览器显示旧版。

**根因**：浏览器强缓存。`meta http-equiv` 标签对已缓存的页面无效。

**修复（四重保障）**：
1. `meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate"` + `Pragma: no-cache` + `Expires: 0`
2. 每次修改后给URL加唯一 `?t=...` 参数强制重新加载
3. 重启 HTTP 服务器清除服务端缓存
4. 告知用户 Cmd+Shift+R 或无痕窗口打开

**最可靠的验证方式**：`curl -s http://127.0.0.1:8765/工具/xxx.html | grep -c "新特征字符串"` 确认服务器已更新，然后用户无痕窗口打开。

# 等待加载后提取内容
osascript -e 'tell application "Google Chrome"
  set js to "document.body.innerText"
  set result to execute front window'"'"'s active tab javascript js
  return result
end tell'
```

## Pitfall 29: Feishu Gateway 常见故障排查（2026-07-10，扩展 2026-07-19）

### 29a. 消息被静默拦截

**症状**：`hermes gateway setup` 配好飞书，发消息无响应，日志无任何收到的消息。

**根因**：`.env` 中 `FEISHU_ALLOW_ALL_USERS=false` 且 `FEISHU_ALLOWED_USERS=` 为空，所有外来消息被静默拦截。

**修复**：
```bash
sed -i '' 's/FEISHU_ALLOW_ALL_USERS=false/FEISHU_ALLOW_ALL_USERS=true/' ~/.hermes/.env
hermes gateway restart
```

### 29b. WebSocket 频繁断连（keepalive ping timeout）

**症状**：`grep "receive message loop exit" ~/.hermes/logs/gateway.log` 高频出现（每 12-30 分钟一次），日志含 `no close frame received` 或 `keepalive ping timeout`。Gateway 仍能收发消息但延迟增加。

**排查**：
```bash

# 查看断连频率
grep -c "receive message loop exit" ~/.hermes/logs/gateway.log

# 方案B：JS 侧兼容
html = html.replace('PROFILE.customer', '(PROFILE.customer||PROFILE.name)')
```

## Pitfall 38: 自包含HTML列表列显示 [object Object]（2026-07-12）

**症状**：联系人/商机/项目/客诉列显示 `[object Object],[object Object]...` 长字符串。

**根因**：原 JSON（fetch加载）中 contacts/opps 字段是数字（计数），自包含化内嵌的是完整对象数组。`c.contacts + ''` 将数组隐式转为字符串 → `[object Object]`。

**修复**：添加计数工具函数并替换四列渲染代码：
```javascript
// 添加函数
function countOf(v){return Array.isArray(v)?v.length:(v||0);}

// 逐行替换四列（不能用全文件正则——转义引号细节不同导致匹配失败）
// Before: h+='<td class="num">'+((c.contacts||c._contacts)||'—')+'</td>';
// After:  h+='<td class="num">'+(countOf(c.contacts)>0?countOf(c.contacts):'—')+'</td>';
```
**禁止**：用 Python `str.replace()` 拼接含转义引号的模板字符串。用**逐行检测关键词 + 整行替换**。

## Pitfall 39: 全文件正则移除 iframe 破坏 JavaScript（2026-07-12）

**症状**：自包含化后详情页完全白屏，node --check 通过但浏览器报多个 exception。

**根因**：`re.sub(r'<iframe[^>]*>[^<]*</iframe>', ...)` 同时匹配了 HTML 标签和 JS 模板字符串中的 `<iframe>` 片段，导致 JS 字符串被截断，renderDetail 静默失败。

**修复**：
1. **精确替换** JS 模板中那行代码：`html = re.sub(r"html\+='<iframe[^>]*></iframe>';", "...", html)`
2. 生成后用 `grep -c '<iframe'` 确认残留数 = 0
3. 优先方案：修改原始 HTML 文件去掉 iframe → 再生成自包含版

## Pitfall 40: 自包含JSON缓存版本号需递增（2026-07-12）

**症状**：自包含文件部署后用户看不到新数据，仍是旧版。

**根因**：生成脚本替换掉了 fetch() 调用，但内嵌数据本身不会自动更新。如果只改 JSON 数据不改 HTML 文件，用户体验不到变化。

**修复**：
1. 每次重新生成自包含HTML时递增版本标记（文件注释中的 vN 或 DATA_VER 变量）
2. 部署到 NAS 时同时部署 .sha256 校验文件供用户比对
3. 文件名可加日期后缀：`客户档案_20260712.html`（可选）

## Pitfall 41: MCP 销售订单金额字段恒为 0（2026-07-17）

**症状**：工作台显示 `销售 0 笔订单，总金额 0`，但 ERP 导出显示有数百笔、金额上百万。

**根因**：飞书项目 MCP 中 `销售订单` 工作项的 `金额`、`价税合计`、`含税单价` 字段均返回 `0`。销售订单的财务数据不在飞书项目 MCP 中，只存在于 ERP 系统。

**错误做法**：写 cron 定时任务用 MCP 拉取销售订单，覆盖正确的 ERP 数据文件。

**正确做法**：
1. 销售 KPI 金额以 ERP 导出为唯一数据源。
2. 用户上传 ERP 销售订单 Excel 后，运行 `refresh_erp.py` 更新 `数据/kpi_progress.json`。
3. 前端 `fetch('../数据/kpi_progress.json')` 读取。
4. 若需自动刷新，用 cron 每 30 分钟检测 `月度销售额数据/` 文件夹中的新文件，而不是调用 MCP。

参考：`baoyu-workbench-data-pipeline/references/mcp-sales-amount-limitation.md`。

## Pitfall 42: HTML 重构任务应委派给专用子 Agent（2026-07-17）

**症状**：用户在长会话中要求重构一个大型 HTML 页面，主会话上下文已承载大量历史数据，直接生成容易遗漏数据路径或角色逻辑。

**方案**：使用 `delegate_task` 派生一个独立子 Agent，专门负责 HTML 重构。上下文：
- 工作目录
- 源文件路径
- 所有依赖 JSON 的路径和字段名
- 必须保留的行为（如 localStorage 待办、登录密码校验）
- 输出路径和验证方式（`node --check`、浏览器控制台无错误）

**配置子 Agent 使用 Kimi K2/K3**：
```python
delegate_task(
    goal='重构 工具/销售工作台.html',
    model='k3',
    provider='kimi-coding',  # 注意：built-in provider 名是 kimi-coding，不是 kimi
    toolsets=['file', 'terminal', 'code_execution'],
    context='...'
)
```

或通过 CLI 启动独立进程：
```bash
hermes chat -q "任务" --provider kimi-coding --model kimi-k2 --toolsets terminal,file,browser
```

**主会话**：
- 不直接读取/写入 HTML 全部内容（避免 token 爆炸）
- 等待子 Agent 返回结果摘要
- 验证 Tailscale 访问和关键功能

## Pitfall 43: Kimi 模型配置在 Hermes 中

**Built-in provider 名**: `kimi-coding`（**不是** `kimi`），使用 `KIMI_API_KEY` 环境变量。

**可用模型**：
- `kimi-k2` — Kimi K2（通用对话，已验证可用）
- `kimi-k2.6` — Kimi K2.6（2026-07-26 验证可用，回复 OK）
- `k3` — Kimi K3（编程/HTML 旗舰模型，高峰期可能被限流 429）
- `kimi-for-coding` — Kimi K2.7 Code（标准速度）
- `kimi-for-coding-highspeed` — Kimi K2.7 Code 高速版

**CLI 调用**：
```bash

# 一次性任务
hermes chat -q "任务" --provider kimi-coding --model kimi-k2 --quiet


# 指定工具集
hermes chat -q "任务" --provider kimi-coding --model kimi-k2 --toolsets terminal,file,browser --quiet
```

**delegation 配置**：
```bash
hermes config set delegation.provider kimi-coding
hermes config set delegation.model kimi-k2
```

## Pitfall 44: `hermes gateway start` Bootstrap 失败（2026-07-19）

**症状**：`hermes gateway start` 报错 `Bootstrap failed: 5: Input/output error`。

**根因**：launchd plist 已有的服务定义与新版本 Hermes 不兼容，直接 start 尝试覆盖注册时失败。

**修复**：
```bash

# 直接用 restart 通常可以绕过 bootstrap 错误
hermes gateway restart
```

如果 restart 也不行，手动清理后重试：
```bash

# 删除旧 plist
rm -f ~/Library/LaunchAgents/ai.hermes.gateway.plist

# 获取 provider name（如 deepseek）并大写，加 _API_KEY 后缀写入 .env
PROVIDER=$(python3 -c "import yaml;c=yaml.safe_load(open('/Users/liuxinyuan/.hermes/config.yaml'));print(c.get('model',{}).get('provider','deepseek'))")
echo "${PROVIDER^^}_API_KEY=$MODEL_KEY" >> ~/.hermes/.env

hermes gateway restart
```
> ⚠️ 步骤2 经常被遗漏。仅同步 config key 而不设环境变量，Gateway 仍会报 `RuntimeError: Provider 'X' is set in config.yaml but no API key was found`。

**验证**：从飞书发一条简单消息（如 "你好"），确认能得到正常回复而非 "Agent error"。

**注意**：直接 curl Gateway 的 api_server（`curl http://127.0.0.1:8642/v1/chat/completions`）不带 auth header 时也会返回 "Invalid API key"——这是 api_server 自身的保护机制，不代表 LLM 调用失败。诊断时应结合 Gateway 日志判断是真故障还是正常防护。

## Pitfall 47: Hermes 在 tmux 中直接启动即退出（2026-07-19）

**症状**：`tmux new-session -d -s agent 'hermes --provider kimi-coding --model kimi-k2'` 执行后，tmux 会话瞬间退出（`tmux capture-pane` 返回空或 "no server running"）。

**根因**：Hermes 的 prompt_toolkit TUI 需要真正的终端环境。直接作为 tmux 的启动命令传入时，Hermes 检测到环境异常后立即退出。

**正确做法**：先创建普通 shell 的 tmux 会话，再通过 `send-keys` 注入 Hermes 启动命令：
```bash

# 验证（看 ❯ 提示符是否出现）
tmux capture-pane -t turing -p | grep '❯'
```

**管理脚本模板**：`~/.hermes/scripts/turing.sh` 封装了完整的 tmux 子 Agent 管理（start/send/log/watch/stop/status/run）。

## Pitfall 52: Ollama qwen3 推理模型的 content 字段为空（2026-07-20）

**症状**：Ollama API 返回 `completion_tokens: 800`，但 `choices[0].message.content` 为空字符串，导致批处理16个chunk全部产出0字摘要。

**根因**：qwen3:4b-16k 默认启用 chain-of-thought 思考模式，所有 token 输出到 `reasoning` 字段，`content` 始终为空。`options: {num_think: 0}` 也无法完全关闭。

**修复**：解析时必须双字段 fallback：
```python
msg = d['choices'][0]['message']
summary = msg.get('content', '') or msg.get('reasoning', '')
```

**适用范围**：qwen3、deepseek-r1 等带思考过程的推理模型。Ollama 和 vLLM 均可能出现。

## Pitfall 53: 数据刷新脚本按文件名排序选错最新文件（2026-07-20）

**症状**：`refresh_erp.py` 扫描 `月度销售额数据/` 目录，挑选"最新"文件处理。结果处理了旧文件（7/1-9日 90.7万）而非新上传的（7/1-20日 189.6万），KPI 少报111万。

**根因**：`sorted(files)[-1]` 按**字母序**排序。`销售订单_2026年` 因下划线（ASCII 95）排在 `销售订单导出`（Unicode）之前，被排到列表前面而非末尾。

**修复**：按文件修改时间排序：
```python
files = [os.path.join(SRC, f) for f in os.listdir(SRC) if ...]
files.sort(key=lambda f: os.path.getmtime(f))
latest = files[-1]
```

**教训**：任何"选最新文件"的逻辑必须用 `mtime`，不能用文件名推断。同理，`stamp_file` 防重复机制应记录文件 mtime 而非仅记录"已处理过"。

## Pitfall 55: Kimi k3 高峰期持续 429 限流（2026-07-23）

**症状**：k3 模型在中文工作时间（尤其是下午/晚间）频繁返回 `HTTP 429: The engine is currently overloaded`，3次重试全部失败。

**根因**：k3 是 Kimi 的旗舰编程模型，高峰期并发量大，API 资源紧张。

**应对**：
1. **首选 fallback**：`--provider kimi-coding --model kimi-k2`（k2 几乎不限流）
2. 非高峰时段（早上/深夜）k3 通常可用
3. 长会话结束时 k3 更容易限流（上下文 token 多 + 高峰期叠加）
4. 不要死等重试 — 第一次 429 就切换到 k2

**验证 k3 可用性**：
```bash
hermes chat -q "回复OK" --provider kimi-coding --model k3 --quiet 2>&1 | head -3
```

## Pitfall 56: tmux 子 Agent 会话过长导致上下文爆炸（2026-07-23）

**症状**：Turing（tmux 中的 Hermes 子 Agent）运行 6 小时后响应变慢，8 小时后每次 API 调用消耗 400K+ token（上下文压缩后仍 50%+），最终 API 报 429 或超时。

**根因**：tmux 中的 Hermes 会话不会自动 `/reset`，消息积累导致 prompt 前缀越来越长。每次工具调用都携带完整历史摘要。

**应对**：
1. **每日重启**：子 Agent 会话不超过 1 天。早上升级/重启。
2. **拆分会话**：大任务（如重构整个页面）用独立 one-shot `hermes chat -q` 而非累加到长会话
3. **监控**：`tmux capture-pane` 中看到 `🗜️ Compacting context` 频繁出现时，说明会话该重启了
4. **重启命令**：`turing stop && sleep 2 && TURING_MODEL=kimi-k2 turing start`

## Pitfall 57: 商机沙盘数据单位不统一（元 vs 万元混合）（2026-07-23）

**症状**：同一 JSON 文件中，部分商机的 target 是元（如 2600000 = 260万），部分是万元（如 100W = 100万）。按统一公式格式化后数据偏差极大。

**根因**：原始 Excel `2026商机达成沙盘.xlsx` 中不同销售员填写习惯不同。黄文才、赵云浩用"万元+W后缀"，陈溪子、冯贤平等用"元纯数字"。

**修复**：所有金额格式函数统一先除以 10000 再格式化：
```javascript
function fmtWan(v) {
  if (!v || v === 0) return '0';
  var w = v / 10000;  // 统一换算为万元
  return w >= 100 ? Math.round(w) + '万' : w.toFixed(1) + '万';
}
```
大数值（>100000）在商机沙盘中就是元，除以10000后得到正确的万元值。小数值（<100000）可能是已按万元填写，除以10000后需要用 `toFixed(1)` 保留小数。

**症状**：HTML 模板中写了 `onclick="toggleYear('2024')"`，页面渲染后元素显示 `cursor:pointer`，但点击无反应。控制台无报错。

**根因**：在 JS 字符串拼接中，`onclick` 属性内的引号转义容易出错：
```javascript
// ❌ 容易出错：转义引号在多层拼接中丢失
html += '<tr onclick="y3Toggle(\'2024\')">...';

// 实际渲染可能是：onclick="y3Toggle('2024')" — 看起来对但可能因引号层级问题失效
```

**正确方案**：用 `addEventListener` + `data-*` 属性绑定：
```javascript
// HTML 模板中只设 data 属性，不写 onclick
html += '<tr class="y3-year-row" data-year="2024">...';

// 渲染完成后统一绑定事件（放在 setTimeout 中确保 DOM 就绪）
function y3BindEvents() {
  var rows = document.querySelectorAll('.y3-year-row');
  for (var i = 0; i < rows.length; i++) {
    (function(row) {
      var year = row.getAttribute('data-year');
      row.addEventListener('click', function() { y3Toggle(year); });
    })(rows[i]);
  }
}

// 在 render() 末尾调用
setTimeout(function() { y3BindEvents(); }, 50);
```

**为什么用 IIFE**：`var year` 在 for 循环中没有块级作用域，直接用会所有事件共享最后一个值。IIFE 创建独立闭包捕获每轮的值。

**注意**：图灵 (Kimi k3) 在处理这类问题时，会自己发现 `onclick` 不工作并自动切换到 `addEventListener` 方式。

## Pitfall 49: 配置 Ollama 本地模型为 Hermes Provider（2026-07-19）

**场景**：需要在 Hermes 中使用本地运行的 Ollama 模型（如 qwen3:4b-16k）。

**前提**：
1. Ollama 已安装（`brew install ollama` 或官网下载）
2. 至少已 pull 一个模型（`ollama pull qwen3:4b-16k`）
3. Ollama 服务已运行（`ollama serve`，可在后台启动）

**配置步骤**：
```bash

# 确认进程存在但不响应
lsof -i :8765                    # 看到 LISTEN 但 curl 超时/空响应
ps aux | grep 销售工作台服务      # 确认 PID
curl -v http://127.0.0.1:8765/   # Empty reply from server
```

**修复**：
```bash

# 杀旧进程
kill $(lsof -t -i :8765)
sleep 2


# 验证
sleep 2 && curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8765/
```

**⚠️ 为什么用 tmux 而非 background=true**：`hermes update` 完成后会重启 Gateway（`hermes gateway restart`），可能触发进程组清理，SIGTERM 所有 background 进程。tmux 会话独立于 Hermes 进程树，不受影响。

**关联陷阱**：如果 HTTP 服务是 CloudBase 工作台的后端，服务器重启后需确认 CDN 缓存状态——`tcb hosting download` 验 Origin，`curl` 直接 URL 验 CDN。参见 `baoyu-cloudbase-deployment` 技能。

**症状**：用户问"浏览器打开页面在哪？"——Agent 用 `browser_navigate` 打开了飞书权限授权页，但用户看不到这个无头浏览器。

**根因**：`browser_navigate` 在远程/无头浏览器中打开页面，用户本地桌面看不到。当打开的是需要用户手动扫码登录、点击授权等交互的页面时，用户无法操作。

**正确做法**：
- 如果页面需要用户交互（登录、授权、填写表单），**直接给出 URL 文本**让用户自己打开
- `browser_navigate` 仅用于 Agent 自己需要抓取/分析页面内容的场景
- 给出 URL 时附带简短说明（"请在自己浏览器打开这个链接..."）

**适用场景**：飞书权限授权、任何 OAuth 登录、需要扫码的页面、需要用户填写的表单。

## Pitfall 58: hermes update 后多 Profile Gateway 端口冲突（2026-07-24）

**症状**：`hermes update` 完成后，默认 profile Gateway 无法启动。日志显示：
- `Port 8642 already in use`
- `Another local Hermes gateway is already using this Feishu app_id (PID XXXX)`
- `Weixin bot token already in use (PID XXXX)`
Gateway 随启随崩，LastExitStatus=19968。

**根因**：其他 profile（如 dev-agent、zone-a）的 Gateway 在旧版 Hermes 上运行，占用了共享资源：
- `127.0.0.1:8642`（API Server 端口）
- 飞书 App ID WebSocket 连接
- 微信 Bot Token

`hermes update` 只重启了默认 profile 的 Gateway，profile 级 Gateway 仍运行旧版，导致端口/连接冲突。

**诊断**：
```bash

# 查看端口占用
lsof -i :8642

# 查看错误日志
tail -30 ~/.hermes/logs/gateway.error.log
```

**修复**：先停止所有 profile 级 Gateway，再启动默认 Gateway：
```bash

# 等待端口释放
sleep 2


# 验证
hermes gateway status
hermes cron status          # 确认 cron ticker 有心跳
```

**⚠️ 重要**：不要用 `kill <PID>` 杀 Gateway 进程——macOS launchd 会自动重启它们。必须用 `hermes --profile <name> gateway stop`。

**预防**：hermes update 后如果有其他 profile Gateway 在运行，应一并重启它们以使用新版本代码。

## Pitfall 59: MEMORY.md 精简——用批量 operations 而非整体 replace（2026-07-24）

**症状**：memory tool 的 `action=replace` 尝试用大段文本整体替换 MEMORY.md 时失败，老内容与新内容不完全匹配导致操作被拒绝。

**根因**：MEMORY.md 中每个 `§` 分隔的块是独立条目。memory tool 的 replace 需要 `old_text` 与整个条目内容精确匹配。当多个条目混成一段 old_text 时无法匹配。

**正确做法**：用 `operations` 数组模式，逐个条目独立操作：
```python
memory(
  target="memory",
  operations=[
    # 按条目逐个删除（old_text 取条目前20字符即可唯一匹配）
    {"action": "remove", "old_text": "浏览器强缓存：三重防缓存meta标签"},
    {"action": "remove", "old_text": "铁律:真实数据不估算"},
    {"action": "remove", "old_text": "进度监控:后台长任务"},
    # 精简合并（只替换该条目内容）
    {"action": "replace",
     "old_text": "工作台密码:gm=biorigm...",
     "content": "工作台密码:gm=biorigm,director=bioridir。k3频繁429优先kimi-k2。"},
    # 补充丢失的关键信息
    {"action": "add",
     "content": "用户刘新元,偏好自动化>手工,渐进迭代,bug零容忍。"},
  ]
)
```

**原则**：
- 删除：已在 skills 中覆盖的技术细节（Pitfall 已记录的）
- 保留：稳定业务事实（组织结构/路径/密码/基础设施）
- 合并：同一主题多条 → 一条精简版
- `remove` 只需条目前几个字即可匹配，`replace` 需 old_text 精确匹配原条目

**参考**：完整的 MEMORY.md 精简方案见 `references/hermes-health-check.md`。

## Pitfall 60: state.db VACUUM 后大小无明显变化（2026-07-24）

**症状**：`hermes sessions prune --older-than 60` 删除 57 个会话后，执行 `sqlite3 state.db "VACUUM;"`，文件大小从 273MB 变为 276MB（反而增大）。

**根因**：state.db 使用 SQLite FTS5 全文索引。FTS5 表有独立的内部存储结构（`_content`、`_segdir`、`_docsize` 等影子表），VACUUM 对这些表的回收效果有限。199 个会话、18621 条消息的 FTS5 索引本身就是主要空间占用。

**可接受**：276MB 对 199 sessions 属于正常范围。如需进一步缩小，应 `prune --older-than 30` 更激进地清理。

**附加发现**：SQLite 3.50.4 有 WAL-reset 损坏漏洞（python-build-standalone 内嵌版本）。不影响正常使用，但建议关注 Hermes 更新中 Python 版本的 SQLite 升级。

## Pitfall 61: web_search 不可用——缺少搜索引擎 API Key（2026-07-24）\n\n**症状**：`hermes doctor` 显示 `⚠ web (missing TAVILY_API_KEY / BRAVE_SEARCH_API_KEY / ...)`。\n\n**推荐方案：Tavily（免费，无需信用卡）**\n\n```bash\n# 1. 注册 https://app.tavily.com → 获取 Key（格式：tvly-dev-...）\n# 2. 写入 .env\necho \"TAVILY_API_KEY=tvly-dev-xxx\" >> ~/.hermes/.env\n# 3. 验证\ncurl -s -X POST https://api.tavily.com/search -H \"Content-Type: application/json\" \\\n  -d '{\"api_key\":\"tvly-dev-xxx\",\"query\":\"test\",\"max_results\":2}'\n# 4. 启用\nhermes tools enable web\n# 5. /reset 后生效\n```\n\n## Pitfall 62: state.db 损坏恢复——从 .clone 失败到 JSONL 重建（2026-07-26）\n\n**症状**：`integrity_check` 失败，`.clone` 产出 0KB 文件，`.dump` 重建有 UNIQUE 冲突。\n\n**唯一可靠路径**：\n```bash\nhermes gateway stop\nmv ~/.hermes/state.db ~/.hermes/state.db.corrupt\nrm -f ~/.hermes/state.db-shm ~/.hermes/state.db-wal\nhermes gateway start  # 自动新建 176KB 健康 state.db\n```\n旧数据仍在 `~/.hermes/sessions/*.jsonl`（365MB/24文件）中保留。\n\n## Pitfall 63: CloudBase 页面数据加载失败——三大原因叠加（2026-07-27）\n\n**根因**：① `loadData()` 将 URL 数组当字符串拼接 ② JSON 文件未部署到 CloudBase ③ HTTPS→HTTP 混合内容被浏览器静默拦截。\n\n**修复**：实现 JSON 优先降级逻辑 + `tcb hosting deploy 数据/ 数据` 部署全部 1398 个文件。\n\n## Pitfall 64: Cloudflare Tunnel 稳定性 + 离线登录双保险（2026-07-27）\n\n**Tunnel 问题**：trycloudflare.com 无固定域名、QUIC 被墙回退 HTTP/2、hermes update 进程清理波及。\n\n**修复**：\n1. tmux 隔离启动 Tunnel（`tmux new-session -d -s tunnel 'cloudflared tunnel --url http://localhost:8765'`）\n2. 页面添加离线登录（OFFLINE_USERS 硬编码，API 不可用时自动降级）\n3. 数据加载 JSON 优先（CDN），API 备用\n\n## Pitfall 65: Gateway 飞书会话 1000+ 消息未 /reset 导致 API 超时（2026-07-28）\n\n**症状**：飞书回复 3-7 字符，`APIConnectionError` 全重试失败，`hermes gateway restart` 60s 超时。\n\n**根因**：同一飞书会话累积 1000+ 条消息，每次 API 调用发送全部上下文，请求体过大导致 DeepSeek 连接超时。\n\n**诊断**：`grep \"Persisted transcript lagged\" gateway.log` → disk=1019 即 1000+ 条。\n\n**修复**：`kill` + `hermes gateway start`，飞书发 `/reset`。\n\n## Pitfall 66: 工作台服务器端口被 Tailscale Serve 占用（2026-07-28）\n\n**症状**：8765 端口反复 `Address already in use`，`lsof` 看不到进程，`netstat -anv` 显示 `io.tailscale.ipn`。\n\n**修复**：`tailscale serve reset` 释放所有绑定。\n\n## Pitfall 67: model.default/provider 为空导致 Gateway 模型发到错误 API（2026-07-26）\n\n**症状**：Gateway 日志 `provider=custom base_url=https://api.kimi.com/v1 model=deepseek-v4-pro → 404`。\n\n**修复**：`hermes config set model.default deepseek/deepseek-v4-pro` + `model.provider deepseek`。\n\n**关键**：`model.provider` 必须显式设置，否则 Gateway 自行拼凑错误组合。\n\n## Pitfall 68: KIMI_API_KEY 同时 401+404——Key 已失效（2026-07-27）\n\n**症状**：`moonshot.cn → 401`、`kimi.com → 404`，已验证可用的 kimi-k2.6 也报错。\n\n**修复**：在 https://platform.moonshot.cn 重新生成 Key。\n\n**高消耗原因**：长会话未 reset + state.db 损坏重试风暴，3 小时消耗 ~100 元（12-25M tokens）。\n\n## Pitfall 69: 工作台登录需完整邮箱格式 + 统一密码（2026-07-26）\n\n**症状**：`director` / `admin` 等短名称登录失败\"邮箱未注册或密码错误\"。\n\n**根因**：服务器 `DEFAULT_USERS` 使用完整邮箱（如 `liuxinyuan@biori.com`），密码统一为 `biori2026`。\n\n**修复**：\n- 登录填写完整邮箱 `xxx@biori.com`\n- 或添加简短别名：在 `DEFAULT_USERS` 中增加 `'admin': {...}`\n- 新增用户同步更新 `DEFAULT_USERS` + 重启服务器

**症状**：`hermes doctor` 显示 `⚠ web (missing TAVILY_API_KEY / BRAVE_SEARCH_API_KEY / ...)`，`web_search` 工具调用返回空或无结果。

**根因**：Hermes 的 web_search 工具需要第三方搜索引擎 API Key。内置支持 Tavily、Brave Search、Exa、Firecrawl 等，但默认均未配置。

**推荐方案：Tavily（免费，无需信用卡）**

```bash

# 确认 API 连接失败
grep "APIConnectionError\|Connection error" ~/.hermes/logs/gateway.error.log | tail -5
```

**修复**：
```bash

# 退出码 0 不代表成功——clone 后 integrity check 可能仍 fail

# 本次 clone 产出 0KB 文件 → 失败
```

### 路径 C：.dump + 重建——本次场景部分成功但需处理 UNIQUE 冲突
```bash
sqlite3 ~/.hermes/state.db ".dump" > /tmp/state_dump.sql
sqlite3 /tmp/state_rebuilt.db <<'EOF'
.bail off
.read /tmp/state_dump.sql
.quit
EOF
```
- UNIQUE constraint failed（损坏源数据中 message id/segid 重复）→ 被跳过
- 重建后 integrity check 可能显示 `ok`，但大小异常（0KB 或偏小）需核对

### 路径 D：JSONL 备份 + 全新 state.db ✅（本次唯一成功的路径）
```bash

# 全新 state.db ~176KB, integrity check: ok


# hermes update 前验证 state.db 健康
sqlite3 ~/.hermes/state.db "PRAGMA integrity_check;"

# 如果报错，先处理损坏再 update
```

## Pitfall 66: CloudBase 页面数据加载失败——三大原因叠加（2026-07-26）

**症状**：CloudBase 部署后登录成功但数据全报"加载失败"，错误信息含 `../数据/...` 路径。

**根因（三层叠加）**：

1. **loadData() URL 拼接 bug**：`ENDPOINTS` 中每个条目存的是 `[api_path, fallback_path]` 数组，但原 `loadData()` 用 `ep[1]` 直接赋值给 `url`，然后 `fetch(url + '?v=...')` 将数组隐式转为逗号分隔字符串——产生无效 URL（如 `/api/mcp/customers,../数据/pricing/...json?v=...`）。

2. **JSON 文件未部署到 CloudBase**：回退路径 `../数据/pricing/_key_customers.json` 在 CloudBase 上返回 404。

3. **HTTPS 页面不能 fetch HTTP**（混合内容策略）：HTTPS CloudBase 页面尝试 `fetch('http://127.0.0.1:8765/...')` 被浏览器静默拦截。

**修复**：

```javascript
// loadData() 正确实现——JSON 优先（已部署到 CDN），API 备用
function loadData() {
  var apiBase = API_BASE_URLS[0];  // Tunnel URL
  var fetches = ENDPOINTS.map(function(ep) {
    var key = ep[0], urls = ep[1];  // urls = [api_path, fallback]
    var apiUrl = urls[0], fallbackUrl = urls[1];
    function tryFetch(url) {
      return fetch(url + '?v=' + Date.now(), {cache:'no-store'})
        .then(function(r) { if (!r.ok) throw new Error(key+':'+r.status); return r.json(); });
    }
    // JSON 优先（CloudBase 已部署），API 作为加速
    if (fallbackUrl) return tryFetch(fallbackUrl).catch(function() {
      if (apiUrl) return tryFetch(apiBase + apiUrl); throw new Error(key);
    });
    if (apiUrl) return tryFetch(apiBase + apiUrl);
    return Promise.reject(new Error(key + ': 无数据源'));
  });
  // ... Promise.all 同上
}
```

```bash

# 输出示例：

# https://macbook-air-2.tail6864e8.ts.net:8765 (tailnet only)

# |-- / proxy http://127.0.0.1:8000


# 确认占用进程
netstat -anv | grep 8765

# 输出含 io.tailscale.ipn 即为 Tailscale
```

**修复**：
```bash

# 重置 Tailscale Serve（释放所有端口绑定）
tailscale serve reset
sleep 2

# 验证释放
curl -s --max-time 3 http://127.0.0.1:8765/ && echo "可用" || echo "仍被占用"


# 重启动工作台服务器
python3 脚本/销售工作台服务.py 8765
```

**注意**：`tailscale serve reset` 会清除所有 Serve 配置。如果需要保留 Funnel 或 Serve 配置，用 `tailscale serve --https=<新端口>` 迁移而非 reset。

## Pitfall 68: model.default 格式——provider/model 双段 vs 分设（2026-07-26）

**症状**：`hermes config set model.default deepseek-v4-pro` 设置后，Gateway 仍可能找不到正确的 provider——因为未同时设置 `model.provider`。

**根因**：Hermes 有两种模型配置格式：

1. **双段格式**（推荐）：`provider/model` — `hermes config set model.default deepseek/deepseek-v4-pro`
2. **分设格式**：单独设置 `model.default` + `model.provider` — 必须两个都设

只设 `model.default` 不设 `model.provider` → Gateway 可能随机选 provider（如本次选了 Kimi base_url 搭配 DeepSeek model = 404）。

**正确做法**：
```bash

# 方案 A（推荐——一个命令搞定，不会遗漏）
hermes config set model.default deepseek/deepseek-v4-pro
hermes config set model.provider deepseek  # 仍需设，作为 fallback


# 方案 B（分设——必须两个都设）
hermes config set model.default deepseek-v4-pro
hermes config set model.provider deepseek  # ⚠️ 这一步不能省！
```

**验证**：
```bash
python3 -c "
import yaml
with open('/Users/liuxinyuan/.hermes/config.yaml') as f:
    c = yaml.safe_load(f)
print('default:', repr(c.get('model',{}).get('default','MISSING!')))
print('provider:', repr(c.get('model',{}).get('provider','MISSING!')))
"

# default 和 provider 都不应为 None/null/空字符串
```

## Pitfall 70: DeepSeek 内容审核（Content Exists Risk）导致 Gateway 假死（2026-08-01）

**症状**：飞书突然回复"model provider failed after retries"，或回复极短（3-7字符）。Gateway PID在线但无响应。`hermes gateway restart` 60s超时（卡在draining in-flight API调用）。

**根因**：DeepSeek API 返回 `HTTP 400: Content Exists Risk`——安全审核拒绝了某条消息内容。Gateway 的3次重试机制耗尽后表现异常，后续所有消息被阻塞。

**诊断**：
```bash
grep "Content Exists Risk\|400.*invalid_request" ~/.hermes/logs/gateway.error.log | tail -5
grep "Persisted transcript lagged" ~/.hermes/logs/gateway.log | tail -3

# disk > 100 表示会话累积过多，需 /reset
```

**修复**：
```bash

# restart 会超时 → 直接 kill + start
kill $(pgrep -f "hermes_cli.main.*gateway")
sleep 3
hermes gateway start

# 读取 key（Hermes 安全脱敏会遮蔽，需在本地终端直接 cat）
cat ~/.hermes/.env | grep KIMI_API_KEY


# 分别测试两个端点
curl -s --max-time 10 -X POST https://api.moonshot.cn/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $KIMI_API_KEY" \
  -d '{"model":"kimi-k2","messages":[{"role":"user","content":"hi"}],"max_tokens":5}'

curl -s --max-time 10 -X POST https://api.kimi.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $KIMI_API_KEY" \
  -d '{"model":"kimi-k2","messages":[{"role":"user","content":"hi"}],"max_tokens":5}'
```

**修复**：在 https://platform.moonshot.cn 重新生成 API Key，更新 `.env` 中的 `KIMI_API_KEY`。

**预防**：定期检查 API 用量。Kimi K2 定价 ~¥4-8/百万 token。3 小时内消耗 ~100 元 ≈ 12-25M tokens——可能是长会话未 reset + state.db 损坏重试风暴叠加导致。### P14: 日报数据源时效性（2026-07-30）
**症状**：日报引用2024年华安证券研报（预测2026年集采），当成2026年实际发生。
**根因**：搜索返回的研报URL含日期戳（如 `20241017`），但摘要显示"预测2026年…"容易混淆。
**修复**：区分**预测** vs **已发生**。寻找2026年实际执行文件（湖南省3月通知）替代预测。
**检查**：所有外部链接检查URL日期戳，`2024` 年的不能当最新。

### P13: manifest 类型检测 — relpath 无前导斜杠（2026-07-29）
**症状**：所有拜访卡 type="other"，访前准备中心检测不到新生成的文件。
**根因**：`os.path.relpath()` 返回 `拜访卡/xxx.html`（无前导/），但判定条件用了 `/拜访卡/ in rel`（前导斜杠导致不匹配）。
**修复**：`~/.hermes/scripts/regenerate_manifest.sh` 中 `'/拜访卡/' in rel` → `rel.startswith('拜访卡')`。同步修复访前背调/市场调研卡/客户调研的类型判定。
**预防**：每次修改 manifest 脚本后，`grep '"type"' 数据/file_manifest.json | sort | uniq -c` 确认无 "other" 类型。|

## P19-P22: 顺丰物流管线（2026-08-01）

| P# | 症状 | 根因 | 修复 |
|----|------|------|------|
| P19 | 661条月结卡号不匹配 | checkPhoneNo=收件人手机后4位，非宝锐注册号 | 脚本phone4(o)逻辑正确 |
| P20 | 批量查询仅首条通过 | SF API只校验第一个单号 | 改逐条查询 |
| P21 | watchdog 50%成功率误杀 | 保护阈值导致661失败后全部丢弃 | 移除，仅告警 |
| P22 | 新下单查不到路由 | SF需处理数小时后路由才上线 | 接受延迟，定期重跑覆盖 |
