Bump baked version in install scripts, CD workflow default, and
README examples to 0.7.1 so the release pipeline picks up the
correct version. Add docs/0.7.1-coord-norm-fixes.md documenting
all fixes in this release.
- Change issue-autofix concurrency group from global `qwen-autofix-issue`
to per-issue `qwen-autofix-issue-${{ issue_number }}`, allowing multiple
issues to be fixed in parallel instead of serializing all runs.
- Add concurrency group to the route job with `cancel-in-progress: true`,
so stacked empty runs from rapid label events cancel each other instead
of queuing up (previously 9+ runs queued for 39+ minutes).
- Add `assigned` event trigger: when an issue is assigned to the autofix
bot, the route job routes directly to the issue phase, bypassing the
label gates. The assignee itself serves as the trust signal.
Co-authored-by: Qoder <noreply@qoder.com>
Suggestion-level findings were routed to a single updatable issue comment
(the "suggestion summary") while only Critical findings became inline review
comments. That split traded away two things that turned out to matter more
than the convergence it bought:
- An issue comment has no lifecycle. GitHub folds an inline review thread away
as Outdated once the author edits the line it is anchored to, so an addressed
finding removes itself from the page. The summary comment just sits in the PR
conversation forever; PATCHing it to "all addressed" replaces its content but
not the comment. The mechanism meant to prevent clutter was the clutter.
- A Markdown table cannot carry a one-click fix. GitHub renders a ```suggestion
fence as an applicable change only inside a review comment on a diff line.
Suggestion findings are exactly the mechanical, localized cleanups that
benefit most from one-click apply, so the split withheld the feature from the
findings that needed it most.
Both severities now post as inline comments, distinguished by a **[Critical]**
or **[Suggestion]** body prefix. The `qwen review post-suggestions` subcommand
and its plumbing are removed.
Follow-on changes required by the reroute:
- pr-context: the "Previous suggestion summary" section is gone. Legacy summary
comments are still recognised so they stay out of "Already discussed", but the
exclusion is now marker-only rather than author-gated. The author check missed
summaries posted by the *other* identity: /review runs as a maintainer locally
and as qwen-code-ci-bot in CI, and roughly half of the last 60 PRs carry a
bot-authored summary. Those leaked into "Already discussed" and told the review
agents not to re-report the findings listed there. The check originally guarded
promotion into a trusted rendering section; that section no longer exists, so
it only gated exclusion, where a third party embedding the marker merely hides
their own comment.
- qwen-autofix: the workflow filters "suggestion summaries" out of the autofix
bot's actionable queue, but only on the issue-comment channel. With Suggestions
now inline, they entered the unfiltered inline channel and the bot would apply
non-blocking recommendations and spend a review round on them. The inline
channel now applies the same gate, keyed on the **[Suggestion]** prefix plus
the /review footer so a human quoting the prefix stays actionable.
- Step 7 gains a 422 fallback. Create Review is all-or-nothing, so one Suggestion
anchored outside the diff would take the Critical findings down with it — a risk
that did not exist when Suggestions travelled on a line-agnostic issue comment.
GitHub's 422 does not name the offending entry, so the model rechecks anchors
against the diff, relocates failing Criticals into the body, discards failing
Suggestions, and degrades to an all-prose review rather than posting nothing.
COMMENT reviews now always carry a one-line body: an empty body is only known
to be accepted alongside inline comments on REQUEST_CHANGES, and a Suggestion-
only review is the common case for a clean PR.
* fix(ci): detect silent triage failures with empty-response check
The qwen-triage workflow relied on qwen-code-action to surface failures,
but when the CLI exited 0 with empty output the step reported success
with no triage comments posted. Add a post-step that checks the action's
summary output and fails the job if it is empty, making silent failures
visible in the Actions log.
Defense-in-depth for QwenLM/qwen-code#6553 (primary fix in
qwen-code-action).
* ci: bump qwen-code-action pin to 6d08e91
Picks up the stderr visibility fix (QwenLM/qwen-code-action#12) that
always emits stderr to the step log and warns on empty responses.
Bumps all 5 workflows pinned to the action.
* fix(ci): pass triage summary through env
* Initial plan
* fix(ci): add retry logic to VSCode IDE Companion publish steps
The publish step failed due to a request timeout when publishing the
universal VSIX to the VS Code Marketplace. Add retry logic (up to 3
attempts with 15s delay) to both the Microsoft Marketplace and OpenVSX
publish steps to handle transient network failures gracefully.
Closes#6550
* fix(ci): make OpenVSX publish retries idempotent
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: yiliang114 <effortyiliang@gmail.com>
* perf(ci): optimize autofix pipeline — fast-track, skip duplicate build, scoped tests (#6196)
Three optimizations to reduce autofix wall-clock from ~48 min to ~28-35 min:
1. Fast-track decision: skip LLM assessment for trusted triggers
(workflow_dispatch with explicit issue, issues:labeled event).
2. Skip duplicate build: set QWEN_SKIP_PREPARE=1 so npm ci does not
re-run the prepare hook that builds+bundles before the explicit
build step.
3. Scoped verification tests: run only changed-file tests via
--changed instead of full per-package suites. Full regression
is covered by regular CI on the PR.
Also hardens live test gating (require QWEN_CODE_RUN_LIVE_TESTS=1)
and increases crawler test timeout to 30s.
* refactor(ci): simplify verification gate package discovery
Replace 30-line inline Node script with the original one-liner
`grep -oE '^packages/[^/]+'`. The Node script checked for
package.json existence and test scripts, but `--if-present` already
handles missing test scripts and all workspace dirs have package.json.
Addresses design-review item #7.
* fix(ci): tighten autofix changed-test gate
* fix(ci): require maintainer-applied `autofix/approved` label for tier-1 fast-path
The scheduled scan and `issues:labeled` event paths in `qwen-autofix.yml`
previously trusted the `status/ready-for-agent` label alone, which is
applied by an LLM reading untrusted issue text. An attacker could craft
issue content to trick the triage LLM into labeling it ready, bypassing
human review.
Introduce an `autofix/approved` label that only maintainers (write+
permission) can apply. Both the cron scan and event-triggered paths now
require this label alongside `status/ready-for-agent` before entering the
autonomous fix pipeline (dual-factor: LLM signal + human confirmation).
Also:
- `release.yml` automatically adds `autofix/approved` on workflow-created
release-failure issues (trusted source, preserves existing automation)
- Forced-issue path (non-dispatch) also checks for the new label
- Claim step strips `autofix/approved` to keep processed issues clean
Closes#5634
* fix(ci): address autofix approval review
* fix(ci): address autofix approval follow-ups
* test(ci): cover autofix approval gate
* fix(ci): harden autofix approval revalidation
* fix(ci): avoid autofix approval retry loop
* fix(ci): harden autofix claim handling
* fix(ci): clarify autofix reapproval label
* fix(ci): make autofix claim label update non-destructive
The macOS audio prebuild job now packages both arm64 and x64 slices from the macos-14 runner, but the artifact name still advertised only arm64. Add a matrix suffix so that upload-artifact names the macOS bundle accurately while leaving other platform names unchanged.
Constraint: Existing collect job downloads prebuilds-* and should not need a pattern change
Confidence: high
Scope-risk: narrow
Tested: actionlint v1.7.7 .github/workflows/audio-capture-prebuilds.yml
Tested: node YAML parse for .github/workflows/audio-capture-prebuilds.yml
Tested: git diff --check
git diff --quiet exits 0 when only CRLF normalization differs (content
is identical after filter), so the conditional git restore was skipped
even though the working tree was dirty. This caused git checkout -B to
fail on NOTICES.txt. Remove the conditional guard so restore always runs.
Co-authored-by: Qwen Autofix <qwen-autofix@alibaba-inc.com>
These jobs transitively depend on precheck-pr via authorize. precheck-pr
is intentionally skipped for same-repo PRs (only runs for forks). Without
always(), GitHub Actions' default behavior propagates the skipped upstream
job, causing delay-automatic-review to be skipped even when authorize
succeeds. This breaks the entire review chain for same-repo PRs on
opened/synchronize events.
Fixes PR #5629 review not triggering.
* fix(ci): allow triage for fork PRs that pass safety precheck
Fork PRs by non-write authors were blocked from triage even when the
safety precheck passed, because the authorize job gates on write
permission. Triage is read-only (checks out trusted base code, reads PR
via API), so precheck pass is sufficient to run it safely.
Split the pull_request_target and issue_comment authorization paths:
- pull_request_target: accept write permission OR precheck pass
- issue_comment /triage: still require write permission on the commenter
tmux-testing is unchanged — it executes PR code and must keep the write
permission gate.
* fix(ci): allow prechecked fork PR automation
* docs(ci): clarify PR review authorization routing
* test(ci): guard fork precheck authorization
* fix(ci): tighten fork precheck review guards
* test(ci): guard review-request authorization
* fix(ci): use CI_BOT_PAT for precheck comment on fork PRs
The precheck workflow's "Upsert/Clear manual approval comment" steps
fail with HTTP 403 on fork PRs because `github.token` from
`pull_request_target` via `workflow_call` lacks sufficient permissions
to read/write issue comments.
- Use `secrets.CI_BOT_PAT || github.token` for the comment steps
- Add `secrets: inherit` to both caller workflows so the reusable
workflow can access CI_BOT_PAT
- Drop the `.user.login == "github-actions[bot]"` filter from the jq
query since the HTML comment marker is sufficient and the posting
user may differ depending on which token is used
* fix(ci): scope precheck comment dedup to known bot users
Narrow the jq filter to match comments from github-actions[bot],
qwen-code-ci-bot, or any Bot-type user — prevents a manually posted
marker from hijacking the dedup logic.
* ci: pass only precheck bot token
* ci(workflows): remind authors not to force-push active PRs
Add a workflow that detects force-pushes (rebase/amend/reset) to open PRs
via the pull_request_target synchronize event and posts a one-time,
bilingual reminder that force-pushing invalidates existing review comments
and that the integration bots squash all changes into a single commit
automatically. A normal push (compare status "ahead") is ignored; the
reminder is posted at most once per PR, bot-initiated pushes are skipped,
and a failed compare is treated conservatively (no comment).
* ci(workflows): address review — add issues:write, serialize without cancel
- Add `issues: write`: the listComments/createComment calls go through the
Issues API; declaring it matches the repo's other PR-commenting workflows
and avoids any risk of a 403 making the workflow inert.
- Set `cancel-in-progress: false`: an in-flight run that already detected a
force-push must finish and post. The concurrency group still serializes
runs per PR, and the once-per-PR marker prevents duplicates, so later
pushes queue and then no-op instead of cancelling (and silently dropping)
a pending reminder.
* ci(workflows): harden force-push detection per review
- Marker dedup now requires the comment to be from github-actions[bot], so a
user pasting the marker string into a comment can't suppress reminders.
- Skip known automation logins (qwen-code-dev-bot et al.) that push via PAT as
sender.type 'User', not just GitHub App bots (mirrors qwen-autofix KNOWN_BOTS).
- Narrow the compare catch to 404 (orphaned old tip -> skip); rethrow other
errors so auth/rate failures go red instead of silently no-op'ing.
- Wrap createComment with structured error logging + rethrow.
Kept 3-dot compare and base-repo owner: verified that 3-dot returns
diverged/behind for force-pushes and that the base repo resolves fork-PR
commits, while the suggested 2-dot syntax 404s in the REST API.
* test(ci): add structural test for the force-push reminder workflow
- Add scripts/tests/pr-force-push-reminder-workflow.test.js (runs under
test:scripts, which CI chains into test:ci). It asserts the trigger, repo
guard, permissions, serialized concurrency, KNOWN_AUTOMATION sync with
qwen-autofix, the 3-dot compare on the base repo, 404-vs-rethrow, the marker
author check, and the bilingual body — locking in the reviewed behaviors.
- Wrap the listComments paginate call in the same core.error + rethrow the
other two API calls already use.
- Note that KNOWN_AUTOMATION must stay in sync with qwen-autofix.yml KNOWN_BOTS.
* ci(workflows): drop concurrency group, rely on marker for idempotency
A concurrency group keeps at most one pending run per group, so a burst of
pushes can cancel a still-pending force-push run before it reaches the script,
dropping the reminder this workflow exists to post. Remove the group entirely:
every synchronize event now runs independently and is always evaluated, and the
once-per-PR marker provides idempotency. A rare double-post on two
near-simultaneous first force-pushes is the acceptable cost of never silently
missing one. Update the structural test to assert there is no concurrency block.
The reviewer's suggested `queue: max` is not a valid GitHub Actions concurrency
key (only `group`/`cancel-in-progress` are allowed) and fails actionlint.
* test(ci): use Qwen Team header and assert the dedup skip path
- Switch the copyright header to the prevailing `Qwen Team` (14 of 17 sibling
test files use it; this file had copied an older Google LLC header).
- Assert the idempotency skip log line so removing the marker guard fails a test.
* test(ci): mechanically enforce KNOWN_AUTOMATION sync with qwen-autofix
Read qwen-autofix.yml's KNOWN_BOTS and assert each login is also skipped here,
so adding a bot there without updating this workflow fails the test instead of
silently drifting. Replaces the hardcoded login list whose comment overclaimed
that the sync was verified.
* ci(autofix): loosen issue candidate filters so the agent finds work
The scheduled issue phase had been finding 0 candidates on every run. Tier-1
requires the rarely-applied status/ready-for-agent label, and tier-2's
"unattended = no human comment at all" rule fought its ">2 days old" age
gate: on a busy repo every aged bug already has a community reply, so the
funnel collapsed (128 aged bugs -> 0 survivors) purely on the comment rule.
- Unattended now keys off maintainer engagement (OWNER/MEMBER/COLLABORATOR
comments, excluding our own bots), not any human comment. Community
"+1"/"me too" no longer disqualifies an issue.
- Tier-1 and tier-2 are always both gathered (tier-1 prioritized, then
de-duped by number) so a single weak ready-for-agent issue can't starve
the run.
- Tier-2 scans a bounded age window via MIN_ISSUE_AGE_DAYS..MAX_ISSUE_AGE_DAYS
(1..15) to focus on fresh, settled bugs instead of an unbounded set.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(ci): preserve autofix issue tier priority
* fix(ci): keep ready autofix issues in tier one
* fix(ci): reserve autofix tier two slots
* fix(ci): tolerate tier two autofix scan failures
* fix(ci): tolerate tier one autofix scan failures
* fix(ci): harden autofix candidate merging
* fix(ci): harden autofix issue scanning
* fix(ci): harden autofix diagnostics
* fix(ci): skip unsafe autofix comment fallbacks
* fix(ci): drop unused autofix comments payload
* test(ci): strengthen autofix comment refresh guard
* test(ci): satisfy autofix workflow lint
* test(ci): tighten autofix tier two assertion
* test(ci): cover autofix tier merge guards
* test(ci): cover autofix unattended filter
* fix(ci): summarize autofix comment refresh drops
* fix(ci): bound autofix tier-2 comment-refresh API calls
Cap the tier-2 issues fed into the comment-refresh loop to 15 (a margin
above the ~10 ever selected, since filter_unattended_candidates drops
attended issues afterward) and request full pages with per_page=100, to
avoid GitHub secondary rate limits. Add workflow tests asserting the
forced-issue skip/in-progress exclusion and the tier-2 ready-for-agent
label exclusion stay in place.
Co-Authored-By: Qwen-Coder <noreply@qwen.ai>
* fix(ci): refresh all scanned tier-2 autofix issues, not just first 15
The previous change capped comment-refresh to the first 15 tier-2 issues
before filter_unattended_candidates runs. The scan still fetches 30, so
valid unattended bugs at positions 16-30 were never refreshed nor
filterable: if the first 15 were all maintainer-attended/dropped, the run
could end with zero candidates again — the failure this PR set out to fix.
Drop the .[0:15] refresh cap and refresh the full scanned set (already
bounded by --limit 30 on the scan). per_page=100 stays as the
pages-per-issue rate-limit mitigation, and the drop summary total/counters
reflect the full refreshed set again. Top-N selection after filtering is
unchanged.
Co-Authored-By: Qwen-Coder <noreply@qwen.ai>
* fix(ci): order tier priority before recency in autofix assess prompt
The assess prompt gave two conflicting selection rules: the tier note says not to pick a tier-2 issue over a comparably actionable tier-1 one, while the recency tiebreaker says to prefer the most recently reported. Since tier-1 has no age bound and tier-2 is the recent (1-15 day) tier, these point in opposite directions for comparable confidence. Make recency apply only after the tier preference and only within the same tier, removing the contradiction. Prompt text only; no shell/jq change.
Co-Authored-By: Qwen-Coder <noreply@qwen.ai>
* fix(ci): guard forced-issue jq and derive autofix comment scratch path
Address two review suggestions on the autofix candidate scan step.
- Wrap the forced-issue candidate jq in the same error guard the other
jq calls use (tier-1/tier-2 stamp, tier merge): on malformed
forced-issue JSON it now emits a :⚠️: and falls back to an empty
candidate list instead of silently producing an empty candidates.json
with no diagnostic.
- Make refresh_issue_comments reuse-safe by deriving its NDJSON scratch
path from the output_file parameter (${output_file%.json}.ndjson)
instead of hardcoding tier2-with-comments.ndjson, so a second call or a
different tier can't clobber a shared scratch file. Behavior for the
current single call is unchanged.
Co-Authored-By: Qwen-Coder <noreply@qwen.ai>
---------
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: Qwen-Coder <noreply@qwen.ai>
Large PRs with extensive diffs across multiple packages can exceed
the 85-minute effective review window (90 - 5 buffer). The recent
run #28318973107 timed out on PR #5777 which touched acp-bridge,
serve, config, and chrome-extension packages.
Bump both the job timeout-minutes and the validation cap to 120 so
the review agent has enough headroom for complex multi-package PRs.
* Upgrade GitHub Actions to latest versions
Signed-off-by: Salman Muin Kayser Chishti <13schishti@gmail.com>
* ci: restore ratchet annotations on upgraded actions
The action version bumps had replaced '# ratchet:owner/repo@<ver>'
annotations with bare '# vX.Y.Z' comments, which silently breaks
ratchet's ability to track and update these SHA pins. Restore the
annotations on every changed line (updated to the new major), matching
each line's pre-existing convention on main.
---------
Signed-off-by: Salman Muin Kayser Chishti <13schishti@gmail.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
Co-authored-by: yiliang114 <effortyiliang@gmail.com>