Skip to content

Daily Brief implementation

A thoughtful morning read that is true. One factual snapshot, rendered by every surface that shows it: the /brief page linked from the desktop's Today dashboard, and an opt-in email digest. The page also fits a narrow browser; there is no separate mobile app. These brief renderers share their counts and content. The existing Today dashboard remains a separate overview.

harness/daily_brief.py is that snapshot builder. It is deterministic, evidence backed, and model-free: a brief that says "3 things need your attention" must be able to point at the three rows, and a sentence a model wrote cannot be pointed at.

What it is not

  • Not a second agent loop. The builder does not fetch, schedule, send, crawl, or call a model. The brief's one outbound request, the opt-in feed reader (see News below), lives outside it and hands it headlines already stored.
  • Not an authority. Titles, agendas, headlines and mail-derived text are data. They are collapsed to one bounded line, stripped of control characters, and HTML-escaped again in the renderers. Nothing in a payload can become an instruction or a link.
  • Not a task store. The builder never writes to the sources it reads. The only file it owns is its own small preferences/seen store. The one source the brief page writes is the person's own to-do list (see To-dos below), through its own route and its own store — never a mission, session, calendar or message.

Integration API

from harness import daily_brief

brief = daily_brief.build(
    payloads,                     # {source name: the JSON body that source returned}
    now=None,                     # epoch seconds; default wall clock
    timezone="Europe/Helsinki",   # IANA key, or a datetime.tzinfo instance
    utc_offset_minutes=None,      # preferred fallback: what a browser/phone knows
    fallback_timezone="utc",      # or "system"
    language="en",                # "en" and "zh" have labels; others fall back to en
    state_dir=None,               # enables dismiss/snooze + staleness; omit for pure
    profile="default",
    remember=True,                # record seen-bookkeeping when state_dir is set
    news=None,                    # None = off. A list of already-sourced items
                                  # (the web layer passes the feed reader's headlines).
    top_limit=3,
)

text  = daily_brief.render_text(brief, bilingual=False)   # -> str
email = daily_brief.render_email(brief, bilingual=False)  # -> subject/text/html/headers

payloads keys are daily_brief.SOURCE_NAMES, and daily_brief.PAYLOAD_ENDPOINTS maps each to the local endpoint Today already fetches:

name endpoint used for
personal /api/personal sourced reminders, tracked events, connected sources
missions /api/missions attention / progress / done, scheduler health
approvals /api/approvals blocking decisions (always rank first)
procedures /api/procedures?limit=20 proposed routines
runs /api/runs in-flight and finished-today runs
meetings /api/meetings/schedule the real calendar agenda
task_inbox /api/task-inbox/pending queued work, and what is stranded on a person
communications /api/channels messages already received, replies already written
todos /api/brief/todos the person's own to-do list (<state>/daily-brief/todos.db)

Each value is read three ways, and the difference is the whole point:

value state rendered as
a payload dict ok its actual entries
{"__unavailable": true}, a dict with error, or any non-dict unavailable "Could not read: … Nothing missing has been assumed clear."
missing / None absent never configured; contributes to the setup state

all_clear is true only when every supplied source was read and at least one answered and nothing needs attention. A failed integration can never present as a clear day.

Two distinctions inside those payloads decide whether the brief is honest, and both are the source stores' own vocabulary rather than this module's guess:

  • Terminal is not finished. webapp._run_end publishes stop_reason beside state precisely because a run stopped by an error or a turn/budget cap has ended without answering. Those rows are attention, carrying the run's own error; only a completed run is listed under Done today; canceled work is omitted. Counting an aborted run as done is how the same work gets asked for twice.
  • A scheduled wait is not always progress. quota_resume.status reports scheduled / queued / starting (the server will start this) but also stalled, stopped and unknown (nothing will, without a person). Only the first group files a queued session under In progress; the rest are attention, with the wait's own reason as the detail.

A fourth state sits between ok and unavailable: partly read. A mailbox is unbounded and a brief is not, so the collector reads at most COMMS_CONNECTION_LIMIT (16) connections and COMMS_ROW_LIMIT (60) received messages and replies per connection. Whatever is past that — or a connection whose store would not open at all — puts the source in coverage["partial"], which forces all_clear to false and adds a notice saying what was not covered. Reporting it unavailable would throw away the connections that did open; reporting nothing would let an unread message be rendered as a clear day.

The session collector uses task_inbox.pending_sessions_window, a read surface over the same local inbox store. It enumerates candidate file metadata, opens at most 100 inboxes and stops once 50 relevant rows are found; journals are not decoded. File modification time selects this recent window. Unexamined and unreadable inboxes put task_inbox in coverage["partial"] with an English or Chinese notice. The scheduler's full pending_sessions contract is unchanged.

Messages

communications is the only source whose rows were written by strangers, so it is the most tightly bounded one. It is a read of the local store behind /api/channels — ChannelService.overview(), .events() and .results(), and nothing else. Opening the brief does not poll a mailbox, probe, send, retry, accept, reject or read a credential, and it is not a live check with a provider: it reports what the connection last stored, with each source's own collected_at beside it.

what the store holds how the brief reads it
pending message, sender the owner allowed needs you — ready for review
pending message, sender not allowed / automatic / bulk counted in a notice, no row
rejected message settled; it keeps its record in Communications and makes no claim
accepted message the task it became, folded into that session's existing row
pending reply needs you — ready to send, and says so if the connection is paused
failed / unknown reply needs you; unknown is never retried by itself
sending in progress
submitted today done today — "The service accepted it. Delivery is not confirmed."

Four rules hold that table up:

  • Only a subject. No body, no sender or recipient address, no attachment name, no raw-message reference and nothing about a credential leaves the store. A message with no subject gets a fixed, module-written line instead. The collector projects those fields away before the builder ever sees them, and the builder reads no others.
  • Severity is the stored state, never the text. "URGENT" in a subject buys exactly as much rank as any other subject. If it did not, ranking a person's morning would belong to whoever sends the most mail.
  • Accepted work is shown once. An accepted message carries the session its task runs under, so it shares that session's dedupe key at the lowest rank and collapses into the Missions/Needs You/session row that already exists (evidence.also_in). A reply still waiting to go out wins that same key: the inbound message has been dealt with, the send has not.
  • Accepted by a provider is not delivered. submitted means the transport took the message. The brief says that in those words, and delivery_known stays false everywhere; a bounce arriving later is not something this snapshot can know.

A paused connection is read exactly like any other. Pausing stops new mail arriving; it does not settle the messages and drafts already sitting in the store, and hiding them would be the actual dishonesty. A root with no connections is an empty local store — ok, zero rows, no notice — and never a claim that a mailbox is connected.

Likewise, nothing is connected and everything we asked failed are opposite facts and get opposite words: setup["reason"] is "no sources are configured" only when every source was absent, and "no source responded" when any of them errored. A fresh profile whose endpoints all answered with empty bodies is ok and reaches neither — an empty store is an answer.

To-dos

todos is the one source a person writes directly, on the brief page, and it follows the rules the brief already applies to personal reminders and events:

to-do where it appears
open, due date before the reader's local date needs you — Past its due date. (overdue)
open, due today needs you — Due today. (due_today)
open, due later, or no due date not in the snapshot; it stays in the list on the page
ticked off during this local day done today, at the time it was ticked

"Late" is decided against the brief's own local date, never UTC's. Severity comes from the due date alone (3 late, 4 due today), so a to-do never outranks a waiting decision or a failed run however it is worded. The title is the person's own sentence and is never translated; only the detail line is ours. Rows link to /brief?todo=<id>, which the page reads to show that row. Hiding one from the brief is, as everywhere else, not ticking it off: it stays open in the list, and a changed due date or title brings it back.

harness/daily_brief_todos.py owns the list (at most TODO_LIMIT, 2000, so the builder always reads every row). Every row carries a revision. POST /api/brief/todos {"action": "save" | "delete", "todo": {...}} must name the revision it was made against; a row another window moved first is refused with 409 and conflict: true, and nothing is written — a stale tab can neither overwrite a newer edit nor bring back a deleted row. The page picks a new row's id before sending, so a create whose answer was lost is safe to send again: it finds its own untouched row instead of adding a second one. After an accepted save the page clears only fields nobody changed while the answer was on its way. A list that cannot be read makes the source unavailable and the page says so, rather than showing an empty list to start again in.

News

news= is filled from RSS and Atom feeds the person adds on the brief page, by harness/daily_brief_news.py. It is off until a feed is saved: with none, the web layer passes news=None, nothing is fetched and no thread runs. News is not one of SOURCE_NAMES — a feed being down is not a fact about the person's day, so it never makes coverage partial or the day unclear — and its per-feed state is reported in the page's own news panel instead.

What a fetch may do, each rule a guard:

  • Request only a saved feed address: https, port 443, a host name, no user name or password. Never an item link, image or icon.
  • Connect only to the public internet. Every address the name resolves to must be is_global (IPv4 carried in IPv6 — mapped, 6to4, Teredo, NAT64 — is checked as IPv4; the deprecated IPv4-compatible ::/96 and site-local fec0::/10, which Python calls global, are refused outright), and the socket is pinned to the checked address, so DNS rebinding cannot swap one in between check and connect. TLS still names the original host (SNI) and verifies its certificate. Every redirect, at most four, is checked again from the start.
  • Stay bounded: no proxy from the environment, Accept-Encoding: identity (a compressed answer is refused), at most 2 MiB (refused, not cut), a 7 s socket timeout per read, and a 20 s deadline for the whole fetch. A socket timeout alone restarts with every byte, so a watchdog timer shuts the connection down at the deadline — during the TLS handshake, the headers, a chunk-size line or the body alike — through a duplicate of the socket taken when it was created. Name resolution is the one step it cannot interrupt; the operating system's resolver bounds that, and nothing is sent until it answers.
  • Parse plain XML only, in one linear streaming pass (expat). A DTD or an entity is refused, by a byte scan and again by the parser. Deeper than 32 levels or more than 50,000 elements is refused as it is read; only an item's own children are read, never an item nested in one; each field keeps at most 4,096 characters and is cut again before tags are stripped with a pattern that cannot backtrack; reading stops after 100 items. A 2 MiB hostile feed is read or refused in hundredths of a second. Only items whose link passes safe_href(external=True) are kept; the rest are counted and the page says how many were left out.
  • The User-Agent is Collie-DailyBrief/1.0 (+https://github.com/colliehq/collie); no cookie, credential or topic is sent. docs/privacy.md lists this destination.

When it happens: on POST /api/brief/news (settings saves at a named revision and reads the feeds that are due — a new one always is; refresh is Check now, which still skips a feed read in the last minute), and in a lazy background worker that GET /api/brief starts once a feed is saved. The worker reads a feed at most once per its interval (15 minutes to a day), and ends by itself when no feed is saved. Opening the brief never waits on a fetch: headlines are whatever the last fetch stored, and a failed fetch keeps the last good headlines with its reason beside the feed. Nor does a save or Check now wait for the worker: each refresh claims the feeds it fetches and leaves feeds another refresh has claimed alone, and no lock is held while fetching, so removing a feed that hangs is answered at once.

Settings carry a revision, as to-dos do: a stale window's save is a 409 and saves nothing. A fetch that finishes after its feed was removed is not written back, so it cannot resurrect the feed's headlines.

Remote text stays display-only. Titles and summaries are reduced to one plain line when read, bounded again by the builder, drawn with textContent, and linked only as a validated https URL opened with no opener or referrer. Headlines are tone: "news" at the lowest severity: never in top, attention or any other section, never a suggestion's evidence or prompt, and "URGENT" in a headline changes nothing. The only route by which any brief text reaches a model is a reply to the emailed brief (daily_brief_reply), which quotes that morning's text inside markers saying it is an untrusted historical snapshot that authorizes nothing; a headline is one line there, so it cannot forge the quote's end marker on a line of its own.

The snapshot

build() returns a JSON-safe dict: id, date, generated_at, language, timezone, greeting, headline, all_clear, sources, coverage, top (≤3 actionable/attention), attention, agenda (compact, today only), progress, completed, news, suggestions (1–3), suppressed, setup, counts, notices, reply.

Every item carries a stable id (kind:16-hex, derived from source + native id), a content fingerprint, a source, a source_ref with a validated href, bounded evidence, first_seen_date, days_seen, changed_since_last_brief, stale, and generated (below). A message or reply id is namespaced by connection as well as by the provider's row id, because two accounts can hold the same Message-ID and they are not the same thing.

coverage is {ok, unavailable, absent, partial, complete, configured}; counts adds messages_quiet (messages deliberately not shown) and connections (how many message connections were read) to the section lengths.

Language, and whose words get translated

item["generated"] lists the fields whose words this module wrote — the fallback title of a row that had none, and the fixed detail lines like "Coming up soon." or "Ready to send from Communications." Those are translated when language="zh"; every other string is the source's own — a subject line, a mission title, a store's error message — and is rendered exactly as it was stored, in whatever language it was written. Translating those would be a rewrite of somebody's text, not a translation of ours.

Translation happens after ids, fingerprints and ordering are fixed, so switching language does not move a row, split a history entry, or forget that a row was hidden.

counts are len() of real entries — there is no placeholder row anywhere. An empty agenda is [] plus a notice; the "No events today" row that gets counted as an appointment by the next person to write a loop does not exist here. The notice fires whenever there is no calendar evidence at all — including the commonest case, a profile where the calendar endpoint was never wired up — and stays quiet when the meetings source is unavailable, because "could not be read" is already said and "not connected" would be a second, wrong explanation for the same empty list.

Rows with a when also carry when_offset_minutes — the UTC offset in force at that instant, not at local midnight. On a spring-forward day those differ by an hour, and a single day-level offset printed every afternoon meeting one hour early.

Two identities, on purpose

id names this content. It digests the date, profile, resolved zone, headline, counts, coverage, setup state and the fingerprint of every rendered row. A mission going needs_you → failed, an approval arriving, a source falling over or a row being hidden all produce a different id, because they are a different brief. An id built only from the date and the row ids (which never move when a row's status changes) would collapse two different briefs into one history entry and put the same X-Collie-Brief-Id on two different emails.

reply["day_key"] (daily-brief:<profile>:<YYYY-MM-DD>) names the day. It is stable across every rebuild of that local day, and it — not id — is the at-most-one-email-per-day job key. Deduping sends on id would mail the user again every time anything moved.

reply is {brief_id, date, day_key, subject_tag, sources}; with the email X-Collie-Brief-Id / X-Collie-Brief-Date headers it is what lets a later reply be tied back to the brief that prompted it. Storing and matching that is the caller's job.

Feedback

daily_brief.dismiss(item_id, state_dir=..., fingerprint=item["fingerprint"])
daily_brief.snooze(item_id, until_epoch, state_dir=...)
daily_brief.restore(item_id, state_dir=...)
daily_brief.feedback_state(state_dir=...)

Written to <state_dir>/daily-brief/<profile>.json under statelock.transaction (process lock + os.replace), so concurrent web/CLI/native writers cannot lose each other's updates. Retention is bounded: 500 preferences / 45 days, 1000 seen entries / 30 days, 60 logged briefs. The store keeps ids and fingerprints — no titles.

Hiding an item from the brief is not cancelling, completing, or acknowledging it. The task keeps its row in Missions, Needs You and the thread list, and the brief's own counts["attention_total"] still counts it. A dismissal applies only while the content fingerprint is unchanged: a changed status or changed evidence resurfaces the item. Pending approvals can never be hidden (UNSUPPRESSIBLE_KINDS) — dismiss() returns {"ok": false, "refused": ...}.

Pass fingerprint=item["fingerprint"]. A caller that omits it has recorded nothing that can be re-checked when the item changes, so the "it comes back when it changes" guarantee cannot be honoured for that preference; rather than let it run to the 45-day TTL and bury a mission that has since failed, an unanchored dismissal lasts only for its own local day. A snooze is already bounded by its own deadline and is unaffected.

Repeating yesterday's obligations verbatim forever is the defect that makes a daily brief worthless. Beyond dismissal, an unchanged non-decision item older than STALE_DAYS (3) is marked stale and loses its claim on the three top slots. It is still listed, and renderers print "unchanged since <date>" — demoted, never dropped, because silently dropping an obligation is worse than repeating it.

Timezones and day boundaries

The day is local midnight to the next local midnight, so a DST day is 23 or 25 hours (timezone["day_hours"]). An invalid zone name, or a valid IANA key on a machine with no tzdata — which is the stock Windows CPython this product ships against — does not raise and does not silently pretend to be UTC. It degrades in this order:

  1. utc_offset_minutes, if the caller passed one (a browser and a phone both know it);
  2. the OS local zone, if fallback_timezone="system";
  3. UTC.

timezone["degraded"], ["kind"], ["reason"] and ["resolved"] record what happened, and both renderers print the reason. A midnight that does not exist in a spring-forward zone resolves to the pre-transition offset.

greeting follows the reader's current local hour, not the start of the day window — whose hour is 0 on every day there has ever been, which is how a 07:00 morning summary came to open with "Good evening."

source_ref["href"] is either a local whitelisted UI route (first segment in _LOCAL_ROUTES) or, for news only, a validated https URL with a hostname and no embedded credentials. javascript:, data:, //host, http, traversal, backslashes, interior whitespace and control characters are dropped, not escaped — a link is an action target, not text. Nothing in a brief executes; each suggestion is a prompt plus requires_user_intent: true.

The allowlist is the set of paths webapp.Handler actually serves. Missions, Needs You, Today, sessions, the Library and Activity are panes of the single-page app at /, not routes: rows that linked to /missions or /needs-you 404ed. They are now reached the way the page reaches them itself — /?mission=<id> and /?session=<id>, the query keys index.html reads on load; a to-do links to /brief?todo=<id>, which the brief page reads the same way. The identifier is percent-encoded data and the finished link still has to satisfy safe_href, so no id can change a link's target; a row whose id will not survive that simply renders as unlinked text.

Architecture, and what is actually available

stores under <state root>        harness/daily_brief_web.py      harness/daily_brief.py
 personal / missions / runs  ->  collect(root)  -> payloads ->  build() -> one snapshot
 approvals / procedures          (read-only, one                  |
 meetings / task_inbox            guard per source)               +-> render_text()
 channels + communications                                        +-> render_email()
 todos (daily-brief/todos.db)                                           |
 news.db (stored headlines) -----------------> news= -------------->    |
 webapp.Handler  --  GET /brief (daily_brief.html)   <- fetch --  GET/POST /api/brief
                     GET/POST /api/brief/preferences  ------------> daily_brief_schedule
                     POST /api/brief/todos  -----------------------> daily_brief_todos
                     POST /api/brief/news  ------------------------> daily_brief_news
                                                  (the only fetch: saved feeds, https,
                                                   public addresses, lazy worker)
surface state
GET /brief — the page, in-app and in a browser mounted, authenticated
GET /api/brief — snapshot + freshness + email preview + the to-do list + feed state mounted, authenticated; starts the feed worker only if a feed is saved
POST /api/brief — dismiss / snooze / restore / preview mounted, authenticated
POST /api/brief/todos — save / delete one to-do, at a named revision mounted, authenticated
POST /api/brief/news — settings (at a named revision) / refresh mounted, authenticated; the only route that reaches the internet
GET/POST /api/brief/preferences — the opt-in email settings mounted, authenticated
the opt-in daily email (daily_brief_schedule) implemented and off by default; the settings routes are mounted, and the periodic tick(root) that actually sends is called from the app's pump (parent-owned wiring). A profile that never opts in never sends, and nothing here starts a send by itself.
mobile not started; it would be the same endpoint and the same snapshot

Every route but POST /api/brief/news is an authenticated read or write of local state, and that one fetches only the person's saved feeds. Opening the brief runs no model and no tool, never waits on a feed, and _preview renders the mail text without sending it (sendable: false).

A brief is a snapshot, not a live check. Each source is read from disk (or, for runs and approvals, from this process's memory) when the brief is built, and every source carries its own collected_at that the page shows. In particular, the messages source reports what the connection last stored — it does not contact a mail server, and a message that arrived one second ago appears once the connection's own polling has stored it. "Fresh" here means freshly read from the store, and the brief never claims more than that.

Dismiss and snooze are about this brief only. They hide a row while its content fingerprint is unchanged; they do not cancel, complete or acknowledge the work, and approvals cannot be hidden at all. See Feedback above.

Provider accepted ≠ delivered. A reply the transport took is reported as accepted by the service, with delivery explicitly unconfirmed — in the brief, in the email, and in the schedule's own outbox row.

Not built, and not claimed

  • No news discovery. News is only the RSS/Atom feeds the person saved (see News). There is no crawler, no recommended or default feed, no fetching of the linked articles, and no summarising, translating or ranking of headlines by a model.
  • No semantic reading of your mail. The messages source summarises connected local work — what is waiting, what is drafted, what failed to send. It does not extract commitments, deadlines, prices or intent from message bodies; it never reads a body at all. A "what did my inbox actually ask of me today" summary is a different feature and is not here.
  • No account provisioning. Connecting a mailbox, creating an address and storing credentials live in the communications settings surface, not here. The brief reads connections that already exist; if there are none, it says the store is empty rather than offering to make one.
  • The email digest's rules are enforced by daily_brief_schedule, not by this module. At most one message per local day keyed on reply["day_key"] (never on id, which moves whenever content moves), a frozen recipient taken from the connection's owner address at opt-in, a bounded send window with a visible skip, and no send at all without an explicit opt-in.

Limitations, honestly

  • Offline / partial. Only local sources are read. A source that is down is unavailable, which visibly shrinks the brief's claims; it never widens them.
  • News is off by default. With no feed saved nothing is fetched. With feeds, the builder still fetches nothing: it takes the headlines the feed reader last stored, and drops any row without both a publisher (the feed's host) and a safe https link. Headlines are only as fresh as the last fetch, which happens only while Collie runs.
  • Replies and actions need explicit intent. A reply to a digest is a description of a request, routed through the existing untrusted-data framing in harness/communications.py. It cannot approve, send, buy or cancel anything.
  • Lock screens. Notifications derived from a brief default to counts and section names only — no titles, no senders, no amounts. Calendar rows the meeting store marks sensitive are already reduced to "Private event" with no location inside the snapshot itself, so no renderer can leak them.
  • language ships labels for en and zh and falls back to English elsewhere. Only the strings this module wrote are translated (item["generated"]); text that came out of a source is always the source's own words.
  • Messages are summarised, not understood. A waiting message is reported as waiting. What it asks for is not read, inferred or ranked, and a subject line cannot move a row up the page.
  • Not a planner. suggestions are 1–3 deterministic drafts derived from rows in the same brief. They are prompts a person may choose, not a plan being executed.

Tests

tests/test_daily_brief.py builds its own payloads; tests/test_daily_brief_web.py drives real stores under tmp_path, including a configured message connection whose transport raises on every call. No network, no mail server, no credentials, no model and no real user state: addresses are example.test fixtures and message bodies are literals written in the test file. tests/test_daily_brief_todos.py covers the to-do store, builder and route; tests/test_daily_brief_todos_browser.py drives the real page in Chromium against the real server — stale windows, lost answers and words typed while a save is on its way. tests/test_daily_brief_news.py covers every fetch rule without the network — DNS is an injected resolver, feeds come from a local server behind an injected pinned connection, and the real TLS connection is aimed at a local socket that records its hello — plus the feed store, the worker, and what a hostile headline can and cannot become; tests/test_daily_brief_news_browser.py drives the page's news panel.

The builder suite covers item identity and cross-source dedupe, counts equal to real entries, no phantom agenda rows, empty vs unavailable vs absent vs partly-read sources, local-day and DST boundaries, invalid zone and missing tzdata, hostile HTML and unsafe links, dismiss/snooze/restore with content-change resurfacing, unhideable approvals, stale demotion, a corrupt store preserved and not applied, bounded retention, and text/HTML renderer agreement.

Each of these is a counterexample to a defect the module actually had:

test what it would otherwise do
test_the_greeting_follows_the_reader_not_local_midnight greet every reader "Good evening.", at any hour
test_times_use_the_offset_in_force_at_the_event_not_at_midnight print afternoon rows an hour early on a spring-forward day
test_a_run_that_stopped_without_finishing_is_not_done_today list an error/turn-capped run under Done today
test_a_stranded_request_is_not_hidden_behind_a_dead_scheduled_wait file a stalled request as progress and call the day clear
test_every_source_failing_is_not_reported_as_nothing_connected tell a user whose endpoints all 500ed that nothing is connected yet
test_an_empty_day_without_a_calendar_says_so_even_when_unconfigured show an empty agenda with no caveat when no calendar exists
test_the_brief_id_names_the_content_and_the_day_key_names_the_day give two materially different briefs one id
test_a_hide_with_no_fingerprint_cannot_bury_work_for_forty_five_days keep hiding a mission that has since failed
test_every_row_links_somewhere_the_server_actually_serves link every row to a 404
test_a_stranger_cannot_rank_himself_first_by_typing_urgent let anyone who can reach the mailbox head somebody's morning
test_a_send_that_failed_or_was_never_confirmed_is_never_quiet leave an unknown send — which is never retried — unmentioned
test_provider_acceptance_is_not_delivery report a reply the transport merely accepted as delivered
test_a_reply_waiting_to_be_sent_outranks_the_message_it_answers show the same exchange twice, inbound row and outbound row
test_an_unreadable_connection_is_partial_coverage_not_a_clear_day read one broken connection as an empty inbox
test_a_mailbox_bigger_than_one_brief_says_so_instead_of_reading_clear call a mailbox clear after looking at the newest 60 rows
test_nothing_from_inside_a_message_reaches_the_brief copy a body, an address or an attachment name into a mailed digest
test_chinese_translates_our_words_and_leaves_the_readers_own_alone print a Chinese brief with "Coming up soon." in it
test_the_email_names_the_clock_and_keeps_our_ids_out_of_sight mail bare times with no zone, and an internal id in the subject
test_messages_are_read_from_the_store_and_the_transport_is_never_touched open a mailbox because somebody opened the brief