mirror of
https://github.com/karatektus/pl_mail.git
synced 2026-10-25 10:04:18 +00:00
Gmail classifies after delivery, and re-classifies every time the user drags mail between tabs, so CATEGORY_* comes and goes on rows plMail has held for months. Re-fetching exactly those rows is what the relabel sync exists for — and enrichExisting() overwrote gmailLabelIds, the only signal the categorizer consults on a Gmail row, without asking what those new labels now mean. So the category kept whatever ingest computed on the day the mail arrived. The drift was visible from two directions at once: the reading pane explains the category live, from the labels, while the inbox tabs filter on the thread's stored column. A relabelled promotion said "Gmail said so: CATEGORY_PROMOTIONS" in the reading pane and sat in Primary in the list, until the next `app:backfill category` run happened to agree with it. The row is recategorised in the same breath as the labels that decide it, and then re-adopted onto the thread — the tabs read the thread, not the message, so the row alone never reaches them. An empty correspondent map is passed on purpose: gmailLabelIds is non-null by then, so the categorizer takes its Gmail branch and never reaches the correspondence override that map feeds. MessageThreader::refreshCategory() is the other half of recordActivity(), which could not do this job: it adopts only while moving lastMessageAt forward, and a message being re-read is already counted in that key, so its gate never opens. Most-recent-wins instead — adopt when this message IS the newest the thread has. Ties adopt, matching the backfill's DISTINCT ON, which picks between two rows of equal received_at without ceremony either. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>