Sprint 03 runtime: Graph connect, workers, initial sync
Duckbill can authorize a Microsoft mailbox, run restartable initial sync against the provider port (mock or Graph), and process background work with leases, retry, DLQ, and pause switches.
Graph connect
GET /api/providers/microsoft/startissues a PKCE authorize URL. The JSON body contains onlyauthorizationUrl.GET /api/providers/microsoft/callbackexchanges the code, upsertsConnectedAccount, and stores encrypted tokens. The response is account health, never tokens.POST /api/providers/microsoft/revokedeletes ciphertext and setsauthorization_status = AUTH_REQUIRED.- Refresh is single-flight per account.
AUTHORIZATIONerrors stop retry and markAUTH_REQUIRED.
Initial sync
runInitialSyncPage enumerates folders, pages messages, upserts MailMessage / MessageInstance (unique on account + provider message id), writes an outbox event, and enqueues independent FETCH_BODY and CLASSIFY work items. AI enqueue failure cannot prevent the upsert. Classification UNPROCESSED is valid. initial_sync_status stays awaiting_reconciliation until an explicit reconciliation marks healthy.
Workers
Leased sync_work_items plus transactional outbox (ADR 0010). Transient errors back off. Authorization and exhausted attempts go to dead_letter_items. DLQ replay is explicit and audited. Poison isolation is per message id so siblings continue.
Pause and circuit breaker
automation_pauses scopes: GLOBAL, MAILBOX, ACTION_TYPE, AI. Global and mailbox pauses block COMMAND work (provider mutations). Sync pages still run. The ai circuit breaker opens on an error budget and skips only CLASSIFY.
