-
Notifications
You must be signed in to change notification settings - Fork 3.3k
fix(desktop): stop cancelled desktop CI runs reporting as failures #91373
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -98,8 +98,19 @@ jobs: | |
| runs-on: depot-ubuntu-24.04 | ||
| timeout-minutes: 5 | ||
| steps: | ||
| # A superseded run (cancel-in-progress) cancels its jobs. That is not a | ||
| # test failure, so note it and let the check below pass instead of | ||
| # posting a red required check. cancelled() is true only for a whole-run | ||
| # cancel, so a job-level cancel or timeout still reaches the guards. | ||
| - name: Note run cancellation | ||
| if: ${{ cancelled() }} | ||
| run: echo "RUN_CANCELLED=true" >> "$GITHUB_ENV" | ||
| - name: Check results | ||
| run: | | ||
| if [[ "${RUN_CANCELLED:-}" == "true" ]]; then | ||
| echo "Run was cancelled (superseded); not treating it as a failure." | ||
| exit 0 | ||
| fi | ||
|
Comment on lines
+101
to
+113
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Manual cancellation can make required gates passWhy we think it's a valid issue
Issue description
Suggested fixOnly short-circuit after the workflow proves that a newer run superseded this run. For example, read the pull request's live head SHA and compare it with Prompt to fix with AI (copy-paste)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Confirmed, and this is the better-anchored twin of the skill-file finding — same root cause, pointed at the code where the bypass runs. I'm escalating rather than editing, because the fix has to change CI workflow files and pick a design, neither of which this automated fixer does unattended. What I verified: the What a human needs to decide: whether to drop the |
||
| if [[ "${{ needs.build.result }}" != "success" && "${{ needs.build.result }}" != "skipped" ]]; then | ||
| echo "Desktop build did not succeed (result: ${{ needs.build.result }})." | ||
| exit 1 | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guidance publishes an unsafe required-gate recipe
Why we think it's a valid issue
.github/workflows/desktop-ci.yml:105-113writesRUN_CANCELLED=trueon${{ cancelled() }}and thenexit 0before every dependency guard. GitHub'scancelled()reports that the run was cancelled; it carries no cause, so a person clicking Cancel, an API/gh run cancelcall, and acancel-in-progresssupersede are indistinguishable inside the expression. The PR's stated property, "Only a supersede — which lands on a dead SHA — passes", is therefore false.Desktop * Pass, which only happens because the gate job exits nonzero while the run conclusion iscancelled. By the same path,exit 0posts green..github/workflows/desktop-ci.yml:91-93callsDesktop Tests Pass"the one check name to require in the master ruleset"..github/workflows/desktop-ci.yml:15-19and the child conditions (for example.github/workflows/desktop-build.yml:67) skip every real job onmerge_group, and the gate treatsskippedas success. The PR run is the only place desktop tests execute..github/workflows/ci-backend.yml:1348and:2375rungh run cancel ${{ github.run_id }}after a deterministic repo-check or OpenAPI failure. If the published recipe reaches a gate in that workflow, those deliberate hard failures convert to a green required check.tools/hogli-commands/hogli_commands/workflow_lint/checks/required_gates.py:332-345only asks whether eachneeds.<dep>.resulttextually reaches a guard inside some step; it models no unconditional earlyexit 0that makes those guards unreachable. Its docstring names the exact outcome it exists to block — "green, with zero tests run" — which this recipe reintroduces by a different route. So the PR's "WF007 still passes" evidence proves the guards are present, not that they run.Desktop Tests Passgreen with no desktop build, lint, typecheck, or test executed, and the merge queue does not repeat that work. The change converts a fail-closed merge gate into a fail-open one, and.agents/skills/authoring-ci-workflows/SKILL.md:110-112publishes it as the general pattern for required-check gates.must_fix. The reviewer framed the risk as future copying of unsafe guidance, but the bypass is already live in five gates in this PR, it defeats a required merge gate, and an ordinary human action triggers it.Issue description
This skill presents the cancellation short-circuit as fail-closed guidance. GitHub defines
cancelled()for any workflow cancellation, including a manual cancellation. The recipe can mark an untested required gate green. Future CI authors can copy this bypass into other workflows.Suggested fix
Remove this recipe until the workflow can distinguish a superseded run from other cancellations. Document the broad
cancelled()behavior. Extend WF007 before approving any early success path that bypasses dependency guards.Prompt to fix with AI (copy-paste)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Confirmed — this is a real must_fix, and it's inseparable from the workflow change it documents, so I'm escalating rather than editing the skill in isolation.
What I verified: GitHub's
cancelled()is true for any whole-run cancellation and carries no cause. A superseded run (cancel-in-progress), a person clicking Cancel,gh run cancel, and an API cancel all set it. So the recipe's premise that 'only a supersede passes' does not hold: a manual or scripted cancel on a live head SHA also hits theexit 0short-circuit before any dependency guard runs, leavingDesktop Tests Passgreen with no desktop build, quality, typecheck, or test executed — and on merge queue entries the real jobs are skipped, so nothing re-runs them. That converts a fail-closed required gate into a fail-open one. The skill then publishes this as the general pattern, which is riskier still given the repo already self-cancels on purpose in other workflows.Why I'm not auto-fixing it: a correct fix has to change the five
.github/workflows/**gate files, not just this doc — editing the skill alone would leave the hole live and the PR self-contradictory. Workflow files are outside what this automated fixer may change, and the right fix is a design decision, not a mechanical one: either drop thecancelled()short-circuit, or add a discriminator that GitHub doesn't expose natively (for example comparing the run's head SHA against the branch head to tell a supersede from a live cancel), likely alongside a WF007 extension so the earlyexit 0can't bypass the guards unnoticed. Its correctness can only be proven by a real superseded-run race on GitHub, which this PR did not run.What a human needs to decide: whether to abandon the short-circuit approach or how to safely distinguish a supersede from other cancellations — and only then what this skill should document. This shares its root cause with the companion thread on desktop-ci.yml.