8b1cdafd019d4adcad11a6712f48549b0460f1fa
lrnassar
  Tue Jul 14 10:31:16 2026 -0700
Fix codeReviewAi.py false auth-failure on reviews that quote error strings. refs #36890

detect_cli_failure scanned the whole CLI response for auth-error markers before
validating, so a well-formed review whose text legitimately quotes strings like
"authentication_error" or "API Error: 401" (e.g. a review of the auth-handling
code itself) was misflagged as a Claude CLI authentication failure - skipping
the author email and firing a spurious alert. Validate the response first and
only scan for auth markers when it is not a valid review.

diff --git src/utils/codeReviewAi.py src/utils/codeReviewAi.py
index e8acc71abad..9a0dadd1d72 100755
--- src/utils/codeReviewAi.py
+++ src/utils/codeReviewAi.py
@@ -497,38 +497,42 @@
 # failed to produce a usable review. Used to alert instead of failing silently.
 CLI_AUTH_ERROR_MARKERS = (
     'Failed to authenticate',
     'authentication_error',
     'Invalid authentication credentials',
     'API Error: 401',
 )
 
 def detect_cli_failure(response, validator):
     """Return an error description if the CLI response indicates a hard failure
     (no output, an authentication error, or output that fails validation),
     otherwise return None. Lets the caller alert rather than silently save a
     broken review."""
     if not response:
         return "No response from Claude CLI (timeout, crash, or empty output)"
+    # A well-formed review is a success even when its text quotes auth-error
+    # strings - e.g. a review of the auth-handling code itself. Only scan for
+    # auth markers when the output is NOT a valid review, so such reviews are
+    # not misflagged as authentication failures.
+    is_valid, msg = validator(response)
+    if is_valid:
+        return None
     for marker in CLI_AUTH_ERROR_MARKERS:
         if marker in response:
             first_line = next((l for l in response.strip().splitlines() if l.strip()), response)
             return f"Claude CLI authentication failure: {first_line.strip()[:300]}"
-    is_valid, msg = validator(response)
-    if not is_valid:
     return f"Invalid or incomplete review output: {msg}"
-    return None
 
 def call_claude_cli(prompt, timeout=600, retries=1, validator=None):
     """Call Claude Code CLI with a prompt and return the response"""
     if validator is None:
         validator = validate_review_output
     for attempt in range(retries + 1):
         try:
             result = subprocess.run(
                 [CLAUDE_CLI, '-p', prompt, '--output-format', 'text',
                  '--allowedTools', 'Bash,Read,Glob,Grep,Agent'],
                 capture_output=True,
                 text=True,
                 timeout=timeout
             )