Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

fix(rules): categorize threads in historical/bulk runs#2774

Open
casar68 wants to merge 2 commits into
elie222:mainelie222/inbox-zero:mainfrom
casar68:fix/historical-thread-categorizationcasar68/inbox-zero:fix/historical-thread-categorizationCopy head branch name to clipboard
Open

fix(rules): categorize threads in historical/bulk runs#2774
casar68 wants to merge 2 commits into
elie222:mainelie222/inbox-zero:mainfrom
casar68:fix/historical-thread-categorizationcasar68/inbox-zero:fix/historical-thread-categorizationCopy head branch name to clipboard

Conversation

@casar68

@casar68 casar68 commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Summary

When bulk-processing past emails (the "Process rules" / assistant history UI), threads were left entirely uncategorized when their first message was outside the selected date range (or just not processed).

Root cause: the UI dedupes to one representative message per thread — the most recent (ProcessRules.tsx). For a multi-message thread that representative is a mid-thread message (message.id !== message.threadIdisReplyInThread true). The matcher's thread-continuity guard in findPotentialMatchingRules then skips every runOnThreads=false categorization rule (Notification, Receipt, Marketing, …) because the thread has no prior category, leaving the model only the conversation meta-rule → no match → the whole thread gets no label.

Measured impact on a real bulk run: ~8% of processed emails (system notifications — deliveries, order updates, receipts) ended up with no category, all confirmed as threads with zero applied rule.

Fix

Add an isHistorical flag, set by the bulk UI, threaded
runRulesAction → runRules → findMatchingRules → findPotentialMatchingRules.
When set, the thread-continuity skip is bypassed so categorization runs on the representative message and the thread gets categorized.

// match-rules.ts
if (isThread && !isHistorical && !rule.runOnThreads) { /* skip */ }

Why this is safe

  • Real-time unchanged (isHistorical defaults false): first message of a thread still categorizes; later messages still continue the existing category. No new real-time AI calls, no behaviour change.
  • No double-labelling: the bulk path already dedupes to one message per thread, so there is no concurrent same-thread categorization that could assign competing labels.

Test plan (TDD)

  • match-rules.test.ts (written first, watched fail, then green):
    • historical run + thread message + no prior category → categorization rule is offered (not in skippedThreadRuleNames);
    • real-time run, same setup → rule is skipped (continuity guard preserved).
  • Full unit suite green (pnpm test): 0 failures.
  • pnpm --filter inbox-zero-ai build:ci green (type-check across the threaded flag).

🤖 Generated with Claude Code

@vercel

vercel Bot commented Jun 2, 2026

Copy link
Copy Markdown

@casar68 is attempting to deploy a commit to the Inbox Zero OSS Program Team on Vercel.

A member of the Team first needs to authorize it.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 6 files

Re-trigger cubic

@casar68
casar68 force-pushed the fix/historical-thread-categorization branch from 87a6171 to 6a055ad Compare June 2, 2026 07:34
When bulk-processing past emails, threads were left uncategorized when their
first message was outside the date range (or not processed). The bulk UIs
dedupe to one representative message per thread (the most recent), which for a
multi-message thread is a mid-thread message. The matcher's thread-continuity
guard then skipped every runOnThreads=false categorization rule (the thread had
no prior category), leaving the model only the conversation meta-rule -> no
match -> the whole thread uncategorized. ~8% of bulk-processed emails (system
notifications: deliveries, order updates, receipts) ended up with no label.

Add an isHistorical flag threaded runRulesAction -> runRules ->
findMatchingRules -> findPotentialMatchingRules. When set, the thread-continuity
skip is bypassed so categorization runs on the representative message. The flag
is set by both bulk entry points: runAiRules (BulkRunRules) and ProcessRules.

Real-time is unchanged (flag defaults false): first message still categorizes,
later messages still continue the existing category, no extra real-time AI
calls. Safe under the bulk path's one-message-per-thread dedup (no concurrent
same-thread categorization -> no competing labels).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@casar68
casar68 force-pushed the fix/historical-thread-categorization branch from 6a055ad to ab151eb Compare June 2, 2026 07:35
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

Morty Proxy This is a proxified and sanitized view of the page, visit original site.