OpenSpec 項目實戰(七)| verify 2 個工具、3 處修復,第 4 維度依然缺席
整理版優先睇
OpenSpec verify第4維度修復失效,json-formatter工具成功實現,揭示提示詞全鏈路同步嘅侷限
呢篇文章係術哥嘅OpenSpec項目實戰系列第7篇。作者係術哥,專注AI編程同開源技術,今次分享嘅係verify工具第4維度修復同json-formatter工具實現嘅過程。之前三期改造後,verify嘅Task Granularity維度一直冇出現,今期目標係修復SKILL.md入面嘅矛盾,再驗證效果。
修復咗Summary Scorecard模板加返Task Granularity行,同埋Graceful Degradation段改three做four,但係verify報告依然只輸出3維度。另一方面,json-formatter成功實現,複用咗text-summary嘅組件模式,速度明顯快咗。總結係提示詞全鏈路同步係必要,但唔足夠,質量保證需要更強嘅過程控制,後續會引入三檔工作流。
- 修復SKILL.md全鏈路後verify第4維度依然缺席,提示詞約束有天花板。
- 本期採用先修SKILL.md再行Propose→Apply→Verify流程,驗證修復效果。
- json-formatter開發速度比text-summary快,因為組件模式可直接複用。
- 質量保證不能只壓喺verify一個環節,需按風險選強度。
- 後續每個新工具模板應固定export default,避免動態加載失敗。
內容片段
Create a report structure with four dimensions:
- **Completeness**: Track tasks and spec coverage- **Correctness**: Track requirement implementation and scenario coverage- **Coherence**: Track design adherence and pattern consistency- **Task Granularity**: Track task format compliance, TDD adherence, code completeness, and granularity assessment
verify SKILL.md修復:定義同引用嘅矛盾
上期改造加咗第4維度Task Granularity,但係verify報告從來冇出現過。翻查SKILL.md發現:定義部分(L46)寫咗four dimensions,但係後面兩處引用仲停留喺three dimensions。一處係Summary Scorecard模板,只有3行;另一處係Graceful Degradation段嘅「verify all three dimensions」。AI執行verify時讀到舊文案,直接按3維度出報告。
定義同引用不一致,AI唔覺得有問題,照跟舊文案行。
改動好細:Summary Scorecard加一行Task Granularity,Graceful Degradation改three做four。但係呢個同步不到位正正係第4維度缺席嘅直接原因。
- 1 矛盾點1:Summary Scorecard模板(L117-127)只有3行,缺Task Granularity行。
- 2 矛盾點2:Graceful Degradation段(L159-164)寫「verify all three dimensions」,剩係改定義冇用。
json-formatter工具實現:組件模式複用
json-formatter嘅catalog同路由第2期就配好咗,但係src/modules/json-formatter/一直空咗。今期將佢填返,實際係個純前端工具,用原生JSON.parse同JSON.stringify實現格式化、壓縮同語法校驗。
複用text-summary嘅組件模式:頁面組件負責UI,純函數內聯喺組件入面。
- 格式化:接收JSON字符串,輸出縮排整齊嘅JSON。
- 壓縮:移除多餘空白,輸出單行JSON。
- 校驗:檢測語法錯誤,返回錯誤位置同描述。
apply過程行TDD五步結構,AI按tasks.md順序執行,交互好少。相比text-summary,json-formatter嘅實現速度快好多,因為核心邏輯簡單,而且組件模式可以直接套用。
不過踩咗個坑:json-formatter用咗named export(export function JsonFormatterPage),但router嘅動態import取mod.default,搞到頁面卡死喺加載中。修復方法係加返export default JsonFormatterPage。
後續每個新工具模板應該將export default做固定項寫死。
驗證結果與後續方向
執行/opsx:verify之後,報告Summary表格仍然只有3行——Completeness、Correctness、Coherence,Task Granularity維度冇出現。修復SKILL.md冇生效,AI似乎冇跟足新模板。
純SKILL.md文案修改嘅約束力有天花板,AI嘅執行行為受上下文慣性影響。
不過verify報告發揮咗其他價值:發現咗1個CRITICAL issue(大文件JSON解析場景未實現)同1個WARNING(有效JSON校驗測試缺失)。呢啲係specs寫咗但tasks冇覆蓋嘅,verify幫手撈返出嚟。
- 快速檔:低風險改動(文案、樣式),OpenSpec + fresh verify就夠。
- 標準檔:普通工具開發,OpenSpec + Superpowers writing-plans控制計劃顆粒度。
- 嚴格檔:核心邏輯、bugfix、重構,疊加TDD、debug、code review。
呢個係系列從「摸索OpenSpec增強方案」轉向「組合使用OpenSpec + Superpowers」嘅轉折點。
🚩 2026 年「術哥無界」系列實戰文檔 X 篇原創計劃 第 127 篇,OpenSpec 項目實戰「2026」系列第 7 篇
大家好,歡迎嚟到 術哥無界 | ShugeX | 運維有術。
我是術哥,一個專注於 AI 編程、AI 智能體、Agent Skills、MCP、雲原生、AIOps、Milvus 向量數據庫嘅技術實踐者同開源佈道者!
Talk is cheap, let's explore。無界探索,有術而行。

圖:資訊圖封面:OpenSpec verify 修復 + json-formatter 實現
上一期做咗三層改造——template 改咗 tasks 格式、review 加咗 4 維度審查同拆分方向建議、verify 加咗第 4 維度 Task Granularity。三層改造嘅驗證結果:template 生效咗,review 生效咗,verify 冇生效。
verify 卡喺邊度?執行 /opsx:verify 之後,報告只輸出咗 Completeness、Correctness、Coherence 三個維度,Task Granularity 始終缺席。第 6 期加嗰個第 4 維度嘅定義,AI 完全冇用過。
翻咗一遍 SKILL.md 源文件,根因揾到咗:L46 定義部分確實寫咗 four dimensions,但後面兩處引用呢個數字嘅地方仲停留喺 three dimensions。一處係 Summary Scorecard 模板表格,得 3 行冇 Task Granularity。另一處係 Graceful Degradation 段嘅最後一行,明確寫住 "verify all three dimensions"。AI 執行 verify 時,讀到呢兩處舊文案,直接按 3 維度出咗報告。定義同引用不一致,AI 唔覺得有問題,跟住舊文案行就係喇。
講到底,呢個係典型嘅"改咗定義冇改引用"嘅問題。寫代碼嘅時候我哋都知道改咗接口要改曬所有調用方,但改提示詞嘅時候容易忽略同樣嘅道理。
今期做兩件事:先將 verify SKILL.md 嘅內部矛盾修完,然後實現第二個工具 json-formatter。json-formatter 嘅 catalog 註冊同路由第 2 期就配好咗(catalog.ts 裏面嘅 stage: 'active',路由 /tools/json-formatter),但 src/modules/json-formatter/ 目錄一直空咗。今期將佢填上,同時驗證修復後嘅 verify 係咪真係可以輸出 4 維度報告。
兩個任務有先後順序:先修 SKILL.md,再行 Propose → Apply → Verify。咁樣今期 verify 階段就可以用返修復後嘅配置,直接檢驗效果。
完整流程如下:
說明:本文內容係基於 OpenSpec v1.3.1 實際項目操作記錄整理。verify SKILL.md 修復同 json-formatter 工具實現都在 shuge-ai-toolbox 項目中實際驗證,但 verify 第 4 維度(Task Granularity)修復後仍然未生效,文中如實記錄。文中嘅配置修改同代碼僅供參考,實際效果請以你嘅項目環境測試結果為準。如果有實際使用經驗,歡迎喺評論區分享交流。
修復 verify SKILL.md:將矛盾嘅地方同步改完
先定位問題。文件路徑係 .claude/skills/openspec-verify-change/SKILL.md,總共 173 行。
L46 嘅定義部分其實係啱嘅:
Create a report structure with four dimensions:
- **Completeness**: Track tasks and spec coverage
- **Correctness**: Track requirement implementation and scenario coverage
- **Coherence**: Track design adherence and pattern consistency
- **Task Granularity**: Track task format compliance, TDD adherence, code completeness, and granularity assessment
四個維度定義齊全,L50-54 仲詳細拆咗 Task Granularity 嘅四項檢查:任務格式、TDD 合規、代碼完整性、粒度評估。定義冇問題。
問題出喺後面兩處引用呢個數字嘅地方。
矛盾點 1:Summary Scorecard 模板(L117-127)
呢個表格係 verify 報告末尾嘅彙總模板,AI 按呢個格式輸出最終結論。目前得 3 行:
### Summary
| Dimension | Status |
|--------------|------------------|
| Completeness | X/Y tasks, N reqs|
| Correctness | M/N reqs covered |
| Coherence | Followed/Issues |
Task Granularity 行缺失。AI 生成報告時跟住模板行,模板得 3 行,輸出自然只得 3 維度。
矛盾點 2:Graceful Degradation 段(L159-164)
呢段描述嘅係"當工件唔齊全時點樣降級驗證"。最後一句:
- If full artifacts: verify all three dimensions
寫嘅係 three dimensions。就算所有工件都齊全,AI 讀到呢句都會認為只需要驗證 3 個維度。

圖:SKILL.md 三處矛盾位置標註
具體修改
改動唔大,但位置分散,需要逐個同步。
修改 1:Summary Scorecard 加行
改前:
| Dimension | Status |
|--------------|------------------|
| Completeness | X/Y tasks, N reqs|
| Correctness | M/N reqs covered |
| Coherence | Followed/Issues |
改後:
| Dimension | Status |
|------------------|------------------|
| Completeness | X/Y tasks, N reqs|
| Correctness | M/N reqs covered |
| Coherence | Followed/Issues |
| Task Granularity | Format/TDD/Code |
新增嘅 Task Granularity 行,狀態列用 Format/TDD/Code 簡寫,對應任務格式檢查、TDD 合規檢查、代碼完整性檢查三項。
修改 2:Graceful Degradation three → four
改前:
- If full artifacts: verify all three dimensions
改後:
- If full artifacts: verify all four dimensions
一個詞嘅事。但呢個詞決定了 AI 驗證時係咪行第 4 維度。

圖:SKILL.md 修復前後對比
改完存盤,總共改咗兩處三行。睇落微不足道,但呢個同步唔到位就係 verify 第 4 維度一直缺席嘅直接原因。
呢度有個教訓值得記一筆:提示詞約束係一條鏈路,唔係孤立嘅定義。L46 定義寫得幾靚都好,後面模板同退化邏輯冇跟上,執行層就跟舊路徑行。2/8 法則嘅體現——定義佔 20% 篇幅但決定方向,引用點佔 80% 篇幅而且決定實際行為。改提示詞要改全鏈路,唔可以只改最顯眼嗰一處。
改完 verify SKILL.md 之後,馬上進入 Propose。咁樣今期生成嘅工件先至可以用返修復後嘅配置。
Propose:記錄工件產出過程
今期跳過 Explore,需求好明確——實現 json-formatter 工具,重用 text-summary 已建立嘅組件模式。
執行 /opsx:propose:
**AI**:What change do you want to work on? Describe what you want to build or fix.
**用戶**:本期做一個 implement-json-formatter 變更。在 src/modules/json-formatter/ 下實現 JSON 格式化工具,複用 text-summary 已建立的組件模式。功能包括格式化、壓縮、語法校驗。catalog.ts 中 json-formatter 已註冊為 active,路由已存在,但模塊目錄尚未創建。同時需要在 router/index.tsx 的 toolModules 中添加 json-formatter 的映射行。
**AI**:
**Change created: `implement-json-formatter`**
**Location:**`openspec/changes/implement-json-formatter/`
**Artifacts created:**
| Artifact | Description |
|----------|-------------|
| `proposal.md` | Why we need JSON formatting (dev高頻需求,純前端實現) |
| `design.md` | Technical design: single-file component, native JSON.parse/JSON.stringify, useEffect+import pattern |
| `specs/json-formatter/spec.md` | 8 scenarios covering format/minify/validate, empty input, large file |
| `review.md` | 4-dimension review with task split direction |
| `tasks.md` | 3 tasks: JsonFormatterPage (TDD), router mapping, verification |
**Task breakdown:**
- 任務 1: JsonFormatterPage 組件(TDD 模式,測試 + 實現)
- 任務 2: Router 映射配置(toolModules 添加 json-formatter)
- 任務 3: 驗證完整功能
**All artifacts created! Ready for implementation.**
Run `/opsx:apply implement-json-formatter` to start implementing.
AI 一次生成咗 5 個工件。按實際產出順序記錄。
proposal.md
變更內容:
- 新增 `src/modules/json-formatter/` 目錄,包含頁面組件、格式化邏輯和測試
- 修改 `router/index.tsx`,在 toolModules 中添加 json-formatter 映射行
能力清單:
- 新增能力:json-format(JSON 格式化 / 壓縮 / 校驗)
影響範圍:路由加載、src/modules/ 目錄結構
proposal 簡潔,一頁紙,說明咗"點解做"同"改咩範圍"。
specs
能力清單只得一個 json-format,所以只生成一個 spec 文件。需求定義咗三個核心行為:
格式化:接收 JSON 字符串,輸出縮進整齊嘅 JSON。Scenario 覆蓋咗簡單物件、巢狀物件、陣列三種輸入 壓縮:移除多餘空白,輸出單行 JSON。Scenario 包含已有縮進嘅 JSON 同帶註釋嘅非法 JSON 校驗:檢測語法錯誤,返回錯誤位置同描述。Scenario 覆蓋咗缺少引號、缺少逗號、多餘嘅尾部逗號、未閉合嘅花括號等常見錯誤
每個需求至少有一個正常輸入 Scenario 同一個異常輸入 Scenario。Spec 嘅質量比 text-summary 嗰期好啲——text-summary 當時得一個"短/中/長"嘅長度選項需求,json-formatter 嘅三個需求方向更清晰,邊界條件都寫得更具體。
design.md
技術決策部分記錄咗幾個要點:
純前端實現,唔依賴外部 API——json-formatter 係一個本地工具,唔需要調用任何後端服務 重用 text-summary 嘅組件模式:頁面組件負責 UI,純函數文件負責邏輯——呢個模式喺 text-summary 上驗證過,直接沿用 使用原生 JSON.parse+JSON.stringify實現格式化同壓縮,唔引入第三方庫——減小打包體積,同時JSON.parse自帶嘅錯誤信息足夠定位語法錯誤位置
仲有一個值得注意嘅決策:校驗功能唔單獨用 try-catch 包一層,而係重用格式化函數嘅錯誤處理。因為 JSON.parse 喺解析失敗時已經會拋出包含位置信息嘅 SyntaxError,冇必要重複實現。呢個決策後來喺 tasks.md 裏面體現為 formatJSON 同 validateJSON 共用同一個 parse 調用。
不過 design.md 仲做咗一個後來影響實現結構嘅決策:single-file component 模式。佢冇好似 text-summary 咁將純函數拆到獨立文件,而係選擇將格式化、壓縮、校驗邏輯直接內聯喺頁面組件中。呢個決策直接決定了 apply 後嘅文件數量——比預期少。
review.md
今期繼續用第 6 期改造嘅 4 維度 review instruction。睇下拆分方向建議有冇參考價值。
4 個維度嘅審查結果:
1. **邊界條件** ✅ 通過:空字符串、null 輸入、非法 JSON、超長字符串均有場景覆蓋
2. **回滾方案** ⚠️ 警告:純前端新增模塊,回滾即刪除目錄,風險可控但 proposal 未顯式說明回滾步驟
3. **測試覆蓋** ✅ 通過:format/compress/validate 三個方向各有獨立測試場景
4. **向後兼容** ✅ 通過:不影響 text-summary 的接口和路由
拆分方向建議:
建議按邏輯層 → 頁面層 → 路由層的順序拆分任務。三個純函數(formatJSON / compressJSON / validateJSON)優先編寫並測試,確保核心邏輯正確後再接入頁面組件。路由映射放在最後一個任務。
同 text-summary 嘅 tasks 拆分思路一致——先純函數、再組件、最後路由。說明 review instruction 嘅拆分方向引導係穩定輸出,唔係偶然碰運氣。
tasks.md
對比 text-summary 嘅 tasks,格式完全一致:每個任務都用 ### 任務 N 標題,附文件列表同 TDD 五步結構(寫失敗測試 → 確認失敗 → 寫最小實現 → 確認通過 → 提交)。
但任務數量比預想嘅少。tasks.md 得 1 個核心任務——JsonFormatterPage 組件整體,唔係 formatJSON / compressJSON / validateJSON 三個獨立嘅純函數任務。呢個係 design.md "單文件組件"決策嘅直接結果:邏輯內聯喺組件中,冇必要拆成獨立嘅純函數 TDD 步驟。
工件自洽性檢查
按照每期嘅慣例,檢查 5 個工件之間係咪存在矛盾:
proposal.md 話"新增 json-format 能力",specs 目錄下確實得一個 specs/json-formatter/spec.md,對應一致design.md 話"使用原生 JSON.parse + JSON.stringify",冇提到任何第三方依賴,同 proposal 嘅"純前端實現"一致 review.md 俾出嘅拆分方向係"邏輯層 → 頁面層 → 路由層",但 tasks.md 實際得組件整體 + 路由映射兩個任務,review 嘅建議冇被完全採納 tasks.md 中嘅文件路徑都指向 src/modules/json-formatter/,冇引用唔存在嘅模塊
5 個工件全部生成完畢,進入 Apply。
Apply:記錄執行過程
執行 /opsx:apply:
**AI**:Test failed as expected (Module not found). Now writing the implementation.
**AI**:One test is failing because `getByText` normalizes whitespace. Let me fix the test to use a regex matcher:
**AI**:
## Implementation Complete
**Change:** implement-json-formatter
**Schema:** with-review
**Progress:** 11/11 tasks complete ✓
| Task | Description | Status |
|------|-------------|--------|
| 1.1 | 寫失敗測試 | ✓ |
| 1.2 | 運行測試——確認失敗 | ✓ |
| 1.3 | 寫最小實現 | ✓ |
| 1.4 | 運行測試——確認通過 | ✓ |
| 1.5 | 提交 | ✓ |
| 2.1 | 添加 json-formatter 映射 | ✓ |
| 2.2 | 驗證 router 測試 | ✓ |
| 2.3 | 提交 | ✓ |
| 3.1 | 運行所有測試 | ✓ |
| 3.2 | 驗證路由可達 | ✓ |
| 3.3 | 最終提交 | ✓ |
Commits:
- `d3ff798` feat(json-formatter): implement JsonFormatterPage component
- `59c13cd` feat(router): add json-formatter tool module mapping
- `e26c616` feat: implement json-formatter tool page
Files Created/Modified:
- `src/modules/json-formatter/index.tsx` (component)
- `src/modules/json-formatter/index.test.tsx` (8 tests)
- `src/router/index.tsx` (added mapping)
All tasks complete! You can archive this change with `/opsx:archive`.
AI 按 tasks.md 嘅順序執行。tasks.md 得 1 個核心任務——JsonFormatterPage 組件整體。TDD 流程係:寫組件嘅失敗測試(渲染標題、輸入區、按鈕交互),確認模塊揾唔到報錯之後,再寫組件實現。唔似 text-summary 嗰期有獨立嘅純函數 TDD 步驟,今期整個組件(含內聯嘅格式化、壓縮、校驗邏輯)喺一個任務裏面完成咗。
整個過程 AI 同用戶之間嘅交互唔多,因為需求明確、tasks 拆分清晰,AI 基本一路執行落嚟冇卡殼。唔似第 4 期佈局改造嗰次,AI 來回問咗好幾輪"Tab 切換行為係咩"、"滾動狀態點處理"。今期呢種"跟住 tasks 一步步寫"嘅場景,OpenSpec 嘅 TDD 五步結構確實減少咗交互輪次。

圖:Apply 執行流程:TDD 分步提交
文件核實
Apply 完成之後,核實文件係咪真係創建成功。
ls src/modules/json-formatter/
實際得 2 個文件,唔係預期嘅 4 個:
index.tsx # 頁面組件(含格式化、壓縮、校驗邏輯)
index.test.tsx # 8 個測試用例
對比 text-summary 嘅 8 個文件(4 源文件 + 4 測試),json-formatter 比 text-summary 更簡潔——冇獨立嘅邏輯文件,格式化、壓縮、校驗三個函數直接寫喺 index.tsx 嘅組件中。每個函數嘅核心就係 JSON.parse + JSON.stringify 嘅唔同參數組合,唔需要拆文件。
呢個就係 design.md "single-file component"決策嘅直接體現。text-summary 有 extract-summary.ts、text-utils.ts、stopwords.ts 三個輔助文件係因為邏輯確實複雜(詞頻統計、句子評分、停用詞),json-formatter 嘅三個功能加埋都係得十幾行代碼,拆文件反而多餘。
路由映射檢查
呢個係每期必查嘅環節。上一期 text-summary 都喺呢度手動加過映射。AI 執行 tasks 時可能跳過路由映射呢步——tasks.md 寫咗呢步,但 AI 容易忽略文件列表之外嘅操作。
讀取 router/index.tsx,確認 toolModules 部分:
const toolModules: Record<string, () => Promise<{ default: React.ComponentType<unknown> }>> = {
'text-summary': () => import('/src/modules/text-summary/index.tsx'),
'json-formatter': () => import('/src/modules/json-formatter/index.tsx'),
};
json-formatter 行已經喺度。今次 AI 冇漏。不過呢個檢查唔可以省——上一期 text-summary 嘅 review 過程中,我就發現過 AI 標記咗 [x] 但實際文件冇改嘅情況。手動核實係每期 apply 後嘅固定動作,唔可以信 AI 嘅完成報告。
實現體驗對比
對比 text-summary,json-formatter 嘅實現過程有明顯差異:
組件模式重用度高:頁面組件 index.tsx 基本套用 text-summary 嘅 textarea + 操作控件 + 結果展示三段式佈局,只係將"生成摘要"按鈕換成"格式化/壓縮/校驗"三個按鈕 純函數邏輯更簡單:text-summary 嘅 extract-summary.ts 涉及詞頻統計、句子評分、位置權重,json-formatter 嘅內聯邏輯本質係 JSON.parse+JSON.stringify嘅三種參數組合測試更好寫:text-summary 要模擬中文分詞場景,json-formatter 輸入輸出都係字符串,測試用例更直觀
呢個就係建立組件模式嘅價值:第一個工具花時間摸索模式,第二個工具直接套用。如果後續第三個、第四個工具繼續行呢條路徑,實現速度會越來越快。
文件清單確認完畢,進入今期重點——Verify。
Verify:記錄驗證過程(今期重點)
今期 Verify 係核心驗證點。修咗 SKILL.md 嘅兩處矛盾之後,verify 報告係咪首次出現 4 個維度?
執行 /opsx:verify。
verify 報告
AI 實際輸出嘅 verify 報告:
## Verification Report: implement-json-formatter
### Summary
| Dimension | Status |
|--------------|---------------------|
| Completeness | 11/11 tasks, 7/8 scenarios |
| Correctness | Requirement implemented, 1 scenario uncovered |
| Coherence | Design followed, pattern consistent |
---
### Issues by Priority
#### CRITICAL (Must fix before archive)
**Scenario not implemented: 大文件 JSON 解析**
- **Spec requirement**: "用戶輸入一個非常大的 JSON(超過 1MB)" → "錯誤提示區顯示'JSON 數據過大,請控制在中。'"
- **Current state**: No size check in implementation
- **Recommendation**: Add size check in `src/modules/json-formatter/index.tsx`:
```typescript
const MAX_SIZE = 1024 * 1024; // 1MB
if (input.length > MAX_SIZE) {
setError('JSON 數據過大,請控制在中。');
setOutput('');
return;
}
```
Add corresponding test in `src/modules/json-formatter/index.test.tsx`
#### WARNING (Should fix)
**Scenario not tested: 用戶輸入有效 JSON 並點擊語法校驗按鈕**
- **Spec requirement**: "錯誤提示區顯示'JSON 語法正確',結果展示區顯示原始 JSON"
- **Current state**: Test for valid JSON validation is missing
#### SUGGESTION (Nice to fix)
**Test file uses getAllByRole for output textarea**
- **Current**: `screen.getAllByRole('textbox')[1]` relies on order
- **Alternative**: Add `aria-label` to output textarea
### Final Assessment
**1 critical issue found. Fix before archiving.**
Summary 表格得 3 行。Task Granularity 維度冇出現——同上一期完全一樣,修復 SKILL.md 冇生效。呢個對應草稿預測嘅"情況 B"。
不過 verify 報告本身嘅質量比上期好唔少。佢發現咗 1 個 CRITICAL issue:spec 裏面定義咗"大文件 JSON 解析"場景(超過 1MB 嘅 JSON 要提示用戶),但實現中冇做 size check。仲發現咗 1 個 WARNING:有效 JSON 點擊語法校驗按鈕嘅測試用例缺失。呢啲發現係 specs 裏面寫咗但 tasks.md 冇覆蓋到嘅場景,verify 將佢哋執返出嚟。

圖:verify 報告摘要:3 維度 + 缺失標註
build 驗證
npm run build
npm run build(實際執行 tsc -b && vite build)因 tsc 類型錯誤失敗。報咗 4 個錯誤,其中 2 個係 router 動態 import 路徑嘅既有問題(從第 2 期就存在),1 個係測試文件裏面 vi 冇用到但 import 咗。呢啲都係類型層面嘅問題,唔影響運行。
跳過 tsc 直接跑 npx vite build,構建成功:
vite v8.0.12 building client environment for production...
✓ 1757 modules transformed.
rendering chunks...
computing gzip size...
dist/index.html 0.46 kB │ gzip: 0.30 kB
dist/assets/index-8W2XdHU1.css 20.28 kB │ gzip: 4.75 kB
dist/assets/json-formatter-DwIBtDQv.js 2.63 kB │ gzip: 0.88 kB
dist/assets/text-summary-C_blhUgt.js 2.84 kB │ gzip: 1.39 kB
dist/assets/index-BtN7sydP.js 295.12 kB │ gzip: 94.23 kB
✓ built in 197ms
json-formatter 同 text-summary 各自獨立打包為 chunk(json-formatter-DwIBtDQv.js 和 text-summary-C_blhUgt.js),動態路由嘅 code splitting 生效咗。json-formatter 得 2.63 kB(gzip 後 0.88 kB),體積控制得唔錯。
瀏覽器檢查:先踩咗一個坑
啓動開發服務器,訪問 /tools/json-formatter——頁面停喺加載中...唔鬱了。text-summary 頁面正常。同一個 router 邏輯,一個可以加載一個唔得,問題肯定出喺 json-formatter 模塊本身。
仔細對比兩個模塊嘅代碼,發現根因:json-formatter 嘅 index.tsx 只用咗 named export(export function JsonFormatterPage()),而 router 嘅 ToolPage 組件取嘅係 mod.default。text-summary 有 export default TextSummaryPage,json-formatter 漏咗。
俾 AI 報咗呢個問題,佢自己揾到原因加咗 export default JsonFormatterPage;。
修復後單獨提交咗一個 commit:
4b8e1d4 fix(json-formatter): add default export for lazy loading
呢個 bug 嘅教訓係:組件模式重用時,export 方式都要對齊。named export 同 default export 喺動態 import 時行為唔同,少寫一行 export default 就會導致整個頁面加載失敗。後續每個新工具嘅模板裏面應該將 export default 作為固定項寫死,避免再踩呢個坑。
瀏覽器檢查:修復後嘅功能驗證
修復 export default 後重新訪問 /tools/json-formatter,頁面正常加載:

圖 1:json-formatter 頁面修復後正常加載,顯示標題、輸入區同三個操作按鈕
頁面佈局同 text-summary 類似:
標題區:JSON 格式化 輸入區:textarea,placeholder 提示輸入 JSON 操作區:格式化、壓縮、校驗三個按鈕 輸出區:textarea 展示結果
輸入一段壓縮嘅 JSON 測試格式化功能:
{"name":"shuge-ai-toolbox","version":"1.0.0","dependencies":{"react":"^19.0.0","react-dom":"^19.0.0"}}
點擊格式化按鈕,輸出帶縮進嘅版本:

圖 2:輸入壓縮 JSON 後點擊"格式化",輸出帶縮進嘅可讀版本
再測試校驗功能——輸入一段唔合法嘅 JSON:
{"name": "test", "age":}

圖 3:輸入無效 JSON 後點擊"校驗",顯示語法錯誤提示
校驗功能正常,返回咗語法錯誤嘅提示信息。瀏覽器檢查通過。
Archive:歸檔
確認 verify 通過後執行歸檔:
## Archive Complete
**Change:** implement-json-formatter
**Schema:** with-review
**Archived to:** `openspec/changes/archive/2026-05-31-implement-json-formatter/`
**Specs:** No delta specs (json-formatter is a new capability, not yet in main specs)
All artifacts complete. All tasks complete (11/11).
**Note:** The verification report found a missing "large file" scenario check (>1MB), but since you chose to archive without addressing it, the spec remains in the archive for future reference.
注意最後嗰句 Note:AI 提醒 verify 報告發現嘅大文件場景(>1MB)未修復就歸檔咗。呢個說明 verify 確實起到咗"檢查遺漏"嘅作用,雖然 Task Granularity 維度冇生效,但其他三個維度(特別是 Correctness)將 spec 裏面寫咗但實現冇覆蓋嘅場景執返出嚟。
驗證歸檔結果:
ls openspec/changes/
活躍變更目錄應該係空嘅(或者剩低其他未完成嘅 change),implement-json-formatter/ 已移到 openspec/archive/ 下。
Git 推送:提交到 GitHub
AI 按 TDD 步驟分 3 個獨立 commit 提交,加上後續修復 export default 嘅 1 個 commit,共 4 個 commit:
4b8e1d4 fix(json-formatter): add default export for lazy loading
e26c616 feat: implement json-formatter tool page
59c13cd feat(router): add json-formatter tool module mapping
d3ff798 feat(json-formatter): implement JsonFormatterPage component
呢個唔係一個大合併 commit,而係按 TDD 節奏嘅增量提交:組件實現 → 路由映射 → 最終整合 → bug 修復。每個 commit 粒度細、職責單一,符合 TDD 分步提交嘅模式。
SKILL.md 嘅修復冇納入 git commit——因為佢係喺項目外嘅 .claude/skills/ 目錄下執行嘅,唔屬於項目倉庫嘅變更範圍。
**AI**:已推送到遠端。3 個 commit 從 `d387013` 到 `e26c616`。
回顧:今期學到咗啲乜
verify 修復冇生效
改咗 SKILL.md 三處(定義本身已正確、Summary Scorecard 加行、Graceful Degradation 改 three→four),全鏈路同步咗,但 verify 報告仍然只輸出 3 維度。AI 唔係冇讀到修改——佢確實加載咗 SKILL.md——但輸出時冇嚴格按模板逐項填充,而係按自己嘅理解行咗老路徑。
呢個說明單靠改提示詞嘅約束力有天花板:改全鏈路係必要條件,但唔係充分條件。就算定義、模板、退化邏輯全部統一咗,AI 喺生成報告時仍然可能跳過模板,直接按慣性輸出。
有個結論係確定嘅:提示詞嘅全鏈路同步比單點增強重要得多。L46 嘅定義寫得幾靚都好,後面模板同退化邏輯冇跟上,執行層就跟舊路徑行。呢個係 2/8 法則嘅又一次驗證。但同時要承認,全鏈路同步都唔可以保證 AI 一定按模板行——呢個係提示詞約束嘅固有侷限。
verify 報告雖然冇出現第 4 維度,但喺其他方面發揮咗價值:佢發現咗大文件 JSON 解析場景嘅遺漏同有效 JSON 校驗測試嘅缺失。呢啲係 specs 裏面寫咗但實現冇覆蓋嘅,verify 將佢哋執返出嚟。
第二個工具嘅實現體驗
json-formatter 嘅實現速度明顯比 text-summary 快。核心原因:
組件模式可以直接重用,唔使重新摸索 JSON 格式化嘅核心邏輯比文本摘要嘅詞頻統計簡單得多 測試用例更好寫——輸入輸出都係字符串,唔需要模擬中文分詞
第一個工具花時間建立模式,第二個工具享受模式紅利。如果後續繼續按呢個節奏迭代,每加一個工具嘅邊際成本會越來越低。
export default 呢個坑
json-formatter 實現過程中踩嘅 export default 坑值得單獨記一筆。text-summary 有 export default,json-formatter 冇,頁面直接卡死喺"加載中..."。呢個唔係複雜邏輯 bug,而係一行代碼嘅遺漏,但排查花咗唔短嘅時間——因為第一反應係"路由配置有問題",而唔係"export 方式唔啱"。
後續每個新工具嘅模板應該將 export default 作為固定項寫死,同 import React 一樣成為模板嘅必選項。
路由加載策略嘅侷限
toolModules 手動映射每加一個工具改一次 router/index.tsx,兩期落嚟已經改咗兩次(text-summary 同 json-formatter)。目前得兩個 active 工具還好,等工具數量上去咗呢個就係維護負擔。但今期唔改呢個,屬於"用得到但唔夠優雅"嘅範疇,留俾後續專門嘅重構任務。
理想嘅做法係將 toolModules 改成動態掃描 src/modules/ 目錄,或者喺 catalog.ts 裏面加一個 modulePath 字段,令路由映射自動生成。不過呢種重構屬於"改善型"需求,當前階段優先級唔高——先將工具做出嚟先講。
關於 verify 嘅邊界思考
如果今期 verify 4 維度仍然冇生效,咁就說明純 SKILL.md 文案修改嘅約束力有天花板。AI 嘅執行行為受上下文慣性影響——佢可能讀到新嘅模板但仍然按舊習慣輸出。單靠提示詞約束,冇辦法保證 AI 嚴格跟隨每一條規則。呢個發現本身有價值:佢說明質量保證唔可以只壓喺 verify 呢一個環節上,需要引入更強嘅過程控制。
下一期會詳細討論呢個問題,以及點解後續唔再死磕 OpenSpec verify 嘅增強,而係引入 Superpowers 嘅計劃紀律嚟補充。
預告
第 8 期暫時唔寫代碼,覆盤第 5-7 期三層改造嘅實驗結果:template 改造嘅投入產出比、review 拆分方向建議嘅實際價值、verify SKILL.md 修復嘅最終效果。然後引入三檔工作流嘅概念:
快速檔:低風險改動(文案、樣式),OpenSpec + fresh verify 就夠曬 標準檔:普通工具開發,OpenSpec + Superpowers writing-plans 控制計劃顆粒度 嚴格檔:核心邏輯、bugfix、重構,疊加 TDD、debug、code review
按風險選強度,唔再一刀切。呢個都係呢個系列從"摸索 OpenSpec 增強方案"轉向"組合使用 OpenSpec + Superpowers"嘅轉折點。
聲明:本文基於 OpenSpec v1.3.1 源碼分析、實際項目操作記錄同讀者反饋整理。所有改造都在 shuge-ai-toolbox 項目中實際驗證。配置同代碼僅供參考,請以實際環境測試為準。
項目倉庫:https://github.com/shuge-x/shuge-ai-toolbox
好啦,多謝你睇我嘅文章,如果鍾意可以點讚轉發俾需要嘅朋友,我哋下一期再見!敬請期待!
🚩 2026 年「術哥無界」系列實戰文檔 X 篇原創計劃 第 127 篇,OpenSpec 項目實戰「2026」系列第 7 篇
大家好,歡迎來到 術哥無界 | ShugeX | 運維有術。
我是術哥,一名專注於 AI 編程、AI 智能體、Agent Skills、MCP、雲原生、AIOps、Milvus 向量數據庫的技術實踐者與開源佈道者!
Talk is cheap, let's explore。無界探索,有術而行。

圖:信息圖封面:OpenSpec verify 修復 + json-formatter 實現
上一期做了三層改造——template 改了 tasks 格式、review 加了 4 維度審查和拆分方向建議、verify 加了第 4 維度 Task Granularity。三層改造的驗證結果:template 生效了,review 生效了,verify 沒生效。
verify 卡在哪?執行 /opsx:verify 後,報告只輸出了 Completeness、Correctness、Coherence 三個維度,Task Granularity 始終缺席。第 6 期加的那個第 4 維度的定義,AI 壓根沒用上。
翻了一遍 SKILL.md 源文件,根因找到了:L46 定義部分確實寫了 four dimensions,但後面兩處引用這個數字的地方還停留在 three dimensions。一處是 Summary Scorecard 模板表格,只有 3 行沒有 Task Granularity。另一處是 Graceful Degradation 段的最後一行,明確寫着 "verify all three dimensions"。AI 執行 verify 時,讀到這兩處舊文案,直接按 3 維度出了報告。定義和引用不一致,AI 不覺得有問題,照着舊文案走就是了。
說到底,這是個典型的"改了定義沒改引用"的問題。寫代碼的時候我們都知道改了接口要改所有調用方,但改提示詞的時候容易忽略同樣的道理。
本期做兩件事:先把 verify SKILL.md 的內部矛盾修完,然後實現第二個工具 json-formatter。json-formatter 的 catalog 註冊和路由第 2 期就配好了(catalog.ts 裏的 stage: 'active',路由 /tools/json-formatter),但 src/modules/json-formatter/ 目錄一直空着。這期把它填上,同時驗證修復後的 verify 是否真的能輸出 4 維度報告。
兩個任務有先後順序:先修 SKILL.md,再走 Propose → Apply → Verify。這樣本期 verify 階段就能用上修復後的配置,直接檢驗效果。
完整流程如下:
說明:本文內容基於 OpenSpec v1.3.1 實際項目操作記錄整理。verify SKILL.md 修復和 json-formatter 工具實現均在 shuge-ai-toolbox 項目中實際驗證,但 verify 第 4 維度(Task Granularity)修復後仍未生效,文中如實記錄。文中的配置修改和代碼僅供參考,實際效果請以你的項目環境測試結果為準。如果有實際使用經驗,歡迎在評論區分享交流。
修復 verify SKILL.md:把矛盾的地方同步改完
先定位問題。文件路徑是 .claude/skills/openspec-verify-change/SKILL.md,總共 173 行。
L46 的定義部分其實是對的:
Create a report structure with four dimensions:
- **Completeness**: Track tasks and spec coverage
- **Correctness**: Track requirement implementation and scenario coverage
- **Coherence**: Track design adherence and pattern consistency
- **Task Granularity**: Track task format compliance, TDD adherence, code completeness, and granularity assessment
四個維度定義齊全,L50-54 還詳細拆了 Task Granularity 的四項檢查:任務格式、TDD 合規、代碼完整性、粒度評估。定義沒問題。
問題出在後面兩處引用這個數字的地方。
矛盾點 1:Summary Scorecard 模板(L117-127)
這個表格是 verify 報告末尾的彙總模板,AI 按這個格式輸出最終結論。當前只有 3 行:
### Summary
| Dimension | Status |
|--------------|------------------|
| Completeness | X/Y tasks, N reqs|
| Correctness | M/N reqs covered |
| Coherence | Followed/Issues |
Task Granularity 行缺失。AI 生成報告時照着模板走,模板只有 3 行,輸出自然只有 3 維度。
矛盾點 2:Graceful Degradation 段(L159-164)
這個段描述的是"當工件不全時怎麼降級驗證"。最後一句:
- If full artifacts: verify all three dimensions
寫的是 three dimensions。即使所有工件都齊全,AI 讀到這句也會認為只需要驗證 3 個維度。

圖:SKILL.md 三處矛盾位置標註
具體修改
改動不大,但位置分散,需要逐個同步。
修改 1:Summary Scorecard 加行
改前:
| Dimension | Status |
|--------------|------------------|
| Completeness | X/Y tasks, N reqs|
| Correctness | M/N reqs covered |
| Coherence | Followed/Issues |
改後:
| Dimension | Status |
|------------------|------------------|
| Completeness | X/Y tasks, N reqs|
| Correctness | M/N reqs covered |
| Coherence | Followed/Issues |
| Task Granularity | Format/TDD/Code |
新增的 Task Granularity 行,狀態列用 Format/TDD/Code 簡寫,對應任務格式檢查、TDD 合規檢查、代碼完整性檢查三項。
修改 2:Graceful Degradation three → four
改前:
- If full artifacts: verify all three dimensions
改後:
- If full artifacts: verify all four dimensions
一個詞的事。但這一詞決定了 AI 驗證時是否走第 4 維度。

圖:SKILL.md 修復前後對比
改完存盤,總共改了兩處三行。看起來微不足道,但這個同步不到位正是 verify 第 4 維度一直缺席的直接原因。
這裏有個教訓值得記一筆:提示詞約束是一條鏈路,不是孤立的定義。L46 定義寫得再漂亮,後面模板和退化邏輯沒跟上,執行層就按舊路徑走。2/8 法則的體現——定義佔 20% 篇幅但決定方向,引用點佔 80% 篇幅且決定實際行為。改提示詞要改全鏈路,不能只改最顯眼的那一處。
改完 verify SKILL.md 後,馬上進入 Propose。這樣本期生成的工件才能用上修復後的配置。
Propose:記錄工件產出過程
本期跳過 Explore,需求很明確——實現 json-formatter 工具,複用 text-summary 已建立的組件模式。
執行 /opsx:propose:
**AI**:What change do you want to work on? Describe what you want to build or fix.
**用戶**:本期做一個 implement-json-formatter 變更。在 src/modules/json-formatter/ 下實現 JSON 格式化工具,複用 text-summary 已建立的組件模式。功能包括格式化、壓縮、語法校驗。catalog.ts 中 json-formatter 已註冊為 active,路由已存在,但模塊目錄尚未創建。同時需要在 router/index.tsx 的 toolModules 中添加 json-formatter 的映射行。
**AI**:
**Change created: `implement-json-formatter`**
**Location:**`openspec/changes/implement-json-formatter/`
**Artifacts created:**
| Artifact | Description |
|----------|-------------|
| `proposal.md` | Why we need JSON formatting (dev高頻需求,純前端實現) |
| `design.md` | Technical design: single-file component, native JSON.parse/JSON.stringify, useEffect+import pattern |
| `specs/json-formatter/spec.md` | 8 scenarios covering format/minify/validate, empty input, large file |
| `review.md` | 4-dimension review with task split direction |
| `tasks.md` | 3 tasks: JsonFormatterPage (TDD), router mapping, verification |
**Task breakdown:**
- 任務 1: JsonFormatterPage 組件(TDD 模式,測試 + 實現)
- 任務 2: Router 映射配置(toolModules 添加 json-formatter)
- 任務 3: 驗證完整功能
**All artifacts created! Ready for implementation.**
Run `/opsx:apply implement-json-formatter` to start implementing.
AI 一次生成了 5 個工件。按實際產出順序記錄。
proposal.md
變更內容:
- 新增 `src/modules/json-formatter/` 目錄,包含頁面組件、格式化邏輯和測試
- 修改 `router/index.tsx`,在 toolModules 中添加 json-formatter 映射行
能力清單:
- 新增能力:json-format(JSON 格式化 / 壓縮 / 校驗)
影響範圍:路由加載、src/modules/ 目錄結構
proposal 簡潔,一頁紙,說明了"為什麼做"和"改什麼範圍"。
specs
能力清單隻有一個 json-format,所以只生成一個 spec 文件。需求定義了三個核心行為:
格式化:接收 JSON 字符串,輸出縮進整齊的 JSON。Scenario 覆蓋了簡單對象、嵌套對象、數組三種輸入 壓縮:移除多餘空白,輸出單行 JSON。Scenario 包含已有縮進的 JSON 和帶註釋的非法 JSON 校驗:檢測語法錯誤,返回錯誤位置和描述。Scenario 覆蓋了缺少引號、缺少逗號、多餘的尾部逗號、未閉合的花括號等常見錯誤
每個需求至少有一個正常輸入 Scenario 和一個異常輸入 Scenario。Spec 的質量比 text-summary 那期好一些——text-summary 當時只有一個"短/中/長"的長度選項需求,json-formatter 的三個需求方向更清晰,邊界條件也寫得更具體。
design.md
技術決策部分記錄了幾個要點:
純前端實現,不依賴外部 API——json-formatter 是個本地工具,不需要調用任何後端服務 複用 text-summary 的組件模式:頁面組件負責 UI,純函數文件負責邏輯——這個模式在 text-summary 上驗證過了,直接沿用 使用原生 JSON.parse+JSON.stringify實現格式化和壓縮,不引入第三方庫——減小打包體積,同時JSON.parse自帶的錯誤信息足夠定位語法錯誤位置
還有一個值得注意的決策:校驗功能不單獨用 try-catch 包一層,而是複用格式化函數的錯誤處理。因為 JSON.parse 在解析失敗時已經會拋出包含位置信息的 SyntaxError,沒必要重複實現。這個決策後來在 tasks.md 裏體現為 formatJSON 和 validateJSON 共用同一個 parse 調用。
不過 design.md 還做了一個後來影響實現結構的決策:single-file component 模式。它沒有像 text-summary 那樣把純函數拆到獨立文件,而是選擇把格式化、壓縮、校驗邏輯直接內聯在頁面組件中。這個決策直接決定了 apply 後的文件數量——比預期少。
review.md
這期繼續用第 6 期改造的 4 維度 review instruction。看看拆分方向建議有沒有參考價值。
4 個維度的審查結果:
1. **邊界條件** ✅ 通過:空字符串、null 輸入、非法 JSON、超長字符串均有場景覆蓋
2. **回滾方案** ⚠️ 警告:純前端新增模塊,回滾即刪除目錄,風險可控但 proposal 未顯式說明回滾步驟
3. **測試覆蓋** ✅ 通過:format/compress/validate 三個方向各有獨立測試場景
4. **向後兼容** ✅ 通過:不影響 text-summary 的接口和路由
拆分方向建議:
建議按邏輯層 → 頁面層 → 路由層的順序拆分任務。三個純函數(formatJSON / compressJSON / validateJSON)優先編寫並測試,確保核心邏輯正確後再接入頁面組件。路由映射放在最後一個任務。
和 text-summary 的 tasks 拆分思路一致——先純函數、再組件、最後路由。說明 review instruction 的拆分方向引導在穩定輸出,不是偶爾碰運氣。
tasks.md
對比 text-summary 的 tasks,格式完全一致:每個任務都用 ### 任務 N 標題,附文件列表和 TDD 五步結構(寫失敗測試 → 確認失敗 → 寫最小實現 → 確認通過 → 提交)。
但任務數量比預想的少。tasks.md 只有 1 個核心任務——JsonFormatterPage 組件整體,不是 formatJSON / compressJSON / validateJSON 三個獨立的純函數任務。這是 design.md "單文件組件"決策的直接結果:邏輯內聯在組件中,沒必要拆成獨立的純函數 TDD 步驟。
工件自洽性檢查
按照每期的慣例,檢查 5 個工件之間是否存在矛盾:
proposal.md 說"新增 json-format 能力",specs 目錄下確實只有一個 specs/json-formatter/spec.md,對應一致design.md 說"使用原生 JSON.parse + JSON.stringify",沒有提到任何第三方依賴,和 proposal 的"純前端實現"一致 review.md 給出的拆分方向是"邏輯層 → 頁面層 → 路由層",但 tasks.md 實際只有組件整體 + 路由映射兩個任務,review 的建議沒有被完全採納 tasks.md 中的文件路徑都指向 src/modules/json-formatter/,沒有引用不存在的模塊
5 個工件全部生成完畢,進入 Apply。
Apply:記錄執行過程
執行 /opsx:apply:
**AI**:Test failed as expected (Module not found). Now writing the implementation.
**AI**:One test is failing because `getByText` normalizes whitespace. Let me fix the test to use a regex matcher:
**AI**:
## Implementation Complete
**Change:** implement-json-formatter
**Schema:** with-review
**Progress:** 11/11 tasks complete ✓
| Task | Description | Status |
|------|-------------|--------|
| 1.1 | 寫失敗測試 | ✓ |
| 1.2 | 運行測試——確認失敗 | ✓ |
| 1.3 | 寫最小實現 | ✓ |
| 1.4 | 運行測試——確認通過 | ✓ |
| 1.5 | 提交 | ✓ |
| 2.1 | 添加 json-formatter 映射 | ✓ |
| 2.2 | 驗證 router 測試 | ✓ |
| 2.3 | 提交 | ✓ |
| 3.1 | 運行所有測試 | ✓ |
| 3.2 | 驗證路由可達 | ✓ |
| 3.3 | 最終提交 | ✓ |
Commits:
- `d3ff798` feat(json-formatter): implement JsonFormatterPage component
- `59c13cd` feat(router): add json-formatter tool module mapping
- `e26c616` feat: implement json-formatter tool page
Files Created/Modified:
- `src/modules/json-formatter/index.tsx` (component)
- `src/modules/json-formatter/index.test.tsx` (8 tests)
- `src/router/index.tsx` (added mapping)
All tasks complete! You can archive this change with `/opsx:archive`.
AI 按 tasks.md 的順序執行。tasks.md 只有 1 個核心任務——JsonFormatterPage 組件整體。TDD 流程是:寫組件的失敗測試(渲染標題、輸入區、按鈕交互),確認模塊找不到報錯後,再寫組件實現。不像 text-summary 那期有獨立的純函數 TDD 步驟,本期整個組件(含內聯的格式化、壓縮、校驗邏輯)在一個任務裏完成了。
整個過程 AI 和用戶之間的交互不多,因為需求明確、tasks 拆分清晰,AI 基本一路執行下來沒卡殼。不像第 4 期佈局改造那次,AI 來回問了好幾輪"Tab 切換行為是什麼"、"滾動狀態怎麼處理"。本期這種"照着 tasks 一步步寫"的場景,OpenSpec 的 TDD 五步結構確實減少了交互輪次。

圖:Apply 執行流程:TDD 分步提交
文件核實
Apply 完成後,核實文件是否真的創建成功。
ls src/modules/json-formatter/
實際只有 2 個文件,不是預期的 4 個:
index.tsx # 頁面組件(含格式化、壓縮、校驗邏輯)
index.test.tsx # 8 個測試用例
對比 text-summary 的 8 個文件(4 源文件 + 4 測試),json-formatter 比 text-summary 更簡潔——沒有獨立的邏輯文件,格式化、壓縮、校驗三個函數直接寫在 index.tsx 的組件中。每個函數的核心就是 JSON.parse + JSON.stringify 的不同參數組合,不需要拆文件。
這就是 design.md "single-file component"決策的直接體現。text-summary 有 extract-summary.ts、text-utils.ts、stopwords.ts 三個輔助文件是因為邏輯確實複雜(詞頻統計、句子評分、停用詞),json-formatter 的三個功能加起來也就十幾行代碼,拆文件反而多餘。
路由映射檢查
這是每期必查的環節。上一期 text-summary 也在這裏手動加過映射。AI 執行 tasks 時可能跳過路由映射這步——tasks.md 寫了這步,但 AI 容易忽略文件列表之外的操作。
讀取 router/index.tsx,確認 toolModules 部分:
const toolModules: Record<string, () => Promise<{ default: React.ComponentType<unknown> }>> = {
'text-summary': () => import('/src/modules/text-summary/index.tsx'),
'json-formatter': () => import('/src/modules/json-formatter/index.tsx'),
};
json-formatter 行已經在。這次 AI 沒漏。不過這個檢查不能省——上一期 text-summary 的 review 過程中,我就發現過 AI 標記了 [x] 但實際文件沒改的情況。手動核實是每期 apply 後的固定動作,不能信 AI 的完成報告。
實現體驗對比
對比 text-summary,json-formatter 的實現過程有明顯差異:
組件模式複用度高:頁面組件 index.tsx 基本套用 text-summary 的 textarea + 操作控件 + 結果展示三段式佈局,只是把"生成摘要"按鈕換成了"格式化/壓縮/校驗"三個按鈕 純函數邏輯更簡單:text-summary 的 extract-summary.ts 涉及詞頻統計、句子評分、位置權重,json-formatter 的內聯邏輯本質是 JSON.parse+JSON.stringify的三種參數組合測試更好寫:text-summary 要模擬中文分詞場景,json-formatter 輸入輸出都是字符串,測試用例更直觀
這就是建立組件模式的價值:第一個工具花時間摸索模式,第二個工具直接套用。如果後續第三個、第四個工具繼續走這條路徑,實現速度會越來越快。
文件清單確認完畢,進入本期重點——Verify。
Verify:記錄驗證過程(本期重點)
本期 Verify 是核心驗證點。修了 SKILL.md 的兩處矛盾後,verify 報告是否首次出現 4 個維度?
執行 /opsx:verify。
verify 報告
AI 實際輸出的 verify 報告:
## Verification Report: implement-json-formatter
### Summary
| Dimension | Status |
|--------------|---------------------|
| Completeness | 11/11 tasks, 7/8 scenarios |
| Correctness | Requirement implemented, 1 scenario uncovered |
| Coherence | Design followed, pattern consistent |
---
### Issues by Priority
#### CRITICAL (Must fix before archive)
**Scenario not implemented: 大文件 JSON 解析**
- **Spec requirement**: "用戶輸入一個非常大的 JSON(超過 1MB)" → "錯誤提示區顯示'JSON 數據過大,請控制在中。'"
- **Current state**: No size check in implementation
- **Recommendation**: Add size check in `src/modules/json-formatter/index.tsx`:
```typescript
const MAX_SIZE = 1024 * 1024; // 1MB
if (input.length > MAX_SIZE) {
setError('JSON 數據過大,請控制在中。');
setOutput('');
return;
}
```
Add corresponding test in `src/modules/json-formatter/index.test.tsx`
#### WARNING (Should fix)
**Scenario not tested: 用戶輸入有效 JSON 並點擊語法校驗按鈕**
- **Spec requirement**: "錯誤提示區顯示'JSON 語法正確',結果展示區顯示原始 JSON"
- **Current state**: Test for valid JSON validation is missing
#### SUGGESTION (Nice to fix)
**Test file uses getAllByRole for output textarea**
- **Current**: `screen.getAllByRole('textbox')[1]` relies on order
- **Alternative**: Add `aria-label` to output textarea
### Final Assessment
**1 critical issue found. Fix before archiving.**
Summary 表格只有 3 行。Task Granularity 維度沒有出現——和上一期完全一樣,修復 SKILL.md 沒有生效。這對應草稿預測的"情況 B"。
不過 verify 報告本身的質量比上期好不少。它發現了 1 個 CRITICAL issue:spec 裏定義了"大文件 JSON 解析"場景(超過 1MB 的 JSON 要提示用戶),但實現中沒有做 size check。還發現了 1 個 WARNING:有效 JSON 點擊語法校驗按鈕的測試用例缺失。這些發現是 specs 裏寫了但 tasks.md 沒覆蓋到的場景,verify 把它們撈出來了。

圖:verify 報告摘要:3 維度 + 缺失標註
build 驗證
npm run build
npm run build(實際執行 tsc -b && vite build)因 tsc 類型錯誤失敗。報了 4 個錯誤,其中 2 個是 router 動態 import 路徑的既有問題(從第 2 期就存在),1 個是測試文件裏 vi 沒用到但 import 了。這些都是類型層面的問題,不影響運行。
跳過 tsc 直接跑 npx vite build,構建成功:
vite v8.0.12 building client environment for production...
✓ 1757 modules transformed.
rendering chunks...
computing gzip size...
dist/index.html 0.46 kB │ gzip: 0.30 kB
dist/assets/index-8W2XdHU1.css 20.28 kB │ gzip: 4.75 kB
dist/assets/json-formatter-DwIBtDQv.js 2.63 kB │ gzip: 0.88 kB
dist/assets/text-summary-C_blhUgt.js 2.84 kB │ gzip: 1.39 kB
dist/assets/index-BtN7sydP.js 295.12 kB │ gzip: 94.23 kB
✓ built in 197ms
json-formatter 和 text-summary 各自獨立打包為 chunk(json-formatter-DwIBtDQv.js 和 text-summary-C_blhUgt.js),動態路由的 code splitting 生效了。json-formatter 只有 2.63 kB(gzip 後 0.88 kB),體積控制得不錯。
瀏覽器檢查:先踩了一個坑
啓動開發服務器,訪問 /tools/json-formatter——頁面停在加載中...不動了。text-summary 頁面正常。同一個 router 邏輯,一個能加載一個不能,問題肯定出在 json-formatter 模塊本身。
仔細對比兩個模塊的代碼,發現根因:json-formatter 的 index.tsx 只用了 named export(export function JsonFormatterPage()),而 router 的 ToolPage 組件取的是 mod.default。text-summary 有 export default TextSummaryPage,json-formatter 漏了。
給 AI 報了這個問題,它自己找到原因加上了 export default JsonFormatterPage;。
修復後單獨提交了一個 commit:
4b8e1d4 fix(json-formatter): add default export for lazy loading
這個 bug 的教訓是:組件模式複用時,export 方式也得對齊。named export 和 default export 在動態 import 時行為不同,少寫一行 export default 就會導致整個頁面加載失敗。後續每個新工具的模板裏應該把 export default 作為固定項寫死,避免再踩這個坑。
瀏覽器檢查:修復後的功能驗證
修復 export default 後重新訪問 /tools/json-formatter,頁面正常加載:

圖 1:json-formatter 頁面修復後正常加載,顯示標題、輸入區和三個操作按鈕
頁面佈局和 text-summary 類似:
標題區:JSON 格式化 輸入區:textarea,placeholder 提示輸入 JSON 操作區:格式化、壓縮、校驗三個按鈕 輸出區:textarea 展示結果
輸入一段壓縮的 JSON 測試格式化功能:
{"name":"shuge-ai-toolbox","version":"1.0.0","dependencies":{"react":"^19.0.0","react-dom":"^19.0.0"}}
點擊格式化按鈕,輸出帶縮進的版本:

圖 2:輸入壓縮 JSON 後點擊"格式化",輸出帶縮進的可讀版本
再測試校驗功能——輸入一段不合法的 JSON:
{"name": "test", "age":}

圖 3:輸入無效 JSON 後點擊"校驗",顯示語法錯誤提示
校驗功能正常,返回了語法錯誤的提示信息。瀏覽器檢查通過。
Archive:歸檔
確認 verify 通過後執行歸檔:
## Archive Complete
**Change:** implement-json-formatter
**Schema:** with-review
**Archived to:** `openspec/changes/archive/2026-05-31-implement-json-formatter/`
**Specs:** No delta specs (json-formatter is a new capability, not yet in main specs)
All artifacts complete. All tasks complete (11/11).
**Note:** The verification report found a missing "large file" scenario check (>1MB), but since you chose to archive without addressing it, the spec remains in the archive for future reference.
注意最後那句 Note:AI 提醒 verify 報告發現的大文件場景(>1MB)未修復就歸檔了。這說明 verify 確實起到了"檢查遺漏"的作用,雖然 Task Granularity 維度沒生效,但其他三個維度(特別是 Correctness)把 spec 裏寫了但實現沒覆蓋的場景撈出來了。
驗證歸檔結果:
ls openspec/changes/
活躍變更目錄應該是空的(或只剩其他未完成的 change),implement-json-formatter/ 已移到 openspec/archive/ 下。
Git 推送:提交到 GitHub
AI 按 TDD 步驟分 3 個獨立 commit 提交,加上後續修復 export default 的 1 個 commit,共 4 個 commit:
4b8e1d4 fix(json-formatter): add default export for lazy loading
e26c616 feat: implement json-formatter tool page
59c13cd feat(router): add json-formatter tool module mapping
d3ff798 feat(json-formatter): implement JsonFormatterPage component
這不是一個大合併 commit,而是按 TDD 節奏的增量提交:組件實現 → 路由映射 → 最終整合 → bug 修復。每個 commit 粒度小、職責單一,符合 TDD 分步提交的模式。
SKILL.md 的修復沒有納入 git commit——因為它是在項目外的 .claude/skills/ 目錄下執行的,不屬於項目倉庫的變更範圍。
**AI**:已推送到遠端。3 個 commit 從 `d387013` 到 `e26c616`。
回顧:本期學到了什麼
verify 修復沒有生效
改了 SKILL.md 三處(定義本身已正確、Summary Scorecard 加行、Graceful Degradation 改 three→four),全鏈路同步了,但 verify 報告仍然只輸出 3 維度。AI 不是沒讀到修改——它確實加載了 SKILL.md——但輸出時沒有嚴格按模板逐項填充,而是按自己的理解走了老路徑。
這說明單靠改提示詞的約束力有天花板:改全鏈路是必要條件,但不是充分條件。即使定義、模板、退化邏輯全部統一了,AI 在生成報告時仍然可能跳過模板,直接按慣性輸出。
有個結論是確定的:提示詞的全鏈路同步比單點增強重要得多。L46 的定義寫得再漂亮,後面模板和退化邏輯沒跟上,執行層就按舊路徑走。這是 2/8 法則的又一次驗證。但同時要承認,全鏈路同步也不能保證 AI 一定按模板走——這是提示詞約束的固有侷限。
verify 報告雖然沒有出現第 4 維度,但在其他方面發揮了價值:它發現了大文件 JSON 解析場景的遺漏和有效 JSON 校驗測試的缺失。這些是 specs 裏寫了但實現沒覆蓋的,verify 把它們撈出來了。
第二個工具的實現體驗
json-formatter 的實現速度明顯比 text-summary 快。核心原因:
組件模式可以直接複用,不用重新摸索 JSON 格式化的核心邏輯比文本摘要的詞頻統計簡單得多 測試用例更好寫——輸入輸出都是字符串,不需要模擬中文分詞
第一個工具花時間建立模式,第二個工具享受模式紅利。如果後續繼續按這個節奏迭代,每加一個工具的邊際成本會越來越低。
export default 這個坑
json-formatter 實現過程中踩的 export default 坑值得單獨記一筆。text-summary 有 export default,json-formatter 沒有,頁面直接卡死在"加載中..."。這不是複雜邏輯 bug,而是一行代碼的遺漏,但排查花了不短的時間——因為第一反應是"路由配置有問題",而不是"export 方式不對"。
後續每個新工具的模板應該把 export default 作為固定項寫死,和 import React 一樣成為模板的必選項。
路由加載策略的侷限
toolModules 手動映射每加一個工具改一次 router/index.tsx,兩期下來已經改了兩次(text-summary 和 json-formatter)。目前只有兩個 active 工具還好,等工具數量上去了這就是維護負擔。但本期不改這個,屬於"能用但不夠優雅"的範疇,留給後續專門的重構任務。
理想的做法是把 toolModules 改成動態掃描 src/modules/ 目錄,或者在 catalog.ts 里加一個 modulePath 字段,讓路由映射自動生成。不過這種重構屬於"改善型"需求,當前階段優先級不高——先把工具做出來再說。
關於 verify 的邊界思考
如果本期 verify 4 維度仍然沒生效,那說明純 SKILL.md 文案修改的約束力有天花板。AI 的執行行為受上下文慣性影響——它可能讀到新的模板但仍然按舊習慣輸出。單靠提示詞約束,無法保證 AI 嚴格遵循每一條規則。這個發現本身有價值:它說明質量保證不能只壓在 verify 這一個環節上,需要引入更強的過程控制。
下一期會詳細討論這個問題,以及為什麼後續不再死磕 OpenSpec verify 的增強,而是引入 Superpowers 的計劃紀律來補充。
預告
第 8 期先不寫代碼,覆盤第 5-7 期三層改造的實驗結果:template 改造的投入產出比、review 拆分方向建議的實際價值、verify SKILL.md 修復的最終效果。然後引入三檔工作流的概念:
快速檔:低風險改動(文案、樣式),OpenSpec + fresh verify 就夠了 標準檔:普通工具開發,OpenSpec + Superpowers writing-plans 控制計劃顆粒度 嚴格檔:核心邏輯、bugfix、重構,疊加 TDD、debug、code review
按風險選強度,不再一刀切。這也是這個系列從"摸索 OpenSpec 增強方案"轉向"組合使用 OpenSpec + Superpowers"的轉折點。
聲明:本文基於 OpenSpec v1.3.1 源碼分析、實際項目操作記錄和讀者反饋整理。所有改造均在 shuge-ai-toolbox 項目中實際驗證。配置和代碼僅供參考,請以實際環境測試為準。
項目倉庫:https://github.com/shuge-x/shuge-ai-toolbox
好啦,謝謝你觀看我的文章,如果喜歡可以點贊轉發給需要的朋友,我們下一期再見!敬請期待!