qwen-code/scripts
Shaojin Wen b286875e72
fix(review): harden the pipeline against four live-run failures (#9086)
* fix(review): harden the pipeline against four live-run failures

Measured on three parallel PR reviews (qwen3.8-max, 2026-08-13, PRs
#9013/#9014/#9045) run via `qwen review run`:

- run.ts: pin the composed-verdict and report scans to the run's own
  target. The generic newest-composed scan captured a concurrent run's
  artifact — two of the three runs republished a neighbour PR's verdict
  (one reported REQUEST_CHANGES for a review whose own report said
  Comment). Also keep re-reading while the child runs: a coverage
  re-check legitimately recomposed a verdict 12 minutes after the first
  write, and the first-snapshot capture would republish the superseded
  one.

- budget.ts: drop placeholder gaps whose completion word carries a
  trailing budget adverbial. Three "none — all checks … completed
  within budget" non-answers reached two posted bodies because the
  completion idiom required the completion word to end the text.

- coverage.ts: label a non-chunk agent by the brief codename found
  anywhere in its launch prompt. Launchers prepend context lines, so the
  first-line label gave twelve finders one shared PR-summary sentence,
  and every budget-gap disclosure rendered as the same truncated PR
  quote instead of a name.

- copy_bundle_assets.js: emit dist/cli.js with a shebang and the execute
  bit. shellContextEnv blanks a QWEN_CODE_CLI a POSIX shell cannot exec,
  so every review subcommand issued from a session launched off the
  bundle silently fell back to the PATH's global install — all three
  runs executed the machine's auto-updated release instead of the tree
  they were launched from.

* test(review): follow the codename label into compose-review's fixtures

The backtick-collapse fixture's first line was itself the brief codename
shape, so the new codename extraction labels it `agent security` and the
first-line assertion no longer holds. Keep the sanitization intent on a
prose-only first line, and pin the codename behaviour — a prepended
context line must not reintroduce the shared-PR-quote label — as its own
case.

* fix(review): classify the run target with the child's own parser

Review feedback on the target pin: prNumberFromTarget re-derived PR
classification with a narrower regex than parse-args — /pull/<n>/files
URLs went unpinned, 0042 pinned pr-0042- while the child writes pr-42-,
and docs/pull/42 pinned a file target as a PR — so a completed (and
posted) review could be reported as one that produced no verdict.
Delegate to parseReviewArgs, whose verdict is what the child names its
artifacts from, and pin the divergent shapes as tests.

Also gate the bundle's shebang/exec-bit block with a package-assets
case (mode asserted off-win32, double-run must not stack shebangs), and
document the accepted same-target residual race on composedPatternFor.

* fix(review): pin run artifacts by exact target identity, share the identity-line parser

Round-2 review feedback, all six findings:

- run.ts: replace name-shape pins with the exact composed filename each
  target class produces (pr-<n> / file basename / the fixed 'local' token,
  per the skill's --out template). The (?!pr-\d+-) lookahead rejected a
  file run's own artifact whenever the reviewed file was named
  pr-<digits>-…, the PR branch's .* wildcard claimed that same artifact,
  and the pooled null class let concurrent file and no-target runs
  cross-capture each other's verdicts. Target classification now comes
  from classifyRunTarget (parse-args' verdict, basename for files).

- run.ts: newestArtifactSince returns {path, mtime}, so the capture poll
  reuses the scan's own stat instead of re-statting the path — the
  scan-vs-sweep window (and its untestable catch branch) is gone
  structurally.

- lib/agent-identity.ts: one parser for the identity line agent-prompt
  bakes into every launch, shared by cost-ledger's row labels and
  coverage's disclosure labels — the two hand-rolled copies could drift,
  and coverage's copy dropped the (round N) and owned-file suffixes,
  folding reverse-audit rounds into indistinguishable disclosure lines.
  cost-ledger still feeds it only the first line (quoted identity lines
  below must never be credited); coverage scans for the first
  line-anchored identity line (launchers prepend context lines).

- lib/budget.ts: one vocabulary for the budget-idiom family — 'below'
  joins the completion tail's position words, and the stayed idiom takes
  the same qualifiers ('stayed inside the tool-call budget').

- run.test.ts: handler-level assertion that the report scan is pinned
  (a strictly newer neighbour report must not become this run's
  reportPath), alongside the pattern-level cases for every shape the
  review probed.

* fix(review): round-3 review polish — CRLF identity lines, producer-side no-gap rule, edge-case pins

- agent-identity: tolerate a trailing CR (CRLF-recorded prompts fed
  through \n-splitting callers failed every parse and fell back to
  first-line prose); scan the launch prompt with one multiline match
  instead of materializing a line array per agent record; pin the
  round-over-file precedence with a both-suffixes test.

- agent-prompt: state the no-gap rule at the producer — write NO
  'Budget gap:' line when nothing was cut short — instead of leaving
  each agent to improvise a 'none' phrasing the consumer-side
  placeholder filter must chase forever.

- run.ts: strip trailing path separators before taking a file target's
  basename (a tab-completed 'src/' pinned 'qwen-review--composed.json',
  which no child artifact carries — fail-closed exit 1 on a completed
  review); pin file-run reports by their filename slot so a file named
  'pr-1234.md' claims its own report; document the two collision
  classes the basename-keyed pin defines (same-basename files,
  basenames spelling 'local'/'pr-<n>').

- budget.test: pin the parenthesis-form exception keep case beside the
  dash form.

* fix(review): round-4 polish — one budget vocabulary, named pin expectation, honest prompt claim

- budget.ts: spell the budget-position vocabulary once (BUDGET_QUALIFIED /
  COMPLETION_TAIL) and build PLACEHOLDER_GAP_RE from it — the literal
  carried three hand-copies that had already drifted twice in two review
  rounds; the space-separated 'tool call' form is pinned in both branches.

- agent-prompt.ts: the no-gap rule now states what actually happens to a
  'none' disclosure — at best filtered, and any unrecognized wording is
  published as a phantom coverage gap — instead of claiming the parser
  treats it as a gap, which was the negation of the filter shipped beside
  it.

- run.ts: derive the composed pin from composedNameFor and name the
  expected filename in both the no-verdict prose and the JSON result
  (expectedComposedName) — a naming drift between the pin and the skill's
  template was undiagnosable once Step 9 swept the near-miss.

- compose-review.ts: publicAgentSubject's provenance note now describes
  the codename labels coverage prefers, with first-line prose as the
  fallback.

* test(review): guard the no-verdict diagnostic and the pinned capture; align the chunk-role grammar

- run.test.ts: assert the no-verdict report names the artifact it waited
  for, in prose and as expectedComposedName — mutation-verified: dropping
  the suffix now fails.

- run.test.ts: force the neighbour's composed artifact strictly NEWER in
  the concurrent-run fixture. With it older, an unpinned newest-composed
  scan landed on the right file anyway and the regression passed;
  mutation-verified: reverting composedPatternFor to the generic scan now
  fails the handler test, not only the pattern units.

- agent-identity.ts: CHUNK_ROLE_RE takes coverage's CHUNK_RE shape
  (whitespace-tolerant, case-insensitive) so a hand-edited 'Chunk 3 of 7'
  cannot resolve as a chunk owner in the posted body and a role agent in
  the ledger row.

* fix(review): keep the bundle's write time across the shebang rewrite; hold the pins to the skill

Round-6 review feedback, all five findings:

- copy_bundle_assets.js: preserve dist/cli.js's atime/mtime across the
  shebang rewrite. stampReviewSourceDigest reads that mtime as the build
  time, so a bumped one certifies a bundle as newer than review sources
  edited before it and the staleness warning the skill's Step 0 stops on
  never fires. A full bundle stamps before reaching here, but a
  standalone run of this script — a flow the gate's own comment
  contemplates — was exposed.

- package-assets.test.js: pin both halves the block owes. The mtime is
  asserted against a fixture built 60s in the past, and the second run
  now arrives at mode 0644 so the exec bit must be re-set — demoting the
  chmod inside the shebang guard previously stayed green.

- run-skill-parity.test.ts: new. composedNameFor and reportPatternFor
  encode the bundled skill's Step 6 --out template and Step 8 report
  stems, and were pinned only against self-referential literals. This
  reads the templates out of SKILL.md and renders them per target class,
  so a skill-side edit fails next to the code that must follow it
  instead of silently in a later review.

- cost-ledger.test.ts: pin the first-line-only invariant — a launch
  whose prepended context sits above the identity line keeps the
  transcript's own id, never a label lifted from below. Consolidating
  both callers on labelFromLaunchPrompt now fails.

- agent-identity.test.ts: assert the two entry points genuinely differ
  on that prompt, so neither caller's policy can be collapsed into the
  other unnoticed.

* fix(review): stop the mtime assertion from pinning libuv's timespec truncation

The assertion compared the recorded mtime against the Date handed to
utimesSync, so it also pinned libuv's double-seconds → timespec
conversion: about half of all millisecond values read back 1 ns low
(X - 0.001), and builtAt is a fresh Date.now() - 60_000 every run — a
~50% coin flip that would have landed intermittent reds on unrelated
PRs through test:ci.

Capture what the filesystem actually recorded after the setup and
compare against that; the invariant under test is only whether the
shebang rewrite moves the stored time. 10/10 green through the CI entry
point, and it keeps its teeth: removing the production
fs.utimesSync(cliEntry, atime, mtime) restore fails it 3/3.
2026-08-14 04:38:49 +00:00
..
installation fix(install): avoid Get-FileHash for Windows checksums (#9112) 2026-08-14 01:12:08 +00:00
lib feat(core): support QWEN_HOME env var to customize config directory (#2953) 2026-05-09 15:51:52 +08:00
tests fix(review): harden the pipeline against four live-run failures (#9086) 2026-08-14 04:38:49 +00:00
acp-http-smoke.mjs feat(daemon): merge daemon-mode feature batch into main (#4490) 2026-06-12 00:34:49 +08:00
audit-runtime-critical.js ci: keep the critical-audit gate honest when npm cannot answer (#7743) 2026-07-26 06:59:13 +00: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): GitHub polling adapter with notification-as-wakeup architecture (#7632) 2026-07-25 09:31:50 +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): package Web Shell as a release-ready desktop app (#8132) 2026-08-02 08:20:16 +00: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 feat(ci): fail the startup bundle check when the CLI entry is hoisted into a chunk (#8203) 2026-07-31 08:57:57 +00:00
check-voice-guard-sync.js feat(voice): support trusted private ASR base URLs (#8350) 2026-08-06 14:04:57 +00:00
clean-package-build-artifacts.js feat(channels): GitHub polling adapter with notification-as-wakeup architecture (#7632) 2026-07-25 09:31:50 +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): preserve Qwen Review startup version in footers (#8431) 2026-08-04 14:58:56 +00:00
copy_bundle_assets.js fix(review): harden the pipeline against four live-run failures (#9086) 2026-08-14 04:38:49 +00:00
copy_files.js refactor(core): move review skill incident narratives to DESIGN.md (#8499) 2026-08-04 12:41:18 +00:00
create-standalone-package.js feat(review): say so when the bundle is older than the review it runs (#8390) 2026-08-07 03:21:26 +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 fix(release): raise model timeouts and shrink batch size for slow networks (#8007) 2026-07-29 22:38:35 +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(release): bump preview base past published stable (#7978) 2026-07-29 23:21:00 +00:00
lint.js fix(ci): cache downloaded linters on ECS runners (#9001) 2026-08-13 05:13:23 +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 chore(deps): bump sharp to ^0.35.0 to resolve GHSA-f88m-g3jw-g9cj (#8952) 2026-08-13 06:56:10 +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
review-audit-layers.mts feat(review): cover modeled-system defect layers in the reverse audit (#8956) 2026-08-12 18:15:11 +00:00
run-java-daemon-sdk-e2e.ts ci: reduce SDK Java runner queueing (#8441) 2026-08-03 16:21:05 +00: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-capture.mjs fix(ci): avoid verify capture color conflict (#8236) 2026-07-31 14:15:40 +00: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(release): pin channel-base dep to exact version during release bump (#7953) 2026-07-28 16:58:28 +00:00
workspaces.js feat(desktop): Add desktop app package with Qwen ACP SDK integration (#3778) 2026-06-11 21:57:20 +08:00