# Google Workspace Auth Health

## Problem

Google sign-in happens outside the CTM browser tab. After OAuth completes, the
setup page can still show an old "Google account needs reconnection" banner if
the page does not refresh its Wall-E credential state. The browser's Google
login state is not a valid source of truth for CTM; Wall-E must verify the
stored `gws` credentials and then update both setup UI and service alerts from
that verified state.

## Source Of Truth

`/api/wall-e/gws/accounts` is the authoritative health endpoint for connected
Google accounts. It derives each account state by asking the bundled
`gws-workspace` setup module for usable credentials:

- `tokenValid: true` means Wall-E has a usable access token for that account.
- `reauthRequired: true` means the saved refresh credential is missing, expired,
  or revoked.
- `authIssue` is a user-facing explanation of the credential problem.

The setup page must render the reconnection banner only from this endpoint. It
must not infer success from a browser Google cookie or from returning to the CTM
tab after OAuth.

## Alert Reconciliation

Service alerts are persisted in Wall-E's `service_alerts` KV entry and surfaced
on the Wall-E panel and session pages. Google Workspace account alerts use this
stable service key:

```text
google_workspace:<profile-id-or-default>:<lowercase-email>
```

Whenever Wall-E proves an account is usable, it should clear only resolved
Google Workspace auth alerts for that same account. This mirrors the existing
Slack health model while keeping unrelated alerts, disabled-skill alerts, and
other providers intact.

Reconciliation happens at two boundaries:

1. OAuth completion: `completeGoogleAuthFlow()` only completes after
   `gwsSetup.getCredentials()` returns a usable access token, then clears the
   account's stale `gws_reauth` alert.
2. Health reads: `/api/wall-e/gws/accounts` opportunistically clears stale
   auth alerts for every account it reports as usable, so any setup page refresh
   self-heals old alert state.

## Browser Refresh Contract

Setup should refresh connected services when the user returns from an external
OAuth window:

- `pageshow`
- `focus`
- visible `visibilitychange`
- `online`

These events only trigger a small debounced `/api/wall-e/gws/accounts` refresh.
The page still uses explicit OAuth flow polling while CTM owns the flow, but it
does not rely on blind background polling to repair stale UI.

The endpoint and browser fetch should use no-store/no-cache semantics because
credential health is live operational state, not a static catalog.

## Tests

Coverage should prove:

- Google auth completion clears stale account-specific `gws_reauth` alerts only
  after credentials are usable.
- Google alert clearing does not remove unrelated Google, Slack, or disabled
  skill alerts.
- The setup page removes the reconnection banner when a foreground lifecycle
  refresh sees the account become healthy.
