Skip to content

v0.10.0 — Mail complete

Choose a tag to compare

@elfensky elfensky released this 20 Aug 19:01
· 20 commits to develop since this release

v0.10.0 — Mail complete

The whole mail arc since 0.9.0: every planned Mail capability shipped, hardened on
device, and the #119/#140 release gate closed. 75 commits.

Mail — new capabilities

  • Recoverable destructive plane (#159): move_mail, trash_mail, create_mailbox,
    update_mail_status — every destructive batch backs up message bytes + source mailbox
    first and returns a receipt; mail_undo replays it. Soft delete is the only delete
    (Mail scripting cannot permanently erase — documented, not worked around).
  • Outbound lifecycle (#157): send_mail (new message or approved-draft send),
    reply_all, forward_mail — all dry-run-by-default, gated behind
    MACOS_APPS_ALLOW_SEND; drafts plane (create_draft, mail_reply, drafts,
    delete_draft).
  • Reads that answer completely (#155/#156, breaking): every read returns the
    addressing triple (id + folder + account); ids resolve on their own months later.
  • Bulk + body reads: mail_bodies (batch), mail_thread(snippets=), body FTS via
    mail_index_bodies.partial.emlx bodies included (#119: a partial is missing
    attachments, not text; 99.47% of bodies are local).
  • Attachments (#81): mail_attachments, save_mail_attachment — hostile-name-safe,
    size-capped, never overwrites.
  • Stats & hygiene: mail_overview, mail_stats, mail_duplicates report;
    export_mail (.eml, lossless-or-labeled); cross-account dedupe CLI gated on body
    identity, not byte size (#153).
  • Triage: mail_needs_response / mail_awaiting_reply — real In-Reply-To/References
    threading; scans now get their declared 120s budget (#188).

Runtime & operations

  • Wedged-vs-busy classification on the Mail timeout path (#183) — a permanent event-
    queue wedge is distinguished from a benign resync, with the right remediation named.
  • doctor().build (#143): build stamp baked by build_app.sh; a same-version
    rebuild is now provable. Deploy proof = doctor().version + doctor().build.
  • Shim↔daemon transport contract (#170): no read deadline on the UDS hop — a bulk
    Mail pass may run hours; a dead stream answers loudly instead of hanging.
  • The daemon registers the outbound tier from argv role detection (#166) —
    allow-send works under launchd.

Fixed

  • #188 triage scans died at the 30s host cap while their scripts budget 120s
  • #170 the shim silently killed any destructive Mail call over ~5s
  • #174 _MOVE re-checks before accusing; #171 local:// source refused at the boundary
  • #146 any mailbox reachable, not just inbox; #144 one mailbox vocabulary
  • AppleScript missing value blanked across all adapters

Declined / closed by evidence (device-verified, documented in

docs/mail-applescript-facts.md)

  • #84 Send Later: no scripting surface exists — not shippable under that name
  • #167 nothing scriptable converts a .partial.emlx; #119's premise was wrong
  • #164 dropped deletes are a sick-Mail symptom; restart, don't retry-loop

Known degradation

  • mail_awaiting_reply can exceed its (raised) 600s budget on large stores — the
    unified All-Sent scan is high-variance O(store) (#192, open). It fails loud,
    classified, and bounded; the fix direction is moving the scan onto the Envelope
    Index. mail_needs_response is unaffected (~34s). The send tools' id-resolve is
    fast with a concrete folder token; a canonical name ("inbox") can hit the same
    slow path on large stores.

Dependencies

  • cryptography 50.0.0 + mcp 1.29.0 (clears both high security alerts), fastmcp 3.4.7,
    full lock refresh; CI actions off deprecated Node 20 runners (#112).