Skip to content

test(managed-agent): pin untested contracts from the #12692 R2 review - #13348

Merged
wenshao merged 9 commits into
mainfrom
fix/managed-agent-r2-java-tests
Oct 6, 2026
Merged

wenshao merged 9 commits into
mainfrom
fix/managed-agent-r2-java-tests

Conversation

@wenshao

@wenshao wenshao commented Oct 3, 2026

Copy link
Copy Markdown
Collaborator

What this PR does

Adds test witnesses for the twelve R2 review follow-ups on #12692 that were missing in the test surface. Every witness was first written against the pre-change code, confirmed to fail or to expose the gap, then edited to compile against the public surface whose contract it pins (no production code change in this PR). Each finding was re-verified against current main (2c591ecc08) before the test was written.

Why it's needed

These behaviors were shipped with the merged PR but lacked direct witnesses, so review could not read current-main behavior from tests:

  • SessionEventHub had no overflow witness: a 600-event publish against capacity 512 plus a slow consumer was the only way to discover whether await reported the dropped position or hung.
  • HarnessCoordinator had no witness for the three failure modes the recovery flow can take: a recovered-but-not-ready runtime must fail the turn with managed_runtime_recovery_incomplete; a generation that moved between witness and bind must fail terminally with hosted_harness_recovery_generation_mismatch; an admission-epoch move triggers a retry instead of admission.
  • HarnessEventProjector had no witness for the out-of-alphabet error code fallback, nor for the redaction rule excluding both the value and the key of a sensitive attribute.
  • QwenHostedHarnessConnector had no witness that UnknownCreateOutcomeException actually falls back to load and propagates the complete (bootId, recoveryHandle, harnessGeneration, eventEpoch) tuple, nor that a genuine load path carries the same four fields, nor that a 500 daemon error is rethrown untouched.
  • The contract fixtures for ManagedSessionStore were shape-only: nothing pinned recordCount == records.size(), per-record session identity, or (firstSequence..lastSequence).size + 1 ≥ eventCount.
  • The per-page 8 MiB restore budget had no behavior witness; only protocol constants were pinned.
  • ManagedAgentMySqlIT was not rerunnable against a persistent database: reruns collided on the fixed-id legacy fixtures, and the migration-bound assertions (V15 event identity, V17 command-to-operation, V29 hook backfill) are by definition not re-applicable to a rerun's seeds.
  • ManagedAgentServerIntegrationTest treated the in-process recovery attachment as a global single-shot; the second test to claim a dispatchable turn out of the shared H2 silently won, leaving earlier sub-cases to flake.

Reviewer Test Plan

How to verify

  • Hub overflow: evictsBeyondCapacityAndSignalsOverflowBelowTheWatermark publishes 600 events against CAPACITY = 512; the slow consumer's await(0) reports overflowed; await(88) returns the contiguous 89..600.
  • Recovery failure modes: failsTurnWhenARecoveredRuntimeIsNotReadyForContinuation (verifies failTurn with managed_runtime_recovery_incomplete, never continue/submit), failsTerminallyWhenTheRecoveredGenerationMoved (bind false, code hosted_harness_recovery_generation_mismatch), retriesTheTurnWhenTheRecoveryWatermarkMoved (epoch-move → scheduleTurnRetry, never recordRecoveryAdmission).
  • Projector codes & redaction: substitutesTheSafeFallbackCodeForAnOutOfAlphabetErrorCode pins hosted_harness_error; the existing redaction test now also asserts doesNotContainKey("secret") and doesNotContainValue("must-not-leak").
  • Connector recovery: unknownCreateOutcomeFallsBackToLoadAndPropagatesTheFullAttachment, loadPathAlsoPropagatesTheFullAttachment, rethrowsANonConflictDaemonErrorWithoutLoading (each uses the new exception seam).
  • Contract fixtures: ManagedSessionStoreContractFixtureTest pins record count, per-record session identity, and a sequence range consistent with event count.
  • Per-page budget: holdsRestorePagesInsideThePerPageByteBudget writes a genesis then twelve 1 MiB-padded commits in two-line canonical form; page 1 returns transactions 1..9 with hasMore=true; page 2 (afterRevision=9) returns 10..12 and hasMore=false. The test goes red against any of the 8 MiB, 1 MiB, record-count, or firstSequence rules being violated.
  • MariaDB rerunnable: run mvn failsafe:integration-test -Dit.test='ManagedAgentMySqlIT' -Dmysql.url=... twice against the same persistent database; both runs go green (19/19). Sources of rerun collision: mysql-upgrade/mysql-lifecycle/mysql-hooks namespaces per run; migration-bound assertions are guarded by legacySeedsBackfilled; the workspace idempotency probe re-seeds the V9 scope row explicitly.
  • Integration flake: ManagedAgentServerIntegrationTest previously had ~1-of-N flakes after broad runs; it now deterministically cleans up claimed turns in a finally wrap.

Evidence (Before & After)

N/A in the production sense — the new tests pin existing contracts; on the pre-change code, no production test or witness existed for the listed behaviors.

Tested on

OS Status
🍏 macOS ✅
🪟 Windows N/A
🐧 Linux N/A

mvn verify on packages/sdk-java/managed-agent-server (JDK 21, H2) after same-source reinstall of qwencode-sdk and qwen-managed-runtime-broker (alpha jar ~/.m2 md5 fingerprints verified equal pre- and post-run). The MySqlIT witness ran against a throwaway MariaDB 11.3 datadir on 127.0.0.1:33307; both Tests run: 19, Failures: 0, Errors: 0 invocations passed back-to-back.

Environment (optional)

JDK 21 (~/Install/jdk21); Maven 3.9.11; MariaDB 11.3.2 only for the MySqlIT witness runs (the unit/integration suite is H2).

Risk & Scope

  • Main risk or tradeoff: the MySqlIT rewrite makes the rerunnable story explicit by namespacing, at the cost of conditionalizing the backfill assertions. Backfilled behavior is still witnessed on the first pass; the second pass pins that the seeds no longer collide and that all migration-order-independent exercises still hold.
  • Not validated / out of scope: production behavior changes — none. Design-level deferrals tracked by Tracking: design-level follow-ups from the PR #12692 R2 post-merge review #13302 (e.g., pending-lease TTL fibers) are not touched here.
  • Breaking changes / migration notes: none.

Linked Issues

Follow-up to the post-merge R2 review on #12692. Design-level deferrals tracked by #13302.

中文说明

本 PR 内容

为 #12692 合并后 R2 评审提出的 12 条「测试面不足」跟进项补见证用例。每条都先在改动前代码上写出并确认失败/暴露缺口,再调到贴合被钉住的公共契约——本 PR 不改任何生产代码。每条 finding 在落笔前都对照当前 main(2c591ecc08)重新核实过。

动机

这些行为随合并 PR 上线,但缺少直接的回归见证,导致评审无法从测试中读出当前 main 的真实行为:

  • SessionEventHub 没有溢出见证:600 条事件怼到 CAPACITY=512 配上慢消费者,只能跑一遍才知道 await 是返回 overflow 还是挂起。
  • HarnessCoordinator 的三条恢复失败路径均无见证:已恢复但未 ready 的 runtime 必须以 managed_runtime_recovery_incomplete 失败 turn;见证读到 bind 之间代际变化必须以 hosted_harness_recovery_generation_mismatch 终止;admission-epoch 移动必须改成 scheduleTurnRetry 而不是 admission。
  • HarnessEventProjector 没有「字母表外错误码兜底为 hosted_harness_error」的见证;敏感 attributes 的 key 与 value 都不可进泄露容器,此前只测了一半。
  • QwenHostedHarnessConnector 没有见证 UnknownCreateOutcomeException 会真的回退去 load 并把 (bootId, recoveryHandle, harnessGeneration, eventEpoch) 四元组完整透传到 Attachment;load 路径同样未钉;500 类 daemon 错误必须原样重抛,不能误触 fallback。
  • ManagedSessionStore 的 contract fixture 只测形状,没有钉 recordCount == records.size()、逐条 record 的 session identity、(first..last).size + 1 ≥ eventCount。
  • 单次 8 MiB 恢复分页预算此前只有常量没有行为见证。
  • ManagedAgentMySqlIT 在持久 db 上不可重跑:重跑会撞固定 id 的 Legacy fixture;且 V15/V17/V29 这三条数据迁移物理上不可能被重放到「同一份种子」上。
  • ManagedAgentServerIntegrationTest 的 fixture 把「runtime recovery attachment」当全局一次性值用,共享 H2 上后续的 dispatchable-turn 子断言会静默漂移。

评审者验证计划

如何验证

  • 集线器溢出:evictsBeyondCapacityAndSignalsOverflowBelowTheWatermark 按 512 容量推 600 条;慢消费者 await(0) 报告 overflow、await(88) 返回连续 89..600。
  • 恢复失败模式:三个新用例分别钉 failTurn 的 code 与 never-continue、bind 失败的 terminate code、epoch-move 的 retry-not-admission。
  • 投影器:substitutesTheSafeFallbackCodeForAnOutOfAlphabetErrorCode 钉 hosted_harness_error;现有 redaction 用例追加 doesNotContainKey/Value 断言。
  • 连接器恢复:unknownCreateOutcomeFallsBackToLoadAndPropagatesTheFullAttachment / loadPathAlsoPropagatesTheFullAttachment / rethrowsANonConflictDaemonErrorWithoutLoading。
  • Contract fixture:钉 record 数与逐 record 的 session 一致性、序列区间与事件数一致。
  • 8 MiB 分页:holdsRestorePagesInsideThePerPageByteBudget 写 genesis + 12 条 1 MiB pad 双行 commit;page1 拿事务 1..9 hasMore=true,page2(after=9)拿 10..12 hasMore=false。任何 8 MiB / 1 MiB / recordCount / firstSequence 规则破坏都会让此用例红。
  • MariaDB 重跑:对同一持久 maria 跑两遍 failsafe:integration-test -Dit.test='ManagedAgentMySqlIT',两轮 19/19 全绿。
  • 集成 flake:ManagedAgentServerIntegrationTest 通过 finally 包裹清理 claimed turn,fresh-namespaced tenant recovery map,跨子用例不再漂移。

前后对比

生产行为无差异 —— 本 PR 全是测试与见证,没有生产代码改动。

测试平台

macOS 已测(JDK 21,H2):packages/sdk-java/managed-agent-server 执行 mvn verify 通过;qwencode-sdk 与 qwen-managed-runtime-broker 在装到 ~/.m2 后, jar md5 在测试前后一致(防跨 worktree 竞写)。MySqlIT 双跑 witness 使用了临时 11.3 MariaDB(127.0.0.1:33307),两轮 Tests run: 19, Failures: 0, Errors: 0。

风险与范围

  • 主要风险/取舍:MySqlIT 改写把「不可重跑」的根因(migration-bound 断言)显式条件化为 legacySeedsBackfilled,作为固定 cost 换来了 namespace-per-run 的真实重跑能力。fresh db 的首跑做完整 backfill 断言;重跑把同一份断言退化为「种子不冲突 + store 后续操作仍正常」。
  • 未验证/范围外:不改生产代码。设计级延缓(TTL、oss 阈值等)由 Tracking: design-level follow-ups from the PR #12692 R2 post-merge review #13302 跟进。
  • 破坏性变更/迁移说明:无。

关联 Issue

#12692 合并后 R2 评审的跟进。设计级延缓项由 #13302 跟踪。

Twelve R2 review follow-ups on #12692 in the test surface, re-verified
against current main (2c591ec) before writing each witness:

- SessionEventHub evicts beyond CAPACITY (512) and reports whether
  the watermark still held the requested position, pinning the
  overflow signal the SSE fold relies on.
- HarnessCoordinator fails the turn when a recovered runtime is not
  ready for continuation, fails terminally when the recovery moved
  between the witness read and the bind, and schedules a retry when
  the admission epoch moved before commit.
- HarnessEventProjector substitutes the safe fallback code for an
  out-of-alphabet error code, and the secret-redaction sweep now
  holds both the key and the value of a sensitive attribute out of
  the leaked map.
- QwenHostedHarnessConnector's unknown-outcome create falls back to
  load and propagates the full attachment (boot id, recovery handle,
  generate and event epoch); the load path propagates the same four
  fields; a non-conflict daemon error is rethrown without any
  fallback load.
- ManagedSessionStore contract fixtures assert per-record session
  identity, record count by the records list, and a monotone
  sequence range with an event count that fits.
- ManagedSessionStore integration holds the per-page restore byte
  budget: twelve dense two-line commits with a 1 MiB pad page flush
  the first page after nine transactions (revisions 1..9,
  hasMore=true) and finish on the second page (revisions 10..12,
  hasMore=false).
- The MariaDB MySqlIT is rerunnable against a persistent database:
  the legacy fixture namespaces every fixed identity per run
  (upgrade/lifecycle/hooks tenants and sessions), skips the
  migration-bound assertions (V15/V17/V29 were applied once and
  cannot re-apply to a rerun's seeds), and re-seeds the V9 scope
  conflict source explicitly so the workspace idempotency probe is
  not migration-order dependent. The projection, private-store and
  lease-precision sub-exercises are equally namespaced so a second
  mvn failsafe run on the same database is green.
- ManagedAgentServerIntegrationTest fixture harness is keyed by
  tenant for the runtime-recovery attachment, and the dispatchable
  turns it claims are cleaned up between sub-cases so the retries,
  the generation transfer and the epoch retraction stay
  deterministic against a shared H2.

Verified on the managed-agent-server module with mvn verify after
same-source reinstall of qwencode and runtime-broker (alpha-jar md5
fingerprints matched before and after): witness runs of the
ManagedAgentMySqlIT against a persistent temp MariaDB passed twice
in a row (19 tests, 0 failures, 0 errors each).
yiliang114
yiliang114 previously approved these changes Oct 4, 2026

@yiliang114 yiliang114 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Contract pins for the previously untested surfaces (projector redaction, out-of-alphabet error-code substitution, legacy seed backfill guards). Test-only, CI pending at review time.

Overlapping test additions: keep this branch's three recovery-fence
witnesses and the out-of-alphabet fallback pin alongside main's retraction
and deadline-expiry witnesses (both arms splice cleanly; test-compile is
the gate for structure).
@wenshao
wenshao dismissed stale reviews from yiliang114 and ghost via 82f9c2a October 4, 2026 09:50
@wenshao

wenshao commented Oct 4, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /takeover

@qwen-code-dev-bot qwen-code-dev-bot added the autofix/takeover Summon the autofix loop to manage this PR (remove to release; needs triage+) label Oct 4, 2026
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤝 Takeover engaged: the autofix loop now manages this PR — it will address new review feedback and resolve base conflicts until the label is removed or the round cap is reached. Remove the autofix/takeover label (or comment @qwen-code /takeover stop) to release.

中文说明

🤝 已接管:autofix 循环现在管理此 PR —— 将持续处理新的评审反馈与 base 冲突,直到移除标签或达到轮次上限。移除 autofix/takeover 标签(或评论 @qwen-code /takeover stop)即可释放。

@qwen-code-dev-bot

qwen-code-dev-bot commented Oct 4, 2026 •

Copy link
Copy Markdown
Collaborator

✅ AutoFix round 6 finished — view run. See this round's report below.

中文说明

✅ AutoFix 第 6 轮已完成 —— 查看运行。本轮报告见下方。

qwen-code-ci-bot added 2 commits October 4, 2026 18:22
…java-tests

# Conflicts:
#	packages/sdk-java/managed-agent-server/src/test/java/com/alibaba/qwen/code/managedagent/ManagedAgentServerIntegrationTest.java
- ManagedAgentMySqlIT: derive the first-pass gate from this run's own
  Flyway target-15 migrate result instead of V15's item_id output, so a
  V15 regression can no longer silence its own witnesses; correct the
  rerun comment (consumer_progress is gated, agent_revision reads V13's
  DEFAULT) and merge the adjacent gate blocks.
- ManagedAgentMySqlIT: derive the journal case-sensitivity probe from
  the namespaced storeTenant so it stays a pure case variant.
- ManagedAgentMySqlIT: drop the inert per-connection
  SET FOREIGN_KEY_CHECKS toggle; the child-first delete order is the
  real invariant and is now stated as such.
- HarnessEventProjectorTest: assert secret absence on the serialized
  data (any nesting depth), pin the raw code's absence from the
  fallback-code event, and add the oversize/at-bound error-code arms
  for SAFE_ERROR_CODE's {1,128} bound.
- ManagedSessionStoreContractFixtureTest: assert the transaction
  summary rule the server actually enforces, branching on operation
  (genesis zero rule vs range/record equality).
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤖 Addressed the latest review feedback (round 1/100). What changed, and what I pushed back on: · 已处理最新评审反馈(第 1/100 轮)。改动内容与我反驳保留之处如下:

Autofix round — PR #13348

Base update (conflict resolution)

Merged origin/main (16 commits) into the branch as 0537f5b0c1. One conflict, in ManagedAgentServerIntegrationTest.java (ignoresLateEnvironmentResultFromAnOlderTurn): main replaced the singular findLatestEnvironmentEvent(tenant, sessionId) with the batch findLatestEnvironmentEvents(tenant, findLatestTurns(...)).get(sessionId), while this branch had wrapped the call in a try/finally cleanupTurn(...). The resolution keeps both intents — main's new batch API inside the branch's cleanup wrapper. No other conflicts; the other three auto-merged files were taken as git merged them after review.

Findings addressed (8 of 11)

  • R1-1 [Critical] (ManagedAgentMySqlIT.java, rerun gate) — implemented the reviewer's preferred minimal fix: the gate is now firstPass, captured from this run's own Flyway … target("15").migrate().migrationsExecuted > 0 (i.e. "did this run apply V2..V15"), instead of counting V15's item_id output rows. A neutered V15 on a fresh database now leaves the gate true and LegacyEvents.assertBackfilled red; a rerun still executes nothing at target 15 and skips the one-shot-backfill witnesses. All listed constraints hold: rows 1/6/9 keep item_id == null (assertions unchanged), an empty database classifies as fresh (target-1 migrate just ran), no assumptions so testcase - skipped still counts the class, no Flyway.clean(), and the agent_revision assertion stays outside the gate. The two adjacent if blocks were merged into one, which also covers the standing triage item about the adjacent if (legacySeedsBackfilled) pair.
  • R1-4 (same hunk) — the rerun comment now names what a rerun actually covers: the three legacy backfill witnesses and the V2-derived consumer_progress count are listed as gated (V2 named alongside V15/V17/V29), the surviving surface is the re-seeded idempotency conflict plus the fresh-projection exercises, and agent_revision is documented as reading V13's column DEFAULT on a rerun.
  • R1-3 (ManagedAgentMySqlIT.java case probe) — the journal case-sensitivity probe now passes storeTenant.toUpperCase(java.util.Locale.ROOT) instead of the frozen "MYSQL-PRIVATE-STORE" literal, restoring it as a pure case variant of the namespaced tenant.
  • R1-2 (ManagedAgentMySqlIT.java cleanup) — deleted the inert SET FOREIGN_KEY_CHECKS = 0/1 pair (per-connection session variable on a non-pooling DriverManagerDataSource; also a pooled-connection poisoning hazard after the HikariCP→Druid swap). The comment now states the real invariant: every statement runs on its own connection, so the hand-written delete list must stay child-first, and every FK to managed_agent_session is RESTRICT.
  • R1-7 (HarnessEventProjectorTest.java:31) — absence is now asserted on the serialized form (event.data().toString() doesNotContain("secret") / doesNotContain("must-not-leak")), which holds at any nesting depth; the containsEntry positives stay.
  • R1-8 (HarnessEventProjectorTest.java:64) — added assertThat(event.data().toString()).doesNotContain("DROP TABLE") to the out-of-alphabet fallback test, matching the sibling redaction test.
  • R1-6 (HarnessEventProjectorTest.java) — added substitutesTheSafeFallbackCodeForAnOversizeErrorCode: a 129-char in-alphabet code projects as hosted_harness_error, and a 128-char in-alphabet code passes through unchanged, pinning both sides of the {1,128} bound that protects error_code VARCHAR(128).
  • R1-9 (ManagedSessionStoreContractFixtureTest.java:87) — the coherence assertion now encodes the rule the server enforces, branching on the published operation: session.create requires eventCount/firstSequence/lastSequence == 0, recordCount == 2, and all three digest fields absent-or-null; any other operation requires lastSequence - firstSequence + 1 == eventCount, recordCount == eventCount + 1, and non-null eventsDigest/commitDigest. The rewrite uses the file's static assertEquals/assertTrue imports, which also clears the standing triage item about the fully-qualified Assertions.assertTrue.

Deferred to the next round (batch bound ~8; replied on each thread, threads left open)

  • R1-10 (QwenHostedHarnessConnectorTest.java) — replace the three inlined connector constructions with connector(client). Verified as a pure dedup; deferred only to keep this round's batch bounded.
  • R1-11 (HarnessCoordinatorTest.java) — add the equal-epoch/regressed-watermark sibling case for the continuation fence. Deferred only for batch size.
  • R1-5 (ManagedAgentServerIntegrationTest.java) — consolidate turn-residue cleanup into a tenant-scoped @AfterEach sweep and delete the six per-site try/finally blocks plus cleanupTurn. Deferred for batch size; noted on the thread that this round's merge resolution had to keep one of those try/finally wrappers around main's new batch API, which the sweep will absorb.

Verification

  • git merge origin/main --no-edit — one conflict (above), resolved and committed as 0537f5b0c1.
  • mvn -f packages/sdk-java/qwencode/pom.xml -DskipTests -Dgpg.skip=true -Dmaven.javadoc.skip=true install and mvn -f packages/sdk-java/runtime-broker/pom.xml -DskipTests -Dspotbugs.skip=true install (CI's prerequisite installs, .github/workflows/sdk-java.yml:293-296) — passed.
  • mvn -f packages/sdk-java/managed-agent-server/pom.xml clean test — 648 tests, 0 failures, 1 pre-existing environment error: RuntimeBrokerDefaultOnTest.defaultCombinationBootsWithTheYmlDefaultsBound fails to load the Spring context because this sandbox has no /etc/machine-id ("Trusted Linux host/boot identity is unavailable"). Reproduced identically with the round's fixes stashed (same error on the bare merge commit), so it is not caused by this round; GitHub runners provide the host identity. All changed and added tests pass.
  • mvn -f packages/sdk-java/managed-agent-server/pom.xml checkstyle:check — passed.
  • npm run build — passed (needed COREPACK_HOME=/tmp/corepack-cache; the sandbox's default corepack cache path is not writable).
  • npm run typecheck — passed.
  • npm run lint — passed.
  • Not runnable locally: the -Pmysql-integration failsafe lane that executes ManagedAgentMySqlIT needs a live MySQL/MariaDB and this sandbox has neither Docker nor a MySQL server. The edits there are compile-verified (the clean test run's test-compile phase covers all IT sources), and the reviewer's recorded mutation matrices on real MariaDB 10.11.18 / MySQL 8.4.11 containers cover the behavioral flips. CI's sdk-java MySQL job remains the final gate.

Mutation probes (each applied, measured red, then restored with git checkout):

  • R1-6 pin: widening SAFE_ERROR_CODE to {1,1024} in HarnessEventProjector turned substitutesTheSafeFallbackCodeForAnOversizeErrorCode red at the oversize assertion (Tests run: 6, Failures: 1).
  • R1-7 pin: adding the raw update map under a debug key in textEvent turned projectsTextWithoutLeakingOtherUpdateFields red under the new serialized-form absence assertion.
  • R1-8 pin: putting the raw source code into the projected data() map as rawCode turned substitutesTheSafeFallbackCodeForAnOutOfAlphabetErrorCode red.
  • R1-9 pin: editing the shared fixture's genesis expectedRequest.eventCount from 0 to 1 turned reconstructsSharedExactBytesAndDigests red at the new genesis arm (expected: <0> but was: <1>) — the exact flip the reviewer measured for the branch-on-operation form.
  • R1-1 pin (analysis): the requested pin (neutered V15 → red on a fresh database) holds by construction: on a fresh database the target-15 migrate applies V2..V15, so firstPass is true regardless of what V15's UPDATE did, and LegacyEvents.assertBackfilled then observes the missing item_id backfill. Not executed locally (no MySQL); the reviewer's arm-A/B/C matrix on real containers measured the old gate green under the same mutation.
  • R1-2/R1-3 pins: covered by the reviewer's recorded 7-arm MySQL 8.4.11 matrix (A1/A2/R-base flips) and the MariaDB FOREIGN_KEY_CHECKS probe; both changes are deletions/derivations with no new guard to witness locally.
中文说明

Autofix 本轮报告 — PR #13348

基线更新(冲突解决)

将 origin/main(16 个提交)合并进本分支,提交为 0537f5b0c1。有一处冲突,位于 ManagedAgentServerIntegrationTest.java(ignoresLateEnvironmentResultFromAnOlderTurn):main 把单数形式 findLatestEnvironmentEvent(tenant, sessionId) 换成了批量形式 findLatestEnvironmentEvents(tenant, findLatestTurns(...)).get(sessionId),而本分支此前用 try/finally cleanupTurn(...) 包住了该调用。解决方案保留两边意图 —— 在本分支的清理包装内使用 main 的新批量 API。无其他冲突;其余三个自动合并的文件经审查后按 git 合并结果采用。

已处理的发现(11 条中的 8 条)

  • R1-1【Critical】(ManagedAgentMySqlIT.java,重跑判据)—— 按评审建议的最小修复实施:判据改为 firstPass,取自本次运行自身的 Flyway … target("15").migrate().migrationsExecuted > 0(即「本次运行是否应用了 V2..V15」),不再统计 V15 的 item_id 产物行。在全新数据库上掏空 V15 时,判据仍为 true,LegacyEvents.assertBackfilled 变红;重跑时 target 15 不执行任何迁移,一次性回填的见证仍被跳过。列出的全部约束均满足:第 1/6/9 行保持 item_id == null(断言未动)、空库判为首趟(target-1 迁移刚执行过)、未使用 assumption(testcase - skipped 计数不受影响)、未使用 Flyway.clean()、agent_revision 断言仍在判据之外。两个相邻的 if 块合并为一个,同时覆盖了 triage 已记录的「相邻 if (legacySeedsBackfilled) 对」条目。
  • R1-4(同一 hunk)—— 重跑注释现在如实描述重跑覆盖范围:三条遗留回填见证与由 V2 派生的 consumer_progress 计数列为被条件化(V2 与 V15/V17/V29 并列写出),重跑仍存活的部分是重新播种的幂等冲突与 fresh-projection 用例,并注明 agent_revision 在重跑时读的是 V13 的列 DEFAULT。
  • R1-3(ManagedAgentMySqlIT.java 大小写探针)—— journal 大小写敏感探针改为传 storeTenant.toUpperCase(java.util.Locale.ROOT),取代冻结的字面量 "MYSQL-PRIVATE-STORE",使其重新成为命名空间化租户的纯大小写变体。
  • R1-2(ManagedAgentMySqlIT.java 清理)—— 删除无效的 SET FOREIGN_KEY_CHECKS = 0/1 对(非池化 DriverManagerDataSource 上的连接级会话变量;且在 HikariCP→Druid 切换后还存在池化连接被毒化的隐患)。注释现在写明真正的不变量:每条语句各自跑在独立连接上,因此手写删除清单必须保持子表在前,且所有指向 managed_agent_session 的外键都是 RESTRICT。
  • R1-7(HarnessEventProjectorTest.java:31)—— 「不存在」断言改为针对序列化形式(event.data().toString() 的 doesNotContain("secret") / doesNotContain("must-not-leak")),在任意嵌套深度都成立;containsEntry 正向断言保留。
  • R1-8(HarnessEventProjectorTest.java:64)—— 在乱码字母表回退用例中新增 assertThat(event.data().toString()).doesNotContain("DROP TABLE"),与兄弟脱敏用例写法一致。
  • R1-6(HarnessEventProjectorTest.java)—— 新增 substitutesTheSafeFallbackCodeForAnOversizeErrorCode:129 字符、字母表内的 code 被投影为 hosted_harness_error;128 字符、字母表内的 code 原样通过。{1,128} 上界(保护 error_code VARCHAR(128))的两侧均被钉住。
  • R1-9(ManagedSessionStoreContractFixtureTest.java:87)—— 一致性断言现在编码服务端真正强制的规则,并按发布的 operation 分支:session.create 要求 eventCount/firstSequence/lastSequence == 0、recordCount == 2、三个 digest 字段缺失或为 null;其他 operation 要求 lastSequence - firstSequence + 1 == eventCount、recordCount == eventCount + 1 且 eventsDigest/commitDigest 非 null。改写使用文件已有的静态 assertEquals/assertTrue 导入,同时清掉了 triage 已记录的「全限定 Assertions.assertTrue」条目。

延后到下一轮(批量上限约 8 条;已在各线程回复,线程保持打开)

  • R1-10(QwenHostedHarnessConnectorTest.java)—— 把三处内联的 connector 构造替换为 connector(client)。已核实为纯去重;仅为控制本轮批量而延后。
  • R1-11(HarnessCoordinatorTest.java)—— 为 continuation 栅栏新增「epoch 相同、watermark 回退」的姊妹用例。仅为批量大小而延后。
  • R1-5(ManagedAgentServerIntegrationTest.java)—— 把 turn 残留清理收敛为 @AfterEach 的按租户清扫,删除六处逐点 try/finally 与 cleanupTurn。为批量大小而延后;已在线程中注明:本轮的合并解决方案不得不把其中一个 try/finally 包装保留在 main 的新批量 API 之外层,清扫方案会把那一处一并吸收。

验证

  • git merge origin/main --no-edit —— 一处冲突(见上),已解决并提交为 0537f5b0c1。
  • mvn -f packages/sdk-java/qwencode/pom.xml -DskipTests -Dgpg.skip=true -Dmaven.javadoc.skip=true install 与 mvn -f packages/sdk-java/runtime-broker/pom.xml -DskipTests -Dspotbugs.skip=true install(CI 的前置安装步骤,.github/workflows/sdk-java.yml:293-296)—— 通过。
  • mvn -f packages/sdk-java/managed-agent-server/pom.xml clean test —— 648 个测试,0 失败,1 个既有环境错误:RuntimeBrokerDefaultOnTest.defaultCombinationBootsWithTheYmlDefaultsBound 因本沙箱缺少 /etc/machine-id 无法加载 Spring 上下文(「Trusted Linux host/boot identity is unavailable」)。把本轮改动 stash 后在不带修复的纯合并提交上复现了完全相同的错误,故与本轮无关;GitHub runner 提供主机标识。所有被改动和新增的测试均通过。
  • mvn -f packages/sdk-java/managed-agent-server/pom.xml checkstyle:check —— 通过。
  • npm run build —— 通过(需要 COREPACK_HOME=/tmp/corepack-cache,沙箱默认的 corepack 缓存路径不可写)。
  • npm run typecheck —— 通过。
  • npm run lint —— 通过。
  • 本地无法运行:执行 ManagedAgentMySqlIT 的 -Pmysql-integration failsafe 通道需要真实的 MySQL/MariaDB,本沙箱既没有 Docker 也没有 MySQL 服务。该文件的改动已通过编译验证(clean test 的 test-compile 阶段覆盖全部 IT 源码),行为翻转由评审在真实 MariaDB 10.11.18 / MySQL 8.4.11 容器上记录的变异矩阵覆盖。CI 的 sdk-java MySQL 作业仍是最终门禁。

变异探针(均已实际施加、实测变红、随后用 git checkout 还原):

  • R1-6 钉:把 HarnessEventProjector 的 SAFE_ERROR_CODE 放宽为 {1,1024} 后,substitutesTheSafeFallbackCodeForAnOversizeErrorCode 在超长断言处变红(Tests run: 6, Failures: 1)。
  • R1-7 钉:在 textEvent 中以 debug 键挂上原始 update map 后,projectsTextWithoutLeakingOtherUpdateFields 在新的序列化形式不存在断言下变红。
  • R1-8 钉:把原始 code 以 rawCode 放进投影的 data() map 后,substitutesTheSafeFallbackCodeForAnOutOfAlphabetErrorCode 变红。
  • R1-9 钉:把共享 fixture 的 genesis expectedRequest.eventCount 从 0 改成 1 后,reconstructsSharedExactBytesAndDigests 在新的 genesis 分支处变红(expected: <0> but was: <1>)—— 正是评审为按 operation 分支形式实测的那个翻转。
  • R1-1 钉(分析):所要求的钉(掏空 V15 → 全新库上变红)在构造上成立:全新库上 target-15 迁移会应用 V2..V15,因此无论 V15 的 UPDATE 做了什么 firstPass 都为 true,LegacyEvents.assertBackfilled 随后会观察到缺失的 item_id 回填。本地未执行(无 MySQL);评审的 arm-A/B/C 矩阵已在真实容器上实测旧判据在同一变异下为绿。
  • R1-2/R1-3 钉:由评审记录的 7 组 MySQL 8.4.11 对照(A1/A2/R-base 翻转)与 MariaDB FOREIGN_KEY_CHECKS 探针覆盖;这两处改动都是删除/派生,没有需要在本地见证的新守卫。

Base-conflict check · 基分支冲突检查: conflicted with main — resolved in this push. · 与 main 有冲突——已在本次推送中解决。

🧵 Resolved all 8 selected review thread(s). · 已关闭全部选中的 8 条评审线程。

Re-review when you have a moment. After round 100 this bot stops and leaves the PR for a human. · 有空请复审;第 100 轮后本 bot 停止并将 PR 交给人工。


🧠 Handled by Qwen Code · model/模型 kimi-k3 · CLI 0.24.7

…ermark operand (#13348)

- ManagedAgentServerIntegrationTest: replace the per-call-site
  cleanupTurn helper with one @AfterEach sweep that settles every
  non-terminal Turn before the recovery scanner re-arms, covering the
  two retraction tests that never invoked the helper; the
  concurrent-submit finally whose re-await could mask the real failure
  goes away with it.
- ManagedAgentMySqlIT: extend the warm-database delete list with
  managed_agent_operation and managed_workspace_create_command so it
  covers all seven RESTRICT children of managed_agent_session.
- ManagedSessionStoreContractFixtureTest: drop the unreachable
  non-genesis else arm; pin the published genesis shape
  unconditionally.
- QwenHostedHarnessConnectorTest: route the three new recovery tests
  through the existing connector(client) helper.
- HarnessCoordinatorTest: add
  retriesTheTurnWhenTheRecoveredWatermarkRegresses — same epoch, lower
  admission watermark — the unique witness for the lastEventId guard
  disjunct (mutation probe: deleting the disjunct fails exactly this
  test).

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤖 Addressed the latest review feedback (round 2/100). What changed, and what I pushed back on: · 已处理最新评审反馈(第 2/100 轮)。改动内容与我反驳保留之处如下:

Autofix round — PR #13348 review feedback

All five inline findings from the latest review are addressed in commit
fd78979d81 (test-only; +122/−110 lines).

Dispositions

  • [rc:4179703345] R1-9 — unreachable else arm in ManagedSessionStoreContractFixtureTest — resolved.
    Took the reviewer's smaller option: deleted the unreachable branch instead
    of publishing a non-genesis transaction into the shared cross-language
    fixture (which would have expanded this PR's footprint into
    packages/core). Verified against the fixture itself: its only transaction
    is session.create (eventCount 0, recordCount 2, digests absent), so
    the else could never execute. The test now pins the published genesis
    shape unconditionally — assertEquals("session.create", …) plus the zero
    rule the fixture actually carries — so a regenerated fixture with a
    different operation now fails loudly instead of silently skipping.

  • [rc:4179703350] R3-1 — warm-database cleanup missed 2 of 7 RESTRICT children — resolved.
    Applied the suggested list: managed_agent_operation and
    managed_workspace_create_command are now deleted child-first before the
    unwrapped parent delete. Verified against the migrations: the seven FK
    children of managed_agent_session are turn/event (V1),
    item/snapshot/consumer_progress (V2), workspace_create_command
    (V9), and operation (V17); item_part references item and already
    heads the list; both added tables are leaves (nothing references them), so
    appending them before the parent delete is order-safe.

  • [rc:4179703418] R1-5 — hand-placed per-site turn cleanup left two siblings uncovered — resolved by consolidation.
    Replaced the cleanupTurn helper and its six call sites with a single
    @AfterEach sweep that settles every non-terminal Turn
    (ACCEPTED/RUNNING/CANCELLING — exactly what findDispatchable
    reads) to FAILED/test_cleanup. The sweep runs before
    harness.setAvailable(true) in the same lifecycle method, so the scanner
    cannot claim residue in between; the H2 database
    (jdbc:h2:mem:managed-agent) backs only this class. The two previously
    uncovered tests (retractionRenamesTheDeltaThatContinuedTheRetractedOne,
    retractsInBandRetryOutputFromItsFirstDelta) are now covered without
    anyone finding a seventh call site. Side effect: the consolidation removes
    the concurrentSameKeySubmitsCreateOneTurn finally whose re-await could
    mask the real failure — the still-open thread from the earlier round that
    also tracked this concern.

  • [rc:4179703484] R1-10 — three new connector tests re-inlined the helper — resolved.
    All three sites now call the existing connector(client) helper (same
    shape as the five pre-existing callers). The helper body and the
    legitimately different inline at L251-253 are untouched.

  • [rc:4179703540] R1-11 — watermark operand undiscriminated — resolved.
    Added retriesTheTurnWhenTheRecoveredWatermarkRegresses: attachment and
    admission on the same epoch (epoch-new) with the admission watermark
    strictly lower (7 < 9), asserting scheduleTurnRetry and
    never().recordRecoveryAdmission(...). Mutation probe (below) confirms it
    is the unique witness for the second disjunct.

Failed-check note

Hosted process fault gates / MySQL 8.4 / Java 21 was failing at the
pre-round head. No CI-log access from this environment, so the diagnosis is
bounded by construction: this PR changes no production code and no
Hosted*IT class; the sibling check (Runtime Broker and Managed Agent MariaDB / Java 21), which compiles the same module test sources and runs
checkstyle:check plus ManagedAgentMySqlIT, is not reported failed, so a
compile/checkstyle break from this PR is ruled out. The failing job's unique
steps (Hosted*IT runtime, Runtime Broker fault gates, failover E2Es) execute
code paths this PR never touches; the merge from main brought substantial
runtime-broker changes into that job's scope. This round keeps the same
property (test-only, outside the hosted paths); the workflow's CI re-run on
the new head is the final gate.

Verification

  • npm run build — passed
  • npm run typecheck — passed
  • npm run lint — passed
  • mvn -f packages/sdk-java/qwencode/pom.xml -DskipTests install and
    mvn -f packages/sdk-java/runtime-broker/pom.xml -DskipTests -Dspotbugs.skip=true install
    (JDK 21 / Maven 3.9.11) — passed (module prerequisites)
  • Focused mvn test for the four touched classes
    (HarnessCoordinatorTest, QwenHostedHarnessConnectorTest,
    ManagedAgentServerIntegrationTest,
    ManagedSessionStoreContractFixtureTest) — 86 tests, 0 failures,
    BUILD SUCCESS (final tree state)
  • Mutation probe for the new guard witness: deleted
    || admission.lastEventId() < attachment.lastEventId() from
    HarnessCoordinator.java → HarnessCoordinatorTest 33 run / 1 failure —
    exactly retriesTheTurnWhenTheRecoveredWatermarkRegresses
    ; guard
    restored → 33/33 green
  • mvn checkstyle:check (managed-agent-server) — BUILD SUCCESS
  • mvn spotbugs:check (managed-agent-server) — 0 bugs, BUILD SUCCESS
  • Full-module mvn verify — 649 tests, 1 pre-existing environmental
    error unrelated to this round: RuntimeBrokerDefaultOnTest cannot boot in
    this sandbox because /etc/machine-id is absent ("Trusted Linux host/boot
    identity is unavailable"); the class is untouched by this round and the
    file absence was confirmed directly. ManagedAgentMySqlIT needs a live
    MySQL and runs only under -Pmysql-integration in CI; its change here is
    a delete-list extension verified against the migration files.
中文说明

Autofix 本轮处理 — PR #13348 评审反馈

最新一轮评审的 5 条行内发现全部在提交 fd78979d81 中处理完毕(仅测试代码;+122/−110 行)。

处理结论

  • [rc:4179703345] R1-9 —— ManagedSessionStoreContractFixtureTest 中不可达的 else 分支 —— 已解决。
    采用评审建议中较小的方案:删除不可达分支,而不是往共享的跨语言
    fixture 里发布非 genesis 事务(那会把这个 PR 的足迹扩大到
    packages/core)。已对 fixture 本体核实:它唯一的事务是
    session.create(eventCount 0、recordCount 2、摘要字段缺失),
    因此 else 永远不会执行。测试现在无条件钉住已发布的 genesis 形状——
    assertEquals("session.create", …) 加上 fixture 实际携带的归零规则——
    这样一旦 fixture 被重新生成成其他 operation,测试会响亮地失败,而不是
    静默跳过。

  • [rc:4179703350] R3-1 —— 热库清理漏掉 7 张 RESTRICT 子表中的 2 张 —— 已解决。
    应用了建议的列表:在未被包裹的父表删除之前,按子表优先顺序补删
    managed_agent_operation 和 managed_workspace_create_command。已对照
    迁移文件核实:managed_agent_session 的 7 个外键子表分别是
    turn/event(V1)、item/snapshot/consumer_progress(V2)、
    workspace_create_command(V9)和 operation(V17);item_part
    引用的是 item,本来就在列表最前;新增的两张表都是叶子表(没有任何
    表引用它们),因此追加在父表删除之前是顺序安全的。

  • [rc:4179703418] R1-5 —— 按调用点手工放置的 Turn 清理漏掉两个兄弟用例 —— 通过合并解决。
    用单个 @AfterEach 统一清扫替换了 cleanupTurn helper 及其 6 个调用
    点:把每个非终态 Turn(ACCEPTED/RUNNING/CANCELLING——正是
    findDispatchable 读取的状态)结清为 FAILED/test_cleanup。清扫在
    同一个生命周期方法内先于 harness.setAvailable(true) 执行,扫描器
    没有机会在两者之间认领残留;该 H2 数据库
    (jdbc:h2:mem:managed-agent)只由本测试类使用。此前未覆盖的两个用例
    (retractionRenamesTheDeltaThatContinuedTheRetractedOne、
    retractsInBandRetryOutputFromItsFirstDelta)现在自然被覆盖,不再需要
    有人去找第七个调用点。附带效果:这次合并同时消除了
    concurrentSameKeySubmitsCreateOneTurn 中那个 finally——它的二次
    await 可能掩盖真正的失败——这正是上一轮仍未关闭的评论串所跟踪的问题
    之一。

  • [rc:4179703484] R1-10 —— 三个新增 connector 测试重复内联了 helper 本体 —— 已解决。
    三处现在都调用已有的 connector(client) helper(与五个既有调用者
    形态一致)。helper 本体以及 L251-253 处确实不同的内联保持不动。

  • [rc:4179703540] R1-11 —— 水位操作数不可区分 —— 已解决。
    新增 retriesTheTurnWhenTheRecoveredWatermarkRegresses:attachment 与
    admission 处于相同 epoch(epoch-new),但 admission 水位严格更低
    (7 < 9),断言 scheduleTurnRetry 被调用且
    recordRecoveryAdmission(...) 从未发生。下方的变异探针确认它是第二个
    析取项的唯一见证。

关于失败检查的说明

Hosted process fault gates / MySQL 8.4 / Java 21 在本轮之前的 head 上
失败。本环境无法读取 CI 日志,因此诊断以构造性论证为界:本 PR 不修改
任何生产代码,也不修改任何 Hosted*IT 类;同级检查
(Runtime Broker and Managed Agent MariaDB / Java 21)会编译同一模块
的全部测试源码并运行 checkstyle:check 和 ManagedAgentMySqlIT,它未
被报告失败,因此可以排除本 PR 造成编译或 checkstyle 破坏。失败作业独有
的步骤(Hosted*IT 运行时、Runtime Broker 故障门、故障转移 E2E)执行的
代码路径本 PR 从未触及;从 main 合入的 runtime-broker 大改动进入了该
作业的范围。本轮保持了同样的性质(仅测试代码,且在 hosted 路径之外);
workflow 会在新 head 上独立重跑 CI 作为最终门禁。

验证

  • npm run build —— 通过
  • npm run typecheck —— 通过
  • npm run lint —— 通过
  • mvn -f packages/sdk-java/qwencode/pom.xml -DskipTests install 以及
    mvn -f packages/sdk-java/runtime-broker/pom.xml -DskipTests -Dspotbugs.skip=true install
    (JDK 21 / Maven 3.9.11)—— 通过(模块前置依赖)
  • 对四个被修改的测试类执行聚焦 mvn test
    (HarnessCoordinatorTest、QwenHostedHarnessConnectorTest、
    ManagedAgentServerIntegrationTest、
    ManagedSessionStoreContractFixtureTest)—— 86 个测试,0 失败,
    BUILD SUCCESS(最终工作树状态)
  • 针对新守卫见证的变异探针:从 HarnessCoordinator.java 删除
    || admission.lastEventId() < attachment.lastEventId() 后,
    HarnessCoordinatorTest 33 个测试中恰好 1 个失败——正是
    retriesTheTurnWhenTheRecoveredWatermarkRegresses
    ;恢复守卫后
    33/33 全绿
  • mvn checkstyle:check(managed-agent-server)—— BUILD SUCCESS
  • mvn spotbugs:check(managed-agent-server)—— 0 个 bug,BUILD SUCCESS
  • 全模块 mvn verify —— 649 个测试,1 个与本轮无关的环境性既有
    错误:RuntimeBrokerDefaultOnTest 在本沙箱中无法启动,因为缺少
    /etc/machine-id("Trusted Linux host/boot identity is
    unavailable");该类未被本轮修改,且文件缺失已直接确认。
    ManagedAgentMySqlIT 需要真实的 MySQL,只在 CI 的
    -Pmysql-integration 下运行;本轮对它的修改是删除列表扩充,已对照
    迁移文件核实。

Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。

🧵 Resolved all 5 selected review thread(s). · 已关闭全部选中的 5 条评审线程。

Re-review when you have a moment. After round 100 this bot stops and leaves the PR for a human. · 有空请复审;第 100 轮后本 bot 停止并将 PR 交给人工。


🧠 Handled by Qwen Code · model/模型 kimi-k3 · CLI 0.24.7

…ts (#13348)

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@wenshao

wenshao commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /triage

…jection (#13348)

The deterministic gate rejected 3a3b203 on npm run lint, but the 589
errors were all in untracked, git-ignored Maven javadoc output under
packages/sdk-java/qwencode/target/reports/apidocs/ left in the runner
workspace by a same-round mvn package/install of the qwencode module -
not in anything the commit touched. The committed tree needs no change;
this empty follow-up records the repair: the generated output was
removed from the workspace and npm run build, npm run typecheck, and
npm run lint all pass, with mvn -Dtest=HarnessCoordinatorTest test
(33/33) and mvn checkstyle:check green.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
qqqys
qqqys previously approved these changes Oct 5, 2026

@qqqys qqqys left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Critical-only review at head fd78979d81f5d0ad26e632540fdf5419b80808c0.

The one Critical ever filed is fixed at this head

Eight files, all under src/test/java — no production code. For a test-only PR the reportable defect class is a false green, and this PR had exactly one, R1-1, filed sev:"C" in rounds 1 and 2 and re-asserted at 82f9c2ad with the cited code byte-identical.

The charge was that legacySeedsBackfilled counted managed_agent_event rows with item_id IS NOT NULL, a column only V15's data migration writes for these seeds, so the flag meant "V15 succeeded" rather than "this database is a rerun". Break V15 and on a fresh CI database the count is 0, the gate reads false, and the four legacy-migration witnesses plus the V2-derived managed_agent_consumer_progress count all skip behind a plain if while the method still reports passed with failsafe skipped="0".

Verified in the source at this head rather than from the resolved flag: legacySeedsBackfilled no longer exists anywhere in ManagedAgentMySqlIT.java. The gate is now

boolean firstPass = Flyway.configure().dataSource(dataSource)
        .locations("classpath:db/migration")
        .target(MigrationVersion.fromVersion("15")).load().migrate()
        .migrationsExecuted > 0;

migrationsExecuted is Flyway's own count of what it ran during the staged v1→v15 step — a measurement of the database's prior state, taken before V15's data effects exist, and therefore independent of whether V15 is correct. The circularity is gone in the direction that matters: on a fresh database firstPass is true whatever V15 does, so LegacyEvents.assertBackfilled, LegacyLifecycleCommands.assertMigrated, LegacyHookRecords.assertBackfilled and the consumer_progress == 1 count all execute and a V15 regression fails loudly. On a genuine rerun the skip is correct rather than circular, since one-shot backfills cannot re-apply to that run's seeds, and the comment says so. The agent_revision V13-DEFAULT witness below the gate runs unconditionally.

Rounds 3 and 4 both report zero Criticals, and round 4 at this head filed two Suggestions.

Current scan — no provable Critical

I swept the added lines for the constructs that turn a new test into a silent no-op. There are zero occurrences of @Disabled, @EnabledIf*, @EnabledOnOs, assumeTrue, assumeThat, Assumptions. or ctx.skip in anything this diff adds — notably no JUnit assumption, so nothing here can report as skipped-instead-of-failed. The diff adds 11 @Test/@ParameterizedTest methods and 36 assertion lines.

Five added if statements exist and none of them gates an assertion away:

  • if (firstPass) and if (!firstPass) are the two arms of the gate above, and both do real work — the rerun arm re-seeds the idempotency conflict rather than returning early.
  • if (revision == 1) / else and if (revision >= 3) are arrange-phase request construction inside the commit lambda: genesis shape versus a ~1 MiB padded transaction, and when to attach previousCommitDigest. Both branches build a request, so no iteration silently does nothing.
  • if (result.getResponse().getStatus() != 200) throws IllegalStateException carrying the revision, the status and the first 240 characters of the body. A failed arrange-phase commit is a hard failure, which is the correct shape — the opposite of the R1-1 defect.

The blob-budget test those guards belong to commits one small genesis plus twelve transactions of roughly 1 MiB per record line and asserts the page is cut by the byte budget before the count limit, which is a real boundary rather than a restatement of the code.

On the standing CHANGES_REQUESTED

reviewDecision is CHANGES_REQUESTED, so it is worth being explicit about why that does not carry into this verdict. Both such reviews are against superseded heads — c1a61b2d31 at 10:55 and 82f9c2ad0b at 15:32 on 10-04. The same bot's two newest reviews of this PR are COMMENTED, at bd2e6e7b57 and at this head, and neither files a Critical. The Critical those requests rested on is the one I verified fixed above. The two unresolved threads are both [Suggestion].

CI

No failing, errored or timed-out check. For a test-only PR the lanes that execute the changed files are the ones that matter, and they ran rather than being skipped: Runtime Broker and Managed Agent MariaDB / Java 21 and Hosted process fault gates / MySQL 8.4 / Java 21 both pass, as do ubuntu-latest / Java 11, Java 17, Java 21, macos-latest / Java 21, windows-latest / Java 21, Real daemon E2E / Java 11, Test (ubuntu-latest, Node 22.x) and Lint & Static. I did not parse the job logs to confirm each new method by name, so I am relying on the suites being selected by those lanes rather than claiming per-case witnesses.

Note on the two open Suggestions

R4-1 is the one with teeth and is worth a follow-up: the rerun isolation uses a hand-maintained nine-table delete list that has already drifted once — it held 7 of the 9 names at the previous head and was missing two RESTRICT children of managed_agent_session. Its failure mode is loud rather than silent, an un-wrapped DELETE FROM managed_agent_session hitting MySQL error 1451 on a second run against the same database, so it cannot produce a false green; but the file's own dominant convention of namespacing the tenant per run needs no list at all, and a future migration adding a child table will break the rerun path until someone updates it. R1-11's residual is that the new watermark test verifies only store-side state and carries no harness-side verification, so a handler that drove the continuation twice would not be caught even though scheduleTurnRetry is called once. Both are coverage and maintainability, not correctness at this head.

No Critical found. Approving.

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤖 Addressed the latest review feedback (round 3/100). What changed, and what I pushed back on: · 已处理最新评审反馈(第 3/100 轮)。改动内容与我反驳保留之处如下:

Autofix round summary — PR #13348

This round was a same-run verification repair: the previous attempt had already implemented both round-4 findings in commit 3a3b203f53, and the deterministic gate rejected that commit because npm run lint failed — not on anything the commit contains, but on untracked, git-ignored Maven javadoc output left in the runner workspace. This round preserves 3a3b203f53 unchanged, removes the workspace pollution, re-verifies everything, and records the repair in one empty follow-up commit f093e1766f (there was genuinely nothing to change in the tree — the rejection was workspace state, not committed content). No base-branch conflicts (--conflict false); no merge performed. Net diff this round: 0 lines.

Feedback dispositions

1. rc:4180490215 — R4-1: hand-maintained nine-table delete list in isolatesTenantsThatDifferOnlyByCase — resolved (in preserved commit 3a3b203f53)

The test now namespaces both tenants per run ("case-" + UUID.randomUUID()... / case-folded upper twin, differing only by case by construction), and the nine-table child-first delete loop, the parent DELETE FROM managed_agent_session, and the dead deleteIfTableExists helper are all deleted (−24/+10 in the file). This matches the finding's primary recommendation exactly. Re-verified this round: the module test-compiles (including this IT) and the focused suite is green; the two-back-to-back-runs MySQL witness remains unrunnable on this runner (no MySQL server, no Docker) and stays with the CI MySQL lane.

2. rc:4180490220 — R1-11: retry tests carry no harness-side verification — resolved (in preserved commit 3a3b203f53)

Both retry tests gained verify(harness, times(1)).continueManagedRuntime(tenantId, sessionId, promptId, "checkpoint-1", "activation-1") (exact literals matching the stubs), plus verify(harness, never()).submit(...) and the six-String verify(store, never()).failTurn(...); both fail-path tests gained the four-String-plus-long verify(store, never()).scheduleTurnRetry(...). Re-verified this round: HarnessCoordinatorTest runs 33/33 green with the guards. The previous attempt's mutation probe (double-drive mutant on the watermark-mismatch branch → exactly the two retry tests red; reverted → 33/33 green) still stands — the tree has not changed since it ran.

The verification repair (why the gate rejected, what changed)

  • Reproduced first: npm run lint on the workspace as left by the previous attempt failed with the gate's exact 589 errors. Every one of them is in packages/sdk-java/qwencode/target/reports/apidocs/*.js (jQuery, javadoc search indexes) — untracked build output that is git-ignored by packages/sdk-java/qwencode/.gitignore (target/) but still linted, because the root eslint flat config's global ignores cover packages/desktop/src-tauri/target/** yet no packages/sdk-java/**/target/**. The files were generated at 03:56 UTC during the previous round by a Maven package/install goal on the qwencode module (maven-javadoc-plugin's attach-javadocs execution, bound to package), after that round's own lint run.
  • Repair: deleted packages/sdk-java/qwencode/target/reports (untracked, git-ignored, regenerable build output; the commit under repair never touched it). Re-ran the gate's commands to green.
  • Confirmed non-regeneration: this round's own Maven runs (test phase, checkstyle:check, module-scoped to managed-agent-server) do not regenerate the apidocs, and npm run build does not invoke Maven at all — so the workspace the gate re-verifies is the one leaving lint green.
  • One for the maintainers, out of autofix bounds: the durable fix is one line in the root eslint.config.js global ignores (packages/sdk-java/**/target/**, mirroring the existing packages/desktop/src-tauri/target/** entry) — any local mvn package/install/verify on a javadoc-enabled Java module followed by npm run lint reproduces this failure on any branch. Autofix is barred from touching workspace-root eslint config, so it is flagged here instead.

Not in this round

  • The review body's convergence observations (root-cause triage, batching, --severity-floor critical, land-and-defer) are process suggestions aimed at the PR/workflow; no code change follows, and review-severity configuration is CI/workflow machinery, out of bounds regardless.
  • The three already-reported round-3 suggestions keep their dispositions: the deleteIfTableExists blanket catch is gone with the helper (fixed as a side effect of disposition 1); the rerun-witness visibility item (ManagedAgentMySqlIT.java:101) and the unpinned recovery flags (QwenHostedHarnessConnectorTest.java:599, deferred in round 3) are untouched, and their threads stay open.
  • No tests were deleted or weakened this round (the round adds an empty commit only), so no test-weakening.json; nothing new was deferred, so no deferred-findings.json; no inline finding was declined/left-open this round, so no comment-replies.json.

Verification

  • npm run lint (before cleanup, reproduction) — failed with the gate's exact 589 errors, 100% of them in packages/sdk-java/qwencode/target/reports/apidocs/ (10 javadoc JS files); confirmed zero errors anywhere else, including the two lint-clean .mjs fixtures under runtime-broker/target/test-classes.
  • mvn -o -Dmaven.repo.local=/tmp/m2-pr13400/repository -Dtest=HarnessCoordinatorTest test (managed-agent-server, JDK 21 /tmp/toolchain/jdk, offline) — 33/33 passed; module test-compile covers the edited ManagedAgentMySqlIT.
  • mvn -o -Dmaven.repo.local=/tmp/m2-pr13400/repository checkstyle:check (managed-agent-server) — BUILD SUCCESS; confirmed afterwards that the apidocs were not regenerated.
  • Removed packages/sdk-java/qwencode/target/reports (the untracked, git-ignored javadoc output).
  • npm run build — passed (first attempt hit an environment-only EACCES on corepack's cache under the sandboxed $HOME; re-ran with COREPACK_HOME=/tmp/corepack-home, exit 0 — no repo content involved).
  • npm run typecheck — passed.
  • npm run lint (after cleanup, and once more after the successful build) — passed, 0 errors.
  • Final sweeps: git status --porcelain clean; no eslint-visible JS/TS remains under any packages/**/target/ except the two lint-clean .mjs fixtures.
  • Not runnable here (unchanged from the previous round): the MySQL integration lane (ManagedAgentMySqlIT etc.) needs a MySQL server this runner does not have; the CI MySQL lane remains the execution witness. The previous round's mutation probe for disposition 2 is cited, not re-run — the tree is byte-identical to when it ran.
中文说明

Autofix 本轮总结 — PR #13348

本轮是一次同轮验证修复:上一轮已把第 4 轮的两条发现全部实现在提交 3a3b203f53 中,确定性门禁拒绝该提交是因为 npm run lint 失败——但失败点不在提交内容里,而在 runner 工作区中残留的、未被 git 跟踪且被 gitignore 覆盖的 Maven javadoc 产物。本轮原样保留 3a3b203f53,清除工作区污染,重新跑通全部验证,并用一个空的跟进提交 f093e1766f 记录本次修复(树上确实没有任何需要改动的东西——被拒绝的原因是工作区状态,不是已提交的内容)。无基线分支冲突(--conflict false),未做合并。本轮净改动:0 行。

发现处置

1. rc:4180490215 — R4-1:isolatesTenantsThatDifferOnlyByCase 手工维护的九表删除清单 —— 已解决(在被保留的提交 3a3b203f53 中)

该用例改为按运行命名空间化两个 tenant("case-" + UUID.randomUUID()... 及其大小写折叠的大写孪生,二者在构造上只差大小写),九表子表优先删除循环、父表 DELETE FROM managed_agent_session 以及随之失去用途的 deleteIfTableExists 辅助方法全部删除(该文件 −24/+10)。这与发现的首选修复建议完全一致。本轮重新验证:模块 test-compile 通过(含该 IT),聚焦测试套件全绿;评审要求的「同一 MySQL 库连跑两遍」见证在本 runner 上仍无法执行(无 MySQL 服务、无 Docker),继续由 CI 的 MySQL lane 承担。

2. rc:4180490220 — R1-11:两个 retry 用例缺少 harness 侧校验 —— 已解决(在被保留的提交 3a3b203f53 中)

两个 retry 用例新增 verify(harness, times(1)).continueManagedRuntime(tenantId, sessionId, promptId, "checkpoint-1", "activation-1")(与打桩完全一致的精确字面量),以及 verify(harness, never()).submit(...) 和六个 String 的 verify(store, never()).failTurn(...);两个 fail 路径用例新增四个 String 加一个 long 的 verify(store, never()).scheduleTurnRetry(...)。本轮重新验证:HarnessCoordinatorTest 带守卫 33/33 全绿。上一轮的变异对照(水位不匹配分支二次驱动变异体 → 恰好两个 retry 用例变红;还原后 → 33/33 全绿)依然有效——自该对照运行以来树未发生任何变化。

验证修复(门禁为何拒绝、修了什么)

  • 先复现:对上一轮留下的工作区直接跑 npm run lint,失败,589 个错误与门禁完全一致。全部错误都在 packages/sdk-java/qwencode/target/reports/apidocs/*.js(jQuery、javadoc 搜索索引)——这些文件未被 git 跟踪、被 packages/sdk-java/qwencode/.gitignore(target/)忽略,但仍被 eslint 扫描,因为根 eslint flat 配置的全局 ignores 覆盖了 packages/desktop/src-tauri/target/**,却没有覆盖 packages/sdk-java/**/target/**。这些文件由上一轮在 03:56 UTC 对 qwencode 模块执行的 Maven package/install 目标生成(maven-javadoc-plugin 的 attach-javadocs 执行绑定在 package 阶段),时间在那一轮自己跑 lint 之后。
  • 修复:删除 packages/sdk-java/qwencode/target/reports(未被跟踪、被 gitignore、可再生的构建产物;被修复的提交从未触及它)。随后把门禁同款命令跑到全绿。
  • 确认不会再生:本轮自己的 Maven 命令(test 阶段、checkstyle:check,且只作用于 managed-agent-server 模块)不会重新生成 apidocs,npm run build 完全不调用 Maven——因此门禁复核时看到的工作区就是 lint 全绿的工作区。
  • 一条留给 maintainer 的线索(超出 autofix 边界):根治办法是在根 eslint.config.js 的全局 ignores 里加一行 packages/sdk-java/**/target/**(比照已有的 packages/desktop/src-tauri/target/**)——在任何分支上,对启用 javadoc 的 Java 模块执行本地 mvn package/install/verify 后再跑 npm run lint 都会复现这个失败。autofix 被禁止改动仓库根 eslint 配置,因此在此标记而不代劳。

本轮未处理

  • 评审正文中的收敛观察(根因归类、批量修复、--severity-floor critical、先合入再转后续)是面向 PR/工作流的流程建议,不产生代码改动;调整评审严重级别属于 CI/工作流机制,无论如何都超出边界。
  • 第 3 轮已报告的三条建议保持原处置:deleteIfTableExists 的 blanket 捕获已随辅助方法一并删除(作为处置 1 的副作用解决);重跑见证可见性(ManagedAgentMySqlIT.java:101)与 recovery 标志未钉住(QwenHostedHarnessConnectorTest.java:599,第 3 轮已推迟)两项未被触及,对应线程保持打开。
  • 本轮未删除或削弱任何测试(本轮仅新增一个空提交),故无 test-weakening.json;无新的推迟项,故无 deferred-findings.json;本轮没有被拒绝或留开的行内发现,故无 comment-replies.json。

验证

  • npm run lint(清理前,复现)——失败,589 个错误与门禁完全一致,100% 位于 packages/sdk-java/qwencode/target/reports/apidocs/(10 个 javadoc JS 文件);确认其他位置零错误,包括 runtime-broker/target/test-classes 下两个 lint 全绿的 .mjs fixture。
  • mvn -o -Dmaven.repo.local=/tmp/m2-pr13400/repository -Dtest=HarnessCoordinatorTest test(managed-agent-server,JDK 21 /tmp/toolchain/jdk,离线)——33/33 通过;模块 test-compile 覆盖被编辑的 ManagedAgentMySqlIT。
  • mvn -o -Dmaven.repo.local=/tmp/m2-pr13400/repository checkstyle:check(managed-agent-server)——BUILD SUCCESS;事后确认 apidocs 未被重新生成。
  • 删除 packages/sdk-java/qwencode/target/reports(未被跟踪、被 gitignore 的 javadoc 产物)。
  • npm run build —— 通过(首次尝试命中纯环境问题:沙箱 $HOME 下 corepack 缓存目录 EACCES;改用 COREPACK_HOME=/tmp/corepack-home 后 exit 0——与仓库内容无关)。
  • npm run typecheck —— 通过。
  • npm run lint(清理后一次,build 成功后再一次)—— 通过,0 错误。
  • 收尾检查:git status --porcelain 干净;所有 packages/**/target/ 下除两个 lint 全绿的 .mjs fixture 外,不存在 eslint 可见的 JS/TS 文件。
  • 本地无法运行(与上一轮相同):MySQL 集成 lane(ManagedAgentMySqlIT 等)需要本 runner 不具备的 MySQL 服务;CI 的 MySQL lane 仍是执行见证。处置 2 的上一轮变异对照为引用而非重跑——当时的树与现在逐字节一致。

Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。

🧵 Resolved all 2 selected review thread(s). · 已关闭全部选中的 2 条评审线程。

Re-review when you have a moment. After round 100 this bot stops and leaves the PR for a human. · 有空请复审;第 100 轮后本 bot 停止并将 PR 交给人工。


🧠 Handled by Qwen Code · model/模型 kimi-k3 · CLI 0.24.7

@wenshao

wenshao commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator Author

Verdict: findings — 24/25 assertions pass, 1 non-blocking coverage gap. Maintainer-local verification round; verified head fd78979d81f5d0ad26e632540fdf5419b80808c0 (merge-base 9915c7ff == current origin/main; effective diff is 8 test files, +613/−49, zero production code).

中文摘要

结论:findings(1 条非阻塞覆盖缺口) —— 核心主张全部实测成立,是否合并由维护者判断。

  • A/B 基线:同一生产代码上 head 测试 100/100 绿、merge-base 测试 89/89 绿(图 1),PR 净增 11 个测试方法。
  • 变异体矩阵(图 2):13 个生产守卫变异体中 11 个被 head 新测试杀死、且全部不被 base 测试杀死——新增覆盖真实有效、非 vacuous;6 个对照变异体两臂全红,证明两臂套件都是活的;无变异体出现「base 杀/head 存」的回退。commit 自称的探针「删掉 lastEventId 析取支恰好只红 retriesTheTurnWhenTheRecoveredWatermarkRegresses」被精确复现。
  • MySqlIT 可重跑(图 3):同一持久 MySQL 8.4.7 数据目录连续两轮 failsafe 均 19/19 全绿——这是 PR 头号主张,CI 只覆盖全新库首跑(MariaDB 10.11,图 4),本地双跑补齐了「持久库重跑」这一半。
  • Findings(均为完备性提示,非缺陷):F1 未知结果回退 load 的 passiveManagedRuntimeRecovery=false 操作数未被钉住(翻转为 true 后全套件仍绿);F2(存量)普通 submit 路径的 recordAdmission 调用在 base/head 均无测试钉住。
  • 未覆盖:flake 修复的统计显著性;Hosted*IT 故障门(CI 已覆盖);fixture 的 TS 侧消费者;逐 commit 归因。

A/B baselines — identical production code, only the test files differ (A/A control: both arms must be green, both are):

arm tests result
head fd78979d test files 100 100/100 green
merge-base 9915c7ff files overlaid 89 89/89 green

A/B baselines

Mutation A/B — single-point mutants of the unmodified production files, run against head tests and merge-base tests. Coverage mutants expected head-RED/base-GREEN, controls RED/RED. 11/13 coverage mutants killed at head, none killed at base (the two misses are adjudicated below); 6/6 final controls killed on both arms; no mutant regressed from killed-on-base to survived-on-head.

Highlights: deleting the admission.lastEventId() < attachment.lastEventId() disjunct fails exactly retriesTheTurnWhenTheRecoveredWatermarkRegresses (the commit's own probe claim, reproduced verbatim); the fixture coherence mutant (recordCount 2→3) reds with expected: <3> but was: <2> — the new assertion, not the digest check; the 8 MiB→64 MiB budget mutant shifts page 1 from 9 to 10 transactions.

Mutation A/B record

MySqlIT rerunnability (headline claim) — two back-to-back failsafe runs against one persistent throwaway MySQL 8.4.7 datadir: both Tests run: 19, Failures: 0, Errors: 0. CI covers the fresh-DB first pass only (MariaDB 10.11 lane, job 111564496520, 19/19 green — figure 4); this round supplies the persistent-DB rerun half. Dialects now covered: MariaDB 10.11 (CI), MySQL 8.4.7 (here), MariaDB 11.3 (author's body claim).

MySqlIT double-run

CI MariaDB lane

Findings (both completeness notes, not defects):

  • F1 (low) — the unknown-outcome fallback's passiveManagedRuntimeRecovery=false operand is unpinned: flipping it to true in QwenHostedHarnessConnector.create() leaves the full head suite green (M7c). The PR witnesses that the fallback happens and that the tuple propagates, but not which recovery mode it requests; one ArgumentCaptor<LoadHarnessSession> assertion would close it.
  • F2 (low, pre-existing) — the plain-path store.recordAdmission(...) call is pinned by no test in either suite version (deleting it survives both). Out of this PR's stated scope, which pins recovery admission; noted so a future refactor doesn't drop it silently.

One harness caveat, not a PR issue: when the unknown-outcome mock exception propagates (fallback deleted), JUnit's failure reporting NPEs on the mock and truncates the class at 10/22 — the red verdict was still caused by the removed fallback, and a second mutant (tuple mapping drops lastEventId) produced the clean assertion-level red in exactly the two new tuple tests.

Not covered: statistical flake-rate A/B for ManagedAgentServerIntegrationTest (3× green at head is a smoke signal only); Hosted*IT fault gates (need the CLI bundle; CI job 111564496388 covers them); TS consumers of the fixture; per-commit attribution (verified as the aggregate diff). macOS arm64, JDK 26 (--release 21), Maven 3.9.16; Linux/Windows Java lanes green in CI.

Full harnesses (matrix.py, matrix2.py, baseline-ab.sh, mysql-double-run.sh) and per-cell JSON available on request.

…rsions (#13348)

- ManagedAgentMySqlIT: replace the single firstPass flag with
  BackfillWitnesses derived from the versions Flyway had applied at the
  run's start. One shared flag reads a database left mid-window as a
  first pass (V2's consumer_progress count then fails on rows V2 never
  saw) or as a rerun (the V17 and V29 witnesses then silently skip over
  freshly seeded rows their migrations did migrate). The V9 re-seed now
  keys on V9's application too: at V14 firstPass is true, so the old
  keying skipped the re-seed and the idempotency_conflict probe failed.
- BackfillWitnessesTest: pin the gate tuple against H2 databases staged
  at every boundary version (fresh, 1, 8, 9, 14, 15, 16, 17, 28, 29,
  head); reverting to the shared flag reds it.
- QwenHostedHarnessConnectorTest: stub getSuppressed()/getStackTrace()
  on the mocked unknown-outcome exception so a regressed fallback
  reports the failing test's name instead of aborting the class report
  on a null array; capture the LoadHarnessSession and pin the
  passiveManagedRuntimeRecovery=false operand.
- SessionEventHubTest: await one below the watermark so CAPACITY is
  pinned from above as well (a 513 ring now reds the witness).
- HarnessEventProjectorTest: witness the tool_call allowlist, the
  sibling of the text-path redaction the PR already pinned (the raw
  update leak mutant now dies).

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤖 Addressed the latest review feedback (round 4/100). What changed, and what I pushed back on: · 已处理最新评审反馈(第 4/100 轮)。改动内容与我反驳保留之处如下:

Round 6 — review feedback addressed (head 55d45fcc3a)

One commit, test-only, inside the PR's existing footprint (packages/sdk-java/managed-agent-server/src/test/**). 6 files, +169/−23.

Dispositions

rc:4181897454 — R5-1: per-witness migration gates in ManagedAgentMySqlIT — Implemented

The single firstPass flag is gone. upgradesAndExercisesStoresOnMySql now captures the versions Flyway had already applied before it migrates anything (BackfillWitnesses.appliedVersions) and derives one gate per one-shot backfill (BackfillWitnesses.forApplied): the V2-derived consumer_progress count opens iff V2 was pending, the V15/V17/V29 witnesses open iff their own migration was pending. A database left mid-window by an interrupted or older run can no longer fail the V2 count (V14 case) nor silently skip the V17/V29 witnesses over freshly seeded rows (V16 case). The agent_revision assertion stays outside every gate, all gates stay hard assertions (no Assumptions), and the skip invariant holds: a witness whose migration did not run over this run's seeds is still skipped.

Two evidence-backed deviations from the finding's literal sketch, both forced by its own measured acceptance criteria:

  1. No assertThat(firstPass).isEqualTo(emptyDatabase). At V14 target("15") applies V15 alone, so firstPass is true while emptyDatabase is false — the equality would fail exactly where the finding's pin demands "pre-staging at V14 … the method passes". The per-version gates make the flag unnecessary, so the premise assertion went with it.
  2. The V9 re-seed keys on V9's application (appliedAtStart.contains("9")), not on !firstPass. At V14 !firstPass is false, so the old keying skipped the re-seed; requireCreationScope then inserts workspace_bound = TRUE itself and reads it back equal, and the idempotency_conflict probe fails instead of throwing — again contradicting "V14 must pass". The condition still keys off the step that contains V9, now exactly rather than by proxy. Measured below: with this keying the fixed method passes at V14, probe included.

The alternative the finding offered (per-run schema from :1028-1064) was not taken: it would make every gate unconditionally true by abandoning the persistent-database rerun this PR exists to support — a direction call for a maintainer, and unnecessary now that the gates are exact.

Sandbox verification F1 — mocked Throwable breaks the surefire reporter — Implemented, with a correction

unknownCreateOutcomeFallsBackToLoadAndPropagatesTheFullAttachment now stubs the mock's getSuppressed() and getStackTrace(). Correction to the report's measured fix (a): stubbing getSuppressed() alone is not sufficient here. Local probe on this module's classpath: a plain mock reads getSuppressed(), getStackTrace(), getCause() and getMessage() all as null; under the report's M11b mutant (fallback rethrows), the getSuppressed-only arm still aborted the class at 10/22 with the bare NullPointerException, while the both-stubs arm reported all 22 tests with the error attributed to the named test — matching the report's own cell 4 (both stubbed → no NPE).

Sandbox verification F3 — CAPACITY pinned from below only — Implemented

evictsBeyondCapacityAndSignalsOverflowBelowTheWatermark now also awaits 87 (one below the watermark) and asserts overflowed(). Mutation probe: CAPACITY 512→513 reds the witness (the previously surviving M3), 511 still reds, unmutated green.

Sandbox verification F4 — safeToolData allowlist unwitnessed — Implemented

New projectsToolCallsWithoutLeakingOtherUpdateFields witnesses the tool_call path's allowlist (toolCallId/name/title/status projected; rawInput/secret absent at any nesting depth). Mutation probe: the report's M10 (raw update bleeds through) now dies at this test. This closes the last surviving projector mutant, in the file this PR already hardens — one instance of the same class, not a scope expansion.

Sandbox verification F5 — import order — Implemented

SessionCreationOutcomeUnknownException moved to its alphabetical position. (The pre-existing mis-placed org.mockito.ArgumentCaptor import was left alone — not introduced by this PR and not part of the finding.)

Sandbox verification F2 — overflow witness name vs. the redundant droppedThrough operand — Declined in place, simplification deferred

The finding self-classifies as "redundant defence … not a coverage hole to fill and not a defect" and explicitly warns against removing the field without a separate simplification review. The test name describes the observable contract (eviction + overflow below the watermark), which the test does pin; renaming would be churn without behavior change. The invited simplification review of the production guard is recorded in the deferred-findings queue for follow-up, since this PR is test-only.

Maintainer verification F1 (ic:5988750035) — passiveManagedRuntimeRecovery=false operand unpinned — Implemented

The unknown-outcome witness now captures the LoadHarnessSession and asserts the operand is false (active path — passive belongs to the observe-only attachment). The field is private and toJson() is package-private in another package, so the assertion reads it via the file's existing ReflectionTestUtils idiom. Mutation probe: flipping the fallback to load(session, true) (the report's M7c, previously green) now reds exactly this test.

Maintainer verification F2 — plain-path recordAdmission unwitnessed — Deferred to follow-up

Verified real by the maintainer's mutant and explicitly "out of this PR's stated scope". Recorded in deferred-findings.json so it survives the merge.

No conflict resolution was needed (--conflict false; no merge performed).

Verification

Environment: Temurin JDK 21.0.12.1 + Maven 3.9.11 (unpacked under /tmp), plus a local MariaDB 10.11.18 — the exact image CI pins — installed from the official binary tarball and run rootless on 127.0.0.1:13306; mid-window databases pre-staged with a throwaway Flyway driver. Nothing of the local harness enters the repo.

  • npm run build / npm run typecheck / npm run lint — all passed.
  • mvn test -Dtest='BackfillWitnessesTest,SessionEventHubTest,HarnessEventProjectorTest,QwenHostedHarnessConnectorTest' — 33/33 green.
  • Full module surefire (default includes): 651 tests, 0 failures, 1 error — RuntimeBrokerDefaultOnTest fails because this container has no /etc/machine-id ("Trusted Linux host/boot identity is unavailable"); the independent sandboxed verification measured the identical failure at the unmodified PR head in its container, and CI's Java lanes are green. 651 = the head's 649 + this round's 2 new tests.
  • mvn -Pmysql-integration failsafe:integration-test failsafe:verify (all non-Hosted ITs, persistent DB): 52/52 green, incl. ManagedAgentMySqlIT 19/19.
  • mvn checkstyle:check — 0 violations.
  • R5-1 end-to-end (real failsafe IT vs. pre-staged databases): pre-fix baseline at V14 reds with expected: 1 but was: 0 at ManagedAgentMySqlIT:130 (the finding's witness reproduced exactly); pre-fix at V16 greens while V17/V29 install over the run's fresh seeds with their witnesses silently skipped (the too-broad limb reproduced). Fixed code: V14 green (V2 count unasserted; V15/V17/V29 witnesses execute; idempotency_conflict probe passes), V16 green, fresh DB 19/19, immediate rerun on the same persistent DB 19/19.
  • Witness-execution discrimination (fixed code): tampering LegacyLifecycleCommands.assertMigrated to throw reds the V16 run ("V17 witness executed") and stays green on the at-head rerun (correctly skipped); same pair for LegacyHookRecords.assertBackfilled (V29).
  • Mutation probes, each red-then-restored-green: CAPACITY 512→513 (kills M3 via the new below-watermark assertion); safeToolData raw-update leak (kills M10 via the new tool_call witness); fallback load(session, false→true) (kills M7c via the new captor assertion); BackfillWitnesses.forApplied reverted to single-flag semantics (reds BackfillWitnessesTest at "database staged at 8").
  • One discarded run, recorded for honesty: an earlier clean verify attempt passing -Dtest='!RuntimeBrokerDefaultOnTest' to skip the container-blocked test made surefire run the *IT classes it normally never runs (a specified -Dtest replaces surefire's default includes), including Hosted ITs missing their prerequisites and the MySQL IT classes in one shared-DB session — 15 failures/7 errors, all invocation artifacts of that flag, none present in the properly scoped runs above.

Deferred: deferred-findings.json carries maintainer-F2 (plain-path recordAdmission witness) and verify-F2 (the redundant droppedThrough guard's simplification review). Resolved inline threads: rc:4181897454. No test was deleted, skipped, or weakened (the four MySqlIT witness calls remain verbatim under finer gates; the connector's verify(client).loadSession(...) was strengthened, not removed).

中文说明

第 6 轮 —— 评审反馈处理(head 55d45fcc3a)

一个 commit,仅改测试,落在 PR 既有范围内(packages/sdk-java/managed-agent-server/src/test/**)。6 个文件,+169/−23。

逐条处置

rc:4181897454 —— R5-1:ManagedAgentMySqlIT 的逐见证迁移判据 —— 已实现

单一的 firstPass 标志已移除。upgradesAndExercisesStoresOnMySql 现在在做任何迁移之前先采集 Flyway 已应用的版本(BackfillWitnesses.appliedVersions),并为每个一次性回填各推导一个判据(BackfillWitnesses.forApplied):V2 派生的 consumer_progress 计数仅当 V2 处于 pending 时断言,V15/V17/V29 见证仅当它们各自的迁移处于 pending 时执行。被中断运行或旧版运行留在窗口中间的数据库,既不会再让 V2 计数失败(V14 情形),也不会再在本运行新播种的行上静默跳过 V17/V29 见证(V16 情形)。agent_revision 断言仍在所有判据之外;所有判据都是硬断言(无 Assumptions);跳过不变量保持:其迁移未在本运行的种子行上执行的见证仍被跳过。

对该发现字面方案的两处有据偏离,均由其自己实测的验收标准强制推出:

  1. 没有 assertThat(firstPass).isEqualTo(emptyDatabase)。 在 V14 上 target("15") 只应用 V15,于是 firstPass 为 true 而 emptyDatabase 为 false——该等值断言恰好在发现要求的 "预置 V14……方法通过" 处失败。逐版本判据使该标志失去存在必要,前提断言随之取消。
  2. V9 重播种改以 V9 是否已应用为准(appliedAtStart.contains("9")),而非 !firstPass。 在 V14 上 !firstPass 为 false,旧键控会跳过重播种;requireCreationScope 随后自行插入 workspace_bound = TRUE 并读回相等,于是 idempotency_conflict 探针不抛异常而失败——同样与"V14 必须通过"矛盾。该条件仍以包含 V9 的那一步为准,只是从代理变为精确。下方实测:采用此键控后,修复后的方法在 V14 通过(含探针)。

发现给出的另一方案(:1028-1064 的按运行独立 schema)未采用:它会让所有判据恒真,代价是放弃本 PR 存在所系的持久库重跑——那属于维护者的方向决策,且判据精确化后已无必要。

沙箱验证 F1 —— mock 出来的 Throwable 打崩 surefire 报告器 —— 已实现,并有一处修正

unknownCreateOutcomeFallsBackToLoadAndPropagatesTheFullAttachment 现在同时打桩 mock 的 getSuppressed() 和 getStackTrace()。对报告所给实测修法 (a) 的修正:仅打桩 getSuppressed() 在这里并不够。本模块 classpath 上的本地探针:裸 mock 的 getSuppressed()、getStackTrace()、getCause()、getMessage() 全部读出 null;在报告的 M11b 变异体(回退改为重抛)下,只打桩 getSuppressed 的一臂仍在 10/22 处以裸 NullPointerException 中止整个类,而双桩一臂报告全部 22 个用例、错误归属到具名测试——与报告自己的第 4 格(双桩→无 NPE)一致。

沙箱验证 F3 —— CAPACITY 只从下界被钉住 —— 已实现

evictsBeyondCapacityAndSignalsOverflowBelowTheWatermark 现在还会 await 87(水位线之下一格)并断言 overflowed()。变异探针:CAPACITY 512→513 使该见证变红(此前存活的 M3 被杀死),511 仍变红,未变异全绿。

沙箱验证 F4 —— safeToolData 白名单无见证 —— 已实现

新增 projectsToolCallsWithoutLeakingOtherUpdateFields,为 tool_call 路径的白名单作证(toolCallId/name/title/status 被投影;rawInput/secret 在任意嵌套深度均不存在)。变异探针:报告中的 M10(原始 update 泄漏)现在死于此测试。这关闭了投影器最后一个存活变异体,且就在本 PR 已在加固的文件里——是同一类问题的另一个实例,不是范围扩张。

沙箱验证 F5 —— import 顺序 —— 已实现

SessionCreationOutcomeUnknownException 移到字母序位置。(既有的错位 org.mockito.ArgumentCaptor import 未动——非本 PR 引入,也不属于该发现。)

沙箱验证 F2 —— 溢出见证的命名 vs 冗余的 droppedThrough 操作数 —— 就地婉拒,简化问题转后续

该发现自分类为"冗余防御……不是要补的覆盖空洞,也不是缺陷",并明确警告未经单独的简化评审不得删除该字段。测试名描述的是可观察契约(容量淘汰 + 水位线以下报溢出),而测试确实钉住了该契约;改名只有churn没有行为变化。其邀请的对生产守卫的单独简化评审已记入 deferred-findings 队列转后续,因为本 PR 仅改测试。

维护者验证 F1(ic:5988750035)—— passiveManagedRuntimeRecovery=false 操作数未被钉住 —— 已实现

未知结果见证现在捕获 LoadHarnessSession 并断言该操作数为 false(活跃路径——passive 属于只观察的附加)。该字段是 private、toJson() 在另一个包里是包私有,因此断言沿用本文件已有的 ReflectionTestUtils 手法读取。变异探针:把回退改成 load(session, true)(报告的 M7c,此前全绿)现在恰好使该测试变红。

维护者验证 F2 —— 普通路径 recordAdmission 无见证 —— 转后续

维护者的变异体验证为真,且其明确"超出本 PR 声明范围"。已记入 deferred-findings.json,合入后不会丢失。

无需冲突解决(--conflict false;未做合并)。

验证

环境:Temurin JDK 21.0.12.1 + Maven 3.9.11(解包在 /tmp),外加本地 MariaDB 10.11.18——正是 CI 所钉的镜像——由官方二进制包安装、以非 root 跑在 127.0.0.1:13306;窗口中间态数据库用一个一次性 Flyway 驱动预置。本地脚手架一律不进仓库。

  • npm run build / npm run typecheck / npm run lint —— 全部通过。
  • mvn test -Dtest='BackfillWitnessesTest,SessionEventHubTest,HarnessEventProjectorTest,QwenHostedHarnessConnectorTest' —— 33/33 绿。
  • 模块全量 surefire(默认 includes):651 个测试,0 失败,1 错误 —— RuntimeBrokerDefaultOnTest 因本容器没有 /etc/machine-id 而失败("Trusted Linux host/boot identity is unavailable");独立沙箱验证在其容器中、在未修改的 PR head 上测得了完全相同的失败,且 CI 的 Java 泳道为绿。651 = head 的 649 + 本轮新增的 2 个测试。
  • mvn -Pmysql-integration failsafe:integration-test failsafe:verify(全部非 Hosted IT,持久库):52/52 绿,其中 ManagedAgentMySqlIT 19/19。
  • mvn checkstyle:check —— 0 违规。
  • R5-1 端到端(真实 failsafe IT 对预置数据库):修复前基线在 V14 于 ManagedAgentMySqlIT:130 以 expected: 1 but was: 0 变红(精确复现该发现的见证);修复前在 V16 通过,同时 V17/V29 在本运行新播种的行上安装完成而见证被静默跳过(偏宽一侧亦复现)。修复后:V14 绿(V2 计数未断言;V15/V17/V29 见证执行;idempotency_conflict 探针通过),V16 绿,全新库 19/19,同一持久库立即重跑 19/19。
  • 见证执行判别(修复后):把 LegacyLifecycleCommands.assertMigrated 改为直接抛异常时,V16 运行变红("V17 witness executed"),而在 head 重跑上保持绿色(被正确跳过);LegacyHookRecords.assertBackfilled(V29)同样的一对结果。
  • 变异探针,均先变红、还原后回绿:CAPACITY 512→513(经新的水位线下断言杀死 M3);safeToolData 原始 update 泄漏(经新的 tool_call 见证杀死 M10);回退 load(session, false→true)(经新的 captor 断言杀死 M7c);BackfillWitnesses.forApplied 退回单标志语义(使 BackfillWitnessesTest 在 "database staged at 8" 处变红)。
  • 一次作废的运行,如实记录:早前一次 clean verify 传了 -Dtest='!RuntimeBrokerDefaultOnTest' 试图跳过容器受限测试,结果 surefire 跑起了它 normally 从不运行的 *IT 类(一旦指定 -Dtest 就会替换 surefire 的默认 includes),包括缺前置条件的 Hosted IT 以及同库同会话的全部 MySQL IT 类——15 失败/7 错误,全部是该标志的调用方式产物,在上述正确限定的运行中均不存在。

转后续:deferred-findings.json 记录了维护者 F2(普通路径 recordAdmission 见证)与验证 F2(冗余 droppedThrough 守卫的简化评审)。已解决的行内线程:rc:4181897454。没有任何测试被删除、跳过或削弱(MySqlIT 的四个见证调用原样保留在更细的判据之下;连接器的 verify(client).loadSession(...) 是被加强而非移除)。

Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。

🧵 Resolved all 1 selected review thread(s). · 已关闭全部选中的 1 条评审线程。

Re-review when you have a moment. After round 100 this bot stops and leaves the PR for a human. · 有空请复审;第 100 轮后本 bot 停止并将 PR 交给人工。


🧠 Handled by Qwen Code · model/模型 kimi-k3 · CLI 0.24.7

…java-tests

Resolve SessionEventHubTest.java as a union: keep this branch's
evictsBeyondCapacityAndSignalsOverflowBelowTheWatermark witness beside
the five hub tests main added with the Condition rewrite (#13402),
whose CAPACITY-512 watermark semantics it still pins (#13348).
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤖 Addressed the latest review feedback (round 5/100). What changed, and what I pushed back on: · 已处理最新评审反馈(第 5/100 轮)。改动内容与我反驳保留之处如下:

Address-review round — PR #13348 (round 7)

Feedback dispositions

[rv:5415434423] @qwen-code-ci-bot — "Partially reviewed — gaps disclosed" (COMMENTED)

  • The one Suggestion-level finding it confirmed (D6-2, driveRuntimeRecovery
    unpinned on the unknown-create-outcome fallback,
    QwenHostedHarnessConnectorTest.java:612) is not new work: the review notes
    it is already recorded as round 3's deferral at the same location and was not
    re-posted. No action.
  • The four Suggestions listed under the qwen-review-deferred marker
    (ManagedAgentMySqlIT.java:118, BackfillWitnessesTest.java:27,
    HarnessEventProjectorTest.java:75, HarnessEventProjectorTest.java:94)
    were deferred by the reviewer's own convergence posture — "recorded, not
    requested in this round" — and remain tracked in the review ledger. Per the
    critical-posture round rules they are an audit record, not work for this
    round. No action.
  • The disclosed gap ("reverse audit did not converge within the round cap of
    5") is a coverage disclosure, not a finding. No action.

Inline comments: none. Issue-level comments: none. Failed checks: none.
Still-red checks: none.

Base-branch conflict resolution (--conflict true)

Merged origin/main (8648508) into the branch. Main had changed four of
the ten files this PR touches; three auto-merged cleanly
(ManagedSessionStoreContractFixtureTest.java,
ManagedSessionStoreIntegrationTest.java,
QwenHostedHarnessConnectorTest.java), and one conflicted:

  • service/SessionEventHubTest.java — resolved as a union. The base had two
    hub tests; this PR added
    evictsBeyondCapacityAndSignalsOverflowBelowTheWatermark (pins the
    CAPACITY-512 watermark at 88/89) while main's fix(managed-agent): serve SSE subscribers from a Condition instead of pinning carriers (#13388 follow-up) #13402 Condition rewrite added
    five tests (bufferIsEvictedWhenTheLastSubscriberCloses,
    closingOneOfTwoSubscribersKeepsTheBuffer,
    closingTheSameSubscriberTwiceKeepsTheBufferForTheOther,
    publishWakesEveryParkedSubscriber,
    awaitPropagatesInterruptionLikeObjectWait). I verified main's rewritten
    SessionEventHub keeps CAPACITY = 512 and the same
    eviction/droppedThrough watermark semantics, so the PR's witness still
    pins the ring size from both sides, and kept all eight tests plus main's
    concurrency imports.

Post-merge audit of the four overlap files confirmed no test method from
either side was lost, and the focused Maven run exercises all of them.

Verification

  • mvn install -DskipTests for packages/sdk-java/qwencode (merged
    ManagedSessionStoreConnection.java) — BUILD SUCCESS
  • mvn install -DskipTests for packages/sdk-java/runtime-broker — BUILD
    SUCCESS
  • mvn test -Dtest=SessionEventHubTest,QwenHostedHarnessConnectorTest,HarnessCoordinatorTest,ManagedSessionStoreContractFixtureTest,ManagedSessionStoreIntegrationTest,BackfillWitnessesTest,HarnessEventProjectorTest,ManagedAgentServerIntegrationTest
    (managed-agent-server) — Tests run: 113, Failures: 0, Errors: 0, Skipped: 0
  • mvn checkstyle:check (managed-agent-server) — BUILD SUCCESS
  • npm run build — passed
  • npm run typecheck — passed (re-run after the merge commit: passed)
  • npm run lint — passed (re-run after the merge commit: passed)

Not run (environment-bound, unchanged by this round): the MySQL-backed
hosted-harness-mysql failsafe profile has no MySQL service on this runner;
CI remains the gate for it. The round's only edit is a test-file union in
pure-Java unit tests, which the 113-test surefire run above covers.

No test weakening: the resolution adds main's five tests to the PR's three in
SessionEventHubTest.java; nothing was removed or disabled. No inline
findings existed, so resolved-comments.txt and comment-replies.json are
omitted.

中文说明

Address-review 轮次 — PR #13348(第 7 轮)

反馈处置

[rv:5415434423] @qwen-code-ci-bot ——「部分审查——缺口已披露」(COMMENTED)

  • 该评审确认的唯一一条 Suggestion 级发现(D6-2,unknown-create-outcome
    回退路径上 driveRuntimeRecovery 未钉住,
    QwenHostedHarnessConnectorTest.java:612)并非新工作:评审注明它已在
    第 3 轮于同一位置记录为延后,且未重复发布。不做处理。
  • 列在 qwen-review-deferred 标记下的四条 Suggestion
    (ManagedAgentMySqlIT.java:118、BackfillWitnessesTest.java:27、
    HarnessEventProjectorTest.java:75、HarnessEventProjectorTest.java:94)
    由审查方自身的收敛姿态延后——「已记录,本轮不要求修改」——并仍由审查
    台账跟踪。按 critical 发布姿态的轮次规则,这些是审计记录而非本轮工作。
    不做处理。
  • 已披露的缺口(「反向审计在 5 轮上限内未收敛」)是覆盖面披露,不是发现。
    不做处理。

行内评论:无。issue 级评论:无。失败的检查:无。持续红灯的检查:无。

基线分支冲突解决(--conflict true)

将 origin/main(864850816e)合入本分支。main 改动了本 PR 触及的十个
文件中的四个;三个自动合并干净
(ManagedSessionStoreContractFixtureTest.java、
ManagedSessionStoreIntegrationTest.java、
QwenHostedHarnessConnectorTest.java),一个发生冲突:

  • service/SessionEventHubTest.java —— 以并集方式解决。基线有两个 hub
    测试;本 PR 新增了
    evictsBeyondCapacityAndSignalsOverflowBelowTheWatermark(在 88/89 处
    钉住 CAPACITY-512 水位线),而 main 的 fix(managed-agent): serve SSE subscribers from a Condition instead of pinning carriers (#13388 follow-up) #13402 Condition 重写新增了五个
    测试(bufferIsEvictedWhenTheLastSubscriberCloses、
    closingOneOfTwoSubscribersKeepsTheBuffer、
    closingTheSameSubscriberTwiceKeepsTheBufferForTheOther、
    publishWakesEveryParkedSubscriber、
    awaitPropagatesInterruptionLikeObjectWait)。我核实了 main 重写后的
    SessionEventHub 保持 CAPACITY = 512 及相同的驱逐/droppedThrough
    水位线语义,因此 PR 的见证仍从上下两侧钉住环形缓冲区大小;八个测试及
    main 的并发相关 import 全部保留。

合并后对四个重叠文件的审计确认两侧的测试方法无一丢失,上述聚焦 Maven
运行覆盖了全部测试。

验证

  • mvn install -DskipTests(packages/sdk-java/qwencode,含合入的
    ManagedSessionStoreConnection.java)—— BUILD SUCCESS
  • mvn install -DskipTests(packages/sdk-java/runtime-broker)——
    BUILD SUCCESS
  • mvn test -Dtest=SessionEventHubTest,QwenHostedHarnessConnectorTest,HarnessCoordinatorTest,ManagedSessionStoreContractFixtureTest,ManagedSessionStoreIntegrationTest,BackfillWitnessesTest,HarnessEventProjectorTest,ManagedAgentServerIntegrationTest
    (managed-agent-server)—— Tests run: 113, Failures: 0, Errors: 0,
    Skipped: 0
  • mvn checkstyle:check(managed-agent-server)—— BUILD SUCCESS
  • npm run build —— 通过
  • npm run typecheck —— 通过(合并提交后重跑:通过)
  • npm run lint —— 通过(合并提交后重跑:通过)

未运行(受环境限制,且本轮未改动):MySQL 支撑的
hosted-harness-mysql failsafe profile 在本 runner 上没有 MySQL 服务;
CI 仍是其最终门禁。本轮唯一的编辑是纯 Java 单元测试文件的并集合并,
上面的 113 个 surefire 测试已覆盖。

无测试削弱:解决方案把 main 的五个测试加入 PR 原有的三个测试中
(SessionEventHubTest.java),未删除或禁用任何内容。本轮没有行内发现,
因此省略 resolved-comments.txt 与 comment-replies.json。

Base-conflict check · 基分支冲突检查: conflicted with main — resolved in this push. · 与 main 有冲突——已在本次推送中解决。

Re-review when you have a moment. After round 100 this bot stops and leaves the PR for a human. · 有空请复审;第 100 轮后本 bot 停止并将 PR 交给人工。


🧠 Handled by Qwen Code · model/模型 kimi-k3 · CLI 0.25.0

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下:

Autofix round: no action taken

No code changes were made in this round.

Why

Critical-only mode is active for this PR. The deterministic brake has engaged: 5 change-producing rounds are complete in the current counting window, so this round's actionable sections exclude non-Critical feedback.

The actionable sections of the prepared feedback were empty:

  • Reviews — none new from trusted maintainers or the automated reviewer.
  • Inline comments — none.
  • Issue-level comments — none.
  • Failed checks — none.
  • Still-red checks — none.

The one new item, a review by @qwen-code-ci-bot (link), is recorded in the Deferred non-Critical feedback section. That section is an audit record, not work: per the round rules, those items must not be addressed, have their threads resolved, or receive comment replies from this loop. They remain open for human follow-up, and a maintainer can comment @qwen-code /retry to start a fresh counting window if they want the bot to pick them up.

Diff growth this window is within budget (source 186/400, test 0/400 net lines), so no growth audit was required, and --conflict false meant no base merge was needed.

What happens next

The PR is left exactly as it was: working tree untouched, no commits added. A maintainer can act on the deferred non-Critical review directly, or re-arm the loop with @qwen-code /retry.

中文说明

Autofix 本轮:未采取任何改动

本轮未对代码做任何修改。

原因

本 PR 已进入仅处理 Critical 的模式。 确定性刹车机制已触发:当前计数窗口内已完成 5 个产生改动的轮次,因此本轮的可执行区域已排除非 Critical 反馈。

准备好的反馈中,各可执行区域均为空:

  • Reviews(评审) —— 可信维护者或自动评审机器人均无新评审。
  • Inline comments(行内评论) —— 无。
  • Issue-level comments(Issue 级评论) —— 无。
  • Failed checks(失败的检查) —— 无。
  • Still-red checks(持续失败的检查) —— 无。

唯一的新条目是 @qwen-code-ci-bot 的一条评审(链接),被记录在 Deferred non-Critical feedback(延后处理的非 Critical 反馈) 区域。该区域是审计记录,而不是待办工作:按照本轮规则,这些条目不得由本循环处理、不得解决其讨论串、也不得回复评论。它们保持开放状态,留待人工跟进;维护者如需让机器人处理这些条目,可评论 @qwen-code /retry 开启新的计数窗口。

本窗口的 diff 增长在预算之内(源代码净增 186/400 行,测试净增 0/400 行),因此无需进行增长审计;且 --conflict false 表示无需合并基线分支。

后续

PR 保持原样:工作区未被触碰,未新增任何提交。维护者可以直接处理被延后的非 Critical 评审,或使用 @qwen-code /retry 重新启动循环。

Deferred non-Critical feedback

Critical-only mode is active: 5 change-producing rounds are complete. The workflow excluded the non-Critical feedback below from this round's actionable sections; the items remain open for human follow-up. Maintainer feedback is deferred only after its author has used 2 regular feedback batches in this window's Critical-only tail; authors at that budget, if any, are named below. (@qwen-code /retry starts a fresh counting window.)

中文说明

已进入仅处理 Critical 的模式:已完成 5 个产生改动的轮次。本轮可执行区域已排除下方非 Critical 反馈;这些条目保持开放,留待人工跟进。维护者反馈仅在其本人于本窗口 Critical-only 阶段已使用 2 批常规反馈预算后才会延后;达到预算的作者(如有)在下方点名。(评论 @qwen-code /retry 可开启新的计数窗口。)

Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。


🧠 Handled by Qwen Code · model/模型 kimi-k3 · CLI 0.25.0

@wenshao

wenshao commented Oct 6, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /triage

@wenshao
wenshao enabled auto-merge October 6, 2026 14:14
@wenshao

wenshao commented Oct 6, 2026

Copy link
Copy Markdown
Collaborator Author

Verdict: pass: no new findings. This is round 2 of maintainer-local verification, run on head bd13b6151591d8a94a784eca722e9d8debe38e57 and on a trial merge of that head onto current main (1246dfbc). Round 1 verified fd78979d; its F1 is now closed. The only mutants that still survive are the three items already recorded as deferred. The diff is test-only as stated: 10 files, all under src/test, +759/−52, and none of the added lines contains @Disabled, @EnabledIf*, @EnabledOnOs or a JUnit assumption.

中文摘要

结论:pass(无新发现)。这是维护者本地验证第 2 轮,对象是 head bd13b615 及其与当前 main 1246dfbc 的试合并。第 1 轮的 F1 已关闭;仍存活的变异体只有已登记延后的 3 项。PR 确实只改测试:10 个文件全部在 src/test 下,没有新增任何跳过类写法。是否合并由维护者决定。

  • R2 测试修复的 A/B(图 1):f093e176 → 55d45fcc 两臂只有测试文件不同,生产代码逐字节一致。
    • K1(回退 load 时 passive=true,即第 1 轮 F1)、H1(CAPACITY 512→513)、P1(tool_call 泄漏原始 update):在修复前的测试上存活;在 55d45fcc、head 和试合并上都被击杀,而且各自恰好被新增的那条断言击杀。
    • B1(门控退回成单一标志)被新增的 BackfillWitnessesTest 击杀。
    • K3(回退被删、异常逃逸):修复前类报告停在 10/22,抛出无名 NPE;修复后整类正常上报,失败用例有名字。
    • 第 1 轮已覆盖的 9 个变异体经过两次 main 合并后仍全部被击杀,没有一个从「被击杀」退化成「存活」。3 个对照变异体在四个臂上都被击杀。
  • 真实数据库上的门控矩阵(图 2):用模块自带的 Flyway 迁移(含 Java 写的 V15/V29)把库预置到 V1/8/9/14/15/16/17/28/29/head,加上全新库和同库重跑,在 MySQL 8.4.7 和 MariaDB 10.11.18(CI 镜像)上各跑一遍。
    • 旧的单一标志门控在 V8、V9、V14 上两种库都报假红(行 130,expected: 1 but was: 0)。按构造,起始版本在 V2–V14 之间都会这样,比 PR 里只提 V14 的范围更大。
    • 新门控 24 格全绿。
    • 在真实库上读出的门控五元组,与 BackfillWitnessesTest 在 H2 上的 11 行表完全一致。
  • 见证能否抓到回填被破坏(图 3):分别删掉 V17、V29 的回填。
    • 全新库(CI 的形态)上,新旧门控都报红。
    • 停在 V16/V28 的持久库上,旧门控把它当作重跑、跳过见证,结果假绿;新门控恰好打开对应见证,在行 120/124 报红。这是本 PR 改动的实际价值。
  • 套件、重跑与合并完整性(图 4):
    • CI 等价命令 -Pmysql-integration clean verify checkstyle:check:head 为 738 个单元测试 + 52 个 IT,SpotBugs 0、Checkstyle 0;试合并为 1037 + 52,同样全绿。
    • ManagedAgentMySqlIT 整类在同一持久库上第二次运行:MySQL(head 与试合并)19/19,MariaDB 首跑和重跑 19/19。
    • bot 的合并提交经 remerge-diff 检查,只是对 SessionEventHubTest 做了干净的并集;4 个重叠文件的测试方法一个没丢。
  • 不阻塞合并的说明:
    • 3 个已延后的缺口(D6-2 driveRuntimeRecovery、第 1 轮 F2 的普通路径 recordAdmission、冗余的 droppedThrough 操作数)仍然存活,符合预期。
    • AutoFix 引用的两条 qwen-code-ci-bot 评审现在用 REST 和 GraphQL 查都是 404,延后清单在 PR 页面上已看不到;如需跟踪,建议记到 Tracking: design-level follow-ups from the PR #12692 R2 post-merge review #13302 或单开 issue。
    • 集成测试抖动修复在单独运行时,两臂各 20 次都没有复现抖动,所以无法测出修复效果。

What changed since round 1 (fd78979d → bd13b615):

  • 3a3b203f: single-drive guards and per-run case tenants. This drops the hand-maintained delete list (the earlier R4-1 concern).
  • f093e176: empty re-verification commit.
  • 55d45fcc:
    • per-version backfill gates (BackfillWitnesses) plus a new H2 test;
    • the R1 F1 captor;
    • stubbed Throwable accessors on the mocked exception;
    • CAPACITY pinned from above;
    • a tool_call allowlist witness.
  • bd13b615: merge of main 864850816e.

1. Mutation A/B across four arms (figure 1). From f093e176 to 55d45fcc only test files change; the production tree is byte-identical between the two arms.

  • K1, H1 and P1 confirm three of the R2 claims. Each survives the pre-fix tests and dies on 55d45fcc, on head and on the trial merge, killed by exactly the new assertion:
    • K1: the unknown-outcome fallback loads with passive=true (the R1 F1 mutant).
    • H1: CAPACITY changed from 512 to 513.
    • P1: the raw tool_call update leaks into the projected event.
  • B1: reverting the gate to a single shared flag is killed by the new BackfillWitnessesTest.
  • K3: with the fallback deleted, the pre-fix tests abort the class report at 10/22 with an unnamed NullPointerException. After the fix the whole class is reported and the failure names the test.
  • R1 coverage after the two main merges: all 9 R1-era mutants are still killed on head and on the trial merge, including on main's Condition-based SessionEventHub. No mutant went from killed to survived. All 3 controls die on every arm.

Mutation A/B

2. Backfill gates on real MySQL 8.4.7 and MariaDB 10.11.18 (figure 2). I staged each database with the module's own Flyway migrations, including the Java V15/V29 migrations. The staged states were V1, 8, 9, 14, 15, 16, 17, 28, 29 and head, plus a fresh database and a genuine second run on the same database. Each cell then runs upgradesAndExercisesStoresOnMySql through failsafe.

  • Old gate (the f093e176 IT file on the head tree): false-RED at V8, V9 and V14 on both engines, at line 130 with expected: 1 but was: 0. By construction this happens for any start version from V2 to V14, which is wider than the "V14 case" the fix commit names. target(15) executes migrations, so the run reads as a first pass and asserts a consumer_progress row that V2 never wrote for these seeds.
  • New gate: green in all 24 cells.
  • Gate values on real databases: I read the gate tuple through BackfillWitnesses.appliedVersions on each staged database. The values match the 11-row H2 table in BackfillWitnessesTest exactly, on both engines.

Gate matrix

3. Does the witness catch a broken backfill? (figure 3). I removed the V17 backfill (the INSERT…SELECT and UPDATE), and separately made V29's migrate() return immediately.

  • Fresh database (what CI runs): both gates go red.
  • Persistent database left at V16 or V28: the old gate reads the run as a rerun, skips the witness and goes GREEN, so the regression is missed. The new gate opens exactly that witness and goes RED: at line 120 (LegacyLifecycleCommands.assertMigrated) for V17, and at line 124 (LegacyHookRecords.assertBackfilled) for V29.
  • Engines: the results are identical on MySQL and MariaDB.

Broken-backfill detection

4. Suites, reruns and merge integrity (figure 4).

  • CI-equivalent -Pmysql-integration clean verify checkstyle:check:
    • head: 738 surefire tests (1 skipped: RuntimeBrokerDefaultOnTest, which is @EnabledOnOs(LINUX)), failsafe 52/52, SpotBugs 0, Checkstyle 0.
    • trial merge: 1037 surefire tests and failsafe 52/52, also green. The merge is clean; main adds V41–V47, and no gate references a version above V29.
  • Whole ManagedAgentMySqlIT class, second pass on the same persistent database:
    • MySQL: 19/19 on head and 19/19 on the trial merge.
    • MariaDB 10.11.18: 19/19 on the fresh run and 19/19 on the rerun.
  • Merge integrity of bd13b615:
    • git show --remerge-diff differs from the auto-merge only in SessionEventHubTest, as a clean union.
    • None of the 4 overlap files lost a test method from either side.

Suites and merge integrity

Notes for the merge decision (none blocking):

  • The expected survivors are the three already-deferred items:

    • K2: the fallback with driveRuntimeRecovery=true (D6-2).
    • C5: the plain-path store.recordAdmission call (R1 F2).
    • H3: the droppedThrough operand of overflowed. It is redundant; the contiguity check gives the same result.

    The deferred list lives only in AutoFix's ledger, and the two qwen-code-ci-bot reviews AutoFix cites (5415434423, 5419188436) now return 404 through both REST and GraphQL. Nothing on the PR page records these items, so if they should be tracked, Tracking: design-level follow-ups from the PR #12692 R2 post-merge review #13302 or a new issue is the place.

  • The ManagedAgentServerIntegrationTest cleanup fix is not measurable here. Repeating the class alone gave 20/20 green with the base test file and 20/20 green with head. The flake does not reproduce in isolation, and the PR says it appears after broad runs. The change itself (tenant-keyed recovery map plus @AfterEach turn settling) is sound by inspection.

  • Review state: reviewDecision is REVIEW_REQUIRED, and all 3 review threads are resolved. CI on bd13b615 is fully green (SDK Java run 37330062280, Qwen Code CI run 37330062207).

Not covered:

  • the Hosted*IT fault gates (CI's Hosted process fault gates / MySQL 8.4 lane is green on this head);
  • Windows and Linux runs (CI lanes are green);
  • a flake rate measured under broad-suite runs.

Environment: macOS arm64; Zulu JDK 21.0.12; Maven 3.9.16 with a private local repository per tree (qwencode and runtime-broker installed from the same tree); native MySQL 8.4.7; MariaDB 10.11.18 (mariadb:10.11.18, the CI image) in colima. Every measurement ran in its own detached worktree, with HEAD asserted before and after each run. Harness scripts and per-cell JSON are available on request.

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下:

AutoFix round — no action required

Outcome: no code change this round. No commit was created and the working tree is untouched.

What the feedback contained

Critical-only mode is active for this PR (5 change-producing rounds complete), so only Critical findings, failed checks, and requested base-conflict resolution are actionable this round. The only new feedback since the last evaluation is one issue-level comment from @wenshao:

  • [ic:6018927371] Verdict: pass — no new findings. This is the maintainer's round-2 local verification report on head bd13b615 and a trial merge onto main. It confirms:
    • Round 1's F1 is closed; the only surviving mutants are the three already-deferred items (K2/D6-2 driveRuntimeRecovery, C5/R1 F2 plain-path recordAdmission, H3 redundant droppedThrough operand).
    • The diff is test-only as stated: 10 files under src/test, +759/−52, with no added skip-style annotations. Local inspection of git diff origin/main...HEAD agrees.
    • The per-version backfill gates are green in all 24 cells on real MySQL 8.4.7 and MariaDB 10.11.18, and the new witnesses catch a broken backfill where the old single-flag gate went falsely green.
    • CI on head bd13b615 is fully green.

There are no inline comments, no failed checks, no still-red checks, and no requested conflict resolution (--conflict false), so the branch was not merged with origin/main even though main has since advanced past the merge point.

Non-blocking notes from the report (acknowledged, not actionable by this bot)

  • Deferred-item tracking: the report suggests recording the three deferred items on Tracking: design-level follow-ups from the PR #12692 R2 post-merge review #13302 or a new issue because the two cited bot reviews now return 404. Filing or editing issues is a GitHub write outside this bot's scope; the suggestion is relayed here for the maintainer.
  • Flake-fix measurability: the ManagedAgentServerIntegrationTest cleanup could not be measured in isolation (20/20 green on both arms); the report judges the change sound by inspection. Nothing to change.
  • The three deferred findings remain correctly deferred and are not part of this Critical-only round.

Conclusion

The maintainer's independent verification passes the PR with no new findings and no blocking notes. With Critical-only mode engaged and zero actionable items, the correct outcome is no action; the merge decision rests with the maintainer.

中文说明

AutoFix 本轮 —— 无需处理

结论:本轮不改动代码。 未创建任何提交,工作树保持原样。

反馈内容

本 PR 已进入仅处理 Critical 的模式(已完成 5 个产生改动的轮次),因此本轮只有 Critical 发现、失败的检查和明确要求处理的基线冲突才可执行。自上次评估以来唯一的新反馈是 @wenshao 的一条 issue 级评论:

  • [ic:6018927371] 结论:pass —— 无新发现。 这是维护者对 head bd13b615 及其与 main 试合并的第 2 轮本地验证报告,确认:
    • 第 1 轮的 F1 已关闭;仍存活的变异体只有已登记延后的 3 项(K2/D6-2 driveRuntimeRecovery、C5/R1 F2 普通路径 recordAdmission、H3 冗余的 droppedThrough 操作数)。
    • PR 确实只改测试:src/test 下 10 个文件,+759/−52,未新增任何跳过类注解。本地核对 git diff origin/main...HEAD 结果一致。
    • 逐版本回填门控在真实 MySQL 8.4.7 和 MariaDB 10.11.18 上 24 格全绿,且新见证能抓到旧单一标志门控漏报的回填破坏。
    • head bd13b615 上 CI 全绿。

本轮没有行内评论、没有失败的检查、没有持续飘红的检查,也没有要求处理冲突(--conflict false)。因此尽管 main 已越过当前合并点,仍按规则不做多余合并。

报告中的非阻塞说明(已知悉,不属于本 bot 可执行范围)

  • 延后项跟踪: 报告建议把 3 个延后项记录到 Tracking: design-level follow-ups from the PR #12692 R2 post-merge review #13302 或单开 issue,因为被引用的两条 bot 评审现已 404。创建或编辑 issue 属于 GitHub 写操作,超出本 bot 范围,在此转达给维护者。
  • 抖动修复的可测性: ManagedAgentServerIntegrationTest 的清理修复在单独运行时无法测出效果(两臂各 20 次全绿);报告已通过代码审查判断改动合理,无需改动。
  • 3 个延后发现保持延后状态正确,不属于本 Critical-only 轮的处理范围。

结论

维护者的独立验证已通过本 PR,无新发现、无阻塞说明。在 Critical-only 模式下没有任何可执行项,正确结果就是不采取行动;是否合并由维护者决定。

Deferred non-Critical feedback

Critical-only mode is active: 5 change-producing rounds are complete. The workflow excluded the non-Critical feedback below from this round's actionable sections; the items remain open for human follow-up. Maintainer feedback is deferred only after its author has used 2 regular feedback batches in this window's Critical-only tail; authors at that budget, if any, are named below. (@qwen-code /retry starts a fresh counting window.)

中文说明

已进入仅处理 Critical 的模式:已完成 5 个产生改动的轮次。本轮可执行区域已排除下方非 Critical 反馈;这些条目保持开放,留待人工跟进。维护者反馈仅在其本人于本窗口 Critical-only 阶段已使用 2 批常规反馈预算后才会延后;达到预算的作者(如有)在下方点名。(评论 @qwen-code /retry 可开启新的计数窗口。)

Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。


🧠 Handled by Qwen Code · model/模型 kimi-k3 · CLI 0.25.0

@qwen-code-review-bot

qwen-code-review-bot commented Oct 6, 2026 •

Copy link
Copy Markdown
Collaborator

Sandboxed verification: ❌ not passed — findings reported (agent verdict) - workflow run

Ran the PR in an isolated, token-free container: A/B against the base build, mock-free harness assertions, targeted gates. Advisory evidence for human reviewers — not a review, an approval, or a CI check.

Scripted assertions: 57 passed · 2 failed · 59 total

Flakiness gate: not applicable — no runnable changed test files (0 out-of-scope file(s) noted in the log)

中文 — 判定:❌ 不通过 · 报告了发现(agent 判定)

沙箱验证在隔离、无凭证的容器中执行了该 PR 的代码(与 base 构建 A/B 对照、无 mock harness 断言、定向门禁)。仅作为评审证据,不构成评审、批准或 CI 检查。

脚本断言:57 通过 · 2 失败 · 59 总计

抖动门:不适用 — no runnable changed test files (0 out-of-scope file(s) noted in the log)

Verification report

PR #13348 deep verification — test(managed-agent): pin untested contracts from the #12692 R2 review

Verdict: findings — 57 / 59 scripted assertions passed, 2 failed (both are PR-description inaccuracies, not code defects).
Verified head: bd13b6151591d8a94a784eca722e9d8debe38e57 (git rev-parse HEAD^2; identical to the snapshot's headRefOid, no drift). Base tip b2c95e04dc53e633f25aad1dc1c79717b1d81455, merge commit df63aed9c527165066bb93e4e9484b78277a3423.

No behavioural defect was found in this PR. The central claim is proven: all 12 production mutants are killed at head, 10 of the 11 applicable ones survive when the PR's test surface is reverted to base, and no mutant regressed from killed to survived. The two failures are stale sentences in the PR body describing code shapes that later commits in this same PR replaced. A maintainer can reasonably land this after a one-line body edit.

中文摘要

结论:findings(有发现) — 59 条脚本化断言中 57 条通过、2 条失败;两条失败都是 PR 描述与代码不一致,不是代码缺陷。

  • A/B 结论:这是一个纯测试 PR(10 个改动文件全部位于 src/test/,未触碰任何生产代码)。因此本轮的 A/B 是变异矩阵:对生产代码植入 12 个变异体,分别在 head 与 base 两套测试面上运行。head:12/12 全部被杀;base:11 个可比变异体中仅 1 个被杀(M8,且由两个既有测试杀掉),M12 的目标文件在 base 不存在。没有任何变异体从「被杀」退化为「存活」。PR 自己在 commit message 中提出的 4 条变异预言(513 容量环、删除 lastEventId 析取项、tool_call 原始 update 泄漏、退回共享 flag)全部逐条验证成立,且 M2 确实「只红 33 个测试中的那 1 个」。
  • 未变异的基线:head 上 8 个被改动测试类全绿,113 个测试、0 失败 0 错误 0 跳过。
  • 仓库自有门禁:Flyway 版本唯一性(45 个迁移全部唯一)通过;checkstyle:check 对 src/main 0 违规。但经植入违规的存活性对照证明:该 checkstyle 门禁根本不扫描测试源码——同一个 tab 字符放进 main 触发 3 条违规并 BUILD FAILURE,放进 test 则是 0 违规 BUILD SUCCESS。因此作者引用的「mvn checkstyle:check 全绿」对这个纯测试 diff 是空洞的绿。为回答「那这些测试代码本身干净吗」,改用 pom 覆盖真正扫描测试源:head 274 条 vs base 275 条,本 PR 净减 1 条、两个新文件 0 违规,即代码实际上是干净的。
  • findings(均为低严重度,均为描述问题):①PR 正文称 redaction 测试「新增了 doesNotContainKey("secret") 与 doesNotContainValue("must-not-leak")」,实际代码里这两种断言形式完全不存在,用的是对序列化字符串的 doesNotContain(实际更强,可覆盖任意嵌套深度);②PR 正文称 ManagedAgentServerIntegrationTest「在 finally 包裹中确定性清理已认领的 turn」,实际代码是单个 @AfterEach 清扫,而本 PR 的 commit fd78979 明确写了那个 finally 已被移除。
  • 未覆盖范围:ManagedAgentMySqlIT 的真实 MariaDB 双跑重运行见证(容器内无 MariaDB、无 docker、无 apt/sudo 权限),因此「两轮 19/19 全绿」无法执行验证;逐 commit 归因(浅克隆仅 1 个 commit 可达,元数据有 9 个);全量套件中唯一的 1 个 error 已用 A/A 对照证明为环境所致(容器缺 /etc/machine-id),与本 PR 无关。

Central claim

The PR adds test witnesses for twelve R2 review follow-ups and changes no production code — verified: git diff --name-only HEAD^1..HEAD | grep -v '/src/test/' returns nothing, and git diff --stat HEAD^1..HEAD -- 'packages/sdk-java/*/src/main/**' is empty.

For a test-only PR the load-bearing question is not "does it pass" but "does the suite now hold down what it claims to". So the A/B is a mutation matrix over the production code each witness names, run against two test surfaces: head (the PR's) and base (the same 8 files reverted to HEAD^1, the 2 new files deleted). Production code is byte-identical on both arms by construction, so the test surface is the only variable.

A/B mutation matrix

Witness: 02-mutation-matrix-head-12-of-12-killed.png (head arm) and 04-base-arm-survivors-and-aa-control.png (base arm).

# Mutation to production code Head Base Head tests red / class size
M1 SessionEventHub.CAPACITY 512 → 513 KILLED SURVIVED 1 / 8 (base class had 7)
M2 delete the admission.lastEventId() < attachment.lastEventId() disjunct KILLED SURVIVED 1 / 33 (base 29)
M3 tool_call path returns the raw update map instead of safeToolData(...) KILLED SURVIVED 1 / 7 (base 4)
M4 SAFE_ERROR_CODE alphabet check made vacuous KILLED SURVIVED 2 / 7
M5 SAFE_ERROR_CODE bound {1,128} → {1,129} KILLED SURVIVED 1 / 7
M6 recovered-runtime-not-ready guard disabled KILLED SURVIVED 1 / 33
M7 bindRecoveredHarness generation-mismatch guard disabled KILLED SURVIVED 1 / 33
M8 409-only create fallback widened to any DaemonHttpException KILLED KILLED 3 / 28 at head, 2 / 25 at base
M9 catch (SessionCreationOutcomeUnknownException) fallback removed KILLED SURVIVED 1 error / 28
M10 Attachment drops lastEventId + eventEpoch on the create path KILLED SURVIVED 2 / 28
M11 per-page 8 MiB byte budget never cuts the page KILLED SURVIVED 1 / 5 (base 4)
M12 BackfillWitnesses reverted to one shared firstPass flag KILLED target absent at base 1 / 1 (class is new)

Head 12/12 killed. Base 1/11 killed. Zero killed→survived regressions. The class-size deltas (7→8, 29→33, 4→7, 25→28, 4→5) independently confirm the witnesses are additions, and that each mutant ran against a suite that actually collected the mutated code.

The PR's own four mutation probes — all verified

The commit messages make four falsifiable mutation claims. Each was measured, not read:

Claim (commit) Measured
"a 513 ring now reds the witness" (55d45fc) M1: exactly evictsBeyondCapacityAndSignalsOverflowBelowTheWatermark red, 1 of 8. Assertion is the intended one — Expecting value to be true but was false at SessionEventHubTest.java:84, the await(87) "one below the watermark" arm. Verified.
"deleting the disjunct fails exactly this test" (fd78979) M2: exactly 1 of 33 red, retriesTheTurnWhenTheRecoveredWatermarkRegresses, on recordRecoveryAdmission — Never wanted here … But invoked here -> HarnessCoordinator.runClaimed(HarnessCoordinator.java:325) with arguments: […, epoch-new, epoch-new, 7]. The regressed watermark 7 is visible in the arguments, so the red is the behavioural mismatch (the regressed cursor being persisted), not a crash. Verified, including the word "exactly". See 03-m2-disjunct-kills-exactly-one-of-33.png.
"the raw update leak mutant now dies" (55d45fc) M3: exactly 1 of 7 red, projectsToolCallsWithoutLeakingOtherUpdateFields, with the leak printed: Expecting actual: "{rawInput={path=/private/workspace}, secret=must-not-leak, …}" not to contain: "secret". Verified.
"reverting to the shared flag reds it" (55d45fc) M12: gatesFollowTheVersionsPendingAtRunStart red with expected: BackfillWitnesses[consumerProgress=true, eventIdentity=true, pendingOperations=true, hookAdmissions=true, reseedCreationScope=false] but was: BackfillWitnesses[consumerProgress=false, …, reseedCreationScope=true]. Verified.

Kill quality, honestly classified

Not every red is equally strong, and the difference matters:

  • Intended-assertion kills (10): M1, M2, M3, M4, M5, M6, M7, M10, M11, M12 all fail on an AssertJ/Mockito assertion naming the expected-versus-actual value of the contract under test. M11 is a good example: expected:<9> but was:<10> — the page cut at 9 transactions is exactly the 8 MiB budget.
  • Escaping-exception kill (1): M9's red is Errors: 1, the mocked SessionCreationOutcomeUnknownException escaping createOrLoad because the fallback catch was removed. This is not a failed assertion, but it does demonstrate the behaviour under test (fall back to load) did not happen. Counted as a kill with the mechanism stated.
  • Incidental-crash kill (1): M8's three reds are all Expecting actual: java.lang.NullPointerException — with the fallback widened, the unstubbed client.loadSession(...) returns null and attachments.put(key, null) throws inside ConcurrentHashMap. The mutant is detected, but by a crash rather than by the intended .isSameAs(failure) mismatch. Worth knowing: M8 was already killed at base by two pre-existing tests (failedAttachmentReleasesTheAttachmentLock, failedFirstAttachmentKeepsQueuedCallersInASingleFlight), so the new rethrowsANonConflictDaemonErrorWithoutLoading is a named witness for the 409-only guard, not its unique defence. That is redundant defence — correct as it stands, not a gap.

Positive control

The unmutated head run is green: 113 tests, 0 failures, 0 errors, 0 skipped across all 8 touched classes (01-baseline-green-113-tests.png). Combined with 12/12 kills, this rules out "the harness never ran the suite". Each mutant ran the whole class (not a single method), so a kill also proves the runner collected the mutated file, and the surviving base arm proves the harness can report green.

Corrections to the PR description

These are corrections to the description, not requests to change the code. In both cases the shipped code is the better of the two.

  1. Redaction assertions (Reviewer Test Plan, "Projector codes & redaction"). The body says the existing redaction test "now also asserts doesNotContainKey("secret") and doesNotContainValue("must-not-leak")". Neither form appears anywhere in HarnessEventProjectorTest.java. What the test actually asserts (lines 33–34) is assertThat(event.data().toString()).doesNotContain("secret").doesNotContain("must-not-leak") — a substring check on the serialized map. That is stronger than the described form, because it holds at any nesting depth, which is precisely the reason commit bd2e6e7b gives for the change. The body was not updated when the assertion was strengthened.

  2. Turn cleanup mechanism (Reviewer Test Plan, "Integration flake"). The body says ManagedAgentServerIntegrationTest "now deterministically cleans up claimed turns in a finally wrap". There is no per-call-site finally cleanup in the file. Cleanup is a single @AfterEach settleLeftoverTurnsAndRestoreHarness() that runs one SQL UPDATE settling every non-terminal Turn. Commit fd78979d in this same PR states it replaced the per-call-site helper with that sweep and that "the concurrent-submit finally whose re-await could mask the real failure goes away with it". The body describes a state this PR itself removed.

  3. A cited gate is vacuous for this diff. Commit f093e176 records "mvn checkstyle:check green" as part of its repair evidence. That gate is real but blind here: includeTestSourceDirectory is unset in managed-agent-server/pom.xml (and in qwencode/pom.xml), so the plugin's default of false applies and only src/main/java is scanned. Measured with a planted-violation control (05-checkstyle-gate-blind-to-test-sources.png): the same tab character produces 3 violations + BUILD FAILURE in a main source file and 0 violations + BUILD SUCCESS in a test source file. For a PR whose entire diff is test code, that citation carries no information.

    I then answered the question the gate cannot, by overriding <includeTestSourceDirectory>true</includeTestSourceDirectory> in the pom — itself validated with a planted-violation control (276 violations reported, so the override genuinely scans test sources). Result (06-checkstyle-ab-pr-adds-no-violations.png):

    arm test-source violations (whole module) in the PR's 10 files
    head 274 21
    base (HEAD^1) 275 22

    The PR introduces no new violations and removes one (HarnessCoordinatorTest 2 → 1). Both new files, BackfillWitnesses.java and BackfillWitnessesTest.java, are clean at 0. All 21 remaining violations in PR-touched files are inherited, part of 274 across 46 test files whose largest offenders (HostedWorkspaceToolTurnIT 28, O4MySqlGate 22, HostedPublicWorkspaceIT 21) this PR does not touch. So the disabled-test-scan configuration looks like deliberate accommodation of pre-existing debt, and this PR is not a reason to change it. Recording this because the author's evidence was vacuous, not because the code is dirty — it is clean.

Findings

Only the two description inaccuracies above (F1, F2 in assertions-detail.json), both low severity, both documentation-only. They are the reason the verdict is findings rather than merge-ready under the counting contract: a reviewer following the Reviewer Test Plan would look for two assertions that do not exist and for a finally block that was deliberately deleted.

No blocking finding. No behavioural defect. No survivor in the mutation matrix.

Two non-blocking observations, neither a defect:

  • The @AfterEach sweep is a blunt instrument by design. It force-fails every non-terminal Turn in the class's H2 database with error_code = 'test_cleanup'. That is the right trade for cross-test isolation, but it means a future test that intends to leave a Turn non-terminal and assert on it from a later test would be silently broken by the sweep. Measured as harmless today: 28/28 green on 5 consecutive runs (07-fixture-mutant-and-determinism-x5.png).
  • The flake claim is confirmed only in the forward direction. I can confirm the class is now deterministic across 5 consecutive runs and across the full 976-test module run. I cannot confirm the pre-PR "~1-of-N flakes" rate, which would need the base test surface run many times under load; the mechanism (a shared single-shot runtimeRecovery field consumed by whichever test claimed a dispatchable turn first, now a per-tenant ConcurrentHashMap with remove) is consistent with the described flake, and the base arm shows the old shape compiling and passing in isolation, which is what an order-dependent flake looks like.

Not covered

  • ManagedAgentMySqlIT was never executed. It is a failsafe IT requiring a real MariaDB (-Pmysql-integration -Dmysql.url=…). This container has no docker, no mysql/mariadbd binaries, and no sudo/apt (running as uid 1000 node; /var/lib/apt/lists/lock is permission-denied). So the PR's central rerunnability claim — "run twice against the same persistent database; both runs go green (19/19)" — is unverified by execution. What I did verify instead: the BackfillWitnesses gate tuple it depends on, via BackfillWitnessesTest on H2 staged at 11 boundary versions (fresh, 1, 8, 9, 14, 15, 16, 17, 28, 29, head), plus mutant M12 proving that gate is load-bearing; and the Tests run: 19 figure by arithmetic — 13 @Test methods plus a 4-value @ValueSource plus a 2-value @ValueSource = 19, matching the claim exactly (a naive grep -c "@Test" gives 14 because it also matches @TestMethodOrder). The namespacing-per-run rewrite and the legacySeedsBackfilled conditionalization were read, not run.
  • Per-commit attribution. The checkout is shallow (git rev-parse --is-shallow-repository → true) and git rev-list HEAD^1..HEAD^2 returns 1 commit while the snapshot lists 9. Only the aggregate HEAD^1..HEAD diff was verified. The four mutation-probe claims quoted above come from commit messages in the snapshot, which I tested against the aggregate head tree — I could not attribute any behaviour to an individual commit.
  • The hosted-harness-mysql, o4-mysql-gates and fault-gates lanes, and scripts/check-failsafe-reports.js (which requires failsafe reports that only exist after the ITs run). All need MySQL/MariaDB.
  • The Java 11 and Java 17 lanes of sdk-java.yml. I installed only Temurin 21 (matching managed-agent-server's <java.version>21</java.version> and the lane that actually runs this module).
  • runtime-broker and qwencode test suites. Staged with -DskipTests to make the module's test compile resolve; their tests are not affected by this PR (no production change) and were not run.
  • SpotBugs. Skipped on every invocation (-Dspotbugs.skip=true) to stay inside budget. It analyses src/main, which this PR does not touch.
  • No full-repo JS/TS gate was run (npm run lint, npm run typecheck, npm run build). The diff contains no TypeScript; the tree was already built by the lane before this round started.

Methodology

Environment: the CI verify lane container (node:22-bookworm, x86_64, 64 cores, 240 GB RAM), working tree at the merge-ref checkout df63aed9c. The container ships no JDK and no Maven, so I bootstrapped both into $HOME/tools: Temurin JDK 21.0.12.1 from the Adoptium API, and Apache Maven 3.9.11 whose tarball SHA512 I checked against the value pinned in .github/workflows/sdk-java.yml (MAVEN_SHA512=bcfe4fe3…) — it matched. Sibling modules were staged with the workflow's own commands (qwencode then runtime-broker, -DskipTests … install), then managed-agent-server was test-compiled; all three stages exited 0 in ~50 s total, and ~/.m2 was empty beforehand so every dependency resolved from Maven Central.

Because this PR changes no production code, the head and base arms differ only in their test surface, so no dependency-tree confound applies and the usual monorepo symlink hazard does not arise — the Java modules resolve their siblings from ~/.m2 jars built from the same (unchanged) source on both arms. The base arm was produced by git checkout HEAD^1 -- <8 modified test files> plus deleting the 2 added files, with git checkout HEAD -- … restoring afterwards; both arms asserted a clean git status --porcelain -- packages/sdk-java before starting and after restoring. The round ends with git status --porcelain completely empty — the artifact directory is under tmp/, which .gitignore:134 excludes, so no residue of any mutant, planted violation, or temporary pom edit remains in the tree.

Mutants were applied as exact single-occurrence literal replacements (the harness aborts a mutant as ANCHOR-NOT-UNIQUE if the anchor does not match exactly once), each followed by a full mvn test -Dtest=<Class> run of the class containing the witness, so a kill also proves the runner collected the mutated file. Twelve mutants ran on the head arm and eleven on the base arm — M12's target, the new BackfillWitnesses.java, does not exist at HEAD^1, so the harness reported it TARGET-ABSENT-AT-BASE rather than fabricating an outcome. Raw per-mutant Maven output is in mutants/M*-<Class>.log and mutants/base-M*-<Class>.log, with machine-readable results in mutants/results.json, mutants/base-results.json and mutants/attribution.json. Harnesses: mutate.mjs (head arm), mutate-base.mjs (base arm plus the A/A control), probes.sh (checkstyle liveness, fixture mutant, determinism repeats), cs-test-scan.sh and cs-ab.sh (per-file checkstyle attribution, head vs base).

The one full-suite error at head — RuntimeBrokerDefaultOnTest.defaultCombinationBootsWithTheYmlDefaultsBound, 976 tests run with 0 failures and 1 error — was traced to java.nio.file.NoSuchFileException: /etc/machine-id, which the broker's durable-local-process mode requires; /etc/machine-id is confirmed absent in this container. Per the A/A rule I did not stop at "seems environmental": the same class was run on the base test surface and failed identically (exit=1, Errors: 1, same /etc/machine-id cause), and the class is byte-identical between arms (git diff --stat HEAD^1..HEAD -- '*RuntimeBrokerDefaultOnTest.java' is empty). Repo gates that did run: node scripts/check-flyway-migrations.js (45 migrations, all versions unique, exit 0) and mvn checkstyle:check (0 violations on main sources), both proven live by planted-violation controls before being cited.

One probe cell was superseded rather than counted: -Dcheckstyle.includeTestSourceDirectory=true on the command line silently had no effect — a tab planted in a test file still reported 0 violations. The planted-violation control caught this before the vacuous green could be cited, and the measurement was redone via a pom <configuration> override that was itself validated the same way. It is recorded in assertions-detail.json under harnessNote and excluded from the pass/fail tally because it is a Maven property-binding fact about this container, not a property of the PR.

Evidence images were rendered with scripts/verify-capture.mjs from the real command output; every number quoted above comes from a saved log in this artifact directory.

Flakiness gate log


verdict: n/a
summary: no runnable changed test files (0 out-of-scope file(s) noted in the log)

Evidence images

01-baseline-green-113-tests

02-mutation-matrix-head-12-of-12-killed

03-m2-disjunct-kills-exactly-one-of-33

04-base-arm-survivors-and-aa-control

05-checkstyle-gate-blind-to-test-sources

06-checkstyle-ab-pr-adds-no-violations

07-fixture-mutant-and-determinism-x5

Harness scripts and raw logs are in the workflow run artifacts (7-day retention).

— Qwen Code · sandboxed verification

@qqqys qqqys left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed head: bd13b6151591d8a94a784eca722e9d8debe38e57 (base main).

Approve. No historical blocking finding stands at this head, and the Critical-only scan found nothing blocking. This diff is test-only — all ten files are under src/test/java/ and no production source changes — so the one Critical class that applies is a false green: a witness that silently skips, silently narrows, or asserts something that cannot fail. That is what I looked for, and the changes move in the opposite direction.

Historical blocking findings

None to re-verify. All three review threads are resolved, there are no [Critical] inline comments and no review ledger, and reviewDecision is REVIEW_REQUIRED. The two dismissed reviews — yiliang114's LGTM and my own earlier pass at fd78979d — were dismissed by head movement and are not standing positions; this is a fresh pass over the current head, not a restatement of that one.

Critical-only scan: no false green

Nothing in the diff disables or conditions a test out. Across all 1,022 patch lines there is no added @Disabled, @EnabledIf, @DisabledIf, assumeTrue, @Tag or environment-variable gate. The only two occurrences of the word "skip" are in comments describing silent-skip behaviour the PR removes. Assertion density is real: 79 added assert*/verify( lines against ~759 added lines.

The migration witnesses are gated on the database's prior state, not on the code under test — which is what keeps a regression from switching off its own witness. BackfillWitnesses.appliedVersions(dataSource) reads Flyway's MigrationInfo.applied() before the run migrates anything, and forApplied(...) derives one boolean per witness: consumerProgress = !applied("2"), eventIdentity = !applied("15"), pendingOperations = !applied("17"), hookAdmissions = !applied("29"), reseedCreationScope = applied("9"). Each one-shot backfill applies only to rows present when it runs, so its witness is valid only when that specific migration was still pending at the run's start — and because the gate comes from the database rather than from the migration's outcome, a V15 regression cannot turn off the V15 witness. The helper's Javadoc names the exact trap this replaces: gating all of them on one shared flag reads a database left mid-window either as a first pass (so the V2-derived count fails) or as a rerun (so the V17 and V29 witnesses silently skip). The mixed polarity is deliberate and the fields are named for the witness rather than the migration, so the direction stays legible.

Two cross-test contamination paths are closed, and both were capable of making a test pass for the wrong reason. In ManagedAgentServerIntegrationTest, the @AfterEach now settles every Turn the test left non-terminal (ACCEPTED/RUNNING/CANCELLING → FAILED with error_code = 'test_cleanup', clearing dispatch_owner, dispatch_lease_until and retry_after) before re-arming the harness; the comment records why — a leftover Turn would be claimed once its dispatch lease expired and poison the counter-sensitive tests running later in the same shared H2 context. And FixtureHarness replaces its single global volatile HarnessRuntimeRecovery slot with a per-tenant map consumed by tenantRecoveries.remove(tenantId), so a test arms a recovery only its own tenant can consume and another test's background claim can never steal it. That is precisely the "second test to claim a dispatchable turn silently won" shape the PR set out to fix. Neither change weakens an assertion; the rest of that file's diff is assertion reflow with no semantic change.

The overflow witness cannot pass vacuously, and it pins the constant from both sides. evictsBeyondCapacityAndSignalsOverflowBelowTheWatermark publishes 600 events against CAPACITY = 512 and then makes three distinct observations: below the watermark await(0) must report overflowed == true with empty events (so a hub that stalls forever fails on the bounded 10 ms await, and one that returns nothing without the flag fails on the assertion); at the watermark await(88) must return exactly 89..600 via containsExactlyElementsOf, an ordered exact-sequence check rather than a size or contains check; and one below the watermark await(87) must also report overflowed == true, with the comment stating the purpose — "pins CAPACITY from above too, so a ring grown to 513 can no longer keep this green." An off-by-one in either direction therefore fails, which is the property that makes the witness non-vacuous rather than merely present.

No Critical found.

CI

Fully settled and green at this head: 24 pass, 27 skipped, 0 failed, 0 pending. The passing set includes the whole Java matrix (ubuntu Java 11/17/21, windows Java 21, macos Java 21) and both database-backed lanes — Runtime Broker and Managed Agent MariaDB / Java 21 and Hosted process fault gates / MySQL 8.4 / Java 21 — which are what execute the managed-agent-server witnesses, plus Flyway migration version uniqueness. Nothing to attribute to this PR.

Not scanned — disclosed, not asserted clean

Two honest limits on this approval. First, the MySQL IT's witnesses are conditional on the database's starting state by design — that conditionality is what makes the IT rerunnable at all — so against an already-migrated persistent database they skip. I did not prove by CI log-marker multiplicity that each individual witness executed in a lane rather than being correctly skipped as inapplicable. Second, I did not re-run the mutation witnesses the PR claims (each written against pre-change code and confirmed to fail or expose the gap first); I assessed the witnesses' assertion shapes for non-vacuity instead, which is what the capacity bracketing and the exact-sequence checks above evidence. I also did not read every one of the twelve witnesses line by line — the connector tuple-propagation, projector redaction and store-contract fixture cases were reviewed at the level of their added assertions rather than in full.

Scope note

Approval is bound to commit bd13b615. Since no production code changes, this approval concerns the test surface only: that the new witnesses pin what they claim, and that the two shared-state fixes remove contamination rather than masking it.

@yiliang114 yiliang114 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No blocking findings at bd13b61 — approving.

This head has moved past two stale-head approvals (mine at c1a61b2, qqqys's at fd78979), so I re-reviewed the full base...head diff plus the three content commits after fd78979. The post-approval delta only strengthens the witnesses: 3a3b203 adds never scheduleTurnRetry to both recovery failure modes and exactly-once continueManagedRuntime / never-submit / never-failTurn guards on the recovery paths (closing the harness-side gap left by R1-11), and 55d45fc replaces the shared firstPass flag with per-migration BackfillWitnesses gates, pinned by an H2/Flyway boundary test at every boundary version. f093e17 is an empty re-verify commit.

Two things I checked specifically at this head:

  • The witness gates are derived from the versions applied before this run migrates anything, so a broken backfill can't switch off its own witness; the V9 re-seed conditionalizes arrange only, and the idempotency_conflict probe stays unconditional. The SessionEventHub overflow witness pins CAPACITY from both sides (await(87) still reports overflow), so growing the ring to 513 turns it red instead of silently passing.
  • The main-merge reconciliation in the four overlapping test files is purely additive, and the contracts these tests pin still exist in the merged production code (hub CAPACITY = 512 + overflow signaling; the connector's SessionCreationOutcomeUnknownException fallback at QwenHostedHarnessConnector.java:347).

CI is green on the test-bearing commit 55d45fc across all Java lanes, MariaDB, and the MySQL 8.4 fault gates; bd13b61 is a pure main-merge, so the full lanes did not re-run on the merge commit itself.

Non-blocking residual (R4-1): the rerun cleanup lists are now tenant-scoped and finally-wrapped in child-before-parent order, so a future child table fails loudly (FK 1451) instead of silently passing — but they still need a human touch when migrations add tables.

@wenshao
wenshao added this pull request to the merge queue Oct 6, 2026
Merged via the queue into main with commit fd4af70 Oct 6, 2026
89 checks passed
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下:

AutoFix round — no action required

🤖 Reviewed the latest feedback — no changes needed.

Round basis: head bd13b6151591d8a94a784eca722e9d8debe38e57, base main, working tree clean, no merge conflicts.

What was triaged this round

  • Reviews: none new requiring action. The most recent maintainer review (@qqqys, submitted 2026-10-06T15:36:24Z) APPROVED the PR at the current head, and the maintainer's verification comment posted at 14:52:58Z reported Verdict: pass — no new findings.
  • Inline comments: none new since the last evaluation.
  • Issue-level comments: the only new comment is @qwen-code-review-bot's "Sandboxed verification is running" status notification (verification-run marker), which is not review feedback and carries no actionable finding.
  • Failed checks: none. All checks on the current head are green (the latest check suite completed successfully; only expected SKIPPED statuses otherwise).
  • Deferred non-Critical feedback: Critical-only mode is active (5 change-producing rounds complete). The deferred items in that section are an audit record per the workflow rules and are intentionally not acted on in this mode; they remain open for human follow-up.

Conclusion

No Critical finding, no maintainer request, and no failing check is outstanding. The PR stands approved at the current head, so this round makes no code changes and posts no thread replies.

中文说明

AutoFix 本轮——无需处理

🤖 已审阅最新反馈——无需改动。

本轮依据: head bd13b6151591d8a94a784eca722e9d8debe38e57,base main,工作区干净,无合并冲突。

本轮分诊内容

  • 评审(Reviews): 无需要处理的新评审。最新的维护者评审(@qqqys,提交于 2026-10-06T15:36:24Z)已在当前 head 批准(APPROVED) 本 PR,且维护者于 14:52:58Z 发布的验证评论报告 Verdict: pass——无新发现。
  • 行内评论(Inline comments): 自上次评估以来无新增。
  • Issue 级评论: 唯一的新评论是 @qwen-code-review-bot 的"沙箱验证正在运行"状态通知(验证运行标记),它不是评审反馈,不携带任何可处理的发现。
  • 失败的检查: 无。当前 head 上的所有检查均为绿色(最新的检查套件已成功完成;其余仅为预期的 SKIPPED 状态)。
  • 延后的非 Critical 反馈: 仅处理 Critical 的模式已激活(已完成 5 个产生改动的轮次)。按照工作流规则,该区域中的延后条目属于审计记录,本模式下刻意不予处理;它们保持开放,留待人工跟进。

结论

没有未解决的 Critical 发现、维护者请求或失败的检查。PR 已在当前 head 获得批准,因此本轮不做任何代码改动,也不在讨论线程中发布回复。

Deferred non-Critical feedback

Critical-only mode is active: 5 change-producing rounds are complete. The workflow excluded the non-Critical feedback below from this round's actionable sections; the items remain open for human follow-up. Maintainer feedback is deferred only after its author has used 2 regular feedback batches in this window's Critical-only tail; authors at that budget, if any, are named below. (@qwen-code /retry starts a fresh counting window.)

中文说明

已进入仅处理 Critical 的模式:已完成 5 个产生改动的轮次。本轮可执行区域已排除下方非 Critical 反馈;这些条目保持开放,留待人工跟进。维护者反馈仅在其本人于本窗口 Critical-only 阶段已使用 2 批常规反馈预算后才会延后;达到预算的作者(如有)在下方点名。(评论 @qwen-code /retry 可开启新的计数窗口。)

Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。


🧠 Handled by Qwen Code · model/模型 kimi-k3 · CLI 0.25.0

@qwen-code-review-bot

qwen-code-review-bot commented Oct 6, 2026 •

Copy link
Copy Markdown
Collaborator

✅ Qwen Triage finished — view run. See the stage comments in this thread for the result.

✅ Qwen Triage 已完成 —— 查看运行。结果见本线程中的各阶段评论。

wenshao added a commit that referenced this pull request Oct 6, 2026
…-harness

Absorbs fd4af70 (test: pin untested contracts from the #12692 R2
review, #13348): contract witnesses for the connector attachment
propagation, the recovered-watermark drive guards, the store
integration and the hub suites.

Resolutions:
- QwenHostedHarnessConnectorTest: this branch's load-timeout
  construction witness and main's three attachment-propagation tests
  coexist (distinct subjects, shared-tail splice).
- HarnessCoordinatorTest: main's two new never-admission verifications
  name the old pre-R10 recordRecoveryAdmission shape; widened their
  matchers to the split-expectation signature (turn/session epochs are
  separate operands since R10-3) without touching their intent.

Verified: HarnessCoordinatorTest 59, QwenHostedHarnessConnectorTest
38, ManagedAgentServerIntegrationTest 29; the test compile covers
every auto-merged suite (Hub, Projector, Store, Backfill, MySQL).
@qwen-code-review-bot

Copy link
Copy Markdown
Collaborator

Thanks — this one is easy to gate and worth gating carefully, because "tests only" is exactly the shape where a witness can pass whether or not the contract holds.

Template looks good ✓

Problem: real and documented, not theoretical. These are the twelve test-surface follow-ups from the R2 post-merge review of #12692 (merged 2026-09-25), with the design-level deferrals tracked separately in #13302 (still open). I did not take the gap list on faith — I confirmed each named branch exists in production at this head: managed_runtime_recovery_incomplete and hosted_harness_recovery_generation_mismatch in the coordinator, the ^[A-Za-z0-9._:-]{1,128}$ alphabet with its hosted_harness_error fallback in the projector, CAPACITY = 512 in the event hub, the 409-versus-unknown-outcome split in the hosted connector, and the 8 MiB per-page budget in the session store's paging query. So every witness points at code that is actually there.

Direction: aligned. Our own review rules treat a missing test for changed behavior as a Suggestion rather than a blocker, which means those suggestions legitimately land after the merge — this is that follow-up. No production surface is touched, so there is no direction risk to weigh.

Size: not applicable. All ten files sit under packages/sdk-java/managed-agent-server/src/test/, which is not a core path, and the production logic line count is 0 — the full 759/52 is test code. The author also has admin on the repo, so the two-tier core gate would not apply regardless. No large-PR advisory either, since that counts production lines.

Approach: the scope is right — one witness per named branch, added to the existing test class for that component rather than into a new parallel harness. Two things I would question, neither blocking:

  • There are three pure re-wrap hunks in the server integration test and a deleted blank line in the coordinator test that have nothing to do with the witnesses. Trivial, but it is churn a reviewer has to read and dismiss.
  • The description says the contract-fixture test pins (firstSequence..lastSequence).size + 1 ≥ eventCount. The code actually asserts exact genesis values (eventCount 0, firstSequence 0, lastSequence 0, recordCount 2). That is stronger for this fixture but it is not the general invariant, so the description oversells it slightly.

The one place I expected over-engineering was BackfillWitnesses — a five-field gate record plus its own H2 test that stages databases at eleven boundary versions. Having read it, it earns its place: gating every witness on one shared flag misreads a database left mid-window by an interrupted run, and the companion test pins the truth table so a migration renumbering fails loudly instead of silently skipping witnesses. That is the right trade, and it is the part of the PR I would defend if someone tried to simplify it away.

Risk: no elevated risk signals — nothing here matches the high-risk paths we track. One practical note: the branch is 31 commits behind main. I checked that none of the production classes these tests pin changed between the merge base and main, so the lag should not invalidate any witness, but the merge still wants a green run on the merged result.

Moving on to code review. 🔍

中文说明

感谢贡献!这个 PR 属于「只加测试」的类型,恰恰是最需要认真把关的形态——见证用例可能在契约成立与否两种情况下都绿。

模板完整 ✓

问题: 真实且有据可查,不是理论性加固。这是 #12692(已于 2026-09-25 合并)合并后 R2 评审提出的 12 条测试面跟进项,设计级延缓项由 #13302(仍 open)单独跟踪。我没有直接采信这份缺口清单——逐条核实了对应分支在本地 head 的生产代码中确实存在:coordinator 里的 managed_runtime_recovery_incomplete 与 hosted_harness_recovery_generation_mismatch、projector 里的 ^[A-Za-z0-9._:-]{1,128}$ 字母表及 hosted_harness_error 兜底、事件集线器的 CAPACITY = 512、hosted connector 的 409 与 unknown-outcome 分流、以及 session store 分页查询的 8 MiB 单页预算。每条见证都指向真实存在的代码。

方向: 对齐。我们自己的评审规则把「行为变更缺测试」定为 Suggestion 而非阻塞项,因此这类补充本来就应该在合并之后落地——本 PR 就是这个跟进。不涉及任何生产接口,没有方向性风险需要权衡。

规模: 不适用。10 个文件全部位于 packages/sdk-java/managed-agent-server/src/test/,不属于核心路径;生产逻辑行数为 0,759/52 全是测试代码。作者对仓库有 admin 权限,两层核心门槛本就不适用。也不触发大 PR 提示,因为该提示按生产行数计算。

方案: 范围合理——每条命名分支一条见证,加进该组件既有的测试类,而不是另起一套平行夹具。有两点想提出,均不阻塞:

  • 服务端集成测试里有 3 处纯换行重排、coordinator 测试里删了 1 个空行,与见证无关。很琐碎,但评审需要读一遍再排除。
  • 描述里说 contract-fixture 测试钉的是 (firstSequence..lastSequence).size + 1 ≥ eventCount。代码实际断言的是 genesis 的精确取值(eventCount 0、firstSequence 0、lastSequence 0、recordCount 2)。对这份 fixture 来说更强,但不是一般不变式,描述略有夸大。

我原以为会过度设计的地方是 BackfillWitnesses——一个五字段门控 record,外加一个把 H2 库预置到 11 个边界版本的专属测试。读完之后认为它值得存在:把所有见证挂在单一共享标志上,会把被中断的运行留下的「窗口中间态」数据库误判;而配套测试钉住了真值表,迁移版本重排时会大声失败,而不是静默跳过见证。这个取舍是对的,如果有人想把它简化掉,我会为它辩护。

风险: 无升级风险信号——未命中我们跟踪的任何高风险路径。一个实际提示:分支落后 main 31 个提交。我已确认这些测试所钉的生产类在 merge base 与 main 之间没有变化,因此落后不会让任何见证失效,但合并结果仍应跑一次绿。

进入代码审查 🔍

— Qwen Code · qwen3.8-max-2026-09-02

Reviewed at bd13b6151591d8a94a784eca722e9d8debe38e57 · re-run with @qwen-code /triage

@qwen-code-review-bot

Copy link
Copy Markdown
Collaborator

Code review

Because the branch is 31 commits behind main, I read the pinned production code at this head rather than at main, after first confirming that none of the classes under test changed between the merge base and main. No Critical findings and no AGENTS.md violations. What follows is what I actually checked, including the two deletions — deletions are the risky direction in a tests-only PR, so I verified them instead of assuming the accompanying comment was right.

Event hub overflow. The witness pins CAPACITY = 512 from both sides, which is more than I expected. After 600 publishes the buffer holds 89..600 and droppedThrough is 88; delivery reports overflowed = afterSequence < droppedThrough. So await(0) overflows with no events, await(88) returns the 512 contiguous survivors, and await(87) overflows again. Grow the ring to 513 and droppedThrough becomes 87, which fails both of the latter two assertions. It is also flake-free: hasAfter short-circuits for all three sequence arguments, so the 10 ms timeouts are never actually waited on.

Projector. The 128/129 pair is exactly right against {1,128}. The new tool-call test's source update genuinely carries secret and rawInput, and production copies only five scalar keys into the projection, so the doesNotContain assertions bite rather than decorating. The pre-existing text test already had "secret", "must-not-leak" in its input, so extending it is not vacuous either — and asserting on the serialized form is the correct way to cover nesting depth, since containsEntry cannot prove absence.

Connector recovery. Production is catch (DaemonHttpException) { if (getStatusCode() != 409) throw; return load(session, false); } catch (SessionCreationOutcomeUnknownException) { return load(session, false); }, and the three new tests map 1:1 onto it, including the negative case that a 500 must never reach loadSession. Mocking those two exceptions looks like a smell and is not: both are final with package-private constructors in com.alibaba.qwen.code.daemon and there is no public factory, so a real instance is unreachable from the test's package without a production change — which this PR correctly declines to make. The getSuppressed()/getStackTrace() stubs are a deliberate guard against surefire's reporter dereferencing a mocked Throwable and losing the failing test's name. The same reasoning covers ReflectionTestUtils on passiveManagedRuntimeRecovery: LoadHarnessSession exposes constructors only, no accessor.

Per-page byte budget. I checked the arithmetic rather than trusting the expected counts. Paging breaks on selectedCount > 0 && selectedBytes + candidate.byteLength() > 8 MiB. A ~1 KB genesis plus eight dense transactions of ~1,000,050 bytes is 8,001,400 — under the 8,388,608 ceiling — while the ninth would reach 9,001,450. Page 1 is therefore exactly revisions 1..9 with hasMore = candidates(11) > selected(9) = true, and page 2 is 10..12 with hasMore = 3 > 3 = false. The ~387 KB headroom means the test is not sensitive to incidental byte drift, but it does go red if the budget or the record-count rule moves. Well calibrated.

MySqlIT rerunnability. Per-run UUID namespacing is the correct fix for fixture collisions, and deriving the gates from the versions applied before this run migrates anything — rather than from the migrated rows — avoids the self-disabling failure mode the comment describes, where a regression in one migration switches off its own witness. Two deletions verified:

  • The three removed when(recovery.getPhase()) stubs in the coordinator test are dead. Nothing under packages/sdk-java/**/src/main calls getPhase(); only HarnessRuntimeRecovery defines it. No coverage was lost.
  • The removed TIMESTAMPDIFF(MICROSECOND, …) isPositive assertion is genuinely subsumed, and the swap is a strengthening. isPositive passes under whole-second truncation as long as the lease is merely in the future, whereas assertLeaseDeadline compares UNIX_TIMESTAMP(writer_lease_until) * 1000 for exact equality against the app-computed grant.leaseUntil() — which cannot hold if the sub-second fraction is dropped.

Integration flake. Keying the fixture's recovery arm by tenant (tenantRecoveries.remove(tenantId)) removes a real cross-test steal, where the second test to claim a dispatchable turn silently won the arm. The unscoped bulk UPDATE in @AfterEach is safe as written: jdbc:h2:mem:managed-agent is used by this class alone — I checked every jdbc:h2:mem: URL across the Java test sources — so it cannot reach another class's turns.

Two nits, both non-blocking: the formatting churn named in Stage 1, and the commit BiConsumer in the budget test does a catch-IllegalStateException-rethrow / catch-Exception-wrap dance that a small private method would express more plainly. Ten files, all test-scope and all discussed above, so I have not added a files table or a sequence diagram — there is no new runtime flow to draw.

Test evidence

This is an unattended CI run, so per the gate's rules I did not build or execute anything from this PR. The evidence below is the PR's own CI on the reviewed commit, fetched through the API: 24 non-skipped checks, all success, zero failures, zero pending.

Check Conclusion
SDK Java success
Qwen Code CI success
Runtime Broker and Managed Agent MariaDB / Java 21 success
Hosted process fault gates / MySQL 8.4 / Java 21 success
Real daemon E2E / Java 11 success
ubuntu-latest / Java 21 success
ubuntu-latest / Java 17 success
ubuntu-latest / Java 11 success
macos-latest / Java 21 success
windows-latest / Java 21 success
Flyway migration version uniqueness success
Test (ubuntu-latest, Node 22.x) success
Lint & Static (ubuntu-latest, Node 22.x) success
Integration Tests (no-AK, No Sandbox) success
Desktop Shell (ubuntu-22.04) success
Desktop Shell (windows-2022) success
web-shell E2E Smoke (ubuntu-latest, Node 22.x) success
Bot orchestration (Classify PR, assign, authorize, label, route, review-pr, delay-automatic-review, delete-asset-branch, Remind on force-push) success

What that green actually covers, and what it does not. The MariaDB lane runs mvn -Pmysql-integration … clean verify checkstyle:check against a fresh MariaDB 10.11.18 service container and then runs a report gate that proves every non-Hosted integration test class really executed rather than being silently skipped. So the MySqlIT first pass — every witness open, full backfill assertions — is CI-covered and green. The rerun path, a second pass against the same persistent database with the gates closed, is not coverable by CI at all, since each run gets a fresh container. What makes that acceptable rather than blind is that BackfillWitnessesTest pins the gate truth table deterministically in H2 and does run in CI, so the branch the rerun takes is witnessed even though the rerun itself is not.

Not verified: the load-bearing claim itself. A green suite proves these tests pass; it cannot prove they fail when the pinned contract breaks. That claim currently rests on the author's word — specifically the maintainer's own round-2 local report on this exact head, which describes mutation A/B kills (passive-recovery flag, CAPACITY 512→513, tool-call raw-update leak, single-flag gating, escaping exception), the gate matrix on MySQL 8.4.7 and MariaDB 10.11.18, backfill-deletion witnesses, 19/19 on a double run, and 738 unit + 52 IT green on head with 1037 + 52 on a trial merge onto main. That is thorough work and it is consistent with everything I could check statically, but it is the author's claim, not evidence I reproduced — this review is static and never executes PR code.

Sandboxed verification would settle exactly that gap: @qwen-code /verify — that each new witness actually goes red when the production contract it pins is perturbed, which no amount of diff reading or green CI can show. An independent run is already in flight on this head as a sibling job of this triage in run 37477236069; its A/B report is the independent version of the mutation evidence above. The author has write access, so no sponsored-run caveat applies. That run's tmux-testing job was correctly skipped — there is no TUI surface here.

Real-scenario testing: N/A — unattended CI run, and a test-only Java change with nothing user-visible to drive.

中文说明

代码审查

由于分支落后 main 31 个提交,我先确认了被测生产类在 merge base 与 main 之间没有变化,然后按本地 head(而非 main)阅读被钉住的生产代码。无 Critical 问题,也无违反 AGENTS.md 之处。 下面是我实际核对的内容,包含两处删除——在「只加测试」的 PR 里,删除才是风险方向,所以我逐条验证,而不是采信旁边的注释。

集线器溢出。 该用例从两个方向钉住 CAPACITY = 512,比我预期的更强。推满 600 条后缓冲区留下 89..600、droppedThrough 为 88,投递逻辑按 overflowed = afterSequence < droppedThrough 判定:await(0) 溢出且无事件,await(88) 返回 512 条连续存活事件,await(87) 再次溢出。把环扩到 513,droppedThrough 变成 87,后两条断言同时失败。而且不会 flake:三个序列参数都会让 hasAfter 短路,10 ms 超时根本不会被真正等待。

投影器。 128/129 这一对与 {1,128} 精确对齐。新增的 tool_call 用例,其源 update 确实带有 secret 与 rawInput,而生产代码只把 5 个标量键拷进投影结果,因此 doesNotContain 是真起作用的,不是装饰。既有的文本用例输入里本来就有 "secret", "must-not-leak",所以扩展它也不是空断言——用序列化形式断言是覆盖任意嵌套深度的正确做法,containsEntry 无法证明「不存在」。

连接器恢复。 生产代码是 catch (DaemonHttpException) { if (getStatusCode() != 409) throw; return load(session, false); } catch (SessionCreationOutcomeUnknownException) { return load(session, false); },三个新用例与之 1:1 对应,包含「500 绝不能走到 loadSession」这个反向用例。这里 mock 两个异常看着像坏味道,其实不是:两者都是 final,构造函数在 com.alibaba.qwen.code.daemon 包内包级私有,且没有公开工厂方法——从测试所在包根本拿不到真实实例,除非改生产代码,而本 PR 正确地拒绝这么做。getSuppressed()/getStackTrace() 两个桩是刻意防御:surefire 的报告器若解引用被 mock 的 Throwable 会中断整类报告,丢掉失败用例的名字。passiveManagedRuntimeRecovery 用 ReflectionTestUtils 同理:LoadHarnessSession 只有构造函数,没有访问器。

单页字节预算。 我没有采信期望值,而是自己算了。分页在 selectedCount > 0 && selectedBytes + candidate.byteLength() > 8 MiB 时中断。约 1 KB 的 genesis 加 8 条约 1,000,050 字节的密集事务合计 8,001,400,低于 8,388,608 的上限;第 9 条会到 9,001,450。因此第 1 页恰好是事务 1..9,hasMore = candidates(11) > selected(9) = true;第 2 页是 10..12,hasMore = 3 > 3 = false。约 387 KB 的余量说明它对无关字节漂移不敏感,但预算或记录数规则一变就会红。校准得很好。

MySqlIT 可重跑。 按运行 UUID 命名空间化是修复 fixture 碰撞的正确做法;门控取自本次运行开始迁移之前已应用的版本(而不是迁移后的行),避免了注释所说的自失效模式——某个迁移回归时会把自己的见证关掉。两处删除已核实:

  • coordinator 测试里删掉的 3 个 when(recovery.getPhase()) 桩是死桩。packages/sdk-java/**/src/main 下没有任何地方调用 getPhase(),只有 HarnessRuntimeRecovery 定义了它。没有丢失覆盖。
  • 删掉的 TIMESTAMPDIFF(MICROSECOND, …) isPositive 确实被吸收了,而且这次替换是加强。isPositive 只要租约在未来就通过,即使小数秒被截断也照样绿;而 assertLeaseDeadline 把 UNIX_TIMESTAMP(writer_lease_until) * 1000 与应用侧算出的 grant.leaseUntil() 做精确相等比较——小数秒一旦丢失就不可能成立。

集成抖动。 把夹具的 recovery arm 按租户分键(tenantRecoveries.remove(tenantId))消除了真实的跨用例抢占:此前第二个抢到 dispatchable turn 的用例会静默赢走这个 arm。@AfterEach 里那条不限定范围的批量 UPDATE 按现状是安全的:jdbc:h2:mem:managed-agent 只有这个类在用——我核对了 Java 测试源里所有 jdbc:h2:mem: URL——因此碰不到其他类的 turn。

两个小问题,均不阻塞:Stage 1 提到的格式化杂音;以及预算测试里的 commit BiConsumer 用了「捕获 IllegalStateException 重抛 / 捕获 Exception 包装」这套写法,改成一个小私有方法会更直白。10 个文件全在测试范围且上文已逐个讲到,因此没有附加文件表或时序图——这里没有新的运行时流程可画。

测试证据

这是无人值守的 CI 运行,按门禁规则我没有构建或执行本 PR 的任何代码。下面的证据来自通过 API 取到的、针对被评审提交的 PR 自身 CI:24 项非 skipped 检查全部 success,零失败,零 pending。

(CI 表格见上方英文区,此处不重复。)

这份绿实际覆盖了什么、没覆盖什么。 MariaDB 通道对全新的 MariaDB 10.11.18 服务容器执行 mvn -Pmysql-integration … clean verify checkstyle:check,随后有一道报告门禁,证明每个非 Hosted 集成测试类确实跑过而不是被静默跳过。因此 MySqlIT 的首跑形态——见证全开、完整回填断言——已被 CI 覆盖且为绿。而重跑形态(对同一持久库跑第二遍、门控关闭)CI 原理上无法覆盖,因为每次运行都是全新容器。让这一点可接受而非盲目的是:BackfillWitnessesTest 在 H2 上确定性地钉住了门控真值表,并且确实在 CI 中运行——重跑会走的那条分支有见证,即便重跑本身没有。

未验证:承载性结论本身。 绿色的套件只证明这些测试通过,无法证明「被钉契约被破坏时它们会失败」。该结论目前依赖作者陈述——具体是维护者本人针对这个 head 的第 2 轮本地验证报告,其中描述了变异 A/B 击杀(passive-recovery 标志、CAPACITY 512→513、tool_call 泄漏原始 update、单一标志门控、异常逃逸)、MySQL 8.4.7 与 MariaDB 10.11.18 上的门控矩阵、回填删除见证、双跑 19/19,以及 head 上 738 单测 + 52 IT 全绿、试合并到 main 后 1037 + 52 全绿。这些工作很扎实,也与我静态核对到的一切一致,但它是作者的陈述,不是我复现出的证据——本次评审是静态的,从不执行 PR 代码。

沙箱验证正好能补上这个缺口:@qwen-code /verify —— 验证每条新见证在其钉住的生产契约被扰动时确实变红,这是读 diff 和看 CI 绿都无法给出的。针对该 head 的独立验证已在运行中,与本次 triage 同属运行 37477236069 的兄弟 job;它的 A/B 报告就是上述变异证据的独立版本。作者有写权限,因此不适用 sponsored-run 的额外提醒。该运行的 tmux-testing job 已被正确跳过——这里没有 TUI 界面。

真实场景测试:N/A —— 无人值守 CI 运行,且为纯测试的 Java 改动,没有任何用户可见行为可驱动。

— Qwen Code · qwen3.8-max-2026-09-02

Reviewed at bd13b6151591d8a94a784eca722e9d8debe38e57 · re-run with @qwen-code /triage

@qwen-code-review-bot

Copy link
Copy Markdown
Collaborator

Confidence: 4/5 — every contract this PR pins checks out against production at the reviewed head and CI is fully green; the only things I would change are cosmetic, and the one gap that matters is inherent to CI rather than to this PR.

My independent baseline before reading the diff was: one focused witness per R2 finding, added to the existing test class for that component; namespace the MySqlIT fixtures per run; derive the migration-bound gates from run-start state rather than a hand-maintained flag; and add deterministic cleanup for the shared-context flake. That is essentially what landed. I did not find a materially simpler path, and the one piece of machinery I was ready to challenge — BackfillWitnesses plus its own truth-table test — is the part that most earns its keep, because the single-flag alternative it replaces demonstrably misreads a database left mid-window.

The failure mode I was hunting for is the one that makes tests-only PRs dangerous: a witness that stays green whether or not the contract holds. I checked the three that are cheap to check by arithmetic rather than by trust — hub capacity from both sides, the 128/129 error-code boundary, and the 8 MiB page split — and all three are calibrated to go red on a one-unit change. The deletions worried me more than the additions, and both hold up: the removed getPhase() stubs are dead code (nothing in production calls it), and the lease assertion that went away was strictly weaker than the exact-equality one that stays. Mocking two final exceptions and reflecting on a private field both look like shortcuts until you notice the constructors are package-private in another module — at which point they are the only way to pin the behavior without changing production code, which is the right call for this PR.

Reservations, all non-blocking and none of them reasons to hold this up:

  • The rerun-against-a-persistent-database path has no CI coverage by construction, so it rests on the maintainer's local double run plus the H2 truth-table test. That is a property of CI, not a defect here.
  • The load-bearing claim — that these witnesses actually fail when the contract breaks — is not something I could reproduce statically. The independent /verify A/B on this head is in flight and will supply it.
  • Formatting churn in two files, and a description that slightly oversells what the contract-fixture test pins.
  • The branch is 31 commits behind main. The pinned production classes are untouched across that range, so I do not expect the rebase to invalidate any witness, but the merged result should land green.

Would I curse whoever wrote this in six months? No — the comments explain why each witness is shaped the way it is, which is precisely the part that usually goes missing and the part that stops someone "simplifying" a deliberate boundary assertion later. Approving, pinned to the commit I reviewed.

中文说明

信心:4/5 —— 本 PR 钉住的每一条契约都在被评审 head 的生产代码上核对通过,CI 全绿;我想改的地方都属外观层面,唯一实质缺口来自 CI 本身的性质,而非这个 PR。

读 diff 之前我的独立方案是:每条 R2 发现补一条聚焦见证,加进该组件既有的测试类;MySqlIT 夹具按运行做命名空间隔离;迁移相关门控取自运行起始状态而不是手工维护的标志;并为共享上下文抖动加上确定性清理。落地的基本就是这个方案。我没有找到明显更简的路径;而我原本准备质疑的那套机制——BackfillWitnesses 及其专属真值表测试——恰恰是最值得存在的部分,因为它替换掉的单一标志方案会被「窗口中间态」数据库明确误判。

我要找的失效模式,正是让「只加测试」PR 危险的那种:契约成立与否都保持绿色的见证。我挑了三条能靠算术而非采信来核对的——集线器容量的双向钉定、128/129 错误码边界、8 MiB 分页切分——三条都在「改动一个单位」时会变红。删除比新增更让我警惕,而两处都站得住:删掉的 getPhase() 桩是死代码(生产侧无人调用),删掉的租约断言严格弱于留下的精确相等断言。mock 两个 final 异常、反射读私有字段,看着像走捷径,但注意到构造函数在另一个模块里是包级私有之后,就会明白这是在不改生产代码前提下钉住行为的唯一办法——对本 PR 来说是正确取舍。

保留意见,均不阻塞,也不构成压住这个 PR 的理由:

  • 「对同一持久库重跑」这条路径按构造没有 CI 覆盖,因此依赖维护者本地的双跑加上 H2 真值表测试。这是 CI 的属性,不是本 PR 的缺陷。
  • 承载性结论——契约被破坏时这些见证确实会失败——我无法靠静态方式复现。针对该 head 的独立 /verify A/B 正在运行,会补上这一点。
  • 两个文件里的格式化杂音,以及描述对 contract-fixture 测试所钉内容略有夸大。
  • 分支落后 main 31 个提交。这段区间内被钉的生产类未被改动,因此我不认为 rebase 会让任何见证失效,但合并结果应当跑绿。

六个月后我会骂写这段代码的人吗?不会——注释解释了每条见证为什么是这个形状,而这恰恰通常缺失的那部分,也是阻止后人把一个刻意的边界断言「简化」掉的那部分。予以批准,并钉定在我实际评审的那个提交上。

— Qwen Code · qwen3.8-max-2026-09-02

Reviewed at bd13b6151591d8a94a784eca722e9d8debe38e57 · re-run with @qwen-code /triage

@qwen-code-review-bot qwen-code-review-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, looks ready to ship. ✅

wenshao added a commit that referenced this pull request Oct 6, 2026
…e-budget test

How: holdsRestorePagesInsideThePerPageByteBudget now builds each dense
transaction from 210 well-formed message.delta lines (text at the
reader's 4096-byte cap, ~1 MB per transaction) plus the commit marker,
through a shared TurnEventLines composer, and asserts that revisions
1..9 fit the 8 MiB page budget while a tenth does not. The reader replay
IT now also replays that delta shape. The class turns off MockMvc
print-on-failure.

Why: #13348 added the test with placeholder lines ({"subtype":"event_v1"}
plus a padded commit_v1 line), and #13355 (merged later, never run
against it) made the commit gate refuse any non-event line inside the
event range, so every commit after genesis answered 409 and main's SDK
Java lanes went red. The failure was masked as timeouts: Spring Boot
printed the failed test's ~1.3 MB request body as one log line, which
stalled the Actions log pipeline for ~45 min, so the Hosted Verify and
O4 steps blew their ceilings and the MariaDB lane hit its job timeout.

Test: ManagedSessionStoreIntegrationTest and ManagedExtensionRecordStoreTest
green; full managed-agent-server surefire (1077) and checkstyle green;
HostedCommittedEventLineReplayIT green through the real TS reader and
red when the delta text exceeds 4096 bytes; dropping the page byte
budget in ManagedSessionStore fails the test (10 rows instead of 9)
with no log line over 400 chars.
Sumire-no-kai pushed a commit to Sumire-no-kai/qwen-code that referenced this pull request Oct 7, 2026
…e-budget test (QwenLM#13551)

How: holdsRestorePagesInsideThePerPageByteBudget now builds each dense
transaction from 210 well-formed message.delta lines (text at the
reader's 4096-byte cap, ~1 MB per transaction) plus the commit marker,
through a shared TurnEventLines composer, and asserts that revisions
1..9 fit the 8 MiB page budget while a tenth does not. The reader replay
IT now also replays that delta shape. The class turns off MockMvc
print-on-failure.

Why: QwenLM#13348 added the test with placeholder lines ({"subtype":"event_v1"}
plus a padded commit_v1 line), and QwenLM#13355 (merged later, never run
against it) made the commit gate refuse any non-event line inside the
event range, so every commit after genesis answered 409 and main's SDK
Java lanes went red. The failure was masked as timeouts: Spring Boot
printed the failed test's ~1.3 MB request body as one log line, which
stalled the Actions log pipeline for ~45 min, so the Hosted Verify and
O4 steps blew their ceilings and the MariaDB lane hit its job timeout.

Test: ManagedSessionStoreIntegrationTest and ManagedExtensionRecordStoreTest
green; full managed-agent-server surefire (1077) and checkstyle green;
HostedCommittedEventLineReplayIT green through the real TS reader and
red when the delta text exceeds 4096 bytes; dropping the page byte
budget in ManagedSessionStore fails the test (10 rows instead of 9)
with no log line over 400 chars.
JadeCong pushed a commit to CloudEngineHub/qwen-code that referenced this pull request Oct 7, 2026
…wenLM#13174)

* feat(managed-agent): adopt the next Hosted Harness generation (G3)

A Hosted Session no longer dies with the Harness process generation
that first served it (QwenLM#12952 G3, Steps 1+2). On a generation signal
the control plane renegotiates once through the connector instead of
failing every bound Session until its own restart; pending Turns
re-attach through the takeover load as their retries come due.
Takeover refusals split into a typed terminal decline (deterministic
in the journal) and the existing retriable code; the takeover load is
idempotent against a lost reply and gets its own timeout; negotiation
requires the journal-contract feature token so a rolled-back Harness
is refused once; a marked-but-never-admitted Turn withdraws its
submission mark, backstopped by journal commandId idempotency.

The failover runner gains a Harness-only restart arm on all three
scenarios (harness_boot_id moves with no Java restart) and a
SIGSTOP/SIGCONT frozen former-owner fencing arm, wired into
hosted-harness-mysql together with the previously local-only basic
mode. Design docs included in English and Chinese.

* fix(managed-agent): tolerate the bootstrap 404 of a restarting Hosted Harness

The serve delegating app answers every routed path with a bare
pre-contract 404 while its runtime is still starting. The Harness-restart
arms raced that window: a prompt submitted milliseconds after the new
process bound the port could meet the bare 404, which the client read as
a generation contract violation and ended the Turn as
hosted_harness_protocol_error without any retry. A missing boot header on
404 now maps to a transient transport error so the coordinator retries
through the window, and the failover runner waits on deep health
(?deep=1) before driving turns into a restarted Harness. Terminal turn
failures now also log their underlying exception.

* fix(managed-agent): freeze only the Harness writer in the former-owner fencing arm

SIGSTOPping both original owners left the original Spring's workspace
binding unreclaimable: the reclaim proves death from /proc liveness, and
a stopped JVM still reads as alive there, so the replacement's reconcile
timed out (runtime_broker_reconcile_timeout) and the Turn never
completed. The arm now stops only the original Harness (reclaiming its
workspace binding requires the Spring to die anyway — the continuation
mode's crashProcess), completes the Turn with a full replacement, then
wakes the frozen writer and asserts the journal, transcript, and
session binding are untouched. Design D7 updated in both languages with
the discovered boundary: resource-level takeover of a surviving owner is
structurally out of reach today, which is exactly what this issue's
sequential-generation scope excludes.

* ci: retrigger sdk-java workflow after event delivery stall

* fix(managed-agent): pin the fencing proof on writer identity, not head revision

The first merge-base run of the freeze arm failed its own gate: after
waking the frozen Harness the journal head moved (rev 30 -> 45) while
the writer generation, boot binding, transcript, and terminal count all
held. The moved revisions were the replacement's own legal churn, not
old-writer mutation, so the head-equality assertion conflated the two.
The exit-check claim is identity: no transaction out of the old writer
generation after it wakes. Count that straight off
qwen_managed_session_journal_tx (which carries writer_generation), keep
the binding/transcript/terminal assertions, and align design D7 in both
languages. The error string now also reports the old-writer tx count.

* fix(managed-agent): qualify the journal tx schema in the freeze-arm gate

The identity-based old-writer count queried qwen_managed_session_journal_tx
unqualified; the runner's MySQL connection has no default schema, so the
arm died with ERROR 1046 instead of evaluating the fence. Qualify it as
qwen_managed_agent.qwen_managed_session_journal_tx like every other query
in this runner. No behavior change to the assertions themselves.

* fix(managed-agent): harden takeover correctness from the R1 review

- settle turn_settled checkpoints through the load route's own tail
  instead of a terminal decline, and keep transient store verdicts
  (missing_state/missing_checkpoint) retriable on both authorization
  reads
- exempt only takeover-shaped 409s from the pre-admission retry budget;
  every other failure kind meets it
- scope the 120s load-timeout to recovery loads so plain attaches under
  the CHM bin locks stay on 30s
- adoptGeneration: move map churn out of the connector monitor
  (lock-order inversion), evict only stale-boot entries on equal-boot
  mismatches
- answer a duplicate submit of an already-settled prompt with a 202
  replay anchored at its input.accepted sequence
- withdrawSubmissionAttempted: guard on the same status window as its
  peer CAS methods; complete capability mismatch terminally in both
  remaining coordinator layers
- runner: freeze-arm pre-freeze liveness assertion, /health-proven
  wake non-vacuity, teardown SIGCONT, exact-string dispatch-generation
  bounds
- CI: job ceiling 95 with corrected ceiling math; pin all seven
  failover arms in hosted-process-ci.test.js
- sync both design-doc languages with the shipped behavior

* fix(managed-agent): close the R2 review round on the replaceable-host-harness slice

- withdraw + cancel interference (R2-1, Critical): a CANCELLING Turn
  whose never-admitted mark was withdrawn is fast-cancelled instead of
  being re-dispatched into a second live execution at the adopted
  generation
- the generation-mismatch catch escapes the pre-admission budget only
  on a bound Session, like every sibling arm (R2-3)
- bound the remote-supplied decline reason to the error_message column
  so the terminal write itself never throws (R2-5)
- the last fail(...) in the catch ladder is failTerminally with the
  exception logged, like its siblings (R2-6); the withdrawal itself is
  logged too (R2-7)
- freeze arm: the replacement Spring inherits the original port so the
  woken writer meets a live fencing control plane, not a dead socket
  (R2-2); the wake block asserts the head actually advanced past the
  frozen owner's writer generation, drops the wrong heartbeat claim
  (R1-8 follow-up), separates the two disk-audit meanings, and asserts
  the retained Harness home (R2-8)
- the hosted /capabilities feature list derives from the registry
  instead of a hand-maintained literal (R2-9)
- docs: D7 scoped to the journal half of the Q2 exit check, the binding
  half and the pre-contract-404 classification recorded in Boundaries
  (R2-4, R2-10)

* docs(sdk-java): correct the load-timeout coverage comment in the client test

* fix(managed-agent): reference the frozen Harness through the children registry in teardown

The R1-4 teardown SIGCONT referenced the try-block-scoped `harness`
binding from the finally block, so every freeze-arm run died with
ReferenceError after all fencing assertions had already passed (CI run
37009843147). Reach the child through the children registry by its
start() name instead.

* docs(managed-agent): scope the adoption sentence to this slice's takeover reach

* fix(managed-agent): close the R3 review round at its five shared roots

- retract the turn_settled settle tail to a typed decline: the tail
  answered 200 with no recovery watermark (Java then failed the bind,
  orphaned a completed journal turn), fabricated state:'completed' on
  phase alone, ran mutating work under a passive load, and retained no
  snapshot for the lost-reply retry. D10 already owns
  rebind-and-keep-reading as the Step 3 row (R1-25-re, R3-2 .. R3-5)
- the load route's restore guard applies the same durable-vs-transient
  verdict read, because the bundle collapses both into one blocked bit
  and the durable decline was unreachable from production (R1-26-re)
- the pre-admission exemption keys on lease-shaped 409 codes only:
  configuration-shaped 409s (e.g. hosted_tool_profile_conflict) meet
  the budget, and the same 409 exempts nothing on an unbound Session
  (R1-1-re, R1-30-re, R3-13)
- equal-boot adoption keeps pendingRecovery: the markers were minted by
  the same live client (R1-29-re)
- lifecycle capability mismatch: revert completing-as-unconfirmed —
  that skipped the drain, flipped the session, and recorded a clean row
  with no FAILED vocabulary to tell it apart; the reason-loud retry is
  the honest end of the line until an operator realigns versions, and
  the README sentence says so. Action-response outbox keeps its honest
  FAILED-with-code terminal (R1-45-re, R3-5, R3-15)
- test hardening: concurrency close-once now surfaces worker assertion
  failures via Future.get and pins that no real client build happened
  (R3-12); loadTimeout-vs-requestTimeout discriminated at the call site
  (R3-9); single-walk acceptedInputSequence (R3-18)
- runner: 5-column execution queries pin runtime_session_id unchanged
  under --harness-only (R3-14); frozen-arm teardown looks the child up
  by a shared label constant and fails the run on a drift (R3-17)
- CI: ceiling 105 covers the nine summed step ceilings (92) plus the
  uncapped setup steps (R3-6); the seven-arm pin also asserts each
  script's flags and the install step's existence (R3-16)
- docs: both languages re-synced (D5 retraction, D9a code allow-list,
  D7 teardown, D8 runtime identity, honest validation digests, the four
  missing changes-table rows, README retry clause)

* fix(managed-agent): replay takeover snapshots only to a same-shape request

A passive load only asks broker.status(), so its snapshot keeps
phase='await_runtime'; replaying it to a drive load handed the
coordinator a checkpoint that isContinuationReady() can never accept,
terminally failing an otherwise continuable Turn. Record the request
shape with the snapshot and replay only on a mode match; the clear
conditions stay promptId-only.

Also make the adoption race test deterministic: a package-private
createClient() seam lets the test inject the replacement instead of a
real /capabilities call (proven flaky on CI), worker assertion failures
now surface through Future.get, and the pendingRecovery fixture seeds
its marker through the recovery path.

* fix(managed-agent): close the self-audit round on the replaceable-harness slice

Three rounds of undirected plus adversarial audit over the whole PR diff
(31 files), with three parallel deep-dive passes over the Java, TypeScript
and runner/docs surfaces. Every finding was re-verified against the tree
before acting; five reported defects were rejected on evidence.

Correctness:
- the load route read the blocked-restore verdict AFTER managed.close();
  sealing the journal makes every later store read fail as "writer is not
  active", which the authority erases into missing_state, so the durable
  branch this PR added could never fire and a corrupt checkpoint stayed in
  the retry-forever class. Read the verdict first, and pin the order with
  a witness that goes red when the read moves back (the local authority's
  seal does not disable reads, so only the ordering assertion catches it).
- drop hosted_session_already_attached from the lease-bounded 409 set: the
  daemon removes an attachment only on an explicit detach or delete and this
  control plane never detaches, so a Spring restart against a surviving
  Harness retried a permanent refusal forever instead of ending the Turn.
- adoptGeneration evicts by boot identity in both branches instead of
  clearing, so a marker minted by a concurrent rebuild can no longer be
  erased between two adjacent clears (which left a live attachment with a
  null recovery report), and markers follow their attachment.
- the post-withdrawal fast-cancel reads the row again: a cancel landing
  after the claim is invisible in the claimed snapshot, and acting on it
  submitted a live execution only to cancel it below.
- a durable verdict re-read after settling now declines as
  checkpoint_blocked, matching the identical pre-settle classification.
- an unrecognized blocked reason throws instead of declining, so a reason
  core adds later cannot silently become a terminal Turn failure.
- the operator-settable load-timeout is validated at connector
  construction; a bad value previously threw on every client() call and
  surfaced as an endless transient retry naming only the exception class.

Tests: already_attached and lost-withdrawal-CAS witnesses; the fast-cancel
witness now pins the re-read (cancel after claim); the concurrent-adoption
test surfaces worker assertions through Future.get and injects the
replacement through a package-private createClient() seam instead of
standing up a live /capabilities call; the CI pin gains each arm's mode
flag and a ceiling-sum invariant.

Docs (both languages): D1 now describes the boot-identity eviction and
lists what this slice really added to HostedHarnessClient; D3 no longer
claims the bind-refusal path stops being reached (it is D4's trigger); D6
records the same-shape replay clause; D7's fence rationale no longer blames
heartbeats (lease renewal touches writer_lease_until only); D9a names the
two exempt codes and why already_attached is not one; the validation digest
states which claims are pinned and which are not; the CI arithmetic reads
12 + 8x10 = 92; the stale workflow nit is dropped.

* chore(ide): regenerate NOTICES for the merged dependency set (email channel)

* fix(ide): replace the workspace-polluted NOTICES with the pristine regeneration

The file committed in f7a960c was generated under a polluted module
layout left by an aborted install: its resolution hoisted
is-fullwidth-code-point@5.1.0 and produced 663 total dependencies, so
CI's own regeneration (pristine: 662) mismatched and the up-to-date gate
failed. Replace it with the pristine worktree's output, which the gate's
own regeneration produces to a no-diff state.

* fix(managed-agent): close the R4 review finds on the takeover and refusal paths

- classify missing_checkpoint and a bare missing_state as durable verdicts
  so a permanently unrecoverable session declines instead of being retried
  past the lease window; only a missing_state carrying the erased store
  error's message stays retriable
- map a fenced predecessor's managed_session_writer_conflict to the coded
  retriable 409 in the load route so the wait provably ends with the lease,
  and allowlist that code in LEASE_BOUNDED_409_CODES (dropping the inert
  hosted_prompt_recovery_required, which can only arrive post-mark where
  the exemption gate is already bypassed); null-guard the membership test
  against codeless error bodies
- replay a takeover snapshot only to a request whose parsed store identity
  matches the attached session's, never to any takeover-shaped caller
- fetch the harness client AFTER resolving the attachment at the six entry
  points, so an adoption completed during a create/load round trip cannot
  strand a call on the closed client
- pin the reply watermark of the journal-replayed prompt admission, the
  construction-time loadTimeout guard, the marker-eviction half of
  adoptGeneration, and the withdrawal CAS ordering with witnesses, and
  widen the load-timeout test's durations so the capabilities negotiation
  keeps headroom on contended lanes
- narrow the README's typed-decline sentence to the surviving row and
  generation binding, and mirror the exempt-code list in both design docs

* fix(managed-agent): answer the round-5 waits without terminalizing them

- a takeover now splits three ways: drivable answers recovered, a
  deterministically unrecoverable drive keeps its typed decline, and
  anything whose wait belongs to someone else (a requested approval, or
  the whole non-drivable space on a cancellation-only load) answers
  inapplicable so the route falls through to the plain attach — a
  user-cancelled Turn cancels instead of failing as
  managed_runtime_recovery_blocked, and an approval wait survives its
  generation rather than dying while the answer is still deliverable;
  the coordinator keeps the await_action guard as a retriable path even
  if a Harness still declines it
- an unconfirmed cancellation re-drives with its snapshot restored: the
  cancel admission's rollback is now symmetric, so the retrying takeover
  load replays instead of being refused already-attached
- an unrecognised blocked reason at the final re-read stays retriable on
  the drive side like the pre-settle read, instead of terminalizing on
  unresolved_after_settle; only durable verdicts may end a Turn
- the hosted persona's curated tag set is declared once in the registry
  (hostedPersona descriptor flag) instead of being filtered by a third
  hand-maintained list at the route, pinned by the docs-contract test
- the harness-only arms pin a surviving worker through the runtime
  session row's own liveness metric, not the insert-frozen id column
- witnesses: declined reason on the wire, cancel-report replay after a
  lost answer, inapplicable shapes at the recovery kernel (both loads),
  the drive disjunct of the load-timeout predicate, the one rebuild per
  adoption race, and coordinator corners for cancelling/await_action

* fix(ci): qualify the runtime-session heartbeat query with its schema

The harness-only arms' liveness beat read qwen_runtime_session bare;
mysql runs without a default database, so the Harness-restart in-flight
arm died on ERROR 1046 with 'No database selected'. Every other probe in
the runner already addresses qwen_managed_agent.<table> — this one now
does too.

* fix(managed-agent): close the round-6 shape and wedge findings

- the pre-kernel no-tool refusal and the restore guard now honour the
  same shape rule the kernel does: a cancellation-only load answers
  inapplicable and attaches plain (or the baseline retriable refusal
  where no attach is possible) instead of terminalizing a Turn the user
  asked to cancel; a takeover that answers inapplicable no longer trips
  the bare-load refusal on its empty recovery
- the lease-bounded exemption is keyed on the writer lease's own wire
  code only: hosted_turn_recovery_required covers arbitrary takeover
  failures, and exempting it wedged durable refusals in an unbounded
  pre-admission retry; a refusal carrying that code now meets the budget
  like every other body shape while managed_session_writer_conflict
  keeps its D9a window
- witnesses: the no-tool plain-attach coincidence for cancel vs the
  typed model_start decline for drive, the durable restore verdict on
  the cancellation arm, and the budget-hit for a durable 409 on the
  bound path (the old takeover-409 premise rewritten, its writer-
  conflict twin already covered)

* fix(managed-agent): settle a cancel first on a plain-attached replacement

A real-stack round-4 wedge: cancelling a Turn whose Harness died mid
model wedge (Work realized after the merge) failed as
hosted_harness_generation_mismatch — the plain attach leaves the bind
CAS unwinnable (boot-old != boot-new), the cancel was never issued, and
everything queued behind the Turn then retry-forever: later prompts
409, a close 409, no public-API escape.

runClaimed's recurrence without recovery now cancels before it binds:
a CANCELLING Turn does not submit, and a bind exists for submissions —
the next Turn's takeover adopt moves the generation when something
actually continues. cancelledOnAttach suppresses the tail's later
re-cancel. The R5 witness now also pins: bindHarness is never asked,
withdrawSubmissionAttempted is never touched, and the Turn is neither
recovery-blocked nor generation-mismatched. Design docs D3/D4 gain the
bypass rule in both languages.

* fix(managed-agent): close the inapplicable aftermath the round-8 review found

- an inapplicable takeover must not latch session.blocked — a 200 answer
  that refuses every settlement route is a lie (R5-2's latch regression:
  nothing outside settleCancelledHookTurn clears it for a non-hooks
  session). The blocked latch now splits the same shape rule: only a
  genuinely unsettled takeover parks there, not an inapplicable answer.
- a plain attach of a bound Session after adoption rebinds the Session
  row with its own CAS (owner + live lease + expected = the row's boot),
  since bindHarness provably refuses a turn that already posted its epoch
  — the Turn is neither generation-mismatched nor stranded (R8-1).
- a Turn written turn_settled completes, so it is never stamped as
  managed_runtime_recovery_blocked: the kernel answers inapplicable on
  BOTH load shapes (the plain attach lets the daemon's own projection,
  not a declined verdict, write the terminal record), retaining the
  rebind-and-keep-reading rationale for Step 3 (R8-2).
- the QwenLM#13388 pinning test's mock endpoint now advertises
  managed_session_journal_delta_v1 like every other Harness fixture of
  this branch — a merger's follow-up angry about the gate (D9c), not an
  upstream flake.
- witnesses: turn_settled pinned as inapplicable on both shapes at the
  kernel; plainAttachAfterAdoptionRebindsBeforeItSubmits asserting the
  store CAS adoption; R5-2's corner witnessing 200 without
  recoveryRequired; coordinator 46/46, hosted client + pinning tests,
  TS session+recovery fully green.

* fix(managed-agent): close the inapplicable aftermath the round-9 review found

- the no-tool arm now refuses with the baseline retriable one again
  instead of minting a plain attach whose parked Turn nothing may
  resolve (R5-2'), and a takeover load without broker options shares
  that refusal;
- the journal prompt replay answers 202 only when the request body's
  digest proves identity against the admission its input.accepted
  holds; carrying the same Id with different bytes is a real
  prompt_conflict, never a silent swap of watermark (R9-1);
- a plain attach after adoption moves the Turn's stream epoch through
  recordRecoveryAdmission to the attach's epoch, on both the binding
  ladder and the cancel-on-attach arm — a stream opened with the
  claimed epoch would be rejected on the new generation as epoch
  mismatch (R8-1').
- witnesses: the no-tool cancel arm refusing retriably while drive
  declines with its typed reason, the digest mismatched replay timing
  out as hosted_prompt_conflict, and R8-1 streaming the adopted
  generation's epoch on both arms (plainAttachMoves* and
  cancelOnAttachStreams*) with recordRecoveryAdmission pinned.

* deflake: carry QwenLM#13403's pinning fixture under the journal-delta gate + harden the 13328 mount-holder waitFor

The merge of QwenLM#13403 turned the Java CI lanes red with
DaemonProtocolException: Endpoint does not advertise
managed_session_journal_delta_v1 on every burst caller: this branch's
D9c capability gate (from QwenLM#13388's pinning work) rejects endpoints
without that token, and QwenLM#13403's new /capabilities fixture did not
advertise it. Same fixture-parity fix as QwenLM#13388's — the token is a
fixture property, not production behavior; the deliberate negative
stub (capabilitiesJsonWithoutJournalToken) stays as the gate's
witness.

The ubuntu Test lane red on the same head was the issue-13328
mount-holder vi.waitFor defaulting to its 1 s window against the
admission pipeline on the loaded runner ("expected undefined to be
defined", repeated across both retries). Give it an explicit 10 s
timeout, assertions unchanged — the same deflake pattern as
QwenLM#13411/QwenLM#13323/QwenLM#13430.

* fix(managed-agent): close the R11 review round (inapplicable pays only what it can)

R11 (qwen-code-ci-bot review, 5 threads, 3 new + 2 re-checks) landed on
the shared consequence of R10's fixes: an inapplicable/plain-attach answer
stays honest only where a settlement route can pay.

- R11-1: the prompt route's session-scope guard now answers the
  SESSION-level wedge code (hosted_turn_recovery_required); the
  prompt-scoped code names only the requested prompt's own unsettled
  duplicate, so the duplicate-admission adopt branch can no longer be
  forged by a refusal about someone else's parked Turn — and the budget
  treats the session-level code as pre-admission whenever the Turn
  provably recorded no epoch, recording the wedge's own code on
  exhaustion (provenance-gated on an existing submission mark).
- R11-2 / R10-1 re-check: both takeover arms compute the bare branch's
  settle projection inline (`settleProjectablePromptId`): approval waits
  keep the plain attach (resolve pays), turn_settled is settled by the
  load itself via the extracted `runSettleProjection`, and an unpayable
  park keeps the baseline retriable 409 instead of a healthy-looking 200.
- R10-2 re-check: the kernel's passive inapplicable is narrowed to those
  two payable states; initial / durably blocked / model-start / unknown
  phase / wrong-checkpoint throw into the retriable refusal.
- R11-3: createOrLoad's final attachment put restores the pendingRecovery
  marker for snapshot-carrying passive re-attaches, or the cached branch
  of a later recoverManagedRuntime answers "nothing parked" over a
  snapshot it holds.

Witnesses: 245/245 CLI across the three hosted suites (2 new route
witnesses + updated session-code assertion + 2 recovery-suite flips),
QwenHostedHarnessConnectorTest 34/34 (marker witness),
HarnessCoordinatorTest 52/52 (session-busy witness; R6 budget witnesses
pin the load side as recorded). Docs updated in both languages.

* fix(managed-agent): settle the no-tool cancellation takeover instead of refusing forever (Arm B)

The round-6 real-stack wedge: a Turn with no Runtime work parked mid
model round, its Harness generation dead, cancelled — the no-tool arm of
the takeover branch answered the baseline retriable 409 on every
cancellation-side redispatch, and with the Turn still carrying its
submission mark, the retry budget never fired. Turn 2 stayed CANCELLING
forever and every later Turn met the same wall.

The fix keeps the wire honest and the settlement explicit:

- LoadHarnessSession carries `cancellationTakeover`, set ONLY by
  recoverManagedRuntime's cancellation arm. A plain passive re-attach
  shares the passive wire shape and deliberately never sets it — nothing
  may mint a canned CANCELLED record for a wait whose owner could still
  exist.
- With the signal present, the no-tool arm of the takeover branch
  settles the ownerless park into the daemon's journal itself
  (turn_result/cancelled, landing turn.settled); the writer fence on the
  very load is the safety boundary (it proves the producing generation
  can never write again). On write failure the arm keeps the baseline
  retriable 409. Without the signal the arm keeps its merge-baseline
  answers — retriable 409 on cancel, typed model_start decline on
  drive — so the collision guard holds by construction.

Witnesses: `settles the cancellation of an ownerless parked no-tool Turn
on the takeover load` (200 plain attach + durable settle tag + cancel
reads settled-at-tail as 204 + next prompt admits; the revert flips the
verdicts red) with the collision-guard passive-only rerun still at 409,
plus wire-side `carriesTheCancellationTakeoverFlagOnlyOnTheCancellationLoad`
asserting the flag travels only with the signal.

Verification: TS hosted suites 259/259, qwencode 32/32,
QwenHostedHarnessConnectorTest 34/34, HarnessCoordinatorTest 52/52,
typecheck, eslint, prettier. Design doc updated in both languages.

* fix(managed-agent): converge P1-1 (tool-config vs unpaid Runtime work) and P1-2 (stale approval copies)

Round-7 re-review of 275f934 found two remaining wedge families
inside the cancellation settlements this PR introduced. Both converge on
durable proof, never on the stale checkpoint copy.

P1-1: a takeover cancellation must separate "the Session is configured
for tools" from "the Turn owes unpaid Runtime work". A files-profile
session whose owner died BEFORE its first tool call carried no unsettled
Runtime work (checkpointless or a bootstrap checkpoint naming no Turn) —
and the kernel's different-Turn check threw on the bootstrap's null
turnId, so the load answered the retriable 409 forever. The load route
now hoists that split ahead of the kernel: with the explicit
cancellationTakeover signal (and only with it — the collision guard
stays), any ownerless park without unpaid Runtime work settles into the
journal itself; work in flight follows the recovery-cancel report; the
no-signal shape keeps its baseline refusal unchanged.

P1-2: the durable action record — not the checkpoint's stale copy of the
approval — decides an owner-died approval. When the record says the wait
ended, the recovery kernel no longer maps it to the inapplicable plain
attach: expired/cancelled is transient (route refusal), decided is
advanced through its own durable gate ONLY on a drive load (a
cancellation never crosses it), and every other shape (still requested,
or undefined) keeps the plain attach a resolve route can pay. The
cancel/expired arrive by the same separation (settle with the signal;
decided is settleable with the signal too — a CANCELLING takeover does
not resume approved work no matter which side the user took).

Witnesses: `settles the cancellation of an ownerless parked Turn on the
takeover load (profile=null|FILE_PROFILE)` parameterized exactly as the
re-review demanded; three recovery-kernel witnesses for the cross-read
(resolves-inapplicable only while requested; throws for ended-without-a-
decision; drive declines checkpoint_blocked on an undrivable decided
wait); route-level `settles a cancellation takeover whose durable
approval already ended (state=cancelled|decided)`. Design doc updated in
both languages. Suites: hosted-harness-session 222→(+10 new),
hosted-runtime-recovery 36→(+3 new), issue-13328 33→, all green;
typecheck and eslint clean.

* chore(vscode-ide-companion): regenerate NOTICES for the merged dependency layout

* fix(managed-agent): read owed Runtime work off the work itself and pay coded plain-cancel refusals with the cancellation takeover (R9)

Round-9 real-stack measurement found the cancellation separation still
wedging on two families: every cancelled Turn after the first, on both
profiles, and every cancel row of P1-2 — where no load ever left the
coordinator, because a plain-cancel retry can never settle a parked
Turn and no redispatch was forthcoming.

- The park gate now reads owed work off the work itself: a checkpoint
  naming an earlier Turn whose tool items all settled and were consumed
  owes nothing to a cancelled Turn that never reached a tool call; and
  a no-tool Session cannot owe Runtime work by definition, so its
  cancellation arm settles unconditionally again (the round-8 behavior
  the gate had displaced onto a blocked restore basis).
- The admitted-cancel path turns a plain cancel's coded 409
  hosted_turn_recovery_required into an immediate cancellation
  takeover load over the same attachment (recoverManagedCancellation),
  and the connector sends it even with a healthy cached attachment —
  the shortcut would swallow it and the load would never leave the
  process. A recovered Runtime park it reports is cancelled through
  its checkpoint admission; the already-running stream lands the
  settle either way.

Witnesses: hosted-harness-session settles the second-Turn cancellation
park on both profiles (the round-9 rig witness adopted); the
coordinator drives the takeover load exactly on the coded refusal
(plain park and recovered park) and on no other answer; the connector
always sends the cancellation load over a cached attachment. Suites:
hosted 229, HarnessCoordinatorTest 55, QwenHostedHarnessConnectorTest
35, ManagedAgentServerIntegrationTest 29.

The decided-approval drive arm of P1-2 (rows where the user answers
allow or the approval expires unanswered) remains open: it needs the
plain-attached replacement to drive the parked Turn itself once the
durable wait ends, and lands as its own slice.

* fix(managed-agent): pay the cancellation signal identically on an attached re-answer (R9-2)

A cancellation takeover load the coordinator forces onto a Session
ALREADY attached in this daemon used to skip the entire settle
separation: the attached branch called the passive kernel directly,
which never advances a durable wait passively — so a park whose
approval ended after the attach (the round-10 allow, then cancel
repro) was thrown back as an unknown phase and refused retry-invariant,
while the first-load branch settled the identical shape. Hoist the
separation above the attachment split: the attached branch now reads
the signal too and runs the same no-tool arm, owed-work gate and
durable cross-read, settling through settleCancelledHarnessTurn into
the journal the already-running stream lands.

Witnesses parameterize both ended states: attach plain while the
durable approval says requested, end the wait after the attach with
the stale checkpoint copy untouched, then redrive with the cancel
signal — 200 with the redriven-load settle log, and the plain cancel
route reads settled-at-tail. Suites: hosted session 231, recovery 44.

* fix(managed-agent): close the durable wait before the cancelled terminal lands (R9-3)

settleCancelledHarnessTurn only wrote turn_result/cancelled into the
journal, and the record sink's turn.settled only advances next-turn
checkpoints at a model-start phase — so a cancelled Turn parked at an
approval wait ended in the journal while its checkpoint stayed at
await_action, and the Session's next prompt met
`ManagedHarnessBlockedError: await_action is not a model-start phase`
(the round-11 repro: old Turn completed cleanly, new Turn failed as
hosted_turn_failed before the model was ever called, closing 1 P1).

The cancelled settle now closes the ended wait first through the
wait's own durable gate (resolveDurableWait → model_output_committed,
a model-start family phase) whenever — and exactly when — the durable
approval already ended, mirroring the cross-read the caller's gate
performed. The decision remains the USER's and nothing resumes: the
Turn dies immediately after. Runs of requested waits or of in-flight
Runtime work keep the kernel's existing paths.

Witness (both answers): requested approval attaches plain on the
passive takeover, the record ends after the attach with the stale
copy untouched, and the attached cancellation takeover settles —
200 with the redriven-load settle log, plain cancel reads 204, and
the settle provably commits the model_output_committed boundary
ahead of the terminal record. Suites: hosted session 231, recovery
44; typecheck, prettier, eslint clean.

The unit suite cannot stage "approval-first park + literal owner
death" today (DELETE refuses active Turns, and abort unwinds the
wait cleanly), so the end-to-end relief-Turn acceptance stays with
the real-stack probe; the annex-level witnesses cover the settlement
payment and the wait-close commit.

* chore(vscode-ide-companion): regenerate NOTICES from a clean-room install

The previously committed file was generated in the long-lived
worktree whose pnpm layout had drifted (is-fullwidth-code-point@5.1.0
+ get-east-asian-width@1.5.0 + fdir/picomatch slot differences) even
though pnpm-lock.yaml is byte-identical to main. Regenerated in a
fresh worktree with a frozen-lockfile clean install: 662 deps, and
the output matches the lint lane's renewed file byte for byte, which
the polluted layout could not reproduce.

* fix(managed-agent): pace forced takeover loads per Turn and make the cancelled settle idempotent (R9-4)

Two round-10 verdict items:

1. The coded-409 escalation (R9-P1-2) ran on every ~500ms lease-renewal
   tick, so a Turn cancelled while its wait still owns a live durable
   record paid ~4 requests/s of daemon work forever (21 forced loads and
   20 cancels in the verdict's captured window). cancelAdmittedTurn now
   paces the forced cancellation takeover load per Turn (5s minimum
   interval): the cheap plain-cancel retry keeps carrying the wait, and
   a wait that ends inside the interval still settles on the next paced
   attempt — far below the approval timeout's 45s budget.

2. A settle that already landed was not idempotent: the coordinator's
   next forced load inside the stream's landing window met
   `event id turn:<id> is already committed` (3/3). The cancelled settle
   now re-reads the journal's own turn.settled for this prompt before
   writing, so the redriven load is a re-answer, never a second
   turn_result racing the event-id CAS.

Witnesses: three paced coded-refusals (t0 / t+500ms / t+5s) yield three
plain cancels but two forced loads (HarnessCoordinatorTest 60); the
round-9-2 witness pair now races a second identical load inside the
landing window and asserts one cancelled record and no
takeover_unavailable line (hosted suites 275).

* test(managed-agent): commit authority-valid deltas in the restore byte-budget test

How: holdsRestorePagesInsideThePerPageByteBudget now builds each dense
transaction from 210 well-formed message.delta lines (text at the
reader's 4096-byte cap, ~1 MB per transaction) plus the commit marker,
through a shared TurnEventLines composer, and asserts that revisions
1..9 fit the 8 MiB page budget while a tenth does not. The reader replay
IT now also replays that delta shape. The class turns off MockMvc
print-on-failure.

Why: QwenLM#13348 added the test with placeholder lines ({"subtype":"event_v1"}
plus a padded commit_v1 line), and QwenLM#13355 (merged later, never run
against it) made the commit gate refuse any non-event line inside the
event range, so every commit after genesis answered 409 and main's SDK
Java lanes went red. The failure was masked as timeouts: Spring Boot
printed the failed test's ~1.3 MB request body as one log line, which
stalled the Actions log pipeline for ~45 min, so the Hosted Verify and
O4 steps blew their ceilings and the MariaDB lane hit its job timeout.

Test: ManagedSessionStoreIntegrationTest and ManagedExtensionRecordStoreTest
green; full managed-agent-server surefire (1077) and checkstyle green;
HostedCommittedEventLineReplayIT green through the real TS reader and
red when the delta text exceeds 4096 bytes; dropping the page byte
budget in ManagedSessionStore fails the test (10 rows instead of 9)
with no log line over 400 chars.

* fix(managed-agent): propagate the settle's own wait-check fault instead of degrading it to a successful cancel (R9-5)

The cancellation settle's authorization re-read was wrapped in
`.catch(() => undefined)`, so a transient store fault surfacing
between the caller's gate and the settle's own wait-check degraded
into 'nothing to close' — the cancelled terminal landed over a wait
the fault hid, and the Session's next prompt then found the same
obsolete checkpoint that family wedges on (the round-11 fault
injection at this exact boundary: authorization flips
runnable → blocked/missing_state → runnable once, the settle still
mints turn_result, and the run dies on `await_action is not a
model-start phase`).

A read failure is a retriable store fault, not 'nothing to close': it
now propagates into the caller's try-catch, which keeps the baseline
retriable refusal — the fault's own retry ladder owns the retry, and
the replayed shape then settles identically.

Witness mirrors the probe: the wait-gate reads fine, the settle's own
check faults once — load refuses hosted_turn_recovery_required with no
Cancelled record and an honest 409 on the plain cancel, then the same
shape settles after the fault clears (settle log, the
model_output_committed boundary, plain cancel 204). Suites 276/276
(hosted session 232, recovery 44), typecheck/prettier/eslint clean.

* fix(managed-agent): refuse the cancelled settle on fault-shaped authorization verdicts too (R9-5')

R9-5 propagated THROWN authorization faults into the caller's retriable
refusal, but the authority never throws the same class of failure: the
real path takes a retry-exhausted ManagedSessionStoreTransportError and
converts it in place into `{status: 'blocked', reason: 'missing_state'}`.
From there the cancelled settle still marched on — it skipped the wait
advance and wrote the cancelled terminal anyway, spending the Session's
next prompt on the obsolete `await_action` checkpoint the verdict hid
(the round-11 verdict at `964b87a50a`, reproduced with the production
error type: 200 on the takeover, the terminal lands, and the next turn
dies `await_action is not a model-start phase`).

Fault-shaped authorizations are never "nothing to close":
`missing_state` (the TransportError conversion), `opaque_state` and
`invalid_state` now all answer the same retriable refusal — the settle
refuses rather than minting what it cannot prove. `missing_checkpoint`
stays payable on purpose: it is the Arm B park's honest form (a no-tool
Session with history provably has no checkpoint) and its settle is the
already-verified behaviour.

The witness covers both faces of the store fault
(`it.each(['exception', 'missing_state'])`): same park, same stage,
either a thrown fault or a folded `blocked/missing_state` — the load
refuses with zero settle and an honest plain cancel 409, and the replay
settles the moment the fault clears. Suites 277/277 (hosted session
233, recovery 44), typecheck/prettier/eslint clean; design docs note
the boundary in both languages.

* docs(design): split the R9-5' verdict paragraph into its own bullet

The R9-5' text rode mid-bullet after R9-5's run-on, which Prettier
then flattened to column zero — breaking the list structure the lint
lane rejects outright. Both languages carry the split now, and the
lint-facing check passes again.
@qwen-code-review-bot

Copy link
Copy Markdown
Collaborator

Released in v0.25.1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

autofix/takeover Summon the autofix loop to manage this PR (remove to release; needs triage+)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants