Skip to content

feat(review): validate Aone inline anchors against the captured diff before posting - #9634

Merged
wenshao merged 17 commits into
QwenLM:mainfrom
wenshao:feat/review-aone-anchor-gate
Aug 22, 2026
Merged

feat(review): validate Aone inline anchors against the captured diff before posting#9634
wenshao merged 17 commits into
QwenLM:mainfrom
wenshao:feat/review-aone-anchor-gate

Conversation

@wenshao

@wenshao wenshao commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator

What this PR does

This PR pins the inline-anchoring semantics of /review --comment on Aone Code targets. Before anything posts, the Aone write path now validates every well-formed inline finding's anchor against the diff the review captured: an anchor must sit inside a new-side hunk of its file, and a declared old-side anchor is unanchorable by construction. A finding whose anchor cannot be vouched for degrades deterministically instead of posting — a Critical is relocated into the review summary body with its path:line attribution kept, a Suggestion is discarded and counted — and every degrade is disclosed in the terminal, exactly the dispose GitHub's server-side 422 recovery performs in prose. A missing captured diff refuses the whole post before anything writes. Malformed comment shapes (missing path/line, a reversed range, a renders-as-nothing body) keep the existing consistency refusals, and garbage state shapes stand the gate down so the composition's pinned field-naming refusal fires instead of being laundered. The GitHub path is untouched.

Why it's needed

A controlled probe against a scratch Aone code review proved the platform performs zero server-side anchor validation: any positive integer posts, an old-side (deleted-line) number silently lands on the same-numbered NEW-side line — including on untouched code outside every hunk — and the read-back outdated flag cannot tell a misanchored comment from an anchored one. The old side cannot be anchored at all (the CLI expresses --line as a new-side position only, even in the latest release), and file-level comments drop their path entirely, so they are not a usable degrade target. On GitHub this whole failure class is caught server-side with a 422 and the skill's recovery loop turns it into relocated Criticals and discarded Suggestions; on Aone the behavior was undefined — the anchor either failed at post time or, worse, landed on a wrong line silently. Findings on removed lines are a normal review output ("this deletion drops the last caller of X"), so the write path owed them a defined, disclosed dispose. That was open question Q2 in the platform-provider design document; this PR records the probe evidence and lands the behavior the probe supports.

Reviewer Test Plan

How to verify

The unit tests narrate the full behavior table — run npx vitest run src/commands/review/submit-aone.test.ts src/commands/review/lib/anchors.test.ts src/commands/review/submit.test.ts in packages/cli. The shapes to confirm: a new-side in-hunk anchor posts unchanged; an out-of-hunk / file-not-in-diff / declared-LEFT Critical relocates into the summary body and counts toward C; the same as a Suggestion is discarded and counts toward S, with each named in the terminal disclosure; a missing captured diff exits 3 with reason: "aone-post-refused" and nothing written; malformed shapes and a non-array body-Criticals field reach the existing refusals untouched; and the GitHub path emits no gate fields and changes no behavior. End-to-end, a live post of a mixed payload (one valid anchor, one out-of-hunk Critical, one beyond-EOF Suggestion) to the scratch CR landed exactly one inline comment at the valid line and a summary carrying the relocated Critical plus the discard sentence — nothing at the two bad lines.

Evidence (Before & After)

Before (current build, ungated): a --dry-run of the mixed payload reports wouldPost: true with 3 inline — both invalid anchors would post, the Critical silently landing on untouched code. After: the same run reports 1 inline, prints the anchor-check disclosure naming the relocated Critical and the discarded Suggestion, and carries anchorsRelocated: 1, anchorsDiscarded: 1 in its JSON. Live read-back after the real post shows one new inline comment (line: 32, side: right) and a summary body containing **[Critical]** qwen-review-anchor-probe.txt:18 — … plus the sentence 1 Suggestion-level finding(s) could not be anchored to a changed line and were dropped; no comment exists at line 18 or 9999. The probe record lives in the repo's e2e-tests directory; the scratch CR is closed with branches retained as evidence.

Tested on

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

Environment (optional)

Unit tests plus the bundled CLI driven against a real Aone scratch MR via the a1 CLI (v0.2.51); the probe and the live verification ran on the intranet.

Risk & Scope

  • Main risk or tradeoff: an Aone post now requires the review's captured diff on disk — a submit run from a directory without it refuses (exit 3) instead of posting unvalidated anchors; the normal skill flow always captures the diff, so this only affects out-of-band re-runs, and the refusal names the remedy.
  • Not validated / out of scope: real old-side anchoring (the platform cannot express it — revisiting needs an a1 CLI surface change first); file-level degrades (path dropped by the platform); the GitHub path (unchanged by construction — the gate runs only on the Aone branch).
  • Breaking changes / migration notes: none; the GitHub write path, the JSON contract off-Aone, and all existing refusal shapes are preserved.

Linked Issues

Closes #9615

中文说明

这个 PR 做了什么

本 PR 钉死 /review --comment 在 Aone Code 目标上的行内锚点语义。在发布任何内容之前,Aone 写路径现在会用审查捕获的 diff 校验每个格式良好的行内发现的锚点:锚点必须落在其文件的新侧 hunk 内,声明的旧侧锚点构造上即不可锚定。无法担保锚点的发现会被确定性地降级而不是发布——Critical 连同其 path:line 归属一起迁入审查总结正文,Suggestion 被丢弃并计数——每一次降级都在终端披露,与 GitHub 服务端 422 恢复流程在 prose 中执行的处置完全一致。缺少捕获的 diff 时,在任何写入发生前整体拒绝发布。畸形评论形状(缺 path/line、反转的 range、渲染为空的 body)保留既有一致性拒绝;垃圾的 state 形状会让门整体退避,使组合阶段钉死的字段命名拒绝生效,而不是被洗白。GitHub 路径完全不受影响。

为什么需要

在 scratch Aone CR 上做的受控探测证明:平台服务端不做任何锚点校验——任何正整数行号都能发布;旧侧(被删除行)的行号会静默落在新侧同号行上——包括落在所有 hunk 之外的未改动代码上;读回的 outdated 标志无法区分错锚与正常锚点。旧侧完全无法锚定(即使是最新版 CLI,--line 也只能表达新侧位置);文件级评论会丢失其 path,因此也不是可用的降级目标。在 GitHub 上,这一整类失败会被服务端以 422 拦截,skill 的恢复循环会把它转化为迁入正文的 Critical 和被丢弃的 Suggestion;而在 Aone 上行为是未定义的——锚点要么在发布时报错,要么(更糟)静默落在错误的行上。关于被删除行的发现是正常的审查产出("这个删除移除了 X 的最后一个调用方"),写路径欠它们一个有定义、有披露的处置。这正是平台 provider 设计文档中的悬而未决问题 Q2;本 PR 记录探测证据,并按探测支持的形态落地行为。

评审测试计划

如何验证

单元测试叙述了完整的行为表——在 packages/cli 下运行 npx vitest run src/commands/review/submit-aone.test.ts src/commands/review/lib/anchors.test.ts src/commands/review/submit.test.ts。需要确认的形态:新侧 hunk 内的锚点照常发布;hunk 外 / 文件不在 diff 中 / 声明 LEFT 的 Critical 迁入总结正文并计入 C;同为 Suggestion 时被丢弃并计入 S,且每一条都在终端披露中点名;缺少捕获的 diff 时以 exit 3 退出、reason: "aone-post-refused"、无任何写入;畸形形状与非数组的 body-Criticals 字段原样到达既有拒绝;GitHub 路径不输出门字段、行为无任何变化。端到端方面:向 scratch CR 真实提交了一个混合 payload(一个合法锚点、一个 hunk 外 Critical、一个越界 Suggestion),结果恰好只在合法行落了一条 inline 评论,总结正文携带迁移后的 Critical 与丢弃句——两个坏行号上没有任何评论。

证据(前后对比)

修复前(当前构建,无门):混合 payload 的 --dry-run 报告 wouldPost: true3 条 inline——两个非法锚点都会发布,Critical 会静默落在未改动代码上。修复后:同样的运行报告 1 条 inline,打印锚点检查披露(点名迁移的 Critical 与丢弃的 Suggestion),JSON 中携带 anchorsRelocated: 1, anchorsDiscarded: 1。真实提交后的读回显示恰好一条新 inline 评论(line: 32, side: right),总结正文包含 **[Critical]** qwen-review-anchor-probe.txt:18 — … 以及句子 1 Suggestion-level finding(s) could not be anchored to a changed line and were dropped;18 与 9999 行上不存在任何评论。探测记录存放在仓库的 e2e-tests 目录;scratch CR 已关闭,分支保留作为证据。

测试环境

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

运行环境(可选)

单元测试 + 经 a1 CLI(v0.2.51)驱动打包后的 CLI 对真实 Aone scratch MR 验证;探测与 live 验证均在内网执行。

风险与范围

  • 主要风险或权衡:Aone 发布现在要求审查捕获的 diff 在盘上——从没有该 diff 的目录运行 submit 会被拒绝(exit 3)而不是发布未校验的锚点;正常 skill 流程总是捕获 diff,因此只影响带外重跑,且拒绝信息指明了补救方法。
  • 未验证 / 范围外:真旧侧锚定(平台无法表达——重启该方向需要先有 a1 CLI 的表面变化);文件级降级(平台丢弃 path);GitHub 路径(构造上不受影响——门只在 Aone 分支运行)。
  • 破坏性变更 / 迁移说明:无;GitHub 写路径、Aone 之外的 JSON 契约、所有既有拒绝形状均保持不变。

关联 Issue

Closes #9615

…before posting

Aone Code performs no server-side anchor validation — a controlled probe
(scratch MR 29427547, a1 v0.2.51) proved any --line integer posts, and
an old-side number silently lands on the same-numbered new-side line.
The old side cannot be anchored at all, and file-level comments drop
their path.

Pin the removed-line semantics for the Aone write path: submit's Aone
branch now validates every well-formed inline anchor against the
review's captured diff before posting. An unanchorable Critical is
relocated into the summary body, an unanchorable Suggestion discarded
and counted — the GitHub 422-recovery dispose, performed in code — each
disclosed in the terminal. A missing captured diff refuses the whole
post; malformed shapes (missing path/line, reversed range,
renders-as-nothing) keep their consistency-gate refusals, and a garbage
state.bodyCriticals stands the gate down so compose's pinned refusal
fires. The GitHub path is untouched — its server performs this
validation.

Issue QwenLM#9615
@github-actions github-actions Bot added the review/self-reported The linked issue was opened by the PR author (self-reported) label Aug 21, 2026
@wenshao

wenshao commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator Author

E2E test report

Probe (platform facts, scratch CR 29427547 of base-biz/sqlt, a1 v0.2.51): a one-file diff shaped so every probe is unambiguous — two deletion blocks plus an appended line, new-side hunk coverage [1-6] ∪ [9-14] ∪ [29-32].

Probe --line intent Accepted? Read-back Conclusion
P1 32, a + line 201 side: right, outdated: false baseline: the write path's shape works
P1b 2, context inside a hunk 201 side: right, outdated: false legal GitHub-style anchor
P2 4 = DELETED old line; new-side 4 is a different in-hunk line 201 side: right, line: 4, outdated: false silent wrong-line anchor
P2b 18 = DELETED old line; new-side 18 outside every hunk 201 side: right, line: 18, outdated: false the GitHub-422 class misanchors with no signal anywhere
P3 9999, beyond EOF 201 side: right, outdated: true zero range validation; outdated only beyond EOF
P4 --file only, no --line 201 path: null, side: null file-level comments are MR-level in disguise — path dropped

Baseline gap (pre-change build): qwen review submit --dry-run of a mixed payload (valid anchor + out-of-hunk Critical + beyond-EOF Suggestion) reported wouldPost: true with 3 inline — both invalid anchors passed ungated.

Gated behavior (this PR): the same dry-run reports 1 inline, prints Aone anchor check: 2 inline comment(s) cannot be anchored to the MR's new side … naming the relocated Critical and the discarded Suggestion, and carries anchorsRelocated: 1, anchorsDiscarded: 1. A declared-LEFT anchor relocates the same way; a missing captured diff exits 3 with reason: "aone-post-refused"; the GitHub dry-run of the identical payload reports 3 inline with no gate fields (server validation is GitHub's).

Live post: a real submit of the mixed payload landed exactly ONE inline comment (line: 32, side: right) plus the summary; the summary body carried **[Critical]** qwen-review-anchor-probe.txt:18 — … and 1 Suggestion-level finding(s) could not be anchored to a changed line and were dropped; read-back confirmed nothing at line 18 or 9999.

Unit: packages/clisubmit-aone.test.ts + submit.test.ts + anchors.test.ts 219/219; full src/commands/review suite 4160 passed / 0 failed across 93 files.

@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 21, 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 21, 2026

Copy link
Copy Markdown
Collaborator

Re-run — this pass reviews f146c811 (the prior pass reviewed 885ac6b2; six fix commits landed since, addressing eight /review rounds).

  • Template: complete ✓ — all required sections, bilingual body, honest Tested-on table.
  • Problem: observed, not theoretical. Linked issue review: Aone Code — inline anchoring for removed lines #9615 is the open Q2 in the provider design docs, and the retained probe (scratch MR 29427547, a1 v0.2.51) demonstrates the platform posts any --line unvalidated and cannot express the old side — an old-side number silently lands on the same-numbered new-side line, even on untouched code outside every hunk. The before/after dry-run comparison in the PR body is the evidence this gate asks for.
  • Direction: aligned — this closes a named open question in already-committed design docs rather than opening a new front, and mirrors the dispose GitHub's 422 recovery already performs.
  • Size: core paths touched — extensionManager.ts (5 lines, prettier import wrap) and the bundled review SKILL.md (one prose sentence). Production logic grew 283 → 684 lines across the review rounds (submit.ts 468, anchors.ts 119, compose-review.ts 80, platform/aone.ts 12, extensionManager.ts 5), against 1548 test lines and 290 docs/skill-prose lines. That crosses the 500-line maintainer-awareness threshold, so it is flagged here per the gate; a feat-type PR is not blocked on size, and the growth is the hardening the review rounds demanded, not scope creep. The core touches themselves are trivial.
  • Approach: scope still feels right — validate-then-degrade on the Aone branch only, deterministic dispose (Critical → relocated into the summary body with attribution kept, Suggestion → discarded and counted), every degrade disclosed, fail-closed refusal when the captured diff is missing. The rounds added structural hardening (built-entry validation against compose's own acceptance, explicit-null-side semantics, authored-index tracking) rather than new surface.
  • Risk: no elevated signals — no changed file matches the revert-correlated high-risk paths.

Moving on to code review. 🔍

中文说明

Re-run —— 本轮审查 f146c811(上一轮审查的是 885ac6b2;此后落地了 6 个 fix 提交,处理 8 轮 /review 反馈)。

  • 模板:完整 ✓ —— 各必填部分齐全,中英双语正文,Tested-on 表格如实填写。
  • 问题:已观测到,而非理论问题。关联 issue review: Aone Code — inline anchoring for removed lines #9615 是 provider 设计文档中悬而未决的 Q2;保留的探测记录(scratch MR 29427547、a1 v0.2.51)证明平台对任意 --line 都不校验、也无法表达旧侧——旧侧行号会静默落在同号的新侧行上,甚至落在所有 hunk 之外的未改动代码上。PR 正文中的 before/after dry-run 对比正是本 gate 要求的证据。
  • 方向:对齐——收尾已提交设计文档中点名的未决问题,而不是另开战线;处置方式镜像 GitHub 422 恢复路径。
  • 规模:触及核心路径——extensionManager.ts(5 行,prettier 导入换行)与 bundled review SKILL.md(1 句文案)。生产逻辑经评审轮次从 283 增至 684 行submit.ts 468、anchors.ts 119、compose-review.ts 80、platform/aone.ts 12、extensionManager.ts 5),另有测试 1548 行、文档/技能文案 290 行。已越过 500 行维护者关注阈值,按 gate 规则在此标记;feat 类型不因规模阻塞,且增量是评审轮次要求的加固而非范围蔓延。核心路径触碰本身很轻。
  • 方案:范围依然合理——仅在 Aone 分支做"校验后降级",处置确定性明确(Critical → 迁入总结正文并保留归属,Suggestion → 丢弃并计数),每次降级都披露,捕获 diff 缺失时 fail-closed 拒发。各轮增加的是结构性加固(构造条目按 compose 自身验收校验、显式 null side 语义、原作者索引跟踪),而非新表面。
  • 风险:无升级信号——改动文件均未命中与 revert 相关的高风险路径。

进入代码审查 🔍

Qwen Code · qwen3.8-max

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

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Code review

This pass covers the current head f146c811 — the six fix commits landed since the last triage pass, addressing eight /review rounds. All 50 review threads are resolved; I verified the two round-8 Criticals against the code rather than taking the thread replies at face value:

  • R7-1 (explicit JSON null side)validateNewSideAnchors now computes sideDeclared/startSideDeclared as !== undefined && !== null, so a model-style null reads as absent (default RIGHT) while any PRESENT non-RIGHT value stays unanchorable by construction. Pinned twice: a validator case and a submit-level post case (posts a single-line comment with an explicit null side inline).
  • R3-2 (relocated-entry channel)relocatedAoneCriticalEntry now validates the BUILT entry against compose's own ingestion (tryIngestBodyCriticals over the single entry) and degrades any refusal to the inert constant finding — (no path):<line>; the demonstrated entrances (a lone CR in the claim, a fence delimiter at position 0) have witnesses. The claim extraction strips a marker RUN (stacked markers), and the path arm rejects CR/LF and fence-leading paths into the (no path) placeholder.

The integration points re-verified on the current head:

  • Gate placement is correct: after normalizeInlineComments (submit.ts:980), before floor enforcement and the consistency gate. The gate consults the SAME commentShapeProblems list the consistency gate reports — the two cannot drift; malformed shapes (missing path/line, reversed range, renders-as-nothing) keep their loud refusals, and the gate rules anchors only.
  • The stand-down reads compose's real acceptance: toStringList throws on any non-array, so tryIngestBodyCriticals returns undefined for a string/garbage bodyCriticals and the whole gate stands down — the payload reaches compose unchanged and dies the pinned refusal. The merge (Array.isArray(bc) ? bc : []) executes only once acceptance is established, so nothing accepted by compose is silently dropped; tryToCount covers the suggestionsDiscarded half (integer-but-not-safe accepted, garbage refused — both pinned).
  • authoredIndices threads through both removal sites (gate relocation and floor enforcement), so post-removal consistency refusals cite the model-authored index the re-compose loop must fix — pinned, including the floor-enforcement-after-gate interaction.
  • GitHub path untouched: the dry-run gate counts spread conditionally on aoneWrite && !anchorsUnchecked, and the success-path emission carrying anchorsRelocated/anchorsDiscarded sits inside the Aone-only branch (submit.ts:1380). Missing captured diff → exit 3 aone-post-refused for the real write, disclosed skip with wouldPost: false / reason: 'aone-diff-missing' for --dry-run.
  • Core touches are benign: extensionManager.ts is a prettier-only import wrap (a drive-by — harmless, noted for hygiene); the bundled review SKILL.md sentence matches the implemented behavior exactly (five refusal shapes, the dry-run exception, the degrade promise).
  • compose-review.ts change is a pure extraction + total-function export: ingestBodyCriticals moves existing logic verbatim; tryIngestBodyCriticals/tryToCount expose compose's acceptance tables so the gate and compose can never drift. No behavior change on the compose side.

No critical blockers and no convention violations found. One non-blocking carry-over from round 8's deferred list, verified still standing: docs/users/features/code-review.md's Aone paragraph still describes the pre-gate behavior (no mention of the anchor check, the degrade, or the missing-diff refusal). The review pipeline explicitly deferred it, so it does not gate this PR — worth a follow-up doc update.

Files changed (12 of 12)
File What changed
packages/cli/src/commands/review/submit.ts the Aone anchor gate: validate-then-degrade, fail-closed missing-diff refusal, authored-index tracking, relocated-entry builder with compose-acceptance validation
packages/cli/src/commands/review/lib/anchors.ts new validateNewSideAnchors: input-domain rejection, null-side semantics, hunk containment with pure-deletion guard
packages/cli/src/commands/review/compose-review.ts extraction of bodyCriticals acceptance plus total-function exports (tryToCount, tryIngestBodyCriticals); no behavior change
packages/cli/src/commands/review/lib/platform/aone.ts doc comment pinning the new-side-only, nothing-unvouched contract
packages/cli/src/commands/review/submit-aone.test.ts ~40 gate scenarios driving the real runSubmit against a captured-diff fixture
packages/cli/src/commands/review/lib/anchors.test.ts 15 validator cases: hunks, ranges, deletion files, fractions, reversed ranges, null side
packages/cli/src/commands/review/submit.test.ts Aone-routing tests now supply the captured diff the gate requires
packages/core/src/skills/bundled/review/SKILL.md one sentence: the Aone anchoring promise now matches the code
packages/core/src/extension/extensionManager.ts prettier import wrap only (drive-by)
docs/design/2026-08-21-review-aone-removed-line-anchoring.md new probe record: platform facts, pinned semantics, failure-shape table
docs/design/2026-08-13-review-platform-provider-abstraction.md Q2 marked resolved with a dated status entry
docs/design/2026-08-15-review-aone-provider.md open question 2's anchor half marked resolved

Testing — the PR's own CI (never run locally in unattended triage)

At review time the PR's own CI is fully settled on f146c811: both pull_request workflow runs (Qwen Code CI, Security Checks) completed success, and nothing is red. The web-shell E2E Smoke that was red on the previously reviewed commit is green here. The macOS/Windows unit legs and the integration tests are skipped, as usual on fork PRs. The finalize workflow keeps ownership of the table below.

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
Classify PR ✅ success
precheck-pr / precheck ✅ success

The suite pins the change: ~40 submit-level gate scenarios drive the real runSubmit against a real captured-diff fixture (only the a1 write seam, compose, and platform routing are mocked — exactly the boundary the probe characterizes), plus 15 validator cases covering hunks, ranges, pure-deletion files, fractions, reversed ranges, and the null-side shape. Two evidence notes, plainly attributed: round 8's review body reported Test Plan: no such file or directory for the three test files — that is the reviewer invoking vitest from the repo root instead of packages/cli (the paths are package-relative), not a PR defect; the green ubuntu suite confirms the files run. And the live before/after numbers in the PR body remain the author's intranet run against the scratch CR — not independently re-run here.

Sandboxed verification would settle the remaining in-repo question — whether the new suite is load-bearing (fails on the base build): the verify job running as part of this very triage run is that A/B proof, and its report will post in this thread when it completes. The other half — the live Aone post — is intranet-only by platform nature; no sandboxed lane can re-run it, and the retained probe record (scratch MR 29427547, E2E report in-thread) is the evidence for that half.

中文说明

代码审查:本轮覆盖当前头部 f146c811——上次 triage 之后落地的 6 个 fix 提交,处理了 8 轮 /review 反馈。全部 50 个评审线程已解决;两个第 8 轮 Critical 我是对照代码核实的,没有只采信线程回复:

  • R7-1(显式 JSON null side)validateNewSideAnchors 现在以 !== undefined && !== null 判定 side 是否声明,模型风格的 null 按"缺省"读(默认 RIGHT),任何"存在且非 RIGHT"的值构造上不可锚定。验证器与 submit 层各有测试钉死。
  • R3-2(重定位条目通道)relocatedAoneCriticalEntry 现在把构造好的条目送 compose 自身的摄取(tryIngestBodyCriticals)校验,任何拒绝降级为惰性常量 finding — (no path):<line>;已演示的入口(claim 中孤立 CR、0 位围栏分隔符)均有 witness。claim 提取剥除成串标记,path 分支拒绝 CR/LF 与围栏开头路径。

集成点在当前头部重新核实:

  • gate 位置正确:位于 normalizeInlineComments 之后、floor 强制与一致性 gate 之前;gate 与一致性 gate 读同一份 commentShapeProblems,两者不会漂移——畸形形状仍走响亮拒绝,gate 只裁锚点。
  • 整体退避读的是 compose 的真实验收toStringList 对非数组抛错,因此字符串/垃圾 bodyCriticals 使 tryIngestBodyCriticals 返回 undefined,gate 整体退避,payload 原样到达 compose 并按既有拒绝失败。合并只在验收成立后执行,compose 会接受的内容不会被静默丢弃;tryToCount 覆盖 suggestionsDiscarded 半边(非 safe 整数被接受、垃圾被拒——均有测试)。
  • authoredIndices 贯穿两个删除点(gate 重定位与 floor 强制),删除后的一致性拒绝引用模型原作者索引——有测试钉死,包括 gate 后 floor 的交互。
  • GitHub 路径未动:dry-run 计数字段条件性附加(aoneWrite && !anchorsUnchecked),成功路径的计数字段位于 Aone 专属分支(submit.ts:1380)。缺捕获 diff:真实发布 exit 3 aone-post-refused--dry-run 披露跳过、wouldPost: falsereason: 'aone-diff-missing'
  • 核心路径触碰无害extensionManager.ts 仅是 prettier 导入换行(顺手改动,记为卫生项);bundled SKILL.md 文案与实现行为逐字一致。
  • compose-review.ts 是纯提取 + 全函数导出ingestBodyCriticals 原样搬移既有逻辑;tryIngestBodyCriticals/tryToCount 把 compose 的验收表暴露给 gate,使两边永不漂移。compose 侧行为无变化。

未发现阻塞问题与规范违规。一项非阻塞遗留(第 8 轮明确延后项,核实仍存在):docs/users/features/code-review.md 的 Aone 段落仍描述门前行为——值得后续补文档,不阻塞本 PR。

测试证据(无人值守 CI,不在本地运行 PR 代码):审查时 f146c811 的 PR 自身 CI 已全部结束:两个 pull_request 工作流(Qwen Code CISecurity Checks)均成功,无红项;上一被审提交上红过的 web-shell E2E Smoke 此处已绿;macOS/Windows 单测与集成测试按 fork PR 惯例跳过。表格由 finalize 工作流维护。套件钉住改动:约 40 个 submit 级场景驱动真实 runSubmit 与真实捕获 diff fixture(仅 mock a1 写缝隙、compose 与平台路由),另有 15 个验证器用例。两点如实标注:第 8 轮评审正文中 "Test Plan: no such file or directory" 是评审者从仓库根而非 packages/cli 运行 vitest 所致(路径是包相对),非 PR 缺陷——绿掉的 ubuntu 套件证明文件可运行;PR 正文的 live before/after 数字仍是作者内网运行结果,本次未独立复跑。沙箱验证能覆盖的剩余问题——新套件是否承重(在 base 构建上失败)——正是本次 triage 运行中正在执行的 verify 任务,报告完成后会发布在本线程。另一半——live Aone 发布——平台属性上仅内网可达,任何沙箱通道都无法复跑,证据即保留的探测记录。

Qwen Code · qwen3.8-max

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

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Confidence: 3/5 — clean review on the current head, capped by policy rather than doubt: the six fix commits since the last pass each trace to a specific review finding, the two remaining round-8 Criticals are verified fixed in code (not just in thread replies), CI is fully green on f146c811, and all 50 threads are resolved — but this feat touches core paths at 684 production-logic lines, past the Stage 0 maintainer-awareness threshold, and an escalated PR does not get the bot's auto-approve.

Stepping back: my independent proposal for this problem was exactly the shape this PR lands — validate anchors against the captured diff in the Aone branch, degrade like GitHub's 422 recovery, fail closed when the diff is absent — and the PR exceeds it where it matters (the compose-acceptance stand-down, the built-entry validation, the authored-index tracking). The growth since the last pass is legitimate: every fix commit answers a named finding from eight adversarial review rounds, and the production line count grew by hardening, not by scope creep. The one drive-by (the prettier import wrap in extensionManager.ts) is harmless hygiene, not worth a round trip. The problem stays real and evidenced — the probe record demonstrates the silent-misanchor class concretely — and if I had to maintain this in six months, the failure-shape table in the design doc and the dense why-comments would read as the constraints they document.

Two open items remain before an approval decision, and neither is something the diff can settle:

  1. The Stage 0 awareness escalation — the gate requires a maintainer's sign-off on a core-touching feat of this size before the bot's approval vote.
  2. The sandboxed verify report for this head is still in flight (running as part of this triage run); it settles the A/B load-bearing question for the new suite, and its verdict should land in this thread before anyone approves on the strength of the suite alone.

⏸️ Deferring to @wenshao — Stage 0 maintainer-awareness escalation on an otherwise-clean PR, plus the pending verify report. You are the maintainer of record here (and the author): either route this to a second maintainer for the sign-off the escalation asks for, or weigh the green CI + resolved threads + probe record yourself. The bot's approval vote stays withheld until then; nothing in this review requests changes.

中文说明

置信度:3/5 —— 当前头部的审查是干净的,压分来自政策而非疑虑:上次审查之后的 6 个 fix 提交每一条都能对应到具体的评审发现;第 8 轮剩余的两个 Critical 已对照代码确认修复(而非仅采信线程回复);f146c811 上 CI 全绿;50 个线程全部解决——但本 feat 触及核心路径且生产逻辑 684 行,越过 Stage 0 维护者关注阈值,被升级的 PR 不获得 bot 的自动批准。

退一步看:我为这个问题给出的独立方案正是本 PR 落地的形态——在 Aone 分支对捕获 diff 校验锚点、按 GitHub 422 恢复降级、diff 缺失时 fail-closed——而 PR 在关键处做得更深(compose 验收整体退避、构造条目校验、原作者索引跟踪)。上次审查之后的增量是合理的:每个 fix 提交都回应 8 轮对抗性评审中点名的发现,生产行数增长来自加固而非范围蔓延。唯一顺手改动(extensionManager.ts 的 prettier 导入换行)是无害卫生项,不值得来回。问题依然真实且有证据——探测记录具体展示了静默错锚一类失败——六个月后维护时,设计文档的失败形态表与密集的 why 注释读起来是其所记录的约束。

批准决定前还剩两个开放项,均非 diff 本身能定夺:

  1. Stage 0 关注升级——gate 要求维护者对这一规模的核心触碰 feat 签认后,bot 才投批准票。
  2. 针对当前头部的沙箱 verify 报告仍在进行(作为本次 triage 运行的一部分);它回答新套件是否承重的 A/B 问题,其结论应先落在这条线程里,再谈仅凭套件绿色批准。

⏸️ 转交 @wenshao —— 审查其余部分全部干净,但本 PR 触发 Stage 0 维护者关注升级,外加未落地的 verify 报告。你是此处的维护者(也是作者):可以按升级要求转请第二位维护者签认,也可以自行权衡绿 CI + 已解决线程 + 探测记录。在此之前 bot 的批准票保留;本审查不要求任何修改。

Qwen Code · qwen3.8-max

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

@wenshao

wenshao commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /takeover

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

Copy link
Copy Markdown
Collaborator

🤝 Takeover engaged: the autofix loop now manages this PR — it will address new review feedback and resolve base conflicts until the label is removed or the round cap is reached. This is a fork PR, so the first round comes from the next scheduled scan (usually within minutes). Remove the autofix/takeover label (or comment @qwen-code /takeover stop) to release.

中文说明

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

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

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

@wenshao

wenshao commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /resolve

@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: reverse audit — did not converge within the reverse-audit round cap of 10.

Test Plan (not a blocker): src/commands/review/submit-aone.test.tsno such file or directory; src/commands/review/lib/anchors.test.tsno such file or directory; src/commands/review/submit.test.tsno such file or directory.

中文说明

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

未审查:反向审计——在 10 轮的反审轮数上限内未收敛。

Test Plan(非阻断):src/commands/review/submit-aone.test.tsno such file or directory; src/commands/review/lib/anchors.test.tsno such file or directory; src/commands/review/submit.test.tsno such file or directory

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

Comment thread packages/cli/src/commands/review/lib/anchors.ts
Comment thread packages/cli/src/commands/review/submit.ts Outdated
Comment thread packages/cli/src/commands/review/submit.ts Outdated
Comment thread packages/cli/src/commands/review/submit.ts Outdated
Comment thread packages/cli/src/commands/review/submit.ts Outdated
Comment thread packages/cli/src/commands/review/lib/anchors.test.ts
Comment thread packages/cli/src/commands/review/submit.ts Outdated
Comment thread packages/cli/src/commands/review/submit.ts Outdated
Comment thread packages/cli/src/commands/review/submit.ts Outdated
Comment thread packages/cli/src/commands/review/submit.ts Outdated
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

Qwen Code attempted to resolve merge conflicts but the run did not complete successfully.

Check the workflow run for full logs.

@qwen-code-dev-bot

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

Copy link
Copy Markdown
Collaborator

⚠️ AutoFix round 1 ended without publishing a reportview run.

中文说明

⚠️ AutoFix 第 1 轮结束但未发布报告 —— 查看运行

…e refusals

- validateNewSideAnchors now rejects the input domain (fractional/zero/negative
  lines and reversed ranges) before the hunk scan, so its verdict can no longer
  certify an anchor the zero-validation Aone platform would post silently wrong.
- Extract the consistency gate's per-comment shape checks into one shared
  predicate (commentShapeProblems) read by both the loud refusal and the Aone
  anchor gate, so a shape the gate disposes is never a refusal the operator
  misses (open fence, start_line-without-side). The path check becomes a type
  check, closing truthy non-string paths that reached the write seam unvouched.
@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 round — PR #9634 (Aone anchor gate)

This round merged origin/main (base conflicts resolved, see below), then
addressed the two Critical findings and four Suggestion findings from
the review, and deferred four lower-priority Suggestions to the next round.

Base merge (--conflict true)

Merged origin/main into feat/review-aone-anchor-gate. Main had moved the
review subsystem forward (notably a large compose-review.ts change and an
AI-comment-gate disclosure). Two files conflicted and were resolved by keeping
both sides' independent additions:

  • docs/design/2026-08-13-review-platform-provider-abstraction.md
  • packages/core/src/skills/bundled/review/SKILL.md
    • The Aone --comment bullet: main added the AI-comment gate disclosure;
      this PR added the anchor check as a fifth failure/refusal shape. The
      merged bullet carries both — "Five failure/refusal shapes" including the
      anchor check, plus the AI-comment disclosure.

submit.ts, aone.ts, and submit-aone.test.ts auto-merged cleanly (main's
edits were in regions this PR does not touch). The full review suite passes on
the merged state.

Feedback dispositions

Resolved in code (6):

  • [Critical] R1-1 (anchors.ts): validateNewSideAnchors accepted two
    input classes its contract excludes — reversed ranges ({line:10, startLine:21} degenerates the lo>hi containment test) and non-integer
    lines ({line:11.5} passes the span check). Reproduced both against the
    built function, then added an input-domain rejection (fractional/zero/
    negative lines, reversed ranges) before the hunk scan. Control verdicts
    unchanged.
  • [Critical] R1-18 (submit.ts): a truthy NON-string path (e.g. 42)
    passed both gates and reached the Aone write seam unvouched, because the
    consistency gate only checked !c.path. Reproduced it reaching
    submitAoneReview; the path check is now a type check
    (typeof c.path !== 'string' || c.path === ''), refusing the shape loudly.
  • [Suggestion] R1-2 (submit.ts): the gate's keep predicate hand-copied
    the consistency gate's shape checks and dropped the open-fence and
    start_line-without-side branches. Extracted the per-comment shape checks
    into one shared predicate (commentShapeProblems) read by both the loud
    refusal and the gate, so the two cannot drift; any future shape rule lands in
    both at once. Both probed divergences now refuse loudly regardless of anchor
    position.
  • [Suggestion] R1-4 (anchors.test.ts): the pure-deletion test probed line
    3, which cannot witness the newCount > 0 guard. Added the discriminating
    line-2 case (inside the clamped [newStart, newEnd], rejected only by the
    guard).
  • [Suggestion] R1-5 (submit-aone.test.ts): added the two missing
    suggestionsDiscarded arms — the array form (['x','y'] + one discard → 3)
    and the garbage fall-through ('two' reaches compose unchanged).
  • [Suggestion] R1-6 (submit-aone.test.ts): added the case relocating a
    Critical into an EXISTING bodyCriticals array, asserting both entries
    survive in order.

Deferred to the next round (4) — recorded in comment-replies.json, left
unresolved: R1-9 (stand-down over sibling garbage shapes — already safe
outcomes), R1-3 (toCount acceptance divergence — narrow, cross-module fix),
R1-14 (gate-relocated Criticals' tag-classification route divergence — a design
call), R1-15 (dry-run + missing captured diff exits 3 — dry-run-fidelity fix).

Verification approach

Each Critical/Suggestion that claims current behavior is WRONG was reproduced
first (focused failing test / probe against the unmodified code), then fixed
minimally, and the new test was kept as the witness. Mutation probes confirmed
every new guard has its own witness: with the source fixes reverted, all six
defect tests fail; each guard individually negated fails its own test; restored,
everything is green.

Verification

Commands actually run this round (all from the repo root unless noted):

  • git merge origin/main — conflicts in 2 files, resolved by keeping both
    sides' additions; committed as 38e029ba46.
  • npm ci — installed deps and ran the prepare build. Passed (exit 0). Note:
    required a writable npm cache (--cache /tmp/npm-cache-qc) because
    ~/.npm contains root-owned files on this runner.
  • npm run typecheckpassed (all workspace packages, incl. packages/cli).
  • npm run lintpassed (ESLint, 0 errors).
  • npm run buildpassed (all packages compiled + assets copied).
  • Focused Vitest src/commands/review/{submit-aone,submit}.test.ts +
    lib/anchors.test.ts229 passed (219 prior + 10 new).
  • Focused Vitest src/commands/review (whole subsystem) — 98 files, 4322
    passed, 4 skipped, 0 failed
    (includes compose-review.test.ts, confirming
    the shared-predicate refactor did not change compose's contract).
  • Mutation probes — reverted source fixes → the 6 new defect tests fail;
    restored → green. Per-guard probes (path type check, gate consultation,
    isWholeLine, reversed-range guard) each fail their own test when negated.
  • Settings schema — not required (no settings source changed this round).
  • Integration tests after npm run bundlenot required: the touched
    behavior is exercised through focused unit tests, not only through the bundled
    CLI/integration harness (no review-submit integration tests exist).
  • web-shell E2E Smoke (the one red CI check) — not runnable on this runner;
    see note below.

Note on the web-shell E2E Smoke failure: This check is unrelated to the
change and not reproducible as a code failure here. Evidence: (1) the PR commit
touches zero web-shell/webui/desktop files (verified via
git show 885ac6b29e --name-only); (2) the smoke suite needs a real Chromium —
installing it on this runner and launching it fails with 20+ missing system
libraries (libglib-2.0, libnss3, libX11, ...), which CI provides via
playwright install --with-deps. This is an environment-specific check the
current runner cannot execute; the workflow's independent CI remains the final
verification gate.

中文说明

Autofix 审查轮次 — PR #9634(Aone 锚点门)

本轮先合并了 origin/main(解决基线冲突,见下),随后处理了审查中的两个
Critical 发现与四个 Suggestion 发现,并把四个较低优先级的 Suggestion
延迟到下一轮。

基线合并(--conflict true

origin/main 合并进 feat/review-aone-anchor-gate。main 已把 review 子系统
向前推进(尤其是 compose-review.ts 的大改动,以及 AI 评论门的披露)。有两个
文件冲突,均通过保留双方各自独立的增量来解决:

  • docs/design/2026-08-13-review-platform-provider-abstraction.md
  • packages/core/src/skills/bundled/review/SKILL.md
    • Aone --comment bullet:main 增加了 AI 评论门的披露;本 PR 把锚点检查
      作为第五种失败/拒绝形态加入。合并后的 bullet 两者兼备——"五种失败/拒绝形态"
      (含锚点检查),外加 AI 评论披露。

submit.tsaone.tssubmit-aone.test.ts 自动合并干净(main 的改动位于本 PR
不涉及的区域)。合并后的状态下整个 review 测试套件通过。

反馈处置

已在代码中解决(6 项):

  • [Critical] R1-1anchors.ts):validateNewSideAnchors 接受了其契约所
    排除的两类输入——反转区间({line:10, startLine:21} 使 lo>hi 的包含判断
    退化)与非整数行号({line:11.5} 能通过区间判断)。先对构建后的函数复现了
    这两种形态,随后在 hunk 扫描之前增加输入域拒绝(分数/零/负数行号、反转区间)。
    对照组裁决保持不变。
  • [Critical] R1-18submit.ts):真值但非字符串的 path(如 42)穿过两道
    门、未经验证地到达 Aone 写入缝隙,因为一致性门只检查 !c.path。已复现它到达
    submitAoneReview;现将 path 检查改为类型检查
    typeof c.path !== 'string' || c.path === ''),大声拒绝该形态。
  • [Suggestion] R1-2submit.ts):gate 的 keep 谓词手工复制了一致性门的形状
    检查,遗漏了未闭合围栏与 start_line 缺 side 两个分支。已把逐评论形状检查提取为
    一个共享谓词(commentShapeProblems),供大声拒绝与 gate 两处读取,二者
    不再可能漂移;未来任何新增形状规则都会同时落入两处。两个被探针证实的分歧现在无论
    锚点位置如何都大声拒绝。
  • [Suggestion] R1-4anchors.test.ts):纯删除测试探测的是第 3 行,无法见证
    newCount > 0 守卫。补充了有判别力的第 2 行用例(位于钳制后的
    [newStart, newEnd] 之内,只有该守卫会拒绝)。
  • [Suggestion] R1-5submit-aone.test.ts):补齐缺失的两个
    suggestionsDiscarded 分支——数组形态(['x','y'] 加一次丢弃 → 3)与垃圾兜底
    'two' 原样到达 compose)。
  • [Suggestion] R1-6submit-aone.test.ts):补充把 Critical 迁移进已存在
    bodyCriticals 数组的用例,断言两个条目按序存活。

延迟到下一轮(4 项)——已记录在 comment-replies.json,保持未解决:R1-9
(对姊妹垃圾形态的整体退出——结局本已安全)、R1-3(toCount 接受表分歧——影响面窄、
属跨模块修复)、R1-14(gate 迁移 Critical 的标签分类路径分歧——属设计判断)、
R1-15(dry-run + 缺失捕获 diff 退出 3——dry-run 语义保真修复)。

验证方式

凡是声称当前行为有错的 Critical/Suggestion,都先复现(针对未改动代码写聚焦失败
测试/探针),再做最小修复,并保留新测试作为见证。突变探针确认每个新守卫都有其独立
见证:还原源码修复时六个缺陷测试全部失败;逐个否定每个守卫时对应测试失败;恢复后
全部转绿。

验证

本轮实际执行的命令(除特别说明外均在仓库根目录):

  • git merge origin/main — 2 个文件冲突,通过保留双方增量解决;提交为
    38e029ba46
  • npm ci — 安装依赖并执行 prepare 构建。通过(exit 0)。注:因本 runner 上
    ~/.npm 含 root 所有文件,需改用可写缓存(--cache /tmp/npm-cache-qc)。
  • npm run typecheck通过(所有 workspace 包,含 packages/cli)。
  • npm run lint通过(ESLint,0 错误)。
  • npm run build通过(所有包编译 + 资源拷贝)。
  • 聚焦 Vitest src/commands/review/{submit-aone,submit}.test.ts +
    lib/anchors.test.ts229 通过(原 219 + 新增 10)。
  • 聚焦 Vitest src/commands/review(整个子系统)— 98 个文件、4322 通过、
    4 跳过、0 失败
    (含 compose-review.test.ts,证明共享谓词重构未改变 compose
    契约)。
  • 突变探针 — 还原源码修复 → 6 个新缺陷测试失败;恢复 → 全绿。逐守卫探针
    (path 类型检查、gate 引用、isWholeLine、反转区间守卫)各自在被否定时使对应
    测试失败。
  • 设置 schema — 无需(本轮未改动任何 settings 源)。
  • npm run bundle 后的集成测试 — 无需:所改行为由聚焦单元测试覆盖,并非只能
    通过打包 CLI/集成框架验证(不存在 review-submit 的集成测试)。
  • web-shell E2E Smoke(唯一标红的 CI 检查)— 无法在本 runner 运行;见下注。

关于 web-shell E2E Smoke 失败的说明: 该检查与本改动无关,且在此无法复现为
代码缺陷。证据:(1)PR 提交触碰任何 web-shell/webui/desktop 文件(已用
git show 885ac6b29e --name-only 验证);(2)该冒烟套件需要真实 Chromium——在
本 runner 上安装并启动会因缺少 20 多个系统库(libglib-2.0libnss3libX11
等)而失败,这些依赖在 CI 中由 playwright install --with-deps 提供。这是当前
runner 无法执行的环境相关检查;工作流的独立 CI 仍是最终验证门。

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

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


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

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Partially reviewed — gaps disclosed. Suggestions are inline.

Not reviewed: reverse audit — did not converge within the reverse-audit round cap of 5 (round 5 still surfaced 6 findings, all confirmed; the loop ended at the cap, not at a dry fixed point).

Test Plan (not a blocker): src/commands/review/submit-aone.test.tsno such file or directory; src/commands/review/lib/anchors.test.tsno such file or directory; src/commands/review/submit.test.tsno such file or directory.

中文说明

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

未审查:reverse audit — did not converge within the reverse-audit round cap of 5 (round 5 still surfaced 6 findings, all confirmed; the loop ended at the cap, not at a dry fixed point)。

Test Plan(非阻断):src/commands/review/submit-aone.test.tsno such file or directory; src/commands/review/lib/anchors.test.tsno such file or directory; src/commands/review/submit.test.tsno such file or directory

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

Comment thread packages/cli/src/commands/review/submit.ts Outdated
Comment thread packages/cli/src/commands/review/submit.ts Outdated
Comment thread packages/cli/src/commands/review/lib/anchors.ts
Comment thread packages/cli/src/commands/review/submit-aone.test.ts
Comment thread packages/cli/src/commands/review/submit-aone.test.ts
Comment thread packages/cli/src/commands/review/submit.ts Outdated
Comment thread packages/cli/src/commands/review/submit.ts Outdated
Comment thread packages/cli/src/commands/review/submit.ts Outdated
Comment thread packages/cli/src/commands/review/submit.ts Outdated
Comment thread packages/cli/src/commands/review/submit.ts Outdated
qwen-code-dev-bot and others added 2 commits August 21, 2026 14:52
…or-gate

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

Round-2 review fixes for the Aone anchor gate:

- The stand-down now keys on ANY degrade that touches the payload and
  covers every compose-owned garbage shape: bodyCriticals that is not an
  array of strings, or a suggestionsDiscarded compose's counter refuses.
  The countability test reads compose's OWN acceptance table (toCount,
  exported as the total tryToCount), so the gate's merge and compose's
  counter can never drift — an integer-but-not-safe count now merges
  instead of silently dropping the gate's discards.
- The relocated entry's claim extraction strips a leading marker RUN
  (fixpoint, like every other strip) and treats a fence-delimiter claim
  line as absent — both shapes used to leak raw markers or junk
  delimiters into the posted summary-body blocker line.
- The gate keeps the model-authored comment indices through its removal
  (and floor enforcement keeps them through its own), so the consistency
  gate's refusal names the culprit in the model's payload JSON instead of
  a renumbered position the re-compose loop cannot act on.
- A --dry-run with a missing capture no longer exits 3: it writes
  nothing, so it skips the gate with a disclosure and reports
  wouldPost: false (reason: aone-diff-missing); the exit-3 refusal stays
  reserved for the real write.
- The MULTI_DIFF fixture's second hunk header becomes byte-exact git
  output (@@ -20,0 +22,2 @@, probed against git itself).
- The design doc gains the gate-relocation doctrine (relocated entries
  deliberately inherit the model's own tag-exemption treatment), the
  dry-run carve-out in the failure-shape table, and the corrected
  fence/one-line-channel claim.
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

Review round summary — PR #9634

This round addressed 9 of the 17 open findings and explicitly deferred the
remaining 8 witness-only findings to the next round (replies on each thread).
The four round-1 deferrals (R1-3, R1-9, R1-14, R1-15) were all resolved this
round as promised. No Critical/Required findings were open; every addressed
item was a Suggestion.

Conflict resolution (--conflict true)

Merged origin/main (one new commit, #9629 self-MR detection in presubmit).
One conflict, in the bundled review skill's Aone --comment bullet: our
branch had added the anchor check as the fifth Aone-specific failure shape,
while main rewrote the disclosure sentences because presubmit now backs
self-PR detection. Resolved as the union — kept our five failure/refusal
shapes (anchor check included) and took main's updated disclosure sentences
(self-PR detection IS backed; comment-status skipped, presubmit's
existing-comment classification unbacked). Also fixed the .. double-period
typo our branch had introduced in that bullet. Commit: a26fdda244.

Addressed findings

  • [rc:3831053125] R1-3 — toCount acceptance-table divergence (submit.ts:880). Implemented: compose-review now exports tryToCounttoCount's acceptance as a total function (count when accepted, undefined when it would throw), built from the same code path. The gate's suggestionsDiscarded merge and stand-down both read it, so the two reads of the field share ONE acceptance table and cannot drift. Side effect: an integer-but-not-safe count now merges (compose accepts it) instead of silently dropping the gate's discards. Witness: merges gate discards into an integer-but-not-SAFE suggestionsDiscarded…; probe re-creating the old restated table makes it fail.
  • [rc:3831053132] R1-9 — stand-down narrower than its doctrine (submit.ts:863). Implemented the finding's fix: the stand-down now keys on ANY degrade that touches the payload (anchorsRelocated > 0 || anchorsDiscarded > 0) and covers all three probed sibling shapes — bodyCriticals garbage now includes arrays carrying non-strings (shape 1), the discard-only arm stands down over garbage bodyCriticals (shape 2), and an uncountable suggestionsDiscarded stands the gate down for relocations too (shape 3), judged via tryToCount (undefined ⟺ compose would refuse). Witnesses: two new stand-down tests plus the rewritten garbage-suggestionsDiscarded test; probe disabling the stand-down fails all four.
  • [rc:3831053137] R1-14 — gate relocations and the deterministic-tag scan (submit.ts:892). Resolved via the finding's design-doc alternative: the doc now states the doctrine — gate-relocated entries deliberately inherit compose-review's treatment of the model's OWN body Criticals (whole-entry tag scan included), because the deferral channel's exemption keys on a structured source field gate relocations do not carry, and a tag on the claim line was written by the same model that drafts body Criticals directly. The bounded divergence is named and accepted rather than silently left standing. The code alternative (routing gate entries through the position-anchored rule) would need a new submit→compose provenance field plus verdict-computation changes in compose-review — a focused round of its own if a maintainer wants it.
  • [rc:3831053147] R1-15 — missing-capture refusal vs dry-run (submit.ts:785). Implemented the carve-out: under --dry-run a missing capture skips the gate with an Aone anchor check: SKIPPED — … disclosure, composes the preview over the authored payload, and reports wouldPost: false with reason: 'aone-diff-missing' (gate counts omitted). The exit-3 aone-post-refused refusal stays reserved for the real write. Design doc's Semantics bullet and failure-shape table updated; the skill's Aone bullet names the exception. Witness: a dry run with a MISSING capture skips the gate, discloses, and reports it would NOT post; probe restoring the unconditional refusal makes it fail.
  • [rc:3831053072] R2-6 — stacked-marker leak in relocated entries (submit.ts:135). Implemented: relocatedAoneCriticalEntry now strips a leading marker RUN off the extracted claim via stripSeverityPrefix (the same fixpoint iteration every other strip uses) before composing the entry. Witness: relocates a stacked-marker draft without leaking the second marker into the entry, asserting the entry is exactly src/foo.ts:4 — Off-by-one in the loop bound.; probe removing the strip makes it fail.
  • [rc:3831053079] R2-7 — fence-delimiter claim line (docs/design …md:130). Implemented the finding's first option: a claim line that IS a fence delimiter (marker-alone body leading into a fence) is treated as absent and falls back to the finding placeholder — the entry's path:line — prefix hides the delimiter from compose's line-anchored fence refusal, so the gate refuses to carry it (compose-review's ENTRY_FENCE_DELIMITER_RE is now exported and read here — one statement). The design doc's false pinned claim ("a fenced code block never enters the one-line channel") is corrected accordingly. Witness: relocates a marker-alone body leading into a fence as the placeholder…; probe removing the check makes it fail.
  • [rc:3831053037] R2-1 — claim || 'finding' placeholder witness (submit.ts:139). Folded into the R2-6/R2-7 work because those fixes mutate exactly this branch: added the finding's witness (attribution: false, body '**[Critical]**\n:\n', out-of-hunk line) asserting bodyCriticals equals ['src/foo.ts:9999 — finding']; probe removing the placeholder fallback makes it fail.
  • [rc:3831053113] R2-13 — refusal indices misaligned after gate removals (submit.ts:835). Implemented: the gate keeps the model-authored indices of every kept comment (keptIndices), floor enforcement threads its own removal through the same mapping, and inconsistencies cites the authored index (authoredIndices?.[i] ?? i). The re-compose loop now fixes the comment the index names in the model's JSON. Witness: cites the MODEL-AUTHORED comment index in the refusal after the gate renumbers the array (gate relocates comments[0], malformed comments[1] must be cited as comments[1]); probe reverting to the post-gate index makes it fail.
  • [rc:3831053085] R2-8 — MULTI_DIFF fixture violates git's count-0 invariant (anchors.test.ts:944). Implemented: the second hunk header is now @@ -20,0 +22,2 @@ — probed against git itself in a scratch repo replicating the fixture shapes (delta +1 after the first hunk ⇒ count-0 insertion after old line 20 occupies new-side 22-23; with delta 0 git emits +21, confirming both directions). Doc comment updated; no test changes needed (inSecond line 22 and across keep their verdicts, verified green).

Deferred to the next round (replies posted on each thread)

All eight are witness-only additions (no behavior change claimed), bounded
by this round's ~8-finding batch cap after the four round-1 promises took
priority: R2-2 (start_line spill-shape witness), R2-3 (equal-boundary range
witness), R2-4 (suggestionsDiscarded: 0 boundary witness), R2-5 (empty-path
witness), R2-9 (dry-run compose-input assertions), R2-10 (non-RIGHT
start_side mapping witness), R2-11 (multi-line relocation entry-content
pin), R2-12 (routing-suite cwd isolation).

Verification

Commands actually run and their results:

  • npm run build — passed (exit 0)
  • npm run typecheck — passed (exit 0)
  • npm run lint — passed (exit 0)
  • npx prettier --check on all six changed files — passed
  • vitest packages/cli src/commands/review (focused, touched package) — 98 files, 4362 passed | 4 skipped
  • vitest packages/cli focused suites during development (submit, submit-aone, anchors, compose-review) — 651 passed
  • vitest packages/core src/skills/bundled/review/SKILL.test.ts — 24 passed
  • Mutation probes (each applied, focused test run, restored): probe 1 (marker-run strip removed) → stacked-marker test FAILED; probe 2 (fence check removed) → fence-placeholder test FAILED; probe 3 (placeholder removed) → both placeholder tests FAILED; probe 4 (stand-down disabled) → all four stand-down tests FAILED; probe 5 (old isSafeInteger acceptance table restored) → unsafe-integer merge test FAILED; probe 6 (authored-index citation removed) → authored-index test FAILED; probe 7 (dry-run carve-out removed) → missing-capture dry-run test FAILED. All probes restored; full suite re-run green after restore.
  • Fixture geometry probed against real git diff -U0 in a scratch repo (both delta-0 and delta-+1 shapes).

Integration tests were not run: the touched behavior is fully exercised by the
unit suites above (the Aone write seam is mocked by design in them), not only
through the bundled CLI.

中文说明

审查轮次总结 — PR #9634

本轮处理了 17 个未决发现中的 9 个,并明确将其余 8 个纯见证类发现延迟到下一轮(已在各线索上回复)。第 1 轮的四个延迟项(R1-3、R1-9、R1-14、R1-15)本轮已按承诺全部解决。没有未决的 Critical/Required 发现;所有处理项均为 Suggestion。

冲突解决(--conflict true

已合并 origin/main(一个新提交,#9629 presubmit 中的 self-MR 检测)。唯一冲突在捆绑 review 技能的 Aone --comment 条目:我们的分支把 anchor check 加为第五种 Aone 特有失败形态,而 main 因 presubmit 现已支持 self-PR 检测重写了披露语句。按并集解决——保留我们的五种失败/拒绝形态(含 anchor check),采纳 main 更新后的披露语句(self-PR 检测已有 backing;comment-status 被跳过、presubmit 的既有评论分类无 backing)。同时修复了我们分支在该条目引入的 .. 双句号笔误。提交:a26fdda244

已处理的发现

  • [rc:3831053125] R1-3 — toCount 接受表分歧(submit.ts:880)。 已实现:compose-review 现导出 tryToCount —— toCount 接受规则的全函数版本(接受时返回计数,将抛错时返回 undefined),与 toCount 共用同一代码路径。gate 的 suggestionsDiscarded 合并与整体退出都读取它,因此对同一字段的两种读取共用唯一一张接受表,永不分歧。附带效果:整数但非 safe 的计数现在会被合并(compose 本就接受它),不再静默丢掉 gate 的丢弃数。见证:merges gate discards into an integer-but-not-SAFE suggestionsDiscarded…;重建旧接受表的探针使其失败。
  • [rc:3831053132] R1-9 — 整体退出(stand-down)窄于其宣称的原则(submit.ts:863)。 按发现给出的修复实现:整体退出现在以任何触碰 payload 的降级为键(anchorsRelocated > 0 || anchorsDiscarded > 0),覆盖全部三个被探测过的姊妹形态——bodyCriticals 垃圾现在包含含非字符串元素的数组(形态 1)、仅丢弃分支也会在垃圾 bodyCriticals 上退出(形态 2)、不可计数的 suggestionsDiscarded 同样使迁移退出(形态 3),可计数性经由 tryToCount 判定(undefined 当且仅当 compose 会拒绝)。见证:两个新的 stand-down 测试加重写后的垃圾 suggestionsDiscarded 测试;禁用 stand-down 的探针使四个测试全部失败。
  • [rc:3831053137] R1-14 — gate 迁移与确定性标签扫描(submit.ts:892)。 采用发现提供的设计文档替代方案解决:文档现明确该原则——gate 迁移条目刻意继承 compose-review 对模型自有正文 Critical 的处理(包括整条目的确定性标签扫描),因为 deferral 通道的豁免以其结构化 source 字段为键,而 gate 迁移不携带该字段,且 claim 行上的标签本就是起草正文 Critical 的同一个模型所写。有界的分歧被点名并接受,而非继续无声存在。代码替代方案(把 gate 条目纳入位置锚定规则)需要新的 submit→compose 来源字段外加 compose-review 裁决计算的改动——若维护者需要,值得单独一轮专注处理。
  • [rc:3831053147] R1-15 — 缺少捕获的拒绝与 dry-run 冲突(submit.ts:785)。 已实现豁免分支:--dry-run 下缺少捕获时跳过 gate 并输出 Aone anchor check: SKIPPED — … 披露,按 payload 原样组合预览,报告 wouldPost: falsereason: 'aone-diff-missing'(省略 gate 计数)。exit-3 的 aone-post-refused 拒绝仍保留给真实写入。设计文档的 Semantics 条目与失败形态表已更新;技能的 Aone 条目点明该例外。见证:a dry run with a MISSING capture skips the gate, discloses, and reports it would NOT post;恢复无条件拒绝的探针使其失败。
  • [rc:3831053072] R2-6 — 迁移条目泄漏堆叠标记(submit.ts:135)。 已实现:relocatedAoneCriticalEntry 现在在组合条目前用 stripSeverityPrefix 剥掉提取 claim 的前导标记串(与其它所有剥离相同的不动点迭代)。见证:relocates a stacked-marker draft without leaking the second marker into the entry,断言条目恰为 src/foo.ts:4 — Off-by-one in the loop bound.;移除该剥离的探针使其失败。
  • [rc:3831053079] R2-7 — 围栏分隔符 claim 行(docs/design …md:130)。 按发现的第一选项实现:claim 行若恰为围栏分隔符(marker 单独一行、正文以围栏开头)视为缺失,退回 finding 占位符——条目的 path:line — 前缀会把分隔符藏过 compose 的行首锚定围栏拒绝,因此 gate 拒绝携带它(compose-review 的 ENTRY_FENCE_DELIMITER_RE 现被导出并在此读取——单一声明)。设计文档中错误的钉死声明("围栏代码块永不进入单行通道")已相应修正。见证:relocates a marker-alone body leading into a fence as the placeholder…;移除该检查的探针使其失败。
  • [rc:3831053037] R2-1 — claim || 'finding' 占位符见证(submit.ts:139)。 因 R2-6/R2-7 的修复正好突变该分支,随同纳入本轮:按发现给出的见证补齐(attribution: false、body '**[Critical]**\n:\n'、hunk 外行号),断言 bodyCriticals 等于 ['src/foo.ts:9999 — finding'];移除占位符兜底的探针使其失败。
  • [rc:3831053113] R2-13 — gate 移除后拒绝下标错位(submit.ts:835)。 已实现:gate 保留每个被保留评论的模型原始下标(keptIndices),floor 强制移除也穿过同一映射,inconsistencies 引用原始下标(authoredIndices?.[i] ?? i)。重组循环现在修复的正是下标在模型 JSON 中所指名的那条评论。见证:cites the MODEL-AUTHORED comment index in the refusal after the gate renumbers the array(gate 迁移 comments[0] 后,畸形的 comments[1] 必须被引用为 comments[1]);回退到 gate 后下标的探针使其失败。
  • [rc:3831053085] R2-8 — MULTI_DIFF fixture 违反 git 的 count-0 不变量(anchors.test.ts:944)。 已实现:第二个 hunk 头现为 @@ -20,0 +22,2 @@ —— 已在复刻 fixture 形状的 scratch 仓库中对 git 本身探测确认(第一个 hunk 差量 +1 之后,旧行 20 之后的 count-0 插入占据新侧 22-23;差量为 0 时 git 输出 +21,双向均确认)。文档注释已更新;无需改动测试(inSecond 第 22 行与 across 裁决不变,已验证全绿)。

延迟到下一轮(已在各线索回复)

八项均为纯见证补充(不涉及行为变更),受本轮约 8 个发现的批次上限约束——四个第 1 轮承诺优先:R2-2(start_line 溢出形态见证)、R2-3(等边界区间见证)、R2-4(suggestionsDiscarded: 0 边界见证)、R2-5(空 path 见证)、R2-9(dry-run compose 输入断言)、R2-10(非 RIGHT start_side 映射见证)、R2-11(多行迁移条目内容钉住)、R2-12(路由套件 cwd 隔离)。

验证

实际运行的命令及结果:

  • npm run build — 通过(exit 0)
  • npm run typecheck — 通过(exit 0)
  • npm run lint — 通过(exit 0)
  • 对全部六个改动文件运行 npx prettier --check — 通过
  • vitest packages/cli src/commands/review(聚焦,被触碰包)— 98 文件,4362 通过 | 4 跳过
  • 开发期间运行的 vitest packages/cli 聚焦套件(submit、submit-aone、anchors、compose-review)— 651 通过
  • vitest packages/core src/skills/bundled/review/SKILL.test.ts — 24 通过
  • 突变探针(每次应用、运行聚焦测试、恢复):探针 1(移除标记串剥离)→ 堆叠标记测试失败;探针 2(移除围栏检查)→ 围栏占位测试失败;探针 3(移除占位符)→ 两个占位测试失败;探针 4(禁用 stand-down)→ 四个 stand-down 测试全部失败;探针 5(恢复旧 isSafeInteger 接受表)→ 非 safe 整数合并测试失败;探针 6(移除原始下标引用)→ 原始下标测试失败;探针 7(移除 dry-run 豁免)→ 缺捕获 dry-run 测试失败。所有探针均已恢复;恢复后完整套件重新运行全绿。
  • fixture 几何已在 scratch 仓库中用真实 git diff -U0 探测(delta-0 与 delta-+1 两种形态)。

未运行集成测试:被触碰的行为已由上述单元套件完整覆盖(其中的 Aone 写入接缝按设计被 mock),并非只能通过捆绑 CLI 或集成测试框架验证。

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

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


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

…the relocated entry

Gap-fill on top of the round-2 gate hardening:

- The relocated entry's claim extraction strips the canonical footer
  FIRST: with an empty claim line (a marker-plus-separator-only body),
  the separator strip eats the newline+colon and the extraction falls
  THROUGH into the appended footer's first line, posting it as the
  claim. Witness added for the placeholder shape.
- Pin the multi-line relocation entry CONTENT (it must cite the claimed
  end line, not the start — the start sits inside the hunk and looks
  fine) and the disclosure naming it.
- Witnesses for the remaining mutant-tested gaps: a range whose start
  sits outside every hunk and end inside (the startLine mapping), the
  dry-run compose parity (preview composes from the gate-corrected
  payload), the suggestionsDiscarded 0 merge boundary, the empty-path
  shape (loud refusal, never a gate disposal), a declared LEFT
  start_side without a start_line, and the equal-boundary range
  (start_line === line, a shape GitHub itself produces).
- The routing suites run from a per-test fixture cwd, so the
  captured-diff seeding and its cleanup can no longer overwrite or
  delete a same-numbered live capture in the real vitest cwd.

Issue QwenLM#9615

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Partially reviewed — gaps disclosed. Suggestions are inline.

Not reviewed: reverse audit — ended at the 5-round cap without a dry convergence (round 5 still surfaced one candidate, rejected in verification).

Not explored to full depth (tool budget reached): chunk 2: executing anchors.test.ts under vitest — the review worktree and the parent checkout both lack node_modules, and a full npm ci was beyond budget; all tests we….

Test Plan (not a blocker): src/commands/review/submit-aone.test.tsno such file or directory; src/commands/review/lib/anchors.test.tsno such file or directory; src/commands/review/submit.test.tsno such file or directory.

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

  • docs/design/2026-08-21-review-aone-removed-line-anchoring.md:3 — [review] Status line says "implementation planned" while the same PR ships the implementation
  • docs/design/2026-08-21-review-aone-removed-line-anchoring.md:186 — [review] "Files affected" omits compose-review.ts (the tryToCount export the doc's prose depends on)
  • packages/cli/src/commands/review/lib/anchors.test.ts:1112 — [probe] Reversed-range test does not exercise the in-hunk-endpoints degeneracy its title advertises
中文说明

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

未审查:reverse audit — ended at the 5-round cap without a dry convergence (round 5 still surfaced one candidate, rejected in verification)。

未探索到全部深度(达到工具调用预算):chunk 2:executing anchors.test.ts under vitest — the review worktree and the parent checkout both lack node_modules, and a full npm ci was beyond budget; all tests we…

Test Plan(非阻断):src/commands/review/submit-aone.test.tsno such file or directory; src/commands/review/lib/anchors.test.tsno such file or directory; src/commands/review/submit.test.tsno such file or directory

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

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

Comment thread packages/cli/src/commands/review/submit.ts Outdated
Comment thread packages/cli/src/commands/review/submit.ts
Comment thread packages/cli/src/commands/review/submit.ts
Comment thread packages/cli/src/commands/review/submit.ts Outdated
Comment thread docs/design/2026-08-21-review-aone-removed-line-anchoring.md Outdated
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🔀 Base updated: red check(s) [Dependency CVE audit] pass on current main — merged current main via update-branch; CI will re-run.

中文说明

🔀 已更新 base:红色检查 [Dependency CVE audit] 在当前 main 上通过 —— 已通过 update-branch 合入当前 main,CI 将重新运行。

wenshao and others added 2 commits August 22, 2026 09:33
# Conflicts:
#	docs/design/2026-08-13-review-platform-provider-abstraction.md
#	packages/cli/src/commands/review/submit-aone.test.ts
#	packages/core/src/skills/bundled/review/SKILL.md

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

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

  • R4-1 ranged non-RIGHT over-promise (second location, docs/design/2026-08-13-review-platform-provider-abstraction.md:377) — already reported (comment 3834195100)

Not explored to full depth (tool budget reached): chunk 5: none — though note the suite was verified by reading against HEAD sources, not by execution (no node_modules in the shared worktree; installing there would dist….

Test Plan (not a blocker): src/commands/review/submit-aone.test.tsno such file or directory; src/commands/review/lib/anchors.test.tsno such file or directory; src/commands/review/submit.test.tsno such file or directory.

中文说明

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

未探索到全部深度(达到工具调用预算):chunk 5:none — though note the suite was verified by reading against HEAD sources, not by execution (no node_modules in the shared worktree; installing there would dist…

Test Plan(非阻断):src/commands/review/submit-aone.test.tsno such file or directory; src/commands/review/lib/anchors.test.tsno such file or directory; src/commands/review/submit.test.tsno such file or directory

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

Comment thread packages/cli/src/commands/review/submit-aone.test.ts Outdated
Comment thread packages/cli/src/commands/review/submit.ts
Comment thread packages/cli/src/commands/review/submit.ts
Comment thread docs/design/2026-08-21-review-aone-removed-line-anchoring.md Outdated
Comment thread packages/cli/src/commands/review/submit-aone.test.ts
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

中文说明

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

@qwen-code-ci-bot 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: reverse audit — ended at the 5-round cap without dry convergence (round 5 still surfaced candidates; the loop ended at the cap, not at a dry fixed point).

Test Plan (not a blocker): src/commands/review/submit-aone.test.tsno such file or directory; src/commands/review/lib/anchors.test.tsno such file or directory; src/commands/review/submit.test.tsno such file or directory.

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

  • packages/cli/src/commands/review/submit.ts:1142 — [probe] Gate-renumbering × floor-enforcement composition of…
  • docs/design/2026-08-21-review-aone-removed-line-anchoring.md:81 — [probe] Doc promises relocate/discard for every non-RIGHT-side…
  • packages/cli/src/commands/review/submit-aone.test.ts:2025 — [review] The hostile-paths test still has no \r witness for the…
  • packages/cli/src/commands/review/lib/anchors.test.ts:1112 — [probe] Reversed-range test's name/comment describe geometry the…
  • packages/cli/src/commands/review/lib/anchors.test.ts:1062 — [probe] Cross-hunk refusal test never constructs a range ACROSS…
  • packages/cli/src/commands/review/lib/anchors.test.ts:1050 — [probe] No unit witness for the lo endpoint (startLine below the…
中文说明

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

未审查:reverse audit — ended at the 5-round cap without dry convergence (round 5 still surfaced candidates; the loop ended at the cap, not at a dry fixed point)。

Test Plan(非阻断):src/commands/review/submit-aone.test.tsno such file or directory; src/commands/review/lib/anchors.test.tsno such file or directory; src/commands/review/submit.test.tsno such file or directory

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

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

Comment thread packages/cli/src/commands/review/submit-aone.test.ts Outdated
Comment thread packages/cli/src/commands/review/submit.ts
Comment thread packages/cli/src/commands/review/submit.ts Outdated
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

中文说明

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

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Partially reviewed — gaps disclosed.

Not reviewed: reverse audit — ended at the 5-round cap without dry convergence (round 5 still surfaced one candidate, confirmed in verification; the loop ended at the cap, not at a dry fixed point).

Test Plan (not a blocker): src/commands/review/submit-aone.test.tsno such file or directory; src/commands/review/lib/anchors.test.tsno such file or directory; src/commands/review/submit.test.tsno such file or directory.

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

  • packages/cli/src/commands/review/lib/anchors.test.ts:1112 — [probe] reversed-range test's title/comment geometry is false for the fixture; the advertised in-hunk-endpoints degeneracy is unwitnessed
  • packages/cli/src/commands/review/submit.ts:1141 — [probe] R3-3 lineage: the gate-renumbering × floor-enforcement authoredIndices composition has zero coverage for its non-identity branch
  • packages/cli/src/commands/review/submit.ts:994 — [probe] the stand-down probes only the two merged fields; a degrade can be disclosed then die on another state field's compose refusal
  • packages/cli/src/commands/review/lib/anchors.test.ts:1061 — [probe] the across-hunks refusal has no discriminating witness; a per-endpoint mutant survives the whole suite
  • docs/design/2026-08-21-review-aone-removed-line-anchoring.md:215 — [review] the failure-shapes table omits the corrupt/zero-byte capture degrade-and-post shape
  • docs/design/2026-08-21-review-aone-removed-line-anchoring.md:195 — [review] Files affected omits compose-review.ts, the module owning the acceptance tables the stand-down depends on
中文说明

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

未审查:reverse audit — ended at the 5-round cap without dry convergence (round 5 still surfaced one candidate, confirmed in verification; the loop ended at the cap, not at a dry fixed point)。

Test Plan(非阻断):src/commands/review/submit-aone.test.tsno such file or directory; src/commands/review/lib/anchors.test.tsno such file or directory; src/commands/review/submit.test.tsno such file or directory

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

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

Comment thread packages/cli/src/commands/review/submit-aone.test.ts Outdated
Comment thread packages/cli/src/commands/review/submit.ts
Comment thread packages/cli/src/commands/review/lib/anchors.ts Outdated
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

中文说明

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

…receipt state

The Aone receipt suite's beforeEach wiped the whole .qwen tree to start
from no receipt — deleting the captured diff the anchor gate needs along
with it. Every post then died at the gate's missing-capture refusal and
no receipt was ever written (ENOENT in the four receipt tests on CI).
Remove only the receipt file; the seeded diff survives.

@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: reverse audit — ended at the 5-round cap without dry convergence (round 5 still surfaced two candidates, both verified; the loop ended at the cap, not at a dry fixed point).

Test Plan (not a blocker): src/commands/review/submit-aone.test.tsno such file or directory; src/commands/review/lib/anchors.test.tsno such file or directory; src/commands/review/submit.test.tsno such file or directory.

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

  • packages/cli/src/commands/review/submit.ts:221 — [review] the path guard admits a whitespace-only path — the entry posts with silently dropped file attribution instead of the (no path) placeholder
  • packages/cli/src/commands/review/submit-aone.test.ts:1822 — [review] stand-down coverage matrix missing the relocation × garbage suggestionsDiscarded cell; a cell-isolated mutant survives 70/70
  • packages/cli/src/commands/review/submit-aone.test.ts:1356 — [review] renumbered-refusal witness covers only the relocation arm; a discard-arm authoredIndices mutant survives 183/183
  • docs/users/features/code-review.md:385 — [review] user-facing feature page still asserts the pre-gate Aone behavior, newly contradicted by this PR's degrade and missing-diff refusal
  • packages/cli/src/commands/review/submit.ts:221 — [review] the path arm lacks the renders-as-nothing projection; invisible-residue paths post as invisible attribution
中文说明

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

未审查:reverse audit — ended at the 5-round cap without dry convergence (round 5 still surfaced two candidates, both verified; the loop ended at the cap, not at a dry fixed point)。

Test Plan(非阻断):src/commands/review/submit-aone.test.tsno such file or directory; src/commands/review/lib/anchors.test.tsno such file or directory; src/commands/review/submit.test.tsno such file or directory

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

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

Comment thread packages/cli/src/commands/review/submit.ts
Comment thread packages/cli/src/commands/review/lib/anchors.ts Outdated
…or-gate

# Conflicts:
#	docs/design/2026-08-13-review-platform-provider-abstraction.md
#	packages/cli/src/commands/review/submit.test.ts
#	packages/core/src/skills/bundled/review/SKILL.md
…trated

Round-3 remediation of the review comments on the Aone anchor gate:

- R3-2 (structural): the BUILT relocated entry is now validated against
  compose's own ingestion (tryIngestBodyCriticals over the single entry)
  before the relocate is disclosed, and any refusal degrades the entry to
  the inert constant `finding — (no path):<line>` — the entrance space is
  unbounded model text and compose's acceptance is the authority, so a
  shape the enumerated guards never anticipated degrades the entry
  instead of refusing the whole post mid-degrade. The demonstrated
  entrance (a lone CR inside the claim: it passes the leading-fence
  guard, compose's CR normalisation then splits the entry and the second
  line leads with a fence delimiter) is covered by a witness.
- Ledger collision: the relocated entry flips to `<claim> — <path>:<line>`
  — the claim leads, so a carried id keeps position 0 and the ^-anchored
  ledger readback matches instead of silently renumbering a carried
  finding as new. Witness asserts the id survives the readback regex.
- R7-1: an explicit JSON null side/startSide reads as ABSENT (defaults
  to RIGHT), the model's idiom for an omitted optional field — never a
  declared old side. Unit and gate-level witnesses.
- R3-3: witness for the non-identity authoredIndices branch — the gate
  renumbers the array, floor enforcement keys on the post-gate array,
  and the remap drops the comment floor enforcement names.
- R4-2: the hostile-paths test gains the \r-bearing path (compose's
  ingestion normalises a bare CR to a line break — the same hostile
  shape as \n; the guard's \r half was unwitnessed).
- R3-5: the design doc states the carve-out — the non-RIGHT degrade runs
  for single-line comments only; a multi-line non-RIGHT comment keeps
  the consistency gate's whole-post refusal; null side is absent, not a
  declaration. The failure-shapes table splits the row accordingly.

Issue QwenLM#9615
@wenshao

wenshao commented Aug 22, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /triage

@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 22, 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: 128 passed · 0 failed · 128 total

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

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

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

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

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

Verification report

PR 9634 — feat(review): validate Aone inline anchors against the captured diff before posting

Verdict: merge-ready — 128/128 scripted assertions passed, 0 unexpected outcomes.
Verified head: f146c8116831bb2f1dcd30dda3e92f9db0313675 (merge-ref checkout 264855b, base tip c10143a).

中文摘要
  • 结论: merge-ready。128 条脚本化断言全部通过,0 个意外结果。
  • A/B 结论(核心主张成立): 在同一个录制版 a1 桩下,base 构建把混合 payload 的 3 个锚点全部送上线路(4 次 comment create,含 hunk 外 Critical@​22 与越界 Suggestion@​1038);head 构建只发 2 次(1 条 inline@​29 + 总结),Critical 迁入总结正文、Suggestion 丢弃计数,终端逐条披露;缺 diff 的真实写入 base 照常发布,head 以 exit 3 / aone-post-refused 拒绝且零写入。声明 LEFT 的 Critical 在 base 被静默内联发布(错锚类),在 head 被迁入正文。见下表 "A/B cell table" 与 01–03 号截图。
  • GitHub 路径零影响: dry-run JSON 在两臂逐字节相同;无门字段、无披露、零 a1 调用。
  • Findings: 仅 1 条 Suggestion 级完整性记录——isWholeLine 的零值半支无测试见证(变异 M8 全绿),经脚本化探针裁定为冗余防御(对 git 形状 diff 判定不变,仅 reason 文案不同),非合并条件。另两条非缺陷观察见 Findings。
  • 未覆盖: 对真实 Aone 平台的活体发布(桩只复现线路形状,不复现平台行为);GitHub 真实发布路径(仅 dry-run 对等);每提交归因(depth-2 浅克隆);docs/ 与 SKILL.md 文案准确性。

Central claim and A/B proof

Central claim: the Aone write path validates every well-formed inline anchor against the captured diff before anything posts; unanchorable Criticals relocate into the summary body, unanchorable Suggestions are discarded and counted, every degrade is disclosed, and a missing captured diff refuses the whole post. Secondary: (1) the GitHub path is unchanged; (2) malformed shapes and garbage compose-owned state still reach the existing refusals untouched.

Harness: driver.mjs spawns cell-runner.mjs, which imports each build's compiled dist/src/commands/review/submit.js and calls runSubmit from a per-cell fixture cwd. Nothing on the unit under test is mocked; the only fake is the a1 binary on PATH (stub-bin/a1), which records every argv as JSONL — the wire oracle. Fixtures are real git diff output (gen-fixture.mjs), line numbers derived from the actual hunk headers with parseDiff's own arithmetic. Base control: worktree at HEAD^1, cli rebuilt with a --noCheck scratch config (a full base npm ci/tsc -b does not fit this container: base core's from-scratch typecheck needs otel packages this image lacks; disclosed below). readlink -f node_modules/@qwen-code/qwen-code-core from the base tree points into the head tree — disclosed confound, behavior-neutral here: the PR's only core change is import-wrapping in extensionManager.ts (plus a SKILL.md asset), and extensionManager is not in submit's import closure.

cell (payload) base (no gate) head (gate) flip
mixed-write: valid Critical@​29 + out-of-hunk Critical@​22 + beyond-EOF Suggestion@​1038, real write exit 0, 4 creates (3 inline: 29, 22, 1038), no disclosure, no gate fields exit 0, 2 creates (1 inline: 29); summary carries **[Critical]** out-of-hunk finding must not post inline — src/probe.txt:22 + the 1-Suggestion discard sentence; stderr names both degrades; JSON anchorsRelocated:1, anchorsDiscarded:1 yes
missing-diff-write exit 0, 4 creates — posts unvalidated exit 3, {"posted":false,"reason":"aone-post-refused"}, zero a1 calls, no receipt yes
missing-diff-dryrun exit 0, wouldPost:true, no reason exit 0, wouldPost:false, reason:"aone-diff-missing", SKIPPED disclosure, zero calls yes
mixed-dryrun wouldPost:true, no gate fields wouldPost:true + counts 1/1, zero calls yes
left-side-write: Critical with side:"LEFT" at a valid line exit 0, 1 inline create — the silent-misanchor class posts exit 0, 0 inline; relocated into summary; disclosure names the non-RIGHT reason yes
filenotindiff-write: Critical on a file the diff doesn't touch exit 0, 1 inline create exit 0, 0 inline; relocated with file is not in the diff reason yes
null-side-write (control, both arms) 1 inline 1 inline, counts 0/0 — null reads as absent parity
malformed-noline (control, both arms) exit 1, consistency refusal names has no usable line, zero calls identical parity
garbage-standdown (control, both arms) exit 1, compose's pinned bodyCriticals refusal, zero calls, no gate disclose identical parity
github-dryrun (control, both arms) wouldPost:true, no gate fields identical; dry-run JSON byte-identical across arms parity

Totals: head 51/51, base 31/31 scripted assertions. Witnesses: 01-ab-cell-table.png, 02-ab-head-arm-live.png, 03-ab-base-arm-live.png. Raw per-cell stdout/stderr/a1-call logs: logs/<arm>-<cell>.{out,err,calls.jsonl}.

Reviewer Test Plan walk

plan step result
new-side in-hunk anchor posts unchanged PASS — inline create --line 29 --file src/probe.txt on the wire, body carries the finding
out-of-hunk / file-not-in-diff / declared-LEFT Critical relocates into summary, counts toward C PASS — three cells, each relocated with path:line attribution kept and named in the disclosure
same as Suggestion discarded, counted, named in disclosure PASS — mixed-write: anchorsDiscarded:1, summary discard sentence, stderr discarded: src/probe.txt:1038
missing captured diff exits 3, aone-post-refused, nothing written PASS — zero a1 calls, no receipt
malformed shapes + non-array bodyCriticals reach existing refusals untouched PASS — malformed-noline and garbage-standdown fire the pre-existing refusals identically on both arms; the gate disposes nothing of theirs
GitHub path emits no gate fields, behavior unchanged PASS — dry-run JSON byte-identical across arms; no disclosure; no a1
live mixed post to a scratch CR NOT COVERED here — stub a1 reproduces the wire shape, not the platform (see Not covered)

Boundary probes (33/33, probe-boundaries.mjs, compiled head dist)

Hunk edges (newStart, newEnd valid; newEnd+1 and mid-gap invalid), context-only deletion hunk lines valid, fully-deleted file (+0,0) validates nothing, ranges (one-hunk valid, equal-boundary valid, across-hunks and start-outside invalid, reversed refused before the scan), input domain (0, −1, 1.5, unsafe-int, NaN refused with the domain reason; safe-int beyond EOF fails the hunk scan), sides (LEFT/startSide-LEFT unanchorable; null/undefined/RIGHT default), CRLF-structured and non-diff/empty inputs decide fail-closed without throwing, quoted-path files found unquoted. Witness: 04-boundary-probes-live.png. Base control: validateNewSideAnchors absent at base (1/1 control).

Mutation matrix (PR's own three suites, 275 tests green unmutated)

mutant suite response classification
C control: invert hunk-containment comparison KILLED, 17 red (accept/relocate tests name expected-vs-actual) positive control — harness can fail the suite
M1 gate keep-condition always true KILLED, 21 red gate is load-bearing
M2 swap relocate/discard direction KILLED, 21 red dispose direction pinned
M3 remove missing-diff refusal KILLED, exactly 1 red: "refuses the WHOLE post when the captured diff is missing" intended assertion
M4 null side treated as declared KILLED, exactly 2 red (unit + gate null-side witnesses) R7-1 pinned
M5 merge drops the state's discard count KILLED, 3 red (merge witnesses) merge pinned
M6 remove newline path guard KILLED, exactly 1 red (hostile-path witness) guard load-bearing
M7 combination: M6 + disable entry ingestion validation KILLED, 2 red (both witnesses) each guard individually load-bearing, not redundant
M8 isWholeLine admits zero SURVIVED (275/275) see Finding 1

Witness: 05-mutation-matrix.png; raw logs logs/mutant-*.vitest.log. Every killed mutant failed the intended assertion with expected-vs-actual text (verified per log), never a compile error.

Findings

  1. Suggestion — coverage gap on a redundant defence (M8 survivor). isWholeLine's zero/negative half has no suite witness: admitting line: 0 leaves all 275 tests green. I proved with a scripted probe on a mutated dist copy (logs/m8-probe.log) that the mutation is verdict-neutral on git-shaped diffs — line 0 still fails the hunk scan (newStart <= 0 is never true for a newCount > 0 hunk); only the terminal reason string changes ("sits in no new-side hunk" vs "not a positive whole number"). The fraction half of the same clause IS load-bearing (1.5 inside a hunk span would otherwise certify) and IS pinned. So the zero half is redundant defence: correct as-is; a one-line witness (validate(diff, [{path, line: 0}])) would pin it. Not a merge condition per the matrix rule.
  2. Observation (non-defect) — lowercase side: "right" is treated as a declared non-RIGHT side (strict !== 'RIGHT'), so such a comment relocates instead of posting. Fail-closed and preserving (the finding lands in the summary with attribution); GitHub's API spelling is uppercase, so the accepted input class is unchanged. Worth a sentence in the design doc, not a code change.
  3. Observation (non-defect) — the +0,0 hunk of a fully-deleted file parses to newStart: 0, and the gate correctly validates nothing inside it (probed). No action.

Not covered

  • Live Aone posting. The stub a1 reproduces the wire protocol shapes the provider reads back (whoami/mr view/comment create), not the platform; the PR's own scratch-CR live verification was run on the intranet and is not reproducible in this credential-free container. The A/B therefore proves the CLI-side behavior at the write seam, matching the PR's claim about the CLI, not a re-probe of the platform.
  • GitHub real post path. Only the dry-run parity was exercised (byte-identical JSON, no gate fields); a full gh-stubbed post was out of budget. The gate block sits under if (aoneWrite) by construction and the parity cell confirms no leakage at compose/dry-run level.
  • Per-commit attribution. Depth-2 checkout; only the aggregate HEAD^1..HEAD diff was verified (the commit list in the snapshot matches the merge history; rows were not individually exercised).
  • docs/design/* and SKILL.md prose accuracy — read for mechanism understanding, not re-probed against the platform.
  • Base control confound (disclosed above): base cli was compiled --noCheck against head's core dist types; base core from-scratch typecheck is environmentally blocked (otel type packages absent from this image's node_modules), and the PR's core delta is formatting-only.
  • Repo-wide gates beyond the review tree: CI covers them; I ran the affected surface only (99 files / 4563 tests green).

Methodology

Environment: CI verify container, merge-ref checkout (HEAD 264855b), pre-built dist at head. Head arm drove the compiled dist/src/commands/review/submit.js via runSubmit from per-cell fixture cwds with a recording stub a1 first on PATH; base arm identical against a HEAD^1 worktree rebuilt with a noCheck scratch tsconfig. Authorization used the documented skillArgs test seam with a --comment recording naming each target (real parseReviewArgs/reviewWriteAuthorization code, no session id). Assertions live in driver.mjs / probe-boundaries.mjs (rerunnable), raw logs in logs/, mutation logs in logs/mutant-*.vitest.log. Gates: npx vitest run over the three named suites (275/275) and the whole src/commands/review tree (4563 passed / 4 skipped / 0 failed) at head.

Flakiness gate log

rounds=5 files=3 skipped=0
file packages/cli/src/commands/review/lib/anchors.test.ts: (cd packages/cli) npx --no-install vitest run ./src/commands/review/lib/anchors.test.ts
file packages/cli/src/commands/review/submit-aone.test.ts: (cd packages/cli) npx --no-install vitest run ./src/commands/review/submit-aone.test.ts
file packages/cli/src/commands/review/submit.test.ts: (cd packages/cli) npx --no-install vitest run ./src/commands/review/submit.test.ts


per-file results (P=pass F=fail I=infra-exit, one letter per run):
  packages/cli/src/commands/review/lib/anchors.test.ts: PPPPP
  packages/cli/src/commands/review/submit-aone.test.ts: PPPPP
  packages/cli/src/commands/review/submit.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/commands/review/lib/anchors.test.ts: P (exit 0)
round 1 · packages/cli/src/commands/review/submit-aone.test.ts: P (exit 0)
round 1 · packages/cli/src/commands/review/submit.test.ts: P (exit 0)
round 2 · packages/cli/src/commands/review/lib/anchors.test.ts: P (exit 0)
round 2 · packages/cli/src/commands/review/submit-aone.test.ts: P (exit 0)
round 2 · packages/cli/src/commands/review/submit.test.ts: P (exit 0)
round 3 · packages/cli/src/commands/review/lib/anchors.test.ts: P (exit 0)
round 3 · packages/cli/src/commands/review/submit-aone.test.ts: P (exit 0)
round 3 · packages/cli/src/commands/review/submit.test.ts: P (exit 0)
round 4 · packages/cli/src/commands/review/lib/anchors.test.ts: P (exit 0)
round 4 · packages/cli/src/commands/review/submit-aone.test.ts: P (exit 0)
round 4 · packages/cli/src/commands/review/submit.test.ts: P (exit 0)
round 5 · packages/cli/src/commands/review/lib/anchors.test.ts: P (exit 0)
round 5 · packages/cli/src/commands/review/submit-aone.test.ts: P (exit 0)
round 5 · packages/cli/src/commands/review/submit.test.ts: P (exit 0)

Evidence images

01-ab-cell-table

02-ab-head-arm-live

03-ab-base-arm-live

04-boundary-probes-live

05-mutation-matrix

06-gate-three-named-suites

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 has neither a verdict nor a deferral on f146c8116831bb2f1dcd30dda3e92f9db0313675 — no APPROVED, CHANGES_REQUESTED, or COMMENTED review of its own. A DISMISSED one does not count: dismiss_stale_reviews voids the bot's approval on every push, which is exactly when a fresh one is needed. If this re-run was meant to review or approve, it did not, and an approval left by another account is a separate vote that does not count as the bot's own.

⚠️ 机器人在 f146c8116831bb2f1dcd30dda3e92f9db0313675既没有裁决也没有 defer —— 没有属于它自己的 APPROVEDCHANGES_REQUESTEDCOMMENTED 评审。DISMISSED 不算:dismiss_stale_reviews 会在每次推送时作废机器人的批准,而那恰恰是需要一次新批准的时刻。如果这次重跑本应评审或批准,那么它没有做到;而其他账号留下的批准是另一张票,不能算作机器人自己的。

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

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

@doudouOUC doudouOUC left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed at HEAD f146c811. Approving — both round-8 Criticals are fixed, verified against the code as it stands rather than the standing verdict (which is anchored before f146c811). All 50 threads are resolved and Test (ubuntu-latest) passes at this head.

R7-1 (anchors.ts) — fixed, including the sibling the finding named. validateNewSideAnchors now reads a JSON null side as absent rather than as a declared non-RIGHT side:

const sideDeclared = check.side !== undefined && check.side !== null;
const startSideDeclared =
  check.startSide !== undefined && check.startSide !== null;

Only a present, non-RIGHT value is refused, which restores the NewSideAnchorCheck contract ("a missing side defaults to RIGHT"). startSide gets the identical treatment — the finding explicitly warned start_side: null was affected the same way, and it is covered. The comment records why (null is the model's idiom for an absent optional field, a recurring shape this pipeline has been bitten by before). This matters more than a placement bug on Aone, where the inline Critical discussion is the merge block: the old behaviour posted a confirmed blocker as advisory-only, deterministically, so no retry could recover it.

R3-2 (submit.ts) — fixed with the structural remedy requested since round 3, not another guard. The relocated one-line entry is now validated against compose's own ingestion and degraded when compose would refuse it:

if (tryIngestBodyCriticals([entry]) === undefined) {
  entry = `finding — (no path):${c.line}`;
}

That is the right shape. The prior enumerated guard list could only ever chase entrances — the round-8 probes found two more (a &nbsp; invisible-entity claim, and ZWSP/NBSP residue defeating the ^-anchored fence test) — whereas delegating to compose's actual acceptance closes the unbounded space by construction, and the inert fallback passes by construction (no fence, no newline, renders as something). The stand-down half is fixed too: it now reads compose's own tables (tryIngestBodyCriticals / tryToCount) rather than a mirror, with the comment noting the two reads of each field therefore cannot drift.

One point I checked rather than assumed: the stand-down validates the pre-existing bc array, not the merged [...bc, ...relocated]. That is sound here, because every relocated entry is individually guaranteed to pass compose's ingestion at build time, so the merged array is safe by composition. And the residual failure mode is benign by design — per the comment, a compose refusal means the payload "dies the pinned death; nothing posts either way, and the findings stay in the saved report," i.e. a safe failure rather than the false-advisory post that made R7-1/R3-2 harmful.

The review-pr check is still in flight at this head; CI is otherwise green (13 pass / 0 fail).

@wenshao
wenshao enabled auto-merge August 22, 2026 17:38

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

No blocking issues. LGTM! ✅

Test Plan (not a blocker): src/commands/review/submit-aone.test.tsno such file or directory; src/commands/review/lib/anchors.test.tsno such file or directory; src/commands/review/submit.test.tsno such file or directory.

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

  • packages/cli/src/commands/review/submit-aone.test.ts:2267 — [probe] multi-line non-RIGHT side shape check has no exactly-one-non-RIGHT-field witness; ||→&& mutant survives
  • packages/cli/src/commands/review/submit.ts:190 — [review] relocatedAoneCriticalEntry doc comment states the inverted entry format (path:line — claim; code builds claim — path:line)
  • docs/design/2026-08-21-review-aone-removed-line-anchoring.md:234 — [probe] failure-shape table's MULTI-LINE row says an explicit null side 'validates', but the shared shape gate refuses it whole
  • packages/cli/src/commands/review/submit-aone.test.ts:1671 — [probe] no witness posts a multi-line range fully inside a hunk inline; kept-branch mutation for start_line comments survives
  • packages/cli/src/commands/review/submit-aone.test.ts:2616 — [probe] floor-remapped authoredIndices is never consumed by a subsequent refusal; remap mutations survive
中文说明

无阻断问题。LGTM!✅

Test Plan(非阻断):src/commands/review/submit-aone.test.tsno such file or directory; src/commands/review/lib/anchors.test.tsno such file or directory; src/commands/review/submit.test.tsno such file or directory

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

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

@wenshao
wenshao added this pull request to the merge queue Aug 22, 2026
Merged via the queue into QwenLM:main with commit f829a02 Aug 22, 2026
677 of 700 checks passed

@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 gate end to end at head f146c81:

  • Anchor math is right against parseDiff's semantics: newEnd is inclusive (newStart + newCount - 1) with newCount as the authority, so the newCount > 0 && newStart <= lo && hi <= newEnd containment correctly excludes pure-deletion hunks, rejects reversed ranges and non-whole-line inputs before the scan, treats JSON null sides as absent (default RIGHT) while a PRESENT non-RIGHT side is unanchorable by construction, and requires a multi-line range to sit in one hunk.
  • Degrade lands in the existing compose counters rather than a parallel path: relocated Criticals re-enter as guarded one-line bodyCriticals (newline/fence-hostile paths handled, final-checked through tryIngestBodyCriticals) and still count toward C; discards merge into state.suggestionsDiscarded and count toward S; both disclosed with the anchorsRelocated/anchorsDiscarded counters. No shape loses a Critical entirely or posts one twice.
  • Refusal ordering holds: a missing capture on a real post exits 3 with aone-post-refused before any write; dry-run previews compose as authored with an anchorsUnchecked disclosure; a corrupt capture parses to zero files and degrades visibly instead of refusing a second shape; garbage state stands the gate down so the composition's pinned refusal fires. The GitHub arm emits no gate fields, and the extensionManager.ts hunk is a cosmetic type-import reformat.

One non-blocking observation for follow-up: the gate trusts the cwd capture file (.qwen/tmp/qwen-review-pr-<N>-diff.txt) with nothing tying it to the live MR head — an amended-then-resubmitted run without re-capture, or a local swap between review and post, makes the gate vouch against the wrong diff and the platform that validates nothing posts the wrong lines. The mid-batch head re-read mechanism already exists; pinning the capture to the head SHA it was fetched at (or re-fetching for real posts) would close both directions. Also minor: the capture is keyed by PR number alone, so same-numbered cross-repo targets sharing a cwd would collide captures (the missing-file direction fails safe; the collision direction trusts silently).

CI at approval time: 13 checks passing, review-pr still pending on head.

wenshao added a commit that referenced this pull request Aug 22, 2026
…p note

Merges origin/main (f829a02) into the Aone dedup PR. Three doc conflicts:

- SKILL.md --comment bullet: main's #9634 adds a fifth Aone failure shape
  (submit-side inline anchor validation against the captured diff, since Aone
  has no server-side anchor validation). Kept main's bullet with the anchor
  check, and swapped its stale "no dedup backing yet" caveat for the
  dedup-backed paragraph from this PR (#9627).
- 2026-08-13 design doc: kept this branch's "Landed (#9627) dedup backing"
  note (main's side of the hunk was empty).
- 2026-08-15 design doc open-question #2: kept BOTH resolutions — this
  branch's threading half (parentNoteId/closed/outdated -> GitHub buckets)
  and main's anchor half (new-side-only anchoring, per #9634's probe).

Code files (aone.ts, submit.ts) auto-merged cleanly. Verified: npm run build
green, tsc clean on packages/cli, SKILL.test.ts 30/30, and 582 review tests
pass (presubmit GitHub+Aone, comment-status, aone/aone-client, submit
GitHub+Aone, cleanup).
@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+) review/self-reported The linked issue was opened by the PR author (self-reported)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

review: Aone Code — inline anchoring for removed lines

5 participants