Skip to content

完善 Checkpoint 变更对比、差异展示与 Web 端交互修复#573

Merged
phantom5099 merged 5 commits into1024XEngineer:mainfrom
Yumiue:html_gui_build
May 8, 2026
Merged

完善 Checkpoint 变更对比、差异展示与 Web 端交互修复#573
phantom5099 merged 5 commits into1024XEngineer:mainfrom
Yumiue:html_gui_build

Conversation

@Yumiue
Copy link
Copy Markdown
Collaborator

@Yumiue Yumiue commented May 7, 2026

变更概述

  • Checkpoint 链路:完善变更对比与差异展示,补齐 per-edit 快照增强和恢复能力
  • Web 端修复:修正模型切换链路一致性,优化 ChatInput 多模态交互,修复 FileChangePanel 文件变更面板展示
  • Patch 解析增强:改进 unified diff 解析器,支持更准确的文件变更内容渲染
  • Bypass 机制:Gateway 层新增 bypass 通路,优化 Runtime 桥接层
  • 发布构建:补齐 goreleaser 配置,Web 端发布版本自动构建依赖

主要变化

Checkpoint

  • 增强 PerEditSnapshotStore 快照捕获与比较能力
  • 新增 checkpoint_restore.go 恢复逻辑
  • 补齐 end-of-turn checkpoint 创建与查找测试

Web 前端

  • ModelSelector:修复模型切换状态不一致问题
  • ChatInput:支持多模态输入,修复快捷键冲突
  • FileChangePanel:重构变更文件展示,适配 enhanced diff 格式
  • PatchParser:增强 unified diff 解析,支持 rename/copy/new file 模式
  • EventBridge:完善前后端事件桥接

Gateway / Runtime

  • Gateway Bootstrap 新增 bypass 模式
  • Runtime 桥接层接口优化

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

Copy link
Copy Markdown

@fennoai fennoai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found 2 noteworthy issues after code quality, performance, security, and documentation passes.

} catch (err) {
console.error('selectProviderModel failed:', err)
}
try {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setSelected(m) has already committed the optimistic UI state by the time this RPC runs, but the failure path only logs to the console. If setSessionModel / selectProviderModel fails, the dropdown keeps showing the new model even though the backend state never changed, and the deferred path has the same problem. Please either revert the optimistic state on error or surface a toast and re-sync from listModels() after a failed apply.


return Array.from(byPath.entries())
.filter(([path]) => path)
.filter(([path]) => {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This new filter drops every run-scoped file entry unless parseUnifiedPatch() produced at least one rendered diff line. That means legitimate backend-reported changes with no hunk body, such as zero-byte file add/delete or rename/copy-only patches, disappear from FileChangePanel even though diff.files still reports them. The UI should preserve those entries and treat the parsed patch as optional metadata instead of a hard requirement.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 7, 2026

@phantom5099

This comment was marked as low quality.

@fennoai

This comment was marked as resolved.

@phantom5099

This comment was marked as low quality.

@fennoai

This comment was marked as duplicate.

@1024XEngineer 1024XEngineer deleted a comment from fennoai Bot May 8, 2026
@phantom5099

This comment was marked as resolved.

@fennoai

This comment was marked as resolved.

@1024XEngineer 1024XEngineer deleted a comment from fennoai Bot May 8, 2026
@1024XEngineer 1024XEngineer deleted a comment from fennoai Bot May 8, 2026
@1024XEngineer 1024XEngineer deleted a comment from fennoai Bot May 8, 2026
@phantom5099

This comment was marked as resolved.

@fennoai
Copy link
Copy Markdown

fennoai Bot commented May 8, 2026

结论

origin/main 角度看,你这 7 条里只有少数能算“结果口径接近”或“结构上近似”,大多数不能算“已有等价实现”。核心原因是:main 现有能力主要依赖 pre-write + v_next / 当前 workdir 的推导,而这个 PR 新增的是把 target end-state 显式落盘并按需查询,这两类语义不是一回事。

逐条判断

  1. guard = FinalizePending + RestoreExact不准确
    origin/main 实际 guard 走的是 Finalize,不是 FinalizePending,见 internal/runtime/checkpoint_restore.go:60。而且 Finalize 写入的是 pending 里的 pre-write 版本,RestoreExact 也只是把这些版本直接写回,见 origin/maininternal/checkpoint/per_edit_snapshot.go:221origin/maininternal/checkpoint/per_edit_snapshot.go:314。这条链路能表达的是“回到 capture 基线”,不是“回到 restore 前的精确工作区状态”。origin/main 的测试也体现了这一点:文件先改成 afterundo 后仍回到 before,见 origin/maininternal/runtime/checkpoint_flow_test.go:421

  2. ExactFileVersions + FinalizeWithExactState + captureExactStateSnapshot 已有等价实现 = v_n 对偶模型:不准确
    origin/main 里没有 ExactFileVersionsFinalizeWithExactStatecaptureExactStateSnapshot 这些能力;我直接对 origin/main 做了符号检索,没有命中。main 现有的目标状态读取核心仍是 contentAtCheckpointLocked,它在没有 v_next 时会 fallback 到当前 workdir,见 origin/maininternal/checkpoint/per_edit_snapshot.go:731。当前 PR 新增的则是显式持久化 exact end-state,并优先读取 ExactFileVersions,见当前分支 internal/checkpoint/per_edit_snapshot.go:228internal/checkpoint/per_edit_snapshot.go:270internal/checkpoint/per_edit_snapshot.go:1028。这不是同一语义层级。

  3. DiffCheckpointsToWorkdir 已有等价实现 = RunAggregateDiff部分准确,但不能算等价
    origin/main 里没有 RunAggregateDiff 这个 helper;符号检索也没有结果。最接近的是 Run() defer 里的 EventRunDiffSummary,它使用 perEditStore.Diff(...) + ChangedFiles(...) 从 baseline checkpoint 到最后 end-of-turn checkpoint 发一次摘要,见 origin/maininternal/runtime/run.go:104。这更像一次性 run 完成事件,不是当前 PR 这种独立、可复用的聚合 API。

  4. DiffCheckpointsToCheckpoint 已有等价实现 = RunAggregateDiff + prevFileVersions不准确
    origin/main 没有“多个 checkpoint 的首触碰基线 -> 指定 target checkpoint 结束态”的独立能力。当前 PR 的 run-scope query 明确走 DiffCheckpointsToCheckpoint(...),见当前分支 internal/runtime/checkpoint_restore.go:404internal/runtime/checkpoint_restore.go:466,而它又依赖 contentAtExactVersionLockedcontentAtCheckpointTargetLocked,见当前分支 internal/checkpoint/per_edit_snapshot.go:576internal/checkpoint/per_edit_snapshot.go:1028origin/main 的最接近实现仍只是“相邻 checkpoint 的 Diff/ChangedFiles”,见 origin/maininternal/runtime/checkpoint_restore.go:371

  5. contentAtExactVersionLocked 已有等价实现 = contentAfterLastVersionLocked不准确
    origin/main 中没有 contentAfterLastVersionLocked 这个符号。现有核心 helper 是 contentAtCheckpointLocked,语义是“给我某 checkpoint 时刻的状态;没有 v_next 时回退到当前 workdir”,见 origin/maininternal/checkpoint/per_edit_snapshot.go:731。而当前 PR 的 contentAtExactVersionLocked 是“直接读取某个明确版本号的内容”,见当前分支 internal/checkpoint/per_edit_snapshot.go:1008。后者语义更强,不能视为前者的别名。

  6. checkpointDiffForRun 已有等价实现 = runDiff部分准确,但不能说等价
    如果你说的 runDiff 指的是 EventRunDiffSummary 这条 run 结束旁路摘要,那它确实和 run 级结果有关;但它不是 checkpoint.diff(scope=run) 这种按需 query path,而且口径也还是老的 Diff + ChangedFiles,见 origin/maininternal/runtime/run.go:104。当前 PR 则新增了真正的 query 入口 checkpointDiffForRun(...),并改为聚合 run 内 checkpoint,见当前分支 internal/runtime/checkpoint_restore.go:404

  7. gate 里的 FinalizeWithExactState 已有等价实现 = Finalize不准确
    这恰好是 PR 的实质变化之一。origin/main 的 end-of-turn 只调用 Finalize,见 origin/maininternal/runtime/checkpoint_gate.go:57;当前分支改成 FinalizeWithExactState,见当前分支 internal/runtime/checkpoint_gate.go:58。如果两者等价,就不需要新增 ExactFileVersionscaptureExactStateSnapshot 和对应读取逻辑了。

建议

  1. 如果你的真实论点是“origin/main 已经有一套可工作的 pre-write + v_next/workdir 推导模型”,这个判断成立;但它只能支持推导式 restore / diff,不能推出“本 PR 这些 exact-state 变更只是重命名”。
  2. guard 链路先明确产品语义。如果要的是“undo restore 回到 restore 发生前的精确工作区状态”,那 origin/mainFinalize + RestoreExact 不够;如果要的是“回到本轮 capture 基线”,那命名、注释、测试都应该收口到这个语义,不要继续写成“restore 前状态”。
  3. run diff 建议显式区分两类能力:
    origin/mainEventRunDiffSummary 更像 run 完成摘要。
    当前 PR 的 checkpoint.diff(scope=run) 是 checkpoint-based query。
    这两者可以并存,但不应继续都泛称为 run diff
  4. 之前已经指出的另外两点,不受这 7 条影响,仍然成立:
    web/src/utils/eventBridge.ts 里 run-scope 文件集合仍会被 patch 解析结果反向过滤。
    bypass 仍是前端自动发一次 allow_once,不是 Gateway/Runtime 的请求级模式。

一句话概括:origin/main 已有的是“可工作的推导式基线”,而这个 PR 引入的是“显式化的 exact target state”;前者和后者并非严格等价。

View job run

@phantom5099
Copy link
Copy Markdown
Collaborator

结论

origin/main 角度看,你这 7 条里只有少数能算“结果口径接近”或“结构上近似”,大多数不能算“已有等价实现”。核心原因是:main 现有能力主要依赖 pre-write + v_next / 当前 workdir 的推导,而这个 PR 新增的是把 target end-state 显式落盘并按需查询,这两类语义不是一回事。

逐条判断

  1. guard = FinalizePending + RestoreExact不准确
    origin/main 实际 guard 走的是 Finalize,不是 FinalizePending,见 internal/runtime/checkpoint_restore.go:60。而且 Finalize 写入的是 pending 里的 pre-write 版本,RestoreExact 也只是把这些版本直接写回,见 origin/maininternal/checkpoint/per_edit_snapshot.go:221origin/maininternal/checkpoint/per_edit_snapshot.go:314。这条链路能表达的是“回到 capture 基线”,不是“回到 restore 前的精确工作区状态”。origin/main 的测试也体现了这一点:文件先改成 afterundo 后仍回到 before,见 origin/maininternal/runtime/checkpoint_flow_test.go:421
  2. ExactFileVersions + FinalizeWithExactState + captureExactStateSnapshot 已有等价实现 = v_n 对偶模型:不准确
    origin/main 里没有 ExactFileVersionsFinalizeWithExactStatecaptureExactStateSnapshot 这些能力;我直接对 origin/main 做了符号检索,没有命中。main 现有的目标状态读取核心仍是 contentAtCheckpointLocked,它在没有 v_next 时会 fallback 到当前 workdir,见 origin/maininternal/checkpoint/per_edit_snapshot.go:731。当前 PR 新增的则是显式持久化 exact end-state,并优先读取 ExactFileVersions,见当前分支 internal/checkpoint/per_edit_snapshot.go:228internal/checkpoint/per_edit_snapshot.go:270internal/checkpoint/per_edit_snapshot.go:1028。这不是同一语义层级。
  3. DiffCheckpointsToWorkdir 已有等价实现 = RunAggregateDiff部分准确,但不能算等价
    origin/main 里没有 RunAggregateDiff 这个 helper;符号检索也没有结果。最接近的是 Run() defer 里的 EventRunDiffSummary,它使用 perEditStore.Diff(...) + ChangedFiles(...) 从 baseline checkpoint 到最后 end-of-turn checkpoint 发一次摘要,见 origin/maininternal/runtime/run.go:104。这更像一次性 run 完成事件,不是当前 PR 这种独立、可复用的聚合 API。
  4. DiffCheckpointsToCheckpoint 已有等价实现 = RunAggregateDiff + prevFileVersions不准确
    origin/main 没有“多个 checkpoint 的首触碰基线 -> 指定 target checkpoint 结束态”的独立能力。当前 PR 的 run-scope query 明确走 DiffCheckpointsToCheckpoint(...),见当前分支 internal/runtime/checkpoint_restore.go:404internal/runtime/checkpoint_restore.go:466,而它又依赖 contentAtExactVersionLockedcontentAtCheckpointTargetLocked,见当前分支 internal/checkpoint/per_edit_snapshot.go:576internal/checkpoint/per_edit_snapshot.go:1028origin/main 的最接近实现仍只是“相邻 checkpoint 的 Diff/ChangedFiles”,见 origin/maininternal/runtime/checkpoint_restore.go:371
  5. contentAtExactVersionLocked 已有等价实现 = contentAfterLastVersionLocked不准确
    origin/main 中没有 contentAfterLastVersionLocked 这个符号。现有核心 helper 是 contentAtCheckpointLocked,语义是“给我某 checkpoint 时刻的状态;没有 v_next 时回退到当前 workdir”,见 origin/maininternal/checkpoint/per_edit_snapshot.go:731。而当前 PR 的 contentAtExactVersionLocked 是“直接读取某个明确版本号的内容”,见当前分支 internal/checkpoint/per_edit_snapshot.go:1008。后者语义更强,不能视为前者的别名。
  6. checkpointDiffForRun 已有等价实现 = runDiff部分准确,但不能说等价
    如果你说的 runDiff 指的是 EventRunDiffSummary 这条 run 结束旁路摘要,那它确实和 run 级结果有关;但它不是 checkpoint.diff(scope=run) 这种按需 query path,而且口径也还是老的 Diff + ChangedFiles,见 origin/maininternal/runtime/run.go:104。当前 PR 则新增了真正的 query 入口 checkpointDiffForRun(...),并改为聚合 run 内 checkpoint,见当前分支 internal/runtime/checkpoint_restore.go:404
  7. gate 里的 FinalizeWithExactState 已有等价实现 = Finalize不准确
    这恰好是 PR 的实质变化之一。origin/main 的 end-of-turn 只调用 Finalize,见 origin/maininternal/runtime/checkpoint_gate.go:57;当前分支改成 FinalizeWithExactState,见当前分支 internal/runtime/checkpoint_gate.go:58。如果两者等价,就不需要新增 ExactFileVersionscaptureExactStateSnapshot 和对应读取逻辑了。

建议

  1. 如果你的真实论点是“origin/main 已经有一套可工作的 pre-write + v_next/workdir 推导模型”,这个判断成立;但它只能支持推导式 restore / diff,不能推出“本 PR 这些 exact-state 变更只是重命名”。
  2. guard 链路先明确产品语义。如果要的是“undo restore 回到 restore 发生前的精确工作区状态”,那 origin/mainFinalize + RestoreExact 不够;如果要的是“回到本轮 capture 基线”,那命名、注释、测试都应该收口到这个语义,不要继续写成“restore 前状态”。
  3. run diff 建议显式区分两类能力:
    origin/mainEventRunDiffSummary 更像 run 完成摘要。
    当前 PR 的 checkpoint.diff(scope=run) 是 checkpoint-based query。
    这两者可以并存,但不应继续都泛称为 run diff
  4. 之前已经指出的另外两点,不受这 7 条影响,仍然成立:
    web/src/utils/eventBridge.ts 里 run-scope 文件集合仍会被 patch 解析结果反向过滤。
    bypass 仍是前端自动发一次 allow_once,不是 Gateway/Runtime 的请求级模式。

一句话概括:origin/main 已有的是“可工作的推导式基线”,而这个 PR 引入的是“显式化的 exact target state”;前者和后者并非严格等价。

View job run

@xgopilot 解决冲突,提交PR到Fork仓库

@fennoai
Copy link
Copy Markdown

fennoai Bot commented May 8, 2026

结果

  • 已解决当前分支相对 origin/main 的冲突点,并保留本 PR 的 exact-state checkpoint 语义。
  • 已补齐与 upstream 演进相关的 restore/guard 兼容改动,更新冲突测试口径。
  • 已执行 gofmt -w ...go test ./...,当前分支测试通过。

提交与 Fork PR

说明

  • 原 PR 分支 html_gui_build 未被直接改写;补丁已推到 Fork 新分支,并在 Fork 仓库内更新对应 PR,便于作者按需合入。

View job run

@Yumiue Yumiue force-pushed the html_gui_build branch from b815902 to 0a04b0d Compare May 8, 2026 08:40
@phantom5099 phantom5099 merged commit 57e5b7e into 1024XEngineer:main May 8, 2026
2 of 3 checks passed
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.

3 participants