|
| 1 | +# McBopomofo 統一使用者模型 — Stacked Branches 開發報告 |
| 2 | + |
| 3 | +## 概述 |
| 4 | + |
| 5 | +本報告記錄使用 Claude Code (Claude Opus 4.6) 開發 McBopomofo 輸入法「統一使用者模型」的完整過程,涵蓋三個 stacked branches 從設計、實作到程式碼審查的全部歷程。 |
| 6 | + |
| 7 | +**時間跨度**: 2026 年 2 月 8 日 02:52 JST — 2 月 9 日 01:09 JST(約 22 小時) |
| 8 | + |
| 9 | +**最終分支狀態**: |
| 10 | +``` |
| 11 | +master (4199b23) |
| 12 | + └── refactor/walk_strategy (f5c3d35) ← Branch 1: +649 -93 行 |
| 13 | + └── feat/contextual_user_model (cbb3870) ← Branch 2: +1,229 -6 行 |
| 14 | + └── feat/keyhandler_user_model (8d4236f) ← Branch 3: +330 -192 行 |
| 15 | +``` |
| 16 | + |
| 17 | +**總變更量**: 13 個檔案,+2,200 -284 行(淨增 +1,916 行) |
| 18 | + |
| 19 | +--- |
| 20 | + |
| 21 | +## 一、Session 全覽 |
| 22 | + |
| 23 | +共 15 個 Claude Code sessions(含設定與雜項),以下列出所有核心工作 sessions: |
| 24 | + |
| 25 | +| # | Session ID | 時間 (JST) | 時長 | 大小 | 子代理 | 活動摘要 | |
| 26 | +|---|-----------|-----------|------|------|--------|---------| |
| 27 | +| 1 | 686c7ac9 | 02:52-03:00 | 8min | 48K | 0 | C++ 語言伺服器設定 | |
| 28 | +| 2 | c0b648b0 | 03:00-03:02 | 2min | 8K | 0 | 插件安裝 | |
| 29 | +| 3 | 2fc7e2da | 03:03-05:13 | 2h10m | 3.1M | 4 | PR #777 閱讀 + 架構設計 | |
| 30 | +| 4 | 9c480a3c | 05:13-06:15 | 1h2m | 2.7M | 1 | Phase 0-3 核心實作 | |
| 31 | +| 5 | cecf82cd | 06:15-06:37 | 22min | 1.1M | 3 | 實作延續(/clear 後)| |
| 32 | +| 6 | 1436378d | 06:37-17:38 | 11h1m | 2.8M | 4 | Phase 4: KeyHandler 整合 | |
| 33 | +| 7 | ef523bd8 | 17:38-17:50 | 12min | 724K | 1 | 建立 3 個 stacked branches | |
| 34 | +| 8 | bfbe9f00 | 17:54-19:03 | 1h9m | 1.1M | 3 | 程式碼審查 Round 1 | |
| 35 | +| 9 | 86c3fcce | 19:03-20:55 | 1h52m | 7.2M | 12 | 審查 Rounds 2-4 + 註解清理 | |
| 36 | +| 10 | a784ab88 | 20:55-23:38 | 2h43m | 11M | 24 | 審查 Rounds 5-7 | |
| 37 | +| 11 | e29a06e1 | 23:38-23:57 | 19min | 10M | 45 | Round 8A: Branch 1 | |
| 38 | +| 12 | b1c07522 | 00:13-00:55 | 42min | 11M | 46 | Round 8B-C: Branch 2-3 | |
| 39 | +| 13 | 8724b694 | 00:00-00:13 | 13min | 624K | 0 | Round 8 context reload | |
| 40 | +| 14 | a8f7492c | 00:56-00:59 | 3min | 1.6M | 7 | Round 8 修復 | |
| 41 | +| 15 | 439d5864+9001dc5e | 00:59-01:09 | 10min | 2.2M | 5 | Round 8 收尾 + 最終驗證 | |
| 42 | + |
| 43 | +--- |
| 44 | + |
| 45 | +## 二、對話階段詳情 |
| 46 | + |
| 47 | +### 階段 A:環境設定與研究(02:52 — 05:13 JST) |
| 48 | + |
| 49 | +#### 對話 1:C++ 語言伺服器設定 |
| 50 | +- **你的提問**:「for this repo, what do I need to install to support c++ language server?」 |
| 51 | +- **討論內容**:clangd 安裝、`compile_commands.json` 生成方式 |
| 52 | +- **互動次數**:13 user / 11 assistant |
| 53 | + |
| 54 | +#### 對話 2:PR #777 深度閱讀 + 統一模型設計 |
| 55 | +- **你的提問**:「read https://github.com/openvanilla/McBopomofo/pull/777 carefully including resolved comments and explain to me in traditional chinese...」 |
| 56 | +- **討論內容**: |
| 57 | + - 深入分析 ChiahongHong 的 Viterbi 重構 PR |
| 58 | + - 五種分詞演算法比較(Viterbi / Beam Search / A* / Greedy / Forward-Backward) |
| 59 | + - 設計四層 KN backoff 使用者模型架構 |
| 60 | + - 產出 1,275 行設計文件(`mighty-fluttering-pudding.md`) |
| 61 | +- **互動次數**:134 user / 232 assistant(含 4 個子代理) |
| 62 | + |
| 63 | +### 階段 B:核心實作(05:13 — 17:38 JST) |
| 64 | + |
| 65 | +#### 對話 3:Phase 0-3 實作 |
| 66 | +- **你的提問**:「Implement the following plan: Unified User Model: Structural Fixes + Interpolated KN with Sub-Span Decomposition...」 |
| 67 | +- **實作內容**: |
| 68 | + - Phase 0A: 動態 span 長度(vector 取代 array<8>) |
| 69 | + - Phase 0B: Walk strategy 介面(ViterbiStrategy 等 4 種策略) |
| 70 | + - Phase 1: 結構性修正(fixedSpans_) |
| 71 | + - Phase 2: ContextualUserModel(四層 KN backoff) |
| 72 | + - Phase 3: Walk 整合(user model scoring + post-walk overrides) |
| 73 | +- **互動次數**:204 user / 349 assistant(跨 2 sessions + /clear) |
| 74 | + |
| 75 | +#### 對話 4:Phase 4 KeyHandler 整合 |
| 76 | +- **你的提問**:「Implement the following plan: Phase 4: KeyHandler Integration...」 |
| 77 | +- **實作內容**: |
| 78 | + - 簡化 `KeyHandler.mm` 的 insert/select 流程 |
| 79 | + - `LanguageModelManager.mm` 全域 ContextualUserModel |
| 80 | + - 舊流程:insert → walk → UOM.suggest → override(score=42) → walk again |
| 81 | + - 新流程:insert → walk(userModel) ← 單次 pass |
| 82 | +- **互動次數**:118 user / 188 assistant |
| 83 | + |
| 84 | +### 階段 C:分支建立(17:38 — 17:50 JST) |
| 85 | + |
| 86 | +#### 對話 5:Stacked Branch 建立 |
| 87 | +- **你的提問**:「Implement the following plan: Stacked Branches for Unified User Model (Phases 0-4)...」 |
| 88 | +- **操作**:從單一 commit 拆分為 3 個 stacked branches,每個有一個乾淨的 commit |
| 89 | +- **互動次數**:41 user / 63 assistant |
| 90 | + |
| 91 | +### 階段 D:程式碼審查 Rounds 1-7(17:54 — 23:38 JST) |
| 92 | + |
| 93 | +#### 對話 6-8:多輪審查 |
| 94 | +- **你的提問**: |
| 95 | + - Round 1:「Code review for stacked branches...」 |
| 96 | + - Rounds 2-4:「Code Review & Comment Cleanup for Stacked Branches...」 |
| 97 | + - Rounds 5-7:「Code Review for Stacked Branches...」(新計劃、更深入) |
| 98 | +- **審查成果**: |
| 99 | + - 清除了 ~66 個 AI 自動生成的不必要註解 |
| 100 | + - 修復了 10 個 bugs |
| 101 | + - 簡化了 strategy pattern |
| 102 | +- **互動次數**:544 user / 821 assistant(跨 3 sessions) |
| 103 | +- **使用了 39 個審查子代理** |
| 104 | + |
| 105 | +### 階段 E:Round 8 最終審查(23:38 JST — 01:09+1 JST) |
| 106 | + |
| 107 | +#### 對話 9-11:Round 8 全面重新審查 |
| 108 | +- **你的提問**:「Implement the following plan: Round 8: Fresh Code Review — Stacked Branches...」 |
| 109 | +- **審查方法**:每個 branch 啟動 7 個並行審查代理(共 21 個/完整周期): |
| 110 | + 1. `pr-review-toolkit:code-reviewer` — 風格、bugs、最佳實踐 |
| 111 | + 2. `pr-review-toolkit:silent-failure-hunter` — 錯誤處理缺口 |
| 112 | + 3. `pr-review-toolkit:code-simplifier` — 簡化機會 |
| 113 | + 4. `pr-review-toolkit:comment-analyzer` — 註解品質 |
| 114 | + 5. `pr-review-toolkit:type-design-analyzer` — 型別設計品質 |
| 115 | + 6. `coderabbit:code-reviewer` — CodeRabbit AI 審查 |
| 116 | + 7. `feature-dev:code-reviewer` — bugs、邏輯錯誤、安全性 |
| 117 | +- **修復了 4 個問題**(詳見下方) |
| 118 | +- **互動次數**:~503 user / ~827 assistant(跨 5+ sessions) |
| 119 | +- **使用了 ~103 個審查子代理** |
| 120 | + |
| 121 | +--- |
| 122 | + |
| 123 | +## 三、分支實作詳情 |
| 124 | + |
| 125 | +### Branch 1: `refactor/walk_strategy`(7 檔案 +649 -93 行) |
| 126 | + |
| 127 | +| 檔案 | 變更 | |
| 128 | +|------|------| |
| 129 | +| `language_model.h` | 新增 `maxKeyLength()` 虛擬方法 | |
| 130 | +| `reading_grid.h` | 動態 span(vector 取代 array<8>)、fixedSpans、walk delegation | |
| 131 | +| `reading_grid.cpp` | 重構 walk() 委派至策略、fixSpan/clearFixedSpans 實作 | |
| 132 | +| `walk_strategy.h` | **新檔案**: Strategy Pattern 介面 | |
| 133 | +| `walk_strategy.cpp` | **新檔案**: RunViterbi + 4 種策略 | |
| 134 | +| `reading_grid_test.cpp` | +8 測試(6 FixedSpan + 3 AlgoComparison = 29 總計)| |
| 135 | +| `CMakeLists.txt` | 更新來源檔案 | |
| 136 | + |
| 137 | +**Commit**: `f5c3d35 refactor: extract walk strategy and add dynamic span support` |
| 138 | +**Commit 時間**: 2026-02-08 17:56:50 +0900 |
| 139 | + |
| 140 | +### Branch 2: `feat/contextual_user_model`(8 檔案 +1,229 -6 行) |
| 141 | + |
| 142 | +| 檔案 | 變更 | |
| 143 | +|------|------| |
| 144 | +| `contextual_user_model.h` | **新檔案**: 四層 KN backoff 模型介面 | |
| 145 | +| `contextual_user_model.cpp` | **新檔案**: 309 行核心演算法實作 | |
| 146 | +| `reading_grid.h` | userModel 整合、post-walk overrides | |
| 147 | +| `reading_grid.cpp` | selectOverrideUnigram、post-walk 使用者模型建議 | |
| 148 | +| `walk_strategy.h` | Relax() 新增 user model 參數 | |
| 149 | +| `walk_strategy.cpp` | user model scoring 整合 | |
| 150 | +| `reading_grid_test.cpp` | +24 測試(9 ContextualUserModel + 15 IntegratedWalk = 53 總計)| |
| 151 | +| `CMakeLists.txt` | 更新來源檔案 | |
| 152 | + |
| 153 | +**核心演算法**: Interpolated Kneser-Ney 四層 backoff |
| 154 | +1. **Bigram**: P(w | left_context) — 使用者觀察紀錄,含時間衰減 |
| 155 | +2. **Continuation**: P_cont(w) — 不同左上下文的數量 |
| 156 | +3. **Base LM**: P_base(w) — data.txt ~160K 詞條 |
| 157 | +4. **Decomposed**: ΠP_base(syllable_i) — 未知詞的音節分解 |
| 158 | + |
| 159 | +**參數**: 折扣 d=0.5, 衰減半衰期=20, 最低機率=1e-10 |
| 160 | + |
| 161 | +**Commit**: `cbb3870 feat: add contextual user model with KN backoff scoring` |
| 162 | +**Commit 時間**: 2026-02-08 18:09:49 +0900 |
| 163 | + |
| 164 | +### Branch 3: `feat/keyhandler_user_model`(5 檔案 +330 -192 行) |
| 165 | + |
| 166 | +| 檔案 | 變更 | |
| 167 | +|------|------| |
| 168 | +| `KeyHandler.mm` | 簡化 insert/select 流程,接入 contextualUserModel | |
| 169 | +| `LanguageModelManager.mm` | 全域 ContextualUserModel 實例、load/save | |
| 170 | +| `LanguageModelManager+Privates.h` | 新增 contextualUserModel 屬性 | |
| 171 | +| `McBopomofo.xcodeproj` | 加入新檔案參照 | |
| 172 | +| `reading_grid_test.cpp` | +1 測試 = 54 總計 | |
| 173 | + |
| 174 | +**流程簡化**: |
| 175 | +- 舊: insert → walk → UOM.suggest → overrideCandidate(score=42) → walk again |
| 176 | +- 新: insert → walk(userModel) ← 單次 pass,KN-smoothed scores 內建 |
| 177 | + |
| 178 | +**Commit**: `8d4236f feat: integrate contextual user model into KeyHandler` |
| 179 | +**Commit 時間**: 2026-02-08 21:47:04 +0900 |
| 180 | + |
| 181 | +--- |
| 182 | + |
| 183 | +## 四、程式碼審查修復紀錄 |
| 184 | + |
| 185 | +### Round 8 修復(4 個問題,3 HIGH + 1 LOW-MED) |
| 186 | + |
| 187 | +| Branch | 嚴重度 | 修復內容 | 檔案 | |
| 188 | +|--------|--------|---------|------| |
| 189 | +| 1 | HIGH | "shortest-path" → "longest-path" 註解錯誤 | walk_strategy.h | |
| 190 | +| 1 | HIGH | MMSEG/SegmentViterbi 加入 placeholder 註解(尚未實作的策略) | walk_strategy.h | |
| 191 | +| 2 | HIGH | `selectOverrideUnigram` 回傳值未檢查,可能跳過有效建議 | reading_grid.cpp:194-197 | |
| 192 | +| 3 | LOW-MED | `"_START_"` 魔術字串替換為 `kStartSentinel` 常數 | KeyHandler.mm:210 | |
| 193 | + |
| 194 | +### 排除的誤報 |
| 195 | + |
| 196 | +| 問題 | 排除原因 | |
| 197 | +|------|---------| |
| 198 | +| Lambda `[&readingStr]` 捕獲 | 同步執行,捕獲的參照在 lambda 生命周期內有效 | |
| 199 | +| Iterator bounds check | `!= cbegin()` 已足夠保證 `*(iter - 1)` 安全 | |
| 200 | +| Missing node validation | 程式碼已有檢查,審查代理隨後撤回了此項 | |
| 201 | + |
| 202 | +### Rounds 1-7 累計修復 |
| 203 | + |
| 204 | +- 清除 ~66 個 AI 自動生成的冗餘註解 |
| 205 | +- 修復 10 個 bugs |
| 206 | +- 簡化 strategy pattern 設計 |
| 207 | + |
| 208 | +--- |
| 209 | + |
| 210 | +## 五、Token 使用與成本 |
| 211 | + |
| 212 | +### 各階段 Token 使用 |
| 213 | + |
| 214 | +| 階段 | Sessions | 輸出 Tokens | 快取讀取 | 快取建立 | 子代理 | |
| 215 | +|------|----------|------------|---------|---------|--------| |
| 216 | +| 環境設定 + 研究設計 | 3 | 33,652 | 24,495,125 | 905,319 | 4 | |
| 217 | +| 核心實作 (Phase 0-4) | 3 | 43,722 | 54,716,122 | 2,814,654 | 8 | |
| 218 | +| 分支建立 | 1 | 6,427 | 5,248,916 | 254,601 | 1 | |
| 219 | +| 審查 Rounds 1-7 | 3 | 45,577 | 76,627,261 | 3,120,698 | 39 | |
| 220 | +| Round 8 最終審查 | 5 | 30,603 | 47,271,647 | 3,557,377 | 103 | |
| 221 | +| **合計** | **15** | **159,981** | **208,359,071** | **10,652,649** | **155** | |
| 222 | + |
| 223 | +### Token 統計摘要 |
| 224 | + |
| 225 | +| 指標 | 數值 | |
| 226 | +|------|------| |
| 227 | +| 輸出 tokens 合計 | 159,981 | |
| 228 | +| 快取讀取 tokens 合計 | 208,359,071(~208M)| |
| 229 | +| 快取建立 tokens 合計 | 10,652,649(~10.7M)| |
| 230 | +| 有效輸入 tokens 合計 | ~219,132,000(~219M)| |
| 231 | +| API 呼叫總數 | ~2,330 | |
| 232 | + |
| 233 | +### /insights 全域統計(stats-cache.json) |
| 234 | + |
| 235 | +以下為 `/insights` 的全域統計資料(涵蓋所有專案,非僅 McBopomofo): |
| 236 | + |
| 237 | +**McBopomofo 工作日**: |
| 238 | + |
| 239 | +| 日期 (UTC) | 對應 JST | 訊息數 | Sessions | 工具呼叫 | 輸出 Tokens | |
| 240 | +|-----------|---------|--------|----------|---------|------------| |
| 241 | +| 2026-02-07 | 2/8 白天 | 28,228 | 60 | 4,388 | 944,933 | |
| 242 | +| 2026-02-08 | 2/8 晚-2/9 凌晨 | 26,168 | 62 | 4,202 | 629,486 | |
| 243 | + |
| 244 | +**claude-opus-4-6 全期使用統計**: |
| 245 | + |
| 246 | +| 指標 | 數值 | |
| 247 | +|------|------| |
| 248 | +| 輸入 tokens | 782,446 | |
| 249 | +| 輸出 tokens | 2,146,964 | |
| 250 | +| 快取讀取 | 2,481,332,835(~2.48B)| |
| 251 | +| 快取建立 | 131,222,845(~131M)| |
| 252 | +| 總 sessions(所有專案) | 525 | |
| 253 | +| 總訊息(所有專案) | 245,066 | |
| 254 | +| 首次使用日期 | 2025-12-26 | |
| 255 | + |
| 256 | +**最活躍時段**(以 UTC 計,所有專案): |
| 257 | +- 最高峰: 17:00-18:00 UTC(02:00-03:00 JST)— 48 sessions |
| 258 | +- 次高峰: 17:00 UTC(43 sessions)、15:00 UTC(42 sessions) |
| 259 | + |
| 260 | +--- |
| 261 | + |
| 262 | +## 六、時間分配 |
| 263 | + |
| 264 | +| 階段 | 時長 | 佔比 | |
| 265 | +|------|------|------| |
| 266 | +| 環境設定 + 研究設計 | ~2.5 小時 | 11% | |
| 267 | +| 核心實作(Phase 0-4) | ~12.5 小時 | 56% | |
| 268 | +| 分支建立 | ~12 分鐘 | 1% | |
| 269 | +| 程式碼審查 R1-7 | ~5.7 小時 | 25% | |
| 270 | +| 最終審查 R8 | ~1.5 小時 | 7% | |
| 271 | +| **總計** | **~22.2 小時** | 100% | |
| 272 | + |
| 273 | +> **註**: 時間跨度(22 小時)包含可能的休息/中斷時間(特別是 Phase 4 的 06:37-17:38 區間),實際活躍 coding 時間可能較短。 |
| 274 | +
|
| 275 | +--- |
| 276 | + |
| 277 | +## 七、程式碼產出統計 |
| 278 | + |
| 279 | +| 指標 | 數值 | |
| 280 | +|------|------| |
| 281 | +| 修改檔案數 | 13 | |
| 282 | +| 新增行數 | +2,200 | |
| 283 | +| 刪除行數 | -284 | |
| 284 | +| 淨增行數 | +1,916 | |
| 285 | +| 新建檔案 | 4(walk_strategy.h/.cpp, contextual_user_model.h/.cpp)| |
| 286 | +| C++ 測試新增 | 33 個(從 21 → 54)| |
| 287 | +| XCTests | 35 個(未變動)| |
| 288 | +| Session 資料總大小 | ~56 MB | |
| 289 | + |
| 290 | +### 測試結果 |
| 291 | + |
| 292 | +| Branch | 測試數 | 結果 | |
| 293 | +|--------|--------|------| |
| 294 | +| refactor/walk_strategy | 29/29 | 全部通過 | |
| 295 | +| feat/contextual_user_model | 53/53 | 全部通過 | |
| 296 | +| feat/keyhandler_user_model | 54/54 | 全部通過 | |
| 297 | + |
| 298 | +壓力測試(8,001 readings):~14-15ms,效能無衰退。 |
| 299 | + |
| 300 | +--- |
| 301 | + |
| 302 | +## 八、已知延遲問題 |
| 303 | + |
| 304 | +以下問題在審查中被記錄但延遲到後續 Phase 5/6 處理: |
| 305 | + |
| 306 | +| # | 問題 | 預計處理 | |
| 307 | +|---|------|---------| |
| 308 | +| 1 | 每次選字都存檔(主執行緒同步 I/O) | Phase 5 | |
| 309 | +| 2 | `gContextualUserModel` 線程安全 | Phase 5 | |
| 310 | +| 3 | bigram store 無容量上限/驅逐機制 | Phase 5 | |
| 311 | +| 4 | 舊版 `_userOverrideModel` 死碼 | Phase 5 | |
| 312 | +| 5 | Aliasing `shared_ptr` 脆弱性 | Phase 5 | |
| 313 | +| 6 | `loadFromFile` 空白字元解析脆弱性 | Phase 5 | |
| 314 | +| 7 | `fixedSpans_` 在 reading insert/delete 時未失效 | Phase 5 | |
| 315 | + |
| 316 | +--- |
| 317 | + |
| 318 | +## 九、設計文件與計劃檔案 |
| 319 | + |
| 320 | +| 文件 | 路徑 | 用途 | |
| 321 | +|------|------|------| |
| 322 | +| 統一使用者模型設計 | `~/.claude/plans/mighty-fluttering-pudding.md` | Phase 0-6 完整設計(1,275 行)| |
| 323 | +| Round 8 審查計劃 | `~/.claude/plans/memoized-toasting-bumblebee.md` | 最終審查計劃與結果 | |
| 324 | +| 架構文件 | `~/.claude/projects/.../memory/architecture.md` | 技術架構摘要 | |
| 325 | +| 專案記憶 | `~/.claude/projects/.../memory/MEMORY.md` | 持久化的專案知識 | |
| 326 | + |
| 327 | +--- |
| 328 | + |
| 329 | +## 十、資料來源說明 |
| 330 | + |
| 331 | +- **Token 使用數據**: 從 15 個 session JSONL 日誌中直接提取(`~/.claude/projects/.../*.jsonl`) |
| 332 | +- **/insights 數據**: 從 `~/.claude/stats-cache.json` 提取(全域統計,涵蓋所有專案) |
| 333 | +- **Git 歷史**: 從 `git log` 和 `git reflog` 提取 |
| 334 | +- **審查結果**: 從計劃檔案 `memoized-toasting-bumblebee.md` 提取 |
| 335 | +- **Session 中的互動次數**: 包含系統訊息(/clear、hook 觸發等),實際使用者輸入訊息數較少 |
| 336 | +- **快取讀取 tokens(~208M)**: 反映了大量上下文重用,大幅降低了實際 API 成本 |
0 commit comments