Repository navigation
PR Review Agent — failures detected 2026-08-18 #1526
Description
Convergence latency (deterministic)
Workflow duration across 535 completed run(s) in the window — computed by pr_review_health.sh, not the model.
| Workflow | Runs | min | p50 | p95 | max |
|---|---|---|---|---|---|
pr-review-trigger.yml |
535 | 2s | 32s | 42s | 2m46s |
Run-outcome mix by triggering event
pr-review run conclusions over the window, split by the event that triggered each run — computed deterministically by pr-review-outcomes.sh, not the model. A high cancelled share means runs were evicted while PENDING (concurrency admits one running + one pending per group); a cancelled run is non-blocking but historically rendered as a failing check (#1421).
| Event | success | cancelled | skipped | failure | total | cancel % |
|---|---|---|---|---|---|---|
check_suite |
3 | 0 | 2 | 0 | 6 | 0% |
pull_request |
2 | 0 | 0 | 0 | 2 | 0% |
repository_dispatch |
154 | 2 | 0 | 4 | 161 | 1% |
workflow_dispatch |
334 | 0 | 0 | 34 | 369 | 0% |
| TOTAL | 493 | 2 | 2 | 38 | 538 | 0% |
Sweep hit-rate (deterministic)
How often the pr-review-sweep scheduled backstop actually had to re-review a PR — computed deterministically by pr-review-sweep-metrics.sh, not the model. The scheduled (cron) path re-dispatches only for genuinely un-eventable cases (GitHub-App / cross-repo checks like SonarCloud that emit no workflow_run); the workflow_run fast path handles every eventable case, so a scheduled re-dispatch is always a case the fast path did not cover.
| Metric | Value |
|---|---|
| Scheduled sweep ticks | 36 |
| Ticks that re-dispatched a review (hits) | 31 |
| Sweep hit-rate | 86% |
Interpretation: a low rate confirms the timer stays exception-only (the event fast path is carrying the load); a rising rate is a signal that an eventable case is leaking onto the timer — a hole in the narrowing worth investigating.
PR Review Agent — Health Report
Workflow: pr-review-trigger.yml | Repo: petry-projects/.github-private
Generated: 2026-08-18
1. Executive Summary
Status: DEGRADED
Period: 2026-08-17T15:42Z – 2026-08-18T15:02Z (≈23.3 hours)
Result: 38 of 538 runs failed (7.07%) | 2 cancelled | 493 successful
Key findings:
- Failures are structurally periodic — approximately 1 failure per cluster of ~14 runs, suggesting a consistent per-cycle fault rather than a transient infrastructure blip
- Three anomalous multi-failure bursts at 2026-08-17T15:42Z (#64967, #64969), T16:39Z (#64988, #64989, #64992), and T18:13Z (#65002, #65003) — consecutive or near-consecutive failures in the same minute, implying a shared upstream condition (rate limit, auth expiry, or a concurrent bad push)
- No log content was returned in the "Failed Run Logs" section — root cause classification below is inferred from timing patterns and workflow structure; direct error messages are unavailable
Action required: Retrieve and inspect actual step-level logs for any two failed runs (suggested: #64988 and #65002) to confirm root cause before acting on the recommendations below.
2. Failure Breakdown
Note: The "Failed Run Logs" section contained no log output. The categories below are inferred from timing patterns, workflow structure, and the ring-0 / reusable-call architecture. Confidence levels are noted.
| Failure Category | Affected Runs | Example Error Message |
|---|---|---|
Reusable workflow / pr-review/next tag fault |
~30 (periodic single failures) | (log unavailable — inferred from 1-per-cluster pattern) |
| Rate limit or quota exhaustion (Claude/GitHub API) | ~5 (multi-failure bursts at 15:42, 16:39, 18:13 on 2026-08-17) | (log unavailable — inferred from consecutive failures within seconds) |
| Auth / token expiry | Unknown | (log unavailable) |
| Timeout / infrastructure | Unknown | (log unavailable) |
| Other / unknown | Remainder | (log unavailable) |
3. Error Patterns
Pattern A — Periodic single failure (~1 per 14-run cluster)
Observed in the vast majority of failure events. In almost every observable cluster of concurrent runs (e.g. #65484–#65472, #65471–#65455, #65454–#65438, …), exactly one run fails at a consistent relative position within the cluster (typically 9–11 runs from the cluster's trailing edge). This regularity is unlikely to be random infrastructure noise.
Probable cause: The called reusable pr-review.yml@pr-review/next enumerates open PRs and reviews them in parallel jobs. If the 10th (or Nth) PR in the list consistently triggers a failure — due to a specific PR's diff characteristics, a Claude quota boundary, or a GitHub API secondary rate limit on the N-th review POST — it would produce exactly this pattern. The failure is absorbed by subsequent runs retrying the same PR list with fresh state.
Affected step: Likely review job within the reusable, step engine.sh or review-one-pr.sh (based on CLAUDE.md reference to scripts/).
Pattern B — Multi-failure bursts (consecutive failures within 1–3 seconds)
Observed at:
- 2026-08-17T15:42Z: #64967, #64969 (two failures, non-consecutive, within the same minute)
- 2026-08-17T16:39Z: #64988, #64989, #64992 (three failures in 18 seconds)
- 2026-08-17T18:13Z: #65002, #65003 (two failures in 2 seconds)
Probable cause: A shared upstream condition that resolves naturally — candidates include a GitHub API 429 rate limit window, a Claude API quota reset boundary, or a brief network partition. The fact that runs return to success immediately after each burst suggests a transient condition, not a persistent misconfiguration.
Pattern C — Isolated standalone failure (#65318 at 07:24Z)
Run #65318 failed with a 28-minute gap from the preceding cluster and is not obviously part of any concurrent group. This is consistent with a one-off infrastructure timeout or a workflow_dispatch-triggered run that hit a different code path.
4. Token Scope Analysis
Scopes declared in pr-review-trigger.yml:
| Permission | Level |
|---|---|
contents |
read |
pull-requests |
write |
checks |
read |
Scopes not declared (potential gaps):
| Missing Scope | Evidence | Recommendation |
|---|---|---|
actions: read |
The reusable is referenced by @pr-review/next tag; resolving that tag at call-time may require actions read on the calling repo |
Add actions: read to the permissions block if the reusable resolver requires it |
statuses: write |
PR review agents commonly post commit statuses alongside PR reviews | Verify pr-review.yml does not write statuses; if it does, add to calling stub |
issues: read |
@mention dispatch path (repository_dispatch: pr-review-mention) may need issue context to identify comment author |
Confirm against pr-review-mention.yml logic |
Assessment: The declared scopes appear minimally correct for a review-posting workflow. Without log output confirming a 403 or "insufficient scope" error, no scope change can be called mandatory. Verify by searching failed run logs for HttpError or 403 before modifying permissions.
5. Recommendations
1. Extract and inspect actual failed run logs [CRITICAL — prerequisite for all other action]
- What: Run
gh run view <run-id> --log-failedfor runs #64988, #65002, and #65473 (one from each failure pattern) - Why: Without error text, all root cause analysis is inferred; wrong diagnosis leads to wrong fix
- Expected impact: Confirms or refutes all categories above; enables targeted remediation
- Command:
gh run view 64988 --log-failed --repo petry-projects/.github-private
2. Investigate N-th PR failure pattern in review-one-pr.sh [HIGH]
- What: Add per-PR error capture and exit-code propagation in
scripts/review-one-pr.shso a single PR failure surfaces in logs rather than silently failing the job; consider wrapping the PR loop with|| trueon non-fatal errors to prevent one bad PR from killing the entire run - Why: The 1-per-cluster failure pattern strongly suggests a specific PR or a fixed-Nth API call is failing; without isolation, the root cause is invisible
- Expected impact: Either isolates the bad PR or reveals the specific API error; reduces failure rate toward 0%
- Urgency: HIGH
3. Add GitHub API rate-limit retry to burst-failure windows [HIGH]
- What: In the engine or trigger script, detect HTTP 429 responses and implement exponential backoff with jitter (min 60s, max 300s) before retrying; alternatively, ensure the
check_suite: completedtrigger does not fan out more than GitHub's secondary rate limit allows per minute - Why: Three distinct multi-failure bursts (15:42, 16:39, 18:13) within 3 hours on 2026-08-17 are consistent with hitting GitHub's 10-requests/minute secondary rate limit on
POST /repos/{owner}/{repo}/pulls/{pull_number}/reviews - Expected impact: Eliminates burst failures; reduces total failure count by ~13%
- Urgency: HIGH
4. Pin agent_ref verification in CI [MEDIUM]
- What: Add a pre-flight step in
pr-review-trigger.yml(or a separate check workflow) that verifies thepr-review/nexttag resolves to a known-good SHA before thereviewjob runs; log the resolved SHA on every run - Why: If a bad commit is pushed to
pr-review/next, all concurrent runs fail simultaneously with no easy way to correlate the tag state at failure time — this is the highest-blast-radius failure mode for ring-0 - Expected impact: Faster incident diagnosis; enables automatic rollback gate
- Urgency: MEDIUM
5. Add actions: read permission if tag resolution fails [LOW — verify first]
- What: Add
actions: readto thepermissions:block inpr-review-trigger.ymlonly if logs confirm a permission error during reusable resolution - Why: Some reusable resolution paths require
actions: readon the calling repo; the current permissions block does not include it - Expected impact: Eliminates any permission-related failures on reusable lookup
- Urgency: LOW (conditional on log confirmation)
6. Health Score
Health: 7/10 — Workflow is functional with a consistent ~7% failure rate that follows a regular-interval pattern, indicating a recoverable per-cycle fault rather than a systemic outage, but the absence of log output prevents definitive root cause identification.
Activity