# 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)