Commit Graph
11736 Commits
Author SHA1 Message Date
易良 46d825d115 Revert "fix(ci): isolate web-shell smoke from shared runner networks (#15886)" (#15961)
This reverts commit cc6de38cb5.
2026-10-31 02:36:35 +00:00
Shaojin Wen 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
2026-10-31 02:30:22 +00:00
Shaojin Wen 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).
2026-10-31 10:25:56 +08:00
Shaojin Wen 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.
2026-10-31 10:20:39 +08:00
Shaojin Wen 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.
2026-10-31 10:14:55 +08:00
Shaojin Wen 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.
2026-10-31 10:02:04 +08:00
Shaojin Wen 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.
2026-10-31 09:41:41 +08:00
Shaojin Wen 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.
2026-10-31 01:01:40 +00:00
Shaojin Wen 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.
2026-10-31 04:43:36 +08:00
Shaojin Wen 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).
2026-10-31 04:41:44 +08:00
Shaojin Wen 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.
2026-10-31 03:23:30 +08:00
jinye 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)
2026-10-30 18:26:43 +00:00
Shaojin Wen 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.
2026-10-30 18:15:45 +00:00
Shaojin Wenandverify-rig 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]>
2026-10-30 18:15:37 +00:00
Shaojin Wen 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).
2026-10-30 18:00:09 +00:00
Kun De 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
2026-10-31 01:46:35 +08:00
Lanre Shittu 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
2026-10-31 00:50:58 +08:00
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]>
2026-10-30 16:29:46 +00:00
JabrailandShaojin Wen 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]>
2026-10-30 16:24:25 +00:00
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]>
2026-10-31 00:18:02 +08:00
易良andQwen-Coder 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]>
2026-10-31 00:02:45 +08:00
Yufeng HeandShaojin Wen 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 c56871d673 failed the new #14751 case at
realConfig.initialize(): ToolRegistry.warmAll constructs SkillTool,
whose constructor requires the SkillManager that skipSkillManager
deliberately omits, aborting initialize() on ubuntu/Node 22. The
codebase already has the option for exactly this seam:
lenientToolWarmup logs and skips such tools instead of aborting.

* fix(core): stop the LSP client even for sessions torn down before initialize

* test(core): pin cleanup after an LSP stop failure

---------

Co-authored-by: Shaojin Wen <[email protected]>
2026-10-30 23:57:46 +08:00
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]>
2026-10-30 15:56:56 +00:00
烽宁 4bd9ed0143 fix(cli): share hosted harness deadlines and bail after CI retries (#14752) 2026-10-30 23:54:26 +08:00
Andrea-BrunoandAndrea Bruno 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]>
2026-10-30 15:54:14 +00:00
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]>
2026-10-30 23:50:44 +08:00
callmeYe 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
2026-10-30 23:46:11 +08:00
Dragon 318babe4d7 fix(ci): weight PR owner assignment by open issue load (#15194) 2026-10-30 15:43:17 +00:00
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]>
2026-10-30 23:43:13 +08:00
2SinceJulyand2SinceJuly 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]>
2026-10-30 23:40:51 +08:00
jinyeandQwen-Coder 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]>
2026-10-30 14:56:35 +00:00
Shaojin Wen 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.
2026-10-30 22:50:30 +08:00
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]>
2026-10-30 13:54:43 +00:00
Kun De b8faa1c915 fix(web-shell): hide empty no-workspace sessions section (#15916) 2026-10-30 21:53:32 +08:00
易良andQwen-Coder 38337f7257 test(managed): count only accepted cancellation takeovers (#15912)
Co-authored-by: Qwen-Coder <[email protected]>
2026-10-30 19:43:26 +08:00
易良andQwen-Coder 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]>
2026-10-30 19:43:04 +08:00
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]>
2026-10-30 19:42:46 +08:00
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]>
2026-10-30 11:27:38 +00:00
易良andQwen-Coder 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]>
2026-10-30 18:25:04 +08:00
易良andQwen-Coder 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]>
2026-10-30 18:24:19 +08:00
易良andQwen-Coder 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]>
2026-10-30 18:24:15 +08:00
易良andQwen-Coder 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 fad5d81a
still could not name the culprit it exists to name.

Two load shapes reach POST /session/:id/load carrying markers the origin
string never read, so they rendered byte-identical to a bare re-attach:

- a recovery-cleanup load sets only recoveryCleanupPromptId
  (LoadHarnessSession.forRecoveryCleanup throws when passive/drive/
  takeover/lifecycle/promptId are set at all), and
  QwenHostedHarnessConnector.doRecheckRecoveryCleanup issues one;
- a lifecycle load sets only lifecycleAuthority
  (QwenHostedHarnessConnector.lifecycleAttachment builds it with
  passive=drive=takeover=false).

promptId could not rescue them: withCancellationPromptId throws unless
passiveManagedRuntimeRecovery && cancellationTakeover, so promptId=true
implies takeover=true and the marker is always false on exactly the
entries every(Boolean) rejects.

Recording also happened eleven lines before await fetch(target, ...), so
a load the daemon refused was indistinguishable from an admitted one.
This driver already expects that refusal for a plain attach
(assert.equal(loaded.error, 'hosted_turn_recovery_required'), HTTP 409),
and the connector then performs the takeover load that actually replaces
the runtime. Move the recording after the response and add status, so a
refused probe that changed nothing no longer prints as the forbidden
admitted plain re-attach.

Verified by mutation over the eight load shapes that can reach this
endpoint: the previous marker set collapsed four of them (refused bare
reattach, admitted bare reattach, recovery-cleanup, lifecycle) into one
indistinguishable string; each of the three added markers is
load-bearing, since dropping any one reintroduces a collision. The
assertion itself is unchanged.

Co-authored-by: Qwen-Coder <[email protected]>
Patrol-Run: qwen-pr-closeout/jmvugxtx22a

* test(managed): distinguish cleanup loads and response outcomes

Co-authored-by: Qwen-Coder <[email protected]>

* test(managed): align recovery and transcript fixture contracts

Co-authored-by: Qwen-Coder <[email protected]>

---------

Co-authored-by: Qwen-Coder <[email protected]>
2026-10-30 18:17:02 +08:00
Kun De 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
2026-10-30 08:23:06 +00:00
ChengFaand易良 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]>
2026-10-30 14:43:09 +08:00
易良andQwen-Coder 48a110cea2 test(web-shell): select retained radio without pointer coordinates (#15896)
Co-authored-by: Qwen-Coder <[email protected]>
2026-10-30 14:17:43 +08:00
顾盼 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 scope
cua-driver-rs-v0.27.0
2026-10-30 14:04:52 +08:00
易良andQwen-Coder 87022fa7c6 test(managed-agent): select managed JDBC in Hosted fault fixtures (#15882)
Co-authored-by: Qwen-Coder <[email protected]>
2026-10-30 13:57:42 +08:00
jinyeandQwen-Coder 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]>
2026-10-30 08:56:08 +08:00
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]>
2026-10-30 01:08:54 +08:00
Shaojin Wen 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.
2026-10-30 00:42:57 +08:00