From 1e4b3863155bb801276f9bcdff8a3cd9f9445f26 Mon Sep 17 00:00:00 2001 From: Ramakrishna Prabhu Date: Fri, 10 Jul 2026 15:14:44 -0500 Subject: [PATCH 1/2] fix(ci): exclude cancelled jobs from pr-test-summary failed count Cancelled jobs (conclusion="cancelled") were counted as failures because the failed list was built as anything not passed or skipped. When one job fails, GitHub cancels downstream queued jobs, inflating the headline count (e.g. "17 failed" when only 1 test actually failed). Fix: match only conclusion=="failure" or "timed_out". Closes #1223 Co-Authored-By: Claude Sonnet 4.6 --- ci/utils/pr_test_summary.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/utils/pr_test_summary.py b/ci/utils/pr_test_summary.py index 6971dd83a3..3f44aa95ae 100644 --- a/ci/utils/pr_test_summary.py +++ b/ci/utils/pr_test_summary.py @@ -177,7 +177,7 @@ def main(): passed = [j for j in test_jobs if j["conclusion"] == "success"] skipped = [j for j in test_jobs if j["conclusion"] == "skipped"] - failed = [j for j in test_jobs if j not in passed and j not in skipped] + failed = [j for j in test_jobs if j["conclusion"] in ("failure", "timed_out")] job_analysis = { job["id"]: _analyze_job_log(job["id"], repo, token) for job in failed From 43e41704406bdb9146e66b88d55262016e3bb0af Mon Sep 17 00:00:00 2001 From: Ramakrishna Prabhu Date: Fri, 10 Jul 2026 15:40:59 -0500 Subject: [PATCH 2/2] fix(ci): track cancelled jobs separately, avoid misleading all-passed Co-Authored-By: Claude Sonnet 4.6 --- ci/utils/pr_test_summary.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/ci/utils/pr_test_summary.py b/ci/utils/pr_test_summary.py index 3f44aa95ae..1c079d8338 100644 --- a/ci/utils/pr_test_summary.py +++ b/ci/utils/pr_test_summary.py @@ -131,13 +131,19 @@ def _add(test_id): return failed[:_MAX_TESTS] -def _build_body(failed, passed, skipped, job_analysis): +def _build_body(failed, passed, skipped, cancelled, job_analysis): lines = [_MARKER, "## CI Test Summary", ""] if not failed: - lines.append(f"✅ All {len(passed)} test job(s) passed.") + if cancelled: + lines.append( + f"✅ {len(passed)} passed · {len(cancelled)} cancelled / not completed" + ) + else: + lines.append(f"✅ All {len(passed)} test job(s) passed.") else: lines.append( f"**{len(failed)} failed** · {len(passed)} passed · {len(skipped)} skipped" + + (f" · {len(cancelled)} cancelled" if cancelled else "") ) for job in failed: tests = job_analysis[job["id"]] @@ -178,12 +184,15 @@ def main(): passed = [j for j in test_jobs if j["conclusion"] == "success"] skipped = [j for j in test_jobs if j["conclusion"] == "skipped"] failed = [j for j in test_jobs if j["conclusion"] in ("failure", "timed_out")] + cancelled = [ + j for j in test_jobs if j not in passed and j not in skipped and j not in failed + ] job_analysis = { job["id"]: _analyze_job_log(job["id"], repo, token) for job in failed } - body = _build_body(failed, passed, skipped, job_analysis) + body = _build_body(failed, passed, skipped, cancelled, job_analysis) comments = list( _paginate(f"/repos/{repo}/issues/{pr_number}/comments", token)