mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-08-06 15:25:34 +00:00
8268 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
e76dff1c6b
|
feat(review): add declarative repository-context manifest (#8401)
Some checks are pending
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 1/2 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 2/2 (push) Waiting to run
E2E Tests / channel-plugin E2E (nightly) (push) Waiting to run
E2E Tests / cron-interactive E2E (nightly) (push) Waiting to run
E2E Tests / web-shell Browser Regression (push) Waiting to run
SDK Java / ubuntu-latest / Java 11 (push) Waiting to run
SDK Java / ubuntu-latest / Java 17 (push) Waiting to run
SDK Java / macos-latest / Java 21 (push) Waiting to run
SDK Java / ubuntu-latest / Java 21 (push) Waiting to run
SDK Java / windows-latest / Java 21 (push) Waiting to run
SDK Java / Real daemon E2E / Java 11 (push) Waiting to run
* feat(review): add OpenJDK repository context Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * refactor(review): extract repository context foundation Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(review): repair CI type guard and add manifest repository context Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(review): harden repository context per maintainer review Address both maintainer reviews on the repository-context PR: - repo-context: a PR plan whose merge base never resolved (mergeBaseSha: null) now degrades to a null artifact without consulting the worktree, instead of throwing a misleading "invalid plan" error or falling back to the PR head. - Identity reads return the same shape in PR and local modes (CRLF->LF, trimmed) and fail closed: absence yields null, a present-but-unreadable file throws. - Context-required roles can no longer override the roster's effort, topology, and mode gates. - The relatedPaths scan bound rises from 1024 visited entries to 16384 and is documented, so honestly scoped manifests no longer abort reviews. - A present-but-invalid repositoryContext now fails closed in every consumer; the gate no longer silently drops the disclosure. - The duplicated validators and bounds are shared between the wire format and the manifest provider; the context role allow-list is derived from a single const; manifest arrays no longer require hand-sorting (uniqueness only). - Nits: dead mkdir removed, output message names the provider, escape-message fix, unsafe changed paths skip instead of aborting, segment-glob regexes memoised, list helper hoisted. - Docs: user-facing manifest section, trust-boundary residuals and foundation status in the design doc, fail-closed exit guidance in the skill. * fix(review): skip unsafe related paths in manifest context (#8401) * fix(ci): align review timeout helper test with externalized variables (#8401) * fix(review): harden repository context bounds and base identity reads (#8401) * fix(review): bound manifest matching work and pin round-2 review gaps (#8401) * fix(test): isolate serve streaming suite from stray workspace settings (#8401) * fix(review): cap identity reads, bill match work by length, pin round-3 gaps (#8401) --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com> |
||
|
|
95655daf30
|
feat(cli): render inline terminal images (#8305)
* feat(cli): render inline terminal images * fix(cli): preserve text around hidden citations * fix(cli): clear pending image state on reset * fix(cli): bound inline image rendering * fix(cli): clear compacted image overflow markers * docs(cli): clarify inline image resume scope * fix(cli): address inline image review feedback --------- Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> |
||
|
|
79027bb2db
|
fix(web-shell): scope artifact actions to owning workspace (#8510)
* fix(web-shell): scope artifact actions to owning workspace * fix(web-shell): preserve artifact authority in strict mode * fix(web-shell): address artifact workspace review * test(web-shell): cover missing file owner * fix(web-shell): keep open artifact tabs alive across pane and list gaps |
||
|
|
02f1692d40
|
fix(web-shell): allow session refresh with daemon auth (#8445)
* fix(web-shell): allow session refresh with daemon auth * test(web-shell): cover SPA fallback shell branch for non-session navigations * test(web-shell): retarget sec-fetch SPA fallback test to non-session navigation Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(web-shell): serve pre-auth navigations during the deferred runtime window The deferred-runtime gate applied bearerAuth to every non-bootstrap request while the runtime was cold, so a browser refresh of /session/<id> (and / and /assets/*) 401'd on the default `qwen serve --token ...` start until something else warmed the runtime. Exempt the same surface mountWebShellAssets registers before auth, via a shared isPreAuthWebShellRequest predicate, so cold document navigations start the runtime and load the shell while JSON fetches, API subpaths, and --no-web daemons stay gated. The predicate is dynamically imported to respect the serve fast-path import-boundary guards. * fix(cli): align deferred pre-auth web shell gate with warm routing (#8445) * fix(cli): report daemon startup failure to pre-auth web shell navigations (#8445) A pre-auth-exempted Web Shell navigation that hit a failed deferred runtime startup fell through to the bootstrap app's bearer gate and received a misleading 401 instead of the 503 daemon_runtime_failed envelope authenticated requests get for the same failure. Track the exemption in the deferred dispatch and answer the diagnostic envelope directly. Also cover the deferred gate's HEAD exemption, which was previously untested. * fix(cli): exempt bare /assets from the deferred pre-auth gate (#8445) * refactor(cli): dedupe runtime failure envelopes and deferred-window test setup (#8445) * refactor(cli): rename startup envelope helper and pin query-string deep links (#8445) * fix(cli): serve the // root alias pre-auth and fail-close the deferred predicate (#8445) * docs(cli): record the pre-auth %2F session deep-link invariant (#8445) * fix(test): isolate serve streaming suite from stray workspace settings (#8445) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> --------- Co-authored-by: 克竟 <dingbingzhi.dbz@alibaba-inc.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
732f4d8a29
|
feat(voice): support trusted private ASR base URLs (#8350)
* feat(voice): support trusted private ASR base URLs * fix(voice): address private endpoint review findings * test(voice): cover private endpoint edge cases * test(voice): pin remaining endpoint edge cases * fix(voice): address private endpoint review feedback * fix(voice): clarify allowlist URL and normalize IPv6 * fix(voice): harden NAT64 address validation * fix(voice): address managed endpoint review findings * refactor(voice): extract shared IPv6 transition unwrap ladder (#8350) Deduplicate the IPv6-transition unwrapping sequence (mapped, compatible, NAT64, dotted-quad) that was repeated verbatim between isPrivateNetworkIp and isAlwaysBlockedVoiceAddress on both CLI and Desktop surfaces. A single unwrapIpv6TransitionStep helper now yields the next canonical address (or 'blocked' for unrecognized ::ffff: forms), and each predicate recurses through it, preserving the exact re-check semantics at every unwrap level. * test(voice): cover allowInsecureBaseUrl wiring through desktop default transports (#8350) * fix(voice): add allowlist hint to private-network rejection error (#8350) * fix(voice): reject always-blocked base URLs before offering the allowlist hint (#8350) * fix(voice): resolve exact desktop voice provider before OAuth (#8350) * fix(voice): address review feedback for trusted private base URLs (#8350) * fix(voice): align desktop voice resolution with CLI semantics (#8350) * fix(voice): scope desktop fail-closed resolution to policy-bearing entries (#8350) * fix(voice): address round-8 review findings for trusted private base URLs (#8350) Run the invasive process-global `mock.module('ws')` suite as voice-ws-handler.isolated.ts so the desktop package's single-process `bun test` run no longer leaks the fake socket into unrelated ws consumers; the existing isolated loop runs it in its own process. Shape-guard the desktop provider scan: non-object modelProviders elements are skipped (falling through to OAuth instead of throwing a raw TypeError), and non-string baseUrl/envKey/settings.env values on a voice-model entry now surface the PROVIDER_ENTRY_REMEDY remediation error instead of crashing. Compute the DashScope-compatible /v1 rewrite before any allowlist match in fromExactModelProvider so the stage-1 check, the remediation messages, and the top-level recheck all compare the same final URL and a single allowlist entry converges for split-horizon deployments. Extend the CLI allowlist remediation messages to state which settings scopes honor the entry, since serve mode never shows the interactive workspace-strip warning. Thread providerProtocol through the CLI voice model seams (createVoiceModelSource and the daemon buildModelsConfig) so protocol-mapped custom provider groups resolve like the rest of the CLI model surface, and document the remaining protocol-agnostic desktop scan in the design doc. Correct the getHomeEnvFallback comment: it adopts the narrower getHomeEnvFallbackVars candidate set on purpose. Add multi-record DNS answer tests on both CLI and desktop net guards so the records.some classification is pinned against the array shape defaultLookupHost always produces in production. * fix(voice): address round-9 review findings for trusted private base URLs (#8350) * fix(voice): address round-10 review findings for trusted private base URLs (#8350) * fix(voice): classify desktop voice duplicates before ambiguity check (#8350) * fix(scripts): compare voice guard mirrors as parse trees (#8350) --------- Co-authored-by: rockybot2026 <265985139+rockybot2026@users.noreply.github.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com> Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> |
||
|
|
2221ea0325
|
fix(web-shell): Refresh sidebar branch chip immediately after checkout (#8600)
The sidebar git chip only polls every 60s, so after switching branches through the branch picker it kept showing the old branch for up to a minute — making the checkout look like it silently failed. Wire the picker's branch-changed callback to an immediate status refetch, matching the composer chip's realtime behavior. |
||
|
|
f4cf4268f5
|
fix(core): cap a streaming response's total lifetime, slim the review fan-out launch (#8602)
* fix(core): cap a streaming response's total lifetime The stream inactivity watchdog resets on every chunk, so a drip-fed stream — a gateway trickling keep-alive chunks, or a model crawling through an oversized single message — kept it alive forever while the message never completed: in issue #8597's CI review runs that meant 2.5-4.5 hours of silence ending in the outer timeout's kill. Add a per-request lifetime cap (default 15 min) that does not reset on chunk arrival. Tripping it throws a retryable ETIMEDOUT, so the existing transport-continuation recovery resumes a healthy generation the cap happened to cut. Config field streamMaxLifetimeMs; env knob QWEN_STREAM_MAX_LIFETIME_MS; 0 disables. * fix(review): carry findings lists as digest-named files, not inline agent-prompt folded the cumulative findings list into every printed verify/reverse-audit block. On a 12-14-auditor round that made the launch one 65-82 KB assistant message — the oversized single message whose stream generation never completed in #8597 — and cost a 5-10 minute paged relay through the orchestrator's context before every round. The list now goes where the brief already goes: on disk, named by the same findings digest that keys the record; the block carries a read_file pointer. The delivery guarantee is unchanged — a launch that drops the read matches no record — and the retirement scheduler's echo guard reads the list back from the file the prompt names, failing toward auditing when it is gone. * fix: address review feedback on stream guards and findings files * fix: address review feedback on findings delivery and stream guards The delivery floor counted only the brief's read receipt, so an instruction-skipping verifier could open its brief, skip the one instructed read of the findings file its block points at, and clear the gate having never seen the list it ruled on. The floor now extracts the findings pointer from the recorded prompt and requires a successful read of it — a new findings-unread delivery shape, with gap texts for the verify, reverse-audit, and combined steps. A failed findings-file write also speaks on stderr instead of silently pointing a whole round at a missing file. Stream guards: consult the lifetime deadline at the top of the loop, not only when the timer wins the race — a pre-buffered chunk resolves next() as a microtask and beats setTimeout(…, 0) every time. Merge the two ETIMEDOUT bypass blocks into one rule. New tests pin the idle-off + lifetime-on branch, the both-guards-0 disable (config and env), and the buffered-source shape. Also reword the prose sites that still described the inlined list. * fix(review): name the findings file in the verify/reverse-audit briefs The two briefs still told the agent the findings were "listed in the message that launched you", but since the list moved behind a read_file pointer they find only a pointer there. The agent reads its brief first (the block mandates it), so the stale text sent it looking for finding blocks in the launch message — the exact findings-unread shape the new delivery floor gates on. Point both briefs at the .findings.md file and the required read instead. * fix(review): address round-3 review — empty-round brief, guard hardening The b796708 brief fix stated unconditionally that the launch message points at a findings file, but an early reverse-audit round on a clean review names no file (the empty branch prints '## Nothing is confirmed yet' with no pointer) — the auditors were being sent to read a path their prompt does not contain. The reverse-audit brief now says the file is named when there is a list, and that an early round has none. Also from the round-3 review: - writeFindingsFile's failure diagnostic now uses writeStderrLineSafe: the catch exists to keep the build alive, so it must not throw out of it on EPIPE (qwen … | head). - The retirement echo-guard resolves the findings pointer from the CLI's own record (never the orchestrator's pasted copy), confined to the plan's record dir, memoized per round — an out-of-bounds or unreadable file degrades to the prompt, failing toward auditing. - Document the delivery floor's deliberate weakening: it proves the findings file was opened, not paged to completion (coverage.ts), and drop the last stale 'record folds the findings in' comment. - withStreamInactivityTimeout returns the source untouched when both guards are disabled, so the invariant survives a caller refactor (setTimeout(Infinity) would otherwise clamp to ~1ms). - settings.md + the config comment now say the stream guards are OpenAI-compatible-only, and that the 15-minute cap bounds a stream whose idle timeout was raised above it (raise or disable the cap to keep a longer window). * fix(review): address round-4 review — memo hygiene, read-visibility, naming The retirement echo-guard memoized a failed read's per-record fallback under the round's shared findings pointer, so one chunk's launch prompt would serve as a sibling chunk's findings list. Memoize only successful reads; a miss falls back to THIS record's own prompt, uncached. The findings block now prints the list's line count, so an agent whose read_file truncates can see it saw a fraction rather than the whole confirmed list — a visibility aid the delivery floor (which proves the file was opened, not paged) does not provide. Also from the round-4 review: rename withStreamInactivityTimeout to withStreamGuards (it now enforces two guards), correct the constants comment (the cap is measured from the stream's first iteration, not its first byte), and give the two stream-guard knobs a dedicated settings.md entry instead of burying them in the timeout paragraph. * fix(review): address round-5 review — deterministic record walk, accurate line count The cross-contamination regression test only discriminated under one readdir order: readRecordedPrompts walked the record dir in filesystem (filename-hash) order, so which chunk's fallback poisoned the shared memo depended on the walk. Sort the directory listing — a deterministic walk removes that whole class of order-sensitivity from a module that reasons per-record, not just from this test (a temporary revert of the memo fix confirms the test now fails against the buggy shape). findingsSection printed the line count of the TRIMMED findings body while writeFindingsFile writes the untrimmed content, so a list with leading/trailing blank lines got a label smaller than the file the agent actually reads — precisely the under-reading the count exists to make visible. Count the untrimmed content. * fix(core,review): charge the lifetime cap on upstream-wait, not delivery time Round-2's top-of-loop deadline check made the lifetime cap measure end-to-end delivery time: a healthy upstream that finished and buffered its chunks was cut for the CONSUMER's slowness (a paused IDE client, a big render), and a stream whose terminal done resolved at the boundary was converted into a retry. The cap is now charged on accumulated upstream-wait — the time the loop is blocked in await it.next() — so a buffered, already-complete stream always completes and only real upstream latency counts; the drip-fed never-completing stream spends exactly that time waiting, so #8597's shape is still caught. Also from the round-6 review: - Hoist the stream-guard error branch above the thinking-tag check: a drip-fed gateway cutting mid-<think> surfaced the guard's ETIMEDOUT as a PROTOCOL_TAG_LEAK and burned the tag-leak retry budget. - The findings line count drops the trailing newline's empty segment, so a 12-line list is not advertised as 13. - settings.md: the stream guards are env/config-only (no settings.json key); document that streamIdleTimeoutMs: 0 embedders now also need streamMaxLifetimeMs: 0 to fully opt out. - constants: a functionCall already streamed (the tool-heavy common case) recovers as a visible classified error, not a continuation. - coverage.ts: drop the stale 'four shapes' counts after Delivery grew a fifth; pipeline: dedupe the instanceof in the guard debug log; and correct the both-guards-off test's comment to pin the outcome, not the caller mechanism. * fix(core,review): monotonic guard clock, findings-write fallback, read-only floor Round-6 follow-ups the previous commit left open: - The stream guards accounted on Date.now(): an NTP step forward (or a long sleep) killed a healthy generation on the next iteration, and a backward step silently disabled the lifetime cap — the hang #8597 exists to bound. All guard accounting is now performance.now(); the setTimeout it races is monotonic too, so the two agree. Vitest fakes performance alongside the timers, and a new test A/B-verified against the wall-clock shape (it fails on Date.now() accounting). - A failed findings-file write returned the path anyway, pointing a whole 12-14-agent round at a file that does not exist — every agent burned its round, then the delivery floor failed it. writeFindingsFile now returns null on failure and findingsSection falls back to inlining the list (the pre-#8597 shape): the recorded prompt carries the list, the delivery check compares it verbatim, and the build stays alive. - The findings delivery floor matched the path in ANY successful tool call's serialized args, so a search_file_content or list_directory that merely named the file cleared it without reading a line. The transcript parser now records read_file calls apart, and the floor counts only those — a mention is not an open. * fix(core,review): round-7 leftovers — upstream-wait wording, key helper, test mock The round-6 error message and class doc still said 'total lifetime cap' and promised the continuation recovery unconditionally, and the wrap-site comment still read 'aborts at maxLifetimeMs from stream start' — all three now describe the upstream-wait semantics the guard actually implements, and the message names the wall clock separately so the two numbers reconcile. The round suffix baked into findings-role record keys and the findings file name was derived independently in three sites (findingsFileFor, runAllChunks, the single build) — a change to how a round is spelled would update two of three and silently fork the artifacts; roundPartOf spells it once. The writeFindingsFile test's module mock replaced all of stdioHelpers (three stubs, missing the other exports) and asserted mock.calls[0][0] with no mock reset — it now spreads importOriginal, clears mocks in beforeEach, and matches the stderr lines with stringContaining. * fix(review,core): round-3 follow-ups — conditional findings briefs, JSDoc placement, log labels The verify/reverse-audit briefs told the agent its findings live in the .findings.md file unconditionally, on the exact path (writeFindingsFile returning null -> findingsSection inlining the list) this PR added to work WITHOUT one; both now say 'when the message points at a findings file, read it; on the rare write-failure fallback the list is inlined in the message, read it there.' roundPartOf had been inserted between findingsFileFor's JSDoc and the function, orphaning the comment that records the one-file-per-round and null-means-inline contracts; the helper now sits above it. The guard debug log labelled the wall clock 'streamLifetimeMs' beside the cap; it is now 'wallClockMs' so the two numbers reconcile the same way the error message does. * fix(review): anchor the findings-pointer extraction to its emitted shape findingsPointerOf matched the FIRST read_file(file_path="….findings.md") anywhere in the recorded prompt. On the write-failure inline fallback the findings list occupies exactly the position the pointer would sit in, and a finding entry there can itself quote a read_file pointer of its own (a finding about this pipeline, which the harness produces when it reviews this repo). The loose match then extracted the quotation as the pointer and the readers diverged: coverage demanded a read of a path no agent was told to read (a spurious findings-unread on a run that is already degraded), and retirement, worse, confined-and-read an earlier round's file and flipped a just-filed finding to an echo, retiring a chunk that had just reported — the one direction the module's header commits to never failing. A quoted pointer inside a findings entry is indented or embedded in prose, so anchoring to a standalone read_file line removes it; the happy-path pointer is alone on its own line inside its fence. A test drives an inlined list containing a pointer-shaped line (fails under the old loose regex). --------- Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> |
||
|
|
44747cc27b
|
docs: add legacy code audit (/audit) design doc (#8397)
* docs: add legacy code audit (/audit) design doc Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs: revise legacy audit design with round-2 replication evidence Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs: note cross-file tracer cost and budget rule in legacy audit design Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs: address review feedback on legacy audit design (#8397) * docs: wire invariant triple, personas, and event detection into audit design (#8397) * docs: address round-3 review feedback on legacy audit design (#8397) * docs: address round-4 review feedback on legacy audit design (#8397) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs: address round-5 review feedback on legacy audit design (#8397) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs: address round-6 review feedback on legacy audit design (#8397) * docs: address round-7 review feedback on legacy audit design (#8397) * docs: address round-8 review feedback on legacy audit design (#8397) * docs: address round-9 review feedback on legacy audit design (#8397) * docs: address round-10 review feedback on legacy audit design (#8397) * docs: address round-11 review feedback on legacy audit design (#8397) * docs: address round-12 review feedback on legacy audit design (#8397) * docs: address round-13 review feedback on legacy audit design (#8397) * docs: address round-14 review feedback on legacy audit design (#8397) * docs: address round-15 review feedback on legacy audit design (#8397) * docs: address round-16 review feedback on legacy audit design (#8397) * docs: address round-17 review feedback on legacy audit design (#8397) --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com> |
||
|
|
41f9b83145
|
fix(core): remove fixed Goal continuation limit (#8421)
* fix(core): remove fixed Goal continuation limit * test(core): name former Goal continuation limit in regression guards --------- Co-authored-by: qqqys <266654365+qqqys@users.noreply.github.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com> |
||
|
|
2394afa797
|
fix(core): resolve symlinks before granting read permission (#8636)
The read permission check classified a path lexically, so a symlink planted inside an always-allow root returned arbitrary host files with no confirmation prompt. Canonicalize the candidate before the containment test, and the roots alongside it where doing so cannot be steered by repo-tracked contents. Refs #8635 |
||
|
|
35108c0cf0
|
ci(autofix): run heavy autofix jobs on the ECS pool with hosted fallback (#8603)
* ci(autofix): run heavy autofix jobs on the ECS pool with hosted fallback
The heavy autofix jobs (issue-autofix, build-cli, review-address) were
pinned to GitHub-hosted runners, where they hold up to five 300-minute
slots per scan. Combined with CI, that saturates the org's ~20 hosted
concurrency slots and starves the PR-review workflow's hosted-only jobs
(delay timer, fork authorize, /resolve).
Route the three heavy jobs to the persistent ecs-qwen pool using the same
repository-guarded expression as the rest of the fleet, with an
ubuntu-latest fallback for forks of this repo and for
MAINTAINER_ECS_RUNNER_DISABLED.
This is safe for the fleet's two secret-bearing agent jobs:
- Every review-address target is live-gated to write+ (internal) authors
at scan AND address time; in-repo PR heads already require push access.
- CI_DEV_BOT_PAT is a write-level branch-push token with no privilege
escalation (cannot bypass branch protection).
- The ECS pool ships docker, and repo-hygiene already runs the sandbox
image there in production; sandbox containers use --rm with no fixed
name, so concurrent legs on one machine do not collide.
Relax the 'Check runner environment' gate to accept self-hosted, and drop
the github-hosted condition on 'Set up Node.js' so Node 22 is provisioned
on ECS. The contract test is updated to pin the new ECS routing expression
(including the repository guard and hosted fallback) instead of the old
hosted-only one.
* ci(autofix): harden ECS-routed heavy jobs for the shared persistent pool
- Restore workspace ownership before checkout in issue-autofix,
build-cli, and review-address, matching the sibling pool workflows
(root-owned leftovers from containerised jobs break checkout/npm ci).
- Sanitize the reused workspace's local git config (allowlisted
unset-all + symlink-aware hook sweep, qwen-triage's pattern) before
the PAT-bearing git steps in issue-autofix and review-address.
- Give issue-autofix a per-run WORKDIR (/tmp/autofix-<run_id>): pool
registrations share one /tmp and issue-phase runs never serialize.
- Drop stale local autofix/issue-* branches after checkout so a retry
on the same registration cannot hit "branch already exists" or push
a failed attempt's stale commits.
- Extend the ECS routing guard for PR-family events (same-repo head or
write+ author), mirroring ci.yml's classify_pr convention, and fix
the runs-on comments that claimed fork PRs already fell back.
- Stop persisting CI_DEV_BOT_PAT into the origin remote URL: publish
pushes authenticate transiently, and the redundant set-url in
'Push and report' is removed (push/fetch already use a URL inline).
- Pin all of the above in the workflow contract tests, reusing hoisted
job-block constants.
* ci(autofix): harden ECS pool hygiene with shared hardened sanitize action
Review round for the ECS routing of the heavy autofix jobs. The
sanitize step shipped in the previous commit was the trusted-lane
variant of the qwen-triage sweep, which two verified bypasses defeat
(worktree-scoped config carrying core.hooksPath, and a global
core.hooksPath steering the hook deletion). Port the hardened variant
into a composite action so all three heavy jobs share one copy, and
add it to build-cli, whose checkout runs in the same reused workspace
and feeds the bundle every PAT-bearing leg executes.
Also completes the persistent-pool hygiene the routing depends on:
per-run/per-target WORKDIRs now chmod 700 at creation and are removed
by an always() teardown step after the artifact upload (nothing else
ever deleted them); the stale-branch sweep detaches HEAD first and
globs via BRANCH_PREFIX; the artifact upload reads env.WORKDIR
instead of a duplicated literal.
The tautological runner-environment gate is repurposed as a
fail-fast docker preflight (a missing daemon otherwise surfaces only
at 'Resolve sandbox image', after npm ci/build), and Install tmux
switches to sudo -n so hosts without passwordless sudo fail with a
clear message instead of dying on a prompt.
The runs-on comments are rewritten to say exactly what they guard:
which events carry the same-repo/write+ clause and which rely on the
live write+ or label gates, why review-address is an author-permission
gate rather than a head-repository gate, and where the pool's docker
availability is proven in-repo (qwen-triage's container jobs on the
same labels).
Contract tests pin all of it: hygiene steps present and ordered
before checkout in every heavy job, the hardened sweep's ordering and
containment in the shared action, the docker preflight and tmux
hardening, the WORKDIR lifecycle, hosted-only short jobs, and generic
next-job slice boundaries so a job inserted after review-address can
no longer hide inside its test slice.
* ci(autofix): inline git-config sanitize step before checkout
The composite sanitize action was invoked as a local action
(`uses: './.github/actions/sanitize-workspace-git-config'`) BEFORE
`actions/checkout` in all three ECS-routed jobs. A local action resolves
from $GITHUB_WORKSPACE, so:
- on any clean workspace it hard-fails with "Can't find 'action.yml'" —
every hosted-fallback run (forks, MAINTAINER_ECS_RUNNER_DISABLED=true,
i.e. the documented rollback path) and any freshly registered ECS
runner — and it cannot self-heal, dying before checkout.
- on a reused workspace it executes the leftover copy, which for
review-address is the previous run's PR branch — pre-checkout execution
of PR-controlled content, the exact vector the step exists to prevent.
Inline the hardened sanitize script as a plain `run:` step in each job
(the qwen-triage 'Clean stale agent state' pattern) and delete the
now-consumer-less composite action. Update the contract test, which had
pinned the broken ordering, to pin the inline run step instead, and add a
generic guard that no local action may precede a checkout.
* ci(autofix): harden PAT handling and pool isolation on the shared pool
Address the Medium findings from the ECS-routing review:
- PAT pushes (Publish PR, Push and report, and the fork dry-run
preflight) now authenticate via a transient credential helper instead of
a token-bearing remote URL. The token enters neither the reused
workspace's .git/config nor the process argv, which is world-readable
via /proc on this shared host; the helper config holds only a
${GITHUB_TOKEN} reference and is swept by the next sanitize pass.
- 'Check runner environment' now asserts the self-hosted runner is an
ecs-qwen pool member by name, so a mis-labelled registration cannot
silently claim a PAT-bearing 300-minute job.
- 'Reset autofix workspace' age-sweeps abandoned /tmp/autofix-* dirs (a
hard runner kill skips the always() teardown and run_id never repeats)
and prunes the reused workspace's .git.
The contract test is updated to pin the tokenless push/fetch URLs, the
credential-helper authentication, and the absence of a token-bearing URL.
* ci(autofix): create autofix workdirs with umask 077 and correct cleanup comments
* ci(autofix): scope PAT credential helper to a one-shot git -c, plus review fixes
Address the latest review round on the ECS-routed heavy jobs.
High — the transient credential helper was not transient: `git config
--local credential.helper` wrote into the reused workspace's .git/config
and the matching unset was skipped on every error path (bash -e abort,
the fork-preflight exit 0, the salvage-loop exit 1s), stranding a helper
that answers any host with the PAT where ci.yml / pr-review jobs could
read it. All three push paths now use a one-shot, host-scoped
`git -c credential."https://github.com".helper=...` (a git_auth wrapper
for the salvage loop), so nothing is ever written to .git/config.
Medium — narrow the sanitize allowlist's `remote.*` to
`remote.<n>.(url|fetch|pushurl)` (uploadpack/receivepack are command
strings the sweep previously kept), and cover all three inlined sanitize
copies in the hardening test with a byte-identical pin (previously one
of three), rewording the stale "composite action" references.
Low — drop the recursive `rm -rf` hooks fallback that could wipe the git
dir itself (warn instead), extend the /tmp sweep glob to the legacy fixed
dir (`autofix*`), and make `git gc` threshold-driven (`--auto --prune=now`).
The contract test pins the git -c / git_auth form, the absence of any
config-written credential helper, and the tokenless URLs throughout.
* ci(autofix): pin gc to the foreground and anchor push auth assertions
Round-2 review follow-ups:
- `git gc --auto --prune=now` detaches by default (gc.autoDetach=true),
and --prune=now is unsafe when other processes write concurrently —
exactly what follows in these 300-minute jobs. Force it synchronous
with `-c gc.autoDetach=false` so the repack still only fires when the
--auto thresholds say so, but never races the checkout, agent commits,
or merge/retry loop that come after it.
- Tighten the two push assertions (dry-run preflight, Publish PR) to
require the host-scoped `git -c credential."https://github.com".helper`
prefix immediately before the push, instead of a bare
`push --no-verify …` match that a `git push` regression would still
satisfy.
---------
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
|
||
|
|
2c514b50b9
|
fix(autofix): serialize scan-and-pick issue runs in one concurrency group (#8435)
Some checks are pending
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 1/2 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 2/2 (push) Waiting to run
E2E Tests / channel-plugin E2E (nightly) (push) Waiting to run
E2E Tests / cron-interactive E2E (nightly) (push) Waiting to run
E2E Tests / web-shell Browser Regression (push) Waiting to run
* fix(autofix): serialize scan-and-pick issue runs in one concurrency group The issue-phase concurrency group fell back to github.run_id for every run that route did not force a target — which is every scheduled run and every label-triggered run. Run-unique groups exclude nothing, so two overlapping scans (cron effectively fires every 40-70 minutes while the job may run for up to 180) could both pass the live label recheck during the minutes-long assess call, double-claim the same issue, and burn two multi-hour agent runs on it; the loser then fails its push and posts a withdraw comment. Key forced dispatches per issue, label events on the payload issue, and all scan-and-pick runs (cron or unforced dispatch) on one shared 'scheduled' group. cancel-in-progress stays false so a superseded tick still runs when targets remain. * fix(autofix): make concurrency group pin prettier-stable (#8435) * fix(tests): sync qwen-resolve-workflow timeout pins with repository variables (#8435) * fix(ci): pin issue-phase concurrency group equal to FORCED_ISSUE (#8435) * test(ci): anchor right edge of issue-phase concurrency group pin (#8435) * fix(autofix): keep never-runnable runs out of the issue-phase concurrency group (#8435) * test(autofix): pin issue-autofix concurrency gate to the job if predicate (#8435) * fix(autofix): exclude dry runs from the issue-phase concurrency groups (#8435) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * test(autofix): pin the Claim/Publish dry-run step gates (#8435) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> --------- Co-authored-by: verify <verify@local> Co-authored-by: 易良 <1204183885@qq.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
ec4f1e02e4
|
fix(cli): probe sandbox runtime before selecting it (#7734)
* fix(cli): probe sandbox runtime before selecting it Sandbox selection treated PATH presence as proof a runtime works, so an installed-but-unusable docker (daemon stopped, socket unreachable, user not in the docker group) was still selected and the podman branch below it became unreachable. Each candidate is now probed with `version` — the cheapest command that still contacts the daemon — and the first one that actually runs wins. When nothing usable is found, the error names the runtime that broke and quotes its failure instead of claiming nothing is installed. An explicit QWEN_SANDBOX choice is never silently redirected; it fails with the daemon error attached. sandbox-exec is not probed, being a kernel facility rather than a daemon client. Fixes #7732 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(cli): attribute the sandbox command to its real source The probe failure hardcoded "(from QWEN_SANDBOX)", but an explicitly named command also arrives from --sandbox or tools.sandbox in settings. Naming the env var unconditionally sends a user who never set it looking in the wrong place — the same misdirection this change set out to remove. The parenthetical is now emitted only when the env var actually supplied the value, which also corrects the pre-existing "Missing sandbox command" message. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(cli): apply source-accurate attribution to the auto-detect errors too The explicit-string path stopped hardcoding QWEN_SANDBOX, but the auto-detect errors still did, so `qwen --sandbox` with a broken runtime pointed at an env var the user never set. Both auto-detect messages now name the env var only when it was what enabled sandboxing, and otherwise suggest --sandbox. Also lowers the probe timeout from 10s to 5s. Probes run sequentially, so the ceiling is paid once per wedged runtime; a healthy `docker version` answers in roughly 200-500ms, so 5s keeps an order of magnitude of headroom while halving the worst-case startup delay. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * test(cli): assert the sandbox probe argv and timeout The spawnSync stub routed on command name alone, so the probe arguments were never observed. Rewriting the probe to `docker --version` — which prints the client build without contacting the daemon, restoring the original defect — left all 12 tests green, as did deleting the timeout that bounds a wedged daemon. Validate both in the stub, so every probing test carries the check, and pin the argv at the fallback call site where the behavior is asserted. Reported by @wenshao in the mutation matrix on #7734 (M9, M8). * test(cli): cover the empty-output and timeout probe branches Two probe branches in probeSandboxCommand were unpinned, so a mutant in either survived the whole suite: - a non-zero exit with empty output relied on the synthesized-message fallback; dropping it made the probe return undefined and a broken runtime read as usable - the result.error branch that the probe timeout produces had no test; deleting it degraded the error text with the suite still green Each new test fails against its mutant and passes on the real code. Reported by @qwen-code /review on #7734. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * test(cli): isolate the sandbox probe in config precedence tests The image-precedence tests enable the sandbox and assert only which image wins. Since the runtime probe added here spawns a real `docker version` subprocess, and this file mocks command-exists but not child_process, the probe runs for real. On macOS the sandbox-exec branch returns before probing, so it passed there and on CI runners that have docker; on any other host without a running daemon getSandboxCommand throws and all four tests fail on image assertions they never reach. Mock the docker/podman `version` probe to report healthy, so selection is deterministic and the tests exercise image precedence on every platform. Every other spawnSync call stays real. Reported by @qwen-code /review on #7734. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(cli): cache the sandbox probe and sanitize its error output loadSandboxConfig runs twice on a sandboxed startup, so every candidate was probed twice — the wedged-docker-then-podman fallback paid the 5s cap twice (~10s), which the PR description wrongly called "once per wedged runtime". Cache each command's probe outcome per process (with a test-only reset), mirroring the ripgrep health cache, so a runtime is contacted at most once. The probe also returned the runtime's stderr verbatim into FatalSandboxError messages, carrying ANSI/control bytes to the terminal. Strip them with the existing stripAnsiAndControl helper, whose own doc names this case. Both requested by @wenshao in the review on #7734 (items 1 and 3). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(cli): keep an all-control-character probe failure from reading as usable The sanitizer checked the failure line for emptiness before stripping, so a runtime whose stderr is only escape/control bytes stripped to '' — falsy — and the broken runtime was selected as usable, reintroducing the presence-vs- liveness bug through the sanitizer. Check emptiness after stripping and fall back to the synthesized message. Also drop the redundant `candidate !== 'sandbox-exec'` guard (sandbox-exec is only a candidate once its presence is confirmed), reword the all-broken hint to "try another installed runtime" since another may be installed but also broken, and add tests pinning the control-character failure and the first-of-several- broken diagnosis. Reported by @qwen-code /review on #7734. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
8fd0162c68
|
fix(release): normalize Live Host signing identity (#8579) | ||
|
|
89b3d5ea8e
|
fix(autofix): ship core dist in the review CLI bundle (#8612)
* fix(autofix): ship core dist in the review CLI bundle The review fan-out (#8548) dropped the per-leg build: legs restore the shared bundle's repo-root dist/ and rely on the verify gate's full build for branch verification. But the gate's settings-schema and i18n checks run BEFORE any build, on every path including no-action, and their tsx-transpiled cli sources import '@qwen-code/qwen-code-core', which resolves through the workspace symlink to packages/core/dist/index.js. With no build on the leg, the generator crashes with ERR_MODULE_NOT_FOUND and the gate misreports a deterministic "settings schema is stale" rejection (run 31031063525 on PR 8600), then burns an 18-minute repair agent round on an environment problem no agent can fix. Ship packages/core/dist (+~8.5MB gzipped) alongside the root dist/ in the fan-out artifact and assert its entry point on restore. This restores exactly the pre-fan-out state: legs used to build the trusted base themselves before the branch checkout, so the gate always ran against base-built core dist. The workflow contract tests pin the new tar command and the restore-side assertion. * fix(autofix): rebuild branch-touched core dist before the schema gate Review feedback on the core-dist bundle fix: - Rebuild packages/core from branch sources in the review verify gate when the branch diff touches core's sources, so the pre-build settings-schema check never compares the branch's committed schema against a base-built dist (changed runtime constants) or crashes the generator (changed exports). Lives in the shared gate script so both the initial and the repair gate are covered. - Narrow the bundle/restore comments and their test mirror to the settings-schema generator: the i18n check resolves core to sources via the packages/cli tsconfig paths map and needs no dist (verified empirically). - Anchor the tar contract pin at end-of-line so additive path drift fails the suite instead of passing on a substring match. |
||
|
|
cb3dc107f7
|
test(core): deflake glob external-path test — dedicated empty dir, not /tmp (#8604)
* test(core): glob external-path test uses a dedicated empty dir, not /tmp The test really walks the path it names; on loaded self-hosted runners a littered /tmp made it time out at 15s — three times across #8388's CI runs alone, each reddening the required Test check for a test whose claim is only 'no workspace-boundary refusal'. An empty mkdtemp dir outside the workspace proves that claim deterministically. * test(core): apply review nits to glob external-path test (#8604) Address review feedback: - Use the same `glob-external-` mkdtemp prefix as the neighbouring external-dir test. - Assert `result.error` is undefined so an unrelated glob failure cannot slide past the negative workspace assertion. - Shorten the CI-narrative comment; the flake evidence lives here instead: run 31044530774, job 92443611234 (#8388). --------- Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> |
||
|
|
3235faf418
|
ci: add hk ECS runners to update matrix (#8599)
Some checks are pending
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 1/2 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 2/2 (push) Waiting to run
E2E Tests / channel-plugin E2E (nightly) (push) Waiting to run
E2E Tests / cron-interactive E2E (nightly) (push) Waiting to run
E2E Tests / web-shell Browser Regression (push) Waiting to run
npm cache producer / Save npm cache (push) Waiting to run
SDK Java / ubuntu-latest / Java 17 (push) Waiting to run
SDK Java / macos-latest / Java 21 (push) Waiting to run
SDK Java / ubuntu-latest / Java 21 (push) Waiting to run
SDK Java / windows-latest / Java 21 (push) Waiting to run
SDK Java / Real daemon E2E / Java 11 (push) Waiting to run
SDK Java / ubuntu-latest / Java 11 (push) Waiting to run
Update ECS Runner Qwen / Update Qwen on ecs-update-64c (push) Waiting to run
Update ECS Runner Qwen / Update Qwen on ecs-update-hk-1 (push) Waiting to run
Update ECS Runner Qwen / Update Qwen on ecs-update-sg (push) Waiting to run
Update ECS Runner Qwen / Update Qwen on ecs-update-hk-2 (push) Waiting to run
|
||
|
|
5173052e37
|
chore(release): v0.21.6 (#8598)
* chore(release): v0.21.6 * docs(changelog): sync for v0.21.6 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> |
||
|
|
2ad72fd5e9
|
fix(cli): Bound ACP textual tool-result payloads (#8450)
* fix(cli): Bound ACP textual tool-result payloads Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): Harden ACP text projection budgets Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * perf(cli): Cap multi-block ACP projection scans Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * test(cli): Cover ACP projection boundary guards Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
86a33777b3
|
feat(review): test the diff's reverse-dependency closure with disclosed caveats (#8490)
* feat(review): test the diff's reverse-dependency closure, fail open to the full suite
build-test tested only the workspaces the diff changed. That under-tests in
the one way a compile cannot catch: a behaviour change in core leaves every
dependent compiling and still fails their suites, so the break surfaces in a
consumer's tests or nowhere. The test phase now runs the changed workspaces
plus their transitive dependents (dependencies/devDependencies edges, the
same declared graph the build set already walks) - still a subset of the
build set, so every tested package was built with what it compiles against.
Scoping is an optimisation over the full suite, and every input that would
make the scoped set unsound now falls back to the repo's own full-suite
command (one root `npm test`; per-workspace suites when the root defines no
test script), never silently:
- a changed file outside every workspace (root scripts/, .github/, docs):
the test scripts themselves live in the root package.json, so no
per-workspace subset covers such a change;
- a workspace whose package.json does not parse: it is invisible to the
dependency graph, so the closure may be missing a real dependent;
- a closure past half the workspaces: not a meaningful narrowing, and the
root command brings the repo's own parallelism.
The report discloses the decision either way in a new `testScope` field
({ mode: "workspaces", workspaces: [...] } | { mode: "full", reason }), and
the ok-note names the scoped suites, so Agent 7 can state exactly what was
and was not run instead of implying the whole suite passed. Agent 7's brief
is updated to read it. Single-package repos keep a byte-identical report -
their one suite is their full suite, and no scoping decision happened.
On this monorepo the closure keeps the common cases scoped: a cli-only diff
runs 1 of 22 suites, a core diff runs its 7-package reverse closure.
The new lib/workspace-scope.ts carries the pure decision (resolveTestScope,
unparseableWorkspaceManifests); the reverse closure is extracted from
buildSetFor into reverseDependencyClosure so the built set and the tested
set cannot drift apart.
* fix(review): keep inert prose from forcing the full-suite fallback
The out-of-workspace fail-open was too blunt: it sent a README or LICENSE
edit to the full suite, spending minutes measuring nothing - prose cannot
fail a test, and "run everything" for a docs PR is the exact waste test
scoping exists to remove.
The scope decision now distinguishes the two kinds of outside file:
- inert prose (what the plan pipeline's own classifyPath calls docs, plus
the extensionless license family: LICENSE, COPYING, NOTICE and variants)
neither forces the full suite nor widens a scoped set. A diff of prose
alone obliges no test at all - the pre-scoping "nothing to run, and that
is a complete answer" behaviour, restored; prose riding along with one
workspace leaves the run scoped to that workspace.
- influential files (scripts/, .github/ workflows, root package.json and
other root config) still fail open to the full suite with the reason
recorded - the root package.json defines the test scripts themselves.
Reusing classifyPath rather than a second docs definition means the two
cannot drift, and inherits its safe bias: markdown outside the docs dirs
and the repo root stays influential (in-tree markdown can be executable
behaviour), erring toward running MORE tests. LICENSE.js stays influential
too - a name is only inert when nothing executes it.
* fix(cli): run the scoped closure with caveats instead of a full-suite fallback (#8490)
The full-suite fallback ran the repo root npm test, which cannot finish
inside a command deadline on a large monorepo (31 minutes in this repo's
CI against a 300s deadline) and fired for about a third of diffs, trading
a working scoped signal for a guaranteed timeout. Replace it: the scoped
set always runs, and every input that makes it possibly incomplete is
disclosed as a caveat on testScope instead.
Also close the silent-scope gaps the review found: manifests that parse
but lack a usable name now count as unreadable graph entries; symlinked
workspace members are visible to the graph; optionalDependencies are
reverse edges; a root suite that declares a workspace dependency runs as
a dependent; negation-excluded members earn no caveat; the half cap
counts testable suites only; build-only probes report no testScope; and
the docs-classified inert carve-out is gone (root AGENTS.md is load-
bearing for packages/cli's own suite) — only the license family stays
inert.
* fix(cli): address review round 2 on scoped build/test honesty
Resolve the round-2 findings on the scoped closure work:
- testScope is attached only once the scope executed; every early return
that ran zero test commands no longer carries it (R2-1).
- The more-than-half cap counts a participating root suite on both sides
(R2-2), and its witness is pinned in both directions (R2-13/24).
- Manifests whose body is the JSON literal `null` classify as skipped
instead of throwing past the try/catch (R2-3); test-plan honours the
skipped signal rather than ruling a false absence (R2-5).
- The single-root note no longer claims tests ran when the root defines
none (R2-11), and the scoped note no longer claims build-only
dependents were tested (R2-21).
- A negation only excludes a file when it excludes the owning member, so
a partial negation keeps the member's suite visible (R2-7); a
glob-claimed dir with no manifest self-discloses (R2-20).
- The build set and test closure are computed over one root-inclusive
graph so a member that depends on the root is built before it is
tested (R2-23); the dead single-root skipped reset is removed (R2-9).
- peerDependencies gains a witness (R2-17), the skipped docblock records
the per-shape truth (R2-18), and caveat substance is asserted in the
note, not just the label (R2-15).
* fix(cli): address review round 3 on scoped build/test graph honesty
Round-3 Critical findings, all probe-verified against the tree:
- R3-1: the build-only (merge-base probe) path excluded the root from the
scope graph, so the probe measured a different build set than the run it
baselines. The graph is now identical for probe and full run.
- R3-2: a root that joins the closure as a dependent ran `npm test` at the
root — which for a `--workspaces` fan-out script repeats the ENTIRE suite
inside one command deadline, the fallback this module refuses. A fan-out
root now leaves the executed set with a caveat; it stays in the graph.
- R3-3: root participation was gated on a TEST script, so a build-only root
vanished as a graph node and every dependent reached through the root's
name was silently dropped. The root now joins the graph whenever it is a
package with a build or test script; the dir->package map is built from
the scope graph so the root's own build runs too.
- R3-5: test-plan ruled `contradicted` ("script does not exist") from a
table that was silently incomplete for unmodeled globs (`packages/**`) and
`./`-prefixed globs. Unmodeled layouts now rule `unchecked`, and `./` is
normalized everywhere the walker reads globs.
- R3-6: a literal member listed BEFORE a `*` claiming its parent segment was
silently dropped (npm includes it under either order). It now lands in
`skipped`, so the broken-graph caveat fires and names it.
- R3-7: a negation excluding a NESTED member nulled ownership instead of
falling back to the surviving outer member, certifying "a complete answer"
over a suite that collects the file. Ownership now falls back through the
previous-owner chain.
Round-3 Suggestions: caveat test names the shadowed shape; half-cap comment
arithmetic fixed (R3-11); the three stale "subset of workspaces the diff
touched" prose spots now say "plus the workspaces that depend on them"
(R3-12); test-plan merges scripts of parseable-but-nameless manifests and
reserves `unchecked` for genuinely unreadable ones (R3-14); the single-root
build-only test witnesses the executed commands (R3-16).
218/218 across the four touched test files; full src/commands/review suite
1751 passed, 1 unrelated real-git flake that passes standalone; typecheck,
eslint --max-warnings 0, and prettier clean.
* fix(cli): address review round 4 on scoped build/test honesty
Findings from the round-4 review of ec7b202:
- F1 (whole-call budget): the closure's per-command deadlines SUM, and on
this repo a core diff's closure is 7 suites covering ~86% of test files —
past the 600s ceiling the brief welds on, where the outer kill discards
the report. The test loop now runs against a whole-call budget (--budget,
default 2x --timeout = 600s): when the next command's deadline would
cross it, the loop stops and names the suites that did not run, through
testScope.caveat (or the note for single-root repos). A partial report is
signal; a discarded one is the 71-timeouts failure this command exists
to end.
- F2 (name collision): the root and packages/cli share the name
@qwen-code/qwen-code on this very repo. The root now goes FIRST in the
scope graph so members win the name map — last-write-wins would have
resolved a dependent of the CLI package to the root and silently dropped
the member's dependents from the closure.
- F3 (-ws alias): rootTestFansOut now also matches npm's -ws/--ws
shorthands, while deliberately not matching -w/--workspace (singular).
- F4 (caveats compose): resolveTestScope disclosed at most two of five
possible caveats — skipped short-circuited the outside-file facts, and
any caveat suppressed the half-cap. All applicable caveats now compose,
strongest first, because "nothing is silent" means composing the
disclosures, not letting the first one hide the rest.
Smaller items from the same review:
- build/test commands shell-escape the workspace dir (PR-authored tree
input; $() and backticks stay live inside double quotes on POSIX).
- The ok-note counts the root separately instead of reporting "of 23
workspaces" on a 22-member repo.
- Dropped the pointless `const rootPackage = rootPkg` alias and the two
no-op buildSet filters; un-exported workspaceDirCandidates (internal
only); documented the previous-owner stack's contrived-ordering limit.
224/224 across the four touched test files; full src/commands/review suite
1757 passed (1 unrelated real-git flake that passes standalone); typecheck,
eslint --max-warnings 0, and prettier clean.
* fix(cli): address review round 5 on budget-stop honesty and root builds
Blocking and high findings from the round-5 review of 0c0e907:
- F1 (blocking): a budget stop left `testScope.workspaces` claiming suites
ran that never did — the note said "Everything passed" two clauses from
the caveat naming them not-run. The trim is now structural: `workspaces`
is exactly the suites that ran, a new `notRun` field names the trimmed
ones, and the zero-ran note branch says the budget was spent instead of
"no workspace defines a test script".
- F2 (blocking): budget truncation was alphabetical, so the CHANGED
workspace's own suite could be the one dropped (a `zebra` change ran
`alpha`'s suite first). The test loop now runs affected workspaces first;
the dependents are the widening, and the widening is what a budget trims.
- F3 (high): a root that devDepends on a workspace put `.` in the build
set and ran a bare `npm run build` — the whole-monorepo build this module
exists to stop. A fan-out root build (`--workspaces`/`-ws`/`--ws`) is now
skipped like its test counterpart: an aggregator produces no artifacts of
its own, and the scoped loop already builds the members it drives.
`rootTestFansOut` generalized to `rootScriptFansOut(root, script)`.
Calibration and nits:
- F4: the budget default keeps 30s of headroom under the 600s tool ceiling
(the clock outside starts before node does), floored at one per-command
deadline so a tiny --timeout cannot go negative; option and docblock now
say the budget covers the whole call, install included.
- F5: the half-cap caveat no longer says "of the suite" — it counts
workspaces and now says exactly that.
- F6: shellArg's docblock scopes the claim to POSIX (cmd.exe is not a
sealed surface); the "every return above ran zero test commands" comment
no longer contradicts the nothing-to-run early return; failure notes
carry the caveat too (the note is what the brief renders first); and the
root docs/ tree is carved out of the influential set — a caveat that
fires on most PRs teaches the reader to ignore caveats, while root-level
prose (AGENTS.md, asserted on by load-rules.test.ts) stays influential.
229/229 across the four touched test files; full src/commands/review suite
1762 passed (1 unrelated real-git flake that passes standalone); typecheck,
eslint --max-warnings 0, and prettier clean.
* fix(cli): address review round 6 on budget admission and report honesty
Findings from the round-6 review of 17209f09:
- F1 (medium, efficacy): the budget guard reserved a full --timeout per
suite, so at shipped defaults (300s deadline, 570s budget) at most one
test command could ever run after install+build — the headline coverage
was inert exactly where it mattered. The loop now ATTEMPTS every suite
with whatever of the budget remains, up to its own deadline: a suite
killed at the boundary is a timeout (already framed as infrastructure),
and only suites never attempted are named notRun. A partial attempt is
signal; a skipped suite was none.
- F2 (low-medium): results.buildSet kept '.' when the fan-out root build
was skipped — the same class of defect round 5 fixed structurally for
testScope.workspaces. The reported set is now filtered to what was
actually (to be) built.
- F3 (low): rootScriptFansOut classified `--workspaces=false` — an
explicit opt-OUT — as a fan-out, because `\b` matches before `=`. The
flag must now stand alone: `--workspaces(?=\s|$)`.
- F4 (low): testScope.notRun had no consumer — the agent's brief now
names it: suites the budget stopped before they ran are stated as not
run, never folded into the coverage.
F5 (half-cap caveat meaning) and F6 (ok:true on a zero-suite run) are
answered without code change in the PR reply: the half-cap sentence tells
the agent not to oversell the scoping, and ok reflects failures, never
coverage — both fully disclosed.
229/229 across the four touched test files (the budget witness now uses
real wall clock); full src/commands/review suite 1988 passed (1 unrelated
real-git flake that passes standalone); typecheck, eslint
--max-warnings 0, and prettier clean.
* fix(cli): address review round 7 on budget coverage and caveat calibration
Findings from the round-7 review of 00556278:
- R7-1: the whole-call budget guarded only the test loop — a 300s install
plus one 300s build already reached the 600s tool ceiling before any
suite was attempted, discarding the report the budget exists to save.
Install and every build now spend from the same budget (each command gets
min(its deadline, what remains)). A build phase the budget cuts short is
disclosed as `notBuilt`, filtered from the reported buildSet, and suites
of unbuilt packages (plus their dependents, via the closure) are not run
— running them would manufacture failures the diff did not cause.
- R7-2: a near-zero remaining slice manufactured a fake timeout (npm cannot
boot in 200ms: exitCode null, ok flips false, the suite absent from
notRun). A 15s attempt floor now routes those suites to notRun instead,
and the timeout notes interpolate the deadline the command was actually
given (CommandResult.deadlineMs), not the flag default.
- R7-3: the outside-file caveat fired on 38% of recent commits (measured)
— .github/**, CHANGELOG.md, and editor/VCS dotfiles earn no caveat now
(no workspace suite reads them, and the workflow tests that do live
outside the npm workspaces either way). Same cry-wolf argument the docs/
carve-out made, now with numbers.
- R7-4 (sizing): explicitly accepted — the PR body now states the cost
honestly: on the most common closure (7 suites incl. core+cli, ~56% of
workspace-touching commits) the 570s default realistically fits the
affected suite plus a dependent or two, the rest disclosed in notRun.
Smaller items:
- A diff inside a negated member (!packages/desktop) no longer reads as a
complete answer: the softest caveat says its own toolchain's suite was
not run — without claiming the scope is incomplete.
- scriptFansOut is pure on the script text; readRootPackage returns
RootPackage with scriptsText, ending the manifest re-reads.
- One named predicate (rootBuildSkipped) drives both the build-loop skip
and the buildSet filter, fixing the singleRoot mismatch.
- TestScope.workspaces' docblock now says the order is scope order, not
run order (test[] records execution order).
- New witnesses: the all-notRun note branch, notBuilt/notRun below the
floor, the negated-member soft disclosure, the CI/changelog carve-out.
230/230 across the four touched test files; full src/commands/review suite
1989 passed (1 unrelated real-git flake that passes standalone); typecheck,
eslint --max-warnings 0, and prettier clean.
* fix(cli): address review round 8 — structural notBuilt for base-tree
Findings from the round-8 re-review of 0f1492f9:
- R8-1 (the one that mattered): a budget-truncated BUILD passed base-tree's
availability gate — ok:true, toolchain npm, build[] non-empty — and got
the success marker, so test-delta would rerun the PR's failing files
against a base whose packages were never compiled; those reruns fail and
land in `shared`, and "shared = pre-existing by measurement, never filed"
waves a real regression through with the confidence of an A/B. notBuilt
is now structural on BuildTestReport, and base-tree treats a non-empty
one as unavailable — writing NO marker (truncation is a budget artifact,
not a settled answer about the SHA), so a later shard may repay and
succeed.
- R8-2 (carried over): the aggregate test-timeout note still quoted
--timeout; it now interpolates the deadline the command was actually
given, like the install and build-failure notes already did.
Nits:
- install gets the same 15s attempt floor as the build/test loops — a
sub-second `npm ci` would only manufacture a fake timeout, so it is
skipped and disclosed.
- notRun is sorted (both scope fields stable and comparable).
- rootSuffix now keys on the unified rootBuildSkipped predicate, and a
single-root repo counts its one package as the one workspace again
("Built 1 of 1", not "0 of 1 (plus the root package)").
- The 中文说明 block in the PR body is rewritten to match the English
(docs/CI carve-outs, all-phase budget, notRun/notBuilt, current counts).
246/246 across the five touched test files (incl. a base-tree witness:
truncated build → unavailable, neither marker written, next shard repays);
typecheck, eslint --max-warnings 0, and prettier clean.
---------
Co-authored-by: verify <verify@local>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
|
||
|
|
6b4a6295a2
|
feat(web-shell): run read-only info commands immediately mid-turn (#8496)
Some checks failed
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 1/2 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 2/2 (push) Waiting to run
E2E Tests / channel-plugin E2E (nightly) (push) Waiting to run
E2E Tests / cron-interactive E2E (nightly) (push) Waiting to run
E2E Tests / web-shell Browser Regression (push) Waiting to run
SDK Java / ubuntu-latest / Java 11 (push) Waiting to run
SDK Java / ubuntu-latest / Java 17 (push) Waiting to run
SDK Java / macos-latest / Java 21 (push) Waiting to run
SDK Java / ubuntu-latest / Java 21 (push) Waiting to run
SDK Java / windows-latest / Java 21 (push) Waiting to run
SDK Java / Real daemon E2E / Java 11 (push) Waiting to run
Sync cua-driver to Aliyun OSS / Mirror cua-driver binaries to Aliyun OSS (push) Has been cancelled
* feat(web-shell): run read-only info commands immediately mid-turn /stats, /about (/status) and /context were silently swallowed while a turn was streaming, because their local user echo would act as a turn boundary in applyTurnCollapse and split the active turn. Their output is a status block, which is not a turn boundary and is not counted in turn metrics, so only the echo needs to be skipped mid-turn. Add appendLocalUserEchoIfIdle, which echoes when idle and skips the echo while streaming without blocking the command, and switch these three commands to it so their results render inline immediately even during an active turn. * fix(web-shell): keep streaming assistant block intact for mid-turn info commands Address PR review. A status dispatch finalizes the active assistant block by default, so running /stats, /about or /context mid-turn would fragment the streaming answer around the status card and drop later usage frames. Add an optional clearActiveText flag to the status event and pass false from these three command dispatches, covered by reducer-level tests. Also collapse the echo gate into a single body (the new helper now delegates to appendOrDeferLocalUserMessage), add App-level wiring tests for the responding/idle behavior of /stats and /about, and surface failed getStats via reportError instead of swallowing them. * fix(web-shell): reset the echo user block when info output keeps streaming (#8496) The clearActiveText: false opt-out skipped the whole clearActiveText call, leaving the local command echo as the active user block indefinitely. A peer client's prompt echo then merged into it, corrupting turn boundaries. Keep the streaming assistant/thought block open on the opt-out path but still drop the user pointer. Also report /about load failures like /stats and /context already do, and pin the new /context wiring plus the /stats failure path with tests. * refactor(web-shell): centralize the mid-turn read-only status dispatch (#8496) Address the round-3 review feedback on the mid-turn read-only commands: - The read-only result dispatch (status block with clearActiveText: false plus the follow-resume) was copied verbatim at the /context, /stats, and /about sites, leaving the load-bearing flag enforced by convention at three places. Centralize it in one dispatchReadOnlyStatus callback next to echoLocalCommandIfIdle; the three .then bodies now call it with their serialized text. - Pin the /about catch the way the sibling /stats catch is pinned: make collectSystemInfo throw once and assert the failure surfaces through console.error instead of becoming an unhandled rejection with zero user feedback. * test: pin thought opt-out and serialized mid-turn status payloads (#8496) * refactor(web-shell): consolidate read-only command echo into echoOrDeferLocalCommand (#8496) * test(web-shell): cover /status routing and document the echo-suppression exception (#8496) --------- Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> |
||
|
|
477859bb3f
|
feat(channels): support local gh authentication (#8461)
* feat(channels): support local gh authentication Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * test(channels): align registry catalog test and visuals with optional GitHub token (#8461) * fix(channels): address review feedback for GitHub local gh auth (#8461) Treat a blank replacement of an optional secret as a clear so an existing GitHub channel can no longer ship an empty or whitespace-only PAT to the daemon. Reuse the shared missing-field predicate in the editor's GitHub credential validation, wrap malformed baseUrl failures in an actionable channel error, and surface sanitized gh stderr in local authentication failures. * fix(channels): address second-round review feedback for GitHub local gh auth (#8461) Pin the whitespace-only token gate, the bounded gh stderr sanitization, and the required-secret blank-replacement guard with mutation-resistant tests. Log the authenticated account identity on channel connect so an out-of-band gh auth switch is visible to operators. Align test secret-source fixtures with the SDK union and complete the design doc's change footprint. * fix(channels): address third-round review feedback for GitHub local gh auth (#8461) * fix(channels): address fourth-round review feedback for GitHub local gh auth (#8461) * fix(channels): address fifth-round review feedback for GitHub local gh auth (#8461) * fix(channels): address sixth-round review feedback for GitHub local gh auth (#8461) * fix(channels): address seventh-round review feedback for GitHub local gh auth (#8461) * fix(channels): address eighth-round review feedback for GitHub local gh auth (#8461) --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> |
||
|
|
a123d0030a
|
ci(review): prepare evidence-image tooling for GitHub-triggered reviews (#8454)
* ci(review): prepare evidence-image tooling for GitHub-triggered reviews Reviews triggered on GitHub cannot attach images today for three reasons; this wires the two that live in the workflow: - Install tmux and freeze (pinned, checksum-verified) before the review runs. Both are optional by contract — the evidence ladder degrades honestly without them (png -> ans-only -> refused, recorded in the capture manifest) — so the step never fails the review; it only decides which rung the runner can reach. tmux mirrors the tolerant install qwen-autofix.yml already uses; freeze falls back to ~/.local/bin when passwordless sudo is absent. - Pass QWEN_REVIEW_ASSETS_REPO from a repository variable to the review step. Publishing stays OPT-IN by design: with the variable unset the env is empty and publish-assets refuses (parseAssetsRepo trims and rejects empty), so nothing changes until a maintainer sets the variable. When set, evidence images land on commit-pinned pr-assets/<pr>-review branches — already covered by the visuals cleanup workflow — pushed with the same CI_BOT_PAT the step uses. The third reason is release lag: the capture producer (capture-tui, #8388) has to merge and ship in a release before rendering claims can generate images on CI at all. This change is inert until then. * fix(ci): capture-tools step review fixes — enforced tolerance, version pin, cached fallback R1-1: the never-fails contract is now enforced twice — continue-on-error at the YAML level (the belt) and set +e with a trailing exit 0 inside (the suspenders); under the runner's default bash -e several statements (mktemp, install, sudo install with an empty path) could previously abort the step and fail the review the comment promised never to fail. R1-6: probe the VERSION, not just the binary — on a persistent self-hosted runner an installed freeze made any FREEZE_VERSION/SHA bump a silent no-op; the pin now forces a refresh when the cached binary does not match. Cached-fallback fix: put ~/.local/bin on PATH (and GITHUB_PATH) before the probe — a sudo-less runner otherwise re-downloads the tarball on every review run forever. R1-3: the step comment says capture-tui is UPCOMING (#8388, not in the released CLI) and names qwen review drive as today's tmux consumer, so the step cannot be mistaken for stale dead weight and deleted from under the follow-up. R1-4: the retention comment scopes the cleanup-workflow claim to the same-repository designation; a fork or scratch destination manages its own retention (docs updated to match, plus a note documenting the repository VARIABLE a maintainer sets to enable publishing). R1-5: the step's real bash now runs in the workflow behavioural harness under bash -e with stubbed sudo/apt/curl/sha256sum/tar/uname: worst-runner and checksum-reject scenarios exit 0 installing nothing, the no-sudo happy path pins the ~/.local/bin + GITHUB_PATH pairing, and the version-pin probe is pinned from both sides (wrong version re-downloads, matching version skips). Real freeze/sudo on a developer machine are shadowed so the tests are deterministic and can never install to /usr/local/bin. Nit: both sudo guards now check sudo -n true. * fix(ci): capture-tools step review fixes — step-owned tool dir, anchored probe, honest failures Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(ci): capture-tools test harness — shadow tmux, don't blank its PATH dir The harness dropped every host PATH directory that ships a tmux so the step's apt branch would depend on the scenario, not on the machine hosting the suite. On GitHub-hosted ubuntu runners tmux lives in /usr/bin, so the filter blanked /usr/bin wholesale — bash, grep, mkdir, and tar included — and execFileSync('bash') died of ENOENT: all seven capture-tools tests failed in the Test (ubuntu-latest Node 22.x) job while passing on tmux-less dev machines. Replace the directory-level drop with an entry-level shadow: each tmux-bearing directory is mirrored (symlinks) into a scratch dir minus the tmux entry, in place, preserving PATH order and the empty-entry stripping the old filter did. Hosts without tmux take the map through unchanged, and Windows (no tmux in its PATH, no symlink branch) keeps its current behavior exactly. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(ci): capture-tools test review fixes — faithful stubs, env shape pins, missing-branch scenarios Round-3 review findings: the harness executed several of the step's branches but asserted nothing about them, so probe-verified mutants (dropped tmux guard, deleted warning/degradation messages, malformed or missing FREEZE_VERSION/FREEZE_SHA256, wrong hash variable, dropped URL `v` prefix or curl `-L`, severed tarball paths, broken regex boundary, leaked mktemp dir) all shipped green. - Make the curl/sha256sum/tar stubs model their real contracts: exact pinned URL, pinned checksum over a file curl actually wrote, existing -xzf operand - Pin FREEZE_VERSION/FREEZE_SHA256 shape in captureToolsSource - Pin the full curl flag set and the three-site tarball path agreement - Assert the stale-renderer warning (fires on degraded re-download, silent on the happy path) and the tmux-unavailable message - Pin TMPDIR and assert the mktemp cleanup leaves it empty - Add the two missing scenarios: tmux-present skips apt, cached version extending the pin with a leading digit re-downloads Verified by 13 mutation probes: every named mutant now turns the suite red (13/13 killed), baseline 34/34 green. * fix(ci): capture-tools step review fixes — hash-verified cache, per-run PATH promotion * fix(ci): capture-tools step review fixes — verified-bytes-only installs, step timeout Review findings on the capture-tools step: - Drop the PATH-trust branch: a freeze already on PATH was accepted on its own --version and executed to probe it — exactly the self-report the FREEZE_BIN_SHA256 comment declares attacker-controllable, from dirs writable between jobs on both runner classes. The checksummed download always runs now; the cache makes it free after the first run. - Guard $tools_bin in the download branch: with mktemp failing, the unguarded install resolved to /freeze — harmless unprivileged, but a root-in-container self-hosted runner writes it and reports success with nothing on PATH. - Copy-then-verify the cache: install into the fresh per-run dir FIRST, verify THOSE bytes, delete both copies on mismatch — the verified bytes are the bytes later steps execute, closing the check-then-copy race for free. This makes the separate pre-verify block redundant; it is deleted. - Add timeout-minutes: 5 — continue-on-error bounds failure, not duration, and a stalled `sudo apt-get update` mirror had no other bound under the 300-minute job cap. - Report block: say the resolved freeze is likely broken when its --version produces nothing, instead of echoing a blank line and calling it stale; the mismatch wording is direction-neutral now. Tests: replace the PATH-trust scenario with a planted-PATH one (marker outside the scenario dir proves the plant never executes), add the mktemp-failure scenario (the install stub succeeds like root would, so the unguarded mutant is caught) and the promoted-dir 0700 assertion; re-anchor the two digit-boundary tests on the report's warning. 41/41 green; both fix mutants verified killed. * fix(ci): capture-tools review fixes — stale-dir cleanup, pinned guards Address round-5 review: - R5-1 (Critical): the per-run qwen-review-tools.* dir under RUNNER_TEMP was never removed; RUNNER_TEMP survives across jobs on the shared pool, so every review run accumulated one dir + one Go binary, unbounded. 'Clean stale agent state' now removes stale dirs before the install step creates the current run's dir, matching the qwen-triage.yml convention. The harness comment claiming the dirs were runner-cleaned is corrected. - R5-6: the cache re-verification rejection branch now logs why it deletes the cached binary instead of degrading silently. - R5-7: bump-checklist note beside the freeze pins — the harness stubs key on the same env values, so a transposed hash pair must be caught against the real release artifacts at bump time. - R5-2/R5-3/R5-4/R5-5: four unpinned step properties now pinned (the if: guard, the sudo -n probe flag, install-after-context ordering, and the cache branch's tools_bin guard via a new mktemp-fails scenario); six mutation probes confirm each pin kills its mutant. * fix(ci): capture-tools review fixes — curl budget, swept scratch dir, wiring pins * fix(ci): capture-tools review fixes — harness mutation pins, pin-pair self-check Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(ci): capture-tools review fixes — shadow-farm cleanup, backoff budget term * fix(ci): capture-tools review fixes — report probes only installed freeze, age-gated sweep --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com> |
||
|
|
c73b5ed887
|
ci: run Windows merge queue tests on ECS (#8386)
* ci: run Windows merge queue tests on ECS
* test(channels): skip POSIX mode assertion on Windows
* ci: expose Git Bash on Windows ECS runner
* ci: scope Windows ECS tuning to self-hosted and restore full test:ci
Review feedback on the Windows ECS routing: dropping test:scripts removed the only Windows execution of 9 Windows-only install-script tests, and the job-wide PowerShell default plus narrowed test command changed the kill-switch fallback away from the known-good hosted configuration.
Restore the full npm run test:ci on both paths (bash is available: pre-installed on hosted runners, exposed via the Git Bash PATH entry on ECS) and gate every ECS-specific adjustment on runner.environment: the PowerShell setup step (now also skip_ci-guarded), TEMP/TMP/LC_ALL env writes, and the Linux-style Node setup split that fails with an actionable error naming MAINTAINER_ECS_RUNNER_DISABLED. The windows-2022 fallback is byte-for-byte the pre-ECS job again.
* test: make Windows CI suites platform-aware
* ci: add stale-checkout guard to Windows ECS test job
* test(core): compare canonical directory identity
* ci: add fork guard and review follow-ups to Windows ECS job
* test(core): exercise real directory identity change
* test(core): wait for killed lease process exit
* test(scripts): avoid cmd echo trailing spaces
* test(scripts): use unambiguous cmd echo syntax
* test(cli): avoid sidecar I/O in truncation test
* test: fix Windows script-suite gaps and unify platform gating
- Fix missed trailing-space cmd stub in package-scripts.test.js so the
'runs prepare steps in order' assertion passes on Windows.
- Add qwen-pr-review-workflow.test.js and pr-self-report-label.test.js to
the win32 exclude list (both test Linux-only workflows and are not
portable to Windows).
- Replace local itPosix/describeOnNonWindows consts with vitest's built-in
it.skipIf/it.runIf/describe.skipIf, matching the codebase idiom.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* test(scripts): restore Windows workflow coverage
* test(scripts): re-exclude Windows-incompatible workflow tests on win32
Re-add pr-self-report-label.test.js and qwen-pr-review-workflow.test.js to
the win32 exclude list. Both fail on a Windows runner for reasons the code
still carries: qwen-pr-review-workflow.test.js calls execFileSync('mkdir'),
which has no executable to resolve there, and pr-self-report-label.test.js
joins PATH with ':', corrupting the ';'-separated Windows PATH so its gh
stub never resolves. Excluding them restores a green Windows gate; Linux CI
remains their authoritative coverage. Document the criterion inline.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* ci: extract checkout-head guard into composite action, pin Windows gate (#8386)
Address review round 2: move the stale-checkout guard shared by the four CI gates into .github/actions/verify-checkout-head so the copies cannot drift, pin the Windows gate kill-switch routing and guard wiring in the script tests, re-enable lint.test.js on Windows via separator normalization and a lazy linter setup in scripts/lint.js, unify the platform skips on it.skipIf(process.platform === 'win32'), and document the queued-run behavior of the ECS kill switch.
* ci: fail fast in Windows gate environment setup (#8386)
* ci: dedupe self-hosted runner steps into actions, pin gate mutations (#8386)
* fix(ci): checkout before repository-local actions in Windows gates (#8386)
* fix(ci): configure Windows runner before bash guard
* test(ci): pin remaining shared-action wiring in script tests (#8386)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(ci): skip zip-dependent packaging tests when zip is missing (#8386)
* fix(ci): validate full Windows smoke path
* fix(ci): match Windows smoke shell to gate and drop dead runs-on guard (#8386)
* fix(ci): make SIGTERM escalation test Windows-aware and tighten pins (#8386)
The CDP acceptance test asserted a POSIX-only SIGKILL escalation, which
fails deterministically on Windows where kill('SIGTERM') terminates the
child directly — blocking the Windows merge-queue gate. Assert the
platform-appropriate signal instead.
Also address review suggestions: probe `unzip` alongside `zip`, pin the
integration_cli guard's missing step-level `if:`, stop getWorkflowStep
at unnamed steps, pin install-script.test.js out of the win32 excludes,
add the stale-checkout guard to windows-runner-smoke.yml, pin the
Node preflight warning branch and the guard reject path contiguously,
and extend the smoke shell-parity loop to the npm cache step.
* docs(ci): clarify Windows runner trust boundary
---------
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.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>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: qwen-code-ci-bot <qwen-code-ci@service.alibaba.com>
|
||
|
|
93cd019088
|
fix(release): reuse configured Apple signing secrets (#8574) | ||
|
|
a5c637b749
|
feat(web-shell): add native Live Voice (#7859)
* feat(web-shell): add native Live Voice * fix(web-shell): address review feedback for Live Voice PR (#7859) - Quote all strings in electron-builder.yml to fix yamllint CI failure - Gate discovery publish on liveVoiceEnabledAtBoot to avoid writing bearer token to disk when Live Voice is disabled (M1) - Add child identity guard to CommandMonitor stdout/stderr handlers to prevent stale helper output from corrupting the new buffer (M4) - Add exponential backoff to sent-completion delivery retry (M3) - Skip broadcastState when setCallState/setTranscript value is unchanged to reduce per-audio-delta overhead (H1) - Document sent-mode completion notification in module docstring (H2) - Remove dead protocol/nonce aliases from readDiscoveryFile - Fix single instance lock fall-through with process.exit(0) * fix(cli): register realtime_voice in docs contract and env guard (#7859) * fix(web-shell): address review feedback for Live Voice PR (#7859) * fix(cli): discard orphaned isolated dir when parent restore fails (#7859) * fix(web-shell): address review feedback for Live Voice PR (#7859) * fix(serve): harden live turn recovery * fix(desktop): restore Live Host native build * fix(live): align native host and session isolation * fix(acp): preserve live worker continuation lineage * fix(live): classify provider close reasons * fix(serve): discard unused recovered conversation dirs * fix(live): isolate authorized realtime responses * fix(live): preserve realtime response authority * feat(web-shell): complete Live Voice onboarding * fix(live): persist realtime-owned dialogue * fix(live): preserve final speech while stopping * Revert "fix(web-shell): address review feedback for Live Voice PR (#7859)" This reverts commit 7110bec6b034c702bca6e28e35b93c7f70e729cd. * Revert "fix(cli): discard orphaned isolated dir when parent restore fails (#7859)" This reverts commit 85165f1b2ddfaa311b8be91acdd76a6f388f6204. * Revert "fix(web-shell): address review feedback for Live Voice PR (#7859)" This reverts commit 9199fa633e102bb8f24e4b216d322be4323eb3fc. * Revert "fix(cli): register realtime_voice in docs contract and env guard (#7859)" This reverts commit 6b6b1718352ef01a98a73976b5c7c4433fd14c35. * Revert "fix(web-shell): address review feedback for Live Voice PR (#7859)" This reverts commit e083779105199d26de3afd8ad00719a08efe3099. * revert(live): remove remaining takeover behavior * revert(live): restore pre-rollback implementation * test(cli): align Live diagnostics env guard * test(release): cover Live Host publication * fix(ci): re-sign Live Host package before verification * fix(serve): scope sent completion notifications to Live * fix(web-shell): preserve live setup errors * fix(live): align realtime backend speech lifecycle * ci(live): publish Live Host independently * test(cli): mock Live speech bridge handler * test(release): align Live Host workflow contract * fix(live): address release and lifecycle review findings * fix(live): release completed call tracking --------- Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.com> Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com> Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com> |
||
|
|
67d128715e
|
chore(cua-driver): sync upstream v0.17.0 (#8564) | ||
|
|
6d4d9b5238
|
perf(review): retire dry chunks and pipeline verification in the reverse audit (#8498)
Some checks are pending
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 1/2 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 2/2 (push) Waiting to run
E2E Tests / channel-plugin E2E (nightly) (push) Waiting to run
E2E Tests / cron-interactive E2E (nightly) (push) Waiting to run
E2E Tests / web-shell Browser Regression (push) Waiting to run
SDK Java / ubuntu-latest / Java 11 (push) Waiting to run
SDK Java / ubuntu-latest / Java 17 (push) Waiting to run
SDK Java / macos-latest / Java 21 (push) Waiting to run
SDK Java / ubuntu-latest / Java 21 (push) Waiting to run
SDK Java / windows-latest / Java 21 (push) Waiting to run
SDK Java / Real daemon E2E / Java 11 (push) Waiting to run
* feat(review): retire dry chunks from reverse-audit rounds and pipeline verification Rebuild of the retirement/pipelining feature as one commit on top of the merged reverse-audit budget gate (#8468). - retirement.ts: per-chunk scheduler over the CLI's own prompt records and the harness transcripts — a chunk whose two most recent audits are substantive dry receipts is cold-checked on the even rounds instead of audited on every one, and a cold check that yields returns it to every-round auditing. The certifying match is counted records per transcript (one launch matching several records certifies none), dry receipts are read structurally with the zh forms beside the English ones, and a filed finding requires the File+Severity pair so an echoed quotation cannot pin a chunk hot. Everything fails toward auditing. - agent-prompt --all-chunks: requireAuditableChunks, then the schedule (round >= 3, fail-open to all-due on any error), then CONVERGED exit 5 (nothing built, no stamp, no marker), then the budget gate (exit 4 + marker), then the build. The admission stamp keeps the #8468 ordering and lands only after the build succeeds: a cold-check-only round that builds still stamps, a converged round never does, and a build that throws leaves no stamp. - agent-prompt --chunk: a round holding an admission stamp is repaired without gates or scheduling; an unadmitted round answers to the same sequence as --all-chunks (convergence, then budget), and its first chunk build is the round's admission — stamped after the build. - prompt-record: optional sinceMs fence on readRecordedPrompts (history readers only; coverage's obligation reads stay unfenced), plus the flattenPrompt/deliveredVerbatim split so the scheduler flattens each launch once instead of once per (record, transcript) pair. - deadline: doc-comments rewritten for the pipelined cadence — the admission-to-admission measure no longer contains a verification pass, so the tail reserve is the terminal round's only cover (replacing the 'deliberate margin' overlap rationale), and the workflow's reserve cap is cross-referenced. runEpochMs fencing, the bilingual budget-stop marker and the stamp semantics are unchanged from #8468. - SKILL Step 5: builder-owned 3B scheduling, the CONVERGED exit-5 termination rule, verification launched alongside the next round's auditors, and the cumulative reported list with '— [unverified]' tagging (added at the admitting merge, cleared or removed after the verdict; anything still tagged is excluded from Step 6). Superseded pieces of the parallel branch were dropped in favour of the #8468 form now on main: the planMtimeMs-equality fence (runEpochMs stays), the budget-scaled round-1 estimate, stamping inside the admission helper, and the branch's variants of the budget-gate tests. * test(review): split the tool-call guards in the retirement classifier tests Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(review): harden the retirement classifier and pin its gate orderings (#8498) Review-round fixes for the per-chunk retirement feature: - retirement.ts: admit the full-width colon (U+FF1A) in zh dry receipts, which the old [::] class silently refused; refuse the brief's own example receipt and prose artifacts (a stray backtick, the conjunction "and/or") in the substance check; require the transcript's diff reads to overlap the chunk's baked territory before a dry receipt counts; stop counting a quoted cumulative-list entry — a File+Severity block whose file line appears verbatim in the agent's own launch prompt — as a filed finding. Every change fails toward auditing. - agent-briefs.ts: export the reverse-audit example receipt (REVERSE_AUDIT_EXAMPLE_RECEIPT) and interpolate it in the brief, so the brief and the classifier's parrot refusal cannot drift. - Tests: rewrite the transcript-fence test, which a future-dated plan made vacuous, and add probe-verified pins for every fix plus the previously unpinned guards — converged-before-budget under deadline on the --chunk path, the --chunk transcripts-unavailable degrade, the stamp-keyed repair exemption (records without a stamp stay refused), budget-stop marker absence on the admission side, uncertified cold-check recovery, the history-less chunk guard, and the same-round multi-record merge in both digest orders. - SKILL.md: schedule the Step 5 findings merge unconditionally — verdicts land on dry rounds too — and cap a would-be Approve at COMMENT when a reverse-audit entry's verifier never ruled on it. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(review): bind the retirement territory to the diff read and reprice the budget gate (#8498) * fix(review): machine-check the unverified-tag backstop and reprice the tail reserve (#8498) --------- Co-authored-by: verify <verify@local> Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
da37110e60
|
perf(autofix): build the review CLI bundle once per scan and fan it out to legs (#8548)
* perf(autofix): build the review CLI bundle once per scan and fan it out to legs Each review-address leg repeated the same trusted-base build: measured 3.5-5 minutes of npm ci + build + bundle per leg (~25 runner-minutes on one 6-leg scan) before the agent could start. A build-cli job now compiles the bundle once per scan, uploads the repo-root dist/ as an artifact, and the legs download it; their checkout is pinned to the compiled SHA so a mid-run base push can never pair a leg's bundle with different sources. The legs keep npm ci (the agent and the verify gate still need node_modules against the PR branch), and the issue phase is untouched — it runs only when no review targets exist, so gating the build on do_issue too would rebuild on every quiet scheduled tick. * fix(autofix): validate fan-out bundle SHA and pin shared CLI recipe contracts (#8548) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> --------- Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
8b0e8b8192
|
fix: add onCompromised handlers to proper-lockfile calls to prevent daemon crash (#8442)
* fix: add onCompromised handlers to proper-lockfile calls to prevent daemon crash When a lock.lock directory is deleted while held (e.g. by another process cleaning stale locks), proper-lockfile's updateLock timer gets ENOENT on stat and calls the default onCompromised handler, which throws and crashes the process. Add onCompromised handlers that log instead of throw, consistent with existing handlers in tasks.ts and mailbox.ts. * fix: guard lock release after compromise and cover trusted folders (#8442) * fix: guard mailbox/task lock release and cover compromise handlers with tests (#8442) * test(core): add lock-compromise regression tests for mailbox and task guards (#8442) * test: share lock-compromise simulation via test-utils helpers (#8442) --------- Co-authored-by: 易良 <1204183885@qq.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> |
||
|
|
3084326243
|
fix(webui): recover complete turns after live journal truncation (#8414)
* fix(webui): recover live journal turns Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(webui): address PR review feedback (#8414) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(webui): refresh repair pagination anchor (#8414) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(webui): restore evicted repair side effects Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
e34780e24d
|
fix(ci): clean review worktrees after cancellation (#8474)
* fix(ci): clean review worktrees after cancellation * fix(ci): remove orphaned review worktree directories * fix(tests): sync qwen-resolve-workflow expectations with externalized review timeouts (#8474) * fix(ci): pin review worktree cleanup patterns to paths.ts (#8474) * fix(ci): harden review cleanup sweeps and cover integration_cli (#8474) * fix(ci): extend review cleanup sweep to web_shell_e2e_smoke (#8474) * fix(ci): harden review cleanup git calls * fix(ci): tighten review cleanup comments and test guards (#8474) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * test(ci): pin review cleanup recipe copies byte-identical (#8474) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(ci): guard review worktree removal and pin cleanup invariants (#8474) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> --------- Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
2601d815dd
|
test(ci): align resolve-workflow timeout expectations with externalized variables (#8460 follow-up) (#8485)
* test(ci): align resolve-workflow timeout expectations with externalized variables #8460 moved the review timeout numbers into repository variables (QWEN_REVIEW_JOB_TIMEOUT_MINUTES / QWEN_REVIEW_MAX_TIMEOUT_MINUTES) but left qwen-resolve-workflow.test.js expecting the old hardcoded 300/240 values — main's Test lane has been red since. The five expectations now pin the variable-driven forms the workflow actually carries. * test(ci): pin resolve-workflow timeout enforcement, tiering, and fallback machinery * test(ci): pin the timeout-advice branch CONDITION, not just both bodies With both branch bodies asserted as substrings of the same step, any comparison flip (-ge/-gt/-le) keeps both strings present and ships the wrong recovery advice on every timeout — a below-max run told it already used the maximum, an at-cap run told to retry with a timeout that cannot work. Raised in #8388's review round (R4-21). * test(ci): anchor resolve-workflow arm slices at their if starts Address review feedback on #8485: search for each sliced arm's else from the arm's own if start so an unrelated earlier if/else in the step cannot invert the slice (or vacuously satisfy .not.toContain on an empty slice). Also slice the small-PR tier arm instead of comparing first-occurrence indexes, unifying the technique and proving the assignments sit in opposite arms. * test(ci): keep the max-timeout text out of the below-max arm slice * test(ci): pin fallback arm bodies, comment wiring, and tiering order * review: line-anchor the at-max arm's closing fi A bare indexOf('fi') stops at the first word CONTAINING the letters — 'specified', 'notification' — so a harmless wording change inside the at-max arm would silently truncate the slice and hand the arm's not-toContain a vacuous pass. The end anchor is now the line-anchored /\n\s*fi\b/, with its own found-assertion. --------- Co-authored-by: Qwen Autofix <autofix@qwen-code.dev> Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com> Co-authored-by: verify <verify@local> |
||
|
|
1a2bb10298
|
fix(review): admit evidence images by content, not by name — magic-byte sniffing (#8459)
* fix(review): admit evidence images by content, not by name — magic-byte sniffing The publish-assets allowlist was extension-based, and an extension is a claim anyone can make: combined with a prompt-injected review run, whatever could name a file evidence.png could host up to the size cap of arbitrary bytes at a github.com URL through the evidence push (raised in #8454's review as an enablement consideration). sniffImageFormat reads the four admitted signatures (PNG, JPEG, GIF87a/89a, RIFF+WEBP — RIFF alone is not enough, AVI and WAV share the container prefix) and validateAssetContent rules the content against the format the extension claims, fail-closed: an unrecognized signature refuses even when the extension is allowed. publish-assets applies the ruling to every file's first bytes before anything is uploaded — all-or-nothing, same refusal contract as the other gates. Pinned: the four signatures, truncated/empty headers, the RIFF/AVI near-miss, extension-format mismatch, fail-closed unknown extensions, and end-to-end: a shell script named evidence.png refuses with exit 3 and nothing pushed. * fix(ci): re-pin review timeout tests to vars externalization (#8459) * fix(review): single-source the asset allowlist and pin sniff depth (#8459) Address round-1 review suggestions: - ASSET_EXTENSIONS now derives from EXTENSION_FORMAT, so admitting a format is a one-place change the batch gate and the content gate cannot drift on; the duplicated extension extraction moves into one claimedExtension helper shared by both gates. - Pin what the mutation probes showed unpinned: the GIF87a branch (sniff + admission), uppercase extensions at the content gate, the refusal message direction, the full depth of every signature (near-miss negatives), and the publish-time 16-byte slice end to end (a WEBP publishes through runPublishAssets; verified the test fails when the slice shrinks to 8). * fix(review): pin every sniff check and guard the allowlist lookup (#8459) * fix(review): pin every sniff byte and the two-gate format coupling (#8459) * fix(review): align the two-gates comment with the pin that enforces it (#8459) * fix(review): sharpen evidence-gate diagnostics and pins (#8459) - Content refusals now name the JSON-quoted full path, so two same-named files from different directories are tellable apart (the sibling read-error refusal already spent the path). - Export ASSET_HEADER_BYTES from the lib that owns the sniff depth; the publish call site uses it and the two-gates pin slices canonical headers to it, so a future longer signature fails the pin, not real publishes. - One shared refusal builder keeps the allowlist message identical in validateAssetFile and validateAssetContent. - Narrow the sniffImageFormat threat model to what magic bytes buy: binds the claimed type to the leading bytes, does not stop prefixed payloads. - One-byte-off matrix becomes a labeled it.each table (failures name the exact corrupted byte); imports re-alphabetized. * test(review): pin the shared extension refusal across both asset gates (#8459) * test(review): pin lastIndexOf extension parsing for multi-dot asset names (#8459) * fix(review): admit WEBP by its fourcc and name refused files once (#8459) --------- Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> |
||
|
|
4f79036a22
|
feat(review): a cost ledger from the records already on disk (#8471)
* feat(review): a cost ledger from the records already on disk "0.21.3 was fine, 0.21.4 got slow" was settled only by replaying a whole review under a telemetry exporter and hand-aggregating the output — hours of forensics to find a repair round that had silently doubled a run (measured: a +93/-48 PR at high effort cost 523 model calls and 37.8M input tokens, 9.7M of them redelivering prompts the agents had already acted on). The usage data was on disk the whole time: every chat and subagent transcript event carries usageMetadata. qwen review cost-ledger --plan <plan> aggregates those records — the same files check-coverage trusts for delivery, found via the same environment-exported location, floored at the plan's mtime so a review started an hour into a session does not bill that hour — into per-stream totals: the main loop and each agent, with input / cached / output / thinking counts and wall time. Step 8 pastes the printed block into the saved report, so the next slowness question is a diff of two archives instead of an excavation. Informational by construction: an incomputable ledger prints why and exits 0. Validated against the measured run above — 521 calls, 37.7M input (93% cached), 849k output, 107 min — matching the telemetry-side aggregation, minus the two side-query calls that are not the review's. * test: register cost-ledger in the subcommand registry and its demand message * fix(review): honest cost-ledger output and a safe archive write (#8471) Address the review of the cost ledger: report output tokens once (thinking is a subset of candidates, not a sibling), keep the --out write inside the exit-0 contract and mkdir its parent, name a missing plan as the plan, read each transcript once, compare timestamps as instants, fold relaunched agents into marked rows, and archive the full ledger next to the Step 8 report. * fix(review): cost ledger — honest failures, validated plan, shared records (#8471) Address the second review round: a missing or faulted chat transcript now says "cost-ledger unavailable" instead of rendering agents-only totals as the whole cost (the plan proves the main loop ran), and a subagent dir that fails listing with anything but ENOENT does the same. The --plan file is validated as a plan report before its mtime alone sets the billing window. Output derives from totalTokenCount − promptTokenCount when present, correct under both usage conventions. Chunk agents label "chunk N" via the shared CHUNK_RE instead of the malformed "agent chunk N of M"; the transcript listing is one helper shared with the coverage gate; glued JSONL records are recovered via parseLineTolerant; totals reuse the rows' accumulator; folded (×N) rows rank by combined total; stale agent files are skipped by mtime without being opened. Rendered block gains pluralization, "agent runs: N", and a B tier; SKILL.md states the ledger's bounded window. * fix(review): close the cost-ledger audit — refusals, labels, pinned math Address the remaining review threads on the cost ledger: - Refuse agents-only totals when the chat file exists but holds no above-floor records: a degraded recorder leaves the file present and empty while agents run — the same infrastructure fact as an unreadable transcript, and exactly the output the missing-file refusal exists to prevent. - Read the agent label from the first user record, not a raw 64KB head slice: a fork's agent_bootstrap record precedes the launch prompt, quotes other agents' identity lines, and can outgrow any fixed window. - Distinguish parallel invariant agents by their owned file, so per-file runs stop folding into a phantom (xN) relaunch row. - Coerce negative provider counts to zero: the agent path records usage uncoerced, and summed negatives rendered >100% cached shares. - Accept degraded diff-less Step 1 reports: validate diffLines + chunks, the pair every plan report carries, instead of check-coverage's stricter contract that refused them. - Pin every branch the second round proved unobservable: the exit code on all handler paths, total - prompt under both usage conventions, per-agent fault tolerance, the wall-minutes conversion, array-shaped usage, the mtime pre-filter and the event-level floor, human() rounding, per-condition plan validation, sort order against a lexical readdir, the zero-event skip, the --out per-stream archive contract, error messages naming their paths, truncation membership and folded-run counting, and the assistant-type filter. Every new assertion was mutation-probed: each mutant the review named now turns the suite red. * review: pipeline stages keep their own ledger rows The (×N) fold keyed on the label alone, and three legitimate multi-launch shapes shared one: a reverse-audit chunk auditor is launched with the same 'chunk N of M' identity as the Step 3B territory finder (five audit rounds folded into the finder's row — one agent where six pipeline stages ran), and repeat rounds of the findings roles carry their round OUTSIDE the backticks (every round folded as a phantom relaunch). labelOf now reads the stage from the audit brief's record key in the launch (audit chunk N (round K)) and the round from the identity LINE — never the whole launch, whose folded findings can quote a budget disclosure's own '(round N)' — so rounds are rows and only true relaunches and same-round verify shards fold. The (×N) comment now says what the marker means: N runs under one label. * fix(cli): annotate cost-ledger test helper to restore strict build (#8471) * fix(cli): anchor cost-ledger labels and harden broken-usage defenses (#8471) --------- Co-authored-by: verify <verify@local> Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> |
||
|
|
32e2741577
|
perf(core): clear tool results to a low watermark to preserve prompt cache (#8464)
Some checks are pending
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 1/2 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 2/2 (push) Waiting to run
E2E Tests / channel-plugin E2E (nightly) (push) Waiting to run
E2E Tests / cron-interactive E2E (nightly) (push) Waiting to run
E2E Tests / web-shell Browser Regression (push) Waiting to run
SDK Java / ubuntu-latest / Java 11 (push) Waiting to run
SDK Java / ubuntu-latest / Java 17 (push) Waiting to run
SDK Java / macos-latest / Java 21 (push) Waiting to run
SDK Java / ubuntu-latest / Java 21 (push) Waiting to run
SDK Java / windows-latest / Java 21 (push) Waiting to run
SDK Java / Real daemon E2E / Java 11 (push) Waiting to run
* perf(core): clear tool results to a low watermark to preserve prompt cache Size-triggered microcompaction now clears oldest compactable tool results down to half the threshold instead of stopping just below it, so the conversation prefix stays stable between clearings and provider prompt caches keep matching. The recent-result budget now protects committed results only; pending results no longer consume protection slots but stay counted, uncleared, and live for file-read-cache resolution. Adds the watermark to cleanup metadata and the debug log. Fixes #8463 * fix(core): harden size-cleanup protection against zero-char and pending refs Review follow-up for the low-watermark change: keepRecent now selects from committed results that are actually clearable (positive, successful, uncleared output), so trailing errors, prior placeholders, and empty outputs no longer absorb protection slots. Pending refs are dropped from the keep set entirely — a pending read may be a cache-hit placeholder rather than file bytes, so it must not suppress eviction reporting; over-disarming only costs a redundant re-read. Adds regression tests for both plus the protected-saturation consecutive-trigger corner. * qwen: address PR review feedback (#8464) Pin the (soft-exceeded) log marker with the one-line assertion suggested by the sandboxed verification report (finding S-1): the all-protected overage test now asserts 'target 250000 (soft-exceeded)', killing the surviving mutant M4. * qwen: address PR review feedback (#8464) * qwen: address PR review feedback (#8464) * qwen: address PR review feedback (#8464) Two P1 context-integrity fixes from review: (1) media-only tool results (image/PDF reads with empty text output and bytes on functionResponse.parts) stay in the idle-path keepRecent candidates instead of being dropped by the zero-char filter; (2) only write_file results vouch for file residency in kept-path accounting — edit calls carry just old/new snippets while still setting the cache's sticky full-read flags, so a kept edit can no longer suppress eviction reporting after the full read is blanked. Regression tests for both. * qwen: address PR review feedback (#8464) Pin the absence of the (soft-exceeded) marker at the exact watermark boundary: clearing that lands the virtual total exactly on the watermark must not be flagged. Kills the >= and always-true mutants of the marker condition that previously survived the suite. * qwen: address PR review feedback (#8464) --------- Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> |
||
|
|
2bd5c94111
|
fix(serve): detect lineEnding across the file, not the returned slice (#8383)
* fix(serve): detect lineEnding across the file, not the returned slice `readText` reported `meta.lineEnding` from the slice it was about to return. A slice holding a single CRLF line arrives as text ending in '\r' — the '\n' was consumed as that line's terminator — so detecting on it answers 'lf'. Page one of a cursor sequence then disagreed with page two about the same file, and a client that trusts the first page would rewrite CRLF content as LF. The truncation branch re-detected on the truncated slice for the same reason and had the same flaw. Detect on the whole decoded file once, which is what the field is describing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * test(serve): guard byte-truncated reads against slice-based lineEnding re-detection * fix(core): report crlf on cursor pages resuming after a CRLF terminator (#8383) * fix(core): count a skipped CRLF terminator on byte-truncated pages (#8383) When a window's first line exceeds both the read-chunk size and maxOutputBytes, the byte cut fires before the line's terminator is decoded, and the re-snap then walks over that terminator without reading it. The next page seeds from the pair and reports 'crlf' while the cut page reported 'lf' — adjacent pages of one file disagreeing, the exact symptom this PR removes. Consume the same two-byte evidence after the re-snap so the pages agree. Also qualify the design-doc agreement guarantee to files with uniform line endings (mixed-ending files can still flip between pages), and pin the seed's load-bearing placement with tests: it must run on the snapped offset, and the minimum probe offset (startOffset == 2) is now covered. * docs: correct the lineEnding spec for byte-cursor pages (#8383) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs: qualify the mixed-EOL verification bullet for byte-cursor pages (#8383) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs: name the uniform-file line-window-vs-cursor lineEnding split (#8383) --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
3ad4fbdb7d
|
fix(cli): preserve Qwen Review startup version in footers (#8431)
* fix(cli): preserve review startup version in footers * fix(cli): keep review startup version dynamic in bundle * fix(cli): reset review version after managed update * test(cli): use indexed env access * fix(cli): harden review footer strip and version stamping (#8431) * fix(tests): sync qwen-resolve-workflow expectations with externalized review timeouts (#8431) The timeout externalization in #8460 replaced the hardcoded 300/240 values in qwen-code-pr-review.yml with the QWEN_REVIEW_JOB_TIMEOUT_MINUTES and QWEN_REVIEW_MAX_TIMEOUT_MINUTES repository variables but left scripts/tests/qwen-resolve-workflow.test.js asserting the old literals, so the full-profile Test job fails on any branch carrying that change. Update the three affected assertions to pin the externalized shape. * fix(cli): harden the review footer strip per review feedback (#8431) The strip regex kept a 2^(N-1) partition ambiguity for same-line footer runs (measured 5.3 s at n=20) and missed footers truncated before their closing `_`; forged footers also survived on the body channel through `bodyCriticals`, and the values interpolated into the footer were not shape-validated. Guard the repeated group so an iteration cannot span another footer's start, make the final `_` optional, strip body Criticals per entry, refuse footer-forging model ids and non-version stamps, refuse non-object comment entries, pin the CLI-glue test suite against an ambient startup stamp, and cross-assert the LGTM filter regex against the footer builder. * fix(cli): strip review footers before ledger carryover * fix(cli): align ledger footer regression expectation --------- Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> Co-authored-by: qwen-code-ci-bot <qwen-code-ci@service.alibaba.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> |
||
|
|
bf9b47e5e3
|
fix(core): reuse prompt cache for multimodal compression (#8419)
* fix(core): reuse prompt cache for multimodal compression * test(core): remove inert media modality fixture * fix(core): guard compression cache-sharing window * fix(core): harden compression cache-sharing gate * fix(core): tighten compression cache preflight * test(core): pin lazy compression slimming |
||
|
|
21ad3b464a
|
fix(desktop): codesign ripgrep and node binaries before tauri build (#8518)
* fix(desktop): codesign ripgrep and node binaries before tauri build macOS notarization rejects the app bundle because Tauri only signs the main binary, not the embedded ripgrep and Node.js runtime binaries under Contents/Resources/runtime/qwen-code/. Add a pre-build codesign step that signs all native macOS executables in the bundled runtime with the Developer ID identity, hardened runtime, and the existing entitlements. * fix(desktop): allow Windows build without signing certificate The Tauri release workflow threw when WINDOWS_CERTIFICATE was missing, blocking the entire release (including macOS). Mirror the old Electron workflow behavior: warn and continue unsigned when no cert is configured. Also add fallback to legacy WIN_CSC_LINK/WIN_CSC_KEY_PASSWORD secrets so existing Electron-era credentials still work if present. * fix(desktop): allow unsigned Windows artifacts in verify step The 'Verify Windows signature' step threw on any non-Valid status, including NotSigned. With no Windows code signing certificate configured, this blocked the Windows build job, which in turn blocked the publish job (needs: [prepare, build]). Allow NotSigned with a warning instead of throwing, matching the fallback behavior of the 'Import Windows certificate' step. A genuinely invalid signature (HashMismatch, etc.) still throws. * fix(desktop): narrow find scope and deduplicate pfx import - Scope ripgrep codesign find to *-darwin/* paths so Linux ELF binaries (built in the same matrix) aren't targeted. - Unify the two pfx-import branches into a single code path to eliminate duplicated write/import/configure logic. * fix(desktop): guard optional Windows signing config * fix(desktop): harden vendor signing workflow |
||
|
|
5631f4b112
|
feat(serve): add a required external tool guard provider (#8125)
* feat(serve): add required external tool guard * fix(serve): keep guard constants off fast path closure * test(serve): cover guard startup options * refactor(acp-bridge): centralize external tool guard validation and ack value (#8125) * fix(core): align MCP reconnect timeout test with safe replay policy (#8125) The reconnect-on-timeout test still built its mock tools without server trust or tool annotations, which the safe replay change now requires before automatically replaying a connection-loss failure. Update the fixtures the same way the surrounding reconnect tests were updated, keeping the test's original assertion that a timeout on a known disconnected server goes through the reconnect path. Mirrors the same alignment already landed on main. * fix(cli): alias externalToolGuard subpath for vitest source resolution (#8125) This PR added `@qwen-code/acp-bridge/externalToolGuard` imports to cli serve/acp modules but not the vitest source alias every other acp-bridge subpath carries. Without it, any vitest run whose acp-bridge dist is stale or absent fails to resolve the import and the five serve test files die at transform time. Add the alias following the documented convention in the config so tests read the live source. * fix(serve): reject non-ASCII external tool guard bearer tokens A token outside the ASCII range passed construction but made the handshake throw ERR_INVALID_CHAR when interpolated into the Authorization header, blocking qwen serve startup in required mode with an unexplained error. Enforce printable ASCII (0x21-0x7E) at validation time so the configuration fails fast with a clear message. --------- Co-authored-by: 秦奇 <gary.gq@alibaba-inc.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.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> Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> |
||
|
|
eacc85e846
|
fix(cli): stop review test-efficacy tests depending on ambient tmpdir vitest (#8537)
Two tests failed on hosts where vitest resolves up-tree from os.tmpdir() (observed on self-hosted CI where a node_modules above TMPDIR provides one): findVitestBin's "cannot be resolved" case never threw, and runControlMutant's "cannot run" case executed the probe for real instead of throwing. Make the failure conditions host-deterministic while keeping every assertion: findVitestBin accepts an injected resolver (default unchanged) so the MODULE_NOT_FOUND case is forced directly, and the runControlMutant test plants a shadow vitest whose exports hide package.json, which wins resolution from any ancestor install and makes the run fail deterministically. |
||
|
|
6e9ecc41e4
|
fix(core): resolve DashScope thinking-knob conflicts by family (#8488 round 2) (#8536)
Second review round on #8488: - Honour an explicit extra_body enable_thinking: false on the qwen3.8-max family as reasoning_effort: 'none' instead of silently deleting it and re-enabling thinking - Legacy qwen hybrids now drop the inert reasoning_effort override when it conflicts with a meaningful thinking_budget, keeping the knobs the model actually reads - Family-gate the pipeline's enable_thinking tool_choice clause like the reasoning_effort clause: on non-qwen models sharing the endpoint the field is an opaque no-op (GLM reads thinking.enabled), and stripping forced tool selection there degraded their side queries - The tier-native disable path emits reasoning_effort: 'none' — the knob the family reads — instead of enable_thinking: false; the required-thinking retry trigger recognises the new shape so runtime learning still fires - Warn once per generator (not debug per request) when user extra_body knobs are dropped; hoist the wire-model family predicates to modalityDefaults.ts and share the provider's extra_body merge tail - Tests for every behavior above (all load-bearing, verified by targeted mutation); docs attribute the vendor rejection to thinking_budget only and document the extra_body exceptions |
||
|
|
52e0d1b364
|
feat(web-shell): bind plan approval to its Todo revision (#8393)
* feat(web-shell): gate session workflow behind experimental setting * feat(web-shell): bind plan approval to todo revision * fix(cli): clear stale workflow revision on plan entry * test(web-shell): pin revised workflow snapshot * fix(cli): clear stale plan revisions on restore * fix(cli): keep replayed history from rebinding plan revisions History replay re-sends stale plan updates through Session.sendUpdate, re-stamping activeTodoPlanRevision from finished plan cycles. Clear the revision after every replay path (cold replayHistory and live non-bulk loadSession) so a replayed snapshot can never bind a later exit_plan_mode approval; reloaded sessions fall back to text-only approval until the next live todo_write re-establishes the binding. Also drop the bulk-load restore that could never be read before a plan-mode transition cleared it, and pin the workflow gates and mode-entry clears with negative tests. * test(web-shell): pin older plan revision in ChatPane approval test (#8393) * test(cli): pin unbindable plan updates in approval revision test (#8393) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): clear Todo plan revision on history restore (#8393) restoreHistory was the one history-resetting path that kept activeTodoPlanRevision, so a restored snapshot could let a stale revision bind the next exit_plan_mode approval. Clear it like the sibling reset paths, pin the behavior with a test, and pin the live-load clear ordering after the replayed updates. * fix(cli): restore Todo stop guard clear on plan re-select (#8393) The previous-mode guard added for the revision binding also skipped the Todo Stop Guard trust clear on a redundant plan re-select; scope the guard to the revision reset so every transition into plan clears the stop guard as before. The replay-time revision clears now run in finally blocks so a transport failure part-way through a replay cannot leave a replayed binding on the live session, and the web-shell exit-plan approval rule is unified in one predicate. Revision tests assert through the observable qwenTodoApproval approval metadata instead of the private field. --------- Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> |
||
|
|
d2c7cb1f15
|
fix(autofix): normalize paginated fetches to one flat array per file (#8438)
* fix(autofix): normalize paginated fetches to one flat array per file gh api --paginate emits one JSON array PER PAGE, so any PR past 100 comments/reviews/events produces a multi-document stream. The workflow already slurps correctly in a few readers (jq -rs add, --slurpfile + add), but more than a dozen plain-jq consumers of the WORKDIR files mis-aggregate on a multi-doc input: - MARKERS/REARM_AT/RED_HEAD/REARM_KEY in the scan and their LIVE_* mirrors in prepare emit one result per page; ROUND then becomes a multi-line string, [[ -ge ]] arithmetic fails, and the round cap silently stops holding — on exactly the PRs (takeover, 100-round cap, one report comment per round) that reach page two first. - CAP_NOTICED / BASE_UPDATE_RECENT / LAST_REJECTION / PRIOR_TIMEOUTS / the milestone census and the report-step consecutive-failure census all degrade the same way. - NEWEST and LIVE_NEW bind rv/rc/ic/checks POSITIONALLY (.[0]..[3]); a two-page rv.json shifts rc/ic into the wrong slots and later feedback is silently lost. Fix at the fetch sites: every --paginate that lands in a WORKDIR json file (and the report step's COMMENTS_JSON fallback) now pipes through jq -s 'add // []', so each file holds ONE flat array. Existing slurp-style readers are unaffected — add is idempotent over a single array — and every plain consumer becomes correct past 100 items with no program changes. Failure semantics are preserved: the workflow-level bash default gives -eo pipefail, so a failed gh still fails the pipeline exactly where it failed the bare redirect before, and the pr-events/COMMENTS_JSON fallbacks keep their '[]' paths. The check-runs/annotations/status-comment reads stay raw on purpose: they aggregate per-page via --jq + slurp, line-streams, or .[][] and were already pagination-safe. Tests: a behavioral case runs the real MARKERS→ROUND pipeline and the positional NEWEST program against two-page fixtures through the normalizer, with negative controls demonstrating the pre-fix corruption (two MARKERS lines; the page-2 review timestamp lost to slot shift). Shape assertions pin all nine normalized fetch sites and ban raw --paginate file redirects. * fix(autofix): pin total --paginate occurrence count in tripwire test (#8438) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(autofix): correct gh --paginate merge model in pagination comments (#8438) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(autofix): make engage-ack ic re-fetch atomic on failure (#8438) * test(autofix): pin atomic engage-ack re-fetch and empty-input normalization (#8438) --------- Co-authored-by: verify <verify@local> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> |
||
|
|
ac67de2e46
|
fix(review): stop the reverse-audit loop while there is still time to report (#8468)
* fix(review): stop the reverse-audit loop while there is still time to report Measured on CI run #8368 (+1699 lines): the iterative reverse audit ran to its 5-round cap, each round a per-chunk fan-out whose findings then went back through verification, and the loop consumed 3.5 of the job's 4 budgeted hours. The outer GNU-timeout kill arrived while round 5's findings were still being verified. The review died holding every confirmed finding it had; nothing reached the pull request. The loop's rounds are driven by the orchestrator, but every round begins at the same place: agent-prompt building the round's prompts. So the builder becomes the loop's clock. When the environment carries a review deadline (QWEN_REVIEW_DEADLINE_EPOCH, exported per attempt by the review workflow) and the remaining time is inside the reserve kept for the last verification, compose-review and submission (default 60 minutes, QWEN_REVIEW_DEADLINE_RESERVE_SECONDS to override), a reverse-audit round is refused: a BUDGET line on stderr, exit code 4, no prompt built and no record written. The message carries the exact unreviewedDimensions entry to file, so the disclosure that caps the verdict is the CLI's text, and Step 6 proceeds with the findings already confirmed. Local runs have no deadline and are untouched. A malformed deadline fails open — the outer kill still bounds the run, and a broken variable must degrade to today's behaviour rather than wedge every budgeted review at round 1. The verifier is deliberately not gated: the reserve exists so it can run. * fixup: scale the deadline reserve to the externally-chosen budget The budget is not this workflow's to assume: it arrives from a repository variable, a workflow input, or a /review --timeout=N comment. A fixed 60-minute reserve would consume most of a 70-minute budget and refuse the audit loop outright on a 30-minute one. The workflow now passes a reserve of a quarter of the attempt, floored at 10 minutes and capped at 60; the CLI constant remains only the fallback for a caller that sets a deadline without a reserve. * review feedback: admit the round only if IT fits, and cap deterministically Three findings from review, all taken: 1. The gate budgeted for the tail but not for the round it admits — the terminal round is by construction the one that starts closest to the boundary, so the killed-mid-verification failure survived one round wide. The gate now requires remaining >= round + reserve, where the round's cost is the previous round's, measured admission-to-admission from a stamp the builder writes (one per round; a same-round rebuild is not a round), falling back to a 30-minute constant for round 1, which starts with the most headroom. 2. The refusal was deterministic; the disclosure that caps the verdict was prose the orchestrator had to carry. The builder now records a budget-stop marker beside the prompt records and compose-review synthesizes the unreviewedDimensions entry from it — deduped against a relayed copy — so a run that drops the sentence still cannot approve past a truncated audit. 3. Exit code 4 is documented in the command's describe. Also restores the Step 5 bullet the previous commit's edit displaced (new findings merge into the cumulative list before the next round). * review feedback: pin the budget gate's all-chunks refusal and ordering Cover the two behaviours the review noted were only asserted on the bare --findings form: an exhausted budget refuses the loop's real --all-chunks round before ANY of the per-chunk records is written, and a malformed call (--round 0) still gets its validation error first — exit 4 is for a well-formed round the budget refuses, never a replacement error. Also name what the code already does: reserve=0 is the deliberate escape hatch (the gate shrinks to the round estimate alone), and the workflow's 3600s cap mirrors DEFAULT_RESERVE_SECONDS. * docs(review): describe the soft-deadline env vars for time-budgeted runs The review noted the two new variables appeared in no user-facing doc; the reserve in particular is an operator-facing knob. State what each does, the fail-open posture, and how the refusal surfaces in the verdict. * fix(cli): align budget-stop disclosure with the gate's refusal (#8468) A round-1 budget refusal left no reverse-audit records, so the Step 4/5 floor reported the deliberate stop as a rogue/unlaunched audit with a rebuild FIX the same gate deterministically rejects; the refusal's own disclosure was swallowed by the caller-echo dedup. The floor now stands down when the budget-stop marker exists, and compose-review renders the disclosure structurally, bilingually, from the marker. Also: `--role reverse-audit` requires `--round <k>` (an unlabeled admission stamps an entry no estimate can attribute), the budget gate runs after the plan/findings reads (a broken plan or unreadable findings deserves its own error, and nothing is stamped ahead of a buildable call), and the gate's admission boundary, measured-cost behaviour, and the workflow env contract are pinned by tests. * review: a budget stop excuses only the round it refused The budget-stop suppression keyed on the marker's existence alone, so every reverse-audit gap shape went silent once any round was refused — including the shapes that describe rounds which RAN before the budget hit. A hand-written round-1 launch is exactly as undelivered when round 3 later hits the budget, and suppressing its disclosure let 'stopped before round 3' imply the rounds that did run were faithful. Exactly one shape is by design under a marker: not-built — the refusal writes no record, so an audit with no records IS the audit the gate stopped, and its FIX (rebuild the round) would be refused by the same gate. The suppression now names that shape and no other; a rewritten, unlaunched or brief-unread round keeps its disclosure and its repair. The new test pins the operative halves: the verdict stays capped, the marker's disclosure posts, and the operator channel carries the rewritten round's exact repair. (The posted body collapses same-subject disclosures — both say 'reverse audit' — so the author sees the stop; repairs are acted on from stderr, where the rewritten fix rides.) * fix(review): fence budget state per run, and let gate errors beat budget stops Address the round-2 review threads on the reverse-audit budget gate: - Fence budget-rounds.json and budget-stop.json by the plan's own mtime. Every run rewrites the plan at its Step 1 capture, so records older than the plan belong to a previous run of the same PR: a run killed before cleanup no longer prices the next run's rounds off stale stamps (an hours-old stamp read as an hours-long round refused round 1 of a fresh budget) and no longer caps a later run's verdict on a stop that did not happen in it (R2-1, R2-2). - Refuse a structurally unbuildable plan (no chunks[], duplicate or non-integer ids) with its own error ahead of the budget gate, so the same corruption gets the same diagnosis whatever the clock says, and no budget-stop marker is written over a corrupt plan (R2-5). - Stamp a round admitted only after its build succeeds: a build that throws leaves no stamp, so the next round's cost is never measured from a build that produced nothing and floored to 600s (R2-6). - Keep the budget entry's 'reverse audit' subject out of the caller-echo prefix filter: other reverse-audit scopes the orchestrator disclosed (a twice-whiffed chunk from the rounds that DID run) are no longer silently dropped in the marker's shadow; the marker's own relays stay deduped by the phrase splice (R2-7). - Render --round unbracketed in the reverse-audit rebuild fix — the CLI refuses a round-less reverse-audit call, so the paste-and-run repair must not present the flag as optional (R2-14). - Document the deliberate one-verification overlap between the measured round estimate and the tail reserve, at both definitions (R2-13). - Test hardening, each assertion mutation-probed to fail its named mutant: a reshaped relay only the marker-phrase splice dedups (R2-8); the stamp's round label and the verifier's no-stamp invariant (R2-9); whole-line, unit-arithmetic and reserve-cap pins on the CI wiring contract (R2-10); the first-wins stamp survivor (R2-11); the reserve=0 escape hatch (R2-12). --------- Co-authored-by: verify <verify@local> Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> |
||
|
|
56baa7af7b
|
perf(review): the review-round refinements for the setup batch (#8487)
The batched-setup paragraph merged to main through #8499's squash of its base branch, without the two review rounds that followed on #8487. This re-lands those refinements as the delta against main's current text: - 'ONE response' now says separate tool calls, never an &&/;-joined Shell chain — a chain changes the failure semantics (pr-context failing must warn-and-continue, not skip the other two) and merges the warning: size lines the paging decisions read. - The rules load names its ref uniformly (<remote>/<baseRefName>, the ref fetch-pr just updated) with the baseFetchFailed carve-out spelled in both Step 1 and Step 2, replacing the prefer-local probe language — deciding 'does <base> exist locally' costs exactly the serial turn the batch removes, and an unresolvable ref makes load-rules report 'no rules found', indistinguishable from a repo that has none. - The incremental-cache read pairs with the fetch-report read where the read is instructed (both read_file, genuinely parallel). - The executable-script lint's enumeration counts file reviews — they have a tree and scriptLintGate owes them the lint; the adjacent gate note already said so. Co-authored-by: verify <verify@local> |
||
|
|
874e46d734
|
fix(core): harden Qwen 3.8 reasoning effort wire shape (#8488)
Some checks are pending
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 1/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 2/3 (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none - shard 3/3 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 1/2 (push) Waiting to run
E2E Tests / E2E Test - macOS - shard 2/2 (push) Waiting to run
E2E Tests / channel-plugin E2E (nightly) (push) Waiting to run
E2E Tests / cron-interactive E2E (nightly) (push) Waiting to run
E2E Tests / web-shell Browser Regression (push) Waiting to run
* fix(core): harden Qwen 3.8 reasoning effort wire shape (#8472 follow-up) Follow-up to #8472, addressing the post-merge review findings: - Drop enable_thinking/thinking_budget after the extra_body merge whenever reasoning_effort ships: the Token Plan preset made qwen3.8-max-preview carry both thinking knobs, and DashScope rejects reasoning_effort combined with thinking_budget - Family-gate the new tool_choice=required strip clause to qwen wire models: reasoning_effort is an opaque sampling override on non-qwen DashScope models, and dropping forced tool selection degraded their structured side queries - Prefix-match the qwen3.8-max family so dated snapshots and -latest aliases receive the selected tier instead of silently collapsing to enable_thinking - Log the tool_choice strip; restore the effort-config JSDoc and comment the request-level override copy * fix(core): family-gate DashScope thinking-knob drop (#8488) --------- Co-authored-by: qwen-code-ci-bot <qwen-code-ci@service.alibaba.com> |
||
|
|
10291e16f2
|
refactor(core): move review skill incident narratives to DESIGN.md (#8499)
* perf(review): issue independent setup calls in one response Measured on a real small-PR run: the stretch from parse-args to the first agent launch took 7 minutes of wall clock, one round-trip at a time, on calls that never needed an order — pr-context, comment-status and the Step 2 rules load are mutually independent reads. Step 1 now tells the orchestrator to issue all three in a single response (the same rule Step 3 already enforces for the agent fan-out) and to page their outputs in shared responses too. comment-status loses its wait-for-the-context-file guard in worktree mode: learning whether inline comments exist cost a serial round-trip, while running it on a commentless PR just writes an empty index. Step 6's two deterministic gates (script-lint, test-plan) get the same one-response note. The orderings that matter are kept explicit: fetch-pr before everything (it creates the worktree and the plan), the roster after the rules load (it bakes the rules into every brief). * refactor(core): move review skill incident narratives to DESIGN.md SKILL.md is injected wholesale into the review orchestrator's context on every /review run and re-billed on each of its turns, and ~16KB of it was incident narrative — accounts of past dogfood failures and measurements that justify rules but are not themselves instructions. Move 50 such narrative blocks into a new 'Measured incidents (moved from SKILL.md)' section of DESIGN.md (47 anchors, not loaded at runtime), leaving every rule in place with a short '(measured; DESIGN.md — <anchor>)' pointer. Force-bearing figures stay inline where the number is the argument (e.g. the ~161s cold npm ci, the 41% test-code median, the PR #6457 one-of-five checklist measurement). No instruction, gate, format, flag, threshold, or ordering changed; the YAML frontmatter and all 35 fenced code blocks are byte-identical, and the MUST / Do not / never imperative counts are unchanged outside the moved narrative text (verified by script). SKILL.md: 237,847 -> 228,266 bytes; DESIGN.md: 106,708 -> 125,184 bytes. * fix(review): keep DESIGN.md out of the runtime bundle and pin pointers The slim refactor left DESIGN.md shipped beside SKILL.md in dist/bundled/, so one curious read_file of the 125 KB maintainer document would cost more context than the refactor saves. The bundle copy now skips DESIGN.md, and SKILL.md gains a one-line guard telling the orchestrator the pointers are for humans auditing a rule. Also addresses review feedback: a test pins both directions of the SKILL.md incident-pointer mapping, the transcribed-argument narrative keeps its referent after the move, the incidents section title loses its changelog suffix, and Step 2 no longer asks for a base fetch that fetch-pr already performed. * fix(review): gate setup batching by effort and consolidate incident blocks Address round-1 review feedback on the skill-slim PR: - Gate the ONE-response setup batch and the comment-status call to high and medium effort, matching Step 2's low-effort skip. - Scope the Step 6 lint/test-plan batching to same-repo PR reviews. - Merge same-run incident blocks (self-composed Approve into the paraphrased roster prompt; archive verdict into the narrated-away cap), cross-reference the roster-size and relocated-Critical tellings, and state the #8368 path in its block plus the pointer it was missing. - Pointer-ize the last inline QQChannel narrative and fix the scripts-nobody-ran summary to match its block. - Extend the DESIGN.md exclusion to copy_files.js so the transpiled dist/src build and the published core tarball stop shipping it. - Pin the no-read_file guard and the batch ordering constraints in SKILL.test.ts, and fail loudly on pointers the regex cannot parse. --------- Co-authored-by: verify <verify@local> Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com> |
||
|
|
e7362d5d08
|
fix(web-shell): add explicit ::selection for message content in Firefox (#8417)
* fix(web-shell): add explicit ::selection for message content in Firefox Firefox does not paint the default selection highlight for text whose element chain passes through a display:contents element (the data-user-selectable wrapper on MessageItem). The logical selection (copy, selectionchange popup) works fine - only the visual highlight is missing. An explicit ::selection background makes Firefox paint the highlight where the default painting fails. Fixes #8214 * fix: use fixed color instead of non-existent CSS variable --selection-bg was never defined in the codebase (only --chat-editor-selection-bg exists in App.module.css). Use a fixed hsl(210 100% 50% / 30%) to avoid confusion. * test(web-shell): pin ::selection rule and soften root-cause framing Reframe the standalone.css comment and PR description as a defensive workaround, not a confirmed root-cause fix: the data-user-selectable wrapper is shared by user and assistant rows, and the reporter's screenshot shows an embedding-page toolbar this package does not ship. Add a getComputedStyle(..., '::selection') assertion to the smoke e2e so a future cleanup cannot silently drop the rule. * fix(web-shell): move ::selection rule to component-scoped globals.css The defensive ::selection rule for [data-user-selectable] message content was in standalone.css, which is only loaded by the standalone app entry (client/main.tsx) and the e2e harness. The npm package entry (client/index.tsx via vite.lib.config.ts) never loads standalone.css, so embedded deployments of @qwen-code/web-shell - including the reporter of #8214 - did not receive the rule and still saw no selection highlight. Move it to globals.css, which is imported by App.tsx and WebShellTranscript.tsx and therefore ships with the component-scoped stylesheet. Verified against the lib build: the rule now appears in dist/index.js correctly scoped under [data-web-shell-root][data-web-shell-shadcn]. The standalone app also loads globals.css, so the e2e smoke pin still passes. Addresses the review finding on standalone.css:119. * test(web-shell): pin ::selection across all rows and in the lib bundle Address review findings on the round-3 move to globals.css: - The smoke e2e only sampled the first [data-user-selectable] row (the user row in this fixture). Assert the rule on every selectable row so a future narrowing to user rows keeps assistant rows covered. - Nothing asserted the rule survives in the npm lib bundle - the deployment this fix exists for. Add a build-artifact test that parses the injected component CSS in dist/index.js and pins the scoped [data-user-selectable] ::selection rule under [data-web-shell-root]. * test(web-shell): assert ::selection on selectable wrapper rows, not descendants Per review: querySelectorAll('[data-user-selectable] *') counts element descendants, not the wrapper rows themselves - a single user row renders 4+ descendants, so the >=2 invariant did not actually enforce that both roles are present. Match the [data-user-selectable] wrappers directly and sample one descendant per row. * test(web-shell): match ::selection lib-bundle pin by effect, not notation Per review (R6-1): the pin matched an exact selector substring (including the space) and an exact prop name, coupling to the current notation. A maintainer switching 'background' to 'background-color' (the CSS Pseudo-Elements-4 name) would fail this test with a misleading message while the e2e pin stayed green. Match the two selector halves independently and accept either prop name. --------- Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> |