Close Spring contexts before fixture database cleanup, run integration classes in isolated reusable forks, and remove redundant fixture validation and duplicate load-test execution. Document bounded local validation and preserve full CI gates.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(ci): align Java integration database and lock lifetime
* test(ci): re-pin the sdk-java lock and MySQL probe after the single-step merge
The merge commit staged the conflict resolution before these two re-pins were
written, so they land as a follow-up in the same push:
- `keeps the host lock out of every Maven child` counted three lock-bearing
steps; #14903 collapsed the MariaDB lane's two Maven steps into one, so the
count is now two (test job + mysql-integration).
- The MySQL startup probe took the step's first `mvn` line, which is now the
`-DskipTests install` staging command; select the `-Pmysql-integration`
command instead so the probe still exercises the consumer.
Verified: vitest sdk-java-workflow.test.js 96 passed; prettier --check clean.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Patrol-Run: qwen-pr-conflict/jmvgz448zlp
* fix(ci): skip the MySQL binlog, drop the unused database, correct the reaper bound
Three independent corrections to the mysql-integration lane this PR reworks.
1. MySQL 8 enables the binary log by default (MariaDB 10.11 did not in the
configuration this lane replaced), and the datadir is an uncapped tmpfs.
Nothing in packages/managed-agent-server/src or packages/sdk-java reads a
binlog (0 hits for binlog|log_bin|GTID|SHOW MASTER STATUS), and the
container is disposable with no replica, so `--skip-log-bin` is appended
after the image name beside --innodb-use-native-aio=0. Without it the
~67 MiB hex-encoded LONGBLOB query this lane already raises
max_allowed_packet for is serialized a second time into host RAM.
2. `--env MYSQL_DATABASE='runtime_broker_test'` had no consumer: the lane's
only connection is -Dmysql.url=.../managed_agent_test?createDatabaseIfNotExist=true.
The declaration invited a cleanup that drops createDatabaseIfNotExist and
dies at first connect with Unknown database. Dropping it lets the JDBC URL
own the schema and shrinks the diff.
3. The cleanup comment and removal-failure warning said the host reaper
reclaims a stranded container "after a 24h age gate" / "up to a day".
The real bound is ~48h: qwen-docker-cleanup.sh:31 gates on a strict
`now - created_at > 86400` (exactly 24h is SKIPPED) and
qwen-docker-cleanup.timer fires once a day, so a container created just
after a fire is skipped at the next one and reaped at the one after.
Test pins updated in the same change: the start-step assertion, the exact
docker-run trace literal, and the cleanup warning literal. All three were
mutant-verified red (drop --skip-log-bin / re-add MYSQL_DATABASE / restore
"after 24h") and restored byte-identical.
Only this PR's own copy of the reaper wording is corrected; the two
pre-existing copies (sdk-java.yml's event-transport-multi-node job and
release-managed-agent-reference.yml) are untouched to keep this diff scoped.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Patrol-Run: qwen-pr-closeout/jmvhb9cysmc
* feat(ci): restore a MariaDB leg for the non-Hosted IT family
#14936 moved the mysql-integration lane onto MySQL 8.4 and removed the last
real MariaDB server, leaving the published MariaDB-only V12 repair (RTRIM,
error 1901) and the schema catalog's MariaDB branches without a falsifier.
Both engines now run the same non-Hosted *IT family as two matrix legs of one
job: the container image, its startup arguments, its client, and its readiness
signal come from the leg, and the container name carries the engine so two
legs on one pool host cannot collide.
---------
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* feat(managed-agent): Add session lifecycle UI and reading exports
Expose durable lifecycle actions and archive navigation in Managed Web Shell, with identity-scoped browser recovery and immutable HTML/Markdown reading exports.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(managed-agent): Resolve lifecycle review and smoke regressions
Use the host React DOM server renderer, announce global errors once, and advance the OpenAPI version. Keep smoke selectors specific to session navigation and align the Workspace expectation with its existing Managed label.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* test(managed-agent): Preserve schema bindings in channel race fixture
Reuse the production schema-aware JDBC template so repeated H2 queries keep binary identity parameters. Preserve the existing ownership race and its assertions.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(managed-agent): Correct lifecycle retry and export handling
Keep failed unadmitted archive intents idle until explicit retry, scope approval capability to each session profile, and preserve public export semantics and embedded downloads.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
---------
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* test(managed-agent): keep a settled run's outcome (FG11d)
* test(managed-agent): reuse a same-key cancel (FG11d)
* test(managed-agent): refuse a second fire while the turn runs (FG11d)
* revert: move the second-fire cell onto its own branch
The cell belongs to the next PR in the chain, which bases on this branch, so
it cannot also live here: the next PR's diff would be empty. Content of this
branch is unchanged from acdab642b7.
* test(managed-agent): refuse a second fire while the turn runs (FG11d)
* test(managed-agent): keep a sibling run alive past a cancel (FG11d)
* docs(managed-agent): name the settled run's real refusal code
The cell's own comment still said task_already_settled while the assertions
and both design docs record 409 task_action_unavailable, which is the code the
measured behaviour actually answers.
* test(managed-agent): assert the replayed cancel operation's identity
The cell discarded both cancel responses, so "reuses its operation" rested on
the run state alone — which a second operation could also have produced. It now
compares the two operation ids, pins task_id to the cancelled task, and asserts
the replay flag flips false then true.
* docs(managed-agent): separate the queued-input claim from the settled one
The bullet ran the two claims together with no separator, so a reader could not
tell whether "a queued input cancelled before any attempt" was delivered too.
Both language versions now take the same form as the neighbouring bullets, and
the Chinese continuation line gets its indentation back.
* test(managed-agent): pin the occurrence ledger in the isolation cell
Review R1-1 and R1-2: the cell's comment claimed the schedule's future fires
survive, which nothing in it observes, and it was the only cancel cell that
never read ma_schedule_occurrence. The comment now says what the cell proves
(the definition stays live; a scheduled slot is outside the arm) and the cell
pins both keys fired exactly once with no re-drive. The workflow comment's
wrap figure follows the fork to 11781.
* docs(managed-agent): leave the queued-input arm open and fix its carriers
Review round 2. R1-1: the queued-input criterion is reachable, so the bullet
no longer books it delivered — under queue_one (and allow below quota) a second
manual fire is admitted while the first run is active, because hasOpenTurn reads
only public ma_turn rows. The cell pins the default-skip refusal, not that arm.
R1-10: the cell's comment now names the count arm instead of the open-Turn arm.
R2-1/R2-2: the workflow's two budget comments and both derivation ledgers record
this cell's 25 s (fork 11212, healthy 10612).
* test(managed-agent): catch a re-drive by attempts, not by row count
Review R1-2 on this PR: the count assertion cannot witness a re-drive, because
the occurrence primary key makes a re-drive an UPDATE that bumps attempts rather
than an INSERT. Both keys now pin attempts == 0, and the count assertion is
labelled for what it does catch - a spurious third key. Re-ran the cell on
JDK 21 + MySQL 8.0.46: 6.204 s, green.
---------
Co-authored-by: 易良 <1204183885@qq.com>
* feat(web-shell): allow hosts to inject disabled catalog models
Hosts can show product models that are not currently usable in the composer picker, with a framework-neutral hover slot for text or authorize actions.
Co-authored-by: Cursor <cursoragent@cursor.com>
* docs(web-shell): add unavailable-model picker screenshots
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web-shell): polish unavailable-model tooltip card
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web-shell): make unavailable models look disabled
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(ci): isolate script fixtures and reuse runtime archives
* test(cli): bound command budget fixture work and drain timed-out writes
---------
Co-authored-by: Ethan Ye <ethanye@U-463KXYWL-1938.local>
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(ci): bound the MariaDB lane's cache write-back and size its ceiling (#15000)
Run 39563394993's mysql-integration job was cancelled at the 200-minute ceiling: 54 minutes queued for the host lock, 75 minutes of Maven work, then a 60-minute unbounded tar of the host-shared ~/.m2. The cache is an optimization, so skip it after five minutes; the ceiling now covers the 90-minute wait, the measured Maven pass, the bounded write-back and setup headroom.
* fix(ci): write back only the MariaDB lane's Maven delta by hardlink
The bounded tar pipeline extracted straight into the host-shared ~/.m2,
so a timeout mid-member left a truncated artifact that --skip-old-files
never repaired and the next seed hardlinked into its job. Its 300 s cap
was also below the measured 26-61 minute whole-tree cost, so it would
have tripped on every run.
Publish only the files Maven fetched in this job (nlink == 1 after the
hardlink seed) with per-file cp -ln, keeping the two in-house excludes.
Each link is atomic and never replaces a host file, so the 300 s
backstop can only leave artifacts missing. Distinguish the timeout from
other failures, and fold the backstop into the derived ceiling floor
instead of a second hardcoded one.
* ci: record sdk-java.yml's real size in the workflow ratchet
This PR grows .github/workflows/sdk-java.yml from 113473 to 114180 bytes:
the MariaDB lane's timeout ceiling moves 200 -> 280 with the arithmetic
that justifies it, and the Maven write-back is rewritten to publish only
this job's own downloads (nlink == 1) under a 300 s backstop instead of
taring the whole tree. The growth is the change, so record it rather than
move the step out.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Patrol-Run: qwen-pr-conflict/jmvj37bcsp8
---------
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(ci): serve the fast Java tier before full-tier lock holds (#15032)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(ci): keep a parked lock head's ticket alive under fast priority
A head blocked in `flock --wait` could not touch its ticket, so once a
hold outlasted the 1800s mtime arm another waiter reaped a live head and
the next ticket, whatever its class, parked in the kernel too. With two
classes that lets normal tickets take kernel positions ahead of fast
tickets that arrive later during a long hold. A keepalive now refreshes
the parked head's ticket at the waiters' two-second cadence; it closes
the lock fd and uses `touch -c`, so it can neither hold the lock nor
recreate a removed ticket.
The ordering and promotion cases used a stub whose `--wait` returned
every 200 ms, so they exercised a head that loops, which production never
does. They now park `--wait` until release and assert the reachable
paths: a fast ticket overtaking a normal ticket that is still waiting,
and a promoted waiting normal ticket preceding a later fast ticket.
The comments and design docs no longer claim a fast job waits at most
the hold already running (a parked head still goes first) or cite
#14962/#15032 as fast-behind-full evidence; they state what priority
removes and that a single hold longer than the budget is outside it.
---------
Co-authored-by: Qwen Autofix <qwen-code-assistant@users.noreply.github.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: wenshao <shaojin.wensj@alibaba-inc.com>
* test(managed-agent): keep a settled run's outcome (FG11d)
* test(managed-agent): reuse a same-key cancel (FG11d)
* test(managed-agent): refuse a second fire while the turn runs (FG11d)
* revert: move the second-fire cell onto its own branch
The cell belongs to the next PR in the chain, which bases on this branch, so
it cannot also live here: the next PR's diff would be empty. Content of this
branch is unchanged from acdab642b7.
* test(managed-agent): refuse a second fire while the turn runs (FG11d)
* docs(managed-agent): name the settled run's real refusal code
The cell's own comment still said task_already_settled while the assertions
and both design docs record 409 task_action_unavailable, which is the code the
measured behaviour actually answers.
* test(managed-agent): assert the replayed cancel operation's identity
The cell discarded both cancel responses, so "reuses its operation" rested on
the run state alone — which a second operation could also have produced. It now
compares the two operation ids, pins task_id to the cancelled task, and asserts
the replay flag flips false then true.
* docs(managed-agent): separate the queued-input claim from the settled one
The bullet ran the two claims together with no separator, so a reader could not
tell whether "a queued input cancelled before any attempt" was delivered too.
Both language versions now take the same form as the neighbouring bullets, and
the Chinese continuation line gets its indentation back.
* docs(managed-agent): leave the queued-input arm open and fix its carriers
Review round 2. R1-1: the queued-input criterion is reachable, so the bullet
no longer books it delivered — under queue_one (and allow below quota) a second
manual fire is admitted while the first run is active, because hasOpenTurn reads
only public ma_turn rows. The cell pins the default-skip refusal, not that arm.
R1-10: the cell's comment now names the count arm instead of the open-Turn arm.
R2-1/R2-2: the workflow's two budget comments and both derivation ledgers record
this cell's 25 s (fork 11212, healthy 10612).
---------
Co-authored-by: 易良 <1204183885@qq.com>
* test(managed-agent): keep a settled run's outcome (FG11d)
* test(managed-agent): reuse a same-key cancel (FG11d)
* test(managed-agent): refuse a second fire while the turn runs (FG11d)
* revert: move the second-fire cell onto its own branch
The cell belongs to the next PR in the chain, which bases on this branch, so
it cannot also live here: the next PR's diff would be empty. Content of this
branch is unchanged from acdab642b7.
* docs(managed-agent): name the settled run's real refusal code
The cell's own comment still said task_already_settled while the assertions
and both design docs record 409 task_action_unavailable, which is the code the
measured behaviour actually answers.
* test(managed-agent): assert the replayed cancel operation's identity
The cell discarded both cancel responses, so "reuses its operation" rested on
the run state alone — which a second operation could also have produced. It now
compares the two operation ids, pins task_id to the cancelled task, and asserts
the replay flag flips false then true.
* docs(managed-agent): separate the queued-input claim from the settled one
The bullet ran the two claims together with no separator, so a reader could not
tell whether "a queued input cancelled before any attempt" was delivered too.
Both language versions now take the same form as the neighbouring bullets, and
the Chinese continuation line gets its indentation back.
* fix(release): cover every spawned vendored binary in the tarball exec-bit gate
The gate matched only vendor/ripgrep/*/rg, but the tarball spawns a second
vendored executable: vendor/landlock-run/<arch>-linux/qwen-landlock-run. Its
own runtime heal shares the ripgrep heal's hard limit — it can only chmod an
install the running user owns, so a root-owned sudo install degrades the
same silent way. Widen the expected set with a small spec list keyed on the
leaf binary's presence (the landlock-run/src source directory falls out
structurally), parse every regular-file tar entry instead of a single
ripgrep regex, and extend the fixture tests to cover both trees with
pass/reject cases.
Also correct the stale comment above the landlock heal: it claimed npm
archives strip non-bin exec bits, which is the inverse of what #12668
established — pnpm's packer wrote 0644 for every non-bin entry from 0.24.4
to 0.25.3; npm keeps working-tree modes.
Refs #12668
* fix(release): keep missing-binary strictness in the widened exec-bit gate
Deriving the expected set from the leaf binary's presence meant a platform
directory whose binary was dropped during staging silently shrank the
expected set: a dist without vendor/ripgrep/x64-linux/rg but with the
directory would pass with five entries. Platform membership now comes from
the directory name alone — ripgrep skips '-win32', landlock-run skips the
'src' source directory — so a missing binary fails as 'missing from the
packed tarball' again, matching the pre-widening strictness. Also update the
function doc block, which still claimed the gate covered ripgrep only.
Regression test: an empty ripgrep platform directory fails with the
missing-entry diagnostic even when every other binary passes.
* fix(ci): align Java integration database and lock lifetime
* test(ci): re-pin the sdk-java lock and MySQL probe after the single-step merge
The merge commit staged the conflict resolution before these two re-pins were
written, so they land as a follow-up in the same push:
- `keeps the host lock out of every Maven child` counted three lock-bearing
steps; #14903 collapsed the MariaDB lane's two Maven steps into one, so the
count is now two (test job + mysql-integration).
- The MySQL startup probe took the step's first `mvn` line, which is now the
`-DskipTests install` staging command; select the `-Pmysql-integration`
command instead so the probe still exercises the consumer.
Verified: vitest sdk-java-workflow.test.js 96 passed; prettier --check clean.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Patrol-Run: qwen-pr-conflict/jmvgz448zlp
* fix(ci): skip the MySQL binlog, drop the unused database, correct the reaper bound
Three independent corrections to the mysql-integration lane this PR reworks.
1. MySQL 8 enables the binary log by default (MariaDB 10.11 did not in the
configuration this lane replaced), and the datadir is an uncapped tmpfs.
Nothing in packages/managed-agent-server/src or packages/sdk-java reads a
binlog (0 hits for binlog|log_bin|GTID|SHOW MASTER STATUS), and the
container is disposable with no replica, so `--skip-log-bin` is appended
after the image name beside --innodb-use-native-aio=0. Without it the
~67 MiB hex-encoded LONGBLOB query this lane already raises
max_allowed_packet for is serialized a second time into host RAM.
2. `--env MYSQL_DATABASE='runtime_broker_test'` had no consumer: the lane's
only connection is -Dmysql.url=.../managed_agent_test?createDatabaseIfNotExist=true.
The declaration invited a cleanup that drops createDatabaseIfNotExist and
dies at first connect with Unknown database. Dropping it lets the JDBC URL
own the schema and shrinks the diff.
3. The cleanup comment and removal-failure warning said the host reaper
reclaims a stranded container "after a 24h age gate" / "up to a day".
The real bound is ~48h: qwen-docker-cleanup.sh:31 gates on a strict
`now - created_at > 86400` (exactly 24h is SKIPPED) and
qwen-docker-cleanup.timer fires once a day, so a container created just
after a fire is skipped at the next one and reaped at the one after.
Test pins updated in the same change: the start-step assertion, the exact
docker-run trace literal, and the cleanup warning literal. All three were
mutant-verified red (drop --skip-log-bin / re-add MYSQL_DATABASE / restore
"after 24h") and restored byte-identical.
Only this PR's own copy of the reaper wording is corrected; the two
pre-existing copies (sdk-java.yml's event-transport-multi-node job and
release-managed-agent-reference.yml) are untouched to keep this diff scoped.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Patrol-Run: qwen-pr-closeout/jmvhb9cysmc
---------
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* test(managed-agent): resume the automation streams across a settle (FG11e)
Gate the FG11e row of #14446 with two cells in the FG11 automation class.
One cuts a run's task event feed and a public Session stream while the
wake Turn is held between its fire and its settle, and resumes both from
their last positions; the other pages the run list across an insert. The
Session arm asserts today's precondition that a run adds no event to the
Session stream, so it gates the resume across that window rather than
automation content.
The cells book 39 s on the shared Hosted fork (healthy 10272 s, fork
10872 s, so the Verify step moves to 192 minutes and the job ceiling to
295), and the FG11e design record moves to partly delivered in both
languages.
* test(managed-agent): decode the FG11e task cursor independently
The stream cell built each expected task cursor with the store's own
encoder, so the cursor format was never witnessed apart from the code
that writes it. The served cursor is now decoded in the test and must
name its row's sequence. The Session comparison trims the ledger with a
limit instead of subList, so a stream that served more frames than the
journal holds fails as an assertion rather than an IndexOutOfBounds.
* test(managed-agent): count each run's settle in the FG11e list cell
The run-list cell counted model Turns for the automation but never read
the settle commands, so a run settled twice without a second model call
would pass it, while both design records say each cell checks one settle
per occurrence. It now asserts the journal holds exactly one settleRun
per run, in the order the runs settled.
* test(managed-agent): fail an FG11e task cursor outside its format
The independent cursor check fell back to the decoded text when it did
not match the cursor format, so a cursor that decodes to a bare number
became a valid-looking sequence and matched the ledger. A cursor outside
the format now fails the check outright.
* test(managed-agent): rebook the FG11e cells at their slower samples
Two later runs measured the stream cell at 14.1 s and the run-list cell
at 5.6 s, above the 13.8 s and 5.2 s the ledger was booked against. At 2x
the slower samples the cells take 41 s: healthy 10424 s, fork 11024 s,
which the 194-minute Verify step still wraps with 16 s of margin.
* feat(managed-agent): derive Session Store wiring on a single host
An enabled Hosted Harness requires the Managed Session Store, yet the
store's switch, base URL and workspace ID all had to be configured by
hand, and the shipped templates set a workspace ID that the documented
local-process tool path then rejects.
The store now follows the Harness switch, takes its base URL from this
server's loopback or wildcard listener, and shares the Runtime Broker's
workspace identity, derived from the Workspace directory when no ID is
set. Explicit values keep precedence. Preflight reports the effective
store wiring, and the templates, bootstrap and deployment guide name the
Workspace directory instead of a conflicting ID.
* fix(managed-agent): derive no plaintext Store URL for a TLS listener
When the public listener serves TLS through server.ssl and no
dedicated internal listener exists, the derived http:// loopback URL
reached the TLS connector, so every Store call failed while preflight
reported PASS. Such a listener now derives nothing and the existing
refusal asks for an explicit URL. The internal listener is always
plaintext, so it still derives behind a TLS public listener.
* test(managed-agent): pin the dual-path entry to the derived Store wiring
The dual-path README contract still required the explicit store switch
that the entry no longer exports, and its ordering check would pass
vacuously once the name was gone. It now checks that the store follows
the Harness by default, that Prerequisites exports the workspace ID,
and that the Harness base-url export precedes the restart cue, with
both positions required.
* test(managed-agent): lose the store ack after the result commit (FG13a)
StoreFaultGate's existing seam rejects a commit before it applies, so the
whole commit rolls back. This layer adds the opposite failure: the commit
lands and the caller never sees its acknowledgement. The faulting store
calls afterApply only after super.apply succeeds; the new cell proves one
physical Hook call, a durable settled result, and a status read that
returns it without a second call.
Adds the bilingual design note. One cell adds 150 s to the shared fork:
healthy 10189 s, fork 10789 s, Verify 190 minutes, job 293 minutes.
* test(managed-agent): keep the durable dispatch after a lost ack (FG13a)
* test(managed-agent): reuse the pinned registration after a lost ack (FG13a)
* test(managed-agent): report the lost ack after the commit lands (FG13a)
* test(managed-agent): let the dispatch ack-loss cell call its Hook (FG13a)
* docs(managed-agent): describe the ack seam without overclaiming (FG13a)
* test(managed-agent): bound the dispatch recovery instead of guessing (FG13a)
* docs(managed-agent): carry the audit fixes into the registration slice (FG13a)
* docs(managed-agent): align the Chinese dispatch slice with its cell (FG13a)
* docs(managed-agent): drop the model-request claim from the Chinese slice (FG13a)
* docs(managed-agent): align the Chinese registration slice budget (FG13a)
* test(managed-agent): witness the replay instead of a transient phase (FG13a)
* test(managed-agent): witness the replay on the registration ack loss (FG13a)
* test(managed-agent): lose the store ack after the result commit (FG13a)
StoreFaultGate's existing seam rejects a commit before it applies, so the
whole commit rolls back. This layer adds the opposite failure: the commit
lands and the caller never sees its acknowledgement. The faulting store
calls afterApply only after super.apply succeeds; the new cell proves one
physical Hook call, a durable settled result, and a status read that
returns it without a second call.
Adds the bilingual design note. One cell adds 150 s to the shared fork:
healthy 10189 s, fork 10789 s, Verify 190 minutes, job 293 minutes.
* test(managed-agent): keep the durable dispatch after a lost ack (FG13a)
* test(managed-agent): report the lost ack after the commit lands (FG13a)
* test(managed-agent): let the dispatch ack-loss cell call its Hook (FG13a)
* docs(managed-agent): describe the ack seam without overclaiming (FG13a)
* test(managed-agent): bound the dispatch recovery instead of guessing (FG13a)
* docs(managed-agent): align the Chinese dispatch slice with its cell (FG13a)
* docs(managed-agent): drop the model-request claim from the Chinese slice (FG13a)
* test(managed-agent): witness the replay instead of a transient phase (FG13a)
* test(managed-agent): lose the store ack after the result commit (FG13a)
StoreFaultGate's existing seam rejects a commit before it applies, so the
whole commit rolls back. This layer adds the opposite failure: the commit
lands and the caller never sees its acknowledgement. The faulting store
calls afterApply only after super.apply succeeds; the new cell proves one
physical Hook call, a durable settled result, and a status read that
returns it without a second call.
Adds the bilingual design note. One cell adds 150 s to the shared fork:
healthy 10189 s, fork 10789 s, Verify 190 minutes, job 293 minutes.
* test(managed-agent): report the lost ack after the commit lands (FG13a)
* docs(managed-agent): describe the ack seam without overclaiming (FG13a)
* docs(managed-agent): drop the model-request claim from the Chinese slice (FG13a)
* test(managed-agent): keep a settled run's outcome (FG11d)
* docs(managed-agent): name the settled run's real refusal code
The cell's own comment still said task_already_settled while the assertions
and both design docs record 409 task_action_unavailable, which is the code the
measured behaviour actually answers.
* feat(core): separate app launcher and JS interpreter runtime boundary
Establishes the runtime boundary the Bun migration (MYWO-8 S1) needs
before workers, hooks, sandbox helpers and the code-mode host spawn
JavaScript children under a future compiled-app flavor: arbitrary-JS
child processes resolve their interpreter through one accessor (package
manifest first, process.execPath fallback) instead of reading
process.execPath directly, Bun detection has a single seam, and the
app-launcher contract is documented alongside the full call-site
inventory in a bilingual design doc. Adds the same-fixture Node/Bun
regression matrix (stdio framing, exit codes, SIGTERM, IPC channel,
--expose-gc, --input-type=commonjs --eval).
* fix(core): anchor interpreter resolution to the trusted install root
Arbitrary-JS child resolution no longer walks upward looking for a
manifest: the only trusted location is the standalone package root —
the parent of the caller's bundle directory, which must hold both a
manifest.json and the standalone entry marker lib/cli-entry.js — so an
unrelated ancestor manifest in npm, source or SDK layouts can never be
read. Declarations are validated before use: runtime must be exactly
'bun' or 'node', and the interpreter must be an existing executable
regular file; any invalid or missing declaration falls back to
process.execPath without throwing (non-string interpreter, directory,
non-executable file, unknown runtime, absent binary, missing marker).
Adds the regression matrix for unrelated ancestor manifests (npm
bundle and deep SDK layouts), object/number/directory interpreters,
unknown runtime, missing and non-executable interpreters, and the
trust anchor; syncs both design-doc language versions with the
validated contract.
* docs(design): complete the migration inventory handoff
Adds the three interpreter-identity call sites the re-review found
missing from the call-site inventory (hook-command-cgroup launcher,
bwrap-execution and landlock-execution allowlist staging), marks the
unwired rows as owned by the S3 migration sweep, and notes platform
applicability: the cgroup/bwrap/landlock rows are Linux-only
mechanisms validated against the Linux targets of the platform
matrix, while the mem0 and pem rows apply on every platform. Both
design-doc language versions are updated; no product or test code
changes.
* feat(core): add a real PTY backend for the Bun runtime
Under Bun, @lydell/node-pty's wrapper pumps the PTY master fd through a
tty.ReadStream, and Bun surfaces the nonblocking fd's EAGAIN as an error
event instead of "no data yet", destroying the stream and closing the
master: onData never fires, resize fails with EBADF, and the shell tool
and web terminal hang. Reproduced on Bun 1.3.14 and 1.4.0.
getPty() now loads a qwen-bun-pty backend under Bun (non-Windows) that
drives the same native addon directly with a main-thread async fs.read
pump: EAGAIN retries on a short timer instead of erroring, EIO/EBADF end
the pump and close the fd, writes queue through an async fs.write with
EAGAIN retries, and exit waits briefly for the drained fd so data is
never truncated behind onExit. The wrapper's observable contract (env
sanitizing, flow-control bytes, encoding, resize validation, IPty
lifecycle) is mirrored, and the pump starts in the constructor so an
unpumped fd can never hold the event loop open.
Packaging stages the node-pty addon for both runtime flavors, since Bun
installs now load it through this backend. The Windows-under-Bun gate
stays honest (explicit load error), and the runtime-boundary design docs
point at the new backend doc for the mechanism and evidence.
Tests: unit coverage for the backend lifecycle (output, write, resize,
kill, pause/resume, flow control, raw encoding), getPty selection under
Bun/Windows, and a cross-runtime regression that runs the same fixture
through the real getPty() seam under both Node and Bun when a bun binary
is present.
* fix(core): keep PTY exit detection alive while paused
The pinned node-pty addon fires its native exit callback only around
master-fd read activity (isolated-probe evidence, identical on Node and
Bun), so the old pause() that stopped the pump lost onExit entirely:
pause then child exit left the master fd open and the host unable to
drain — the same mechanism behind the XOFF-then-cancel FD residue under
handleFlowControl.
pause() now buffers output into a bounded hold (1 MiB) that resume()
flushes, while reads continue so exit detection rides on the pump.
On end of life the hold is discarded for wrapper parity: onExit arrives
exactly once and the fd is released, but resume-after-exit replays
nothing, matching the wrapper's destroyed paused socket. Docs are
synced to the actual main-thread async fs.read pump (the earlier
worker-threads/blocking-read sketch is documented as abandoned), and
regressions cover pause-at-exit, hold overflow, and XOFF-cancel on both
runtimes.
* fix(core): make the Bun PTY pause hold lossless and exits leak-free
Serializes master-fd reads behind an in-flight guard (a resume chaining
into a read that is still outstanding would cross-observe the shared
64 KiB buffer), holds paused output without a cap so nothing is ever
silently dropped, and routes every end-of-life path through one cleanup
that flushes the decoder, stops the retry timer, closes the master fd
and fires onExit exactly once — including the 500 ms fallback, which is
now ref'd so exit delivery cannot depend on a droppable timer. Pins all
of it with byte/line-exact regressions: no-gap pause/resume storms and
a ~1.9 MB flood resumed byte-for-byte, cross-runtime.
* fix(core): cap the Bun PTY pause hold and terminate on overflow
The lossless pause hold could grow without bound while a consumer
stays paused. The hold now copies chunks into fixed 64 KiB blocks
under a per-pty byte ledger (4 MiB default) inside a process-wide
budget (32 MiB total hold, 8 active ptys, 1 MiB write queue), so the
bound holds for any producer chunk pattern.
Reaching a cap terminates that pty (SIGTERM then SIGKILL) and emits
one structured PtyLimitError — never a success result and never a
fabricated native exit; the real signal death lands only in
stats.nativeExitRecord. Shell executions converge the error into
{error, exitCode: null, signal: null}; web terminals mark the session
failed and the /terminal route sends an error control frame followed
by close 4001. Node behavior is unchanged.
Design docs corrected per review: the drip "kernel corruption" claim
is withdrawn, and exit detection wording no longer overstates when
exits are observed.
* fix(core): harden post-termination pty edges per review
Dual-review follow-ups on the bounded hold: resize() joins write() in
treating a terminated/closed pty as a no-op instead of throwing EBADF
from the addon; a read that was in flight when the limit termination
closed the fd no longer delivers or re-charges its late bytes; and a
resume() replay stops at the first data listener that terminates the
pty, so no held bytes flow after the structured error.
* fix(core): detach pty error subscriptions by observed shape, not assumed Disposable
node-pty's Terminal.prototype.on proxies the listener to its master socket
and returns undefined, while an EventEmitter-based pty (the Bun backend)
returns the emitter itself. The registry stored that return value as a
Disposable and called dispose() on release, so every Bun release, natural
exit, or backend failure path threw TypeError from the route/registry and
could take the whole serve process down (server exit 1, client saw 1006
instead of the explicit close).
Store the subscription return as unknown and detach by observed shape: a
real { dispose } is used as-is, otherwise off/removeListener removes the
listener, and undefined (node-pty's actual return) keeps the previous
no-dispose behavior unchanged.
Covered by two registry unit tests on the mocked shapes plus a real-serve
lifecycle probe (release 4004 / exit 4000 / backend over-limit 4001 with
failed-session reconnect replay, server alive throughout) run under Bun
1.3.14, Bun 1.4.0, and Node.
* fix(core): close Bun PTY fds only after in-flight ops settle
Review round on #14046:
- bun-pty closeFd() ran closeSync() while libuv fs.read/fs.write ops could
still own the master fd, so the recycled descriptor number could take a
queued write into an unrelated session. fdClosed now flips and the
process-wide admission slot is released immediately, but the real close
is deferred until the last outstanding op settles, with witnesses for
both the read-held and write-held arms.
- A write-side EIO/EBADF (child already gone) is the expected teardown
race and is no longer reported, matching the wrapper's swallowed EIO;
other write errors keep their errno code so the entry classifier and
getPtyLimitMessage can recognize them instead of escaping as an
uncaught exception. The pump's emit dispatch runs under try/finally so
a throwing error listener can never strand the pump.
- The web-terminal registry's pty error subscription no longer re-throws:
a throw there leaves the backend's fs callback as an uncaught exception
and kills the serve daemon. EIO/EAGAIN races are swallowed and other
non-limit errors go to the diagnostic sink.
- Failed sessions no longer count against the web-terminal admission cap,
and release() no longer fabricates a 143/15 exit frame for them.
- processPtyBudget.maxActivePtys is 64 (headroom over the eight-slot
web-terminal cap so a full house cannot starve the shell tool), with
the per-pty vs process-wide cap relationship documented.
- ShellExecutionResult.executionMethod declares 'qwen-bun-pty', its
error-field contract documents resource-limit termination, and the two
casts that hid the Bun backend name are dropped.
- getPty tests that assert the Bun arm loads now pin a POSIX platform so
they pass on Windows hosts; docs and the packaging help text are
aligned (correct smoke-runtime.js path, boundary-doc PTY row now cites
the bun-pty fixture, node-pty staging applies to both runtimes).
* chore: re-verify S1 boundary test-file merge resolution with recorded evidence
Empty commit: no code change is warranted by the deterministic gate's
test-weakening rejection. The merge ddc7666b9f resolved
packages/core/src/utils/runtime-info.test.ts and
packages/core/src/utils/runtime-boundary.node-bun.test.ts to main's
reviewed versions from #14036 (2eab3cc431), replacing the older
stacked draft copies this branch carried while the prerequisite was
unmerged. Both files are byte-identical to origin/main (empty merge-
base diff: this PR no longer modifies them), and main's versions are
strictly richer (19/16 vs 16/15 expect() calls), so no assertion
coverage is lost. The per-file evidence is recorded in the round's
test-weakening.json; restoring the drafts would revert the reviewed
suites and re-introduce the stacked duplicates the merge correctly
eliminated.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(core): preserve PTY failure output and bounded settlement
* fix(core): deliver reaped PTY exits on limit trips, replay failed scrollback
Review round on the Bun PTY backend:
- terminateResourceFailure no longer signals a pid it already reaped
(pendingExit parked): the real exit is delivered and the structured
limit error reported, instead of SIGTERM/SIGKILL at a recycled pid.
- The failed-reconnect branch of the terminal WS route replays the
retained scrollback through the backpressure guard before the error
frame, matching the exited path.
- QWEN_PTY_ACTIVE_LIMIT no longer claims a termination that never
happened, and acceptedBytes stays a byte count (0 at refusal).
- sanitizeEnv also applies when options.env is omitted, matching the
wrapper's resolved-env rule.
- The arithmetically unreachable paused-hold-segments cap is deleted.
- Tests: the live-failure route test now reaches a live session; the
registry limit test is parametrized over both limit codes; the
paused-exit fixture gains a withheld-tail oracle so it cannot pass
without a real pause; the bounded-hold tests get afterEach failure
isolation; the process-wide write-queue budget is exercised; and the
stale throw-propagation assertion is reconciled with the deliberate
reportListenerError containment (un-breaks the core test lane).
* docs(core): clarify pending PTY close validation
* docs(core): fix PTY validation checklist indentation
* fix(pty): make resource failures the terminal event
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* test(cli): raise ps maxBuffer for loaded CI shards
The managed-runtime process probe lists the whole process table with execFileSync. On a loaded CI shard that output exceeds the 1 MiB default and the probe fails with ENOBUFS; raise the cap to 16 MiB.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* docs(core): name the PTY fd-lifetime tests
Point the deferred-close validation entry at the two exact fd-lifetime tests in both design languages.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(cli): release failed terminal replay sessions safely
* test(web-shell): verify failed terminal replay protocol
* test(cli): pin failure listener cleanup on terminal exit
* fix(core): preserve failure precedence across terminal exits
* fix(core): isolate terminal failure notifications and verify release
* fix(core): preserve PTY write and admission failure diagnostics
* test(core): assert PTY cleanup drains every budget
* test(core): verify production PTY refunds start with charged budgets
* fix(core): stop late PTY signals and integrate cleanup refund tests
* test(core): witness PTY subscriber delivery and document native loading
* test(core): reclaim captured PTYs when fd race assertions fail
* test(core): verify exit diagnostics with a real PTY child
* fix(core): avoid signalling reaped PTY leaders during fallback
* test(core): pin paused PTY boundaries and isolate loader probes
* fix(core): verify PTY ownership and target-specific packaging
* fix(core): refuse oversized terminal input before the pty cap
* fix(core): park paused PTY reads at the hold cap instead of killing the tree
Under the Bun backend the shell tool passes handleFlowControl: true, so a
single Ctrl+S (XOFF) byte calls pause(). The pump kept reading into the
paused hold and, once the 4 MiB per-pty (or 32 MiB process-wide) hold was
full, terminated the child process tree with QWEN_PTY_OUTPUT_LIMIT. During
a flood that killed the command about a second after one keystroke.
Size each paused read to the room left in the hold and, once there is
none, stop issuing reads until resume(). The kernel pty buffer then fills
and the child blocks on write, which is the backpressure the node-pty
wrapper's paused socket applies. Nothing is dropped or killed, and
resume() replays the hold and restarts the reads; pty.stats.readParked
exposes the state. QWEN_PTY_OUTPUT_LIMIT and the paused-hold limit kinds
are removed together with the consumer branches that handled them. The
write-queue and admission limits are unchanged.
While parked, a child that dies with output undrained may only finish
exiting on macOS once the master is read again, so the shell tool's
cancel now calls resume() before it signals the process group.
The design docs also get the live-pty cap right (64, not 8) and no longer
describe a block-count cap that the hold never had.
* test(core): run the PTY drain-window witness on Linux only
The real-child test for a write-limit trip after the native exit relies
on a HUP-ignoring grandchild keeping the pty slave open after the session
leader exits. macOS ends the master side right away (a plain-pty probe on
Darwin reads EOF about 70 ms after the leader exits), so the pump closes
the fd before the write and the case failed 3/3 there. Skip it off Linux;
bun-pty-failure-order.test.ts still pins the same guard on every platform
with a mocked native exit.
* fix(core): reap a PTY's whole session on a resource-limit termination
terminateResourceFailure signalled only the leader and the leader's
process group. An interactive shell runs each foreground job in its own
group, so a job that ignores SIGTERM and SIGHUP outlived the termination:
the failure was reported and the budgets refunded while the job kept
running, reparented to init. Reproduced on Linux and macOS.
List what the pty owns with ps while the leader is still unreaped: its
descendants, plus every process in its session (Linux sid) or on its
controlling tty (macOS tdev). Signal each of them as well as the group.
The SIGKILL pass after the grace period lists the tree again. It keeps
an earlier member only while that member's start time still matches, so
a recycled pid is never signalled. It reuses the scope only where the
scope still names the session: macOS drops the tty with the leader, and
Linux keeps the sid unless the pid now leads a new process.
The web terminal registry's killPtyTree already walked the same ps
listing; both now share collectPtyProcessTree.
* test(core): tolerate the pty's CR jitter in paused-flood oracles
macOS's pty driver occasionally inserts an extra CR before LF; a plain script(1) probe reproduces it without this project's code. The paused-flood tests compared the stream byte-for-byte and waited for pausedBytes to equal the logical byte count, so a jittered stream could never satisfy the predicate.
Wait for pausedBytes >= the logical size, derive the process-wide case's expected hold from the observed hold, and compare the resumed stream with runs of CR before LF collapsed. Every line's content, order and count is still asserted, so loss and duplication remain caught.
---------
Co-authored-by: gary.gq <gary.gq@alibaba-inc.com>
Co-authored-by: qwen-code-autofix <qwen-code-autofix@localhost>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
Co-authored-by: Qwen Autofix <qwen-autofix@users.noreply.github.com>
Co-authored-by: wenshao <shaojin.wensj@alibaba-inc.com>
Cover #14880 item 3. During a lifecycle v2 close the Broker proxy refuses
the owner release after every configuration is drained, then the test
replaces Spring and its embedded Broker. Detach must recover with exactly
one forwarded owner release (no acquire, no MCP control), clear the
storage holder, and leave the Runtime Session RELEASED.
The recorded blocker was the rig, not WorkspaceStorageGuard:
startSpring() registered the storage and inserted the Workspace rows on
every boot, and the guard refuses a second registration while the holder
is booked. Production never re-registers on start, so seed only on the
first boot and restart in the JVM; the Broker's close writes nothing and
the durable provisioner keeps the worker alive, which is the state R1-1
needs.
R1-1 does not reproduce on main: the replaced Broker reaches the
persisted-Session release path, and #13673's managed-context branch
releases the saved Session while the Harness drains. Disabling that
branch turns the case red 3 of 3 times with the original symptom (every
retry answers 503 and the holder stays booked).
Budget the cell at 24 s (2x its measured 11.9 s): healthy 10039 -> 10063,
fork 10639 -> 10663, Verify stays 188 minutes.
* 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>
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>
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(release): publish the generated CLI with npm so vendored ripgrep keeps its exec bit
`pnpm pack` writes 0755 for the entries named in the manifest's `bin` map and
0644 for every other entry, so ever since #12400 moved publishing to
`corepack pnpm publish` the released tarball has shipped `vendor/ripgrep/*/rg`
without an exec bit: 0.24.2 carries `-rwxr-xr-x`, 0.24.4 onward `-rw-r--r--`,
while only `cli-entry.js` (the single `bin` entry) keeps 0755. A fresh install
then cannot spawn the bundled ripgrep at all, and on a machine without a system
rg search silently degrades to the built-in grep. The #12673 / #12892 runtime
heals cannot chmod a root-owned or read-only install, so they do not cover it.
The tar writer is the only place the bit is lost: `copy_bundle_assets.js`
restores it on the staged binaries and every other copy path preserves it. So
publish the generated CLI with npm, which keeps the working-tree mode, exactly
as it was before #12400. The recursive workspace publish stays on pnpm;
`publish_package` is only ever called for `dist`, the one package that carries
vendored binaries.
A pre-publish gate now packs the prepared CLI the same way the publish step
does and reads the archive's recorded entry modes, failing when any unix
vendored ripgrep lacks all three exec bits. It runs in the arm that produces
`dist`, before the publish step consumes it, and refuses to pass vacuously when
the vendored tree is missing. Unit coverage pins npm as the CLI's publisher,
keeps the gate in that arm, and exercises both the npm-keeps-0111 and
gate-rejects-0644 directions.
Fixes#12668
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(release): run the tarball exec-bit gate from the workflow-pinned scripts
The gate was invoked through the selected release ref's own `scripts/` path.
The publish job's trusted checkout only materializes the paths named in its
sparse-checkout list, and a manual release may select any branch or full SHA —
so releasing a ref that predates the gate (v0.25.3, or any commit before this
change) died in `build-package` with MODULE_NOT_FOUND, dry runs included.
Ship the gate with the workflow-pinned scripts — add its path to the release
workflow checkout's sparse list — and run it from `.release-workflow/`, the
same way the version guard rides that checkout. The working directory stays
the selected release ref, so the `dist` argument still resolves to that ref's
prepared package. The sparse-checkout list and the invocation are both pinned
in the release workflow and package script tests.
Fixes the blocking review finding on #12668.
---------
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(ci): hold chosen RocketMQ ports until the JVMs bind them
The chooser released its sockets as soon as it printed them, so between
the choose step and the JVM bind (download, namesrv boot) any sibling
job on the pool host could take the port: #14545's full lane died twice
this way, on the broker HA listener and on the NameServer listener.
Park each chosen port behind a detached holder process instead, and let
rocketmq-lite-broker.sh kill only the holder of the port it is about to
hand to a JVM, shrinking the pick-to-bind race to the sub-second
kill-to-bind window. The pid files live in RMQ_HOLDER_DIR and are
cleaned up on start success, rollback and stop; local runs without
RMQ_HOLDER_DIR behave as before.
* fix(ci): keep the broker companion arithmetic readable by macOS Bash 3.2
The inner quotes around the numeric operand make macOS's system Bash 3.2
raise "operand expected", so every start and stop failed there after the
NameServer had already booted. The script supports macOS, so the operands
stay unquoted.
* fix(ci): terminate holder pid records and reject overlapping companions
A pid file without a trailing newline makes bash read the last line and
return 1, so unhold_port and release_holders aborted start and stop under
set -e once the workflow consumed RMQ_HOLDER_DIR. Terminate the record and
require the file to name the child this chooser just spawned.
A broker companion (listenPort - 2 / + 1) can repeat a port an earlier role
already parked, and the new holder then died on bind while the live holder's
pid file faked success, leaving the fast channel or HA listener colliding
with that role. Reject those companions and release only the holders the
rejected candidate parked.
The script tests now drive the real chooser, then start and stop against
stand-in components with its ports and RMQ_HOLDER_DIR.
* test(ci): cover the holder records on the stop path too
unhold_port and release_holders read the chooser's holder records through
separate code paths, and only the start side was exercised: stop with a
populated holder directory is what rollback and stop rely on, so give it
its own case and share the chooser invocation between both.
* test(ci): check a released port by its listener, not by a bind probe
A holder binds 0.0.0.0, and binding 127.0.0.1 against a wildcard listener
still succeeds on macOS, so the stop case asserted a port was free while the
holder could still be alive: with release_holders' kill removed the test
stayed green. Ask the port's listener the way the script does, and wait for
the socket the killed holder releases on exit rather than on kill.
* test(ci): clean leaked holders up by pid, not by their records
The afterEach cleanup read the holder records back, so a regression that
makes release_holders drop a record without killing the process left the
Node holder running and its port bound after a red run. Track the pids the
chooser started and kill those, mirroring how this file already cleans up a
leaked stand-in.
---------
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(ci): hold the MariaDB lane's sdk-java lock once per job (#14896)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* test(ci): pin the merged MariaDB step's order and SpotBugs witness
The single-step merge dropped guarantees that the two-step layout got for
free from step boundaries, and one witness became satisfiable by prose:
- spotbugs-gate matched `verify` anywhere in the step body, and the merged
step's own comments explain the incident with the word 'verify' twice.
A later narrowing to `clean test` would stay green. Match `clean verify`
on command lines only.
- seed-before-write-back was a step-order invariant; both strings now live
in one body with presence assertions only, and the write-back's warning
arm swallows the ordering failure. Pin seed < install < verify <
write-back.
- `working-directory:` applied to the whole step and could not be
misplaced; its `cd` replacement is positional inside the body. Pin it
between the two Maven runs.
- Drop the finder arm that matched the deleted `working-directory:`
property: no step in either inspected job carries it any more.
---------
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: 易良 <1204183885@qq.com>
Co-authored-by: Shaojin Wen <szujobs@gmail.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
* 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>
* 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>
The daemon E2E job's install ran prepare, which built and bundled the tree, then the job's next two steps built and bundled it again. The fast-tier lane failed inside that install-path prepare build. Set QWEN_SKIP_PREPARE so the install stays an install, matching the e2e build job.
Co-authored-by: Qwen Autofix <autofix@qwen-code.dev>
* 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>
* 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.
* test(managed-agent): ignore transient MySQL deadlocks in hosted gate waits (#14791)
The Hosted MySQL gates poll their own JDBC reads inside Awaitility waits. A MySQL 1213 deadlock can roll back one of those reads while sibling delivery threads hold the rows; Awaitility treats the resulting CannotAcquireLockException as terminal and fails the wait immediately, so a healthy gate flakes on a loaded runner. HostedTeamLeadMySqlIT already configures ignoreExceptionsInstanceOf(CannotAcquireLockException) before its failFast guard, and the hosted-process CI guard documents that pattern. Apply the same deadlock-ignore to the remaining wait helpers. The failFast guard still stops each case at its @Timeout, and a persistent failure still times out with the original assertion.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(managed-agent-server): preserve connection-refused retries in hosted waits (#14812)
Awaitility replaces the exception predicate on each ignore call, so chaining the deadlock filter after the ConnectException filter dropped the readiness retry these two helpers need while the child JVM starts. Use one predicate for both exception types and pin it in the Hosted process wiring test.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(managed-agent-server): reindent the hosted wait failFast bodies (#14812)
Moving .failFast(...) onto its own continuation line changed the required
indentation of the lambda body, but the if/throw/closing braces kept the old
levels. maven-checkstyle-plugin's Indentation check flagged four violations in
each of the two helpers.
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
---------
Co-authored-by: qwen-code-autofix <qwen-code-autofix@localhost>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: 易良 <1204183885@qq.com>
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
Co-authored-by: Shaojin Wen <szujobs@gmail.com>
* fix(ci): retry transient pnpm installs in the SDK Java workflow (#14845)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(ci): correct the retry's failure class and exercise the loop
The install step's prepare re-enters the workspace build, so an absorbed
failure here can be a build failure; the warning no longer routes it at
the #11726 network-transient counter, and the recorded cost counts each
attempt's rebuild. The meta-test now runs the loop under a stubbed
corepack to prove the retry, the absorbed warning and the exit status.
---------
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: yiliang114 <1204183885@qq.com>
* 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.