# 官方 KBDB 誤寫清理 SOP(issue #3 待辦 1) > **狀態**:runbook 已備妥,**待官方運營方(leo)親自執行**。 > **為什麼不由 CC 直接跑**:對官方 prod D1 執行不可逆 `DELETE`,需官方憑證 + 人類明示確認 > (mindset §7「絕不代替人類做有風險的確認」;rule 06)。CC 只備妥可審、防誤刪的腳本,DELETE 由人按下。 > **來源**:issue #3(leo 2026-06-24 拍板,14-E 遷移善後)。根因 bug 已修(issue #2,commit 9c4333d)。 --- ## 背景 14-E 遷移期間(issue #2 的 `KBDB_BASE_URL` fallback bug 修好**之前**),mira 的 `_kbdb_client.py` 把 **~11 萬筆 `owner_id='leo'`** 的資料誤寫進**官方 prod kbdb**(`arcrun-kbdb`,非 leo21c self-hosted)。 - **歸屬**:官方 SaaS 庫的清理 = arcrun 官方運營方的事,不是 mira(用戶)。讓用戶拿官方憑證 DELETE 官方 prod 本身違反隔離。 - **重要性**:SaaS 尚未營運,這批誤寫資料不重要 → 可刪。但**官方 prod DELETE 不可逆 → 必須防誤刪**。 --- ## 目標庫(精確座標) | 項目 | 值 | |------|-----| | Worker / DB name | `arcrun-kbdb` | | D1 database_id | `0c580910-e00b-4f8e-9c57-ac54ea52242f`(官方 prod,見 `kbdb/wrangler.toml:13`) | | 官方 CF account | `58309bb9…`(記憶 [[cf-account-official-vs-loadtest]]) | | 誤寫標記 | `entries.owner_id = 'leo'` | ⚠️ **帳號對齊**:執行前確認本機 wrangler 對的是**官方帳號**(不是 leo21c)。 `wrangler whoami` 應顯示官方 uncle6.me account。誤寫在官方庫,所以這次**就是要對官方帳號**操作 (與 self-hosted 部署相反,那邊要避開官方——見記憶 [[selfhosted-deploy-account-override-trap]])。 --- ## 表關係(決定刪除範圍) base 三表(`kbdb/migrations/0001_base.sql`): - `entries`:主表,誤寫資料在這(`owner_id='leo'`)。 - `entry_values`:slot-link,`entry_id REFERENCES entries(id)`。若 leo 資料含 record(用 template 組的結構化資料), 其 slot 連結在這。**刪 entries 會留下孤兒 entry_values** → 要一併清。 - `templates`:`created_by` 可能是 `'leo'`。**先確認** leo 有沒有建 template(待辦 2 步驟會查), template 較可能是共享/誤建,刪前單獨核實。 --- ## SOP(逐步,每步有 gate,防誤刪) > 全程用 `wrangler d1 execute arcrun-kbdb --remote --command "..."`。**`--remote` 不可漏**(漏了打本地空庫,假綠)。 ### 步驟 0:帳號 + 庫核實(gate) ```bash wrangler whoami # 確認 = 官方 uncle6.me account(58309bb9) wrangler d1 info arcrun-kbdb # 確認 database_id = 0c580910... ``` ### 步驟 1:備份(整庫導出,防誤刪的底氣) ```bash wrangler d1 export arcrun-kbdb --remote --output backup-before-cleanup-2026-06-24.sql ls -lh backup-before-cleanup-2026-06-24.sql # 確認檔案非空、大小合理 ``` ### 步驟 2:標記 / 核實刪除範圍(**最關鍵的 gate**) ```bash # 2a. 誤寫總數(應 ~11 萬) wrangler d1 execute arcrun-kbdb --remote --command \ "SELECT count(*) AS leo_entries FROM entries WHERE owner_id='leo';" # 2b. 關鍵確認:owner_id='leo' 是否只有這批誤寫,有沒有別的 leo 真資料混入 # 看 entry_type 分布 + 時間範圍(誤寫應集中在 14-E 遷移那段時間) wrangler d1 execute arcrun-kbdb --remote --command \ "SELECT entry_type, count(*) AS n, min(created_at) AS first_at, max(created_at) AS last_at \ FROM entries WHERE owner_id='leo' GROUP BY entry_type ORDER BY n DESC;" # 2c. 孤兒 entry_values(會被 entries 刪除留下的) wrangler d1 execute arcrun-kbdb --remote --command \ "SELECT count(*) AS leo_entry_values FROM entry_values \ WHERE entry_id IN (SELECT id FROM entries WHERE owner_id='leo');" # 2d. leo 建的 template(單獨核實,勿盲刪——可能是共享/系統 template 誤標) wrangler d1 execute arcrun-kbdb --remote --command \ "SELECT id, name, created_by FROM templates WHERE created_by='leo';" ``` **Gate 判定**(人類看數字決定): - 2a count ≈ 11 萬、2b 時間集中在遷移期 → 範圍乾淨,可進步驟 3。 - 若 2b 出現非遷移期、或 entry_type 異常 → **停手**,逐筆核實,別整批刪。 - 2d 若有 template → 個別判斷是否該刪(template 通常想保留,除非確認是誤建)。 ### 步驟 3:刪除(確認範圍乾淨後) ```bash # 3a. 先刪孤兒 entry_values(外鍵指向即將被刪的 entries) wrangler d1 execute arcrun-kbdb --remote --command \ "DELETE FROM entry_values WHERE entry_id IN (SELECT id FROM entries WHERE owner_id='leo');" # 3b. 再刪 entries wrangler d1 execute arcrun-kbdb --remote --command \ "DELETE FROM entries WHERE owner_id='leo';" # 3c.(可選,僅當步驟 2d 確認某 template 是誤建才刪) # wrangler d1 execute arcrun-kbdb --remote --command \ # "DELETE FROM templates WHERE created_by='leo' AND id='<確認過的 id>';" ``` ### 步驟 4:驗證(刪後核實) ```bash # 4a. leo 誤寫歸零 wrangler d1 execute arcrun-kbdb --remote --command \ "SELECT count(*) AS remaining_leo FROM entries WHERE owner_id='leo';" # 應 = 0 # 4b. 孤兒 entry_values 歸零 wrangler d1 execute arcrun-kbdb --remote --command \ "SELECT count(*) AS orphan_ev FROM entry_values \ WHERE entry_id NOT IN (SELECT id FROM entries);" # 應 = 0 # 4c. 官方庫其餘資料不受影響(總 entries 數應 = 刪除前總數 - 11 萬) wrangler d1 execute arcrun-kbdb --remote --command \ "SELECT owner_id, count(*) AS n FROM entries GROUP BY owner_id ORDER BY n DESC;" ``` ### 步驟 5:收尾 - 4a/4b/4c 符合預期 → 清理完成。 - 備份檔(`backup-before-cleanup-2026-06-24.sql`)可棄(SaaS 未營運,無長期保留必要)。 - 在 issue #3 comment 回報:刪除數量 + 驗證 count + 確認官方庫其餘不受影響。 --- ## 為什麼這樣設計(防誤刪三道閘) 1. **備份先行**(步驟 1):DELETE 不可逆,先有 d1 export 的整庫快照當底氣。 2. **核實再刪**(步驟 2 gate):不盲信「~11 萬都是誤寫」,看 entry_type + 時間分布確認範圍乾淨, 排除別的 leo 真資料混入(issue #3 待辦 1 步驟 2 的「關鍵確認」)。 3. **驗證歸零**(步驟 4):刪後客觀證據(count=0 + 孤兒=0 + 其餘不受影響),不靠「跑完了」口頭宣布 (mindset §7 完成=客觀證據)。 ## 待辦 2(願景)落點 `acr migrate` 一等公民雙向遷移已記頂層 `docs/1-vision/product-wishlist.md` C7 + 本 repo backlog,不急做。 詳見 issue #3 待辦 2。