发布

  • fix(x): harden the Gmail rate-limit cooldown after v0.9.1 field reports (#949)

    frostbyte_neo 发布于 2026-09-08 13:39:25 +00:00

    A throttled user on v0.9.1 still saw a degraded cycle: the promised resume
    time kept sliding forward (5:25 → 5:31), waits pinned at exactly 15 minutes
    (the fallback cap, not Gmail's word), and each resume re-tripped the limit
    with a full maintenance burst. Root causes and fixes:

    • No-slide rule: a Gmail-named deadline may always extend an active cooldown
      (it's Gmail's own word), but the no-deadline fallback can never extend one.
      Un-gated callers failing during a lockout used to slide the resume time
      indefinitely.
    • Per-episode strikes: the 1m→15m ladder escalates only when arming from an
      expired state. Concurrent callers used to each burn a strike, jumping the
      first lockout straight to the 15-minute cap.
    • Deadline parsing hardened: space-separated timestamps, UTC/GMT/offset
      suffixes, missing zone (assumed UTC — Date.parse would read it as local),
      and raw string response bodies, plus the classic ISO-with-Z form.
    • Recovery probe: getUserEmail keeps making its 1-quota-unit getProfile call
      during a lockout (at most once a minute, negative-cached) and its success
      calls noteGmailSuccess(), ending a stale cooldown the moment Gmail actually
      recovers and resetting the ladder.
    • The hidden 10s hammer: agent_notes' loop (a leftover "(for testing)" 10s
      interval) re-called getProfile every tick until one succeeded — during a
      fresh-connect lockout, 6 failing calls a minute, each re-arming the
      cooldown. It now attempts at most every 15 minutes and never during a
      lockout.
    • Gentle re-entry: new gmailQuotaTight() (active cooldown + 60s grace after
      it, ended early by a successful probe) stands down the inbox prune,
      classify sweep, and timer backfill, so the first pass back is the lean core
      sync instead of the burst that immediately re-earned the limit.
    • Lingering red "sync failed" after quiet recovery (pre-existing): a
      syncDegraded flag emits a one-time "Gmail sync recovered" run on the first
      successful pass after any failure, clearing the sidebar state.
    • Diagnosability: the console warning and the yellow feed notice now record
      whether the wait came from a parsed Gmail deadline or the fallback ladder,
      with the exact ISO deadline in the notice details — the next field report's
      services.jsonl will say which path fired.

    Co-authored-by: Claude Fable 5 noreply@anthropic.com

    下载附件