Skip to main content

Module mailbox

Module mailbox 

Source
Expand description

Mailbox-pane data source and tab definitions.

The Triptych mailbox presents two tabs, organised by direction rather than channel type (#462):

  • Inbox — everything inbound to the focused agent, time-merged: DMs (recipient = '<project>:<agent>') plus inbound channel and wire traffic (sender != '<project>:<agent>', so a broadcast the agent itself sent shows under Sent, not here).
  • Sent — every row whose sender = '<project>:<agent>', irrespective of recipient class. Sender-side, so it already catches outbound DMs, channel posts, and broadcasts.

Four data shapes still back these tabs — the SQL fetch is unchanged (inbox, sent, channel_feed, wire); only the tab surface folds them by direction. The Channel and Wire MailboxTab variants survive as internal buffer keys (they’re dropped from MailboxTab::ALL, so they’re never user-navigable tabs) because the channel buffer still feeds the MailboxFirst layout’s channel feed and the Inbox merge:

  • Channel — channel traffic for channels the focused agent is a member of (recipient is 'channel:<channel_id>', filtered through channel_members).
  • Wire — project-wide broadcast traffic on the all channel (recipient = 'channel:<project>:all').

INVARIANT: every messages.recipient value falls into exactly one of three prefix classes — <project>:<agent> (DM, no scheme prefix; the channel-or-user split below depends on this absence), channel:<channel_id>, or user:<handle>. data::mailbox_counts relies on the same contract when it filters out channel/user rows for the per-agent unread-mail counter; if a fourth prefix class ever lands, the comment there and the queries here both need to learn it. Sent is the one tab whose filter is sender-side and recipient-class-agnostic — it returns rows from all three recipient prefix classes.

Modules§

test_support
Shared mock — public so unit tests, integration tests, and downstream coverage can wire in a recorder without rolling their own. Matches the shape used by compose::test_support and approvals::test_support.

Structs§

BrokerMailboxSource
Production impl reading the broker SQLite at <root>/state/mailbox.db. Each call opens a fresh connection — mailbox.db is local and short-lived connections cost effectively zero.
CursorState
UI cursor state for one mailbox tab. PR-1 stores only the selected row index; the rendered scroll-window is derived at render time from selected_idx + the actual pane height, so a terminal resize just changes the next-paint window without touching persisted state. selected_idx is an index into MailboxBuffers::visible_indices.
MailboxBuffers
Per-agent buffer state — four tabs, four after_id cursors. Lives on App so swapping the focused agent resets the cursors without trying to back-fill: the operator sees only forward motion in the tab they’re watching.
MessageRow

Enums§

MailboxInputKind
Which mailbox input the operator is editing. Singleton at the App level (only one input can be open at a time across all tabs); distinct from the per-tab filter_text / search_text it targets, which live on MailboxBuffers. Defined here so the data-side methods (input_push_char, input_pop_char, etc.) can take it without crossing the App boundary.
MailboxTab

Constants§

PAGE_JUMP
PageUp/PageDown jump size — a screen-ish chunk of rows. Fixed for PR-1 to keep scope surgical; a follow-up can wire this to the actual rendered mailbox-pane height once that’s plumbed onto App.

Traits§

MailboxSource
Lookup contract: each method returns rows newer than after_id for the given filter, in ascending id order. Callers fold the returned rows into a per-tab buffer and bump after_id to the last returned id.

Functions§

kind_label
T-131 PR-3: human-readable kind label for the detail modal. Derived from the recipient shape — the same prefix classes the module-doc INVARIANT pins (<project>:<agent> DM, channel:<project>:all wire, other channel: channel, user: DM-from-or-to-a-user).
render_row
Format a single row for the mailbox pane. Kept terse: prefix in brackets + one-line body. Multi-line bodies are flattened with a space so a single message stays one row in the pane.
row_timestamp
T-131 PR-4: short absolute-datetime stamp for the right-side mailbox-row indicator. Computed every render from now_secs (clock reading at render time) and the row’s sent_at (epoch seconds). Format is today-folded to save column budget on the common case:
row_timestamp_in
TZ-injected variant of row_timestamp — keeps the production path on Local while tests pin behaviour with Utc.
transport_label
T-131 PR-3: best-effort transport / origin label for the detail modal. Heuristic from the sender prefix (variant (b) locked):