生活分享
修复 Bug 的完整流程
好的除错从可重现的症状开始,再用证据缩小原因,最后验证修正。『网站坏了』不够具体;提供哪个输入、在哪个步骤、期待什么、实际出现什么,能让 Codex 更快找到相关程式。
阅读时间约 14 分钟 · 操作 25 分钟

返回 Codex 教学总目录Codex 学习中心:完整教程目录从安装、第一个任务到 MD 规则与进阶集成,规划 60 篇 Codex 教程、十个单元。按程度、平台、需求或命令搜索下一篇;尚未公开的教程会标示状态,方便安排学习路线。阅读全文
目标与准备
本段提到的教学与资源: 既有专案阅读先读懂一个既有专案用唯读流程找到启动点、资料流与测试,产生有档案依据的专案地图。阅读全文
步骤 1:固定故障版本与重现步骤
从练习 ZIP 的 broken 复制五个档案到新资料夹 codex-bug-lab,保留原版。这份程式已有筛选分支,但 Completed 的条件故意写反;与 start「尚未实作筛选」不同。开编辑器,PowerShell 用 Get-Location、macOS/Linux 用 pwd 确认位置,再执行既有测试,预期 2 过 1 败。
node --test core.test.mjs
要确认画面,从本目录启动本机预览:Windows 执行 py -m http.server 4173 --bind 127.0.0.1,macOS/Linux 执行 python3 -m http.server 4173 --bind 127.0.0.1。开 http://127.0.0.1:4173;若有想保留的虚构资料先记录,再使用 Reset practice data,切到 All tasks 并确认空清单。接著依序新增 Read、Build,只勾选 Read,再切 Completed。预期应是 Read,故障版实际却显示 Build;把这个顺序完整记下。资料重设不会还原程式档。
故障报告要带执行环境、起点、操作、预期、实际与证据,先不要填「原因一定是快取」。下列范本只记已观察的现象;日期与测试结果由你填入。若你的画面显示不同,先核对预览目录及是否混入 expected,不把文章预期硬写成自己的实测。
# Bug: Completed shows unfinished tasks
Environment/date: fill from this run
Fixture: broken copied to codex-bug-lab
Steps: reset practice data; add Read and Build; complete Read; select Completed.
Expected: Read only.
Observed: Build only, if reproduced.
Baseline: node --test core.test.mjs; fill actual result.
Scope: keep UI, storage format, ordering and tests unchanged.
Root cause: not confirmed yet.
Unperformed checks: list explicitly.
步骤 2:建立不依赖画面的最小重现
在根目录新增 repro.mjs,贴入下面完整程式。它直接把一个已完成与一个未完成任务送给 visibleTasks,不经 localStorage、DOM、浏览器快取或外部网路。保存后在另一个终端机执行 node repro.mjs。故障版应先印出实际 b,再因期待 a 而以非零状态结束;这次 assertion 失败就是要保留的证据。
import assert from "node:assert/strict";
import { visibleTasks } from "./core.mjs";
const tasks = [
{ id: "a", title: "Read", completed: true },
{ id: "b", title: "Build", completed: false },
];
const actual = visibleTasks(tasks, "completed").map((task) => task.id);
console.log("Completed IDs:", JSON.stringify(actual));
assert.deepEqual(actual, ["a"]);
console.log("Reproduction passed.");
node repro.mjs
现在可以缩小调查:核心函式在没有浏览器的情况下就已回传错误,故障不需要快取或按钮事件才能发生。这不能证明所有 UI 都正确,但足以先查核心 Completed 分支。请 Codex 用证据解释「为什么目前条件选中了未完成任务」,再谈修正;不要以一次重新整理偶然正常当根因已找到。
先分辨程式失败与环境失败
若 node repro.mjs 显示 ERR_MODULE_NOT_FOUND,尚未执行到 Completed 断言,先检查目前资料夹与 core.mjs 的档名;若是 SyntaxError,核对是否完整贴上程式。只有程式成功载入,印出 b,接著因期待 a 而失败,才是此缺陷的重现。反过来,第一轮直接通过也不是你已修好:可能拿到 expected 副本,应回查材料来源。把命令、退出码、实际输出及副本位置一起留下,不只记「红色」或「失败」。
步骤 3:要求最小修正与原因说明
桌面版先以 codex-bug-lab 建立 Codex 任务;CLI 则在该资料夹确认路径后执行 codex。接著送出下面的完整要求,将范围限定到 core.mjs 的 Completed 条件。既有测试与 repro.mjs 都不要修改,否则无法比较前后。教材的故障注解在修好后会过期,可一并移除那一行;除此以外不重构所有函式、不改 UI 文案、不换框架。若代理没有读测试输出,就要求先确认原始失败再继续。
Fix the reproduced Completed-filter bug in this codex-bug-lab.
First read core.mjs, core.test.mjs and repro.mjs. Run node repro.mjs and node --test core.test.mjs to confirm the current failure.
Explain the predicate error using the actual a/b IDs. Modify only the completed predicate in core.mjs and remove its obsolete deliberate-bug comment. Do not change tests, repro.mjs, active behavior, storage or UI.
Rerun both commands, inspect the final diff and report actual results. Browser checks must be marked NOT RUN unless actually performed. Do not publish or deploy.
根因是 Completed 使用 !task.completed,与 Active 一样选未完成;正确条件是 task.completed。只需把该分支改成下列一行,不要连 Active 的 ! 也删除。若只把下拉选单的标签交换,画面有时看起来合理,但 repro 仍会失败;这说明修表象与修行为是两件事。
if (filter === "completed") return tasks.filter((task) => task.completed);
步骤 4:用同一证据做回归
修正后 node repro.mjs 应印出 ["a"] 与 Reproduction passed,退出码为 0;原测试应 3 项全过。再依第一步相同操作重测画面:Completed 只有 Read,Active 只有 Build,All 保留两笔。先用相同输入证明原错误消失,再新增空清单与取消完成等边界,不要一开始换整批资料而失去前后比较。
| 证据 | 修正前 | 修正后 |
|---|---|---|
| 最小重现 | b,assertion 失败 | a,退出码 0 |
| 原本核心测试 | 2 过 1 败 | 3 过 0 败 |
| Completed 画面 | Build | Read |
| Active/All | 需记实际结果 | Build/两笔皆在 |
| 尚未做的检查 | 明列未执行 | 不自动改成通过 |
最后看 core.mjs 的差异,确认没有改 addTask、decodeTasks 或测试期待。若对方回报修好了却没显示执行结果,要求命令、退出状态及失败摘要;不能执行时就记原因。两个测试通过也不能取代真正画面检查,要由你或具备浏览器工具的代理完成,并标明平台与预览网址。
补验取消完成与空清单
原重现已通过后,另建 regression.mjs,贴上下面程式,再执行 node regression.mjs。它先验证 Completed 的 a,取消 a 的完成状态后验证 Completed 为空、Active 保留 a/b,并检查原输入未被改动与三种空清单。预期印出 Regression passed,退出码 0。它是独立断言程式,不会把原 node --test core.test.mjs 的测试数自动增加。
import assert from "node:assert/strict";
import { toggleTask, visibleTasks } from "./core.mjs";
const tasks = Object.freeze([
Object.freeze({ id: "a", title: "Read", completed: true }),
Object.freeze({ id: "b", title: "Build", completed: false }),
]);
const ids = (items, filter) => visibleTasks(items, filter).map((task) => task.id);
assert.deepEqual(ids(tasks, "completed"), ["a"]);
const changed = toggleTask(tasks, "a");
assert.deepEqual(ids(changed, "completed"), []);
assert.deepEqual(ids(changed, "active"), ["a", "b"]);
assert.deepEqual(ids(changed, "all"), ["a", "b"]);
assert.deepEqual(tasks.map((task) => task.completed), [true, false]);
for (const filter of ["all", "active", "completed"]) {
assert.deepEqual(ids(Object.freeze([]), filter), []);
}
console.log("Regression passed.");
node regression.mjs
原 broken/core.mjs 还原练习也保留 regression.mjs;它应再次以非零状态失败,与 repro.mjs 的 b 一致。若你另外更动测试、标签或保存流程才让结果转绿,回到保存的原档重新做单一修正,并在交接纪录上下文与工作交接长工作需要把决策与证据留下,不能只依靠对话长度。README 说明怎么使用专案,设计文件记录为何这样做,交接文件整理目前做到哪里;AGENTS.md 则放持续有效的工作规则,避免把所有进度塞成规则。阅读全文标示这次被舍弃的假设。完整回归仍需实际画面与重载检查,未做就保留未执行。
排错习惯、还原与交付
一次只改一个可验证的假设,失败时把「做了什么、得到什么」追加到报告,避免下一个任务再次重试相同无效修正。若根因不在本篇预设位置,保留新证据并重新缩小范围,不因为教学说一行就硬改一行。真实专案的计时、帐号及网路条件可能造成不同故障,重现资料应先去除私人内容再交给 Codex。
交付包含 Bug 报告、最小重现、原因、限定差异及回归表。要重做时,停止自己的预览,只把原 broken/core.mjs 复制回来,保留 repro.mjs;它应再次失败,原测试回到 2 过 1 败。需要完整功能案例时接功能验收篇实作功能:完成待办筛选从 start 材料补上 Active/Completed 筛选,保留资料格式并用正常与边界案例验收。阅读全文。图中 1 是重现,2 是定位修正,3 是回归;参考修正可本机验证,Codex 实际对话和各平台操作仍要依你的执行记录判定。
返回 Codex 教学总目录Codex 学习中心:完整教程目录从安装、第一个任务到 MD 规则与进阶集成,规划 60 篇 Codex 教程、十个单元。按程度、平台、需求或命令搜索下一篇;尚未公开的教程会标示状态,方便安排学习路线。阅读全文
阅读完整文字说明
Reproduce to Fix to Regression
同主题延伸阅读
生活分享
Codex 学习中心:完整教程目录
从安装、第一个任务到 MD 规则与进阶集成,规划 60 篇 Codex 教程、十个单元。按程度、平台、需求或命令搜索下一篇;尚未公开的教程会标示状态,方便安排学习路线。
生活分享
Worktree 与多任务隔离
Worktree 让同一个 Git 程式库有不同的工作目录,各自承接不同分支。它适合让两项工作分开改档,但资料库、连接埠与外部服务仍可能共用,不能把档案隔离当成所有资源隔离。
生活分享
实战:制作小网站
从 brief.md 规划并制作 Small Steps 待办网站,完成新增、完成、删除、筛选与本机资料保存。将 HTML、CSS、资料函式、画面事件与测试分开,以 Node 测试和浏览器操作验收,并留下可重新启动与还原的交接纪录。
生活分享
用量与效率:减少重工
记录任务条件、模型选项、时间与成果,找出能减少无效重试和过多上下文的调整。
引用本文的文章
最新旅游情报攻略

攻略东京
东京住哪一区:新宿、上野、东京站、涩谷、浅草、池袋、银座七区比较,机场交通、住宿税、行李寄送一次看
东京住哪一区?用同一套标准比较新宿、上野、东京站、涩谷、浅草、池袋、银座七个区域:从成田、羽田机场怎么过来、有哪些线路、周边有什么、街区氛围、适合谁。附比较表与山手线示意图,以及 2026 年 9 月核实的东京都住宿税(2027 年 4 月改为 3%)和机场宅急便寄送行李的规则。
- 预算
- 酒店

攻略东京
东京交通票券怎么选:Suica/Welcome Suica、Tokyo Subway Ticket、JR Pass 值不值得买
第一次去东京,每人先用一张 IC 卡按次付费(Welcome Suica 免押金、有效期 28 天)。一天搭四趟以上地铁,再加买 2,000 日元的 Tokyo Subway Ticket 72 小时券;只玩东京、不去关西,买 JR Pass 一定不划算。用决策图比较 TOURIST PASMO、iPhone 里的 Suica、东京 Metro 一日券能搭什么、不能搭什么;价格于 2026 年 9 月核实。
- 交通
- 预算

攻略东京
东京迪士尼乐园、海洋攻略:票价、梦幻泉乡 Fantasy Springs、尊享卡 DPA 与预约等候卡怎么用,第一次去选哪个园区
东京迪士尼一日护照采用浮动票价,2026 年 9 月平日大多为 9,900 日元、周末为 10,900 日元,官网每天 14:00 开售两个月后同一天的门票;免费的优先通行卡已不在官网服务清单,缩短排队时间只剩付费的迪士尼尊享卡(每人每次 1,000 至 3,500 日元)。另有运营时间与 25 周年活动、预约等候卡与报名体验、梦幻泉乡如何进入,以及第一次去选乐园还是海洋;2026 年 9 月通过东京迪士尼度假区官网核实。
- 行程范例
- 亲子