• v0.29.5 fe79825200

    0.29.5 — one message, one search result
    All checks were successful
    CI / gate (push) Successful in 1m25s
    CI / image (push) Successful in 14s
    Stable

    joeyr released this 2026-08-21 23:57:10 -05:00 | 15 commits to main since this release

    search_messages returned one message once per label it carried. Found by driving the
    deployed connector through an acceptance run — a person asking it twelve questions — rather
    than by any test here.

    Fixed

    • A search that fans out across labels returned duplicates. from:google older_than:6m has:attachment came back as three results that were one message, sitting in INBOX,
      Sent Mail and a user label; a month of attachments came back as 25 rows for 23 messages.
      Gmail files one message under every label it has, and search_messages concatenated the
      per-label hits.

      This is 0.29.2's defect one tool along. That release fixed the aggregate count and did
      not sweep the fan-out — the same overlap, the same wrong number, in the tool next door.

      Results are now collapsed on X-GM-MSGID, Gmail's own per-message id, which is
      identical across every label a message appears under (verified live). The RFC822
      Message-ID header was considered and rejected: it is written by the sender, so it is
      absent on some mail and forgeable on the rest, and a dedup key an attacker can choose is
      one that can hide a message by colliding with another.

      found counts messages too, not rows — otherwise the truncation warning claims more
      matches than exist.

    • The surviving copy is now the useful one. Default searches order labels INBOX first,
      then user labels, then role folders, and keep the first match. Previously the survivor was
      whatever LIST returned first, which could report a message as sent — or as spam —
      because a copy of it was also there. An explicit folders argument keeps the caller's
      order, since they expressed a preference.

    Notes

    • The fake could not express the bug. _FakeIMAP implemented list_folders and
      folder_status and nothing else, so search_messages had never been run end to end in a
      test — only _search_targets was, which checks the folder list and not what comes back
      from it. The fake now holds messages that carry LABELS rather than a location, which is
      the property under test: a fake where every message sits in one folder cannot fail a
      deduplication bug, however many tests are written against it.

    • Mutation-tested, and the first attempt was wrong. Disabling the continue still
      passed, because the dict collapses by key on its own; only giving every row a unique key
      removes deduplication, and that fails all four new tests. A mutation that does not fail is
      a test that does not test.

    • G1's live pass re-run after the change: 52 checks, 0 failed. Required, because the read
      path was touched.

    Downloads