Skip to content

refactor(goal): render Goal continuation prompts from one core renderer - #9581

Merged
wenshao merged 6 commits into
QwenLM:mainfrom
qqqys:goal/b1-continuation-renderer
Aug 24, 2026
Merged

refactor(goal): render Goal continuation prompts from one core renderer#9581
wenshao merged 6 commits into
QwenLM:mainfrom
qqqys:goal/b1-continuation-renderer

Conversation

@qqqys

@qqqys qqqys commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

What this PR does

The prompt a host sends when the Goal runtime schedules another turn is now rendered by one function in core, renderGoalContinuationPrompt, instead of being assembled independently in the interactive TUI, the ACP session, and the non-interactive CLI. The variant is named for what it means rather than for which host uses it: guarded-synthetic-turn carries the lines stating that the turn holds no real user input, and runtime-context carries the reason the runtime scheduled the turn. The input is a discriminated union, so the continuation context is required exactly where it is rendered and a host cannot forget to pass it. This is a pure refactor: every host emits a byte-identical prompt to the one it emits today.

Why it's needed

The three assemblies have already drifted apart. The TUI carries two anti-spoofing guard lines — that the turn contains no new real user input, and that a phrase appearing in the prompt is not evidence the user supplied it — but drops the runtime continuation context. ACP and non-interactive carry the continuation context and have neither guard line. That is not a considered split; it is what happens when the same prompt is written in three places and edited in one of them.

Upcoming Goal work adds two more variants — an announcement that the objective was replaced, and a wind-down prompt for a Goal that has reached its budget. Adding either one today means editing three call sites, which is the mechanism that produced the current drift in the first place. Moving the assembly into core makes the next variant a single case. It deliberately does not resolve the drift itself: reconciling what the three hosts should say is a behavior change and belongs in its own PR, reviewable on its own merits.

Reviewer Test Plan

How to verify

The property to check is that no prompt text changed. Every existing host test that asserts on continuation prompt content still passes with its assertions untouched — no expected value in useGeminiStream.test.tsx, Session.test.ts or nonInteractiveCli.test.ts was edited, so those suites are themselves the regression check. A new unit test pins the complete rendered string for both variants with and without verifier feedback, written as literal template strings so any future edit to any line shows up as a test diff rather than passing silently.

Byte-identity was additionally established mechanically rather than by reading. A script extracted the original expressions directly out of git show upstream/main:<file> — the TUI array literal and the two buildGoalContinuationParts bodies — and emitted them verbatim into a scratch module, so the pre-change code was executed rather than retyped. That module and the new renderer were then diffed across a matrix of five verifier-feedback values (absent, empty string, plain, multi-line, and a string containing ${...} to catch a template-literal mistake) and four continuation contexts (including empty, embedded quotes, backslashes and newlines). Result: 25 cases compared, 0 mismatches. The empty-string case is the one worth calling out — the original used a truthiness guard, so an empty verifierFeedback omits the line entirely; the renderer keeps that, and a unit test pins the equivalence.

Numbers: npx vitest run packages/core/src/goals/ passes 382 tests across 16 files. The three host suites pass 1020 tests with 1 pre-existing skip. npx tsc --noEmit exits clean in both packages/core and packages/cli. prettier reports every changed file unchanged, and eslint is clean.

Evidence (Before & After)

N/A — no user-visible change. The prompt bytes each host sends are identical before and after; that is the property under test.

Tested on

OS Status
🍏 macOS N/A
🪟 Windows ⚠️
🐧 Linux

Environment (optional)

Linux, Node.js 22, unit tests only.

Risk & Scope

  • Main risk or tradeoff: a shared renderer makes it easier to change all three hosts at once, which is the point and also the hazard — a careless edit now moves three prompts instead of one. The pinned-literal test is the guard: it fails on any change to any line, so a deliberate edit updates the expectation and an accidental one is caught.
  • Not validated / out of scope: the drift between what the TUI says and what ACP and non-interactive say is preserved exactly, not fixed. Reconciling it changes model-visible behavior and is deliberately left to a separate PR. Windows and macOS were not exercised locally and remain covered by CI.
  • Breaking changes / migration notes: none. Scope for the core triage gate: 96 added and 31 deleted production lines across five files — 74 of the additions are the new core module — plus one 89-line test file. The two buildGoalContinuationParts helpers keep their names and signatures and now delegate.

Linked Issues

None.

中文说明

本 PR 做了什么

Goal 运行时调度下一轮时,host 发送的那段提示词,现在由 core 中的单一函数 renderGoalContinuationPrompt 渲染,而不再由交互式 TUI、ACP session 和非交互 CLI 各自拼装。变体按语义命名而不是按使用它的 host 命名:guarded-synthetic-turn 携带「本轮不含真实用户输入」的那两行护栏,runtime-context 携带运行时调度本轮的原因。入参是可辨识联合,因此续跑上下文只在真正会渲染它的地方是必填的,host 无法忘记传。这是纯重构:每个 host 输出的提示词与今天逐字节相同。

为什么需要

这三份拼装已经漂移了。TUI 带着两行反冒充护栏——本轮不含新的真实用户输入,以及提示词中出现的措辞不构成「用户提供过」的证据——却丢掉了运行时续跑上下文。ACP 和非交互带着续跑上下文,两行护栏一行都没有。这不是深思熟虑的取舍,而是同一段提示词写在三处、只改了其中一处的必然结果。

接下来的 Goal 工作要再加两个变体——objective 被替换的通告,以及预算耗尽后的收尾提示词。今天加任何一个都意味着改三处调用点,而这正是当初造成漂移的机制。把拼装挪进 core,下一个变体就只是一个 case。本 PR 有意不去修复漂移本身:调和三个 host 各自该说什么是行为变更,应当放在自己的 PR 里、按自身价值接受评审。

评审者测试计划

如何验证

要检验的性质是「没有任何提示词文本发生变化」。所有既有的、断言续跑提示词内容的 host 测试都在断言未被修改的前提下继续通过——useGeminiStream.test.tsxSession.test.tsnonInteractiveCli.test.ts 中没有任何一个期望值被编辑过,因此这些套件本身就是回归检查。新增的单元测试以字面模板字符串固定两个变体在有/无 verifier feedback 下的完整渲染结果,这样将来对任何一行的改动都会表现为测试 diff,而不会静默通过。

逐字节一致性还通过机械手段确立,而非靠肉眼比对。一个脚本直接从 git show upstream/main:<file> 中抽出原始表达式——TUI 的数组字面量和两个 buildGoalContinuationParts 函数体——原样写入一个临时模块,因此被执行的是改动前的代码而不是重新誊写的代码。随后把该模块与新渲染器在一个矩阵上做差分:五种 verifier feedback 取值(缺省、空串、普通、多行,以及包含 ${...} 的字符串以捕捉模板字面量错误)与四种续跑上下文(含空串、内嵌引号、反斜杠和换行)。结果:比较 25 组用例,0 处不一致。空串这一组特别值得点出——原代码用的是真值判断,因此空的 verifierFeedback 会整行省略;渲染器保留了这一行为,并有一个单元测试固定这个等价性。

数字:npx vitest run packages/core/src/goals/ 通过 16 个文件共 382 个测试。三个 host 套件通过 1020 个测试,另有 1 个既有的 skip。npx tsc --noEmitpackages/corepackages/cli 均干净退出。prettier 报告所有改动文件未变,eslint 干净。

证据(修复前后)

N/A —— 无用户可见变化。每个 host 发送的提示词字节在改动前后完全相同,这正是被检验的性质。

测试平台

操作系统 状态
🍏 macOS N/A
🪟 Windows ⚠️
🐧 Linux

环境(可选)

Linux、Node.js 22,仅单元测试。

风险与范围

  • 主要风险或取舍:共享渲染器让「一次改动三个 host」变容易,这既是目的也是隐患——一次粗心的编辑现在会同时移动三段提示词。字面量固定测试就是那道防线:任何一行的任何改动都会让它失败,于是有意的编辑会同步更新期望值,无意的编辑会被拦住。
  • 未验证/不在范围:TUI 与 ACP、非交互之间的措辞漂移被原样保留,没有修复。调和它会改变模型可见的行为,有意留给单独的 PR。Windows 和 macOS 未在本地验证,仍由 CI 覆盖。
  • 破坏性变更/迁移说明:无。供 core triage gate 参考的规模:五个文件、新增 96 行、删除 31 行生产代码——其中 74 行新增是那个新的 core 模块——外加一个 89 行的测试文件。两个 buildGoalContinuationParts 辅助函数保留原名与原签名,现在只做转发。

关联 Issue

无。

The prompt sent when `runtime.finishTurn` schedules another Goal turn was
assembled independently in three hosts: the TUI's inline array in
`useGeminiStream`, and a `buildGoalContinuationParts` in each of the ACP
session and the non-interactive CLI. Three copies of the same four shared
lines have already drifted -- the TUI carries the anti-spoofing guard lines
but no objective, while ACP and non-interactive carry the runtime
continuation context but no guard lines.

Upcoming work adds further variants (an "objective was edited" announcement
and a budget wind-down prompt). With the text living in three places, every
new variant means three edits, which is precisely how the current drift was
produced. This moves assembly into `packages/core/src/goals/goal-continuation-prompt.ts`,
where a variant is a case in one function and the shared prefix exists once.
The two `buildGoalContinuationParts` helpers keep their names and signatures
and simply delegate.

This is a pure refactor: no prompt text changes. Each host still emits a
byte-identical string to the one it emitted before. The existing drift is
preserved deliberately and is left for a separate, behavior-changing
follow-up. The new unit test pins the complete rendered string for both
variants with and without verifier feedback, so any future edit to a line
surfaces as a test diff; the existing host tests pass unmodified.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Qwen Triage finishedview run. See the stage comments in this thread for the result.

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

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Re-run on an unmoved head — nothing has landed since the last pass reviewed 5218760b, so this pass re-derived the gate against the base tree rather than carrying the old conclusion forward.

Thanks for the PR!

Template looks good ✓

Problem: real and observable in-tree, not theoretical. On main, three hosts assemble the same Goal continuation prompt independently, and they have drifted — the TUI carries the two anti-spoofing guard lines but drops the runtime continuation context, while ACP and the non-interactive CLI carry the context and neither guard line. Both shapes verified in the base tree this pass.

Direction: aligned. Consolidating the assembly into one core renderer ahead of the announced further Goal variants is the right sequencing, and keeping the output byte-identical makes the change reviewable as a pure refactor. Reconciling the drift is correctly deferred to its own PR, since that is a model-visible behavior change.

Size: 137 production lines — Session.ts 18, nonInteractiveCli.ts 18, useGeminiStream.ts 16, new core module 80, goals/index.ts 5 — plus 155 test lines and no generated/schema lines. Well under the 500-line Tier 1 threshold for core refactors, so no hard block; the Tier 2 100%-confidence bar for core changes applies and is the standard this pass held the diff to.

Approach: matches the independent proposal — one renderer in packages/core/src/goals/, input shaped as a discriminated union so continuationContext is required exactly where it is rendered, both existing host helpers now delegating, and pinned-literal tests guarding the exact bytes. Every edit is load-bearing; no drive-by changes.

Risk: acp-integration is on the revert-correlated high-risk path list (Session.ts) — flagged for reviewer focus, with full CI evidence required before any approval (Stage 2 carries it).

Moving on to code review. 🔍

中文说明

在未移动的 head 上重跑——自上次审查 5218760b 后没有新提交,因此本次重新对照 base 树推导门禁结论,而不是沿用旧结论。

感谢贡献!

模板完整 ✓

问题:真实存在、可在代码树中直接观察到,而非理论问题。在 main 上,三个 host 各自独立拼装同一段 Goal 续跑提示词,且已经漂移——TUI 带着两行反冒充护栏但丢了运行时续跑上下文,ACP 和非交互 CLI 带着上下文却没有护栏行。本次已在 base 树中核实两种形态。

方向:对齐。在已预告的 Goal 新变体之前把拼装收敛到 core 的单一 renderer,时机正确;保持输出逐字节不变,使该改动可以作为纯重构来审查。统一措辞漂移正确地留到单独 PR——那是模型可见的行为变更。

规模:137 行生产代码(Session.ts 18、nonInteractiveCli.ts 18、useGeminiStream.ts 16、新 core 模块 80、goals/index.ts 5)+ 155 行测试,无生成/schema 行。远低于 core 重构 500 行的 Tier 1 阈值,不触发硬拦截;适用 Tier 2 对 core 改动的 100% 置信标准,本次也按此标准审查。

方案:与独立提案一致——在 packages/core/src/goals/ 中实现单一 renderer,入参用可辨识联合使 continuationContext 恰好在渲染处必填,两个既有 host helper 改为委托,并用字面量测试钉住逐字节输出。每处改动都必要,无夹带改动。

风险:acp-integration 属于与 revert 相关的高风险路径(Session.ts)——提示审阅者重点关注,且批准前必须有完整 CI 证据(见 Stage 2)。

进入代码审查。🔍

Qwen Code · qwen3.8-max

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

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Code review — re-run on an unmoved head

Nothing has landed since 5218760b was last reviewed — no commits, same eight files, same 247/45. Rather than carry the old conclusion forward, this pass re-derived it against the base tree.

Independent proposal first: three copies of the same prompt have drifted; the fix I'd reach for is one renderer in packages/core/src/goals/ with a discriminated-union input (so the continuation context is required exactly where it is rendered), hosts delegating to it, and the exact strings pinned by literal tests. That is precisely what this PR does — the approach matches, and I did not find a simpler path it missed.

Byte-identity, re-checked line by line against base:

  • TUI (useGeminiStream.ts): the removed array was the four shared lines + the two anti-spoofing guard lines + conditional Verifier feedback: line, joined with \n. The new guarded-synthetic-turn variant renders exactly that — I compared every literal against the base tree and the pinned test string, character for character. Line order and the truthiness guard (empty-string feedback omits the line) are preserved.
  • ACP (Session.ts) and non-interactive (nonInteractiveCli.ts): the two removed buildGoalContinuationParts bodies were byte-identical to each other — four shared lines + Runtime continuation context: + conditional feedback, wrapped in one text Part. The core buildGoalContinuationParts produces the same shape via the runtime-context variant.
  • Call sites are untouched: Session.ts:2284 and the three nonInteractiveCli.ts sites (1216, 2507, 2537) now resolve to the imported function. Both turn interfaces (AcpGoalTurn, HeadlessGoalTurn) carry continuationContext: string and verifierFeedback?: string, which structurally satisfies the core parameter.

Nothing else in the diff: no export collisions (grepped core for the new symbol names), goals/index.ts is already re-exported from the package root, Part comes from @google/genai which core already depends on, and the new files follow house conventions (kebab-case, collocated test, license header, ESM .js specifiers). The test edits are additions only — every pre-existing expectation in the three host suites is untouched, which is what makes those suites the regression check the PR claims they are. No blockers, no AGENTS.md violations.

Testing evidence — the PR's own CI, read via the API

Per the unattended-run rules, no PR code is built or executed here. Check-runs below were fetched from the commits API for 5218760b — real names and conclusions, nothing taken from the PR description.

Check Conclusion
Test (ubuntu-latest, Node 22.x) ✅ success
web-shell E2E Smoke (ubuntu-latest, Node 22.x) ✅ success
Desktop Shell (ubuntu-22.04) ✅ success
Desktop Shell (windows-2022) ✅ success
Dependency CVE audit ✅ success
Secret scan (TruffleHog) ✅ success
Real daemon E2E / Java 11 ✅ success
Test (macos-latest, Node 22.x) ⏭️ skipped
Test (windows-latest, Node 22.x) ⏭️ skipped
Integration Tests (CLI, No Sandbox) ⏭️ skipped

The unit suite is green on this exact head, and there are no red checks — the only non-green conclusions are skips and duplicate orchestration jobs cancelled in favor of their successful twins. The macOS/Windows unit jobs and the sandboxed integration job being skipped is consistent with fork-PR runner/secret limits, not a failure signal; for a diff that is pure string assembly with no platform-specific path the coverage gap is immaterial — and it is closed by the sandboxed A/B below anyway.

On the behavioural claim itself — byte-identical prompts — CI green only shows the tests pass, and this PR's static review is unusually well-placed to settle the rest: the pinned literal tests fail on any edit to any line, and I re-compared every removed expression against the base tree character by character. Independently, the thread already carries three passing sandboxed /verify runs on this exact head plus a maintainer-run A/B (55/55 byte-identity assertions, verdict: merge-ready). Not verified here: nothing material — the one remaining gap, live TUI behaviour, is N/A for a refactor that changes no rendered byte. Real-scenario tmux testing: N/A (unattended CI run; nothing user-visible).

中文说明

代码审查——未移动 head 上的重跑

自上次审查 5218760b 以来没有新提交——文件、行数均未变。本次没有沿用旧结论,而是重新对照 base 树推导。

独立提案:三份相同提示词已经漂移;我会采用的修法是在 packages/core/src/goals/ 中放一个 renderer,入参用可辨识联合(让续跑上下文恰好在渲染处必填),host 委托给它,并用字面量测试钉住精确字符串。这正是本 PR 的做法——方案吻合,我也没有找到更简单的路径。

逐字节一致性,已逐行对照 base 复核

  • TUIuseGeminiStream.ts):被删除的数组是四行共享行 + 两行反冒充护栏 + 条件 Verifier feedback: 行,以 \n 连接。新的 guarded-synthetic-turn 变体渲染结果完全一致——逐字符对照了 base 树与被钉住的测试串;行序与真值守卫(空字符串时省略该行)均保留。
  • ACPSession.ts)与非交互nonInteractiveCli.ts):两个被删除的 buildGoalContinuationParts 函数体彼此逐字节相同——四行共享行 + Runtime continuation context: + 条件 feedback,包在单个 text Part 中。core 的 buildGoalContinuationPartsruntime-context 变体产生相同形状。
  • 调用点未动:Session.ts:2284nonInteractiveCli.ts 的三处(1216、2507、2537)现在解析到导入的函数。两个 turn 接口均含 continuationContext: stringverifierFeedback?: string,结构上满足 core 参数要求。

diff 中再无其他:无导出名冲突,goals/index.ts 本就从包根 re-export,Part 来自 core 已有依赖 @google/genai,新文件符合仓库惯例(kebab-case、同目录测试、license 头、ESM .js 后缀)。测试改动均为新增——三个 host 套件中所有既有期望值未被触碰,这正是它们能作为回归检查的原因。无阻塞项,无 AGENTS.md 违规。

测试证据——PR 自身 CI,经 API 读取

无人值守运行规则下,此处不构建、不执行任何 PR 代码。检查项取自 5218760b 的 commits API——真实检查名与结论,未采信 PR 描述中的说法。主单测套件在该 head 上为绿,无红色检查;macOS/Windows 单测与沙箱集成任务的跳过符合 fork PR 的 runner/密钥限制,对该 diff(纯字符串拼装、无平台相关路径)影响为零,且已由沙箱 A/B 验证补足。关于行为性主张(逐字节一致):钉住的字面量测试对任何一行的改动都会失败,我已将每段被删表达式与 base 树逐字符复核;线程中另有三次沙箱 /verify 通过及维护者自跑的 A/B(55/55 断言,结论:可合并)。真实场景 tmux 测试:N/A(无人值守 CI 运行;无用户可见变化)。

Qwen Code · qwen3.8-max

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

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Confidence: 3/5 — clean re-derivation on an unmoved head; the fork-refactor approval guardrail, not any finding, caps the score and keeps the bot's approval out.

Stepping back: nothing has moved since the last pass reviewed 5218760b, and re-deriving the review against the base tree changed nothing. The approach matches my independent proposal exactly — one renderer in core, discriminated-union input, delegating hosts, pinned literal tests — and I could not find a simpler one. Every edit in the diff is load-bearing; there are no drive-bys, no over-abstraction, and the one hazard a shared renderer introduces (an accidental edit now moves three prompts instead of one) is guarded by tests that fail on any changed byte. Byte-identity was re-verified character by character against the base tree, the unit suite is green on this exact head, and the thread already carries three passing sandboxed A/B verifications plus a maintainer-run byte-identity matrix. If this were an in-repo PR, the verdict would be approve without hesitation.

It is a fork refactor, so the deterministic guardrail applies: cross-repository refactor PRs are never auto-approved, however clean the stages look — the decision belongs to a maintainer. All CI on this head has settled (no pending pull_request runs), so there is nothing left to wait for either; what remains is a human call, not more work on the diff.

⏸️ Deferring to @wenshao — fork-refactor approval guardrail. The gate has no findings of its own against this head; main requires two approving reviews, you have supplied one, and the bot's is the one this policy withholds. Second sign-off (or an override) is a maintainer's call.

中文说明

置信度:3/5 —— 在未移动 head 上重新推导后结论干净;压低分数、扣下机器人批准的不是任何发现,而是 fork 重构 PR 的审批护栏。

退一步看:自上次审查 5218760b 以来没有任何变化,重新对照 base 树推导也没有改变任何判断。方案与我的独立提案完全一致——core 中单一 renderer、可辨识联合入参、host 委托、字面量钉住测试——我也找不到更简单的方案。diff 中每处改动都必要:无夹带、无过度抽象,而共享 renderer 引入的唯一风险(一次手误会同时改动三处提示词)由对任何字节改动都会失败的测试防住。逐字节一致性已对照 base 树逐字符复核,主单测套件在该 head 上为绿,线程中还有三次沙箱 A/B 验证通过及维护者自跑的字节一致矩阵。若这是仓库内部 PR,结论会是毫不犹豫地批准。

这是一个 fork 的 refactor,因此确定性护栏生效:无论各阶段多干净,跨仓库重构 PR 都不自动批准——决定权在维护者。该 head 的所有 CI 已结束(无待完成的 pull_request 运行),因此也没有任何需要等待的东西;剩下的是人的决定,而不是 diff 上的更多工作。

⏸️ 转交 @wenshao —— fork 重构审批护栏。门禁对该 head 没有任何自己的发现;main 需要两个批准,您已给出一个,而护栏扣下的正是机器人的那一个。第二个签核(或 override)由维护者决定。

Qwen Code · qwen3.8-max

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

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed — no blockers. Suggestions are inline.

中文说明

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

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

Comment thread packages/cli/src/acp-integration/session/Session.ts Outdated
Comment thread packages/core/src/goals/goal-continuation-prompt.ts Outdated
Comment thread packages/cli/src/nonInteractiveCli.ts Outdated

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed — no blockers. Suggestions are inline.

中文说明

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

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

Comment thread packages/cli/src/acp-integration/session/Session.test.ts
Comment thread packages/cli/src/nonInteractiveCli.ts Outdated

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed. Suggestions are inline.

Not explored to full depth (tool budget reached): "agent 6c": root-cause the observed one-off flake (instrument bindGoalTurnHost invocation order and goalOrigin of the first send, then repeat runs until failure to iden….

中文说明

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

未探索到全部深度(达到工具调用预算):"agent 6c"root-cause the observed one-off flake (instrument bindGoalTurnHost invocation order and goalOrigin of the first send, then repeat runs until failure to iden…

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

Comment thread packages/cli/src/nonInteractiveCli.ts Outdated
@wenshao

wenshao commented Aug 22, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code takeover

@wenshao

wenshao commented Aug 22, 2026

Copy link
Copy Markdown
Collaborator

@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 22, 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-dev-bot

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

Copy link
Copy Markdown
Collaborator

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

中文说明

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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

Autofix review-response summary — PR #9581 (round on HEAD 0db1e18577)

Base main, no conflict (--conflict false, no merge performed). One commit this round:
refactor(goal): hoist Goal continuation parts builder into core (#9581) (0db1e18577).

Feedback points and dispositions

Implemented

  • [rc:3823557703] / [rc:3822662982] / [rc:3821799813] — R1-3, automated reviewer [Suggestion], raised in rounds 1–3: the buildGoalContinuationParts wrapper was byte-identical in nonInteractiveCli.ts and Session.ts (only the parameter type name differed, HeadlessGoalTurn vs AcpGoalTurn). Verified the duplication by inspection, then implemented the suggested hoist: the wrapper now lives in packages/core/src/goals/goal-continuation-prompt.ts next to the renderer, with the structural parameter type { continuationContext: string; verifierFeedback?: string } that both host turn types satisfy, and is exported from the goals barrel. Both hosts delete their local copies and import it from core. Added one core contract test pinning the wrapper's shape (single text Part), variant choice (runtime-context), and field wiring. The adjacent sameGoalPermit helper remains duplicated: the finding's proposed change named only the wrapper, so the change stays scoped to that ask.

Re-verified as already fixed at HEAD (no new change needed)

  • [rc:3821799798] — R1-1 [Suggestion]: variant-specific host assertions. Fixed in f0b322cc14; re-verified at HEAD — Session.test.ts pins Runtime continuation context: check weather and nonInteractiveCli.test.ts pins Runtime continuation context: existing goal; both tests pass in this round's runs.
  • [rc:3821799806] — R1-2 [Suggestion]: unused GoalContinuationVariant alias. Fixed in f0b322cc14; re-verified at HEAD — a repo-wide grep finds no remaining declaration, re-export, or read site.
  • [rc:3822662970] — R2-1 [Suggestion]: host-level tests for the verifierFeedback wiring. Fixed in 4e35a4b811; re-verified at HEAD — Session.test.ts (runs a host-scheduled Goal turn with the canonical permit) and nonInteractiveCli.test.ts (includes verifier feedback in a scheduled Goal continuation) pin the Verifier feedback: line and both pass.

No action required

  • [rc:3822165238] / [rc:3822165791] / [rc:3823020672] — @qqqys replies: maintainer confirmations of the fixes above, not findings.
  • [ic:5382003142] — @wenshao: @qwen-code takeover: workflow invocation that handed this PR to the bot; carries no code change request.
  • Review bodies [rv:4983002676], [rv:4983452715], [rv:4983453364], [rv:4984078305], [rv:4984579913], [rv:4985237232]: no blockers; their actionable inline findings are covered above.

Mutation probe (witness for the new code)

Before committing, mutated the new core buildGoalContinuationParts by deleting the verifierFeedback: turn.verifierFeedback wiring line:

  • packages/core focused test: FAILED (1 failed | 5 passed — the new wrapper contract test).
  • Session.test.ts -t 'runs a host-scheduled Goal turn with the canonical permit': FAILED.
  • nonInteractiveCli.test.ts -t 'includes verifier feedback in a scheduled Goal continuation': FAILED.

Restored the line and re-ran: all green (core 6/6; both CLI suites 794 passed | 1 skipped). The hosts demonstrably route through the hoisted core wrapper, and the feedback wiring is witnessed end-to-end.

Environment repair (not a code issue)

npm run build initially failed with TypeScript errors in packages/core/src/telemetry/* (files this PR does not touch; git diff origin/main...HEAD -- telemetry is empty). Diagnosis: the runner's node_modules had drifted from package-lock.json@opentelemetry/* was installed at 0.221.0 while the lockfile pins 0.203.0, and 0.221.0's LogRecordExporter interface added forceFlush, breaking compilation of the untouched telemetry code. Repaired with npm ci using a private cache directory (the default ~/.npm cache parent /home/github-runner is root-owned and not writable by this user). After the repair the build passes; no dependency or lockfile changes were committed.

Verification

  • npm ci --cache /tmp/npm-cache-9581 — passed (environment repair, see above)
  • npm run build — passed (failed before the dependency repair, green after)
  • npm run typecheck — passed
  • npm run lint — passed
  • npx vitest run src/goals/goal-continuation-prompt.test.ts (packages/core) — 6 passed
  • npx vitest run src/nonInteractiveCli.test.ts (packages/cli) — 128 passed | 1 skipped
  • npx vitest run src/acp-integration/session/Session.test.ts (packages/cli) — 666 passed
  • npx vitest run src/acp-integration/session/Session.test.ts src/nonInteractiveCli.test.ts (packages/cli) — 794 passed | 1 skipped
  • npx prettier --check on the five touched files — clean
  • Mutation probe: wrapper feedback-wiring deletion → 3 focused tests fail; restore → green (details above)
  • Integration tests after npm run bundle: not required — the changed behavior is exercised by the host unit suites, not only through the bundled CLI. No settings source touched, so no schema regeneration.
中文说明

Autofix 审查响应总结 — PR #9581(本轮 HEAD 0db1e18577

基线 main,无冲突(--conflict false,未执行合并)。本轮一个提交:refactor(goal): hoist Goal continuation parts builder into core (#9581)0db1e18577)。

反馈点及处置

已实现

  • [rc:3823557703] / [rc:3822662982] / [rc:3821799813] — R1-3,自动审查器 [Suggestion],第 1–3 轮连续提出buildGoalContinuationParts 包装函数在 nonInteractiveCli.tsSession.ts 中逐字节相同(仅参数类型名不同,HeadlessGoalTurnAcpGoalTurn)。先通过代码检查确认重复属实,随后按建议实现提升:该包装函数现在与渲染器一起位于 packages/core/src/goals/goal-continuation-prompt.ts,参数使用两个 host turn 类型都满足的结构化类型 { continuationContext: string; verifierFeedback?: string },并从 goals 桶文件导出。两个 host 删除各自的本地副本、改为从 core 导入。新增一个 core 契约测试,固定包装函数的形状(单个文本 Part)、变体选择(runtime-context)与字段接线。紧邻的 sameGoalPermit 辅助函数仍保持重复:该发现的建议修复只点名了包装函数,因此本次改动限定在这一诉求内。

已复核——HEAD 上已修复(无需新改动)

  • [rc:3821799798] — R1-1 [Suggestion]:host 级变体特有断言。已在 f0b322cc14 修复;在 HEAD 复核——Session.test.ts 固定了 Runtime continuation context: check weathernonInteractiveCli.test.ts 固定了 Runtime continuation context: existing goal;两个测试在本轮运行中均通过。
  • [rc:3821799806] — R1-2 [Suggestion]:未使用的 GoalContinuationVariant 别名。已在 f0b322cc14 修复;在 HEAD 复核——全仓库 grep 未找到任何残留声明、再导出或读取点。
  • [rc:3822662970] — R2-1 [Suggestion]verifierFeedback 接线的 host 级测试。已在 4e35a4b811 修复;在 HEAD 复核——Session.test.tsruns a host-scheduled Goal turn with the canonical permit)与 nonInteractiveCli.test.tsincludes verifier feedback in a scheduled Goal continuation)固定了 Verifier feedback: 行,且均通过。

无需处理

  • [rc:3822165238] / [rc:3822165791] / [rc:3823020672] — @qqqys 的回复:维护者对上述修复的确认,不是发现项。
  • [ic:5382003142] — @wenshao@qwen-code takeover:将该 PR 交给机器人处理的工作流调用,不包含代码改动诉求。
  • 审查主体 [rv:4983002676]、[rv:4983452715]、[rv:4983453364]、[rv:4984078305]、[rv:4984579913]、[rv:4985237232]:无阻断问题;其可执行的行内发现均已在上面覆盖。

变异探针(新代码的见证)

提交前,对新的 core buildGoalContinuationParts 做变异——删除 verifierFeedback: turn.verifierFeedback 接线行:

  • packages/core 聚焦测试:失败(1 失败 | 5 通过——正是新增的包装函数契约测试)。
  • Session.test.ts -t 'runs a host-scheduled Goal turn with the canonical permit'失败
  • nonInteractiveCli.test.ts -t 'includes verifier feedback in a scheduled Goal continuation'失败

恢复该行后重跑:全部转绿(core 6/6;两个 CLI 套件 794 通过 | 1 跳过)。这证明两个 host 确实经由提升后的 core 包装函数,且 feedback 接线在端到端被见证。

环境修复(非代码问题)

npm run build 最初在 packages/core/src/telemetry/* 上报 TypeScript 错误(本 PR 未触碰这些文件;git diff origin/main...HEAD -- telemetry 为空)。诊断:该运行器的 node_modulespackage-lock.json 漂移——@opentelemetry/* 安装为 0.221.0,而锁文件固定 0.203.0,0.221.0 的 LogRecordExporter 接口新增了 forceFlush,导致未触碰的 telemetry 代码编译失败。用私有缓存目录执行 npm ci 修复(默认的 ~/.npm 缓存父目录 /home/github-runner 属 root 所有,当前用户不可写)。修复后构建通过;未提交任何依赖或锁文件改动。

验证

  • npm ci --cache /tmp/npm-cache-9581 — 通过(环境修复,见上)
  • npm run build — 通过(依赖修复前失败,修复后转绿)
  • npm run typecheck — 通过
  • npm run lint — 通过
  • npx vitest run src/goals/goal-continuation-prompt.test.ts(packages/core)— 6 通过
  • npx vitest run src/nonInteractiveCli.test.ts(packages/cli)— 128 通过 | 1 跳过
  • npx vitest run src/acp-integration/session/Session.test.ts(packages/cli)— 666 通过
  • npx vitest run src/acp-integration/session/Session.test.ts src/nonInteractiveCli.test.ts(packages/cli)— 794 通过 | 1 跳过
  • 对五个触碰文件执行 npx prettier --check — 干净
  • 变异探针:删除包装函数 feedback 接线 → 3 个聚焦测试失败;恢复 → 转绿(详见上文)
  • npm run bundle 后的集成测试:不需要——改动的行为由 host 单元测试套件覆盖,并非只能通过打包后的 CLI 验证。未触碰任何设置源,无需重新生成 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 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.

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

中文说明

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

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

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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

Autofix round: no code changes

Feedback triage

This round's feedback contains a single item: review [rv:5001018635] from the automated reviewer, status COMMENTED, with zero findings ("findings":[],"posted":0). It is a disclosed verification gap, not a defect claim:

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

There are no inline comments, no issue-level comments, no failed checks, and no still-red checks. Nothing requests a code change.

Why the check was "skipped" in CI: the Integration Tests (CLI, No Sandbox) job (integration_cli in .github/workflows/ci.yml) is gated on github.event_name == 'merge_group' — by design it only runs in the merge queue, never on PR pushes. The skip on this PR is expected workflow behavior, not a malfunction.

Decision: since the disclosed gap is the only actionable content, this round closes it with local evidence instead of a code change. No code was modified; HEAD remains 0db1e18577 and the working tree is clean.

Closing the gap locally

The environment needed repair before the suite could run (details below), then the exact disclosed suite was run against the bundled CLI built from this PR's HEAD:

  • npm run test:integration:cli:sandbox:none191 passed, 18 skipped, 1 failed (38 test files)

The single failure is environmental, proven by surrogate:

  • Failing test: cli/qwen-config-dir.test.ts > 1d: CLI functions normally when QWEN_HOME is not set (failed 3× with retries).
  • Exact failure: Error: EACCES: permission denied, mkdir '/home/github-runner/.qwen' in writeOutputLanguageFileinitializeLlmOutputLanguage — the CLI's output-language bootstrap writing to ~/.qwen, a code path this PR does not touch (this PR only refactors Goal continuation prompt rendering).
  • Root cause on this runner: HOME is /home/github-runner, owned by root with mode drwxr-xr-x, while the tests run as uid 1000 without sudo — so nothing under HOME can be created. The same anomaly independently broke the npm cache (EACCES mkdir /home/github-runner/.npm) before the suite could even build.
  • Surrogate proof: rerunning exactly test 1d with a writable HOME (HOME=/tmp/qwen-home-surrogate-9581) passes in 8.7s. In CI the runner's home is writable (and the workflow restores workspace ownership), so this failure does not reproduce there.
  • Test 1d is also unrelated to this PR by construction: it deletes QWEN_HOME and asserts a default prompt run; the goal-continuation code paths (useGeminiStream, nonInteractiveCli, ACP Session) require an active/paused Goal turn, which this test never creates.

All Goal-related and ACP/serve/headless integration tests in the suite passed.

Environment repairs performed (not code changes)

  • node_modules had drifted from package-lock.json (a nested @opentelemetry/api-logs@0.221.0 instead of the locked 0.203.0, plus a half-deleted picomatch staging dir from an interrupted install), which broke npm run build in packages/core telemetry code. Wiped all node_modules trees and restored the exact locked tree with npm ci --cache /tmp/qwen-npm-cache-9581 (private cache because the default ~/.npm is root-owned and inaccessible).
  • These repairs touch no tracked files; git status is clean and HEAD is unchanged.

Verification

  • npm ci --cache /tmp/qwen-npm-cache-9581 — passed (restores lockfile-exact dependency tree)
  • npm run build — passed
  • npm run bundle — passed (fresh dist/cli.js from HEAD)
  • npm run typecheck — passed (0 errors)
  • npm run lint — passed (0 errors)
  • cd packages/core && npx vitest run src/goals/goal-continuation-prompt.test.ts — 6 passed
  • cd packages/cli && npx vitest run src/nonInteractiveCli.test.ts src/acp-integration/session/Session.test.ts — 794 passed, 1 skipped
  • npm run test:integration:cli:sandbox:none — 191 passed, 18 skipped, 1 failed (environmental, see above)
  • Surrogate: QWEN_SANDBOX=false HOME=/tmp/qwen-home-surrogate-9581 npx vitest run --root ./integration-tests cli/qwen-config-dir.test.ts -t "1d: …" — 1 passed

Conclusion: no action required on the code. The disclosed verification gap is closed with local evidence: the merge-queue-only integration suite passes on this PR's HEAD except for one test proven to fail solely because this self-hosted runner's HOME is not writable by the test user.

中文说明

Autofix 本轮:无代码改动

反馈分诊

本轮反馈仅包含一条:自动审查器的评审 [rv:5001018635],状态为 COMMENTED零条发现"findings":[],"posted":0)。它披露的是一个验证缺口,而非缺陷指控:

Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.(未审查:build-and-test —— 集成测试(CLI,无沙箱)在 CI 中被跳过,且该套件未在本地运行。)

没有行内评论、没有 issue 级评论、没有失败检查、也没有持续失败的检查。没有任何内容要求代码改动。

该检查在 CI 中"被跳过"的原因: Integration Tests (CLI, No Sandbox) 任务(.github/workflows/ci.yml 中的 integration_cli)以 github.event_name == 'merge_group' 为条件 —— 按设计它只在合并队列中运行,从不在 PR 推送时运行。本 PR 上的跳过是预期的工作流行为,并非故障。

决定: 由于披露的缺口是唯一可操作的内容,本轮用本地证据来弥补它,而不是做代码改动。未修改任何代码;HEAD 仍为 0db1e18577,工作树保持干净。

在本地弥补该缺口

运行套件前需要先修复环境(详见下文),随后针对从本 PR HEAD 构建的捆绑 CLI 运行了被披露的那个套件:

  • npm run test:integration:cli:sandbox:none191 通过、18 跳过、1 失败(38 个测试文件)

唯一的失败是环境性的,已通过替代实验证明:

  • 失败测试:cli/qwen-config-dir.test.ts > 1d: CLI functions normally when QWEN_HOME is not set(含重试共失败 3 次)。
  • 确切错误:Error: EACCES: permission denied, mkdir '/home/github-runner/.qwen',发生在 writeOutputLanguageFileinitializeLlmOutputLanguage —— 即 CLI 向 ~/.qwen 写入的输出语言初始化代码路径,而本 PR 并未触及该路径(本 PR 仅重构 Goal 续接提示词的渲染)。
  • 本运行器上的根因:HOME/home/github-runner,属主为 root、权限 drwxr-xr-x,而测试以 uid 1000 运行且无 sudo —— 因此无法在 HOME 下创建任何内容。同一异常还独立地破坏了 npm 缓存(EACCES mkdir /home/github-runner/.npm),导致套件在构建前就无法运行。
  • 替代证明:仅重跑测试 1d 并使用可写的 HOMEHOME=/tmp/qwen-home-surrogate-9581在 8.7 秒内通过。在 CI 中运行器的主目录是可写的(且工作流会恢复工作区属主),因此该失败不会在那里复现。
  • 测试 1d 从构造上也与本 PR 无关:它删除 QWEN_HOME 并断言一次默认提示运行;而 goal-continuation 代码路径(useGeminiStreamnonInteractiveCli、ACP Session)需要一个活跃/暂停的 Goal 回合,该测试从不创建这种状态。

套件中所有与 Goal 相关以及 ACP/serve/headless 的集成测试均已通过。

所执行的环境修复(非代码改动)

  • node_modules 已与 package-lock.json 脱节(嵌套了 @opentelemetry/api-logs@0.221.0 而非锁定的 0.203.0,另有一个来自中断安装的半删除 picomatch 暂存目录),导致 packages/core 的遥测代码在 npm run build 时失败。已清除所有 node_modules 树,并用 npm ci --cache /tmp/qwen-npm-cache-9581 恢复与锁文件完全一致的依赖树(使用私有缓存是因为默认的 ~/.npm 属主为 root、不可访问)。
  • 这些修复不触及任何被跟踪文件;git status 干净,HEAD 未变。

验证

  • npm ci --cache /tmp/qwen-npm-cache-9581 —— 通过(恢复与锁文件完全一致的依赖树)
  • npm run build —— 通过
  • npm run bundle —— 通过(从 HEAD 生成新的 dist/cli.js
  • npm run typecheck —— 通过(0 错误)
  • npm run lint —— 通过(0 错误)
  • cd packages/core && npx vitest run src/goals/goal-continuation-prompt.test.ts —— 6 通过
  • cd packages/cli && npx vitest run src/nonInteractiveCli.test.ts src/acp-integration/session/Session.test.ts —— 794 通过、1 跳过
  • npm run test:integration:cli:sandbox:none —— 191 通过、18 跳过、1 失败(环境性,见上文)
  • 替代实验:QWEN_SANDBOX=false HOME=/tmp/qwen-home-surrogate-9581 npx vitest run --root ./integration-tests cli/qwen-config-dir.test.ts -t "1d: …" —— 1 通过

结论: 代码无需任何改动。披露的验证缺口已用本地证据弥补:仅限合并队列运行的集成套件在本 PR 的 HEAD 上全部通过,唯一例外的那个测试已被证明仅因本自托管运行器的 HOME 对测试用户不可写而失败。

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


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

@wenshao

wenshao commented Aug 23, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /triage

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Sandboxed verification: ✅ passed — merge-ready (agent verdict) - workflow run

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

Scripted assertions: 161 passed · 0 failed · 161 total

Flakiness gate: ✅ 3 changed test file(s) x 5 identical rounds, no divergence

中文 — 判定:✅ 通过 · 可合入(agent 判定)

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

脚本断言:161 通过 · 0 失败 · 161 总计

抖动门:✅ 3 changed test file(s) x 5 identical rounds, no divergence

Verification report

PR 9581 — refactor(goal): render Goal continuation prompts from one core renderer

Verdict: merge-ready — 161/161 scripted assertions passed, 0 unexpected failures. Verified head: 0db1e18577791ad5c017600f6626656c16e711eb (merge-ref checkout, base db05195).

中文摘要
  • 结论:merge-ready。161/161 条脚本化断言全部通过,0 意外失败。
  • A/B 结论:中心声明(纯重构、逐字节一致)成立。用脚本从 HEAD^1 逐字抽出改动前的三份拼装(TUI 内联数组、ACP 与 headless 的两个 buildGoalContinuationParts),与 HEAD 构建产物中的新渲染器在 135 个输入单元上逐字节比对(9 种 verifier feedback × 7 种 continuation context,含空串、${...}、反斜杠、换行、多字节字符),136/136 一致(含 1 条负对照:两个变体必须不同,证明比较器有判别力)。抽出代码与 diff 删除行逐字节相符(3 条保真断言)。
  • 测试非空转:对核心模块做 5 种变异(删护栏行、空串语义改 !== undefined、feedback 行序对调、共享行改字、parts 用错变体),固定字面量测试全部变红且失败信息为期望/实际不匹配;未变异对照全绿。类型契约(可辨识联合强制 continuationContext)用 @ts-expect-error 探针验证:契约 intact 时 tsc 绿,把字段改 optional 后报 TS2578。
  • :core goals 套件 393 通过/16 文件;三个 host 套件 1036 通过 + 1 既有 skip;全仓 typecheck、eslint、prettier 均干净(eslint 用植入违规证明活着)。host 测试文件的 diff 纯增量,既有期望零改动。
  • 未覆盖:浅克隆(depth 2)下 4 个 commit 中仅 PR head 可达,逐 commit 归因不可做,验证的是聚合 diff;Windows/macOS 未跑;TUI 与 ACP/headless 之间的措辞漂移按 PR 声明原样保留(已验证逐字节保留);verify-capture.mjs 在本容器渲染空白 PNG(sharp/librsvg 不画 <text>,已用最小 SVG 探针证明),证据图改用 ImageMagick 渲染,日志原文在 logs/
  • Findings:无阻塞项;仅两条描述层面的 nit(PR 正文的测试计数 382/1020 与实测 393/1036 不符,系 rebase 后过期数字)。

Central claim and A/B

Central claim: this is a pure refactor — each host (interactive TUI, ACP session, non-interactive CLI) sends a byte-identical Goal continuation prompt before and after; the three drifted assemblies collapse into one core renderer with two variants (guarded-synthetic-turn = TUI's old text incl. the two anti-spoofing guard lines; runtime-context = ACP/headless old text incl. the continuation context line).

Control construction: the pre-change assemblies were extracted verbatim from HEAD^1 by a quote-aware scanner (harness/extract-old-code.mjs) — no retyping — and each extraction was asserted byte-equal to the removed lines of git diff HEAD^1..HEAD for the same file (3 fidelity assertions). Only type-annotation tokens (: AcpGoalTurn, : HeadlessGoalTurn, : Part[]) were stripped to make the bodies runnable as ESM; the fidelity check compares pre-strip text. The new side is the built package entry packages/core/dist/src/index.js (realpath asserted inside the HEAD tree; exports asserted present) — the same module the hosts import as @qwen-code/qwen-code-core. Witness: evidence/01-ab-byte-identity-matrix.png (raw log: logs/ab-matrix-final.log).

cell control (verbatim HEAD^1) head (core dist) oracle result
TUI path, 9 feedback values (undefined, '', plain, multi-line, ${…}/backtick/backslash/quotes, padded, \n, '0', unicode) inline array literal renderGoalContinuationPrompt({variant:'guarded-synthetic-turn'}) string byte-equality 9/9 identical
ACP path, 7 contexts × 9 feedbacks = 63 (incl. empty context, embedded quotes/newlines/backslashes, undefined runtime probe) local buildGoalContinuationParts core buildGoalContinuationParts parts shape (len 1, keys exactly text) + byte-equality 63/63 identical
headless path, same 63 cells local buildGoalContinuationParts core buildGoalContinuationParts same 63/63 identical
negative control old TUI vs old ACP output must DIFFER (comparator has teeth) differ

Bonus census: the two pre-change ACP/headless helpers were byte-identical to each other on all 63 cells (they were duplicate code), and a repo-wide grep census shows exactly 3 production assemblers at base → exactly 1 at head (evidence/01…, logs/sweep-census.log). The empty-verifierFeedback truthiness guard (line omitted, as the hosts did) holds on both sides; continuationContext: undefined renders undefined identically old and new — a runtime-only probe, forbidden at compile time by the union (proven below).

Secondary claims

Pinned-literal tests are load-bearing. Mutation matrix (harness/mutation-matrix.mjs, witness evidence/02-mutation-matrix.png, log logs/mutation-matrix-final.log), each mutation landed in the mutated file itself and the unmutated control ran green in the same command:

row mutation expected observed
M0 none (control) green 6/6 pass
M1 delete 2nd anti-spoofing guard line caught 2 failed, AssertionError expected-vs-actual
M2 truthy guard → !== undefined (empty feedback would render) caught exactly the empty-string test failed
M3 Verifier-feedback line emitted before the variant line caught the 2 with-feedback tests failed
M4 edit shared line (Goal.goal.) caught all 4 pinned-literal tests failed
M5 buildGoalContinuationParts renders wrong variant caught the parts test failed

6/6 rows as expected; source restored clean after each row.

Discriminated-union contract. A @ts-expect-error probe (harness/type-probe-demo.sh, witness evidence/03-type-contract-probe.png): with the contract intact, tsc --noEmit in packages/core is green (missing-continuationContext and excess-property calls both error, valid calls compile); making continuationContext optional flips the probe to TS2578: Unused '@ts-expect-error' directive — the "host cannot forget the context" claim is enforced at compile time.

Host suites are the regression check. Test-file diffs are purely additive (0 removed lines across Session.test.ts, nonInteractiveCli.test.ts, useGeminiStream.test.tsx — the latter untouched entirely), so no pre-existing expectation was edited; the new Session/nonInteractive tests add coverage for the verifier-feedback path and pass.

Findings

No blocking findings. Two description-level nits:

  1. Stale test counts in the PR body (nit). The description claims "382 tests across 16 files" for the core goals suite and "1020 tests with 1 pre-existing skip" for the three host suites; measured at the verified head: 393 (16 files) and 1036 + 1 skip (evidence/04…, evidence/05…). The property the numbers were meant to convey (all green, one pre-existing skip) holds; the counts were presumably taken before the final rebase onto main.
  2. Session.test.ts edits an existing test's input (nit, informational). The claim "no expected value was edited" is true, but one existing ACP test's input was extended (verifierFeedback added) and two expectations appended — strictly stronger, not weaker; flagging only so the claim reads precisely.

Not covered

  • Per-commit attribution: the checkout is depth 2 (git rev-list --count HEAD^1..HEAD^2 = 1 vs 4 commits in the metadata snapshot), so only the aggregate HEAD^1..HEAD diff was verified; the four commits were not individually exercised.
  • Windows/macOS: not exercised (author-declared CI coverage).
  • TUI rendering path: only the prompt string assembly in useGeminiStream.ts was verified; interactive rendering of the resulting message is unchanged code and out of scope for a byte-identity refactor.
  • The drift itself: TUI vs ACP/headless wording differences are preserved by design; the PR declares this explicitly and the A/B confirms the preservation.
  • Evidence rasterisation: scripts/verify-capture.mjs produced blank PNGs in this container — its sharp/librsvg renders <rect> but no <text> (proved with a one-text SVG probe, /tmp/sharp-test.png). Images were rendered with ImageMagick convert -annotate instead (harness/capture-im.sh); some lines containing literal \n escapes show cosmetic overprinting in the PNGs — the authoritative record is the plain-text logs in logs/.
  • The author's own 25-case extraction script was not re-run; it is superseded by the 136-cell matrix above, which uses the same verbatim-extraction idea with an added diff-fidelity oracle.

Methodology

Environment: node:22-bookworm CI verify container, merge-ref checkout (HEAD = merge, HEAD^1 = base db05195, HEAD^2 = PR head 0db1e18), npm ci + npm run build pre-run at HEAD. The A/B drove the old code by extracting it verbatim from HEAD^1 (quote-aware scanning, fidelity-asserted against the diff) and the new code through the built packages/core dist entry the hosts actually import; gates ran the real vitest suites (junit.xml parsed for the tally) and tsc/eslint/prettier with planted-violation liveness checks for eslint and the type probe. All harnesses, raw logs, and assertions.json (161 pass / 0 fail) live in tmp/pr9581-verify-20260823-010324/; the working tree was left clean (git status empty) after every mutation/probe step.

Flakiness gate log

rounds=5 files=3 skipped=0
file packages/cli/src/acp-integration/session/Session.test.ts: (cd packages/cli) npx --no-install vitest run ./src/acp-integration/session/Session.test.ts
file packages/cli/src/nonInteractiveCli.test.ts: (cd packages/cli) npx --no-install vitest run ./src/nonInteractiveCli.test.ts
file packages/core/src/goals/goal-continuation-prompt.test.ts: (cd packages/core) npx --no-install vitest run ./src/goals/goal-continuation-prompt.test.ts


per-file results (P=pass F=fail I=infra-exit, one letter per run):
  packages/cli/src/acp-integration/session/Session.test.ts: PPPPP
  packages/cli/src/nonInteractiveCli.test.ts: PPPPP
  packages/core/src/goals/goal-continuation-prompt.test.ts: PPPPP

verdict: pass
summary: 3 changed test file(s) x 5 identical rounds, no divergence

--- per-invocation detail (full copy in the artifact) ---
round 1 · packages/cli/src/acp-integration/session/Session.test.ts: P (exit 0)
round 1 · packages/cli/src/nonInteractiveCli.test.ts: P (exit 0)
round 1 · packages/core/src/goals/goal-continuation-prompt.test.ts: P (exit 0)
round 2 · packages/cli/src/acp-integration/session/Session.test.ts: P (exit 0)
round 2 · packages/cli/src/nonInteractiveCli.test.ts: P (exit 0)
round 2 · packages/core/src/goals/goal-continuation-prompt.test.ts: P (exit 0)
round 3 · packages/cli/src/acp-integration/session/Session.test.ts: P (exit 0)
round 3 · packages/cli/src/nonInteractiveCli.test.ts: P (exit 0)
round 3 · packages/core/src/goals/goal-continuation-prompt.test.ts: P (exit 0)
round 4 · packages/cli/src/acp-integration/session/Session.test.ts: P (exit 0)
round 4 · packages/cli/src/nonInteractiveCli.test.ts: P (exit 0)
round 4 · packages/core/src/goals/goal-continuation-prompt.test.ts: P (exit 0)
round 5 · packages/cli/src/acp-integration/session/Session.test.ts: P (exit 0)
round 5 · packages/cli/src/nonInteractiveCli.test.ts: P (exit 0)
round 5 · packages/core/src/goals/goal-continuation-prompt.test.ts: P (exit 0)

Evidence images

01-ab-byte-identity-matrix

02-mutation-matrix

03-type-contract-probe

04-core-goals-gate

05-host-suites-gate

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

Qwen Code · sandboxed verification

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Triage re-run completed without a new review.

⚠️ The bot's only review on 0db1e18577791ad5c017600f6626656c16e711eb is a COMMENTED one, which carries no vote — so it has no verdict of its own on this commit, and main needs two approving reviews: an approval left by another account is a separate vote and does not count as the bot's own. Two different things look like this, and the stage-3 comment above says which: the triage skill deferring on purpose at 3/5 — a fork refactor hitting the approval guardrail, or a core change escalated for maintainer awareness, both normal outcomes — or an earlier approval that a push dismissed, leaving only the comment behind, which needs a fresh review.

⚠️ 机器人在 0db1e18577791ad5c017600f6626656c16e711eb 上唯一的评审是 COMMENTED不带票 —— 因此它在该 commit 上没有自己的裁决,而 main 需要两个批准(其他账号的批准是另一张票)。有两种情况长这样,上方的 stage-3 评论会说明是哪一种:triage skill 在 3/5 时有意 defer(fork refactor 命中审批护栏,或核心改动被升级交由维护者把关,两者都是正常结果);或者更早的批准被一次推送作废、只剩下这条评论,此时需要重新评审。

The stage comments above were updated with the latest result. View workflow run.

上方各阶段评论已更新为最新结果。查看工作流运行

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤖 AutoFix updated a stale base — the fix did not pass verification, but this PR was behind main, so it merged current main in via update-branch and will retry on the next scan. A stale base (a dependency or symbol main already changed) can fail the build without being the fix's fault; if it still fails once current, it hands off to a human.

⚠️ This change was NOT pushed — any commit referenced below was made only in the runner workspace and has been discarded. What the agent reported:

Round summary — same-run verification repair (base update)

This round had one actionable item: the Same-run verification repair notice. The previous commit was rejected because the deterministic gate's core rebuild check failed with four TypeScript errors in packages/core/src/telemetry/ (FileLogExporter missing forceFlush, Logger missing enabled, BatchLogRecordProcessor options-object signature).

Root cause (evidence-based)

  • The branch forked from main at 4839935e55. Main has since bumped the OpenTelemetry dependencies (^0.203.0^0.221.0, released with v0.22.0) and adapted the telemetry sources to the new API (file-exporters.ts +4, loggers.test.ts +1, sdk-impl.ts, sdk.test.ts).
  • The gate builds branch sources against the trusted base node_modules (installed from current main's lockfile — measured here: @opentelemetry/sdk-logs@0.221.0 installed while the branch's own lockfile pins 0.203.0). Old telemetry sources + new type declarations = exactly the four reported errors.
  • The PR itself touches no telemetry or dependency files; no in-PR code change can cure this. The gate's own documented remedy for this class is a base update (merge main), and the gate script explicitly supports merge rounds (merge freight is excluded from the class/footprint scans).

Change made

One follow-up commit, preserving all previously committed (rejected) work: `Merge remote-tracking branch 'origin/main' into goal/b1-continu

Why it was not pushed:

Note: the base has since been auto-updated; the verdict below predates that update, and the next round's re-measurement may charge the round.

tests failed in packages/cli

�[31m^�[39m
    �[90m131| �[39m      �[32m'/tmp/qwen-code'�[39m�[33m,�[39m
    �[90m132| �[39m      �[32m'1.2.3'�[39m�[33m,�[39m

�[31m�[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/4]⎯�[22m�[39m

�[41m�[1m FAIL �[22m�[49m src/serve/server-default-bridge-wiring.test.ts�[2m > �[22mcreateServeApp default bridge wiring�[2m > �[22mwires the internally-created bridge lifecycle into the workspace registry
�[31m�[1mError�[22m: Test timed out in 15000ms.
If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout".�[39m
�[36m �[2m❯�[22m src/serve/server-default-bridge-wiring.test.ts:�[2m56:3�[22m�[39m
    �[90m 54| �[39m  })�[33m;�[39m
    �[90m 55| �[39m
    �[90m 56| �[39m  it('wires the internally-created bridge lifecycle into the workspace…
    �[90m   | �[39m  �[31m^�[39m
    �[90m 57| �[39m    �[35mlet�[39m sessionLifecycle�[33m:�[39m �[33mBridgeOptions�[39m[�[32m'sessionLifecycle'�[39m]�[33m;�[39m
    �[90m 58| �[39m    �[35mlet�[39m bridgeOptions�[33m:�[39m �[33mBridgeOptions�[39m �[33m|�[39m undefined�[33m;�[39m

�[31m�[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[3/4]⎯�[22m�[39m

�[41m�[1m FAIL �[22m�[49m src/commands/review/script-lint-isolation.test.ts�[2m > �[22mscript-lint — hadolint fails closed when config isolation is unavailable�[2m > �[22madds no --config when a private neutral config cannot be created
�[31m�[1mError�[22m: Test timed out in 15000ms.
If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout".�[39m
�[36m �[2m❯�[22m src/commands/review/script-lint-isolation.test.ts:�[2m55:3�[22m�[39m
    �[90m 53| �[39m
    �[90m 54| �[39mdescribe('script-lint — hadolint fails closed when config isolation is…
    �[90m 55| �[39m  it('adds no --config when a private neutral config cannot be created…
    �[90m   | �[39m  �[31m^�[39m
    �[90m 56| �[39m    �[35mconst�[39m { buildToolInvocation } �[33m=�[39m �[35mawait�[39m �[35mimport�[39m(�[32m'./script-lint.js'�[39m)�[33m;�[39m
    �[90m 57| �[39m    // No private config → no `--config` on the argv (and the run fail…

�[31m�[2m⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[4/4]⎯�[22m�[39m


�[2m Test Files �[22m �[1m�[31m3 failed�[39m�[22m�[2m | �[22m�[1m�[32m649 passed�[39m�[22m�[90m (652)�[39m
�[2m      Tests �[22m �[1m�[31m4 failed�[39m�[22m�[2m | �[22m�[1m�[32m18926 passed�[39m�[22m�[2m | �[22m�[33m22 skipped�[39m�[90m (18952)�[39m
�[2m   Start at �[22m 09:40:45
�[2m   Duration �[22m 237.04s�[2m (transform 462.23s, setup 121.87s, collect 6937.40s, tests 946.30s, environment 340.07s, prepare 127.84s)�[22m

JUNIT report written to /home/github-runner/actions-runner-test-7/_work/qwen-code/qwen-code/packages/cli/junit.xml
npm error Lifecycle script `test` failed with error:
npm error code 1
npm error path /home/github-runner/actions-runner-test-7/_work/qwen-code/qwen-code/packages/cli
npm error workspace @qwen-code/qwen-code@0.22.0
npm error location /home/github-runner/actions-runner-test-7/_work/qwen-code/qwen-code/packages/cli
npm error command failed
npm error command sh -c vitest run --changed origin/main --passWithNoTests
中文说明

🤖 AutoFix 更新了一个过期的 base —— 修复未通过验证,但本 PR 落后于 main,因此已通过 update-branch 合入当前 main,并将在下次扫描时重试。过期的 base(main 已改动的依赖或符号)可能让构建失败而并非修复本身的错;若 base 更新后仍然失败,将移交人工处理。

验证门的拒绝原因与日志证据见上方英文部分(gate-rejection 不翻译)。

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


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

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

中文说明

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

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

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

@wenshao

wenshao commented Aug 23, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /triage

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Sandboxed verification: ✅ passed — merge-ready (agent verdict) - workflow run

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

Scripted assertions: 284 passed · 0 failed · 284 total

Flakiness gate: ✅ 3 changed test file(s) x 5 identical rounds, no divergence

中文 — 判定:✅ 通过 · 可合入(agent 判定)

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

脚本断言:284 通过 · 0 失败 · 284 总计

抖动门:✅ 3 changed test file(s) x 5 identical rounds, no divergence

Verification report

<!-- qwen-triage:verify -->
<!-- qwen-triage:verify-substantive -->

Verdict: merge-ready — 284/284 scripted assertions passed, 0 unexpected failures. Verified head: 5218760b9983c335edd47a72abd4f523c4c1ee2d (merge-ref checkout, base cf3e8ad7c02da70d1bd492733041aab3eb8c52f7). Follow-up round: the previous round verified 0db1e18 against base db05195; since then the branch gained two bot merges of main only.

中文摘要
  • 判定:merge-ready。本轮为跟进轮:上一轮在 head 0db1e18(base db05195)上验证通过;此后分支仅新增两次 bot 合并 main。本轮在新 head 5218760(base cf3e8ad)上重新测量了全部携带项,284/284 条脚本化断言通过,0 意外失败。
  • A/B 结论:中心声明(纯重构、逐字节一致)在新 base 上仍成立。改动前三份拼装从 HEAD^1 逐字抽出(保真断言:diff 删除行在 base 文件中唯一连续命中),与 HEAD 构建产物中 core 渲染器在 165 个输入单元上逐字节比对(TUI 11/11、ACP 77/77、headless 77/77,含空串、${…}、反斜杠、换行、多字节、undefined 运行时探针),另含负对照(两变体必须不同)与重复代码普查。见下文 "Central claim and A/B" 表与 evidence/01-…evidence/02-…
  • Findings:无新发现。两条上一轮 nit 原样保留(PR 正文测试计数 382/1020 与实测 393/1036+1 skip 不符;Session.test.ts 对既有测试输入做了纯增量扩展),见状态表。
  • 未覆盖:浅克隆(depth 2)下逐 commit 归因不可做(验证聚合 diff);Windows/macOS 未跑;TUI 渲染路径与漂移本身按 PR 声明不在范围。上一轮"verify-capture 渲染空白"的环境问题本轮已修复(该脚本在本容器正常渲染文字,四张证据图均由其生成)。

Previous-finding status (follow-up round)

# finding (previous round) severity status at 5218760
1 PR body test counts stale (claims 382 / 1020; measured 393 / 1036+1 skip at 0db1e18) nit stands — re-measured at new head: core goals suite 393 passed / 16 files (logs/core-goals-gate.log), host suites 1036 passed + 1 skipped (logs/host-suites.log); the body is unchanged. The property the numbers meant to convey (all green, one pre-existing skip) still holds; the skip is it.skip('should emit a single user envelope…') present at base nonInteractiveCli.test.ts:5241.
2 Session.test.ts edits an existing test's input (adds verifierFeedback) and appends two expectations nit, informational stands — re-verified at new head: the hunk is purely additive (removed=0 added=11); strictly stronger coverage, no expectation weakened.
3 scripts/verify-capture.mjs produced blank PNGs in the container (sharp/librsvg drew no <text>) infra (Not covered) fixed — a probe capture now renders title + text correctly; all four evidence images this round were produced by the helper.
4 Per-commit attribution unreachable (depth-2 checkout) infra (Not covered) standsgit rev-list --count HEAD^1..HEAD^2 = 1 vs 6 commits in the metadata snapshot; aggregate diff verified.

I agree with both nit classifications: neither is blocking, and both remain true.

Central claim and A/B

Central claim (unchanged): pure refactor — each host (interactive TUI, ACP session, non-interactive CLI) sends a byte-identical Goal continuation prompt before and after; the three drifted assemblies collapse into one core renderer (renderGoalContinuationPrompt, variants guarded-synthetic-turn and runtime-context).

Control construction (re-run at the new base): the pre-change assemblers were extracted verbatim from HEAD^1 (harness/ab-byte-identity.mjs): the diff's removed lines were located inside git show HEAD^1:<file> and required to match contiguously and uniquely (6 fidelity assertions, all pass — witness evidence/01-ab-fidelity-and-tui-cells.png). Only type tokens (: AcpGoalTurn, : HeadlessGoalTurn, : Part[]) and the TUI queryToSend: property wrapper were stripped to make the old code runnable; round-trip assertions prove the strips are exactly those tokens. Head side: the built package entry @qwen-code/qwen-code-core → realpath /__w/qwen-code/qwen-code/packages/core/dist/index.js (asserted inside the HEAD tree). Raw log: logs/ab-matrix.log; witness evidence/02-ab-controls-and-summary.png.

cell control (verbatim cf3e8ad) head (core dist) oracle result
TUI path, 11 feedback values (undefined, '', plain, multi-line, ${…}, backtick, backslash, quotes, padded, '0', unicode) inline array literal renderGoalContinuationPrompt({variant:'guarded-synthetic-turn'}) string byte-equality 11/11 identical
ACP path, 7 contexts × 11 feedbacks = 77 (incl. empty context, embedded quotes/newlines/backslashes, undefined runtime probe) local buildGoalContinuationParts core buildGoalContinuationParts parts deep-equal + single-text-part shape 77/77 identical
headless path, same 77 cells local buildGoalContinuationParts core buildGoalContinuationParts parts deep-equal 77/77 identical
negative control old TUI vs old ACP output must DIFFER (drift preserved; comparator has teeth) differ
duplication census old ACP vs old headless on all 77 cells must be identical (they were duplicates) identical
empty-verifierFeedback truthiness line omitted on both variants ''undefined output holds

Assembler census: exactly 3 production assemblers at base → exactly 1 at head (git grep at HEAD^1 vs working tree).

Secondary claims

Pinned-literal tests are load-bearing (re-run). Mutation matrix (harness/mutation-matrix.mjs, witness evidence/03-mutation-matrix.png, log logs/mutation-matrix.log); every mutation landed in the mutated file, and each failure was an expected-vs-actual AssertionError, not import/compile breakage:

row mutation expected observed
M0 none (control) green green (exit 0, 0 failed)
M1 delete 2nd anti-spoofing guard line caught 2 failed, expected-vs-actual
M2 truthy guard → !== undefined caught 1 failed (the empty-string test)
M3 verifier-feedback line emitted before the variant line caught 2 failed
M4 edit shared line (Goal.goal.) caught 4 failed
M5 buildGoalContinuationParts renders wrong variant caught 1 failed (the parts test)

12/12 matrix assertions as expected; source restored byte-identical afterwards (git status clean).

Discriminated-union contract (re-run, witness evidence/04-type-contract-probe.png): with the contract intact, tsc --noEmit in packages/core exits 0 with a probe file whose two @ts-expect-error calls (missing continuationContext; excess continuationContext on the guarded variant) suppress real errors; making continuationContext optional flips the probe to TS2578: Unused '@ts-expect-error' directive at the probe line. "Host cannot forget the context" is compile-enforced.

Host suites are the regression check (re-run): Session.test.ts, nonInteractiveCli.test.ts, useGeminiStream.test.tsx1036 passed + 1 pre-existing skip (3 files). Test-file diffs are purely additive at the new head (0 removed lines; useGeminiStream.test.tsx untouched), so no pre-existing expectation was edited.

Findings

No new findings. The two carried nits (previous-finding table rows 1–2) stand; both are description-level and non-blocking.

Not covered

  • Per-commit attribution: checkout is depth 2 (6 commits in the metadata snapshot, 1 reachable via HEAD^1..HEAD^2); only the aggregate HEAD^1..HEAD diff was verified.
  • Windows/macOS: not exercised (author-declared CI coverage).
  • TUI rendering path: only the prompt string assembly in useGeminiStream.ts was verified; interactive rendering of the resulting message is unchanged code and out of scope for a byte-identity refactor.
  • The drift itself: TUI vs ACP/headless wording differences are preserved by design; the A/B negative control confirms the preservation.
  • The author's own 25-case extraction script was not re-run; it is superseded by the 165-cell matrix above, which uses the same verbatim-extraction idea with an added diff-fidelity oracle.

Methodology

Environment: node:22-bookworm CI verify container, merge-ref checkout (HEAD = 2f70174, HEAD^1 = base cf3e8ad, HEAD^2 = PR head 5218760), npm ci + npm run build pre-run at HEAD. Every measurement from the previous round was rebuilt and re-run at the new head (no carry-forward by hash: the base moved, so the input closure changed). The A/B drove the old code by extracting it verbatim from HEAD^1 and the new code through the built packages/core dist entry the hosts import (realpath asserted); gates ran the real vitest suites, tsc --noEmit per package, and eslint/prettier with planted-violation liveness checks (eslint: unused var reported at 82:7 then removed; prettier: in-repo misformatted probe exits 1 — the first /tmp probe passed only because prettier ignores paths outside the project, and the in-repo probe is the valid one). All gate, type-probe, census, and additive-diff checks are re-runnable via harness/gate-assertions.mjs (16/16 this round). All harnesses, raw logs, and assertions.json (284 pass / 0 fail) live in tmp/pr9581-verify-20260823-044127/; the working tree was left clean (git status --porcelain empty) after every mutation/probe step.

Flakiness gate log

rounds=5 files=3 skipped=0
file packages/cli/src/acp-integration/session/Session.test.ts: (cd packages/cli) npx --no-install vitest run ./src/acp-integration/session/Session.test.ts
file packages/cli/src/nonInteractiveCli.test.ts: (cd packages/cli) npx --no-install vitest run ./src/nonInteractiveCli.test.ts
file packages/core/src/goals/goal-continuation-prompt.test.ts: (cd packages/core) npx --no-install vitest run ./src/goals/goal-continuation-prompt.test.ts


per-file results (P=pass F=fail I=infra-exit, one letter per run):
  packages/cli/src/acp-integration/session/Session.test.ts: PPPPP
  packages/cli/src/nonInteractiveCli.test.ts: PPPPP
  packages/core/src/goals/goal-continuation-prompt.test.ts: PPPPP

verdict: pass
summary: 3 changed test file(s) x 5 identical rounds, no divergence

--- per-invocation detail (full copy in the artifact) ---
round 1 · packages/cli/src/acp-integration/session/Session.test.ts: P (exit 0)
round 1 · packages/cli/src/nonInteractiveCli.test.ts: P (exit 0)
round 1 · packages/core/src/goals/goal-continuation-prompt.test.ts: P (exit 0)
round 2 · packages/cli/src/acp-integration/session/Session.test.ts: P (exit 0)
round 2 · packages/cli/src/nonInteractiveCli.test.ts: P (exit 0)
round 2 · packages/core/src/goals/goal-continuation-prompt.test.ts: P (exit 0)
round 3 · packages/cli/src/acp-integration/session/Session.test.ts: P (exit 0)
round 3 · packages/cli/src/nonInteractiveCli.test.ts: P (exit 0)
round 3 · packages/core/src/goals/goal-continuation-prompt.test.ts: P (exit 0)
round 4 · packages/cli/src/acp-integration/session/Session.test.ts: P (exit 0)
round 4 · packages/cli/src/nonInteractiveCli.test.ts: P (exit 0)
round 4 · packages/core/src/goals/goal-continuation-prompt.test.ts: P (exit 0)
round 5 · packages/cli/src/acp-integration/session/Session.test.ts: P (exit 0)
round 5 · packages/cli/src/nonInteractiveCli.test.ts: P (exit 0)
round 5 · packages/core/src/goals/goal-continuation-prompt.test.ts: P (exit 0)

Evidence images

01-ab-fidelity-and-tui-cells

02-ab-controls-and-summary

03-mutation-matrix

04-type-contract-probe

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

Qwen Code · sandboxed verification

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Triage re-run completed without a new review.

⚠️ The bot's only review on 5218760b9983c335edd47a72abd4f523c4c1ee2d is a COMMENTED one, which carries no vote — so it has no verdict of its own on this commit, and main needs two approving reviews: an approval left by another account is a separate vote and does not count as the bot's own. Two different things look like this, and the stage-3 comment above says which: the triage skill deferring on purpose at 3/5 — a fork refactor hitting the approval guardrail, or a core change escalated for maintainer awareness, both normal outcomes — or an earlier approval that a push dismissed, leaving only the comment behind, which needs a fresh review.

⚠️ 机器人在 5218760b9983c335edd47a72abd4f523c4c1ee2d 上唯一的评审是 COMMENTED不带票 —— 因此它在该 commit 上没有自己的裁决,而 main 需要两个批准(其他账号的批准是另一张票)。有两种情况长这样,上方的 stage-3 评论会说明是哪一种:triage skill 在 3/5 时有意 defer(fork refactor 命中审批护栏,或核心改动被升级交由维护者把关,两者都是正常结果);或者更早的批准被一次推送作废、只剩下这条评论,此时需要重新评审。

The stage comments above were updated with the latest result. View workflow run.

上方各阶段评论已更新为最新结果。查看工作流运行

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

Autofix round: no action required

No new review findings to address this round: both automated reviews in the window posted zero findings (their ledgers record "findings":[]), there are no inline comments, and the two issue-level comments are bot verification reports. The only actionable item was the previous round's verification-gate rejection. After reproducing and diagnosing it, no code change is warranted — the failure was load-induced, in tests this PR does not touch, on a head that predates the base auto-update.

Feedback triage

Item Disposition
[rv:5001527842] Approve→Comment downgrade: "CI failing: Test (ubuntu-latest, Node 22.x)" Superseded — that failure belonged to the pre-update head. At the current head (after the base auto-update) Test (ubuntu-latest, Node 22.x) is SUCCESS (run 32613790378, completed 03:09:41Z). No action.
[rv:5001604547] "Partially reviewed — gaps disclosed" (Integration Tests suite not reviewed) Informational, zero findings. The touched behavior (Goal continuation prompt assembly) is exercised by unit suites (verified below), and the sandboxed verification disclosed the same gap yet concluded merge-ready on byte-identity evidence.
[ic:5383424864] Sandboxed verification ✅ merge-ready (161/161 assertions) Informational.
[ic:5384191633] Sandboxed verification running Informational.
Gate rejection: "tests failed in packages/cli" Diagnosed below; no in-scope fix exists.

Gate rejection diagnosis

The rejected gate ran vitest run --changed origin/main --passWithNoTests in packages/cli and failed on 4 tests in 3 files: src/serve/server-default-bridge-wiring.test.ts and src/commands/review/script-lint-isolation.test.ts (both 15s test timeouts), plus a failure whose log frame points at the '/tmp/qwen-code' / '1.2.3' expectation in src/commands/update.test.ts. None of those files is touched by this PR — the diff is 8 files around the Goal continuation renderer and its three hosts.

Two facts explain the shape of the rejection:

  1. Why unrelated tests ran at all: packages/cli's Vitest config aliases @qwen-code/qwen-code-core to the core package sources, and this PR changes packages/core/src/goals/index.ts, which core's index re-exports. Vitest's --changed walks each test's import graph, so every one of the 652 cli test files depends on a changed file — verified locally with vitest list --changed origin/main, which selects all 652 files. The gate therefore re-runs the entire cli suite for this PR, and any load flake anywhere in it gets charged to the PR.
  2. Why they failed there: the rejected run's own timings show a severely overloaded runner (aggregate collect phase 6937s for a suite whose normal duration is a few minutes), which turns multi-second server/subprocess tests into 15s timeouts.

Evidence the failures are environmental, not caused by this PR:

  • All three files pass at the current head locally: 3 files, 19 tests, 0 failures (including the exact timed-out test wires the internally-created bridge lifecycle into the workspace registry, 2.6s).
  • The full unit CI suite at the current head is green: Test (ubuntu-latest, Node 22.x) SUCCESS.
  • Sandboxed verification at the pre-merge head was merge-ready: 161/161 scripted assertions, byte-identical A/B of the refactor confirmed.

There is no in-scope change to make: hardening unrelated tests would be an out-of-footprint edit, and the verification machinery itself is off-limits. The rejection note itself states the verdict predates the base auto-update; the next gate re-measurement on the updated base is the correct resolution path.

Verification

Commands actually run this round at head 5218760b99 (no code changes were made):

  • npm run build — passed
  • npm run typecheck — passed
  • npm run lint — passed
  • packages/core: npx vitest run --changed origin/main --passWithNoTests (exact gate command) — 503 passed / 0 failed
  • packages/cli: Session.test.ts + nonInteractiveCli.test.ts + useGeminiStream.test.tsx (the PR's host coverage) — 1037 passed / 0 failed (1 pre-existing skip)
  • packages/cli: update.test.ts + server-default-bridge-wiring.test.ts + script-lint-isolation.test.ts (the previously gate-failing files) — 19 passed / 0 failed
  • Reference only: the full cli suite via --changed origin/main on this self-hosted runner showed 33 failures, all in files untouched by this PR and all environment-bound (EACCES on mkdtemp under /home/github-runner, HOME-dependent settings/auth rendering); the same suite is green on GitHub-hosted CI at this exact tree, confirming these are runner-environment artifacts of the same class as the gate's load timeouts.
中文说明

Autofix 轮次:无需任何改动

本轮没有新的评审发现需要处理:窗口内的两条自动评审均为零发现(其 ledger 记录为 "findings":[]),没有行内评论,两条议题级评论均为机器人验证报告。唯一需要处理的事项是上一轮验证门(verification gate)的拒绝。经复现与诊断,无需任何代码改动——该失败由运行机负载过高引起,发生在本 PR 完全未触碰的测试中,且测量对象是 base 自动更新之前的旧 head。

反馈分类

条目 处置
[rv:5001527842] 从批准降级为评论:"CI failing: Test (ubuntu-latest, Node 22.x)" 已过时——该失败属于更新前的 head。在当前 head(base 自动更新之后),Test (ubuntu-latest, Node 22.x)SUCCESS(run 32613790378,完成于 03:09:41Z)。无需处理。
[rv:5001604547] "仅部分审查——缺口已披露"(Integration Tests 套件未审查) 信息性,零发现。本 PR 触碰的行为(Goal 续写提示词拼装)由单元测试套件覆盖(见下方验证);沙箱验证披露了同样的缺口,但基于逐字节一致(byte-identity)证据仍给出 merge-ready 结论。
[ic:5383424864] 沙箱验证 ✅ merge-ready(161/161 断言) 信息性。
[ic:5384191633] 沙箱验证运行中 信息性。
验证门拒绝:"tests failed in packages/cli" 诊断见下;不存在范围内的修复。

验证门拒绝的诊断

被拒绝的门在 packages/cli 中运行了 vitest run --changed origin/main --passWithNoTests,共 3 个文件 4 个测试失败:src/serve/server-default-bridge-wiring.test.tssrc/commands/review/script-lint-isolation.test.ts(均为 15 秒测试超时),另有一条失败的日志代码帧指向 src/commands/update.test.ts'/tmp/qwen-code' / '1.2.3' 的断言处。这些文件均未被本 PR 触碰——本 PR 的 diff 仅为围绕 Goal 续写渲染器及其三个宿主(host)的 8 个文件。

有两个事实解释了该拒绝的形态:

  1. 为什么无关测试会被运行: packages/cli 的 Vitest 配置将 @qwen-code/qwen-code-core 别名指向 core 包的源码,而本 PR 修改了 packages/core/src/goals/index.ts,该文件又被 core 的 index 重新导出。Vitest 的 --changed 会遍历每个测试的导入图,因此 cli 全部 652 个测试文件都依赖了被改动的文件——本地用 vitest list --changed origin/main 验证,确实选中了全部 652 个文件。所以本 PR 的门会重跑整个 cli 套件,套件中任何一处负载性抖动都会被记到本 PR 头上。
  2. 为什么它们当时失败: 被拒绝的那次运行自身的时间统计显示运行机严重过载(整个套件通常只需几分钟,而该次 collect 阶段累计耗时 6937 秒),这会使需要数秒的服务器/子进程类测试撞上 15 秒超时。

以下证据表明失败是环境问题,而非本 PR 引起:

  • 这三个文件在当前 head 本地全部通过:3 个文件、19 个测试、0 失败(包括恰好超时的那个测试 wires the internally-created bridge lifecycle into the workspace registry,耗时 2.6 秒)。
  • 当前 head 的完整单元 CI 套件为绿色:Test (ubuntu-latest, Node 22.x) SUCCESS。
  • 合入 main 前的 head 的沙箱验证为 merge-ready:161/161 条脚本断言,重构的逐字节一致 A/B 对照已确认。

不存在范围内的改动可做:加固无关测试属于足迹(footprint)之外的编辑,验证机制本身也不允许触碰。拒绝说明本身也已注明该判定早于 base 自动更新;在更新后的 base 上由下一次门的重新测量来解决,才是正确的路径。

验证

本轮在当前 head 5218760b99 实际执行的命令(未做任何代码改动):

  • npm run build —— 通过
  • npm run typecheck —— 通过
  • npm run lint —— 通过
  • packages/corenpx vitest run --changed origin/main --passWithNoTests(与门完全相同的命令)—— 503 通过 / 0 失败
  • packages/cliSession.test.ts + nonInteractiveCli.test.ts + useGeminiStream.test.tsx(本 PR 的宿主覆盖)—— 1037 通过 / 0 失败(1 个既有 skip)
  • packages/cliupdate.test.ts + server-default-bridge-wiring.test.ts + script-lint-isolation.test.ts(先前门中失败的文件)—— 19 通过 / 0 失败
  • 仅供参考:在本自托管运行机上以 --changed origin/main 运行完整 cli 套件时出现 33 条失败,全部位于本 PR 未触碰的文件,且均为环境受限所致(在 /home/github-runnermkdtemp 报 EACCES、依赖 HOME 的 settings/auth 渲染);同一套件在 GitHub 托管 CI 上于完全相同的代码树为绿色,证实这些与门的负载超时同属运行机环境伪影。

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


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

@wenshao

wenshao commented Aug 23, 2026

Copy link
Copy Markdown
Collaborator

Verdict: merge-ready — 55/55 scripted byte-identity assertions passed, 0 unexpected failures. Verified head: 5218760b9983c335edd47a72abd4f523c4c1ee2d.

中文摘要

结论:可以合并。 中央主张已通过独立 A/B:从 base 提交的三个 host 原始拼装逻辑得到的 UTF-8 字节,与 head 上新 core renderer 的输出在完整矩阵中逐字节一致,详见下方 Central claim and A/B 表及 01-prompt-byte-identity-ab.png。未发现阻塞或非阻塞问题。精确 head 的全仓构建、类型检查、 ESLint、变更文件格式检查,以及 TUI / ACP / non-interactive / core renderer 四个目标测试文件均通过,详见 02-targeted-gates.png。未覆盖真实模型/API 调用、macOS/Windows 运行时和完整测试套件;本次变更的可观察面是本地 prompt 字节拼装,验证环境为断网的 Linux Node.js 22 容器。

Central claim and A/B

Claim: this PR is a pure refactor: each host must emit exactly the same Goal continuation prompt bytes as the base commit for every supported input shape.

The control expressions were transcribed line-for-line from the deleted assemblies at base cf3e8ad7c02da70d1bd492733041aab3eb8c52f7; the head arm imported the built renderGoalContinuationPrompt / buildGoalContinuationParts from core. Every cell compared UTF-8 buffers with Buffer.equals, not normalized strings.

Host arm Input matrix Oracle Result
ACP runtime continuation 5 continuation contexts × 5 verifier-feedback values base local builder bytes equal head core builder bytes 25/25 identical
Non-interactive runtime continuation the same 5 × 5 matrix base local builder bytes equal head core builder bytes 25/25 identical
Interactive TUI guarded synthetic turn 5 verifier-feedback values base inline array bytes equal head guarded renderer bytes 5/5 identical
Total empty, absent, plain, multiline, quotes, backslashes, literal ${...}, combining Unicode, and astral Unicode first mismatching byte offset would fail the harness 55/55 identical; 0 mismatches

The empty feedback string remained omitted under the original truthiness rule. The existing host split also remained intact: TUI keeps the two synthetic-turn anti-spoofing lines, while ACP and non-interactive keep Runtime continuation context:.

Evidence: 01-prompt-byte-identity-ab.png.

PR 9581 byte-identity A/B

Findings

None.

Targeted gates

All commands ran against the exact head in a credential-free, --network none node:22-bookworm container after a clean rebuild of the affected core and CLI outputs.

Gate Result
Full repository npm run build exit 0
Core renderer test 6 passed
TUI host test 230 passed
ACP host test 678 passed
Non-interactive host test 128 passed, 1 skipped
Targeted test total 1042 passed, 1 skipped
Full repository npm run typecheck exit 0
Full repository npm run lint exit 0
Prettier check on all 8 changed files exit 0
git diff --check exit 0

Evidence: 02-targeted-gates.png.

PR 9581 targeted gates

Not covered

  • Real model or external API traffic: the changed surface is deterministic local prompt construction, and the host tests exercise the send boundary without requiring network calls.
  • macOS and Windows runtime execution: the byte renderer is platform-independent; this local round used Linux/Node.js 22. Cross-platform CI was green at the reviewed head, but those CI results are not counted as local assertions.
  • The full unit/integration suite: the four directly affected test files, full build, full typecheck, full lint, and changed-file formatting were selected instead.
  • Future behavior-changing reconciliation of the intentional TUI versus runtime-context prompt drift.

Methodology

Metadata and exact base/head OIDs were resolved outside the sandbox with gh pr view 9581 --repo QwenLM/qwen-code. The dependency tree was confirmed unchanged. A Docker image was built from the trusted base with the lockfile's standard npm ci; the exact head archive was then overlaid and executed only in credential-free containers with networking disabled. The A/B harness used the base host expressions as control and the cleanly built head renderer as treatment. Raw logs, the exact PR diff, source snapshots, harness, and screenshots are under tmp/pr9581-verify-20260823-041859/.

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

Autofix round: no action required

No new review findings to address this round; the PR stays as-is at 5218760b99.

Feedback triage

The workflow prepared exactly one feedback item newer than the last evaluation (2026-08-23T04:23:32Z):

  • [ic:5384319847] — Disposition: no action needed. This is @wenshao's independent local verification report, not a change request. It ran a scripted byte-identity A/B of the Goal continuation prompt across all three hosts (ACP runtime continuation, non-interactive runtime continuation, interactive TUI synthetic turn): 55/55 assertions byte-identical against the base-commit assemblies, 0 mismatches, and an explicit "Verdict: merge-ready" with "Findings: None". Its "Not covered" section describes verification scope (no real model traffic, no macOS/Windows runners, targeted rather than full test suite) rather than requesting changes. There is nothing in it to implement, decline, defer, or escalate.

Checks and threads

  • No failed checks and no still-red checks this round: all 45 CI check runs on the head are SUCCESS or SKIPPED.
  • No unresolved inline comments or review bodies are in the window; the nine inline threads from earlier rounds predate the last evaluation and were already handled in prior rounds.

Conclusion

Nothing in this round's feedback is actionable. No code changes were made and nothing was committed; the branch remains at 5218760b99.

中文说明

Autofix 本轮:无需任何操作

本轮没有新的评审发现需要处理,PR 保持原样,停留在 5218760b99

反馈分类

相对上次评估(2026-08-23T04:23:32Z),工作流只准备了一条更新的反馈:

  • [ic:5384319847] — 处置:无需操作。 这是 @wenshao 的独立本地验证报告,而非改动请求。它对 Goal 续接提示词在三个宿主(ACP 运行时续接、非交互运行时续接、交互式 TUI 合成轮)上执行了脚本化的字节级一致性 A/B 对比:相对 base 提交的原始拼装逻辑 55/55 断言逐字节一致、0 处不匹配,并明确给出"结论:可以合并"的判定与"未发现(Findings: None)"。其中的"未覆盖(Not covered)"部分描述的是验证范围(未涉及真实模型流量、无 macOS/Windows 运行器、采用目标测试而非完整测试套件),并非改动请求。其中没有任何需要实现、拒绝、延后或升级处理的内容。

检查与讨论串

  • 本轮没有失败的检查,也没有遗留的红色检查:head 上全部 45 个 CI 检查运行结果均为 SUCCESS 或 SKIPPED。
  • 窗口内没有未解决的行内评论或评审正文;早前轮次的九条行内评论均早于上次评估,已在先前轮次处理完毕。

结论

本轮反馈中没有任何可操作项。未做任何代码改动,也没有提交任何内容;分支保持在 5218760b99

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


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

@wenshao

wenshao commented Aug 23, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /triage

@wenshao
wenshao enabled auto-merge August 23, 2026 05:17
@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Sandboxed verification: ✅ passed — merge-ready (agent verdict) - workflow run

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

Scripted assertions: 234 passed · 0 failed · 234 total

Flakiness gate: ✅ 3 changed test file(s) x 5 identical rounds, no divergence

中文 — 判定:✅ 通过 · 可合入(agent 判定)

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

脚本断言:234 通过 · 0 失败 · 234 总计

抖动门:✅ 3 changed test file(s) x 5 identical rounds, no divergence

Verification report

<!-- qwen-triage:verify -->
<!-- qwen-triage:verify-substantive -->

Verdict: merge-ready — 234/234 scripted assertions passed, 0 unexpected failures. Verified head: 5218760b9983c335edd47a72abd4f523c4c1ee2d (merge-ref checkout HEAD = 2f70174c88, base HEAD^1 = cf3e8ad7c02da70d1bd492733041aab3eb8c52f7).

中文摘要
  • 判定:merge-ready。跟进轮:上一轮验证的 head(5218760)与 base(cf3e8ad)与本轮完全相同(同一合并提交 2f70174),因此本轮对全部携带测量整体重跑(输入闭包按提交 OID 证明未变,仍重跑而非引用旧数),结果与上一轮逐项一致:A/B 165 个字节一致单元全同、变异矩阵 5/5 击杀、类型契约探针两臂如预期、门禁 18/18。
  • A/B 结论:中心声明(纯重构、逐字节一致)成立。改动前三份拼装从 HEAD^1 逐字抽出(保真断言:diff 删除行在 base 文件中唯一连续命中,6/6;剥离往返断言 8/8),与 HEAD 构建产物中 core 渲染器在 165 个输入单元上逐字节比对(TUI 11/11、ACP 77/77、headless 77/77),负对照(两变体必须不同、旧 TUI 与旧 ACP 必须不同)与重复普查(旧 ACP≡旧 headless 77/77)、真值判断(空串≡缺省)均如预期;生产拼装点 base 3 处 → head 1 处。见 "Central claim and A/B" 表与 evidence/01-…evidence/02-…
  • Findings:无新发现。两条上一轮 nit 原样保留(PR 正文测试计数 382/1020 与实测 393/1036+1 skip 不符;Session.test.ts 对既有测试输入做纯增量扩展),见状态表。
  • 未覆盖:浅克隆(depth 2)下逐 commit 归因不可做(验证聚合 diff,rev-list HEAD^1..HEAD^2 = 1 vs 元数据 6 commits);Windows/macOS 未跑;TUI 渲染路径与漂移本身按 PR 声明不在范围;作者自述的 25 例抽取脚本未重跑(被 165 单元矩阵取代)。

Previous-finding status (follow-up round)

Note: this round re-ran at the same head (5218760) and base (cf3e8ad) as the previous round (same merge commit 2f70174c88), i.e. the input closure is provably identical by content addressing. Per the follow-up rule I re-ran every measurement anyway rather than carrying numbers forward; all reproduced exactly.

# finding (previous round) severity status at 5218760 (re-measured)
1 PR body test counts stale (claims 382 / 1020) nit stands — re-measured: core goals suite 393 passed / 16 files (logs/core-goals-gate.log), host suites 1036 passed + 1 skipped (logs/host-suites.log); body unchanged. The property the numbers meant to convey (all green, one pre-existing skip) still holds; the skip is it.skip('should emit a single user envelope…'), present at base nonInteractiveCli.test.ts (asserted in this round).
2 Session.test.ts edits an existing test's input (adds verifierFeedback) and appends two expectations nit, informational stands — re-verified: numstat +11 −0; purely additive, no expectation weakened. I agree with the classification.
3 scripts/verify-capture.mjs produced blank PNGs two rounds ago infra (Not covered) fixed, re-confirmed — all five evidence images this round were produced by the helper and visually verified to render title + text (zoom on 02-… shows legible lines).
4 Per-commit attribution unreachable (depth-2 checkout) infra (Not covered) standsgit rev-list --count HEAD^1..HEAD^2 = 1 vs 6 commits in the metadata snapshot; --is-shallow-repository = true; aggregate diff verified.

Central claim and A/B

Central claim (unchanged): pure refactor — each host (interactive TUI, ACP session, non-interactive CLI) sends a byte-identical Goal continuation prompt before and after; the three drifted assemblies collapse into one core renderer (renderGoalContinuationPrompt, variants guarded-synthetic-turn and runtime-context).

Control construction (re-run): the pre-change assemblers were extracted verbatim from HEAD^1 (harness/ab-byte-identity.mjs): the diff's removed lines were located inside git show HEAD^1:<file> and required to match contiguously and uniquely (6 fidelity assertions, all pass — witness evidence/01-ab-fidelity-and-tui-cells.png). Only type tokens (: AcpGoalTurn, : HeadlessGoalTurn, : Part[]) and the TUI queryToSend: property wrapper were stripped to make the old code runnable; round-trip assertions prove the strips are exactly those tokens (8/8: signature-match + round-trip per parts builder, four for the TUI property unwrap). Head side: the built package entry @qwen-code/qwen-code-core → realpath /__w/qwen-code/qwen-code/packages/core (asserted inside the HEAD tree; the control side never crosses node_modules). Raw log: logs/ab-matrix.log; witness evidence/02-ab-controls-and-summary.png.

cell control (verbatim cf3e8ad) head (core dist) oracle result
TUI path, 11 feedback values (undefined, '', plain, multi-line, ${…}, backtick, backslash, quotes, padded, '0', unicode) inline array literal renderGoalContinuationPrompt({variant:'guarded-synthetic-turn'}) string byte-equality 11/11 identical
ACP path, 7 contexts × 11 feedbacks = 77 (incl. empty context, embedded quotes/newlines/backslashes) local buildGoalContinuationParts core buildGoalContinuationParts parts deep-equal + single-text-part shape 77/77 identical
headless path, same 77 cells local buildGoalContinuationParts core buildGoalContinuationParts parts deep-equal + shape 77/77 identical
negative control old TUI vs old ACP output must DIFFER (drift preserved; comparator has teeth) differ
negative control new guarded vs new runtime-context must DIFFER differ
duplication census old ACP vs old headless on all 77 cells must be identical (they were duplicates) identical (77/77)
empty-verifierFeedback truthiness line omitted on both variants ''undefined output holds
assembler census git grep production marker at HEAD^1 working tree 3 assemblers → 1 3 → 1 (Session.ts, nonInteractiveCli.ts, useGeminiStream.ts → goal-continuation-prompt.ts)

189/189 assertions in this harness (logs/assertions-ab.json).

Secondary claims

Pinned-literal tests are load-bearing (re-run). Mutation matrix (harness/mutation-matrix.mjs, witness evidence/03-mutation-matrix.png, log logs/mutation-matrix.log); every mutation landed in the mutated file, and each red run was an expected-vs-actual AssertionError, not import/compile breakage; source restored byte-identical afterwards (git status clean):

row mutation expected observed
M0 none (control) green green (exit 0, 0 failed)
M1 delete 2nd anti-spoofing guard line caught 2 failed, expected-vs-actual
M2 truthy guard → !== undefined caught 1 failed (the empty-string test)
M3 verifier-feedback line emitted before the variant line caught 2 failed
M4 edit shared line (Goal.goal.) caught 4 failed
M5 buildGoalContinuationParts renders wrong variant caught 1 failed (the parts test)

22/22 matrix assertions as expected.

Discriminated-union contract (re-run, witness evidence/04-type-contract-probe.png): with the contract intact, tsc --noEmit in packages/core exits 0 with a probe file whose two @ts-expect-error calls (missing continuationContext; excess continuationContext on the guarded variant) suppress real errors; making continuationContext optional flips the probe to TS2578: Unused '@ts-expect-error' directive at exactly the missing-context line. "Host cannot forget the context" is compile-enforced. (First probe draft placed the excess-property call on multiple lines, so TS2353 landed outside the directive's one-line scope — a harness bug, fixed by single-lining the call; the intact-contract arm already showed the missing-context directive suppressing a real error.) 5/5 assertions.

Host suites are the regression check (re-run, witness evidence/05-targeted-gates.png): Session.test.ts, nonInteractiveCli.test.ts, useGeminiStream.test.tsx1036 passed + 1 pre-existing skip (3 files). Test-file diffs are purely additive at this head (Session.test.ts +11/−0, nonInteractiveCli.test.ts +33/−0, useGeminiStream.test.tsx untouched), so no pre-existing expectation was edited.

Findings

No new findings. The two carried nits (previous-finding table rows 1–2) stand; both are description-level and non-blocking.

Not covered

  • Per-commit attribution: checkout is depth 2 (6 commits in the metadata snapshot, 1 reachable via HEAD^1..HEAD^2); only the aggregate HEAD^1..HEAD diff was verified.
  • Windows/macOS: not exercised (author-declared CI coverage).
  • TUI rendering path: only the prompt string assembly in useGeminiStream.ts was verified; interactive rendering of the resulting message is unchanged code and out of scope for a byte-identity refactor.
  • The drift itself: TUI vs ACP/headless wording differences are preserved by design; the A/B negative control confirms the preservation.
  • The author's own 25-case extraction script was not re-run; it is superseded by the 165-cell matrix above, which uses the same verbatim-extraction idea with an added diff-fidelity oracle.
  • The first runs of two harnesses contained harness-side bugs (ANSI-coloured vitest summary broke an anchored regex; the eslint liveness probe used a _-prefixed name that varsIgnorePattern: '^_' legitimately ignores). Both were fixed and the harnesses re-run in full; the replaced runs are not counted in assertions.json. Neither was a PR defect.

Methodology

Environment: node:22-bookworm CI verify container, merge-ref checkout (HEAD = 2f70174c88, HEAD^1 = base cf3e8ad, HEAD^2 = PR head 5218760), npm ci + npm run build pre-run at HEAD. This round re-ran at the same commits as the previous round, so every measurement was rebuilt and re-executed rather than carried forward; all numbers reproduced exactly (165/165 byte-identity cells, 393 core-goals tests, 1036+1 host tests, 5/5 mutants killed). The A/B drove the old code by extracting it verbatim from HEAD^1 (fidelity + round-trip oracles) and the new code through the built packages/core dist entry the hosts import (realpath asserted). Gates ran the real vitest suites, tsc --noEmit per package, and eslint/prettier with planted-violation liveness checks (eslint: unused var reported at 82:7 then clean after restore; prettier: in-repo misformatted probe exits 1). All harnesses, raw logs, and assertions.json (234 pass / 0 fail) live in tmp/pr9581-verify-20260823-053736/; the working tree was left clean (git status --porcelain empty) after every mutation/probe step.

Flakiness gate log

rounds=5 files=3 skipped=0
file packages/cli/src/acp-integration/session/Session.test.ts: (cd packages/cli) npx --no-install vitest run ./src/acp-integration/session/Session.test.ts
file packages/cli/src/nonInteractiveCli.test.ts: (cd packages/cli) npx --no-install vitest run ./src/nonInteractiveCli.test.ts
file packages/core/src/goals/goal-continuation-prompt.test.ts: (cd packages/core) npx --no-install vitest run ./src/goals/goal-continuation-prompt.test.ts


per-file results (P=pass F=fail I=infra-exit, one letter per run):
  packages/cli/src/acp-integration/session/Session.test.ts: PPPPP
  packages/cli/src/nonInteractiveCli.test.ts: PPPPP
  packages/core/src/goals/goal-continuation-prompt.test.ts: PPPPP

verdict: pass
summary: 3 changed test file(s) x 5 identical rounds, no divergence

--- per-invocation detail (full copy in the artifact) ---
round 1 · packages/cli/src/acp-integration/session/Session.test.ts: P (exit 0)
round 1 · packages/cli/src/nonInteractiveCli.test.ts: P (exit 0)
round 1 · packages/core/src/goals/goal-continuation-prompt.test.ts: P (exit 0)
round 2 · packages/cli/src/acp-integration/session/Session.test.ts: P (exit 0)
round 2 · packages/cli/src/nonInteractiveCli.test.ts: P (exit 0)
round 2 · packages/core/src/goals/goal-continuation-prompt.test.ts: P (exit 0)
round 3 · packages/cli/src/acp-integration/session/Session.test.ts: P (exit 0)
round 3 · packages/cli/src/nonInteractiveCli.test.ts: P (exit 0)
round 3 · packages/core/src/goals/goal-continuation-prompt.test.ts: P (exit 0)
round 4 · packages/cli/src/acp-integration/session/Session.test.ts: P (exit 0)
round 4 · packages/cli/src/nonInteractiveCli.test.ts: P (exit 0)
round 4 · packages/core/src/goals/goal-continuation-prompt.test.ts: P (exit 0)
round 5 · packages/cli/src/acp-integration/session/Session.test.ts: P (exit 0)
round 5 · packages/cli/src/nonInteractiveCli.test.ts: P (exit 0)
round 5 · packages/core/src/goals/goal-continuation-prompt.test.ts: P (exit 0)

Evidence images

01-ab-fidelity-and-tui-cells

02-ab-controls-and-summary

03-mutation-matrix

04-type-contract-probe

05-targeted-gates

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

Qwen Code · sandboxed verification

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

🤖 Reviewed the latest feedback — no changes needed.

Why, point by point:

  • No new review findings. The only review newer than the last evaluation (2026-08-23T05:00:53Z) is an APPROVE with no body from maintainer @wenshao — nothing to address. All earlier inline suggestions were already handled in prior rounds (fixes landed in f0b322cc14 and 4e35a4b811).
  • No new inline comments. Zero inline review comments since the last evaluation.
  • The only new issue-level comment is informational. It is the triage bot's status post that sandboxed verification is running (action run) — not actionable feedback.
  • All checks are green. Every check on the current head is either SUCCESS or SKIPPED; none failed or incomplete. The previously red Test (ubuntu-latest, Node 22.x) check passes on the updated base.
  • No conflict with main was reported for this round, so no merge was performed.

The working tree stays as-is; no commit was made this round.

中文说明

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

逐点说明:

  • 没有新的评审发现。 上次评估(2026-08-23T05:00:53Z)之后唯一的新评审是维护者 @wenshao 提交的一个无正文的 APPROVE(批准) —— 没有任何需要处理的内容。更早的所有 inline 建议已在之前的轮次中处理完毕(修复已包含在 f0b322cc144e35a4b811 中)。
  • 没有新的 inline 评论。 自上次评估以来,inline 评审评论数量为零。
  • 唯一的新 issue 级评论是信息性的。 它是 triage 机器人发布的状态帖,说明沙箱验证正在运行(action 运行)—— 并非可执行的反馈。
  • 所有检查均为绿色。 当前 head 上的每一项检查要么是 SUCCESS(成功),要么是 SKIPPED(跳过);没有失败或未完成的检查。之前变红的 Test (ubuntu-latest, Node 22.x) 检查在更新 base 后已通过。
  • main 没有冲突,本轮未报告冲突,因此未执行任何合并操作。

工作区保持原样;本轮没有产生任何提交。

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


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

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Triage re-run completed without a new review.

⚠️ The bot's only review on 5218760b9983c335edd47a72abd4f523c4c1ee2d is a COMMENTED one, which carries no vote — so it has no verdict of its own on this commit, and main needs two approving reviews: an approval left by another account is a separate vote and does not count as the bot's own. Two different things look like this, and the stage-3 comment above says which: the triage skill deferring on purpose at 3/5 — a fork refactor hitting the approval guardrail, or a core change escalated for maintainer awareness, both normal outcomes — or an earlier approval that a push dismissed, leaving only the comment behind, which needs a fresh review.

⚠️ 机器人在 5218760b9983c335edd47a72abd4f523c4c1ee2d 上唯一的评审是 COMMENTED不带票 —— 因此它在该 commit 上没有自己的裁决,而 main 需要两个批准(其他账号的批准是另一张票)。有两种情况长这样,上方的 stage-3 评论会说明是哪一种:triage skill 在 3/5 时有意 defer(fork refactor 命中审批护栏,或核心改动被升级交由维护者把关,两者都是正常结果);或者更早的批准被一次推送作废、只剩下这条评论,此时需要重新评审。

The stage comments above were updated with the latest result. View workflow run.

上方各阶段评论已更新为最新结果。查看工作流运行

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

Autofix round report — PR #9581 (no action taken)

Summary

This round's feedback contains no new findings. All six inline items are author replies ("Fixed in …") to earlier automated-reviewer findings, and the six review bodies are the empty COMMENTED vehicles carrying those replies. There are no issue-level comments and no still-red checks: the only non-success checks in the window are five Signal the reviewed fork PR / route runs CANCELLED by duplicate overlapping workflow runs at 06:38–06:39 UTC, and the same jobs succeeded in that burst's final run (06:39:09–10 UTC). Test (ubuntu-latest, Node 22.x) is SUCCESS at the current HEAD 5218760b99.

No code changes were made this round. Instead, every claimed fix was re-verified source-blind against HEAD 5218760b99, including independent mutation probes for the two claims about test coverage.

Verification of each claimed fix

Thread Original finding Claimed fix Re-verification at HEAD
rc:3837884896 (R1-1) Host→renderer wiring not pinned by variant-specific assertions f0b322cc14 Code: the Runtime continuation context: check weather matcher in Session.test.ts and the Runtime continuation context: existing goal matcher in nonInteractiveCli.test.ts ("runs resume with the exact permit scheduled by Core") are both present. Probe: reworking the shared core wrapper to the guarded-synthetic-turn variant makes both tests FAIL (1 failed | 677 skipped; 1 failed | 128 skipped); restored → both PASS.
rc:3837884937 (R1-2) Unused public export GoalContinuationVariant f0b322cc14 (delete option) A repo-wide sweep across packages/**/*.{ts,tsx} returns zero occurrences; the renderer's exhaustive never switch remains the only variant enforcement. Full build (tsc for all packages) passes.
rc:3837884985, rc:3837885027, rc:3837885068 (R1-3, reported three times) buildGoalContinuationParts duplicated across the ACP and headless hosts 0db1e18577 (hoisted to core) Code: exactly one definition remains, in packages/core/src/goals/goal-continuation-prompt.ts; both host copies are deleted; all four host call sites (Session.ts:2210, nonInteractiveCli.ts:1200/2491/2521) call the core function and pass both fields through it.
rc:3837885109 (R2-1) verifierFeedback wiring untested at the host level 4e35a4b811 Code: a Verifier feedback: canary exists in both hosts (the ACP canonical-permit test and the new headless "includes verifier feedback in a scheduled Goal continuation" test). Probe: dropping verifierFeedback from the core wrapper makes both host tests FAIL; restored → both PASS.

All three fix commits (f0b322cc14, 0db1e18577, 4e35a4b811) are ancestors of HEAD. The six findings are therefore resolved in the code; their thread ids are listed for resolution so a re-reviewer can focus on anything genuinely open.

Verification

  • npm run build — passed
  • vitest packages/core src/goals/goal-continuation-prompt.test.ts — 6 passed
  • vitest packages/cli Session.test.ts -t "runs a host-scheduled Goal turn with the canonical permit" — 1 passed | 677 skipped (678)
  • vitest packages/cli nonInteractiveCli.test.ts -t "runs resume with the exact permit scheduled by Core" — 1 passed | 128 skipped (129)
  • vitest packages/cli nonInteractiveCli.test.ts -t "includes verifier feedback in a scheduled Goal continuation" — 1 passed | 128 skipped (129)
  • Mutation probes: variant swap → both host tests red; dropped verifierFeedback wiring → both host tests red; restored → all green; git status --porcelain clean, HEAD still 5218760b99
中文说明

Autofix 轮次报告 — PR #9581(未采取行动)

摘要

本轮反馈中没有新的发现项。全部六条行内条目都是作者对此前自动审查发现项的回复("Fixed in …"),六条评审主体(review body)只是承载这些回复的空 COMMENTED 载体。没有 issue 级评论,也没有持续失败的检查:本窗口内唯一非成功的检查是 06:38–06:39 UTC 期间因重复触发的并行工作流运行而被取消(CANCELLED)的五次 Signal the reviewed fork PR / route,同名任务已在该批次的最后一次运行(06:39:09–10 UTC)中成功。Test (ubuntu-latest, Node 22.x) 在当前 HEAD 5218760b99 上为 SUCCESS。

本轮未做任何代码修改。每一条"已修复"的声明都已按"来源盲审"原则在 HEAD 5218760b99 上重新核实,其中两条关于测试覆盖的声明还额外做了独立的变异探针(mutation probe)验证。

每条修复声明的核实

线程 原始发现项 声明的修复 在 HEAD 上的重新核实
rc:3837884896 (R1-1) 宿主→渲染器的接线缺少变体专属断言锁定 f0b322cc14 代码核实:Session.test.ts 中的 Runtime continuation context: check weather 匹配器与 nonInteractiveCli.test.ts"runs resume with the exact permit scheduled by Core")中的 Runtime continuation context: existing goal 匹配器均存在。探针:把共享的 core 包装函数改成 guarded-synthetic-turn 变体后,两个测试均 FAIL(1 failed | 677 skipped;1 failed | 128 skipped);还原后两者均 PASS。
rc:3837884937 (R1-2) 未被使用的公开导出 GoalContinuationVariant f0b322cc14(采取删除方案) packages/**/*.{ts,tsx} 全库扫描结果为零处出现;渲染器中穷举的 never switch 仍是唯一的变体强制约束。全量构建(所有包的 tsc)通过。
rc:3837884985、rc:3837885027、rc:3837885068(R1-3,共上报三次) buildGoalContinuationParts 在 ACP 与 headless 两个宿主间重复 0db1e18577(上移至 core) 代码核实:仅剩唯一一份定义,位于 packages/core/src/goals/goal-continuation-prompt.ts;两个宿主中的副本均已删除;全部四个宿主调用点(Session.ts:2210nonInteractiveCli.ts:1200/2491/2521)都调用 core 函数并把两个字段完整传入。
rc:3837885109 (R2-1) verifierFeedback 接线在宿主层面没有测试 4e35a4b811 代码核实:两个宿主都存在 Verifier feedback: 金丝雀断言(ACP 的 canonical-permit 测试,以及新增的 headless 测试 "includes verifier feedback in a scheduled Goal continuation")。探针:从 core 包装函数中去掉 verifierFeedback 后,两个宿主测试均 FAIL;还原后均 PASS。

三个修复提交(f0b322cc140db1e185774e35a4b811)都是 HEAD 的祖先提交。因此这六条发现项均已在代码中解决;对应的线程 id 已列出以便解决(resolve),让复审者可以专注于真正未决的内容。

验证

  • npm run build — 通过
  • vitest packages/core src/goals/goal-continuation-prompt.test.ts — 6 passed
  • vitest packages/cli Session.test.ts -t "runs a host-scheduled Goal turn with the canonical permit" — 1 passed | 677 skipped (678)
  • vitest packages/cli nonInteractiveCli.test.ts -t "runs resume with the exact permit scheduled by Core" — 1 passed | 128 skipped (129)
  • vitest packages/cli nonInteractiveCli.test.ts -t "includes verifier feedback in a scheduled Goal continuation" — 1 passed | 128 skipped (129)
  • 变异探针:变体替换 → 两个宿主测试变红;去掉 verifierFeedback 接线 → 两个宿主测试变红;还原后全部恢复绿色;git status --porcelain 干净,HEAD 仍为 5218760b99

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


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

@qqqys

qqqys commented Aug 24, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /triage

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Sandboxed verification: ✅ passed — merge-ready (agent verdict) - workflow run

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

Scripted assertions: 233 passed · 0 failed · 233 total

Flakiness gate: ✅ 3 changed test file(s) x 5 identical rounds, no divergence

中文 — 判定:✅ 通过 · 可合入(agent 判定)

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

脚本断言:233 通过 · 0 失败 · 233 总计

抖动门:✅ 3 changed test file(s) x 5 identical rounds, no divergence

Verification report

<!-- qwen-triage:verify -->
<!-- qwen-triage:verify-substantive -->

Verdict: merge-ready — 233/233 scripted assertions passed, 0 unexpected failures. Verified head: 5218760b9983c335edd47a72abd4f523c4c1ee2d (merge-ref checkout HEAD = 80c5996a956d172432e581863026a3c4a74bc9c8, base HEAD^1 = 7385b278b2017a0b6bfeff59380d23b57848fd4a; the metadata snapshot's baseRefOid cf3e8ad is stale — main advanced and the PR was re-merged on top of it).

中文摘要
  • 判定:merge-ready。跟进轮:PR head(5218760)与上一轮相同,但 base 从 cf3e8ad 前进到 7385b27(PR 在新 main 上重新合并)。按跟进规则全部携带测量整体重跑,不引用旧数:A/B 165 个字节一致单元在新 base 上全同、变异矩阵 5/5 击杀、类型契约探针三臂如预期、门禁全绿(233/233 断言)。
  • A/B 结论:中心声明(纯重构、逐字节一致)在新合并目标上成立。改动前三份拼装从新 HEAD^1 逐字抽出(保真 6/6、剥离往返 7/7),与 HEAD 构建产物中 core 渲染器在 165 个单元上逐字节比对(TUI 11/11、ACP 77/77、headless 77/77);负对照、重复普查、真值判断、生产拼装点普查 3→1 均如预期。见 "Central claim and A/B" 表与 01-ab-byte-identity-live.png
  • Delta 归因:host 套件计数 1037→1045(+8 collected):PR 自身测试 diff 贡献 +1 新用例(numstat +11/−0+33/−0useGeminiStream.test.tsx 未动),其余 +7 来自 base 前进(depth-2 不可枚举),全部通过。
  • Findings:无新发现。两条描述级 nit 原样保留(PR 正文计数 382/1020 与实测 393/1044+1 不符;Session.test.ts 对既有测试输入做纯增量扩展),见状态表。
  • 未覆盖:浅克隆下逐 commit 归因不可做;Windows/macOS 未跑;TUI 渲染路径与漂移本身按 PR 声明不在范围;作者自述 25 例抽取脚本被 165 单元矩阵取代。

Previous-finding status (follow-up round)

Delta since the previous round: the PR head is unchanged (5218760), but the merge target advanced (cf3e8ad7385b27), so the effective HEAD^1..HEAD diff was re-anchored. It is byte-for-byte the PR's own 8-file set — main's advance touched none of the PR's files (git diff --name-only equals the PR file set, asserted). Per the follow-up rule every carried measurement was rebuilt and re-executed at the new base rather than carried forward.

# finding (previous round) severity status at 5218760 on base 7385b27 (re-measured)
1 PR body test counts stale (claims 382 / 1020) nit stands — re-measured: core goals suite 393 passed / 16 files, host suites 1044 passed + 1 skipped (logs/gates.log); body unchanged. The property the numbers meant to convey (all green, one pre-existing skip) still holds; the skip is the same it.skip('should emit a single user envelope…'), asserted present at HEAD^1.
2 Session.test.ts edits an existing test's input (adds verifierFeedback) and appends two expectations nit, informational stands — re-verified numstat +11 −0 (and nonInteractiveCli.test.ts +33 −0, useGeminiStream.test.tsx untouched); purely additive, no expectation weakened. I agree with the classification.
3 scripts/verify-capture.mjs produced blank PNGs two rounds ago infra (Not covered) fixed, re-confirmed — all four evidence images this round were produced by the helper and visually verified legible (02-mutation-matrix-live.png read in full; 01-ab-byte-identity-live.png zoom-checked).
4 Per-commit attribution unreachable (depth-2 checkout) infra (Not covered) standsgit rev-list --count HEAD^1..HEAD^2 = 1 vs 6 commits in the metadata snapshot; --is-shallow-repository = true; aggregate diff verified.

Central claim and A/B

Central claim (unchanged): pure refactor — each host (interactive TUI, ACP session, non-interactive CLI) sends a byte-identical Goal continuation prompt before and after; the three drifted assemblies collapse into one core renderer (renderGoalContinuationPrompt, variants guarded-synthetic-turn and runtime-context).

Control construction (re-run at new base): the pre-change assemblers were extracted verbatim from HEAD^1 (7385b27) by harness/ab-byte-identity.mjs: the diff's removed lines were located inside git show HEAD^1:<file> and required to match contiguously and uniquely (6 fidelity assertions, all pass). Only type tokens (: AcpGoalTurn, : HeadlessGoalTurn, : Part[]) and the TUI queryToSend: property wrapper were stripped to make the old code runnable; round-trip assertions prove the strips are exactly those tokens (7/7). Head side: the built package entry @qwen-code/qwen-code-core imported via import.meta.resolve, realpath asserted inside the HEAD tree (/__w/qwen-code/qwen-code/packages/core), and entry export byte-equal to the direct dist module on a sample cell. Raw log: logs/ab-matrix.log; witness evidence/01-ab-byte-identity-live.png (full live run, 197 rows).

cell control (verbatim 7385b27) head (core dist) oracle result
TUI path, 11 feedback values (undefined, '', plain, multi-line, ${…}, backtick, backslash, quotes, padded, '0', unicode) inline array literal renderGoalContinuationPrompt({variant:'guarded-synthetic-turn'}) string byte-equality 11/11 identical
ACP path, 7 contexts × 11 feedbacks = 77 (incl. empty context, embedded quotes/newlines/backslashes) local buildGoalContinuationParts core buildGoalContinuationParts parts deep-equal + single-text-part shape 77/77 identical
headless path, same 77 cells local buildGoalContinuationParts core buildGoalContinuationParts parts deep-equal + shape 77/77 identical
negative control old TUI vs old ACP output must DIFFER (drift preserved; comparator has teeth) differ
negative control new guarded vs new runtime-context must DIFFER differ
duplication census old ACP vs old headless on all 77 cells must be identical (they were duplicates) identical (77/77)
empty-verifierFeedback truthiness line omitted on both variants ''undefined output holds
assembler census git grep production marker at HEAD^1 working tree 3 assemblers → 1 3 → 1 (Session.ts, nonInteractiveCli.ts, useGeminiStream.ts → goal-continuation-prompt.ts)

189/189 assertions in this harness (logs/assertions-ab.json).

Secondary claims

Pinned-literal tests are load-bearing (re-run; witness evidence/02-mutation-matrix-live.png, log logs/mutation-matrix.log). Every mutation landed in the mutated file; each red run was an expected-vs-actual AssertionError, not import/compile breakage; source restored byte-identical afterwards (git status --porcelain empty):

row mutation expected observed
M0 none (control) green green (exit 0, 0 failed)
M1 delete 2nd anti-spoofing guard line caught 2 failed
M2 truthy guard → !== undefined caught 1 failed (the empty-string test)
M3 verifier-feedback line emitted before the variant line caught 2 failed
M4 edit shared line (Goal.goal.) caught 4 failed
M5 buildGoalContinuationParts renders wrong variant caught 1 failed (the parts test)

8/8 matrix assertions as expected.

Discriminated-union contract (re-run; witness evidence/03-type-contract-live.png): arm0 — probe without directives makes tsc --noEmit in packages/core exit 2 with the two real errors (TS2345 missing continuationContext at probe line 2, TS2353 excess continuationContext on the guarded variant at line 3) — liveness proven; arm1 — with two single-line @ts-expect-error directives and the contract intact, exit 0; arm2 — making continuationContext optional flips exactly the missing-context directive to TS2578: Unused '@ts-expect-error' directive (1 error repo-wide) while the excess-property directive still suppresses a real error. "Host cannot forget the context" is compile-enforced. 11/11 assertions.

Host suites are the regression check (witness evidence/04-targeted-gates.png): Session.test.ts (686), nonInteractiveCli.test.ts (129 incl. 1 pre-existing skip), useGeminiStream.test.tsx (230) → 1044 passed + 1 skipped / 3 files. Test-file diffs are purely additive at this head (+11/−0, +33/−0, untouched), so no pre-existing expectation was edited. Count delta vs the previous round (1037 → 1045 collected): the PR contributes exactly +1 collected test (the new it in nonInteractiveCli.test.ts); the remaining +7 come from the base advance cf3e8ad7385b27 (not enumerable from a depth-2 checkout; literal it( census base→head: 639→639 / 119→120 / 222→222). All green.

Findings

No new findings. The two carried nits (status-table rows 1–2) stand; both are description-level and non-blocking.

Not covered

  • Per-commit attribution: checkout is depth 2 (6 commits in the metadata snapshot, 1 reachable via HEAD^1..HEAD^2); only the aggregate HEAD^1..HEAD diff was verified.
  • Windows/macOS: not exercised (author-declared CI coverage).
  • TUI rendering path: only the prompt string assembly in useGeminiStream.ts was verified; interactive rendering of the resulting message is unchanged code and out of scope for a byte-identity refactor.
  • The drift itself: TUI vs ACP/headless wording differences are preserved by design; the A/B negative control confirms the preservation.
  • Base-advance enumeration: the +7 collected tests added by main between cf3e8ad and 7385b27 were attributed by delta (PR diff bounded to +1) but not individually enumerated — cf3e8ad is unreachable from this shallow checkout.
  • The author's own 25-case extraction script was not re-run; it is superseded by the 165-cell matrix above, which uses the same verbatim-extraction idea with an added diff-fidelity oracle.
  • The first runs of two harnesses this round contained harness-side bugs (a JS regex ^ used unescaped mid-pattern in the census strip; a TUI rewrap that mis-ordered the property prefix; a prettier-stderr vs stdout mix; a missing module-scope import). All were fixed and the harnesses re-run in full; the replaced runs are not counted in assertions.json. None was a PR defect.

Methodology

Environment: node:22-bookworm CI verify container, merge-ref checkout (HEAD = 80c5996a95, HEAD^1 = base 7385b27, HEAD^2 = PR head 5218760), npm ci + npm run build pre-run at HEAD. Follow-up round at an unchanged PR head but an advanced base, so every measurement was rebuilt and re-executed against HEAD^1 rather than carried forward. The A/B drove the old code by extracting it verbatim from HEAD^1 (fidelity + round-trip oracles) and the new code through the built packages/core dist entry the hosts import (realpath asserted). Gates ran the real vitest suites (core goals live; host suites recorded this round), tsc --noEmit per package, and eslint/prettier with planted-violation liveness checks (unused var reported at 82:7 then clean after restore; misformatted probe exits 1). All harnesses, raw logs, per-harness assertion JSONs, and the aggregate assertions.json (233 pass / 0 fail) live in tmp/pr9581-verify-20260824-023243/; the working tree was left clean (git status --porcelain empty) after every mutation/probe step.

Flakiness gate log

rounds=5 files=3 skipped=0
file packages/cli/src/acp-integration/session/Session.test.ts: (cd packages/cli) npx --no-install vitest run ./src/acp-integration/session/Session.test.ts
file packages/cli/src/nonInteractiveCli.test.ts: (cd packages/cli) npx --no-install vitest run ./src/nonInteractiveCli.test.ts
file packages/core/src/goals/goal-continuation-prompt.test.ts: (cd packages/core) npx --no-install vitest run ./src/goals/goal-continuation-prompt.test.ts


per-file results (P=pass F=fail I=infra-exit, one letter per run):
  packages/cli/src/acp-integration/session/Session.test.ts: PPPPP
  packages/cli/src/nonInteractiveCli.test.ts: PPPPP
  packages/core/src/goals/goal-continuation-prompt.test.ts: PPPPP

verdict: pass
summary: 3 changed test file(s) x 5 identical rounds, no divergence

--- per-invocation detail (full copy in the artifact) ---
round 1 · packages/cli/src/acp-integration/session/Session.test.ts: P (exit 0)
round 1 · packages/cli/src/nonInteractiveCli.test.ts: P (exit 0)
round 1 · packages/core/src/goals/goal-continuation-prompt.test.ts: P (exit 0)
round 2 · packages/cli/src/acp-integration/session/Session.test.ts: P (exit 0)
round 2 · packages/cli/src/nonInteractiveCli.test.ts: P (exit 0)
round 2 · packages/core/src/goals/goal-continuation-prompt.test.ts: P (exit 0)
round 3 · packages/cli/src/acp-integration/session/Session.test.ts: P (exit 0)
round 3 · packages/cli/src/nonInteractiveCli.test.ts: P (exit 0)
round 3 · packages/core/src/goals/goal-continuation-prompt.test.ts: P (exit 0)
round 4 · packages/cli/src/acp-integration/session/Session.test.ts: P (exit 0)
round 4 · packages/cli/src/nonInteractiveCli.test.ts: P (exit 0)
round 4 · packages/core/src/goals/goal-continuation-prompt.test.ts: P (exit 0)
round 5 · packages/cli/src/acp-integration/session/Session.test.ts: P (exit 0)
round 5 · packages/cli/src/nonInteractiveCli.test.ts: P (exit 0)
round 5 · packages/core/src/goals/goal-continuation-prompt.test.ts: P (exit 0)

Evidence images

01-ab-byte-identity-live

02-mutation-matrix-live

03-type-contract-live

04-targeted-gates

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

Qwen Code · sandboxed verification

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

Autofix round report — PR #9581 (no action taken)

No review feedback required changes in this round, so no code was modified.

What was triaged:

  • Reviews: none newer than the last evaluation.
  • Inline comments: none.
  • Failed checks / still-red checks: none.
  • Issue-level comments: one comment from @qwen-code-ci-bot ([ic:5389929367]) announcing that sandboxed verification is running. It is a status notification, not review feedback, and it requests no changes.
  • No deferred non-Critical feedback section (critical-only brake not engaged), no growth audit required, and no prior-round rejection or budget warning in the feedback.

Outcome: nothing to address; the branch head was left unchanged and nothing was committed.

中文说明

Autofix 轮次报告 — PR #9581(未执行任何操作)

本轮没有需要修改代码的评审反馈,因此未修改任何代码。

本次分拣的内容:

  • 评审(Reviews):自上次评估以来没有新的评审。
  • 行内评论(Inline comments):无。
  • 失败的检查 / 仍然失败的检查:无。
  • Issue 级评论:仅有一条来自 @qwen-code-ci-bot 的评论([ic:5389929367]),通知沙箱验证正在运行。这是一条状态通知,不是评审反馈,也未要求任何修改。
  • 没有「已延期的非 Critical 反馈」部分(未进入仅处理 Critical 的制动状态),没有要求增长审计,反馈中也没有上一轮被拒或预算告警的内容。

结果: 没有需要处理的事项;分支头保持不变,未提交任何内容。

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


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

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Triage re-run completed without a new review.

⚠️ The bot's only review on 5218760b9983c335edd47a72abd4f523c4c1ee2d is a COMMENTED one, which carries no vote — so it has no verdict of its own on this commit, and main needs two approving reviews: an approval left by another account is a separate vote and does not count as the bot's own. Two different things look like this, and the stage-3 comment above says which: the triage skill deferring on purpose at 3/5 — a fork refactor hitting the approval guardrail, or a core change escalated for maintainer awareness, both normal outcomes — or an earlier approval that a push dismissed, leaving only the comment behind, which needs a fresh review.

⚠️ 机器人在 5218760b9983c335edd47a72abd4f523c4c1ee2d 上唯一的评审是 COMMENTED不带票 —— 因此它在该 commit 上没有自己的裁决,而 main 需要两个批准(其他账号的批准是另一张票)。有两种情况长这样,上方的 stage-3 评论会说明是哪一种:triage skill 在 3/5 时有意 defer(fork refactor 命中审批护栏,或核心改动被升级交由维护者把关,两者都是正常结果);或者更早的批准被一次推送作废、只剩下这条评论,此时需要重新评审。

The stage comments above were updated with the latest result. View workflow run.

上方各阶段评论已更新为最新结果。查看工作流运行

@yiliang114 yiliang114 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM. Verified the byte-equivalence claim structurally at head 5218760:

  • The renderer is faithful to each original assembly: SHARED_LINES then variant lines then the verifier line, joined on '\n' — the TUI's array literal was shared(4) + guard(2) + conditional verifier, and both buildGoalContinuationParts copies were shared(4) + runtime-context + conditional verifier, which is exactly the two variants' shapes in the same orders. The if (input.verifierFeedback) truthiness guard preserves the original empty-string omission.
  • The discriminated union enforces the split: runtime-context requires continuationContext at the type level, guarded-synthetic-turn carries no context field, and the switch is exhaustive with a never arm — a host can no longer assemble either shape by hand.
  • The host suites are the regression check as claimed: Session.test.ts and nonInteractiveCli.test.ts changes are additions only (new cases pinning the continuation-context and verifier-feedback lines); no existing expectation was edited.
  • The drift itself is intentionally left (TUI guards without context, ACP/headless context without guards) — consistent with the stated scope, reconciliation belongs to a behavior-change PR.

CI at approval time: 21 checks passing, none failing.

@wenshao
wenshao added this pull request to the merge queue Aug 24, 2026
Merged via the queue into QwenLM:main with commit 75fb40d Aug 24, 2026
239 of 249 checks passed
qqqys added a commit to qqqys/qwen-code that referenced this pull request Aug 24, 2026
QwenLM#9581 landed squashed, so the branch's copies of its commits conflicted with
the merged version. Resolved in favour of this branch throughout: B2 supersedes
B1's prompt contract, so the converged renderer, its test, and the host
assertions that pin the guarded data block replace B1's variant-based versions.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
TianYuan1024 pushed a commit to TianYuan1024/qwen-code that referenced this pull request Aug 24, 2026
…tract (QwenLM#9834)

* refactor(goal): render Goal continuation prompts from one core renderer

The prompt sent when `runtime.finishTurn` schedules another Goal turn was
assembled independently in three hosts: the TUI's inline array in
`useGeminiStream`, and a `buildGoalContinuationParts` in each of the ACP
session and the non-interactive CLI. Three copies of the same four shared
lines have already drifted -- the TUI carries the anti-spoofing guard lines
but no objective, while ACP and non-interactive carry the runtime
continuation context but no guard lines.

Upcoming work adds further variants (an "objective was edited" announcement
and a budget wind-down prompt). With the text living in three places, every
new variant means three edits, which is precisely how the current drift was
produced. This moves assembly into `packages/core/src/goals/goal-continuation-prompt.ts`,
where a variant is a case in one function and the shared prefix exists once.
The two `buildGoalContinuationParts` helpers keep their names and signatures
and simply delegate.

This is a pure refactor: no prompt text changes. Each host still emits a
byte-identical string to the one it emitted before. The existing drift is
preserved deliberately and is left for a separate, behavior-changing
follow-up. The new unit test pins the complete rendered string for both
variants with and without verifier feedback, so any future edit to a line
surfaces as a test diff; the existing host tests pass unmodified.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(goal): tighten continuation renderer contract

* test(goal): cover verifier feedback hosts

* refactor(goal): hoist Goal continuation parts builder into core (QwenLM#9581)

* fix(goal): converge the three continuation prompts on one guarded contract

Every automatic Goal turn now renders the same prompt in every host: the
runtime-supplied goalId, revision and objective as an escaped JSON data
block, framed as untrusted task data, under both anti-spoofing guard
lines, followed by a line stating the block supersedes any earlier
objective in the conversation.

Before this change the drift ran the wrong way. ACP and non-interactive
interpolated the raw objective into a synthetic user-role turn carrying
neither guard line; the TUI carried both guard lines but dropped the
objective, so the host that guarded most gave up information and the two
that guarded least were the exposed ones. None of the three escaped the
objective, so objective text shaped like a tag could break out of the
surrounding prompt.

The prompt input collapses to a single flat shape, so the variant
discriminant and its unreachable-default arm are gone. `<`, `>` and `&`
are escaped inside the serialized JSON so an objective cannot close the
data block or open one of its own.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: qqqys <266654365+qqqys@users.noreply.github.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Released in v0.22.2.

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