# 交付通知丢失：企微WS凌晨断连 + fire-and-forget架构

## 事件：2026-07-09 职业卫生+舜珙血压计两份合同交付无通知

### 时间线
- 01:23:06 — 最后一条成功发送（gateway → doro）
- 01:25~01:27 — WS断连（原因未知，WeCom服务端）
- 01:27:23 — 首次846609 "aibot websocket not subscribed"
- 01:28:01 — 职业卫生监督thread=end，final_review尝试通知→失败
- 01:30:44 — WS reconnected
- 02:04:16 — 成功发送（QiuTing），说明短暂恢复
- 02:12:29 — 舜珙thread=end，通知可能在02:05-02:12期间尝试
- 02:15:50 — WS再次断开
- 持续不稳定直到 06:36

### 根因链
1. WeCom WS凌晨不稳定（每30-60min断一次，服务端维护/长连接超时）
2. Gateway自动重连成功但846609持续（"not subscribed"是服务端状态滞后）
3. workflow 24/7运行，final_review完成时间不可控
4. final_review通知是fire-and-forget：`_send_wecom(extra, 'doro', msg)` 调一次，失败即丢弃

### 通知机制分析
```
final_review procedure step 3:
  cd ~/.hermes/hermes-agent && source venv/bin/activate && python -c "
  from tools.send_message_tool import _send_wecom
  ...asyncio.run(_send_wecom(extra, 'doro', msg))..."
```

`_send_wecom`实现：
- 创建**新的** WeComAdapter实例
- connect() → send() → disconnect()
- 独立WS连接，不依赖gateway的WS
- 但用的是同一个WeCom API，846609是服务端状态，新连接一样受影响
- 失败返回 `{"error": "..."}` 给LLM，LLM可能仍标记notification_sent=true

### 7月8日也有相同模式
- 01:13 Timeout → 03:07 reconnect失败 → 06:04 gateway重启才恢复
- 约5小时不可用窗口

### 解决方案（待实施）

**推荐方案B：watchdog补发**
- watchdog cron（每20min）增加逻辑：
  1. 扫描tracker中 `status=delivered` + `delivered_at > 30min前` + `notification_sent != true`
  2. 用 `wecom_dm.py --to doro` 补发通知（独立WS连接）
  3. 成功后写 `notification_sent=true` + `notification_at=timestamp`
  4. 失败则 `notification_attempts += 1`，下次tick继续重试
  5. attempts > 6（即2小时）仍失败→日志告警不再重试

**tracker字段扩展**：
```json
{
  "notification_sent": false,
  "notification_at": null,
  "notification_attempts": 0
}
```

**wecom_dm.py优势**：
- 独立WS连接，不受gateway状态影响
- 有明确的返回值（success/fail）
- 凌晨WS虽然不稳定但有恢复窗口（如02:04成功发送）
- 20min tick间隔 × 多次重试，大概率能命中一个可用窗口

### 临时止血
当发现合同delivered但Doro没收到通知时：
```bash
python3 ~/.hermes/scripts/wecom_dm.py --to doro --text "合同审查完成通知（补发）: ..."
```
