Repository navigation
Keep interrupted Todo and Monitor confirmations recoverable in Chat - #8727
loopx-agent wants to merge 25 commits into
Conversation
Signed-off-by: LoopX Agent <[email protected]>
Use the serving coordination runtime for reviewed Todo and Monitor actions when no registered runtime owns the route. Keep the same provider for preview, apply and receipt replay, and retain registry precedence when a source is registered. Signed-off-by: LoopX Agent <[email protected]>
Route reviewed Todo creation, assignment and Monitor creation through the same Goal source used for Task reads. Use the serving runtime only for an unbound project registry. A shared directory resolves its source registry before any write, and a Monitor confirmation becomes stale when that source registration changes. Signed-off-by: LoopX Agent <[email protected]>
Persist the reviewed provider, source and operation before a create. On retry, the canonical writer recovers the original receipt before checking freshness for a new write. Monitor retries retain the first due time and concurrent callers share the saved request. Signed-off-by: LoopX Agent <[email protected]>
Signed-off-by: LoopX Agent <[email protected]>
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent · gpt-6.1-sol · OpenAI · runtime_reported · reasoning_effort=max
Request changes conclusion (author-owned PR; GitHub blocks formal self-review)
评审提交 20705491d40a17942b05a35011b21718055f2727,目标分支基线 a00b3dc0e1161f2bcce4f5e626ddc2597338de9a。
- [P2] 取消已提交的任务确认会截断原回执恢复。 对展示写入失败但权威 Todo 已提交的提案,调用原提案的公开 POST /api/actions/{id}/cancel,再解除展示故障并重试 /apply。 候选在 File 和 SQLite 上都返回 200 cancelled,权威 Todo 保留,但原提案随后返回 409,展示和原回执无法从原确认恢复。基线同条件拒绝取消。 进入待恢复状态 取消 transition
- [P2] 同一 Goal 的两条待恢复任务只显示一条原确认。 在同一 Goal 的概览依次确认两个不同名称的任务,让两次权威写入成功而展示写入失败。关闭抽屉并刷新页面,再打开 Goal 对话。 概览最多留下最新一个恢复按钮,刷新后即消失。两个后端确认仍在,Goal 对话把它们折成一个 Create task 卡;只有较新的确认恢复后,较早的确认才出现。 概览的恢复入口 对话卡片归并
动机 / Motivation
这项改动面向在 Chat 或飞书确认创建任务、希望恢复原结果的 Goal 用户。 基线在同一展示写入故障下把确认标成已完成,错误地给出 projection_verified=true。 候选在 File 和 SQLite 上都返回 200 cancelled,权威 Todo 保留,但原提案随后返回 409,展示和原回执无法从原确认恢复。基线同条件拒绝取消。 概览最多留下最新一个恢复按钮,刷新后即消失。两个后端确认仍在,Goal 对话把它们折成一个 Create task 卡;只有较新的确认恢复后,较早的确认才出现。 单项展示待交付时,页面读到已创建并可重开原确认。丢失第二次 apply 响应和列表读取时,当前原确认仍可重试。两条实际重试都保留原 Todo ID,权威修订不增。 实测为合成 Goal 上的打包 Chat、真实本机 HTTP、File/SQLite。飞书路径由现有模拟确认测试覆盖,实际租户、已安装 App 和托管 CI 待对应验证。目标分支 #8725 单独存在与 main 的冲突。
改动思路 / Approach
权威任务写入、回执与后续恢复由现有 provider 和 ChatActionStore 负责,Dashboard 消费当前 Goal 的持久提案。 权威存储已完成创建时,Chat 按类型化状态提示展示待更新。用户原先确认的操作仍可重试,修复 Markdown 展示后可读回原 Todo。取消和恢复入口也需要共用这个已提交状态。原确认处理 恢复计划
具体改动 / Changes
关键代码讲解
_pending_create_projection 保存 Todo 和 operation ID,并把待展示写成 failed。现有取消入口接受这个通用状态,后续 apply 又拒绝 cancelled。概览的 AddTask 只取上次提交对应的 React 状态。对话虽然读回两条提案,却用 action kind、Goal、空的 Todo 字段和相同标题归并,结果是较新的操作遮住较早的操作。
基线 docs/project-agent-todo-contract.md 的 原操作身份 已在重复重试中验证通过。已提交仍可恢复 和 可见恢复入口 各有反例。基线验收依据
对主干的风险 / Risks
File 和 SQLite 中,取消都没有撤回已创建任务,provider revision 保持原值。打包页面丢失一次重试响应和提案列表读取后,已经打开的原确认仍能重试。恢复较新项会让较旧项重新出现,两个原确认按各自 ID 都能最终完成。桌面和窄屏的待更新文案及重试可见,但新开页面不会重建概览入口。#8725 自身的 main 合成冲突也出现在该堆叠头,冲突文件属于前置分支。
语义与 CI 对齐
本地 37 项 Python、18 项 TypeScript、16 项 standard premerge 通过。对照 File 和 SQLite 原生 HTTP 及 1200/390 像素打包页面。 当前展示错误用同一隔离 HTTP fixture 触发,外部租户仍由实装路径验证。合并需重新核验前置分支和评审结果。
我的整体评价 / Verdict
请求修改。在 action store 的原子 transition 中拒绝取消已确认提交、仍待展示的 Todo/Monitor。继续允许未执行预览取消,保留同一 proposal 和 operation ID 的恢复。 按原始 proposal ID 保留每个可重试创建。概览从当前 Goal 的持久提案读回推导恢复项,对话按真实任务内容区分每项。 用同一 File/SQLite HTTP fixture 断言取消返回 409、Todo 与 provider revision 不变。清除故障后同一确认必须回读原 Todo 和已验证的展示。 扩展打包浏览器测试,在两个不同任务同时待展示时刷新、切换视图、先恢复任一项,并验证两条原始确认分别可见且权威 Todo 不增。
打包页面在 1200 × 854 及 390 × 854 都能读取已创建、展示待更新及重试原操作。窄屏抽屉保留上下文与重试,桌面抽屉收窄概览的指标,一些短状态断行。刷新后恢复入口和标题归并可实测。 实测为合成 Goal 上的打包 Chat、真实本机 HTTP、File/SQLite。飞书路径由现有模拟确认测试覆盖,实际租户、已安装 App 和托管 CI 待对应验证。目标分支 #8725 单独存在与 main 的冲突。
English verdict: REQUEST_CHANGES at 2070549. The public cancel route strands a committed create on File and SQLite, and two independently committed pending tasks cannot both be selected for recovery after a packaged Dashboard reload.
| def _pending_create_projection( | ||
| self, proposal: dict[str, Any], *, todo_id: str, operation_id: str, | ||
| ) -> dict[str, Any]: | ||
| saved = self.store.mark_failed( |
There was a problem hiding this comment.
[P2] 取消已提交的任务确认会截断原回执恢复。 对展示写入失败但权威 Todo 已提交的提案,调用原提案的公开 POST /api/actions/{id}/cancel,再解除展示故障并重试 /apply。 候选在 File 和 SQLite 上都返回 200 cancelled,权威 Todo 保留,但原提案随后返回 409,展示和原回执无法从原确认恢复。基线同条件拒绝取消。 在 action store 的原子 transition 中拒绝取消已确认提交、仍待展示的 Todo/Monitor。继续允许未执行预览取消,保留同一 proposal 和 operation ID 的恢复。 用同一 File/SQLite HTTP fixture 断言取消返回 409、Todo 与 provider revision 不变。清除故障后同一确认必须回读原 Todo 和已验证的展示。
| const submitting = useRef(false); | ||
| const [reviewed, setReviewed] = useState<{text: string; id: string} | null>(null); | ||
| const proposal = reviewed ? proposals[reviewed.id] : undefined; | ||
| const pendingDisplay = proposal?.reviewPlan?.reason === "canonical_create_projection_pending" ? proposal : null; |
There was a problem hiding this comment.
[P2] 同一 Goal 的两条待恢复任务只显示一条原确认。 在同一 Goal 的概览依次确认两个不同名称的任务,让两次权威写入成功而展示写入失败。关闭抽屉并刷新页面,再打开 Goal 对话。 概览最多留下最新一个恢复按钮,刷新后即消失。两个后端确认仍在,Goal 对话把它们折成一个 Create task 卡;只有较新的确认恢复后,较早的确认才出现。 按原始 proposal ID 保留每个可重试创建。概览从当前 Goal 的持久提案读回推导恢复项,对话按真实任务内容区分每项。 扩展打包浏览器测试,在两个不同任务同时待展示时刷新、切换视图、先恢复任一项,并验证两条原始确认分别可见且权威 Todo 不增。
|
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 |
Signed-off-by: LoopX Agent <[email protected]>
Signed-off-by: LoopX Agent <[email protected]>
Signed-off-by: LoopX Agent <[email protected]>
Integrate the current Goal source routing. Prepare the exact Todo or Monitor operation before the authority write, bind recovery to the original store and registry, and show the saved confirmation after a reload. Validate recovery on the packaged workspace against File and SQLite. Signed-off-by: LoopX Agent <[email protected]>
…tion-receipt-pr-20261114 Signed-off-by: LoopX Agent <[email protected]>
Signed-off-by: LoopX Agent <[email protected]>
…ay result Signed-off-by: LoopX Agent <[email protected]>
…lay-recovery-pr-20261114 Signed-off-by: LoopX Agent <[email protected]>
Signed-off-by: LoopX Agent <[email protected]>
…task recovery Signed-off-by: LoopX Agent <[email protected]>
… current main Signed-off-by: LoopX Agent <[email protected]>
…eipt Signed-off-by: LoopX Agent <[email protected]>
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent · gpt-6.1-sol · OpenAI · runtime_reported · reasoning_effort=max
Request changes conclusion (author-owned PR; GitHub blocks formal self-review)
评审提交 14b696af5a5e00b3fabd6b08e8e9855e5fe40db5,目标基线 af92301ab4cc67d209e64c115eb6694e3c74ceb7。
- [P2] 502 且读回失败时丢掉已提交任务的原确认重试。 Todo 已提交且展示待更新。重试原确认时,上游已处理请求,但网关返回 HTML 502;原提案详情和 Goal 列表同时返回 503。 打包桌面(File)和窄屏(SQLite)都移除「重试原操作」,只留下禁用的「确认并应用」。File 端已核验更新;SQLite 端仍待展示。两者恢复后都能通过同一提案读回原 Todo 和回执,权威修订号不变。 中断响应判定
- [P2] 首个准备记录写入失败后,页面不能恢复原确认。 这是 #8725 的前置问题,已在当前提交复现。初次确认运行到保存 todo_create_prepared 时遇到一次 I/O 错误,权威 writer 尚未执行。 File/SQLite 均无首次写入,后端报告 retry_safe,四个处置入口返回 409;同一 apply 能安全创建一次。打包桌面刷新后可见对照卡,但这条失败确认已消失。 重试以准备记录为前提 #8725 的评审。
动机 / Motivation
影响范围:在 Goal 中确认 Todo 或 Monitor 的操作者。 确认一次,遇到写入或通知故障仍能找回该确认并完成同一任务。 目标主干在相同展示写入故障下会报告 projection_verified=true,虽然实际写入权威 Todo 后没有完成展示。候选在普通丢包及一条读回失败时保留原确认;两条摘要相同的待展示项在概览和对话刷新后独立可选。取消返回 409。重试分别保留原提案、Todo、回执和权威修订;Monitor 的原回执恢复也通过实际 HTTP。 本轮验证源码构建的打包 Chat、真实本机 HTTP 及隔离 File/SQLite。PostgreSQL 的相关用例跳过,未验证真实飞书租户、已安装 App 或托管 CI。
改动思路 / Approach
Chat source 选择实际 Goal;已有 action store 固定提案和计划;权威 Todo owner 负责写入和原 operation 的唯一性。Dashboard 投影同一提案。 确认保存原操作 ID 与来源见证;重试核对当前来源和权限,已经写入的 Todo 只更新展示。复用现有 transport 错误分类和 action 恢复类型;在原 apply 上优先保留类型化权威结果,避免新增恢复命令或状态 owner。
具体改动 / Changes
准确差异 40 个文件,+2191/-312,主要为叠加的源码和回归测试。#8717 的来源路由、#8725 的原确认身份与本 PR 的展示恢复都在实际差异内。
关键代码讲解
- resolve_chat_todo_source 把 Chat 读写绑定到 Goal 的注册源。_recover_create_display 核实原 Todo 的权威回执,仍使用原 operation ID 修复展示。真实 File/SQLite 均验证同一回执,未增加权威修订。
- 概览中的独立恢复项 和 对话按原 ID 保留恢复卡 让两条同摘要的待展示任务在刷新后分别可选。原取消返回 409,未确认的陈旧预览仍可生成新预览。
- applyProposal 的精确读回在列表失败时能恢复结果。在两条读取都失败时,同一个上游提交是否保留重试取决于客户端是否收到 HTTP 状态;无响应的对照通过,HTML 502 进入清除重试的分支。
依据 主干 Todo 恢复约定 和 打包交互交付要求:
source-fence:使用当前 Goal 源和 provider 见证,拒绝换来源。两种存储通过。verified-original-receipt:原确认回读同一 Todo 和已验证的展示。普通重试通过。display-recovery-visible:未知提交响应的原确认继续可恢复。502 加两条读回失败时不满足。before-commit-recovery:初次准备失败暂未写入,用户仍可继续原操作。刷新后找不到原确认。
对主干的风险 / Risks
129 项 Python 通过;33 项 TypeScript 通过、1 项 PostgreSQL 跳过;8 项 Todo 打包旅程、3 项 Goal 会话检查通过。19 项标准 premerge 中 quota-plan smoke 存在本地导入失败,补齐 Python 搜索路径后基线和候选单跑通过。全量控制面类型检查在两者的同一行报 TS2345。 已通过的打包用例覆盖 File/SQLite 两种宽度上的普通断连、详情或列表不可用、取消和重复读取。实际网关替换响应后的反例独立验证。Monitor 的回执丢失通过本机 HTTP 恢复;502 的界面反例使用 Todo。
我的整体评价 / Verdict
请求修改。把无权威结果的 5xx 网关响应归为结果未明;只对已经核验提交的同一提案保留原重试,按原来源和权限再校验。已核实的过期、拒绝或身份冲突仍须阻止。 让 action owner 明确返回安全的原操作恢复状态,并通过同一类型化条件保护转换和投影列表、抽屉。恢复时仍校验原预览、来源和 revision。
复验时分别覆盖两条读回失败的 502、已知权限或来源错误、首次准备写故障和普通断连。恢复网络或存储后,从原卡完成;验证相同提案、Todo、回执及预期权威修订。
视觉复验(1200 × 854、390 × 854):桌面和窄屏的概览首屏都能分别找到两条混合语言长文本的展示待更新任务。502 后抽屉仍留着任务标题,但重复提示读回不可用,只余禁用确认,用户无法在原卡中继续。 本轮验证源码构建的打包 Chat、真实本机 HTTP 及隔离 File/SQLite。PostgreSQL 的相关用例跳过,未验证真实飞书租户、已安装 App 或托管 CI。
English verdict: REQUEST_CHANGES at 14b696af5a5e00b3fabd6b08e8e9855e5fe40db5. A gateway 502 erases the retry control when the detail and list cannot be read, although the original committed Todo remains recoverable on File and SQLite. A first checkpoint write failure also strands an uncommitted confirmation in the packaged UI. Preserve the permitted original recovery in both cases.
| } | ||
| const interruptedResponse = error instanceof ChatApiError && error.payload.error_code === "chat_api_unavailable" | ||
| && (error.payload.http_status === undefined | ||
| || (typeof error.payload.http_status === "number" && error.payload.http_status < 400)); |
There was a problem hiding this comment.
[P2] 502 且读回失败时丢掉已提交任务的原确认重试。 Todo 已提交且展示待更新。重试原确认时,上游已处理请求,但网关返回 HTML 502;原提案详情和 Goal 列表同时返回 503。 打包桌面(File)和窄屏(SQLite)都移除「重试原操作」,只留下禁用的「确认并应用」。File 端已核验更新;SQLite 端仍待展示。两者恢复后都能通过同一提案读回原 Todo 和回执,权威修订号不变。 把无权威结果的 5xx 网关响应归为结果未明;只对已经核验提交的同一提案保留原重试,按原来源和权限再校验。已核实的过期、拒绝或身份冲突仍须阻止。
| && proposal.permission_classification === "durable_write" | ||
| && failure?.retry_safe !== false | ||
| && identity.proposalId && identity.sourceFingerprint && textValue(parameters?.goal_id) | ||
| && createPlan?.operation_id === ("chat-create:" + identity.proposalId) |
There was a problem hiding this comment.
[P2] 首个准备记录写入失败后,页面不能恢复原确认。 初次确认运行到保存 todo_create_prepared 时遇到一次 I/O 错误,权威 writer 尚未执行。 File/SQLite 均无首次写入,后端报告 retry_safe,四个处置入口返回 409;同一 apply 能安全创建一次。打包桌面刷新后可见对照卡,但这条失败确认已消失。 让 action owner 明确返回安全的原操作恢复状态,并通过同一类型化条件保护转换和投影列表、抽屉。恢复时仍校验原预览、来源和 revision。
Signed-off-by: LoopX Agent <[email protected]>
Signed-off-by: LoopX Agent <[email protected]>
|
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 |
Signed-off-by: LoopX Agent <[email protected]>
Signed-off-by: LoopX Agent <[email protected]>
Signed-off-by: LoopX Agent <[email protected]>
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent · gpt-6.1-sol · OpenAI · runtime_reported · reasoning_effort=max
Request changes conclusion (author-owned PR; GitHub blocks formal self-review)
评审提交 4b8d35befc39410c90c54e9fde9bd5ae61bac18c;对照目标基线 1965965992fffa1a1cca1a18cb297860155bc133。
[P2] 首次保存准备记录前中断后,原确认无法恢复。 确认请求在保存首份创建计划和写入任务之前退出;前端刷新后只读回 applying,且没有 checkpoint 或失败结果。 桌面和窄屏的原卡都还在,抽屉只显示禁用的「正在应用」,没有重试。File/SQLite 两种存储都没有首写;同一 apply 能成功完成一次,第二次返回原回执。 对应代码
[P2] 首次计划丢失后,Monitor 重试使用未审阅的新修订。 Monitor 确认遇到首份计划保存错误,未写入;有人对同一 Goal 完成一次有效修改,provider revision 前进,来源注册表不变。 同一 Monitor 提案重试返回 200,用新的修订号保存计划并新增 Monitor;同条件的 Todo 返回 409,仍未写入。两个后端结果一致。 对应代码
动机 / Motivation
在 Goal 里从对话确认待办或定时检查(Monitor)的人。 任务已写入、页面尚未展示时,操作者应能重试同一确认,并从原回执核对结果。 原来任务虽已写入,网关报错后原重试会从界面消失。显示仍待更新时,提交人很难判断是否可以安全再次确认。 要么只能等待,要么离开当前确认查询后台,核对是否已写入和是否会重复。 实际 502 且两条读回返回 503 时,页面保留原重试;File 已完成展示、SQLite 仍待展示,随后都找回原 Todo 和回执。可捕获的准备写入错误保留原提案;未变更修订时只创建一次。写入已发生但回执丢失时,重试仍保留原 Todo/Monitor 和回执。 验证使用源码构建的打包 Chat、实际本机 HTTP 和隔离 File/SQLite;PostgreSQL 用例跳过,未验证装机 App、实际飞书租户或托管 CI。
改动思路 / Approach
以原提案 ID 找回操作。Hub 的 action store 保留确认和步骤,Goal 对应的 Todo 存储判定能否写入并生成回执,Dashboard 展示原记录和恢复入口。 复用现有操作锁和已经有来源绑定的 provider 写入。保留一个类型化恢复条件,并将阶段与原确认依据配对;不再建独立重试协议或让界面从错误文案推断写入。 服务判定恢复和初次写入权限;provider 拥有唯一写入和原回执;页面只展示原确认和读回结果。 先保存同一提案的准备信息,再交给已注册 Goal 的权威存储;已有原回执时按同一 ID 核验和更新展示。 这两处来自 #8725 的共同确认链。单独的展示恢复已核验,合并这条堆叠分支也会带入未修复的首写边界。
具体改动 / Changes
关键代码讲解
apply;compileActionReviewPlan;_apply_monitor_create;applyProposal。原提案的锁会阻止仍在执行的同一次 apply;锁释放后,服务能够安全读回或重放。当前抽屉在首份记录缺失时要求先看到已经持久化的失败,遗漏了请求先退出的分支。Monitor 的动作指纹只有注册表和来源路径;记录尚未保存时,服务给它的计划写入了恢复时的存储版本,无法证明这个版本是操作者审阅过的。生产 29 文件,+912/-303;测试和夹具 9 文件,+1334/-9;其余为文档和工作流。
基线写入约束、打包任务验收及本提交的原确认约束:original-create-result 已验证;ambiguous-display-readback 已验证;preplan-interruption-recovery 未满足;reviewed-monitor-revision 未满足。
对主干的风险 / Risks
这两处来自 #8725 的共同确认链。单独的展示恢复已核验,合并这条堆叠分支也会带入未修复的首写边界。 桌面和窄屏的原卡都还在,抽屉只显示禁用的「正在应用」,没有重试。File/SQLite 两种存储都没有首写;同一 apply 能成功完成一次,第二次返回原回执。 同一 Monitor 提案重试返回 200,用新的修订号保存计划并新增 Monitor;同条件的 Todo 返回 409,仍未写入。两个后端结果一致。 由已有 action owner 区分仍有持锁请求和可恢复的原确认;为后者开放同一 apply,继续由原锁、来源和修订号把关,保留对取消和重新生成的限制。 在原 Monitor 确认依据中保留已审阅的修订号及存储见证,在首写前比较;有原提交回执时仍按原 operation ID 恢复,不让重试静默采用当前修订。 恢复权限只覆盖所选的原提案。服务须区分活请求、陈旧依据和可安全重试的原确认;有历史回执时沿用原结果。基线 HTTP 已能恢复 applying 提案,本轮缺口是被当前交付承诺覆盖的页面和未写 Monitor 的修订检查。
语义与 CI 对齐
PASS:101 项定向 Python、27 项定向 TypeScript、19 项标准 premerge(含 diff 与双语 RFC 检查)。 标准门首次因本机示例导入路径和临时目录位于私有树下失败,换用隔离的系统临时目录并保留示例导入路径后通过。全量类型检查在基线和候选的同一位置报 TS2345。 验证使用源码构建的打包 Chat、实际本机 HTTP 和隔离 File/SQLite;PostgreSQL 用例跳过,未验证装机 App、实际飞书租户或托管 CI。 旧 wire 的降级和缺见证对照仍由同一验证入口拒绝;原 Todo 修订过期后可重新审阅且不写任务。用打包 Chat/HTTP 在标为 applying 后、保存准备记录前中断请求,刷新后从原抽屉重试;核验只创建一次、返回同一回执,另设仍持锁和旧修订对照。 让首份 Monitor 计划写入报错,再通过另一项 Todo 写入推进修订,重试同一提案;断言原请求拒绝首写,且此前已提交的 Monitor 仍可读回原回执。
我的整体评价 / Verdict
请求修改。正常的已提交恢复能继续工作;请求退出前后仍有两处未满足的约束,持续恢复和页面可操作性都还未验收。桌面保留原卡,窄屏抽屉中长标题可完整换行;首份准备前的中断在两处都只显示禁用的「正在应用」。 优先修复共同的确认 owner,再重跑上述两个对照和原回执、浏览器恢复;沿用现有状态字段和权限边界。验证使用源码构建的打包 Chat、实际本机 HTTP 和隔离 File/SQLite;PostgreSQL 用例跳过,未验证装机 App、实际飞书租户或托管 CI。
English verdict: REQUEST_CHANGES at 4b8d35b. A persisted applying confirmation can stay disabled after reload, and an unwritten Monitor can adopt an unreviewed revision on retry.
| && textValue(createPlan.expected_store_identity); | ||
| // The server may fail before any checkpoint is saved. The same apply still | ||
| // owns the reviewed source and must revalidate it before the first write. | ||
| const interruptedBeforePlan = createAttemptFailed && failure?.retry_safe === true && proposal.checkpoint == null |
There was a problem hiding this comment.
[P2] 首次保存准备记录前中断后,原确认无法恢复。 确认请求在保存首份创建计划和写入任务之前退出;前端刷新后只读回 applying,且没有 checkpoint 或失败结果。 桌面和窄屏的原卡都还在,抽屉只显示禁用的「正在应用」,没有重试。File/SQLite 两种存储都没有首写;同一 apply 能成功完成一次,第二次返回原回执。 由已有 action owner 区分仍有持锁请求和可恢复的原确认;为后者开放同一 apply,继续由原锁、来源和修订号把关,保留对取消和重新生成的限制。 用打包 Chat/HTTP 在标为 applying 后、保存准备记录前中断请求,刷新后从原抽屉重试;核验只创建一次、返回同一回执,另设仍持锁和旧修订对照。
| def _monitor_create_fingerprint(source: ChatTodoSource) -> str: | ||
| from ..chat_actions import _digest | ||
|
|
||
| return _digest({ |
There was a problem hiding this comment.
[P2] 首次计划丢失后,Monitor 重试使用未审阅的新修订。 Monitor 确认遇到首份计划保存错误,未写入;有人对同一 Goal 完成一次有效修改,provider revision 前进,来源注册表不变。 同一 Monitor 提案重试返回 200,用新的修订号保存计划并新增 Monitor;同条件的 Todo 返回 409,仍未写入。两个后端结果一致。 在原 Monitor 确认依据中保留已审阅的修订号及存储见证,在首写前比较;有原提交回执时仍按原 operation ID 恢复,不让重试静默采用当前修订。 让首份 Monitor 计划写入报错,再通过另一项 Todo 写入推进修订,重试同一提案;断言原请求拒绝首写,且此前已提交的 Monitor 仍可读回原回执。
|
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 |
Signed-off-by: LoopX Agent <[email protected]>
Signed-off-by: LoopX Agent <[email protected]>
Signed-off-by: LoopX Agent <[email protected]>
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent · gpt-6.1-sol · OpenAI · runtime_reported · reasoning_effort=max
Request changes conclusion (author-owned PR; GitHub blocks formal self-review)
评审提交 e4fbd0f87df3f91c08fe511f8dbd15fec8b39dfb,对照目标基线 cbdc7655482e3db8cc70c5b0c4e49451d902a360。
- [P2] 升级后无法从原确认读回已提交的 Todo。 在精确基线确认一条只创建的 Todo,提交并保存旧版 todo_created 后中断。在同一个 Goal、注册表和权威库重启候选版,重试原确认。 File 和 SQLite 均返回 HTTP 400,提示缺少来源绑定。取消和重新生成也返回 409。同一存储由基线重新打开时返回 200 和相同的原回执,权威修订和 Todo 数量一致。 旧确认读取分支
- [P2] 无关写入卡住原任务指派。 确认创建并指派任务。原 Todo 提交且保存 checkpoint 后,在指派前向同一 Goal 提交一条无关 Todo。保留原任务内容、来源和目标 Agent,重试原确认。 File 和 SQLite 的首次指派和重试均返回 HTTP 400,原 Todo 一直未分配。同条件的基线完成指派并在重放时返回原回执。 这是 #8717 已报告的缺口,在本提交独立复现。指派的 revision 参数 #8717 的上游发现
动机 / Motivation
从 Chat 确认 Todo 或 Monitor,并需在断线、重启或升级后取回原操作结果的用户。 用户已经确认一条任务或监控。恢复时需要看到原确认、确定提交状态,并在同一 Todo 上完成剩余动作。 精确基线会接受过时 Monitor 确认,未持久化首份计划的丢失请求没有可重试标志;同源无关提交后仍能指派原 Todo。 候选保留首份计划中断后的原确认和两条同摘要的待展示卡。打包页面在 HTML 502 与两路 503 后仍可重试,读回原回执;预审后的无关修订使未写入 Monitor 返回 409。 独立验证使用源码打包 Chat 与真实回环 HTTP、隔离 File 和 SQLite。PostgreSQL 联调用例跳过,已安装桌面、在线飞书及托管 CI 待验证。
改动思路 / Approach
Chat 复用注册表来源、权威 Todo 交易与原操作回执。新 checkpoint 记录所审阅的 store、registry、revision 和操作身份。来源校验与可见的恢复入口分别落实在已有 HTTP 与展示所有者。 保留原确认的提交身份和权限校验。分开核对旧提交的只读回执与未执行的后续指派,后者在原 Todo 和授权仍匹配时采用当前 revision。 基线的来源见证和历史回执合同 注册来源解析
具体改动 / Changes
关键代码讲解
原确认在中断后可重试。已释放的首份计划显示原重试,活跃确认仍保持等待。未提交 Monitor 的原修订得到校验,过时请求返回 409。 同名恢复卡分别可达,两条待展示任务在概览和对话均能打开。原确认判定 Monitor 审阅修订 各提案独立身份
历史提交恢复仍不满足。旧提案的 canonical receipt 和 Todo 已保存,恢复只需可证明的原结果。原任务指派闭环未满足,Goal 级历史修订在一次普通提交之后仍用于后续指派。候选说明和边界
对主干的风险 / Risks
升级会留下仍存在于同一权威库、但从原确认取不回结果的任务。同源正常更新会让已确认任务悬在未分配状态。两个反例中 provider 都保持单次创建,后续重试没有新增写入。仓库现有 operation receipt、权威读取和 CAS 可用于恢复,保留换源、换库及撤销拒绝。当前恢复覆盖
语义与 CI 对齐
候选通过 131 项定向 Python 测试、27 项 TypeScript 测试及控制面类型检查,标准 premerge 通过 6 项直接和 19 项选中检查。两种宽度及两种存储的 16 个打包浏览器场景通过。精确基线的 50 项相关用例通过,两项反例均有同条件 HTTP 对照。 独立验证使用源码打包 Chat 与真实回环 HTTP、隔离 File 和 SQLite。PostgreSQL 联调用例跳过,已安装桌面、在线飞书及托管 CI 待验证。
我的整体评价 / Verdict
请求修改。为旧版已提交确认恢复只读回执。在历史证据能证明原预览、Goal 与权威源时,读回其原提交;证据不足时在原卡给出可执行的原来源恢复路径。 在同一权威源以原创建回执复核待分配 Todo 和当前授权,用当前 revision 做一次条件指派。保留同一指派操作 ID 与已提交回执路径。 用旧版实际写入的 checkpoint 启动候选,验证同源返还原回执、原 Todo ID 和一次提交;换源或同 ID 异库仍拒绝。 在 File 和 SQLite 加入无关提交,验证原指派恰好恢复一次;原 Todo 已变化、已被他人接管或注册撤销时继续拒绝。 桌面和 390 像素首屏都把两条待展示任务放在普通待办前。打开原确认后,长标题换行,重试按钮在状态说明下方,高级诊断折叠。 截图覆盖两种宽度、同摘要多条记录和网关故障后的确认抽屉。已安装 WebView 及超长任务列表待验证。
English verdict: REQUEST_CHANGES at e4fbd0f. Recover old committed confirmations across upgrades and finish the original assignment after unrelated same-Goal commits.
| raise ValueError("Todo creation checkpoint is malformed") | ||
| binding = todo_step.get("source") | ||
| if not isinstance(binding, dict): | ||
| raise ValueError("The created Task predates source binding. Recover the original Todo before assigning it.") |
There was a problem hiding this comment.
[P2] 升级后无法从原确认读回已提交的 Todo。 在精确基线确认一条只创建的 Todo,提交并保存旧版 todo_created 后中断。在同一个 Goal、注册表和权威库重启候选版,重试原确认。 File 和 SQLite 均返回 HTTP 400,提示缺少来源绑定。取消和重新生成也返回 409。同一存储由基线重新打开时返回 200 和相同的原回执,权威修订和 Todo 数量一致。 为旧版已提交确认恢复只读回执。在历史证据能证明原预览、Goal 与权威源时,读回其原提交;证据不足时在原卡给出可执行的原来源恢复路径。 用旧版实际写入的 checkpoint 启动候选,验证同源返还原回执、原 Todo ID 和一次提交;换源或同 ID 异库仍拒绝。
| claimed_by=str(agent_id), agent_id=str(agent_id), | ||
| authority_reason="owner-confirmed typed Chat action", | ||
| update_operation_id=assignment_operation_id, | ||
| update_expected_provider_revision=binding["provider_revision"], |
There was a problem hiding this comment.
[P2] 无关写入卡住原任务指派。 确认创建并指派任务。原 Todo 提交且保存 checkpoint 后,在指派前向同一 Goal 提交一条无关 Todo。保留原任务内容、来源和目标 Agent,重试原确认。 File 和 SQLite 的首次指派和重试均返回 HTTP 400,原 Todo 一直未分配。同条件的基线完成指派并在重放时返回原回执。 在同一权威源以原创建回执复核待分配 Todo 和当前授权,用当前 revision 做一次条件指派。保留同一指派操作 ID 与已提交回执路径。 在 File 和 SQLite 加入无关提交,验证原指派恰好恢复一次;原 Todo 已变化、已被他人接管或注册撤销时继续拒绝。 上游已有发现
Chat keeps the original confirmation available after a committed Todo or Monitor is waiting for display. Two pending confirmations with the same summary stay independently selectable. If a gateway returns HTML 502 and neither readback route is available, the same operation stays available for retry.
This update includes #8725's recovery before the first plan is saved and its Monitor revision check. A released confirmation can be retried on reload. A live confirmation stays pending. A Monitor whose reviewed revision changed before the first write returns stale.
Validation
e4fbd0f87dagainst disposable File and SQLite. All 16 scenarios at 1200 and 390 pixels passed. The gateway cases recovered both original receipts without advancing the authority revision. SQLite also covered the case where the display was still pending.cbdc765548.Review sequence remains #8717 → #8725 → #8727. All three target
main.Visual evidence
Packaged Chat with disposable Goal data at
e4fbd0f87d. Each image shows the original retry after HTML 502 and unavailable detail and list readback. The before-and-after capture of the first-plan interruption is on #8725.确认中断后从原操作续做。Monitor 首写沿用审阅时的来源和修订。
Release browser check
The installed browser shard reaches the saved Goal workspace-selection case and times out on its old start-first-run assertion. The failure reproduces on packaged main and on the installed wheel from the #8725 run. With the test correction, the full typed-actions scenario passes in both local comparisons. Hosted verification of the correction is pending. Failed job Test correction