今天是第 30 天,也是最後一天。
我沒有開新功能。
也沒有改 production code。
今天只補一條 browser regression,收掉 Day 28 結尾列出的最後一個缺口:
Project Constraints 重新按確認,但內容沒有變,Tech Stack 不能被標成 needsReview。
今天新增一條測試後,npm test 從 38 條變成 39 條,全過。
ClarifyBuild 是我這系列正在做的小工具:它會把一個模糊的產品 idea,透過幾站釐清流程,整理成 Project Specification,最後再組成 AI Coding Prompt。
第 30 天做這件事剛好。
因為這幾天其實在處理同一個產品問題:
什麼情況下,已經填好的規格還算有效?
Day 28 我把 needs-review 規則對齊 Day 11 的 Schema。
那天的重點是:
不是每個 needs review 都代表同一種過期。
需求變更有很多種。
Target User、Problem、Goal 改了,影響的是產品語意。
例如使用者從「研究生」變成「研究生與助教」,那主要流程和功能規格很可能要重新看過。
但 Tech Stack 不一定要重新檢查。
Platform 和 Project Constraints 不一樣。
它們是建置邊界。
如果平台從 Web 改成 Mobile,或限制從「必須可以部署為靜態網站」改成「不得使用付費 API」,那 Tech Stack 的授權範圍就變了。
所以 Day 28 的產品判斷是:
| 變更 | 主要流程 | 功能規格 | 專案限制 | 技術設定 |
|---|---|---|---|---|
| Target User / Problem / Goal | 需要重新檢查 | 需要重新檢查 | 不影響 | 不影響 |
| Usage Scenario | 需要重新檢查 | 不影響 | 不影響 | 不影響 |
| Platform | 需要重新檢查 | 需要重新檢查 | 未完成 | 需要重新檢查 |
| Project Constraints 內容改變 | 不影響 | 不影響 | 完成 | 需要重新檢查 |
| Project Constraints 重新確認、內容沒變 | 不影響 | 不影響 | 完成 | 不影響 |
Day 29 補的是 Usage Scenario 的 browser regression:從已完成 setup 的 draft 回到 Scope,在「修改前面的需求」補填使用情境,再回 Specify,確認只有主要流程變成「需要重新檢查」。
今天 Day 30 補的,是表格最後一列。
這樣 Day 28 到 Day 30 的 needs-review browser regression 就收成一組比較完整的保護網。
Day 28 已經有一條 browser test:
browser project constraint edits mark tech stack for review
那條測的是:
Project Constraints 內容改了,所以 Tech Stack 要重新檢查。
例如原本是:
必須可以部署為靜態網站
改成:
必須部署到 GitHub Pages
這會讓技術設定變成:
技術設定:需要重新檢查
這是合理的。
因為 Tech Stack 的 ai_delegated 不是「我沒有意見,所以 AI 隨便決定」。
它的語意是:
使用者明確授權 Coding Agent,在 Platform、Project Constraints 與 AI Decision Boundary 內選擇最適合、最簡單的技術。
Project Constraints 變了,授權範圍就變了。
那 Tech Stack 當然要被標成「需要重新檢查」。
授權範圍是由限制的內容決定的。
內容沒變,授權範圍就沒變,Tech Stack 沒有理由過期。
今天測的,就是內容沒變的這一半。
也就是:
使用者按了「確認專案限制」,但限制內容完全沒有變。
這時候,系統不應該因為「按了確認」這個事件,就推論「內容改了」。
這兩件事在 UI 上很像。
都是按同一顆按鈕:
確認專案限制
但產品語意不同。
一個是:
我改了限制,所以相關技術設定需要重新看。
另一個是:
我看過了,這些限制仍然有效。
今天補的就是第二種。
新增的測試叫:
browser unchanged project constraint re-review keeps setup complete
名稱裡的 re-review,指的就是使用者重新按一次「確認專案限制」。
它一樣從已完成 setup 的 draft 出發。
這個起點很重要。
因為今天要證明的是:
原本完整可產出的 setup,在重新確認未變更的 Project Constraints 後,仍然完整可產出。
如果一開始就不是完整狀態,後面就很難判斷按鈕 disabled 是誰造成的。
測試先確認起點,接著不改任何文字,只按:
確認專案限制
按之前和按之後,這五項應該一模一樣:
| 項目 | 按之前 | 按之後 |
|---|---|---|
| 主要流程 | 完成 | 完成 |
| 功能規格 | 1 / 1 | 1 / 1 |
| 專案限制 | 完成 | 完成 |
| 技術設定 | 完成 | 完成 |
產生 Project Specification |
可以按 | 可以按 |
功能規格卡片也還是:
功能規格:搜尋目前論文 完成
另外也確認 Setup Status 裡沒有出現「需要重新檢查」,Tech Stack 的提示也沒有出現:
平台或專案限制已變更。請確認目前技術設定是否仍然適用。
這條測試很小。
但它守住的是一個產品細節:
「我看過了」不能被當成「我改了」。
今天沒有改 production code。
因為 Day 28 修改 saveConstraints() 時,已經把「內容是否改變」拆出來了:
const constraintsContentChanged =
state.draft.projectConstraints.items.length !== nextItems.length ||
state.draft.projectConstraints.items.some((item, index) => item !== nextItems[index]);
這個函式裡,跟今天有關的有兩件事,而且互相獨立。
第一件,確認成功就一定會做:
state.draft.projectConstraints.reviewed = true;
也就是記下「使用者確認過了」。
第二件,只有內容真的變了才做:
if (constraintsContentChanged) {
markTechStackNeedsReview(state.draft);
}
所以 Day 30 做的不是修 bug。
而是補一條 browser regression,確認這段邏輯真的在 UI 路徑上成立。
使用者不會直接呼叫 saveConstraints()。
使用者會看到文字區、radio、按鈕、Setup Status、產生 Project Specification 按鈕。
browser test 要守的是這一整段路。
Day 28 我說 Setup Status 的斷言「現在還可以忍」。
Day 29 我說,Day 30 補完最後一條,再決定要不要抽。
最後一條補完了。
同樣的四行,現在在 browserFlow.test.js 裡出現了五次:
assert.match(await page.text(".sidebar"), /主要流程:完成/);
assert.match(await page.text(".sidebar"), /功能規格:1 \/ 1/);
assert.match(await page.text(".sidebar"), /專案限制:完成/);
assert.match(await page.text(".sidebar"), /技術設定:完成/);
Setup Status 的斷言行數,Day 29 結束時是 47 行,今天是 56 行。
重複確實更明顯了。
要抽 helper 可以。
但我今天沒有抽。
原因是第 30 天的範圍應該停在 regression 本身。
抽 helper 會改動更多既有測試。
那不難,但它會讓最後一天的 diff 從「補一條產品保護」變成「順便整理測試結構」。
這不是今天最重要的事。
所以我先接受一點重複。
等之後如果還要繼續加 Setup Status 相關 browser tests,再抽會比較自然。
今天沒有改文案。
例如「修改前面的需求」面板裡還是寫:
如果這裡的內容改變,既有主要流程、功能規格或技術設定會保留,但可能需要重新檢查。
這句話只有改 Platform 時完全貼切。
改 Usage Scenario,只會碰到主要流程;改 Target User、Problem、Goal,也不會碰到技術設定。
要細拆文案可以之後再做。
但 Day 30 不碰這個。
今天也沒有補「沒改內容就按儲存前段需求」的 browser regression。
那條也有價值。
它要守的是:
在 Scope 的「修改前面的需求」面板中,如果 Target User、Problem、Goal、Platform、Usage Scenario 都沒改,只按儲存,不該標記任何東西。
但 Day 29 已經決定不把它排進 30 天內。
Day 30 如果再補那條,就會從「收掉 Day 28 結尾列出的最後一個缺口」變成「又多開一條相鄰但不同的流程」。
我想讓最後一天停在更乾淨的地方。
今天新增一條 browser test,測試數量從 38 條變成 39 條。
完整結果是:
npm test
tests 39
pass 39
fail 0
跟前幾天一樣,我的執行環境第一次跑完整測試時,browser tests 因為 local server 不能 bind 到 127.0.0.1 失敗,11 條都是 listen EPERM。
放寬本機執行權限後,同一個 npm test 通過。
今天動的程式檔只有 test/browserFlow.test.js。
production source code 沒有變。
Day 29 我說過,三十天後 ClarifyBuild 不會是一個很大的產品。
現在三十天到了,它確實不是。
它沒有 AI API。
沒有漂亮的 onboarding。
沒有多專案管理。
沒有登入、同步、團隊協作。
但它已經有一條很清楚的主線:
幫使用者把模糊 idea 變成可以交給 Coding Agent 的 Project Specification。
這 30 天裡,我一直在補的,是主線旁邊更細的邊界:
Candidate 不等於 Resolved。
Scope 不等於全部都要做。
資料存在不等於資料有效。
按了確認不等於內容改了。
AI Delegation 不等於 AI 可以亂猜。
這些句子看起來都很小。
但它們其實是這個工具的產品性格。
ClarifyBuild 最核心的價值不是「幫你多產一些字」。
而是:
在可以產出的時候產出,在不該產出的時候停下來。
這其實就是 Day 29 結尾那句話的短版。
這也是 Day 27 到 Day 30 一直在收的事。
Day 27 修 Setup Status,不讓不完整的 draft 看起來完成。
Day 28 拆 needs-review 原因,不讓不同類型的過期混在一起。
Day 29 補 Usage Scenario browser regression,確認規則真的走過 UI。
Day 30 補 unchanged Project Constraints re-review,守住「重新按確認」不等於「內容改了」。
最後這幾天沒有很炫。
但我覺得它們很重要。
因為一個要交給 Coding Agent 的規格工具,最怕的不是少產一點。
最怕的是把已經失效、未確認、或根本沒有來源的內容,包裝成一份看起來很完整的規格。
三十天後,ClarifyBuild 至少開始學會兩件事:
不確定的地方,要誠實。
確定沒變的地方,不要亂喊過期。
Day 30 完成。