mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-11-07 06:19:43 -10:00
1876eb49970d7d9f72df67cb7245ffbbfaef36ee
11492
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
1876eb4997 |
test(managed-agent): Add shared Harness Kubernetes qualification tools (#15519)
* test(managed-agent): Add Kubernetes pool qualification tools Build from immutable source, constrain deployment to explicit business workers, and verify deployment identity plus signed multi-tenant public flows. Include the cross-Pod foreground publication configuration exercised on ACK. Co-authored-by: Qwen-Coder <[email protected]> * style(managed-agent): Match Kubernetes qualification YAML lint rules Co-authored-by: Qwen-Coder <[email protected]> --------- Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
517ba13ad0 |
test(managed-agent): pin the row pool's fan-out, correct its design claims (#15528)
* docs(managed-agent): state the row pool's real shutdown and row bounds The design pair claimed the pool never parks the context close and that SCAN_LIMIT is a per-tick row bound. The pool's destroy does return immediately, but a tick caught mid-join still holds the close until the application's shutdown phase expires, and one tick submits two queries' worth of rows (deduped), not one. * test(managed-agent): pin the row pool's dedupe guard and interrupted join A mutant that removes the armed/firing dedupe survived the suite, and nothing exercised the join's interrupt arm. The backlog case now asserts the completed-task count instead of a pool gauge sampled after the fact. * test(managed-agent): read the backlog drain off the joined count, not a pool counter ThreadPoolExecutor increments completedTaskCount after a task's future unparks the joining thread, so the counter can lag the tick's own answer; the joined fire count already proves the backlog drained. Recorded on review as a low-severity race in the previous assertion. * docs(managed-agent): name the scheduler bean behind the shutdown bound The shutdown sentence said "the application's shutdown phase"; the bound belongs to the scheduler bean that invokes the tick, which is the SmartLifecycle the lifecycle processor waits on. Also list the two new tests where the validation section lists the others. * test(managed-agent): pin that the armed task records its due slot Claiming once proves the row was submitted once, but a tick that kept only the firing task would also claim once and never derive the slot that came due meanwhile. Assert the due slot is recorded, which only the armed task does — the dropped-armed-task mutant now fails here. * docs(managed-agent): call the shutdown phase a bound, not a fixed wait The lifecycle processor caps the scheduler bean's stop at timeout-per-shutdown-phase; it does not necessarily wait the full phase out before interrupting a mid-join tick. Say upper bound. |
||
|
|
75c9e5ef69 |
test(memory): pin recovery-path and hard-rescue catalog accounting (#15535)
Land the permanent coverage that the review verified only with temporary witnesses: the output-recovery request keeps the superseded snapshot off the wire while carrying the current catalog once, its output budget is computed from that catalog-bearing payload when no usage arrived, and a pending non-empty catalog is what pushes the post-compression estimate over the hard limit, aborting the send. Each assertion fails when the corresponding retention flag flips or when the estimator drops the pending snapshot. |
||
|
|
afd0bdb376 |
fix(cli): keep a Web Shell /autofix-pr watch alive through an idle session (#15523)
* fix(cli): keep a Web Shell /autofix-pr watch alive through an idle session A daemon session is reclaimed once nobody has watched it for the idle timeout, taking the in-memory scheduler of /autofix-pr's session-only task with it: the watch stopped with no report, and the Web Shell's scheduled-tasks page never listed it. `autofix-pr schedule` now prints `durable: true` with `sessionMode: "current"` when it runs in a daemon session, so the watch is a durable task bound to that conversation: the daemon keeps the session resident, rehydrates the task after a restart, and the page lists it. A terminal session keeps the session-only task. The skill creates the task from what `schedule` printed and falls back to a session-only one when a daemon cannot bind a task to its session. Tested: packages/cli schedule.test.ts (8), packages/core SKILL.test.ts (5), eslint, prettier. * fix(cli): cover a daemon resume and name the watch's restart caveats A daemon restart drops the gate's in-process approval, and closing the browser tab does not end a daemon watch; the guide now says both. The daemon test also asserts the durable pair on `schedule --again`, and drops a save/restore the fixture already performs. Tested: packages/cli schedule.test.ts (8), prettier. * fix(cli): say a daemon conversation carries one watch A conversation already bound to a scheduled task cannot take a second one, so /autofix-pr on a second PR needs a conversation of its own. The skill now names that refusal instead of reporting only that the watch has no task, and the guides and the design note record the limit. Tested: packages/core SKILL.test.ts (5), prettier. * docs(autofix-pr): resume one watch per daemon conversation A daemon conversation carries one scheduled task, so resuming several watches there schedules only the first and leaves the rest without a task. The guide now says to resume them one conversation at a time. * fix(cli): keep another session's watch out of a bare stop or resume Durable tasks are project-visible to cron_list, so a second conversation in the same project sees the first one's task. Stop deleted every matching task before cleanup checked ownership, so a bare stop in B killed A's running watch; resume's "another session runs it" exclusion keyed on the PR having no task, which A's visible task bypassed. Stop now reads status first, leaves a task whose watch another session still runs (unless the user named the PR), runs cleanup before any delete, and deletes only for PRs whose cleanup ended the watch. Resume treats a task naming the watch's session with thisSession false as another session's running watch: a bare resume excludes it and the confirmation warns about it. A named PR still takes the watch over with --take-over. Tested: packages/core SKILL.test.ts (5), prettier. |
||
|
|
e7a67ee4e3 |
feat(managed-agent): give the Hosted Harness its Broker through the environment (#15244)
* feat(managed-agent): give the Hosted Harness its Broker through the environment
The Hosted Harness reached the Runtime Broker only through command-line
options, so the shipped unit expanded the Broker token into argv, where
any local user can read it, and the token was stored again in
server.env for the control plane. A busy Harness port also moved the
Harness to another port that the control plane could not reach.
harness.env now carries QWEN_MANAGED_RUNTIME_BROKER_URL and
QWEN_MANAGED_RUNTIME_BROKER_TOKEN, which qwen serve already reads and
deletes from its environment, and the unit no longer passes Broker
arguments. Every secret gate lists the token too: core's child and
${VAR} denylist, the ACP scrub list, the channel worker environment and
the control plane's Runtime worker filter. The Hosted Harness profile
fails on a busy port instead of moving.
The Harness credentials file may carry the Broker token for the control
plane, refusing a second direct copy and binding nothing on a conflict;
both Broker lines follow the strict credential rules. Preflight adds a
broker-url row that compares the file's URL with the Broker's address
and warns when the file has none, and the broker row's fix names the
file only when startup read it. The bootstrap, templates, systemd unit
and guides keep the token in harness.env only and tell upgraded hosts
to replace QWEN_HOSTED_HARNESS_BROKER_ARGS.
* fix(managed-agent): check the Harness Broker URL against the actual listener
The broker-url preflight row matched loopback addresses by class, so a
Broker bound to 127.0.0.1 passed a file URL on 127.0.0.2. It failed any
URL that differed from the bind address, although a proxy or TLS front
end may forward it. And it ignored the scheme once a port was given, so
https to the plain-HTTP Broker passed.
The row now passes only a direct http URL: the Broker's port, and a host
that resolves to the bound address itself or, for a wildcard bind, to an
address of this machine. https to that same listener fails, since the
embedded Broker serves plain HTTP. Any other URL warns that a proxy may
forward it, which preflight cannot verify, so it no longer fails --check.
* fix(managed-agent): hold the Harness Broker URL to the Harness's own rules
- broker-url first applies the rules managed-runtime-broker-url.ts applies
at Harness startup (an http or https origin, plain http only on loopback),
reads the host of a registry authority such as an underscore name, and
names the direct loopback URL, or the TLS-terminating proxy for a
non-loopback bind, in its fix.
- A broker check fails a non-loopback bind without
runtime-broker.allow-non-loopback, which the Broker refuses at startup.
- The Harness credentials file requires the Broker URL and token together,
refuses a key containing whitespace such as `export KEY=value` (systemd
ignores it, a shell assigns it), and lets the URL bracket an IPv6 literal.
- qwen serve warns when --managed-runtime-broker-token is on the command
line; serve tests cover the environment fallback, its removal and flag
precedence.
- The upgrade runbook names the server.env token to delete, the server
README lists the Broker prefix among the stripped ones, and the bootstrap
test checks stdout for every generated secret.
* fix(managed-agent): read the Harness Broker URL the way the Harness parses it
The broker-url preflight row predicted the Harness with java.net.URI and a
hand-written loopback check, which disagree with Node's WHATWG URL parser in
both directions. It failed http://127.1:4182, http:/127.0.0.1:4182 and
http://127.0.0.1:4182/./, which the Harness takes as its loopback origin, and
passed http://::1:4182, http://127.0.0.08:4182 and port 99999, which the
Harness refuses before it starts.
- HarnessBrokerUrl follows the URL Standard for the part of an http(s) URL a
credentials-file value can reach: the scheme, the slashes after it, the
IPv4, IPv6 and ASCII-domain host parsers, the port and the path's dot
segments. An xn-- label needs IDNA, so the row warns that it cannot read
that URL instead of failing.
- managed-runtime-broker-url.fixtures.json records the Harness's verdict for
each spelling; the CLI test holds the Harness to it and HarnessBrokerUrlTest
holds preflight to it.
- The fix's direct URL is built from the address the bind resolves to, so a
::ffff:127.0.0.1 bind yields http://127.0.0.1:4182.
- Docs: the upgrade backs up server.env and harness.env and a rollback
restores them; the guide names the row's no-URL warning; the operator pages
allow [ and ] in the URL key; the server README states the URL/token pairing
rule.
* fix(managed-agent): keep the Broker pair across a daemon update restart
A daemon self-update replaces `qwen serve` through execve, which keeps
the PID, so systemd never hands the replacement the Broker pair from
harness.env again, and serve has already removed the pair from its own
environment. Hand the update restarter the resolved pair and add it to
the replacement's environment only, beside the server token.
Also from the same review round:
- preflight decides the plain-http, path and ends-in-a-number refusals
for a host with an xn-- label without IDNA, and leaves only an https
URL to such a host unclassified;
- the Java fixture loop allows only the two documented approximations, a
scheme or path read before the host and an xn-- host read without
IDNA; the shared fixture gains cases for both;
- the CLI fixture loop fails on a verdict it does not know instead of
passing on any throw;
- the broker-url row brackets an IPv6 Broker address;
- the credentials file refuses an empty Broker URL or token, which the
Harness takes as set and then refuses to start with;
- the deployment guide no longer says a wildcard Broker bind is reached
through a proxy.
* fix(managed-agent): warn on an IPv6 URL for an IPv4 wildcard Broker bind
The JDK binds 0.0.0.0 to IPv4 alone under -Djava.net.preferIPv4Stack=true,
so a Harness given http://[::1]:P cannot reach a Broker bound there, while
the broker-url row passed it as served. Preflight cannot see the server's
JVM options, which may come from an environment it does not share, so a
wildcard bind now serves only addresses of its own family, and an IPv6 URL
to the IPv4 wildcard warns and names the IPv4 loopback URL. An https URL
there still fails. The JDK binds :: only on a dual-stack socket, so the
IPv6 wildcard keeps serving IPv4 too.
* fix(managed-agent): warn on an https Broker URL across address families
When the Broker binds the IPv4 wildcard and the URL names an IPv6
address, the Broker's own socket takes it only from a dual-stack JVM.
Under -Djava.net.preferIPv4Stack=true another listener, such as a TLS
proxy, may hold that address and forward to the Broker, so preflight
cannot tell an https URL there apart from a working deployment. It now
warns for both schemes and fails https only for an address the Broker's
plain-HTTP socket takes in either mode.
---------
Co-authored-by: 易良 <[email protected]>
|
||
|
|
94ccc02203 |
fix(cli): surface retry classification in headless mode (#15515)
* fix(cli): surface retry classification in headless mode * fix(cli): cover continuation retries and disambiguate the full classification * fix(cli): enforce the retry classification allowlist at the export boundary |
||
|
|
9c9088ee50 | fix(ci): run credential-free release fanout on ecs runners (#15517) | ||
|
|
33759ef518 |
fix(core): handle a failed queued memory extraction rejection (#15338)
* fix(core): handle a failed queued memory extraction rejection A trailing auto-memory extraction starts from the finishing extraction's finally block with `void`, so when it failed its rejection had no handler. The task record and telemetry event already carried the failure, but the rejection still reached the process handler: vitest counted it as a run error that failed Core CI, and the interactive CLI's handler would report CRITICAL and open the debug console. Attach the same debug warning the two direct scheduleExtract callers use, so the failure stays observable without escaping. The lifecycle integration test now drains the manager before deleting its temp directory. A failed or timed-out attempt no longer leaves a running extraction writing into a removed tree, which is what produced the ENOENT that surfaced after teardown. Fixes #15269 * test(core): wait out every extraction before lifecycle teardown A single drain() snapshots the in-flight set, so an extraction queued by a finishing extraction's finally block registers after that snapshot and still outlives the teardown. A failed attempt that stops before awaiting its first extraction therefore deletes the tree under the queued run and records it as failed with ENOENT. Drain until no extract task is running or pending, which is the invariant the teardown needs before it removes the project. Fixes #15269 * test(core): pin queued-extract and teardown drain coverage (#15338) A failed queued extraction has no caller, so its task record and telemetry event are the only trace. Pass a config so the telemetry branch runs, and assert both carriers rather than only the terminal status. The lifecycle teardown wait loop was entered by no committed test. Add a case that ends with a queued successor still gated, and assert extract work is terminal and failure-free before fs.rm deletes the tree. --------- Co-authored-by: 易良 <[email protected]> Co-authored-by: qwen-code-dev-bot <[email protected]> |
||
|
|
67d4d3f1b2 |
fix(web-shell): keep UI language changes out of standalone workspace scope (#15521)
A standalone (no-workspace) session refuses `/language ui --project`, so changing Language: UI from the settings panel's default Workspace tab failed with "Project language settings are not available in this session." Offer the UI language row only under User and open the panel there when the active session cannot write workspace settings. Keep a defensive guard that downgrades a workspace-scoped language change to `--global` for standalone sessions. |
||
|
|
33e80fc1aa |
fix(runtime): unblock independent resident workspaces and tool admission (#15457)
* docs(runtime): revise resident Workspace delivery scope Remove complete CSI auditing from the first-release prerequisites and retain bounded retirement with ownership preserved. Record platform-managed reclamation as separately designed and qualified work. Co-authored-by: Qwen-Coder <[email protected]> * docs(runtime): distinguish withdrawal and acceptance baselines Keep the historical audit withdrawal baseline separate from the source pinned for S1 qualification. Co-authored-by: Qwen-Coder <[email protected]> * docs(runtime): record resident cold placement acceptance blocker Co-authored-by: Qwen-Coder <[email protected]> * docs(runtime): record resident public tool admission blocker Co-authored-by: Qwen-Coder <[email protected]> * fix(runtime): unblock independent resident workspaces and tool admission Keep independent resident mount paths distinct from storage ownership and reject unsupported tools before dispatch while preserving public Plan approval and existing unknown outcomes. Co-authored-by: Qwen-Coder <[email protected]> * fix(runtime): preserve hosted capability lookup compatibility Limit resident capability discovery to file profiles, reuse validated warm metadata on legacy route absence, and allow failed queries to be retried. Preserve existing nonresident paths and fault-driver identity assertions. Co-authored-by: Qwen-Coder <[email protected]> * test(cli): drain pending hosted approval turns before teardown Cancel and await the test-owned execution when approval observation or assertions fail, retaining the original happy-path awaits and timeout. Co-authored-by: Qwen-Coder <[email protected]> --------- Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
6dfd4e4747 |
fix(runtime): deliver bounded provider images and PDFs (#13606)
* fix(runtime): deliver bounded provider images and PDFs Use invocation-local media capabilities for actual file reads so managed providers can deliver images and PDFs without a model or inherited Omni uploads. - Enforce inline media and complete result budgets before settlement - Preserve accepted media across execute, status, and cancel responses - Propagate PDF cancellation and wait for child cleanup - Cover capability isolation, reply loss, and Broker restart recovery - Document provider media limits and refresh dependency notices * fix(runtime): repair media review validation gates Keep provider media validation usable in standard CI while retaining explicit activation of the full MySQL media scenario. - Gate media integration on the existing bundle-ready opt-in - Align PDF call assertions with the optional cancellation signal - Keep the maximum-result fixture writable without changing its budget - Explain the complete-result gate and restore baseline notices * fix(runtime): preserve media diagnostics and clean up cancelled reads Keep admitted media observations intact while retaining useful Hook and PDF diagnostics. Bound fixture cleanup so cancelled reads and stalled processes do not leave unused files or consume test resources. - Fit Hook reasons and errors against the actual response budget - Handle PDF ranges beyond document length and retain size errors - Preserve read failures and propagate PDF fetch cancellation - Add regression witnesses and instrument restarted media workers - Bound MySQL commands and include media scratch paths in cleanup - Record Computer Use comparisons and the typed browser facade plan * fix(runtime): bound PDF cancellation and strengthen media probes Prevent cancelled PDF reads from waiting forever for an unresponsive child and make provider-media verification reflect the live runtime. - Escalate cancelled PDF children and bound the remaining close wait - Track the restarted provisioner and share fixture scratch prefixes - Preserve MySQL initialization diagnostics during cleanup - Skip redundant page probes and verify delivered ranges and statuses - Update media design guidance for diagnostics and cancellation * fix(runtime): tolerate the expected media probe reply loss Keep lost-execute response loss from poisoning recovery evidence while preserving fatal errors for all other requests. - Consume and count one drop for the matching execute call - Adapt media tests to the borrowed descriptor source - Assert oversized descriptor media is refused before reading * fix(runtime): verify media reply loss at the worker probe The media driver checked a worker route that its broker client never traverses, so the required loss counter always remained zero. - Observe the actual Java probe drop instead of a proxy-only counter - Allow broker recovery while preserving the lost-start assertions - Verify the real drop, file replacement and single-use evidence * fix(core): remove duplicate filesystem service import The automatic main merge retained both copies of the same import and failed the TypeScript build with TS2300. - Keep one upstream import for the existing filesystem test fixtures * fix(runtime): align media probe with the managed schema Keep the provider media acceptance probe usable after the main schema rollout replaces legacy tables and logical storage ownership keys. - Read execution and runtime evidence from canonical managed tables - Resolve physical ownership through the tenant storage alias - Cover prepared, settled and released evidence on the fresh schema * style(runtime): align media probes with Java checks Keep the media integration gate compatible with the Java rules introduced on main. - Sort imports and remove the obsolete charset import - Brace existing conditions and loops without changing behavior * fix(runtime): adapt media validation to server migration Keep provider media validation runnable after the Java server move and the managed schema's epoch-millisecond timestamp conversion. - Point the MySQL launcher at the migrated server POM - Bind a numeric last-active time in the canonical schema fixture * style(runtime): fix inherited MCP fault test checkstyle Keep the module verification gate passing after integrating the new upstream MCP fault test. - Remove an unused CompletableFuture import - Normalize blank lines without changing test logic or assertions * test(runtime): align media probe with execution membership Keep the media acceptance probe compatible with shared runtime execution membership after integrating main. - Check the original binding, generation and physical storage member - Reject mismatched or exclusive members and leaked released membership * docs(runtime): add the English provider media design and drop unrelated CUA docs Translate the provider media design so the bilingual pair linked from the Chinese document resolves. Drop two CUA planning documents that were carried by the media commit but describe unrelated browser work. The Java/MySQL provider-media scenario passes locally against an isolated MySQL instance: 12 cases, 24 model requests, one dropped start, every reference dispatched once and released after broker restart. * test(runtime): adapt the provider-media M4 driver to the broker client main replaced the high-level broker provider with ManagedRuntimeBrokerClient. Add a test-only adapter that exposes the ManagedToolV2Client surface the M4 driver uses, backed by the new client, and update the driver import and status narrowing. Verified: integration typecheck, ESLint, and the Java/MySQL M4 scenario (12 cases, 24 model requests, one dropped start, all references dispatched once and released after Broker restart). * style(tests): add the broker media adapter final newline Restore Prettier compliance for the provider-media integration helper so the formatting lane can pass. --------- Co-authored-by: wangheyang <[email protected]> Co-authored-by: wenshao <[email protected]> |
||
|
|
ccd463a835 |
perf(memory): retain unchanged legacy catalog snapshots (#15246)
* perf(memory): retain unchanged legacy catalog snapshots Keep an unchanged legacy memory catalog at a stable history position so later requests can reuse the cached prefix. A changed catalog appends a full snapshot that supersedes earlier ones; resume, retry, compression and suppressed-memory requests handle the snapshots consistently. Refs #15027 * fix(core): keep resumed token counts when legacy catalogs stay visible * fix(core): keep catalog snapshots exact across replay and recovery IDE context no longer merges into a marked catalog snapshot, so replay parts keep the exact text deduplication compares. A turn that ends without a usable usage report still charges a retained catalog, and an output-recovery request strips stale snapshots before appending the current catalog. Curated shallow tails filter marked parts like their siblings, and the latest-snapshot scan is shared between live requests and transcript replay. Tests now delegate the client environment stubs to production, pin the retained-catalog reads and side-query strips with immutable sentinels and a catalog-active pass, make the telemetry-mirror assertions order sensitive, and fail without the replay marking loop, the recovery retain flag, the replayed-snapshot flag slot, or the snapshot-only classification. Design docs record the one-way token-count invalidation and the complete per-package validation recipe. Refs #15027 * fix(core): reuse the gate estimate for the zero-count output clamp When lastPromptTokenCount is 0 and no manual plan-exit notice was consumed, the fallback ignores the conservative flag, so recomputing for the clamp repeats the same full shallow-history walk the gate already paid for. Reuse the gate estimate on that path, matching the pre-change behavior. Also add an aborted-turn witness that an uncharged retained catalog still feeds the next gate estimate with an authoritative count flag. Refs #15027 * fix(memory): deduplicate recording type import after base merge * test(memory): compare serialized history after prompt identity restore |
||
|
|
6aa6438136 |
fix(managed-agent): guard lifecycle renewal scheduling during shutdown (#15208) (#15231)
* fix(managed-agent): guard lifecycle renewal scheduling during shutdown (#15208) SessionLifecycleCoordinator.deliver scheduled its lease renewal after stopRenewals had already shut the scheduler down. The rejected task escaped on the shared executor thread during context shutdown, which is the RejectedExecutionException the MySQL lane reported alongside a concurrently running integration test. Treat a closed scheduler as shutdown: return without scheduling and let the claim lease re-drive the operation after restart. * fix(managed-agent): log and pin abandoned shutdown deliveries Log the operation and lease when a queued lifecycle delivery is abandoned at shutdown, and make the regression test assert that the delivery stops before any Harness call or durable write instead of only checking that no exception escapes. * fix(managed-agent): qualify the shutdown abandonment log and comment SessionLifecycleCoordinator's shutdown guard told operators the claim's lease re-drives the abandoned operation unconditionally. The recovery scan reaches expired leases only when its first page has room under SCAN_LIMIT, so a sustained PENDING/BLOCKED backlog delays the re-drive past the lease. Say so in the comment and the WARN; no behavior change. Co-authored-by: Qwen-Coder <[email protected]> --------- Co-authored-by: qwen-code-autofix <[email protected]> Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
3eff5f7793 |
feat(web-shell): create workspaces from a Git URL (#15361)
* feat(web-shell): create workspaces from a Git URL
The Add-workspace dialog could only register an existing directory or
create an empty scratch directory, so starting from a repository meant
leaving the browser, cloning on the daemon host, and registering the
path afterwards.
Add a Git source that starts an asynchronous clone job, reports progress,
and supports cancellation. A successful clone is registered through the
existing workspace route, so capacity, nesting, persistence, and the
daemon's trust policy stay in one place.
* fix(cli): classify git_workspace_clone in the capability parity matrix
The parity matrix landed on main after this branch, and every capability
tag needs a row. Managed workspace creation only creates empty
directories, so record the clone surface as an explicit Managed gap
rather than claiming parity.
* fix(cli): reserve active clone targets before overlapping work
An outer clone's failure/cancel cleanup removes its target recursively,
so a nested clone or workspace registration must not start underneath a
running job. Reserve the canonical target for the job lifetime, reject
overlapping clone and registration paths, and release the reservation
only after cleanup settles.
Also resolve the success path before publishing `succeeded`, so a reader
never observes a terminal snapshot without the `cwd` it registers.
* fix(web-shell): keep clone polling recoverable
A failed poll left the last known status running, so the panel offered
Cancel instead of the recheck that can recover the existing job. Prefer
the unknown-state action.
Reset the unmounted guard in the effect setup: StrictMode's development
replay otherwise leaves it set and discards every later poll, including a
successful clone.
* feat(web-shell): reuse the directory path as the clone parent
When the source switches to Git, treat the directory path as the clone
parent and append the repository name from the URL. A path whose basename
already matches stays as-is, and a manually edited or browsed target is
never overwritten by later URL edits.
* feat(web-shell): suggest folders for the clone target
Headless daemons do not provide a native directory picker, so the clone
target had to be typed in full. Reuse the directory suggestion list:
selecting an existing folder uses it as the parent and appends the
repository name, while a manually edited target still wins.
* fix(cli): keep clone progress monotonic
git restarts the percentage for some clone phases (remote counting,
then receiving), so the Web Shell progress bar could jump backwards.
Clamp the reported percent to the running maximum; the status message
still follows the current git line.
Also pin the clone admission guards left unpinned by review: reserved
roots, unknown request keys, promotion of a workspace under an active
clone target, file URLs that name a host, percentages above 100, and
the dialog fallback when the daemon capability disappears.
* fix(cli): reserve the clone target before claiming it
The claim created the target with mkdir, then awaited the existence check
and the final realpath, and only reserved the canonical path afterwards.
A concurrent ordinary registration could admit the freshly created
directory in that window and then lose it to the clone's cancel/failure
cleanup.
Reserve the canonical target inside claimCloneTarget before mkdir, share
the reservation with registration, and release it on every claim failure
and on post-claim admission failures. Add a regression test that overlaps
the registration with the blocked claim and a unit test that asserts the
reservation exists before the directory does.
Also update the serve integration capability envelope for the
host-conditional git_workspace_clone tag, mirroring the daemon's probe.
* fix(cli): register git_workspace_clone in serve capability guards
Test (ubuntu) failed five capability-registry guards because the new
git_workspace_clone tag was not registered alongside the existing
conditional features:
- document it in the qwen serve protocol table;
- allow the clone spawner's process-environment copy and SystemRoot
lookup in the serve process.env guard;
- add it to EXPECTED_REGISTERED_FEATURES and the conditional-feature
drift-insurance branch.
Verified: capabilities-docs-contract, process-env-guard and server
suite 1399/1399; typecheck, ESLint, Prettier clean.
* fix(cli): keep clone targets away from reserved and Live paths
A clone target that contains the reserved Conversations root was accepted
when that root did not exist yet: creating the target made the root's
parent part of the clone, and the Live runtime could then be published
inside it. Because the Live exemption skipped the "canonical inside
target" direction for active clone targets, cancelling or failing the
clone deleted the registered Conversations workspace.
Reject clone targets that contain a reserved root, even before the root
exists, and apply strict two-way nesting to active clone targets in the
owned-runtime admission regardless of provenance.
Verified: workspace-git-clone + workspace-management 196/196;
typecheck, ESLint, Prettier clean.
* fix(cli): resolve reserved roots through existing ancestors
The reserved-root containment check fell back to the unresolved spelling
when the Conversations root did not exist yet. A symlinked ancestor such
as ~/Documents then made the canonical clone target and the lexical
reserved path disagree: the clone was accepted, the Live runtime created
the root inside it, and cancelling the clone left ConversationWorkspace
with a cached identity for a directory that no longer existed.
Resolve each path through its nearest existing ancestor and append the
missing suffix before comparing, so a clone target containing a missing
reserved root is rejected before mkdir even when ancestors are symlinks.
Verified: workspace-git-clone + workspace-management 197/197;
typecheck, ESLint, Prettier clean.
* fix(cli): cover case aliases and dangling links in reserved roots
The reserved-root guard compared the reconstructed missing suffix with
case-sensitive isWithinRoot, so a case-variant ancestor such as
`Documents/qwen code` did not match `Documents/Qwen Code/Conversations`
on a case-insensitive filesystem. It also walked past a dangling symlink
ancestor, so a clone target that was the link's missing destination
could later make the link valid inside the clone's cleanup scope.
Compare canonical paths case-insensitively after resolving through the
nearest existing ancestor, and follow dangling symlinks while
reconstructing the missing suffix. Add regressions for both aliases.
Verified: workspace-git-clone + workspace-management 199/199;
typecheck, ESLint, Prettier clean.
* fix(cli): harden git clone credentials, config, and admission
- Strip URL credentials before git's argv and supply them through a
command-line credential helper backed by the child environment, so the
secret no longer appears in /proc/<pid>/cmdline or .git/config.
- Disable global/system git config for the clone child so a repository's
.gitattributes cannot run host-configured filter commands during checkout.
- Keep the first fatal/error stderr line for clone failures instead of the
trailing SSH boilerplate.
- Only treat Receiving objects/Resolving deltas as progress phases, so
remote counting cannot pin the bar at 100.
- Strip OSC/C1 and all other control characters from clone messages; add
the missing Windows taskkill 'error' listener.
- Require operator authority for clone cancellation; reject clone targets
inside the managed scratch root or equal to a registered/in-flight
workspace; keep case-insensitive containment scoped to clone targets.
Verified: workspace-git-clone + workspace-management 205/205;
typecheck, ESLint, Prettier clean.
* fix(web-shell): gate the clone flow during submit and IME input
- Disable the post-clone Back button while registration is in flight and
guard backToForm, so it cannot reset a submitting flag owned by onAdd.
- Ignore clone-target key handling while an IME composition is active.
- Dismiss the clone-target suggestion list when the git form is submitted,
so its Escape interceptor cannot stay armed over the progress view.
Verified: AddWorkspaceDialog 57/57; Prettier and ESLint clean.
* docs: align git clone guarantees with credential and config isolation
- Document the `{ kind: "git" }` form and its 202 job response in the
`POST /workspaces` reference.
- State that URL credentials are moved out of git argv and the stored remote
URL, and that global/system git config is disabled for the clone child so
committed filters cannot run host commands during checkout.
- Mirror both changes in the Chinese design document.
* fix(cli): use bracket access for clone credential env
The strict index signature on NodeJS.ProcessEnv rejects dot access to
QWEN_GIT_USERNAME/QWEN_GIT_PASSWORD; all CI jobs that build the CLI
failed at tsc with TS4111 before running any test.
* fix(web-shell): cancel the running clone from the left action
- Route the progress panel's left Cancel through cancelClone while the job
is running, so it stops the daemon job instead of only closing the dialog.
- Clear the pending poll timer at pollCloneJob entry and before cancel, and
guard registration per job id, so a terminal snapshot cannot register the
same clone twice.
Verified: AddWorkspaceDialog 57/57; Prettier and ESLint clean.
* fix(web-shell): harden git clone env and clone-job dialog states
Pin LC_ALL/LANG for the clone child and sweep host Git config channels (GIT_CONFIG_*, GIT_ASKPASS, GIT_SSH*, GIT_PROXY_COMMAND) so a localized git still reports parseable progress and a browser-chosen URL cannot borrow host credentials. Decode URL credentials defensively, reject control characters, and print the inline credential helper with printf so dash does not mangle tokens.
In the add-workspace dialog, tear the clone state down when the capability disappears, report a pruned clone job instead of offering recheck forever, honour a cancel that loses the race with a finished clone, and close instead of cancelling an unconfirmed job. Correct the host-authentication prose in the design docs, README and URL hint to match what the isolated clone child actually supports.
* fix(cli): resolve relative symlinks physically and keep cancel intent
- Resolve a relative symlink target from its physical parent before appending
the missing suffix, so a dangling relative Documents link cannot hide the
reserved Conversations root from clone admission.
- Keep the per-job cancellation intent across overlapping poll responses, so
a second succeeded poll cannot auto-register after Cancel. Clear it only on
an explicit Back/new submission.
Verified: route + clone 209/209; AddWorkspaceDialog 61/61; typecheck with a
6 GB heap; Prettier and ESLint clean.
---------
Co-authored-by: verify <verify@local>
|
||
|
|
2a245baff5 | fix(cli): Hide unavailable Managed background tools (#15497) | ||
|
|
1df5031e70 |
perf(ci): overlap web-shell and standalone tests with the CLI suite (#15438)
* perf(ci): overlap web-shell and standalone tests with the CLI suite The Linux Test job ran every workspace suite, the standalone runtime regression and scripts/tests one after another. The CLI suite keeps its workers busy for 13-20 minutes, while web-shell's suite spends most of its run on App.test.tsx alone and the standalone regression starts one runtime process at a time, so those two added their mostly idle minutes straight to the job. Run them in a side lane beside the other workspaces instead. .github/scripts/ci/run-unit-test-lanes.sh starts web-shell and the standalone regression in the background, runs every other workspace's test:ci (listed with npm pkg get, in npm's workspace order) and then scripts/tests, and replays the side lane's log after the main lane so the two never interleave. The step runs the script under the same setpriv wrapper, so every test command still runs without the DAC override capabilities. test:scripts now reaches its Vitest run through a new test:scripts:unit script with a trailing --, so the main lane can run it without the standalone regression while test:ci, test:ci:workspaces and test:scripts run what they ran before. * fix(ci): name the cause when the lane script cannot start a lane - Fail with an ::error:: line when mktemp cannot create the side lane's log file, instead of running the main lane alone and dying in tail. - Check the exit status of `npm pkg get` and of the parser. A failing `npm pkg get --json` prints an error object, which used to parse as an empty listing and report "Found no workspaces". - Note in the header that the replay puts side-lane failures after the main lane's in main-failure-signature.mjs's title and search markers. - Lane test: clear the caller's NODE_OPTIONS, assert the main lane's output is present before checking its order, and cover the failed listing and the missing temp dir. - Cross-check npm's workspace resolution against the selector in scripts/workspaces.js. * fix(ci): halve web-shell's worker cap beside the main lane Each Vitest run applies VITEST_MAX_FORKS / VITEST_MAX_THREADS on its own, so running two lanes at once doubled the step's worker cap, and on the hosted runners, where no cap is set, put two all-CPUs pools on 4 vCPU. The lane script now runs web-shell at half the cap, at least 1, and at 2 where the cap is unset; the main lane keeps the full cap. - Refuse a workspace name with whitespace in it: the main lane's arguments are read one per line, so a line break would split a name into other arguments, flags among them. - Lane test: web-shell and the main lane's suites now wait for each other, so a side lane serialized before or after the main lane fails; record each call's worker caps; run the script against npm's real listing and compare its main lane with the selector the release pins use; cover a name with a line break in it. - ci.yml: the standalone runtime cache comment names the lane script's side lane, not test:scripts, as what runs the regression in this job. - ci-variables.md: say the cap applies per Vitest run and what the two-lane step runs at its peak. - release-workflow.test.js: follow test:scripts through test:scripts:unit to vitest; #15102 pinned the shape before the split. |
||
|
|
4b32800459 |
feat(cli): list /autofix-pr watches and resume them in a later session (#15510)
* feat(autofix-pr): list watches and resume them in a later session A watch ends with the session that ran it and its scheduled task expires after 7 days, and getting it back meant typing `/autofix-pr <n>` again and confirming a take-over, PR by PR, with the interval, `--no-reply` and instructions remembered by the user. `status` also had nothing to read but the state files' raw fields. - `qwen autofix-pr status [<pr>]` lists every watch of the clone from its files, without a lock or a GitHub call: head, pushes, owning session, the last gate check (the gate now touches its cursor on every run) and round, whether the gate saw the PR end, the recorded task and what was left for a person. - `qwen autofix-pr schedule <pr>` records the watch's task in the state file and prints its cron, gate and prompt for `cron_create`, so the skill no longer composes them; `--again` prints the recorded task for the session that took the watch over. - The reply plan takes `needsHuman` lines, kept per head (newest 20) for `status`. - The skill gains `/autofix-pr resume [<pr>]`: one confirmation, then a take-over, one round and the recorded task for each watch this session does not run. * fix(autofix-pr): keep resumed watches whole and their old tasks gone - prepare keeps the recorded task and needsHuman when it rebuilds a removed worktree, so resume can schedule it again. - A round woken by a task made for a session that no longer owns the watch deletes that task (watched_elsewhere now names gateSession); the start and resume delete such tasks before the round, not after a schedule that may be refused. - status reads the gate cursor only for the watch's repository, keeps a watch whose cursor cannot be read, and reads only the state files the helpers name, each of its own PR. - cleanup --take-over lets stop end a watch another session left behind while keeping its work, and a cleanup that keeps the worktree drops the recorded task so resume does not discard the kept work. - resume goes through a round for a watch the gate saw end, rather than cleaning it up unconfirmed, and leaves out a watch another session checked recently unless the PR is named. - The start records its task before the round and schedules it only if the round did not stop the watch; session ids must start with a letter or digit, control characters in instructions are folded, and a recorded task is held to one line of 2,000 characters. * fix(autofix-pr): give each watch one task and say when another session runs it - schedule mints a task id each time (the gate carries --task); a gate whose id the state no longer records — a task a later start or resume replaced, or a copy in a second process of the same session — answers watched_elsewhere, and a --session gate whose watch cleanup removed answers watch_ended, so the round deletes exactly that task. The start schedules with --again after its round, which refuses a watch the round ended, and schedule refuses a PR whose author cannot push. - status says whether a gate checked within two intervals (checkedRecently, with now), what the worktree holds (worktreeWork), and reads only regular files; resume and take-over confirmations quote both. - prepare --take-over on a removed worktree moves the watch only after the PR passed its checks; cleanup drops the recorded task only while it still owns the watch; stop takes over every PR it ends. - Instructions and needsHuman lines drop format characters. * fix(autofix-pr): let only a watch's own task run its rounds - The task's prompt carries its id (tick ... --task <id>) and a round's first sync checks it: a fire queued before a later schedule replaced the task is refused, and the round deletes it. Resume runs schedule --again before its round, so a second process of the session stops there too. - A cleanup that keeps the worktree marks the watch ended: the round helpers refuse it, its gate answers watch_ended, and only a start resumes it (prepare reports wasEnded). - The gate counts a task with no id as stale once the watch records one, answers watch_ended to a task of a watch that records none, and refuses --task without --session. - The watch's own gate marks its checks in autofix-pr-<n>-gate.checked, which cleanup removes; a gate with no session leaves it, and status takes nothing from a cursor older than the watch (preparedAt). - The state accepts only the four task fields, and schedule builds the task from them field by field. - A stop the user did not name a PR for takes no watch from another session. * fix(autofix-pr): keep a recreated watch on cancel and check the task at every helper - prepare says recreated when it only made a removed worktree again, so a cancelled start, or the end of a --once round, cleans up only a watch it made; a --once round that resumed a stopped watch ends it again, and a stopped watch is resumed only after the question --yes cannot skip. - snapshot, ci-log, push, reply and rerun take the round's --task too, so a round already past sync when a later schedule replaced its task stops at its next helper. Taking over a round that is still running stays a race for its fix agent, which calls no helper: the questions say so. - An ended watch says so before ownership is checked, and another session's watch is offered back with resume only when it records a task. - The state's watch ignores fields it does not know, which never reach the task; status runs git without optional locks, names the file and the way out for what it cannot read; the start deletes the PR's other tasks before its round. * fix(autofix-pr): schedule a start's task from what was printed before its round - The start and resume make their task from what schedule printed before the round — the round runs under that task id — once status shows the watch still records it, so nothing the fix agent writes to the state file reaches the task or its prompt. - The state is read with the known fields of watch, ended and needsHuman only; a rebuild of a stopped watch's removed worktree reports wasEnded; a cleanup that keeps a worktree removes the gate's check mark. - The instructions file is read only if it is a regular file, before the lock; a refused task names which task to delete and which to keep. - The skill: every round helper's first four refusals are handled alike; a take-over warns of another session only when no task of the PR is listed here; a resume that stops a watch takes it over; a refused schedule after a take-over leaves the watch to resume. * fix(autofix-pr): resume every watch's task before any round, and ask GitHub who may push - Resume takes over and schedules every watch it resumes before any round runs — a round's fix agent works beside the other watches' state files — leaves out one whose printed options are not those it asked about, and runs each round with the options schedule printed. - prepare asks GitHub again on a resume whether the PR's author can push instead of reading it back from the state file, and schedule refuses any state but authorCanPush: true. - readState reads only a regular file, so --force can discard a FIFO planted as the state; cleanup that finds the watch taken over during its check refuses instead of reporting it ended. - The skill: stop reports the needsHuman items cleanup removes; status sorts ended and --once watches first; --yes does not skip the question where another process may be running a round; the start's and resume's status check also requires thisSession; a refused cron_create says to resume. * fix(autofix-pr): ask GitHub before moving a watch, and read only regular files - Only a 404 from the permission API means the author cannot push; any other failure is a refusal that changes nothing, so a rate limit no longer ends a running watch. A resume asks GitHub before a take-over is written, so a failure leaves the watch with the session that has it. - A resume derives the remote and the push target from the clone's remotes again, and refuses a repository the clone does not serve. - The gate cursor, the history and the reply cache are read only when they are regular files, as the state is (a link to nothing included), and cleanup's sweep removes a directory planted under a watch's names. - cleanup checks again under the lock that the watch is still this session's before it removes anything, and keeps the latest history. - The skill: a PR whose author lost write access has its tasks deleted and its watch ended after a --once round; a refused instructions write ends the start; the start's last line reports a watch only when its task exists. * fix(autofix-pr): write a watch's files without following links, and ask who may push before making anything - Every write of a watch's files (state, cursor, history, snapshot, reply cache, CI log) replaces a link instead of following it, and reply reads the round's snapshot only if it is a regular file. - A new watch asks whether the author can push before it fetches or makes anything, so a failed ask leaves no worktree, branch or state; a resume refuses a PR whose head repository is gone, and reads and clears ended under the lock that writes the rest. - cleanup removes a watch under the lock after checking ownership again; a directory planted at the history is replaced, and --force clears a cursor that is no regular file. - A state that is no regular file names cleanup --force; a cancelled start of a PR whose author cannot push cleans up too. * fix(autofix-pr): keep human decisions and a failed take-over intact - reply: record what a round left for a person before posting anything. A reply that reached the PR marks its comments handled at once, so after a later POST failed the next round never listed them again. - cleanup --take-over: move the watch only as it ends, under the lock. A stop that failed before then left the watch owned by no running session, and its owner's gate stopped it. - One predicate for gh's 404, read from its stderr. - Skip the FIFO tests on Windows. * docs(autofix-pr): say a daemon session refuses a watch it cannot run, on a resume too |
||
|
|
a4ce90270e | feat(managed): add durable mid-turn user message queue (#15449) | ||
|
|
a4331340ad |
fix(ci): skip main-failure issues for post-merge reruns (#15239) (#15250)
* fix(ci): skip main-failure issues for post-merge reruns (#15239) A rerun re-executes the PR's pre-merge workflow. When it starts after the PR merged, its failure describes a head that main has already replaced, and the post-merge push run owns that signal. Compare the attempt's start time with the merge time and skip filing for the stale head. Run 39768204855's attempt 2 started after PR #15094 merged, hit the pre-#15128 suite-wide host-lock hold, and filed #15239. * fix(ci): discriminate post-merge reruns by attempt (#15239) The clock proxy suppressed fresh manual dispatches and post-merge approval runs while missing reruns dispatched before the merge. Use run_attempt, which states rerun identity directly: attempt 1 still files, later attempts on a merged PR keep the comment but open no issue. Announce the empty-attempt fail-open path. Preserve an existing tracking-issue link when a suppressed attempt updates the PR comment, and sync the design docs and the contract comments with the narrower scope. * fix(ci): pin rerun guard scope and tracking-link recovery (#15239) Drop the pre-loop body write that no publish path could read, and cover the publish-retry truncate with a row that fails the first publish. Pin the writer's tracking line against the recovery grep's anchored pattern, and pin that the attempt guard never suppresses a main run. Scope the design doc's exclusivity sentence to the infrastructure path in both languages. The workflow size ratchet records the file's new size; the growth is the attempt guard and tracking-link recovery this PR adds. Co-authored-by: Qwen-Coder <[email protected]> * test(ci): pin tracking-link precedence for PR failure comment (#15239) Co-authored-by: Qwen-Coder <[email protected]> * test(ci): pin tracking-link wiring and POST coverage (#15239) * fix(ci): file dispatch reruns on merged PR branches (#15239) * test(ci): pin merged-PR rerun event and lookup-failure publish guard (#15239) Co-authored-by: Qwen-Coder <[email protected]> * test(ci): pin approval-run suppression and merged-PR comment guard (#15239) Co-authored-by: Qwen-Coder <[email protected]> --------- Co-authored-by: qwen-code-dev-bot <[email protected]> Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
ba051f804a |
fix(ci): run the sdk-java suite before taking the host lock (#15254)
* fix(ci): run the sdk-java suite before taking the host lock (#15242) Run 39771949573's fast-tier job spent both attempts' full 5400 s lock budget waiting: the full-tier Java 21 leg of run 39754414693 ran for 89 minutes on the same host, and the fast job failed five seconds after that leg ended. The MariaDB lane's #15128 fix scoped the lock to its cache write-back, but the test job still held the host lock across the SDK and Managed Agent Maven suites. Seed the test job's Maven repository from the host cache, run its suite from that job-local copy, and take the ticketed host lock only for the cache write-back. The write-back children close fd 9 so a cancelled job's survivor cannot retain the lock, and the workflow pins move with the new order. * fix(ci): keep the SDK Java gate green when the write-back lock expires (#15242) The write-back lock acquisition could redden a job whose suite had already passed (CI run 39814549427). Treat it like the best-effort copy it guards: warn and skip on timeout in both the helper and fallback arms, while leaving the helper's pinned lock-not-acquired signature alone. Tighten the workflow pins: assert the region below the lock instead of first-occurrence Maven indices, pin both write-back copies byte-equal, bind the job-local MAVEN_ARGS to its step, and include the write-back bound in the test job's ceiling model. Restate the hold-length derivations and record the concurrency blast radius in both design languages. Co-authored-by: Qwen-Coder <[email protected]> * fix(ci): keep the lock helper outside this PR's footprint (#15242) Co-authored-by: Qwen-Coder <[email protected]> * fix(ci): describe the sdk-java 89-minute leg as the leg, not the suite (#15242) Co-authored-by: Qwen-Coder <[email protected]> * fix(ci): keep tolerated sdk-java lock timeouts out of rerun classification (#15242) The warn-and-skip downgrade left the helper's `lock not acquired within` annotation on a step that now exits 0, so a later genuine failure in the same job could be classified as infrastructure. Both call sites rewrite the timeout line before it reaches the log, and probe flock plus the cache directory first: bash suppresses errexit for a function on the left of `||`, so without the probes a setup fault spun out the full wait green. The skip test now plants a publishable delta, asserts nothing was published, checks the captured annotations against the live INFRA_FAILURE_SIGNATURES list, and adds a setup-fault arm. The workflow size baseline is re-measured, and the design docs' classifier, promotion, and budget claims are corrected in both languages. --------- Co-authored-by: Qwen-Coder <[email protected]> Co-authored-by: Qwen Autofix <[email protected]> |
||
|
|
1c9cdd234f |
feat(verify-pr): declare an argument hint for the command prompt (#15463)
* feat(verify-pr): declare an argument hint for the command prompt Typing `/verify-pr` showed no parameter hint, unlike `/review`, because the skill's frontmatter carried only `name` and `description`. The TUI renders `argument-hint` beside the command name and `/review` relies on exactly that field, so `/verify-pr` looked like it took no arguments at all. The hint lists the PR number and every flag the skill accepts — `--publish`, `--watch`, `--repo`, `--assets-repo`, `--assets-branch` — and a scripts assertion pins it, so dropping a flag from the hint reddens the test. * test(verify-pr): pin the parsed argument hint instead of its raw line Assert the parsed frontmatter value so a requoted plain scalar stays green while a dropped value placeholder goes red, and record in the skill's environment contract that .qwen/** is the base commit's copy in the verify lane. |
||
|
|
5aeee2ceec | fix(release): authenticate managed OSS preflight (#15504) | ||
|
|
cc49daa282 | fix(ci): preserve independent validation for main push SHAs (#15508) | ||
|
|
b423ed9042 |
feat(runtime-broker): add HTTP-backed external scratch workers (#15261)
* feat(runtime-broker): add external scratch HTTP provisioner
* docs(runtime-broker): format external provider design and state tool-consumer gap
* docs(runtime-broker): document external scratch provider deployment
* docs(runtime-broker): note external placement capacity bound
* fix(runtime-broker): free external retry slot on permanent outcome
* docs(runtime-broker): reconcile external provider verification evidence
* docs(runtime-broker): record exact-head local Java evidence
* test(runtime-broker): exercise external provider with real worker
Cover lost provision response, original worker adoption, UNKNOWN recovery and file tools in the existing fault gate. Runtime verification pending CI; no local Maven run within the exhausted shared budget.
* docs(runtime-broker): describe real-worker gate scope
* test(managed-agent): update duration field inventory
* test(managed-agent): re-acquire the Session after Broker recreation
Session liveness is per Broker process by contract (requireSession
checks the process-local map and rejects with 'Runtime Session is not
active in this Broker process'). The restored Broker must adopt the
worker and then the caller re-acquires the Session; the repository
dedupe reuses the READY record. The fault gate now mirrors that client
flow before driving executions on the adopted worker.
* fix(cli): drop the removed V2 tool lists from the parity test (#15362)
The parity matrix landed one commit before the shell-lifecycle unification,
which deleted HOSTED_WORKSPACE_FILE_TOOLS_V2 and HOSTED_WORKSPACE_SHELL_TOOLS_V2
and began adding glob inline when search is on. The test kept importing both,
so tsc --build failed at the merge-base and every PR's prepare step failed
before a single test ran.
Those two lists were the base lists plus glob, so dropping them removes no
tool name the matrix cites: its evidence tokens name edit, monitor,
run_shell_command and write_file only.
(cherry picked from commit
|
||
|
|
a5cf7aaa4d |
test(cli): budget the hosted approval wait for loaded runners (#15093) (#15101)
* test(cli): budget the hosted approval wait for loaded runners (#15093) Co-authored-by: Qwen-Coder <[email protected]> * test(cli): keep the hosted approval budget under the per-test ceiling (#15093) Co-authored-by: Qwen-Coder <[email protected]> * test(cli): pin the requested() timeout wiring to the slow-host policy (#15093) Co-authored-by: Qwen-Coder <[email protected]> * test(cli): pin the requested() wait at its use site (#15093) Co-authored-by: Qwen-Coder <[email protected]> * test(cli): keep malformed-Unicode test names JUnit-safe (#15093) The parametrized malformed-Unicode cases interpolate lone surrogates into the test name. Vitest's JUnit reporter strips a lone low surrogate together with the preceding character, which is the semicolon of an ' entity, so packages/cli/junit.xml becomes invalid and the CI report publisher fails. Label each value for the title and keep the raw value in the test body. Co-authored-by: Qwen-Coder <[email protected]> * test(cli): pin the hosted approval wait to the slow-host policy (#15093) Co-authored-by: Qwen-Coder <[email protected]> --------- Co-authored-by: Qwen-Coder <[email protected]> Co-authored-by: 易良 <[email protected]> |
||
|
|
10c036b655 |
fix(ci): keep the incremental lint history fetch blobless and visible (#15511)
Lint & Static can already hold a blobless merge base: Report test growth fetches it with --filter=blob:none. A later plain depth-100 fetch then fails resolving thin-pack deltas against blobs this checkout does not have (fatal: missing blob object + remote did not send all necessary objects), and continue-on-error turns that into a silent full scan: 4 of 8 sampled PR runs after #15381 merged, with 5 of 8 falling back to full lint in total. Fetch blobless too, and drop the recorded filter so later fetches in the checkout stay ordinary. lint-scope reads only commits and trees. Announce a history fallback as ::warning:: plus a step-summary line on workflow runs, deduplicated across the seven lint.js invocations, so the optimization can no longer stop working without a trace. |
||
|
|
07c1c2b30e | fix(web-shell): simplify status when loading phrases are hidden (#15423) | ||
|
|
58a4c1b9cc |
feat(generated-ui): continue analysis with reviewed parameters (#15333)
* feat(generated-ui): continue analysis with reviewed parameters * test(generated-ui): reveal outer frames before continuation clicks * fix(generated-ui): keep continuation feedback accurate when nothing was sent A capture failure no longer reports that a sent request may still be accepted, and the unconfirmed message now covers cancelled or rejected reviews, which the host reports the same way as an unknown outcome. --------- Co-authored-by: qqqys <[email protected]> |
||
|
|
abb7fcf020 |
fix(cli): refuse an autofix watch a daemon cannot run (#15506)
* fix(cli): refuse an autofix watch a daemon cannot run A daemon session that started /autofix-pr from a checkout other than the PR's clone prepared its worktree in the clone's main worktree, outside the session's own working directory. The shell guard then refused every command in that worktree, so the round could not test, commit or push anything — and the refusal named only a path, which sent the fix looking for a way around the boundary instead of at it. prepare now refuses that start in a daemon session, before anything is made under .qwen/tmp, and names the directory the session has to contain. The guard's refusal also says which roots it accepts, so a caller does not retry the same command in a fresh session and call it a fix. The skill says a refused shell command stops the round: a worktree nothing can run in cannot be verified, committed or pushed, and no sub-session should be spawned to run it one command at a time. Tested: packages/core SKILL.test.ts (5), packages/cli prepare.test.ts (39), packages/cli daemon-git-worktree-guard.test.ts (464 passed, 4 skipped), eslint, prettier and a full typecheck. * fix(cli): name the shell guard boundary, not the caller The refusal added for a worktree outside the session's directory called the affected caller a sub-agent. A session whose own effective directory moved outside the one the daemon tracks is refused the same way, so the message speaks about the directory rather than the caller. The user guide had the containment backwards: the clone has to sit inside the session's working directory, not the other way round. The prepare refusal now names the clone root to open the session at instead of describing the condition abstractly, so the sentence tells the reader where to go. The guard suite asserts the boundary hint, so a later edit cannot drop it without a failure. * fix(cli): refuse a daemon resume it cannot run too The refusal only covered a fresh start. A resume reports the worktree already there and returned before the check, so a session that resumed, or took the watch over, in a sibling checkout was still handed a worktree the daemon refuses every command in — the same dead end, one start path later. Both refusals now run before the state is read, so a resume meets them as well, and a new case prepares in the clone, adds a linked worktree, and asserts that the resume from there is refused with the state file left untouched. The refusal says to prepare from the clone root, which is the fix even when only the helper's working directory was narrower than the session's. |
||
|
|
e84e0f3dac |
test(cli): budget hosted approval waits for slow runners (#15176) (#15183)
* test(cli): budget hosted approval waits for slow runners (#15176) The hosted approval tests wait through a serial chain of fsync-backed publishes and journal commits. On the shared post-merge CI pool that chain can outlast the fixed 10s wait, so the continuation and inline-limit suites failed with phase "before_model" instead of "await_action". Pick the wait and per-test budgets through the existing slow-host policy: fast hosts keep their current ceilings, slow hosts get 45s under the 60s per-test ceiling, so a genuine stall still fails on the assertion. * test(cli): pin non-ecs RUNNER_NAME fast budget (#15176) Co-authored-by: Qwen-Coder <[email protected]> * test(cli): pin the saturated-host equality boundary (#15176) * test(cli): keep slow-host timeout headroom for hosted approvals (#15176) * test(cli): budget hosted harness settle waits on slow hosts (#15176) Co-authored-by: Qwen-Coder <[email protected]> --------- Co-authored-by: Qwen Autofix <[email protected]> Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
b5958d300b |
feat(managed-agent): pool the automation scanner's rows and lease from the claim time (#15442)
* feat(managed-agent): pool the automation scanner's rows and lease from the claim time A scan tick worked every armed definition on the scheduler's only thread, so one gated fire_run holding the Harness relay (probe up to 20 s inside 30 s, plus up to 120 s of Session load) delayed every definition on the node; measured gate runs of 10-13 s cap one node at about four one-minute PR watches (#15418). Work the tick's candidate rows on a bounded pool (automation.scanner-threads, default 4), one task per row, claimed inside the task, and join them before the tick returns so fixedDelay still never overlaps. The lease now runs from the claim time, not the tick's start: a task can start halfway through a lease's lifetime, and a tick-start lease would be born part-expired and stealable by another node. A dedicated automationScannerExecutor bean (never the one-thread managedAutomationScheduler, which the tick parks on while joining) finishes in-flight rows at shutdown without interrupting them. The gate design's second route — answering a gated fire asynchronously — stays open as a follow-up; it needs a wire change the funnel does not carry today. Refs #15418 * refactor(managed-agent): answer review nits on the scanner row pool The DIRECT executor owns no threads, so it no longer simulates a shutdown state: the lifecycle surface is inert and documented as such. The design doc's Validation section now lists all eight new unit witnesses, including the two the review fixes added. Refs #15418 * test(managed-agent): pin the accepted same-Session fan-out and the tick join The #15442 verify lane (verdict findings, 43/43 assertions) measured three gaps; two are closed here and one is documented: - Two definitions sharing one Session are admitted concurrently and both fire: across definitions the admission guards only on public Turns, and automation fires leave no ma_turn row, so the serial baseline behaved the same in production; the runs serialize in the Harness funnel. Accepted and pinned by the new shared-Session test, and recorded in the design's residual ceilings (finding 1). - aTickJoinsEveryRowBeforeItReportsOneFailure now runs on a real one-thread pool with the second row's claim in flight when the first one throws; under the direct executor a fail-fast break in the join survived, so the test pinned submission, not the join. Verified the rewrite kills that mutant (finding 2). - The design's residual ceilings also record that a context close lets the pool's queued rows run on its non-daemon threads: destroy() returns immediately, process exit waits, every such row stays fenced and re-drivable (finding 3). * test(managed-agent): count #15448's two permission_rules columns in the CSI inventory #15448 added permission_rules_json to ma_session and ma_turn without bumping this test's column sum, which is latent-red on main and broke the merged fast tier here. Local chain: red at 747 expected/749 actual, green at 749. The same literal lands for main in the open #15455, so this edit merges conflict-free against it. Refs #15442 |
||
|
|
e9b09e1c82 |
fix(test): budget the standalone runtime suite for the release pool (#15102)
* fix(test): budget the standalone runtime suite for the release pool (#15091) The new Node/Bun regression suite runs two sequential workers that each spawn hundreds of probes. Release run 39621619809 lost both attempts at the 300 s per-worker and 600 s total spawn caps on the release pool, even though the same suite completes in about five minutes on a developer machine. Raise the per-worker budget to 600 s and the total budget to 1500 s so release validation can finish on the shared runner. The job's own 30-minute timeout remains the upper bound. * fix(test): fit the runtime budget inside the release job (#15091) The old caps were never both hit: in release run 39621619809 the node worker passed at 294 s while the bun worker was SIGTERM'd by the 300 s per-worker cap at 301 s, and the child exited before the 600 s outer cap. Correct that attribution in the budget comment. Derive the outer cap from the two sequential workers plus setup, and pick a 540 s worker cap so the derived 1140 s spawn still fits the 30-minute quality_scripts job beside the measured ~295 s setup and ~288 s scripts suite. A release-workflow meta-test pins the derivation, the worker/outer ordering, and the job-budget fit. Co-authored-by: Qwen-Coder <[email protected]> * fix(test): classify the OpenTUI parity suites for the no-AK gate (#15091) Main's OpenTUI migration added three interactive TUI parity suites, but the no-AK membership guard requires every runnable integration test to be either selected or explicitly exempted. The merged tree therefore failed the Test job at no-ak-integration-ci.test.js:378. The three suites are heavyweight interactive tests already covered by the three-leg tui-parity workflow, so exempt them as "Runtime budget" alongside the existing tui-migration and interactive-session-viewport entries. * fix(ci): preserve enrolled parity suites in runtime budget repair * test(scripts): pin standalone runtime timeout wiring and budget envelope Cover the outer-margin floor, both spawnSync timeout bindings, and the package.json hop that places the spawn inside quality_scripts, so the release budget ratchet fails when any of them detaches. Co-authored-by: Qwen-Coder <[email protected]> * fix(test): close the standalone runtime budget over setup phases (#15091) The budget ratchet counted only the child spawn plus a hand-picked reserve, leaving the parent's four downloads and two tar extractions and the child's five pre-worker probes outside the model. Bound each process's setup with a shared SETUP_TIMEOUT_MS, derive the outer cap from it, and assert the closed sum against quality_scripts' 30-minute budget. Also pin the per-host failure diagnostic the margin protects and the package.json hop that reaches --ci, so removing either fails the ratchet. Co-authored-by: Qwen-Coder <[email protected]> * test(scripts): make the runtime cache fetch pin shape-insensitive (#15091) Co-authored-by: Qwen-Coder <[email protected]> * test(scripts): enforce the setup budget through one factory (#15091) Co-authored-by: Qwen-Coder <[email protected]> --------- Co-authored-by: Qwen Autofix <[email protected]> Co-authored-by: Qwen-Coder <[email protected]> Co-authored-by: 易良 <[email protected]> Co-authored-by: qwen-code-dev-bot <[email protected]> |
||
|
|
12c620e314 |
test(ci): pin JUnit report upload paths (#15502)
Guard the CI artifact contract by resolving each JUnit writer against its Vitest root and requiring the package-level upload location. Tested: targeted Vitest, ESLint, Prettier, build, typecheck, diff check |
||
|
|
195029c12c |
ci(sdk-java): upload Surefire text reports on test failure (#14910)
* ci(sdk-java): upload Surefire text reports on test failure * ci(sdk-java): quote if-no-files-found for yamllint |
||
|
|
fa3d9027c0 |
test(managed-agent): wait for worker exit visibility (#15503)
Co-authored-by: zzj <[email protected]> |
||
|
|
b3783a36aa |
fix(serve): probe X11 display reachability before advertising the native directory picker (#15434)
isNativeDirectoryPickerAvailable only checked that DISPLAY or WAYLAND_DISPLAY was set and that some PATH entry held an executable named zenity. A headless host with a stale DISPLAY therefore advertised the native_directory_picker capability and Web Shell rendered a Browse button whose click could only fail with "cannot open display". For a local ":<n>" DISPLAY the X server is reached through /tmp/.X11-unix/X<n>, so the probe now requires that socket to exist before the tag is advertised. It stays a synchronous existence check -- no spawn, no connection -- to fit the startup probe budget. DISPLAY values that are not a local ":<n>" display keep their existing result, and the WAYLAND_DISPLAY-only path is unchanged. Refs #9981 Patrol-Run: qwen-issue-patrol/jmvm6asvfj7 Co-authored-by: yiliang114 <[email protected]> Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
08a06a46bd |
fix(web-shell): Prevent duplicate Managed composers (#15496)
Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
32b1f12f75 | fix(release): bound summary concurrency and refresh release PRs (#15500) | ||
|
|
017017f095 |
fix(cli): stop double-counting reasoning tokens in cost estimates (#15464)
* fix(cli): stop double-counting reasoning tokens in cost estimates Four sites computed the billable output token count as `candidates + thoughts`. That is right for the Gemini-style convention where `thoughts` is disjoint from `candidates`, but OpenAI-style providers already include reasoning inside `candidates` (and their reported `total` reflects that), so the reasoning got billed twice. With prompt=100000, candidates=150000, thoughts=120000, total=250000 the output came out as 270000 ($0.2700 at $1/M output) instead of the 150000 ($0.1500) the provider actually reported. Derive output as `total - prompt`, which is correct under both conventions, guarded by `total > prompt` and falling back to `candidates + thoughts` when no usable total is reported. This mirrors the idiom already in `commands/review/cost-ledger.ts` and the derivation in `services/tokenEstimation.ts`; the guard keeps a record whose total is absent or inverted from billing a negative output. Sites: - ui/components/ModelStatsDisplay.tsx (hasPricing probe + Estimated row) - ui/opentui/item-projection.ts (entryCost) - ui/commands/statsCommand.ts (non-interactive /stats output) No-op on the disjoint convention: for prompt=100000, candidates=50000, thoughts=120000, total=270000 both derivations give 170000. Fixes #15444 Co-authored-by: Qwen-Coder <[email protected]> Patrol-Run: qwen-issue-patrol/jmvmj5rjfjg * fix(cli): trust total - prompt only inside the usage band The bare `total > prompt` guard read the raw `models` bucket, which uiTelemetry accumulates without the prompt/total normalization it applies to statsModels. A record whose prompt did not survive the provider -- a total-only usage payload, or cached-only input coerced to prompt 0 -- passed the guard and billed input at the output rate; a short total under-billed. Bound the derivation to the band both usage conventions allow, and keep summing outside it: whether `thoughts` is folded into `candidates` depends on the provider's auth_type, which an accumulated bucket no longer carries, so guessing there would drop a disjoint provider's reasoning from the bill entirely. One rule in one place: the four cost sites now share billableOutputTokens in costCalculator instead of four hand-copied ternaries. Co-authored-by: Qwen-Coder <[email protected]> Patrol-Run: qwen-pr-closeout/jmvmqaysjth * fix(cli): bill /stats model per source bucket, not the model aggregate R2-1: `billableOutputTokens` is a clamp, so it is not additive -- f(sum of buckets) != sum of f(bucket). The three panel sites bill the per-(model, source) buckets that `flattenModelsBySource` renders, but `statsCommand.ts` billed the per-model aggregate, so the non-interactive `/stats model` figure could disagree with the panel and fall straight back into the double count this PR removes. Measured counterexample (two buckets of one model, output at $1/M): main {prompt:100000, candidates:150000, thoughts:120000, total:250000} -> f=150000 researcher {prompt:0, candidates:10000, thoughts:2000, total:52000} -> f=12000 sum of buckets = 162000 ($0.1620) <-- what the panel shows aggregate = {prompt:100000, candidates:160000, thoughts:122000, total:302000} f(aggregate) = 202000 ($0.2020) <-- what /stats model printed Sum the same buckets the panel renders. `Object.values(bySource)` with an aggregate fallback mirrors `flattenModelsBySource`, so the two surfaces stay equal in every case it distinguishes (empty bySource, main-only collapse, multi-source split). Adds one leg pinning it. Verified against three individually-applied mutants, each restored byte-identical afterwards (baseline 41 passed): M1 revert to f(aggregate) -> 1 failed ($0.1620 leg) M2 plain bucket candidates (R2-2) -> 1 failed ($0.1620 leg) M3 pre-PR candidates + thoughts -> 2 failed (both #15444 legs) Also normalizes one blank line in the merged item-projection.test.ts so the file is prettier-clean. Co-authored-by: Qwen-Coder <[email protected]> Patrol-Run: qwen-pr-closeout/jmvn35xgdtw * fix(cli): gate billableOutputTokens band on totalMissing to keep the derivation monotone When a telemetry bucket mixes events with and without total_tokens, the cumulative total lags behind prompt/candidates. The band [candidates, candidates+thoughts] could still admit the understated derived value, making the cost estimate go down after additional usage — turning a monotone quantity non-monotone. Track totalMissing at the accumulation site (uiTelemetry.ts:653-656) and gate the band on !totalMissing in billableOutputTokens. When a bucket saw any total-less event, fall back to candidates + thoughts rather than trusting a total that may be incomplete. * fix(cli): accumulate billable output per API response * fix(cli): preserve raw usage schema and verify zero-cost visibility --------- Co-authored-by: yiliang114 <[email protected]> Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
f28fa001ef |
fix(hosted): preserve primary MySQL isolation failures (#15505)
(cherry picked from commit
|
||
|
|
4339775208 |
fix(cli): preserve OpenTUI clipboard source across draft recovery (#15396)
* fix(cli): align OpenTUI cancellation and retry with Ink * fix(cli): discard abandoned OpenTUI tool attempts * feat(cli): preserve OpenTUI session replay and rewind * fix(cli): preserve checkpoint restore ownership and cold continuation * test(cli): cover committed conversation rewind across renderers * feat(cli): capture and restore OpenTUI checkpoints Candidate checkpoint before parent test integration; full normal and combined product validation are still pending. * test(cli): remove duplicate checkpoint regression declarations * fix(cli): preserve Ink compact tool summaries after restore * fix(cli): preserve OpenTUI clipboard source through draft recovery * test(cli): cover OpenTUI raw recall and framed Vim submissions * fix(ci): register clipboard regression in TUI parity gate * fix(cli): preserve logical restore identity across authorized edits * test(cli): assert saved restore call identity in permanent acceptance * test(cli): align native tool result provenance assertion |
||
|
|
b3b17eb572 | fix(web-shell): keep permission rule declarations self-contained (#15501) | ||
|
|
52b0574b25 |
test: capture expected disk-full logs (#8549)
* test: capture expected disk-full logs * test(acp): capture rewind persistence warnings --------- Co-authored-by: xingjianding1-collab <[email protected]> Co-authored-by: 易良 <[email protected]> |
||
|
|
15aae44b36 |
test(integration): pin removeScratchDir's retry budget with a witness (#15488)
removeScratchDir's rm() budget (maxRetries: 5 / retryDelay: 200) was unpinned: mutating it to 0 kept every test green, so a regression that removed retrying entirely would ship silently. The existing ENOTDIR case cannot catch it -- ENOTDIR is outside rm's retryable set -- and asserting only that the promise resolves is vacuous, because the catch swallows every rejection. Add a success-path case with a self-limiting straggler refill writer. Seeded entries widen the removal walk so a refill lands between readdir and rmdir (ENOTEMPTY, retryable), and the writer is capped by both a file ceiling and a wall-clock cutoff so it goes quiet well inside the shipped budget. The load-bearing assertions are that the tree is actually gone and that no warning was logged. Red witness: setting maxRetries to 0 in scratch-dir.ts fails this case on 2/2 runs while the ENOTDIR case still passes; scratch-dir.ts is restored byte-identical (md5 3cdb5f2f504ea6cc7663e2708ae133f4). Refs #11310 Patrol-Run: qwen-issue-patrol/jmvn0b1rrjt Co-authored-by: yiliang114 <[email protected]> Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
cf3ba47dfd |
fix(ci): file main CI failures whose successor has not settled (#15471)
* fix(ci): file main CI failures whose successor has not settled
The guard added in #15272 treats a queued or in-progress successor at
main's tip as owning the result, so the report is skipped. A successor
that later ends cancelled, timed_out or skipped never re-enters the
workflow — its gate admits only failures — so the failure is never
reported at all.
That is how 10 main-push failures between 14:00Z and 17:30Z on
2026-10-24 produced no issue (#15470), with 65 of the last 100 Qwen
Code CI push runs on main ending cancelled.
The reporter cannot wait for the successor either: it runs on
ubuntu-latest, and that pool queued it for 20-100 minutes in the same
window. Report instead, marked provisional, since the per-signature
route hands new issues to a human rather than to autofix: a stale
provisional report costs a close, a dropped one costs the regression.
* fix(ci): keep a provisional head off the infra rerun path
Four review findings on
|
||
|
|
1a98854b76 |
test(ci): pin the disk-pressure collector revision and FULL_PAYLOAD run bodies (#15475)
* test(ci): pin the disk-pressure collector revision and FULL_PAYLOAD run bodies Two deferred review findings from #10919 (issue #11032). Both are assertion-only: no workflow file is touched. The shared-prelude equality loop compares `test` and `lint_and_static` to each other, so both jobs' disk-pressure collector moving to a different `actions/upload-artifact` revision together leaves both serializations equal and reports green. The SHA-format regex on `Upload Test Results Artifact` is not a witness either: it accepts any 40-hex revision, on a different step. Pin the literal revision instead, resolved per job because the collector step carries the same name in both. The FULL_PAYLOAD test pinned name, order and gate, but only the two notices steps had a command body pinned: emptying `Run ESLint`'s `run:` or repointing it at `true` left every suite green while a required check stopped running the tool it is named for. Extend the existing loop with a name -> load-bearing-substring map that is total over FULL_PAYLOAD, and assert the substring rather than whitespace-exact text so reformatting one of the multi-line blocks stays benign. Verified by mutation in both directions. Against the pre-change suite, moving the collector pin in both jobs, emptying `Run ESLint` and repointing it at `true` all stayed green (44/44) -- that green was the defect. With these assertions the same three mutations fail, and the unmutated suite passes 45/45. Refs #11032 Co-authored-by: Qwen-Coder <[email protected]> Patrol-Run: qwen-issue-patrol/jmvmng32bjj * test(ci): pin collector retention, payload gates and failure propagation Addresses the four review findings on the pins this PR adds, all of them the same class of gap: an assertion that proves a string is present but not that the thing it guards still happens. R1-1: `with.retention-days` was unpinned on both disk-pressure collectors, so a coordinated edit reported green through the job-to-job equality loop (the loop is blind to both sides moving together). Pinned per job as the literal 14; the JUnit `Upload Test Results Artifact` step deliberately retains 7, so no shared constant. R1-2: map totality over FULL_PAYLOAD was only incidental — `toContain` coerces a missing entry to the literal string "undefined", which a body containing that word passes silently, and a stale key after a rename reads as coverage that no longer exists. Asserted the key sets match instead. R1-3: payload gates were filtered by a `ci_profile == 'full'` substring, so appending any further `&&` clause dropped a step from the unattended post-merge lane while every substring still matched. All 19 gates are byte-identical, so pin the whole literal. R1-4: containment proves the command is present, not that its failure reaches the job status. Pinned `continue-on-error` absent and no `|| true`/`|| :` in the body, plus `exit 1` in the settings-schema gate. Both stay inside the loop: `Report test growth` and `Fetch incremental lint history` set continue-on-error deliberately, and the helper-tests retry legitimately uses `|| {`. Each new assertion was shown to fail by mutating `.github/workflows/ci.yml` one edit at a time: the six gap mutants pass 45/45 against the previous head and each is killed by exactly the assertion added for it. The one-sided retention control still trips the pre-existing equality loop, so those greens were coordinated-edit blindness rather than a dead comparator. Co-authored-by: Qwen-Coder <[email protected]> Patrol-Run: qwen-pr-closeout/jmvmwqg38tp --------- Co-authored-by: yiliang114 <[email protected]> Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
c7c9717d07 |
fix(cli): run OpenTUI on private Bun 1.4.4 (#15387)
* fix(cli): run OpenTUI on private Bun 1.4.4 * docs(cli): bind runtime acceptance to integrated main * test(cli): add permanent installed npm runtime acceptance * ci: record installed TUI workflow size * ci: record installed TUI job budget * ci: quote missing installed artifact failure mode * fix(core): preserve encrypted storage identity across Bun handoff * fix(test): retain installed command startup evidence * fix(cli): reject Bun loader options during npm handoff |
||
|
|
17b8efa953 |
feat(cli): capture and restore complete OpenTUI checkpoints (#15389)
* fix(cli): align OpenTUI cancellation and retry with Ink * fix(cli): discard abandoned OpenTUI tool attempts * feat(cli): preserve OpenTUI session replay and rewind * fix(cli): preserve checkpoint restore ownership and cold continuation * test(cli): cover committed conversation rewind across renderers * feat(cli): capture and restore OpenTUI checkpoints Candidate checkpoint before parent test integration; full normal and combined product validation are still pending. * test(cli): remove duplicate checkpoint regression declarations * fix(cli): preserve Ink compact tool summaries after restore * fix(cli): preserve logical restore identity across authorized edits * test(cli): assert saved restore call identity in permanent acceptance * test(cli): align native tool result provenance assertion |
||
|
|
f520bac55c |
fix(cli): preserve checkpoint restore ownership and cold continuation (#15386)
* fix(cli): align OpenTUI cancellation and retry with Ink * fix(cli): discard abandoned OpenTUI tool attempts * feat(cli): preserve OpenTUI session replay and rewind * fix(cli): preserve checkpoint restore ownership and cold continuation * test(cli): cover committed conversation rewind across renderers * fix(cli): preserve logical restore identity across authorized edits * test(cli): assert saved restore call identity in permanent acceptance * test(cli): align native tool result provenance assertion |
||
|
|
b44e033315 |
feat(cli): preserve OpenTUI session replay and rewind (#15384)
* fix(cli): align OpenTUI cancellation and retry with Ink * fix(cli): discard abandoned OpenTUI tool attempts * feat(cli): preserve OpenTUI session replay and rewind * test(cli): cover committed conversation rewind across renderers * test(cli): align native tool result provenance assertion |