ci: isolate per-run agent state for triage and PR review (#5885)

Both the triage job and the PR-review job run the qwen agent directly on
the persistent self-hosted ECS pool with no per-run isolation. $HOME,
/tmp and the workspace are reused between runs, so a prior run's agent
session/memory (default ~/.qwen) or leftover draft comments
(/tmp/stage-*.md, which survive git clean) can bleed into the next run.

This surfaced on #5874: its triage posted #5872's review verbatim
(wrong author, wrong approver, wrong diff), while the same run's internal
stage actually exercised #5874 — the PR id was correct, the agent state
was stale.

Point QWEN_HOME at a per-run $RUNNER_TEMP/qwen-home on the Qwen step and
reset it (plus /tmp/stage-*.md) in the pre-run cleanup, for both jobs.
QWEN_HOME relocates the entire global qwen dir (storage.ts), so this
isolates sessions/memory/temp without touching $HOME and disturbing
git/npm. The tmux-testing job is already container-isolated and unchanged.

Refs #5882
This commit is contained in:
易良 2026-06-26 15:09:27 +08:00 committed by GitHub
parent 953f1b4ca6
commit 91bf331cc6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 34 additions and 10 deletions

View file

@ -326,12 +326,20 @@ jobs:
pull-requests: 'write'
issues: 'write'
steps:
# Self-hosted runners reuse the workspace, so an interrupted review can
# leave a stale `.qwen/tmp/review-pr-*` worktree or `qwen-review/*` branch
# that trips the checkout below. Prune defensively; never fail the job.
- name: 'Clean stale review worktrees'
# Self-hosted runners reuse $HOME, /tmp and the workspace, so a prior run
# can bleed into this one: its agent session/memory (under QWEN_HOME),
# leftover draft comments (/tmp/stage-*.md, which survive `git clean`), or
# a stale `.qwen/tmp/review-pr-*` worktree / `qwen-review/*` branch from an
# interrupted review. Reset all three per run; never fail the job.
- name: 'Clean stale agent state'
run: |-
set -uo pipefail
# Fresh per-run agent home (must match QWEN_HOME on the Qwen step
# below) + drop any leftover stage drafts.
QWEN_HOME="${RUNNER_TEMP:?}/qwen-home"
rm -rf "$QWEN_HOME" 2>/dev/null || true
mkdir -p "$QWEN_HOME"
rm -f /tmp/stage-*.md 2>/dev/null || true
# `.git` is a directory in a normal checkout but a gitlink file in a
# worktree; -e covers both, and a missing .git (first run) too.
if [ ! -e .git ]; then
@ -409,6 +417,10 @@ jobs:
PR_NUMBER: '${{ steps.context.outputs.pr_number }}'
REVIEW_MODE: '${{ steps.context.outputs.review_mode }}'
TIMEOUT_MINUTES: '${{ steps.context.outputs.timeout_minutes }}'
# Per-run agent home so this review's session/memory cannot leak into
# the next on the reused self-hosted workspace (reset in "Clean stale
# agent state"). Must match the QWEN_HOME computed there.
QWEN_HOME: '${{ runner.temp }}/qwen-home'
run: |-
set -euo pipefail
fail() {

View file

@ -195,13 +195,21 @@ jobs:
-f content='eyes' > /dev/null ||
echo "Failed to add triage acknowledgement reaction; continuing." >&2
# Self-hosted ECS runners reuse the workspace between runs, so an
# interrupted triage (its agent has enter_worktree/exit_worktree) can
# leave a stale `.qwen/tmp/*` worktree that trips the checkout below.
# Prune defensively; never fail the job. No-op on a fresh hosted runner.
- name: 'Clean stale triage worktrees'
# Self-hosted ECS runners reuse $HOME, /tmp and the workspace between runs,
# so a prior run can bleed into this one: its agent session/memory (under
# QWEN_HOME), leftover draft comments (/tmp/stage-*.md, which survive
# `git clean`), or a stale `.qwen/tmp/*` worktree from an interrupted
# triage (its agent has enter_worktree/exit_worktree). Reset all three
# per run; never fail the job. No-op on a fresh hosted runner.
- name: 'Clean stale agent state'
run: |-
set -uo pipefail
# Fresh per-run agent home (must match QWEN_HOME on the Qwen step
# below) + drop any leftover stage drafts.
QWEN_HOME="${RUNNER_TEMP:?}/qwen-home"
rm -rf "$QWEN_HOME" 2>/dev/null || true
mkdir -p "$QWEN_HOME"
rm -f /tmp/stage-*.md 2>/dev/null || true
# `.git` is a directory in a normal checkout but a gitlink file in a
# worktree; -e covers both, and a missing .git (first run) too.
if [ ! -e .git ]; then
@ -210,7 +218,7 @@ jobs:
fi
rm -rf .qwen/tmp/* 2>/dev/null || true
git worktree prune -v || true
echo "stale triage worktrees cleaned"
echo "stale agent state cleaned"
- name: 'Checkout repo'
uses: 'actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd' # v6.0.2
@ -234,6 +242,10 @@ jobs:
GITHUB_TOKEN: '${{ secrets.QWEN_CODE_BOT_TOKEN || secrets.CI_BOT_PAT }}'
GH_TOKEN: '${{ secrets.QWEN_CODE_BOT_TOKEN || secrets.CI_BOT_PAT }}'
REPOSITORY: '${{ github.repository }}'
# Per-run agent home so this run's session/memory cannot leak into the
# next on the reused self-hosted workspace (reset in "Clean stale
# agent state"). Must match the QWEN_HOME computed there.
QWEN_HOME: '${{ runner.temp }}/qwen-home'
with:
OPENAI_API_KEY: '${{ secrets.OPENAI_API_KEY }}'
OPENAI_BASE_URL: '${{ secrets.OPENAI_BASE_URL }}'