三段高鐵官網上的購票規則,不到 200 字,最後逼出了 21 條驗收條件。這篇文章記錄整個過程:先用 Matt Pocock 的 grill-me 在 Claude Code 裡盤問需求,再用 Example Mapping 把規則展開成範例,最後用決策表把範例收斂成可驗收的清單。
三個工具的分工很清楚。grill-me 負責找出「規則沒說的事」;Example Mapping 負責用具體範例證明每條規則的解讀是對的;決策表負責保證條件組合沒有漏掉。單獨用任何一個都會有缺口,接起來才完整。
全文的對話記錄以 【人】 標記 DavidKo 輸入的內容,以 【AI】 標記 Claude Code 的回覆。為了讓文章獨立可讀,grill-me 的建議答案在本文中一律視為正確並採納;實務上你會在那些地方停下來跟 PO 確認。
起點是這三段原始需求:
- 每筆交易最多以 10 張乘車票為限,去回票每筆交易最多可訂購去回程各 5 張。
- 旅客可預訂 29 天內(含乘車當日)至發車前 5 分鐘為止之車次,且每逢週五及週六至多可預訂四週後至週日之車票(如因特殊事由調整開放時間,本公司將另行公告)。
- 座位偏好功能僅適用於單人乘客,系統係依列車訂位概況媒合您期望的座位,如該車次已無合適座位時,為讓您仍可順利完成訂票作業,將由系統自動配置座位。
第一步:grill-me 盤問,三輪問出 16 個規則沒說的事
grill-me 的做法是把需求攤成一棵決策樹,每輪只問「前提已經確定、現在可以問」的問題,每題附上它自己的建議答案。查得到的事實它自己查,只有決策才問人。這次沒有 repo,所以它沒有任何事實可查,第一輪就直接問決策。
安裝與啟動只有兩行:先在 Claude Code 裡 claude plugin install mattpocock-skills@claude-plugins-official,再在任意資料夾打 /grill-me。
第一輪
【人】
/grill-me 請用繁體中文訪談我。我要定義台灣高鐵一般對號座的訂票規則,需求如下:
- 每筆交易最多以 10 張乘車票為限,去回票每筆交易最多可訂購去回程各 5 張。
- 旅客可預訂 29 天內(含乘車當日)至發車前 5 分鐘為止之車次,且每逢週五及週六至多可預訂四週後至週日之車票(如因特殊事由調整開放時間,本公司將另行公告)。
- 座位偏好功能僅適用於單人乘客,系統係依列車訂位概況媒合您期望的座位,如該車次已無合適座位時,為讓您仍可順利完成訂票作業,將由系統自動配置座位。
【AI】
這三段規則各自獨立,第一輪我把三段的根問題都放上來,共 7 題。
❓ Q1 – 「每筆交易」的邊界:「交易」是一次結帳產生的一張訂單,還是一次登入 session?同一人連續結帳兩筆、各 10 張,是否合法?
➡️ 定義為「一次結帳產生的一張訂單」。張數上限只在單張訂單內檢查,跨訂單不限制。
❓ Q2 – 10 張與去回各 5 張的關係:去回票是否同時受 10 張總量限制?去程 5 張、回程 3 張可以嗎?
➡️ 單程票上限 10 張;去回票去程、回程各自上限 5 張,不另外檢查總量(最多本來就是 10)。去 5 回 3 合法。
❓ Q3 – 「29 天內(含乘車當日)」怎麼數:今天 11/02(一)可訂到 11/30 還是 12/01?日界以什麼時區切換?
➡️ 今天算第 1 天,可訂的最後乘車日是今天 + 28 天,即 11/30。日界以 Asia/Taipei 的 00:00 切換。
❓ Q4 – 「發車前 5 分鐘」以哪一站為準:旅客的起程站表定發車時間,還是該車次始發站?
➡️ 旅客起程站的表定發車時間。
❓ Q5 – 週五及週六的延伸規則:「四週後至週日」指哪一個週日?週五幾點開放?週日 00:00 之後就收回 29 天規則嗎?
➡️ 延伸上限為「本週的週日 + 28 天」。週五 00:00 開放,週六 23:59:59 結束,週日 00:00 起回到 29 天規則。範例:11/06(五)用 29 天規則只能訂到 12/04,延伸後可訂到 12/06(日)。
❓ Q6 – 「單人乘客」的定義:是整筆交易只有 1 張票,還是單一行程只有 1 張票?去回票去程 1 張、回程 1 張算不算?
➡️ 以「單一行程只有 1 張票」判斷,去程與回程各自判斷。去 1 回 1 的去回票,兩個行程都可以使用座位偏好。
❓ Q7 – 自動配位要不要告知旅客:偏好未滿足時,是付款前就顯示實際座位,還是只在票面上呈現?
➡️ 付款前顯示實際配到的座位,並標示「未能符合您的座位偏好」。
【人】
Q1 同意。Q2 同意。Q3 同意。Q4 同意。Q5 同意。Q6 同意。Q7 同意。
第二輪
【AI】
第一輪的答案打開了 7 個下游問題。
❓ Q8 – 超過上限時的處理:單程 11 張、或去回票去程 6 張時,整筆拒絕並提示上限,還是自動截到上限?
➡️ 整筆拒絕,提示「單程最多 10 張」或「去程最多 5 張」。不自動截斷,避免旅客在不知情下少買。
❓ Q9 – 張數下限:單程 0 張、去回票去程 2 張回程 0 張,是否合法?
➡️ 單程至少 1 張;去回票去程、回程各至少 1 張。回程 0 張應改買單程票,系統拒絕並提示。
❓ Q10 – 「發車前 5 分鐘」的邊界:恰好剩 5 分 0 秒時可以訂嗎?
➡️ 「現在時刻 ≤ 起程站表定發車時刻 − 5 分」可訂。14:00 發車,13:55:00 可訂,13:55:01 不可。
❓ Q11 – 回程是否也受預訂窗口限制:去回票的回程乘車日,是否獨立適用 29 天與週末延伸規則?回程能否早於去程?
➡️ 去程、回程各自獨立檢查預訂窗口;兩者都通過才接受。回程乘車日不得早於去程乘車日。
❓ Q12 – 乘車當日的車次:29 天含當日,所以今天的車次可訂,此時只受「發車前 5 分鐘」限制?
➡️ 是。乘車日 = 今天時,窗口規則一定通過,只檢查 5 分鐘截止。
❓ Q13 – 多張票時座位偏好的 UI:2 張以上時,是不顯示偏好選項,還是顯示但忽略?
➡️ 不顯示。「僅適用於單人乘客」解讀為功能不提供,而非提供後忽略。
❓ Q14 – 特殊事由調整開放時間:要不要在這次範圍內做成可設定的開放時間表?
➡️ 不在範圍內。這次只實作 29 天與週末延伸兩條規則,公告調整留到下一個 story。
【人】
Q8 同意。Q9 同意。Q10 同意。Q11 同意。Q12 同意。Q13 同意。Q14 同意,先不做。
第三輪
【AI】
剩 2 題,都是上一輪答案的收尾。
❓ Q15 – 延伸期間訂到的票,週日之後怎麼處理:週五訂到 12/06 的票,週日 00:00 窗口縮回 12/04 後,這張票是否受影響?
➡️ 不受影響。窗口規則只在「建立訂單」當下檢查,已成立的訂單不回溯。
❓ Q16 – 車次完全無空位時:座位偏好無法滿足會自動配位,但如果整個車次沒有任何空位呢?
➡️ 拒絕訂票並提示「該車次已無座位」。自動配位的前提是還有空位。
這兩題確認後,決策樹上沒有未訪問的分支了。我整理的共識如下,請確認:
- 交易 = 一張訂單;單程 1–10 張,去回票去程、回程各 1–5 張;超量整筆拒絕。
- 預訂窗口 = 今天 ≤ 乘車日 ≤ 今天 + 28;週五、週六延伸至本週日 + 28;去程、回程各自檢查;回程不早於去程。
- 乘車當日的車次只檢查「現在 ≤ 起程站發車時刻 − 5 分」。
- 窗口只在建單時檢查,不回溯。特殊事由調整不在範圍內。
- 座位偏好只在「該行程 1 張票」時提供;無法滿足時自動配位並在付款前告知;車次無空位則拒絕。
我們是否已達成共識?確認後我才會繼續。
【人】
Q15 同意。Q16 同意。確認,我們達成共識了。
16 題裡沒有一題是原始需求寫明的,但每一題都會影響程式怎麼寫。這就是 grill-me 的價值:它不產出驗收條件,它產出「驗收條件應該涵蓋哪些決策」。
第二步:Example Mapping,7 條規則、30 個範例、2 張紅卡
grill-me 結束時留下的是一串「決策」,還不是規則。Example Mapping 的工作是把決策整理成規則(藍卡),再為每條規則配上具體範例(綠卡)證明解讀無誤;配不出範例、或範例之間互相矛盾的地方,就是紅卡。
這一步仍在同一個 Claude Code 對話裡進行,不需要額外的 skill。
【人】
請用 Example Mapping 的方式,把我們剛才確認的共識整理成規則與範例。Story 是「旅客訂購一般對號座」。每條規則至少 3 個範例,範例要用具體日期和數字,今天是 2026/11/02(一)。規則無法用範例說清楚的地方列為問題。
【AI】
Story:旅客訂購一般對號座。
規則 1 — 單程票每筆交易 1 到 10 張
- 訂 1 張 → 接受
- 訂 10 張 → 接受
- 訂 11 張 → 拒絕,提示「單程最多 10 張」
- 訂 0 張 → 拒絕
規則 2 — 去回票去程、回程各 1 到 5 張,回程不早於去程
- 去 5 回 5 → 接受
- 去 5 回 3 → 接受
- 去 6 回 4 → 拒絕,提示「去程最多 5 張」
- 去 2 回 0 → 拒絕,提示「回程至少 1 張,或改購單程票」
- 去程 11/10、回程 11/09 → 拒絕,提示「回程不得早於去程」
規則 3 — 預訂窗口為今天起 29 天(含今天)
- 今天 11/02 訂 11/02 的車次 → 通過窗口檢查
- 今天 11/02 訂 11/30 的車次 → 通過(今天 + 28)
- 今天 11/02 訂 12/01 的車次 → 拒絕,提示「尚未開放預訂」
- 今天 11/02 訂 11/01 的車次 → 拒絕,提示「乘車日已過」
規則 4 — 週五、週六延伸至本週日 + 28 天
- 11/05(四)訂 12/04 → 拒絕(29 天規則只到 12/03)
- 11/06(五)訂 12/06(日) → 接受(本週日 11/08 + 28 = 12/06)
- 11/06(五)訂 12/07(一) → 拒絕
- 11/07(六)訂 12/06 → 接受
- 11/08(日)訂 12/06 → 接受(29 天規則本身就到 12/06)
- 11/08(日)訂 12/07 → 拒絕
規則 5 — 乘車當日的車次,截止於起程站發車前 5 分鐘
- 車次 14:00 從台中發車,現在 13:55:00 → 接受
- 同車次,現在 13:55:01 → 拒絕,提示「已停止售票」
- 車次 13:30 從台北始發、14:00 到台中,旅客從台中上車,現在 13:40 → 接受(以台中 14:00 計)
規則 6 — 座位偏好只在該行程 1 張票時提供
- 單程 1 張 → 顯示偏好選項
- 單程 2 張 → 不顯示偏好選項,系統自動配位
- 去回票去 1 回 1 → 去程、回程都顯示偏好選項
- 去回票去 1 回 2 → 去程顯示、回程不顯示
規則 7 — 偏好無法滿足時自動配位並告知;車次無空位則拒絕
- 選靠窗,車次有靠窗空位 → 配到靠窗
- 選靠窗,車次只剩靠走道 → 配到靠走道,付款前顯示「未能符合您的座位偏好」
- 未選偏好 → 系統自動配位,不顯示提示
- 車次無任何空位 → 拒絕,提示「該車次已無座位」
問題(紅卡)
- 座位偏好有哪些選項?目前只知道靠窗、靠走道,需求沒列舉。
- 「特殊事由調整開放時間」已確認不在範圍內,但上線後若公告延伸到 35 天,規則 3 的 28 要可設定還是改程式?
【人】
規則 4 的第 5 個範例我原本以為週日應該拒絕,看了範例才發現 29 天規則自己就涵蓋到了。這個範例留著。兩張紅卡先記錄,不擋這個 story。
規則 4 那個範例正是 Example Mapping 存在的理由。grill-me 在 Q5 問清楚了「週日 00:00 回到 29 天規則」,但只有把 11/08 和 12/06 這兩個日期真的擺出來,才看得出週日的延伸與不延伸結果相同。規則對了,但人對規則的直覺是錯的;範例把這個落差攤在桌上。
第三步:決策表,4 張表收斂成 21 條驗收條件
Example Mapping 的範例是人想出來的,涵蓋度靠直覺。決策表把條件列出來做組合,用「不相關(–)」合併,保證每一種條件組合都有對應的結果。這一步我請 Claude Code 用決策表技法整理,並要求條件之間獨立的部分拆成不同的表,避免一張表爆到上百欄。
【人】
請用決策表測試技法,把 7 條規則整理成決策表,再從每一欄導出一條驗收條件。條件互相獨立的規則分成不同的表。驗收條件用 Given / When / Then,數值要具體。
【AI】
7 條規則分成 4 個獨立的判斷面向:單程張數、去回票張數、預訂窗口、座位配置。4 張表,合併後共 21 欄,對應 21 條驗收條件。
表 A:單程票張數
| 條件 | A1 | A2 | A3 |
|---|---|---|---|
| 張數 | 0 | 1–10 | 11 以上 |
| 結果 | 拒絕 | 接受 | 拒絕,提示單程最多 10 張 |
表 B:去回票張數與日期
| 條件 | B1 | B2 | B3 | B4 | B5 | B6 |
|---|---|---|---|---|---|---|
| 去程張數 | 0 | 6 以上 | 1–5 | 1–5 | 1–5 | 1–5 |
| 回程張數 | – | – | 0 | 6 以上 | 1–5 | 1–5 |
| 回程乘車日 ≥ 去程乘車日 | – | – | – | – | 是 | 否 |
| 結果 | 拒絕 | 拒絕,提示去程最多 5 張 | 拒絕,提示回程至少 1 張 | 拒絕,提示回程最多 5 張 | 接受 | 拒絕,提示回程不得早於去程 |
表 C:預訂窗口(每個行程各自套用一次)
| 條件 | C1 | C2 | C3 | C4 | C5 | C6 | C7 |
|---|---|---|---|---|---|---|---|
| 乘車日 ≥ 今天 | 否 | 是 | 是 | 是 | 是 | 是 | 是 |
| 乘車日 ≤ 今天 + 28 | – | 是 | 是 | 是 | 否 | 否 | 否 |
| 乘車日 = 今天 | – | 否 | 是 | 是 | – | – | – |
| 現在 ≤ 起程站發車時刻 − 5 分 | – | – | 是 | 否 | – | – | – |
| 今天為週五或週六 | – | – | – | – | 是 | 是 | 否 |
| 乘車日 ≤ 本週日 + 28 | – | – | – | – | 是 | 否 | – |
| 結果 | 拒絕,乘車日已過 | 接受 | 接受 | 拒絕,已停止售票 | 接受(週末延伸) | 拒絕,尚未開放 | 拒絕,尚未開放 |
表 D:座位配置(每個行程各自套用一次,張數與窗口都通過後)
| 條件 | D1 | D2 | D3 | D4 | D5 |
|---|---|---|---|---|---|
| 車次尚有空位 | 否 | 是 | 是 | 是 | 是 |
| 該行程張數 = 1 | – | 否 | 是 | 是 | 是 |
| 旅客選了座位偏好 | – | – | 否 | 是 | 是 |
| 有符合偏好的空位 | – | – | – | 是 | 否 |
| 結果 | 拒絕,該車次已無座位 | 不顯示偏好選項,自動配位 | 自動配位 | 配置符合偏好的座位 | 自動配位,付款前告知未符合偏好 |
21 條驗收條件
每一欄一條,欄號即驗收條件編號。日期以今天 = 2026/11/02(一)為基準。
單程票張數
- AC-A1 Given 旅客選購單程票 When 張數為 0 Then 系統拒絕建單
- AC-A2 Given 旅客選購單程票 When 張數為 10 Then 系統接受並進入座位配置
- AC-A3 Given 旅客選購單程票 When 張數為 11 Then 系統拒絕並提示「單程最多 10 張」
去回票張數與日期
- AC-B1 Given 旅客選購去回票 When 去程 0 張 Then 系統拒絕建單
- AC-B2 Given 旅客選購去回票 When 去程 6 張、回程 4 張 Then 系統拒絕並提示「去程最多 5 張」
- AC-B3 Given 旅客選購去回票 When 去程 2 張、回程 0 張 Then 系統拒絕並提示「回程至少 1 張,或改購單程票」
- AC-B4 Given 旅客選購去回票 When 去程 3 張、回程 6 張 Then 系統拒絕並提示「回程最多 5 張」
- AC-B5 Given 旅客選購去回票,去程 11/10、回程 11/12 When 去程 5 張、回程 3 張 Then 系統接受並進入座位配置
- AC-B6 Given 旅客選購去回票,去程 11/10、回程 11/09 When 去程 1 張、回程 1 張 Then 系統拒絕並提示「回程不得早於去程」
預訂窗口
- AC-C1 Given 今天 11/02 When 選擇 11/01 的車次 Then 系統拒絕並提示「乘車日已過」
- AC-C2 Given 今天 11/02 When 選擇 11/30 的車次 Then 系統接受
- AC-C3 Given 今天 11/02,車次 14:00 從台中發車,現在 13:55:00 When 選擇該車次從台中上車 Then 系統接受
- AC-C4 Given 今天 11/02,車次 14:00 從台中發車,現在 13:55:01 When 選擇該車次從台中上車 Then 系統拒絕並提示「已停止售票」
- AC-C5 Given 今天 11/06(五) When 選擇 12/06(日)的車次 Then 系統接受
- AC-C6 Given 今天 11/06(五) When 選擇 12/07(一)的車次 Then 系統拒絕並提示「尚未開放預訂」
- AC-C7 Given 今天 11/05(四) When 選擇 12/04(五)的車次 Then 系統拒絕並提示「尚未開放預訂」
座位配置
- AC-D1 Given 旅客選購 1 張單程票 When 該車次無任何空位 Then 系統拒絕並提示「該車次已無座位」
- AC-D2 Given 旅客選購 2 張單程票,車次有空位 When 進入座位配置 Then 不顯示座位偏好選項,系統自動配位
- AC-D3 Given 旅客選購 1 張單程票,車次有空位 When 未選擇座位偏好 Then 系統自動配位,不顯示偏好相關提示
- AC-D4 Given 旅客選購 1 張單程票,車次有靠窗空位 When 選擇偏好「靠窗」 Then 系統配置靠窗座位
- AC-D5 Given 旅客選購 1 張單程票,車次只剩靠走道空位 When 選擇偏好「靠窗」 Then 系統配置靠走道座位,並在付款前顯示「未能符合您的座位偏好」
需求待釐清清單
- 座位偏好的選項有哪些?本表只以靠窗、靠走道為例。
- 去回票的去程、回程在表 C、表 D 各自套用一次,意味一筆去回票最多會出現兩次「未能符合偏好」的提示。這是否符合預期?
- 「特殊事由調整開放時間」不在本次範圍。表 C 的「28」若未來需調整,建議做成設定值。
【人】
表 C 的欄位合併得不錯。但 AC-C3 和 AC-C4 我想補一個始發站與起程站不同的案例,確認是以起程站計算。
【AI】
補上一條:
- AC-C3b Given 今天 11/02,車次 13:30 從台北始發、14:00 抵達台中,現在 13:40 When 選擇該車次從台中上車 Then 系統接受(以台中 14:00 為截止基準)
這條不是新的決策表欄位,是 C3 的補充案例,用來鎖定「起程站」的解讀。
決策表沒有多找出新的規則,這很正常,因為前兩步已經把規則問乾淨了。它找出的是表 C 第 1 列:「乘車日 ≥ 今天」。Example Mapping 的規則 3 有「11/01 已過」這個範例,但只有在決策表裡把它和週五週六延伸規則並排時,才會發現如果少了這個條件,週五訂過去的日期會被延伸規則誤判為接受。範例看得到單一情境,決策表看得到條件之間的交互作用。
結語:三個工具各自補了什麼
| 工具 | 輸入 | 輸出 | 它找到了什麼 |
|---|---|---|---|
| grill-me | 3 段原始需求 | 16 個決策 | 規則沒寫的事:交易邊界、日期怎麼數、哪一站發車、超量怎麼處理 |
| Example Mapping | 16 個決策 | 7 條規則、30 個範例、2 張紅卡 | 人對規則的直覺哪裡是錯的:週日的延伸與不延伸結果相同 |
| 決策表 | 7 條規則 | 4 張表、21 條驗收條件 | 條件之間的交互作用:少了「乘車日 ≥ 今天」,延伸規則會放行過去的日期 |
三步的順序不能換。先做決策表,條件還沒問清楚,表會建在錯的假設上;先做 Example Mapping,範例會圍繞你自己的解讀打轉,問不出 Q4、Q5 那種你沒想到的分歧。grill-me 的價值在它完全不產出驗收條件,只產出「驗收條件應該回答哪些問題」。
反過來說,grill-me 停在決策這一層也是它的極限。它問出「週日 00:00 回到 29 天規則」,但不會自己擺出 11/08 和 12/06 來看結果;它問出「乘車日已過要拒絕」,但不會把這個條件和週五延伸規則並排,看出兩者的交互。那兩件事分別要靠範例和決策表。
整個過程人只打了 8 段文字,其中 5 段是「同意」。工作量不在打字,在每一輪停下來判斷 AI 的建議答案能不能接受。這篇文章假設全部能接受;真實專案裡,Q2、Q5、Q13 這三題大概要拉 PO 進來才能定案。
發佈留言