Skip to content

fix(actions): CodeQL aggregate check times out on matrix language skew - #686

Merged
3 commits merged into
github-actionsfrom
lopu/workflow-check-fix-34088654571
Sep 11, 2026
Merged

3 commits merged into
github-actionsfrom
lopu/workflow-check-fix-34088654571

Conversation

@lopugit

@lopugit lopugit commented Sep 7, 2026

Copy link
Copy Markdown
Owner

Lopu controller check repair

Lopu identified a failed PR check whose root cause is in the protected controller/workflow code.

Lopu controller fix — CodeQL aggregate check times out on matrix language skew

File changed: .github/workflows/codeql-analysis.yml (only)
Found while reviewing: PR #649 (claude/subspace-communitiesdevelop), head cb9d095d
Also currently affecting: PR #683. Previously recorded in this file's own comments as the PR #557 incident.

Diagnosis

PR #649's only failing check is CodeQL, owned by the github-advanced-security
app (check run 101637358172), conclusion timed_out. It is not a finding
and not a code defect:

  • Both of the repository's own analyses for the analyzed revision
    (825e20669a, refs/pull/649/merge) succeeded and uploaded:
    /language:actions at 05:54:39Z (0 results) and
    /language:javascript-typescript at 06:01:06Z (12 results).
  • All 12 results are pre-existing alerts that are already dismissed
    (js/insecure-randomness ×10, js/stack-trace-exposure, js/xss-through-dom),
    none of them in a file this PR touches. Open alerts on the PR ref: 0,
    which matches the trusted snapshot.
  • The workflow's Analyze jobs both reported success
    (actions 60s, javascript-typescript 452s).

Advanced Security opens a PR's aggregate CodeQL check when the first
analysis for the ref lands and closes it timed_out if the remaining languages
have not answered inside its own budget. On this tree actions finishes in
about a minute while javascript-typescript now needs seven or more, so the
fast language opens the window roughly 390s before the slow one can answer it.

Measured upload skew (actionsjavascript-typescript) against the live
outcome across the repository's open PRs:

PR skew aggregate check
#671 14s success
#677 18s success
#675 20s success
#662 95s success
#681 122s success
#682 132s success
#680 197s success
#665 199s success
#660 388s success
#649 387s timed_out
#683 392s timed_out

Every skew ≤199s passed; both timeouts sit in the 387–392s band, and #660 at
388s shows the cliff is not a clean threshold but a coin flip once the skew
approaches it. PR #649 lost that flip by one second: the check closed at
06:01:05Z and the javascript-typescript analysis landed at 06:01:06Z.

This is the same failure the scope job above already guards against — quoted
in its own comments as PR #557, where the check closed timed_out at
11:36:46Z, exactly 387s after the fast analysis opened it — but reached
through matrix language skew rather than through duplicate scans. The
existing guard cannot see it, because here there is no duplicate scan: a single
pull_request run, two languages, one of which is simply far slower.

It is therefore a control-plane defect rather than a PR defect, and it is not
self-correcting: javascript-typescript analysis time grows with the tree, so
the skew drifts further into the failing band with every large PR. A bare
re-run is not a repair either — it re-rolls the same coin flip.

Fix

Hold the fast language until the slow one has uploaded, so the aggregate check
opens on the slow analysis and the residual skew collapses to seconds —
deep inside the band that has never timed out. New step
Let the slowest language open the aggregate check in the analyze job,
gated on matrix.language != 'javascript-typescript', polling the sibling
matrix job in the same run via the actions: read permission the job already
holds.

Design points:

  • Placed after Initialize CodeQL and before the ownership re-check, so the
    fast language's database build still overlaps the slow analysis, and so
    Confirm this push still owns the analysis keeps its "last moment before
    upload" meaning instead of going stale across the wait.
  • Breaks on completed regardless of conclusion. A failed sibling has no
    upload left to wait for; stalling would hide a broken analysis behind a slow job.
  • Bounded at 1800s against the job's 3600s timeout-minutes, with a 120s
    grace for an absent sibling. Every degraded path uploads rather than letting
    the runner kill the job, which would discard a built database and produce
    exactly the red check this step prevents.
  • Preserves gh's exit status (never || true), matching the convention
    the scope pre-flight and the ownership step already follow; a transient
    lookup failure falls back to the prior unpaced behaviour.
  • Suffix job-name match, because workflow_call runs prefix job names
    (control-plane / Analyze (javascript-typescript)).

Job names, check contexts, the matrix, permissions and the concurrency group are
all unchanged, so no required-status-check configuration is affected.
Expected cost: the actions job idles instead of finishing early; total
wall-clock for the run is unchanged (it was already bounded by the slow language).

Validation run

  1. YAML parse + step wiringyaml.safe_load; asserted the new step is
    ordered before Confirm this push still owns the analysis; confirmed matrix,
    actions: read permission and timeout-minutes: 60 unchanged. Pass.
  2. Shell syntax — extracted the run: block, bash -n. Pass.
  3. Selector against the real payload — ran the exact jq filter against the
    live jobs JSON of the failing run 34088527888. Resolved
    control-plane / Analyze (javascript-typescript)completed, matched
    exactly one job, and did not match Analyze (actions). Pass.
  4. Exit-path simulation — faithful re-implementation of the loop over five
    scenarios: sibling already done → paced at 0s; sibling finishes at 450s →
    paced at 450s; sibling absent → unpaced at 120s; sibling stuck → uploads with
    a warning at 1800s (inside the 3600s job timeout); gh lookup fails →
    unpaced immediately. All five terminate and upload. Pass.

actionlint is not installed on this runner, so that check was skipped rather
than reported as passing.

Not done deliberately

  • No CodeQL alert was dismissed and 649.json dispositions remain []: there
    are no open alerts on this PR head, so there is nothing to dispose of.
  • No change was made in PR feat(subspaces): Reddit-style communities + up/down votes as a focused reaction kind #649's worktree; its branch is not the cause and
    carries none of this fix. That worktree is clean.
  • The controller checkout is left uncommitted for the trusted step that opens
    the dedicated Lopu fix branch against github-actions.

Source Lopu workflow run

@github-actions github-actions Bot added lopu: mergeable The PR branches can currently be merged without conflicts lopu: overlapping files This PR changes files also changed by another open PR labels Sep 7, 2026
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

🦄 Lopu review — #686: correct diagnosis, but it is a rival of #663. Recommend closing this one.

Reviewed lopu/workflow-check-fix-34088654571 @ 5bc552bf against github-actions @ 8ea707d8 (1 file, +70/−0). This PR had no prior review pass. CodeQL snapshot for this head: 0 open alerts; all checks pass or skip, so there is no failure on this PR itself to diagnose. I left the worktree byte-identical — no changes published.

The diagnosis holds

I could not find a hole in it. Advanced Security opens the aggregate CodeQL check on the first analysis to land for the ref and closes it timed_out when the rest have not answered. actions finishes in ~1 min here, javascript-typescript in 7+, so the fast leg was opening a window the slow leg could not reach. Holding the fast leg until the slow leg's job completes does collapse the skew — the fast leg still pays its own Analyze cost (~1 min) after the barrier lifts, landing well inside the ≤199s band that has never timed out.

The loop is safe as written: only non-slowest legs wait (no leg can wait on itself), every exit path breaks, the 1800s ceiling sits far under the job's own timeout-minutes: 60, and releasing on completed without inspecting the conclusion is the right call and is correctly justified in the comment.

The measured skew table is the best part of this PR and I would like it preserved regardless of what happens to the code.

Blocking: #663 fixes the same defect in the same hunk

#663 was opened ~21 hours earlier and rewrites the same region of .github/workflows/codeql-analysis.yml. Two independent rewrites of the same lines never 3-way apply onto each other, so these two block each other rather than compose. On the merits #663 is the stronger survivor:

#663 #686
Upload-ordering hold
Start barrier before init (the "1 configuration not found" shape, which is what killed #610)
Contract coverage ✅ +151 lines in workflow-control-plane-contract.mjs ❌ none
Malformed-payload guard on the jobs lookup ❌ (see below)

Without contract coverage, a later prompt/workflow reflow can delete this step silently — which is the failure mode workflow-control-plane-contract.mjs exists to prevent.

One real defect, if this branch is landed anyway

The guard step can turn the Analyze (actions) job red — the exact check state it exists to prevent.

status="$(jq -r --arg name "$PACING_JOB" '
  [.jobs[] | select(.name | endswith($name))] | .[0].status // "absent"
' <<<"$jobs_json")"

gh api exits 0 on any 2xx, so $jobs_json is not guaranteed to carry .jobs: an edge-served HTML body, a truncated response, or a {"message": …} payload all reach jq with gh reporting success. .jobs[] over null is a hard jq error, and under set -euo pipefail a failing command substitution in a plain assignment aborts the step and fails the job — discarding an already-built database on the way out. The gh call itself is correctly guarded with if ! jobs_json=…; only the jq consuming it is not.

Reproduced with the exact program from the diff, against <!DOCTYPE html>… and {"message":"Moved Permanently","url":"…"}:

# this PR's form
jq: parse error: Invalid numeric literal at line 1, column 10   -> exit 5, step aborts
jq: error (at <stdin>:1): Cannot iterate over null (null)       -> exit 5, step aborts

# #663's form, same two payloads
sibling=unreadable                                              -> exit 0, keeps waiting

#663 already guards this with .name? | strings plus an if ! sibling=… || [ -z … ] fallback, and documents this precise failure mode in the step's comment.

Why I did not patch it here

Hardening a branch whose recommended disposition is closure would deepen the duplication, and the surviving implementation already carries the guard. I also did not open a third controller-repair PR for this defect and left $RUNNER_TEMP/lopu-workflow-fix.md unwritten.

Worth recording for #677: I verified that the reviewer-prompt paragraph #677 adds — "Before writing that fix, inventory the repairs already open with gh pr list … --base github-actions --limit 500 …" — exists only on #677's head and is absent from github-actions@8ea707d8. It was therefore not in force when this PR was authored at 06:57:23Z, ~40 minutes after #677's most recent approving pass. #686 is a live, dated instance of the defect #677 fixes, and the third rival pair on this control plane after #671/#675 and #663/#686.

Recommendation

Close #686 as superseded by #663, after folding this description's skew table into #663 as corroborating evidence.


Lopu — Thingtime principal developer & PR manager. Handing over to the serialized fleet after this PR; the remaining candidates in this batch are untouched and unreviewed.

@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Lopu repository review

Lopu reviewed this PR against github-actions as Thingtime's principal PR and repository manager. Using Claude Opus 5.

Lopu found no justified local change to publish from this review pass.

Lopu review — PR #686 "fix(actions): CodeQL aggregate check times out on matrix language skew"

Head ebce0b11 · Base github-actions @ 3ce68d55 · Checks 23 pass / 58 skipping, none failing · CodeQL open alerts on this head: 0

What I compared

Full head against github-actions in the supplied worktree, the PR body's claimed change, and the ancestry of every commit that has ever touched the file the body names.

Key finding — the fix this PR exists to deliver is already merged into its own base

The PR body states "File changed: .github/workflows/codeql-analysis.yml (only)". That file is not in the contributed diff at all:

$ git diff 3ce68d55..HEAD --name-only -- . ':(exclude)graphify-out/**'
(empty)                     # 0 files

Every commit on this head that touched codeql-analysis.yml is already an ancestor of the base:

commit ancestor of github-actions @ 3ce68d55?
c5e8b443 chore(lopu): apply repository review improvements yes
a3ca46f0 fix(actions): Lopu repairs failed PR checks yes
6a84863f fix(actions): Lopu repairs failed PR checks yes
de924899, c2c5da8c, 2a621555, a16fc8ba, db975652 yes

The base branch already carries the mitigation the body describes. I read it in the worktree's own copy of the workflow: the Analyze job holds each language's SARIF upload behind a slowest-language barrier (codeql-analysis.yml around lines 413–447, with the $SLOWEST_LANGUAGE wait and its warning paths at 505–593), and the scope pre-flight guard at 135–201 documents the same timed_out hazard. That is exactly the "don't let the fast language open the aggregate check 390s before the slow one answers" repair.

Ancestry makes the delivery route explicit — the fix reached github-actions through the sibling repair PRs already merged into the base:

3ce68d55 Merge pull request #671 from lopugit/lopu/workflow-check-fix-34009290475
32eb3c80 Merge pull request #663 from lopugit/lopu/workflow-check-fix-33997069565
99d1ec11 Merge pull request #677 from lopugit/lopu/workflow-check-fix-34033623289

Secondary finding — all that remains is Graphify churn

The ten remaining files are five graphify-out/cache/semantic-cas/v1/** entries plus a snapshot swap (4f485494…2e779517…). Merging this PR would apply only that swap, deleting the base's active snapshot for no control-plane benefit.

The base is an ancestor of the head here, so unlike #709 this is a clean redundancy rather than a stale-snapshot regression — but it is still a large write with zero value.

Changes made

None, deliberately. There is no defect left to repair: the workflow fix is already in the base, and the diagnosis in the PR body is sound and was acted on. Re-applying it would duplicate merged code. The worktree is left clean and $RUNNER_TEMP/lopu-workflow-fix.md is intentionally unwritten, as the contract requires when no uncovered controller defect exists.

I inventoried the open repairs against github-actions first (#724, #686, #675); none of them needs a competing patch from me.

Recommendation

Close PR #686 without merging. Its diagnosis was correct and its fix has already shipped via #663/#671/#677. Leaving it open costs an ~81-check matrix and a Lopu review session per wake-up to re-review an empty control-plane diff.

Validation

  • Contributed-diff emptiness re-checked with an explicit graphify-out exclusion — empty (command and result above).
  • Ancestry of all eight codeql-analysis.yml commits verified individually with git merge-base --is-ancestor — all yes.
  • The mitigation was read in the worktree's own codeql-analysis.yml to confirm it is genuinely present, not merely claimed.
  • Live check state inspected with gh pr checks 686: 23 pass, 58 skipping, no failing, cancelled, or timed-out run on this head — the failure this PR was opened to fix no longer reproduces, which independently corroborates that the fix is live.

View Lopu workflow run

@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Lopu review — PR #686 (lopu/workflow-check-fix-34088654571github-actions, head 5bc552bf)

Verdict: the diagnosis holds, but this is a rival repair of #663. Recommend closing #686 in favour of #663.

The diagnosis is correct

I re-derived the matrix-language-skew claim against live job timings on product-branch PRs, and it stands:

PR base Analyze (actions) Analyze (javascript-typescript) skew aggregate CodeQL
#660 main 54s 2m47s ~113s pass
#682 main 42s 2m52s ~130s pass
#680 main 47s 3m24s ~157s pass
#683 develop 48s 3m56s ~188s pass
#649 develop 1m00s 7m32s ~392s fail — timed_out after 6m27s

The one red CodeQL check in the repository today sits at the largest skew, and both of its language analyses succeeded. So this is a control-plane defect, not a PR defect, and inverting the upload order is the right shape of repair.

The mechanism also demonstrably engages. On this PR's own pull_request run the hold fired: Analyze (actions) took 2m34s against a 1m11s baseline on github-actions-base PRs that carry neither fix (#671 1m11s, #675 1m09s, #677 1m13s), i.e. the fast leg waited for the slow one instead of finishing early.

Why I am not recommending this PR

#663"CodeQL aggregate check times out on the largest PRs", opened 2026-09-06 00:50Z, 20 hours before this PR — repairs the same defect in the same file, is MERGEABLE/CLEAN, and has every check green. The two are mutually exclusive:

$ git apply --3way --check <#663.patch>   # onto this PR's head 5bc552bf
Applied patch to '.github/scripts/workflow-control-plane-contract.mjs' cleanly.
Applied patch to '.github/workflows/codeql-analysis.yml' with conflicts.

That is exactly the publisher fall-through #677 documents: two independent rewrites of the same lines never 3-way apply onto each other, so the second review pass opens a rival PR instead of folding into the first. #686 was authored 2026-09-07 06:57Z, after #677 was opened but before its prompt guard could land — this is the third instance of that pattern (#671/#675 were the first two), and the first to hit codeql-analysis.yml.

Where they differ, #663 is strictly stronger:

#686 (this PR) #663
Release predicate sibling job reaches completed the js-ts analysis appears in code-scanning/analyses
Processing lag not covered — a SARIF that has landed but is still being processed still closes the check (#291, #592) covered, and it is the stated reason for the design
Re-run scoping runs/$RUN_ID/jobs (filter=latest) — a partial re-run reports the previous attempt's js-ts leg as completed, releasing the hold at 0s and silently restoring the race runs/$RUN_ID/attempts/$RUN_ATTEMPT/jobs
Lone-first-uploader (1 configuration not found, PR #610) not addressed sibling-start barrier before init, gated on strategy.job-total
Matrix drift PACING_JOB hardcoded gate and awaited language asserted equal, and asserted to be a real matrix entry
Contract coverage none ~150 lines of property assertions in workflow-control-plane-contract.mjs

That last row is the one I would flag even if #663 did not exist. This PR adds a load-bearing, non-obvious ordering guard to the control plane with nothing in workflow-control-plane-contract.mjs pinning it, so a later edit can delete it and every check stays green until the aggregate CodeQL check starts flapping again. Every comparable guard in this file — the merge-ref freshness checks, the push-ownership re-check, the permission block — is contract-pinned.

What I did

No changes. The worktree is clean and left at 5bc552bf.

Deliberately so: hardening this PR toward parity with #663 would deepen a conflict that a human then has to resolve by hand, which is the specific outcome #677 argues against. There is also no failing check to repair here — all of #686's own checks are green.

I ran node .github/scripts/workflow-control-plane-contract.mjs --self-test on this head: self-test OK.

Recommendation

Land #663 and close #686 as superseded. If any part of this PR is judged worth keeping, the cheap version is to graft it onto #663 as a follow-up rather than to reconcile two whole-step rewrites.

No CodeQL alerts are open on this head (trusted snapshot is []), so there was nothing to fix or dispose of.

— Lopu, automated repository review

@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Lopu review — this fix works, but it collides with #663

I reviewed 5bc552bf against github-actions@8ea707d8. No failing checks: everything on this head is green, and the only non-passing results in my batch were cancelled control-plane jobs, which I confirmed are concurrency supersession (run 34108052955 was cancelled the same second its replacement 34108241593 was created, with zero steps executed) rather than a defect.

The mechanism demonstrably works. From this head's own run 34093148072:

Leg Started Finished
Analyze (javascript-typescript) 06:57:43 06:59:10
Analyze (actions) 06:57:43 07:00:12

The pacing step ran 06:57:58 → 06:59:16 — it released 6s after the slow leg finished (inside the 15s poll), then actions analyzed and uploaded by 07:00:12. The slow leg opens the aggregate check and the residual skew is ≈62s, far inside the ≤199s band this PR reports as never having timed out. I also checked the two things that could have made this unsafe and both are fine: fail-fast: false with no max-parallel means no deadlock, the 1800s cap is well under the job's timeout-minutes: 60, and the unpaginated jobs?per_page=100 lookup is safe because these runs carry 3 jobs.

The blocking problem is that #663 fixes the same defect in the same file. I verified with a read-only git merge-tree that the two heads hard-conflict:

CONFLICT (content): Merge conflict in .github/workflows/codeql-analysis.yml

They cannot both land — merging either strands the other. On the merits I'd keep #663: it adds a pre-init barrier for the "1 configuration not found" shape, waits on the authoritative code-scanning/analyses API instead of using job completion as a proxy, scopes the match to the current attempt so a re-run can't match a stale analysis of the same SHA, releases early when the slow leg is missing/failed/declined its upload, and ships +151 lines of workflow-control-plane-contract.mjs coverage. This PR's virtue is being ~70 lines against ~400, but that extra size is carrying real edge cases plus the regression test.

Recommendation: close this as superseded by #663. I've deliberately made no edits here — the fix is correct as written, and rewriting these lines a third time is exactly the failure mode #677 exists to stop.

Worth noting this is the second instance of that pattern in one batch: #671 and #675 both independently rewrite promotion-pr-changelog.mjs for the zero-diff promotion claim. #677 adds the review-prompt rule requiring Lopu to inventory open github-actions repairs and report an existing PR number instead of opening a rival — landing it first would stop this recurring.

One small accuracy note for the record: the step comment says the skew "collapses to seconds". Measured it's ≈62s, floored by the fast leg's own analyze+upload after the barrier lifts. The conclusion still holds; #663's comment phrases it accurately as "about a minute later".

Posted by Lopu (github-actions[bot]) as part of an automated repository review.

@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

🤖 Lopu review — post-batch review pass, dispatch lopu-review:conflict-batch:34102168243

The diagnosis is right and the code is correct — but this PR is a rival of #663, which has had the same fix open since run 33997069565.

Both hold the fast actions leg until javascript-typescript has landed, in the same file, on overlapping lines:

$ git merge-tree --write-tree 5bc552b 15ac0e7
CONFLICT (content): Merge conflict in .github/workflows/codeql-analysis.yml

Both read MERGEABLE/CLEAN only because neither has merged; merging either conflicts the other.

This is the class of defect #677 documents for #671#675 — the reviewer prompt never tells Lopu to inventory the controller repairs already open, so each pass diagnoses from scratch and writes its own patch. #677's body predicted a recurrence; this PR is that recurrence, and it's the pair #677 doesn't yet mention. #677 should land first.

Recommendation: close in favour of #663 — but keep two things

I'd land #663 on the strength of its 151 lines of workflow-control-plane-contract.mjs coverage (this PR ships no test) plus incumbency. Before this one closes, though:

  1. Your evidence table is the better one. fix(actions): CodeQL aggregate check times out on the largest PRs #663 argues from Components library: /components page, component thing kind, 1000-component catalog #291 (6m10s) and feat(lopu): Lopu AI assistant — streamed chat, model catalog, builder tools, live patches, voice, own providers #592 (6m28s). You add feat(subspaces): Reddit-style communities + up/down votes as a focused reaction kind #649 (387s) and Unify Builder and Thing sharing audiences #683 (392s) as fresh timed_out cases and — most usefully — [Promote] feat: rename Thingtime plugin and add login command (#560) #660 surviving 388s, which shows the threshold is a coin flip in that band rather than a clean cutoff. That's a stronger argument for removing the skew than fix(actions): CodeQL aggregate check times out on the largest PRs #663 currently makes, and it should be transplanted into whichever patch lands.
  2. This approach is genuinely simpler: 70 lines against 403, and waiting on the sibling job to reach completed has strictly fewer moving parts than polling code-scanning/analyses with an attempt-scoped timestamp baseline. If the repo weights simplicity over test coverage, this is a defensible pick — but then fix(actions): CodeQL aggregate check times out on the largest PRs #663's contract tests need to come across with it.

I'm flagging the trade-off for a human rather than silently closing either PR.

Review of the change

No defects found.

  • No deadlock — only the non-javascript-typescript legs wait; the slow leg waits for nobody.
  • Bounded and fail-open: limit=1800 sits far below the job's own timeout, and an unreadable API, an absent sibling (after the 120s grace) or an exhausted wait all break to an unpaced upload with a warning. Right polarity — a killed job would discard a built database and produce exactly the red check this step prevents.
  • Deliberately not gated on the sibling's conclusion is correct: a failed sibling has no upload left to wait for, and stalling would hide a broken analysis behind a slow job.
  • endswith matching correctly handles the workflow_call name prefix (control-plane / Analyze (javascript-typescript)).
  • Placing this before the push-ownership re-check is right, and your comment justifies it — that check must keep its "last moment before upload" meaning rather than going stale across a wait of up to 30 minutes.

Validation: existing workflow-control-plane-contract.mjs --self-test and resolve-pr-conflicts-routing-contract.mjs --self-test both pass against this head. gh pr checks → 84/84 passing. CodeQL snapshot for 5bc552b is empty.

The fix is self-demonstrating here too: Analyze (actions) 2m34s vs Analyze (javascript-typescript) 1m27s — the pacing step inverted the finish order as designed, and the aggregate CodeQL check went green in 4s.

@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

🐙 Lopu — repository review of lopu/workflow-check-fix-34088654571 @ 5bc552bfgithub-actions

All checks green, 0 CodeQL alerts, control-plane contract still passes on this head. The fix is correct — but it is one of two rival PRs for the same defect.

#686 and #663 cannot both land. Verified mechanically:

$ git apply --check <663.patch>   # onto this head
error: patch failed: .github/workflows/codeql-analysis.yml:307
error: .github/workflows/codeql-analysis.yml: patch does not apply

Both rewrite the same region of codeql-analysis.yml to fix the same aggregate-check timeout. The publisher folds by 3-way apply, so whichever merges first strands the other. This is the recurrence of exactly what #677 fixes — merge that one first.

My recommendation: keep #686, close #663. Same race removed with 70 lines instead of 252. The key reason: waiting on the sibling job to reach completed is a valid ordering signal, because a CodeQL job only completes after its upload step — which lets this PR skip the code-scanning/analyses API entirely, and with it the whole retained-analysis staleness problem #663 has to reason carefully around (that API retains every analysis ever uploaded for a ref, so #663 needs per-attempt run_started_at anchoring just to avoid releasing instantly on a re-scan).

Things this gets right that are easy to get wrong:

  • Placement after Initialize CodeQL but before the push-ownership re-check, so that re-check keeps its "last moment before upload" meaning rather than going stale across a potentially 30-minute wait.
  • Not gated on the sibling's conclusion — a failed sibling has no upload to wait for, and stalling would hide a broken analysis behind a slow job.
  • endswith rather than equality on the job name, correctly handling workflow_call runs prefixed with the caller's job id.
  • Bounded well under timeout-minutes, so a wedged sibling degrades to a late upload rather than a runner-killed job that discards the built database — the very red check this exists to prevent.

I also checked the late-runner-allocation case that #663 adds a second barrier for: a not-yet-allocated matrix leg is listed as queued, not absent, so this loop already keeps waiting. #663's extra pre-init barrier is largely redundant.

Two minor, non-blocking notes:

  1. waited drifts from wall-clock — it adds a flat 15 per iteration while each iteration also costs a gh api round trip, so it under-reports elapsed time and the effective ceiling exceeds 1800s. Harmless for a backstop, but bash's SECONDS is exact and free.
  2. No contract pinning. fix(actions): CodeQL aggregate check times out on the largest PRs #663 adds assertions to workflow-control-plane-contract.mjs for its steps; this has none. Since this repo pins control-plane behaviour by contract, if fix(actions): CodeQL aggregate check times out on matrix language skew #686 is the one kept, port an equivalent assertion across so a later reflow can't silently drop the barrier.

No changes made. I left both notes unapplied deliberately — the counter is cosmetic, and the contract assertion only makes sense once the #663/#686 selection is settled; editing now would deepen the conflict rather than resolve it.

@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Lopu review — same defect as #663; I recommend closing this in favour of it

The diagnosis here is the best-evidenced of the five open controller repairs. The skew/outcome table across eleven PR heads — every skew ≤199s passing, both timeouts in the 387–392s band, #660 passing at 388s, #649 losing by one second (06:01:05Z close vs 06:01:06Z analysis) — is exactly what establishes this as a control-plane defect rather than a PR defect, and why a bare re-run isn't a repair. The step itself is also correct: every path uploads, the 1800s bound sits inside the 3600s job ceiling, endswith handles the workflow_call job-name prefix, and a queued sibling is waited for rather than raced.

The problem is that #663 (opened a day earlier) repairs the same defect in the same region of the same file:

git merge-tree --write-tree --merge-base=8ea707d8 5bc552bf 15ac0e74
→ CONFLICT (content): .github/workflows/codeql-analysis.yml

Neither can be folded into the other. Comparing on the merits, #663 wins on three substantive points:

  1. Release signal — it waits for the slow category's analysis in code scanning, not the sibling job concluding. A job can conclude before GHAS has processed its SARIF.
  2. The exposure the inversion creates — once javascript-typescript uploads first, it becomes the leg that can upload alone, and it's exempt from the hold in both designs. If the actions runner is allocated late, the check can close "1 configuration not found" (the feat(marketing): generated marketing suite — 1,600+ pages, animated walkthroughs, social image suite #610 shape). fix(actions): CodeQL aggregate check times out on the largest PRs #663 adds a sibling-start barrier for this; this PR has none.
  3. Contract coveragejavascript-typescript is hardcoded twice here (the if: gate and PACING_JOB) with nothing pinning them to each other or to the matrix. If they drift, the slow leg waits on its own unpublished upload.

Smaller point: the jobs lookup is unscoped (/actions/runs/$RUN_ID/jobs), so a partial re-run carrying a previous attempt's completed slow leg skips the pacing. #663 scopes to /attempts/$RUN_ATTEMPT/jobs.

Recommendation: close as superseded by #663 — but carry this PR's measured skew table across to it. That evidence is the better of the two and should outlive the patch. If the 403-line surface of #663 is judged too much and this smaller step is preferred instead, then #663's start barrier and language cross-check should be brought over here rather than dropped.

This is good work; it collided only because the review session that authored it had no instruction to inventory open controller repairs first — the gap #677 closes.

Validation at 5bc552bf: YAML parses; bash -n pass; step order is Initialize CodeQL → new step → Confirm this push still owns the analysis as described; control-plane contract --self-test pass (no existing assertion broken); job config unchanged; gh pr checks 27 pass / 0 failing; CodeQL open alerts: 0. actionlint isn't installed here, so that was skipped rather than reported as passing. Worktree left clean.

@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Lopu review — #663 and #686 are rival repairs for one defect. Exactly one must land.

Both patch .github/workflows/codeql-analysis.yml at the same insertion point to fix the same thing: the aggregate CodeQL check opening on the fast actions leg and timing out before javascript-typescript can answer.

The defect is real — I reproduced it live on #557, whose check concluded timed_out after 6m42s while its Analyze (javascript-typescript) job passed at 7m46s. Both diagnoses are correct.

Merging both is actively harmful, not just redundant. The actions leg would serve, in order:

Wait Source Cap
sibling-start barrier #663 600s
job-completion hold #686 1800s
analysis-landed hold #663 1200s
total 3600s = 60 min

That is exactly the analyze job's timeout-minutes: 60, consumed before its own checkout, init and analysis. The runner would kill the job and discard a built database — producing precisely the red check both PRs exist to prevent. There is also a direct textual conflict at the shared insertion point, and #663's contract assertions pin step names #686 does not provide.

My recommendation: land #686, close #663. Both work; the tiebreaker is a real correctness property rather than size. #663 waits on the code-scanning/analyses list, which retains every analysis ever uploaded for a ref — so it needs run-attempt baselines, created_at comparisons, a sibling-job classifier and a grace window (~100 of its 403 lines) just to prove an entry belongs to this attempt. #686 waits on this run's job and never consults historical analyses, so it cannot have a stale-analysis bug at all — it removes the class by construction, in 70 lines.

#663 is the more thorough engineering and its contract test is the one asset #686 lacks. Best path: land #686, then port #663's contract assertions (renamed to #686's step) as a small follow-up so the fix stays regression-locked. Choosing #663 instead is entirely defensible — the only non-negotiable is that one of the two closes before either merges.

Full reasoning is in my review reports for both PRs. I made no changes to either branch: the diffs are correct, the problem is coordination.

@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

🐙 Lopu — gap to absorb before this lands: the aggregate check latches red

From reviewing #557, whose CodeQL check is live-red at head 0c0cfc1d right now. Its numbers confirm this PR's diagnosis exactly:

aggregate check open   11:30:53Z
aggregate check closed 11:37:35Z   (window 6m42s, timed_out)
actions   SARIF        11:30:54Z
js-ts     SARIF        11:37:48Z   (skew 6m54s)
                                   -> js-ts landed 13s AFTER the close

Both analyses succeeded (actions 0 results, js-ts 14, all pre-existing/dismissed); open alerts on that head: 0.

The gap: the upload-ordering fix here prevents recurrence on future scans, but it does not reopen an aggregate check that has already closed on an existing head. On #557 there is exactly one CodeQL check run, the timed-out one, and three later Lopu CodeQL all branches runs on that same head — 34252919544, 34279478575, 34279742365 — all concluded success while only executing the pr-handoff metadata hop; their control-plane analysis job was skipped, so no new SARIF was ever uploaded.

Net effect: #557 stays red even after this merges, until something forces a fresh analysis for its current revision. Worth either handling here (a way to force a re-upload for an already-analyzed SHA — note the scope job's "already has both Lopu CodeQL language analyses" guard blocks a plain re-dispatch) or tracking explicitly as a follow-up, so the fix isn't judged by a PR it cannot repair.

I did not open a third controller PR for this — #663 and #686 are already two repairs for one defect, which is what #677 exists to prevent. Recommendation unchanged: land #677, then pick exactly one of #663/#686 and close the other.

@github-actions github-actions Bot added the lopu: queued The current PR snapshot is waiting in Lopu's PR-management queue label Sep 9, 2026
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

🤖 Lopu live PR update

Status: ✅ Lopu finished — this PR is mergeable

Current phase: GitHub verified the published branch result

Estimated completion: Done — no further active-work ETA.

Time conversion (UTC source)

Moment UTC Los Angeles Melbourne
Updated 2026-09-09 07:52 UTC (UTC+00:00) 2026-09-09 00:52 PDT (UTC-07:00) 2026-09-09 17:52 AEST (UTC+10:00)

Los Angeles and Melbourne use their real IANA time zones, so PDT/PST and AEST/AEDT offsets change automatically.

Lopu queue and PR pulse

Scope Metric Count
Repository Open PRs 23
Repository Conflicting 10
Repository Out-of-date with target 9
Repository GitHub state unknown 0
Repository Part of an open stack 2
Repository Touch files changed by another open PR 18
Repository Target a non-root branch without an open parent PR 0
This resolver batch Admitted snapshots 2
This resolver batch Currently resolving 0
This resolver batch Waiting 0
This resolver batch Finished 2

Related PR context

  • Stack: No open parent or child PR currently links to this branch.
  • Target: github-actions is a repository root/integration branch.
  • Changed-file overlap: No changed paths overlap another open PR in this snapshot.

Exact branch pair: github-actionslopu/workflow-check-fix-34088654571.

Timeline

  • 07:17 UTC — Detected that github-actions needs to be merged into lopu/workflow-check-fix-34088654571; assigning the exact snapshot to the resolver queue.
  • 07:20 UTC — Still safely queued behind earlier admitted Lopu work; no duplicate resolver was spawned.
  • 07:31 UTC — 10-minute check-in: still working — Waiting in Lopu's serialized PR-management lane.
  • 07:41 UTC — 10-minute check-in: still working — Waiting in Lopu's serialized PR-management lane.
  • 07:46 UTC — Preparing the isolated repository environment.
  • 07:47 UTC — Using repository context to resolve the conflict semantics.
  • 07:51 UTC — Publishing the verified branch update.
  • 07:52 UTC — The resolver worker completed successfully and GitHub now reports this PR as mergeable.

Technical run details — optional; this comment is the human-facing source of truth.

@github-actions github-actions Bot added lopu: conflicting GitHub reports merge conflicts for the current PR snapshot and removed lopu: mergeable The PR branches can currently be merged without conflicts lopu: overlapping files This PR changes files also changed by another open PR labels Sep 9, 2026
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

🤝 Merged github-actions into lopu/workflow-check-fix-34088654571 — conflicts auto-resolved by Lopu's PR manager.

Conflicted files:

  • .github/workflows/codeql-analysis.yml

Rebuilt the merged code graph first with graphify update ., then ran LLM semantic extraction (graphify extract ., claude-cli backend) and committed the result.

Please review the merge commit before relying on it.

@github-actions github-actions Bot added lopu: resolving Lopu is actively managing this PR branch and removed lopu: queued The current PR snapshot is waiting in Lopu's PR-management queue labels Sep 9, 2026
github-actions Bot and others added 2 commits September 9, 2026 07:50
…olved conflicts)

Conflicted paths: .github/workflows/codeql-analysis.yml

Resolved by the resolve-pr-conflicts workflow: https://github.com/lopugit/thingtime/actions/runs/34323168283

Lopu-Conflict-Resolution: run=34323168283 pr=686

Co-Authored-By: Lopu <github-actions[bot]@users.noreply.github.com>
Structural `graphify update` followed by LLM semantic `graphify extract` (graphify 0.9.4, claude-cli backend); unchanged content served from the tracked semantic cache.

Refreshed by the resolve-pr-conflicts workflow: https://github.com/lopugit/thingtime/actions/runs/34323168283

Lopu-Conflict-Resolution: run=34323168283 pr=686
@github-actions github-actions Bot added the lopu: overlapping files This PR changes files also changed by another open PR label Sep 9, 2026
@github-actions github-actions Bot added lopu: mergeable The PR branches can currently be merged without conflicts and removed lopu: resolving Lopu is actively managing this PR branch lopu: conflicting GitHub reports merge conflicts for the current PR snapshot labels Sep 9, 2026
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Lopu · repository review

This PR no longer carries its fix, and I think it should be closed.

The deliverable was the 70-line pacing step 5bc552bf added to .github/workflows/codeql-analysis.yml. It is not in the head's diff against github-actions:

$ git diff --stat 3ce68d55 ebce0b11 -- .github/workflows/codeql-analysis.yml
(no output — byte-identical to base)

The merge c80e2312 resolved that conflict in favour of base, and that was the right resolution. Base independently acquired a stronger version of the same idea, Hold the faster analysis until the slowest language lands.

The difference matters. This branch's step releases the fast actions leg as soon as the sibling job reports completed — the moment the job ends, not the moment Advanced Security has processed its SARIF — and it has no notion of run attempts. Base's step matches against code-scanning/analyses filtered by this attempt's run_started_at, so it survives the re-scan-of-an-already-analyzed-head path (a re-run, a queue: max duplicate, a backfill dispatch), where an earlier attempt's analysis is still listed under the same ref and SHA. This branch's version would release instantly on exactly that path and hand back the race it was written to remove.

So the fix isn't merely redundant — it's the weaker of the two, and the better one is already live. The aggregate CodeQL check passing on this head is itself evidence base's version works.

What remains is ~20k lines of regenerated graphify-out/ snapshot churn across 10 files, delivering nothing. Recommending close as superseded. I've left the branch untouched rather than acting on it myself.

@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Lopu review — this PR is superseded and should be closed.

I compared the full head ebce0b11 against github-actions @ 3ce68d55, not just the incremental commits.

The AI-resolved merge c80e2312 was right to drop this PR's fix. The repair commit 5bc552bf added a 70-line Let the slowest language open the aggregate check step to codeql-analysis.yml. The merge took the base side of that file verbatim, because github-actions already landed an equivalent and stronger guard via #671Hold the faster analysis until the slowest language lands (.github/workflows/codeql-analysis.yml:438).

Both hold the fast actions leg until javascript-typescript lands. The base version is better on three counts:

  • It waits on the sibling's uploaded analysis for this run attempt, not merely on the sibling job reaching completed. That is what stops a re-scan of an already-analyzed head from being released instantly by a stale analysis from a previous attempt — the Components library: /components page, component thing kind, 1000-component catalog #291 attempt-2 case.
  • It pins the wait to needs.scope.outputs.analysis_ref/analysis_sha rather than assuming the event ref, so the dispatched backfill path is covered.
  • It fails open on every uncertain lookup, same as this PR intended.

Landing 5bc552bf on top would have stacked a second, weaker serialization wait on the same matrix leg.

What's left is only generated churn. The .github tree is byte-identical between base and head (da9d6e4652d256ef193411e2dbc2bc9e87adfff8 on both), as is PRs. All 10 changed files are under graphify-out/ — five appended semantic-CAS entries plus a snapshot re-key. Merging this PR would push graphify bookkeeping into the control plane and nothing else.

Checks are green, including the aggregate CodeQL check this PR was opened to repair — now passing under the base's own guard, which is the cleanest possible confirmation that #671 fixed it. CodeQL reports 0 open alerts on this head, so there was nothing to fix or dispose.

No changes made. Editing this branch just to produce a commit would be churn. Recommendation: close as superseded by #671; there is nothing here to salvage into another PR.

Lopu · automated repository review

@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Lopu review — this PR's fix is already on github-actions, in a better form.

Comparing ebce0b11 against github-actions @ 3ce68d55, the head-vs-base diff is only graphify-out/ artifacts. The workflow file is byte-identical to base:

git diff --quiet <base> <head> -- .github/workflows/codeql-analysis.yml   → IDENTICAL

That is not a lost fix. The AI-resolved merge (c80e2312) dropped this branch's step "Let the slowest language open the aggregate check" because base already carries "Hold the faster analysis until the slowest language lands" (codeql-analysis.yml:438), which solves the same skew more soundly:

  • this branch waited for the sibling job to reach completed via runs/$RUN_ID/jobs;
  • base waits for the analysis itself to land — it polls for the /language:javascript-typescript category at ref@sha, and separately handles "no slowest leg in this run", "slowest leg ended without success", and "leg succeeded but published no analysis in the grace window", each with a bounded fallback.

Ordering on the upload rather than on job completion is the right call: a job can complete having declined its upload, and this branch's version would have treated that as a satisfied wait — reopening the exact timed_out window it was written to close.

Checks are green (23 pass / 58 skipping / 0 failing) and the CodeQL snapshot for this head is empty, so there is nothing red to diagnose and no alert to fix or dispose.

Recommendation: close without merging. Merging now would land only a graphify snapshot rotation, and leaving it open keeps a second open repair touching codeql-analysis.yml in the queue — the overlap that blocks two controller repairs at once. I made no changes to the worktree; manufacturing a commit here would be pure churn.

@github-actions

Copy link
Copy Markdown
Contributor

🦄 Lopu review — this PR no longer contains its repair

Recommendation: close as superseded.

The diff against github-actions is 10 files / +20179 / −11201, but none of it is controller code:

$ git diff --name-only 3ce68d55...HEAD -- .github/
    # empty

Everything remaining is regenerated graphify-out/snapshots/v1/** plus content-addressed cost.json blobs.

The repair commit did carry a real fix — 5bc552bf added a 70-line Let the slowest language open the aggregate check step to codeql-analysis.yml. It is absent from both sides now (0 matches on base, 0 on head); the AI conflict resolution in c80e2312 (resolver run 34323168283) dropped it.

Dropping it was correct. github-actions already solves the same root cause, more completely:

  • Wait for every sibling language leg to start — holds every leg until all are out of the queue, citing the same aggregate check opened 06:09:39 / closed timed_out 06:09:41 evidence.
  • A SLOWEST_LANGUAGE upload gate — the generalized form of what this PR proposed, which additionally handles a sibling leg that ends without success, an unclassifiable jobs payload, and release refs. This PR hardcoded matrix.language != 'javascript-typescript'.

Re-adding the step would layer a second, narrower wait on top of a better one — the "serializing trades timed_out-on-the-largest-PRs for timed_out-on-every-PR" tradeoff that file's own comments warn against. So I made no code change, and the worktree is left clean.

Why not just merge it: the only payload is a Graphify snapshot re-key, so merging retires the base branch's active snapshot and installs this branch's — zero controller change, under a title claiming a fix the commit no longer contains. The changelog would credit a repair that merged as a no-op.

The reason this redundant PR never closed itself (Graphify refreshes keep the diff non-empty) is already fixed in open repair #724, so I deliberately did not write a rival controller fix for those lines.

Checks were all green and CodeQL reported 0 open alerts on this head — nothing to diagnose or dispose.

@github-actions

Copy link
Copy Markdown
Contributor

Lopu review — this PR is now a no-op and should be closed as superseded.

I compared head ebce0b11 against its base github-actions @ 3ce68d55. This PR no longer contains the fix it describes:

  • The .github tree at head is byte-identical to base — both hash da9d6e46. git diff base..head -- .github/ is empty.
  • Every one of the 10 changed files is a generated graphify-out/ snapshot.
  • The original payload landed in 5bc552bf (+70 lines in .github/workflows/codeql-analysis.yml, step Let the slowest language open the aggregate check). The AI-resolved conflict merge c80e2312 removed all 54 surviving lines of it (-54/+262 on that file) and took the base side instead.

That merge resolution was correct — do not restore the hunk. Base already implements this exact guard, better, at codeql-analysis.yml:438: Hold the faster analysis until the slowest language lands, same if: matrix.language != 'javascript-typescript' condition and same purpose (let the slow language open the aggregate check so the skew collapses). It adds three things this PR's version lacked:

  1. a per-attempt baseline from run_started_at, so a re-scan of an already-analyzed SHA cannot be released instantly by a stale analysis from an earlier attempt (the Components library: /components page, component thing kind, 1000-component catalog #291 failure mode);
  2. a bounded sibling_grace window, so the case where neither leg uploads idles ~3 min rather than the full ceiling;
  3. an explicit 20-minute deadline below the job's own 60-minute timeout.

That guard reached base as a16fc8ba, merged in #663, which is an ancestor of this PR's base. So the defect this PR was opened for — the aggregate CodeQL check closing timed_out on matrix language skew — is already fixed on github-actions.

Restoring the dropped step would re-add a weaker duplicate of a guard that is already live, putting two independent waits on the same matrix leg. I made no code change here; there is no defect left on this branch to repair.

Validation run: .github tree-hash comparison base vs head, git diff --name-only base..head (generated snapshots only), presence of the superseding step at head, and yaml.safe_load of codeql-analysis.yml (parses; jobs scope, analyze).

Recommended disposition: close #686 as superseded by #663. Its remaining diff is only a graphify refresh and carries no controller change worth merging.

@github-actions

Copy link
Copy Markdown
Contributor

Lopu review — this fix has already landed; the PR is now empty

I compared head ebce0b11 against github-actions @ 3ce68d55. This PR's body states "File changed: .github/workflows/codeql-analysis.yml (only)" — but that file is not in the contributed diff:

$ git diff 3ce68d55..HEAD --name-only -- . ':(exclude)graphify-out/**'
(empty)                     # 0 files

Every commit on this head that touched codeql-analysis.yml (c5e8b443, a3ca46f0, 6a84863f, de924899, c2c5da8c, 2a621555, a16fc8ba, db975652) is already an ancestor of the base. The fix reached github-actions through the sibling repairs merged into it:

3ce68d55 Merge pull request #671 from lopugit/lopu/workflow-check-fix-34009290475
32eb3c80 Merge pull request #663 from lopugit/lopu/workflow-check-fix-33997069565
99d1ec11 Merge pull request #677 from lopugit/lopu/workflow-check-fix-34033623289

I confirmed the mitigation is genuinely present rather than merely claimed, by reading the base's own codeql-analysis.yml: the slowest-language SARIF upload barrier sits at ~413–447 with its $SLOWEST_LANGUAGE wait and warning paths at 505–593, and the scope pre-flight guard at 135–201 documents the same timed_out hazard.

Independent corroboration: gh pr checks 686 on this head is 23 pass / 58 skipping with nothing failing, cancelled, or timed out — the aggregate-check timeout this PR was opened to fix no longer reproduces.

The ten remaining files are five graphify-out/cache/semantic-cas/v1/** entries plus a snapshot swap (4f485494…2e779517…).

Recommendation: close without merging. The diagnosis in this body was correct and was acted on. Leaving it open costs an ~81-check matrix and a Lopu review session per wake-up to re-review an empty control-plane diff. I made no changes and wrote no lopu-workflow-fix.md, since no uncovered controller defect remains.

— Lopu, automated repository review

@lopugit lopugit closed this pull request by merging all changes into github-actions in 45f6327 Sep 11, 2026
@github-actions github-actions Bot removed lopu: mergeable The PR branches can currently be merged without conflicts lopu: overlapping files This PR changes files also changed by another open PR labels Sep 11, 2026
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