diff --git a/scripts/ci/pr_review_merge_scheduler.py b/scripts/ci/pr_review_merge_scheduler.py index 00d71905d9..1289218a08 100644 --- a/scripts/ci/pr_review_merge_scheduler.py +++ b/scripts/ci/pr_review_merge_scheduler.py @@ -3097,9 +3097,18 @@ def dispatch_opencode_review(repo: str, workflow: str, pr: dict[str, Any], *, dr return "dispatched" +def is_strix_scan_check_run(node: dict[str, Any]) -> bool: + """Return whether a check run is the authoritative Strix scan job.""" + return ( + node.get("__typename") == "CheckRun" + and node.get("name") == "strix" + and is_strix_context(node) + ) + + def dispatch_strix_evidence(repo: str, workflow: str, pr: dict[str, Any], *, dry_run: bool) -> str: """Dispatch same-head Strix workflow evidence before OpenCode reviews.""" - job_id = matching_actions_job_id(pr, is_strix_context) + job_id = matching_actions_job_id(pr, is_strix_scan_check_run) if job_id: rerun_actions_job(repo, job_id, dry_run=dry_run, action="rerun-strix-evidence") return "rerun" if not dry_run else "dry_run" diff --git a/tests/test_strix_rerun_job_selection.py b/tests/test_strix_rerun_job_selection.py new file mode 100644 index 0000000000..ab6d7ba4c6 --- /dev/null +++ b/tests/test_strix_rerun_job_selection.py @@ -0,0 +1,57 @@ +"""Regression coverage for exact-head Strix rerun job selection.""" + +from scripts.ci import pr_review_merge_scheduler as sched + + +def _strix_job(name: str, job_id: int, conclusion: str) -> dict: + """Build one exact-head job from the trusted Strix workflow.""" + return { + "__typename": "CheckRun", + "name": name, + "status": "COMPLETED", + "conclusion": conclusion, + "startedAt": "2026-08-30T05:24:23Z", + "detailsUrl": f"https://github.com/ContextualWisdomLab/bandscope/actions/runs/33294403831/job/{job_id}", + "checkSuite": { + "createdAt": "2026-08-30T05:22:18Z", + "workflowRun": {"workflow": {"name": "Strix Security Scan"}}, + }, + } + + +def test_dispatch_strix_reruns_scan_job_not_sibling_publisher(monkeypatch) -> None: + """A skipped status-publisher sibling must never be selected as the Strix rerun target.""" + pr = { + "number": 1055, + "statusCheckRollup": { + "contexts": { + "nodes": [ + _strix_job("strix", 99212031836, "FAILURE"), + _strix_job("publish-manual-pr-evidence-status", 99212677006, "SKIPPED"), + ] + } + }, + } + reruns: list[tuple[str, str, str]] = [] + + def record_rerun(repo: str, job_id: str, *, dry_run: bool, action: str) -> None: + reruns.append((repo, job_id, action)) + + monkeypatch.setattr(sched, "rerun_actions_job", record_rerun) + + assert ( + sched.dispatch_strix_evidence( + "ContextualWisdomLab/bandscope", + "Strix Security Scan", + pr, + dry_run=False, + ) + == "rerun" + ) + assert reruns == [ + ( + "ContextualWisdomLab/bandscope", + "99212031836", + "rerun-strix-evidence", + ) + ]