Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 75 additions & 4 deletions .github/workflows/qwen-autofix.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1009,10 +1009,81 @@ jobs:
done
fi

- name: 'Flake detection'
id: 'flake'
if: |-
${{ steps.decision.outputs.go_issue != '' }}
env:
GITHUB_TOKEN: '${{ secrets.CI_DEV_BOT_PAT }}'
ISSUE: '${{ steps.decision.outputs.go_issue }}'
DRY_RUN: '${{ needs.route.outputs.dry_run }}'
run: |-
set -euo pipefail
IS_FLAKE=false

# Only applies to auto-filed CI failure issues.
ISSUE_JSON="$(gh issue view "${ISSUE}" --repo "${REPO}" --json title,body 2>/dev/null || true)"
TITLE="$(jq -r '.title' <<< "${ISSUE_JSON}")"
Comment thread
yiliang114 marked this conversation as resolved.
Outdated
if [[ "${TITLE}" != Main\ CI\ failed:* ]]; then
echo "Not a CI failure issue; skipping flake detection."
echo "is_flake=false" >> "${GITHUB_OUTPUT}"
exit 0
fi

# Extract the failed run ID from the issue body.
BODY="$(jq -r '.body' <<< "${ISSUE_JSON}")"
RUN_ID="$(grep -oP 'Run ID: \K[0-9]+' <<< "${BODY}" || true)"
if [[ -z "${RUN_ID}" ]]; then
echo "Could not extract run ID from issue body; proceeding normally."
echo "is_flake=false" >> "${GITHUB_OUTPUT}"
exit 0
fi

# Get authoritative metadata for the failed run.
RUN_JSON="$(gh api "repos/${REPO}/actions/runs/${RUN_ID}" \
--jq '{name: .name, workflow_id: .workflow_id, branch: .head_branch, event: .event, conclusion: .conclusion, created: .created_at}' 2>/dev/null || true)"
if [[ -z "${RUN_JSON}" ]]; then
echo "Failed to fetch run ${RUN_ID}; proceeding normally."
echo "is_flake=false" >> "${GITHUB_OUTPUT}"
exit 0
fi
if [[ "$(jq -r '.branch' <<< "${RUN_JSON}")" != 'main' ||
"$(jq -r '.event' <<< "${RUN_JSON}")" != 'push' ||
"$(jq -r '.conclusion' <<< "${RUN_JSON}")" != 'failure' ]]; then
echo "Run ${RUN_ID} is not a failed main push; proceeding normally."
echo "is_flake=false" >> "${GITHUB_OUTPUT}"
exit 0
fi
WF_NAME="$(jq -r '.name' <<< "${RUN_JSON}")"
WF_ID="$(jq -r '.workflow_id' <<< "${RUN_JSON}")"
FAILED_AT="$(jq -r '.created' <<< "${RUN_JSON}")"

# Check if any subsequent run of the same workflow on main succeeded.
LATER_GREEN="$(gh api --method GET "repos/${REPO}/actions/workflows/${WF_ID}/runs" \
-F branch=main -F event=push -F status=success -F per_page=100 \
--jq "[.workflow_runs[] | select(.created_at > \"${FAILED_AT}\")] | length" \
2>/dev/null || echo "0")"

if [[ "${LATER_GREEN}" -gt 0 ]]; then
IS_FLAKE=true
echo "✅ Subsequent ${WF_NAME} run(s) on main succeeded — this is a flake."
fi

if [[ "${IS_FLAKE}" == "true" ]]; then
if [[ "${DRY_RUN}" != 'true' ]]; then
gh issue comment "${ISSUE}" --repo "${REPO}" --body "🤖 Closing as a transient CI flake — a subsequent \`${WF_NAME}\` run on \`main\` has already passed. No code fix needed."
gh issue close "${ISSUE}" --repo "${REPO}" --reason 'not planned'
gh issue edit "${ISSUE}" --repo "${REPO}" --add-label 'autofix/skip' 2>/dev/null || true
fi
echo "is_flake=true" >> "${GITHUB_OUTPUT}"
else
echo "is_flake=false" >> "${GITHUB_OUTPUT}"
fi

- name: 'Claim issue'
id: 'claim'
if: |-
${{ steps.decision.outputs.go_issue != '' && needs.route.outputs.dry_run != 'true' }}
${{ steps.decision.outputs.go_issue != '' && needs.route.outputs.dry_run != 'true' && steps.flake.outputs.is_flake != 'true' }}
env:
GITHUB_TOKEN: '${{ secrets.CI_DEV_BOT_PAT }}'
ISSUE: '${{ steps.decision.outputs.go_issue }}'
Expand Down Expand Up @@ -1045,7 +1116,7 @@ jobs:
- name: 'Develop fix'
id: 'develop'
if: |-
${{ steps.decision.outputs.go_issue != '' }}
${{ steps.decision.outputs.go_issue != '' && steps.flake.outputs.is_flake != 'true' }}
env:
ISSUE: '${{ steps.decision.outputs.go_issue }}'
OPENAI_API_KEY: '${{ secrets.AUTOFIX_OPENAI_API_KEY }}'
Expand Down Expand Up @@ -1100,7 +1171,7 @@ jobs:
- name: 'Verification gate'
id: 'verify'
if: |-
${{ steps.decision.outputs.go_issue != '' }}
${{ steps.decision.outputs.go_issue != '' && steps.flake.outputs.is_flake != 'true' }}
env:
ISSUE: '${{ steps.decision.outputs.go_issue }}'
run: |-
Expand Down Expand Up @@ -1218,7 +1289,7 @@ jobs:
- name: 'Publish PR'
id: 'publish'
if: |-
${{ steps.decision.outputs.go_issue != '' && needs.route.outputs.dry_run != 'true' }}
${{ steps.decision.outputs.go_issue != '' && needs.route.outputs.dry_run != 'true' && steps.flake.outputs.is_flake != 'true' }}
env:
# CI_DEV_BOT_PAT opens the PR as the configured autofix bot. This is
# required: the default GITHUB_TOKEN is
Expand Down
37 changes: 37 additions & 0 deletions .github/workflows/qwen-triage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ jobs:
else
echo "number=${{ github.event.issue.number }}" >> "$GITHUB_OUTPUT"
fi
echo "started_at=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$GITHUB_OUTPUT"

# The agent runs as one long step, but its output streams live to the
# Actions log. Post a status comment up front carrying that run link so a
Expand Down Expand Up @@ -576,6 +577,42 @@ jobs:
fi
echo "Triage response received (${#RESPONSE} chars)."

- name: 'Verify triage output posted'
if: 'success()'
shell: 'bash'
env:
GH_TOKEN: '${{ secrets.QWEN_CODE_BOT_TOKEN || secrets.CI_BOT_PAT }}'
NUMBER: '${{ steps.resolve.outputs.number }}'
STARTED_AT: '${{ steps.resolve.outputs.started_at }}'
run: |-
set -euo pipefail
# The agent posts stage=1 unless a terminal gate submits a review.
# A non-empty summary does not prove either one reached GitHub.
BOT_LOGIN="$(gh api user --jq '.login' 2>/dev/null || true)"
STAGE_FOUND="$(
gh api "repos/$GITHUB_REPOSITORY/issues/$NUMBER/comments" \
--method GET --paginate -F per_page=100 2>/dev/null |
jq -rs \
--arg bot "$BOT_LOGIN" \
--arg marker '<!-- qwen-triage stage=1 -->' \
--arg since "$STARTED_AT" \
'[.[][] | select(.user.login == $bot and .updated_at >= $since and (.body | startswith($marker)))] | length'
)" || STAGE_FOUND=0
REVIEW_FOUND="$(
gh api "repos/$GITHUB_REPOSITORY/pulls/$NUMBER/reviews" \
--method GET --paginate -F per_page=100 2>/dev/null |
jq -rs \
--arg bot "$BOT_LOGIN" \
--arg marker '<!-- qwen-triage terminal-review -->' \
--arg since "$STARTED_AT" \
'[.[][] | select(.user.login == $bot and .state == "CHANGES_REQUESTED" and .submitted_at != null and .submitted_at >= $since and (.body | startswith($marker)))] | length'
)" || REVIEW_FOUND=0
if [[ "${STAGE_FOUND}" -eq 0 && "${REVIEW_FOUND}" -eq 0 ]]; then
echo "::warning title=Triage silent gap::Triage produced a summary but no stage comment or review was posted to #${NUMBER}. The agent may have failed at the posting step."
else
echo "Triage output verified (${STAGE_FOUND} stage comment(s), ${REVIEW_FOUND} review(s))."
fi

- name: 'Notify silent triage re-run'
if: >-
success() &&
Expand Down
13 changes: 9 additions & 4 deletions .qwen/skills/triage/references/pr-workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ COMMENT_ID=$(gh api "repos/$REPO/issues/$PR_NUMBER/comments" -F body=@/tmp/stage
**Terminal gate exception:** if any terminal exit triggers (Stage 0 core
module hard block, Stage 1a template failure, Stage 1b problem-does-not-exist,
or Stage 1c direction escalation), submit exactly one `CHANGES_REQUESTED`
review and stop. Do not also post or update a Stage 1 issue comment, and do not
continue to Stage 2, Stage 3, or approval.
review whose body starts with `<!-- qwen-triage terminal-review -->`, then
stop. Do not also post or update a Stage 1 issue comment, and do not continue
to Stage 2, Stage 3, or approval.

**Re-runs:** if the triage runs again on the same PR, update each comment in place. **Resolve the comment id by its stage marker AT PATCH TIME — never from memory, list position, or an earlier stage's bookkeeping.** On a re-run the thread holds four or more bot comments whose list order is not the stage order, and a wrong id silently overwrites another stage's comment (observed on a real re-run: the stage=3 comment clobbered with stage=1 content mid-run). The author filter matters too — the marker is public text anyone can paste into a comment, and the bot PAT may be able to edit other users' comments:

Expand All @@ -49,7 +50,7 @@ PR). Only update issue comments, not PR reviews.
```bash
# Check for existing terminal-exit review before re-submitting
EXISTING=$(gh api "repos/$REPO/pulls/$PR_NUMBER/reviews" \
--jq '[.[] | select(.user.login=="qwen-code-ci-bot" and .state=="CHANGES_REQUESTED")] | length')
--jq '[.[] | select(.user.login=="qwen-code-ci-bot" and .state=="CHANGES_REQUESTED" and (.body | startswith("<!-- qwen-triage terminal-review -->")))] | length')
# Only submit if no existing terminal review
if [ "$EXISTING" -eq 0 ]; then gh pr review ... ; fi
```
Expand Down Expand Up @@ -96,7 +97,7 @@ Core infrastructure: files matching `packages/core/src/**`, `packages/*/src/auth
**Tier 1 — Large-scope `refactor` changes to core → HARD BLOCK.** Applies to non-maintainer PRs only (skip this check if the author is a known maintainer). Hard-block on _size_, not breadth: if a core-path `refactor`-type PR (title starts with `refactor` — `refactor:`, `refactor(scope):`, `refactor(scope)!:`, case-insensitive) totals **500+ production logic lines** (additions + deletions, using the size calculation above) → reject immediately. No evaluation, no Stage 1.

```bash
gh pr review "$PR_NUMBER" --repo "$REPO" --request-changes --body "This refactor touches core infrastructure at scale (N production lines). Core refactors of this size must be maintainer-initiated — please open an issue to discuss the design first."
gh pr review "$PR_NUMBER" --repo "$REPO" --request-changes --body $'<!-- qwen-triage terminal-review -->\n\nThis refactor touches core infrastructure at scale (N production lines). Core refactors of this size must be maintainer-initiated — please open an issue to discuss the design first.'
```

Then **stop**. This is a wall, not a guideline.
Expand Down Expand Up @@ -128,6 +129,8 @@ This is the most important stage — catch problems before anyone spends time re
**1a. Template check:**

PR body missing required headings from `.github/pull_request_template.md` (read from worktree) → request changes, @mention author, link the template, stop. This is the only public output for this terminal gate.
The first line of `/tmp/pr-gate-template.md` must be
`<!-- qwen-triage terminal-review -->`.

```bash
gh pr review "$PR_NUMBER" --repo "$REPO" --request-changes --body-file /tmp/pr-gate-template.md
Expand All @@ -142,6 +145,8 @@ Before "is the direction right?", ask **"does this problem actually exist?"**

```bash
cat > /tmp/stage-1b-reproduction.md <<'EOF'
<!-- qwen-triage terminal-review -->

<!-- qwen-triage stage=1b -->

This PR addresses a theoretical concern — "could theoretically send X" — but
Expand Down
Loading
Loading