mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-11-07 06:19:43 -10:00
46d825d1150e647d9790b24b3425f47e4798e874
11736
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
46d825d115 |
Revert "fix(ci): isolate web-shell smoke from shared runner networks (#15886)" (#15961)
This reverts commit
|
||
|
|
66b5fe7f3c |
fix(managed-agent): tell a broker that cannot write apart from a wrong topic type (#15941)
* fix(managed-agent): tell a broker that cannot write apart from a wrong topic type The startup send probe reported every failure as a topic-type misconfiguration and named the mqadmin remedy. When a broker answered but refused the write itself — a full disk, a stopped store, an HA failover — an operator was told to reconfigure a topic that was already correct, with the real cause buried at the bottom of the chain. A type conflict arrives as a BadRequestException (40014/40020), while a broker-side write refusal arrives as an InternalErrorException (50000/50001/50002), so the exception type separates the two without parsing messages. Only the second case changes: it now leads with the broker's own inability to accept writes. Genuine misconfiguration keeps today's fail-fast wording, and the capability probe is untouched. Refs #15892 * fix(managed-agent): cover HA in the write-refusal hint and pin the exception mapping Review found that both branch tests construct their own exceptions, so neither pins the client's code-to-type mapping the branch selection depends on — while the description claimed the contrast test did. Add a contract test that drives the real StatusChecker over 40014/40020 versus 50000/50001/50002, so a client upgrade that remapped a type conflict onto InternalErrorException fails at unit speed instead of only at the real-broker gate. Asserting the wrong type for 40014 makes it fail, so the guard is not vacuous. Also widen the hint: InternalErrorException covers HA_NOT_AVAILABLE too, where naming only disk space and message store was narrower than the condition. It now names HA state as well. Refs #15892 * fix(managed-agent): name the persistence-timeout family in the write-refusal arm The arm caught only InternalErrorException, but the client reports a master or slave store timing out on the probe write as ProxyTimeoutException — a sibling under ClientException, not a subclass. So the stopped-store cause the comment itself lists still told an operator to run mqadmin updateTopic against a topic that was already LITE, which is the misdiagnosis this branch exists to remove. Catch both types; Java rejects parent/child alternatives in a multi-catch, so the fact that it compiles is itself proof they are siblings. UnsupportedException stays out deliberately: it collects REQUEST_TIMEOUT alongside NOT_IMPLEMENTED and UNSUPPORTED, mixing the unreachable question with the incapable-broker fail-fast, and a disk-space hint for either would trade one misdiagnosis for another. Also pin the whole operator hint, not just its first fragment. The write-refusal test asserted only "disk space", so trimming "message store and HA state" shipped green; both halves are now asserted, and the mapping contract test covers all eight codes the split depends on. Refs #15892 * fix(managed-agent): name the refusal families and stop overclaiming reachability Two more gaps in the same enumeration, both found by review with mutation witnesses. Throttling, lite-topic quota and ACL refusals are five more siblings under ClientException — TooManyRequests, LiteTopicQuotaExceeded, LiteSubscriptionQuotaExceeded, Unauthorized, Forbidden — so a rate limit or an exhausted quota still told an operator to run mqadmin updateTopic on a topic that was already LITE. 42901 is the sharpest case: the probe's lite topic exists, and an exhausted quota is not a missing one. They get their own arm pointing at quota, flow control and ACL state, which is a different thing to inspect than a disk or a store. The write-failure message also claimed the broker "is reachable", which 50400 PROXY_TIMEOUT does not establish: the proxy produces it from ACCESS_BROKER_TIMEOUT and RemotingTimeoutException, exactly when it got no answer from the broker. That overclaim came in with the previous widening. Drop it, name the proxy-to-broker path in the hint, and scope the comment so it no longer says the broker answered. UnsupportedException stays outside the arms deliberately, and the residual limit of enumerating families is now stated in the description rather than left implicit. The mapping contract test covers all thirteen codes. Refs #15892 |
||
|
|
b3e9ce0cd1 |
test(managed-agent): gate the A3 mixed-sibling approval crash window (#15945)
* test(managed-agent): gate the A3 mixed-sibling approval crash window Package the native half of recovery-matrix row A3 (#14481) as a hosted-failover-e2e arm: crash a replacement inside a two-call approval batch (sibling[0] decided, sibling[1] still requested) and prove the surviving siblings recover from MySQL alone — earlier decisions persist, the pending sibling keeps its original Action/deadline and earns its own Allow, and both calls settle once each in their original order. The rewritten-input / Hook-no-rerun half stays a commandStep follow-up because a native continuation refuses Hook/MCP sessions. * chore: re-trigger CI after the main merge The web 'Update branch' merge incorporated main's .prettierignore (lint gate freshness) but did not trigger a CI run on the updated head; this empty commit re-triggers the lanes on the merged tree. * test(managed-agent): harden the A3 arm per review (R1-1..R1-7) Address the seven inline review suggestions on the mixed-sibling approval arm: read the decided sibling and require it still decided with its original deadline before answering the pending one (R1-4); gate execution settle order on settled_at along the plan (R1-5); add an ascending-link behavioural case so a first-match plan-link selection reds (R1-6); anchor the execution-count pin and pin the per-call identity loop (R1-7). Correct the design docs in both languages: the fixture is two write_file calls, the validation plan lists the reds actually produced, and the arm proves matrix clauses 1-2 plus a narrower pending-sibling observation, not the rewritten-input clause 3 (R1-1/R1-2/R1-3). |
||
|
|
6519110be5 |
refactor(managed-agent): converge session creation onto SessionCreationCommand (#15955)
Collapse the nine insertWorkspaceSessionCommand overloads in AgentStateStore and ManagedAgentStore into a single method taking a named SessionCreationCommand record, with a per-component builder so call sites construct by name instead of position. The interface default now fails closed for implementations that have not opted into workspace creation; the store method body is unchanged behind a record destructure. Migrate the production caller and all 133 test call sites, re-pin the transaction-boundary and fail-closed tests, and add a contract pin that ratchets the creation entry to exactly one. Implements the P0 overload convergence of the structure review design, including the named-construction builder decision; role-interface segregation follows as a separate slice. Public API, schema, and byte-level protocol semantics are untouched. |
||
|
|
10b48ab972 |
fix(verify-pr): run the artifact check in the CI publisher (#15938)
* fix(verify-pr): run the artifact check in the CI publisher The CI publisher validated only the assertion count triple. The failure ledger and the per-commit mutation claim were checked by verify-pr-check.mjs, which local rounds run before posting and CI never did, so the sandboxed lane could publish shapes every local round refuses. The publisher now runs that checker from its trusted checkout; a refusal, or a checker that cannot run, leaves the agent verdict untrusted and the comment says why. A trusted findings verdict with no failed assertion is now published as "passed with findings" instead of "not passed". Over the last 30 days, 94 of 150 published findings reports had zero failed assertions, and the reports among the latest 18 run artifacts that hit this case all described their findings as non-blocking. The skill now states the counting rule that headline relies on: a defect reproduced at head is a failed assertion attributed to the PR, not an expected-red pass. * fix(verify-pr): bind the headline to the checked report directory The report and the assertion counts were picked by two independent finds, so a run that left an earlier round directory holding only assertions.json could headline a later report with that directory's zero: "passed with findings" over a report whose own counts carry a PR-attributed failure. The counts now come from the report's own directory when there is a report, and the checker must read the same verdict the run reported beside that report; a mismatch is a refusal. A test now runs the checker through its relative production path and pins the checkout layout that path relies on, since every other case injects an absolute path. The comments added to the triage workflow are trimmed, and its size baseline moves to 370027 bytes: the remaining growth is the checker wiring and its bilingual explanation in the comment body, which the job has no sibling script or document to hold. * fix(verify-pr): read only the checker summary and say which check failed The publisher matched the reported verdict anywhere in the checker log, and the warnings above the summary can spell out an agent-chosen evidence filename, so it now reads only the last stdout line. Node's own errors go to a separate stream that the publisher prints when the checker cannot run. Warnings are still never printed, and a test now pins that. The untrusted-verdict paragraph pointed every state at "errors in the run log", which two of the three states never print. A refusal still points at its errors; a verdict that differs from the one beside the report, and a checker that could not run, each get a sentence of their own. The publisher checks out scripts/lib/ as a directory instead of naming one helper. The production-path test runs the checker from exactly the paths that checkout fetches, so an import outside them fails the suite whatever form it takes. That replaces the import-list check, which could not see side-effect imports. The local-round design record no longer says the checker merely mirrors the publisher, in either language. The size baseline moves to the file's new size, 370588 bytes. * fix(verify-pr): read the verdict from the report's own directory The verify job picks the agent verdict by its own search, which can land on a leftover round directory holding only verdict.txt while the report comes from a later, complete one. The previous fix flagged that as a mismatch, blaming a verdict file that was consistent with its own report. The publisher now reads the verdict from the report's directory itself, with the same four-word allowlist, so the report, the counts and the verdict always come from one round, and the mismatch state is gone. The vocabulary pin now covers both places the step spells out the four words: the allowlist and the headline labels. The Chinese note for a checker that cannot run is asserted too. The design record no longer promises that every checker rule change reaches CI in the same commit, since the publish step still validates the count triple and refuses merge-ready over failures on its own. Decision 4 now rests on the reason that still holds: legitimate rounds can lack a screenshot or a cited head. Both languages changed together. * fix(verify-pr): read verdict.txt once, beside the published report The verify job read its own copy of verdict.txt from whichever round directory its search found first, emitted it as agent_verdict, and wrote it to its step summary, while the publisher read the word again from the report's directory. With a leftover round directory the two could name different verdicts in the same run. Drop the verify job's reader and its output so the publisher is the only reader, and: - warn when the report's directory has no usable verdict.txt instead of blanking the word silently; - bound the report search to depth 2 so a report.md nested in a round cannot stand in for the round's own; - drop the unreachable "report.md missing" warning. Tests pin the single reader, the report-only round (no borrowed counts or word), the nested report, and blocked staying not-passed over an all-green ledger. The skill's harness-fault rule now states what CI actually publishes for findings over non-PR failures. |
||
|
|
bd0950774e |
feat(web-shell): open context memory files from the usage panel (#15932)
* feat(web-shell): open context memory files from the usage panel The right-hand Context Usage panel listed the instruction files loaded into the model (AGENTS.md, QWEN.md) as plain text, so reading one meant leaving the panel and opening the file elsewhere. Make those rows clickable: clicking opens the file in a read-only artifact preview. The context detail only carried a display label, which a client cannot resolve back to a real path (it has no home directory, and synthetic aggregates share the same shape). Add an optional absolutePath to the memory detail across the CLI, bridge and SDK types; the parser already computes it, so real file rows now carry it while synthetic aggregates do not. The panel opens a row only when it has an absolute path, reading through the memory route so global files outside the bound workspace open too. Cover the clickable rendering with unit tests and add a visual e2e that opens AGENTS.md from the panel and captures the preview. * fix(web-shell): open context files through their owning workspace Address two review findings on the instruction-file preview. The opener read through the primary-bound memory hook, so a file owned by a registered secondary workspace was rejected by the primary sandbox. Resolve the session's owning workspace from the context panel's workspace cwd and read through its qualified file route, never the primary; the read logic moves into a unit-tested readContextInstructionFile helper. An absolute path also does not mean the preview can read the file: hierarchical parent-directory instructions and extension context files live outside both the workspace file route and the memory route's discovery. Only emit absolutePath for files the preview can open (inside the session workspace, or a global memory file at the global dir root), so unsupported rows stay non-interactive instead of failing on click. Add regression tests for the secondary-workspace read path and for the readable-scope gate (subdirectory session with a parent instruction file and an extension context file). * fix(web-shell): resolve context file owner from the admission workspace A session that enters a worktree or cds into a subdirectory keeps its registered workspace root, but its live target dir moves. The context panel resolved the file owner from the live cwd, which no longer matches the registered root exactly, so every instruction-file click in such a session was rejected before any request. Carry the stable admission workspace root in the context-usage status (from the admission-bound storage project root, separate from the live workspaceCwd) and resolve the owner from it, falling back to the live cwd for older daemons. Secondary workspaces keep their own admission root, so the read still uses their qualified route rather than the primary. Add regressions for a registered repo with a worktree instruction file (helper opens it through the registered root and rejects the live worktree cwd) and for the panel passing the admission root to the opener. * fix(web-shell): align context file preview scope with the admission root Address nine review suggestions on the instruction-file preview. Gate openable paths on the session's admission root (the same root the client resolves the owner from), not the live working dir, so a session that cd'd into a subdirectory still opens the root's own instruction file and never offers a file outside the admission root. Normalize the global memory directory comparison so a trailing separator in QWEN_HOME does not disable the global row. In the reader, handle a filesystem-root workspace in the containment check, propagate the truncation flag (the opener now warns when a preview is partial), and distinguish a listed memory file whose text is withheld (non-UTF-8) from a path the route does not list. Wire the opener through the transcript path so context breakdowns in the chat history open files like the side panel does, and drop the dead memory-route mock from the visual test. Add regressions: the admission-root gate and trailing-separator global row, the workspaceRoot producer and the older-daemon fallback, the root-workspace read, truncation and encoding errors, and the transcript opener wiring. |
||
|
|
3df7f9ce83 |
feat(web-shell): keep skill argument hints visible while typing arguments (#15930)
* feat(web-shell): keep skill argument hints visible while typing arguments
The inline argument hint for skill slash commands disappeared as soon as any argument text was typed, leaving no guidance for the remaining flags (e.g. /verify-pr <pr-number> [--publish] [--watch] ...).
Parse the skill's argument hint into placeholder/flag/literal tokens and consume them as the user types, showing only the parts not yet provided. Matching is order-independent, keeps a flag visible while it is being typed, surfaces a missing flag value, and prefers literal mode branches for hints with top-level alternatives. Built-in commands keep their existing subcommand-driven behavior; unknown or fully consumed arguments hide the hint as before.
* fix(web-shell): recognize live-session skill sources and tighten hint matching
Review follow-up on the progressive skill argument hints:
- Recognize the loader sources live sessions actually send ('skill-dir-command', 'bundled-skill') in addition to the pre-session 'skill' label, so the hints survive session attachment. Covered by a mapper-to-editor regression with a real EditorView for project and bundled skills.
- Render a just-typed flag's missing value before the remaining arguments, matching what the matcher consumes next.
- Only accept an unfinished flag prefix as the trailing token; a prefix followed by more words is a completed, unmatchable argument and hides the hint.
- Drop the unreachable empty-args guard flagged in review.
* fix(web-shell): cover extension skills in progressive argument hints
Extension skills arrive from live sessions with the shared 'plugin-command' source label, so the source-only classification lost their progressive hints after session attachment. Treat session skill membership (availableSkills) as authoritative: the composer now feeds the skill list into the input highlight extension, and the hint matcher recognizes members regardless of source label while ordinary plugin commands keep their existing behavior.
Extends the mapper-to-editor regression with an extension-provided skill and an ordinary plugin-command control.
* fix(web-shell): consume flags typed after free text and pin the malformed-hint fallback
Free-text placeholders absorbed the whole typed tail, so a flag entered after the prose was still advertised as missing (and the same words in flag-first order hid the hint). Free text now absorbs only prose words and hands flag-looking words back to the normal flag path, restoring order independence and the unmatchable-hides rule.
Tighten the malformed-hint regression from a type tautology to asserting the hint actually hides, including the empty-group shape.
* fix(web-shell): drop empty hint groups so malformed metadata cannot echo
The R1-2 witness still reproduced: with argument-hint '[] []', typing one word consumed the first empty group and rendered the second as a leftover '[]' hint. Empty bracket groups are malformed skill metadata, so they are now dropped during tokenization and can never survive as renderable remainder.
Pin the original witness ('[] []' with '/demo x' hides) as its own regression, independent of the unknown-flag path the tightened loop happened to exercise.
* fix(web-shell): hide whitespace-only empty hint groups and pin the skills wiring
The empty-group filter only matched the literal '[]' and '<>' shapes, so whitespace-only groups like '[ ] [ ]' still echoed a leftover token after an argument was typed. Drop any bracket group whose inner text trims to empty, and pin the whitespace witnesses as their own regressions.
Add a composer-level DOM test for the skills accessor feeding the input highlight: an extension skill listed in the session skills renders its progressive hint, the same command without membership does not. Mutating the accessor to a constant empty list kills the new case while the parser-level suites stay green.
Also reword the source-set comment: 'skill-dir-command' labels custom markdown commands too, so the set selects the free-form hint path rather than strictly skill-backed commands.
|
||
|
|
0644fcf7ab |
feat(autofix-pr): add --in-place co-driving mode (#15929)
When the session sits in the user's own checkout of a PR's head branch, /autofix-pr --in-place fixes the PR right there: the fix agent works in the foreground under the session's approval mode, the user watches and edits alongside, and the round pushes what the branch holds — the user's commits included. The worktree mode's destructive lifecycle becomes refuse-and-ask: sync never discards or resets the checkout, requireWorktree never switches the user's branch back, and cleanup removes only the watch's own files (state, tmp artifacts, the private head ref), keeping the checkout, the branch and the history. Entry is a narrow checked seam (head branch checked out, clean, at or behind the PR head, named-remote upstream, daemon session at the checkout root), and an in-place watch is once-shaped: no scheduled task, no background fix, no unattended grant. The PR head is fetched into a private ref outside refs/heads rather than the shared FETCH_HEAD, which concurrent fetches in the user's checkout rewrite; the dirty check reads NUL-delimited porcelain so C-quoted watch files cannot masquerade as user work; the classic prepare re-checks the mode under the watch lock so a racing in-place start cannot be silently converted; and the autofix_pr tool derives the reply-plan directory from the watch's .qwen/tmp so in-place replies reach the PR. Design: docs/design/2026-10-30-autofix-pr-in-place-copilot.md (English) and docs/design/2026-10-30-autofix-pr-in-place-copilot.zh-CN.md (Chinese), proposed and implemented in this change. |
||
|
|
1ccf0d43f3 |
docs(managed-agent): organize the deployment guide in three tiers (#15944)
* docs(managed-agent): organize the deployment guide in three tiers The guide ran its steps in the order they were written rather than the order a first deployment needs them: it exported the credentials by hand before introducing the bootstrap that generates them, never said how the Harness gets a model, and stopped at a healthy actuator without running a Session. It now opens with a choice of tier, each adding to the one before: text-only Hosted Sessions, local-process tools, and Kubernetes through the Helm chart. Tier 1 runs in order: verify, bootstrap, start the Harness with harness.env and a model, preflight with server.env loaded, start the control plane, and complete a first Session with curl. Tier 2 is the tool-path section, Tier 3 points at deploy/kubernetes, and the maintenance, upgrade, key rotation and recovery sections move under "Operate the deployment". Their text is unchanged, as is the anchor the key-rotation design links to. * docs(managed-agent): make the first-Session check repeatable and page its events A check repeated after an upgrade with the same Idempotency-Key replays the old Session and its old turn.completed, so it passes even when the new Harness cannot run a Turn. The example now makes a key per check and says to reuse it only to retry that request. The events endpoint returns at most `limit` events after `after`, so polling the first page again never reaches a terminal event beyond it. The step now says to advance `after` to the last event's sequence. |
||
|
|
de49b34c70 |
docs(managed-agent): add structure review and refactor proposal (#15942)
* docs(managed-agent): add structure review and refactor proposal Capture the measured structural state of the Managed Agent server and propose spending the pre-release contracts window on collapsing the session-creation overload chain into a SessionCreationCommand record, followed by slicing the two god classes along aggregate and concern lines. Bilingual design pair; no code change. * docs(managed-agent): correct the controller count in the structure review The API package holds 30 classes but only 23 are controllers; all 187 HTTP mappings sit on those controllers. Found by the post-publication adversarial audit; both language versions updated together. * docs(managed-agent): address review on record scope and Duration units Three review findings, fixed in both languages: the bare record keeps a positional canonical constructor and breaks constructor compatibility on every new component, so P0 now explicitly scopes itself to store-overload convergence with a named-construction builder as an open decision; the Duration item is rescoped because per-field units are a pinned, security-relevant binding contract, making unification a separate behavior-change proposal; the annotation count is corrected from 40 to 36 (the earlier grep counted the import and code references). |
||
|
|
e7fe14ee83 |
docs(managed-agent): generate the server configuration reference from its metadata (#15939)
* docs(managed-agent): generate the server configuration reference from its metadata
The server has about 180 settings, 84 of them mapped to QWEN_MANAGED_AGENT_*
variables, and no list of them with their variables, defaults and limits:
operators read a 2000-line developer README for them.
- The server module runs spring-boot-configuration-processor once more,
over ManagedAgentProperties only (the two Druid beans share a prefix,
which the processor refuses), and writes the configuration metadata.
The compiled classes are unchanged. runtime-broker.ssh is marked
@NestedConfigurationProperty, and STRICT_HARNESS_KEYS @Getter(NONE), so
the metadata lists the one and not the other.
- configuration-descriptions.json holds an English and a Chinese
description for each setting and section.
- scripts/generate-managed-agent-configuration-reference.mjs writes
docs/users/managed-agent-configuration-reference{,.zh-CN}.md from the
metadata, the packaged application.yml (variables and defaults), the
${qwen.managed-agent.*} placeholders in the main sources (settings read
outside the properties class) and the descriptions. --check fails on a
setting without a description, a description of no setting, or a stale
page; the reference workflow runs it after the Java build.
- The archive ships the pages as docs/configuration{,.zh-CN}.md, and the
deployment guide and the README link them.
* fix(managed-agent): link the shipped documents by their archive names
The archive renames each document it ships, so a link written against
the repository, such as the configuration reference's language switch or
the guide's link to it, named a file the archive does not have. The
packager now points every link between shipped documents at the
document's name in the archive and leaves every other link as written.
* build(managed-agent): take the configuration processor's version from the BOM
spring-boot.version is defined nowhere in this build, so the processor
path's <version> only resolved because the compiler plugin falls back to
dependency management. Say so by naming no version.
* test(managed-agent): name no tracked Markdown in a link fixture
classify-profile.test.mjs requires every Markdown file a test names to be
in TEST_READ_MARKDOWN, and the kept-link fixture's docs/runtime-broker.md
matched packages/managed-agent-server/docs/runtime-broker.md, which no
test reads. The fixture only needs a link to a file the archive does not
ship, so it names one that does not exist.
|
||
|
|
9ebd2de171 |
feat(managed): add experimental Kubernetes deployment (#15492)
* feat(managed): add experimental Kubernetes Helm deployment * feat(managed): add trusted-node tools and dedicated WebShell gateway * test(web-shell): isolate Managed gateway in boot tests * docs(managed): clarify Kubernetes gateway requirements * fix(managed): align Helm workspace identity with runtime broker * fix(web-shell): keep managed permission rules key distinct * fix(managed): align Helm lint and web test boundaries * codex: address PR review feedback (#15492) |
||
|
|
0c1b42fa31 |
test(managed-agent): gate the B3a finished-before-commit crash window (#15881)
* test(managed-agent): gate the B3a finished-before-commit crash window Package the recovery-matrix B3a row: crash the replacement Harness after its post-tool main stream records the durable Finished marker but before the assistant output commits. A test-gated hook (QWEN_E2E_CRASH_BEFORE_ASSISTANT_COMMIT, set only on the crashing generation, never in production) holds the turn in that window; the runner asserts the barrier landed, kills the generation, and requires the next one to reissue the saved request deep-equal and project one terminal with the recovered answer rather than compensate an already-committed output. Adds the failover arm, CI step and ceiling (25 arms), contract pins, the serve env-guard allowance, and bilingual design/README updates. * test(managed-agent): harden the B3a arm barrier, hold and contract pins Address review R1-1..R1-4: assert the durable crash precondition (the approved execution SETTLED) from MySQL before the SIGKILL like the sibling crash arms, instead of trusting the hook log alone; wire the test-gated hold to the Turn abort signal so a leaked flag cannot park a real Session uncancellably; pin the crashing/recovery generation call sites and the parameter default rather than bare identifiers; and pin the combined deep-equal parity gate so reverting it to after-result-only reds the fast-tier contract suite. * test(managed-agent): assert the B3a crash window from the durable journal The finished-before-commit barrier proved only that the approved execution settled (executionAtCrash=SETTLED) and that the hook printed its log line. It did not read the post-tool main model attempt's durable Finished marker, so a hold moved above the model layer's usage-only output_committed commit could crash with no durable Finished marker and still pass every downstream check (the recovery reader also accepts a saved request whose attempt is started). Before the SIGKILL, read the same journal the recovery reads (ma_session_journal_tx) and assert findHostedCommittedModelOutput's own discriminator: the latest <promptId>:main: model.attempt is output_committed and no assistant message.committed follows it. Retain the attempt identity and sequence in approval-crash-barrier.json. Add a window-shaped fast-tier contract pin for the new assertion, keeping the existing pins. Verified on real MySQL/Spring/Broker: head green (attempt retained, parity equal); moving the hold above output_committed reds at the new pre-crash assertion; removing the hook still reds at the barrier timeout; moving the hook after the assistant commit now reds at the new post-commit assertion. * test(cli): cover the finished-before-commit hold's abort release The QWEN_E2E_CRASH_BEFORE_ASSISTANT_COMMIT hold's abort wiring had no test that reds without it: the env-guard only counts AST reads, the meta-tests grep source text, and the packaged arm SIGKILLs the pending generation, so no lane exercised the release path. Arm the module-scope switch via a vi.hoisted env stub set before the static import under a dedicated Session id, then drive a real turn into the hold and assert the abort settles it cancelled with no assistant message.committed; a non-matching-id case pins that the hold never fires. Removing the release/addEventListener wiring makes the matching case time out. Test-only; the single env read and the hold's park-until-killed behaviour are unchanged. * test(managed-agent): pin the B3a hold id-guard and window arming R4-1: run the non-matching finished-before-commit hold case before the abort case so the module-scope one-way latch is still unset, letting the session-id comparison (not a spent latch) suppress the hold. Deleting the id conjunct now reds the non-matching case. R4-2: pin the finishedBeforeCommitWindow arming ternary condition, so narrowing its guard can no longer silently delete the arm's only durable-window check while the scripts suite stays green. * test(managed-agent): exercise the B3a window helper on injected journal rows Address the round-5 deferred suggestion: finishedBeforeCommitWindow had only source-spelling pins. Add a behavioural test that injects runMysql through the existing load() machinery and asserts the latest-attempt selection and both throw branches on journal rows (the output_committed window holds; a started or newer-started latest attempt reds before the Finished marker; a following assistant commit reds after it; role/prompt/sequence filters hold). Witness: mutating the latest-attempt index to mainAttempts[0] — a change the source pins survive — reds the behavioural test. |
||
|
|
6e0145bfad |
feat(autofix-pr): merge a stale base before fixing red checks (#15922)
* feat(autofix-pr): merge a stale base before fixing red checks A PR can fail CI purely because its base is stale: main already carries the fix (a dependency bump, a corrected test, a renamed symbol) that the branch has not merged. The watch had no way to see this — a stale-base failure was classified as outside the PR, re-run once, and handed to a human while the branch stayed behind. The CI-side fleet workflow already merges main in for this case; the local skill did not. A round snapshot now asks GitHub's compare endpoint, lazily and only when a check already failed, whether the branch is behind its base, and marks the snapshot with baseBehind. The brief tells the fix agent to merge the base first in that case, reusing the conflict recipe and the existing push path; a failure the merge fixed needs no code change, and the rest go through the usual failed-check classification. The gate probe is untouched, no new GitHub write surface is added, and repetition is bounded by the existing per-attempt reporting: a successful merge makes the branch contain its base, and a failed attempt is answered and suppressed on that head. Verified with focused unit tests (compare semantics, flag conditions, gate and lagging exemptions, degraded reads), the skill text pins, a full build and typecheck, and a read-only prepare/snapshot/cleanup run against a real behind PR with red checks. * fix(autofix-pr): exempt the brief's named fields from the Events scoping The verification round's single PR-attributed failure (F1): the brief's Events block ended with "Nothing else in that file is yours to act on" while the new stale-base bullet instructs the fix agent to act on baseBehind, a top-level snapshot field outside events. Since the prose is the hint's only delivery mechanism, the contradiction is the feature's single point of failure. The scoping sentence now exempts the fields the instructions name, and a consistency pin in the skill suite goes red if the exemption or the field bullet is ever removed alone. Also answers the round's coverage suggestions: three fixtures for the load-bearing guards the author suite had collapsed (a resync round with a failed check, a round whose only item is a conflict or a trusted comment, and a round standing on the watch's own pushed head), each asserting the events are really present so none can pass vacuously; and the design now prices the compare read's inherited transient-error retry (about nine seconds on a 5xx before the round goes on without the hint) in both languages. --------- Co-authored-by: verify-rig <[email protected]> |
||
|
|
dd1520729b |
fix(cli): finish the settle-budget rename in hosted harness tests (#15935)
#14752 introduced the per-test shared settle deadline and converted 251 waits to settleTimeoutMs(), but left 25 reads of the removed SETTLE_TIMEOUT_MS constant in hosted-harness-session.test.ts. The cli build typechecks test sources, so every workspace build/install lane fails with TS2552 and main's own CI is red. Replace exactly those 25 reads with settleTimeoutMs() calls — the form the design document prescribes and the 251 sibling waits already use. Test-only: no assertion, ceiling, or product change. Clean tsc --build: 25 errors -> 0. Affected suites: 692/692 passed (hosted-harness-session + settle-timeout). |
||
|
|
dba7d065ce |
feat(web-shell): expose archived export and restore inline (#15872)
* feat(web-shell): expose archived export and restore inline * test(web-shell): use inline restore in standalone E2E |
||
|
|
6e0220f839 |
fix(cli): show million-token counts in millions in /context (#13237)
* fix(cli): show million-token counts in millions in /context * test(cli): pin the /context million cutoff from both sides * test(cli): check /context million scaling beyond the boundary |
||
|
|
57d9a8fb50 |
fix(web-shell): wrap long lines in tool-card diff instead of per-line scrollbars (#13272)
Co-authored-by: ifan855 <[email protected]> Co-authored-by: Shaojin Wen <[email protected]> |
||
|
|
03bc0a56a4 |
fix(memory): report omitted index entries at write time (#14937)
* fix(memory): report index omissions at write time * test(memory): keep the omission regression independent of new exports * fix(memory): attribute size pressure only to budget candidates * fix(memory): match omission advice to the active limit * fix(memory): align omission remedies and compatibility rebuilds * fix(memory): attribute index overflow to causal excess * fix(memory): correct cumulative index overflow advice --------- Co-authored-by: Shaojin Wen <[email protected]> |
||
|
|
6d50e88870 |
fix(sessions): explain messaging suppression across guidance surfaces (#13948)
* fix(sessions): explain messaging suppression across guidance surfaces * fix: address review feedback for #13948 * fix: follow up review findings for #13948 * docs(sessions): correct peer lookup rationale and verification guidance --------- Co-authored-by: Zhangchenhao-111 <[email protected]> Co-authored-by: Shaojin Wen <[email protected]> |
||
|
|
5f5664e596 |
test(managed): treat targeted cleanup loads as non-resuming recovery (#15926)
The crash audit classified every post-failure cleanup load as a failed cancellation takeover because cleanup names a prompt other than the client prompt. Both cleanup branches return before any resume, so a targeted cleanup is a non-resuming recovery mode; keep requiring at least one accepted cancellation takeover. Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
e8e8e34ff4 |
fix(core): stop the session LSP client on Config shutdown (#14778)
* fix(core): stop the session LSP client on Config shutdown
Config.shutdown() never stopped the session's LSP client:
shutdownResourcesOnce() cleaned up the skill manager, tool registry and
registries but never touched this.lspClient, the LspClient interface had
no stop/dispose member, and NativeLspService.stop() had no production
caller. In the ACP/daemon shape each newSession builds its own
LspServerManager with language-server subprocesses, so every closed
session leaked its servers until the host child exited.
Add optional stop() to LspClient, implement it in NativeLspClient by
delegating to NativeLspService.stop(), and await it first in the
initialized cleanup block of shutdownResourcesOnce so a sibling cleanup
failure cannot strand the subprocesses. reinitializeLsp() is untouched.
Fixes #14751
* test(cli): boot the agent with an inner config in the lsp cleanup test
The live-session describe's bootAgent takes the inner config argument;
the zero-arg call failed tsc on CI (TS2554).
* test(cli): warm tools leniently in the lsp cleanup test
The CI run on
|
||
|
|
4e05e69637 |
fix(web-shell): prune split panes whose session left the active catalog (#14577)
* fix(web-shell): treat archived-session 409 as terminal in DaemonSessionProvider
The daemon answers 409 {code: 'session_archived'} for every active-route load/resume/attach of an archived session, but 409 is not in TERMINAL_SESSION_HTTP_STATUSES (401/403/404/410), so the provider retried forever with growing backoff and parked on a silent empty transcript.
isTerminalSessionHttpError now returns true for 409 with a session_archived body code; a plain 409 (session-writer conflict) stays retriable because it can clear on its own.
* fix(web-shell): prune split panes whose session left the active catalog
A pane whose session was archived (or deleted) kept re-seeding the stale id from the persisted pane set on every entry into the split view, and with the provider parking silently the pane looked permanently empty.
SplitView now reconciles its live pane set with the settled active catalog (and, on a multi-workspace daemon, waits for the other-workspace lists to settle too): stale panes are probed as standalone sessions first - a live standalone pane, or any transient probe failure, survives - and only a confirmed not-found or vanished session is removed. Pruning goes through onPanesChange (controlled) or setPaneIds (uncontrolled) against the freshest pane/catalog refs, so a re-unarchived session survives the round trip. useOtherWorkspaceSessions gains a loading flag for the settle wait.
* fix(web-shell): prune split panes only from a proven-complete catalog
Address the review round on #14577: the pane reconcile read absence from
an incomplete catalog as proof a session is gone, and its async
read-modify-write ran against a pane-set mirror that lags the controlled
prop.
- Read truncated / nextCursor / liveMergeFailed off the settled primary
page and refuse to prune from a page the daemon did not vouch for as
complete. The useScopedSessions scoped branch now carries the same
markers so a workspace-locked split call site can read them off the
union (TS2339 otherwise).
- useOtherWorkspaceSessions: `loading` is in-flight only (a failed first
fetch no longer pins it forever); new `degraded` reports a
landed-with-error list and an unqueried (untrusted) non-primary
workspace, which the prune also waits for.
- Never prune the current session — archiving it keeps its pane showing
the provider's terminal error instead of closing the pane the user is
looking at (a scheduled_task-bound current session can never appear in
the sourceType:'default' page, so pruning it would bounce the user out
of the split).
- Read the prop-derived pane set in controlled mode (a stale state mirror
resurrected a pane the parent just closed); record definitive probe
verdicts (alive / absent) so a kept-but-stale pane is not re-probed on
every catalog commit.
- Keep title/workspace resolvable for panes a guard keeps (last-seen map)
so a pane whose workspace flips untrusted does not remount under the
primary workspace.
- 10 new pinning tests (9 SplitView + 1 hook) and 2 existing cases
adapted to the never-prune-current design; every new assertion is
proven RED against a named mutant (12/12 killed, 0 survived).
* fix(web-shell): prune split panes only from per-cwd proven-complete coverage
R2 fix round for #14576: readiness is positive proof per cwd, not a
fan-out-wide gate.
- useOtherWorkspaceSessions: report queriedCwds/notReadyCwds per
workspace (a page only proves absence when it landed fresh, complete
and not stale-retained); a disabled fan-out certifies nothing
- useScopedSessions / session-catalog-hooks: forward nextCursor,
truncated, liveMergeFailed and stale-retained markers off the scoped
and primary branches
- SplitView: prune only panes whose cwd is proven (primary page
fresh+complete, or a fan-out cwd with a ready page); panes in
unproven cwds become probe candidates, never direct prunes
- TerminalArchivedReporter: per-pane prune signal while the primary
page is incomplete (provider parked on 409 session_archived)
- probe verdicts: join in-flight probes, cache deterministic 409
standalone_session_conflict, re-probe after transient failures
- pane identity from last-seen summaries (title + data-session-details)
- single derived paneIds set (prop-derived in controlled mode)
* test(web-shell): fresh-cwd store fixtures and acked prune report in tests
The scoped-sessions suite shares one catalog store (module-level client
mock), so the marker/stale-retained cases must use cwd no earlier test
cached; the controlled composite case must re-render with the parent-
acked pane set before asserting titles and session details; the
never-landed case learns b1 cwd from a first ready page, since a
cold-mount pane with an unknown cwd is a probe candidate by design.
* style(web-shell): apply prettier formatting to split-view prune fix files
* fix(web-shell): act on a pane's own archived answer and harden the prune probe
Round-4 review fixes for #14576.
- The provider now publishes a structured `sessionArchived` flag when it
parks on the terminal 409 session_archived answer (status
`disconnected`, `error` a display string). The per-pane reporter reads
that flag; it previously required `status: 'error'` and a
DaemonHttpError instance, a shape the provider never emits, so the
fallback never fired outside tests.
- A pane's own terminal answer prunes it on a complete page as well,
ahead of the probe-verdict cache, so a cached `alive` cannot keep it.
- The seed pane keeps its prune exemption and its workspace through the
park: the provider clears `connection.sessionId`, so the exemption is
keyed on the last defined current-session id.
- Probe: an archived standalone session (200 with `isArchived`, or 409
session_archived) is pruned like a not-found; a conflict marked
`retryable` (pending deletion journal) caches nothing.
- A pane of unknown workspace is settled only while every fan-out
workspace can prove absence: the probe's not-found also answers for a
live workspace session.
- Drop the unread `degraded` field from the fan-out hook (`notReadyCwds`
is the single readiness signal).
- Tests: the useSession mock emits the real parked shape; terminal
fallback across every incomplete-page signal, uncontrolled mode,
un-park, current-session park and seed workspace; unknown-workspace
panes per page-completeness arm; stale-without-error at the primary
passthrough, the fan-out and SplitView; catalog-listed panes are never
probed; duplicate fan-out not-ready cases collapsed into one.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---------
Co-authored-by: Сергей Панченко <[email protected]>
Co-authored-by: Shaojin Wen <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
|
||
|
|
4bd9ed0143 | fix(cli): share hosted harness deadlines and bail after CI retries (#14752) | ||
|
|
ad21b1f7a0 |
fix(core): retry bodyless 400 responses instead of treating them as fail-fast (#15821)
* fix(core): retry bodyless 400 responses instead of treating them as fail-fast * fix(core): retry bodyless 4xx when the SDK stamps a request id Address maintainer findings on PR #15821: register empty-body-4xx in the diagnostic allowlist (F2) and classify a bodyless 4xx as retryable even when the OpenAI SDK stamps an x-request-id that sets providerMessage to the marker text (F1), while a genuine provider code/type still fails fast. Tests: 79/79. --------- Co-authored-by: Andrea Bruno <[email protected]> |
||
|
|
4dab368387 |
fix(core): skip memory imports of files already loaded as context files (#15687)
An @import whose target is another top-level context file (for example CLAUDE.md containing @AGENTS.md) no longer expands that file a second time. The set of top-level files is built before the parallel reads, so the top-level copy always wins regardless of batch order. Fixes #15679 Co-authored-by: tneemo <[email protected]> Co-authored-by: Shaojin Wen <[email protected]> |
||
|
|
1dbe26a97d |
fix(cli): separate instruction files from auto memory in context usage (#15863)
* fix(cli): separate instruction files from auto memory in context usage * fix(cli): complete context usage translations and guards * test(cli): guard split context usage rows and accounting * test(cli): cover clamped context details and legacy snapshots |
||
|
|
318babe4d7 | fix(ci): weight PR owner assignment by open issue load (#15194) | ||
|
|
504556b6a9 |
ci(e2e): time-box the artifact download retry and the two uncapped legs (#15917)
Each leg downloads the shared build archive twice: once, and again from the retry that only fires when the first attempt failed. Only the first attempt carried timeout-minutes, so a retry that stalls held its runner with no ceiling at all — up to GitHub's 360-minute default. Run 37119220504 (#13284) already showed both attempts lost inside one window on a macOS shard while its sibling downloaded the same artifact. Two limbs: - Give the four 'Download build artifact (retry)' steps timeout-minutes: 10. The value is not new: the four first-attempt downloads in the same jobs already pin 10. - Give e2e-test-macos and isolated-nightly a job-level timeout-minutes: 60. The two other artifact-consuming legs (e2e-test-linux, e2e-interactive-opentui) already use 60, and 60 is also the ceiling the shard-retry budget gate in run-e2e-tests.sh takes its 25-minute reserve out of. `build` keeps its own 30 — it produces the archive rather than consuming it. web-shell-browser-regression has the same missing job ceiling but is left alone: it is outside this finding's scope and does not consume the build artifact. The retry steps keep their absence of continue-on-error — the first attempt's continue-on-error is what makes the retry reachable, and copying it onto the retry would let a stalled download pass silently into the unpack step. isolated-nightly's job-level continue-on-error is untouched, so its 60-minute ceiling frees the runner without changing the leg's conclusion. Pinned in scripts/tests/e2e-workflow.test.js: both limbs, the retry's visible failure, and a regression guard over the already-landed values (build 30, the two consuming legs 60, the four first-attempt steps 10). Refs #12132 Patrol-Run: qwen-issue-patrol/jmvuv88frpw Co-authored-by: yiliang114 <[email protected]> Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
3a4a077362 |
fix(web-shell): keep "+ Add session" clickable when the catalog is empty (#15835)
* fix(web-shell): keep + Add session clickable when the catalog is empty The add button was gated on the cached session catalog already containing an addable session, so the picker could never open to refresh itself in the one case its reload-on-open effect exists for. Gate the button on pane capacity alone and let the picker report an empty list after reloading. Closes #15678 * test(web-shell): pin the empty-picker guard with a negative assertion * test(web-shell): assert add-session button disables at MAX_PANES The PR narrowed canAdd to the capacity term only, and the new test pinned just the removed half (empty catalog stays enabled). Without a cap assertion, dropping the pane-count check would leave every test green while the picker could open a seventh pane. * test(web-shell): pin the add button stays enabled below MAX_PANES --------- Co-authored-by: 2SinceJuly <[email protected]> |
||
|
|
f3af3dd857 |
refactor(managed-agent): Split server into Maven modules (#15871)
* refactor(managed-agent): split server into Maven modules Separate contracts, orchestration, persistence, adapters, assembly, and verification while retaining the existing service delivery model. Move tests and build consumers together and document local evidence and pending CI acceptance. Co-authored-by: Qwen-Coder <[email protected]> * refactor(managed-agent): reduce configuration and SDK boilerplate Co-authored-by: Qwen-Coder <[email protected]> * refactor(managed-agent): narrow contracts and simplify test scaffolding Co-authored-by: Qwen-Coder <[email protected]> * fix(managed-agent): repair verification after module migration Resolve shared fixtures and worker paths from the Maven module root, update CI packaging assertions, and align existing test fixtures with the extracted contracts. Restore restricted Workspace constructors and remove redundant test visibility changes without altering inherited MySQL coverage. Co-authored-by: Qwen-Coder <[email protected]> * test(managed-agent): align remaining Harness and OSS fixtures Preserve SDK refusal messages and register the managed OSS adapter at fixture injection points. Keep the existing retry and client shutdown assertions intact. Co-authored-by: Qwen-Coder <[email protected]> * style(managed-agent): order Hosted cleanup Harness imports Co-authored-by: Qwen-Coder <[email protected]> * test(managed-agent): fix recovery smoke fixture and import order Supply the required transcript coverage in the recovery browser fixture and wait for history before testing a complete handoff. Preserve its existing safety and submission assertions. Order the cleanup coordinator test imports for Checkstyle. Co-authored-by: Qwen-Coder <[email protected]> --------- Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
e3f12f54f9 |
feat(verify-pr): reuse the current tree behind a clean-head prepare gate (#15913)
* feat(verify-pr): reuse the current tree behind a clean-head prepare gate A local round already runs the head side of its A/B in the current tree, but nothing said so and nothing checked it: preparing on the wrong branch silently measured code the report never names, and the round snapshot carried only the head OID, leaving every base reference to re-derive the HEAD^1 warning the skill repeated in three places. Prepare now refuses a HEAD other than the PR head (naming the checkout to run) and any uncommitted change, tracked or untracked, before it writes anything; it never stashes for the maintainer. The status probe pins --untracked-files=normal so a status.showUntrackedFiles=no config cannot hide files from the gate. The round snapshot records the full coordinates (repo, pr, baseRefOid, headRefOid), and the skill consolidates its three HEAD^1 warnings into one rule: local coordinates come from that snapshot, and the clean current tree is the head side, reusing its install and build. The isolation boundary is unchanged: the tree gate runs on the host coordinate path only, and --require-isolation still guards PR-code execution. * fix(verify-pr): make build reuse conditional on head freshness Review reproduced a clean head checkout whose gitignored dist still ran an earlier commit's code while prepare advertised unconditional build reuse. The gate attests source identity only, so the success line now says to verify or refresh the install/build first, the skill makes reuse conditional on establishing the artifacts were produced for this head (otherwise rebuild per the local install strategy), and the design document records the boundary in both languages. The PR body's risk section matches. * fix(verify-pr): close the index-flag hole and make refusals actionable Review found four gaps in the tree gate: skip-worktree / assume-unchanged entries (which sparse checkouts set en masse) hide tracked divergence from git status, so a partial tree passed with the gate's own clean stamp; the dirty-tree remedy looped because a plain git stash leaves untracked files behind; the printed checkout remedy's detached-HEAD round trip was untested; and the fixture re-declared the repository's tmp/ ignore rule instead of pinning it. The gate now refuses any index entry that is not a plain cached H, the dirty refusal names the entries and a stash form that clears them, a detached HEAD at the PR head is pinned to reach exit 0, and a coupling test fails if the real .gitignore stops ignoring the round's own artifacts. Each guard carries a mutation-verified test, and the four-step recipe was driven by hand against a scratch clone. |
||
|
|
7a0beb2f7e |
chore(release): sdk-typescript v0.1.26 [skip ci]
* chore(release): v0.26.4 * chore(release): sdk-typescript v0.1.26 --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Shaojin Wen <[email protected]> |
||
|
|
b8faa1c915 | fix(web-shell): hide empty no-workspace sessions section (#15916) | ||
|
|
38337f7257 |
test(managed): count only accepted cancellation takeovers (#15912)
Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
cc6de38cb5 |
fix(ci): isolate web-shell smoke from shared runner networks (#15886)
* fix(ci): isolate web-shell smoke from shared runner networks Co-authored-by: Qwen-Coder <[email protected]> * docs(ci): clarify hosted smoke font guard behavior Co-authored-by: Qwen-Coder <[email protected]> * docs(ci): explain dormant smoke pool steps Co-authored-by: Qwen-Coder <[email protected]> * docs(ci): stop overstating which dormant smoke guards are pinned The retained comment claimed every self-hosted step's guard is pinned by checkout/preflight tests. Only two of six are: `Recreate runner Git metadata` (scripts/tests/qwen-runner-checkout-workflow.test.js) and `Use pre-installed Node.js (self-hosted)` (scripts/tests/no-ak-integration-ci.test.js). `Check host font baseline (self-hosted)` is named by no test file, and its `runner.environment == 'self-hosted'` guard can never be true under `runs-on: 'ubuntu-latest'` — so it is parked, not pinned. Say which two are pinned and that the font baseline guard is parked, and re-measure the ci.yml size ratchet entry (155625 -> 155708). Co-authored-by: Qwen-Coder <[email protected]> Patrol-Run: qwen-pr-closeout/jmvugxtx22a --------- Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
5cba899e46 |
docs(ci): correct the qwen-autofix job cap and budget table to match the workflow (#15914)
Two entries in .github/workflows/qwen-autofix.md restated review-address bounds that the authoritative workflow no longer has: - af-039 said "The 300-minute job cap puts the worst case at 5 runner-hours per slot (100 across the fleet at 20)". The cap is timeout-minutes: 345 (qwen-autofix.yml:3670), so it becomes 5.75 runner-hours per slot and 115 across the fleet at the max-parallel fallback of 20 (:3679). - af-050's worst-case budget table listed "Repair 20" and "worst case 280 => job timeout 300". The Repair deterministic rejection step is bounded at 70 minutes (:5540, "the 60-minute budget below plus the same 10-minute margin"), so the row becomes 70 and the table's own six rows sum to 330, quoted against the real 345 cap. The trailing "on ubuntu-latest, whose own ceiling is 360" clause is left as-is: 345 < 360 keeps it coherent, and re-deriving the conditional runs-on expression (:3669) is out of scope. The table total is 330, leaving 15 minutes against the 345 cap. The workflow comment at :3667-3668 separately describes a 25m reserve for the four-step unarmed chain (130+60+70+60 = 320), which excludes the setup and report rows this table itemises. The two are deliberately not conflated here. Adds a test that derives every quoted figure from qwen-autofix.yml and requires the doc to agree, so neither entry can drift silently again. The existing sum check reads only the workflow and structurally cannot see a doc that restates the same numbers in prose. Witness: - red, doc unmodified: "x keeps the af-039 and af-050 budget prose in step with the job cap -> expected '# `qwen-autofix.yml` - design record...' to contain '345-minute job cap'"; Tests 9 failed | 327 passed | 14 skipped (350), rc=1 - green, both sites fixed: that test passes; Tests 8 failed | 328 passed | 14 skipped (350), rc=1. The 8 are pre-existing local-environment noise, identical to the unmodified-base baseline (Tests 8 failed | 327 passed | 14 skipped (349), rc=1). Patrol-Run: qwen-issue-patrol/jmvuqxwvapt Co-authored-by: yiliang114 <[email protected]> Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
7c9e79e70b |
perf(release): reuse verified native audio prebuilds across releases (#15854)
* perf(release): reuse verified native audio prebuilds across releases Every release rebuilds the five native audio prebuilds even when nothing that affects those binaries changed. The build is short; the wait is not. For v0.26.3 the Linux x64 prebuild queued 74 minutes to execute for 50 seconds, and the collection step queued again after it — and `publish` depends on that collection, so the whole release sits behind it. Fingerprint the audio build inputs and reuse an artifact from an earlier successful official main release when the fingerprint matches. The key covers the audio package, the dependency lock, the package manager pin and the contents of the producing workflow and this helper, so the Node pin and the prebuildify target arguments are part of it. The package version is excluded deliberately: no part of the native build reads it, and including it would make reuse impossible between releases. Reuse means executing bytes an earlier run produced, so provenance is checked rather than assumed: exact fingerprint name, unexpired, same repository for both run and head run, and a completed successful release.yml run on main from workflow_dispatch or schedule. The pinned download-artifact already verifies the artifact digest. Retention is checked differently at selection and consumption. Selection requires 48 hours of headroom so the artifact outlives the release; consumers require only that it has not expired. Re-applying the margin against a later clock would reject an artifact the release had already committed to, after the native matrix was skipped and with no fallback. Lookup, trial download and payload validation are all non-fatal, and the reuse ID is published only once a trial download has validated; an empty ID runs the full matrix, which is today's behaviour. The publisher does not trust that decision: it recomputes the fingerprint from its own checkout, re-verifies the source run, and validates the payload again, fatally — by then the matrix was skipped, so a bad artifact must stop the release. This does not depend on ECS_RELEASE_HOST_RUNNER_ENABLED and takes effect with the switch unset. The collector needed three fixes to be a trustworthy producer. Its `rm -rf -- "$GITHUB_WORKSPACE/packages/audio-capture/prebuilds"` resolved through whatever `packages` was on a persistent host: with a leftover symlink it deleted an external tree and exited 0, and the following download wrote through the same symlink. It now wipes through a shared preflight that canonicalises the workspace and refuses paths resolving outside it. It also ran `node` with no Node contract, inheriting Node from the hosted image by accident. And its release-only label pinned `x64` while the runners holding that label are ARM64, which never matches and queues until timeout. Contract tests pin the wiring, each confirmed to fail against an injected regression. Design doc in both languages. * fix(release): reconcile audio reuse workflow contracts Share the pre-checkout wipe, preserve the workflow size cap, and let fingerprint failures rebuild native audio. Co-authored-by: Qwen-Coder <[email protected]> * fix(ci): use block-style release permissions Co-authored-by: Qwen-Coder <[email protected]> * fix(release): drop x64 from publish's release-host expression The review's unresolved item: collect got the ARM64 label fix but publish kept ["self-hosted", "linux", "x64", "ecs-qwen-release-host"], which can never match the ARM64 machines holding that label, so the OIDC-carrying job would queue forever once ECS_RELEASE_HOST_RUNNER_ENABLED is true. Same expression as the collect fix, same one-word drop. * docs(release): clarify audio reuse rollout and validation Co-authored-by: Qwen-Coder <[email protected]> * test(release): cover artifact overwrite and contained symlink guards * test(web-shell): include transcript coverage in recovery fixture Bring the fixture correction from #15883 into this branch to address the observed smoke failure. Co-authored-by: Qwen-Coder <[email protected]> * fix(release): make audio cache seeding best effort Keep the validated same-run artifact usable when retaining a keyed copy fails. Pin the reuse wiring and correct the retention and producer fixtures without changing release trust boundaries. Co-authored-by: Qwen-Coder <[email protected]> * chore(test): apply prettier to the audio prebuild fixtures * docs(release): clarify audio reuse run provenance Co-authored-by: Qwen-Coder <[email protected]> --------- Co-authored-by: Qwen-Coder <[email protected]> Co-authored-by: zzj <[email protected]> |
||
|
|
bf074c4ad8 |
test(managed-agent): retry the items read through a lagging projection (#15910)
* test(managed-agent): retry the items read through a lagging projection The public reader answers 503 message_projection_pending while projection catches up, and #15870 documents that as retryable. The crash fixture asserted 200 on the first response, so a coordinator restart -- exactly when projection lags -- failed the gate with 'expected: 200' instead of polling (#15909). Poll the read through that one response and widen the await budget to 60s; every other status still fails the way it did. * test(managed-agent): preserve projection retry bounds and wire contract Co-authored-by: Qwen-Coder <[email protected]> --------- Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
84aee5b9b7 |
test(web-shell): include transcript coverage in recovery fixture (#15883)
* test(web-shell): include transcript coverage in recovery fixture Co-authored-by: Qwen-Coder <[email protected]> * test(web-shell): complete recovery event fixtures Remove the unevaluated transcript type guard and supply required event terminal flags without changing assertions. Co-authored-by: Qwen-Coder <[email protected]> * fix(ci): use runner temp for Web Shell browser smoke (#15884) * fix(ci): use runner temp for Web Shell browser smoke Co-authored-by: Qwen-Coder <[email protected]> * fix(ci): resolve runner temp in the browser step context Co-authored-by: Qwen-Coder <[email protected]> --------- Co-authored-by: Qwen-Coder <[email protected]> * fix(ci): partition the complete macOS test suite into bounded jobs (#15888) * fix(ci): use runner temp for Web Shell browser smoke Co-authored-by: Qwen-Coder <[email protected]> * fix(ci): resolve runner temp in the browser step context Co-authored-by: Qwen-Coder <[email protected]> * fix(ci): partition the complete macOS test suite into bounded jobs Co-authored-by: Qwen-Coder <[email protected]> * fix(ci): account for the macOS aggregate job budget Record the additional five-minute aggregate without changing any test execution timeout. Co-authored-by: Qwen-Coder <[email protected]> * test(install): isolate Windows fixtures from persistent PATH (#15889) Co-authored-by: Qwen-Coder <[email protected]> * fix(ci): write the macOS shard matrix in block style and pin its gates The seven-row matrix used YAML flow mappings, which `.yamllint.yml` forbids (`braces: forbid: 'non-empty'`), so the `Run yamllint` step cannot go green on this branch. Rewrite the rows in the block style every other workflow matrix in this repo already uses. Add the test pins the shard plumbing was missing: - the `cli`/`core` dispatch argv, including the bare `--` that keeps `--shard` forwarded to vitest instead of consumed by npm, and the per-group `NODE_OPTIONS` choice - `id: 'install'` on `test_macos_shards`, which the suite's `steps.install.outcome` gate silently reads as '' if it is renamed - the aggregate `test_macos` gate against the shards' gate, so the preserved check name cannot report `skipped` while the legs fail Co-authored-by: Qwen-Coder <[email protected]> Patrol-Run: qwen-pr-closeout/jmvu6810z1y * fix(ci): preserve shell fixture gates on macOS system Bash Handle empty issue families under nounset without mapfile and explicitly reject either missing OSS credential. Keep failure assertions and include shell diagnostics. Co-authored-by: Qwen-Coder <[email protected]> --------- Co-authored-by: Qwen-Coder <[email protected]> * fix(ci): keep macOS aggregate failures eligible for infra retry Co-authored-by: Qwen-Coder <[email protected]> --------- Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
54fd8e0372 |
fix(ci): route the E2E build job through the pool-first runner expression (#15885)
* fix(ci): route the E2E build job through the pool-first runner expression * fix(ci): carry the full self-hosted contract on the E2E build job * test(ci): pin the pool contract's step order and sync the build-routing design note * test(ci): pin the npm-cache position and heal body on every pool job The pool-contract loop only asserted that `Configure persistent npm cache (self-hosted)` exists, so moving it below `Install dependencies` or dropping its `if:` stayed green while the pool install silently fell back to the default npm cache and re-downloaded through the slow egress the step exists to avoid. It also left the build job's ownership-heal body unpinned: the full body was only asserted on the Linux leg, so dropping the `sudo -n` fallbacks from the build copy stayed green while the next checkout on a pool host still holding root-owned leftovers dies with EACCES. Pin the cache step's position and `if:`, and compare every pool job's heal body against the leg copy the docker-lock ownership suite already pins in full. Three mutants (cache step moved below install, cache `if:` stripped, build heal `sudo -n` dropped) now each fail one test; unmutated 130/130 pass. Co-authored-by: Qwen-Coder <[email protected]> Patrol-Run: qwen-pr-closeout/jmvu6810z1y * docs(design): pair the E2E build-once note with its zh-CN version docs/design/README.md asks that updating an existing single-language design adds the missing version and aligns the pair, and this PR rewrites the section that records why the build left the hosted runner. Add e2e-build-once.zh-CN.md with the same section order and the same decisions, and link both directions immediately under each title. Also drop the "only hosted-pinned structural job" claim from the English note: `e2e-interactive-opentui` is hosted-pinned too, which the same note already records two paragraphs down. The remaining sentence keeps the actual cause - every leg waits on `build`, and `build` sat on hosted ubuntu. Co-authored-by: Qwen-Coder <[email protected]> Patrol-Run: qwen-pr-closeout/jmvu6810z1y --------- Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
d896c1816a |
test(managed): align recovery and transcript fixture contracts (#15899)
* test(managed): record which load path produced each post-crash entry
HostedProcessCrashIT fails on main with postFailureLoads.every(Boolean), but
the recorded sequence changes shape between runs (#15898: 9 vs 10 entries,
different true positions, one run with none), so the current message cannot
say which of the connector's load paths sent the offending request.
Record a compact origin discriminator per entry — cancellationTakeover,
passiveManagedRuntimeRecovery, driveRuntimeRecovery, mcpManagementOnly and
whether cancellationPromptId was present — and include it in both assertion
messages. The assertion itself is unchanged: 'no tool replay after a crash'
is the property it protects, and the next red run should name its own origin
instead of being guessed at.
* test(managed): name the load path behind each post-crash entry
Both review findings were correct: the origin string added in
|
||
|
|
0976826090 |
fix(web-shell): align no-workspace category header with peers (#15897)
* fix(web-shell): align no-workspace category header with peers * test(web-shell): preserve archived no-workspace header presentation * docs(web-shell): show sidebar category header comparison |
||
|
|
4d74e86aae |
test(review): pin ghApiAllNested's paginated nested-array request (#12560)
* test(review): pin ghApiAllNested's paginated nested-array request Follow-up from #6828 (thread #3569105135). presubmit.test.ts mocks ghApiAllNested out, so nothing pinned the argv it actually builds. Assert it passes --paginate with the per-key .`key[]` jq, decodes the streamed NDJSON, and templates the caller-provided key. Test-only; no behavior change. * test(review): harden ghApiAllNested coverage per /review Expand the ghApiAllNested block from 2 to 5 cases to make the coverage mutation-resistant per the /review suggestions on #12560: - fail-closed on a non-transient fetch failure (no silent [] collapse) - pin the strict-parse wiring against a malformed streamed line - decode all streamed records (guard a silent page cap) - assert a single gh() round-trip per call - correct the rationale comment (drop the false "gh api has no --slurp") Test-only; no production code changed. Locally: vitest 31 passed and each new assertion reddens under the corresponding mutation of ghApiAllNested. Assisted-by: AI (agentic coding); all claims verified against source. --------- Co-authored-by: 易良 <[email protected]> |
||
|
|
48a110cea2 |
test(web-shell): select retained radio without pointer coordinates (#15896)
Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
5f4b60d2a0 |
fix(cua): align input and session repairs with 0.27.0 (#15784)
* fix(cua): correct background input and pending native cleanup * chore(cua): prepare aligned 0.26.1 release * fix(cua): discover live accessory apps outside install roots * fix(cua): Return pending actions when popup windows hide * fix(cua): Avoid unbound Windows input value probes * fix(cua): Check macOS class factories on the class * fix(cua): Verify app text insertion through accessibility * fix(cua): Route macOS editing keys to their AX hosts * fix(cua): Preserve owner windows and public refusal recovery * docs(cua): Complete the 0.26.1 repair release scopecua-driver-rs-v0.27.0 |
||
|
|
87022fa7c6 |
test(managed-agent): select managed JDBC in Hosted fault fixtures (#15882)
Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
619a601b39 |
refactor(managed): Remove persisted public message snapshots (#15870)
Use bounded live message pages for public history and exports, remove the public snapshot schema and background lifecycle, and retain native recovery history. Co-authored-by: Qwen-Coder <[email protected]> |
||
|
|
70be140e14 |
fix(release): reduce hosted runner queue delays (#15832)
* perf(release): reuse verified native audio prebuilds across releases Every release rebuilds the five native audio prebuilds even when nothing that affects those binaries changed. The build is short; the wait is not. For v0.26.3 the Linux x64 prebuild queued 74 minutes to execute for 50 seconds, and the collection step queued again after it — and `publish` depends on that collection, so the whole release sits behind it. Fingerprint the audio build inputs and reuse an artifact from an earlier successful official main release when the fingerprint matches. The key covers the audio package, the dependency lock, the package manager pin and the contents of the producing workflow and this helper, so the Node pin and the prebuildify target arguments are part of it. The package version is excluded deliberately: no part of the native build reads it, and including it would make reuse impossible between releases. Reuse means executing bytes an earlier run produced, so provenance is checked rather than assumed: exact fingerprint name, unexpired, same repository for both run and head run, and a completed successful release.yml run on main from workflow_dispatch or schedule. The pinned download-artifact already verifies the artifact digest. Retention is checked differently at selection and consumption. Selection requires 48 hours of headroom so the artifact outlives the release; consumers require only that it has not expired. Re-applying the margin against a later clock would reject an artifact the release had already committed to, after the native matrix was skipped and with no fallback. Lookup, trial download and payload validation are all non-fatal, and the reuse ID is published only once a trial download has validated; an empty ID runs the full matrix, which is today's behaviour. The publisher does not trust that decision: it recomputes the fingerprint from its own checkout, re-verifies the source run, and validates the payload again, fatally — by then the matrix was skipped, so a bad artifact must stop the release. This does not depend on ECS_RELEASE_HOST_RUNNER_ENABLED and takes effect with the switch unset. The collector needed three fixes to be a trustworthy producer. Its `rm -rf -- "$GITHUB_WORKSPACE/packages/audio-capture/prebuilds"` resolved through whatever `packages` was on a persistent host: with a leftover symlink it deleted an external tree and exited 0, and the following download wrote through the same symlink. It now wipes through a shared preflight that canonicalises the workspace and refuses paths resolving outside it. It also ran `node` with no Node contract, inheriting Node from the hosted image by accident. And its release-only label pinned `x64` while the runners holding that label are ARM64, which never matches and queues until timeout. Contract tests pin the wiring, each confirmed to fail against an injected regression. Design doc in both languages. * fix(release): move the release build and SDK build off the hosted queue Behind the existing ECS_RELEASE_HOST_RUNNER_ENABLED switch, prepare the version commit and produce the CLI build outputs on an isolated release runner, and split the TypeScript SDK into an isolated producer plus the existing hosted publisher. Eligible Linux downstream jobs join the same pool. With the switch unset every path is exactly today's behaviour. The final npm publication stays on GitHub-hosted runners. npm trusted publishing and provenance require a cloud-hosted runner, so moving the publisher itself would break the release rather than speed it up — only the build work ahead of it can leave the queue. Each migrated job runs one shared preflight before checkout, referenced as a '$/' self-repository action so it resolves at the running commit without a prior checkout. Release-only labels carry no architecture component: the runners holding that label are ARM64, and an "x64" component never matches instead of falling back to hosted. Jobs that genuinely need amd64 — the OSS mirrors and the managed runtime, which execute a hardcoded linux-amd64 ossutil — keep their hosted path, tracked in #15847. The VSCode build routes by matrix.universal so only the dependency-free leg migrates. The SDK publisher consumes the exact tested tarball through a same-run artifact and refuses to overwrite different already-published bytes on retry. Audio prebuild reuse is the base of this branch and is specified separately; the isolated build job is a second consumer of that artifact and is held to the same re-verification contract as the publisher. Rebased onto the audio prebuild reuse branch, so that mechanism and its contract tests are no longer duplicated here. * fix(release): reconcile audio reuse workflow contracts Share the pre-checkout wipe, preserve the workflow size cap, and let fingerprint failures rebuild native audio. Co-authored-by: Qwen-Coder <[email protected]> * fix(ci): use block-style release permissions Co-authored-by: Qwen-Coder <[email protected]> * fix(release): drop x64 from publish's release-host expression The review's unresolved item: collect got the ARM64 label fix but publish kept ["self-hosted", "linux", "x64", "ecs-qwen-release-host"], which can never match the ARM64 machines holding that label, so the OIDC-carrying job would queue forever once ECS_RELEASE_HOST_RUNNER_ENABLED is true. Same expression as the collect fix, same one-word drop. * docs(release): clarify audio reuse rollout and validation Co-authored-by: Qwen-Coder <[email protected]> * docs(release): reserve runner slots on existing ECS hosts * fix(release): quote audio workflow scalar values --------- Co-authored-by: Qwen-Coder <[email protected]> Co-authored-by: zzj <[email protected]> |
||
|
|
8457254f75 |
docs(managed-agent): say what a SIGKILL leaves behind an upgrade phase (#15878)
The signal cleanup runs only after a command the phase waits for returns, and a SIGKILL runs none of it. Name the scratch directory it then leaves, with the dump's option file or the environment files a command run as the server unit reads, and how to remove it. Record the measurement for a signal while backup --skip-database resolves the configuration, and correct the review's mutant count to 17, one of them equivalent. |