# Callback Prefix 統一評估報告（read-only）

> 產出日期：2026-04-24｜狀態：評估中，未動程式碼
> 範圍：`routes/openclaw_bot_routes.py` + `services/telegram_bot_service.py` + `services/telegram_templates.py`

## 1. 範圍統計（實測）

| 類別 | 數量 | 說明 |
|------|------|------|
| 總 callback_data 字面值 | **308** | 含 f-string，含靜態字串 |
| 已有 `momo:` prefix | **5** | 全在 `telegram_templates.py`（pa/pr/bpa/bpr/eig）＋ `telegram_bot_service.py` 的 `momo:ops:` |
| 冒號分隔但無 prefix | **272** | `cmd:*`、`menu:*`、`await:*` |
| 底線分隔（舊 TrendBot） | **31** | `menu_main/menu_trend/menu_search/menu_copy/menu_keywords/menu_daily/menu_settings`、`settings_*`、`trend_*`、`keywords_*` |

按檔案分布：
- `routes/openclaw_bot_routes.py`：**171 筆**（全冒號，僅 1-2 個已是 momo:）
- `services/telegram_bot_service.py`：**39 筆**（混用 — 30 底線 + 9 冒號）
- `services/telegram_templates.py`：**5 筆**（全 momo:，**已合規**，免改）

> 原始口述「80+」低估。實際 **待修 303 筆**（272 + 31）。

## 2. 修改點列表（按檔案精簡，完整 diff 見附錄 A）

### 2-a. `routes/openclaw_bot_routes.py`（171 筆，抽樣）
- L2896-2897：`cmd:import_confirm` / `cmd:import_cancel` → `momo:cmd:*`
- L2996-2999、3098-3101、3244-3247、3419-3429、3444-3450、3462-3482、3501-3517、3524-3590（主選單+子選單 blocks）
- L3267-3268、3474-3482（promo/competitor）
- L3392 `_BACK` 常數：`menu:main` → `momo:menu:main`
- L3635-3645 `sales_quick_kb`
- L4537-4538、4712-4719、4787-4790、4814-4816
- L5047-5257（搜尋/比價/類別鑽取回傳）
- L5414-5418、5536-5539、5658、5748、5810、5846、5859、5891、5902

### 2-b. `services/telegram_bot_service.py`（39 筆）
- L141-156（主選單 8 顆）
- L174、472、483（返回按鈕）
- L1059-1144（trend/keywords/daily 返回群 — 原為底線 `menu_main/menu_trend/menu_keywords/menu_daily`）
- L1208-1212、1265-1266（settings 面板）
- L1436、1445、1515-1516、1558-1559（取消/繼續）

### 2-c. `services/telegram_templates.py`
免改（已全 `momo:` 前綴）。

## 3. Handler（dispatcher）衝擊

### `routes/openclaw_bot_routes.py` 入口 L5610-5663
```
data.startswith('menu:')  → 切 5 字 → _SUBMENUS[key]
data.startswith('await:') → 切 6 字 → _AWAIT_PROMPTS[action]
data.startswith('cmd:')   → 切 4 字 → handle_cmd(parts[0], parts[1])
```
→ **必須在最外層先 strip `momo:`**，否則 `momo:menu:sales` 會落到無人接的分支。

### `services/telegram_bot_service.py::handle_callback` L426-540
```
data == "menu_main" or "menu:main"
data.startswith("menu:")
data == "menu_trend" / "menu_search" / "menu_copy" / "menu_keywords" / "menu_daily" / "menu_settings"
data.startswith("trend_") / "keywords_" / "settings_")
data.startswith("momo:pa:" / "momo:pr:" / "momo:ops:" / "momo:bpa:" / "momo:bpr:" / "momo:eig:")
data.startswith("cmd:")
```
→ 同樣需要 prefix strip；底線家族（`menu_*`、`trend_*`、`keywords_*`、`settings_*`）建議**一併**轉冒號並加 prefix，永久消滅舊 TrendBot 命名痕跡。

## 4. 推薦方案

| 方案 | 實作成本 | 安全性 | 歷史訊息相容 | 推薦 |
|------|---------|-------|------------|------|
| **A** 雙路徑（新發 momo:，handler 同收新舊，3 個月後砍舊） | 高（308 行 + 2 dispatcher 都改） | 最高 | 完整 | 備選 |
| **B** 破壞式升級（只收 momo:） | 中（僅改 dispatch 分支） | 低，歷史鈕變磚 | ❌ | 否決 |
| **C** Dispatcher 入口 strip `momo:`（發送端漸進升級） | **最低**（僅 2 個 dispatcher 頂端加 3 行） | 中高 | 完整 | ✅ **首推** |

### 方案 C 核心 patch（示意，非 apply）
```python
# routes/openclaw_bot_routes.py 在 L5627 後、L5630 前
if data.startswith('momo:'):
    data = data[5:]

# services/telegram_bot_service.py handle_callback L443 後
if data.startswith('momo:') and not data.startswith(('momo:pa:','momo:pr:','momo:ops:','momo:bpa:','momo:bpr:','momo:eig:')):
    data = data[5:]  # 保留 ADR-012 L2 短碼分支原樣
```
→ **即時達成跨專案隔離**：OpenClaw/AWOOOI 送來的非 `momo:` callback 不會被 momo-pro 誤接；momo-pro 日後新發按鈕統一加 prefix，舊按鈕仍可被處理。

發送端（308 行）可在方案 C 上線後，分批以 sed 腳本加 `momo:` prefix（純文字替換，風險低）。

## 5. 風險與成本

| 風險/成本 | 等級 | 說明 |
|----------|------|------|
| 歷史未點擊按鈕失效 | 低（方案 C 下）| dispatcher 入口 strip 即可相容 |
| 誤觸他專案按鈕（當前實況） | **高** | 272 筆無 prefix callback 會讓 OpenClaw/AWOOOI 同名按鈕走到 momo-pro handler |
| 底線家族語意改變（`menu_main` → `momo:menu:main`）| 中 | 需同步處理 `settings_notify_on` 等 4 組 startswith |
| ADR-012 短碼分支（`momo:pa:` 等）被誤剝 | 中 | 方案 C patch 要加白名單，不可對這 6 個前綴 strip |
| 預估工時 | 方案 C 純 dispatcher：**0.5 小時 + critic 0.5 小時**；全量加 prefix：**3-4 小時 + 測試 2 小時** |
| 測試 | dispatcher 變更須在 staging 跑 smoke（主選單 6 條主幹 + ADR-012 confirm/reject 按鈕 + L2 ops 按鈕）|

## 6. 等統帥決策

1. **是否啟動？** 建議「是」——當前 272 筆跨專案外漏是真實資安/功能風險（三 bot 共用 Token）。
2. **採方案？** 首推 **C**（入口 strip + 分批 prefix）；若統帥要求一次到位選 **A**。
3. **派誰執行？**
   - 方案 C dispatcher 改動：`fullstack-engineer` + `critic`（0.5h）
   - 308 行 prefix 批量加：`refactor-specialist`（P9 子任務，3-4h）
   - 底線家族轉冒號：同上，獨立 commit
4. **驗收**：staging smoke（主選單點擊 → ADR-012 按鈕 → L2 ops 按鈕 → 歷史按鈕仍可觸發）＋ critic 審查無 regression。

---

### 附錄 A：完整修改點行號索引

（需全量 diff 時再展開；檔案/行號已於第 2 節列出，可用以下指令重生）
```bash
grep -n "callback_data" routes/openclaw_bot_routes.py \
    services/telegram_bot_service.py | grep -v "momo:"
```
