# Notification Silent Failure — WeChat 846609 WebSocket Disconnection ## Incident: 2026-07-09 ### Timeline - 01:27 UTC — Gateway errcode 846609 first appears (WebSocket not subscribed) - 01:28 — 职业卫生监督 workflow final_review completes, notification fails silently - 01:30 — WebSocket error attempt 6 - 02:12 — 舜珙血压计 workflow final_review completes, notification fails silently - 02:15 — WebSocket error attempt 7 - 02:18 — Doro sends "hi", WebSocket recovers (inbound works before outbound stabilizes) ### Root Cause `final_review` calls `_send_wecom(extra, 'doro', msg)` in a subprocess. When the WeCom WebSocket is disconnected (846609), the send fails but: 1. The uwf thread still ends successfully (status=end) 2. The queue-runner marks the contract as `delivered` in tracker 3. No retry mechanism exists for failed notifications 4. No alarm fires for silent notification failures ### Diagnostic Commands ```bash # 1. Find delivered contracts that may have missed notifications python3 -c " import json t = json.load(open('$HOME/.hermes/data/contract-tracker.json')) for c in t['contracts']: if c.get('status') == 'delivered': print(f\" {c['original_filename']} delivered_at={c.get('delivered_at','?')}\") " # 2. Check for 846609 errors in the time window grep '846609' ~/.hermes/logs/gateway.log | grep "$(date +%Y-%m-%d)" # 3. Check WebSocket disconnection periods grep 'WebSocket error\|websocket closed' ~/.hermes/logs/gateway.log | grep "$(date +%Y-%m-%d)" # 4. Verify if notification was actually sent (look for successful send around delivered_at) # A successful notification looks like: # INFO gateway.platforms.base: [Wecom] Sending response (XXX chars) to doro # WITHOUT a subsequent 846609 error in the same second # 5. Check which threads completed during outage grep 'DONE.*status=end' /tmp/contract-queue/queue.log | grep "TIME_RANGE" ``` ### Remediation ```bash # Manually re-send notification for affected contracts python3 ~/.hermes/scripts/wecom_dm.py --to doro --text "合同审查完成通知(补发): 文件名: 【修】XXX.docx 顾问单位: XXX 修订摘要: X处插入、Y处删除 主要修订: ... 已上传至Nextcloud任务交付目录。 (因企微连接中断未能实时送达,现补发)" ``` ### Prevention (not yet implemented) - `final_review` should check send result and retry 3x with backoff - Queue-runner should distinguish "delivered + notified" from "delivered + notification failed" - Watchdog could audit: for each `delivered` record older than 30 min, verify gateway.log has a matching successful send