Skip to content

fix(goal): stamp the wind-down hand-off only when its turn was delivered - #10260

Merged
qqqys merged 2 commits into
QwenLM:mainfrom
qqqys:goal/wind-down-delivery
Aug 28, 2026
Merged

fix(goal): stamp the wind-down hand-off only when its turn was delivered#10260
qqqys merged 2 commits into
QwenLM:mainfrom
qqqys:goal/wind-down-delivery

Conversation

@qqqys

@qqqys qqqys commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

What this PR does

Stamps GoalRecord.windDownTurnId — the marker that says "the user received the budget hand-off" — only when the wind-down turn was actually delivered to the model, using the delivery mark hosts already set (markTurnDelivered) and the rule #10013 established for the objective-updated notice. finishTurn reads currentTurnDelivered before the announcement settle resets it; a wind-down permit that finished undelivered leaves the record clean, so the next queueContinuation grants the hand-off again instead of settling usage_limited. The in-memory permit marker is released either way, since it belongs to the permit rather than to the outcome.

Why it's needed

#10132 inferred "the hand-off was delivered" from "the turn holding the wind-down permit finished". #10013 showed why that inference fails: a system message (Cron/Notification/Teammate via claimSystemGoalTurn) or a direct user query (/btw via claimDirectUserAdmission) can claim a queued continuation's permit and send its own text under it, skipping both the continuation render and the delivery mark. If the claimed permit is the wind-down permit, the record was stamped, the next continuation stopped the Goal on a hand-off the user never got, and a resume did not repair it — the marker is cleared only by a re-arm. Filed as #10150.

Reviewer Test Plan

How to verify

  • cd packages/core && npx vitest run src/goals/ — 478 pass (17 files). goal-runtime.test.ts gains two cases: grants the hand-off again when its turn finished without being delivered (finish the wind-down turn with no delivery mark → no windDownTurnId on the record or in the journal, Goal still active, the next continuation is windDown: true again) and stops after the hand-off once a delivered wind-down turn finishes (mark delivered, finish → marker stamped, usage_limited, no third turn). The three existing wind-down tests that finish the hand-off turn now mark it delivered first, so they keep meaning "the model saw the hand-off".
  • Mutation probe run during development: making the stamp unconditional again (finishedWindDown = heldWindDown) fails exactly the undelivered case, 145 others green.
  • cd packages/cli && npx vitest run src/nonInteractiveCli.test.ts src/ui/hooks/useGeminiStream.test.tsx src/acp-integration — 2151 pass; the host suites that exercise wind-down are unchanged, since hosts already mark delivery at their send sites.
  • tsc --noEmit: no goal-code errors in packages/core; prettier + eslint clean on the two changed files.

Evidence (Before & After)

N/A (runtime bookkeeping; the visible surfaces are unchanged — what changes is whether the hand-off is re-offered when the first attempt never reached the model).

Tested on

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

Environment (optional)

N/A (unit tests only).

Risk & Scope

  • Main risk or tradeoff: a wind-down turn whose host never calls markTurnDelivered would now re-grant the hand-off each window instead of stopping after one; all three hosts mark delivery at their real send site as of feat(goal): tell the model the objective changed, once, when it changed #10013, and the runtime tests were updated to say so explicitly rather than rely on the old unconditional stamp.
  • Not validated / out of scope: no change to the budget gate, the re-arm rules, or the wind-down prompt; no host code touched.
  • Breaking changes / migration notes: none. Persisted records are read the same way; only when the marker is written changes.

Linked Issues

中文说明

这个 PR 做了什么

GoalRecord.windDownTurnId——表示「用户已收到预算收尾交接」的标记——现在只在收尾轮真正送达模型时才盖章,复用 host 已在真实发送点设置的送达标记(markTurnDelivered)以及 #10013 为「objective 已变更」通知确立的规则。finishTurn 在宣告结算重置之前读取 currentTurnDelivered;未送达就结束的收尾 permit 不在记录上留标记,于是下一次 queueContinuation 会再次授予交接,而不是落为 usage_limited。内存中的 permit 标记无论如何都会释放,它属于 permit 而非结果。

为什么需要

#10132 以「持有收尾 permit 的轮次结束了」推断「交接已送达」。#10013 说明了这个推断为何不成立:系统消息(经 claimSystemGoalTurn 的 Cron/Notification/Teammate)或直接用户查询(经 claimDirectUserAdmission/btw)可以认领排队中续跑的 permit 并在其下发送自己的文本,跳过续跑渲染与送达标记。若被认领的正是收尾 permit,记录会被盖章,下一次续跑会在一份用户从未收到的交接上停止 Goal,resume 也无法修复——标记只在重新武装时清除。已记录为 #10150

评审验证计划

如何验证

  • cd packages/core && npx vitest run src/goals/——478 通过(17 个文件)。goal-runtime.test.ts 新增两个用例:grants the hand-off again when its turn finished without being delivered(未标记送达就结束收尾轮 → 记录与日志均无 windDownTurnId,Goal 仍为 active,下一次续跑再次为 windDown: true)和 stops after the hand-off once a delivered wind-down turn finishes(标记送达后结束 → 盖章、usage_limited、无第三轮)。原有三个结束收尾轮的测试现在先标记送达,使其含义保持为「模型看到了交接」。
  • 开发期间的变异检验:把盖章改回无条件(finishedWindDown = heldWindDown),恰好挂未送达用例,其余 145 绿。
  • cd packages/cli && npx vitest run src/nonInteractiveCli.test.ts src/ui/hooks/useGeminiStream.test.tsx src/acp-integration——2151 通过;涉及收尾的 host 套件不变,因为 host 已在发送点标记送达。
  • tsc --noEmit:packages/core 中 goal 代码无错误;两个改动文件 prettier + eslint 干净。

证据(前后对比)

N/A(运行时账本;可见界面不变,改变的是首次交接未到达模型时是否重新提供)。

已测试平台

Linux ✅;macOS / Windows ⚠️(CI 覆盖)。

环境(可选)

N/A(仅单元测试)。

风险与范围

  • 主要风险或权衡:若某个 host 从不调用 markTurnDelivered,收尾轮会在每个窗口重复授予而不是一次即停;自 feat(goal): tell the model the objective changed, once, when it changed #10013 起三个 host 都在真实发送点标记送达,运行时测试也已改为显式表达这一点,而不再依赖旧的无条件盖章。
  • 未验证/范围外:不改变预算闸门、重新武装规则或收尾提示词;不触碰 host 代码。
  • 破坏性变更/迁移说明:无。持久化记录的读取方式不变,变的只是何时写入标记。

关联 Issue

QwenLM#10132 marked the record's `windDownTurnId` whenever the turn holding
the wind-down permit finished -- reading "the permit was used" as "the
user got the hand-off". QwenLM#10013 established why that inference is wrong
for the objective-updated notice: a system message or a direct user
query can claim a queued continuation's permit and send its own text
under it, so the turn finishes with the prompt never reaching the
model. Hosts therefore mark delivery at the real send site, and only a
delivered turn commits what it carried.

The hand-off now follows the same rule. `finishTurn` stamps the marker
only when the wind-down turn was marked delivered; an undelivered one
leaves the record clean, so the next `queueContinuation` grants the
hand-off again instead of settling `usage_limited` on a hand-off the
user never received (which a resume would not have repaired either,
since the marker is cleared only by a re-arm). The in-memory permit
marker is released either way; it belongs to the permit, not the
outcome.

The wind-down tests that finish the hand-off turn now mark it delivered
first, so they keep meaning "the model saw the hand-off". Two new cases
pin the split: finished-but-undelivered leaves no marker and re-mints
the hand-off; finished-and-delivered stamps it and stops.

Mutation probe: making the stamp unconditional again fails exactly the
undelivered case (145 others green).
@qqqys

qqqys commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /takeover

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

Copy link
Copy Markdown
Collaborator

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

中文说明

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

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

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

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

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Thanks for the PR!

Template looks good ✓

Problem: observed, not theoretical. The linked issue #10150 (filed out of the #10013 review round) documents the exact mechanism: a system message (claimSystemGoalTurn) or a /btw query (claimDirectUserAdmission) can claim a queued continuation's wind-down permit, finish the turn under its own text, and finishTurn stamps GoalRecord.windDownTurnId even though the hand-off prompt never reached the model — the next continuation then stops the Goal on a hand-off the user never got, and resume doesn't repair it. Same-shape hole #10013 already plugged for the objective-updated notice.

Direction: aligned. This is correctness bookkeeping inside the already-shipped goal runtime, applying the delivery rule #10013 established. Upstream CHANGELOG shows active investment in /goal budget-exhaustion/hand-off semantics (e.g. clearing the goal with a notice on unrecoverable stops), so getting the hand-off marker right matters.

Size: core path touched (packages/core/src/goals/) — 13 production lines (goal-runtime.ts +10/−3), 74 test lines. Far below any escalation threshold.

Approach: minimal and exactly on point. One production hunk: capture currentTurnDelivered before the announcement settle resets it, gate the record stamp on heldWindDown && delivered, and release the in-memory permit marker whenever the permit was held (it belongs to the permit, not the outcome). The two new tests cover both branches; the three existing wind-down tests are updated to mark delivery explicitly instead of relying on the old unconditional stamp. No drive-by changes.

Risk: no elevated risk signals — none of the changed files match the revert-correlated path list.

Moving on to code review. 🔍

中文说明

感谢贡献!

模板完整 ✓

问题:已观测到,不是理论问题。关联 issue #10150(来自 #10013 评审轮次)记录了确切机制:系统消息(claimSystemGoalTurn)或 /btw 查询(claimDirectUserAdmission)可以认领排队中续跑的收尾 permit、在自己的文本下结束该轮,而 finishTurn 会在交接提示词从未送达模型的情况下盖章 GoalRecord.windDownTurnId——下一次续跑会在用户从未收到的交接上停止 Goal,resume 也无法修复。与 #10013 已修复的「objective 已变更」通知漏洞同形。

方向:对齐。这是已上线 goal 运行时内部的正确性记账,应用 #10013 确立的送达规则。上游 CHANGELOG 显示对 /goal 预算耗尽/交接语义的持续投入(例如不可恢复停止时带通知清除 goal),交接标记的正确性因此重要。

规模:触及核心路径(packages/core/src/goals/)——13 行生产代码(goal-runtime.ts +10/−3),74 行测试。远低于任何升级阈值。

方案:最小且切中要害。一个生产 hunk:在宣告结算重置送达标记之前捕获 currentTurnDelivered,以 heldWindDown && delivered 为记录盖章设闸,并在 permit 曾被持有时无条件释放内存中的 permit 标记(它属于 permit 而非结果)。两个新测试覆盖两个分支;原有三个收尾测试改为显式标记送达,不再依赖旧的无条件盖章。无顺手改动。

风险:无升级风险信号——改动文件均未命中回滚关联路径列表。

进入代码审查 🔍

Qwen Code · qwen3.8-max

Reviewed at eb5a1202f7779dd33ea1116bd09659e9d3736e25 · 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

My independent take before reading the diff: the stamp means "the user got the hand-off", so it must be gated on the same delivery flag #10013 introduced — capture currentTurnDelivered before the announcement settle resets it, and release the in-memory permit marker regardless (the permit was consumed either way). The PR does exactly this, which is also the fix #10150 prescribes. Nothing simpler comes to mind, and nothing in the diff goes beyond it.

What I verified against the code at the reviewed commit:

  • The read-before-reset ordering is load-bearing: settleCurrentTurnAnnouncement zeroes currentTurnDelivered, and the PR captures delivered first, then passes it through — semantics for the notice are unchanged.
  • The stamp path is singular: reduceGoalTurnFinished only receives a windDownTurnId payload from finishTurn, and the record's marker has one consumer — the queueContinuation budget gate, which stops on a stamped record and re-grants the hand-off on an unstamped one. With the marker absent, the next continuation re-offers the hand-off instead of settling usage_limited. That closes the loop the issue describes.
  • The key assumption holds on all three hosts: the TUI marks delivery right before sendMessageStream and only for SendMessageType.Goal submits, and the headless and ACP hosts mark at their send sites too — so a permit claimed by a system message or /btw genuinely stays unmarked. That's also the tradeoff the PR names: a host that never marked delivery would re-grant every window, but no such host exists in tree.
  • Non-wind-down turns are untouched (heldWindDown is false → identical behavior), and the journal/persisted-record schema is read the same way; only when the marker is written changes.

No correctness, security, or convention issues found. Comment style matches the file's existing why-comments. No AGENTS.md violations.

Testing

Evidence carried: this PR's own CI, read through the API (unattended run — I don't execute PR code). The Qwen Code CI run on the reviewed commit is still in progress: the Linux unit lane (Test (ubuntu-latest, Node 22.x)) is running; the security lanes and precheck already landed green. The macOS/Windows test and no-sandbox integration jobs report skipped — that's standing repo CI configuration (the PR trigger for those lanes is off), not coverage dropped by this PR. The table below is updated in place once CI settles.

The two new tests pin the change by structure, not by author's word: the undelivered case asserts the record carries no windDownTurnId, the Goal stays active, and the third continuation is windDown: true again — none of which the pre-change unconditional stamp can produce. The author's suite-size numbers (478 goals tests, 2151 CLI tests) are their own report; the CI column below is what this review counts. Real-scenario testing: N/A — nothing user-visible changes (runtime bookkeeping only), so there is no terminal surface to drive.

Final CI results for eb5a120 (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
route ✅ success
Secret scan (TruffleHog) ✅ 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,失败项排在最前。

中文说明

代码审查

读 diff 之前我的独立思路:盖章的含义是「用户已收到交接」,因此应当用 #10013 引入的送达标记来设闸——在宣告结算重置送达标记之前先捕获 currentTurnDelivered,并无论结果如何都释放内存中的 permit 标记(permit 已被消耗)。PR 正是这样做的,也与 #10150 开出的修法一致。想不出更简的路径,diff 也没有任何超出之处。

在受审提交上核实过的内容:

  • 先读后重置的顺序是关键:settleCurrentTurnAnnouncement 会把 currentTurnDelivered 清零,PR 先捕获 delivered 再传入——通知的语义保持不变。
  • 盖章路径唯一:reduceGoalTurnFinished 只从 finishTurn 收到 windDownTurnId 载荷,记录上的标记只有一个消费者——queueContinuation 预算闸门:已盖章即停,未盖章则再次授予交接。标记缺位时,下一次续跑会重新提供交接而不是落为 usage_limited,闭合了 issue 描述的漏洞。
  • 关键假设在三个 host 上都成立:TUI 在 sendMessageStream 之前、且仅对 SendMessageType.Goal 提交标记送达;headless 与 ACP host 也在各自的发送点标记——因此被系统消息或 /btw 认领的 permit 确实不会被标记。这也是 PR 自述的权衡:若有 host 从不标记送达,交接会每个窗口重复授予,但树中不存在这样的 host。
  • 非收尾轮不受影响(heldWindDown 为假 → 行为完全一致);日志/持久化记录的读取方式不变,只是写入标记的时机变了。

未发现正确性、安全性或约定问题。注释风格与文件中现有的 why-注释一致。无 AGENTS.md 违规。

测试

本次携带的证据:该 PR 自身的 CI,通过 API 读取(无人值守运行——不执行 PR 代码)。受审提交上的 Qwen Code CI 仍在进行:Linux 单元车道(Test (ubuntu-latest, Node 22.x))运行中;安全车道与 precheck 已通过。macOS/Windows 测试与免沙箱集成任务显示 skipped——这是仓库既有的 CI 配置(这些车道的 PR 触发已关闭),并非本 PR 丢掉的覆盖。CI 落定后下方表格会就地更新。

两个新测试从结构上钉住了改动,而非仅凭作者口径:未送达用例断言记录上没有 windDownTurnId、Goal 保持 active、第三次续跑再次为 windDown: true——旧的无条件盖章不可能产生这些结果。作者的套件规模数字(478 个 goal 测试、2151 个 CLI 测试)是其自述;本审查以上表 CI 为准。真实场景测试:N/A——无用户可见变化(纯运行时记账),没有可驱动的终端界面。

Qwen Code · qwen3.8-max

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

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Confidence: 5/5 — clean across every stage; approval is deferred only until the Linux unit lane lands green on the reviewed commit.

What I'm actually thinking after the full pass: this is the delivery rule from #10013 applied a second time, and it's settling into a real principle in this runtime — the record may only say what the host's delivery mark can prove. The PR follows that principle exactly and goes no further: 13 production lines, no scaffolding, no drive-bys. My independent proposal (gate the stamp on the delivery flag captured before the settle resets it; release the permit marker either way) is what the diff does, and I couldn't construct a materially simpler path — clearing the marker earlier (e.g. in releaseTurn) wouldn't fix the stamp, and stamping at grant time is precisely the bug.

The tests are the right shape. The undelivered case cannot pass on pre-change code: the old unconditional stamp settles the Goal usage_limited after two turns, while the test demands a third wind-down continuation — so a green run means the gate is load-bearing, not decorative. The delivered case pins the happy path, and the three existing wind-down tests were honestly updated to mark delivery rather than quietly kept passing. The author is a high-volume contributor with many open PRs; this one is judged on its own merits and earns its place — it closes a documented defect (#10150) with the minimal change.

The one residual risk is the one the PR itself names: a future host that forgets to mark delivery would re-grant the hand-off every window instead of stopping. All three current hosts mark at their real send sites (verified in tree), and re-offering is the better failure mode — it's loud, where the bug was silent.

CI on the reviewed commit is still running (the Linux unit lane), so no approval is posted in this run — approval is deferred until CI lands green on the reviewed commit, and the finalize job will act on it.

中文说明

置信度:5/5 —— 各阶段均干净;仅因受审提交上的 Linux 单元车道尚未落绿而暂缓批准。

完整过一遍之后我真实的想法:这是 #10013 送达规则的第二次应用,正在沉淀为该运行时的真实原则——记录只能陈述 host 送达标记能够证明的事实。PR 恰好遵循这一原则且毫无超出:13 行生产代码,无脚手架,无顺手改动。我的独立方案(以结算重置前捕获的送达标记为盖章设闸;无论如何都释放 permit 标记)与 diff 一致,而且我想不出更简的路径——更早清除标记(如在 releaseTurn 中)修不了盖章问题,在授予时盖章正是这个 bug 本身。

测试形态正确。未送达用例在旧代码上不可能通过:旧的无条件盖章会在两轮后把 Goal 落为 usage_limited,而测试要求第三次收尾续跑——因此跑绿即证明闸门是承重的,不是摆设。送达用例钉住正常路径,原有三个收尾测试被诚实地改为显式标记送达,而不是悄悄放行。作者是有大量在途 PR 的高产贡献者;本 PR 凭自身价值获得评价——它以最小改动关闭了一个有记录的缺陷(#10150)。

唯一残留风险正是 PR 自述的那条:未来某个忘记标记送达的 host 会导致交接每个窗口重复授予而非一次即停。现有三个 host 都在真实发送点标记(已在树中核实),且重复提供是更好的失败模式——它是显性的,而这个 bug 是静默的。

受审提交上的 CI 仍在运行(Linux 单元车道),本次运行不发布批准——批准推迟到 CI 在该提交上落绿,finalize 任务将据此执行。

Qwen Code · qwen3.8-max

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

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed. Suggestions are inline.

Not explored to full depth (tool budget reached): "agent reverse-audit (round 2)": executing npx vitest run src/goals/goal-runtime.test.ts in packages/core — the worktree has no installed/built node_modules and install-plus-build exceeds the…; "agent 3b": none — no check was cut short..

中文说明

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

未探索到全部深度(达到工具调用预算):"agent reverse-audit (round 2)"executing npx vitest run src/goals/goal-runtime.test.ts in packages/core — the worktree has no installed/built node_modules and install-plus-build exceeds the…"agent 3b"none — no check was cut short.

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

// else's text leaves no marker, and the next continuation grants
// the hand-off again instead of stopping cold.
const heldWindDown = windDownTurnId === permit.turnId;
const finishedWindDown = heldWindDown && delivered;

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.

[Suggestion] This change tightens the wind-down stamp rule — finishedWindDown = heldWindDown && delivered — but leaves three earlier comments stating the old "finished ⇒ stamps" rule: the in-memory field doc at goal-runtime.ts:300-304 ("only the turn that actually finishes stamps the record"), the budget-gate comment at goal-runtime.ts:608-610 ("The record marks the hand-off that finished" — its case list omits the new granted-finished-but-undelivered state), and the GoalTurnFinishedTransition.windDownTurnId contract at goal-reducer.ts:49 ("Set when the finishing turn was the spend window's wind-down hand-off"). goal-protocol.ts:175-183 already documents the delivered rule, so the module now contradicts itself. A maintainer extending the settle/release/restore paths — or adding a caller of reduceGoalTurnFinished — reads one of these comments first, concludes that finishing a wind-down turn alone stamps the record, and stamps an undelivered hand-off through a new path, silently reintroducing the #10150 defect: a Goal stopped at usage_limited with the record claiming a hand-off the user never received. Reword all three to the delivered-and-finished rule, for example:

// goal-runtime.ts (field doc)
 * In memory only: a wind-down the host dropped undelivered must be minted
 * again, and only a wind-down turn that finishes delivered stamps the
 * record; one finished under someone else's text leaves the hand-off owed.

// goal-runtime.ts (budget gate)
// A spent window buys one hand-off before it stops. The record marks
// the hand-off that was delivered and finished; until then -- never
// granted, dropped before the model saw it, or finished under another
// text -- grant it.

// goal-reducer.ts (transition contract)
/** Set when the finishing turn was the spend window's wind-down hand-off and was delivered to the model. */
中文说明

此变更收紧了收尾盖章规则——finishedWindDown = heldWindDown && delivered——但留下了三处仍在陈述旧规则(「结束即盖章」)的注释:goal-runtime.ts:300-304 的内存字段文档("only the turn that actually finishes stamps the record")、goal-runtime.ts:608-610 的预算闸门注释("The record marks the hand-off that finished"——其情形列表缺少新增的「已授予、已结束但未送达」状态)、以及 goal-reducer.ts:49GoalTurnFinishedTransition.windDownTurnId 契约("Set when the finishing turn was the spend window's wind-down hand-off")。goal-protocol.ts:175-183 已记载送达规则,模块内部因此自相矛盾。未来扩展 settle/release/restore 路径(或新增 reduceGoalTurnFinished 调用方)的维护者会先读到这些注释,误以为仅结束收尾轮即可盖章,从而在新路径上为未送达的交接盖章,悄悄重现 #10150 缺陷:Goal 停在 usage_limited,记录却声称用户已收到交接,而用户从未收到。建议将三处注释都改为「已送达且结束」规则,例如:

// goal-runtime.ts(字段文档)
 * In memory only: a wind-down the host dropped undelivered must be minted
 * again, and only a wind-down turn that finishes delivered stamps the
 * record; one finished under someone else's text leaves the hand-off owed.

// goal-runtime.ts(预算闸门)
// A spent window buys one hand-off before it stops. The record marks
// the hand-off that was delivered and finished; until then -- never
// granted, dropped before the model saw it, or finished under another
// text -- grant it.

// goal-reducer.ts(transition 契约)
/** Set when the finishing turn was the spend window's wind-down hand-off and was delivered to the model. */

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

@qwen-code-dev-bot

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

Copy link
Copy Markdown
Collaborator

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

中文说明

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

…wenLM#10260)

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@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 轮)。改动内容与我反驳保留之处如下:

Address-review summary — PR #10260 (round 2)

Feedback point

  • [rc:3870463568] (automated reviewer, Suggestion) — the PR tightened the wind-down stamp rule to finishedWindDown = heldWindDown && delivered, but three comments still state the old "finished ⇒ stamps" rule, contradicting goal-protocol.ts, which already documents the delivered rule.

Decision: Implemented. Verified before editing by reading all three cited sites: the in-memory windDownTurnId field doc (goal-runtime.ts), the spent-budget gate comment (goal-runtime.ts), and the GoalTurnFinishedTransition.windDownTurnId contract (goal-reducer.ts) all stated the pre-fix rule. markTurnDelivered is documented as "Confirms the turn's prompt reached the model", so the reworded contract uses that meaning. All three comments now state the delivered-and-finished rule, matching the code and goal-protocol.ts.

Changes (comment-only, 2 files, +9/−4):

  • packages/core/src/goals/goal-runtime.ts — field doc now says only a wind-down turn that finishes delivered stamps the record, one finished under someone else's text leaves the hand-off owed; budget-gate comment now lists the third owed state (granted, finished, but undelivered).
  • packages/core/src/goals/goal-reducer.tswindDownTurnId transition contract now requires the finishing turn to have been delivered to the model.

No mutation probe: this round adds no guard, branch, or behavior — comments only. No deferred findings, no escalations.

Verification

  • npm run build — passed (exit 0)
  • npm run typecheck — passed (exit 0)
  • npm run lint — passed (exit 0; touched files also checked individually with eslint)
  • npx prettier --check on the two touched files — passed
  • Focused Vitest in packages/core: npx vitest run src/goals/goal-runtime.test.ts src/goals/goal-reducer.test.ts — 2 test files, 239 tests passed
  • No settings source touched, so npm run generate:settings-schema was not needed; the touched behavior is covered by unit tests, so no bundled-CLI integration run was needed.
中文说明

处理评审总结 — PR #10260(第 2 轮)

反馈点

  • [rc:3870463568](自动审查器,建议)— 本 PR 将收尾盖章规则收紧为 finishedWindDown = heldWindDown && delivered,但仍有三处注释沿用旧的「结束即盖章」规则,与已经记载送达规则的 goal-protocol.ts 自相矛盾。

决定:已实现。 编辑前逐一核实了三处被引用的位置:goal-runtime.ts 中内存字段 windDownTurnId 的文档、goal-runtime.ts 中预算耗尽闸门的注释、以及 goal-reducer.tsGoalTurnFinishedTransition.windDownTurnId 的契约,三者均陈述修复前的旧规则。markTurnDelivered 的文档语义是「确认该轮的 prompt 已送达模型」,改写后的契约即采用该含义。三处注释现在都表述「已送达且结束」规则,与代码及 goal-protocol.ts 一致。

改动(仅注释,2 个文件,+9/−4):

  • packages/core/src/goals/goal-runtime.ts — 字段文档现说明:只有「已送达且结束」的收尾轮才会盖章;在他人文本之下结束的收尾轮使交接仍然欠付。预算闸门注释现补上第三种欠付状态(已授予、已结束、但未送达)。
  • packages/core/src/goals/goal-reducer.tswindDownTurnId transition 契约现要求结束轮必须已送达模型。

无需变异探针:本轮未新增任何守卫、分支或行为——仅注释改动。无延迟处理的发现,无升级给维护者的问题。

验证

  • npm run build — 通过(exit 0)
  • npm run typecheck — 通过(exit 0)
  • npm run lint — 通过(exit 0;两个改动文件也单独用 eslint 检查过)
  • 对两个改动文件执行 npx prettier --check — 通过
  • packages/core 中聚焦 Vitest:npx vitest run src/goals/goal-runtime.test.ts src/goals/goal-reducer.test.ts — 2 个测试文件、239 个测试全部通过
  • 未改动 settings 源,因此无需运行 npm run generate:settings-schema;改动行为已有单元测试覆盖,因此无需打包后的 CLI 集成测试。

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

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


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

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

No blocking issues. LGTM! ✅

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

  • packages/core/src/goals/goal-runtime.ts:1534 — [probe] the heldWindDown && stamp guard has no witness test — the finishedWindDown = delivered mutation survives the whole suite
中文说明

无阻断问题。LGTM!✅

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

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

@qqqys
qqqys added this pull request to the merge queue Aug 28, 2026
Merged via the queue into QwenLM:main with commit 85399d7 Aug 28, 2026
58 checks passed
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.

fix(goal): the wind-down hand-off is stamped delivered by any turn that holds its permit

4 participants