fix(calendar): make OAuth failures loud and diagnosable; document permanent fix - #130
Merged
Conversation
…manent fix The calendar integration has died recurrently with invalid_grant because the OAuth consent screen is in Testing status (Google expires refresh tokens after 7 days). The code compounded this by degrading silently: a bare logger.warning, no user-visible alert, no health probe, and a bare RuntimeError from google-auth. Per spec_v3.md §3.2.2 (calendar direct API) and the no-silent-fallbacks convention: - GoogleCalendarClient.authenticate() now raises a typed CalendarAuthError (reason=refresh_rejected | token_missing_headless) with remediation steps in the message, instead of leaking google.auth RefreshError. - _try_build_calendar_client logs event_type="fallback_activated" on every degraded path and accepts an on_unavailable callback; cli.py wires it to NotificationService.dispatch_fallback_alert so a dead calendar posts to Discord instead of only Loki. - SelfDiagnostic gains a calendar-token check that live-probes the refresh token at boot and via `donna health`, reporting invalid_grant with the fix. - New runbook docs/operations/calendar-oauth.md: root cause (Testing-status 7-day expiry), one-time Console fix (publish to Production), relink steps. - Followups: Gmail needs the same alert/probe parity; spec §3.2.2 should absorb the failure/alerting contract. The permanent fix requires one operator action documented in the runbook: publish the OAuth app to Production, then relink once. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K7Ppai9Xbhv5iEuGBwi3ty
- conftest calendar-client stub accepts the new on_unavailable kwarg. - cli.py guards the Optional notification_service in the unavailable callback (factory already logged fallback_activated). - Drop an unused type-ignore in the health-check token probe. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K7Ppai9Xbhv5iEuGBwi3ty
nfeuer
pushed a commit
that referenced
this pull request
Jul 10, 2026
Resolve conflict in docs/superpowers/specs/followups.md by keeping both the calendar-OAuth (PR #130, now on main) and output-standard follow-up entries. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0163xNY4AKcd3pHF8CYVGPH5
nfeuer
pushed a commit
that referenced
this pull request
Jul 10, 2026
Resolve conflict in docs/superpowers/specs/followups.md by keeping both the calendar-OAuth (PR #130, now on main) and local-LLM-reliability follow-up entries. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0163xNY4AKcd3pHF8CYVGPH5
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 free
to 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.
Problem
Google Calendar has died recurrently with
invalid_grant(currently dead since 2026-06-24; token last refreshed 2026-06-07). Root cause: the OAuth consent screen is in Testing publishing status, so Google expires refresh tokens 7 days after issuance. The code made it worse by degrading silently —logger.warningonly, no alert, no health probe (violates the no-silent-fallbacks convention).Changes (spec_v3.md §3.2.2, §12.1)
GoogleCalendarClient.authenticate()raises typedCalendarAuthError(reason=refresh_rejected|token_missing_headless) with remediation in the message._try_build_calendar_clientlogsevent_type="fallback_activated"on every degraded path and takes anon_unavailablecallback;cli.pywires it todispatch_fallback_alert→ dead calendar now posts to Discord.SelfDiagnosticgains a calendar-token live probe (boot +donna health).docs/operations/calendar-oauth.md: root cause, one-time Console fix (publish app to Production), relink steps.Operator action required (the actual permanent fix)
Publish the OAuth app to Production in Google Cloud Console, then relink once — see the runbook. Until then the token dies weekly.
Testing
tests/unit/test_self_diagnostic_calendar.py(4 tests),TestAuthenticateRefreshRejectedintest_calendar_client.py.🤖 Generated with Claude Code
https://claude.ai/code/session_01K7Ppai9Xbhv5iEuGBwi3ty