Skip to content

ADR 0023: Triage query APIs and attention queues

Status

Accepted

Context

Duckbill™ Integrated Beta needs read-only Home, Needs Me, conversation, structured search, and the three first-class attention queues (Respond, Waiting, System Alerts). Clients must not talk to Graph for triage. Conversation attention already lives on conversation_states (ADR 0009). MailMessage is content; MessageInstance owns mailbox flags. READ is not COMPLETE. Search is structured metadata only — no vector database. ADR 0022 is the AI inference isolation decision.

Decision

  1. Versioned /api/v1 query contracts live in @inbox-agent/api-contracts and @inbox-agent/application (triage-query.ts, triage-http.ts). Next.js App Router exposes them. AI never calls mail adapters.
  2. Queues are driven by conversation/attention state and classifications, not unread count. RESPOND remains after MessageInstance.is_read changes. Waiting can age. System Alerts are exception-oriented system mail; routine Vercel success is excluded.
  3. Needs Me is the union of ACTION, RESPOND, SYSTEM_ALERT, and low-confidence items. Results always include mailbox and provider.
  4. available_actions is capability-driven. can_send and can_delete are always false. ENABLE_SEND and ENABLE_DELETE stay false. Future command routes are catalogued at GET /api/v1/commands for Stream B; this stream does not execute MailCommand / ProviderMutation.
  5. Structured search uses the local canonical index only (provider_search_used: false, vector_database_used: false).
  6. The lightweight web UI (/inbox) consumes these APIs. It is not a composer and has no send-from-composer path.

Alternatives

Consequences

Triage UI and future clients share /api/v1. Stale sync is labeled. Empty and error states are first-class. No schema migration: queries use existing conversation_states, mail_threads, mail_messages, message_instances, classifications, and connected_accounts. Corrections (MAIL-40/54/55) and write-back stay on other issues.