Skip to content

Allow to/add-to overlap, one response code per recipient entry - #41

Merged
markmnl merged 3 commits into
mainfrom
fix/allow-to-add-to-overlap
Aug 25, 2026
Merged

Allow to/add-to overlap, one response code per recipient entry#41
markmnl merged 3 commits into
mainfrom
fix/allow-to-add-to-overlap

Conversation

@markmnl

@markmnl markmnl commented Aug 25, 2026

Copy link
Copy Markdown
Owner

Follows the ruling in markmnl/fmsg#29: an address MAY appear in both to and add to, re-serving an original recipient who lost the message.

Recipients are not a set. Addresses need only be distinct within to and within add to; an address in both lists is a recipient of each and receives one response code per entry — one for its to entry, one for its add to entry. That is what fmsgd already does, so the wire behaviour is unchanged and no deduplication is involved.

Changes

  • readAddToRecipients no longer rejects an add to address that is also in to with code 1. Duplicates within add to are still rejected (TestReadAddToRecipientsRejectsDuplicateAddTo still covers this).
  • Classification keys off wire position. localRecipients now also reports numLocalTo, the count of entries drawn from to; entries at or after that index came from add to. Previously an overlapping address was classified exclusively as add-to via a set lookup, which would have dropped its msg_to record. Each entry is now recorded against the list it came from, and the msg_to insert's ON CONFLICT ... DO NOTHING preserves its original response code, as SPEC §3's closing NOTE requires.
  • Dead plumbing removed. The overlap check was the only consumer of the to key set, so readToRecipients no longer returns it. Tests updated accordingly.

go build, go vet and go test ./... pass.

Note on behaviour

This makes fmsgd accept such a message instead of rejecting it. For a recipient that still holds the message fmsgd answers 103 (user duplicate), which is conformant — SPEC §3 step 4.1.2 permits 103 or 105. Actually re-serving a recipient whose copy is gone is a host policy decision and is unchanged here.

Merge notes

🤖 Generated with Claude Code

Follows the revised ruling in markmnl/fmsg#29: an address MAY appear in
both _to_ and _add to_, re-serving an original recipient who lost the
message. What made the overlap ambiguous was not the overlap itself but
the per-recipient iteration, which walked occurrences while Terms
defines _recipients_ as a set. The spec now iterates distinct addresses;
this brings fmsgd in line on both sides of the wire.

- readAddToRecipients no longer rejects an add-to address present in
  _to_ with code 1. Duplicates *within* _add to_ are still rejected.
- localRecipients returns one entry per distinct address, in the order
  it first appears scanning _to_ then _add to_. This is what sizes the
  per-recipient code stream on the receive side.
- The sender's domainRecips is deduplicated identically. Without this it
  would read one byte too many for an overlapping recipient and desync
  the stream — the exact failure the prohibition existed to prevent.
- An accepted overlapping address is now recorded against both _to_ and
  the batch, instead of being classified exclusively as add-to. The
  msg_to insert's ON CONFLICT DO NOTHING preserves its original response
  code, as SPEC §3's closing NOTE requires.

Note this makes fmsgd accept such a message rather than reject it; for a
recipient that still holds the message fmsgd answers 103 (user
duplicate), which is conformant. Actually re-serving a recipient whose
copy is gone is a host policy decision, unchanged here.
Follows the revised ruling in markmnl/fmsg#29. Recipients are no longer
treated as a set: addresses need only be distinct within _to_ and within
_add to_, and an address in both lists is a recipient of each, answered
once for its _to_ entry and once for its _add to_ entry.

That is what fmsgd already did, so localRecipients and the sender's
domainRecips go back to plain wire order and the earlier deduplication
here is dropped. What remains is accepting the overlap at all:

- readAddToRecipients no longer rejects an add-to address present in
  _to_ with code 1. Duplicates within _add to_ are still rejected.
- The accepted-recipient classification keys off wire position rather
  than set membership: entries before numLocalTo came from _to_, the
  rest from _add to_. Previously an overlapping address was classified
  exclusively as add-to, losing its _to_ record; now each entry is
  recorded against the list it came from, and the msg_to insert's
  ON CONFLICT DO NOTHING preserves its original response code as
  SPEC §3's closing NOTE requires.
- With the overlap check gone, readAddToRecipients no longer needs the
  _to_ key set, so readToRecipients stops returning it. Tests updated.
@markmnl markmnl changed the title Allow to/add-to overlap, treat recipients as a set Allow to/add-to overlap, one response code per recipient entry Aug 25, 2026
@markmnl
markmnl merged commit 8c1dcf9 into main Aug 25, 2026
1 of 2 checks passed
@markmnl
markmnl deleted the fix/allow-to-add-to-overlap branch August 25, 2026 10:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant