Repository navigation
Recover confirmed task starts and show their execution - #8649
loopx-agent wants to merge 14 commits into
Conversation
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
loopx-agent
left a comment
There was a problem hiding this comment.
Request changes conclusion (author-owned PR; GitHub blocks formal self-review)
Reviewer: model_agent · gpt-6.1-sol · OpenAI · runtime_reported · max
本次评审对应提交 cd35c8971c9e3296aa5d14ec6b4eeb886ab5e315。
[P2] 让首轮回执打开它记录的 Turn。 首轮已经完成时,如果用户继续纠偏,原首轮回执会打开整个 Session 当前状态。页面把后续 Turn 的执行中状态放在首轮回执的目标上。 匹配条件
动机 / Motivation
在 Goal 对话里确认创建并开始执行,再从原确认卡查结果的用户。用户确认创建并开始任务后,需要从同一张确认卡看实际执行。在同配置的 SQLite 硬租约 fixture 上,当前主干的首次任务在归属检查被拒。当前 head 能沿 canonical claim 恢复确认,一次写入创建和认领,启动同一任务,并在卡片上展示已提交执行。验证使用独立安装的本地 wheel、SQLite 和确定性 Codex 协议 fixture。原生桌面安装、真实模型及更多内容规模仍待验证。首轮已经完成时,如果用户继续纠偏,原首轮回执会打开整个 Session 当前状态。页面把后续 Turn 的执行中状态放在首轮回执的目标上。
改动思路 / Approach
认领和重试沿用 canonical claim,这部分保持了同一动作的身份。回执导航仍需把 Turn 从 owner 一直带到读取结果的入口。修复局限在现有任务确认和执行详情链路,原 Session 入口仍适合查看整段历史。 保留创建 Todo、认领和提交 Turn 的顺序。响应丢失时由原 proposal 的 checkpoint 与 canonical claim 恢复。卡片可展示提交状态。连接回执和执行详情时仍需把实际 Turn 身份交给现有读取入口。
具体改动 / Changes
关键代码讲解
按 docs/development/frontend-delivery.md 在 708c68e7040559b2a4368002439570b90bc080b2 的任务交付规则核验 authorized-operation、recovery、result-readback。同一 SQLite 硬租约合成任务在主干发生 actor binding 拒绝,本提交完成认领并启动一轮。ChatActionService.apply 写回原 Todo 和 Session,taskExecutionReadback 校验回执包含 Turn。ContextDrawer 查找 Run 时只比 Goal、Todo、Session。 创建和启动 导航
对主干的风险 / Risks
打包 Chat 上先让首轮完成,再在同一 Session 启动后续纠偏。第一张回执仍绑定首轮,两个 Turn 的 ID 不同。按 Enter 打开原回执后,详情显示后续纠偏的消息与执行中状态,首轮结果混在整段历史里。单次启动时两个身份碰巧一致,现有单轮测试覆盖不了这条路径。 Session 运行投影
语义与 CI 对齐
26 项 Python、19 项 TypeScript、控制面类型检查和本地标准 premerge 通过。匹配当前 main 与 head 的本地 wheel、SQLite 和同一模拟协议。File 与 SQLite、软认领和硬租约的原生 API 回归覆盖分配提交后响应丢失。托管 CI 未查。
我的整体评价 / Verdict
在 taskExecution 保留回执的 turnId,由已验 Goal、Todo、Session、Turn 四元组定位原始结果。原 Turn 未加载时显示回执可用、结果待读的状态。现有产品路径已经能提交任务并展示回执。补上同一 Session 两轮时的原结果定位后,再复核完整旅程。实际查看 1440 px 和 390 px 的已提交卡片。状态与主按钮清楚,诊断折叠在下方。含首轮结果和纠偏消息的窄屏执行详情复现了目标漂移。验证使用独立安装的本地 wheel、SQLite 和确定性 Codex 协议 fixture。原生桌面安装、真实模型及更多内容规模仍待验证。
English verdict: REQUEST_CHANGES. The verified launch receipt loses its Turn ID before navigation, so a later correction can become the selected execution.
| const proposalTarget = selection.kind === "proposal" ? selection.item : null; | ||
| const taskExecution = proposalTarget?.status === "applied" && !proposalReadbackUnavailable | ||
| ? proposalTarget.reviewPlan?.taskExecution : undefined; | ||
| const startedTaskRun = taskExecution && runs.find(run => run.goalId === taskExecution.goalId |
There was a problem hiding this comment.
[P2] 让首轮回执打开它记录的 Turn。 首轮已完成,用户在同一 Session 启动后续纠偏,再从原确认回执选择查看执行过程。首轮已经完成时,如果用户继续纠偏,原首轮回执会打开整个 Session 当前状态。页面把后续 Turn 的执行中状态放在首轮回执的目标上。 taskExecutionReadback 检查资源的 turn_id 非空,但返回时丢掉该字段。ContextDrawer 只匹配 Goal、Todo、Session。现有运行行取 session.active_turn_id,因此会指向后续纠偏。 在 taskExecution 保留回执的 turnId,由已验 Goal、Todo、Session、Turn 四元组定位原始结果。原 Turn 未加载时显示回执可用、结果待读的状态。 在打包 Chat 中确认第一轮并读回结果,随后在同一 Session 启动第二轮。用键盘打开原回执,断言详情以第一轮的 Turn ID 和已读回结果为准。
) Source acceptance for the first Goal and runtime readiness now executes the real backend and requires readback before PASS. Read-only socket recovery and research-help keyboard checks retain their original bounds and assertions. Paired RFC checkpoints record the scoped qualification and remaining R1/M3 boundaries. Validation: complete local and Linux source86-scenario coverage; installed-candidate86-scenario catalog and team/craft companions with common provenance; strict negative cases; exact final premerge. Full bilingual exact-head review is published and all review threads are clear. Maintainer-authorized admin merge: unchanged head reviewed; current changed invariants and required validation pass. Normal readiness is held by six queued Python shards and the identical pre-existing Windows small-row40386/40000 output-baseline failure on the unchanged owner. No historical failure is reclassified and whole-goal regression/qualification remains open. Signed-off-by: lusendong.6789 <lusendong.6789@bytedance.com>
* fix(change-quality): preserve CR and CRLF in Git paths Read Git path output as bytes and split NUL-framed records before decoding. This avoids universal-newline translation rewriting legal CR and CRLF filenames, and stops replacement decoding from collapsing distinct undecodable paths. The repository root read uses the same lossless path boundary and removes only Git's terminal LF. Tests cover untracked CR and CRLF names and a checkout directory ending in LF. Signed-off-by: ChengLong GU <88359731+gcl-coder@users.noreply.github.com> * test(change-quality): cover CR, CRLF, and non-UTF-8 Git scope paths Signed-off-by: gcl-coder <gcl-coder@users.noreply.github.com> --------- Signed-off-by: ChengLong GU <88359731+gcl-coder@users.noreply.github.com> Signed-off-by: gcl-coder <gcl-coder@users.noreply.github.com> Co-authored-by: gcl-coder <gcl-coder@users.noreply.github.com>
) * fix(integration-branch): preserve worktree paths with line breaks `git worktree list --porcelain` frames fields on LF and prints paths verbatim. A worktree path containing LF or CR was split into multiple fields, so `_worktree_for_branch` could return a prefix and cleanup or reset could target the wrong checkout. Read `worktree list --porcelain -z` as bytes, split records on NUL pairs and paths on NUL, and keep the bounded Git process lifecycle shared by text and byte reads. Add real LF and CR worktree regressions. Signed-off-by: ChengLong GU <88359731+gcl-coder@users.noreply.github.com> * fix(integration-branch): support Git without worktree-list NUL framing Git 2.35 rejects 'worktree list -z' with an unknown switch, so every ordinary sync failed before resolving its checkout. Fall back to the line-framed porcelain inventory and keep only structural records; paths that a line-framed format cannot represent now fail closed with an explicit Git 2.36 message instead of resolving a prefix. Add regressions using a legacy Git stub for ordinary worktree resolution and sync --execute, plus LF and CR paths that must be refused. Signed-off-by: ChengLong GU <88359731+gcl-coder@users.noreply.github.com> * fix(integration-branch): accept bare records and verify checkout ownership The line-framed fallback rejected a bare repository's main worktree record because it expected a HEAD field, so an ordinary linked checkout could not sync on Git 2.35. Accept records that carry the bare field and skip them, while requiring every other record to be a complete HEAD-framed checkout. Verify the top-level path, common Git directory and attached branch before resetting a checkout. A worktree path containing line breaks can still fabricate a complete record in the line-framed inventory, so ownership is confirmed from the actual checkout before any write. Regressions cover a bare repository with a linked integration worktree under a legacy Git stub and a parsed checkout on another branch that must not be reset or recorded in the plan. Signed-off-by: ChengLong GU <88359731+gcl-coder@users.noreply.github.com> * fix(integration-branch): preserve ownership paths and select Git format by version Read the checkout path and common directory as bytes and remove only the newline Git appends, so a valid worktree name ending in LF, CR or whitespace is compared exactly before any reset. Choose the worktree inventory format from `git version` instead of parsing a localized usage error. Git 2.36 added `worktree list -z`; older releases keep using the fail-closed line-framed inventory. Add full sync regressions for those path suffixes and a localized legacy-Git diagnostic. Signed-off-by: ChengLong GU <88359731+gcl-coder@users.noreply.github.com> * fix(integration-branch): preserve requested repository roots Resolve the repository root through the byte path reader so a checkout whose path ends in LF or whitespace is not redirected to an adjacent repository. The entry point now strips only the terminal newline emitted by Git, matching the ownership checks added for reset. Add full sync regressions for two independent repositories whose names differ by a trailing LF. The configured checkout must sync itself while leaving its neighbor's integration ref and plan unchanged, and a checkout without a local plan must fail before reading the neighbor. Signed-off-by: ChengLong GU <88359731+gcl-coder@users.noreply.github.com> --------- Signed-off-by: ChengLong GU <88359731+gcl-coder@users.noreply.github.com>
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
Signed-off-by: lusendong.6789 <lusendong.6789@bytedance.com> Co-authored-by: TRAE CLI <traecli@bytedance.com>
…ged-20261112t171437 fix(core): enable guided goal startup through existing owners
Signed-off-by: lusendong.6789 <lusendong.6789@bytedance.com> Co-authored-by: TRAE CLI <traecli@bytedance.com>
Signed-off-by: lusendong.6789 <lusendong.6789@bytedance.com> Co-authored-by: TRAE CLI <traecli@bytedance.com>
…20261112t201145 Isolate startup metadata and restore installed refinement guidance
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com> Co-authored-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
loopx-agent
left a comment
There was a problem hiding this comment.
Request changes conclusion (author-owned PR; GitHub blocks formal self-review)
Reviewer: model_agent · gpt-6.1-sol · OpenAI · runtime_reported · max
本次评审对应提交 13bd68bac660ba70f37765b6695a971dc4d11757。
[P2] 在终止状态先于错误消息写入时保留回执重读。 打开的回执若先读到 failed、后收到该轮错误消息,会一直显示“本次执行已结束,未返回结果”;真正的原因只在收起再打开后出现。 停止重读处
动机 / Motivation
在 Goal 对话里确认开始任务,随后从原回执查结果的用户。用户在 Goal 对话里确认创建并执行任务,再从原回执查看结果。同配置的主干在归属检查拒绝首次执行;前一评审头可启动,但原回执会打开同一 Session 的最新轮次。当前提交能沿同一 proposal 和 canonical claim 恢复启动,并从原回执准确显示第一轮结果,即使后续修正仍在运行。本地独立安装的 wheel、SQLite、合成 Codex 协议与 Chromium 验证;未查托管 CI,未验证真实模型或原生桌面。打开的回执若先读到 failed、后收到该轮错误消息,会一直显示“本次执行已结束,未返回结果”;真正的原因只在收起再打开后出现。
改动思路 / Approach
已有 Todo claim、Chat Turn 和有分页的 history endpoint 足够承载任务身份与回执。新视图是读投影;应从原 Turn 的结果交付判断是否可结束读取。显式启动及其精确 Turn 只读路径;普通建 Todo 和整段 Session 浏览沿用原 owner,视觉反馈文案单独调整。 保留一次确认和 canonical claim;已确认的重试沿原 proposal。只读结果使用原四元组,不再从当前运行行推断。打开正常结果不需要复制 ID、再授权或再启动。终态读取应复用原结果生产边界,并提供同一 Turn 的恢复入口。
具体改动 / Changes
关键代码讲解
依据 docs/development/frontend-delivery.md 在 f6cde42e7c6bb17e128df975669e917a95f0534d 的 Task-first delivery:authorized-operation 已覆盖原 proposal 的启动;recovery 覆盖丢失分配响应与缺失原记录;result-readback 的首轮定位已修,终止状态与结果交付的交错仍未满足。
- ChatActionService.apply 以原 proposal ID 做 claim,保存 Todo 和 Session checkpoint,同一确认重试仍指同一任务。SQLite 硬租约实测通过;File/SQLite × soft claim/hard lease 的响应丢失回归也通过。
- taskExecutionReadback 保留 Goal、Todo、Session、Turn,校验 canonical receipt。普通创建没有 execution ID;既有未验证 operation delivery 仍停在 repair。
- project_chat_session_snapshot 给既有分页读取提供 selected Turn;ConfirmedTaskResult 只展开该轮的可见答复。第二轮运行时,刷新后用 Enter 打开第一轮,仍得到第一轮的已完成结果。
对主干的风险 / Risks
以打包 wheel、真实 SQLite HTTP 和确定性协议复现。在已有 _fail_turn 写入 failed 后,只在 append 错误消息前暂停写入。此时 GET 返回 terminal=true、只有用户行;打开的回执显示“未返回结果”。放开写入后,同一 GET 已有 error 行,已打开的面板仍旧,也没有重试按钮。收起再打开即可读到错误原因。这个问题来自新面板对 terminal 的解释;底层写入次序在主干已有。失败与超时共用 _fail_turn;实测的是 failed。 现有写序 新终止条件
语义与 CI 对齐
原精确头 137 项 Python、20 项 TypeScript、类型检查和本地 standard premerge 通过;与当前 main 的组合 quick 通过,双语 RFC 检查通过。旧 head 的错位已用当前打包 UI 复验修复,原记录缺失后的同回执重试也通过。普通创建的无启动行为相同,文案改为“任务已创建”;显式分配路径原有的相同归属拒绝未变。复用既有终止词表,扩展已有 Turn 读回与展示字段,未增加新的 authority。复验请在现有 Chat HTTP 故障夹具增加 failed 已写而 error 消息仍未落盘的交错,验证同一回执与零新增 turn/start。
我的整体评价 / Verdict
请求修改。启动恢复让后续工作能沿原任务继续;成功结果的定位已改善。失败回执仍会掩盖实际原因并要求用户猜测如何恢复,必须补上同一原 Turn 的可见恢复。有效 diff 15 个文件,另外 28 个远端列表路径是主干继承;未引入第二份任务状态。实际查看 1440 px 的收起态与 390 px 的展开态;任务名、提交状态和主按钮顺序清楚,诊断默认折叠。桌面有混合任务与回执,窄屏结果无需横向滚动。本地独立安装的 wheel、SQLite、合成 Codex 协议与 Chromium 验证;未查托管 CI,未验证真实模型或原生桌面。
English verdict: REQUEST_CHANGES. The exact-turn navigation is fixed, but a terminal status can freeze an empty receipt before the failure transcript arrives.
| const result = await fetchConfirmedTaskTurn({goalId, todoId, sessionId, turnId}, controller.signal); | ||
| if (controller.signal.aborted) return; | ||
| setRead(result); | ||
| if (!result.turn.terminal) next = setTimeout(load, 2_500); |
There was a problem hiding this comment.
[P2] 在终止状态先于错误消息写入时保留回执重读。 原任务已提交;执行器失败,Turn 的终止状态刚提交,错误消息仍在写入,用户此时打开原回执。ChatRuntimeController._fail_turn 先 update_turn(status=failed),随后 append_message(role=error);project_chat_session_snapshot 只按 status 推出 terminal,ConfirmedTaskResult 收到 terminal 后停读,空结果分支也没有重试。 打开的回执若先读到 failed、后收到该轮错误消息,会一直显示“本次执行已结束,未返回结果”;真正的原因只在收起再打开后出现。 让已有精确 Turn 读取区分终止状态与结果已可读;在失败、超时或中断的可见结果尚未写入时,允许同一 Turn 有界重读或给出就地重试。不要重启任务,也不要切到 Session 的新 Turn。 在打包 Chat 的真实 SQLite 路径暂停失败消息 append 前的 IO,用 Enter 打开原回执;确认错误写入后,同一打开面板可显示原因或就地重读,协议 turn/start 次数不增加。
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)
评审提交 13bd68b。
[P2] 原任务回执在 Chat 重启后持续等待。 只打开这张回执时,页面每 2.5 秒查询原轮次,持续显示等待结果。读取同一会话的现有入口后,Core 才把原轮次标为失败并给出可继续会话的说明。模型侧只收到一次原启动。 让回执通过现有执行恢复 owner 核对所选的 Session 和 Turn。读到已退出的 worker 时显示原轮次的终态与恢复说明。保留无关轮次和纯历史读取的边界。 回执轮询 历史读取分支
动机 / Motivation
在 Goal 对话中确认开始任务、随后从原回执查看执行结果的用户会遇到这个问题。 旧版的任务启动可能因认领被拒。上一版提案能启动任务,但同一会话继续纠偏后,原回执会打开会话的最新状态。当前提交能独立显示原轮次。 我在隔离安装的候选 wheel 上核实,后续轮次运行时,旧回执经刷新仍读到原结果。运行中的 Chat 服务被终止并重启后,原回执连续三次仍读到 running,重放确认也维持该状态。 验证使用打包 Web、SQLite 和确定性的 Codex 协议进程。真实模型、原生桌面安装和托管 CI 未测。
改动思路 / Approach
范围限已确认任务的 canonical 认领、同一启动的恢复及原执行回执的展示。 这次沿用 canonical Task claim,把确认动作与同一任务会话和轮次绑定。浏览器沿原历史入口按 Goal、Task channel 和 Turn 读回。保留原回执和窄屏上的一个结果按钮有直接价值。回执和 canonical claim 保留当前边界。退出 worker 的终态由既有恢复 owner 核对。启动和重试 精确结果读取
具体改动 / Changes
关键代码讲解
- authorized-operation 已覆盖。
ChatActionService.apply用同一 proposal 对应的认领操作。认领响应丢失后恢复既有 Todo,在 File、SQLite 的两种认领模式中各启动一次。认领入口 - result-readback 已覆盖。
taskExecutionReadback核对确认回执,project_chat_session_snapshot按原轮次筛选消息,fetchConfirmedTaskTurn核对会话身份。打包后用 HTTP 启动并原样重放同一确认。旧回执在后续轮次 running 时仍返回原先 completed 和同一组消息。1200 px 与 390 px 查看原结果。原记录暂时缺失时提交回执仍在,恢复记录后按 Enter 重试成功。 回执校验 原轮次分页 - failure-recovery 仍有缺口。
ConfirmedTaskResult只按原轮次的历史结果停止等待。服务重启后该读取绕过现有恢复判断。界面的缺失记录重试已经通过。新结果组件
验收依据为 docs/development/frontend-delivery.md,版本 167b0a1。GitHub 页面相对分叉点显示 43 个文件。我将整个 PR 与当前主干试合并,净改 15 个文件。已读原评审及对应 UI 证据。原「后续轮次覆盖首轮」发现已独立复验通过。同头评审另报终态已写而错误消息尚未落盘的交错。本轮复现的是重启后原轮次始终未进入终态,普通会话读取才触发已有恢复。 同头评审任务交付规范
对主干的风险 / Risks
只打开这张回执时,页面每 2.5 秒查询原轮次,持续显示等待结果。读取同一会话的现有入口后,Core 才把原轮次标为失败并给出可继续会话的说明。模型侧只收到一次原启动。 旧普通会话入口和原轮次事件入口已有执行退出处理。原回执在此场景绕过该 owner,令用户只能换入口才能看见失败。应把恢复限定在回执绑定的原轮次,同时保持无关轮次的状态和读历史权限。现有执行恢复
语义与 CI 对齐
新加的任务重试值和选中轮次字段属于现有动作投影及 Chat 历史契约。普通创建各 14 项在主干和候选均通过。候选真实 HTTP/File 与 SQLite 硬租约、软认领的四组认领响应丢失复验通过。三个历史读取用例、20 个 TS 行为测试、打包产物逐文件 HTTP 哈希、Ruff、DCO 和双语门通过。 原 Dashboard action-review smoke 在主干和候选都报 TS5097。显式加入 allowImportingTsExtensions 后,候选 typecheck 和两项行为断言通过。 请在真实打包的同一 SQLite 测试中确认任务并等到 provider 启动,终止隔离 Chat 服务,再只打开原回执。断言同一轮次显示失败和恢复说明,provider 仍只有一次启动。保留同会话另一轮正在运行的反例。
我的整体评价 / Verdict
请求修改。原轮次导航已经修复。重启后仅从回执进入仍无法完成故障读回,页面会持续等待。 多轮结果读回已有改善。当前重启路径会增加等待及反复读取,阻断同一回执下的结果交付。桌面和窄屏的回执把结果按钮放在提交状态下方,诊断默认折叠。展开后完成态和结果同屏,原记录缺失时保留提交状态和重试入口。 视觉核验覆盖一组双轮次合成任务。长结果、高密度任务列表和原生桌面窗口仍待核验。 将故障恢复接入现有 owner 后,可以沿相同的打包测试复审。验证使用打包 Web、SQLite 和确定性的 Codex 协议进程。真实模型、原生桌面安装和托管 CI 未测。
English verdict: REQUEST_CHANGES. The previous exact-result issue is fixed. After a real Chat service restart, the new exact receipt kept reading the exited Turn as running. The existing session recovery marked that same Turn failed, and the provider saw one original start. Reconcile that exact Turn before keeping the receipt in its pending state.
| const result = await fetchConfirmedTaskTurn({goalId, todoId, sessionId, turnId}, controller.signal); | ||
| if (controller.signal.aborted) return; | ||
| setRead(result); | ||
| if (!result.turn.terminal) next = setTimeout(load, 2_500); |
There was a problem hiding this comment.
[P2] 原任务回执在 Chat 重启后持续等待。 隔离 wheel 上真实终止并重启 Chat 服务,连续三次原回执查询和重放确认均保留 running。普通会话读取将同一轮次变为 failed,原 provider 调用仍一次。让回执通过现有执行恢复 owner 核对所选的 Session 和 Turn。读到已退出的 worker 时显示原轮次的终态与恢复说明。保留无关轮次和纯历史读取的边界。 增加仅打开原回执的真实重启回归。
Problem and outcome
Confirming a first task now records that execution was submitted and keeps the original receipt in the conversation. Opening it reads that exact execution, even after a refresh or a later correction in the same session. If the original record is missing, the receipt stays visible and offers a read retry.
The launch still uses the canonical Task claim. A lost response after the claim can be retried through the same confirmation without starting another Task Session. Creating a task without execution retains its existing behavior.
Validation
13bd68bac660ba70f37765b6695a971dc4d11757and ran the packaged Chat against SQLite with the deterministic Codex protocol fixture and public cart exercise. A lost assignment response recovered the original Task Session; the worker ran six passing checks.cd35c8971c9e3296aa5d14ec6b4eeb886ab5e315. In the candidate, reopening the original receipt after reload returned its first result while a second Turn remained active. Removed and restored the original Turn in the disposable fixture: the receipt kept its submitted status and recovered through the same read action.Visual evidence
Public cart fixture, packaged web build, 1440 px and 390 px. The receipt puts the result first, retains the submitted state when the original source is unavailable, and keeps advanced diagnostics collapsed.
Before
After