9191_GROK_OAUTH_RECOVERY_STALE_MINUTES = 24 * 60
9292_GROK_PERMISSION_RETRY_DELAYS_SECONDS = (60 , 120 , 300 )
9393_GROK_PERMISSION_RETRY_BATCH_SIZE = 3
94+ _XAI_CLI_REAUTHORIZATION_ERROR = "xAI CLI OAuth account needs reauthorization"
9495_GROK_PENDING_STATUSES = {
9596 "submitting" ,
9697 "pending_submit" ,
@@ -314,6 +315,22 @@ def _grok_oauth_probe_recoverable(value: object) -> bool:
314315 )
315316
316317
318+ def _grok_oauth_permission_pending (value : object ) -> bool :
319+ probe = value if isinstance (value , dict ) else {}
320+ code = _clean_text (probe .get ("code" )).lower ()
321+ return code == "permission-denied" or (
322+ code == "personal-team-blocked" or code .startswith ("personal-team-blocked:" )
323+ )
324+
325+
326+ def _grok_oauth_reauthorization_required (value : object ) -> bool :
327+ item = value if isinstance (value , dict ) else {}
328+ return (
329+ _clean_text (item .get ("last_error" )) == _XAI_CLI_REAUTHORIZATION_ERROR
330+ or _grok_oauth_probe_recoverable (item .get ("probe" ))
331+ )
332+
333+
317334def _grok_oauth_authorizable (item : object ) -> bool :
318335 """Return whether an SSO registration record is ready for OAuth."""
319336 if not isinstance (item , dict ):
@@ -2283,8 +2300,7 @@ def _recover_grok_oauth_account(
22832300 oauth_account_id = _clean_text (oauth_item .get ("id" ))
22842301 if not oauth_account_id or _clean_text (oauth_item .get ("status" )).lower () == "disabled" :
22852302 return {"status" : "deferred" }
2286- probe = oauth_item .get ("probe" ) if isinstance (oauth_item .get ("probe" ), dict ) else {}
2287- if not _grok_oauth_probe_recoverable (probe ):
2303+ if not _grok_oauth_reauthorization_required (oauth_item ):
22882304 return {"status" : "deferred" }
22892305
22902306 now = datetime .now (timezone .utc )
@@ -2387,7 +2403,7 @@ def _grok_oauth_has_inflight_recovery() -> bool:
23872403 return False
23882404 return any (
23892405 _clean_text (item .get ("status" )).lower () != "disabled"
2390- and _grok_oauth_probe_recoverable (item . get ( "probe" ) )
2406+ and _grok_oauth_reauthorization_required (item )
23912407 and _clean_text (
23922408 item .get ("recovery" , {}).get ("status" ) if isinstance (item .get ("recovery" ), dict ) else ""
23932409 ).lower ()
@@ -2405,7 +2421,7 @@ def _grok_oauth_has_due_invalid_recovery() -> bool:
24052421 now = datetime .now (timezone .utc )
24062422 return any (
24072423 _clean_text (item .get ("status" )).lower () != "disabled"
2408- and _grok_oauth_probe_recoverable (item . get ( "probe" ) )
2424+ and _grok_oauth_reauthorization_required (item )
24092425 and RegisterService ._grok_oauth_recovery_due (item , now = now )
24102426 for item in items
24112427 if isinstance (item , dict )
@@ -2660,7 +2676,7 @@ def _run_grok_permission_retry_once(
26602676 if not isinstance (item , dict ) or _clean_text (item .get ("status" )).lower () == "disabled" :
26612677 continue
26622678 probe = item .get ("probe" ) if isinstance (item .get ("probe" ), dict ) else {}
2663- if _clean_text (probe . get ( "code" )). lower () != "permission-denied" :
2679+ if not _grok_oauth_permission_pending (probe ) :
26642680 continue
26652681 probed_at = _parse_datetime (probe .get ("at" ))
26662682 retry_delay = _grok_permission_retry_delay_seconds (item )
@@ -2696,7 +2712,7 @@ def _run_grok_permission_retry_once(
26962712 1 for item in results if _clean_text (item .get ("status" )).lower () == "valid"
26972713 )
26982714 summary ["pending" ] = sum (
2699- 1 for item in results if _clean_text (item . get ( "code" )). lower () == "permission-denied"
2715+ 1 for item in results if _grok_oauth_permission_pending (item )
27002716 )
27012717 summary ["failed" ] = max (0 , summary ["tested" ] - summary ["valid" ] - summary ["pending" ])
27022718 selected_by_id = {_clean_text (item .get ("id" )): item for item in selected }
@@ -2709,7 +2725,7 @@ def _run_grok_permission_retry_once(
27092725 metadata = source .get ("metadata" ) if isinstance (source .get ("metadata" ), dict ) else {}
27102726 retry = metadata .get ("permission_retry" ) if isinstance (metadata .get ("permission_retry" ), dict ) else {}
27112727 status = _clean_text (result .get ("status" )).lower ()
2712- pending = _clean_text (result . get ( "code" )). lower () == "permission-denied"
2728+ pending = _grok_oauth_permission_pending (result )
27132729 attempts = max (0 , _safe_int (retry .get ("attempts" ))) + (1 if pending else 0 )
27142730 next_delay = (
27152731 _GROK_PERMISSION_RETRY_DELAYS_SECONDS [
@@ -2779,7 +2795,7 @@ def _run_grok_oauth_recovery_sweep(
27792795 item
27802796 for item in oauth_items
27812797 if _clean_text (item .get ("status" )).lower () != "disabled"
2782- and _grok_oauth_probe_recoverable (item . get ( "probe" ) )
2798+ and _grok_oauth_reauthorization_required (item )
27832799 ]
27842800 candidates .sort (
27852801 key = lambda item : 0
0 commit comments