feat(app): decide User gates in the drawer with one confirmation - #5415
Conversation
|
This pull request has merge conflicts with Choose the remote for the base repository, not an out-of-date fork. git fetch upstream
git rebase upstream/main
# Resolve each conflict, git add the resolved files, then git rebase --continue.
git push --force-with-lease origin HEADFor a same-repository clone whose Keep the DCO |
…tion gate.resolve approve/reject/cancel previews now dry-run the canonical complete_goal_todo(role=user, decision_outcome=...) owner, bind the terminal review basis, and apply with the reviewed operation id. The receipt carries the provider's decision_outcome and unblock_resume state. Defer records no decision and stays held as decision_outcome_required. Signed-off-by: huangruiteng <huangrt01@163.com> Co-authored-by: Cursor <cursoragent@cursor.com>
compileActionReviewPlan adds a decisionFrame for gate.resolve decisions: the chosen decision, and after a verified apply the dependent-work effect projected from the canonical ResumeState. Unknown or mismatched receipts stay 'unknown'; decisions retry the original reviewed operation. Signed-off-by: huangruiteng <huangrt01@163.com> Co-authored-by: Cursor <cursoragent@cursor.com>
The request drawer offers Approve / Reject (Withdraw in the menu) for typed User gates, previews one decision, confirms once, and reads back the recorded outcome and its effect on waiting work. Removes the CLI copy hint and the proposal-level reject/defer controls for decisions; run operator gates and non-gate requests stay explanation-only. Also repairs browser smokes that drifted on main: the attention fixture now carries updated_at for the request-content join, and the operation fixture uses a relative expiry, a complete Lark delivery receipt, and the visible-timeline placement of awaiting operations. Signed-off-by: huangruiteng <huangrt01@163.com> Co-authored-by: Cursor <cursoragent@cursor.com>
7121ea6 to
8fd55d0
Compare
|
Rebased onto |
Signed-off-by: huangruiteng <huangrt01@163.com>
…types Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
huangruiteng
left a comment
There was a problem hiding this comment.
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
English verdict: APPROVE - the explicit owner decision uses canonical completion, preserves replay and fencing, and has real packaged App readback.
Exact head: d0f9b51. No blocking finding remains after refinement.
动机
普通用户要在 App 内处理一个待批准请求,原来的流程却要求复制命令、切到终端,再回到页面刷新。主干虽有完整的 User completion owner,App 的 gate.resolve 仍停在 canonical_authority_required。本次把已有审批能力接到用户入口,交付的是可持久化、可恢复关联工作的完整决定流程,而不是只增加一个按钮。
改动思路
批准、拒绝和撤回先走 canonical dry run,确认时才执行同一个 completion owner;已有 terminal review basis、CAS 和 operation id 分别防止过期确认与重复副作用。TypeScript presentation owner 从经过验证的 receipt 投影结果,React 只展示请求、决定和后续工作的影响。审批的权限仍来自对这个具体请求的一次明确确认,不授权预订、支付或任意外部执行。CLI 与 Lark 继续使用各自已有入口,无需改设置,也没有新增隐式启用的能力。
具体改动
关键代码讲解
ChatTodoActionMixin._run_gate_resolve把具体 Todo、决定、证据和执行者归属交给complete_goal_todo(role="user")。_apply_reviewed_todo_edit复用原有更新路径,处理 provider revision、预览失效及原操作重放,避免 App 另设审批状态机。compileDecisionReviewFrame只信任已验证且决定一致的 receipt。修复了两个过度推断:缺少 resume state、无法区分目标和决定范围的缺失,都显示 unknown;它们不能证明“没有等待中的工作”。已知的 resumed、其他审批仍未完成、拒绝、撤回各有明确展示。ContextDrawer允许 User gate 的批准、拒绝和菜单中的撤回,然后只确认一次。确认后显示持久化结果,移除确认按钮。非 gate 请求和运行期 operator gate 保留解释路径;撤回是源请求的 cancel 决定,不再把 proposal defer 冒充成请求决定。demo.workspace.prepare为六个演示 gate 写入明确的 dependent 和 decision_scope,后续任务携带匹配的 required scopes。advance删除手动打开任务的第二条写入路径,审批及 CLI 演示统一依赖 canonical owner。演示清单升级到 v3,旧目录保留,重新演示使用新空目录。
另将现有 DecisionOutcome/ResumeState 放进纯类型模块,供 canonical owner、presentation 和 React 共用,避免前端类型检查引入后端 Node 依赖。修复旧浏览器测试仍点击已删除“稍后决定”的漂移,改为实际撤回流程,并检查预览无写入、确认恰好一次及结果回读。
对主干的风险
默认行为变化明确披露:approve/reject/cancel 现在能确认写入;defer 不记录决定,保持 held;对 user_action 的 approve 在预览时拒绝。未注册的 hard-lease actor、过期预览及旧无 basis proposal 不能绕过 canonical owner。没有新的存储 provider、数据库迁移或外部执行授权。
同一合成 fixture 在不可变主干与本 head 经 ChatActionService 执行:主干全部决定停在旧 hold;新 head 在 legacy、file/hard-lease、SQLite 下批准恢复指定目标,拒绝与撤回维持阻塞,证据持久化、owner 不变、重复 apply 不再写入。旧主干运行独立“必须能确认决定”的断言确实失败,新 head 通过。真实打包 App 在隔离 registry 中确认批准,并从 canonical Todo 和刷新后的任务页分别确认 source done、target open;浏览器的其他测试使用合成 HTTP fixture,不把它们称为真实 Agent 执行。
语义与 CI 对齐
复用已有 approve/reject/cancel 和 canonical ResumeState 词表;dependentEffect 是本地只读投影,gate_resolved 是 Chat receipt 的本地结果。语义 advisory 只是有限语法提示,完整 vocabulary smoke 和 premerge 才提供对应验证。按当前 wait_for_ci=false 策略使用本地验证,不查询或等待远端 CI。
我的整体评价
这是一段有价值且范围合理的 App 审批交付:不再让普通用户换入口重输已知信息,同时保留一次对具体决定的确认。持续性方面,关联任务能进入待执行,旧预览有重新生成恢复路径,重试不重复写入;体验方面,请求与决定的影响在同一个抽屉可见,刷新后状态仍成立。限定的未来维护整理已应用到类型 owner 和演示单一 writer,未扩展成权限或 provider 重构。
验证:17 个决定/演示测试、55 个相关 canonical 测试、Chat actions smoke、TS 类型检查与 completion 测试、decision frame smoke、Python lint/mypy、打包构建、打包 typed-actions/attention 浏览器场景、真实 App 的审批与 reload,以及风险选择的 premerge。无未解决阻塞;没有启动付费模型或长期 Agent 执行,不能据此声称外部预订已经完成。所有变化均有可独立回退的提交,私有运行日志留在本地。
Signed-off-by: huangruiteng <huangrt01@163.com>
huangruiteng
left a comment
There was a problem hiding this comment.
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
English verdict: APPROVE - the explicit owner decision uses canonical completion, preserves replay and fencing, and has real packaged App readback.
Exact head: f01403b. No blocking finding remains after refinement.
动机
普通用户要在 App 内处理一个待批准请求,原来的流程却要求复制命令、切到终端,再回到页面刷新。主干虽有完整的 User completion owner,App 的 gate.resolve 仍停在 canonical_authority_required。本次把已有审批能力接到用户入口,交付的是可持久化、可恢复关联工作的完整决定流程,而不是只增加一个按钮。
改动思路
批准、拒绝和撤回先走 canonical dry run,确认时才执行同一个 completion owner;已有 terminal review basis、CAS 和 operation id 分别防止过期确认与重复副作用。TypeScript presentation owner 从经过验证的 receipt 投影结果,React 只展示请求、决定和后续工作的影响。审批的权限仍来自对这个具体请求的一次明确确认,不授权预订、支付或任意外部执行。CLI 与 Lark 继续使用各自已有入口,无需改设置,也没有新增隐式启用的能力。
具体改动
关键代码讲解
ChatTodoActionMixin._run_gate_resolve把具体 Todo、决定、证据和执行者归属交给complete_goal_todo(role="user")。_apply_reviewed_todo_edit复用原有更新路径,处理 provider revision、预览失效及原操作重放,避免 App 另设审批状态机。compileDecisionReviewFrame只信任已验证且决定一致的 receipt。修复了两个过度推断:缺少 resume state、无法区分目标和决定范围的缺失,都显示 unknown;它们不能证明“没有等待中的工作”。已知的 resumed、其他审批仍未完成、拒绝、撤回各有明确展示。ContextDrawer允许 User gate 的批准、拒绝和菜单中的撤回,然后只确认一次。确认后显示持久化结果,移除确认按钮。非 gate 请求和运行期 operator gate 保留解释路径;撤回是源请求的 cancel 决定,不再把 proposal defer 冒充成请求决定。demo.workspace.prepare为六个演示 gate 写入明确的 dependent 和 decision_scope,后续任务携带匹配的 required scopes。advance删除手动打开任务的第二条写入路径,审批及 CLI 演示统一依赖 canonical owner。演示清单升级到 v3,旧目录保留,重新演示使用新空目录。
另将现有 DecisionOutcome/ResumeState 放进纯类型模块,供 canonical owner、presentation 和 React 共用,避免前端类型检查引入后端 Node 依赖。修复旧浏览器测试仍点击已删除“稍后决定”的漂移,改为实际撤回流程,并检查预览无写入、确认恰好一次及结果回读。
对主干的风险
默认行为变化明确披露:approve/reject/cancel 现在能确认写入;defer 不记录决定,保持 held;对 user_action 的 approve 在预览时拒绝。未注册的 hard-lease actor、过期预览及旧无 basis proposal 不能绕过 canonical owner。没有新的存储 provider、数据库迁移或外部执行授权。
同一合成 fixture 在不可变主干与本 head 经 ChatActionService 执行:主干全部决定停在旧 hold;新 head 在 legacy、file/hard-lease、SQLite 下批准恢复指定目标,拒绝与撤回维持阻塞,证据持久化、owner 不变、重复 apply 不再写入。旧主干运行独立“必须能确认决定”的断言确实失败,新 head 通过。真实打包 App 在隔离 registry 中确认批准,并从 canonical Todo 和刷新后的任务页分别确认 source done、target open;浏览器的其他测试使用合成 HTTP fixture,不把它们称为真实 Agent 执行。
语义与 CI 对齐
复用已有 approve/reject/cancel 和 canonical ResumeState 词表;dependentEffect 是本地只读投影,gate_resolved 是 Chat receipt 的本地结果。语义 advisory 只是有限语法提示,完整 vocabulary smoke 和 premerge 才提供对应验证。按当前 wait_for_ci=false 策略使用本地验证,不查询或等待远端 CI。
我的整体评价
这是一段有价值且范围合理的 App 审批交付:不再让普通用户换入口重输已知信息,同时保留一次对具体决定的确认。持续性方面,关联任务能进入待执行,旧预览有重新生成恢复路径,重试不重复写入;体验方面,请求与决定的影响在同一个抽屉可见,刷新后状态仍成立。限定的未来维护整理已应用到类型 owner 和演示单一 writer,未扩展成权限或 provider 重构。
验证:17 个决定/演示测试、55 个相关 canonical 测试、Chat actions smoke、TS 类型检查与 completion 测试、decision frame smoke、Python lint/mypy、打包构建、打包 typed-actions/attention 浏览器场景、真实 App 的审批与 reload,以及风险选择的 premerge。无未解决阻塞;没有启动付费模型或长期 Agent 执行,不能据此声称外部预订已经完成。所有变化均有可独立回退的提交,私有运行日志留在本地。
Delivery brief
Owners could not decide a User gate in the App without copying a CLI command. This change connects the existing request drawer to canonical User completion: choose Approve/Reject/Withdraw, confirm once, and read back the recorded outcome and its effect on the linked work.
The Chat action adapter reuses the existing completion owner, terminal review basis/CAS and replay operation id. TypeScript presentation derives the frame only from a verified matching receipt. A pure module shares the existing decision/resume types with the frontend. Missing or ambiguous dependent information stays unknown.
Behavior and boundaries
Validation
The initial semantic check found a stale census line; regenerated and reviewed its single-line change, then reran successfully. No paid models, benchmark jobs or external effects were launched. CI is not polled under the current review policy; merge requires published exact-head review, valid exact-scope quality receipt and current readiness.
Future-facing pass: removed the demo's duplicate status writer and reused the pure existing type owner. Persisted pre-basis proposal compatibility remains intentionally stale/regenerate rather than silently changing replay semantics.