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 whosesender = '<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 throughchannel_members).Wire— project-wide broadcast traffic on theallchannel (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_supportandapprovals::test_support.
Structs§
- Broker
Mailbox Source - Production impl reading the broker SQLite at
<root>/state/mailbox.db. Each call opens a fresh connection —mailbox.dbis local and short-lived connections cost effectively zero. - Cursor
State - 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_idxis an index intoMailboxBuffers::visible_indices. - Mailbox
Buffers - Per-agent buffer state — four tabs, four
after_idcursors. Lives onAppso swapping the focused agent resets the cursors without trying to back-fill: the operator sees only forward motion in the tab they’re watching. - Message
Row
Enums§
- Mailbox
Input Kind - 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_textit targets, which live onMailboxBuffers. Defined here so the data-side methods (input_push_char,input_pop_char, etc.) can take it without crossing the App boundary. - Mailbox
Tab
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§
- Mailbox
Source - Lookup contract: each method returns rows newer than
after_idfor the given filter, in ascending id order. Callers fold the returned rows into a per-tab buffer and bumpafter_idto 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>:allwire, otherchannel: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’ssent_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 onLocalwhile tests pin behaviour withUtc. - transport_
label - T-131 PR-3: best-effort transport / origin label for the detail modal. Heuristic from the sender prefix (variant (b) locked):