ADR 0009: Conversation-level attention lives on conversation_states

Status

Accepted

Context

Duckbill needs conversation-level attention, priority, and waiting so triage APIs can answer “what needs a response?” without collapsing message identity.

MailMessage owns RFC-style content. MessageInstance owns mailbox flags such as is_read. Functional requirements also need a conversation RESPOND / WAITING / FYI state. Putting that state on MailMessage would mix content identity with workflow. Equating instance READ with conversation RESPOND would clear a thread’s need-to-respond the moment any copy of a message was marked read in one mailbox.

Decision

Store conversation-level attention on a separate inbox_agent.conversation_states table keyed by canonical thread_id (UUID PK conversation_state_id, unique thread_id).

Columns:

Do not store provider IDs as primary keys. Do not put attention on mail_messages. Do not derive RESPOND from message_instances.is_read.

Alternatives

Consequences

Updating MessageInstance.is_read cannot clear conversation RESPOND by schema alone. Needs-me / attention queries join conversation_states and still exclude message_instances.historical = true (MAIL-174).