Skip to content

fix(cli): show Goal objectives in session picker - #10295

Merged
wenshao merged 14 commits into
QwenLM:mainfrom
qqqys:fix/resume-goal-objective
Sep 1, 2026
Merged

fix(cli): show Goal objectives in session picker#10295
wenshao merged 14 commits into
QwenLM:mainfrom
qqqys:fix/resume-goal-objective

Conversation

@qqqys

@qqqys qqqys commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

What this PR does

Goal-only sessions now use their persisted Goal objective as the fallback label in the resume picker when no custom title or user prompt exists. The same fallback is used in the preview, and picker search can match the displayed objective. Existing custom-title and prompt precedence remains unchanged.

Why it's needed

Sessions started with /goal can contain no ordinary user prompt, so /resume previously rendered them as (empty prompt) even though the Goal objective clearly identifies the work. This makes those sessions recognizable and searchable without changing their stored transcript format.

Reviewer Test Plan

How to verify

Create a session with /goal, leave it without a custom title or ordinary prompt, then open /resume. Confirm that the picker row and preview show the latest persisted Goal objective instead of (empty prompt), and that searching for text from the objective finds the session. Also confirm that a custom title still wins over a prompt or Goal objective, and a prompt still wins over the Goal objective.

Evidence (Before & After)

Before: Goal-only sessions appeared as (empty prompt) in the picker and had no useful preview title.

After: Goal-only sessions display their latest Goal objective in both locations and can be found by objective text. Automated regression coverage verifies the picker row, preview, search behavior, and latest-objective recovery.

Tested on

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

Environment (optional)

Node.js 22; targeted core and CLI unit tests, package typechecks, related ESLint checks, and the repository build.

Risk & Scope

  • Main risk or tradeoff: Sessions without both a title and prompt perform one existing bounded transcript-tail lookup to recover the latest Goal objective.
  • Not validated / out of scope: Manual interactive verification on Windows and Linux; session storage and Goal lifecycle behavior are unchanged.
  • Breaking changes / migration notes: None.

Linked Issues

Fixes #10265

中文说明

本 PR 的改动

仅包含 Goal 的会话在没有自定义标题和普通用户提示词时,现在会使用持久化的 Goal objective 作为 /resume 选择器中的后备名称。预览区使用同一后备逻辑,选择器搜索也可以匹配当前显示的 objective。原有的自定义标题和提示词优先级保持不变。

为什么需要

通过 /goal 启动的会话可能没有普通用户提示词,因此 /resume 之前会把它们显示为 (empty prompt),即使 Goal objective 已经清楚描述了工作内容。此改动让这些会话无需修改存储格式即可被识别和搜索。

Reviewer Test Plan

如何验证

使用 /goal 创建一个会话,不设置自定义标题,也不添加普通提示词,然后打开 /resume。确认选择器行和预览区显示最新持久化的 Goal objective,而不是 (empty prompt);同时确认使用 objective 中的文本搜索可以找到该会话。还应确认自定义标题仍优先于提示词和 Goal objective,提示词仍优先于 Goal objective。

前后对比证据

改动前:仅包含 Goal 的会话在选择器中显示为 (empty prompt),预览区也没有有用的标题。

改动后:仅包含 Goal 的会话在选择器和预览区都会显示最新 Goal objective,并可通过 objective 文本搜索。自动化回归测试覆盖了选择器行、预览、搜索行为和最新 objective 的恢复。

测试平台

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

环境(可选)

Node.js 22;执行了 core 与 CLI 定向单元测试、包级类型检查、相关 ESLint 检查以及仓库构建。

风险与范围

  • 主要风险或取舍:同时缺少标题和提示词的会话会使用现有的有界 transcript 尾部读取来恢复最新 Goal objective。
  • 未验证或范围外:未在 Windows 和 Linux 上手动进行交互验证;会话存储和 Goal 生命周期行为未改变。
  • 破坏性变更或迁移说明:无。

关联 Issue

Fixes #10265

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Qwen Triage finished — CI landed green on f4f202f and the deferred approval was posted. finalize run

Qwen Triage 已完成 —— f4f202f 的 CI 全绿,延迟审批已提交。查看 finalize 运行

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Thanks for the PR!

Template ✓ — all sections filled in, including the bilingual summary and a reviewer test plan.

Problem — observed bug, not theory: the linked issue #10265 comes from a community user report (with screenshot) showing multiple /goal sessions all rendered as (empty prompt) in /resume on 0.22.x, making goal sessions impossible to tell apart. Clear reproduction context.

Direction — aligned. /goal is a first-class feature, and sessions it creates being unidentifiable in the resume picker undermines it. The change stays inside display/search fallback logic — session storage and the Goal lifecycle are untouched. No direct CHANGELOG reference, but the area is plainly relevant.

Size — touches core (packages/core/src/services/sessionService.ts): 64 production logic lines (SessionPicker.tsx 12 + sessionPickerUtils.ts 8 + sessionService.ts 44) vs. 132 test lines. Well under any escalation threshold.

Approach — minimal and pattern-conforming: an optional goalObjective field, populated only when title and prompt are both missing, reusing the same bounded tail/head-window reader customTitle already uses (same pooled scratch buffer), with a fallback through the already-loaded head records via the existing recoverGoalFromRecords (v2 + legacy). Picker row, preview, and search all consume the one value. No scope creep spotted — every edit serves the stated goal.

Risk — no changed file matches the revert-correlated high-risk paths. No elevated risk signals.

Moving on to code review. 🔍

中文说明

感谢贡献!

模板 ✓ — 各部分齐全,包含中英双语说明和 reviewer 测试计划。

问题 — 真实已观测的 bug,不是理论问题:关联 issue #10265 来自社区用户反馈(附截图),0.22.x 上多个 /goal 会话在 /resume 中全部显示为 (empty prompt),goal 会话无法区分。复现背景清晰。

方向 — 对齐。/goal 是一等特性,它创建的会话在恢复列表里无法识别会削弱该特性。改动只落在展示/搜索的回退逻辑上,不触碰会话存储和 Goal 生命周期。CHANGELOG 无直接引用,但该领域明显相关。

规模 — 触及 core(packages/core/src/services/sessionService.ts):64 行生产逻辑(SessionPicker.tsx 12 + sessionPickerUtils.ts 8 + sessionService.ts 44),对应 132 行测试。远低于任何升级阈值。

方案 — 最小且符合既有模式:新增可选 goalObjective 字段,仅在标题与 prompt 都缺失时填充;复用 customTitle 已在使用的同一有界尾/头窗口读取(同一池化缓冲),并以已加载的头部记录经现有 recoverGoalFromRecords(v2 + legacy)兜底。列表行、预览和搜索共用同一取值。未发现范围蔓延——每处改动都服务于既定目标。

风险 — 改动文件均未命中与 revert 相关的高风险路径。无升级风险信号。

进入代码审查 🔍

Qwen Code · qwen3.8-max

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

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Code review

Before reading the diff, my own proposal for this problem was: add an optional goalObjective to the session list item, populate it lazily only for sessions with neither title nor prompt, reuse the bounded tail/head-window reader that already serves customTitle, and show it as the last fallback before (empty prompt) in the row, the preview, and search. This PR does exactly that — I found no simpler path it missed.

Verified against the current tree:

  • recoverGoalFromRecords' return shape (v2payload.snapshot.goal?.objective, legacyobjective, otherwise undefined) matches how extractGoalObjectiveFromRecords consumes it, and GoalSnapshotV2.goal is GoalRecord | null, so the optional chaining is correct.
  • readLastJsonStringFieldSync(filePath, 'objective', '"subtype":"goal_state"', tailBuffer) reuses the bounded ≤128KB tail+head scan, and the listing path passes the existing pooled scratch buffer — no new per-session allocation, no full-file read.
  • The lookup only runs when both prompt and titleInfo.title are empty, so ordinary sessions pay nothing.
  • Both producers feeding the picker (listSessions, getSessionListItem) set the field; the third producer findSessionsByTitle only matches titled sessions, so it doesn't need to. The only (empty prompt) render site for session list items is the patched one (RewindSelector's copy is a different feature).
  • Display truncation reuses truncatePromptForDisplay, same as prompts. The ??|| change in the preview title is a small improvement for the empty-string edge; precedence stays title > prompt > objective.
  • One known boundary (not a defect): goal_state records are not re-anchored to EOF the way titles are, so a very long session whose goal was created early and never updated could miss the file-window read; the head-records fallback (first 10 lines, where a /goal session's creation record lives) catches that case. This is the same documented completeness tradeoff customTitle already lives with — picker latency over completeness.

No blockers, no convention violations. Tests cover the picker row, preview title, search matching, listing exposure, and latest-objective recovery — 132 test lines against 64 production lines.

Testing

Evidence from the PR's own CI at the reviewed commit, fetched via the API — no PR code is built or executed in this review. Linux unit suite and Serve A/B were still running at review time; the macOS/Windows platform variants and the integration suite are skipped in this run. No failures so far. The finalize job updates the table below once CI settles.

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

Check Conclusion
Classify PR ✅ success
Dependency CVE audit ✅ success
Desktop Shell (ubuntu-22.04) ✅ success
Desktop Shell (windows-2022) ✅ success
Secret scan (TruffleHog) ✅ success
Serve A/B (ubuntu-latest, Node 22.x) ✅ success
Test (ubuntu-latest, Node 22.x) ✅ success
web-shell E2E Smoke (ubuntu-latest, Node 22.x) ✅ success

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

Sandboxed verification would settle the remaining gap: @qwen-code /tmux — whether the /resume picker actually renders the Goal objective for a real goal-only session (and search finds it) is not proven until the suite lands green, and the author self-reports testing on macOS only. The author is a collaborator, so the lane can be triggered directly.

Real-scenario (tmux) testing: not run — unattended CI never executes PR code; the TUI surface is exercised only by the isolated @qwen-code /tmux job above. The author's "tested on macOS" line is their own claim, not independently re-run evidence.

中文说明

代码审查

在看 diff 之前,我自己的方案是:给会话列表项加可选 goalObjective,仅在既无标题也无 prompt 的会话上惰性填充,复用已为 customTitle 服务的有界尾/头窗口读取,并在列表行、预览与搜索中作为 (empty prompt) 之前的最后回退。PR 的实现与此完全一致——没有找到更简的遗漏路径。

对照当前主干逐项验证:

  • recoverGoalFromRecords 的返回形态(v2payload.snapshot.goal?.objectivelegacyobjective,其余 undefined)与 extractGoalObjectiveFromRecords 的消费方式一致;GoalSnapshotV2.goalGoalRecord | null,可选链写法正确。
  • readLastJsonStringFieldSync(filePath, 'objective', '"subtype":"goal_state"', tailBuffer) 复用 ≤128KB 的有界尾+头扫描,列表路径传入现有池化缓冲——不新增每会话分配,不做全文件读取。
  • 仅当 prompttitleInfo.title 均为空时才执行查找,普通会话零开销。
  • 喂给选择器的两个生产者(listSessionsgetSessionListItem)都设置了该字段;第三个生产者 findSessionsByTitle 只匹配有标题的会话,无需设置。会话列表项唯一的 (empty prompt) 渲染点已被修改(RewindSelector 里的同名文案属于另一功能)。
  • 展示截断复用 truncatePromptForDisplay,与 prompt 一致。预览标题由 ?? 改为 ||,对空字符串边界是小幅改进;优先级保持 标题 > prompt > objective。
  • 一个已知边界(非缺陷):goal_state 记录不像标题那样被重新锚定到文件尾,极长会话中"早期创建且从未更新"的 goal 可能落在文件窗口读取之外;此时由头部记录回退(前 10 行,/goal 会话创建记录所在位置)兜底。这与 customTitle 已有的、文档化的"选择器延迟优先于完备性"取舍一致。

无阻塞项,无规范违规。测试覆盖列表行、预览标题、搜索匹配、列表字段暴露与最新 objective 恢复——132 行测试对应 64 行生产代码。

测试

证据来自该 PR 自身在被审提交上的 CI,经 API 获取——本审查不构建、不运行任何 PR 代码。审查时 Linux 单元测试与 Serve A/B 仍在运行;macOS/Windows 平台变体与集成套件本轮被跳过。目前无失败。CI 落定后 finalize 任务会更新上方表格。

沙箱验证可以补上剩余缺口:@qwen-code /tmux/resume 选择器在真实 goal 会话下是否确实渲染 Goal objective、搜索是否能命中,要等套件全绿才能确证;且作者自述仅在 macOS 上自测。作者是 collaborator,可直接触发该通道。

真实场景(tmux)测试:未执行——无人值守 CI 从不运行 PR 代码;TUI 表面仅由上述隔离的 @qwen-code /tmux 任务覆盖。作者"已在 macOS 测试"为其自述,非独立复核证据。

Qwen Code · qwen3.8-max

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

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Confidence: 5/5 — clean across every stage; would merge without hesitation once CI lands.

Stepping back: the problem is observed and specific (community report with screenshot, issue #10265), the solution is exactly the minimal approach I'd have proposed independently — an optional field, populated lazily through the same bounded reader customTitle already uses, consumed in row, preview, and search — and the review found no blockers, no scope creep, and no convention violations. Every edit in the diff serves the stated goal, and the test coverage (132 lines against 64 of production code) pins the picker row, the preview, the search behavior, and latest-objective recovery. If I had to maintain this in six months, I'd thank the author: it follows the file's own patterns instead of inventing new ones.

The only reservations are inherent to the established bounded-read pattern this PR correctly reuses (windowed reads trade completeness for picker latency), not defects of this diff.

CI at the reviewed commit is still in flight (Linux unit suite and Serve A/B; security checks already green), so approval is deferred until CI lands green on f4f202f6ac780e1e8c75e4435e8112da5f128092.

中文说明

置信度:5/5 — 各阶段均干净;CI 一通过即可毫不犹豫合入。

整体复盘:问题真实且具体(社区反馈附截图,issue #10265);方案与我独立提出的最小做法完全一致——新增可选字段,经由 customTitle 已在使用的同一有界读取器惰性填充,在列表行、预览与搜索中统一消费;审查未发现阻塞项、范围蔓延或规范违规。diff 中每处改动都服务于既定目标,测试覆盖(132 行测试对 64 行生产代码)钉住了列表行、预览、搜索行为与最新 objective 恢复。若六个月后维护这段代码,只会感谢作者:它沿用了文件自身的既有模式,而非另起炉灶。

唯一的保留意见来自该 PR 正确复用的既有有界读取模式的固有取舍(以选择器延迟优先于完备性),并非本 diff 的缺陷。

被审提交上的 CI 仍在进行(Linux 单元测试与 Serve A/B;安全检查已通过),因此在 CI 于 f4f202f6ac780e1e8c75e4435e8112da5f128092 全绿之前暂缓批准。

Qwen Code · qwen3.8-max

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

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

🩺 serve daemon A/B

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

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

Qwen Code · serve A/B

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Partially reviewed — gaps disclosed.

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

中文说明

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

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

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

Comment thread packages/core/src/services/sessionService.ts Outdated
Comment thread packages/core/src/services/sessionService.ts
Comment thread packages/core/src/services/sessionService.ts Outdated
Comment thread packages/core/src/services/sessionService.ts Outdated
Comment thread packages/core/src/services/sessionService.ts Outdated
Comment thread packages/core/src/services/sessionService.ts Outdated
Comment thread packages/core/src/services/sessionService.ts Outdated
…d label

Review findings on QwenLM#10295:

- R1-1 (Critical): the tail scan kept the last `objective` found on ANY
  `goal_state` line, so a `/goal clear` record — which persists `goal: null`
  and no objective at all — left the picker labelling the session with the
  goal the user had just cleared. `readLastMatchingLineFieldSync` reads the
  field from the LAST marker-carrying line instead, so the newest lifecycle
  record decides even when it omits the field. Its miss is now three-way:
  only `absent` (whole file scanned) lets the records fallback speak. A
  head-window hit is gone entirely — for a file bigger than the window it
  would resurrect a create record with an unknown number of later lifecycle
  records out of reach, and the parsed records are that same oldest slice of
  the file, so the honest answer there is no label.
- R1-5: the pasted-twice policy block is now one `resolveGoalObjective`
  helper called from both `listSessions` and `getSessionListItem`.
- R1-2/R1-3/R1-4/R1-7: tests for the legacy recovery arm, the
  prompt/title suppression guard at both producers, the `getSessionListItem`
  wiring, and the production file scan itself — the last one drives a real
  transcript whose goal record sits past the ten lines the records fallback
  parses, which is the only shape where a dead marker cannot hide behind it.
  The spy-based "prefers the latest objective" test is gone; it asserted the
  spy, not the code.
- R1-6: the other four label surfaces stay as they are; the asymmetry is now
  a documented decision on `SessionListItem.goalObjective` rather than an
  accident, with the shape a follow-up would take.

Mutation-verified: reverting the read to "last objective on any goal_state
line" reddens 3; letting the records fallback answer an out-of-window scan
reddens 1; a marker typo or a renamed field reddens 1 and 4; dropping the
suppression guard reddens 3; dropping the `getSessionListItem` wiring or the
legacy arm reddens 1 each.

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

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Partially reviewed — gaps disclosed.

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

中文说明

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

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

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

Comment thread packages/core/src/services/sessionService.ts Outdated
Comment thread packages/core/src/services/sessionService.test.ts
Comment thread packages/core/src/utils/sessionStorageUtils.ts Outdated
Comment thread packages/core/src/utils/sessionStorageUtils.ts
Comment thread packages/core/src/utils/sessionStorageUtils.ts Outdated
Comment thread packages/core/src/services/sessionService.ts Outdated
Comment thread packages/core/src/utils/sessionStorageUtils.ts Outdated
Comment thread packages/core/src/utils/sessionStorageUtils.ts Outdated

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Partially reviewed — gaps disclosed. Suggestions are inline.

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

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

  • packages/core/src/utils/sessionStorageUtils.ts:330 — [review] New reader inverts the sibling (key, marker) parameter order

Convergence: round 3 posted 2 inline comment(s), 2 of them reported for the first time; the previous round posted 8 (8 new). Findings keep coming back to the same files: packages/core/src/services/sessionService.ts (findings in round 2; 1 more now); packages/core/src/utils/sessionStorageUtils.ts (findings in round 2; 1 more now). A cluster that keeps producing siblings usually means the fixes are treating instances of a shared root cause — triaging that cause before the next round, or splitting an independent cluster into its own pull request, tends to end the loop faster than fixing them one at a time. No Critical finding is open on this round, so merging and moving the remaining Suggestion threads to a follow-up issue is available as an ending — a merged pull request cannot diverge further. (Observation only — nothing was withheld from this review because of this observation.)

中文说明

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

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

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

收敛情况:第 3 轮发布了 2 条行内评论,其中 2 条是首次提出;上一轮发布了 8 条(其中 8 条首次提出)。发现反复回到同一批文件:packages/core/src/services/sessionService.ts(第 2 轮已出过发现,本轮又有 1 条);packages/core/src/utils/sessionStorageUtils.ts(第 2 轮已出过发现,本轮又有 1 条)。一个不断再生兄弟发现的簇,通常意味着逐条修复只在处理同一根因的实例——先定位并处理该根因,或把独立的簇拆成单独的 PR,通常比逐条修复更快结束循环。本轮没有未决的 Critical,因此"合入后把剩余 Suggestion 线程转到后续 issue"是一个可选的结束方式——已合入的 PR 不会继续发散。(仅为观察——本轮评审未因此扣留任何内容。)

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

Comment thread packages/core/src/utils/sessionStorageUtils.ts Outdated
Comment thread packages/core/src/services/sessionService.ts Outdated

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Partially reviewed — gaps disclosed.

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

  • Parameter-order inversion of readLastMatchingLineFieldSync / extractJsonStringFieldFromLastMatchingLine (marker before key, siblings are key-first) — already reported in the round-3 deferral list (review 5054292672)

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

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

中文说明

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

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

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

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

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

Comment thread packages/core/src/services/sessionService.ts Outdated
Comment thread packages/core/src/utils/sessionStorageUtils.ts Outdated
Comment thread packages/core/src/services/sessionService.ts Outdated
Comment thread packages/core/src/utils/sessionStorageUtils.ts

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

⚠️ Round 5, and the diff has grown 3.1x since this review first measured it (171 → 526 source diff lines). The findings below are anchored to the current patch, so they can only say where this approach leaks — never that a different approach would retire all of them at once. Before fixing them, a human should decide whether the shape of the change is still right. Advisory only: this does not affect the verdict, and nothing here is a blocker.

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

Not reviewed: test-efficacy probing — all probes inconclusive (harnessValidated: null; the probe runner tripped the repo's vitest prerequisite guard), neither validated nor refuted.

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

中文说明

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

⚠️ 第 5 轮,且自本审查首次测量以来 diff 已增长 3.1 倍(源码 diff 行数 171 → 526)。下方的发现都锚定在当前这版补丁上,因此它们只能指出这个方案在哪里漏了,而无法说明换一个方案就能一次性消除全部问题。在动手修复之前,应由人来判断这次改动的整体形态是否仍然正确。仅供参考:本段不影响判定结论,其中也没有任何阻断项。

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

未审查:test-efficacy probing — all probes inconclusive (harnessValidated: null; the probe runner tripped the repo's vitest prerequisite guard), neither validated nor refuted。

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

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

Comment thread packages/core/src/utils/sessionStorageUtils.ts
Comment thread packages/core/src/services/sessionService.test.ts Outdated
Comment thread packages/core/src/utils/sessionStorageUtils.ts

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

⚠️ Round 6, and the diff has grown 3.1x since this review first measured it (171 → 526 source diff lines). The findings below are anchored to the current patch, so they can only say where this approach leaks — never that a different approach would retire all of them at once. Before fixing them, a human should decide whether the shape of the change is still right. Advisory only: this does not affect the verdict, and nothing here is a blocker.

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

Not reviewed: build-and-test — Test (macos-latest, Node 22.x) and Test (windows-latest, Node 22.x) unit matrices were skipped in CI; unit suites ran on Linux only.

Not reviewed: test-efficacy probing — all probes inconclusive (harnessValidated: null; the probe runner tripped the repo's vitest prerequisite guard), neither validated nor refuted.

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

  • packages/core/src/services/sessionService.test.ts:7317 — [review] Negative goal tests never assert the session item exists
  • packages/core/src/utils/sessionStorageUtils.ts:327 — [review] Brace-recovery fallback's positive path has no test
  • packages/core/src/services/sessionService.ts:1985 — [review] The records-recovery 'none' branch is unpinned
  • packages/core/src/services/sessionService.ts:1768 — [review] Whole-file inference rests on an undocumented cross-module invariant
  • packages/core/src/utils/sessionStorageUtils.ts:15 — [review] Production consumer of a 'unit tests only' export

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

中文说明

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

⚠️ 第 6 轮,且自本审查首次测量以来 diff 已增长 3.1 倍(源码 diff 行数 171 → 526)。下方的发现都锚定在当前这版补丁上,因此它们只能指出这个方案在哪里漏了,而无法说明换一个方案就能一次性消除全部问题。在动手修复之前,应由人来判断这次改动的整体形态是否仍然正确。仅供参考:本段不影响判定结论,其中也没有任何阻断项。

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

未审查:build-and-test — Test (macos-latest, Node 22.x) and Test (windows-latest, Node 22.x) unit matrices were skipped in CI; unit suites ran on Linux only。

未审查:test-efficacy probing — all probes inconclusive (harnessValidated: null; the probe runner tripped the repo's vitest prerequisite guard), neither validated nor refuted。

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

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

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

Comment thread packages/core/src/utils/sessionStorageUtils.ts Outdated

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Partially reviewed — gaps disclosed.

⚠️ Round 7, and the diff has grown 3.3x since this review first measured it (171 → 564 source diff lines). The findings below are anchored to the current patch, so they can only say where this approach leaks — never that a different approach would retire all of them at once. Before fixing them, a human should decide whether the shape of the change is still right. Advisory only: this does not affect the verdict, and nothing here is a blocker.

Not reviewed: test-efficacy probing — all probes inconclusive (harnessValidated: null; the probe runner tripped the repo's vitest prerequisite guard), neither validated nor refuted.

Not reviewed: build-and-test — the build-test test phase did not complete (the build phase consumed the per-call budget); the PR's own suites were run directly instead (329/329 across the three touched test files; the full packages/core suite measured 22,122 passed with 111 failures attributed to pre-existing/environmental causes outside the PR's files; the packages/cli suites did not run).

7 Suggestion(s) were drafted inline past the resolved critical posting floor; the CLI moved them into the deferral list below (floor enforcement).

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

  • packages/core/src/services/sessionService.test.ts:7375 — [review] R7-1: No added test exercises a goal_state record that passes readGoalStateObjective 's type / subtype gate but fails parseGoalStateRecordPayloadV2 , so the scan reader…
  • packages/core/src/services/sessionService.test.ts:7361 — [review] R7-2: The recordsComplete === false → file scan branch of resolveGoalObjective has no positive witness: the torn it.each is the only test in the file where complete: f…
  • packages/core/src/services/sessionService.test.ts:7460 — [review] R7-3: Three long-transcript/window-limit tests assert only an optional-chained findItem(result.items, sessionId)?.goalObjective , which is satisfied when the session item is…
  • packages/core/src/utils/sessionStorageUtils.test.ts:257 — [review] R7-4: The leadingPartial suffix-recovery path — documented as "a leading partial line contributes only a complete suffix record … a later record glued onto that prefix rem…
  • packages/core/src/utils/sessionStorageUtils.ts:367 — [review] R7-5: The lifecycle decisive return added in this increment makes a half-written marker line match on the first tail read, which suppresses the bounded grown-tail re-read that ex…
  • packages/core/src/utils/sessionStorageUtils.ts:344 — [review] R7-6: On a leading partial line, a glued marker-bearing record with any record after it on the same physical line is unrecoverable — _recoverObjectsFromLine is guarded by !lea…
  • packages/core/src/utils/sessionStorageUtils.test.ts:420 — [review] R7-7: No committed test pins a value-returning glued/torn-line recovery: every glued/torn test in both new describe blocks asserts value: undefined or matched: false , an…
  • packages/core/src/services/sessionService.ts:2301 — [review] getSessionListItem scan path has no label test (R7-8)
  • packages/core/src/utils/sessionStorageUtils.ts:283 — [review] recordMatches parameter is production-dead (R7-9)
  • packages/core/src/utils/sessionStorageUtils.ts:441 — [review] Dead reason union and its merge branch (R7-10)

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

Residual risk: this loop is persistently critical — Criticals stood in the previous round's work-list and stand again this round (1 Critical(s)), the rate of first-time findings is not falling (this round 1, previous 1), and the standing Critical backlog is not shrinking. The severity floor will not converge it. Recommendation: land-with-residual-risk — the exit is a maintainer risk-acceptance decision (merge, carrying the residual risk), not another review round. Residual-risk inventory for that decision (maintainer to complete):

standing Critical attack surface attacker-dependency blast radius
(each standing Critical)

Advisory only — it does not block this review.

中文说明

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

⚠️ 第 7 轮,且自本审查首次测量以来 diff 已增长 3.3 倍(源码 diff 行数 171 → 564)。下方的发现都锚定在当前这版补丁上,因此它们只能指出这个方案在哪里漏了,而无法说明换一个方案就能一次性消除全部问题。在动手修复之前,应由人来判断这次改动的整体形态是否仍然正确。仅供参考:本段不影响判定结论,其中也没有任何阻断项。

未审查:test-efficacy probing — all probes inconclusive (harnessValidated: null; the probe runner tripped the repo's vitest prerequisite guard), neither validated nor refuted。

未审查:build-and-test — the build-test test phase did not complete (the build phase consumed the per-call budget); the PR's own suites were run directly instead (329/329 across the three touched test files; the full packages/core suite measured 22,122 passed with 111 failures attributed to pre-existing/environmental causes outside the PR's files; the packages/cli suites did not run)。

7 条 Suggestion 在已解析的 critical 发布下限之外被起草为行内评论;CLI 已将其移入下方延后清单(下限强制执行)。

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

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

残余风险:本循环处于 persistently-critical 形态——上一轮工作清单中的 Critical 本轮依然存在(本轮 1 条 Critical),首次发现的速率没有下降(本轮 1,上一轮 1),且未决 Critical 积压没有减少。severity floor 无法使其收敛。建议:land-with-residual-risk——出口是 maintainer 的风险接受决定(合入并承担残余风险),而非再开一轮评审。供该决定使用的残余风险清单(maintainer 填写):按每条未决 Critical 列出「攻击面 · 攻击者依赖性 · 影响范围」三栏。仅为建议——不阻断本次评审。

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

Comment thread packages/core/src/utils/sessionStorageUtils.ts Outdated
qqqys and others added 2 commits August 30, 2026 12:25
@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

🖼️ web-shell visual preview

Rendered against a mock daemon (no real backend): the PR base vs this PR head dd58de5. Only screenshots that changed are shown (flows below, if any, are head-only) — refreshes on every push.

Screenshots · before / after

ℹ️ No screenshot changed against the PR base — but this PR edits 2 render-shaping files:

  • packages/web-shell/client/components/InsightReady.tsx
  • packages/web-shell/client/components/dialogs/ModelDialog.tsx

Either the change has no visual effect (logic, plumbing, a state the scenarios never reach), or no scenario renders this UI — in which case the preview cannot see it, and an empty result is a coverage gap rather than a clean bill of health. To make it visible, add a scenario to packages/web-shell/client/e2e/visuals/screenshots.spec.ts that seeds whatever state the UI is gated on; it then appears here as a head-only (NEW) capture.

Full-resolution recordings (.webm) are attached to the workflow run.

Qwen Code · web-shell visuals

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

⚠️ Round 8, and the diff has grown 4.1x since this review first measured it (171 → 704 source diff lines). The findings below are anchored to the current patch, so they can only say where this approach leaks — never that a different approach would retire all of them at once. Before fixing them, a human should decide whether the shape of the change is still right. Advisory only: this does not affect the verdict, and nothing here is a blocker.

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

  • R8-2 production consumer of the 'unit tests only' export (packages/core/src/utils/sessionStorageUtils.ts:15) — already reported in the round-6 deferral list (review 5057402003)
  • Round-3 optional-chained negative-assertion gap (packages/core/src/services/sessionService.test.ts long-transcript tests) — already deferred in round 7 as R7-3
  • Round-3 leading-partial glued-mid-line recovery gap (packages/core/src/utils/sessionStorageUtils.ts:344) — already deferred in round 7 as R7-6

Not reviewed: test-efficacy probing — all probes inconclusive (harnessValidated: null; the probe runner tripped the repo's vitest prerequisite guard), neither validated nor refuted.

Not reviewed: build-and-test — the webui test command was clamped on a budget-shortened deadline; packages/cli and packages/core full suites hit the time cap on a contended runner (every failing file is untouched by the PR with a uniform timeout signature; all 14 PR-touched test files pass in isolation: core 342/342, cli 1151/1151, web-shell 28/28); no A/B baseline (the base tree did not build within budget).

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

Not reviewed: build-and-test — Test (macos-latest, Node 22.x) and Test (windows-latest, Node 22.x) unit matrices were skipped in CI; unit suites ran on Linux only.

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

  • packages/core/src/services/sessionService.test.ts:7608 — [review] module-mocked _recoverObjectsFromLine has no beforeEach default pin — the auto-mock returns undefined and the recovery loop dereferences it unguarded, so a test reaching the …
  • packages/core/src/services/sessionService.ts:432 — [review] readGoalStateObjective type/subtype guard's reject-then-continue semantics have no production-level witness (guard-removal mutant ships green)
  • packages/core/src/services/sessionService.ts:1778 — [review] legacy (pre-v2) Goal recovery unreachable beyond the 10-record prefix — the gate caps the records path and the fallback scan is v2-marker-only
  • packages/core/src/services/sessionService.ts:435 — [review] scan-vs-records divergence — a malformed newest payload is decisive no-label on the scan path but falls through to the older record on the records path
  • packages/core/src/utils/sessionStorageUtils.test.ts:547 — [review] both fstat-spy tests install vi.spyOn(fs, 'fstatSync') and never restore it; the second captures the first's still-installed spy
  • packages/core/src/utils/sessionStorageUtils.test.ts:193 — [review] the new utility tests never drive the production reader, and the crash-truncation tests pin the OPPOSITE of production's hooked semantics for identical bytes
  • packages/core/src/utils/sessionStorageUtils.test.ts:565 — [review] bounded-growth out-of-window arm has no witness — removing the delta condition ships green and would claim a false 'absent'
  • packages/core/src/utils/sessionStorageUtils.test.ts:399 — [review] the leadingPartial guard test is vacuous — a guard-removal mutant keeps the whole suite green (second facet of round-7 deferral R7-4)
  • packages/core/src/services/sessionService.test.ts:7740 — [review] the clear-decisive scan branch has no witness — a non-decisive-clear mutant resurrects cleared Goals while every committed test stays green
  • packages/core/src/utils/sessionStorageUtils.ts:386 — [review] CLASS FINDING — the torn/glued-line recovery surface is unbounded; four verified corners this round (two opened by the round-7 fix), all fail-closed or sub-Critical; close it str…

Mechanism health: this round did not close cleanly, so it withholds the incremental anchor — and the round it recovered had no anchor this round could use either — none at all, one with no certifier, one certified by an identity other than the one this round runs under, or one this round's fetch refused or resolved to the head — so the next review re-reads the whole diff unless recovery grafts an earlier own anchor that the round running it can use onto the complete work list this round leaves behind, and keeps doing so until a round's marker carries an anchor again or a graft lands that the round running it can use. (Stated, not acted on — this changes nothing about what the round posts.)

中文说明

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

⚠️ 第 8 轮,且自本审查首次测量以来 diff 已增长 4.1 倍(源码 diff 行数 171 → 704)。下方的发现都锚定在当前这版补丁上,因此它们只能指出这个方案在哪里漏了,而无法说明换一个方案就能一次性消除全部问题。在动手修复之前,应由人来判断这次改动的整体形态是否仍然正确。仅供参考:本段不影响判定结论,其中也没有任何阻断项。

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

未审查:test-efficacy probing — all probes inconclusive (harnessValidated: null; the probe runner tripped the repo's vitest prerequisite guard), neither validated nor refuted。

未审查:build-and-test — the webui test command was clamped on a budget-shortened deadline; packages/cli and packages/core full suites hit the time cap on a contended runner (every failing file is untouched by the PR with a uniform timeout signature; all 14 PR-touched test files pass in isolation: core 342/342, cli 1151/1151, web-shell 28/28); no A/B baseline (the base tree did not build within budget)。

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

未审查:build-and-test — Test (macos-latest, Node 22.x) and Test (windows-latest, Node 22.x) unit matrices were skipped in CI; unit suites ran on Linux only。

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

机制健康:本轮未能干净收尾,因而扣留了增量锚点,而它恢复到的那一轮也没有留下本轮可用的锚点——要么完全没有、要么没有认证者、要么由本轮运行身份之外的身份认证、要么被本轮的获取拒绝或解析为头提交——因此下一次评审将重读整个 diff,除非恢复流程把本轮能使用的更早自有锚点嫁接到本轮留下的完整工作清单上;并会一直如此,直到某一轮的标记重新带上锚点,或落地的嫁接能被运行该轮的评审使用。(仅陈述,不据此行动——这不改变本轮发布的任何内容。)

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

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

⚠️ Round 9, and the diff has grown 4.1x since this review first measured it (171 → 704 source diff lines); the reverse audit also stopped at its round cap without converging. The findings below are anchored to the current patch, so they can only say where this approach leaks — never that a different approach would retire all of them at once. Before fixing them, a human should decide whether the shape of the change is still right. Advisory only: this does not affect the verdict, and nothing here is a blocker.

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

  • R9-1 vacuous leadingPartial guard pin (sessionStorageUtils.test.ts:399) — already reported in the round-8 deferral list (review 5060725808, second facet of R7-4)
  • R9-2 clear-decisive scan branch has no witness (sessionService.test.ts:7980) — already reported in the round-8 deferral list (review 5060725808)
  • R9-4 legacy (pre-v2) Goal recovery unreachable beyond the 10-record prefix (sessionService.ts:1861) — already reported in the round-8 deferral list (review 5060725808)
  • R9-5 bounded-growth out-of-window arm has no witness (sessionStorageUtils.test.ts:565) — already reported in the round-8 deferral list (review 5060725808)
  • R9-6 dead LastMatchingLineScan.reason union and its merge branch (sessionStorageUtils.ts:473) — already reported in the round-7 deferral list as R7-10 (review 5057402003)

Not reviewed: build-and-test — the harness test phase did not complete (the build phase consumed the per-call budget; the sdk-typescript build timeout is classified as infrastructure); the PR-touched suites were run directly instead (core 350/350, cli 37/37, web-shell 28/28 — 415/415); test-efficacy probing inconclusive (harnessValidated: null), neither validated nor refuted.

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

Not reviewed: build-and-test — Test (macos-latest, Node 22.x) and Test (windows-latest, Node 22.x) unit matrices were skipped in CI; unit suites ran on Linux only.

Not reviewed: build-and-test — CI is failing at the reviewed commit (Test (ubuntu-latest, Node 22.x), web-shell E2E Smoke (ubuntu-latest, Node 22.x), Serve A/B (ubuntu-latest, Node 22.x)); the 14 PR-touched test files pass in isolation locally (415/415), and prior rounds attributed full-suite failures on this runner to time-cap contention on files untouched by the PR, but the CI state at this commit is red and unexplained here.

Not explored to full depth (tool budget reached): "agent reverse-audit (round 2)": forcing the reversed file order (sessionStorageUtils before session-writer-lease in one worker) to reproduce the lease failures live — shuffled seeds 42/7 both ….

Not reviewed: reverse audit — did not converge within the reverse-audit round cap of 5.

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

  • packages/core/src/utils/sessionStorageUtils.ts:386 — [review] D9-1 CLASS FINDING — torn/glued-line recovery surface unbounded; six verified corners across rounds 7-9 (two new this round: torn nested-marker suppression of an active goal's la…
中文说明

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

⚠️ 第 9 轮,且自本审查首次测量以来 diff 已增长 4.1 倍(源码 diff 行数 171 → 704);反向审计也在轮数上限处停止且未收敛。下方的发现都锚定在当前这版补丁上,因此它们只能指出这个方案在哪里漏了,而无法说明换一个方案就能一次性消除全部问题。在动手修复之前,应由人来判断这次改动的整体形态是否仍然正确。仅供参考:本段不影响判定结论,其中也没有任何阻断项。

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

未审查:build-and-test — the harness test phase did not complete (the build phase consumed the per-call budget; the sdk-typescript build timeout is classified as infrastructure); the PR-touched suites were run directly instead (core 350/350, cli 37/37, web-shell 28/28 — 415/415); test-efficacy probing inconclusive (harnessValidated: null), neither validated nor refuted。

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

未审查:build-and-test — Test (macos-latest, Node 22.x) and Test (windows-latest, Node 22.x) unit matrices were skipped in CI; unit suites ran on Linux only。

未审查:build-and-test — CI is failing at the reviewed commit (Test (ubuntu-latest, Node 22.x), web-shell E2E Smoke (ubuntu-latest, Node 22.x), Serve A/B (ubuntu-latest, Node 22.x)); the 14 PR-touched test files pass in isolation locally (415/415), and prior rounds attributed full-suite failures on this runner to time-cap contention on files untouched by the PR, but the CI state at this commit is red and unexplained here。

未探索到全部深度(达到工具调用预算):"agent reverse-audit (round 2)"forcing the reversed file order (sessionStorageUtils before session-writer-lease in one worker) to reproduce the lease failures live — shuffled seeds 42/7 both …

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

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

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

@qqqys

qqqys commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /takeover from 9

@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 31, 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). This window's round counter starts at 9 (the rounds this PR spent in review before takeover), so the Critical-only brake engages after 0 more change-producing round(s) instead of a full fresh 5. Remove the autofix/takeover label (or comment @qwen-code /takeover stop) to release.

中文说明

🤝 已接管:autofix 循环现在管理此 PR —— 将持续处理新的评审反馈与 base 冲突,直到移除标签或达到轮次上限。本 PR 来自 fork,首轮处理将由下一次定时扫描执行(通常几分钟内)。本窗口轮次计数从 9 起算(即本 PR 托管前已进行的评审轮数),因此再经过 0 个产生改动的轮次即进入 Critical-only,而非重新计满 5 轮。移除 autofix/takeover 标签(或评论 @qwen-code /takeover stop)即可释放。

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Partially reviewed — gaps disclosed.

⚠️ Round 10, and the diff has grown 3.5x since this review first measured it (171 → 595 source diff lines); the reverse audit also stopped at its round cap without converging. The findings below are anchored to the current patch, so they can only say where this approach leaks — never that a different approach would retire all of them at once. Before fixing them, a human should decide whether the shape of the change is still right. Advisory only: this does not affect the verdict, and nothing here is a blocker.

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

  • R7-3 real-FS negative Goal tests never pin that the session item exists (packages/core/src/services/sessionService.test.ts:7816) — already reported in the round-6 deferral list (review 5057402003) and re-recorded as R7-3 (review 5059823601)
  • R9-4 legacy (pre-v2) Goal recovery unreachable beyond the 10-record prefix (packages/core/src/services/sessionService.ts:437) — already reported in the round-8 deferral list (review 5060725808) and re-recorded as R9-4 (review 5061664066)
  • R10-1 fstat-spy growth tests never restore the vi.spyOn(fs, 'fstatSync') spy (packages/core/src/utils/sessionStorageUtils.test.ts:430) — already reported in the round-8 deferral list (review 5060725808)
  • R7-9 recordMatches parameter on readLastMatchingLineFieldSync is production-dead (packages/core/src/utils/sessionStorageUtils.ts:413) — already reported as R7-9 (review 5059823601)

Not reviewed: build-and-test — the harness test phase did not complete (the build phase consumed the per-call budget); the PR-touched suites were run directly instead (core 352/352, cli 37/37 — 389/389 across the five PR-touched test files).

Not reviewed: test-efficacy probing — all probes inconclusive (harnessValidated: null; the probe runner tripped the repo's vitest prerequisite guard), neither validated nor refuted.

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

Not reviewed: build-and-test — Test (macos-latest, Node 22.x) and Test (windows-latest, Node 22.x) unit matrices were skipped in CI; unit suites ran on Linux only.

Not reviewed: reverse audit — did not converge within the reverse-audit round cap of 5.

Deferred under the convergence posture (round 10, not a blocker) — recorded, not requested in this round; 1 Critical(s) among them are deferred by their axes — fails-closed on new surface, where no wrong result is certified and the merge base had neither the surface nor the defect — and remain follow-up work recorded in the findings artifact:

  • packages/core/src/utils/sessionStorageUtils.test.ts:572 — [probe] Critical [fails-closed] [new-surface] new fstat-spy growth tests fail on O_NOFOLLOW-absent platforms (Windows): openSyncNoFollow's identity check consumes the rigged first fs…
  • packages/core/src/services/sessionService.ts:1861 — [probe] exact-10-record fully-parsed files are routed to the blind tail scan; >64KB files with the goal_state near the head stay unlabelled
  • packages/core/src/utils/sessionStorageUtils.ts:382 — [probe] picker/resume divergence on torn/glued newest goal_state — under-label identical to the pre-PR display
中文说明

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

⚠️ 第 10 轮,且自本审查首次测量以来 diff 已增长 3.5 倍(源码 diff 行数 171 → 595);反向审计也在轮数上限处停止且未收敛。下方的发现都锚定在当前这版补丁上,因此它们只能指出这个方案在哪里漏了,而无法说明换一个方案就能一次性消除全部问题。在动手修复之前,应由人来判断这次改动的整体形态是否仍然正确。仅供参考:本段不影响判定结论,其中也没有任何阻断项。

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

未审查:build-and-test — the harness test phase did not complete (the build phase consumed the per-call budget); the PR-touched suites were run directly instead (core 352/352, cli 37/37 — 389/389 across the five PR-touched test files)。

未审查:test-efficacy probing — all probes inconclusive (harnessValidated: null; the probe runner tripped the repo's vitest prerequisite guard), neither validated nor refuted。

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

未审查:build-and-test — Test (macos-latest, Node 22.x) and Test (windows-latest, Node 22.x) unit matrices were skipped in CI; unit suites ran on Linux only。

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

收敛姿态下延后(第 10 轮,非阻断)——已记录,本轮不要求修改;其中 1 条 Critical 按其失败方向与对照基线延后——fails-closed 且 new-surface:未认证任何错误结果,且 merge base 既无该功能面也无该缺陷——作为后续工作记录在 findings 工件中:共 3 条(原文未翻译,列表见上方英文部分)。

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

@qwen-code-dev-bot

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

Copy link
Copy Markdown
Collaborator

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

中文说明

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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

Autofix review round — verification only, no code changes needed

Critical-only mode is active. Every actionable item this round is one of the five Critical findings from the automated reviewer, and each already carries a fix committed in an earlier round. Since the last bot push the branch merged main (three merges) and received the maintainer commit 7aef1b0d59 (fix(core): preserve no-follow session goal reads). This round therefore re-verified, source-blind and at HEAD 7aef1b0d59, that none of the reported defects reproduce on the current code — driving the real, unmocked SessionService over real JSONL transcripts shaped exactly like each finding's witness — and then re-ran every required check. No code change was needed and none was made; no commit was created.

Per-finding verdicts (all verified against HEAD)

  1. rc:3872913286 (R1-1) — cleared Goal still labels the session (last-objective-over-all-matching-lines scan + head-window resurrection): resolved. End-to-end probes through both producers: clear inside the window answers unlabelled on both the records path and the scan path (with >10 records forcing the scan); create + clear + ~240KB of filler (clear outside the tail window) answers unlabelled; a small goal-only control still surfaces its objective. The head-window phase no longer exists in readLastMatchingLineFieldSync.
  2. rc:3884607504 (R3-1, fix-induced) — lifecycle-incomplete parsed prefix preferred over the matched scan: resolved. Create + mid-string-torn record + glued clear answers unlabelled via listSessions and getSessionListItem in both the <64KB and the >64KB final-line layouts; the pinned constraint test uses complete parsed records when a few large records exceed the tail window stays green; the gate remains strictly < MAX_PROMPT_SCAN_LINES and now also requires readLinesWithIntegrity's completeness flag.
  3. rc:3884607512 (R4-5) — brace-scanner ordering resurrected a cleared Goal: resolved. One physical line carrying create('OLD-GOAL') + torn note + glued clear answers matched-with-no-value at the extractor and unlabelled at both producers; glued create(old)+create(real) answers the newest value.
  4. rc:3886050890 (R5-1, round 6, fix-induced) — colon-ending torn prefix fall-through and array-nested fragment injection: resolved. A torn prefix ending at a key colon with a glued clear answers unlabelled on both producers; a goal-shaped array element nested in a torn record produces no label.
  5. rc:3888342855 (R5-1, round 7, fix-induced) — payload-bearing fragment injection and glued-record suppression: resolved. Payload-bearing goal_state fragments at array-first and comma positions produce no label; an older genuine goal followed by a torn payload-bearing container stays unlabelled (fail-closed); a genuine record glued before a nested-marker record keeps its value via marker re-attribution.

Mutation cross-check

To prove the witnesses discriminate, the structural position check in extractJsonStringFieldFromLastMatchingLine was temporarily mutated (candidate admission made unconditional): three committed regression tests (rejects a nested marker at the end of a torn containing record, does not read a goal-shaped array element from a torn containing record, does not read a comma-positioned goal-shaped array element from a torn record) plus the end-to-end probe older genuine goal + torn payload container stays unlabelled all turned red; the original code was restored byte-identical and everything returned to green.

Maintainer changes since the last bot push

7aef1b0d59 routes the goal reader's open through openSyncNoFollow, aligning it with the sibling title reader (#10007 line). Verified at HEAD: no dangling getReadOpenFlags references remain anywhere, and the full check matrix below is green on this commit.

Deferred items

The Deferred non-Critical feedback section (round-3/round-5 inline findings, deferred review bodies, and deferred PR comments) was left untouched per Critical-only mode — no code changes, no thread actions, no replies.

Verification

  • npm run build — passed (exit 0)
  • npm run typecheck — passed (exit 0)
  • npm run lint — passed (exit 0)
  • vitest packages/core (touched): sessionService.test.ts + sessionService.rename.test.ts — 271 passed (2 files)
  • vitest packages/core (touched): sessionStorageUtils.test.ts — 81 passed (run together with a temporary 15-test verification probe file, deleted after the round and never committed; combined run 96 passed)
  • vitest packages/cli (touched): sessionPickerUtils.test.ts + StandaloneSessionPicker.test.tsx — 37 passed (2 files)
  • Mutation cross-check: 4 tests red with the structural guard removed, green after restore

Outcome: no changes this round, no commit. All five Critical findings and the addressed Suggestions were re-verified as resolved in the current code; their comment ids are listed in resolved-comments.txt.

中文说明

Autofix 评审轮次 — 仅验证,无需代码改动

当前处于 Critical-only 模式。本轮全部可处理条目是自动评审器提出的 5 条 Critical 发现,且每一条都已在更早的轮次中提交了修复。自上次机器人推送之后,本分支合并了 main(三次合并),并收到了维护者提交 7aef1b0d59fix(core): preserve no-follow session goal reads)。因此本轮在 HEAD 7aef1b0d59 上以来源无关(source-blind)的方式重新验证:对真实(未 mock)的 SessionService 驱动按每条发现的见证(witness)形状构造的真实 JSONL transcript,确认所报告的缺陷在当前代码上均不再复现——随后重跑了全部必需检查。本轮无需任何代码改动,也未做任何改动;未创建提交。

逐条结论(均已在 HEAD 上验证)

  1. rc:3872913286 (R1-1) — 已清除的 Goal 仍作为会话标签(跨所有匹配行取最后一个 objective 的扫描 + head 窗口复活):已解决。经两个生产者端到端探针验证:窗口内清除在记录路径与扫描路径(用 >10 条记录强制走扫描)均返回无标签;创建 + 清除 + 约 240KB 填充(清除位于 tail 窗口之外)返回无标签;小的仅 Goal 对照组仍正常显示 objective。readLastMatchingLineFieldSync 中 head 窗口阶段已不复存在。
  2. rc:3884607504 (R3-1,修复引入) — 生命周期不完整的解析前缀优先于已匹配的扫描已解决。创建 + 字符串中部截断记录 + 粘连清除,在 <64KB 与 >64KB 末行两种布局下,经 listSessionsgetSessionListItem 均返回无标签;固定约束测试 uses complete parsed records when a few large records exceed the tail window 保持绿色;门控仍严格 < MAX_PROMPT_SCAN_LINES,且现在同时要求 readLinesWithIntegrity 的完整性标志。
  3. rc:3884607512 (R4-5) — 花括号扫描顺序复活已清除的 Goal已解决。单物理行 create('OLD-GOAL') + 截断 note + 粘连清除,在提取器层返回 matched 且无值,两个生产者均无标签;粘连的 create(old)+create(real) 返回最新值。
  4. rc:3886050890 (R5-1,第 6 轮,修复引入) — 冒号结尾截断前缀穿透与数组内嵌片段注入已解决。结束于键冒号的截断前缀 + 粘连清除,两个生产者均返回无标签;截断记录内数组中嵌套的 goal 形状片段不产生标签。
  5. rc:3888342855 (R5-1,第 7 轮,修复引入) — 带载荷片段注入与粘连记录抑制已解决。数组首项与逗号位置的带载荷 goal_state 片段均不产生标签;较旧的真实 Goal 后跟带载荷截断容器时保持无标签(fail-closed);真实记录粘连在含嵌套 marker 的记录之前时,通过 marker 重归属保留其值。

变异交叉验证

为证明见证测试具有区分力,临时变异了 extractJsonStringFieldFromLastMatchingLine 中的结构位置检查(无条件接纳候选):三条已提交的回归测试(rejects a nested marker at the end of a torn containing recorddoes not read a goal-shaped array element from a torn containing recorddoes not read a comma-positioned goal-shaped array element from a torn record)以及端到端探针 older genuine goal + torn payload container stays unlabelled 全部变红;恢复原始代码(逐字节一致)后全部回到绿色。

上次机器人推送后的维护者改动

7aef1b0d59 将 Goal 读取器的打开操作改为经由 openSyncNoFollow,与同级的标题读取器保持一致(#10007 系列)。已在 HEAD 验证:全仓不再残留任何 getReadOpenFlags 引用,且下方完整检查矩阵在该提交上全绿。

延后条目

按 Critical-only 模式,Deferred non-Critical feedback 部分(第 3/5 轮行内发现、延后的评审主体、延后的 PR 评论)未做任何处理——不改代码、不操作线程、不回复。

验证

  • npm run build — 通过(exit 0)
  • npm run typecheck — 通过(exit 0)
  • npm run lint — 通过(exit 0)
  • vitest packages/core(触及文件):sessionService.test.ts + sessionService.rename.test.ts — 271 通过(2 个文件)
  • vitest packages/core(触及文件):sessionStorageUtils.test.ts — 81 通过(与一个临时 15 用例验证探针文件同跑,该探针文件轮次结束后已删除、从未提交;合并运行 96 通过)
  • vitest packages/cli(触及文件):sessionPickerUtils.test.ts + StandaloneSessionPicker.test.tsx — 37 通过(2 个文件)
  • 变异交叉验证:移除结构守卫后 4 个用例变红,恢复后绿色

结果:本轮无改动、无提交。全部 5 条 Critical 发现及已处理的 Suggestion 均已重新验证为在当前代码中已解决;其评论 id 列于 resolved-comments.txt

Deferred non-Critical feedback

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

中文说明

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

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

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


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

@wenshao

wenshao commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Maintainer verification — real environment, A/B against origin/main

Verdict: recommend merge. The reported defect reproduces on the base build and is fixed at head 7aef1b0d59. Precedence, lifecycle correctness (/goal clear), search and the preview all behave as the PR claims, on real transcripts recorded by the real CLI. Nothing I found blocks the merge; four non-blocking observations are at the end, one of which is a genuine test-coverage gap worth a follow-up.

How this was verified

Tree worktree at PR head 7aef1b0d59f878bf9dbab61a66720010d90d708e (main already merged in)
A/B method one-file-revert: the 4 production files reverted to origin/main, everything else — deps, merged main, build flags — byte-identical. Two bundles (dist-base / dist-pr) and two core dists from the same tree
Driver the real bundled CLI (node dist/cli.js --yolo) in tmux against a Goal-protocol OpenAI-compatible mock, isolated HOME, isolated git workspace
Session store 7 sessions recorded live by the real CLI via /goal, /goal clear, /rename and an ordinary prompt, plus 7 journals synthesized from those real records to reach window/format edges
Oracle the real SessionService.listSessions() / getSessionListItem() from each build over the identical store, plus the real TUI

1. The reported bug, before and after

Same store, same 7 sessions, only the build differs.

Before — origin/main: five of the seven rows read (empty prompt) and cannot be told apart.

base picker

After — this PR: each /goal session shows its objective. Note the row that stays (empty prompt) — that is the session where /goal clear was run, and it is correct that it has no label.

PR picker

2. Label matrix — 14 scenarios, both builds, identical files

R* are recorded by the real CLI; S* are synthesized from those real records to reach window and format edges.

scenario                           |  BASE (main)                    |  PR 10295                                   | Δ
---------------------------------- |  ------------------------------ |  ------------------------------------------ |--
R1 goal-only, 12 rec (scan path)   |  (empty prompt)                 |  Migrate the billing service to the new pri | YES
R2 goal-only, 7 rec (records path) |  (empty prompt)                 |  Rotate the expired staging TLS certificate | YES
R3 goal-only, 6 rec (records path) |  (empty prompt)                 |  Backfill the analytics events table for Q3 | YES
R4 real /goal clear                |  (empty prompt)                 |  (empty prompt)                             |
R5 goal + /rename                  |  Search cluster migration (man… |  Search cluster migration (manual title)    |
R6 real prompt + goal              |  Summarize the README for me    |  Summarize the README for me                |
R7 real goal, 558 KB transcript    |  (empty prompt)                 |  Long running objective that must survive a | YES
S1 clear decided by tail scan      |  (empty prompt)                 |  (empty prompt)                             |
S2 129 KB, goal in tail window     |  (empty prompt)                 |  BIG-TAIL-OBJECTIVE-IN-WINDOW               | YES
S3 168 KB, goal only in head       |  (empty prompt)                 |  (empty prompt)                             |
S4 legacy goal, 16 records         |  (empty prompt)                 |  (empty prompt)                             |
S5 legacy goal, 5 records          |  (empty prompt)                 |  LEGACY-SHORT-OBJECTIVE                     | YES
S6 torn newest goal_state line     |  (empty prompt)                 |  (empty prompt)                             |
S7 decoy marker line after goal    |  (empty prompt)                 |  DECOY-LINE-MUST-NOT-HIDE-THIS              | YES

What this pins:

  • Both producers, both paths. R2/R3 (< 10 records) take the parsed-records path; R1/R7 (≥ 10 records) take the bounded tail scan. Both label correctly.
  • Precedence is unchanged. R5 keeps the /rename title over an active Goal; R6 keeps the first prompt over a Goal set later in the same session.
  • A cleared Goal is not resurrected. R4 is a real /goal clear; S1 forces the same decision through the file scan (16 records, so the parsed prefix cannot decide). Both stay unlabelled — the "last goal_state line decides, even when it carries no objective" rule holds end to end.
  • Fails closed out of window. S3's only goal_state sits in the head of a 168 KB file; the PR declines to label rather than show a possibly-stale objective. Deliberate, and documented in the source.

3. Search

origin/main cannot find a Goal session by its objective; this PR can. Same store, same query.

before after
base search PR search

4. The 64 KB tail window is not a practical limit for real Goal sessions

S3 shows the fails-closed branch exists, so I checked whether real Goal sessions can land in it. They do not: I drove a real /goal run until its transcript reached 571,777 bytes — 8.7× the 64 KB window — and the label still resolves, because the Goal lifecycle writes a fresh goal_state record every turn:

lines: 320   bytes: 571,777
last goal_state byte offset: 570,486  →  1,291 bytes from EOF   (tail window = 65,536)
last cause: usage_limited   objective: "Long running objective that must survive a transcript larger than the 64KB tail window"

That is R7 in the matrix, and the top row of the "after" screenshot. The bounded read is sized correctly for how this data is actually written.

5. Picker latency

listSessions() over a 150-session store, 6 interleaved rounds of 15 calls each, median of medians:

store base PR delta
worst case — 150 goal-only sessions, 13.4 MB (largest 558 KB) 37.3 ms 39.9 ms +2.7 ms (+7%)
control — 150 prompt-bearing sessions (fallback never runs) 33.8 ms 33.2 ms −0.6 ms (noise)

The worst case is a store made entirely of unlabelled Goal sessions, which is the only shape that pays the extra read on every row. The PR's risk statement ("one existing bounded transcript-tail lookup") measures out accurately.

6. Tests and their efficacy

All 5 PR-touched test files pass locally on Node 22.22.2: core 352/352, cli 37/37 (389/389). CI is green at 7aef1b0d59 (run 33409669840).

Because earlier review rounds reported test-efficacy probing as inconclusive, I ran the probes directly — each breaks exactly one behaviour the PR claims, then re-runs the PR's own suites:

probe result
M1 picker row stops consulting goalObjective caught
M2 search haystack drops goalObjective caught
M3 if (prompt || title) return undefined precedence guard removed caught
M4 type/subtype gate removed from readGoalStateObjective SURVIVED
M5 cleared Goal no longer decisive (last objective on any line wins) caught
M6 scan miss resurrects the head-window objective caught
M7 display truncation removed caught
M8 recordsComplete torn-prefix guard removed caught
M9 preview title reverted to the base expression caught

8 of 9 caught. The one survivor is finding F1 below.

7. Non-blocking findings

F1 — the type/subtype gate is load-bearing but has no test. readGoalStateObjective (packages/core/src/services/sessionService.ts:433) rejects records that are not type: 'system' + subtype: 'goal_state'. Removing that gate ships green through all 389 tests. It is not dead code, though: I built the missing witness — scenario S7, a ui_telemetry record written after the Goal whose serialized line legitimately nests "subtype":"goal_state" in its payload. With the gate, the scan skips that line and reports the objective; with the gate removed, the same session silently falls back to (empty prompt):

S7, PR head            → "DECOY-LINE-MUST-NOT-HIDE-THIS"
S7, gate-removed build → "(empty prompt)"

(verified against a purpose-built mutant core dist, not by reasoning). This confirms the round-8 deferred item and supplies the production-level witness it said was missing. A regression test shaped like S7 would close it — worth a follow-up, not a merge blocker.

F2 — legacy (pre-v2) Goals past the 10-record prefix stay unlabelled. S4/S5 isolate it: a legacy slash_command Goal record is recovered when the session has fewer than 10 records (S5) but not beyond that (S4), because the fallback scan's marker is "subtype":"goal_state", which legacy sessions never wrote. Behaviour is identical to base, so this is an incomplete fix for old sessions rather than a regression. Matches deferred R9-4.

F3 — the picker now disagrees with the other label surfaces. Verified live on this build, same sessions the picker labels:

$ qwen sessions list                                    # abridged
SESSION ID                             TITLE   BRANCH   PROMPT
010dcbff-0ebd-4606-af43-6db043681bcf           master            ← picker shows "Migrate the billing service…"
cd5552fc-a5d6-40e7-a879-2f9be92c7129           master            ← picker shows "Rotate the expired staging TLS…"

$ curl <daemon>/workspace/<ws>/sessions                 # qwen serve, same store
displayName: ''    for every goal-only session

packages/cli/src/serve/server/session-list.ts:483 still computes displayName: item.customTitle || item.prompt. The PR documents this deliberately in the SessionListItem.goalObjective doc comment and scopes it out; recording it here so the follow-up is not lost.

F4 — small unadvertised improvement in the preview header. The base expression customTitle ?? prompt ?? undefined preserves the empty string, since prompt is '' (not undefined) for Goal-only sessions — so the preview header renders blank instead of falling back to "Session Preview". The PR's || chain fixes that as a side effect. Confirmed on the base build:

BASE  prompt="" customTitle=undefined  →  sessionTitle = ""   (header renders empty)

8. Not verified here

  • The TUI preview overlay does not paint under headless tmux on either build, so the preview evidence is the PR's own ink render test (uses the Goal objective as the preview title) plus the M9 probe above, not a screenshot.
  • Windows and macOS. The round-10 deferred Critical about openSyncNoFollow on O_NOFOLLOW-absent platforms is a Windows-only test concern and both OS unit matrices are skipping in CI; this run was Linux only.
  • ACP ListSessions titles (F3 covers the serve and CLI surfaces live; ACP was read, not driven).
中文说明

维护者验证 —— 真实环境,与 origin/main 做 A/B 对比

结论:建议合入。 所报告的缺陷在 base 构建上可复现,在 head 7aef1b0d59 上已修复。优先级、生命周期正确性(/goal clear)、搜索与预览的表现都与 PR 描述一致,且验证均基于真实 CLI 录制的真实 transcript。未发现阻塞合入的问题;末尾列出 4 条非阻塞观察,其中 1 条是值得后续补齐的测试覆盖缺口。

验证方式

代码树 worktree 位于 PR head 7aef1b0d59f878bf9dbab61a66720010d90d708e(已合入 main)
A/B 方法 单文件回退:仅把 4 个生产文件回退到 origin/main,依赖、已合入的 main、构建参数全部逐字节相同。从同一棵树产出两份 bundle(dist-base / dist-pr)与两份 core dist
驱动方式 tmux 中运行真实打包后的 CLInode dist/cli.js --yolo),对接支持 Goal 协议的 OpenAI 兼容 mock,HOME 与 git 工作区均隔离
会话数据 7 个由真实 CLI 通过 /goal/goal clear/rename 及普通提示词录制的真实会话,外加 7 个基于这些真实记录合成的 journal,用于覆盖窗口与格式边界
判定口径 两份构建各自的真实 SessionService.listSessions() / getSessionListItem() 读取同一份会话数据,并辅以真实 TUI

1. 缺陷的前后对比

同一份数据、同样 7 个会话,仅构建不同。

改动前(origin/main:7 行中有 5 行显示为 (empty prompt),彼此无法区分(见上方英文部分第 1 张截图)。

改动后(本 PR):每个 /goal 会话都显示自己的 objective(见第 2 张截图)。请注意仍然显示为 (empty prompt) 的那一行 —— 那是执行过 /goal clear 的会话,不带标签才是正确行为。

2. 标签矩阵 —— 14 个场景、两份构建、同一批文件

矩阵见上方英文部分。其中 R* 为真实 CLI 录制,S* 为基于真实记录合成,用于触达窗口与格式边界。矩阵锁定了以下几点:

  • 两个生产者、两条路径都覆盖。 R2/R3(记录数 < 10)走已解析记录路径;R1/R7(记录数 ≥ 10)走有界 tail 扫描。两条路径标签均正确。
  • 优先级未变。 R5 中 /rename 标题优先于活跃 Goal;R6 中首条提示词优先于会话后期设置的 Goal。
  • 已清除的 Goal 不会被复活。 R4 是真实的 /goal clear;S1 则强制让同一判定走文件扫描路径(16 条记录,已解析前缀无法决定)。两者都保持无标签 —— “最后一条 goal_state 行决定结果,即使它不携带 objective”这条规则端到端成立。
  • 超出窗口时向安全侧失败。 S3 的唯一一条 goal_state 位于 168 KB 文件的头部,本 PR 选择不打标签,而不是展示可能已过期的 objective。这是有意设计,且在源码中有说明。

3. 搜索

origin/main 无法按 objective 搜索到 Goal 会话,本 PR 可以。同一份数据、同一个查询词(见上方英文部分的对比截图)。

4. 对真实 Goal 会话而言,64 KB tail 窗口不构成实际限制

S3 证明了“向安全侧失败”的分支确实存在,因此我进一步检查真实 Goal 会话是否会落入该分支 —— 结论是不会。我驱动一次真实 /goal 运行,直到 transcript 达到 571,777 字节,即窗口的 8.7 倍,标签依然可以解析,因为 Goal 生命周期每一轮都会写入新的 goal_state 记录:最后一条 goal_state 距文件末尾仅 1,291 字节(窗口为 65,536 字节)。这就是矩阵中的 R7,也是“改动后”截图的第一行。有界读取的尺寸与该数据的实际写入方式是匹配的。

5. 选择器延迟

在 150 个会话的数据集上执行 listSessions(),交替进行 6 轮、每轮 15 次调用,取中位数的中位数:

数据集 base PR 差异
最坏情况 —— 150 个仅含 Goal 的会话,13.4 MB(最大单文件 558 KB) 37.3 ms 39.9 ms +2.7 ms(+7%)
对照组 —— 150 个含首条提示词的会话(回退逻辑不会触发) 33.8 ms 33.2 ms −0.6 ms(噪声)

最坏情况是数据集全部由无标签 Goal 会话构成,这也是唯一会让每一行都付出额外读取成本的形态。PR 中“一次现有的有界 transcript 尾部读取”这一风险描述,实测结果与之相符。

6. 测试及其有效性

5 个 PR 涉及的测试文件在本地 Node 22.22.2 上全部通过:core 352/352、cli 37/37(合计 389/389)7aef1b0d59 上 CI 为绿(run 33409669840)。

由于此前的评审轮次报告 test-efficacy 探针结论不确定,我直接运行了变异探针(每个探针只破坏本 PR 声称的一项行为,然后重跑 PR 自带的测试套件):9 个探针中 8 个被捕获,唯一存活的即下面的 F1。明细见上方英文表格。

7. 非阻塞发现

F1 —— type/subtype 门控是有实际作用的,但没有测试覆盖。 readGoalStateObjectivepackages/core/src/services/sessionService.ts:433)会拒绝非 type: 'system' + subtype: 'goal_state' 的记录。移除该门控后,389 个测试全部照常通过。但它并非无用代码:我构造了缺失的见证场景 S7 —— 一条在 Goal 之后写入的 ui_telemetry 记录,其序列化后的行内合法地嵌套了 "subtype":"goal_state"。保留门控时扫描会跳过该行并正确给出 objective;移除门控后,同一个会话会静默退回 (empty prompt)。该结论是针对专门构建的变异 core dist 实测得出的,而非纯推理。这印证了第 8 轮延后的那条发现,并补上了它所说的“缺少生产级见证”。补一个 S7 形态的回归测试即可闭环 —— 属于后续工作,不阻塞合入。

F2 —— 超出 10 条记录前缀的旧版(pre-v2)Goal 仍然无标签。 S4/S5 隔离了这一点:会话记录少于 10 条时(S5)旧版 slash_command Goal 记录可以恢复,超出后(S4)则不行,因为回退扫描的标记是 "subtype":"goal_state",而旧版会话从未写入过该标记。其行为与 base 完全一致,因此这是对旧会话的修复不完整,而非回归。与延后项 R9-4 一致。

F3 —— 选择器现在与其他标签展示面不一致。 已在本构建上实测(与选择器已打标签的是同一批会话):qwen sessions list 的 TITLE/PROMPT 列仍为空;qwen serveGET /workspace/<ws>/sessions 对每个仅含 Goal 的会话仍返回 displayName: ''packages/cli/src/serve/server/session-list.ts:483 依旧是 displayName: item.customTitle || item.prompt。本 PR 已在 SessionListItem.goalObjective 的文档注释中明确记录并将其排除在范围之外;此处记录一笔,以免后续工作被遗漏。

F4 —— 预览标题有一处未被提及的小改进。 base 的表达式 customTitle ?? prompt ?? undefined 会保留空字符串(对仅含 Goal 的会话,prompt'' 而非 undefined),因此预览标题会渲染为空,而不会回退到 “Session Preview”。本 PR 改用 || 链后顺带修复了这一点。已在 base 构建上确认:prompt=""customTitle=undefinedsessionTitle = ""

8. 本次未验证的内容

  • 预览浮层在无头 tmux 下两份构建都不渲染,因此预览部分的证据来自 PR 自带的 ink 渲染测试(uses the Goal objective as the preview title)与上文的 M9 探针,而非截图。
  • Windows 与 macOS。第 10 轮延后的那条关于 openSyncNoFollow 在缺少 O_NOFOLLOW 的平台上的 Critical 属于 Windows-only 的测试问题,且两个操作系统的单测矩阵在 CI 中均为 skipping;本次仅在 Linux 上运行。
  • ACP ListSessions 标题(F3 已实测覆盖 serve 与 CLI 两个展示面,ACP 仅做了代码审阅,未实际驱动)。

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

Autofix review round — no code changes

A maintainer ran a full real-environment A/B verification against origin/main and recommends merge: the reported defect reproduces on the base build and is fixed at head 7aef1b0d59, with precedence, /goal clear lifecycle, search, and the preview all behaving as claimed (see the verification comment). All CI checks at that head are green or skipped, and there is no base conflict to resolve (--conflict false).

There is nothing actionable for this round:

  • The only new feedback is the positive verification above — no Critical findings, no failed checks, and no change requests.
  • This is a Critical-only round (the counting window's round counter has engaged), so the verification's non-blocking observations are deliberately not being used to grow the diff now. Per the project's review policy, after a PR has been through roughly five rounds only Critical fixes land; remaining suggestions are deferred to follow-ups.

The verification's four non-blocking observations are recorded for follow-up rather than merged here:

  • F1 — the type/subtype gate in readGoalStateObjective is load-bearing but has no test witness (the maintainer proved its value with a decoy-record probe against a mutated build). Recorded as a follow-up regression test; explicitly marked "worth a follow-up, not a merge blocker".
  • F2 — legacy (pre-v2) goals past the 10-record prefix stay unlabelled; behaviour is identical to base (a limitation, not a regression), matching the previously deferred R9-4.
  • F3qwen serve (displayName) and qwen sessions list do not yet surface goal objectives the way the picker does; these surfaces were deliberately scoped out of this PR and the fix lives outside its footprint. Recorded for a follow-up.
  • F4 — a small unadvertised improvement: the preview header now falls back to "Session Preview" instead of rendering blank. No action needed.

No code changes were made this round.

Verification

No code changed this round, so no build/typecheck/lint/test commands were run. The working tree is clean and HEAD is the maintainer-verified 7aef1b0d59, where the full CI matrix is green (Test (ubuntu), Integration Tests (no-AK), security and desktop-shell checks all SUCCESS).

中文说明

Autofix 审阅轮次 —— 无代码改动

一位维护者在真实环境对 origin/main 做了完整的 A/B 验证,并建议合入:所报告的缺陷在 base 构建上可复现,在 head 7aef1b0d59 上已修复;优先级、/goal clear 生命周期、搜索与预览的表现均与 PR 所述一致(见该验证评论)。该 head 上所有 CI 检查为绿或跳过,且没有需要解决的 base 冲突(--conflict false)。

本轮没有可执行的工作:

  • 唯一的最新反馈就是上述正面验证——没有 Critical 发现、没有失败的检查、也没有改动请求。
  • 当前处于 Critical-only 轮次(计数窗口的轮次计数已触发),因此该验证中的非阻塞观察项不会被用来扩大当前 diff。按本项目的评审策略,PR 经过约五轮后只合入 Critical 修复,其余建议延后为后续跟进项。

该验证的 4 条非阻塞观察已记录为后续跟进项,而非在本 PR 中合入:

  • F1 —— readGoalStateObjective 中的 type/subtype 门控是有实际作用的,但缺少测试见证(维护者已用一条针对变异构建的诱饵记录探针证明其价值)。记录为后续回归测试;维护者明确标注为“值得后续跟进,不阻塞合入”。
  • F2 —— 超出 10 条记录前缀的旧版(pre-v2)goal 仍无标签;行为与 base 完全一致(属于局限,而非回归),与已延后的 R9-4 相同。
  • F3 —— qwen servedisplayName)与 qwen sessions list 目前还不会像选择器那样展示 goal objective;这些展示面本就被有意排除在本 PR 范围之外,且相应修复位于本 PR 改动范围之外。记录为后续跟进。
  • F4 —— 一处未被提及的小改进:预览标题现在会回退到 “Session Preview”,而不会渲染为空。无需处理。

本轮未做任何代码改动。

验证

本轮未改动任何代码,因此未运行 build/typecheck/lint/测试命令。工作区为干净状态,HEAD 即为维护者验证过的 7aef1b0d59,该提交的完整 CI 矩阵为绿(Test (ubuntu)Integration Tests (no-AK)、安全与 desktop-shell 检查均为 SUCCESS)。

Deferred non-Critical feedback

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

中文说明

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

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


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

@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 at 7aef1b0. Reviewed the full diff:

  • The goal-objective fallback is correctly scoped: precedence stays customTitle > prompt > goalObjective, the policy has a single owner (resolveGoalObjective) so listSessions and getSessionListItem can't disagree, and the field is deliberately limited to the /resume picker with the widening work documented for later.
  • The lifecycle semantics are right: the newest goal_state line decides, including cleared goals (goal: null / no objective), so a cleared Goal stops showing; matched-with-undefined vs absent vs out-of-window vs unreadable are properly distinguished, and the tail-only window deliberately has no head fallback because lifecycle fields can be cleared by unreadable newer records.
  • The new readLastMatchingLineFieldSync is bounded (one LITE_READ_BUF_SIZE tail read plus one re-read for concurrent appends), uses openSyncNoFollow, closes its fd in finally, and handles crash-truncated lines via complete-suffix recovery with an authoritative-parser path that can't expose stale lifecycle values.
  • readLines→readLinesWithIntegrity keeps the existing extraction behavior while exposing the completeness flag the fallback selection needs.
  • Picker display/preview/search all covered by tests; 26 prior threads resolved.

CI shows no failures on this head. Approving; the stale bot CHANGES_REQUESTED predates this head.

@wenshao
wenshao enabled auto-merge September 1, 2026 03:13
@wenshao
wenshao added this pull request to the merge queue Sep 1, 2026
Merged via the queue into QwenLM:main with commit d14008f Sep 1, 2026
91 checks passed

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed at head 7aef1b0d.

  • The prior CHANGES_REQUESTED rounds were all on superseded heads; every review thread (26/26) is resolved and the reworked implementation addresses the earlier findings: the newest goal_state record is decisive (so /goal clear can't resurrect a stale objective), a record-window overflow or unreadable file fails closed to an unlabelled session, and the nested-marker case is handled by reading the parsed record rather than a raw substring.
  • resolveGoalObjective keeps the precedence policy (prompt || title short-circuit, complete-prefix vs bounded file scan) in one place used by both list and single-session read paths, so the TUI picker and serve can't disagree.
  • No new Critical issues found in the diff; test coverage (cleared goal, out-of-window, priority, both read paths) looks appropriate.
  • Required checks are green at this head.

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

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

/resume picker shows "(empty prompt)" for /goal sessions — fall back to the Goal objective

5 participants