Skip to content

fix(codeql): dispatch one current-head scan per pull request - #2008

Merged
seonghobae merged 1 commit into
mainfrom
fix/codeql-one-dispatch-per-pr
Sep 7, 2026
Merged

fix(codeql): dispatch one current-head scan per pull request#2008
seonghobae merged 1 commit into
mainfrom
fix/codeql-one-dispatch-per-pr

Conversation

@seonghobae

Copy link
Copy Markdown
Contributor

Why

The organization 60-job ceiling is saturated by CodeQL Scan Dispatch fan-out. Live measurement on 2026-09-07: ContextualWisdomLab/.github queued ~300 runs, of which codeql-scan-dispatch.yml was 149 (later 157) covering 60 PR@SHA tuples (n=2:29, n=3:27, n=4:2). Duplicate cancellation could not collapse them: the language is not on the run name, the job name, or the REST payload.

Cause: each analyze-head matrix shard POSTed its own repository_dispatch codeql-scan. The handler concurrency group included required_language, so Python/Actions/JS for the same PR were independent runs and each occupied a queue slot.

ADR-0025 recorded that shape on 2026-09-05 after contextual-orchestrator#1049 / run 33938784437, where omitting the language suffix let sibling scans cancel one another. That accident is real. The 60-job ceiling is now the observed need that the 2026-09-05 "do not send the full matrix" rejection did not have. This PR supersedes that rejection: one dispatch per pull request, language independence inside the handler job matrix (fail-fast: false), concurrency {workflow}-{repository}-{PR} with cancel-in-progress: true only for a superseded HEAD of the same pull request.

What

  • codeql-pr.yml: analyze-head still publishes CodeQL compatibility analysis (<language>) with no job-level if:. Shards re-check the live head, consume codeql-dispatch/<language> when an authenticated terminal verdict exists, and otherwise fail pending. They no longer POST.
  • New job dispatch-current-head (needs: [detect-languages, analyze-head], if: always() and not closed, attempt 1 only) collects this run's language job ids and POSTs event_type: codeql-scan once with matrix + required_jobs: [{language, job_id}, ...]. Missing job ids fail closed. All-terminal-verdict skips the POST. github.run_attempt == 1 is required so a single-job wake does not re-POST and cancel the in-flight multi-language handler.
  • codeql-scan-dispatch.yml: concurrency group drops the language suffix. Validation accepts matrix length >= 1, requires required_jobs length == matrix length with 1:1 languages and canonical numeric job ids. Each scan job still publishes codeql-dispatch/<language> and wakes only its own required job. Run-name stays repo#PR@SHA.
  • ADR-0025 amended 2026-09-07.

This change is not on #1938 / #1990 / #1902 / #1962 / #1984. New branch, new PR.

Tests

python3 -m pytest tests -q

2981 passed, 1 skipped, 21 subtests passed.

Chicken-and-egg: this is not a product PR. It is a structural workflow repair for the job ceiling that currently prevents this repository's own required checks from starting. If those checks stay queued behind the ceiling this PR exists to drain, admin bypass merge is the documented recovery for this class of change.

Developer experience: one current-head CodeQL scan run per pull request instead of one per detected language; a superseded HEAD of the same PR cancels its predecessor; sibling languages still fail independently inside that run.

User experience: the required CodeQL compatibility checks keep the same names and still fail a pull request on unsuppressed Medium+ findings; they stop multiplying queue occupancy by language count.

Per-language codeql-scan-dispatch runs were occupying the 60-job
ceiling: 149 queued handler runs across 60 PR@SHA tuples, and
duplicate cancel could not collapse them because the language is
absent from the run name, job name, and REST payload.

analyze-head shards still publish the required check name and still
fail pending to release the runner, but they no longer POST.
dispatch-current-head collects this run's language job ids and sends
one codeql-scan payload (matrix + required_jobs). The handler
concurrency group is {workflow}-{repository}-{PR}; language
independence is fail-fast: false on that run's job matrix.

ADR-0025's 2026-09-05 rejection of a full-matrix dispatch is
superseded. The sibling-cancel failure from
contextual-orchestrator#1049 / run 33938784437 is gone because
siblings are jobs in one run.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@coderabbitai

coderabbitai Bot commented Sep 7, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 48 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 89ab438a-85ae-4c4d-b7e2-206119c7e13b

📥 Commits

Reviewing files that changed from the base of the PR and between c9052e6 and 2fe0a3f.

📒 Files selected for processing (7)
  • .github/workflows/codeql-pr.yml
  • .github/workflows/codeql-scan-dispatch.yml
  • docs/adr/0025-codeql-required-workflow-dispatch-architecture.md
  • tests/test_codeql_pr_workflow_contract.py
  • tests/test_codeql_scan_dispatch_workflow_contract.py
  • tests/test_docs_only_pr_runner_admission.py
  • tests/test_scheduler_and_codeql_dispatch_runner_image_contract.py

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Bypass merge evidence (chicken-and-egg, structural workflow repair, not a product change).

  • Local python3 -m pytest tests -q: 2981 passed, 1 skipped, 21 subtests passed on 2fe0a3f3987c547236a39e449f28f6bf281f664f.
  • Live head re-fetched before merge: 2fe0a3f3987c547236a39e449f28f6bf281f664f.
  • mergeStateStatus=BLOCKED because this PR's own required checks are queued behind the 60-job ceiling this change exists to drain (CodeQL PR, Security Scan, SAST Semgrep, Python Security, Required OpenCode bootstrap, Required Noema, Strix, merge scheduler all queued; CodeQL Scan Dispatch queued total_count=160).
  • Already-queued per-language dispatch runs are left in place; this merge does not cancel them.

@seonghobae
seonghobae merged commit dd7ea81 into main Sep 7, 2026
6 of 16 checks passed
@seonghobae
seonghobae deleted the fix/codeql-one-dispatch-per-pr branch September 7, 2026 07:36
seonghobae added a commit that referenced this pull request Sep 7, 2026
#2008 made required_jobs mandatory on the default-branch handler.
repository_dispatch runs that file, so payloads that lined up before
the merge still carry required_language + required_job_id and a
one-shard matrix. Validate now synthesizes required_jobs from those
scalars when the array is empty, the matrix length is 1, and the
language matches. A present required_jobs array still wins; missing
or mismatched identity still fails closed. Concurrency stays
{workflow}-{repository}-{PR} with no language suffix.

Developer experience: queued single-language dispatches validate
instead of all failing closed after the cutover.
User experience: required CodeQL compatibility checks for those
in-flight PRs can still complete.
seonghobae added a commit that referenced this pull request Sep 7, 2026
…ed claim

Three review findings on the Actions ceiling section, all valid.

The heading read `2026-09-07` while the only measurement window in the section
is `2026-09-06T12:00:00Z..19:00:00Z` and the other reference is 2026-09-04. The
commit was `2026-09-07 05:07 +0900` = `2026-09-06T20:07Z`, so the heading
carried the local calendar date rather than the measurement's. KST rolls the
date nine hours before UTC; date a measurement section by the measurement.

The planning sentence said `#1929` converts "368 cheap no-ops per 7 h" while
the measurement two sentences above is 354, which is also the figure the 20.9%
ratio is computed from (354/1691). 368 appears nowhere else in the document as
a measured value. The sentence now names the same 354 explicitly, so the two
cannot drift apart again.

The two fenced blocks this section added carried no language info string
(MD040). Both are now `text`, matching the document's existing precedent. Three
further bare blocks predate this change and are left alone: no markdownlint
gate runs in this repository, so this is consistency with the reviewer's point
inside this change's own scope rather than a document-wide sweep.

Verifying the third finding showed the section's own "not duplicates" reasoning
has expired: `#2008` removed `required_language` from the dispatch concurrency
group, which was still language-keyed at `2396ddca`, the last `main` inside the
measured window. The replacement paragraph records that, the measured collapse
that followed (`06:16Z..08:15Z`: 86 of 100 runs cancelled, median lifetime
39.1 min, no success since `03:58:07Z`, validation failures 204 to 0 across
`#2009`), and that the cause is not established.

It first recorded a cause -- legacy single-language payloads colliding in the
language-free group -- and that was withdrawn before this commit. The
coordinator on current `main` builds one pending-language matrix and emits a
single dispatch carrying all of it with no `required_language`, so the group
needs no language term and current dispatches cannot collide with themselves.
The candidate survives only for payloads queued before the cutover, which is
what `#2009` exists to validate, and no cancelled run can be shown to carry one
because a cancelled run serves no logs. A mass cancellation at `07:40:40Z` that
crossed several concurrency groups in one second argues against it outright.
The paragraph now states the measurements and leaves the mechanism open.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
seonghobae added a commit that referenced this pull request Sep 7, 2026
Bring in CodeQL one-dispatch-per-PR (#2008) and required_jobs
synthesis (#2009) so this remaining Strix push coalesce can sit
on current main without rewriting those contracts.

Signed-off-by: Seongho Bae <me@seonghobae.me>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant