Skip to content

feat(corecmd): declarative Wait capability (Contract.Wait + framework wait phase) - #1018

Open
typefield wants to merge 26 commits into
DingTalk-Real-AI:mainfrom
typefield:feat/wait-framework
Open

feat(corecmd): declarative Wait capability (Contract.Wait + framework wait phase)#1018
typefield wants to merge 26 commits into
DingTalk-Real-AI:mainfrom
typefield:feat/wait-framework

Conversation

@typefield

@typefield typefield commented Aug 15, 2026

Copy link
Copy Markdown
Collaborator

What

Framework-only PR: adds the reviewed terminal-state wait capability (Contract.Wait), mirroring the established DryRunSpec pattern end to end. Updated after review 4942891040: poll-only mode, ResultInvoke-only pairing, deadline-safe wait loop. No business command declares it yet — approval/export/batch adoption lands separately.

Solves the agent pattern where every async command (approval flows, exports, batch jobs) forces the agent to hand-roll a poll loop: expensive in tokens, blind on exit semantics, and inconsistent across products.

Design (one paragraph)

A command declares contract.WaitSpec (mode poll — the only implemented mode today, event/auto fail validation until they ship with their own execution path; poll_command, status_query, explicit terminal status→success/failure map, pending_values, reviewed default_timeout_secs). Declaration, the runtime WaitPoll hook, and the ResultInvoke dispatcher are paired at construction (any mismatch panics — same philosophy as validateDispatchDecl; legacy Invoke/Orchestrate/RunE paths cannot declare wait because their emitted output cannot be closed into the terminal envelope). Declared leaves register --wait / --wait-timeout natively on Cobra (never FlagSpec, so they can never leak into MCP toolArgs); undeclared leaves reject the flags as unknown-flag instead of silently ignoring them. After a successful dispatch, the framework wait phase polls through the leaf hook: immediate first poll, ×1.5 backoff capped at 30s, fail-closed on unknown status (a status neither terminal nor pending is an error, not a "not yet").

Envelope / exit-code semantics

The wait phase runs after a successful ResultInvoke dispatch and closes the accepted unified envelope exactly once. Deadline exhaustion anywhere (before a poll, during a context-aware poll, or between polls) closes as timed-out pending, never as a poll failure:

Wait result Envelope Exit code
terminal success outcome: success 0
terminal failure outcome: failure + new wire-stable error.type: "wait", subtype: "terminal_failure" 8 (new dedicated code, additive like partial_failure=7)
timeout outcome: pending, meta.operation.timed_out: true + last observed state, preserving declared id/next_command resume facts 0 (per §4: 异步受理不是失败)

Wire-format additions are additive only: new optional catalog key wait (omitempty — no declaring command ⇒ byte-identical wire, verified below), new error.type "wait" + exit code 8 documented in internal/errors code-table comment and RFC §5.0.

Files

  • internal/corecmd/contract/types.goWaitSpec + closed-set Validate
  • internal/corecmd/contract_decl.go / contract/final.go / contractfinal/store.go — declaration → Final payload (deep-copies terminal map)
  • internal/corecmd/corecmd.goSpec.WaitPoll, construction pairing, flag registration, wait phase across all managed dispatch paths, Ctx.Wait()
  • internal/wait/ — engine: poll cadence, dotted status extraction, outcome mapping (DTO-only dep on contract)
  • internal/cli/*wait projected through ToolSpec / snapshot wire / compact+optional whitelists
  • internal/output/*WithOutcome / WithErrorInfo / WithOperationTimedOut; invariants I2/I3 and pending-requires-operation preserved
  • .changes/wait-framework-capability.md — release fragment

Verification

  • DWS_PACKAGE_VERSION=0.0.0-test go test ./... — green
  • Changed-code coverage: 100% (verified locally with the CI -coverpkg cross-package recipe: ALL CHANGED LINES COVERED)
  • ./scripts/policy/check-generated-drift.sh — ok (assembly deterministic, registry/source hashes stable)
  • ./scripts/policy/check-schema-catalog.sh — ok (27 products, 1121 tools, wire unchanged)
  • New tests: contract validation (accept/reject shapes), wait engine (terminal/poll-until/timeout/unknown/poller-error), corecmd pipeline (flag registration, unknown-flag rejection, declaration⇄hook panics, ResultInvoke envelope close incl. exit-code 8 and timed-out pending)

…phase)

Framework-only: adds the reviewed wait contract mirroring the DryRunSpec
pattern (types declaration -> ContractDecl -> ContractFinal -> ToolSpec ->
Schema wait key). No business command declares it yet.

- contract.WaitSpec (mode poll/event/auto, poll_command, status_query,
  terminal status->success/failure map, pending_values, event_key,
  match_field, default_timeout_secs) with closed-set Validate
- Spec.WaitPoll hook pairs with the declaration at construction time
  (declared without hook / hook without declaration both panic)
- declared leaves register --wait / --wait-timeout natively (never
  FlagSpec, so they cannot enter MCP toolArgs); undeclared leaves reject
  the flags as unknown instead of ignoring them
- internal/wait engine: immediate-first-poll, x1.5 backoff capped 30s,
  dotted status extraction, fail-closed on unknown status, timeout ->
  pending
- ResultInvoke path closes the unified envelope: success terminal ->
  success, failure terminal -> failure with new wire-stable
  error.type "wait" (exit code 8, additive like partial=7), timeout ->
  pending + meta.operation.timed_out with last observed state (exit 0)
- output.WithOutcome / WithErrorInfo / WithOperationTimedOut preserve
  envelope invariants (I2/I3, pending requires meta.operation)

Verified: go test ./... green; check-generated-drift.sh ok (schema
assembly deterministic, wire unchanged); check-schema-catalog.sh ok
(27 products, 1121 tools).
@github-actions
github-actions Bot enabled auto-merge August 15, 2026 04:42

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

开源 DWS Codex 自动 CR:不通过,存在代码冲突

feat(corecmd): declarative Wait capability (Contract.Wait + framework wait phase)

  • 评审 SHA:b49bc0ed1403cdd10ad9c9a26e7acf093cb7fb1f
  • CI 状态:未通过(26 通过,4 跳过,1 未通过)
  • 冲突状态:有冲突
  • Agent 测试报告:不涉及
  • 指令 CI 集成测试:不涉及
  • 自动 CR 结论:不通过,存在代码冲突
  • 代码评审结论:不通过,需修复

变更总结

本次改动新增 Wait 契约、Schema 投影、轮询引擎以及统一结果的终态转换,整体分层清晰,但当前实现存在三项阻塞性语义缺陷:event/auto 模式没有对应执行路径,超时可能被误报为轮询失败,非统一结果命令的失败终态仍以成功退出。由于这些行为与公开的 Wait 契约和变更说明直接冲突,当前版本不应合并。未执行测试或仓库代码,结论仅基于静态审查。

CI 单测结果

结论说明

Codex 静态审查发现 P0/P1 阻断问题,需要修复后提交新 commit 重新 CR。

代码问题

  1. [P1 | 必须修改] event 和 auto 模式被公开但运行时始终执行轮询internal/corecmd/corecmd.go:608

    • 说明:WaitSpec 接受 eventauto,其中纯 event 模式甚至不要求 status_query,但 runDeclaredWaitPhase 无条件调用 wait.RunWaitPoll,随后按 StatusQuery 提取状态;没有事件订阅、事件优先或回退逻辑。因此合法的 event 声明会因空查询立即失败,auto 也不会按契约优先使用事件。应在完整实现这些模式前只允许 poll,或为不同模式增加对应执行钩子和回退测试。
  2. [P1 | 必须修改] 等待超时可能返回轮询错误而不是 pendinginternal/wait/wait.go:127

    • 说明:超时检查只发生在一次成功轮询之后,而等待间隔使用不感知 context 的 time.Sleep。如果 deadline 在睡眠期间到达,循环仍会以已取消的 context 再调用一次 poller;正常尊重 context 的 poller会返回 context deadline exceeded,最终被包装为失败,而不是契约规定的 pendingtimed_out=true。睡眠应使用 timer/select 监听 ctx.Done(),并在发起每次轮询前处理 deadline。现有测试替换了 sleep,未覆盖真实的这一边界。
  3. [P1 | 必须修改] 非 ResultInvoke 命令观察到失败终态仍以成功退出internal/corecmd/corecmd.go:638

    • 说明:框架允许 RunE、Orchestrate 和 Invoke 命令声明 Wait,但这些路径把 nil result 传入等待阶段。即使终态映射为 failure,函数也只向 stderr 打印摘要并返回 nil,因此进程退出码仍为 0,且原有输出无法反映最终失败;这与公开说明中失败终态应生成 error.type=wait、退出码 8 的契约不一致。应限制 Wait 只能搭配可重写统一信封的 ResultInvoke,或为旧路径返回能稳定映射到退出码 8 的类型化错误并明确输出契约,同时补充失败终态测试。

此结论已作为 GitHub CHANGES_REQUESTED 提交;不会自动合并。

@wxianfeng

Copy link
Copy Markdown
Collaborator

开源 DWS Codex 自动 CR:不通过,存在代码冲突

feat(corecmd): declarative Wait capability (Contract.Wait + framework wait phase)

  • 评审 SHA:b49bc0ed1403cdd10ad9c9a26e7acf093cb7fb1f
  • CI 状态:未通过(26 通过,4 跳过,1 未通过)
  • 冲突状态:有冲突
  • Agent 测试报告:不涉及
  • 指令 CI 集成测试:不涉及
  • 自动 CR 结论:不通过,存在代码冲突
  • 代码评审结论:不通过,需修复

变更总结

本次改动新增 Wait 契约、Schema 投影、轮询引擎以及统一结果的终态转换,整体分层清晰,但当前实现存在三项阻塞性语义缺陷:event/auto 模式没有对应执行路径,超时可能被误报为轮询失败,非统一结果命令的失败终态仍以成功退出。由于这些行为与公开的 Wait 契约和变更说明直接冲突,当前版本不应合并。未执行测试或仓库代码,结论仅基于静态审查。

CI 单测结果

结论说明

Codex 静态审查发现 P0/P1 阻断问题,需要修复后提交新 commit 重新 CR。

代码问题

  1. [P1 | 必须修改] event 和 auto 模式被公开但运行时始终执行轮询internal/corecmd/corecmd.go:608

    • 说明:WaitSpec 接受 eventauto,其中纯 event 模式甚至不要求 status_query,但 runDeclaredWaitPhase 无条件调用 wait.RunWaitPoll,随后按 StatusQuery 提取状态;没有事件订阅、事件优先或回退逻辑。因此合法的 event 声明会因空查询立即失败,auto 也不会按契约优先使用事件。应在完整实现这些模式前只允许 poll,或为不同模式增加对应执行钩子和回退测试。
  2. [P1 | 必须修改] 等待超时可能返回轮询错误而不是 pendinginternal/wait/wait.go:127

    • 说明:超时检查只发生在一次成功轮询之后,而等待间隔使用不感知 context 的 time.Sleep。如果 deadline 在睡眠期间到达,循环仍会以已取消的 context 再调用一次 poller;正常尊重 context 的 poller会返回 context deadline exceeded,最终被包装为失败,而不是契约规定的 pendingtimed_out=true。睡眠应使用 timer/select 监听 ctx.Done(),并在发起每次轮询前处理 deadline。现有测试替换了 sleep,未覆盖真实的这一边界。
  3. [P1 | 必须修改] 非 ResultInvoke 命令观察到失败终态仍以成功退出internal/corecmd/corecmd.go:638

    • 说明:框架允许 RunE、Orchestrate 和 Invoke 命令声明 Wait,但这些路径把 nil result 传入等待阶段。即使终态映射为 failure,函数也只向 stderr 打印摘要并返回 nil,因此进程退出码仍为 0,且原有输出无法反映最终失败;这与公开说明中失败终态应生成 error.type=wait、退出码 8 的契约不一致。应限制 Wait 只能搭配可重写统一信封的 ResultInvoke,或为旧路径返回能稳定映射到退出码 8 的类型化错误并明确输出契约,同时补充失败终态测试。

此结论已作为 GitHub CHANGES_REQUESTED 提交;不会自动合并。

@typefield
typefield marked this pull request as draft August 15, 2026 09:57
auto-merge was automatically disabled August 15, 2026 09:57

Pull request was converted to draft

玉澜 added 3 commits August 15, 2026 17:59
…tInvoke pairing

Addresses the three P1 findings from review 4942891040:

1. event/auto modes were declared but always executed polls. WaitSpec now
   accepts poll only (event/auto fail validation with a not-implemented
   message); event_key/match_field dead fields removed. Event waiting will
   land with its own execution path and mode constant.
2. a deadline reached during the between-poll sleep re-polled with a
   cancelled context, so a context-aware poller surfaced its error as a poll
   failure instead of the contracted timed-out pending. The wait between
   polls now uses a timer + select on ctx.Done(), the deadline is checked
   before each poll, and a poll error on a cancelled context closes as
   timed-out pending with the last observed status.
3. legacy Invoke/Orchestrate/RunE commands declaring Wait observed a failure
   terminal while still exiting 0. validateWaitDecl now requires the
   ResultInvoke dispatcher (the only path whose unified envelope can be
   closed); the wait phase no longer wraps legacy paths.

Also: dropped the unreachable nonPendingTerminal branch, simplified
waitTimeoutSecs to the flag value (registration always seeds the reviewed
default), and raised changed-code coverage to 100% (new wait-engine edge
tests, output With* unit tests, contractfinal deep-copy coverage,
AttachContract invalid-Wait panic path).
@typefield

Copy link
Copy Markdown
Collaborator Author

感谢 review,三个 P1 已在 4f57967c(冲突解决)+ c68207ad + 64ad5f22 修复,并补齐改动行覆盖率至 100%(本地按 CI 同款 -coverpkg 跨包口径核验:ALL CHANGED LINES COVERED)。

1. event/auto 模式公开但运行时始终轮询 —— 采纳"实现前只允许 poll":WaitSpec.Validate 现在只接受 mode: "poll",声明 event/auto 直接报 not implemented;同时删除了失去意义的 event_key / match_field 死字段。事件驱动等待将随其自身执行路径与 mode 常量一起引入。新增拒绝用例:event mode not implemented / auto mode not implemented

2. 超时可能被误报为轮询失败 —— 等待间隔改为 timer + select ctx.Done()(不再用不感知 context 的 sleep),每次轮询前先检查 deadline,且 poller 返回错误时若 ctx.Err() != nil 一律按 timed-out pending 关闭(保留最后观测状态)。新增三个边界用例:deadline 落在两次轮询之间、deadline 落在轮询中(context-aware poller 返回 ctx.Err())、context 在首次轮询前已取消(attempts=0)。

3. 非 ResultInvoke 命令失败终态仍 exit 0 —— 采纳"限制搭配":validateWaitDecl 现在要求声明 Wait 的命令必须使用 ResultInvoke dispatcher(构造期 panic),Invoke/Orchestrate/RunE 路径不再挂 wait 阶段(信封无法重写的路径从"可声明但行为错误"变为"不可声明")。失败终态仅经统一信封产出 error.type: "wait" + 退出码 8,新增用例断言 StoredExitCode == 8 且 stdout 含 "type": "wait"

另按 CR 精神清理了两处死代码(不可达的 nonPendingTerminal 分支、waitTimeoutSecs 不可达的声明默认回退——flag 注册时已固化评审默认值),并同步更新了 release fragment 与 RFC §5.0 行(poll-only、ResultInvoke 搭配、三方配对校验)。

Completes the wait capability per review guidance ("add corresponding
execution hooks and fallback tests for the modes"):

- contract.WaitSpec restores event/auto modes with event_key,
  match_field, and a new resource_query (dotted path into the accepted
  result data yielding the identifier events correlate against);
  per-mode validation of required fields
- internal/wait adds EventStream (leaf-owned transport) and RunEvent:
  correlated-event filtering, the same terminal/pending/unknown mapping
  as polling, timed-out pending on deadline during consumption, and an
  ErrEventStreamEnded sentinel distinguishing stream termination from
  fail-closed status errors
- Spec.WaitEvents hook; validateWaitDecl pairs mode with hooks
  (poll<->WaitPoll, event<->WaitEvents, auto<->both; surplus hooks
  rejected too)
- the wait phase runs event-first in auto mode and falls back to polling
  when the stream ends or the subscription fails, under one deadline
  spanning both phases; strict event mode surfaces stream errors
- output.CommandResult gains Data() (deep copy) so the framework can
  resolve the resource identifier without exposing mutable state

Changed-code coverage re-verified at 100% (CI cross-package recipe).
@typefield

Copy link
Copy Markdown
Collaborator Author

event / auto 模式已按评审建议补齐实现b7aa6bdd,"为不同模式增加对应执行钩子和回退测试"):

  • event 模式:叶子通过新 Spec.WaitEvents 钩子提供推送流(传输层叶子所有,框架不做 transport 假设);引擎 wait.RunEventmatch_field 与已受理结果的 resource_query 解析值做事件关联,未关联事件忽略,关联事件沿用与轮询完全相同的终态/未知状态映射(未知状态 fail-closed)。流终止返回携带 ErrEventStreamEnded 哨兵的错误,与"关联了但状态非法"这类不可恢复错误区分开。
  • auto 模式:事件优先;流终止或订阅建立失败时回退轮询,一个 deadline 同时覆盖事件与回退轮询两阶段(超时期间无论处于哪个阶段都按 timed-out pending 关闭)。
  • 配对校验升级为按模式poll↔WaitPollevent↔WaitEventsauto↔两者,声明了模式却缺对应 hook、或挂了声明模式用不到的多余 hook,构造期均 panic。
  • 契约层恢复 event_key / match_field 并新增 resource_query(从已受理结果 data 取关联值,如审批实例 ID);output.CommandResult 新增 Data()(深拷贝)供框架解析资源标识,接口含未导出方法故扩展安全。

测试覆盖三种模式的 e2e(事件终态改写信封、auto 流终止回退轮询、auto 订阅失败回退、严格模式流终止报错、资源不可解析拒绝、跨资源事件忽略),改动行覆盖率仍为 100%(CI 同款跨包口径)。全量 go test ./...、check-generated-drift、check-schema-catalog 均通过。

@typefield
typefield marked this pull request as ready for review August 18, 2026 07:34
@github-actions
github-actions Bot requested a review from wxianfeng August 18, 2026 07:34
@github-actions
github-actions Bot enabled auto-merge August 18, 2026 07:34

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

开源 DWS Codex 自动 CR:不通过,需修复

feat(corecmd): declarative Wait capability (Contract.Wait + framework wait phase)

  • 评审 SHA:f118a369b004ac0dedc0cc4fe1ce2dabf4cd776b
  • CI 状态:未通过(29 通过,4 跳过,2 未通过)
  • 冲突状态:无冲突
  • Agent 测试报告:不涉及
  • 指令 CI 集成测试:不涉及
  • 自动 CR 结论:不通过,需修复
  • 代码评审结论:不通过,需修复

变更总结

本次变更新增了声明式等待能力、轮询/事件等待引擎、Schema 投影以及统一结果的终态转换,整体分层和声明校验较完整。但执行路径存在两个阻塞问题:等待阶段会处理非 pending 的初始结果并可能覆盖业务失败;同时等待超时上下文没有传入叶子侧轮询和订阅建立操作,导致 --wait-timeout 无法保证按时返回。受安全边界限制,未执行测试或构建。

CI 单测结果

结论说明

Codex 静态审查发现 P0/P1 阻断问题,需要修复后提交新 commit 重新 CR。

代码问题

  1. [P1 | 必须修改] 仅对 pending 结果启动等待阶段internal/corecmd/corecmd.go:483

    • 说明:这里在 ResultInvoke 返回任意 CommandResult 后都会执行等待阶段,没有检查初始 outcome。若业务调用已经返回 output.Failure--wait 仍会继续轮询,并可能通过 WithOutcome(..., success) 覆盖原始失败;由于原错误信息仍保留,还会形成 success 携带 error 的非法信封,最终把真实业务错误变成框架校验错误。同步 success 也会被无意义地再次等待。应在进入等待循环前要求 outcome 为 pending,对 success/failure/partial 原样返回,并补充初始失败不会调用 WaitPoll/WaitEvents 的测试。
  2. [P1 | 必须修改] 将等待截止上下文传入叶子侧 I/Ointernal/corecmd/corecmd.go:690

    • 说明:runWaitLoop 创建了带 --wait-timeout 截止时间的 loopCtx,但轮询回调丢弃 wait.Run 传入的 context,只调用 spec.WaitPoll(ctx);该 Ctx 内的 Cobra command 仍持有父 context。WaitEvents(ctx) 建立订阅时也使用同一个父 context。因此,只要一次轮询 RPC 或订阅建立阻塞,声明的超时就无法取消它,命令可能在超时后无限挂住;auto 回退中的 pollWithSpec 同样如此。应让等待钩子显式接收 context.Context(或保证其 Ctx.Command().Context()loopCtx),并覆盖阻塞轮询及阻塞订阅建立在超时后返回 pending 的测试。

此结论已作为 GitHub CHANGES_REQUESTED 提交;不会自动合并。

@wxianfeng

Copy link
Copy Markdown
Collaborator

开源 DWS Codex 自动 CR:不通过,需修复

feat(corecmd): declarative Wait capability (Contract.Wait + framework wait phase)

  • 评审 SHA:f118a369b004ac0dedc0cc4fe1ce2dabf4cd776b
  • CI 状态:未通过(29 通过,4 跳过,2 未通过)
  • 冲突状态:无冲突
  • Agent 测试报告:不涉及
  • 指令 CI 集成测试:不涉及
  • 自动 CR 结论:不通过,需修复
  • 代码评审结论:不通过,需修复

变更总结

本次变更新增了声明式等待能力、轮询/事件等待引擎、Schema 投影以及统一结果的终态转换,整体分层和声明校验较完整。但执行路径存在两个阻塞问题:等待阶段会处理非 pending 的初始结果并可能覆盖业务失败;同时等待超时上下文没有传入叶子侧轮询和订阅建立操作,导致 --wait-timeout 无法保证按时返回。受安全边界限制,未执行测试或构建。

CI 单测结果

结论说明

Codex 静态审查发现 P0/P1 阻断问题,需要修复后提交新 commit 重新 CR。

代码问题

  1. [P1 | 必须修改] 仅对 pending 结果启动等待阶段internal/corecmd/corecmd.go:483

    • 说明:这里在 ResultInvoke 返回任意 CommandResult 后都会执行等待阶段,没有检查初始 outcome。若业务调用已经返回 output.Failure--wait 仍会继续轮询,并可能通过 WithOutcome(..., success) 覆盖原始失败;由于原错误信息仍保留,还会形成 success 携带 error 的非法信封,最终把真实业务错误变成框架校验错误。同步 success 也会被无意义地再次等待。应在进入等待循环前要求 outcome 为 pending,对 success/failure/partial 原样返回,并补充初始失败不会调用 WaitPoll/WaitEvents 的测试。
  2. [P1 | 必须修改] 将等待截止上下文传入叶子侧 I/Ointernal/corecmd/corecmd.go:690

    • 说明:runWaitLoop 创建了带 --wait-timeout 截止时间的 loopCtx,但轮询回调丢弃 wait.Run 传入的 context,只调用 spec.WaitPoll(ctx);该 Ctx 内的 Cobra command 仍持有父 context。WaitEvents(ctx) 建立订阅时也使用同一个父 context。因此,只要一次轮询 RPC 或订阅建立阻塞,声明的超时就无法取消它,命令可能在超时后无限挂住;auto 回退中的 pollWithSpec 同样如此。应让等待钩子显式接收 context.Context(或保证其 Ctx.Command().Context()loopCtx),并覆盖阻塞轮询及阻塞订阅建立在超时后返回 pending 的测试。

此结论已作为 GitHub CHANGES_REQUESTED 提交;不会自动合并。

Only a pending ResultInvoke envelope enters the wait phase, so success,
failure, and partial results are returned unchanged. WaitPoll/WaitEvents
now receive the --wait-timeout deadline (and Command().Context() is bound
to the same loop context) so a blocked poll or subscribe cannot hang past
the declared timeout.

Also allowlist the leftover multi drive_tree_list.py orphan that broke CI
after merging main.
@github-actions
github-actions Bot requested a review from wxianfeng August 18, 2026 08:32

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

开源 DWS Codex 自动 CR:不通过,需修复

feat(corecmd): declarative Wait capability (Contract.Wait + framework wait phase)

  • 评审 SHA:c68603fea084bde86ae7127b3b90e4b107c55ac8
  • CI 状态:通过(31 通过,4 跳过)
  • 冲突状态:无冲突
  • Agent 测试报告:不涉及
  • 指令 CI 集成测试:不涉及
  • 自动 CR 结论:不通过,需修复
  • 代码评审结论:不通过,需修复

变更总结

本次变更新增了声明式等待契约、轮询/事件等待引擎、--wait/--wait-timeout 运行阶段,并将等待能力贯通到统一结果信封和 Schema 的完整/紧凑投影;声明与运行钩子的配对、未知状态失败关闭、超时保持 pending、事件模式回退轮询等主要路径设计一致。但超时秒数转换缺少上界校验,极大正整数会溢出为非正 time.Duration,从而意外取消截止时间并导致等待无限持续,这是合并前需要修复的可靠性问题。受审查限制,未执行测试或构建。

CI 单测结果

结论说明

Codex 静态审查发现 P0/P1 阻断问题,需要修复后提交新 commit 重新 CR。

代码问题

  1. [P1 | 必须修改] 防止超大等待秒数溢出后禁用超时internal/corecmd/corecmd.go:653

    • 说明:--wait-timeoutint 直接乘以 time.Second。在 64 位平台传入例如 9223372036854775807 时会溢出成负的 time.Duration;随后 runWaitLoopwait.Run 都只在 timeout > 0 时创建截止时间,因此这个本应有限的等待会变成无期限轮询或事件阻塞。该值能够由 pflag 正常解析,用户输入即可触发。请在转换前限制秒数不超过 math.MaxInt64/int64(time.Second)(并对越界返回 validation 错误),或使用带溢出检查的转换;同时增加极大正值的回归测试。

此结论已作为 GitHub CHANGES_REQUESTED 提交;不会自动合并。

@wxianfeng

Copy link
Copy Markdown
Collaborator

开源 DWS Codex 自动 CR:不通过,需修复

feat(corecmd): declarative Wait capability (Contract.Wait + framework wait phase)

  • 评审 SHA:c68603fea084bde86ae7127b3b90e4b107c55ac8
  • CI 状态:通过(31 通过,4 跳过)
  • 冲突状态:无冲突
  • Agent 测试报告:不涉及
  • 指令 CI 集成测试:不涉及
  • 自动 CR 结论:不通过,需修复
  • 代码评审结论:不通过,需修复

变更总结

本次变更新增了声明式等待契约、轮询/事件等待引擎、--wait/--wait-timeout 运行阶段,并将等待能力贯通到统一结果信封和 Schema 的完整/紧凑投影;声明与运行钩子的配对、未知状态失败关闭、超时保持 pending、事件模式回退轮询等主要路径设计一致。但超时秒数转换缺少上界校验,极大正整数会溢出为非正 time.Duration,从而意外取消截止时间并导致等待无限持续,这是合并前需要修复的可靠性问题。受审查限制,未执行测试或构建。

CI 单测结果

结论说明

Codex 静态审查发现 P0/P1 阻断问题,需要修复后提交新 commit 重新 CR。

代码问题

  1. [P1 | 必须修改] 防止超大等待秒数溢出后禁用超时internal/corecmd/corecmd.go:653

    • 说明:--wait-timeoutint 直接乘以 time.Second。在 64 位平台传入例如 9223372036854775807 时会溢出成负的 time.Duration;随后 runWaitLoopwait.Run 都只在 timeout > 0 时创建截止时间,因此这个本应有限的等待会变成无期限轮询或事件阻塞。该值能够由 pflag 正常解析,用户输入即可触发。请在转换前限制秒数不超过 math.MaxInt64/int64(time.Second)(并对越界返回 validation 错误),或使用带溢出检查的转换;同时增加极大正值的回归测试。

此结论已作为 GitHub CHANGES_REQUESTED 提交;不会自动合并。

int(secs)*time.Second can wrap a pflag-legal MaxInt64 into a non-positive
duration, which skipped the wait deadline and waited forever. Convert with
an overflow check and return a validation error instead.
@github-actions
github-actions Bot requested a review from wxianfeng August 18, 2026 08:59

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

开源 DWS Codex 自动 CR:不通过,需修复

feat(corecmd): declarative Wait capability (Contract.Wait + framework wait phase)

  • 评审 SHA:e625da4c27508b2a70e6c35dfc5667adbac934fb
  • CI 状态:未通过(30 通过,4 跳过,1 未通过)
  • 冲突状态:无冲突
  • Agent 测试报告:不涉及
  • 指令 CI 集成测试:不涉及
  • 自动 CR 结论:不通过,需修复
  • 代码评审结论:不通过,需修复

变更总结

本次变更新增了声明式等待能力、轮询/事件执行引擎、Schema 投影以及统一结果的等待终态映射;模式与 hook 配对、超时共享及未知状态失败关闭的整体设计较完整。但终态封装没有同步已观察到的 operation 状态,会产生自相矛盾的机器输出,因此当前实现不应合并。受安全限制未执行测试或构建,仅完成静态检查。

CI 单测结果

结论说明

Codex 静态审查发现 P0/P1 阻断问题,需要修复后提交新 commit 重新 CR。

代码问题

  1. [P1 | 必须修改] 等待结束后仍发布受理阶段的 operation 状态internal/corecmd/corecmd.go:653

    • 说明:轮询或事件已经观察到终态后,这里只修改顶层 outcome;只有超时分支会通过 WithOperationTimedOut 更新 meta.operation.state。由于 Pending 结果必须携带异步 operation,成功或失败终态因此会继续保留初始的 processing 等状态,例如同时输出 outcome=success 与 meta.operation.state=processing,失败时也可能保留同样的旧状态。机器消费者无法据此判断真实终态,也违背了等待功能宣称的“关闭到终态”。应在 success/failure 两个分支都用 outcome.Status 更新 operation.state(并明确终态是否还应保留 operation 元数据),并增加最终发射信封的断言。
  2. [P2 | 建议修改] WaitSpec 校验使用裁剪值但运行时保留原始状态值internal/corecmd/contract/types.go:144

    • 说明:Validate 对 PendingValues 使用 TrimSpace 后检查冲突,却没有把裁剪后的值写回;Terminal 的键也只检查裁剪后是否为空。随后运行引擎直接用原始 PendingValues 和 Terminal 建表,因此声明如 pending_values=[" processing "] 或 terminal 键带空格能够通过校验及发布 Schema,却会把后端返回的 "processing" 判为未知状态。应要求状态值已经规范化,或在构造最终 WaitSpec 时深拷贝并统一裁剪,同时检测裁剪后重复项和冲突。

此结论已作为 GitHub CHANGES_REQUESTED 提交;不会自动合并。

@wxianfeng

Copy link
Copy Markdown
Collaborator

开源 DWS Codex 自动 CR:不通过,需修复

feat(corecmd): declarative Wait capability (Contract.Wait + framework wait phase)

  • 评审 SHA:e625da4c27508b2a70e6c35dfc5667adbac934fb
  • CI 状态:未通过(30 通过,4 跳过,1 未通过)
  • 冲突状态:无冲突
  • Agent 测试报告:不涉及
  • 指令 CI 集成测试:不涉及
  • 自动 CR 结论:不通过,需修复
  • 代码评审结论:不通过,需修复

变更总结

本次变更新增了声明式等待能力、轮询/事件执行引擎、Schema 投影以及统一结果的等待终态映射;模式与 hook 配对、超时共享及未知状态失败关闭的整体设计较完整。但终态封装没有同步已观察到的 operation 状态,会产生自相矛盾的机器输出,因此当前实现不应合并。受安全限制未执行测试或构建,仅完成静态检查。

CI 单测结果

结论说明

Codex 静态审查发现 P0/P1 阻断问题,需要修复后提交新 commit 重新 CR。

代码问题

  1. [P1 | 必须修改] 等待结束后仍发布受理阶段的 operation 状态internal/corecmd/corecmd.go:653

    • 说明:轮询或事件已经观察到终态后,这里只修改顶层 outcome;只有超时分支会通过 WithOperationTimedOut 更新 meta.operation.state。由于 Pending 结果必须携带异步 operation,成功或失败终态因此会继续保留初始的 processing 等状态,例如同时输出 outcome=success 与 meta.operation.state=processing,失败时也可能保留同样的旧状态。机器消费者无法据此判断真实终态,也违背了等待功能宣称的“关闭到终态”。应在 success/failure 两个分支都用 outcome.Status 更新 operation.state(并明确终态是否还应保留 operation 元数据),并增加最终发射信封的断言。
  2. [P2 | 建议修改] WaitSpec 校验使用裁剪值但运行时保留原始状态值internal/corecmd/contract/types.go:144

    • 说明:Validate 对 PendingValues 使用 TrimSpace 后检查冲突,却没有把裁剪后的值写回;Terminal 的键也只检查裁剪后是否为空。随后运行引擎直接用原始 PendingValues 和 Terminal 建表,因此声明如 pending_values=[" processing "] 或 terminal 键带空格能够通过校验及发布 Schema,却会把后端返回的 "processing" 判为未知状态。应要求状态值已经规范化,或在构造最终 WaitSpec 时深拷贝并统一裁剪,同时检测裁剪后重复项和冲突。

此结论已作为 GitHub CHANGES_REQUESTED 提交;不会自动合并。

@github-actions
github-actions Bot requested a review from wxianfeng August 19, 2026 03:29

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

开源 DWS Codex 自动 CR:不通过,需修复

feat(corecmd): declarative Wait capability (Contract.Wait + framework wait phase)

  • 评审 SHA:33312531c6f971db30d769c90017bbf5363465aa
  • CI 状态:未通过(27 通过,4 跳过,4 未通过)
  • 冲突状态:无冲突
  • Agent 测试报告:不涉及
  • 指令 CI 集成测试:不涉及
  • 自动 CR 结论:不通过,需修复
  • 代码评审结论:不通过,需修复

变更总结

本次变更新增了统一的 wait 契约、轮询/事件等待引擎、结果终态转换、Schema 投影及较完整的超时和失败测试;主路径 corecmd.New 能校验声明与 hook 配对并仅为支持的命令注册参数。但旁路声明 API AttachContract 仍可发布无法执行的 wait 能力,破坏“声明即运行时能力”的一致性,因此当前不应合并。受安全限制未执行测试。

CI 单测结果

结论说明

Codex 静态审查发现 P0/P1 阻断问题,需要修复后提交新 commit 重新 CR。

代码问题

  1. [P1 | 必须修改] 禁止 AttachContract 发布没有运行时实现的 wait 能力internal/corecmd/corecmd.go:1731

    • 说明:AttachContract 会无条件把 decl.Wait 写入 ContractFinal,随后 Catalog 将其作为正向能力发布;但这个路径既不注册 --wait/--wait-timeout,也没有 WaitPollWaitEvents 或等待阶段可执行。任何通过 Tier2/现有 Cobra 迁移路径附加该契约的命令都会在 Schema 中声称支持 wait,而真实 CLI 对示例返回 unknown flag。应让 wait 只能经 corecmd.New 的完整声明/实现配对发布,或让 AttachContract 明确拒绝非空 Wait,并增加 Schema 到真实 CLI 参数的回归测试。

此结论已作为 GitHub CHANGES_REQUESTED 提交;不会自动合并。

@wxianfeng

Copy link
Copy Markdown
Collaborator

开源 DWS Codex 自动 CR:不通过,需修复

feat(corecmd): declarative Wait capability (Contract.Wait + framework wait phase)

  • 评审 SHA:33312531c6f971db30d769c90017bbf5363465aa
  • CI 状态:未通过(27 通过,4 跳过,4 未通过)
  • 冲突状态:无冲突
  • Agent 测试报告:不涉及
  • 指令 CI 集成测试:不涉及
  • 自动 CR 结论:不通过,需修复
  • 代码评审结论:不通过,需修复

变更总结

本次变更新增了统一的 wait 契约、轮询/事件等待引擎、结果终态转换、Schema 投影及较完整的超时和失败测试;主路径 corecmd.New 能校验声明与 hook 配对并仅为支持的命令注册参数。但旁路声明 API AttachContract 仍可发布无法执行的 wait 能力,破坏“声明即运行时能力”的一致性,因此当前不应合并。受安全限制未执行测试。

CI 单测结果

结论说明

Codex 静态审查发现 P0/P1 阻断问题,需要修复后提交新 commit 重新 CR。

代码问题

  1. [P1 | 必须修改] 禁止 AttachContract 发布没有运行时实现的 wait 能力internal/corecmd/corecmd.go:1731

    • 说明:AttachContract 会无条件把 decl.Wait 写入 ContractFinal,随后 Catalog 将其作为正向能力发布;但这个路径既不注册 --wait/--wait-timeout,也没有 WaitPollWaitEvents 或等待阶段可执行。任何通过 Tier2/现有 Cobra 迁移路径附加该契约的命令都会在 Schema 中声称支持 wait,而真实 CLI 对示例返回 unknown flag。应让 wait 只能经 corecmd.New 的完整声明/实现配对发布,或让 AttachContract 明确拒绝非空 Wait,并增加 Schema 到真实 CLI 参数的回归测试。

此结论已作为 GitHub CHANGES_REQUESTED 提交;不会自动合并。

玉澜 added 3 commits August 20, 2026 08:07
Review 5343447650 (P2): AttachContract wrote any non-empty decl.Wait into
ContractFinal, so Tier2 callers (DeclareLeafMetadata / direct attaches)
could publish a wait capability with no runtime behind it — no
WaitPoll/WaitEvents pairing, no --wait/--wait-timeout registration, no
wait phase — leaving Schema advertising a capability the CLI rejects at
flag parse, while validateWaitDecl only guards the corecmd.New path.

The overlay path now panics on a wait declaration and points authors at
the managed New construction. New keeps publishing wait through the new
unexported attachContractPayload, which only runs after validateWaitDecl
proved the hook pairing and registerWaitFlags bound the flags.
…embly

Review 4969419359 (P1): WaitSpec.Validate only proved poll_command was
non-empty, so a typo, a removed command, or a non-runnable path could
still reach the final Schema while the runtime kept working through the
private WaitPoll hook — the declared manual resume path drifted from the
command tree.

validateWaitPollCommands now runs in assembleSchemaRegistryFromBound,
the one phase that sees the complete bound registry and the final tool
set at once. Each poll/auto wait declaration must resolve (canonical or
CLI path form) to a bound public command that is delivered in the same
Schema and carries a read safety effect. Regression tests cover the
missing, excluded, undelivered, and non-read targets plus the accepted
forms, the event-mode exemption, index error propagation, and the full
production assembly path both accepting a resolved target and rejecting
an unresolvable one.
@github-actions
github-actions Bot requested a review from wxianfeng August 20, 2026 00:56
@typefield

Copy link
Copy Markdown
Collaborator Author

感谢 review,两处意见已在 8c45cad9 + b3a71177(rebase 后为 193f7555 头上的三个提交)修复,本地按 CI 同款口径核验:全量 go test ./... 绿、改动行覆盖率 100%(-coverpkg 跨包口径,逐块核对无未覆盖改动块)、check-schema-catalog.sh(27 products, 1153 tools,wire 不变)与 check-generated-drift.sh 均 ok。

1. [P2] 禁止 AttachContract 发布没有运行时实现的等待能力 —— 采纳"拒绝非空 Wait"方案:AttachContract 现在对携带 Contract.Wait(mode 非空)的声明直接 panic,错误信息指向受管的 corecmd.New 构造路径。原实现保留为未导出的 attachContractPayload,仅供 NewembedContractDecl 调用——该路径在到达此处前,validateWaitDecl 已校验声明⇄hook 配对、registerWaitFlags 已注册 --wait/--wait-timeout、分发管线已挂等待阶段,因此 Tier2(DeclareLeafMetadata/直接 attach)无法再产出"Schema 宣称支持、CLI 拒绝 flag"的漂移。回归测试覆盖:非空 Wait panic、nil cmd panic、无 mode 声明不误伤、受管路径仍发布 wait 能力(ContractFinal.Wait + --wait 注册)。

2. CI 失败(Coverage/Test 8 个 job) —— 根因是 runner 侧 azure.archive.ubuntu.com apt 源不可达:Test (workflow and release contracts)Coverage (current: *) 各 job 都卡死在 sudo apt-get update && sudo apt-get install -y zip unzip(日志里全是 Ign: 重试),15/20 分钟超时后被取消,聚合 job 因此判负;所有真正跑起来的测试 job(race 全分片、Windows、macOS、baseline coverage 等)全部通过。属基础设施抖动而非代码问题,本 push 会触发全新 CI 运行。

另:上一轮 4969419359 的 P1(poll_command 只校验非空、未在组装阶段解析)当时没有对应修复提交,本次一并补上(b3a71177):validateWaitPollCommandsassembleSchemaRegistryFromBound(唯一同时看到完整 bound registry 与最终 tool set 的阶段)运行,poll/auto 声明的 poll_command(canonical 或 CLI path 形式)必须唯一解析到 bound registry 中 public、且在最终 Schema 交付、safety effect 为 read 的命令;不满足即组装失败。回归测试覆盖不存在、被排除(非 public)、未交付、非 read 目标与两种合法形式、event 模式豁免,以及走真实组装路径的接受/拒绝用例。release fragment 同步补充了这两条 fail-closed 保证。

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

开源 DWS Codex 自动 CR:不通过,需修复

feat(corecmd): declarative Wait capability (Contract.Wait + framework wait phase)

  • 评审 SHA:193f7555821df6381423e77e635ce216364a8eb7
  • CI 状态:未通过(29 通过,4 跳过,2 未通过)
  • 冲突状态:无冲突
  • Agent 测试报告:不涉及
  • 指令 CI 集成测试:不涉及
  • 自动 CR 结论:不通过,需修复
  • 代码评审结论:不通过,需修复

变更总结

本次变更新增声明驱动的 --wait/--wait-timeout 能力,包括轮询、事件订阅、auto 回退、Schema 投影及统一结果封装;声明归一化、轮询命令可见性校验和终态输出映射整体一致。但等待引擎把调用方取消与自身超时混为一谈,会破坏 Ctrl-C 等中断语义。受审查约束限制,未执行测试或构建。

CI 单测结果

结论说明

Codex 静态审查发现 P0/P1 阻断问题,需要修复后提交新 commit 重新 CR。

代码问题

  1. [P1 | 必须修改] 不要把调用方取消伪装成等待超时成功internal/wait/wait.go:94

    • 说明:Run 在任何 ctx.Err() 情况下都返回 TimedOut:true 且无错误,RunEvent 也采用相同逻辑;而传入的 context 同时继承命令根 context,所以用户按 Ctrl-C、上层主动取消或父级截止时间到期时,也会被 runDeclaredWaitPhase 包装成 outcome=pendingtimed_out=true 并以退出码 0 返回。这既谎报为 --wait-timeout,也丢失仓库已有的 SIGINT=130/取消错误语义。应区分等待阶段自己创建的超时与父 context 的取消:只有内部 wait deadline 到期才能生成 pending timeout,父级取消必须向上传播;轮询、订阅以及 auto 回退路径都应补充回归测试。

此结论已作为 GitHub CHANGES_REQUESTED 提交;不会自动合并。

@wxianfeng

Copy link
Copy Markdown
Collaborator

开源 DWS Codex 自动 CR:不通过,需修复

feat(corecmd): declarative Wait capability (Contract.Wait + framework wait phase)

  • 评审 SHA:193f7555821df6381423e77e635ce216364a8eb7
  • CI 状态:未通过(29 通过,4 跳过,2 未通过)
  • 冲突状态:无冲突
  • Agent 测试报告:不涉及
  • 指令 CI 集成测试:不涉及
  • 自动 CR 结论:不通过,需修复
  • 代码评审结论:不通过,需修复

变更总结

本次变更新增声明驱动的 --wait/--wait-timeout 能力,包括轮询、事件订阅、auto 回退、Schema 投影及统一结果封装;声明归一化、轮询命令可见性校验和终态输出映射整体一致。但等待引擎把调用方取消与自身超时混为一谈,会破坏 Ctrl-C 等中断语义。受审查约束限制,未执行测试或构建。

CI 单测结果

结论说明

Codex 静态审查发现 P0/P1 阻断问题,需要修复后提交新 commit 重新 CR。

代码问题

  1. [P1 | 必须修改] 不要把调用方取消伪装成等待超时成功internal/wait/wait.go:94

    • 说明:Run 在任何 ctx.Err() 情况下都返回 TimedOut:true 且无错误,RunEvent 也采用相同逻辑;而传入的 context 同时继承命令根 context,所以用户按 Ctrl-C、上层主动取消或父级截止时间到期时,也会被 runDeclaredWaitPhase 包装成 outcome=pendingtimed_out=true 并以退出码 0 返回。这既谎报为 --wait-timeout,也丢失仓库已有的 SIGINT=130/取消错误语义。应区分等待阶段自己创建的超时与父 context 的取消:只有内部 wait deadline 到期才能生成 pending timeout,父级取消必须向上传播;轮询、订阅以及 auto 回退路径都应补充回归测试。

此结论已作为 GitHub CHANGES_REQUESTED 提交;不会自动合并。

The coverage gate (99.45% changed code) flagged two leftovers from
8802dcf's waitResource refactor plus one branch my overlay split made
unreachable:

- waitResource's slow path marshal error now has a regression case: a
  DTO with a channel field drives json.Marshal to failure and surfaces
  'cannot be serialized to JSON'.
- attachContractPayload no longer re-normalizes Contract.Wait behind an
  error panic that could never fire: New's normalizeWaitDecl already
  canonicalized and validated the declaration in place, AttachContract
  rejects wait declarations outright, and the store deep-copies the
  terminal map. The branch was dead code, not a guard.
@github-actions
github-actions Bot requested a review from wxianfeng August 20, 2026 01:41
@wxianfeng

Copy link
Copy Markdown
Collaborator

开源 DWS Codex 自动 CR:不通过,CI 未通过

feat(corecmd): declarative Wait capability (Contract.Wait + framework wait phase)

  • 评审 SHA:0bee19186216e56f8e1014fcadfefca3a739bcb4
  • CI 状态:未通过(30 通过,4 跳过,1 未通过)
  • 冲突状态:无冲突
  • Agent 测试报告:不涉及
  • 指令 CI 集成测试:不涉及
  • 自动 CR 结论:不通过,CI 未通过
  • 代码评审结论:通过

变更总结

该 PR 新增了声明式 wait 能力,贯通 Contract、Schema、轮询/事件引擎和统一输出,并对终态映射、事件关联、轮询命令可见性及只读属性做了较完整的闭合校验。但 --wait-timeout 对显式非法值静默回退,导致用户输入未按预期生效,可能把本应立即拒绝的调用变成长时间等待。受安全边界限制,本次仅进行了静态检查,未执行测试。

CI 单测结果

结论说明

自动 CR 不通过,原因如下:

  • CI 单测存在失败、取消或超时

代码问题

  1. [P2 | 建议修改] 显式的非正等待超时被静默替换为 300 秒internal/corecmd/corecmd.go:790

    • 说明:waitTimeoutSecs 仅在 flag 值大于 0 时采用用户输入,否则直接返回框架默认值。因此 --wait-timeout=0--wait-timeout=-1 都不会报参数错误,而会实际等待 300 秒;随后 waitTimeoutDuration 也无法区分这是显式输入还是缺省值。对自动化调用而言,这会把配置错误变成意外的长时间阻塞,并且与溢出值会被明确判为 validation error 的行为不一致。建议保留声明默认值只作为 Cobra 的缺省值,对解析后的显式非正值返回 validation error,并增加 0、负数以及未显式传参三种覆盖。

自动 CR 结论为不通过;未提交 GitHub Review,也不会自动合并。

玉澜 added 2 commits August 20, 2026 09:55
The Policy job's merge-revision sanity check compares the event's
pull_request.base.sha with the first parent of refs/pull/N/merge.
Upstream main advanced between event delivery and the merge-ref rebuild
(d1f1ab7 vs 5aaf2ef), so the check failed on infrastructure timing
with every other job green. A fresh synchronize event realigns both.
@wxianfeng

Copy link
Copy Markdown
Collaborator

开源 DWS Codex 自动 CR:不通过,CI 未通过

feat(corecmd): declarative Wait capability (Contract.Wait + framework wait phase)

  • 评审 SHA:b9145b8d2dfa43bd48c53381959791a350aa5828
  • CI 状态:未通过(30 通过,4 跳过,1 未通过)
  • 冲突状态:无冲突
  • Agent 测试报告:不涉及
  • 指令 CI 集成测试:不涉及
  • 自动 CR 结论:不通过,CI 未通过
  • 代码评审结论:通过

变更总结

本次变更新增声明式等待能力,包括 poll/event/auto 三种模式、统一结果终态转换、超时取消、Schema 投影及跨命令轮询目标校验;运行时声明与 hook 配对、未知状态失败关闭、失败终态专用退出码和主要超时路径均有针对性测试。发现一处非阻塞的 Schema 可维护性缺口:新增 wait 字段未纳入字段级 provenance 不变量。受审查限制未执行测试或构建,仅完成静态检查。

CI 单测结果

结论说明

自动 CR 不通过,原因如下:

  • CI 单测存在失败、取消或超时

代码问题

  1. [P2 | 建议修改] 将 wait 纳入最终字段的 provenance 校验internal/cli/schema_runtime_registry.go:414

    • 说明:这里把 final.Wait 直接交付到 ToolSpec,随后会序列化进完整和 compact Schema,但 contractFinalProvenance 没有为 wait 生成 winner,ToolSpec.provenanceValuevalidateFinalSchemaProvenanceCoverage 也未要求该字段。这样 wait 的模式、终态映射或超时默认值即使与声明来源发生漂移,现有“最终值必须等于 provenance winner”的硬性不变量也不会发现;这与同样作为原子能力的 dry_run 处理不一致。建议为整个 wait 对象记录 contract_final provenance,并在值相等校验和覆盖门禁中将非空 wait 设为必检字段。

自动 CR 结论为不通过;未提交 GitHub Review,也不会自动合并。

@typefield

Copy link
Copy Markdown
Collaborator Author

跟进:0bee1918 + 513337fc 后 CI 全绿(run 32323936630,31 个 job 无失败,Policy/Coverage/Test 均通过)。

本轮补齐了 coverage 门禁上一处真实缺口(changed code 99.45% → 100%):waitResource 慢路径的 json.Marshal 失败分支此前无用例(新增含 channel 字段 DTO 的回归用例);attachContractPayload 里对 Contract.Wait 的二次 Normalize panic 在 overlay 拒绝后已不可达(New 路径已就地规范化),按 fail-closed 审查精神移除该死分支。本地按 CI 口径(base d1f1ab72-coverpkg 跨包聚合)逐块核对:无未覆盖改动块。

另说明两次非代码 CI 失败的处理:上一轮 Coverage/Test 取消是 runner apt 源(azure.archive.ubuntu.com)不可达导致 zip/unzip 安装卡死超时;Policy 的 "merge first parent does not match event base" 是 event base.sha 固定在上次分支合并 main 的 tip、而 pull/N/merge 按最新 main 重建——把 main 重新合入分支(513337fc,同上次 33312531 的做法)刷新 base.sha 后即恢复。

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

开源 DWS Codex 自动 CR:不通过,需修复

feat(corecmd): declarative Wait capability (Contract.Wait + framework wait phase)

  • 评审 SHA:513337fcf9ae9d8b55bb3aca29a387eac2236d77
  • CI 状态:通过(31 通过,4 跳过)
  • 冲突状态:无冲突
  • Agent 测试报告:不涉及
  • 指令 CI 集成测试:不涉及
  • 自动 CR 结论:不通过,需修复
  • 代码评审结论:不通过,需修复

变更总结

本次变更新增了声明式 wait 能力,包括 poll/event/auto 等待模式、Schema 投影、统一结果终态转换及专用退出码;声明、运行时与 Catalog 的大部分约束保持一致,且覆盖了超时、未知状态、事件回退和终态封装。静态审阅发现事件订阅存在一个未封闭的 nil 返回边界,可导致用户命令直接 panic;未执行测试或构建。

CI 单测结果

结论说明

Codex 静态审查发现 P0/P1 阻断问题,需要修复后提交新 commit 重新 CR。

代码问题

  1. [P1 | 必须修改] 事件订阅返回 nil stream 会触发运行时 panicinternal/corecmd/corecmd.go:741

    • 说明:WaitEvents 的返回值只检查了 err,没有验证 stream 非空;随后无条件传给 wait.RunEvent,后者会调用 stream.Recv。只要叶子实现或订阅适配器在无错误时意外返回 (nil, nil),执行 --wait 就会因 nil 接口调用而崩溃,而不是通过统一错误信封失败;auto 模式也无法按设计回退到 polling。请在调用 RunEvent 前拒绝 nil stream(严格 event 模式返回明确错误,auto 模式可按订阅失败规则回退),并补充 event/auto 两种模式的回归测试。

此结论已作为 GitHub CHANGES_REQUESTED 提交;不会自动合并。

@wxianfeng

Copy link
Copy Markdown
Collaborator

开源 DWS Codex 自动 CR:不通过,需修复

feat(corecmd): declarative Wait capability (Contract.Wait + framework wait phase)

  • 评审 SHA:513337fcf9ae9d8b55bb3aca29a387eac2236d77
  • CI 状态:通过(31 通过,4 跳过)
  • 冲突状态:无冲突
  • Agent 测试报告:不涉及
  • 指令 CI 集成测试:不涉及
  • 自动 CR 结论:不通过,需修复
  • 代码评审结论:不通过,需修复

变更总结

本次变更新增了声明式 wait 能力,包括 poll/event/auto 等待模式、Schema 投影、统一结果终态转换及专用退出码;声明、运行时与 Catalog 的大部分约束保持一致,且覆盖了超时、未知状态、事件回退和终态封装。静态审阅发现事件订阅存在一个未封闭的 nil 返回边界,可导致用户命令直接 panic;未执行测试或构建。

CI 单测结果

结论说明

Codex 静态审查发现 P0/P1 阻断问题,需要修复后提交新 commit 重新 CR。

代码问题

  1. [P1 | 必须修改] 事件订阅返回 nil stream 会触发运行时 panicinternal/corecmd/corecmd.go:741

    • 说明:WaitEvents 的返回值只检查了 err,没有验证 stream 非空;随后无条件传给 wait.RunEvent,后者会调用 stream.Recv。只要叶子实现或订阅适配器在无错误时意外返回 (nil, nil),执行 --wait 就会因 nil 接口调用而崩溃,而不是通过统一错误信封失败;auto 模式也无法按设计回退到 polling。请在调用 RunEvent 前拒绝 nil stream(严格 event 模式返回明确错误,auto 模式可按订阅失败规则回退),并补充 event/auto 两种模式的回归测试。

此结论已作为 GitHub CHANGES_REQUESTED 提交;不会自动合并。

WaitEvents' return was only checked for err, so a leaf or subscription
adapter returning (nil, nil) reached wait.RunEvent, whose first Recv
panicked on the nil interface — a user-facing crash instead of the
unified error envelope, and auto mode could not fall back to polling as
designed.

runWaitLoop now rejects a nil stream before the event loop: strict event
mode fails through the envelope with 'event subscription failed:
subscription returned no stream'; auto mode falls back to polling under
the subscription-failure rule (a deadline that already expired during
subscribe still closes as timed-out pending with no fallback, preserving
the shared-deadline contract). Regression tests cover both modes.
@typefield

Copy link
Copy Markdown
Collaborator Author

本轮 P1 已在 5f1f13cd 修复:runWaitLoop 在进入事件循环前显式拒绝 nil stream——WaitEvents 返回 (nil, nil) 时,严格 event 模式经统一错误信封返回 event subscription failed: subscription returned no stream(不再进入 RunEvent 的首个 Recv 触发 nil 接口 panic);auto 模式按订阅失败规则在同一 deadline 下回退 polling(若 subscribe 期间 deadline 已耗尽仍按超时 pending 关闭、不回退,保持共享 deadline 契约)。回归测试覆盖两种模式:TestEventModeRejectsNilStreamWithoutErrorTestAutoModeFallsBackToPollOnNilStream。本地 internal/corecmd 全量测试绿、改动行覆盖 100%(改动区间无未覆盖块)。

@github-actions
github-actions Bot requested a review from wxianfeng August 20, 2026 09:47

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

开源 DWS Codex 自动 CR:不通过,需修复

feat(corecmd): declarative Wait capability (Contract.Wait + framework wait phase)

  • 评审 SHA:5f1f13cd8959d6398ecd2fea158389a6dce4caa5
  • CI 状态:未通过(30 通过,4 跳过,1 未通过)
  • 冲突状态:无冲突
  • Agent 测试报告:不涉及
  • 指令 CI 集成测试:不涉及
  • 自动 CR 结论:不通过,需修复
  • 代码评审结论:不通过,需修复

变更总结

本次 PR 增加了声明式等待能力,贯通了 Contract、Schema、poll/event/auto 运行期和统一结果信封,并对 poll_command 的可见性与只读属性进行了校验。整体结构一致,但 auto 模式从事件流回退轮询后发生超时时,会丢失事件阶段已观察到的最新状态,违反超时结果必须报告真实最后状态的契约,建议修复后合并。审查仅基于静态 Git diff,未执行测试或构建。

CI 单测结果

结论说明

Codex 静态审查发现 P0/P1 阻断问题,需要修复后提交新 commit 重新 CR。

代码问题

  1. [P1 | 必须修改] auto 回退超时会丢失事件阶段的最后状态internal/corecmd/corecmd.go:722

    • 说明:RunEvent 返回流提前结束错误时,其 Outcome 已包含最后一个相关事件的状态;这里直接调用 pollWithSpec 丢弃了该值。若回退后的首次轮询阻塞直至共享 deadline,wait.Run 会以空 Status 返回超时,随后 WithOperationTimedOut("") 保留最初受理状态(例如 NEW),而不是事件阶段已经观察到的 RUNNING。这会让 meta.operation.state 和超时提示回退到陈旧状态,违反本 PR 所声明的“超时保持最后观察到的真实状态”契约。应在 auto 两阶段之间传递最后状态,并在轮询尚未产生新状态就超时时使用它,同时补充“事件观察到 pending → 流结束 → 回退轮询阻塞超时”的回归测试。

此结论已作为 GitHub CHANGES_REQUESTED 提交;不会自动合并。

@wxianfeng

Copy link
Copy Markdown
Collaborator

开源 DWS Codex 自动 CR:不通过,需修复

feat(corecmd): declarative Wait capability (Contract.Wait + framework wait phase)

  • 评审 SHA:5f1f13cd8959d6398ecd2fea158389a6dce4caa5
  • CI 状态:未通过(30 通过,4 跳过,1 未通过)
  • 冲突状态:无冲突
  • Agent 测试报告:不涉及
  • 指令 CI 集成测试:不涉及
  • 自动 CR 结论:不通过,需修复
  • 代码评审结论:不通过,需修复

变更总结

本次 PR 增加了声明式等待能力,贯通了 Contract、Schema、poll/event/auto 运行期和统一结果信封,并对 poll_command 的可见性与只读属性进行了校验。整体结构一致,但 auto 模式从事件流回退轮询后发生超时时,会丢失事件阶段已观察到的最新状态,违反超时结果必须报告真实最后状态的契约,建议修复后合并。审查仅基于静态 Git diff,未执行测试或构建。

CI 单测结果

结论说明

Codex 静态审查发现 P0/P1 阻断问题,需要修复后提交新 commit 重新 CR。

代码问题

  1. [P1 | 必须修改] auto 回退超时会丢失事件阶段的最后状态internal/corecmd/corecmd.go:722

    • 说明:RunEvent 返回流提前结束错误时,其 Outcome 已包含最后一个相关事件的状态;这里直接调用 pollWithSpec 丢弃了该值。若回退后的首次轮询阻塞直至共享 deadline,wait.Run 会以空 Status 返回超时,随后 WithOperationTimedOut("") 保留最初受理状态(例如 NEW),而不是事件阶段已经观察到的 RUNNING。这会让 meta.operation.state 和超时提示回退到陈旧状态,违反本 PR 所声明的“超时保持最后观察到的真实状态”契约。应在 auto 两阶段之间传递最后状态,并在轮询尚未产生新状态就超时时使用它,同时补充“事件观察到 pending → 流结束 → 回退轮询阻塞超时”的回归测试。

此结论已作为 GitHub CHANGES_REQUESTED 提交;不会自动合并。

玉澜 added 2 commits August 20, 2026 18:22
…k timeout

RunEvent dropped lastStatus from its stream-ended outcome, and the auto
fallback called pollWithSpec without it, so a fallback poll that blocked
until the shared deadline timed out with an empty status: the envelope
kept the accepted result's original state (e.g. NEW) instead of the
state the events had already observed (e.g. RUNNING), violating the
declared 'timeout reports the real last observed state' contract.

RunEvent's ErrEventStreamEnded outcome now carries the last correlated
status, and pollWithSpec adopts it when the poll loop ends without
observing a status of its own (first poll blocked to the deadline). The
subscribe-failure fallback keeps passing empty (nothing was observed).
Regression test: event observes pending RUNNING → stream ends →
fallback poll blocks → timeout envelope reports state RUNNING with
timed_out=true, never regressing to NEW.
@typefield

Copy link
Copy Markdown
Collaborator Author

本轮 P1 已在 69a74106 修复(794e65c3 含 main 同步合并,刷新 base.sha 规避 Policy 的 merge-ref 基准失配)。

问题确实如 review 所述,且比描述多一层:RunEvent 流提前结束的错误返回是 Outcome{Attempts},本身就把 lastStatus 丢了——回退侧即使想带也拿不到。修复分两处:

  • internal/wait/wait.goErrEventStreamEnded 返回的 Outcome 现在携带 Status: lastStatus(最后一个相关事件的状态),与超时路径的语义对齐。
  • internal/corecmd/corecmd.gopollWithSpec 增加 eventStatus 参数——流结束回退时传入事件阶段的最后状态;回退轮询若在首个 poll 完成前就耗尽共享 deadline(阻塞 poll),超时 Outcome 的空 Status 采用该携带值,信封不再回退到受理时的旧状态。轮询自身观察到更新状态时仍以轮询为准;订阅失败回退(未观察到任何事件)依旧传空、保持原状态。

回归测试 TestAutoFallbackTimeoutKeepsEventPhaseLastStatus 覆盖 review 要求的完整链路:事件观察到 pending RUNNING → 流结束 → 回退轮询阻塞至超时 → 信封输出 outcome: pending + state: "RUNNING" + timed_out: true(断言不出现 "state": "NEW")。本地 internal/corecmd / internal/wait / internal/cli 全绿,改动行覆盖 100%(改动区间无未覆盖块)。

关于本轮 CI 的 Policy 失败:pull/1018/merge 按最新 main 重建、而 event 的 base.sha 停留在上次分支合并 main 的 tip,两者错位所致;5f1f13cd 上的最新运行(32355405874)实际已全绿。

@github-actions
github-actions Bot requested a review from wxianfeng August 20, 2026 10:25
@wxianfeng

Copy link
Copy Markdown
Collaborator

开源 DWS Codex 自动 CR:不通过,CI 未通过

feat(corecmd): declarative Wait capability (Contract.Wait + framework wait phase)

  • 评审 SHA:794e65c377c51ab3f1212a6e4b0d67f637bb1bad
  • CI 状态:未通过(27 通过,4 跳过,4 未通过)
  • 冲突状态:无冲突
  • Agent 测试报告:不涉及
  • 指令 CI 集成测试:不涉及
  • 自动 CR 结论:不通过,CI 未通过
  • 代码评审结论:通过

变更总结

本次变更新增了声明式等待契约、轮询/事件等待引擎、统一结果终态转换、Schema 投影及较完整的框架测试,整体分层和超时失败关闭策略较一致。但等待能力与统一输出 rollout 的构造期约束缺失,可能发布实际无法执行的 --wait 能力,建议修复后合并。受安全限制未执行测试或构建。

CI 单测结果

结论说明

自动 CR 不通过,原因如下:

  • CI 单测存在失败、取消或超时

代码问题

  1. [P2 | 建议修改] 等待能力未要求统一结果 rollout 已激活internal/corecmd/corecmd.go:584

    • 说明:这里仅检查 ResultInvoke != nil,但 ResultInvoke 可以搭配默认、legacy_onlydual_validate rollout。此类命令仍会注册 --wait/--wait-timeout,Schema 也会无条件发布 wait;实际执行却会在调用 ResultInvoke 前被 !output.UsesUnifiedResult(cmd) 拒绝,因此即使不传 --wait,命令也无法执行,发布契约与运行时不一致。请在构造期要求 OutputRollout 为统一输出激活状态,或像 result/pagination 一样按有效 rollout 抑制等待能力及相关 flags,并增加非激活 rollout 的回归测试。

自动 CR 结论为不通过;未提交 GitHub Review,也不会自动合并。

Upstream main carried fully-consumed flag migrations in
approved-flag-migrations-v1.json whose references (stable v1.0.59,
merge-base, and current tree) all already reached the after state, so
the interface migration lifecycle demanded their removal — main's own
interface-integrity gate fails the same way. Dropping them is exactly
what the policy check prescribes; the 4 still-active migrations stay.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants