Skip to content

Sync provider categories and native importance - #65

Merged
rcsarv merged 2 commits into
mainfrom
codex/server-label-sync
Oct 6, 2026
Merged

rcsarv merged 2 commits into
mainfrom
codex/server-label-sync

Conversation

@rcsarv

@rcsarv rcsarv commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

Existing provider categories were ignored by automatic categorization, and marking Important in Inbox did not reliably update the provider. This change imports recognized server classifications before AI and makes manual classification edits durable and account-specific.

  • Sync Sarv's canonical Important keyword and Gmail's native Important label independently of stars and other categories. Stop stale writes when mailbox UIDVALIDITY changes.
  • Read Gmail's built-in categories through bounded UID SEARCH X-GM-RAW queries, including Primary. Unknown or failed discovery defers AI and retries after sync; provider/manual choices also protect against an AI response already in flight.
  • Add a Categories picker to the message toolbar and email list. Persist the complete replacement as one queue operation, preserve unrelated tags, and serialize rapid Important toggles. Gmail category edits use the owning account's OAuth resolver and precise X-GM-MSGID identity; unsupported changes fail before local mutation.
  • Store provider/manual classification provenance separately from AI verdicts. Seed Forums, Updates and Primary without replacing user definitions. Provider classifications skip categorizer-driven actions while independent conversation/contact processing remains available.
  • Prevent stale automatic label jobs from competing with manual edits, including rapid Important on/off changes and category updates during OAuth refresh.
  • Use Gmail's native category and importance assignments without creating unused Sarv Inbox mirror labels; clean up old native mirrors while preserving ordinary user labels and colored custom AI categories.

Validation: 11,739 tests passed (12 existing opt-in local scanner tests skipped), complete workspace type checks and repository lint passed, renderer dependency guard passed, and at least 90% branch coverage on touched classification paths. Tests cover offline replacement, partial retries, UID reset/missing targets, account isolation, server removals, late AI results, unknown Gmail discovery, popup errors, rapid toggles and stale jobs across retries. The two existing reply-transcript tests now clear their controlled timeout retries before DOM teardown; no reply behavior changed.

Sarv's Important mapping is based on the supplied FETCH ... FLAGS (\Seen Important) transcript. No live mailbox write was used for validation. Gmail protocol/API behavior follows Google's IMAP extensions and message label modification API.

expect(notifyNewMail).toHaveBeenCalledWith(expect.objectContaining({ emailId: 'sarv-native', categories: ['important'] }));
for (const [acct, id] of [['acct-a', 'gmail-native'], ['acct-b', 'sarv-native'], ['acct-b', 'user-empty']]) expect(row(acct, id).ai_categories).toBeNull();
quit();
s = await launch();
rcsarv added a commit that referenced this pull request Oct 5, 2026
"rebuilds a small queue synchronously, before returning" ran catchUp() on its
default 8 ms budget, which is wall time. Two thread rebuilds on a loaded CI
runner can outlast it, leaving one row queued: PR #65's CI failed with
"expected 1 to be +0" though nothing about draining had changed. With every
SQLite statement slowed by 2 ms the old test fails 3/3 with that assertion;
with Date frozen it passes 3/3, since the budget can no longer run out.

The test still guards what it is named for: a catchUp that defers to the pump
instead of draining leaves 2 rows queued and fails it. Running out of budget
stays covered by "stops at its budget, skips the hook, and re-arms the pump".
@rcsarv
rcsarv marked this pull request as ready for review October 6, 2026 06:07
@rcsarv
rcsarv merged commit 50dff66 into main Oct 6, 2026
6 of 7 checks passed
@rcsarv
rcsarv deleted the codex/server-label-sync branch October 6, 2026 06:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants