Root causes + fixes:
- Archive leaked Sent mail: filter was just 'not in inbox'. Added ExcludeGmailLabels;
Archive now excludes SENT/DRAFT/SPAM/TRASH/CHAT by label.
- Read Later / Pinned / Unlabelled returned EVERYTHING (no folder case -> default all).
Pinned = IsImportant; Read Later = new local IsReadLater marker (+toggle endpoints);
Unlabelled = HasUserLabels=false.
- Trash & Spam always empty: IncludeSpamTrash=false + sync never set IsTrashed nor created
EmailLabel rows. Now fetches spam/trash, sets IsTrashed from the TRASH label, and links
every message to its Gmail labels (also fixes Sent/Spam/category-by-label/Unlabelled).
- Old Mail: now strictly older than 6 months (was 1 year).
Guardrail: sync upsert is now idempotent (drops prior copy before reinsert) so re-sync
can't duplicate a message or leave stale labels. 4 new filter tests; 65 backend + frontend
green; migration is a single non-destructive column add.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>