Uh oh!
There was an error while loading. Please reload this page.
Own the attendee-response fold sequence in a shared helper - #372
Merged
Conversation
The library exported the predicates for folding an attendee's response onto its event's thread but stopped short of the sequence around them, so each mail connector restated the same ~40 lines: build the marker key, read it, check for a repeat, decide whether the response earns a note, compose it, save it, record it. The order is load-bearing and none of it was enforced — checking the repeat second re-emits a re-delivered commented acceptance, and writing the marker on the suppressed path leaves it describing something the event thread does not carry. Both mistakes surface the same way: a thread people had already read goes unread again. `foldRsvp()` owns that order. Genuinely per-connector concerns stay injected, because they differ for real reasons: reading and writing the marker (write through immediately, or collect and flush once per pass to stay inside the request budget), saving the note, and the note's key, timestamp and unread flag. Every outcome — emitted, suppressed, already folded — means the response was dealt with, so each caller records "this message was folded" unconditionally after the call, in whatever form is its own: an in-pass set, durable per-thread metadata, or both. The returned outcome names which path ran. Gmail, Outlook and iCloud mail now call it. No behaviour change: their test suites pass unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GcnBUEdW86ovpv1pT2d3b3
Uh oh!
There was an error while loading. Please reload this page.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
@plotday/rsvp-foldexported the predicates for folding an attendee's response onto its event's thread, but stopped short of the sequence around them. Each mail connector restated the same ~40 lines: build the marker key, read it, check for a repeat, decide whether the response earns a note, compose it, save it, record it.That order is load-bearing and nothing enforced it. Checking the repeat second re-emits a re-delivered commented acceptance; writing the marker on the suppressed path leaves it describing something the event thread does not carry. Both mistakes surface identically — a thread people had already read goes unread again.
Three copies of a rule is also three chances to diverge, and one of them did.
What moves
foldRsvp()owns the sequence. What stays injected is what genuinely differs between connectors: how the marker is read and written, how the note is saved, and the note's key, timestamp and unread flag.Every outcome — emitted, suppressed, already folded — means the response was dealt with, so each caller records "this message was folded" unconditionally after the call, in whatever form suits it: an in-pass set, durable per-thread metadata, or both.
The marker-write contract
Injecting the write is what lets a connector batch markers into one flush per pass to stay inside its request budget, and the contract now spells out both requirements that come with doing so — because missing either one re-emits notes:
That second requirement was previously knowledge held inside one connector's implementation rather than in the contract.
No behaviour change
Gmail, Outlook and iCloud mail all call it, and no connector test was edited — 361, 143 and 486 tests respectively pass against the refactored code unchanged, plus 44 in the library (11 new, covering all four paths and that the marker is written on exactly the emitting path). Net 264 lines removed from the connectors.
🤖 Generated with Claude Code
https://claude.ai/code/session_01GcnBUEdW86ovpv1pT2d3b3