Files
claw-email/docs/superpowers/specs/2026-04-28-references-threading-design.md
T
2026-04-28 04:51:38 +07:00

1.8 KiB

Threading: Add References Header Fallback

Problem

Ingress threading only resolves parent via In-Reply-To. When a client sets References without In-Reply-To, the bridge creates a new thread_id instead of attaching to the existing conversation, breaking thread continuity and downstream dispatch.

Requirements

From requirements.md:74:

  • If In-Reply-To or References is present, find parent task in DB and inherit thread_id.
  • Otherwise use message_id as new thread_id.

Design

Current behavior (imap.go:333-369)

  1. Parse MIME body headers, extract In-Reply-To
  2. If found, lookup parent by message ID → inherit thread_id

New behavior

  1. Parse MIME body headers, extract both In-Reply-To and References
  2. Try In-Reply-To first (unchanged)
  3. If no parent found via In-Reply-To, parse References header (space-separated <msg-id> list)
  4. Iterate References from last to first (most recent ancestor first)
  5. First match in DB wins → inherit thread_id

Why last-to-first

References lists message IDs chronologically: <oldest> ... <newest>. The last entry is the most recent message in the chain, most likely already processed by the bridge.

Scope

  • Single file change: internal/mail/imap.go (threading block in processMessage, ~10 lines)
  • New tests: internal/mail/imap_test.go (References parsing, fallback, multi-ID)
  • No changes to DB, config, API, or other packages

Test cases

  1. In-Reply-To matches → existing behavior unchanged
  2. In-Reply-To absent, References has match → inherits thread_id from most recent match
  3. References has multiple IDs, only older one in DB → still matches
  4. Both headers absent → thread_id = message_id (unchanged)
  5. References present but no match in DB → thread_id = message_id (new thread)