yiekheng 1c3d4ef893 fix(transfer): use dedicated /user/batch endpoint, alert+skip on fetch failure
Transfer bot was silently no-op'ing every Monday cycle since /user/
became paginated ({"rows": [...], "total": N}). The bot's silent
guard `len(items) if isinstance(items, list) else 0` collapsed every
contract mismatch and HTTP/JSON error into "0 items" with no signal.

- API: add /user/batch — bare-list, no pagination — for batch jobs.
  Keeps the paginated /user/ contract intact for the web UI.
- Bot: replace silent guard with raise_for_status + isinstance check.
  On any HTTP/JSON/contract failure, log + Telegram-alert + skip the
  cycle (next attempt in 10 min). Empty list still means "no work".
- Tests: 15 new tests pinning both sides of the contract, including a
  regression test that feeds the exact envelope shape that broke prod.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 08:31:08 +08:00
..