fix: 克隆传输期时间心跳 (T13.14) 与 T13.12 两处复核修正 - #5
Merged
qiyinxi merged 7 commits intoSep 7, 2026
Conversation
真机初始化夹具暴露 workspace.clone 脉冲按 sideband Write 次数计数, 64 条预算在握手瞬间耗尽,packfile 传输的 7.9 秒零事件。登记 T13.14, 设计为注入 ticker 的 1 秒时间心跳;仍只发不带数值的 running,不触碰冻结契约。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
workspace.clone 的 running 脉冲原按 go-git sideband 的 Write 次数计数(上限 64), 而 sideband 文本集中在握手瞬间涌入,预算当场耗尽,之后 packfile 传输阶段零事件。 改为 Fetcher 在 Clone 前启动注入 ticker 的 1 秒心跳 goroutine,Clone 返回后先停止 并等待其退出再判定输出故障与终态;心跳仍只发不带数值的 running,sideband 文本 继续丢弃、不解析、不外发。心跳输出失败取消传输 context 并优先映射 OUTPUT_WRITE_FAILED。 测试:假时钟下同一瞬间多次 Write 不产生脉冲、5 秒静默 ≥ 4 条心跳、事件不含 Git 原文与数值字段、输出失败停止心跳并取消传输、终态之后不再出现 running(顺序断言)。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
设计文档的数据流漏了 newCloneHeartbeat 的 interval 参数、把 quit 通道写成 stop, TDD 计划少列了输出失败映射那条测试;AGENTS.md 的 M13 状态行补上 T13.14。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
5deb1d8 给 uv 下载接上字节进度回调后,下载器把回调错误包成 Kind=FailureProgress 的 DownloadFailure,但 bootstrap 的 download 闭包只认 Published 与校验和失败,其余一律 OutcomeSwitchSource。协议输出一断,5 个 uv 镜像源会被各空跑一次(每次都先发 HTTP 请求拿到响应头才触发首个回调),attempt 报告被标成 download_failed,uv 层错误码也降级成 UV_DOWNLOAD_FAILED,与设计文档 「协议写失败沿错误链保留 OUTPUT_WRITE_FAILED」冲突。 新增 isDownloadProgressFailure 谓词,命中时记下错误并以 OutcomeTargetFailure 结束整轮轮换;轮换返回后原样返回该错误(不经 wrapBootstrapError,避免用户可见 文案变成「uv 准备失败」)。对外错误码/退出码/message 本就取最外层四元组, 修复前后字节不变。写法对齐 dependencies_mirror.go 的报告失败与 gitrepo/clone.go 的 emit 失败先例。 测试:TestBootstrap_DownloadProgressFailureStopsRotation 与 TestUVDownloadProgress_OutputFailureStopsRotation 均用真实 Rotator(假 rotator 只调一次尝试且不看 Outcome.Kind,正是此前漏测的原因),修复前二者均报 calls = 5,修复后下载器只调 1 次、错误链保留原因且不是 RotationError, classifyFailure 得到 OUTPUT_WRITE_FAILED / uv.download。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
human_renderer 用 FormatFloat(-1) 原样打印 percent,而下载器给的 percent 是 received/total*100 未取整,human 模式会输出 percent=42.857142857142854%。 只改渲染端:先 math.Round(percent*100)/100 再格式化。NDJSON 数值不动——设计文档 要求三个数值逐字来自 mirror.DownloadProgress、CLI 不二次估算,且生产端取整会在 99.995% 时提前打出 100;架构文档也写明 human 模式不承诺机器可解析。 human 契约矩阵中 1e-9 那条快照期望由 percent=0.000000001% 改为 percent=0%, 42.86% 与 50% 两条不受影响。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
设计文档补「进度回调失败以 OutcomeTargetFailure 结束整轮镜像轮换,不逐源重试」; 任务拆分在 T13.12 条目下登记 2026-09-07 复核修正证据(7c7fc67 / d4fef5a)并在 变更记录加一行。T13.12 的完成状态文字不动。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
审查者指南本 PR 独立修正三处进度可观测性问题:以可注入 ticker 驱动克隆传输心跳并确保生命周期和错误收口,以 TargetFailure 终止 uv 进度输出失败后的镜像轮换并保留原始错误,同时将 human 模式百分比限制为两位小数而保持 NDJSON 数值不变。 克隆传输心跳生命周期时序图sequenceDiagram
participant Fetcher
participant Heartbeat as cloneHeartbeat
participant Ticker
participant Git as go-git
participant Progress as progressEmitter
Fetcher->>Heartbeat: start()
Heartbeat->>Ticker: newTicker(1 second)
Fetcher->>Git: Clone(cloneCtx, Progress=Heartbeat)
Git->>Heartbeat: Write(payload)
Heartbeat-->>Git: len(payload)
loop Every tick during Clone
Ticker-->>Heartbeat: tick
Heartbeat->>Progress: emit ProgressEvent(running)
end
Git-->>Fetcher: Clone returns
Fetcher->>Heartbeat: stop()
Heartbeat-->>Fetcher: goroutine stopped
Fetcher->>Heartbeat: Err()
Fetcher-->>Progress: emit terminal event
UV 进度失败停止镜像轮换流程图flowchart TD
Download["download()"] --> Rotator[rotator.Run]
Rotator --> Attempt[Download attempt]
Attempt --> Failure{isDownloadProgressFailure}
Failure -->|yes| TargetFailure[OutcomeTargetFailure]
TargetFailure --> ReturnError[Return original progress error]
Failure -->|no| OtherOutcome[Other attempt outcome]
OtherOutcome --> Retry[Mirror rotation may continue]
ReturnError --> Output[OUTPUT_WRITE_FAILED preserved]
human 模式进度百分比渲染流程图flowchart LR
Event[ProgressEvent.Percent] --> Human[HumanRenderer.RenderProgress]
Human --> Round[math.Round to two decimal places]
Round --> Text[Human-readable percent output]
Event --> NDJSON[NDJSON numeric value]
NDJSON --> Unchanged[Value remains unchanged]
文件级变更
提示和命令与 Sourcery 交互
自定义你的使用体验访问你的控制面板:
获取帮助Original review guide in EnglishReviewer's Guide本 PR 独立修正三处进度可观测性问题:以可注入 ticker 驱动克隆传输心跳并确保生命周期和错误收口,以 TargetFailure 终止 uv 进度输出失败后的镜像轮换并保留原始错误,同时将 human 模式百分比限制为两位小数而保持 NDJSON 数值不变。 Sequence diagram for clone transfer heartbeat lifecyclesequenceDiagram
participant Fetcher
participant Heartbeat as cloneHeartbeat
participant Ticker
participant Git as go-git
participant Progress as progressEmitter
Fetcher->>Heartbeat: start()
Heartbeat->>Ticker: newTicker(1 second)
Fetcher->>Git: Clone(cloneCtx, Progress=Heartbeat)
Git->>Heartbeat: Write(payload)
Heartbeat-->>Git: len(payload)
loop Every tick during Clone
Ticker-->>Heartbeat: tick
Heartbeat->>Progress: emit ProgressEvent(running)
end
Git-->>Fetcher: Clone returns
Fetcher->>Heartbeat: stop()
Heartbeat-->>Fetcher: goroutine stopped
Fetcher->>Heartbeat: Err()
Fetcher-->>Progress: emit terminal event
Flow diagram for UV progress failure stopping mirror rotationflowchart TD
Download["download()"] --> Rotator[rotator.Run]
Rotator --> Attempt[Download attempt]
Attempt --> Failure{isDownloadProgressFailure}
Failure -->|yes| TargetFailure[OutcomeTargetFailure]
TargetFailure --> ReturnError[Return original progress error]
Failure -->|no| OtherOutcome[Other attempt outcome]
OtherOutcome --> Retry[Mirror rotation may continue]
ReturnError --> Output[OUTPUT_WRITE_FAILED preserved]
Flow diagram for human progress percentage renderingflowchart LR
Event[ProgressEvent.Percent] --> Human[HumanRenderer.RenderProgress]
Human --> Round[math.Round to two decimal places]
Round --> Text[Human-readable percent output]
Event --> NDJSON[NDJSON numeric value]
NDJSON --> Unchanged[Value remains unchanged]
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
三件事,提交彼此独立、文件零重叠。不新增字段、stage、state、错误码或环境变量。
T13.14 克隆传输期时间心跳(
35d027ee8bc217848744298e9fd9)workspace.clone的进度脉冲原本按 sideband 写入次数计数、上限 64。go-git 的 sideband 集中在握手阶段涌入,真机夹具里 64 条脉冲全部落在同一时刻(23.260),之后真正传输 packfile 的 7.9 秒一条事件都没有,而且 66 条消息文案完全一样。改成固定 1 秒的 ticker 心跳:仍只发不带数值的 running(符合《架构设计》对 Git 阶段「只发不带数值的 running,由 Electron 展示不定进度」的要求),
Write保留io.Writer但丢弃 sideband 内容——那是外部自然语言,可能含 URL。stop()在 Clone 返回后、判定结果之前调用并阻塞等 goroutine 退出,保证终态之后不会有迟到的 running。fix(uv): 进度回调失败即结束镜像轮换(
7c7fc67,T13.12 复核修正)download()缺FailureProgress分支,一律落OutcomeSwitchSource。协议输出断掉时会把 5 个 uv 镜像源各空跑一次,attempt 报告标成download_failed,内层错误码降级成UV_DOWNLOAD_FAILED——与 T13.12 设计文档「协议写失败沿错误链保留OUTPUT_WRITE_FAILED,不得降级」冲突。改为OutcomeTargetFailure并原样返回回调错误(不经wrapBootstrapError,否则用户可见文案会从「协议输出失败」变掉)。对外四元组不变:修复前后实测均为
code=OUTPUT_WRITE_FAILED stage=uv.download message=协议输出失败 exit=20,差别只在下载器调用次数 5 → 1。这个缺陷此前测不出来的原因是
fakeRotationRunner只调一次 attempt 且不看Outcome.Kind,所以新增测试改用真mirror.NewRotator()。fix(protocol): human 模式百分比保留两位小数(
d4fef5a,T13.12 复核修正)下载器给的 percent 未取整,human 模式会打印
percent=42.857142857142854%。只改渲染端,NDJSON 数值不动——设计文档要求三个数值逐字来自mirror.DownloadProgress,而且两位取整会在 99.995% 时提前打出 100。验证
工作目录为该分支工作树,go1.26.5 windows/amd64,全部实跑:
gofmt -l .go vet ./...go build ./...go test ./... -count=1git diff --checkgo test -race ./internal/uv ./internal/mirror ./internal/gitrepo -count=1红→绿证据:
TestBootstrap_DownloadProgressFailureStopsRotation与TestUVDownloadProgress_OutputFailureStopsRotation在修复前均报downloader calls = 5, want 1;心跳的四条新测试在实现前编译失败。未做:没有真机跑过带真实字节进度的完整 bootstrap 看 Electron 界面表现。
🤖 Generated with Claude Code
Sourcery 摘要
在保持外部进度协议不变的同时,提高 Git 克隆和 UV 下载过程中进度报告的可靠性。
错误修复:
增强功能:
文档:
测试:
Original summary in English
Summary by Sourcery
Improve progress reporting reliability across Git cloning and UV downloads while keeping the external progress protocol unchanged.
Bug Fixes:
Enhancements:
Documentation:
Tests: