2026 年 7 月 2 日,我在备忘录里写了一点怀念。
那时想起的,是大模型还待在浏览器对话框里的日子。我把问题贴进去,等一段代码,再将代码放回项目。哪里报错,重新描述;哪句没看懂,也常常在复制的过程中暴露出来。
我并不怀念旧模型。手动搬运上下文很麻烦,稍大一点的改动就会反复丢失前文。我记住的是那些停顿:模型说完以后,接下来要等我;代码进入项目以前,要经过编辑器和终端;一次回答能推动的范围很小,我会反复碰到中间的细节。
Coding Agent 将这些停顿压缩了。它可以找文件、修改代码、运行检查,再交回一份清楚的完成报告。事情向前走得更快,阅读却没有自动获得同样的速度。那条备忘录只记录这种落差,没有某次任务的文件数量、测试结果或故障现场。
重新整理这篇文章时,我从自己的公开仓库里挑了一段很小的 diff,重新走了一遍。
我怀念的是停顿
完成报告很有用。任务范围变大以后,没有摘要很难快速知道改了什么、跑了什么、还剩什么。问题出在它太顺滑:每一行前面都有勾时,我很容易顺便相信理解也已经抵达。
过去一次回答只够改一小段,我会在复制、运行和修正之间反复经过代码。现在一个任务可以连续走过多个文件,最后只看到开头的要求和结尾的结果,中间的选择被折叠起来。
工具没有阻止我阅读。只是阅读从必经步骤变成了需要自己安排的步骤。我也不想回到全部手工搬运的日子。任务结束以后,能不能用自己的话说清变化,比“是否亲手写下每一行”更接近我在意的参与感。
提交说明和补丁不是同一份东西
样本来自公开仓库 poboll/thus-note。提交 6502121c 只修改一个文件,新增 6 行、删除 9 行,主题是图片处理中的异步等待和异常限制值。仓库采用 AGPL-3.0 许可证,提交与父提交都可以公开核对。
提交说明提到:给调用补上 await,处理离线模式中的 NaN,使用 blob URL 立即插入图片预览,删除调试日志,并记录几项测试结果。只看这段摘要,修改经过已经很完整。
补丁中最关键的变化很短:
- const onImageChange = (files: File[]) => {
- handleFiles(ceData, files, editor)
+ const onImageChange = async (files: File[]) => {
+ await handleFiles(ceData, files, editor)
}
- handleImages(ceData, imgFiles, editor)
+ await handleImages(ceData, imgFiles, editor)
- if(max_pic_num <= 0) max_pic_num = 9
+ if(!max_pic_num || max_pic_num <= 0 || isNaN(max_pic_num)) max_pic_num = 9
和父提交逐行比较后,有一处差别值得记下来:blob URL 预览逻辑在父提交里已经存在,不由这份补丁新增。日志确实被删除,等待顺序和兜底判断也确实发生了变化;“代码现在拥有什么能力”与“本提交增加了什么”并不是同一个问题。
这次我先把提交说明当成索引:它记录作者希望解决什么、声称检查过什么;再打开 diff,逐项核对其中的动词有没有对应变化。
顺着 await 往下看
第一处 await 出现在 onImageChange。原函数触发 handleFiles 后立即结束;修改后它变成异步函数,并等待 handleFiles 返回。第二处位于 handleFiles 内部:检测到图片时,会等待 handleImages 完成,再判断是否继续处理其他文件。
如果只看红绿行,两处都可以概括成“补 await”。再沿调用链多走一步,问题会变得具体:哪一层需要知道图片已经处理完成?后面是否依赖这个时刻清理状态?上层会不会消费返回的 Promise?
同一文件里,文件拖放监听本来就写着 await handleFiles(...);粘贴入口仍直接调用 handleFiles(...)。在 handleFiles 中,图片分支现在等待 handleImages,非图片分支仍直接调用异步的 handleOtherFiles。
这些差异不会自动构成 bug。浏览器事件可以允许后台动作继续,有些调用也不关心函数何时结束。它们形成了一个需要更多上下文的问题:修改想统一所有文件入口的完成语义,还是只处理图片选择这条路径?补丁没有改测试文件,当前材料无法替作者回答。
我过去常把这类问题当成“审阅还没做完”。这次先把它记成待核的问题,没有凭直觉继续扩大修改范围。
NaN 那一行
另一处修改只有一行。旧代码在 max_pic_num <= 0 时将限制值改为 9。若传入的是 NaN,JavaScript 中 NaN <= 0 为 false,兜底不会触发;随后 canPushNum 也会变成 NaN,循环第一次判断 i < canPushNum 时仍为 false,图片处理不会进入循环。
新条件增加了空值、非正数和 NaN 的判断。仅从固定代码和语言语义,可以确认它覆盖“值确实为 NaN”的分支。提交说明还写着离线模式曾产生这个值,但我没有重建当时的配置与依赖,所以那部分仍属于提交者的历史记录。
两个结论看起来只差几个字。一个来自眼前的代码,一个需要旧环境。完成报告很容易将它们一起收进“已修复”,慢下来读时,我才看见各自能证明到哪里。
测试记录留在它自己的时间里
提交说明记录了 Playwright、离线模式和生产构建通过。本次文章整理没有重建 3 月 3 日的环境,也没有复跑这些命令。我能确认的是:目标提交公开存在,补丁只改一个源文件,其中没有测试文件变化。
“没有测试变化”无法推导出当时没有运行测试;“说明里写着通过”也不会自动变成本轮独立复验。它们可以同时留在记录里,只是时间和证据身份不同。
我还对父提交与目标提交运行了 git diff --check。结果命中一处行尾空格,退出码为 2。这是格式残留,不能说明图片逻辑失败;本次结论因此把功能行为、历史测试和补丁整洁度分开记录。
固定父提交以后,文件现状才有了可以比较的 base 和 head;哪些行属于这次修改,也随之变得明确。
回到这份补丁
固定 base 和 head 后,文件列表与增删规模很快就能说清:只有一个文件,新增 6 行、删除 9 行,也没有生成物、配置或凭据混进来。
接着,我只沿 onImageChange -> handleFiles -> handleImages 这条路径往下走。Promise 在哪里被等待、状态在哪里变化、异常值会走向哪个分支,都可以从固定代码里找到;粘贴入口和非图片分支则停在问号处。
最后再回到提交说明,blob URL、历史测试和离线模式各自落在不同的证据层级。到这里,这份补丁仍有没回答的问题,但已经不再只剩下一段完成摘要。
做完以后
回到提交 6502121c,我现在能说清的内容并不复杂:它改变了图片处理链上的两处等待,扩展了异常限制值的兜底,删除了调试日志;blob URL 预览早已存在;本提交没有测试文件变化;历史测试来自提交说明;格式检查还留着一处空格;粘贴入口和非图片分支的等待语义需要更多上下文。
把这些细节放在一起,比一句“修复完成”更接近我对这次改动的理解。我没有重写 Agent 完成的代码,也没有记住每一行;入口、主要状态和现有证据已经能用自己的话复述。
7 月 2 日那条备忘录没有给出答案。它只是记下速度和参与感之间出现了一点距离。现在我仍然喜欢 Coding Agent 带来的效率,也愿意从省下来的时间里分一小段给 diff。
本文中的最小代码片段来自公开仓库 poboll/thus-note,许可证为 AGPL-3.0;阅读样本固定为提交 6502121c24b312dbed83989de1bab8a35aaa8380 及父提交 62c61f3c39c89d0f3c45bccd284e847645d82b53。本文不声称该提交由 Coding Agent 生成。