Conversation
Lopu repository reviewLopu 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 #395 · fix(actions): Lopu repairs failed PR checksCompared: The failing check — stale, already fixed, not caused by this PR
The cause is GitHub's concurrency queue. That was fixed on
The red check predates its own fix by 44 minutes. It is a stale artefact of I verified Deliberately took no action. The remedy is a re-run or the next push, and Residual note for the maintainers, not a blocker: "Build all branch" is still Findings on the change itselfThe fix is correct and the reasoning in the added comment is accurate.
Points I checked rather than assumed:
Minor, not worth changing: Changes madeNone. The diff is correct as written and the red check is a stale Validation run
CodeQLThree open alerts on this head, all in the protected control plane. Disposed (1):
Left open (2) — both stay open on purpose:
|
🦉 Lopu — diagnosis confirmed against live runsI tried to falsify this one rather than take the description at face value, and the fingerprint is exactly as stated. On PR #135's head Both resolved to This fix currently unblocks three PRs in the open set. #135, #373 and #382 all carry red Two things I checked and liked:
One non-blocking note: concurrency group names cap at 255 chars, and the new group embeds the branch name twice plus a ~68-char workflow path. At current branch lengths (~30–45) worst case lands near 200, so there's headroom — but a ~75-char branch name would cross it. Using just the Also worth knowing: this is complementary to #404, not overlapping. #404 deletes No changes made — the fix is minimal and correctly scoped. |
|
🤖 Lopu — diagnosis verified independently; still needed; the one red mark is a stale cancellation I re-derived both load-bearing claims rather than taking the description's word for them, and they hold. Two push-triggered callers, confirmed. And I found where the second push caller actually lives — it is not That is what makes this fix the valuable one right now. #404 removes the duplicate listener going forward; your change fixes the engine's group on
Scoping is right in both directions. Only the detect namespace gains the caller key; Still needed: I checked The red check is not a failure. CodeQL on this head — 3 alerts, all inherited from
|
|
🦉 Lopu — extra evidence for the Reviewing #400 I traced the aggregator cancellation you documented under "Deliberately NOT changed", and the observed rule is stricter than the "newer run supersedes" framing — worth pinning down before someone designs the follow-up reporting PR around recency. Today's sweep, all in the Three things follow:
That strengthens your conclusion rather than changing it: the concurrency posture is correct (one force-push owner for one generated branch), and the defect is purely that a by-design supersede is reported as a red PR check. It also means a fix keyed on "was I superseded by something newer?" would mis-report — the honest signals are "this run never started" and "another run in the group owns the union", both available without touching the group. No change made here; recording the measurement so the follow-up PR has it. |
|
🤖 Lopu — re-checked on the current controller: still needed, still correct, and #94 has since been fixed upstream Second pass on this head. The 14 lines are unchanged and I have nothing to add to them — but two things moved underneath this PR since my 09:12 comment, so they are worth recording here. #94 is no longer an open question. I flagged it then as real and fixed through the trusted-controller channel. Confirming on .replace(/`/g, ""); // was: .replace(/`/g, "\\`")with the reasoning committed next to it — GFM does not apply backslash escapes inside code spans, so an escaped backtick still closed the span and the escape never protected anything. Removing the one character that can break out is the right call over escaping it. The alert still rides this PR's snapshot only because the snapshot is pinned to this head; it retires on merge. Nothing to do on this branch. #93 dispositioned false positive, same evidence as before: #95 left open, unchanged position: on this head those lines really are an Validation on this worktreeRan the whole
That suite asserts the detect/worker namespace split directly, so a group expression that broke the intended scoping would have failed it. It didn't. The red check, again
No changes requested. |
|
🤖 Lopu — I could not reproduce the topology this change is built on, and I think this PR should be closed. The comment says the rebase engine has "two push-triggered callers — the dedicated rebase listener and the nested call in
There is no dedicated rebase listener; the engine is reusable-only with exactly one caller. So The two runs the comment describes are real, but they were already separated. From the same push on 2026-08-25T04:16:
And the red check this branch is named after ( The change is harmless, but it fixes nothing and the comment documents a caller topology this repository does not have, which is worse than no comment for whoever reads that group key next. If you would rather keep the branch, the comment needs rewriting; otherwise closing it and tracking the all-branch queue displacement separately is the cleaner outcome. Its 3 CodeQL alerts are all inherited from the stale merge base and are already fixed at the |
|
Closing as superseded by the current reusable protected-controller topology. The assumption this patch was built around no longer exists: the rebase engine has one trusted caller and a stable workflow_ref, so this change would not repair a live failure. This matches Lopu’s latest review on this PR. |
Lopu controller check repair
Lopu identified a failed PR check whose root cause is in the protected controller/workflow code.
Lopu control-plane fix — the rebase detector cancels itself on every push
File changed:
.github/workflows/rebase-pr-stacks.yml(protected reusable engine,github-actionsref)Found while: reviewing PR #387, whose two red checks are caused entirely by this — not by the PR.
Symptom
Every PR carries two permanent red checks that no code change can clear:
control-plane / Find stack members that need rebasing— cancelledcontrol-plane / Hand off to trusted github-actions workers— cancelledgh pr checksrenderscancelledasfail, so they read as failures. They arenot stale, not an outage, and not a flake: 15 of the last 15 push-triggered
runs of
rebase-pr-stacks.ymlwere cancelled, across at least four differentbranches over two days. The detect job records
steps: []— it is cancelledbefore its first step ever runs.
Root cause
The engine is a reusable workflow with two push-triggered callers:
bbffbc3f.github/workflows/rebase-pr-stacks.yml(dedicated listener).github/workflows/resolve-pr-conflicts.yml(nests the engine at its line 561)Both resolve the same concurrency group, because the group interpolated only
github.event_nameand the ref — nothing identifying the caller:With
cancel-in-progress: trueon push, the run created one second latercancels the other. The dedicated detector always loses because
resolve-pr-conflicts.ymlis always queued marginally later by the same push.The pairing is exact — every cancelled run has a
resolve-pr-conflicts.ymlpushrun on the same branch created 0–1s later that succeeded:
The group's own comment states the intent — "Detector runs are safe to
supersede" — which means a detector superseding itself on a newer push, not
two distinct sibling workflows cancelling each other.
Blast radius is a false red, not lost detection. The nested engine call
inside
resolve-pr-conflicts.ymldoes run the same detect job to completion (itpasses on this PR), so stack detection still happens. The damage is that every
PR in the repository permanently displays two red checks, which trains reviewers
to ignore red.
The fix
Add the calling workflow to the detect namespace only:
github.workflow_refinside a called workflow is the caller'sfile@ref.This is not a guess:
resolve-pr-conflicts.ymlalready keys its own concurrencygroup on exactly this discriminator (comparing it against
format('{0}/.github/workflows/resolve-pr-conflicts.yml@refs/heads/develop', …)),so the convention is established in this control plane.
The
ai-rebase-pr-<N>worker namespace is deliberately left not caller-keyed— one history rewrite per PR regardless of who dispatched it — and
cancel-in-progressis untouched.Validation
name: Lopu rebase engine, jobs[route, detect, handoff, rebase]intact.node remix/scripts/workflow-caller-contract.mjs→9 thin listeners pinned to github-actions✅ (the contract governs the thin product-branch callers; this change is callee-side and leaves it green).&&/||operand-returning semantics, run against the two real colliding runs:ai-rebase-detect-push-claude/action-thing-permissions-336bc0— colliderepository_dispatchhistory rewriteai-rebase-pr-387, identical across callers,cancel-in-progress: falseai-rebase-pr-387,cancel-in-progress: false— never cancels itselfDeliberately NOT changed:
all-branch.ymlThe agreed follow-up on PR #387 was described as "the per-PR concurrency-group
improvement for the global
all-branch-workerfalse-red." The global group isreal and it does cancel across branches — confirmed:
But making that group per-PR would be a correctness regression, so I did not
make it.
all-branch.ymlrebuilds one shared generated branch —all=develop + main + every open same-repo PR merged together, deterministic
from-scratch, then force-pushed. Its input is "every open PR", not one
branch. A per-PR group would license N concurrent rebuilds of that single branch,
each force-pushing a different union: last-writer-wins corruption of
all, plusN× the doctor's Claude rounds and Vercel builds.
Because the rebuild is idempotent and from-scratch, superseding an in-flight run
is also correct — the newer run recomputes the current union anyway. The global
cancel-in-progress: truesingleton is the right design here, andcancelledisan accurate status for a deliberately superseded run.
The residual problem is reporting, not concurrency: a by-design supersede
surfaces as a red check on whichever PR happened to trigger it. That deserves its
own PR and a deliberate choice (drop the PR-visible check for the aggregator, or
report a superseded run as neutral) rather than a concurrency change that would
trade a cosmetic red for a corrupted shared branch.
Source Lopu workflow run