Skip to content

feat(core): remind the model of the active output style every turn - #10282

Open
qqqys wants to merge 21 commits into
QwenLM:mainfrom
qqqys:feat/output-style-turn-reminder
Open

feat(core): remind the model of the active output style every turn#10282
qqqys wants to merge 21 commits into
QwenLM:mainfrom
qqqys:feat/output-style-turn-reminder

Conversation

@qqqys

@qqqys qqqys commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

What this PR does

This injects the per-turn output-style reminder that #9565 rendered but never sent. Whenever a non-default output style is active, every user turn (and every cron-fired turn) now carries a <system-reminder> line of the form Concise output style is active. Be concise: answer first, cut the narration, keep only what the user needs. — the style's own turnReminder when it defines one, otherwise the generic Remember to follow the specific guidelines for this style. The line joins the existing system-reminder block that already carries the date, plan-mode, and arena reminders, so it sits immediately ahead of the newest user text; tool-result turns are untouched, since the reminder only needs to travel with a fresh user message.

The rule that drops the Learning style from headless runs — its hand-off asks the user to write code and waits, which a single-turn run can never answer — moves out of getCoreSystemPrompt into a shared resolveEffectiveOutputStyle() that both the prompt builder and the reminder consult. That keeps the two in step by construction: a session is never reminded about a style its system prompt does not actually carry. The prompt builder's behaviour is unchanged; the existing headless-Learning tests in prompts.test.ts pass as they were.

The reminder text goes through escapeSystemReminderTags() before being wrapped, so a style whose reminder contains a stray </system-reminder> cannot break out of its block. That matters once user- and project-level style files load in a follow-up, because a custom style's turnReminder will be file-supplied text.

Why it's needed

A style lives in the cached system prompt, and the model drifts back to the default voice over a long conversation — an Explanatory session quietly stops explaining, a Concise one starts narrating again. A short reminder that travels with each new user message is what keeps the style in force for the whole session, and it is the last piece of the core layer that #9565 deliberately left for a separate PR: that PR pinned where the style sits in the prompt, this one pins how it is kept alive turn to turn. Both are still unreachable by users until the selection surfaces land, so this stays a no-op for every existing session; it is the second of the slices that lead up to that surface.

Attaching the reminder as a per-turn message rather than re-stating it in the system prompt is also what keeps the cached prompt prefix stable — the style section is written once, and the nudge rides in the volatile part of the request where it costs a few tokens instead of a cache miss.

Reviewer Test Plan

How to verify

From packages/core, run npx vitest run src/core/output-styles.test.ts src/core/prompts.test.ts src/core/client.test.ts — 500 tests pass, 10 of them new. The output style turn reminder block in client.test.ts is the one to read: it asserts the exact reminder string on two consecutive user turns, the generic wording for a style without its own turnReminder, that nothing is added when no style is active, that a ToolResult turn carries no reminder, that Learning is skipped in a headless session and present once isInteractive() is true, and that a reminder containing </system-reminder> is escaped so exactly one closing tag remains. output-styles.test.ts covers resolveEffectiveOutputStyle() across all three interaction modes.

Also worth confirming the negative: with getOutputStyle() returning undefined — every real session today — the request sent to the model is byte-identical to before. The date-reminder and IDE-context tests that assert the full request array are unchanged and still pass.

npm run typecheck --workspace @qwen-code/qwen-code-core, eslint, and prettier --check were run over every changed file.

Evidence (Before & After)

N/A — no user-visible surface; nothing selects a style yet, so no session's request changes on this commit alone.

Tested on

OS Status
🍏 macOS ⚠️ not tested
🪟 Windows ⚠️ not tested
🐧 Linux ✅ tested

Environment (optional)

Linux, Node 22, unit tests only.

Risk & Scope

  • Main risk or tradeoff: one extra short user-role part per turn while a style is active — roughly 25 tokens for the built-in styles. It is added to the volatile part of the request on purpose, so it never touches the cached system-prompt prefix.
  • Not validated / out of scope: no selection surface exists yet, so the reminder has not been observed against a live model. The settings key, --output-style flag, /output-style command, custom .qwen/output-styles/*.md files, and the output_style field on system/init follow in separate PRs. Whether a reminder is also wanted on Steer/Retry/Notification turns can be decided once a style is selectable and observed.
  • Breaking changes / migration notes: none. resolveEffectiveOutputStyle() is a new export; getCoreSystemPrompt keeps its signature and output.

Linked Issues

Follows #9565.

中文说明

这个 PR 做了什么

本 PR 注入了 #9565 已渲染但从未发送的每轮 output-style 提醒。只要有非默认的输出风格生效,每个用户轮(以及每个 cron 触发的轮次)现在都会携带一行 <system-reminder>,形如 Concise output style is active. Be concise: answer first, cut the narration, keep only what the user needs. —— 风格定义了 turnReminder 时用它自己的文案,否则用通用的 Remember to follow the specific guidelines for this style.。这一行加入到已经承载日期、plan-mode 和 arena 提醒的那个 system-reminder 块中,因此紧挨着最新的用户文本;工具结果轮不受影响,因为提醒只需要跟随新的用户消息一起发送。

把 Learning 风格从 headless 运行中剔除的规则 —— 它的交接会请用户写代码然后等待,而单轮运行永远无法回应 —— 从 getCoreSystemPrompt 移入一个共享的 resolveEffectiveOutputStyle(),提示词构建器和提醒两处共同查询它。这样二者在构造上就保持一致:一个会话绝不会被提醒一个其系统提示词实际并不携带的风格。提示词构建器的行为没有变化;prompts.test.ts 中已有的 headless-Learning 测试原样通过。

提醒文本在被包裹之前会经过 escapeSystemReminderTags(),因此一个提醒里含有多余 </system-reminder> 的风格无法逃出它的块。这一点在后续 PR 加载用户级和项目级风格文件后会很重要,因为自定义风格的 turnReminder 将是来自文件的文本。

为什么需要它

风格存在于被缓存的系统提示词中,而模型在长对话里会漂回默认语气 —— Explanatory 会话悄悄不再解释,Concise 会话又开始叙述过程。一条随每条新用户消息一起发送的简短提醒,正是让风格在整个会话中持续生效的手段,也是 #9565 刻意留给单独 PR 的 core 层最后一块:那个 PR 钉死了风格在提示词中的位置,这个 PR 钉死它如何逐轮保持有效。在选择入口落地之前,二者对用户仍不可达,所以对所有既有会话这仍是空操作;这是通向那个入口的第二个切片。

把提醒作为每轮消息附加、而不是在系统提示词里重复声明,也是保持缓存前缀稳定的关键 —— 风格段落只写一次,提醒则在请求的易变部分中传递,代价是几个 token 而不是一次缓存失效。

评审者测试计划

如何验证

packages/core 下运行 npx vitest run src/core/output-styles.test.ts src/core/prompts.test.ts src/core/client.test.ts —— 500 个测试通过,其中 10 个是新增的。值得阅读的是 client.test.ts 中的 output style turn reminder 块:它断言连续两个用户轮上精确的提醒字符串、没有自带 turnReminder 的风格使用通用文案、没有风格生效时不添加任何内容、ToolResult 轮不携带提醒、headless 会话中跳过 Learning 而 isInteractive() 为 true 后出现、以及含有 </system-reminder> 的提醒被转义后恰好只剩一个闭合标签。output-styles.test.ts 覆盖了 resolveEffectiveOutputStyle() 在三种交互模式下的行为。

同样值得确认反面情况:当 getOutputStyle() 返回 undefined 时 —— 也就是今天的每一个真实会话 —— 发送给模型的请求与之前逐字节一致。断言完整请求数组的日期提醒和 IDE 上下文测试没有改动且仍然通过。

对每个改动文件运行了 npm run typecheck --workspace @qwen-code/qwen-code-coreeslintprettier --check

证据(Before & After)

N/A —— 没有用户可见界面;目前没有任何东西选中风格,所以仅凭这个 commit 任何会话的请求都不会变化。

测试环境

操作系统 状态
🍏 macOS ⚠️ 未测试
🪟 Windows ⚠️ 未测试
🐧 Linux ✅ 已测试

环境(可选)

Linux,Node 22,仅单元测试。

风险与影响范围

  • 主要风险或权衡:风格生效期间每轮多一个简短的 user-role 部分 —— 内置风格大约 25 个 token。它被有意加在请求的易变部分,因此绝不触及被缓存的系统提示词前缀。
  • 未验证 / 不在范围内:目前不存在选择入口,因此提醒尚未在真实模型上观察过。settings 键、--output-style 参数、/output-style 命令、自定义 .qwen/output-styles/*.md 文件,以及 system/init 上的 output_style 字段会在各自的后续 PR 中落地。是否也要在 Steer/Retry/Notification 轮上提醒,可以在风格可选并被观察之后再决定。
  • 破坏性改动 / 迁移说明:无。resolveEffectiveOutputStyle() 是新增导出;getCoreSystemPrompt 的签名和输出保持不变。

关联 Issue

承接 #9565

qqqys added 2 commits August 27, 2026 19:41
Every non-default output style now sends its turn reminder as a
<system-reminder> on each user and cron turn, next to the date, plan-mode
and arena reminders. The headless-Learning gate moves into a shared
resolveEffectiveOutputStyle() so the prompt and the reminder can never
disagree about which style is active. Reminder text is escaped before it
is wrapped, so a file-supplied turnReminder cannot close the block.

Claude-Session: https://claude.ai/code/session_01Gk1gryVzWuW58zkBtoBvnM
Hand-written Config mocks that never set a style (client-goal.test.ts)
should not need the interaction-mode accessors, and the default path
should not pay for a mode lookup it does not use.

Claude-Session: https://claude.ai/code/session_01Gk1gryVzWuW58zkBtoBvnM
@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

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

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

@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

Re-run after the autofix rounds and a base update — gate re-confirmed at the new head.

  • Template ✓ — all sections present, bilingual, and Risk & Scope is honest about what remains unvalidated (no live-model observation until a selection surface exists).
  • Problem: a planned feature slice, not a speculative fix. A style lives in the cached system prompt and drifts back to the default voice over a long conversation — Claude Code's changelog records exactly this fix ("Fixed custom, project, and plugin output styles drifting back to the default voice mid-session"). Direction was already established when @wenshao merged feat(core): add the output-style layer to the system prompt #9565, which explicitly deferred this slice to a separate PR.
  • Direction: aligned — the second planned slice toward the selection surface, still a no-op for every session today.
  • Size: touches core paths. 110 production lines (prompts.ts 65, output-styles.ts 24, client.ts 19, environmentContext.ts 2) vs. 349 test lines. Well under every threshold; no maintainer-awareness flag needed.
  • Approach: minimal and structurally right — the Learning/headless rule now lives in one shared resolveEffectiveOutputStyle() that both the prompt builder and the reminder consult, so the two cannot drift by construction. Escaping reuses the existing wrapSystemReminder(). The only drive-by is test-only (write-file.test.ts → unique mkdtemp root), explained by its comment as a fix for stale root-owned dirs EACCES-ing the suite on shared runners.
  • Risk: no high-risk path matches.

Moving on to code review. 🔍

中文说明

autofix 多轮及 base 更新后的重跑——准入结论不变,在新 head 上重新确认。

  • 模板 ✓——各节齐全、中英双语,Risk & Scope 诚实说明了尚未验证的部分(选择入口落地前无法在真实模型上观察)。
  • 问题:这是计划内的功能切片,不是臆测性修复。风格位于被缓存的系统提示词中,长对话里会漂回默认语气——Claude Code 的 changelog 记录过完全相同的修复("Fixed custom, project, and plugin output styles drifting back to the default voice mid-session")。方向已确立:@wenshao 合并的 feat(core): add the output-style layer to the system prompt #9565 明确把本切片留给单独 PR。
  • 方向:对齐——通向选择入口的第二个计划切片,今天对所有会话仍是空操作。
  • 规模:触及核心路径。生产代码 110 行(prompts.ts 65、output-styles.ts 24、client.ts 19、environmentContext.ts 2),测试 349 行。远低于各阈值,无需维护者关注标记。
  • 方案:最小且结构正确——Learning/headless 规则现在收敛到共享的 resolveEffectiveOutputStyle(),提示词构建器和提醒共同查询,构造上不会漂移。转义复用既有 wrapSystemReminder()。唯一顺手改动仅限测试(write-file.test.ts → 唯一 mkdtemp 根目录),注释说明是修复共享 runner 上残留的 root 属主目录导致套件 EACCES 的问题。
  • 风险:未命中高风险路径。

进入代码审查。🔍

Qwen Code · qwen3.8-max

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

@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

Code review

No blockers. What I verified reading the diff at the reviewed commit:

  • Placement matches the claim. The reminder pushes into the same systemReminders block as the date / plan-mode / arena reminders, inside the UserQuery || Cron gate of LlmClient.sendMessageStream, and the block is prepended ahead of the user text — so it lands immediately before the newest user message. ToolResult / Steer / Retry turns carry nothing, and the PR explicitly defers the Steer/Retry/Notification call until a style is selectable and observed.
  • The invariant is pinned by construction. The system-instruction path (getMainSessionBaseSystemPrompt) and the per-turn gate both consult the same resolveMainSessionOutputStyle(config); the new prompts.test.ts matrix asserts "reminds if and only if the prompt carries the style section" across custom-prompt × QWEN_SYSTEM_MD × style × all three interaction modes.
  • The getCoreSystemPrompt refactor is behavior-preserving. Walked isSystemMdActive() against the old inline guard case by case (unset, switch true/false, path, homedir-resolution failure) — identical outcomes, and systemMdResolution has no remaining user outside its block.
  • Scope is main-session only. Forked/subagent runs call the chat directly and bypass LlmClient.sendMessageStream, so the reminder cannot reach a prompt that lacks the style section.
  • No-op today, as promised. Nothing sets outputStyle yet (no settings key, flag, or command — verified in the config and CLI loader side), so the resolver returns undefined in every real session and the outgoing request stays byte-identical; the unchanged full-request-array tests corroborate.
  • Non-blocking nits: the wrapSystemReminder change is export-only visibility; the write-file.test.ts mkdtemp change is unrelated test hygiene — small and justified by its comment.

Test evidence — the PR's own CI (unattended run; nothing executed locally)

At the previous head (fb30e86…) the unit suite Test (ubuntu-latest, Node 22.x) and Integration Tests (no-AK, No Sandbox) were green; web-shell E2E Smoke (ubuntu-latest, Node 22.x) was red (4 of 44 tests). Reading the failure log, I cannot attribute it to this diff:

  • All four failures share one signature: after page.goto(/session/…), [data-web-shell-root] never mounts, then ECONNREFUSED 127.0.0.1:4170 from the vite proxy — the shell root never rendered and the local daemon refused connections. The failing tests (session replay, constrained collapsed groups, github-prs unavailable state, model switching) have zero overlap with output styles.
  • This diff is inert in today's runtime (see "No-op today" above): the only code paths it adds are pure env/config reads returning undefined when no style is set, and the unit + no-AK integration suites that exercise them are green on the same SHA.
  • The branch merged ~27 commits from main that morning — among them two web-shell features (feat(web-shell): add opt-in interactive browser terminal #9984 browser terminal, feat(web-shell): add opt-in composer add menu #10379 composer add menu) and a web-shell fix (fix(web-shell): keep archive out of the sidebar hover slot and block it on running sessions #10302) — while two unrelated PRs running the same check in the same window passed it. The plausible causes are shared self-hosted-runner flakiness or something that landed via the merged main window, not this change. CI is re-running at the reviewed commit below; if web-shell E2E Smoke goes red again there, that points at the main window and deserves its own look.

Unattended CI run, so no local tmux drive-through. There is also nothing user-visible to drive yet — no surface can select a style on this commit — so real-scenario coverage starts mattering once the selection-surface slice lands. A sandboxed @qwen-code /verify run is in flight on this PR and will post its report separately.

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

Check Conclusion
web-shell E2E Smoke (ubuntu-latest, Node 22.x) ❌ failure
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
Secret scan (TruffleHog) ✅ success
Test (ubuntu-latest, Node 22.x) ✅ success

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

中文说明

代码审查

无阻塞项。在受审 commit 上逐行核对:

  • 位置与描述一致。 提醒被推入与日期 / plan-mode / arena 提醒相同的 systemReminders 块,位于 LlmClient.sendMessageStreamUserQuery || Cron 分支内,整块前置在用户文本之前——紧邻最新用户消息。ToolResult / Steer / Retry 轮不携带;PR 明确把 Steer/Retry/Notification 的取舍推迟到风格可选并可观察之后。
  • 不变量由构造保证。 系统指令路径(getMainSessionBaseSystemPrompt)与每轮闸门查询同一个 resolveMainSessionOutputStyle(config);新增的 prompts.test.ts 矩阵在 自定义 prompt × QWEN_SYSTEM_MD × 风格 × 三种交互模式 上断言"提醒当且仅当提示词携带风格段落"。
  • getCoreSystemPrompt 重构行为不变。isSystemMdActive() 与旧的内联守卫逐情形比对(未设置、开关 true/false、路径、homedir 解析失败)——结果完全一致,且 systemMdResolution 在其块外无残留使用。
  • 作用域仅限主会话。 fork/子代理直接调用 chat,绕过 LlmClient.sendMessageStream,提醒不会到达没有风格段落的提示词。
  • 今天确为空操作。 目前没有任何入口设置 outputStyle(无 settings 键、flag 或命令——已在 config 与 CLI 装载侧核实),所有真实会话中解析器返回 undefined,发出的请求逐字节不变;未改动的完整请求数组测试亦佐证。
  • 非阻塞小项:wrapSystemReminder 仅变为导出;write-file.test.ts 的 mkdtemp 改动属无关测试卫生——很小且注释说明了理由。

测试证据——来自 PR 自己的 CI(无人值守运行,本地不执行任何代码)

上一个 head(fb30e86…)上:单元测试与 no-AK 集成测试为绿;web-shell E2E Smoke 红(44 个用例中 4 个失败)。阅读失败日志后,无法归因于本 diff:

  • 四个失败同一签名:page.goto(/session/…)[data-web-shell-root] 始终未挂载,随后 vite 代理报 ECONNREFUSED 127.0.0.1:4170——壳根未渲染、本地 daemon 拒绝连接。失败用例(会话回放、受限折叠组、github-prs 不可用态、模型切换)与 output style 毫无交集。
  • 本 diff 在今天的运行时是惰性的:新增代码路径只是纯环境/配置读取,无风格时返回 undefined;执行这些路径的单元与 no-AK 集成套件在同一 SHA 上为绿。
  • 分支当天上午合入了约 27 个 main 提交——其中含两个 web-shell 功能(feat(web-shell): add opt-in interactive browser terminal #9984 浏览器终端、feat(web-shell): add opt-in composer add menu #10379 作曲器附加菜单)与一个 web-shell 修复(fix(web-shell): keep archive out of the sidebar hover slot and block it on running sessions #10302)——而同窗口两个无关 PR 通过了同一检查。更可能的原因是共享自托管 runner 抖动或经由 main 合入的内容,而非本改动。CI 正在受审 commit 上重跑;若 web-shell E2E Smoke 再度变红,则指向 main 窗口,值得单独排查。

无人值守 CI 运行,故无本地 tmux 实测;且本 commit 上尚无用户可见面(没有任何入口可选风格),真实场景覆盖将在选择入口切片落地后才有意义。本 PR 已有一个沙箱 /verify 运行在进行中,报告将单独发布。

(上方 CI 表格由 finalize 工作流在 CI 结束后原地更新。)

Qwen Code · qwen3.8-max

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

@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

Confidence: 4/5 — a clean, minimal slice that does exactly what the merged design said the next piece would; the points kept back are the unrelated test-hygiene drive-by (justified, harmless) and the inherent fact that the reminder cannot be observed against a live model until a selection surface exists.

Stepping back over the whole picture: the motivation is real — style drift over long sessions is a documented failure mode, and Claude Code shipped this exact fix — and the implementation is the smallest structure that keeps the prompt and the per-turn reminder honest with each other. The negative case is pinned too: with no style selectable today, the outgoing request is byte-identical, and there are tests asserting exactly that. The 24-case "reminds iff the prompt carries the section" matrix is the test I would have asked for. Every one of the 110 production lines is doing a job; if I had to maintain this in six months I'd thank the author, not curse them.

Verdict: approve. CI is still in flight at the reviewed commit (unit suite running, web-shell E2E Smoke not yet started), so approval is deferred until CI lands green on df210f6c0967e413c287d48e04394fd281b31d90; if anything lands red or the head moves, the approval is withheld and the status comment will say so. The previous head's red web-shell E2E Smoke reads as runner or merged-main noise rather than this diff (evidence in the Stage 2 comment) — the re-run on this commit settles it either way.

中文说明

信心:4/5——干净、最小的切片,恰好实现了已合并设计预留的下一块;扣掉的一分来自无关的测试卫生顺手改动(有正当理由、无害),以及一个固有事实:选择入口落地前,无法在真实模型上观察该提醒。

整体回顾:动机真实——长会话中的风格漂移是已被记录失效模式,Claude Code 也上线过完全相同的修复;实现是讓提示词与每轮提醒互相约束的最小结构。反面情形同样被钉死:今天没有任何入口可选风格,发出的请求逐字节不变,且有测试专门断言这一点。24 例"提醒当且仅当提示词携带风格段落"矩阵正是我会要求的测试。110 行生产代码各司其职;六个月后维护它,只会感谢作者。

结论:批准。受审 commit 上 CI 仍在进行(单元测试运行中,web-shell E2E Smoke 尚未开始),因此批准推迟到该 commit 的 CI 全部变绿;若有检查变红或 head 移动,将不批准并在状态评论中说明。上一个 head 上变红的 web-shell E2E Smoke 更像 runner 或合入 main 的噪声而非本 diff(证据见 Stage 2 评论)——本次 commit 的重跑会给出定论。

Qwen Code · qwen3.8-max

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

@qqqys

qqqys commented Aug 27, 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 Aug 27, 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 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.

LGTM, looks ready to ship — CI landed green after the review. ✅

@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. Suggestions are inline.

Not explored to full depth (tool budget reached): "agent 1d": none — the walk completed within budget (6 tool calls)..

Test Plan (not a blocker): src/core/output-styles.test.tsno such file or directory; src/core/prompts.test.tsno such file or directory; src/core/client.test.tsno such file or directory; 500 tests pass — this review observed 22043, 1770, 25160, 1667, 605, 4331, 639 passed.

中文说明

已审查。 建议见行内评论。

未探索到全部深度(达到工具调用预算):"agent 1d"none — the walk completed within budget (6 tool calls).

Test Plan(非阻断):src/core/output-styles.test.tsno such file or directory; src/core/prompts.test.tsno such file or directory; src/core/client.test.tsno such file or directory; 500 tests pass — this review observed 22043, 1770, 25160, 1667, 605, 4331, 639 passed

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

Comment thread packages/core/src/core/client.ts Outdated
Comment thread packages/core/src/core/client.ts Outdated
Comment thread packages/core/src/core/client.ts
@qwen-code-dev-bot

qwen-code-dev-bot commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

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

中文说明

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

qqqys added 2 commits August 27, 2026 14:10
A custom systemPrompt routes through getCustomSystemPrompt() and a
QWEN_SYSTEM_MD override replaces the base prompt verbatim — neither
carries an output-style section, yet the per-turn reminder still fired
for them. Gate the reminder on the same decision that puts the style
section into the prompt: a shared isSystemMdActive() in prompts.ts,
consulted by getCoreSystemPrompt() and the reminder site alike, plus
the existing getSystemPrompt() override check.

Also route the reminder envelope through the centralized
wrapSystemReminder() instead of a third inline copy, and pin the
intended cron-turn inclusion with a test.
A fixed /tmp/qwen-code-test-root breaks whenever a prior run by another
user (e.g. a sandboxed root run on a shared runner) leaves the directory
behind: mkdirSync(recursive) no-ops on the foreign directory and every
write into it EACCESes. Reproduced the 80 deterministic-gate failures
locally with a stale root-owned directory present; mkdtempSync isolates
each run from any leftover state.
@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 轮)。改动内容与我反驳保留之处如下:

Review feedback addressed — PR #10282 (round 3, same-run verification repair)

The previous commit b31d8fe0fa was REJECTED by the deterministic gate: tests failed in packages/core — 80 failures in src/tools/write-file.test.ts, all EACCES: permission denied on /tmp/qwen-code-test-root/.... Per the same-run verification repair instruction, that commit is kept untouched and this round adds one verified follow-up commit, fix(core): give write-file tests a unique per-run root dir (5a45c98), which repairs the rejection. No conflicts (--conflict false, no merge performed).

Deterministic rejection — diagnosis and fix

Evidence chain:

  1. Gate log: every failure is an EACCES writing into /tmp/qwen-code-test-root/... (e.g. open '/tmp/qwen-code-test-root/dropped.bin', symlink ... -> '/tmp/qwen-code-test-root/output'), raised in the tests' own fixture setup, before the code under test runs.
  2. Source: write-file.test.ts used a fixed shared root — const rootDir = path.resolve(os.tmpdir(), 'qwen-code-test-root'). The beforeEach runs mkdirSync(rootDir, { recursive: true }), which silently no-ops when the directory already exists even if it is owned by another user; every subsequent write into it then fails EACCES.
  3. Environment: this machine (same runner pool) carries exactly such a leftover — /tmp/qwen-code-test-root owned by root:root, mode 755, while the tests run as uid 1000. A stale directory left by any root-privileged run (sandboxed jobs share /tmp) permanently breaks every later non-root run of this suite.
  4. Why the file ran at all: origin/main advanced past the branch's fork point with 435199716b fix(artifacts): refresh updatedAt when artifact content changes (#9929), which touched this file, so the gate's vitest run --changed origin/main selects it even though the PR never did.

Local reproduction (exact gate failure): at the pre-round HEAD (b31d8fe0fa), cd packages/core && npx vitest run src/tools/write-file.test.ts with the stale root-owned directory present → Test Files 1 failed | Tests 80 failed | 3 passed (83), same failure entries ([44/132][46/132]) as the gate log.

Fix (minimal, test-only): the suite now gets a unique per-run root — fs.mkdtempSync(path.join(os.tmpdir(), 'qwen-code-test-root-')) — plus a three-line comment stating why a fixed path is unsafe there. A directory the test process creates itself is always owned by the running user, so leftover state from any other user or job can no longer break the run. No assertion, snapshot, or other file depends on the literal qwen-code-test-root string (repo-wide grep: the fixture line was the only occurrence), and the existing beforeEach/afterEach create/cleanup lifecycle is unchanged.

Footprint note: the fix touches packages/core/src/tools/, an area this PR never touched before. It is required by the same-run verification repair instruction — the rejection lives in a file the gate pulls in via --changed origin/main, and nothing inside the PR's own files can fix it. The change is one fixture line plus a comment, in a test file only.

Inline findings (re-verified resolved in the preserved commit b31d8fe)

All three findings were fixed in code by the previous round's commit, which this round keeps intact; each was re-verified against current HEAD:

  • [rc:3872041263] R1-1 — the reminder is now gated on the same decision that puts the style section into the prompt: activeStyle && !this.config.getSystemPrompt() && !isSystemMdActive() (client.ts), with the shared isSystemMdActive() predicate in prompts.ts consulted by both the prompt builder and the reminder site. Witnesses present: stays silent when a custom system prompt carries no style section, stays silent while QWEN_SYSTEM_MD replaces the base prompt, still reminds when QWEN_SYSTEM_MD is explicitly disabled.
  • [rc:3872041268] R1-2 — wrapSystemReminder() is exported from environmentContext.ts and reused at the reminder site in client.ts; the inline third copy is gone.
  • [rc:3872041274] R1-3 — reminds on cron-fired turns is present in the output style turn reminder block, pinning the UserQuery || Cron guard.

All witnesses are green in this round's focused run (651 passed across the five touched test files).

Mutation probes

Probe Expected witness Result
Revert the fixture to the fixed path.resolve(os.tmpdir(), 'qwen-code-test-root') (stale root-owned directory still present) the suite fails with EACCES exactly as in the gate Test Files 1 failed with 80 EACCES failures, as expected; fix then restored byte-identically (diff verified against the saved patch)
Round-2 probes for R1-1/R1-2/R1-3 (gate drop, UserQuery-only gate, escape drop, isSystemMdActive stuck true) recorded in the round-2 summary; fixes untouched this round unchanged code, re-verified green this round

Verification

  • cd packages/core && npx vitest run src/tools/write-file.test.ts — pre-fix (HEAD b31d8fe, stale dir present): 80 failed | 3 passed (reproduction of the gate failure); post-fix: 83 passed (stale dir still present)
  • cd packages/core && npx vitest run src/tools/write-file.test.ts src/core/client.test.ts src/core/prompts.test.ts src/core/output-styles.test.ts src/core/environmentContext.test.ts — 5 files, 651 passed
  • npm run build — passed (exit 0)
  • npm run typecheck — passed (exit 0)
  • npm run lint — passed (exit 0)
  • npx prettier --check packages/core/src/tools/write-file.test.ts — passed
  • Integration tests after npm run bundle — not run: this round changes only a test fixture; no CLI-observable behavior is affected
  • npm run generate:settings-schema — not applicable: no settings source changed
中文说明

已处理的评审反馈 — PR #10282(第 3 轮,同轮验证修复)

上一个提交 b31d8fe0fa 被确定性验证门禁拒绝:tests failed in packages/core —— src/tools/write-file.test.ts 中 80 个测试失败,全部是对 /tmp/qwen-code-test-root/...EACCES: permission denied 错误。按照"同轮验证修复"(same-run verification repair)指令,该提交原样保留,本轮追加一个已验证的后续提交 fix(core): give write-file tests a unique per-run root dir(5a45c98916)来修复该拒绝项。无冲突(--conflict false,未执行合并)。

确定性拒绝项 — 诊断与修复

证据链:

  1. 门禁日志:所有失败都是向 /tmp/qwen-code-test-root/... 写入时的 EACCES(例如 open '/tmp/qwen-code-test-root/dropped.bin'symlink ... -> '/tmp/qwen-code-test-root/output'),且都发生在测试自身的 fixture 准备阶段,尚未运行到被测代码。
  2. 源码:write-file.test.ts 使用了固定的共享根目录 —— const rootDir = path.resolve(os.tmpdir(), 'qwen-code-test-root')beforeEach 执行 mkdirSync(rootDir, { recursive: true }),当目录已存在时该调用静默地不做任何事——即使目录属于其他用户;之后所有写入都会 EACCES 失败。
  3. 环境:本机(同一 runner 池)恰好存在这样的残留 —— /tmp/qwen-code-test-root 属主为 root:root、权限 755,而测试以 uid 1000 运行。任何 root 权限运行(沙箱任务共享 /tmp)留下的残留目录都会永久破坏后续所有非 root 用户对该套件的运行。
  4. 该文件为何会被运行:origin/main 在分支 fork 点之后合入了 435199716b fix(artifacts): refresh updatedAt when artifact content changes (#9929),该提交改动了此文件,因此门禁的 vitest run --changed origin/main 会选中它——尽管本 PR 从未改过它。

本地复现(与门禁失败完全一致): 在第 2 轮提交(b31d8fe0fa)上,残留 root 属主目录存在时运行 cd packages/core && npx vitest run src/tools/write-file.test.tsTest Files 1 failed | Tests 80 failed | 3 passed (83),失败条目([44/132][46/132])与门禁日志相同。

修复(最小化,仅测试): 套件现在使用每次运行唯一的根目录 —— fs.mkdtempSync(path.join(os.tmpdir(), 'qwen-code-test-root-')) —— 并加了三行注释说明固定路径在此处为何不安全。测试进程自己创建的目录一定属于当前运行用户,因此任何其他用户或任务留下的残留状态都无法再破坏运行。全仓 grep 确认没有任何断言、快照或其他文件依赖字面量 qwen-code-test-root 字符串(fixture 这一行是唯一出现处),既有的 beforeEach/afterEach 创建/清理生命周期保持不变。

足迹说明: 本修复改动了 packages/core/src/tools/——本 PR 此前从未触碰过的区域。这是"同轮验证修复"指令所要求的:拒绝项位于门禁通过 --changed origin/main 拉入的文件中,PR 自身文件范围内的任何改动都无法修复它。改动仅为测试文件中的一行 fixture 加一段注释。

行内发现(已在保留的提交 b31d8fe 中解决并复核)

三条发现均已在上一轮的提交中从代码上修复,本轮完整保留该提交,并逐条对照当前 HEAD 复核:

  • [rc:3872041263] R1-1 —— 提醒现在与"风格段落是否进入提示词"走同一判定:activeStyle && !this.config.getSystemPrompt() && !isSystemMdActive()(client.ts),prompts.ts 中的共享谓词 isSystemMdActive() 同时被提示词构建器和提醒注入点引用。见证测试齐备:stays silent when a custom system prompt carries no style sectionstays silent while QWEN_SYSTEM_MD replaces the base promptstill reminds when QWEN_SYSTEM_MD is explicitly disabled
  • [rc:3872041268] R1-2 —— wrapSystemReminder() 已从 environmentContext.ts 导出,并在 client.ts 的提醒注入点复用;内联的第三份副本已移除。
  • [rc:3872041274] R1-3 —— output style turn reminder 块中已有 reminds on cron-fired turns,钉住 UserQuery || Cron 门控。

所有见证测试在本轮聚焦运行中为绿(五个改动的测试文件共 651 个通过)。

变异探针

探针 预期见证 结果
把 fixture 还原为固定的 path.resolve(os.tmpdir(), 'qwen-code-test-root')(残留 root 属主目录仍在) 套件以与门禁一致的 EACCES 失败 Test Files 1 failed,80 个 EACCES 失败,符合预期;随后逐字节还原修复(diff 与保存的补丁比对一致)
第 2 轮针对 R1-1/R1-2/R1-3 的探针(移除门控、仅 UserQuery 门控、去掉转义、isSystemMdActive 恒真) 已记录于第 2 轮总结;相关修复本轮未改动 代码未变,本轮复核为绿

验证

  • cd packages/core && npx vitest run src/tools/write-file.test.ts —— 修复前(HEAD b31d8fe,残留目录存在):80 失败 | 3 通过(复现门禁失败);修复后:83 通过(残留目录仍存在)
  • cd packages/core && npx vitest run src/tools/write-file.test.ts src/core/client.test.ts src/core/prompts.test.ts src/core/output-styles.test.ts src/core/environmentContext.test.ts —— 5 个文件,651 个通过
  • npm run build —— 通过(exit 0)
  • npm run typecheck —— 通过(exit 0)
  • npm run lint —— 通过(exit 0)
  • npx prettier --check packages/core/src/tools/write-file.test.ts —— 通过
  • npm run bundle 后的集成测试 —— 未运行:本轮仅改动测试 fixture,不涉及任何 CLI 可观测行为
  • npm run generate:settings-schema —— 不适用:未改动任何 settings 源

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

Reviewed. Suggestions are inline.

Test Plan (not a blocker): src/core/output-styles.test.tsno such file or directory; src/core/prompts.test.tsno such file or directory; src/core/client.test.tsno such file or directory; 500 tests pass — this review observed 22047, 1770, 25164, 1667, 605, 4331, 639 passed.

中文说明

已审查。 建议见行内评论。

Test Plan(非阻断):src/core/output-styles.test.tsno such file or directory; src/core/prompts.test.tsno such file or directory; src/core/client.test.tsno such file or directory; 500 tests pass — this review observed 22047, 1770, 25164, 1667, 605, 4331, 639 passed

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

Comment thread packages/core/src/core/client.ts Outdated
…s.ts

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

Review response — PR #10282 (round: newer than 2026-08-27T13:15:23Z)

Commit: b2dc15bbf5refactor(core): centralize the turn-reminder style decision in prompts.ts

Feedback points and decisions

[rc:3873558153] R1-1 (Suggestion, fix-induced): the reminder gate centralises only halfway — Implemented.

The finding is correct: the round-1 gate in client.ts re-derived by hand the composition the prompt builders already embody (custom systemPrompt → no style section, QWEN_SYSTEM_MD → no style section, headless + Learning → no style), so the invariant "a session is never reminded about a style its prompt does not carry" was documented but not enforced as one decision, and nothing could catch one-sided drift because client.test.ts mocked the prompt builders.

Changes:

  • Added resolveMainSessionOutputStyle(config) to prompts.ts — the single decision both consumers now consult (custom prompt or QWEN_SYSTEM_MD → none; otherwise resolveEffectiveOutputStyle(style, resolveInteractionMode(config))). Structural config type, same pattern as resolveInteractionMode.
  • Moved getMainSessionBaseSystemPrompt (and its MainSessionPromptConfig type) from client.ts to prompts.ts; it now passes the resolver's result into getCoreSystemPrompt. Package export surface is unchanged (index.ts star-exports both modules); the CLI /context consumer is untouched and its tests pass.
  • The gate in client.ts reduces to const outputStyle = resolveMainSessionOutputStyle(this.config); (net-13 lines there).
  • Added the equivalence test the invariant claims, in prompts.test.ts: for the full matrix of (custom prompt × QWEN_SYSTEM_MD × style {none, Concise, Learning} × session {interactive, headless, acp}) — 36 named cases — the reminder decision equals whether getMainSessionBaseSystemPrompt(config) contains an # Output Style: section, and the base routing itself is pinned (custom text verbatim / default identity). Plus 3 cases pinning that getMainSessionBaseSystemPrompt renders the interaction mode the config resolves to.
  • client.test.ts now mocks getMainSessionBaseSystemPrompt as the prompt-layer handle. The old wiring tests asserting getCoreSystemPrompt call args (3 mode cases + 1 style case) were removed: they pinned wiring against a mocked prompt layer and can never observe drift — exactly the finding's complaint. Their coverage survives, stronger, in named prompt-layer tests: resolveInteractionMode suite, "aligns the system prompt with {interactive,headless,acp} mode", the new "renders the %s interaction mode" cases, the "outputStyle parameter" suite, and the 36-case equivalence matrix. The client-side contract ("hand the live config to the prompt layer") is pinned by a replacement test.
  • client-goal.test.ts hand-rolled config gained the three getters the resolver now always consults (getSystemPrompt, getExperimentalZedIntegration, isInteractive); the old gate short-circuited before them.

[rv:5042992550] Review body (COMMENTED): no action beyond the inline finding. The Test Plan note (src/core/*.test.ts — no such file) is a path slip in the review's own plan: the files live at packages/core/src/core/*.test.ts; it is explicitly non-blocking.

Failed checks: all CANCELLED (workflow run cancelled, not real failures). No local action; CI re-runs after the push.

Mutation probes (each applied, focused suite run, then restored)

Probe (guard removed/negated) Expected witness Result
Drop config.getSystemPrompt() || in the resolver equivalence custom=yes cases + client custom-prompt reminder test 6 failed (red) ✓
Drop || isSystemMdActive() in the resolver equivalence systemMd=true cases + client QWEN_SYSTEM_MD tests 6 failed (red) ✓
Gate bypasses the resolver (this.config.getOutputStyle()) client reminder tests (custom/systemMd/headless-Learning) 3 failed (red) ✓
getMainSessionBaseSystemPrompt ignores the override branch equivalence custom cases (toContain(customPrompt) / iff) 18 failed (red) ✓
Hardcode 'interactive' mode in getMainSessionBaseSystemPrompt new mode-witness cases (headless, acp) 2 failed (red) ✓

After each restore the focused suite returned to green (49 passed).

Note: getMainSessionBaseSystemPrompt passing the resolver's result (instead of the raw style) into getCoreSystemPrompt is behaviorally identical by construction (the internal resolution is idempotent), so it is structural centralisation, not a behavioral guard — no probe applies.

Diff growth

This round: source +39/−92 (net −53 in client.ts/prompts.ts production code), tests +172/−25 — the round is net-subtractive on source. Window remains far under budget.

Verification

Commands actually run and their results:

  • npm run build — passed (exit 0)
  • npm run typecheck — passed (exit 0)
  • npm run lint — passed (exit 0)
  • npx prettier --check on the five changed files — passed (after --write on client.test.ts)
  • cd packages/core && npx vitest run src/core/prompts.test.ts src/core/output-styles.test.ts src/core/client.test.ts src/core/client-goal.test.ts src/core/environmentContext.test.ts src/core/prompt-tool-examples.test.ts — 6 files, 628 passed
  • cd packages/cli && npx vitest run src/ui/commands/contextCommand.test.ts — 18 passed (exercises the moved export through the rebuilt core dist)
  • Mutation probes: 5 probes, each red with the guard removed, green after restore (see table above)
中文说明

审查回应 — PR #10282(本轮:2026-08-27T13:15:23Z 之后的新反馈)

提交:b2dc15bbf5refactor(core): centralize the turn-reminder style decision in prompts.ts

反馈点与处理决定

[rc:3873558153] R1-1(Suggestion,修复引入):提醒门禁只做了一半的集中化 —— 已实现。

该发现是对的:第 1 轮在 client.ts 中加入的门禁手工重新拼装了提示词构建器已经体现的组合(自定义 systemPrompt → 无风格段落、QWEN_SYSTEM_MD → 无风格段落、headless + Learning → 无风格),因此"一个会话绝不会被提醒一个其提示词并不携带的风格"这一不变量只是被写了下来、并没有作为一个统一决策被强制执行;而且由于 client.test.ts mock 了提示词构建器,任何单侧漂移都无法被捕获。

改动内容:

  • prompts.ts 中新增 resolveMainSessionOutputStyle(config) —— 两个使用者现在共同咨询的唯一决策(自定义提示词或 QWEN_SYSTEM_MD → 无;否则 resolveEffectiveOutputStyle(style, resolveInteractionMode(config)))。采用结构化配置类型,与 resolveInteractionMode 同一模式。
  • getMainSessionBaseSystemPrompt(及其 MainSessionPromptConfig 类型)从 client.ts 移到 prompts.ts;它现在把该解析器的结果传给 getCoreSystemPrompt。包的导出面不变(index.ts 对两个模块都是星号导出);CLI /context 使用方未改动且其测试通过。
  • client.ts 中的门禁简化为 const outputStyle = resolveMainSessionOutputStyle(this.config);(该文件净减 13 行)。
  • prompts.test.ts 中加入该不变量所声称的等价性测试:对(自定义提示词 × QWEN_SYSTEM_MD × 风格 {无, Concise, Learning} × 会话 {interactive, headless, acp})的完整矩阵 —— 36 个具名用例 —— 提醒决策等于 getMainSessionBaseSystemPrompt(config) 是否包含 # Output Style: 段落,并且基础提示词的路由本身也被钉住(自定义文本原样呈现 / 默认身份句)。另有 3 个用例钉住 getMainSessionBaseSystemPrompt 会渲染配置所解析出的交互模式。
  • client.test.ts 现在把 getMainSessionBaseSystemPrompt 作为提示词层的 mock 句柄。原先断言 getCoreSystemPrompt 调用参数的接线测试(3 个模式用例 + 1 个风格用例)已删除:它们只是把接线钉在一个被 mock 的提示词层上、永远观察不到漂移 —— 这正是该发现指出的问题。其覆盖以更强的形式存活在具名的提示词层测试中:resolveInteractionMode 套件、"aligns the system prompt with {interactive,headless,acp} mode"、新增的 "renders the %s interaction mode" 用例、"outputStyle parameter" 套件,以及 36 用例的等价性矩阵。客户端侧的契约("把活的 config 交给提示词层")由一个替代测试钉住。
  • client-goal.test.ts 手工构造的 config 补充了解析器现在总会咨询的三个 getter(getSystemPromptgetExperimentalZedIntegrationisInteractive);旧门禁在触达它们之前就已短路。

[rv:5042992550] 审查正文(COMMENTED):除行内发现外无需处理。 其中 Test Plan 备注(src/core/*.test.ts — 文件不存在)是审查自身计划里的路径笔误:文件实际位于 packages/core/src/core/*.test.ts;且已明确标注为非阻断。

失败的检查:全部为 CANCELLED(工作流运行被取消,并非真实失败)。本地无需处理;推送后 CI 会重跑。

变异探针(逐一应用、运行聚焦套件、再还原)

探针(移除/取反的守卫) 预期见证 结果
删除解析器中的 config.getSystemPrompt() || 等价性 custom=yes 用例 + 客户端自定义提示词提醒测试 6 个失败(红)✓
删除解析器中的 || isSystemMdActive() 等价性 systemMd=true 用例 + 客户端 QWEN_SYSTEM_MD 测试 6 个失败(红)✓
门禁绕过解析器(this.config.getOutputStyle() 客户端提醒测试(自定义/systemMd/headless-Learning) 3 个失败(红)✓
getMainSessionBaseSystemPrompt 忽略覆盖分支 等价性自定义用例(toContain(customPrompt) / 当且仅当) 18 个失败(红)✓
getMainSessionBaseSystemPrompt 中硬编码 'interactive' 模式 新的模式见证用例(headless、acp) 2 个失败(红)✓

每次还原后聚焦套件恢复绿色(49 通过)。

说明:getMainSessionBaseSystemPrompt 把解析器的结果(而非原始风格)传入 getCoreSystemPrompt 在构造上行为完全等价(内部解析是幂等的),因此它是结构性集中而非行为守卫 —— 不适用探针。

差异增长

本轮:源码 +39/−92(生产代码净 −53),测试 +172/−25 —— 本轮在源码上是净缩减的。窗口总量仍远低于预算。

验证

实际运行的命令及结果:

  • npm run build — 通过(退出码 0)
  • npm run typecheck — 通过(退出码 0)
  • npm run lint — 通过(退出码 0)
  • 对五个改动文件运行 npx prettier --check — 通过(client.test.ts 经 --write 修正后)
  • cd packages/core && npx vitest run src/core/prompts.test.ts src/core/output-styles.test.ts src/core/client.test.ts src/core/client-goal.test.ts src/core/environmentContext.test.ts src/core/prompt-tool-examples.test.ts — 6 个文件,628 通过
  • cd packages/cli && npx vitest run src/ui/commands/contextCommand.test.ts — 18 通过(通过重建后的 core dist 验证了被移动函数的导出)
  • 变异探针:5 个探针,移除守卫时均为红、还原后均为绿(见上表)

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

Partially reviewed — gaps disclosed. Suggestions are inline.

Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.

Test Plan (not a blocker): src/core/output-styles.test.tsno such file or directory; src/core/prompts.test.tsno such file or directory; src/core/client.test.tsno such file or directory; 500 tests pass — this review observed 22083, 1770, 25150, 1667, 605, 4331, 639 passed.

Convergence: round 3 posted 2 inline comment(s), 2 of them reported for the first time; the previous round posted 1 (1 new). The rate of new findings is not falling. 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. No Critical finding is open on this round, so merging and moving the remaining Suggestion threads to a follow-up issue is available as an ending — a merged pull request cannot diverge further. (Observation only — nothing was withheld from this review because of this observation.)

中文说明

仅完成部分审查,审查缺口已披露。 建议见行内评论。

未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。

Test Plan(非阻断):src/core/output-styles.test.tsno such file or directory; src/core/prompts.test.tsno such file or directory; src/core/client.test.tsno such file or directory; 500 tests pass — this review observed 22083, 1770, 25150, 1667, 605, 4331, 639 passed

收敛情况:第 3 轮发布了 2 条行内评论,其中 2 条是首次提出;上一轮发布了 1 条(其中 1 条首次提出)。新发现的产出速度没有下降。把剩余修复攒成一批、验证后再推送,或将本 PR 的评审降到 --severity-floor critical,可以避免循环反复推导同一组发现。本轮没有未决的 Critical,因此"合入后把剩余 Suggestion 线程转到后续 issue"是一个可选的结束方式——已合入的 PR 不会继续发散。(仅为观察——本轮评审未因此扣留任何内容。)

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

Comment thread packages/core/src/core/client.test.ts Outdated
Comment thread packages/core/src/core/prompts.ts Outdated
…rding

The prompts.test.ts matrix only asserted that a custom systemPrompt
override appears in the rendered prompt, never that it replaces the
default base — and the config.getModel() forwarding in
getMainSessionBaseSystemPrompt had no witness after the client-side
assertions moved to the prompt layer. Both mutants (layering the
override on the base; dropping the model forward) shipped green in a
scratch probe. Add the replacement assertion and an end-to-end
coder-model case; each now kills its mutant.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@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 review round — PR #10282 (round addressing feedback at head b2dc15bbf5)

No --conflict (false): origin/main was not merged. No Critical findings were open this round; both actionable items were automated-reviewer Suggestions about test pins lost when coverage moved from client.test.ts to prompts.test.ts in an earlier round. Both were reproduced with mutation probes before implementation and are now resolved in code.

Feedback points and dispositions

[rc:3875343795] R3-1 — Suggestion — RESOLVED. The matrix in prompts.test.ts ('reminds if and only if the prompt carries the style section') asserted only that a custom systemPrompt override appears in the rendered prompt (toContain(customPrompt)), never that it replaces the default base — so the comment in client.test.ts claiming "Routing the override to the custom base is pinned by prompts.test.ts" overstated the coverage.

  • Reproduction (before the fix): mutated getMainSessionBaseSystemPrompt to layer the override instead of replacing it (getCoreSystemPrompt(overrideSystemPrompt, config.getModel())) — the suite stayed green at 148/148, and a direct probe rendered CONTAINS_DEFAULT_IDENTITY=true, FIRST_120="You are Qwen Code, an interactive CLI agent developed by Alibaba Group, specializing in software engineering tasks. Your", confirming --system-prompt users would silently get the default identity above their override under that regression.
  • Fix: added expect(prompt).not.toContain('You are Qwen Code'); to the customPrompt branch of the matrix, mirroring the existing QWEN_SYSTEM_IDENTITY_MD case. With the assertion in place the same mutant turns exactly the nine custom=yes / systemMd=off matrix rows red (9 failed | 140 passed); restored code stays green at 149/149. The client.test.ts comment is now accurate as written, so no comment edit was needed.

[rc:3875343803] R3-3 — Suggestion — RESOLVED. The config.getModel() forwarding in the moved getMainSessionBaseSystemPrompt lost its only test pin when the toHaveBeenCalledWith(undefined, 'test-model', ...) assertion was deleted; the matrix's getModel: () => 'test-model' cannot discriminate because 'test-model' selects no prompt variant.

  • Reproduction (before the fix): mutated the forwarding to undefinedprompts.test.ts + prompt-tool-examples.test.ts + client-goal.test.ts stayed green at 172/172, so a one-line regression would ship coder/vl models the generic tool-call examples with nothing failing.
  • Fix: added it('forwards the config model to the base prompt') in the same describe block — a config whose getModel() returns 'qwen3-coder-7b' exercised end to end through getMainSessionBaseSystemPrompt, asserting the coder XML marker '<function=run_shell_command>'. With the case in place the same mutant fails exactly that test (1 failed | 148 passed of 149); restored code stays green.

Review-body disclosures (rv:5045067304, informational — no action): the skipped "Integration Tests (CLI, No Sandbox)" CI job and the test-plan path mismatches are review-harness disclosures, not findings; this round changed only a unit-test file and is fully covered by the focused Vitest runs below. The convergence observation (no open Critical; batching remaining fixes) is consistent with what this round did — both remaining Suggestions are now resolved in the same commit.

Changes

  • packages/core/src/core/prompts.test.ts (+12 lines, test-only): one replacement assertion in the existing matrix + one new end-to-end model-forwarding case. No source changes, no comment edits, nothing else touched.

Mutation probe record (witness verification)

Probe Target Pre-fix result Post-fix result
A: override branch → getCoreSystemPrompt(overrideSystemPrompt, config.getModel()) R3-1 pin suite green (148/148) — missing pin confirmed 9 failed | 140 passed (exactly the custom=yes / systemMd=off rows)
B: config.getModel()undefined R3-3 pin 172/172 green across prompts/prompt-tool-examples/client-goal 1 failed | 148 passed (exactly the new forwarding test)

Both mutants were reverted after each probe; the final committed tree is green.

Verification

All commands actually run this round, in order:

  • Baseline npx vitest run src/core/prompts.test.ts (packages/core) — 148 passed (pre-fix baseline)
  • Mutant A vs pre-fix suite — 148 passed (reproduced missing pin), rendered-prompt probe confirmed default identity survives
  • Mutant B vs pre-fix suite (prompts.test.ts + prompt-tool-examples.test.ts + client-goal.test.ts) — 172 passed (reproduced missing pin)
  • npx vitest run src/core/prompts.test.ts with fixes — 149 passed
  • Mutant A vs fixed suite — 9 failed | 140 passed (witness kills the mutant); mutant reverted
  • Mutant B vs fixed suite — 1 failed | 148 passed (witness kills the mutant); mutant reverted
  • npx vitest run src/core/prompts.test.ts src/core/client.test.ts src/core/client-goal.test.ts src/core/output-styles.test.ts src/tools/write-file.test.ts (packages/core) — 646 passed (5 files)
  • npm run build — passed
  • npm run typecheck — passed
  • npm run lint — passed

Integration tests were not run: the round is test-only and the touched behavior is fully exercised by the unit suite. No settings source changed, so npm run generate:settings-schema was not required.

中文说明

Autofix 审查轮次 — PR #10282(针对 head b2dc15bbf5 上的反馈)

--conflictfalse):未合并 origin/main。本轮没有未决的 Critical;两个可操作项均为自动审查器的 Suggestion,关于早前某轮把覆盖从 client.test.ts 迁移到 prompts.test.ts 时丢失的测试钉子。两者都先通过变异探测复现,然后才实施修复,目前均已在代码中解决。

反馈点及处置

[rc:3875343795] R3-1 — Suggestion — 已解决。 prompts.test.ts 中的矩阵('reminds if and only if the prompt carries the style section')只断言了自定义 systemPrompt 覆盖会出现在渲染出的提示词中(toContain(customPrompt)),从未断言它替换了默认基础提示词——因此 client.test.ts 中那句 "Routing the override to the custom base is pinned by prompts.test.ts" 注释夸大了实际覆盖。

  • 复现(修复前):把 getMainSessionBaseSystemPrompt 变异为叠加覆盖而非替换(getCoreSystemPrompt(overrideSystemPrompt, config.getModel()))——套件仍全绿(148/148);直接探测渲染结果得到 CONTAINS_DEFAULT_IDENTITY=trueFIRST_120="You are Qwen Code, an interactive CLI agent developed by Alibaba Group, specializing in software engineering tasks. Your",证实该回归下 --system-prompt 用户会在自己的覆盖之上悄悄收到默认身份提示词。
  • 修复:在矩阵的 customPrompt 分支中加入 expect(prompt).not.toContain('You are Qwen Code');,参照已有的 QWEN_SYSTEM_IDENTITY_MD 用例。加上该断言后,同一变异恰好让九个 custom=yes / systemMd=off 矩阵行变红(9 failed | 140 passed);恢复后的代码保持 149/149 全绿。client.test.ts 中的注释照原文即成立,因此无需修改注释。

[rc:3875343803] R3-3 — Suggestion — 已解决。 迁移后的 getMainSessionBaseSystemPromptconfig.getModel() 的转发失去了唯一的测试钉子(toHaveBeenCalledWith(undefined, 'test-model', ...) 断言被删除);矩阵里的 getModel: () => 'test-model' 无法区分差异,因为 'test-model' 不会选中任何提示词变体。

  • 复现(修复前):把转发变异为 undefined——prompts.test.ts + prompt-tool-examples.test.ts + client-goal.test.ts 仍全绿(172/172),因此一行回归就会让 coder/vl 模型在没有任何测试失败的情况下收到通用的 tool-call 示例。
  • 修复:在同一 describe 块新增 it('forwards the config model to the base prompt')——令配置的 getModel() 返回 'qwen3-coder-7b',端到端经过 getMainSessionBaseSystemPrompt 演练,断言渲染结果包含 coder XML 标记 '<function=run_shell_command>'。加上该用例后,同一变异恰好让该测试失败(1 failed | 148 passed,共 149);恢复后的代码保持全绿。

审查正文披露(rv:5045067304,仅信息性——无需行动): 被跳过的 "Integration Tests (CLI, No Sandbox)" CI 任务与测试计划路径不匹配属于审查工具自身的披露,不是发现项;本轮只改了一个单元测试文件,下面的聚焦 Vitest 运行已完全覆盖。关于收敛的观察(无未决 Critical;建议攒批修复)与本轮做法一致——剩余的两个 Suggestion 已在同一提交中全部解决。

变更内容

  • packages/core/src/core/prompts.test.ts(+12 行,纯测试):在既有矩阵中加入一条"替换"断言,外加一个新的端到端模型转发用例。无源码改动、无注释改动,未触碰其他任何内容。

变异探测记录(见证验证)

探测 目标 修复前结果 修复后结果
A:覆盖分支 → getCoreSystemPrompt(overrideSystemPrompt, config.getModel()) R3-1 钉子 套件全绿(148/148)——确认缺钉子 9 failed | 140 passed(恰好是 custom=yes / systemMd=off 各行)
B:config.getModel()undefined R3-3 钉子 prompts/prompt-tool-examples/client-goal 共 172/172 全绿 1 failed | 148 passed(恰好是新的转发测试)

两个变异在每次探测后均已还原;最终提交的代码树为全绿。

验证

本轮实际依次执行的命令:

  • 基线 npx vitest run src/core/prompts.test.ts(packages/core)— 148 通过(修复前基线)
  • 变异 A 对修复前套件 — 148 通过(复现缺失的钉子),渲染探测确认默认身份仍然存在
  • 变异 B 对修复前套件(prompts.test.ts + prompt-tool-examples.test.ts + client-goal.test.ts)— 172 通过(复现缺失的钉子)
  • npx vitest run src/core/prompts.test.ts(含修复)— 149 通过
  • 变异 A 对修复后套件 — 9 failed | 140 passed(见证杀死该变异);变异已还原
  • 变异 B 对修复后套件 — 1 failed | 148 passed(见证杀死该变异);变异已还原
  • npx vitest run src/core/prompts.test.ts src/core/client.test.ts src/core/client-goal.test.ts src/core/output-styles.test.ts src/tools/write-file.test.ts(packages/core)— 646 通过(5 个文件)
  • npm run build — 通过
  • npm run typecheck — 通过
  • npm run lint — 通过

未运行集成测试:本轮为纯测试改动,涉及行为已由单元测试套件完全覆盖。未改动任何 settings 源,因此不需要 npm run generate:settings-schema

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

@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

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

Autofix round: no changes needed

Feedback newer than the last evaluation (2026-08-28T13:17:45Z) contains no actionable request, so this round makes no code changes and no commit.

  • Review rounds 8–10 (rv:5053261510, rv:5054124083, rv:5055342924): each posted zero new findings. Every Suggestion-level finding they reference is confirmed already reported on this PR and explicitly recorded as "Deferred under the convergence posture — recorded, not requested in this round": ACP/stream-json and arena sessions carrying the style section but never receiving the per-turn reminder, QWEN_SYSTEM_MD resolved twice in getCoreSystemPrompt, and the reminder turn-type gate lacking negative tests for Retry/Notification/Teammate turns. These stay deferred as the reviewer intended; implementing non-requested items now would only grow the diff against the window's advice.
  • Inline comments: none newer than the last evaluation. The eight existing inline threads are all from rounds 1–4 (R1/R3/R4 findings, created 2026-08-27 to 2026-08-28T06:13) and were addressed in earlier rounds.
  • Issue-level comments: the maintainer's @qwen-code /triage trigger produced a triage re-run that completed without a new review (no CHANGES_REQUESTED). The sandboxed verification comment reports ✅ passed — merge-ready (252/252 scripted assertions, 5×5 flakiness gate clean). The base-update notes are informational; current main was already merged into this branch via update-branch.
  • Checks: all current checks are SUCCESS or SKIPPED (16 / 24); no failed and no still-red checks. No conflicts reported (--conflict false); head 09a253087c already contains the main merge.

No verification commands were run because nothing was changed.

中文说明

Autofix 轮次:无需修改

上次评估(2026-08-28T13:17:45Z)之后的反馈中没有任何可执行的修改请求,因此本轮不做任何代码修改,也不提交任何提交。

  • 评审第 8–10 轮(rv:5053261510、rv:5054124083、rv:5055342924):每一轮均发布了 0 条新发现。它们引用的所有 Suggestion 级发现均已确认此前已在该 PR 上报告过,并被明确记录为"收敛姿态下延后——已记录,本轮不要求修改":ACP/stream-json 与 arena 会话携带风格章节但从不收到逐轮提醒、getCoreSystemPromptQWEN_SYSTEM_MD 被解析两次、以及提醒的轮次类型门缺少 Retry/Notification/Teammate 轮次的负向测试。这些发现按评审者的意图继续保持延后状态;此时实现并未被要求的修改只会增加 diff,与本轮窗口给出的建议相悖。
  • 行内评论:上次评估之后没有新的行内评论。现有的 8 条行内评论线程全部来自第 1–4 轮(R1/R3/R4 发现,创建于 2026-08-27 至 2026-08-28T06:13),且已在更早的轮次中处理完毕。
  • Issue 级评论:维护者的 @qwen-code /triage 触发了一次 triage 重跑,重跑完成后未产生新的评审(没有 CHANGES_REQUESTED)。沙箱验证评论报告 ✅ 通过——可合入(252/252 项脚本断言全部通过,5×5 抖动门禁无分歧)。base 更新说明仅为信息性内容;当前 main 已通过 update-branch 合入本分支。
  • 检查项:当前所有检查项均为 SUCCESS 或 SKIPPED(16 / 24);没有失败的检查,也没有持续红色的检查。未报告冲突(--conflict false);head 09a253087c 已包含 main 合并。

本轮未运行任何验证命令,因为没有任何改动。

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


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

The ACP session assembles its own per-turn reminders because it calls
the chat directly and bypasses LlmClient.sendMessageStream; the style
reminder was missing from that list, so an ACP prompt carried the style
section but never the nudge. It now reads the same
resolveMainSessionOutputStyle() decision as the prompt, so a custom
system prompt or QWEN_SYSTEM_MD keeps it silent there as well.

Also pins that Retry, Notification and Teammate turns carry no style
reminder.

Claude-Session: https://claude.ai/code/session_01Gk1gryVzWuW58zkBtoBvnM

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

⚠️ Downgraded from Approve to Comment: CI failing: Test (ubuntu-latest, Node 22.x). Partially reviewed — gaps disclosed.

Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.

Test Plan (not a blocker): src/core/output-styles.test.tsno such file or directory; src/core/prompts.test.tsno such file or directory; src/core/client.test.tsno such file or directory; 500 tests pass — this review observed 22164, 1794, 1690, 605, 4443, 639 passed.

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

  • packages/cli/src/acp-integration/session/Session.ts:10395 — [probe] ACP notification turns get the style reminder; LlmClient excludes Notification turns
  • packages/cli/src/acp-integration/session/Session.ts:10395 — [review] Style-reminder assembly duplicated between client.ts and Session.ts
  • packages/cli/src/acp-integration/session/Session.ts:10395 — [probe] Outer getOutputStyle?.() pre-guard duplicates the resolver's no-style decision
  • packages/cli/src/acp-integration/session/Session.ts:10392 — [review] #buildInitialSystemReminders doc comment not updated for the new branch
  • packages/cli/src/acp-integration/session/Session.test.ts:4087 — [probe] 'every ACP prompt' test sends one prompt; per-turn repetition unpinned on ACP
  • packages/cli/src/acp-integration/session/Session.ts:10395 — [probe] CLI --continue resume surface gets no style reminder; ACP continuations now do
中文说明

⚠️ 已从批准降级为评论:CI failing: Test (ubuntu-latest, Node 22.x)。 仅完成部分审查,审查缺口已披露。

未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。

Test Plan(非阻断):src/core/output-styles.test.tsno such file or directory; src/core/prompts.test.tsno such file or directory; src/core/client.test.tsno such file or directory; 500 tests pass — this review observed 22164, 1794, 1690, 605, 4443, 639 passed

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

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

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

Partially reviewed — gaps disclosed.

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

  • Style-reminder assembly duplicated between client.ts and Session.ts, incl. the outer getOutputStyle?.() pre-guard — already reported (round 11 deferred list, review 5057521972)
  • ACP notification turns get the style reminder; LlmClient excludes Notification turns — already reported (round 11 deferred list, review 5057521972)
  • QWEN_SYSTEM_MD resolved twice in getCoreSystemPrompt — already reported (round 9 deferred list, review 5054124083)

Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.

Test Plan (not a blocker): src/core/output-styles.test.tsno such file or directory; src/core/prompts.test.tsno such file or directory; src/core/client.test.tsno such file or directory; 500 tests pass — this review observed 22289, 1795, 1699, 605, 4590, 642 passed.

中文说明

仅完成部分审查,审查缺口已披露。

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

未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。

Test Plan(非阻断):src/core/output-styles.test.tsno such file or directory; src/core/prompts.test.tsno such file or directory; src/core/client.test.tsno such file or directory; 500 tests pass — this review observed 22289, 1795, 1699, 605, 4590, 642 passed

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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

Autofix round: no changes needed

Feedback newer than the last evaluation (2026-08-28T21:48:03Z) contains no actionable request, so this round makes no code changes and no commit.

  • Automated reviews (rounds 11–12, rv:5057521972 / rv:5057835730): zero new findings were posted; round 12 confirmed that the three outstanding Suggestion-level findings are already reported on this PR. Round 11's downgrade from Approve was driven solely by the non-green Test check (diagnosed below), not by any Critical finding. The seven Suggestion-level findings the reviewer explicitly "deferred under the convergence posture — recorded, not requested in this round" were each re-verified against the current code and confirmed real, but none affects correctness, security, or data loss. Per this repo's review policy (after ~5 review rounds, only Critical fixes land; this PR is in round 13), they stay deferred and are recorded in the follow-up queue so they are not lost at merge:
    • ACP background-notification turns receive the style reminder while LlmClient excludes Notification turns (Session.ts:9103 vs. the pinned stays out of %s turns cases)
    • the style-reminder composition is duplicated between client.ts and Session.ts, including the redundant outer getOutputStyle?.() pre-guard
    • #buildInitialSystemReminders' doc comment does not mention the new output-style branch
    • the every ACP prompt test sends a single prompt, so per-turn repetition on ACP is unpinned
    • CLI --continue continuation turns get no style reminder while ACP continuations do
    • QWEN_SYSTEM_MD is resolved twice in getCoreSystemPrompt
  • Inline comments (8, @qqqys): all are maintainer replies confirming findings already addressed in earlier commits (b31d8fe, b2dc15b, 79c8b55, b90e28d, bdc53fa, 779902b). Each claim was verified against the current code rather than taken on trust: resolveMainSessionOutputStyle() silences the reminder under a custom --system-prompt or active QWEN_SYSTEM_MD (both pinned in client.test.ts); the shared wrapSystemReminder() envelope is used by both client.ts and the ACP session; the Cron-fired branch and the Retry/Notification/Teammate negative cases are pinned; the prompt/reminder agreement matrix and the custom-override-replaces-base case are pinned in prompts.test.ts; the model-forwarding assertion and the QWEN_CODE_TOOL_CALL_STYLE beforeEach stub (prompts.test.ts:820) are in place. All confirmed — these threads are marked resolved.
  • Checks: both non-green checks are CANCELLED, not failed: Test (ubuntu-latest, Node 22.x) ran 60.7 min into its timeout-minutes: 60 cap and web-shell E2E Smoke (ubuntu-latest, Node 22.x) ran 20.4 min into its timeout-minutes: 20 cap, so neither produced an assertion failure or log. At the same commit, every locally runnable equivalent passes (see Verification), and the round-12 review also completed the full unit suite locally at this exact SHA — there is no evidence-backed code-level fix for job-level timeouts, so the repo's CI re-run/patrol infrastructure settles those checks.

Verification (read-only round, HEAD 2834eef)

  • npm run build — passed
  • npm run typecheck — passed
  • npm run lint — passed
  • vitest run packages/core (client.test.ts, prompts.test.ts, output-styles.test.ts, client-goal.test.ts, write-file.test.ts) — 660 passed
  • vitest run packages/cli (Session.test.ts) — 725 passed
  • Integration Tests (CLI, No Sandbox) — not run: skipped in CI and not exercised locally, the same gap both reviews disclosed; nothing changed this round to verify through the bundled CLI
中文说明

Autofix 轮次:无需修改

上次评估(2026-08-28T21:48:03Z)之后的反馈中没有任何可执行的修改请求,因此本轮不做任何代码修改,也不产生任何提交。

  • 自动评审(第 11–12 轮,rv:5057521972 / rv:5057835730):两轮均未发布新发现;第 12 轮确认当前剩余的 3 条 Suggestion 级发现已在该 PR 上报告过。第 11 轮从 Approve 降级仅由未通过的 Test 检查引起(见下方诊断),并非存在任何 Critical 级发现。评审者明确标注为"收敛姿态下延后——已记录,本轮不要求修改"的 7 条 Suggestion 级发现,本轮已逐条对照当前代码重新核实,均属实,但都不涉及正确性、安全或数据丢失。按照本仓库的评审策略(约 5 轮评审之后只合并 Critical 级修复;该 PR 已处于第 13 轮),这些发现继续保持延后状态,并已记录到后续跟进队列中,避免在合并时丢失:
    • ACP 后台通知轮次会收到风格提醒,而 LlmClient 排除了 Notification 轮次(Session.ts:9103 与已固定的 stays out of %s turns 用例不一致)
    • 风格提醒的组装在 client.ts 与 Session.ts 之间重复,包括多余的外层 getOutputStyle?.() 前置判断
    • #buildInitialSystemReminders 的文档注释未提及新增的输出风格分支
    • every ACP prompt 测试只发送了一次 prompt,ACP 上的逐轮重复行为未被固定
    • CLI --continue 续接轮次收不到风格提醒,而 ACP 续接可以收到
    • QWEN_SYSTEM_MDgetCoreSystemPrompt 中被解析了两次
  • 行内评论(8 条,@qqqys:均为维护者对早期提交(b31d8fe0、b2dc15bb、79c8b55e、b90e28d9、bdc53fa7、779902b038)已处理发现的确认回复。每一条都对照当前代码核实而非直接采信:resolveMainSessionOutputStyle() 在自定义 --system-prompt 或生效的 QWEN_SYSTEM_MD 下保持提醒静默(两种情况均已在 client.test.ts 中固定);共享的 wrapSystemReminder() 封装被 client.ts 与 ACP 会话共同使用;Cron 触发分支以及 Retry/Notification/Teammate 的负向用例均已固定;提示词/提醒一致性矩阵与"自定义覆盖整体替换默认基础提示词"的用例已在 prompts.test.ts 中固定;模型转发的断言以及 QWEN_CODE_TOOL_CALL_STYLE 的 beforeEach 桩(prompts.test.ts:820)均已就位。全部核实无误——这些线程已标记为已解决。
  • 检查项:两个未通过的检查均为 CANCELLED(被取消),而非失败:Test (ubuntu-latest, Node 22.x) 运行 60.7 分钟,触及其 timeout-minutes: 60 上限;web-shell E2E Smoke (ubuntu-latest, Node 22.x) 运行 20.4 分钟,触及其 timeout-minutes: 20 上限,因此两者都没有产生断言失败或日志。在同一提交上,所有本地可运行的等价检查均已通过(见下方验证清单),且第 12 轮评审也在完全相同的 SHA 上本地跑完了完整单元测试套件——对于作业级超时不存在有证据支撑的代码级修复,这些检查交由仓库的 CI 重跑/巡检机制处理。

验证(只读轮次,HEAD 2834eef

  • npm run build — 通过
  • npm run typecheck — 通过
  • npm run lint — 通过
  • vitest run packages/core(client.test.ts、prompts.test.ts、output-styles.test.ts、client-goal.test.ts、write-file.test.ts)— 660 项通过
  • vitest run packages/cli(Session.test.ts)— 725 项通过
  • Integration Tests(CLI,No Sandbox)— 未运行:CI 中跳过且本地未执行,与两轮评审披露的缺口一致;本轮没有任何改动需要通过打包后的 CLI 验证

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

⚠️ Review-thread resolution skipped — guard: live-head drift; resolved 0 of 8 selected thread(s), 0 left for a later round. · 评审线程关闭被跳过——守卫:live-head drift;选中 8 条,本轮关闭 0 条,其余 0 条留待后续轮次。


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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

Autofix review round — no code changes (PR #10282)

No review bodies, inline comments, or issue-level comments newer than the last evaluation were present. The only feedback this round is two failed checks in the SDK Java workflow (run 33249938389):

  • ubuntu-latest / Java 11 — FAILURE
  • ubuntu-latest / Java 21 — FAILURE

Disposition: no code change — failures are not attributable to this PR

Evidence trail (all verified against the reviewed head 21e6ce95c6):

  1. The PR executes no code in the failing jobs. This PR changes 11 TypeScript files only (packages/core/src/core/{prompts,output-styles,client,environmentContext} + tests, packages/cli/src/acp-integration/session/Session.ts + test, packages/core/src/tools/write-file.test.ts). No Java sources, no pom.xml, no package.json/package-lock.json, no serve/acp-bridge changes. The failing jobs run mvn clean test, whose surefire config excludes the integration group (pom.xml line 114): the remaining tests are hermetic JVM tests — DaemonSessionClientTest against an in-JVM com.sun.net.httpserver.HttpServer fixture, JSON/SSE/HTTP support units, permission-mode units, and ProcessTransportTest methods that only spawn a test-created env-printer. None of them launches the qwen CLI, daemon, or Node; none executes anything this PR touched.
  2. The one lane that does exercise this PR's daemon code passed. Real daemon E2E / Java 11 builds the CLI from this branch and drives the Java SDK against the real daemon — SUCCESS in the same run.
  3. The failure matrix rules out a deterministic code defect. ubuntu-latest / Java 17, macos-latest / Java 21, and windows-latest / Java 21 all passed in the same run. A defect in code shared by all lanes cannot fail only the two ubuntu lanes.
  4. Known-flake context. The Java 11 lane had a documented intermittent fixture race ("HTTP/1.1 header parser received no bytes" / outcome-unknown teardowns), fixed on main today by test(sdk-java): close the connection on body-less fixture responses #10472 (07:27 UTC, generalizing fix(java): avoid Java 11 HTTP fixture reuse #10365). This branch merged main at 11:21:16 UTC — the failed run started ~11:21–11:24 UTC against that head — so the fix was already in the tested code. Any recurrence of that signature is a fixture/JDK-connection-pooling matter tracked on main, not something this PR's code is in the path of.
  5. Environment. Both failing lanes ran on the shared self-hosted ecs-qwen pool (per the workflow's runs-on expression for same-repo PRs), which the workflow file itself documents as having environmental hazards (shared $HOME / corruptible ~/.m2/toolchains.xml workaround; fix(ci): recover protected qwen leftovers before checkout #10214 merged this morning to quarantine root-owned leftovers on shared runners). The diff-growth section required no action: net 0 source / 0 test lines vs budget.

Why no speculative fix

This runner has no Java/Maven toolchain and no GitHub credentials, so the job logs cannot be fetched and mvn test cannot be reproduced here; no concrete failure message is available. Editing the Java fixture or test code without a failure signature would be a guess, cannot be verified from this environment, and violates Simplicity First. No maintainer decision is being preempted: the only open question (what the two jobs actually failed on) requires the job logs, which are visible to maintainers.

Suggested next step

Rerun the two failed jobs (the repo's Qwen CI Failure Patrol also picks up stale PR check failures automatically every 10 minutes). If they stay red after rerun, the job logs of 99093772306 (Java 11) and 99093772267 (Java 21) in run 33249938389 will name the actual cause.

Diagnostics performed (read-only)

  • git diff --name-only origin/main...HEAD, commit timestamps and ancestry checks (e5838f4145, c1444bdc40 both IN branch; merge commit 21e6ce95c6 created 11:21:16 UTC, matching the failed run's start)
  • Read .github/workflows/sdk-java.yml (runs-on routing, job steps), packages/sdk-java/qwencode/pom.xml (surefire excludedGroups=integration), and the Java test sources (DaemonSessionClientTest, DaemonServeE2ETest, ProcessTransportTest, QwenCodeCliTest)
  • Read flake-fix commits test(sdk-java): close the connection on body-less fixture responses #10472 / fix(java): avoid Java 11 HTTP fixture reuse #10365 messages and the workdir checks.json
  • No build/typecheck/test commands were run because no code was changed.
中文说明

Autofix 评审轮次 — 无代码改动(PR #10282

自上次评估以来,没有新的 review body、行内评论或 issue 级评论。本轮唯一的反馈是 SDK Java 工作流(run 33249938389)中两个失败的检查:

  • ubuntu-latest / Java 11 — FAILURE(失败)
  • ubuntu-latest / Java 21 — FAILURE(失败)

处置:不做代码改动 — 失败与本 PR 无关

证据链(均基于被评审的 head 21e6ce95c6 核实):

  1. 失败的 job 没有执行本 PR 的任何代码。 本 PR 仅改动 11 个 TypeScript 文件(packages/core/src/core/{prompts,output-styles,client,environmentContext} 及测试、packages/cli/src/acp-integration/session/Session.ts 及测试、packages/core/src/tools/write-file.test.ts)。没有 Java 源码、没有 pom.xml、没有 package.json/package-lock.json、没有 serve/acp-bridge 改动。失败的 job 运行 mvn clean test,其 surefire 配置排除了 integration 分组(pom.xml 第 114 行):剩余测试都是封闭的 JVM 测试 — DaemonSessionClientTest 基于 JVM 内的 com.sun.net.httpserver.HttpServer fixture、JSON/SSE/HTTP 支持单测、权限模式单测,以及只启动测试自建 env-printer 的 ProcessTransportTest 方法。它们都不会启动 qwen CLI、daemon 或 Node,也不会执行本 PR 触碰的任何内容。
  2. 唯一真正执行本 PR daemon 代码的 lane 通过了。 Real daemon E2E / Java 11 从本分支构建 CLI 并用 Java SDK 驱动真实 daemon — 在同一 run 中为 SUCCESS(成功)。
  3. 失败矩阵排除了确定性的代码缺陷。 同一 run 中 ubuntu-latest / Java 17macos-latest / Java 21windows-latest / Java 21 全部通过。所有 lane 共享的代码若有缺陷,不可能只在两个 ubuntu lane 上失败。
  4. 已知 flake 背景。 Java 11 lane 今天有一个已记录的间歇性 fixture 竞态("HTTP/1.1 header parser received no bytes" / teardown 结果未知),main 上今天已由 test(sdk-java): close the connection on body-less fixture responses #10472 修复(07:27 UTC,泛化了 fix(java): avoid Java 11 HTTP fixture reuse #10365)。本分支于 11:21:16 UTC 合并了 main — 失败的 run 约在 11:21–11:24 UTC 针对该 head 启动 — 因此该修复已包含在被测代码中。如果该签名再次出现,也属于 main 上跟踪的 fixture/JDK 连接池问题,而不是本 PR 代码路径上的问题。
  5. 环境因素。 两个失败 lane 都运行在共享的自托管 ecs-qwen 池上(根据该工作流对同仓库 PR 的 runs-on 表达式),工作流文件本身记录了该环境的隐患(共享 $HOME / 易损坏的 ~/.m2/toolchains.xml 规避措施;今早合并的 fix(ci): recover protected qwen leftovers before checkout #10214 用于隔离共享 runner 上 root 所有的残留文件)。diff 增长部分无需处理:相对预算净增 0 行源码 / 0 行测试。

为什么不做推测性修复

本 runner 没有 Java/Maven 工具链,也没有 GitHub 凭据,因此无法拉取 job 日志,也无法在本地复现 mvn test;没有具体的失败信息。在没有失败签名的情况下修改 Java fixture 或测试代码纯属猜测,在本环境中无法验证,且违反 Simplicity First 原则。也没有越权替维护者做决定:唯一的未决问题(这两个 job 到底因何失败)需要 job 日志,而日志对维护者可见。

建议的下一步

重新运行这两个失败的 job(仓库的 Qwen CI Failure Patrol 也会每 10 分钟自动拾取过期的 PR 检查失败)。如果重跑后仍然失败,run 3324993838999093772306(Java 11)和 99093772267(Java 21)的 job 日志将指明真正的原因。

已执行的诊断(只读)

  • git diff --name-only origin/main...HEAD、提交时间戳与祖先检查(e5838f4145c1444bdc40 均在分支内;合并提交 21e6ce95c6 创建于 11:21:16 UTC,与失败 run 的启动时间吻合)
  • 阅读 .github/workflows/sdk-java.yml(runs-on 路由、job 步骤)、packages/sdk-java/qwencode/pom.xml(surefire excludedGroups=integration)以及 Java 测试源码(DaemonSessionClientTestDaemonServeE2ETestProcessTransportTestQwenCodeCliTest
  • 阅读 flake 修复提交 test(sdk-java): close the connection on body-less fixture responses #10472 / fix(java): avoid Java 11 HTTP fixture reuse #10365 的说明以及 workdir 中的 checks.json
  • 由于没有改动任何代码,未运行 build/typecheck/test 命令。

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


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

Partially reviewed — gaps disclosed.

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

  • R13-1 ACP background-notification turns get the style reminder while LlmClient excludes Notification turns — already reported (round 11 deferred list 'ACP notification turns get the style reminder; LlmClient excludes Notification turns', re…
  • R13-2 Style-reminder assembly duplicated between client.ts and Session.ts — already reported (round 11 deferred list 'Style-reminder assembly duplicated between client.ts and Session.ts', review 5057521972)
  • R13-3 Headless twin buildInitialSystemReminders lacks the style reminder (continueInterrupted re-injection loses it) — already reported (round 11 deferred list 'CLI --continue resume surface gets no style reminder; ACP continuations now do'…
  • R13-4 Redundant outer getOutputStyle?.() pre-guard on the ACP mirror — already reported (round 11 deferred list 'Outer getOutputStyle?.() pre-guard duplicates the resolver's no-style decision', review 5057521972)

Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.

Not explored to full depth (tool budget reached): "agent 6c": running the recommended core/cli vitest suites to confirm the new tests pass — node_modules and dist are not installed in this worktree, and npm ci + npm run….

Test Plan (not a blocker): src/core/output-styles.test.tsno such file or directory; src/core/prompts.test.tsno such file or directory; src/core/client.test.tsno such file or directory.

中文说明

仅完成部分审查,审查缺口已披露。

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

未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。

未探索到全部深度(达到工具调用预算):"agent 6c"running the recommended core/cli vitest suites to confirm the new tests pass — node_modules and dist are not installed in this worktree, and npm ci + npm run…

Test Plan(非阻断):src/core/output-styles.test.tsno such file or directory; src/core/prompts.test.tsno such file or directory; src/core/client.test.tsno such file or directory

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

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

Partially reviewed — gaps disclosed.

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

  • R13-1 ACP background-notification turns get the style reminder while LlmClient excludes Notification turns — already reported (round 11 deferred list 'ACP notification turns get the style reminder; LlmClient excludes Notification turns', re…
  • R13-2 Style-reminder assembly duplicated between client.ts and Session.ts — already reported (round 11 deferred list 'Style-reminder assembly duplicated between client.ts and Session.ts', review 5057521972)
  • R13-3 Headless twin buildInitialSystemReminders lacks the style reminder (continueInterrupted re-injection loses it) — already reported (round 11 deferred list 'CLI --continue resume surface gets no style reminder; ACP continuations now do'…
  • ACP cron-fired and background-notification reminder paths lack tests — already reported (round 8 deferred list 'No ACP-mode test for the reminder injection gate', review 5053261510)
  • Arena agents carry the style section but never receive the per-turn reminder — already reported (round 5 deferred list 'Style reminder never reaches ACP, arena, or forked sessions', review 5048374377)

Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.

Not explored to full depth (tool budget reached): "agent 4": none — no check was cut short.; "agent 1a": none — no check was cut short..

Test Plan (not a blocker): src/core/output-styles.test.tsno such file or directory; src/core/prompts.test.tsno such file or directory; src/core/client.test.tsno such file or directory; 500 tests pass — this review observed 22469, 1795, 1699, 605, 4604, 642 passed.

中文说明

仅完成部分审查,审查缺口已披露。

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

未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。

未探索到全部深度(达到工具调用预算):"agent 4"none — no check was cut short."agent 1a"none — no check was cut short.

Test Plan(非阻断):src/core/output-styles.test.tsno such file or directory; src/core/prompts.test.tsno such file or directory; src/core/client.test.tsno such file or directory; 500 tests pass — this review observed 22469, 1795, 1699, 605, 4604, 642 passed

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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

Autofix review round: no changes needed

I reviewed the latest feedback on this PR and no code change is warranted this round. Point by point:

The two new review passes posted zero new findings

Both review comments in this batch (rv:5058176053 round 13, rv:5058599919 round 14) completed against the current head (a868381655) and posted no new findings — each review ledger records "findings":[] / "posted":0. They only re-disclosed Suggestion-level items that were already reported and deferred in earlier rounds (rounds 5, 8, and 11). Re-disclosure is dedup/transparency, not a fresh request, so no new work is taken on them here:

  • ACP background-notification turns get the style reminder while LlmClient excludes Notification turns
  • Style-reminder assembly duplicated between client.ts and Session.ts
  • Headless twin buildInitialSystemReminders lacks the style reminder (--continue re-injection)
  • Redundant outer getOutputStyle?.() pre-guard on the ACP mirror
  • ACP cron-fired / background-notification reminder paths lack tests
  • Arena agents carry the style section but never receive the per-turn reminder

These are already tracked from earlier rounds and intentionally deferred rather than expanded into this PR, consistent with the minimal-diff guidance for this window.

No outstanding inline or issue-level comments

There are no inline review comments and no issue-level comments in this batch. Every prior inline finding (R1-1 through R4-1) already has an "Addressed in …" reply from earlier rounds, and no review on this PR is in a CHANGES_REQUESTED state.

The listed "failed" checks are CANCELLED, not failing

Test (ubuntu-latest, Node 22.x), Integration Tests (no-AK, No Sandbox), and web-shell E2E Smoke (ubuntu-latest, Node 22.x) show CANCELLED — an orchestration state, not a test failure. Inspecting the full check list, every one of the 46 check runs concludes SUCCESS, SKIPPED, or CANCELLED; none is FAILURE. There is no test error or code defect to fix. Identical cancellations in prior rounds were transient and cleared by re-merging main (base update), where the same checks pass — so this is not a code problem and re-running CI is owned by the workflow, not this bot.

No changes were made this round.

中文说明

Autofix 审查轮次:无需改动

我已审阅本 PR 的最新反馈,本轮无需进行任何代码改动。逐点说明如下:

两次新的审查均未提出任何新发现

本批次的两条审查评论(rv:5058176053 第 13 轮、rv:5058599919 第 14 轮)均基于当前 head(a868381655)完成,且都没有发布新发现——每条审查的 ledger 均记录为 "findings":[] / "posted":0。它们只是重新披露了在更早轮次(第 5、8、11 轮)中已经报告过并已延期处理的建议级(Suggestion)条目。这种重新披露属于去重/透明性说明,并非新的整改要求,因此本轮不针对它们开展新工作:

  • ACP 后台通知轮次会收到样式提醒,而 LlmClient 却排除了 Notification 轮次
  • 样式提醒的拼装逻辑在 client.tsSession.ts 之间重复
  • 无头(headless)端的 buildInitialSystemReminders 缺少样式提醒(--continue 重新注入时会丢失)
  • ACP 镜像上多余的外层 getOutputStyle?.() 预守卫
  • ACP 定时触发/后台通知的提醒路径缺少测试
  • Arena 智能体带有样式段落,但从未收到逐轮提醒

这些条目已在更早轮次中被记录在案,并被有意延期处理,而非并入本 PR 扩大范围——这与本窗口期“保持最小 diff”的指导意见一致。

没有未处理的行内评论或议题级评论

本批次中没有行内审查评论,也没有议题级评论。此前的每一条行内发现(R1-1 到 R4-1)在更早轮次中都已有 “Addressed in …”(已在……中处理)的回复,且本 PR 上没有任何审查处于 CHANGES_REQUESTED(要求修改)状态。

被列为“失败”的检查实为 CANCELLED(已取消),并非真正失败

Test (ubuntu-latest, Node 22.x)Integration Tests (no-AK, No Sandbox)web-shell E2E Smoke (ubuntu-latest, Node 22.x) 显示为 CANCELLED——这是一种编排/调度状态,并非测试失败。检查完整的检查列表可以发现,全部 46 个检查运行的结论均为 SUCCESSSKIPPEDCANCELLED没有一个是 FAILURE(失败)。不存在需要修复的测试错误或代码缺陷。此前几轮中相同的取消均为瞬时现象,并通过重新合并 main(更新基线)后得以消除——在 main 上这些相同的检查均能通过。因此这并非代码问题,且重新触发 CI 由工作流负责,而非本机器人。

本轮未做任何改动。

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


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

@wenshao

wenshao commented Aug 30, 2026

Copy link
Copy Markdown
Collaborator

Independent verification — real environment, wire capture

I verified this PR locally against a real bundled CLI (dist/cli.js, built from the merged tree) talking over real HTTP to a local OpenAI-compatible server that logs every request body. No vi.mock, no in-process stubs: every claim below is read off the bytes that left the process.

Trees under test — base 168a88c02e (main), merged f6df5a8d24 (= main + PR head a868381655, merges clean). Both trees carry one identical 6-line harness shim in Config.getOutputStyle() that reads a style from an env var, standing in for the selection surface this PR deliberately leaves to a follow-up. It is byte-identical on both sides, so every A/B difference below is the PR's.

Verdict: the PR does what it says, and the no-op claim is exact. Two behaviours worth a maintainer's eye before merge are at the bottom; both are already on the deferred list, and I'm attaching measurements rather than asking for new work.


1. The bug it fixes, and the no-op claim

wire A/B

  • On main, a session with Concise active ships the # Output Style: section in the system prompt and zero reminders — exactly the gap feat(core): add the output-style layer to the system prompt #9565 left. (The reminder builder is dead code there: getOutputStyleTurnReminder's literal is tree-shaken out of main's bundle entirely, and present in the PR's.)
  • With no style active — every real session today — the request is byte-for-byte identical between main and the PR (cmp clean, 109 656 B on both). The "no session's request changes on this commit alone" claim holds literally.
  • With Concise active the only delta is +172 bytes, all of it in the user turn. The system prompt is byte-identical between main and the PR in every configuration measured, and byte-identical across all three turns of a live session — the cached prefix really is untouched.

2. Behaviour matrix — 17/17 rows match the PR's description

matrix

Every row is a separate run of the real CLI. The invariant the PR is built around — remind if and only if the prompt carries the section — held in all of them, including the ones the unit tests don't cover:

  • --system-prompt, QWEN_SYSTEM_MD=true: no section, no reminder. QWEN_SYSTEM_MD=false: both come back.
  • --append-system-prompt (not in the test matrix): section and reminder, correctly — the append layer doesn't replace the base.
  • --system-prompt + --append-system-prompt: neither.
  • Learning is dropped from both prompt and reminder in a headless run, and kept in both over ACP — the pair that proves the two consult one resolver.
  • On a tool-result turn the request carries the turn-1 reminder replayed from history and no newly injected one, which is the intended shape.
  • Cron-fired turns get it — verified end-to-end through the real ACP cron path (QWEN_CODE_TEST_CRON_FAST), not just the unit test.
  • --system-prompt over ACP stays silent too, i.e. the Session.ts mirror really does go through the shared resolver.

3. Escaping holds for the whole rendered line

escaping

A hostile turnReminder and a hostile style.name both come out neutralised (<\/system-reminder>, &lt;system-reminder&gt;), envelope balanced 4/4 in the whole user turn. Worth noting the name case is covered only because wrapSystemReminder escapes the rendered line rather than the field — good, and worth keeping that way when style files land.

4. Do the new tests actually hold this down? 10/10 mutants killed

mutants

I reverted each decision in the diff one at a time. No survivors — including the two that matter most: swapping resolveMainSessionOutputStyle(...) back to a raw getOutputStyle() is caught in both client.ts and Session.ts. The it.each matrix in prompts.test.ts is the load-bearing test: it alone kills M2 and M3 six ways.

Suites on the merged tree: output-styles + prompts + client + client-goal + write-file = 668 passed; Session.test.ts = 741 passed.

The getCoreSystemPrompt refactor is faithful: the new isSystemMdActive() tests value !== null where the old code tested truthiness, which is equivalent because resolvePathFromEnv only ever returns null or a non-empty string — and M10 confirms the 0/false branch is pinned by tests.


5. Two measurements for the record (not merge blockers)

a) Over ACP, a background-task-notification turn gets the reminder; in client.ts the same event does not.

notification asymmetry

Session.ts reuses #buildInitialSystemReminders() for user turns, cron turns and notification turns (Session.ts:9273), while client.ts scopes the reminder to UserQuery || Cron and client.test.ts pins Notification as excluded. I drove a real background shell through ACP and captured the resulting notification turn — the reminder is there. This is the standing Suggestion from round 5 and it is factually correct; the screenshot is just the measurement. Deciding it either way (in this PR or the follow-up) is a one-line change on whichever side you pick.

b) The reminder repeats every turn and every copy stays in the transcript, so turn N ships N copies.

accumulation

The Risk section reads as a flat "+25 tokens per turn"; measured, the incremental cost is flat (144 chars ≈ 35 tokens with the envelope) but the request grows, so the cumulative cost over a session is quadratic. This is not new and not this PR's doingmain's own plan-mode reminder behaves identically on the same rig, so the PR is following the established pattern. Resumed sessions differ: --resume rebuilds history from the transcript and drops prior per-turn reminders, so a resumed run carries exactly one copy per request. Worth one sentence in the Risk section, nothing more.

c) Nit, forward-looking: style.turnReminder ?? DEFAULT_OUTPUT_STYLE_TURN_REMINDER falls back on null/undefined but not on ''. A style file with an empty turnReminder: key yields "<Name> output style is active. " — a reminder with no guidance in it. Same reasoning that motivated the escaping: file-supplied text arrives in the follow-up PR. || (or a .trim() check) would close it.


Recommendation

Approve on behaviour. The core claim — reminder if and only if section, byte-identical for every session that exists today, cached prefix untouched — is confirmed on the wire across 17 configurations and three entry points (headless, ACP, ACP-cron), and the test suite has no blind spot I could find in 10 mutants. Item (a) is the only one I'd want a decision recorded on before the selection surface makes any of this reachable.

中文说明

独立验证 —— 真实环境、链路抓包

我在本地用真实打包产物(从合并树构建的 dist/cli.js)通过真实 HTTP 打到一个会记录每个请求体的本地 OpenAI 兼容服务端,对本 PR 做了验证。没有 vi.mock、没有进程内打桩:下面每一条结论都是从真正发出去的字节里读出来的。

被测树 —— base 168a88c02emain),合并树 f6df5a8d24(= main + PR head a868381655,干净合并)。两棵树都带同一份 6 行的验证垫片(改在 Config.getOutputStyle(),从环境变量读风格),用来顶替本 PR 有意留给后续 PR 的选择入口。这份垫片在两侧逐字节一致,因此下面所有 A/B 差异都只来自本 PR。

结论:这个 PR 做到了它说的事,而且「空操作」这一条是精确成立的。 底部有两条值得维护者过目的行为特征,二者都已在延期清单上,我只是补上测量数据,并非要求新工作。


1. 它修的那个 bug,以及空操作这一条

  • main 上,激活 Concise 的会话系统提示词里带着 # Output Style: 段落,但提醒数为 0 —— 正是 feat(core): add the output-style layer to the system prompt #9565 留下的缺口。(那边它就是死代码:getOutputStyleTurnReminder 的字面量在 main 的 bundle 里被完全 tree-shake 掉了,在本 PR 的 bundle 里则存在。)
  • 没有风格生效时 —— 也就是今天的每一个真实会话 —— 请求与 main 逐字节一致cmp 通过,两边都是 109 656 B)。「仅凭这个 commit 任何会话的请求都不会变化」这句话是字面成立的。
  • 激活 Concise 时唯一的差异是 +172 字节,且全部落在用户轮里。系统提示词在测过的每一种配置下都与 main 逐字节一致,并且在一个活跃会话的三轮之间也逐字节一致 —— 缓存前缀确实没被动过。

2. 行为矩阵 —— 17/17 行与 PR 描述一致

每一行都是真实 CLI 的一次独立运行。本 PR 所围绕的不变式 —— 当且仅当提示词带该段落时才提醒 —— 在全部行中成立,包括单测未覆盖的那些:

  • --system-promptQWEN_SYSTEM_MD=true:无段落、无提醒。QWEN_SYSTEM_MD=false:两者都回来。
  • --append-system-prompt(不在测试矩阵内):段落提醒都有,这是对的 —— append 层不替换 base。
  • --system-prompt + --append-system-prompt:两者皆无。
  • headless 下 Learning 在提示词和提醒中同时被剔除,ACP 下在两者中同时保留 —— 这一对正好证明两处查的是同一个 resolver。
  • 工具结果轮里,请求携带的是从历史回放的第 1 轮提醒,没有新注入的,形态符合预期。
  • cron 触发轮会收到 —— 这是走真实 ACP cron 路径端到端验证的(QWEN_CODE_TEST_CRON_FAST),不只是单测。
  • ACP 下的 --system-prompt 同样保持静默,即 Session.ts 的镜像确实走了共享 resolver。

3. 转义对整行渲染结果都成立

恶意的 turnReminder 恶意的 style.name 都被中和(<\/system-reminder>&lt;system-reminder&gt;),整个用户轮里标签 4/4 平衡。值得一提:name 这一路之所以被覆盖,是因为 wrapSystemReminder 转义的是渲染后的整行而不是某个字段 —— 这是好事,风格文件落地后也建议保持这样。

4. 新测试真的把行为钉住了吗?10/10 变异体全部被杀

我逐一回退 diff 中的每个决策。无存活变异体 —— 包括最关键的两个:把 resolveMainSessionOutputStyle(...) 换回裸的 getOutputStyle(),在 client.tsSession.ts 两侧都会被抓住prompts.test.ts 里的 it.each 矩阵是承重测试:光它一个就以六种方式杀掉 M2 和 M3。

合并树上的套件:output-styles + prompts + client + client-goal + write-file = 668 通过Session.test.ts = 741 通过

getCoreSystemPrompt 的重构是忠实的:新的 isSystemMdActive()value !== null,旧代码判真值,二者等价,因为 resolvePathFromEnv 只会返回 null 或非空字符串 —— 而 M10 确认了 0/false 分支有测试钉住。


5. 两条记录在案的测量(非合并阻塞项)

a) ACP 下后台任务通知轮会收到提醒,而 client.ts 对同一事件不发。

Session.ts 对用户轮、cron 轮通知轮复用同一个 #buildInitialSystemReminders()Session.ts:9273),而 client.ts 把提醒限定在 UserQuery || Cron,且 client.test.ts 明确钉死 Notification 被排除。我在 ACP 里驱动了一个真实后台 shell 并抓下了随之产生的通知轮 —— 提醒确实在里面。这就是第 5 轮那条 standing Suggestion,它是成立的;截图只是把它量化。无论在本 PR 还是后续 PR 里决断,都只是选一侧改一行的事。

b) 提醒逐轮重复,且每份都留在 transcript 里,因此第 N 轮会发出 N 份。

风险一节读起来像是「每轮固定 +25 token」;实测下来,增量成本是固定的(144 字符 ≈ 含标签约 35 token),但请求本身在变大,所以整个会话的累计成本是平方级的。这不是新问题,也不是本 PR 造成的 —— 在同一套装置上,main 自己的 plan-mode 提醒表现完全一样,本 PR 只是沿用既有模式。恢复会话则不同:--resume 会从 transcript 重建历史并丢掉此前的逐轮提醒,因此恢复运行每个请求恰好只带 1 份。建议在风险一节补一句话,仅此而已。

c) 前瞻性小项: style.turnReminder ?? DEFAULT_OUTPUT_STYLE_TURN_REMINDER 只在 null/undefined 时回退,空字符串 '' 不会。一个 turnReminder: 键为空的风格文件会得到 "<Name> output style is active. " —— 一条不含任何指引的提醒。理由和促成转义的那条一样:来自文件的文本会在后续 PR 中到达。改成 ||(或加 .trim() 判断)即可闭合。


建议

行为层面建议通过。 核心主张 —— 当且仅当有段落才提醒、对今天存在的每一个会话逐字节无变化、缓存前缀不受影响 —— 在 17 种配置、三个入口(headless、ACP、ACP-cron)上于链路层面得到确认,且我用 10 个变异体没能找出测试盲区。(a) 是唯一一条我希望在选择入口让这些变得可达之前先把决策记录下来的。

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

Autofix review round — same-run verification repair (PR #10282)

The deterministic gate rejected the previous commit 4529b44fd7 (the round that implemented feedback item (c)) with tests failed in packages/cli: 10 failed tests in 3 test files, 9 of them Test timed out in 15000ms in suites this PR never touches. Per the same-run repair instruction, that commit is preserved and this follow-up commit 1fffb5a5dc fixes the rejection.

Diagnosis (evidence, not a guess)

  1. All three failing files pass in isolation on this tree: update.test.ts + server-default-bridge-wiring.test.ts + workspace-registration-store.test.ts → 43 passed | 1 skipped.
  2. The files are byte-identical to origin/main — this PR's diff (output-style turn reminder in Session.ts / core) cannot explain their behavior. Nine of ten failures are wall-clock 15s timeouts — scheduling starvation, not assertion mismatches. The single spy assertion failure in update.test.ts is a cascade from the preceding test's timeout in the same file (its handler continuation leaked across the abort).
  3. The host is saturated: load average ~77 on 64 cores during this round, and the repo's own vitest config already documents this failure mode ("CI contention" on the workspace-registration-store tempdir test; "ECS hosts run several jobs at once; leave capacity for neighboring jobs").
  4. Local reproduction of the gate command: npx vitest run --changed origin/main --passWithNoTests in packages/cli (full 701-file fan-out at this session's 64 workers) fails with the same timeout signature in the same two serve files (and more, under the heavier load) — confirming load-induced flakiness, pre-fix.
  5. The gate runs on the ecs-qwen self-hosted pool: the workflow's runner guard refuses any self-hosted runner whose name is not ecs-qwen-*, so the existing maxWorkers: '25%' cap was active during the gate run and the pool's raised-budget convention applies to it.

Change (this round, one commit)

Per-file timeout budgets mirroring the house pattern (worktreeStartup.test.ts, clipboardUtils.test.ts) and the maintainer-co-authored in-flight branch codex/fix-shared-ecs-ci-time-budgets, which chose the same 60s ecs number:

  • packages/cli/src/commands/update.test.ts, packages/cli/src/serve/workspace-registration-store.test.ts, packages/cli/src/serve/server-default-bridge-wiring.test.ts: vi.setConfig({ testTimeout, hookTimeout }) — 60s when RUNNER_NAME starts with ecs-qwen-, else 15s (the previous effective ceiling).
  • Removed the two now-redundant 15_000 per-test literals in server-default-bridge-wiring.test.ts (they equaled the old default; left in place they would cap those tests below the pool budget on ecs). This is byte-identical to the edit the in-flight branch makes to the same file, so a later merge converges cleanly.

A config-level fix (packages/cli/vitest.config.ts) was not an option: the gate deterministically rejects workspace test-config edits in rounds whose PR does not already touch them. Behavior outside the ecs pool is byte-for-byte unchanged (15s == the old default everywhere).

Mutation probes (both branches witnessed)

  • Probe 1 (ecs branch live): temporarily 60_0001_500; run with RUNNER_NAME=ecs-qwen-probe → 3 tests FAILED with Test timed out in 1500ms. Restored.
  • Probe 2 (default branch live): temporarily 15_0001_500; run without RUNNER_NAME → same failure signature. Restored.
  • With both values restored, all three files are green plain and under RUNNER_NAME=ecs-qwen-*.

Feedback dispositions (only feedback this window: [ic:5468448060])

@wenshao's independent wire-capture verification — verdict "Approve on behaviour":

  • Sections 1–4 confirm the PR's claims — no action needed.
  • (c) Empty turnReminder fallback — fixed in the preserved commit 4529b44fd7 (??|| in getOutputStyleTurnReminder, with witness test and mutation probe), exactly as the comment proposed.
  • (a) ACP vs client.ts notification-turn asymmetry — still escalated for a maintainer decision, no code change: both directions are defensible, it is already in the deferred-review-findings queue with the wire measurement attached, and the comment itself attached a measurement rather than requesting work. Open question carried forward: should Notification turns get the style reminder (align client.ts with ACP) or not (align ACP with client.ts)?
  • (b) Risk-section sentence on cumulative cost — lives in the PR description, which this workflow cannot edit (no GitHub writes). The proposed sentence for a maintainer to paste remains in the previous round's summary.

No inline review comments exist this window, so there are no resolved threads and no reply entries.

Remaining risk (honest note)

This round hardens exactly the three files the gate rejected, but pool-wide contention can still flake a different suite in a future full-suite gate run; the strategic fix (config-level ecs budgets for the whole suite) is in flight on codex/fix-shared-ecs-ci-time-budgets and cannot be folded into this round (gate machinery rule above).

Conflict notes

--conflict false — no merge performed; the branch is current with origin/main as of the existing merge commit. No base conflicts expected; the only overlapping in-flight edit (same two 15_000 literals) is byte-identical.

Verification

Commands actually run this round:

  • Focused vitest, packages/cli: npx vitest run src/serve/server-default-bridge-wiring.test.ts src/serve/workspace-registration-store.test.ts src/commands/update.test.ts43 passed | 1 skipped, run twice: plain and with RUNNER_NAME=ecs-qwen-sanity
  • Mutation probe 1 (ecs branch negated to 1.5s, RUNNER_NAME=ecs-qwen-probe) — FAILED as required (3× Test timed out in 1500ms); restored → green
  • Mutation probe 2 (default branch negated to 1.5s, no RUNNER_NAME) — FAILED as required; restored → green
  • Pre-fix evidence: the three files in isolation — 43 passed | 1 skipped; full gate command npx vitest run --changed origin/main --passWithNoTests — FAILED with the same timeout signature (reproduction of the gate rejection)
  • npm run build — passed
  • npm run typecheck — passed
  • npm run lint — passed
  • npm run generate:settings-schema — not needed (no settings source changed)
  • Integration tests — not needed (test-only change; no bundled-CLI behavior touched)
中文说明

Autofix 审查轮 —— 同轮验证修复(PR #10282

确定性门禁拒绝了上一个提交 4529b44fd7(即实现反馈条目 (c) 的那一轮),理由为 tests failed in packages/cli:3 个测试文件共 10 个失败用例,其中 9 个是本 PR 从未触碰的套件里的 Test timed out in 15000ms。按照同轮修复(same-run repair)指令,该提交予以保留,本次后续提交 1fffb5a5dc 负责修复这一拒绝。

诊断(基于证据,而非猜测)

  1. 三个失败文件在本树上单独运行全部通过update.test.ts + server-default-bridge-wiring.test.ts + workspace-registration-store.test.ts → 43 通过 | 1 跳过。
  2. 这些文件与 origin/main 逐字节一致 —— 本 PR 的改动(Session.ts / core 中的 output-style 轮次提醒)无法解释它们的行为。10 个失败中有 9 个是 15 秒墙钟超时 —— 是调度饥饿,不是断言不匹配。update.test.ts 中唯一一处 spy 断言失败是同文件中前一个测试超时的连锁反应(其中止后残留的 handler 延续执行泄漏到了下一个测试)。
  3. 宿主机已饱和:本轮期间 64 核机器负载均值约 77,且仓库自己的 vitest 配置里早已记录了这一失败模式(workspace-registration-store tempdir 测试的 "CI contention";"ECS hosts run several jobs at once; leave capacity for neighboring jobs")。
  4. 门禁命令的本地复现:在 packages/cli 中运行 npx vitest run --changed origin/main --passWithNoTests(701 个文件全量展开、本会话 64 worker)在修复前以同样的超时签名在同样的两个 serve 文件中失败(更重的负载下还波及更多文件)—— 证实是负载导致的 flake。
  5. 门禁跑在 ecs-qwen 自托管池上:工作流的 runner 守卫会拒绝任何名字不是 ecs-qwen-* 的自托管 runner,因此门禁运行时现有的 maxWorkers: '25%' 上限是生效的,该池的「提高预算」惯例也适用于它。

改动(本轮,单个提交)

逐文件设置超时预算,沿用仓库既有模式(worktreeStartup.test.tsclipboardUtils.test.ts),并与维护者共同署名、在途的分支 codex/fix-shared-ecs-ci-time-budgets 保持一致(该分支选了相同的 60 秒 ecs 数值):

  • packages/cli/src/commands/update.test.tspackages/cli/src/serve/workspace-registration-store.test.tspackages/cli/src/serve/server-default-bridge-wiring.test.tsvi.setConfig({ testTimeout, hookTimeout }) —— RUNNER_NAMEecs-qwen- 开头时为 60 秒,否则为 15 秒(即原先的有效上限)。
  • 删除 server-default-bridge-wiring.test.ts 中两个如今冗余的 15_000 逐测试字面量(它们原本等于旧默认值;若保留,会在 ecs 上把这两个测试压到池预算之下)。这与在途分支对同一文件所做的改动逐字节相同,因此后续合并会干净收敛。

配置层修复(packages/cli/vitest.config.ts不可选:门禁会确定性地拒绝「PR 本身未触碰」的包级 test-config 改动。ecs 池之外的行为逐字节不变(15 秒 == 各处旧默认值)。

变异探针(两个分支都有见证)

  • 探针 1(ecs 分支生效):临时把 60_0001_500;以 RUNNER_NAME=ecs-qwen-probe 运行 → 3 个测试失败,报 Test timed out in 1500ms。随后还原。
  • 探针 2(默认分支生效):临时把 15_0001_500;不带 RUNNER_NAME 运行 → 同样的失败签名。随后还原。
  • 两个数值还原后,三个文件在普通环境和 RUNNER_NAME=ecs-qwen-* 下均为绿。

反馈处置(本窗口唯一反馈:[ic:5468448060])

@wenshao 的独立链路抓包验证 —— 结论「行为层面建议通过」:

  • 第 1–4 节确认本 PR 的各项主张 —— 无需动作。
  • (c) 空 turnReminder 回退 —— 已在保留的提交 4529b44fd7 中修复(getOutputStyleTurnReminder??||,附见证测试与变异探针),与评论建议完全一致。
  • (a) ACP 与 client.ts 在通知轮上的不对称 —— 仍上抛给维护者决策,本轮不改代码:两个方向都说得通,该条目已带着链路测量数据在延期发现队列中,且评论本身也只是附测量、并未要求新工作。遗留的开放问题:Notification 轮是否应收到风格提醒(让 client.ts 与 ACP 对齐)还是不发(让 ACP 与 client.ts 对齐)?
  • (b) 风险一节关于累计成本的句子 —— 位于 PR 描述中,本工作流无法编辑(无 GitHub 写权限)。供维护者粘贴的建议句子保留在上一轮的摘要中。

本窗口没有行内评审评论,因此没有可解析的线程,也没有回复条目。

遗留风险(如实说明)

本轮只加固了门禁拒绝的那三个文件;在池级争用下,未来某次全量门禁运行仍可能让其他套件偶发失败。战略性修复(整个套件层面的配置级 ecs 预算)在 codex/fix-shared-ecs-ci-time-budgets 分支上在途推进,且因上述门禁机制规则无法并入本轮。

冲突说明

--conflict false —— 未执行合并;分支经已有合并提交与 origin/main 保持同步。预计无 base 冲突;唯一重叠的在途改动(同样两个 15_000 字面量)逐字节相同。

验证

本轮实际运行的命令:

  • 聚焦 vitest(packages/cli):npx vitest run src/serve/server-default-bridge-wiring.test.ts src/serve/workspace-registration-store.test.ts src/commands/update.test.ts —— 43 通过 | 1 跳过,共运行两次:普通环境与 RUNNER_NAME=ecs-qwen-sanity
  • 变异探针 1(ecs 分支取反为 1.5 秒,RUNNER_NAME=ecs-qwen-probe)—— 按要求失败(3 次 Test timed out in 1500ms);还原后转绿
  • 变异探针 2(默认分支取反为 1.5 秒,无 RUNNER_NAME)—— 按要求失败;还原后转绿
  • 修复前证据:三个文件单独运行 —— 43 通过 | 1 跳过;完整门禁命令 npx vitest run --changed origin/main --passWithNoTests —— 以同样的超时签名失败(门禁拒绝的复现)
  • npm run build —— 通过
  • npm run typecheck —— 通过
  • npm run lint —— 通过
  • npm run generate:settings-schema —— 无需(未改动 settings 源)
  • 集成测试 —— 无需(纯测试改动,未触碰任何打包 CLI 行为)

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

⚠️ Downgraded from Approve to Comment: CI failing: web-shell E2E Smoke (ubuntu-latest, Node 22.x), Test (ubuntu-latest, Node 22.x). Partially reviewed — gaps disclosed.

Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally; this round's local test phase also did not start (budget exhausted during install+build, no suite executed).

Test Plan (not a blocker): src/core/output-styles.test.tsno such file or directory; src/core/prompts.test.tsno such file or directory; src/core/client.test.tsno such file or directory.

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

  • packages/cli/src/commands/update.test.ts:76 (+2 locations) — [review] ecs-qwen timeout block pasted into three test files
中文说明

⚠️ 已从批准降级为评论:CI failing: web-shell E2E Smoke (ubuntu-latest, Node 22.x), Test (ubuntu-latest, Node 22.x)。 仅完成部分审查,审查缺口已披露。

未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally; this round's local test phase also did not start (budget exhausted during install+build, no suite executed)。

Test Plan(非阻断):src/core/output-styles.test.tsno such file or directory; src/core/prompts.test.tsno such file or directory; src/core/client.test.tsno such file or directory

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

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

@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 30, 2026

Copy link
Copy Markdown
Collaborator

🩺 serve daemon A/B

Built the PR base vs this PR head a51dff9, drove a fixed endpoint set against each, and diffed the JSON responses. Only fields that changed are shown.

No response changes against the PR base across 12 scenario(s).

Qwen Code · serve A/B

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

Partially reviewed — gaps disclosed.

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

  • R16-1 ACP background-notification turns get the style reminder while LlmClient excludes Notification turns — already reported (round 11 deferred list 'ACP notification turns get the style reminder; LlmClient excludes Notification turns', re…
  • R16-3 Headless twin buildInitialSystemReminders lacks the style reminder (continueInterrupted re-injection loses it) — already reported (round 11 deferred list 'CLI --continue resume surface gets no style reminder; ACP continuations now do'…
  • R16-5 ecs-qwen timeout block pasted into three test files — already reported (round 15 deferred list, review 5061206621)

Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.

Not reviewed: build-and-test — full packages/cli and packages/core unit suites timed out under shared-runner contention (diff-touched files: 1,453 tests passed); test-efficacy probe inconclusive.

Not explored to full depth (tool budget reached): "agent 1c": exhaustively verifying every test suite that drives LlmClient.sendMessageStream with a partial mock config has all five getters the resolver now calls (527 ca….

Test Plan (not a blocker): src/core/output-styles.test.tsno such file or directory; src/core/prompts.test.tsno such file or directory; src/core/client.test.tsno such file or directory.

中文说明

仅完成部分审查,审查缺口已披露。

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

未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。

未审查:build-and-test — full packages/cli and packages/core unit suites timed out under shared-runner contention (diff-touched files: 1,453 tests passed); test-efficacy probe inconclusive。

未探索到全部深度(达到工具调用预算):"agent 1c"exhaustively verifying every test suite that drives LlmClient.sendMessageStream with a partial mock config has all five getters the resolver now calls (527 ca…

Test Plan(非阻断):src/core/output-styles.test.tsno such file or directory; src/core/prompts.test.tsno such file or directory; src/core/client.test.tsno such file or directory

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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

中文说明

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

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

Partially reviewed — gaps disclosed.

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

  • R17-1 ACP background-notification turns get the style reminder while LlmClient excludes Notification turns — already reported (round 11 deferred list 'ACP notification turns get the style reminder; LlmClient excludes Notification turns', re…
  • R17-2 Redundant outer getOutputStyle?.() pre-guard on the ACP mirror — already reported (round 11 deferred list 'Outer getOutputStyle?.() pre-guard duplicates the resolver's no-style decision', review 5057521972; re-carried as R13-4)
  • R17-3 Style-reminder assembly duplicated between client.ts and Session.ts — already reported (round 11 deferred list 'Style-reminder assembly duplicated between client.ts and Session.ts', review 5057521972; re-carried as R13-2)
  • R17-5 ecs-qwen timeout block pasted into three test files — already reported (round 15 deferred list 'ecs-qwen timeout block pasted into three test files', review 5061206621; re-carried as R16-5)

Not reviewed: build-and-test — the test phase never ran under the build-test harness (install + 15 workspace builds consumed the per-call budget; the packages/cli build also hit its time budget); test-efficacy probe inconclusive with an unvalidated harness.

Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.

Test Plan (not a blocker): src/core/output-styles.test.tsno such file or directory; src/core/prompts.test.tsno such file or directory; src/core/client.test.tsno such file or directory.

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

  • packages/cli/src/acp-integration/session/Session.ts:10676 — [review] ACP reminder gate lacks a QWEN_SYSTEM_MD test at this call site
中文说明

仅完成部分审查,审查缺口已披露。

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

未审查:build-and-test — the test phase never ran under the build-test harness (install + 15 workspace builds consumed the per-call budget; the packages/cli build also hit its time budget); test-efficacy probe inconclusive with an unvalidated harness。

未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。

Test Plan(非阻断):src/core/output-styles.test.tsno such file or directory; src/core/prompts.test.tsno such file or directory; src/core/client.test.tsno such file or directory

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

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

@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 (PR #10282)

Mode: Critical-only mode is active (5 change-producing rounds complete). The actionable sections this round contain no findings — Reviews, Inline comments, and Issue-level comments are all empty. The deferred non-Critical feedback section is an audit record only and was not treated as work. No code changes were made and nothing was committed.

Failed checks — diagnosed as job-level timeouts on the shared ECS pool, not code failures:

The three checks listed as failed all concluded CANCELLED, not FAILURE, in the CI runs for the current HEAD (a51dff9d02, committed 2026-08-30 18:23:29 UTC; the runs started at 18:23:40 UTC). Each one ran right up to its configured job timeout on the shared ecs-qwen self-hosted runner pool:

Check Ran for Configured timeout-minutes
Test (ubuntu-latest, Node 22.x) 90m42s (18:24:08 → 19:54:50Z) 90 (ECS lane, .github/workflows/ci.yml)
Real daemon E2E / Java 11 30m30s (18:24:04 → 18:54:34Z) 30 (.github/workflows/sdk-java.yml)
web-shell E2E Smoke (ubuntu-latest, Node 22.x) 20m27s (19:54:54 → 20:15:21Z) 20 (.github/workflows/ci.yml)

Supporting evidence:

  • All sibling jobs in the same runs are green: Integration Tests (no-AK), both Desktop Shell jobs, and all five SDK Java matrix builds (3m–4m each). The tree is not broadly broken; only the three longest lanes on the shared pool timed out.
  • The Test job's timeout comment in ci.yml itself documents the condition: "Shared ECS hosts can stretch the normally 25-minute lane beyond an hour while tests are still making progress."
  • This PR already contains the mitigation work for this condition (test(ci): budget ecs-pool load spikes in three flaky cli suites), and the follow-up stabilization (ci: stabilize tests under shared ECS host contention, ci: stabilize tests under shared ECS host contention #10552) has already merged to main.

Why no fix was attempted: a CANCELLED-by-timeout result carries no assertion failure and no log evidence pointing at a specific test or code path, so there is no reproducible defect and no code-level hypothesis to implement from the working tree. Raising the timeouts or otherwise editing CI machinery is outside this PR's footprint and maintainer-owned. The workflow's independent CI remains the final verification gate; re-running the cancelled jobs is the appropriate next step.

中文说明

Autofix 轮次:未采取任何行动(PR #10282

模式: 当前处于仅处理 Critical 的模式(已完成 5 个产生改动的轮次)。本轮可执行区域中没有任何发现 —— Reviews、Inline comments 和 Issue-level comments 均为空。被延后的非 Critical 反馈部分仅作为审计记录,不作为本轮工作处理。本轮未做任何代码改动,也没有提交任何内容。

失败检查 —— 经诊断为共享 ECS 资源池上的作业级超时,而非代码失败:

三个被列为失败的检查结论均为 CANCELLED(已取消),而不是 FAILURE(失败),且都属于当前 HEAD(a51dff9d02,提交于 2026-08-30 18:23:29 UTC;相关 CI 运行于 18:23:40 UTC 开始)的 CI 运行。它们全部是在共享的 ecs-qwen 自托管 runner 资源池上一直运行到了各自配置的作业超时上限:

检查 实际运行时长 配置的 timeout-minutes
Test (ubuntu-latest, Node 22.x) 90 分 42 秒(18:24:08 → 19:54:50 UTC) 90(ECS 通道,.github/workflows/ci.yml
Real daemon E2E / Java 11 30 分 30 秒(18:24:04 → 18:54:34 UTC) 30(.github/workflows/sdk-java.yml
web-shell E2E Smoke (ubuntu-latest, Node 22.x) 20 分 27 秒(19:54:54 → 20:15:21 UTC) 20(.github/workflows/ci.yml

佐证:

  • 同一运行中的所有兄弟作业均为绿色:Integration Tests (no-AK)、两个 Desktop Shell 作业,以及全部五个 SDK Java 矩阵构建(各 3–4 分钟)。代码树并未整体损坏;只有共享资源池上三条耗时最长的通道超时了。
  • ci.ymlTest 作业的超时注释本身就记录了这一状况:"共享 ECS 宿主机可能把通常 25 分钟的通道拉长到一个多小时,而测试仍在正常推进。"
  • 本 PR 已经包含针对该状况的缓解工作(test(ci): budget ecs-pool load spikes in three flaky cli suites),后续的稳定化改动(ci: stabilize tests under shared ECS host contentionci: stabilize tests under shared ECS host contention #10552)也已合入 main。

为何未尝试修复: 超时导致的 CANCELLED 结果不包含任何断言失败,也没有日志证据指向具体的测试或代码路径,因此不存在可复现的缺陷,也无法从工作树中得出可实施的代码级假设。调高超时上限或以其他方式修改 CI 机制超出了本 PR 的范围,且属于维护者权限。工作流的独立 CI 仍然是最终验证关口;重新运行被取消的作业是合适的下一步。

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

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