Skip to content

feat(channels): add BTW side questions to Channel conversations - #10713

Merged
qqqys merged 7 commits into
QwenLM:mainfrom
qqqys:feat/channel-btw-channel
Sep 2, 2026
Merged

qqqys merged 7 commits into
QwenLM:mainfrom
qqqys:feat/channel-btw-channel

Conversation

@qqqys

@qqqys qqqys commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

What this PR does

This PR adds /btw <question> handling to Channel conversations through an optional bridge capability. It validates text input and shared-session authorization, resolves the current task, immediately acknowledges the request with a correlation identifier, and delivers the side answer in the background while the main task continues. It limits each session to one active side question while allowing different sessions to run independently, and suppresses stale delivery after clear, close, reroute, session death, or bridge replacement.

Why it's needed

Channel users currently cannot use the existing context-aware side-question flow safely. A /btw message can reach the normal prompt path, polluting the main conversation and potentially interacting with the active turn. The Channel command should preserve the same non-interrupting intent while respecting Channel routing, authorization, and asynchronous delivery lifecycles.

Reviewer Test Plan

How to verify

With a bridge that exposes BTW, start a normal Channel task and send /btw while the task remains active. Confirm that an acknowledgement appears immediately, the main task is not prompted or cancelled, and the correlated answer arrives separately. Confirm that empty, oversized, attachment-bearing, or unauthorized requests are rejected before bridge invocation; a second request for the same session is rejected while one is active; different sessions can ask concurrently; and clearing, closing, rerouting, losing, or replacing the session prevents a stale answer. With a bridge that does not expose BTW, confirm that the command fails closed with an unsupported message instead of falling through to the normal prompt.

Evidence (Before & After)

Before: Channel command routing has no dedicated /btw path, so the message can enter the normal prompt flow. After: /btw is acknowledged and delivered through the optional side-question capability without changing the main turn; unsupported connections fail closed.

Tested on

OS Status
🍏 macOS
🪟 Windows ⚠️
🐧 Linux ⚠️

Environment (optional)

Node.js 22.17.0, local workspace build without a sandbox. All 649 Channel base tests passed on this independent branch, including 16 focused /btw scenarios; workspace build and typecheck also passed. The user-visible combined branch was built, typechecked, and bundled for live Channel validation.

Risk & Scope

  • Main risk or tradeoff: Background responses can outlive the inbound message turn, so delivery is guarded by bridge identity, live-session routing, named-task identity, and cancellation state before sending.
  • Not validated / out of scope: Live delivery through a third-party Channel adapter is reserved for the prepared user validation environment. Windows and Linux were not tested locally.
  • Breaking changes / migration notes: None. The command uses a structural optional capability and safely reports unsupported when the transport PR is not present yet, so this PR can merge independently and in either order.

Linked Issues

Part of #10711.

中文说明

本 PR 做了什么

本 PR 通过可选 bridge 能力为 Channel 会话增加 /btw <question> 处理。它会校验纯文本输入和共享会话授权,解析当前任务,立即用关联标识确认请求,并在主任务继续运行时于后台投递旁路答案。每个会话最多同时运行一个旁路问题,不同会话仍可独立并发;在 clear、close、reroute、会话死亡或 bridge 替换后会抑制过期结果投递。

为什么需要

Channel 用户目前无法安全使用已有的上下文感知旁路提问流程。/btw 消息可能进入普通 prompt 路径,污染主会话并可能影响活跃 turn。Channel 命令需要保留“不打断主任务”的语义,同时遵守 Channel 的路由、授权和异步投递生命周期。

Reviewer 测试计划

如何验证

使用暴露 BTW 能力的 bridge 启动普通 Channel 任务,并在任务仍运行时发送 /btw。确认确认消息立即出现,主任务既未收到 prompt 也未被取消,带相同关联标识的答案随后独立到达。确认空问题、超长问题、带附件问题和未授权请求都会在调用 bridge 前被拒绝;同一会话已有请求时第二个请求会被拒绝;不同会话可以并发;clear、close、reroute、会话丢失或 bridge 替换会阻止过期答案。使用未暴露 BTW 的 bridge 时,确认命令明确报告不支持,而不会落入普通 prompt。

证据(Before & After)

Before:Channel 命令路由没有专用 /btw 路径,消息可能进入普通 prompt。After:/btw 通过可选旁路能力被确认和投递,不改变主 turn;不支持的连接会安全失败。

测试环境

OS 状态
🍏 macOS
🪟 Windows ⚠️
🐧 Linux ⚠️

环境(可选)

Node.js 22.17.0,本地无 sandbox workspace build。此独立分支的 649 个 Channel base 测试全部通过,其中包含 16 个聚焦 /btw 场景;workspace build 与 typecheck 也通过。用于真实 Channel 验证的组合分支已经完成 build、typecheck 和 bundle。

风险与范围

  • 主要风险或取舍:后台响应可能晚于入站消息 turn,因此发送前会同时校验 bridge 身份、存活会话路由、命名任务身份和取消状态。
  • 未验证 / 范围外:第三方 Channel 适配器的真实投递留给已准备的用户验证环境;未在 Windows 和 Linux 本地测试。
  • 破坏性变更 / 迁移说明:无。命令通过结构化可选能力接入,传输 PR 尚未存在时会安全报告不支持,因此本 PR 可以独立合入且两条 PR 顺序任意。

关联 Issue

#10711 的一部分。

@qwen-code-ci-bot

qwen-code-ci-bot commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

⚠️ Deferred approval withheld — 1 PR CI workflow run(s) on a583c68 did not finish green; see the updated table in the Stage 2 comment. Re-run @qwen-code /triage after fixes. finalize run

⚠️ 延迟审批已搁置 —— a583c68 有 1 个 PR CI workflow 未以绿色完成,详见 Stage 2 评论中已更新的表格。修复后可重新运行 @qwen-code /triage查看 finalize 运行

@qqqys

qqqys commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator Author

E2E validation report

Status: automated validation complete; temporary live environment retired.

  • The Channel UX PR passed all 649 Channel base tests on its independent main-based branch, including 16 focused /btw scenarios.
  • The bridge PR passed 145 bridge tests and 96 daemon-worker/wire-contract tests on its independent main-based branch.
  • Both independent branches passed workspace build and typecheck. Focused BTW tests and typecheck were repeated with Node.js 22.17.0.
  • The combined branch passed workspace build, typecheck, and bundle, and its bundled CLI reports version 0.22.3.
  • A standalone dws-review validation service was connected successfully from the combined bundle with an isolated Qwen home. After the validation window was closed, that service and its isolated home were removed, and the existing daemon-managed DWS worker was restored.

Live external messages were not sent by the implementation pass. A future manual validation can run a normal long task, send /btw <question> while it remains active, verify the immediate correlated acknowledgement and later side answer, and confirm that the main task continues without a prompt or cancellation. Same-session duplicate and /clear stale-delivery checks can be repeated after recreating an isolated environment.

@qqqys

qqqys commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /takeover from 0

@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 Sep 1, 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. This is a fork PR, so the first round comes from the next scheduled scan (usually within minutes). Remove the autofix/takeover label (or comment @qwen-code /takeover stop) to release.

中文说明

🤝 已接管:autofix 循环现在管理此 PR —— 将持续处理新的评审反馈与 base 冲突,直到移除标签或达到轮次上限。本 PR 来自 fork,首轮处理将由下一次定时扫描执行(通常几分钟内)。移除 autofix/takeover 标签(或评论 @qwen-code /takeover stop)即可释放。

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Thanks for the PR!

Template looks good ✓

Problem: real, verified gap. main has no /btw handling anywhere in packages/channels, so a Channel message starting with /btw does fall through to the normal prompt path, exactly as described. /btw is already established product surface — interactive TUI, web-shell, and the daemon endpoint from #4610 (merged) — and the parent issue #10711 was triaged earlier today as accepted for exploration with exactly this two-PR split.

Direction: aligned. This is surface parity with shipped infrastructure rather than new machinery: sender authorization reuses the existing channel gates, and nothing touches auth/sandbox/model-selection/telemetry contracts.

Size: 229 production lines (+227/−2 in ChannelBase.ts) and 363 test lines (+360/−3). No core-infrastructure paths touched; well under every threshold.

Approach: the scope matches the delivery plan accepted on #10711 — parsing, authorization, one side question per session, immediate acknowledgement, background delivery, stale-delivery suppression, fail-closed unsupported. The diff carries nothing beyond that. One upfront note: this half only becomes functional once the bridge half (#10712) exposes the capability; until then /btw reports unsupported, which is the agreed behavior and the two PRs may merge in either order.

Risk: no high-risk path matches — no elevated risk signals.

Moving on to code review. 🔍

中文说明

感谢贡献!

模板完整 ✓

问题:真实且已核实的缺口。mainpackages/channels 中没有任何 /btw 处理,以 /btw 开头的频道消息确实会如描述所言落入普通 prompt 路径。/btw 已是既有产品能力——交互式 TUI、web-shell 以及 #4610(已合并)的 daemon 端点——且父 issue #10711 今天早些时候已按"接受探索"完成分诊,并认可了这种两 PR 拆分。

方向:对齐。这是对已发布基础设施的能力面补齐而非新机制:发送者授权复用现有频道门禁,不触及 auth/沙箱/模型选择/遥测契约。

规模:生产逻辑 229 行(ChannelBase.ts +227/−2),测试 363 行(+360/−3)。不触及核心基础设施路径,远低于所有阈值。

方案:范围与 #10711 认可的交付计划一致——解析、授权、每会话单个旁路问题、即时确认、后台投递、过期投递抑制、不支持时失败即关闭。diff 中没有超出该范围的内容。提前说明一点:这一半只有在桥接侧(#10712)暴露能力后才可用;在此之前 /btw 会报告不支持,这是约定行为,两个 PR 可按任意顺序合入。

风险:未命中高风险路径——无升级风险信号。

进入代码审查 🔍

Qwen Code · qwen3.8-max

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

@qwen-code-ci-bot

qwen-code-ci-bot commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Code review

Before reading the diff, my independent proposal was: parse /btw ahead of prompt routing, gate on a structural optional bridge capability that fails closed, validate text/attachments/authorization before touching a session, keep one in-flight side question per session, acknowledge immediately with a correlation ID, deliver in the background, and re-validate session/target/task/bridge identity at delivery time so clear/close/reroute/death/replacement all suppress stale answers. The PR matches that design almost exactly — I did not find a materially simpler path that still meets the lifecycle requirements in #10711.

What stood out reading the diff:

  • Validation order is right: empty, oversized, attachment-bearing, and unauthorized requests are rejected before session resolution, so a malformed /btw neither creates a session nor reaches the bridge.
  • Stale delivery is defended in two layers: lifecycle hooks cancel in-flight requests (setBridge cancels all, onSessionDied cancels one, /clear cancels per removed session, /session close resolves the session id with a pre-close lookup), and isBtwCurrent re-checks bridge identity, live routing, target, and task name right before delivery — so a late result is dropped even if a cancel raced the acknowledgement.
  • Failure paths don't leak: bridge errors are sanitized to stderr, and the user only sees BTW #id failed. Please try again. (pinned by a test).
  • The memory-intent bypass keeps a /btw 记一下... question from being classified as a memory command, and the no-op registered handler routes the command through the dedicated path while keeping isLocalCommand honest (no channel adapter overrides it).

No blockers. Two non-blocking notes:

sequenceDiagram
    participant P1 as Sender
    participant P2 as ChannelBase
    participant P3 as Bridge btw
    participant P4 as Session router
    P1->>P2: send /btw question
    P2->>P2: validate text, attachments, authorization
    P2->>P4: resolve current session and target
    P2-->>P1: ack BTW id, main task continues
    P2->>P3: btw sessionId, question, abort signal
    P3-->>P2: answer
    P2->>P2: re-check session, target, task, bridge identity
    alt still current
        P2-->>P1: deliver BTW id answer
    else cleared, closed, rerouted, died, replaced
        P2->>P2: drop stale answer
    end
Loading

Test evidence — the PR's own CI

At review time the ubuntu unit-test job is still running on the reviewed commit; the macOS/Windows test jobs were skipped in this run, and the security and precheck gates passed. The finalize job updates the table below once CI settles. Not verified here: Windows/Linux behavior (test jobs skipped in this run; the author tested macOS only).

The author reports all 649 Channel base tests passing locally, including 16 focused /btw scenarios — that is the author's claim, attributed as such; this run never executes PR code, so the PR's own CI below is the evidence.

Final CI results for a583c68 (auto-updated by the triage finalize job after CI completed):

Check Conclusion
Test (ubuntu-latest, Node 22.x) 🚫 cancelled
Classify PR ✅ success
Dependency CVE audit ✅ success
Desktop Shell (ubuntu-22.04) ✅ success
Desktop Shell (windows-2022) ✅ success
Integration Tests (no-AK, No Sandbox) ✅ success
route ✅ success
Secret scan (TruffleHog) ✅ success
web-shell E2E Smoke (ubuntu-latest, Node 22.x) ✅ success

One row per check name (latest run); skipped checks omitted; failures sort first. / 每个检查名一行(取最新一次运行),省略 skipped,失败项排在最前。

Sandboxed verification would settle part of this: @qwen-code /verify — that on a real build the /btw command fails closed with "unsupported" instead of falling through to the normal prompt path, and that dispatch modes don't regress. The mocked suite pins the ChannelBase guards, but as this is a fork PR it would be a sponsored run (maintainer-triggered, with a pre-execution risk screen and a workspace wipe — read the report with the same skepticism as the fork's own CI logs). End-to-end delivery itself is not verifiable by any lane until #10712 lands.

中文说明

代码审查

读 diff 之前我的独立方案是:在 prompt 路由之前解析 /btw,用结构化可选 bridge 能力做门禁并在不支持时失败即关闭,在触碰会话前完成文本/附件/授权校验,每会话最多一个在途旁路问题,立即用关联 ID 确认,后台投递,并在投递前重新校验会话/目标/任务/bridge 身份,使 clear、close、reroute、会话死亡、bridge 替换都能抑制过期答案。PR 与该设计几乎完全一致——我没有找到在满足 #10711 生命周期要求的前提下更简单的路径。

要点:

  • 校验顺序正确:空问题、超长、带附件、未授权请求都在会话解析之前被拒绝,畸形 /btw 既不会创建会话也不会到达 bridge。
  • 过期投递双层防御:生命周期钩子取消在途请求(setBridge 全部取消、onSessionDied 取消单个、/clear 按被移除会话逐个取消、/session close 在关闭前查找会话 id),且投递前 isBtwCurrent 重新校验 bridge 身份、存活路由、目标与任务名——即使取消与确认消息竞态,过期结果也会被丢弃。
  • 失败路径不泄露:bridge 错误经净化写入 stderr,用户只看到 BTW #id failed. Please try again.(有测试固化)。
  • 记忆意图旁路使 /btw 记一下... 不会被识别为记忆命令;空操作注册处理器让命令走专用路径,同时保持 isLocalCommand 语义正确(各频道适配器均未覆写它)。

无阻塞项。两点非阻塞提醒:

测试证据

审查时 ubuntu 单测 job 仍在运行;本次 macOS/Windows 测试 job 为 skipped,安全与预检已通过,表格将由 finalize 任务在 CI 落定后更新。此处未验证:Windows/Linux 行为(本次运行中相应 job 被跳过,作者仅在 macOS 上测试)。作者自述 649 个 Channel base 测试全部通过(含 16 个 /btw 场景)——此为作者声明;本运行不执行 PR 代码,以上证据均来自 PR 自身 CI。沙箱验证建议:维护者可发起 @qwen-code /verify(fork PR,属赞助运行,带执行前风险筛查与工作区清理,报告需以审视 fork CI 日志的同样怀疑态度阅读),以确认真实构建下 /btw 失败即关闭而非落入普通 prompt 路径;端到端投递在 #10712 合入前任何通道都无法验证。

Qwen Code · qwen3.8-max

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

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Confidence: 4/5 — clean, focused implementation that does exactly what the accepted issue plan asked for, with genuinely strong lifecycle test coverage; the only reservations are non-blocking (functional dependency on the companion bridge PR, and no timeout on the per-session slot).

Stepping back: my independent proposal and the PR's approach are essentially the same design, and I could not find a simpler path that still meets #10711's lifecycle requirements — every event the issue lists (clear, close, reroute, session loss, bridge replacement) has both a cancellation hook and a delivery-time re-check, which is precisely the watch item the issue triage called out, and it has dedicated tests pinning it. The code reads like the file around it — sanitized logging, thread messages, router/namedSessions reuse — and the 363 test lines are not filler: they pin the guards rather than restate the implementation. This is also one half of a coherent two-PR plan against a triaged issue, not volume.

Approving with one honest caveat: this half only becomes functional once #10712 lands; until then /btw fails closed with "unsupported", which is the agreed behavior.

CI is still running on the reviewed commit, so approval is deferred until it lands green on a583c687a27876a7527fbdf85eec0cdee2ac2020.

中文说明

置信度:4/5 —— 干净、聚焦的实现,恰好完成了已被接受的 issue 计划所要求的内容,生命周期测试覆盖扎实;仅有的保留意见均为非阻塞项(功能上依赖配套 bridge PR,以及每会话名额没有超时)。

整体来看:我的独立方案与 PR 的做法本质上是同一设计,且我没有找到在满足 #10711 生命周期要求前提下更简单的路径——issue 列出的每个事件(clear、close、reroute、会话丢失、bridge 替换)都同时具备取消钩子和投递前复查,这正是 issue 分诊时点名的关注点,并且有专门测试固化。代码风格与所在文件一致——净化日志、线程消息、复用 router/namedSessions——363 行测试也非充数:它们固化的是守卫逻辑而非复述实现。这也是针对已分诊 issue 的两 PR 连贯计划的一半,而非刷量。

予以批准,但带一个诚实的提醒:这一半要等 #10712 合入后才可用;在此之前 /btw 会以"不支持"失败即关闭,这是约定行为。

审查提交上的 CI 仍在运行,因此批准推迟至其在 a583c687a27876a7527fbdf85eec0cdee2ac2020 上全绿后执行。

Qwen Code · qwen3.8-max

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

Comment thread packages/channels/base/src/ChannelBase.ts Outdated
Comment thread packages/channels/base/src/ChannelBase.ts Outdated
Comment thread packages/channels/base/src/ChannelBase.ts Outdated
Comment thread packages/channels/base/src/ChannelBase.ts
Comment thread packages/channels/base/src/ChannelBase.ts Outdated
Comment thread packages/channels/base/src/ChannelBase.ts
Comment thread packages/channels/base/src/ChannelBase.ts
Comment thread packages/channels/base/src/ChannelBase.ts
Comment thread packages/channels/base/src/ChannelBase.ts
Comment thread packages/channels/base/src/ChannelBase.ts
@qwen-code-dev-bot

qwen-code-dev-bot commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

AutoFix round 3 finishedview run. See this round's report below.

中文说明

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

Critical:
- Deliver the /btw answer to the chat/thread captured from the asking
  envelope instead of the session's creation-time router target, which
  froze the destination for sessions shared across chats or threads
- Keep an acknowledged /btw current when SessionRouter promotes the
  live target to a group mid-flight; the promotion changes neither the
  conversation nor the delivery destination, while the named-task
  branch keeps the stricter target comparison

Suggestions:
- Move the shared-session authorization gate ahead of the usage,
  length, and attachment validation so non-members no longer receive
  validation answers
- Move the bridge capability check ahead of session resolution so an
  unsupported /btw no longer creates and persists a session
- Declare btw on ChannelAgentBridge as an optional capability instead
  of a module-private intersection type
- Describe /btw in the /help command list and the channel docs

Tests: cross-chat delivery under sessionScope single, mid-flight group
promotion, foreign-session response rejection, unauthorized bare and
oversized /btw, no-session-creation on unsupported bridges, and the
described /help entry.
@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 address-review summary — PR #10713 (round 1)

Addressed 8 of 17 findings this round (both Criticals first, per the
~8-findings-per-round bound); the remaining 9 are deferred to the next round
with per-thread replies. One commit: b63163af2b on
feat/channel-btw-channel.

Fixed this round

  • [Critical] R1-1 — answer delivered to the wrong conversation (packages/channels/base/src/ChannelBase.ts): handleBtw now captures the asker's envelope.chatId/threadId on the ActiveBtw request, and deliverBtw delivers the answer (and any failure message) there. request.target is untouched and remains the staleness input for isBtwCurrent, so the three suppression tests still pin it. New test delivers the answer to the asker chat when the session spans chats (sessionScope single, session created from chat-a, asker in chat-b — answer lands in chat-b, nothing in chat-a); removing the new routing turns it red.
  • [Critical] R1-23 — unrelated group message voids an acknowledged answer: the request-vs-current freshness comparison in isBtwCurrent now compares sameTaskOwner + threadId only; the SessionRouter.promoteTargetToGroup isGroup flip no longer suppresses a settled answer. Localized to the request-vs-current comparison — the named-task branch keeps the stricter sameSessionTarget check. New test still delivers the answer when a group message promotes the session target mid-flight; restoring the isGroup comparison turns it red.
  • R1-9 — authorization gate ran after input validation: isAuthorizedForSharedSession moved to the top of the /btw block, matching every sibling command; extended rejects unauthorized callers before resolving a shared session with a bare /btw and an oversized /btw from the intruder — both now receive the authorization rejection.
  • R1-5 — unsupported bridge still created and persisted a session: the bridge.btw capability check moved into the pre-resolution validation block in processInbound (and out of handleBtw, which is only reachable after the check), so a refused /btw never creates a session — same invariant as the ! gate. The sourceLabel tag loss on named-session channels for this one message is accepted deliberately, consistent with the sibling pre-resolution validations. The fails-closed test now asserts newSession/btw/prompt are never called.
  • R1-3 — capability type contract: btw? is declared on ChannelAgentBridge next to the sibling optional capabilities; the module-private ChannelBtwProvider interface and both intersections are deleted, and the test harness now types the bridge as the canonical interface. Removing the member from the interface produces 22 fresh type errors in ChannelBase.test.ts.
  • R1-4 — bare /btw line in /help: 'btw' added to the sharedCmds set and a described line /btw <question> — Ask a side question without interrupting the current task added to the help list. The /help sends command list test asserts the described entry and that no bare /btw platform line appears.
  • R1-12 — docs: /btw <question> entry added to the Slash Commands list in docs/users/features/channels/overview.md, noting the text-only / 4096-character limits and that it requires an agent connection with side-question support.
  • R1-13 — session-mismatch guard had no test: new test rejects a response that belongs to a different session — a bridge answering for s-other yields the generic failure message and the foreign answer is never sent; deleting the result.sessionId !== sessionId guard turns it red.

Deferred to the next round (per-thread replies posted)

R1-6 (constant mirror/equality), R1-7 (channel-side bound / cancel path),
R1-8 (lifecycle stderr trace), R1-11 (shared ownership-predicate extraction),
R1-14 (ack-failure cleanup test), R1-15 (abort-signal test), R1-16
(registry-clear assertion), R1-17 (stale-delivery finally-guard test), R1-21
(loop-timeout retirement cancelBtw). Reason: the round is bounded to ~8
findings with the two Criticals first; none of these were declined.

Not actionable / informational

  • [ic:5495406043] E2E validation report — informational, no change requested; no action.
  • Failed check "Test (ubuntu-latest Node 22.x): CANCELLED" — a cancellation, not a test failure; no code-level evidence of a defect, and the check re-runs on the new head commit.

Verification

  • Pre-fix reproduction (packages/channels/base): npx vitest run src/ChannelBase.test.ts -t 'btw' → 4 failed (R1-1, R1-23, R1-5, R1-9); npx vitest run src/ChannelBase.test.ts -t '/help sends command list' → 1 failed (R1-4) — confirming each defect on the pre-round code.
  • Post-fix focused: npx vitest run src/ChannelBase.test.ts -t 'btw' → 19 passed; npx vitest run src/ChannelBase.test.ts -t '/help sends command list' → 1 passed; npx vitest run src/ChannelBase.test.ts → 652 passed.
  • Mutation probes (mutant red, restored green): reverted answer delivery to request.target (new R1-1 test red); restored sameSessionTarget in the request-vs-current comparison (new R1-23 test red); negated the auth gate (extended unauthorized test red); removed the pre-resolution capability check (fails-closed test red); removed 'btw' from sharedCmds (/help test red); deleted the result.sessionId !== sessionId guard (new R1-13 test red). Type probe: removed btw? from ChannelAgentBridge → 22 new tsc errors in ChannelBase.test.ts, restored → clean.
  • Package suite: cd packages/channels/base && npx vitest run → 20 files, 1192 passed.
  • Adapter suites (consume rebuilt channel-base): qqbot 305, dingtalk 478, telegram 25, wecom 137, feishu 280, weixin 92, github 208, gitlab 60, dws 260, plugin-example 4 — all passed.
  • npm run build — passed.
  • npm run typecheck — passed (all workspaces + integration).
  • npm run lint — passed.
  • npx prettier --check on the four changed files — passed.
中文说明

Autofix address-review 摘要 — PR #10713(第 1 轮)

本轮处理了 17 条发现中的 8 条(按每轮约 8 条的上限,优先处理两个 Critical);其余 9 条顺延到下一轮,并已在各自线程回复。单次提交:feat/channel-btw-channel 分支上的 b63163af2b

本轮已修复

  • [Critical] R1-1 — 答案被投递到错误的会话packages/channels/base/src/ChannelBase.ts):handleBtw 现在把提问者所在的 envelope.chatId/threadId 记录到 ActiveBtw 请求上,deliverBtw 将答案(以及任何失败消息)投递到该地址。request.target 保持不变,继续作为 isBtwCurrent 的过期判断输入,因此三个抑制测试仍然固定原有行为。新增测试 delivers the answer to the asker chat when the session spans chats(sessionScope 为 single,会话由 chat-a 创建、提问者位于 chat-b —— 答案落到 chat-b,chat-a 收不到任何消息);移除新的投递路由后该测试变红。
  • [Critical] R1-23 — 无关群消息会使已确认的答案作废isBtwCurrent 中的请求-当前新鲜度比较现在仅比较 sameTaskOwner + threadIdSessionRouter.promoteTargetToGroup 对 isGroup 的翻转不再抑制已完成的答案。改动限定在请求-当前比较处 —— 命名任务分支保留更严格的 sameSessionTarget 检查。新增测试 still delivers the answer when a group message promotes the session target mid-flight;把 isGroup 比较加回去后该测试变红。
  • R1-9 — 授权门在输入校验之后运行isAuthorizedForSharedSession 移到 /btw 块顶部,与所有兄弟命令一致;rejects unauthorized callers before resolving a shared session 扩展为入侵者发送裸 /btw 与超长 /btw —— 两者现在都收到授权拒绝。
  • R1-5 — 不支持的 bridge 仍会创建并持久化会话bridge.btw 能力检查移入 processInbound 的解析前校验块(并从 handleBtw 中移除,因为该函数只在检查通过后才会被调用),被拒绝的 /btw 不再创建会话 —— 与 ! 门保持相同不变量。命名会话频道上该消息丢失 sourceLabel 标签是有意接受的,与兄弟解析前校验保持一致。fails-closed 测试现在断言 newSession/btw/prompt 均未被调用。
  • R1-3 — 能力类型契约btw? 与兄弟可选能力并列声明在 ChannelAgentBridge 上;删除模块私有的 ChannelBtwProvider 接口及两处交集标注,测试装置现在直接用规范接口为 bridge 定型。从接口中移除该成员会在 ChannelBase.test.ts 中产生 22 个新的类型错误。
  • R1-4 — /help 中出现裸 /btw'btw' 加入 sharedCmds 集合,help 列表新增描述行 /btw <question> — Ask a side question without interrupting the current task/help sends command list 测试断言存在该描述条目,且不出现裸 /btw 平台行。
  • R1-12 — 文档docs/users/features/channels/overview.md 的 Slash Commands 列表新增 /btw <question> 条目,注明纯文本 / 4096 字符上限,且需要支持旁路提问的 agent 连接。
  • R1-13 — 会话不匹配守卫没有测试:新增测试 rejects a response that belongs to a different session —— bridge 返回 s-other 的结果时给出泛化失败消息,且外部答案永不被发送;删除 result.sessionId !== sessionId 守卫后该测试变红。

顺延到下一轮(已在各线程回复)

R1-6(常量镜像/相等性)、R1-7(频道侧时限 / 取消路径)、R1-8(生命周期 stderr 日志)、R1-11(共享所有权谓词抽取)、R1-14(确认失败清理测试)、R1-15(中止信号测试)、R1-16(注册表清空断言)、R1-17(过期投递 finally 守卫测试)、R1-21(循环超时退役路径的 cancelBtw)。原因:本轮按约 8 条上限优先处理两个 Critical;以上均未被拒绝。

不可处理 / 信息性

  • [ic:5495406043] E2E 验证报告 —— 信息性内容,未提出变更要求;无需处理。
  • 失败检查 "Test (ubuntu-latest Node 22.x): CANCELLED" —— 属于取消,不是测试失败;没有代码层面缺陷的证据,且该检查会在新 head 提交上重新运行。

验证

  • 修复前复现(packages/channels/base):npx vitest run src/ChannelBase.test.ts -t 'btw' → 4 失败(R1-1、R1-23、R1-5、R1-9);npx vitest run src/ChannelBase.test.ts -t '/help sends command list' → 1 失败(R1-4)—— 确认每个缺陷在本轮前代码上成立。
  • 修复后聚焦测试:npx vitest run src/ChannelBase.test.ts -t 'btw' → 19 通过;npx vitest run src/ChannelBase.test.ts -t '/help sends command list' → 1 通过;npx vitest run src/ChannelBase.test.ts → 652 通过。
  • 变异探针(变异红、恢复绿):把答案投递还原为 request.target(新 R1-1 测试变红);在请求-当前比较中恢复 sameSessionTarget(新 R1-23 测试变红);把授权门取反(扩展后的未授权测试变红);移除解析前能力检查(fails-closed 测试变红);从 sharedCmds 移除 'btw'(/help 测试变红);删除 result.sessionId !== sessionId 守卫(新 R1-13 测试变红)。类型探针:从 ChannelAgentBridge 移除 btw?ChannelBase.test.ts 出现 22 个新 tsc 错误,恢复后干净。
  • 包级测试套件:cd packages/channels/base && npx vitest run → 20 个文件,1192 通过。
  • 适配器套件(消费重新构建的 channel-base):qqbot 305、dingtalk 478、telegram 25、wecom 137、feishu 280、weixin 92、github 208、gitlab 60、dws 260、plugin-example 4 —— 全部通过。
  • npm run build —— 通过。
  • npm run typecheck —— 通过(全部 workspace + integration)。
  • npm run lint —— 通过。
  • 对 4 个改动文件运行 npx prettier --check —— 通过。

🧭 Gate advisory — this round modified areas outside the PR footprint (machine-measured, not agent-authored):

  • docs
    Review the expansion deliberately; the footprint gate is in advisory mode. · 本轮改动了 PR 足迹之外的区域(门自动测量,非 agent 文本),当前足迹门为 advisory 模式,请有意识地审阅该扩张。

Base-conflict check · 基分支冲突检查: no conflict with main. · 与 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/模型 qwen3.8-max

@qwen-code-ci-bot qwen-code-ci-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.

Not explored to full depth (tool budget reached): "agent 5": running ChannelBase.test.ts /btw tests — worktree has no node_modules and a full monorepo install was not attempted within budget; mutation verdicts are reasone….

Deferred under the convergence posture (round 2, not a blocker) — recorded, not requested in this round:

  • packages/channels/base/src/ChannelBase.test.ts:16143 — [probe] length-limit test pins only the reject side (4097); the 4096-char acceptance case is missing
  • packages/channels/base/src/ChannelBase.ts:6134 — [probe] text-only validation test never sends imageBase64; deleting the check ships green
  • packages/channels/base/src/ChannelBase.ts:6126 — [probe] length limit counts UTF-16 units while docs promise characters
  • packages/channels/base/src/ChannelBase.ts:6065 — [probe] redundant btw-only memory-intent carve-outs
中文说明

未探索到全部深度(达到工具调用预算):"agent 5"running ChannelBase.test.ts /btw tests — worktree has no node_modules and a full monorepo install was not attempted within budget; mutation verdicts are reasone…

收敛姿态下延后(第 2 轮,非阻断)——已记录,本轮不要求修改:共 4 条(原文未翻译,列表见上方英文部分)。

— qwen3.8-max via Qwen Code /review (v0.22.3)

Comment thread packages/channels/base/src/ChannelBase.ts
Comment thread packages/channels/base/src/ChannelBase.ts
Comment thread packages/channels/base/src/ChannelBase.ts Outdated
Comment thread packages/channels/base/src/ChannelBase.ts
Comment thread packages/channels/base/src/ChannelBase.ts
Comment thread packages/channels/base/src/ChannelBase.ts
Comment thread packages/channels/base/src/ChannelBase.ts
Comment thread packages/channels/base/src/ChannelBase.ts
Comment thread packages/channels/base/src/ChannelBase.ts
Comment thread packages/channels/base/src/ChannelBase.ts
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🔀 Base updated: red check(s) [Test (ubuntu-latest, Node 22.x)] pass on current main — merged current main via update-branch; CI will re-run.

中文说明

🔀 已更新 base:红色检查 [Test (ubuntu-latest, Node 22.x)] 在当前 main 上通过 —— 已通过 update-branch 合入当前 main,CI 将重新运行。

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Qwen Code review did not complete successfully. The review pipeline failed before a review could be posted. A transient error is retried automatically; if you are seeing this, retry with @qwen-code /review. See workflow logs.

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤖 AutoFix ran out of time before finishing (timeout (7200000ms)) (attempt 2/100) — it will retry on the next scan.

What I found before stopping:
Qwen failed during address-review: timeout (7200000ms).

See the Qwen Autofix agent step logs for model/tool output.

中文说明

🤖 AutoFix 在完成前耗尽了时间(timeout (7200000ms))(第 2/100 次尝试)—— 将在下次扫描时重试。

Run log: https://github.com/QwenLM/qwen-code/actions/runs/33567333885


🧠 Handled by Qwen Code · model/模型 qwen3.8-max

@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 轮)。改动内容与我反驳保留之处如下:

Round summary

Round 2 of review feedback on PR #10713. Per the workflow's budget warning (a previous round exhausted its time budget), this round implemented the smallest blocking subset only — the two Critical findings — and deferred every Suggestion to later rounds with per-thread replies.

Implemented

  1. [Critical] R2-1 (rc:3908619772, ChannelBase.ts named-task branch of isBtwCurrent): the named branch compared the live router target against the registry's creation-time snapshot via sameSessionTarget, which includes isGroup. Whenever a loop/webhook target with isGroup: true resolves the owner's routing key mid-flight, SessionRouter.promoteTargetToGroup flips the live target's isGroup and every acknowledged /btw answer for the named task was silently dropped — the exact transition the plain branch was relaxed for in the prior fix commit. Fixed by relaxing the named branch to owner + thread (same tolerance as the plain branch), updating the explanatory comment, and removing the now-unused private sameSessionTarget helper (subtractive). Delivery stays bound to the asker's envelope chat/thread, which isGroup never affects.

    • Regression test: still delivers a named-task answer when the session target is promoted to a group mid-flight — multiSession channel, /session new review, /btw in flight, promotion via router.resolve(..., isGroup: true) (the same call runLoopJob/runWebhookTask make), answer delivered.
    • Mutation probe: restoring the isGroup comparison in the named branch turns this test red; with the fix the whole suite is green.
  2. [Critical] R2-11 (rc:3908619790, ChannelBase.ts handleBtw cleanup sites): both cleanup sites — the ack-failure catch and the post-ack staleness check — called cancelBtw(sessionId) without verifying the map entry was still their own request, so a stale request settling after a bridge crash/recovery cancelled its successor on the same session id — the identity hazard deliverBtw's finally already guards against. Both sites are now identity-guarded (this.activeBtw.get(sessionId) === request), mirroring that pattern; cancelBtw's delete-then-abort semantics (relied on by /clear, /session close, onSessionDied, setBridge) are unchanged.

    • Regression tests: does not cancel a newer side question when a stale acknowledgement settles (stale ack succeeds — pins the staleness-check site) and does not cancel a newer side question when a stale acknowledgement fails (stale ack throws — pins the catch site).
    • Mutation probes: removing either identity guard turns exactly its corresponding test red. A true pre-round simulation (HEAD's ChannelBase.ts + the three new tests) fails all three.

Deferred to later rounds (budget warning; per-thread replies recorded in comment-replies.json)

  • R2-6 (rc:3908619793): /help advertises /btw unconditionally.
  • R1-6 (rc:3908619799): CHANNEL_BTW_MAX_INPUT_LENGTH forks the core BTW_MAX_INPUT_LENGTH contract.
  • R1-7 (rc:3908619804): no channel-side timeout / user-reachable cancellation for an in-flight /btwescalated for a maintainer decision (question on its thread).
  • R1-8 (rc:3908619809): no stderr trace for the btw lifecycle's silent paths.
  • R1-11 (rc:3908619815): three duplicated ownership-freshness predicates.
  • R1-14 (rc:3908619821): ack-failure cleanup lacks an uncontended-case test.
  • R1-15 (rc:3908619829): cancelBtw's abort has no test witness.
  • R1-16 (rc:3908619834): cancelAllBtw's registry clear has no test witness.
  • R1-17 (rc:3908619837): deliverBtw's finally identity guard has no contested-entry test.
  • R1-21 (rc:3908619845): loop-timeout retirement path lacks the cancelBtw hook.

All ten were verified as real against the current code this round; each remains in the review ledger and will resurface as "Still stands" until addressed. They are deferred, not declined, because the round budget was reserved for the blocking Criticals.

Failed checks

  • review-pr: FAILURE — the review pipeline itself failed before posting; the fallback comment (ic:5501397812) says the transient error is retried automatically. No code action available.
  • Test (ubuntu-latest, Node 22.x): FAILURE and web-shell E2E Smoke (ubuntu-latest, Node 22.x): FAILURE — CI logs are not accessible from this environment (no GitHub credentials), so no exact failing step could be identified. Local reproduction of everything inside this PR's footprint (4 files: docs + packages/channels/base): the full packages/channels/base suite is green (1195/1195), and npm run build, npm run typecheck, npm run lint all pass. The merge commit 783eef078b brought 98 files from main, including the web-shell work the E2E smoke job covers; the workflow's independent CI remains the final verification gate.

Verification

Commands actually run this round:

  • npx vitest run src/ChannelBase.test.ts (in packages/channels/base) — 655 passed (652 baseline + 3 new)
  • npx vitest run (whole packages/channels/base package) — 20 test files, 1195 passed
  • Mutation probe 1: restored the isGroup comparison in the named-task branch → new named-task promotion test FAILED; fix restored, green again
  • Mutation probe 2: removed the identity guard at the post-ack staleness site → ...stale acknowledgement settles FAILED; fix restored, green again
  • Mutation probe 3: removed the identity guard in the ack-failure catch → ...stale acknowledgement fails FAILED; fix restored, green again
  • Pre-round simulation: swapped HEAD's ChannelBase.ts in and ran the three new tests → 3 failed (proves each test witnesses its fix); fix restored, green again
  • npm run build — passed
  • npm run typecheck — passed
  • npm run lint — passed
  • npx prettier --check on the two changed files — passed (after --write on the test file)
中文说明

本轮摘要

PR #10713 的第 2 轮评审反馈处理。根据工作流的预算警告(上一轮耗尽了时间预算),本轮只实现最小阻断子集 —— 两条 Critical 发现 —— 并将所有 Suggestion 以逐线程回复的形式顺延到后续轮次。

已实现

  1. [Critical] R2-1rc:3908619772,ChannelBase.ts 中 isBtwCurrent 的命名任务分支):命名任务分支通过 sameSessionTarget 把存活 router target 与注册表创建时快照比较,而该比较包含 isGroup。一旦 isGroup: true 的循环/回调任务在飞行途中解析到所有者的路由键,SessionRouter.promoteTargetToGroup 就会翻转存活 target 的 isGroup,该命名任务所有已确认的 /btw 答案都会被静默丢弃 —— 这正是上一次修复提交为普通分支放宽的那种转变。修复方式:将命名分支放宽为仅比较 owner + thread(与普通分支同样的容忍度),更新解释性注释,并删除因此不再使用的私有 sameSessionTarget 辅助方法(减法改动)。投递仍绑定提问者 envelope 的 chat/thread,isGroup 对其无影响。

    • 回归测试:still delivers a named-task answer when the session target is promoted to a group mid-flight —— multiSession 频道、/session new review、飞行中的 /btw、经 router.resolve(..., isGroup: true)(与 runLoopJob/runWebhookTask 相同的调用)提升,答案正常投递。
    • 变异探针:在命名分支恢复 isGroup 比较后该测试变红;修复后整套测试全绿。
  2. [Critical] R2-11rc:3908619790,ChannelBase.ts handleBtw 的两处清理点):两处清理点 —— 确认消息失败的 catch 与确认后过期检查 —— 调用 cancelBtw(sessionId) 时均未校验 map 条目是否仍是自己的请求,因此 bridge 崩溃/恢复后迟到完成的过期请求会取消同一会话 id 上的后继者 —— 这正是 deliverBtwfinally 已经防范的身份风险。两处现在都加上了身份守卫(this.activeBtw.get(sessionId) === request),与该模式保持一致;cancelBtw 先删除后中止的语义(/clear/session closeonSessionDiedsetBridge 均依赖)保持不变。

    • 回归测试:does not cancel a newer side question when a stale acknowledgement settles(过期 ack 成功 —— 固定过期检查点)与 does not cancel a newer side question when a stale acknowledgement fails(过期 ack 抛错 —— 固定 catch 点)。
    • 变异探针:移除任一身份守卫后恰好对应的测试变红。真实的前轮模拟(HEAD 的 ChannelBase.ts + 三个新测试)三条测试全部失败。

顺延到后续轮次(预算警告;逐线程回复已记录在 comment-replies.json

  • R2-6(rc:3908619793):/help 无条件展示 /btw
  • R1-6(rc:3908619799):CHANNEL_BTW_MAX_INPUT_LENGTH 分叉了 core 的 BTW_MAX_INPUT_LENGTH 契约。
  • R1-7(rc:3908619804):飞行中的 /btw 没有频道侧超时/用户可触达的取消手段 —— 已升级等待维护者决策(问题见该线程)。
  • R1-8(rc:3908619809):btw 生命周期的静默路径没有 stderr 痕迹。
  • R1-11(rc:3908619815):所有权新鲜度谓词存在三份重复拷贝。
  • R1-14(rc:3908619821):确认失败清理缺少无竞争场景的测试。
  • R1-15(rc:3908619829):cancelBtw 的中止行为没有测试见证。
  • R1-16(rc:3908619834):cancelAllBtw 的注册表清空没有测试见证。
  • R1-17(rc:3908619837):deliverBtw 的 finally 身份守卫没有条目被替换场景的测试。
  • R1-21(rc:3908619845):循环超时退役路径缺少 cancelBtw 钩子。

以上十条本轮均已对照当前代码验证属实;它们仍保留在评审台账中,在处理前会继续以 "Still stands" 形式重现。它们是顺延而非拒绝,因为本轮预算保留给了阻断性的 Critical。

失败检查

  • review-pr: FAILURE —— 评审流水线自身在发布前失败;兜底评论(ic:5501397812)说明瞬时错误会自动重试。无可用代码动作。
  • Test (ubuntu-latest, Node 22.x): FAILUREweb-shell E2E Smoke (ubuntu-latest, Node 22.x): FAILURE —— 本环境无法访问 CI 日志(没有 GitHub 凭据),因此无法定位确切的失败步骤。在本 PR 足迹内(4 个文件:docs + packages/channels/base)的本地复现:packages/channels/base 完整测试套件全绿(1195/1195),npm run buildnpm run typechecknpm run lint 全部通过。合并提交 783eef078bmain 带入了 98 个文件,包含 E2E smoke 任务所覆盖的 web-shell 改动;工作流的独立 CI 仍是最终验证关口。

验证

本轮实际执行的命令:

  • npx vitest run src/ChannelBase.test.ts(在 packages/channels/base 内)—— 655 通过(652 基线 + 3 新增)
  • npx vitest runpackages/channels/base 整包)—— 20 个测试文件,1195 通过
  • 变异探针 1:在命名任务分支恢复 isGroup 比较 → 新的命名任务提升测试失败;恢复修复后重新变绿
  • 变异探针 2:移除确认后过期检查点的身份守卫 → ...stale acknowledgement settles 失败;恢复修复后重新变绿
  • 变异探针 3:移除确认失败 catch 中的身份守卫 → ...stale acknowledgement fails 失败;恢复修复后重新变绿
  • 前轮模拟:换入 HEAD 的 ChannelBase.ts 运行三个新测试 → 3 条失败(证明每个测试都见证了各自的修复);恢复修复后重新变绿
  • npm run build —— 通过
  • npm run typecheck —— 通过
  • npm run lint —— 通过
  • npx prettier --check(两个改动文件)—— 通过(测试文件经 --write 格式化后)

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/模型 qwen3.8-max

@qqqys

qqqys commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /takeover stop

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

Copy link
Copy Markdown
Collaborator

👋 Takeover released: the autofix loop will no longer engage this PR (an in-flight round, if any, completes its bounded work). Re-apply autofix/takeover (or comment @qwen-code /takeover) to re-engage.

中文说明

👋 已释放:autofix 循环不再介入此 PR(在飞的一轮如有,将完成其有界工作)。重新打上 autofix/takeover 标签(或评论 @qwen-code /takeover)即可再次接管。

@qwen-code-ci-bot qwen-code-ci-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.

Reviewed — no blockers. Suggestions are inline.

1 Suggestion-level finding(s) this review confirmed are already reported on this PR and are not repeated:

  • R1-7 unbounded in-flight /btw await (no channel-side timeout, no user-reachable cancel) — already reported (round-1 inline thread, comment 3906696349; escalated for a maintainer decision in round 2)

Deferred under the convergence posture (round 3, not a blocker) — recorded, not requested in this round:

  • packages/channels/base/src/ChannelBase.ts:6122 — [probe] D3-1 /btw question bypasses sanitizePromptText — C0/bidi control chars and line-leading [SYSTEM]:-style tags reach the forked agent verbatim
  • docs/users/features/channels/overview.md:492 — [review] D3-2 docs section preamble 'handled locally (no agent round-trip)' is false for the /btw entry, which always round-trips through the agent capability

Convergence: round 3 posted 3 inline comment(s), 3 of them reported for the first time; the previous round posted 12 (3 new). Findings keep coming back to the same files: packages/channels/base/src/ChannelBase.ts (findings in rounds 1, 2; 3 more now). The rate of new findings is not falling. A cluster that keeps producing siblings usually means the fixes are treating instances of a shared root cause — triaging that cause before the next round, or splitting an independent cluster into its own pull request, tends to end the loop faster than fixing them one at a time. Batching the remaining fixes and verifying them before the next push, or dropping this PR's reviews to --severity-floor critical, keeps the loop from re-deriving the same set. (Observation only — nothing was withheld from this review because of this observation.)

中文说明

已审查——无阻断问题。 建议见行内评论。

本轮确认的 1 条建议级发现已在 PR 上报告过,不再重复发布(列表见上方英文部分)。

收敛姿态下延后(第 3 轮,非阻断)——已记录,本轮不要求修改:共 2 条(原文未翻译,列表见上方英文部分)。

收敛情况:第 3 轮发布了 3 条行内评论,其中 3 条是首次提出;上一轮发布了 12 条(其中 3 条首次提出)。发现反复回到同一批文件:packages/channels/base/src/ChannelBase.ts(第 1、2 轮已出过发现,本轮又有 3 条)。新发现的产出速度没有下降。一个不断再生兄弟发现的簇,通常意味着逐条修复只在处理同一根因的实例——先定位并处理该根因,或把独立的簇拆成单独的 PR,通常比逐条修复更快结束循环。把剩余修复攒成一批、验证后再推送,或将本 PR 的评审降到 --severity-floor critical,可以避免循环反复推导同一组发现。(仅为观察——本轮评审未因此扣留任何内容。)

— qwen3.8-max via Qwen Code /review (v0.22.3)

Comment thread packages/channels/base/src/ChannelBase.ts
Comment thread packages/channels/base/src/ChannelBase.ts Outdated
Comment thread packages/channels/base/src/ChannelBase.ts Outdated

@qwen-code-ci-bot qwen-code-ci-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.

7 Suggestion-level finding(s) this review confirmed are already reported on this PR and are not repeated:

  • R1-7 unbounded in-flight /btw await, no channel-side timeout and no user-reachable cancel — already reported (comment 3906696349, re-posted at comment 3908619804; escalated for a maintainer decision in round 2)
  • R1-6 CHANNEL_BTW_MAX_INPUT_LENGTH mirrors core's BTW_MAX_INPUT_LENGTH with nothing pinning equality — already reported (comment 3906696343, re-posted at comment 3908619799)
  • R1-8 no stderr trace on the btw lifecycle's silent and suppression paths — already reported (comment 3906696361, re-posted at comment 3908619809)
  • R1-11 isBtwCurrent is a third copy of the named-session ownership-freshness predicate — already reported (comment 3906696379, re-posted at comment 3908619815)
  • D3-1 /btw question bypasses sanitizePromptText and sender attribution — already reported (round-3 review body deferred list, ChannelBase.ts:6122)
  • redundant btw-only channel-memory-intent carve-outs — already reported (round-2 review body deferred list, ChannelBase.ts:6065)
  • length-limit test pins only the reject side (4097); the 4096-character acceptance case is missing — already reported (round-2 review body deferred list, ChannelBase.test.ts:16143)

Deferred under the convergence posture (round 4, not a blocker) — recorded, not requested in this round:

  • packages/channels/base/src/ChannelBase.ts:6298 — [probe] D4-1 /btw never claims the session's static context, so operator instructions arrive one turn after the answer they governed
  • packages/channels/base/src/ChannelBase.ts:3607 — [probe] D4-2 two of the four new cancelBtw sites (/session close, onSessionDied) have no test that can observe them
  • packages/channels/base/src/ChannelBase.ts:690 — [probe] D4-3 whitespace-only answer branch and the .trim() that guards it are unpinned
  • packages/channels/base/src/ChannelBase.test.ts:365 — [probe] D4-4 shared createBridge() mock hardcodes the echoed sessionId, mis-modelling the echo contract this diff documents

Convergence: round 4 posted 2 inline comment(s), 2 of them reported for the first time; the previous round posted 3 (3 new). Findings keep coming back to the same files: packages/channels/base/src/ChannelBase.ts (findings in round 3; 1 more now). A cluster that keeps producing siblings usually means the fixes are treating instances of a shared root cause — triaging that cause before the next round, or splitting an independent cluster into its own pull request, tends to end the loop faster than fixing them one at a time. (Observation only — nothing was withheld from this review because of this observation.)

中文说明

本轮确认的 7 条建议级发现已在 PR 上报告过,不再重复发布(列表见上方英文部分)。

收敛姿态下延后(第 4 轮,非阻断)——已记录,本轮不要求修改:共 4 条(原文未翻译,列表见上方英文部分)。

收敛情况:第 4 轮发布了 2 条行内评论,其中 2 条是首次提出;上一轮发布了 3 条(其中 3 条首次提出)。发现反复回到同一批文件:packages/channels/base/src/ChannelBase.ts(第 3 轮已出过发现,本轮又有 1 条)。一个不断再生兄弟发现的簇,通常意味着逐条修复只在处理同一根因的实例——先定位并处理该根因,或把独立的簇拆成单独的 PR,通常比逐条修复更快结束循环。(仅为观察——本轮评审未因此扣留任何内容。)

— qwen3.8-max-2026-09-02 via Qwen Code /review (v0.22.3)

Comment thread packages/channels/base/src/ChannelBase.ts Outdated
Comment thread packages/channels/base/src/ChannelBase.test.ts
No ChannelAgentBridge in this tree implements the optional btw capability
yet, so the unsupported-bridge gate was taken on every shipped connection
and /btw refused. At the merge base /btw was not a locally handled
command: it fell through to the agent, which serves it as its own slash
command and answered. Landing the interception before any producer
therefore replaced a working answer with a permanent refusal.

Intercept only when the bridge can answer out of band. Without the
capability /btw falls through unchanged, so this PR no longer depends on
the bridge half landing first.

The /help de-duplication needed the same treatment: `btw` is registered
locally whether or not the bridge supports it, so the filter hid the
agent's entry even when that entry was the only working one.

Tests: the fail-closed case is replaced by one asserting the /btw text
reaches bridge.prompt, plus a case keeping the agent entry visible in
/help. Also adds the session-scoped de-duplication case — the existing
one runs with no active session, so it never reached
getAgentCommandsForSession and a filter narrowed to the non-session
branch stayed green while a live conversation listed /btw twice.

@qwen-code-dev-bot qwen-code-dev-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.

Reviewed at head 248c78ef.

  • The last round's Critical (R4-1: /btw failing closed on every shipped connection was a regression over the merge base) is fixed at this head exactly as the thread records: interception now happens only behind a bridge.btw capability probe, so unsupported connections let /btw reach the agent like before, and the /help de-dup keeps the agent's entry listed when there is no local handler — both branches pinned by new tests (also closing R4-2's dedup assertion).
  • The handler's own guards read sound: router-target validation before dispatch, one running BTW per session, authorization gating, abortable lifecycle with named-session presentation, and sanitized/attributed delivery back to the chat.
  • All 34 threads across four review rounds are resolved; the remaining items on the bot's list are its own explicitly non-blocking Suggestions (the unbounded-await one was escalated to and accepted by the maintainers in-thread). CI: the only failure on this head is the vscode imageSupport.bundle.test 5000ms timeout — a known contention flake in a package this diff does not touch. Per the channel convention the call is on the review itself.

@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.

Reviewed the full diff (bridge capability + ChannelBase handling + ~700 lines of tests).

What I checked

  • Capability gating: btw? is optional on ChannelAgentBridge; when absent, /btw falls through to the agent as before and /help dedup keeps the agent's entry visible — no behavior change until a bridge implements it.
  • Concurrency: one active side question per session, per-session isolation across sessions, slot released on ack failure / answer delivery failure / route change (identity-checked via activeBtw.get() === request, so stale acks can't cancel a successor).
  • Stale-delivery suppression: /clear, session death, named-task close, bridge replacement (setBridgecancelAllBtw), loop-timeout eviction all abort the controller; isBtwCurrent re-validates target/thread/task before delivery and tolerates group promotion.
  • Security: authorization checked before session resolution and validation; bridge failure details never leak to chat (verified by tests); response sessionId echo mismatch is rejected.
  • Input validation: empty/oversized/attachment cases rejected before any session or bridge call; memory-intent classification bypassed for /btw.
  • CI ubuntu failure is unrelated to this PR: shellAstParser.test.ts CPU-budget flake, imageSupport.bundle.test.ts 5s timeout flake, web-shell MessageList.dom.test.tsx — all pre-existing on main.

LGTM, approving.

@qqqys
qqqys added this pull request to the merge queue Sep 2, 2026
Merged via the queue into QwenLM:main with commit 4f21287 Sep 2, 2026
119 of 122 checks passed
@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Released in v0.23.0.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants