Skip to content

Bound the Google Calendar initial backfill to a year and a day - #369

Merged
KrisBraun merged 4 commits into
mainfrom
recency-first-calendar-google
Aug 3, 2026
Merged

Bound the Google Calendar initial backfill to a year and a day#369
KrisBraun merged 4 commits into
mainfrom
recency-first-calendar-google

Conversation

@KrisBraun

Copy link
Copy Markdown
Contributor

Two changes to the Google Calendar connector's initial sync, one behavioural and one a
correction to a comment that was actively misleading.

Bound the initial backfill to a year and a day

calendarHistoryFloor() returned Jan 1 of two calendar years ago — between 366 and 730 days
back depending on when in the year a connection was made. It now returns a fixed 366 days,
extracted as CALENDAR_HISTORY_DAYS.

A year and a day is chosen deliberately: it is the smallest window that always contains an
annual event, so yearly birthdays and anniversaries stay in scope.

This should not change what a user ends up with. The platform already drops initial-sync
non-recurring items that fall outside the connection's history window, and that window is at
most a year — so the connector was fetching and transmitting events the platform then
discarded. Recurring events are exempt from that filter and are unaffected, for the reason
described below. The practical effect is a shorter backfill: the full pass walks roughly a
third as much history on a connection made late in the calendar year.

Incidentally, the new implementation is also DST-safe. The previous one used
setFullYear/setMonth/setHours, which operate in local machine time; the replacement is
epoch-millisecond arithmetic.

Correct what the quick pass actually returns

The comment on SyncState.phase claimed the quick pass (timeMin = now) front-loads only
non-recurring events, and that the full pass is what "picks up long-running recurring
masters excluded by the quick pass's timeMin".

That is wrong, and it matters — it invites the conclusion that recurring meetings do not
appear until a multi-year history walk completes.

Tested against the Calendar API, timeMin does not filter recurring masters at all. A
FREQ=YEARLY master whose first instance was in 1980, and a FREQ=WEEKLY master whose
RRULEUNTIL had already passed, were both returned by a timeMin=now listing with
singleEvents unset. Only non-recurring events are bounded by timeMin.

So the quick pass already surfaces upcoming recurring meetings, and the full pass exists to
import past one-off events and to establish the nextSyncToken that incremental syncs reuse.
The comment now says this, with the evidence.

It also carries an explicit warning not to generalise the behaviour to Outlook: Microsoft
Graph's $filter=start/dateTime ge … is a literal comparison against the series master's own
first start, which genuinely does exclude a long-running master. The two providers differ, and
the Outlook connector's equivalent comment is left as it was.

Testing

pnpm build and the full connector suite (20 files, 378 tests) pass. Two new tests pin the
366-day value exactly and confirm an event dated one year ago stays inside the window.

Moves mapWithConcurrency out of the Gmail mail module into a new
connectors/google/src/concurrency.ts, re-exported from gmail-api.ts for
existing callers. This lets other product modules within the Google
connector (e.g. calendar) reuse the same bounded-concurrency helper
without importing from the mail module.
The comment on SyncState.phase claimed the quick pass front-loads only
non-recurring events and that the full pass is what picks up long-running
recurring masters "excluded by the quick pass's timeMin".
That is wrong. Google does not apply timeMin to recurring masters: verified
against a live calendar, a FREQ=YEARLY master whose first instance was in 1980
and a FREQ=WEEKLY master whose RRULE UNTIL had already passed were both
returned by a timeMin=now listing. Only non-recurring events are bounded by
timeMin, so the quick pass already surfaces upcoming recurring meetings and
the full pass exists for past one-off events and the nextSyncToken.
Also notes that this is Google-specific and must not be generalised to
Microsoft Graph, whose $filter on start/dateTime is a literal comparison
against the series master's own first start.
@KrisBraun
KrisBraun merged commit 392435f into mainAug 3, 2026
1 check passed
@KrisBraun
KrisBraun deleted the recency-first-calendar-google branch August 3, 2026 18:37
Sign up for freeto 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

@KrisBraun