You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(auth): force re-login on dead refresh token + enrich Sentry auth telemetry (#864)
WIZARD-CLI-F auth failures fire 3-10 min into runs across many wizard
versions — not long-run token expiry, so PR #862's mid-run refresh didn't
help. Root cause: an llm-gateway 401 whose stored refresh token is ALSO dead
(`invalid_grant`) was routed to "just re-run", which silently re-mints the
same rejected token and loops on the identical failure.
Recovery:
- token-refresh: `isDeadRefreshToken()` classifies 400 invalid_grant / 401 as
unrecoverable (NOT 5xx / network) and flags reauth-required
- agent-runner: the AUTH_ERROR outro now clears the stored OAuth session and
sets promptLogin when reauth is required, so the next run forces a clean
browser login instead of looping; new copy steers the user to log in again
- docs/flows.md: Outro flow documents recoverable vs re-login-required
Observability:
- scrubber-safe Sentry tags (failure_surface, recovery, run_elapsed_bucket),
readable/filterable where `auth subkind` is [Filtered]
- fingerprint split by failure_surface so gateway vs mcp auth failures become
separate issues / alerts instead of one undifferentiated group
- breadcrumbs at the three auth-detection points
Refs BA-239
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
| Auth | Back → SignupFullName / ToS / SignupEmail (whichever has the most recent meaningful revert on the create-account path), else RegionSelect |
26
-
| SignupFullName | Back → SignupEmail (clears email + ceremony state via `setSignupEmail(null)`'s bound reset, so the next pass re-probes from scratch) |
27
-
| ToS | Back → SignupEmail (clears email + ceremony state — same reason as SignupFullName) |
28
-
| SigningUp | Transparent (`revert: () => false`) — back-walk skips this entry; no clean undo for an in-flight network call |
29
-
| SignupEmail | Back → RegionSelect (clears captured email *and*`signupRequiredFields` / `signupAuth` / `signupAbandoned` via `setSignupEmail(null)`) |
30
-
| DataSetup | Back → Auth (clears org/project selection) |
31
-
| ActivationOptions | Back → DataSetup (re-runs activation check) |
32
-
| Setup | Pops one answered question; if none, walks back further |
33
-
| Slack | Back → DataIngestionCheck or Mcp |
34
-
| DataIngestionCheck | Back → Mcp; **Enter** or **q** skip verification (with confirm if no events yet); **x** exits to resume later |
35
-
| CreateProject | Cancel (existing) — also functions as back to Auth |
36
-
| FeatureOptIn | Skip (confirms with no features selected — Esc=skip is the |
37
-
|| one screen that breaks the convention; hint bar makes it |
38
-
|| explicit) |
39
-
| Intro | Cancel wizard (existing) |
40
-
| Outro | Close report dialog (existing) |
41
-
| RegionSelect / Mcp | No-op (no revertible step before them) |
| Auth | Back → SignupFullName / ToS / SignupEmail (whichever has the most recent meaningful revert on the create-account path), else RegionSelect |
27
+
| SignupFullName | Back → SignupEmail (clears email + ceremony state via `setSignupEmail(null)`'s bound reset, so the next pass re-probes from scratch)|
28
+
| ToS | Back → SignupEmail (clears email + ceremony state — same reason as SignupFullName)|
29
+
| SigningUp | Transparent (`revert: () => false`) — back-walk skips this entry; no clean undo for an in-flight network call|
30
+
| SignupEmail | Back → RegionSelect (clears captured email _and_`signupRequiredFields` / `signupAuth` / `signupAbandoned` via `setSignupEmail(null)`)|
31
+
| DataSetup | Back → Auth (clears org/project selection)|
32
+
| ActivationOptions | Back → DataSetup (re-runs activation check)|
33
+
| Setup | Pops one answered question; if none, walks back further|
34
+
| Slack | Back → DataIngestionCheck or Mcp|
35
+
| DataIngestionCheck | Back → Mcp; **Enter** or **q** skip verification (with confirm if no events yet); **x** exits to resume later|
36
+
| CreateProject | Cancel (existing) — also functions as back to Auth|
37
+
| FeatureOptIn | Skip (confirms with no features selected — Esc=skip is the|
38
+
|| one screen that breaks the convention; hint bar makes it|
39
+
|| explicit)|
40
+
| Intro | Cancel wizard (existing)|
41
+
| Outro | Close report dialog (existing)|
42
+
| RegionSelect / Mcp | No-op (no revertible step before them)|
42
43
43
44
### Signup ceremony invariants
44
45
45
-
-`setSignupEmail(null)` clears **all** ceremony state (`signupRequiredFields`, `signupAuth`, `signupAbandoned`) so any back-nav path that rewinds to the email step automatically invalidates the prior probe response. The ceremony is a single conceptual unit keyed to the email being present.
46
-
-`SignupFullName.revert` and `ToS.revert` return `false` when the screen was skipped (server never asked, value never set) so the back-walk continues past them rather than firing a no-op revert that traps the user.
47
-
-`SigningUpScreen` is the only signup screen with network I/O. Its `useAsyncEffect` writes one of `signupAuth` (success) / `signupRequiredFields` (needs more info) / `signupAbandoned` (redirect or error). The auth task in `default.ts` waits on this settle before opening browser OAuth (see `isAuthTaskGateReady` in `src/commands/helpers.ts`).
46
+
-`setSignupEmail(null)` clears **all** ceremony state (`signupRequiredFields`,
47
+
`signupAuth`, `signupAbandoned`) so any back-nav path that rewinds to the
48
+
email step automatically invalidates the prior probe response. The ceremony is
49
+
a single conceptual unit keyed to the email being present.
50
+
-`SignupFullName.revert` and `ToS.revert` return `false` when the screen was
51
+
skipped (server never asked, value never set) so the back-walk continues past
52
+
them rather than firing a no-op revert that traps the user.
53
+
-`SigningUpScreen` is the only signup screen with network I/O. Its
54
+
`useAsyncEffect` writes one of `signupAuth` (success) / `signupRequiredFields`
55
+
(needs more info) / `signupAbandoned` (redirect or error). The auth task in
56
+
`default.ts` waits on this settle before opening browser OAuth (see
57
+
`isAuthTaskGateReady` in `src/commands/helpers.ts`).
48
58
49
59
The `[Esc] Back` hint appears in `KeyHintBar` only when back is actually
50
60
available, so it never lies about what the keystroke will do.
@@ -57,20 +67,20 @@ The CLI keeps a persistent prompt open at all times (like Claude). Slash
57
67
commands can be run at any point during the wizard to change settings or trigger
0 commit comments