feat(sync): reconcile secondary Graph calendars

Read documented Graph v1 calendarView pages for secondary calendars and publish each finite window only after the complete bounded listing validates.

Add schema-v2 per-window event membership so moved-out occurrences are evicted without being mislabeled as remote tombstones, while overlapping windows retain shared instances.

Verified: 18/18 fresh normal, 18/18 -Werror, and 18/18 ASan/UBSan tests.
This commit is contained in:
2026-07-18 13:05:21 +01:00
parent 0582444c61
commit 98e07e287e
11 changed files with 1520 additions and 60 deletions

View File

@@ -133,8 +133,9 @@ The Microsoft sign-in design treats Nocal as a public desktop client: sign-in
will open the system browser, use the authorization-code flow with PKCE `S256`,
and return through a loopback redirect. Its application registration must be
multitenant for the intended organizational and personal Microsoft account
audience. Initial synchronization requests only delegated `Calendars.Read`, not
write access. Users can normally consent to that delegated permission, but
audience. Initial synchronization requests delegated `User.Read` and
`Calendars.Read`, not write access. Users can normally consent to those
delegated permissions, but
their organization's tenant policy may still require administrator consent or
deny the application. Nocal never embeds a client secret in its open-source
desktop binary.
@@ -183,21 +184,21 @@ calendar a deterministic local ID. Event reads request immutable Graph IDs and
use strict bounded parsing with credential-safe failures. Requests and opaque
next/delta links are restricted to HTTPS `graph.microsoft.com` URLs.
Event windows are half-open UTC intervals. Each event page, its deletions, and
its continuation cursor cross the cache boundary in one transaction. A partial
round can resume from its durable cursor, and deletion tombstones remain
explicit instead of silently dropping remote state.
Event windows are half-open UTC intervals. Primary-calendar delta pages cross
the cache boundary with their deletions and continuation cursor in one
transaction, so a partial round resumes safely and tombstones remain explicit.
The stable Graph v1.0 `calendarView` delta API is documented only for the
primary calendar. This slice discovers all calendars but delta-syncs only the
primary; it uses neither beta nor undocumented per-calendar routes. Secondary
calendar support requires a deliberate choice between v1 full-window
reconciliation with defined deletion semantics and beta-specific delta. Nocal
does not yet claim Outlook-equivalent coverage.
Stable-v1 secondary-calendar reconciliation reads every page of a complete
per-calendar view before publishing the window. Durable per-window membership
distinguishes an event that moved outside the range from an event Graph actually
deleted: an omitted event loses its cached instance only when no other complete
window references it, while its raw event record remains live. This avoids beta
and undocumented delta routes, but a secondary window requires a complete
refetch on every refresh.
There is still no account UI/CLI orchestration or live Microsoft credential
integration, and remote writes remain out of scope. Account setup/orchestration
and the secondary-calendar reconciliation decision are the next product phase.
is the next product phase.
## Local file interchange