fix(actions): Lopu repairs failed PR checks - #432
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 review selector must fail closed on an unrouted event
Found while reviewing PR #428 (
codex/lopu-default-listener-parity), whichactivates a
workflow_runtrigger on the default-branch Lopu PR managerlistener.
Diagnosis
.github/workflows/resolve-pr-conflicts.yml→ jobreview_detect→ stepSelect one Lopu review scope derived its candidate set with an unconditional
fallback:
Product-branch listeners are metadata-only by design: they carry triggers and
permissions and call this file pinned at
@github-actions. A listenertherefore cannot know which revision of the controller it is calling. When a
listener activates an event this controller does not yet route, no
SELECTED_PR/SELECTED_BRANCHcan be derived, execution reached the bareelse, andreview_handoffdispatched a repository-wide Lopu review — onemodel session covering every eligible open PR (79 at the time of writing) —
for each such signal. The control plane failed open on exactly the input it
understood least.
This is a defect class, not a single-event bug.
route'sifhas per-eventadmission gates for
issue_comment,pull_request_review_commentandcheck_run;detect,manage_rebasesandreview_detecteach excludespecific known events. Nothing established a default for an event nobody had
enumerated yet.
PR #428 is the live trigger. It adds
to
main's listener, while the routing implementation is still open in PR #429against
github-actions.github-actions@cb7e6f2acontains exactly oneoccurrence of the string
workflow_run— a comment. If #428 merges first,every completed run of those workflows on any branch — successes
included, since
on:cannot filter a conclusion — enters this controller andescalates to an all-PR review. Those nine workflows produced 348 runs in the
preceding 24 hours (
Lopu CodeQL all branches157,Develop S3 PR preview85,
Build all branch44,Web CI33,Signed Electron PR Release15,Workflow control-plane CI14). Concurrency bounds how many run at once, sothe failure mode is a permanently saturated Lopu fleet rather than a fork bomb,
but targeted PR reviews would queue behind repo-wide sweeps indefinitely.
Merge order was the only thing standing between the repository and that state,
and merge order across two different base branches is not expressible in
GitHub. The fix belongs in the controller, not in a merge-sequencing
convention.
Change
One
elif/elseinreview_detect's scope selector(
.github/workflows/resolve-pr-conflicts.yml):candidates="$open"for the two signals that legitimately mean everyopen PR: a blank
workflow_dispatch(operator recovery and the internalbatch worker), and a
pushtogithub-actions(a new resolver revisionworth re-applying everywhere).
::notice::, setsany=falseand exits 0.review_handoffneedsany == 'true', so noworker is dispatched and no model tokens are spent.
Deliberately out of scope: the
workflow_runrouting itself. PR #429 alreadyimplements it correctly (
routeconclusion gate,workflow_run.pull_requests[0].numberas the review selector,
workflow_runexcluded fromdetectandmanage_rebases, source run id preserved for log diagnosis). This change isthe default-deny underneath it and is written to merge cleanly alongside #429 —
it touches the shell body of the step, roughly 20 lines below the
SELECTED_PR:env line that #429 edits.manage_rebaseswas checked and already fails closed:rebase-pr-stacks.yml'sevent
caseends in*) candidates='[]' ;;.detectstill runs for anunrouted event, but its scope collapses to "PRs based on
github.ref_name",which is API-only, idempotent, concurrency-serialized and identical to work the
half-hourly sweep already does. #429 removes that residual churn properly.
Validation
Run in
$GITHUB_WORKSPACE/trusted:ruby -ryamlload (aliases: true)python3 -c "yaml.safe_load(...)"git diff --checknode --checkover every.github/scripts/*.mjsbash -nover every.github/scripts/*.shnode .github/scripts/resolve-pr-conflicts-routing-contract.mjs --self-testnode .github/scripts/workflow-control-plane-contract.mjs --self-testnode .github/scripts/promotion-worker-routing-contract.mjs --self-testnode .github/scripts/build-all-branch.mjs --self-testnode .github/scripts/classify-claude-credential-failure.mjs --self-testnode .github/scripts/electron-pr-release-contract.mjsbash .github/scripts/promotion-worker-contract.shbash .github/scripts/rebase-ownership-routing-contract.shBehavioural test: the Select one Lopu review scope step body was extracted
from the YAML with
yaml.safe_load(the real step, not a paraphrase) and runagainst a stubbed
ghreturning three eligible open PRs, before and after thechange.
Before (
github-actions@cb7e6f2a), unroutedworkflow_run:After, across every event shape the job admits:
Every previously working scope is preserved; only the unrouted fallthrough
changes, from "review everything" to "do nothing, and say so".
Source Lopu workflow run