auto-reply-debug-session-20260721.md 2.6 KB

Auto-Reply Debug Session 2026-07-21

Timeline

  1. Watcher daemon died after phone restart (or process killed), ~7/19 15:38
  2. Orchestrator stopped processing incoming.jsonl at the same time
  3. 5579 messages accumulated in incoming.jsonl
  4. Alisa (wxid_qx3jhn1edwie22, role=admin) sent msgId 18334 at 7/21 09:48: 「不错啊,和 BOSS 直聘打通了呀」
  5. Message was captured by watcher --once but orchestrator couldn't process it

Root Causes (layered)

Layer 1: Watcher needs su -c

MM_BASE = /data/user/0/com.tencent.mm — this path is inaccessible without root. read_uin() uses open(xml) directly, not su -c cat, so it fails with "没读到微信 last_login_uin(未登录?没 root?)" when run as normal user.

Fix: su -c '/data/data/com.termux/files/usr/bin/python3 /data/data/.../watcher.py'

Layer 2: Orchestrator also needs su -c

_drain_inner() → account_paths() → read_uin() — same root requirement. When run as normal user, exception is thrown silently (stdout not captured in cron context), cursor is never updated, orchestrator log shows no new entries.

Fix: su -c '/data/data/com.termux/files/usr/bin/python3 /data/data/.../orchestrator.py --drain'

Layer 3: orch.lock residue

When orchestrator crashes under root, drain() finally block can't delete orch.lock (root-owned file, or exception jumped past finally). Subsequent drains see the lock and return immediately (no log). Lock is auto-preempted after 300s, but in those 5 minutes all drains are silent no-ops.

Fix: Watchdog now cleans locks older than 300s before each drain.

Layer 4: copy_db misses rcontact table

Watcher's copy_db() creates an EnMicroMsg.db copy under _stage_orch/ but doesn't include rcontact table. When process_event() tries to look up sender nickname, sqlcipher reports no such table: rcontact. The message send itself may still succeed via hook, but processing is logged as failed.

Status: known bug, not yet fixed.

Recovery Steps (executed)

  1. su -c '...watcher.py --once' — caught up missed messages (msgId to 18387)
  2. Set cursor.json to {"last_msgId": 18387}
  3. su -c '...watcher.py &' — started persistent daemon
  4. rm -f orch.lock — cleared residue lock
  5. su -c '...orchestrator.py --drain' — processed backlog
  6. Manually sent reply to Alisa via send_text_via_hook (orchestrator's rcontact bug blocked automatic processing of #18334)

Prevention

Watchdog script (~/pixelphone/scripts/wechat-viewer-watchdog.sh) now includes:

  • §5: WeChat Watcher daemon check + auto-restart (with su -c)
  • §6: Orchestrator drain every 5 minutes (with su -c + lock cleanup)