生活分享

修 Bug 的完整流程

好的除錯从可重現的症狀開始,再用證據縮小原因,最後驗證修正。『網站壞了』不夠具體;提供哪個輸入、在哪個步驟、期待什麼、實際出現什麼,能讓 Codex 更快找到相關程式。

閱讀時間約 14 分鐘 · 操作 25 分鐘

實作順序示意圖,非產品介面截圖。
圖片:Mokaair (© Mokaair)
回總目錄:Codex 學習中心:完整教學目錄

實作 · Desktop / CLI / VS Code / JetBrains / cloud

本篇目錄
  1. 目標與準備
  2. 步驟 1:固定故障版本與重現步驟
  3. 步驟 2:建立不依賴畫面的最小重現
  4. 步驟 3:要求最小修正與原因說明
  5. 步驟 4:用同一證據做回歸
  6. 排錯習慣、還原與交付

目標與準備

本段提到的教學與資源:

步驟 1:固定故障版本與重現步驟

從練習 ZIP 的 broken 複製五個檔案到新資料夾 codex-bug-lab,保留原版。這份程式已有篩選分支,但 Completed 的條件故意寫反;與 start「尚未實作篩選」不同。開編輯器,PowerShell 用 Get-Location、macOS/Linux 用 pwd 確認位置,再執行既有測試,預期 2 過 1 敗。

終端機:基準測試 · sh
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 報告 · markdown
# 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 失敗就是要保留的證據。

新增檔案:repro.mjs · javascript
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.");
終端機:最小重現 · sh
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 文案、不換框架。若代理沒有讀測試輸出,就要求先確認原始失敗再繼續。

Codex 提示詞:限定修正範圍 · text
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 仍會失敗;這說明修表象與修行為是兩件事。

參考修正:Completed 分支 · javascript
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 畫面BuildRead
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 的測試數自動增加。

檔案:regression.mjs · javascript
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.");
終端機:執行邊界回歸 · sh
node regression.mjs

原 broken/core.mjs 還原練習也保留 regression.mjs;它應再次以非零狀態失敗,與 repro.mjs 的 b 一致。若你另外更動測試、標籤或保存流程才讓結果轉綠,回到保存的原檔重新做單一修正,並在標示這次被捨棄的假設。完整回歸仍需實際畫面與重載檢查,未做就保留未執行。

排錯習慣、還原與交付

一次只改一個可驗證的假設,失敗時把「做了什麼、得到什麼」追加到報告,避免下一個任務再次重試相同無效修正。若根因不在本篇預設位置,保留新證據並重新縮小範圍,不因為教學說一行就硬改一行。真實專案的計時、帳號及網路條件可能造成不同故障,重現資料應先去除私人內容再交給 Codex。

交付包含 Bug 報告、最小重現、原因、限定差異及回歸表。要重做時,停止自己的預覽,只把原 broken/core.mjs 複製回來,保留 repro.mjs;它應再次失敗,原測試回到 2 過 1 敗。需要完整功能案例時接。圖中 1 是重現,2 是定位修正,3 是回歸;參考修正可本機驗證,Codex 實際對話和各平台操作仍要依你的執行記錄判定。

20. 修 Bug 的完整流程 — 實作順序示意圖,非產品介面截圖。 Reproduce → Fix → Regression
20. 修 Bug 的完整流程 — 實作順序示意圖,非產品介面截圖。 Reproduce → Fix → Regression · 圖片:Mokaair (© Mokaair)
閱讀完整文字說明

Reproduce to Fix to Regression

回總目錄

  • 生活分享

    Codex 學習中心:完整教學目錄

    從安裝、第一個任務到 MD 規則與進階整合,規劃 60 篇 Codex 教學、十個單元。依程度、平台、需求或指令搜尋下一篇;尚未公開的教學會標示狀態,方便安排學習路線。

  • 生活分享

    Worktree 與多任務隔離

    Worktree 讓同一個 Git 程式庫有不同的工作目錄,各自承接不同分支。它適合讓兩項工作分開改檔,但資料庫、連接埠與外部服務仍可能共用,不能把檔案隔離當成所有資源隔離。

  • 生活分享

    實戰:製作小網站

    從 brief.md 規劃並製作 Small Steps 待辦網站,完成新增、完成、刪除、篩選與本機資料保存。將 HTML、CSS、資料函式、畫面事件與測試分開,以 Node 測試和瀏覽器操作驗收,並留下可重新啟動與還原的交接紀錄。

  • 生活分享

    用量與效率:減少重工

    記錄任務條件、模型選項、時間與成果,找出能減少無效重試和過多上下文的調整。

最新旅遊情報攻略

資料來源

生活分享