重构 Direct 交付合同与租约机制 #608

Merged
lhk229 merged 14 commits from contract-lease-refactor into master 2026-10-05 14:19:05 +08:00
Member

当前 Direct 把交付合同作为操作准入条件,并在任意付费/执行失败后进入全局 Draining;一条无关的挂起命令可因此阻断后续代码编辑。本 PR 用于推进 #518、#529 的合同与租约机制重构。

当前仅提交草稿里程碑,运行时代码尚未修改,问题尚未修复。

  • 已确认:普通操作成功或失败后返回真实结果,由 Agent 决定下一步;宿主保留回合活动状态、时间与并发控制,取消全局失败排空及返修批次门禁。
  • 保留既有权限、旧回合写入归属,以及资源操作自身的幂等和不确定结果核对。
  • 待细化:交付合同是否及在哪些产品场景保留、工具与提示词调整、已有配置与账本兼容;实现前同步主规范和单里程碑实现计划。

工作范围:docs/project-memory/plans/【里程碑】Direct合同与租约机制重构-2026-10-03.md。

验证:npm run check:doc-index、npm run check:encoding、git diff --cached --check 通过。本次未运行运行时测试。

关联 #518、#529;当前不关闭问题。

当前 Direct 把交付合同作为操作准入条件,并在任意付费/执行失败后进入全局 Draining;一条无关的挂起命令可因此阻断后续代码编辑。本 PR 用于推进 #518、#529 的合同与租约机制重构。 当前仅提交草稿里程碑,运行时代码尚未修改,问题尚未修复。 - 已确认:普通操作成功或失败后返回真实结果,由 Agent 决定下一步;宿主保留回合活动状态、时间与并发控制,取消全局失败排空及返修批次门禁。 - 保留既有权限、旧回合写入归属,以及资源操作自身的幂等和不确定结果核对。 - 待细化:交付合同是否及在哪些产品场景保留、工具与提示词调整、已有配置与账本兼容;实现前同步主规范和单里程碑实现计划。 工作范围:`docs/project-memory/plans/【里程碑】Direct合同与租约机制重构-2026-10-03.md`。 验证:`npm run check:doc-index`、`npm run check:encoding`、`git diff --cached --check` 通过。本次未运行运行时测试。 关联 #518、#529;当前不关闭问题。
lhk229 added 1 commit 2026-10-03 21:20:59 +08:00
记录 Direct 合同与租约重构方向
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Has been cancelled
bee7ffcc07
新增合同与租约重构草稿里程碑,关联 #518 与 #529
明确操作失败不触发全局排空,保留回合生命周期、时间和并发控制
记录合同方案、持久化兼容与后续验收的待定边界
Author
Member

本次讨论关于租约机制的结论,作为后续实现方向:

  1. 操作跟踪不需要同时承担“持久化租约 + 全局排空 + 交付准入”。Agent 发起操作,收到成功或失败结果,然后继续决定下一步;普通工具失败本身不应让整个回合停止工作。
  2. 宿主在开始调用前检查:回合仍活动、时间预算未耗尽、并发槽可用。保留各工具已有的权限及资源约束;不再以交付合同存在性或返修批次作为普通操作准入条件。
  3. 成功、失败或取消后正确释放并发槽,把真实结果交给 Agent。图片生成失败不应因另一条长命令仍在运行而阻断无关代码编辑;不进入全局 Draining,也不因普通失败消耗宿主定义的返修批次。
  4. 回合结束或时间耗尽后拒绝新调用,取消宿主拥有的在途工作并正确回收本地进程。不能仅删除记录就宣称进程退出;旧回合迟到结果不能取得新回合权限继续写入。
  5. 远端付费操作继续使用各自的 operation ID、幂等和结果核对。客户端停止不证明远端任务取消;不确定请求不能因重试或新回合自动重复提交。这是资源操作自身的生命周期约束,不是阻断整轮无关工作的理由。
  6. 不通过增加租约超时、阻塞诊断或“释放租约”工具保留现有全局门禁模型;改造重点是简化运行时控制。

合同方面:已识别 artifact/command 强制验收与 Agent 自身读取文件、判断命令结果的重叠。可选合同曾作为方向讨论,但是否保留新游戏等产品场景的强制交付检查、触发时机和工具形态尚未最终确定,需继续细化,不能把当前草稿视为已完成方案。

以上是已确认方向和明确的未决项;当前 PR 只有范围文档,尚未修改运行时实现。

本次讨论关于租约机制的结论,作为后续实现方向: 1. 操作跟踪不需要同时承担“持久化租约 + 全局排空 + 交付准入”。Agent 发起操作,收到成功或失败结果,然后继续决定下一步;普通工具失败本身不应让整个回合停止工作。 2. 宿主在开始调用前检查:回合仍活动、时间预算未耗尽、并发槽可用。保留各工具已有的权限及资源约束;不再以交付合同存在性或返修批次作为普通操作准入条件。 3. 成功、失败或取消后正确释放并发槽,把真实结果交给 Agent。图片生成失败不应因另一条长命令仍在运行而阻断无关代码编辑;不进入全局 Draining,也不因普通失败消耗宿主定义的返修批次。 4. 回合结束或时间耗尽后拒绝新调用,取消宿主拥有的在途工作并正确回收本地进程。不能仅删除记录就宣称进程退出;旧回合迟到结果不能取得新回合权限继续写入。 5. 远端付费操作继续使用各自的 operation ID、幂等和结果核对。客户端停止不证明远端任务取消;不确定请求不能因重试或新回合自动重复提交。这是资源操作自身的生命周期约束,不是阻断整轮无关工作的理由。 6. 不通过增加租约超时、阻塞诊断或“释放租约”工具保留现有全局门禁模型;改造重点是简化运行时控制。 合同方面:已识别 artifact/command 强制验收与 Agent 自身读取文件、判断命令结果的重叠。可选合同曾作为方向讨论,但是否保留新游戏等产品场景的强制交付检查、触发时机和工具形态尚未最终确定,需继续细化,不能把当前草稿视为已完成方案。 以上是已确认方向和明确的未决项;当前 PR 只有范围文档,尚未修改运行时实现。
Author
Member

This PR shall close #518 #529

This PR shall close #518 #529
Author
Member

合同机制的讨论结论更新:

  1. 移除回合一开始就无条件要求登记交付合同、完成游戏交付的提示与前置要求。不能因为当前目录是尚未交付的 Web 游戏脚手架,就自动要求本次用户消息交付游戏。
  2. 改为告诉 Agent:当用户实际要求“制作游戏 / 完整游戏 / 可运行游戏 / 交付游戏”等目标时,才创建交付合同。这里的例子表达用户意图,不是宿主侧固定关键词匹配表;由 Agent 结合当前用户请求和上下文判断。
  3. “什么也不要做”“只生成一张图片,不制作游戏”等请求不能触发游戏交付义务,也不能因缺少游戏合同或游戏验收结果而被迫继续制作游戏。普通文件编辑、命令和资源操作不再依赖无条件合同准入。
  4. 删除合同中的 artifact 文件验收项与 command 命令返回预期/验收项:Agent 已能读取文件、运行命令并判断结果,不再为这些信息设置额外的强制合同完成门禁。文件读取、构建、测试和命令结果等正常工具能力继续保留。
  5. visual 与 gameplay 两种要求的最终处理暂不决定,后续单独讨论;本条评论不授权按此前建议直接删除或重设计它们。

目标是让合同跟随用户真实的游戏制作/交付请求,而不是由项目初始状态强加任务。此评论记录已确认方向;当前 PR 仍为 WIP,运行时尚未实现这些变更。

合同机制的讨论结论更新: 1. 移除回合一开始就无条件要求登记交付合同、完成游戏交付的提示与前置要求。不能因为当前目录是尚未交付的 Web 游戏脚手架,就自动要求本次用户消息交付游戏。 2. 改为告诉 Agent:当用户实际要求“制作游戏 / 完整游戏 / 可运行游戏 / 交付游戏”等目标时,才创建交付合同。这里的例子表达用户意图,不是宿主侧固定关键词匹配表;由 Agent 结合当前用户请求和上下文判断。 3. “什么也不要做”“只生成一张图片,不制作游戏”等请求不能触发游戏交付义务,也不能因缺少游戏合同或游戏验收结果而被迫继续制作游戏。普通文件编辑、命令和资源操作不再依赖无条件合同准入。 4. 删除合同中的 artifact 文件验收项与 command 命令返回预期/验收项:Agent 已能读取文件、运行命令并判断结果,不再为这些信息设置额外的强制合同完成门禁。文件读取、构建、测试和命令结果等正常工具能力继续保留。 5. visual 与 gameplay 两种要求的最终处理暂不决定,后续单独讨论;本条评论不授权按此前建议直接删除或重设计它们。 目标是让合同跟随用户真实的游戏制作/交付请求,而不是由项目初始状态强加任务。此评论记录已确认方向;当前 PR 仍为 WIP,运行时尚未实现这些变更。
lhk229 added 2 commits 2026-10-04 11:34:54 +08:00
补充操作准入、失败隔离与回合清理的目标行为
更新重构里程碑及合同工作的范围边界
新增租约简化实施顺序、验收场景与回滚计划
merge latest master
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Has been cancelled
87886dc44b
lhk229 added 1 commit 2026-10-04 12:06:14 +08:00
简化 Direct 操作控制并移除全局租约门禁
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Has been cancelled
98c8d9cc51
移除全局排空、执行返修批次与合同存在性的操作准入限制
保留时间预算、并发控制、原回合权限和执行器清理边界
迁移执行账本并隔离普通失败与资源结果不确定状态
更新提示词、回归测试、主规范和实施验收记录
lhk229 added 1 commit 2026-10-04 12:08:52 +08:00
merge latest master
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 6m31s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 3m6s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Failing after 4m34s
Project CI / Frontend tests (pull_request) Successful in 2m46s
Project CI / Backend tests (pull_request) Successful in 6m57s
Project CI / AI game creator shell web tests (pull_request) Successful in 2m39s
Project CI / Native shell tests (pull_request) Successful in 6m31s
Project CI / Repository checks (pull_request) Successful in 5m39s
a5fc97c48b
lhk229 added 1 commit 2026-10-04 13:35:41 +08:00
规划 Direct 交付合同简化
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
7f380b31ce
明确仅在正常响应结束后自动复核合同,移除操作结算与补丁成功触发的提前封口
规定由 Agent 根据用户游戏制作意图登记合同,解除空项目强制登记义务
规划删除产物与命令验收要求,保留视觉与玩法现有判据
补齐持久化迁移、回归验收和实施顺序,同步主规范与共享决策
lhk229 added 1 commit 2026-10-04 13:37:55 +08:00
merge latest master
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m54s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Failing after 4m55s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 5m28s
Project CI / Backend tests (pull_request) Successful in 6m26s
Project CI / Frontend tests (pull_request) Successful in 2m51s
Project CI / Native shell tests (pull_request) Successful in 7m1s
Project CI / AI game creator shell web tests (pull_request) Successful in 3m14s
Project CI / Repository checks (pull_request) Successful in 6m27s
65981237bc
lhk229 added 1 commit 2026-10-04 14:21:34 +08:00
简化 Direct 交付合同并延后自动验收
Project CI / AI game creator shell Rust crates (pull_request) Successful in 3m10s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Failing after 4m34s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 5m11s
Project CI / Backend tests (pull_request) Successful in 7m18s
Project CI / Frontend tests (pull_request) Successful in 3m19s
Project CI / AI game creator shell web tests (pull_request) Successful in 3m11s
Project CI / Native shell tests (pull_request) Successful in 7m22s
Project CI / Repository checks (pull_request) Successful in 6m45s
c0096c642e
移除操作结算与补丁成功后的合同检查,仅在正常响应结束后自动复核
按用户制作和交付游戏的意图提示登记,取消空项目强制合同义务
删除产物与命令验收要求,保留视觉和玩法现有判据及证据校验
升级合同与执行账本格式,保留旧预算和终态并安全处理未完成旧合同
同步运行提示、随包技能、回归测试、主规范与实施验收记录
lhk229 added 1 commit 2026-10-04 15:22:55 +08:00
merge latest master
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m56s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 4m46s
Project CI / Frontend tests (pull_request) Successful in 2m18s
Project CI / Backend tests (pull_request) Successful in 6m12s
Project CI / AI game creator shell web tests (pull_request) Successful in 2m28s
Project CI / Native shell tests (pull_request) Successful in 5m58s
Project CI / Repository checks (pull_request) Successful in 4m53s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Failing after 3m26s
d45a3fffb1
lhk229 added 2 commits 2026-10-04 21:14:33 +08:00
修复 Linux CI 进程组僵尸成员导致 shutdown 超时
Project CI / AI game creator shell Rust crates (pull_request) Successful in 6m41s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 8m12s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 8m25s
Project CI / Backend tests (pull_request) Successful in 9m8s
Project CI / Frontend tests (pull_request) Successful in 3m41s
Project CI / AI game creator shell web tests (pull_request) Successful in 3m44s
Project CI / Repository checks (pull_request) Successful in 5m51s
Project CI / Native shell tests (pull_request) Successful in 7m38s
ea9d5c3ad8
调整 process_tree.rs 的 Unix 进程组空判:Linux 下扫描 /proc 并将僵尸成员视为已退出
避免容器 PID 1 不回收被 reparent 的僵尸孙进程时 kill(-pgid, 0) 误判组仍存活
lhk229 added 1 commit 2026-10-05 13:18:10 +08:00
移除合同登记提示中的空项目与首次输入豁免说明
Project CI / AI game creator shell Rust crates (pull_request) Successful in 5m49s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 6m44s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m18s
Project CI / Backend tests (pull_request) Successful in 8m28s
Project CI / Frontend tests (pull_request) Successful in 3m35s
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
3744b6909a
删除运行提示与随包技能中的空项目、首次输入免登记说明
保留按用户制作、完成或交付游戏的意图登记合同的要求
同步技能包版本与摘要、技术规范和共享决策记录
lhk229 marked the pull request as ready for review 2026-10-05 13:24:02 +08:00
lhk229 added 1 commit 2026-10-05 13:29:16 +08:00
更新 Direct 重构手动验收与范围确认记录
Project CI / AI game creator shell Rust crates (pull_request) Successful in 5m37s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 6m39s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 6m56s
Project CI / Backend tests (pull_request) Successful in 8m53s
Project CI / Frontend tests (pull_request) Successful in 3m26s
Project CI / AI game creator shell web tests (pull_request) Successful in 2m55s
Project CI / Repository checks (pull_request) Successful in 6m20s
Project CI / Native shell tests (pull_request) Successful in 7m56s
063905ee5f
记录用户已完成手动 GUI 检查及 PR 已移除 WIP
明确视觉与玩法检查保持现状并清理后续调整的过期说明
同步主规范、里程碑、实施计划和共享决策记录
保留专项平台验证的证据边界,不记录此前 CI 失败
lhk229 reviewed 2026-10-05 13:52:22 +08:00
lhk229 left a comment
Author
Member

Review by Grok

Reviewed contract-lease-refactor (063905ee) against origin/master.

This branch replaces Direct execution leases and repair batches with per-operation admission, and it narrows delivery contracts to visual and gameplay checks that run only after a normal model response. In-process admission, migration, and evidence tests match that model. The production handoff back to Working still depends on a full process-tree proof that Unix never produces, so no-contract completion and post-response sealing do not run on Linux.

Issue counts

  • bugs: 2
  • suggestions: 1
  • nits: 0

Issues

1. bug — execution.rs process exit proof

finish_model_attempt records ProcessTreeExitProof::confirmed(), which requires full_tree_verified. That flag is Windows-only (process_tree.rs builds scope: "process-group-only" on Unix). On Linux a successful group shutdown still records proven == false. record_process_exit_proof then forces Interrupted and a “缺少完整子进程退出证明” report before finish_attempt runs. finish_attempt returns immediately unless the phase is still Closing, so it never restores Working. review_reply returns that terminal report and does not seal or call finish_without_contract. The same confirmed() value in shutdown_and_report moves a ready contract to Sealing, then the false proof flips the phase to Interrupted before finish_sealing. Mid-operation try_seal was removed, so this is now the only completion path. Unit tests pass record_process_exit_proof(true) directly and do not assert phase or the returned report.

On Unix, set executor_stopped from owned_scope_retired() and leave the phase in Closing so finish_attempt can return to Working. Reserve confirmed() for a missing or failed group shutdown. Assert on Linux that a no-contract attempt with a finished operation reaches Completed with terminal_report == None, and that a ready contract reaches Completed with the host acceptance report.

2. bug — process_tree.rs:195

linux_process_group_has_live_member is meant to ignore zombies so kill(-pgid, 0) does not keep a reparented zombie group alive until STOP_TIMEOUT. entry.ok()? aborts the whole scan to None on the first read_dir error, and the caller falls back to kill(-pgid, 0), which still treats zombies as a live group. An unreadable /proc/<pid>/stat is skipped. If every live member is skipped, the function returns Some(false). observed_tree_empty then returns true without consulting kill. terminate_owned_tree returns immediately without signaling the group, and shutdown can report the owned scope retired while a live child remains.

On a bad directory entry or an unreadable stat for a numeric pid, do not return None or treat the group as empty. Skip only entries that are clearly not a live member. If any numeric pid in the target group cannot be classified, return None so the caller keeps the kill(-pgid, 0) result.

3. suggestion — direct_delivery.rs:522

finish_without_contract calls tick_locked and, if the wall clock or execution budget has just expired, commits Exhausted plus the budget report, then returns Err("direct-execution-close: 回合尚不能结束") because the phase is no longer Working. review_reply uses ? on that error. The GUI/CLI match arms treat review_reply errors as turn failures and do not read terminal_report. The user sees an unclassified close error instead of the budget report that was just persisted.

If finish_without_contract or the post-try_seal path observes a terminal phase, return Ok(Some(terminal_report)) instead of propagating the close error.

Review by Grok Reviewed `contract-lease-refactor` (`063905ee`) against `origin/master`. This branch replaces Direct execution leases and repair batches with per-operation admission, and it narrows delivery contracts to visual and gameplay checks that run only after a normal model response. In-process admission, migration, and evidence tests match that model. The production handoff back to `Working` still depends on a full process-tree proof that Unix never produces, so no-contract completion and post-response sealing do not run on Linux. ## Issue counts - bugs: 2 - suggestions: 1 - nits: 0 ## Issues ### 1. bug — `execution.rs` process exit proof `finish_model_attempt` records `ProcessTreeExitProof::confirmed()`, which requires `full_tree_verified`. That flag is Windows-only (`process_tree.rs` builds `scope: "process-group-only"` on Unix). On Linux a successful group shutdown still records `proven == false`. `record_process_exit_proof` then forces `Interrupted` and a “缺少完整子进程退出证明” report before `finish_attempt` runs. `finish_attempt` returns immediately unless the phase is still `Closing`, so it never restores `Working`. `review_reply` returns that terminal report and does not seal or call `finish_without_contract`. The same `confirmed()` value in `shutdown_and_report` moves a ready contract to `Sealing`, then the false proof flips the phase to `Interrupted` before `finish_sealing`. Mid-operation `try_seal` was removed, so this is now the only completion path. Unit tests pass `record_process_exit_proof(true)` directly and do not assert phase or the returned report. On Unix, set `executor_stopped` from `owned_scope_retired()` and leave the phase in `Closing` so `finish_attempt` can return to `Working`. Reserve `confirmed()` for a missing or failed group shutdown. Assert on Linux that a no-contract attempt with a finished operation reaches `Completed` with `terminal_report == None`, and that a ready contract reaches `Completed` with the host acceptance report. ### 2. bug — `process_tree.rs:195` `linux_process_group_has_live_member` is meant to ignore zombies so `kill(-pgid, 0)` does not keep a reparented zombie group alive until `STOP_TIMEOUT`. `entry.ok()?` aborts the whole scan to `None` on the first `read_dir` error, and the caller falls back to `kill(-pgid, 0)`, which still treats zombies as a live group. An unreadable `/proc/<pid>/stat` is skipped. If every live member is skipped, the function returns `Some(false)`. `observed_tree_empty` then returns true without consulting `kill`. `terminate_owned_tree` returns immediately without signaling the group, and shutdown can report the owned scope retired while a live child remains. On a bad directory entry or an unreadable `stat` for a numeric pid, do not return `None` or treat the group as empty. Skip only entries that are clearly not a live member. If any numeric pid in the target group cannot be classified, return `None` so the caller keeps the `kill(-pgid, 0)` result. ### 3. suggestion — `direct_delivery.rs:522` `finish_without_contract` calls `tick_locked` and, if the wall clock or execution budget has just expired, commits `Exhausted` plus the budget report, then returns `Err("direct-execution-close: 回合尚不能结束")` because the phase is no longer `Working`. `review_reply` uses `?` on that error. The GUI/CLI match arms treat `review_reply` errors as turn failures and do not read `terminal_report`. The user sees an unclassified close error instead of the budget report that was just persisted. If `finish_without_contract` or the post-`try_seal` path observes a terminal phase, return `Ok(Some(terminal_report))` instead of propagating the close error.
@@ -1204,6 +1193,13 @@ impl ExecutionAdapter {
let session = Arc::clone(&self.session);
let _ =
tokio::task::spawn_blocking(move || session.record_process_exit_proof(proven)).await;
Author
Member

[bug] Review by Grok. finish_model_attempt passes ProcessTreeExitProof::confirmed() into record_process_exit_proof. confirmed() requires full_tree_verified, which is Windows-only. On Linux a successful group shutdown still records proven == false, so the phase becomes Interrupted before finish_attempt can return to Working. No-contract completion and post-response finish_sealing therefore do not run. The same confirmed() value in shutdown_and_report flips a ready contract out of Sealing.

Suggestion: On Unix, set executor_stopped from owned_scope_retired() and leave the phase in Closing. Reserve confirmed() for a missing or failed group shutdown. Assert the Linux phase and returned report.

**[bug] Review by Grok.** `finish_model_attempt` passes `ProcessTreeExitProof::confirmed()` into `record_process_exit_proof`. `confirmed()` requires `full_tree_verified`, which is Windows-only. On Linux a successful group shutdown still records `proven == false`, so the phase becomes `Interrupted` before `finish_attempt` can return to `Working`. No-contract completion and post-response `finish_sealing` therefore do not run. The same `confirmed()` value in `shutdown_and_report` flips a ready contract out of `Sealing`. **Suggestion:** On Unix, set `executor_stopped` from `owned_scope_retired()` and leave the phase in `Closing`. Reserve `confirmed()` for a missing or failed group shutdown. Assert the Linux phase and returned report.
lhk229 marked this conversation as resolved
@@ -186,0 +192,4 @@
#[cfg(all(unix, target_os = "linux"))]
fn linux_process_group_has_live_member(pgid: i32) -> Option<bool> {
for entry in std::fs::read_dir("/proc").ok()? {
let entry = entry.ok()?;
Author
Member

[bug] Review by Grok. entry.ok()? aborts the whole /proc scan on the first directory error. The caller then falls back to kill(-pgid, 0), which still treats zombies as a live group. Separately, an unreadable /proc/<pid>/stat is skipped; if every live member is skipped, this returns Some(false) and shutdown can report the owned scope retired while a live child remains.

Suggestion: Skip only entries that are clearly not live members. If any numeric pid in the group cannot be classified, return None so the caller keeps the kill(-pgid, 0) result.

**[bug] Review by Grok.** `entry.ok()?` aborts the whole `/proc` scan on the first directory error. The caller then falls back to `kill(-pgid, 0)`, which still treats zombies as a live group. Separately, an unreadable `/proc/<pid>/stat` is skipped; if every live member is skipped, this returns `Some(false)` and shutdown can report the owned scope retired while a live child remains. **Suggestion:** Skip only entries that are clearly not live members. If any numeric pid in the group cannot be classified, return `None` so the caller keeps the `kill(-pgid, 0)` result.
lhk229 marked this conversation as resolved
@@ -710,2 +520,3 @@
let ledger = session.snapshot()?;
if ledger.contract.is_none() && !ledger.requires_contract {
if ledger.contract.is_none() {
session.finish_without_contract()?;
Author
Member

[suggestion] Review by Grok. finish_without_contract can commit an Exhausted budget report and then return Err("direct-execution-close: 回合尚不能结束") because the phase is no longer Working. review_reply propagates that error, and the GUI/CLI turn-failure arms do not read terminal_report.

Suggestion: If this path observes a terminal phase, return Ok(Some(terminal_report)).

**[suggestion] Review by Grok.** `finish_without_contract` can commit an `Exhausted` budget report and then return `Err("direct-execution-close: 回合尚不能结束")` because the phase is no longer `Working`. `review_reply` propagates that error, and the GUI/CLI turn-failure arms do not read `terminal_report`. **Suggestion:** If this path observes a terminal phase, return `Ok(Some(terminal_report))`.
lhk229 marked this conversation as resolved
lhk229 added 1 commit 2026-10-05 14:05:19 +08:00
修复 Direct 回合收尾与进程退出判断
Project CI / AI game creator shell Rust crates (pull_request) Successful in 5m43s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 6m21s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 7m20s
Project CI / Backend tests (pull_request) Successful in 8m32s
Project CI / Frontend tests (pull_request) Successful in 3m13s
Project CI / AI game creator shell web tests (pull_request) Successful in 2m59s
Project CI / Repository checks (pull_request) Successful in 5m12s
Project CI / Native shell tests (pull_request) Successful in 6m57s
691e51e85c
使用受控归属退出证明完成 Unix 回合,保留完整子树证明边界
保守处理 Linux 进程扫描错误,避免将未确认的活跃进程判为空组
优先返回收尾时已持久化的预算耗尽报告,保留其他关闭错误
阻止正常关闭的迟到通知创建或覆盖成功回合报告
补充进程扫描、完整响应和预算回归测试并同步规范与验收记录
Author
Member

Follow-up by Grok

The three findings from the previous review are fixed on 691e51e85 (修复 Direct 回合收尾与进程退出判断).

  • Linux exit proof: finish_model_attempt and shutdown_and_report record owned_scope_retired() instead of confirmed(). A retired Unix process group sets executor_stopped and leaves the phase in Closing or Sealing, so a no-contract turn can return to Working and a ready contract can finish_sealing. no_contract_operation_completes_with_original_response_after_group_shutdown and ready_contract_allows_operation_then_complete_response_before_host_shutdown passed.
  • /proc group scan: a directory error or an unreadable stat no longer makes the group look empty, and the scan no longer stops at the first bad entry. A vanished pid or a zombie is not a live member. If a numeric pid in the group cannot be classified, the scan returns None and the caller keeps kill(-pgid, 0). incomplete_process_scan_never_proves_empty, process_scan_distinguishes_live_zombie_foreign_and_disappeared_pids, and real_zombie_is_not_a_live_group_member_before_reaping passed.
  • Budget report: review_reply returns a persisted terminal report after finish_without_contract and after sealing. An Exhausted report created during close is shown instead of direct-execution-close: 回合尚不能结束. A close with no terminal report still returns that error. no_contract_review_returns_budget_report_created_during_close and no_contract_review_preserves_close_error_without_terminal_report passed.
Follow-up by Grok The three findings from the previous review are fixed on `691e51e85` (`修复 Direct 回合收尾与进程退出判断`). - **Linux exit proof:** `finish_model_attempt` and `shutdown_and_report` record `owned_scope_retired()` instead of `confirmed()`. A retired Unix process group sets `executor_stopped` and leaves the phase in `Closing` or `Sealing`, so a no-contract turn can return to `Working` and a ready contract can `finish_sealing`. `no_contract_operation_completes_with_original_response_after_group_shutdown` and `ready_contract_allows_operation_then_complete_response_before_host_shutdown` passed. - **`/proc` group scan:** a directory error or an unreadable `stat` no longer makes the group look empty, and the scan no longer stops at the first bad entry. A vanished pid or a zombie is not a live member. If a numeric pid in the group cannot be classified, the scan returns `None` and the caller keeps `kill(-pgid, 0)`. `incomplete_process_scan_never_proves_empty`, `process_scan_distinguishes_live_zombie_foreign_and_disappeared_pids`, and `real_zombie_is_not_a_live_group_member_before_reaping` passed. - **Budget report:** `review_reply` returns a persisted terminal report after `finish_without_contract` and after sealing. An `Exhausted` report created during close is shown instead of `direct-execution-close: 回合尚不能结束`. A close with no terminal report still returns that error. `no_contract_review_returns_budget_report_created_during_close` and `no_contract_review_preserves_close_error_without_terminal_report` passed.
lhk229 merged commit 3ac8ab1c08 into master 2026-10-05 14:19:05 +08:00
lhk229 deleted branch contract-lease-refactor 2026-10-05 14:19:05 +08:00
Sign in to join this conversation.