qwen-code/scripts
Shaojin Wen c06da8da28
feat(autofix): feed the gate's rejection back so the retry can fix what it broke (#7368)
* fix(autofix): retry a verification-gate crash instead of burying the agent's fix

A gate failure had two very different meanings collapsed into one outcome. When
the gate DECLARES a verdict (outcome=failed) it evaluated the agent's attempt
and rejected it, so advancing the watermark is right — the same feedback would
reproduce the same rejection, and MAX_ROUNDS bounds it. But when the gate dies
WITHOUT a verdict it never judged the work at all, and advancing buries a fix
the agent had already written: the next scan sees "nothing new" and the PR sits
until a human deletes the marker by hand.

That is exactly how the nested-package ENOENT stranded #7329 and #7336. Both
agents had implemented the review feedback — the handoff even quoted the
implemented changes — but the gate crashed on its own bug while resolving
packages/channels/*, the commit was discarded, and the PRs read as "Could not
address the latest feedback automatically".

Two halves:

- The review-address gate now declares every rejection it can legitimately
  reach: build, typecheck, lint and the per-package tests each call a
  `reject_fix` helper that writes outcome=failed before exiting. (The resolver
  call is deliberately left undeclared — a resolver error IS a gate bug.)
- The handoff treats an EMPTY outcome on a non-success job as the gate's own
  crash and routes it to the existing sentinel/retry path, so the feedback
  stays live and the next scan retries. The round still increments, so a
  persistently crashing gate is bounded exactly as before, and the headline
  names the real cause ("hit a verification-gate error before reaching a
  verdict") and, on the final attempt, points at the gate logs.

Unchanged: a declared rejection still advances and reads as before, a
no-output crash keeps its own wording and retry, and a crash before the
feedback was read stays terminal.

Tests: the real extracted decision block is replayed under bash across declared
rejection (advances to NEWEST), gate crash (sentinel + retry + round+1), no
output (sentinel, original wording), the round cap (operator fix), and a
successful job (never a crash); plus the reject_fix helper is driven for real
to prove a rejection writes outcome=failed. Both mutation-verified — dropping
the crash arm, or unwiring one known rejection, turns them red.

* feat(autofix): feed the gate's rejection back so the retry can fix what it broke

#7208 was handed to a human over a two-character fix. The agent implemented two
review findings, the gate refused the commit because it did not compile
(TS4111: `truncated` comes from an index signature, use `['truncated']`), and
the loop stopped there — round 5/100, "A human should take over this PR".

Nothing in the loop could have recovered on its own, because the reason was
never carried anywhere the loop could read it:

- the handoff comment showed only the agent's optimistic summary, so neither a
  human nor the next round could see WHY it was refused;
- the feedback filter (correctly) excludes the bot's own comments, so a retry
  re-read only the original review points;
- so `@qwen-code /retry` would have re-run the same agent against the same
  input and produced the same non-compiling change.

The compiler had already said exactly what was wrong. The loop just threw it
away. Three pieces carry it instead:

- Each deterministic check now runs through `run_check`, which tees its output
  to a gate log; `reject_fix` writes the label plus the tail of that output to
  gate-rejection.md. (A four-backtick fence keeps captured ``` output from
  breaking out when this is posted as a comment.)
- The handoff comment carries that block between
  `<!-- autofix-gate-rejection-start/end -->` markers, so a human sees the real
  reason next to the summary instead of a report that reads like success.
- `Prepare branch and feedback` lifts it back out of the bot's newest comment
  and puts it at the top of the next round's feedback: "Your previous attempt
  was REJECTED by the verification gate — fix this first."

So a mechanical rejection now closes inside the loop, which is the point of
takeover. A rejection the agent cannot fix still burns rounds and ends at the
same handoff, bounded exactly as before.

Tests: the round trip is exercised end to end — a failing check's compiler
output lands in gate-rejection.md with its label, the handoff delimits it, and
the prepare step recovers the text (markers stripped) from the newest bot
comment while a round that pushed yields nothing to replay. Both halves
mutation-verified. #7351's verdict test is retargeted to run_check.

* fix(autofix): declare the gate verdict before writing its detail file

CI caught this and macOS could not: reject_fix wrote gate-rejection.md
first and outcome=failed second, so a failure to write the detail took
the verdict with it. An empty outcome on a failed job is the signal for
"the gate never reached a verdict" — a crash, which is RETRIED — so a
clean rejection whose detail write failed would be re-attempted every
round instead of being reported once.

The verdict is now written first and the detail write is non-fatal.

The ordering is pinned by a STATIC assertion, not only the behavioural
one: bash 3.2 suspends set -e through a `||`-invoked function and bash 5
does not, so the wrong order runs clean on macOS and aborts on a Linux
runner. That is exactly how it shipped green locally and red in CI, and
a guard that depends on the reviewer's bash would let it happen again.

* fix(autofix): escape the gate-rejection detail for real

The gate-rejection publish site used `sed 's/<!--/<!\-\-/g'` — single
backslashes, which sed reads as escaped literal `-`, so the replacement
is byte-identical to the match and the whole command is a no-op on both
GNU and BSD sed. The other four publish sites use `\\-\\-` correctly.

That mattered: the detail is `tail -c 3000` of build/typecheck/lint/test
output, published verbatim in a bot-authored comment. The scan parses
markers by matching the literal `<!-- autofix-eval ts=`, and it only
counts markers in bot-authored comments — so any check output containing
that string would have been parsed as a real eval marker.

The existing test counted the CORRECT spelling and asserted there were
four of them. A fifth site with the wrong spelling did not match the
counted string, so the count stayed at four and the test stayed green.
It now asserts every `s/<!--/…/g` site is byte-identical to the correct
form, which fails on exactly this bug.

Reported by qwen-code-ci-bot on PR #7368.

* chore(autofix): correct stale "ALL FOUR" escape-site comment to five (#7368)

* chore(autofix): document the head/tail byte-limit invariant (#7368)

---------

Co-authored-by: wenshao <wenshao@example.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-07-21 13:33:39 +00:00
..
installation fix(packaging): bundle clipboard addon in standalone builds (#6708) 2026-07-11 15:18:24 +00:00
lib feat(core): support QWEN_HOME env var to customize config directory (#2953) 2026-05-09 15:51:52 +08:00
tests feat(autofix): feed the gate's rejection back so the retry can fix what it broke (#7368) 2026-07-21 13:33:39 +00:00
acp-http-smoke.mjs feat(daemon): merge daemon-mode feature batch into main (#4490) 2026-06-12 00:34:49 +08:00
benchmark-api-latency.mjs feat(cli): add API preconnect to reduce first-call latency (#3318) 2026-04-27 06:54:55 +08:00
build-hosted-installation-assets.js fix(installer): auto-detect SYSTEM account and default PATH scope to machine (#4903) 2026-06-10 21:02:10 +08:00
build-standalone-release.js fix(packaging): bundle clipboard addon in standalone builds (#6708) 2026-07-11 15:18:24 +00:00
build.js feat(channels): add WeCom intelligent robot channel (#6436) 2026-07-07 15:24:19 +00:00
build_package.js fix(build): clean stale outputs before tsc --build to prevent TS5055 (#4453) 2026-05-23 23:06:31 +08:00
build_sandbox.js fix(sandbox): fall back to 'latest' tag when image name has no colon (#2962) 2026-04-18 09:07:05 +08:00
build_vscode_companion.js Sync upstream Gemini-CLI v0.8.2 (#838) 2025-10-23 09:27:04 +08:00
check-build-status.js fix(review): report what the transcripts prove; build the roster in one call (#7033) 2026-07-18 00:43:57 +00:00
check-desktop-isolation.js feat(desktop): Add desktop app package with Qwen ACP SDK integration (#3778) 2026-06-11 21:57:20 +08:00
check-i18n.ts fix(cli): localize approval mode UI labels (#6592) 2026-07-11 00:07:03 +00:00
check-lockfile.js Sync upstream Gemini-CLI v0.8.2 (#838) 2025-10-23 09:27:04 +08:00
check-serve-fast-path-bundle.js perf(telemetry): lazy-load the SDK and split OTLP exporter chains by protocol (#7276) 2026-07-21 07:35:30 +00:00
clean-package-build-artifacts.js test(core): stabilize file history eviction test (#6637) 2026-07-10 06:39:52 +00:00
clean.js feat(desktop): Add desktop app package with Qwen ACP SDK integration (#3778) 2026-06-11 21:57:20 +08:00
cli-entry.js fix(cli): update npm installs safely in background (#7322) 2026-07-21 06:32:24 +00:00
copy_bundle_assets.js feat(core): add dataviz bundled skill (#6198) 2026-07-03 01:06:39 +00:00
copy_files.js revert: remove unused script modifications 2026-02-10 14:34:36 +08:00
create-standalone-package.js fix(cli): avoid updating active CLI processes (#6874) 2026-07-15 00:33:17 +00:00
create_alias.sh fix: ambiguous literals (#461) 2025-08-27 15:23:21 +08:00
daemon-dev.js fix(scripts): allow multiple dev:daemon instances by probing Vite port (#7212) 2026-07-19 12:49:47 +00:00
desktop-openwork-sync.ts feat(acp): support desktop qwen integration (#4728) 2026-06-09 19:09:44 +08:00
dev.js fix(review): report what the transcripts prove; build the roster in one call (#7033) 2026-07-18 00:43:57 +00:00
esbuild-shims.js perf(cli): code-split lowlight to cut startup V8 parse cost (#4070) 2026-05-15 17:26:18 +08:00
generate-changelog.js feat(release): generate AI-assisted release notes (#6756) 2026-07-12 13:00:22 +00:00
generate-git-commit-info.js # 🚀 Sync Gemini CLI v0.2.1 - Major Feature Update (#483) 2025-09-01 14:48:55 +08:00
generate-release-notes.js feat(release): generate AI-assisted release notes (#6756) 2026-07-12 13:00:22 +00:00
generate-settings-schema.ts revert: remove local PR verification gate (#7031) 2026-07-16 11:24:38 +00:00
get-release-version.js fix(scripts): handle missing NPM dist-tags gracefully in release versioning (#6476) (#6481) 2026-07-08 12:21:14 +00:00
lint.js revert: remove local PR verification gate (#7031) 2026-07-16 11:24:38 +00:00
local_telemetry.js Merge tag 'v0.3.0' into chore/sync-gemini-cli-v0.3.0 2025-09-11 16:26:56 +08:00
measure-flicker.mjs fix(cli): bound SubAgent display by visual height to prevent flicker (#3721) 2026-04-29 22:34:55 +08:00
pre-commit.js Sync upstream Gemini-CLI v0.8.2 (#838) 2025-10-23 09:27:04 +08:00
prepare-package.js fix(release): raise prepared package size limit to 96 MB (#6687) (#6691) 2026-07-11 01:01:59 +00:00
prepare.js feat(web-shell): git status chip, visual working-tree diff, and sidebar git status (#7054) 2026-07-18 10:06:07 +00:00
release-script-utils.js feat(installer): add standalone hosted install and uninstall flow (#3828) 2026-05-21 11:57:10 +08:00
sandbox_command.js fix(scripts): avoid shell injection in sandbox command detection (#6108) 2026-07-01 16:20:40 +08:00
sdk-node-exporter-stub.js perf(telemetry): lazy-load the SDK and split OTLP exporter chains by protocol (#7276) 2026-07-21 07:35:30 +00:00
sign-release.sh feat(cli): add standalone auto-update support (#4629) 2026-06-04 22:53:12 +08:00
start.js fix(review): report what the transcripts prove; build the roster in one call (#7033) 2026-07-18 00:43:57 +00:00
sync-computer-use-schemas.ts feat(computer-use): configurable screenshot max dimension (setting + env) (#5122) 2026-06-15 15:25:27 +08:00
telemetry.js feat(core): support QWEN_HOME env var to customize config directory (#2953) 2026-05-09 15:51:52 +08:00
telemetry_gcp.js fix(mcp): update OAuth client names and improve MCP commands 2026-02-08 10:46:48 +08:00
telemetry_utils.js feat(core): support QWEN_HOME env var to customize config directory (#2953) 2026-05-09 15:51:52 +08:00
test-rewind-e2e.sh fix(test): update rewind E2E Test 1 assertion after isRealUserTurn fix (#3622) 2026-04-26 06:49:42 +08:00
test-windows-paths.js chore: consistently import node modules with prefix (#3013) 2025-08-25 20:11:27 +00:00
unused-keys-only-in-locales.json feat: add /diff command and git diff statistics utility (#3491) 2026-05-10 11:15:59 +08:00
upload-aliyun-oss-assets.js fix(release): move constants above entry point to avoid TDZ error (#4398) 2026-05-23 22:21:33 +08:00
verify-installation-release.js feat(installer): verify release assets + switch public docs to standalone entrypoint (#3855) 2026-06-04 17:23:04 +08:00
version.js fix(ci): resolve TS5055 release build failure since May 19 (#4383) 2026-05-21 16:01:35 +08:00
workspaces.js feat(desktop): Add desktop app package with Qwen ACP SDK integration (#3778) 2026-06-11 21:57:20 +08:00