fix(wxhook): 图片 .dat 拉取慢导致漏图/漏退 — 加大超时 + 后台补偿
根因 (2026-06-02 21:05 事故): 微信图片以加密 .dat 落盘, 客户端等落盘后解码。 原逻辑 10s 硬超时 + download_attachment 只触发一次 + 兜底 base64Img 多为空, 大图/弱网下 .dat 没及时落盘 → 解码失败 file_path=NULL 入库 → 退款 plugin 扫 file_path IS NOT NULL 漏掉它 (静默漏退) + 转发无图 XML 给下游。
实时层:
- .dat 落盘超时 10s→30s, 等待期间每 5s 重新触发 download_attachment (_wait_for_dat)
- 抽出公共 redecode_image(msg_id), 实时与补偿共用 (无 event 依赖)
补偿层 (状态机 media_status: NULL→pending→ok/dead):
- 解码失败图片标 pending 不转发, 持久化 platform_msg_id
- 新增 MediaRetryService 每 30s 轮询: 用 msgId 重新下载解码
- 成功 → set_media_decoded 回填 file_path 保持 pending (退款立即可见, replay 仍不碰) → forward_compensated 确认 forwarded=1 后才 mark_media_ok
- 失败 20 次 → mark_media_dead + 飞书告警
- 关键不变量: pending 时 replay 排除、ok 时 forwarded=1 也排除 → 不重复转发
- _forward 幂等 + 断连守卫; get_unforwarded 排除 pending/dead
storage 加列 platform_msg_id/media_status/media_attempts (旧库 ALTER 兼容)。 覆盖测试: 状态机流转/幂等/断连/退款可见性。两轮 code-review 确认无重复转发。
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com