* fix(cli): preserve runtime boundaries during standalone updates
Preserve Node/Bun archive flavor and validate actual CLI loading, package
identity, version and prepared installation identity before activation.
Keep Node npm transport and restrict Bun registry lookup to trusted config.
Integrates chiga0's update stack through ce67edaba5,
with isolated fixtures and real Node/Bun runtime regression coverage.
Co-authored-by: gary.gq <gary.gq@alibaba-inc.com>
* test(cli): bound cancellation test waits and cleanup
* fix(cli): validate standalone launchers and registry settings
---------
Co-authored-by: gary.gq <gary.gq@alibaba-inc.com>
* feat(serve): add daemon restart
Restart exactly one registered daemon with its recorded port, hostname, and workspaces. A bearer daemon resolves its token before stopping; the new process is started through the existing ready-wait path.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(serve): harden daemon restart
Reject HTTPS restarts before stopping, resolve and retain the token when --require-auth is explicit, require an explicit --force for Windows stops, and preserve process.execArgv for development entries.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(serve): make daemon restart faithful and fail closed
Record what restart has to replay, and decide every refusal that can be
decided while the daemon still runs before the stop leg.
- serve records startupWorkspaces (explicit inputs only), web and
requireAuth in the discovery record. Restart replays those instead of
the merged workspace list, so a restored registration is no longer
pinned as a startup workspace, and --web/--require-auth default to the
recorded values. An older multi-workspace record is refused.
- An explicit --token configures bearer auth, as it does for
`daemon start`; an inherited QWEN_SERVER_TOKEN is still stripped for
an auth-none daemon. A running bearer daemon must accept the token.
- Refuse when restart runs inside a process the target daemon hosts
(its Web Shell terminal), when a startup workspace no longer validates,
and give restart its own selection and token error messages.
- Report spawn errors on both legs, continue when the record vanished
during the stop leg, and fail when the daemon came back on another
port.
- Extract the sequencing into runDaemonRestart with injectable
dependencies and pin it, the plan, and the record write with tests.
- Update the design docs and the user guide.
---------
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
A MessageDisplay command Hook suppresses the streamed reply; the public
ledger must not carry its text, and after a Harness restart the next model
request's history must not carry it either. The fixture gains a
hook-suppress mode that records the Hook input and answers
{suppressOutput:true}.
Adds the bilingual design note. One cell adds 150 s to the shared fork:
healthy 10012 s, fork 10612 s, Verify 187 minutes, job 290 minutes.
* fix(ci): queue the sdk-java host lock first-come-first-serve (#14743)
flock(2) does not order its wakeups, so under continuous arrivals one waiter can lose every release and die at the wait budget — repeatedly burning 40, then 60, then 90 minutes per starved lane across at least three hosts. Replace the inline flock --wait at all three acquisition sites with a ticketed queue: every acquirer takes the next sequence number atomically, only the head of line retries the lock, dead owners are reaped, and the lock still releases at the step boundary. The pinned infrastructure-signature error text is preserved.
The .size-baseline records the workflow's new size (smaller than main's, but main itself already exceeds its recorded baseline).
* fix(ci): block the queue head instead of polling the lock
The first live run starved its full 5400 s budget as queue ticket 1: the head polled flock --nonblock while main and older branches still run blocking flock --wait, so every release went to a legacy waiter's kernel wakeup. The head now blocks in five-second slices, re-entering the same wake race on even terms; tickets still order every run that uses this helper.
* fix(ci): serve the fast tier before full-tier holds
The queue bounded the wait by position but a fast-tier PR job still queued behind every full-tier hold ahead of it. Give the fast tier its own class: the head is the first sorted ticket and fast tickets sort first, so a PR job waits at most the hold already running. A normal ticket ages into the fast class after 20 minutes, so continuous PR traffic cannot starve the full tier.
* refactor(ci): keep the lock queue plain FIFO.
Drops the priority/aging classes: a single first-come-first-serve line is simpler to review and reason about. The head still blocks in five-second slices so it re-enters the kernel wake race on even terms with legacy waiters, and dead owners are still reaped. The tradeoff is explicit: a fast-tier job waits its turn behind full-tier holds instead of jumping them.
* fix(ci): stop leaking the host-lock ticket and reap stale orphans
Three bounded defects in the fair-lock helper, all confirmed by executing
it rather than by reading alone:
- The EXIT/TERM/INT traps quoted `${ticket}`, a `local` that is already out
of scope once the sourcing step's shell exits, so every trap ran
`rm -f ''` and each successful acquisition left its head ticket behind.
Drop the traps and leave the queue at acquisition instead: a holder needs
no place in line once the kernel holds the lock, and SIGKILL runs no trap.
- The ticket was published after `exec 8>&-` released the counter lock, so
a later arrival could take seq+1, see an empty queue, name itself head and
win the lock out of arrival order. Publish inside the critical section.
- Orphan liveness was decided solely by `kill -0`, so a ticket whose PID had
been recycled to a live process was never aged out and, being head, made
an idle lock unreachable for every job on the host. Age a ticket out on
mtime alone above 1800s; a live waiter re-touches every ~7s.
Measured on a free lock with a live-PID, 2h-old orphan head ticket:
base burns its full 6023ms budget and exits 1 with the orphan intact;
this commit acquires in 19ms and reaps it.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Patrol-Run: qwen-pr-closeout/jmvhb9cysmc
* style(ci): keep only the load-bearing why in the lock helper comments
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Patrol-Run: qwen-pr-closeout/jmvhb9cysmc
* fix(ci): keep the lock queue head in one blocking wait
The head re-entered the kernel wait queue every five seconds, so a release
reached waiters that stayed blocked first; the head could lose every
release and starve to its budget. Run 39472038337 still burned the full
5400 s as queue ticket 2. Wait once for the remaining budget and log the
remaining time at most once a minute.
A resumed release tag can predate the helper, so both acquisition sites
fall back to the bare lock instead of dying before Maven and wedging the
release. Pin the emitted ::error:: annotation prefix rather than a file
substring a comment can satisfy, and observe the real acquisition order in
the stub.
* fix(ci): name the blocking ticket in the sdk-java lock timeout
The timeout line reported only the dying waiter's own ticket, so a deep
queue and a wedged one produced the same message and neither could be
acted on from the log. Name the head of line, which separates a real
sibling hold from an orphan ticket.
Bring both design docs back to the shipped mechanism: two acquisition
sites, the flock'd counter with no aging path, the 1800 s mtime arm and
the ticket removed at acquisition, plus the operator recovery command.
Refresh the stale .size-baseline entry for sdk-java.yml.
* test(ci): wait for the first ticket instead of a fixed sleep
The FIFO case started the second acquirer 800 ms after the first and relied
on that being enough for A to take sequence 1. On a loaded runner it is not,
and B wins sequence 1, so the case fails on timing rather than behavior.
Poll for A's published ticket instead.
* fix(ci): print the lock wait line before blocking
The wait line was emitted only after `flock` returned, so a head parked
behind a sibling hold printed nothing for its whole budget: run
39528681869's step sat in flock for 40 minutes and was cancelled with an
empty log, which is the opposite of the attribution this change exists to
add. Probe with --nonblock, print the ticket line, then block.
The observability bullet in both design docs now states what the code does.
---------
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: Shaojin Wen <szujobs@gmail.com>
* feat(web-shell): show model refresh as an icon beside search
The full-width refresh control crowded the model picker. Keep the action next to search so the list stays scannable.
Co-authored-by: Cursor <cursoragent@cursor.com>
* docs(web-shell): add model picker refresh screenshots
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Ethan Ye <ethanye@U-463KXYWL-1938.local>
Co-authored-by: Cursor <cursoragent@cursor.com>
Cover #14880 item 2 without seeding a row. invoke() commits the
mcp_operation at intent, acquires the owner and only then commits
dispatch_started, and the cancel route is not gated by an in-flight
invoke. The Broker proxy parks the first tool-session acquire that
arrives while the durable record is still intent, and the case cancels
through the supported Harness route inside that window.
The cancel settles managed_mcp_cancelled with the record at
cancelled/not_started_proven; the resumed invoke, a same-id retry and a
status read answer the same view, and no MCP control reaches the Broker
after the parked acquire. Three bundle mutants (cancel skips its intent
branch, invoke skips the post-acquire re-read, invoke ignores the local
proof) each turn the case red; the last only through the wire assertion.
Budget the cell at 18 s (2x its measured 9.1 s): healthy 9518 -> 9536,
fork 10118 -> 10136, Verify stays 179 minutes.
* test(managed-agent): resume both Session streams across a held Hook (FG13e)
A PreToolUse command Hook holds inside the Runtime worker while the public
and WebShell clients read the Session stream. Both clients are then cut,
the deny lands while neither is connected, and each resumes with its own
cursor (Last-Event-ID on the public route, afterSequence on the WebShell
route). Each resumed view must equal the committed ledger byte for byte
with no gap and no duplicate, carry exactly one completion, and the model
must see exactly one tool result carrying the denial reason while the tool
never runs.
The tool-call start frame is only emitted after the call leaves the Hook,
so the cut deliberately happens before it: the frames written during the
hold are exactly the ones a cut client misses. Adds the bilingual design
note. One cell adds 150 s to the shared fork: healthy 9630 s, fork
10230 s, Verify 181 minutes.
* test(managed-agent): read the cut cursors after the readers stop
The resume cursor was sampled before abort(), so a frame the reader
thread appended in that window would be served again on resume and redden
the union as a duplicate. Take the cursors after abort(), matching the
FG12f class.
* test(managed-agent): release the held Hook after both streams are cut
The fixture now offers a hook-release mode that waits for <evidence>.release
instead of sleeping for a fixed 20 s, and the test writes that file only
after both readers abort. The deny therefore cannot land before the cut, so
the gap the cell claims to test is the one it actually creates.
assertResumedView now names what the Hook-held turn put on the ledger: one
failed terminal for call_FG13E_HOLD, past the cut cursor, and one
completion. Transport fidelity to a ledger that lost or duplicated the deny
no longer passes.
fg13-cases joins the Hosted artifact upload and the meta test pins it. Both
design docs correct the CI trigger: pull_request selects the fast tier, and
the full suite runs on the first maintainer approval of the head.
* test(managed-agent): correct the FG13e witness and raise the stall bound
Mutation witness #2 said a live-only resume reddens on the gap assertion.
continueFrom runs after the turn completed, so that client never reaches the
ledger tail: its 90 s wait exhausts and the case reddens on that timeout.
Both design docs now say so, and the Non-goals point the duplicated-helper
extraction at #14921.
The method's stall bound is raised to 480 s, above the 420 s of inner await
budgets, so a hung wait reports its own description instead of the outer
timeout. The Hosted lane trigger sentence was already corrected in
1eb67df537.
* docs(managed-agent): describe the FG13e hold as an explicit release
The step table still said the Hook holds for 20 s, which the explicit-release
fixture replaced. Both design docs now say it is held until the test
releases it, matching the code and the PR body.
* test(managed-agent): keep the digits in the FG13e fixture's call id
The prompt capture used [^A-Z_], which stops at the 1 in FG13E_HOLD, so
the fixture minted call_FG while both deny assertions look for
call_FG13E_HOLD. Add 0-9 to the class; the capture now keeps the whole
marker.
The design docs also carry the merged ledger: this cell adds 150 s, and
with main's FG12f (+20 s) and FG11d retire-at-intent (+18 s) the totals
are healthy 9668 s, fork 10268 s, Verify 182 minutes.
* test(managed-agent): close the FG13e review follow-ups
- Raise the stall bound to 600 s and the Hook command timeout to 240 s so
a slow stream cannot trip the outer timeout or fail-closed before the
release.
- Sweep the cgroup subtree in stop() and pin the rule over every Hosted IT
that exports QWEN_MANAGED_HOOK_CGROUP_ROOT.
- Restore the workflow ledger's FG11d cancel entry so the chain sums from
9915 to 10268.
- Copy processes.jsonl and the harness log into the evidence bundle, and
pin the writer side of the fg13-cases path.
- Enumerate the deferred shared machinery in both design docs; #14921 now
carries the measured 635/810-line scope.
---------
Co-authored-by: 易良 <1204183885@qq.com>
* test(managed-agent): skip a closed Session's automation slots (FG11d)
* test(managed-agent): park the scanner until the Session closes
* test(managed-agent): keep the broker-directory comment on its wider arm
* test(managed-agent): pin the closed-Session skip at one slot, with the helper
---------
Co-authored-by: 易良 <1204183885@qq.com>
* fix(web-shell): Select a named model for managed tasks
Remove the redundant server-default entry when model presets are available and submit the displayed preset Agent.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* feat(managed-agent): Support approval changes during a turn
Read the durable session policy at subsequent permission boundaries and release eligible pending actions through the existing decision journal. Keep Plan controls, admission snapshots, writer fencing, and legacy provider behavior intact.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
---------
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* feat(web-shell): consolidate trajectory chrome into a summary bar and toolbar
Replace the eight stacked bands above the trajectory table with a one-line
summary bar (elapsed and active time, a failures filter chip, one status pill
for live, paused and history, warnings and an About popover), the existing
overview, and a one-row toolbar (search with result stepping, a Filter popover
and the selected range). Earlier and newer records load from boundary rows at
the edges of the list, Jump to latest floats over the rows while paused away
from the tail, and the selected row carries its own details button.
Adds the bilingual design document for the whole redesign (PR-R1 of five).
* docs(web-shell): record the resolved trajectory redesign questions
* fix(web-shell): keep trajectory recovery paths reachable in the summary bar
- Warning actions use the real refresh capability, so an earlier window
that failed to move can still return to latest; a history gap seen from
an earlier window offers the return instead of an in-place refresh.
- Row buttons that only hold focus from a click no longer swallow grid
navigation keys.
- Announce failed refresh and navigation reads in an alert region.
- The status pill pauses while connecting, reconnecting or returning.
- Show the top boundary as loading only when the window itself moves.
- A failed refresh no longer hides the empty filter or range placeholder.
- Drop the stale new-executions flag once the list empties.
- Share compactTokens and drop the unused cached token total.
* fix(web-shell): keep trajectory placeholders, news and focus correct after review
- A refresh that fails on an empty window says the window is empty instead
of loading forever.
- The executions strip stays mounted while empty and renders nothing, so
the first execution that arrives while paused still marks Jump to latest.
- When the strip's focused grid goes away with the strip, focus moves to the
records grid instead of the document body.
- Moving to the first row scrolls to the top, so the boundary row with
Load earlier stays in view.
- Refresh marks itself busy with aria-disabled and keeps the reader's focus.
- Share one failure message helper between the summary bar and the panel.
- The toolbar search uses the shared Input primitive.
* fix(web-shell): keep trajectory boundaries, filters and notices reachable
- The executions strip starts watching the panel height when its first
execution arrives, so a panel opened before any execution still folds
the strip once it is short.
- Folding a group while the top boundary is in view keeps the boundary
where it was instead of scrolling it out by one row.
- Jump to latest is measured again when rows grow or the grid gives way
to a placeholder, not only on scroll events.
- The failed-records chip stays while its filter is on, even in a window
without failures, so the filter can still be turned off there.
- Arrow, Home and End keys pressed on a boundary button hand focus back
to the records grid and move the selection.
- Moving the window announces that the selection was dropped again.
- Reuse the shared plural helper and one timeline point formatter.
* fix(web-shell): keep the way back to latest in a history window
Put Back to latest beside Newer records in the bottom boundary, since
Newer is disabled at the first bookmark and after bookmarks are
released. Show the released notice only when no read is loading or
failed, as before the boundary moved into the list.
* docs(managed-agent): propose where a late reply settles after the connection is gone
* docs(managed-agent): record that no producer-side hold can receive a closed-connection reply
* docs(managed-agent): record the closed-connection limit without a hold gate
* docs(managed-agent): record the closed-connection limit without claiming a recovery path
* docs(managed-agent): scope the closed-connection limit to this implementation
* docs(managed-agent): say the connection is marked closed, not destroyed
---------
Co-authored-by: 易良 <1204183885@qq.com>
* test(managed-agent): settle a claim retired at intent (FG11d)
* test(managed-agent): carry the fire answer across threads, name the admission cell
* ci(managed-agent): budget the retire-at-intent cell in the hosted fork
* fix(managed-agent): stop activation renewal after persistent failure
The renewal timer retried every interval for the life of the process. A
stopped writer cannot renew again, so every retry repeated the same
rejection; a transient outage did the same until it ended. Stop the loop
immediately when the authority reports writes stopped, and after three
consecutive failures, which span one full lease. The writer lock, not the
activation horizon, still decides whether a local session is live, so a
stopped renewal loop does not let a live session be treated as abandoned.
* fix(managed-agent): keep renewing through unsettled appends
A renewal that fails with ManagedSessionAppendUnsettledError is
recoverable: the store keeps the unacknowledged append for a later
request to settle and the authority does not mark writes stopped. The
three-failure stop treated it as permanent, so a store outage that
outlived the lease froze the activation horizon for the rest of the
session and every shell admission failed after recovery.
Log it and retry without counting it toward the permanent stop. Add a
case with three unsettled failures followed by a successful tick.
* docs(managed-agent): state the recoverable renewal exception
The stop comment still said every persistent failure ends the loop.
An unsettled append is recoverable and keeps retrying, so say that next
to the three-failure rule it qualifies.
* fix(managed-agent): keep renewing through rollbackable commit rejections
The three-failure stop also counted ManagedSessionCommitRejectedError, the
class the store and authority treat as a rollbackable, non-fencing refusal,
so one workspace-level refusal window permanently ended renewal for a
session that stayed writable. Defer on that class too, and clear the count
on any deferral so the cap measures consecutive refusals rather than a
process lifetime. Document the stop rule and its exemptions in both design
languages.
* test(managed-agent): gate a late conclusive reply after outcome_unknown
* docs(managed-agent): drop the stale late-reply gap sentence
* docs(managed-agent): align the FG12f budget note with the 50 s ledger entry
* test(managed-agent): budget the fourth case at +10 s on main
* docs(managed-agent): align the Chinese decision order with the English one
* test(managed-agent): carry the class entry from 40 s to 50 s
The class re-measures at 24.16 s, so its 2x entry is 50 s, not 40 s. Main
carries it at 30 s, so the delta is +20 rather than the +10 the earlier
draft assumed: healthy 9485, fork 10085, Verify 179, ledger 269, job 282.
The three ledger chains now name this PR's entry, so each comment still
computes the literal below it, and the class Javadoc lists the fourth cell.
* docs(managed-agent): restate the FG12f entry as 30 s to 50 s
* ci: name the FG12f +20 s in the hosted job ceiling comment
---------
Co-authored-by: 易良 <1204183885@qq.com>
* feat(serve): add daemon start wait
qwen daemon start --wait polls /daemon/status until the daemon reports ok, then returns. A timeout keeps the startup log and exits non-zero. The readiness check receives the same --token or QWEN_SERVER_TOKEN used to spawn the child.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(serve): harden daemon start readiness
Revalidate the recorded listener before each readiness probe and again before accepting an ok response, failing the wait if the child exits. Treat the runtime as serving when status is not error and the daemon_runtime_starting issue is absent, so permanent warnings do not cause a false timeout.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* test(serve): pin daemon readiness starting flag
Assert that summarizeDaemonStatus derives the starting flag from the daemon_runtime_starting issue code, so the readiness loop cannot return early during bootstrap.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
---------
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* feat(web-shell): refresh model catalogs from the model selector
* fix(web-shell): stabilize model refresh state and capability tests
* fix(web-shell): preserve refreshed model catalogs and runtime scope
* fix(ci): sync upstream build heap budget
Sync the 6144 MB build heap ceiling from upstream PR #14822 (eeec911c20) after the Java 11 E2E retry again exhausted the 4096 MB heap in CLI compilation.
* test(managed-agent): Measure the post-commit gate as per-round growth (#14197)
The EventTransportBrokerGate post-commit row compared two independent p95 estimates (flag-on vs flag-off) on a shared two-core CI runner, where machine-wide jitter lands on each arm's order statistic differently and a whole-millisecond budget trips on scheduler noise alone. Compute the per-round growth of the interleaved arms instead: a stall inflates the round's arm it interrupts and a real regression — the flag adding work to every round — still fails the millisecond budget at p95. The journal hand-off keeps its absolute 20 ms p95 budget, and the latency record keeps the on/off figures alongside the delta.
* test(managed-agent): Gate the post-commit growth on its median (#14197)
The p95 of the per-round growth let a twelve-of-225 one-arm stall tail
decide the verdict — the arms are measured sequentially on one thread, so
a scheduler/GC pause survives in that round's delta at full size — and it
still failed the recorded incident's arm levels. Read the median of the
per-round growth instead: a stalled minority no longer decides, while a
cost the flag adds to every round shifts the median in full. Keep the
growth p95 and a rounds-over-budget count in the latency record alongside
per-arm p50/p95/p99/max, name every record key after the statistic it
holds, and carry both arm levels in the assertion failure text. Pin the
statistic's contract with a deterministic broker-less check over synthetic
225-sample pairs, and align both design-doc languages with the statistic.
* test(managed-agent): Bound the post-commit growth verdict at 1 ms everywhere (#14197)
The growth verdict no longer inherits the 20 ms CI allowance #14178
reasoned for a p95-of-levels comparison: the median is the
scheduler-noise mitigation, so the budget is one millisecond in every
environment. The verdict moves into growthWithinBudget — median within
budget, and no more than a tenth of the retained rounds over it — which
the broker-less statistics suite now binds to directly. The record
carries the budget its roundsOverBudget count was taken against and
keeps a deterministic on/off/growth key order. The incident-named case
is renamed to the reconstruction it actually feeds, and both design
docs state the re-scope: the recorded #14197 run predates this
statistic and was already tolerated at the merge base by #14178.
* test(managed-agent): Bound the post-commit growth's per-round magnitude (#14197)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
---------
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: qwen-code-autofix <qwen-code-autofix@localhost>
Co-authored-by: 易良 <1204183885@qq.com>
* test(managed-agent): gate the per-run cancel on a parked wake turn (FG11d)
The cell was recorded as blocked for want of a hold point; the parked model is
that hold point. With the wake turn kept parked, the public task cancel settles
the task and the run cancelled in under a second and the schedule stays live.
Releasing the model immediately after the 202 instead lets the turn finish
first and the run settles completed, which is why the cell asserts before the
release.
The case covers the public task id from the tasks projection, one run record,
one cancelled settlement, and a schedule that survives its run's cancel.
Measured at 7.4 s through the packaged stack, so the fork budget follows the 2x
convention: healthy 9480 s, fork 10080 s.
* docs(managed-agent): extend the pom ledger for the cancel cell
The js ledger gained the cell's 15 s but the pom ledger still ended at 9465 s
and 10065 s, contradicting the literal beneath it. The audit trail now records
the same step the pin test carries.
* docs(managed-agent): align the cancel limits text with #14882
Both PRs rewrite the same Limits bullet, so different wording would conflict on
whichever lands second. This takes #14882's sentence verbatim and makes the
delivered note a list item in English as it already is in Chinese.
* test(managed-agent): pin the cancelled task and its occurrence
The cell asserted the run's state and the schedule, while the matrix also wants
the task and the occurrence to settle. It now pins the projected task's kind
(automation_run) so a later task cannot silently take the cancel, the task's
cancelled state, and the manual occurrence firing exactly once.
The Verify step sat at exactly fork + 600 s after the new cell, so its "plus
margin" comment was no longer true; it moves to 179 minutes and the job to 282.
* ci(managed-agent): record the sdk-java workflow's new size
The workflow grew to 108273 bytes on main without bumping its baseline,
so any PR that touches the file - this one bumps the hosted gate's Verify
timeout - inherits a 4231-byte drift past the 4096-byte allowance.
---------
Co-authored-by: 易良 <1204183885@qq.com>
* test(managed-agent): pin which commit the plan rejection hit
The plan cell also passed when the child's own commit was the refused one:
both leave the marker unsettled and the receipt replayable, so the final
status read settles either way. It now asserts the child settled before the
marker clears, which reddens under a HOOK_SETTLED arm.
The result cell's durable read joins the wait it belongs to, and both design
docs record the eventName == "PreToolUse" narrowing and the corrected
first-witness red (the earlier phase refusal fires attempts and reddens on
the physical-call count, not on the wait).
* test(managed-agent): reuse the single-child helper in the plan cell
The review's suggestion is right: the inline lookup re-implemented
hookExecutions() minus its hasSize(1) guard, so a second child could have
satisfied the assertion on the settled record while the refused one went
unchecked. hookExecution() pins hasSize(1) and the PreToolUse event, which is
exactly the discrimination B2 asks for.
---------
Co-authored-by: 易良 <1204183885@qq.com>
* feat(serve): add daemon status detail
qwen daemon status --detail fetches /daemon/status?detail=summary for each running daemon and adds version, uptime, active sessions, and issues to both the human and JSON output. The request carries QWEN_SERVER_TOKEN when set; a 401/403 is reported as unavailable detail instead of failing the whole status command.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* test(serve): cover daemon status detail failures
Pin the auth-required and non-2xx branches of the detail fetch so the unavailable-detail path cannot regress silently.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(serve): harden daemon status detail
Attach QWEN_SERVER_TOKEN only when the discovery record advertises bearer auth and the recorded process is addressable, alive, and its start time matches. A foreign-namespace or otherwise unverifiable record is reported without making the request. Sanitize daemon-derived status, version, and error text before writing the human-readable detail line.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
---------
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(ci): skip Managed Agent reviews after the PR closes (#14774)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* test(ci): pin closed-PR gate wiring and diagnostics (#14774)
* refactor(ci): skip closed-PR reviews at the gate job level (#14774)
#14857 landed the job-level review guard, so a closed-PR approval can skip
before any job starts instead of selecting `none` from inside the tier step.
Move the closed check into the `scope` and `gate` conditions, drop the
`PR_STATE` env wiring and the tier-script branch, and restore the report text
that described it — no job now reports a reason. Tests pin both jobs skipping
for a closed-PR approval and keep open-PR approvals running.
Resolves#14774
* docs(gate): describe an all-skipped review run precisely
This branch already rewrites the lines that describe a skipped review run, so
the correction belongs here rather than in a second PR touching the same
paragraph.
The skipped run still lists one check per job, and the reporting job's name is
shown as its unevaluated expression, so "nothing reported" is wrong on both
counts: three skipped checks appear, none of them named `Managed Agent gate`.
Verified on run 39392964690, a `pull_request_review` event on the #14857 head.
The `scope.if` comment carried the same overclaim ("it never reported the
required name anyway"): on an untouched PR the review run did report
`Managed Agent gate`, and only the same head's pull_request run makes that
check redundant.
---------
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: 易良 <1204183885@qq.com>
* docs(managed-agent): locate the replay branch and the gap contract
Two of the three open questions had answers in the tree. The replay-versus-
snapshot branch is ManagedAgentService.replayableEvents throwing
ReplayCursorExpired below replay_floor_sequence, with ManagedEventStreamService
turning that into one resync frame; the remaining question is which automation
event types reach the Session stream and how a projection gap differs from a
slow projection at the same sequence.
The detected-gap contract also exists, one design document outside the FG11
set: JSON reads answer 409 cursor_expired with the floor and snapshot sequence,
and streams send agent.session.resync_required carrying reload_snapshot without
an id. What is open is whether automation consumers honour it.
The Why section no longer claims nothing in CI covers contiguity: FG6e, FG8e and
FG12f already gate the public, WebShell, monitor and MCP streams, so FG11e is
the automation-journal slice those do not cover.
* docs(managed-agent): keep the replay identifier on one line
CommonMark turns a line ending inside a code span into a space, so the English
file rendered ManagedAgentService .replayableEvents while the Chinese file did
not. The identifier is the point of the sentence, so it now stays intact.
* docs(managed-agent): record what the remaining FG11d cells answer
The cancel bullet promised an unsettled run and a socket EOF. Re-run at this
head: the cancel is accepted, the run keeps going, and once the model is
released it settles `completed`, so the 120 s wait for `cancelled` expires
against a finished run. The close bullet named the managed Session's
workspace-execution check, while the body says `Hosted Workspace execution is
not available.` from the embedded broker and the action store.
Both bullets describe this fixture at this head; neither cell is implemented.
* docs(managed-agent): name the close route, not two classes that are not on it
The close bullet credited the embedded broker and the action store, but the
public close route takes SessionLifecycleService.admit's workspace arm into
ManagedAgentStore.beginWorkspaceLifecycle, and beginLifecycle throws there.
The message is shared by ten raise sites in five classes, so the bullet now
names the route and says the vocabulary is shared, keeping the distinction from
FG11f's non-durable broker resolveScope path.
* docs(managed-agent): keep FG11f's two refusals apart from this lifecycle throw
FG11f records two of them: the non-durable broker's 409 from resolveScope, and,
under the durable broker, WorkspaceExecutionStore's "Workspace execution
authority is unavailable." Naming only the first would send a durable-mode
investigation to the non-durable branch, so the bullet names both and says
neither is this close-path throw.
* docs(managed-agent): record the cancel ordering instead of a missing hold point
The bullet claimed the fixture has no hold point where the cancel wins. The
parked model is that hold point: with the turn kept parked, the task and the
run both settle cancelled in under a second, and releasing afterwards does not
revive them. Only releasing immediately after the 202 lets the turn finish
first, and then the run settles completed. The bullet now reports both
orderings and says the release order decides, not the fixture.
---------
Co-authored-by: 易良 <1204183885@qq.com>
* feat(serve): add qwen daemon start
- spawn qwen serve as a detached child, wait for its discovery record, and print the bound URL, PID, log path, and stop command
- isolate the child from the launching session identifiers and private capability bindings
- pass a supplied token through QWEN_SERVER_TOKEN, require one for non-loopback binds, and keep tokens out of the startup log
- keep startup output in a 0600 file that is removed on success; report the log tail on failure or timeout
- cover argument construction, environment isolation, and summary formatting with unit tests; document the command in both languages
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(serve): harden daemon start workspace and env handling
- drop every QWEN_CODE_PRIVATE_* key by prefix
- pin relative QWEN_RUNTIME_DIR and QWEN_HOME to the launching directory before spawn
- canonicalize workspaces with the same function serve uses before the duplicate-start check and child arguments
- sweep stale start logs after 24 hours and clarify that a timed-out child may still start
- extend daemon tests for relative paths, private-prefix isolation, symlinks, and log sweeping
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(serve): resolve Windows drive-relative daemon start paths
- use isFullyQualifiedPath() to distinguish drive-letter and UNC forms from Windows drive-relative roots
- resolve drive-relative QWEN_RUNTIME_DIR and QWEN_HOME against the launching directory
- add path.win32 coverage for drive-relative and UNC inputs
- document the Windows path behavior in both design languages and the user guide
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(serve): preserve explicit empty daemon start env values
- keep an explicitly empty QWEN_RUNTIME_DIR or QWEN_HOME as an own environment property
- only remove a variable that was truly absent, matching the environment bootstrap Object.hasOwn distinction
- add an Object.hasOwn regression test and document the behavior in both design languages
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
---------
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* test(managed-agent): reject Hook result and plan-result commits (FG13b)
Adds the two remaining store-rejection cells that reuse the existing seam.
The result cell refuses the settled commit after the worker already ran the
Hook, then reads the status route to prove the receipt still settles the
record without a second physical call. The plan-result cell refuses only the
plan marker's own commit, proving the marker is rebuilt from the saved child
receipts.
The registration-settle cell is not here: it writes a hook-catalog record and
the seam has no catalog phase, so it belongs with the FG13a store-ack slice
rather than growing a second seam.
Both cells add 150 seconds to the shared fork: healthy 9111, fork 9711,
Verify 172, ledger 262/275.
* test(managed-agent): scope the plan fault to PreToolUse and wait for it to fail
Arming HOOK_PLAN_SETTLED matched the empty SessionStart and UserPromptSubmit
plans, which commit a settled marker with no hooks at all: the wait fired
before any physical call and the marker lookup could pick the wrong plan.
The phase now also requires eventName == PreToolUse, and the cell filters its
marker the same way; StoreFaultGateTest pins both sides.
Both new cells also cleared the gate as soon as one commit attempt was
rejected, but the store retries the same commit. They now keep the fault
armed until the turn reaches failed and the record is still unsettled, so the
status read has to recover instead of observing the original attempt land.
* test(managed-agent): read the Harness attachment after the fault fires
submit() returns 202 once the dispatch is queued, not once the connector has
attached the Harness session, so a cold or slow scheduler can leave the
lookup null before the fault is even armed. Both cells now wait for
attempts >= 1, which proves the dispatch ran, and only then resolve the
attachment before the recovery-blocked probe.
* docs(managed-agent): scope the FG11e stream-gap gate
The other FG11 slices fault what an automation does and assume the event
journal a client reads is contiguous. This records the three shapes a gap can
take (delivery, projection, wake), the journal columns and consumers a gate
would read, the four properties it must pin, and the two questions that have to
be answered before a fault arm can be aimed: which branch chooses replay over
snapshot, and what a detected gap looks like to a client.
No implementation; the design exists so the next author does not re-derive the
gap shapes from the schema.
* docs(managed-agent): narrow the FG11e faults to what the code guarantees
The wake bullet read the claim watermark as completion, but TransportWakeActivator
claims before it submits the load and leaves a rejected submission to SQL wake
recovery, so a delayed or reordered wake is normal. The fault is a lost
activation after a committed claim, and the property is that SQL wake recovery
still finds the committed, unconsumed input.
The snapshot bullet required snapshot_stale_since to be set. A cursor below the
floor triggers the fallback regardless: ManagedSnapshotStore sets the stale
marker only when covered_sequence overtakes the snapshot, so the gate must check
the snapshot's own coverage and the tail after it, covering fresh and stale
cases separately.
Adds the tracker's other two FG11e scenarios — task-stream resume between fire
and settle, and runs-list pagination across an insert — plus the Session SSE
resume with its observability precondition.
* docs(managed-agent): assert the task stream's whole sequence, not just its end
The tracker asks the task state sequence to replay without duplicates or gaps.
Asserting the terminal state once would still pass if a resume repeated a
`running` transition, and a missing intermediate state is invisible to a count
of terminal states. The bullet now requires the prefix received before the
disconnect plus the suffix after it to equal the task's persisted state-event
sequence item by item, with terminal-once as an additional check.
Two loop types cover two causes each: turn_tool_call_cap is an explicit
model.maxToolCallsPerTurn, the adaptive backstop or a stuck halt past
the soft cap, and global_tool_call_duplicate is the heuristic duplicate
detector or the duplicate provider tool-call id breaker. Each of these
stops now carries an additive loopReason, and cap stops carry the call
count and the limit that applied, on the LoopDetected event, the
loop_detected telemetry and the daemon turn_error. The SDK keeps the
detail on transcript blocks instead of dropping the loop type.
The headless CLI, the TUI loop dialog, OpenTUI and Web Shell (en and
zh-CN) explain each cause and what to change. No detector fires or
stops at a different point. The export renderer budget rises to
2,050,000 for the new i18n keys (+5,139 bytes measured).
Part of #14828.
* wip(managed-agent): stage the FG11f publication arms on a public Shell wake turn
Not ready to push: the warm-up turn is refused with workspace_unavailable
before the fault arm runs. Stage 1 of the stacked chain.
* test(managed-agent): gate the FG11f lost-ack publication fault (FG11f)
A wake turn that publishes a Shell capture can lose the object store's
acknowledgement after the bytes landed. Nothing in CI pins what happens next:
the shared OSS stub accepts every write, and the only real-bucket fault gate is
opt-in and outside CI.
The case runs a public Shell session through the packaged stack, faults the
physical put, and pins the properties the store actually guarantees: the
committed capture is kept and every large object is this run's bytes, a refused
write never stores anything, the operation settles from what the store recorded,
the Shell runs once, and the run settles once. `fail-before-write` and
`timeout` remain scoped in the design.
The fixture now registers the storage guard whenever the guard itself is
enabled. It previously registered only on Linux, so a Shell turn on macOS was
refused before its fault arm could run.
The fork budget follows the 2x convention: the cell measured 41.1 s, so the
healthy sum becomes 8527 s, the fork 9127 s, the Verify step 163 minutes and the
job 256.
* test(managed-agent): gate the FG11f refusing arms (FG11f)
The publication gate shipped only the lost-ack arm, and the case resolves which
arm to run from a property, so CI exercised whichever one the default picked.
The two refusing arms now have their own methods: a put that throws before the
bytes land, and a put that stays silent past the operation timeout. Both assert
that nothing was stored, that the operation stays unresolved, that the Shell
runs once and that the run settles once.
Measured locally through the packaged stack: 41.2 s and 80.0 s. The fork budget
follows the 2x convention, so the healthy sum becomes 8769 s, the fork 9369 s,
the Verify step 167 minutes and the job 260.
* fix(managed-agent): drop the unused import and re-align the ceiling comment
The FG11f case carried an import for a symbol it never used; with
includeTestSourceDirectory on and UnusedImports at error severity, that is a
checkstyle failure rather than a warning. The step-ceiling comment also still
read 161 while the literal beneath it is 163.
* refactor(managed-agent): take the FG11f arm as a parameter and re-align the comments
The wrapper methods delegated through a mutable field, which made the case
property stop narrowing a run: naming one arm also ran the other wrapper and
the default-resolving method. The arm is now a helper parameter and each method
gates on `selected()` the way fg11b and fg11c do, so an unset property runs
every arm and naming one runs only that arm.
Two comments still described the older budget: the step-ceiling line read 161
against a 167 literal, and the job-ceiling derivation stopped at the 9045 s
fork without the FG12d, FG11f-arm or refusing-arm steps it now includes.
* test(managed-agent): pin that the fault fired and the payload is the run's own
Three probes showed the arm passing for the wrong reason: with the injection
removed, with the retained bytes replaced by a same-sized placeholder, and with
the operation never settling, the case stayed green and only an absent object
reddened it. The arm now asserts that its injection fired, that every
OBJECT_PUT settles RETURNED, and that the retained payload is exactly the
Shell's 2 MiB of output.
Two ceiling comments still described the pre-merge budget; both now carry the
FG11f step and the values the literals hold.
* test(managed-agent): count the physical puts each object takes
A reconcile that regressed into writing the same key again would be invisible
to the arm: putIfAbsent reports FileAlreadyExists, the real adapter swallows it
and the object map still holds the first write, so the settlement assertions
keep passing. The stub now counts putObject calls per key and the lost-ack arm
asserts every key was written exactly once.
* test(managed-agent): restore the FG11b retryable-status guard
The merge that retargeted this branch to main resolved the FG11b helper from
the branch side, silently reverting #14645: it accepted a 409 as final and
named only one code on a 503. The helper and the comment above the case are
main's again, so a public route that starts answering 409 fails at once and a
coded 503 must name the writer conflict or the lost-answer code.
* ci(gate): skip the Managed Agent gate run for reviews that are not approvals
`pull_request_review: [submitted]` fires for `commented` and
`changes_requested` too, but only a maintainer's approval can select a tier
above `none`. Every other review started a run that could only publish the
informational check `Managed Agent review (no full run)`, costing two runner
slots on two different runners. Five comments in nine seconds on PR #14656
produced five such runs on one unchanged head.
Both jobs now skip for a non-approval review, which takes no runner, and the
run completes in seconds. The required check name is unaffected: such a review
never reported it, before or after.
Resolves#14854
* test(gate): drop unreachable dispatch case and clarify skipped-run docs
`workflow_dispatch` is not a trigger of `managed-agent-gate.yml`, so the new
"ignores the review guard" case covered an event this workflow cannot receive.
The three real triggers already assert the same property.
The design doc said a non-approval review produces "no run", while the
paragraph below and the concurrency rationale both depend on a run existing
and merely starting no job. Say that directly, in both languages, so the
per-review concurrency group does not read as dead code.
* test(managed-agent): gate result delivery and catalog change on the Hosted MCP path
* test(managed-agent): re-pin the hosted fork budget for the FG12f delivery class
* test(managed-agent): drop the copied reply-loss machinery and pin the delivery record
* test(managed-agent): witness the list change forcing a re-discovery
* docs(managed-agent): stop restating fork budget absolutes in the FG12f design
* wip(managed-agent): stage the FG11f publication arms on a public Shell wake turn
Not ready to push: the warm-up turn is refused with workspace_unavailable
before the fault arm runs. Stage 1 of the stacked chain.
* test(managed-agent): gate the FG11f lost-ack publication fault (FG11f)
A wake turn that publishes a Shell capture can lose the object store's
acknowledgement after the bytes landed. Nothing in CI pins what happens next:
the shared OSS stub accepts every write, and the only real-bucket fault gate is
opt-in and outside CI.
The case runs a public Shell session through the packaged stack, faults the
physical put, and pins the properties the store actually guarantees: the
committed capture is kept and every large object is this run's bytes, a refused
write never stores anything, the operation settles from what the store recorded,
the Shell runs once, and the run settles once. `fail-before-write` and
`timeout` remain scoped in the design.
The fixture now registers the storage guard whenever the guard itself is
enabled. It previously registered only on Linux, so a Shell turn on macOS was
refused before its fault arm could run.
The fork budget follows the 2x convention: the cell measured 41.1 s, so the
healthy sum becomes 8527 s, the fork 9127 s, the Verify step 163 minutes and the
job 256.
* fix(managed-agent): drop the unused import and re-align the ceiling comment
The FG11f case carried an import for a symbol it never used; with
includeTestSourceDirectory on and UnusedImports at error severity, that is a
checkstyle failure rather than a warning. The step-ceiling comment also still
read 161 while the literal beneath it is 163.
* test(managed-agent): pin that the fault fired and the payload is the run's own
Three probes showed the arm passing for the wrong reason: with the injection
removed, with the retained bytes replaced by a same-sized placeholder, and with
the operation never settling, the case stayed green and only an absent object
reddened it. The arm now asserts that its injection fired, that every
OBJECT_PUT settles RETURNED, and that the retained payload is exactly the
Shell's 2 MiB of output.
Two ceiling comments still described the pre-merge budget; both now carry the
FG11f step and the values the literals hold.
* fix(managed-agent): answer self-healing Harness conflicts as retryable 503
The public automation mutations relayed a dead writer's lease as
`409 managed_session_writer_conflict`, which a client following HTTP
semantics reads as final even though the conflict lapses on its own.
Cross the Harness 409s that heal by themselves as the retryable 503,
sharing the channel routes' conflict set, and keep every other 409.
The fault gate now accepts only 202 or 503, pinning the answer.
* test(managed-agent): pin every self-healing Harness conflict code
Parameterize the retryable-conflict test with a fixed list of the four
codes instead of checking only the writer conflict. Dropping a member
from the shared set now fails the test rather than passing silently.
* fix(managed-agent): keep deferred manual runs inside the scanner budget
A manual-run retry under the same key re-fired a still-firing occurrence
and deferred it again, so a client retrying at roughly 1 Hz could reach
MAX_FIRE_ATTEMPTS and settle the run unknown. Answer the retryable 503
while the recorded defer is still in the future; the scanner owns the
next fire.
Record the hosted_session_blocked exclusion and pin the gate's 503 code.
* fix(managed-agent): let the first lost-answer retry re-drive the run
The defer-window guard blocked the first same-key retry after a lost
answer, so the FG11a manual-run-reply case answered 503 where it expects
202. Apply the guard only once the first re-drive has been spent
(attempts > 1); the first retry still re-drives, and a later retry
answers the code the defer recorded.
Record the defer-window behaviour in the b2 design twins and reconcile
the hosted_session_blocked exclusion with the scanner.
* fix(managed-agent): keep an in-window retry in the recorded refusal class
The defer-window guard answered every in-window retry as a retryable 503,
including final refusals such as hosted_session_blocked, so the same key
and row switched from 409 to 503. Re-answer the class the recorded code
implies: 503 for a transient or lost answer, the same 409 for a final
refusal. Add unit cases for both branches and record the rule in the b2
design twins.
* test(managed-agent): accept the lost-answer code in the FG11b retry gate
The tightened retryUntilAccepted rejected a legitimate 503
automation_operation_unknown: on a cold restart the first retry can lose
its answer before the dead writer's lease is observable. Accept that code
alongside managed_session_writer_conflict, while still rejecting 4xx and
any other coded 503.
* test(managed-agent): teach the store fault gate the Hook phases
* test(managed-agent): reject a Hook intent commit in the store transaction
* test(managed-agent): reject a Hook dispatch commit in the store transaction
* test(managed-agent): teach the model stub the new FG13 prompts
* ci(workflows): raise the sdk-java ledger baseline for the FG13b entries
* test(managed-agent): tighten the FG13b cells and document the gate
* test(managed-agent): describe the store fault gate for both record families
* test(managed-agent): skip the plan marker in the Hook failure phases
* test(managed-agent): pin which Hook commit the store gate refuses
The two FG13b cells only waited for the gate to fire, so swapping the
intent and dispatch_started branches kept both green. The intent cell now
asserts that the rolled-back commit left no hook_execution record, and the
dispatch cell asserts a single record still parked at intent.
The design doc's mutation witnesses now describe the red each mutation was
measured to produce: the phase and domain mutations time out on attempts,
and letting every commit through stays green inside the shipped window and
only reddens once the window is widened.