5d00e71275
頂層 D22 決策(leo 2026-07-03 拍板):推什麼由開發環境歸屬決定, Gitea private=除機敏值/build 產物/.github 外全 push。 解 T1.5 卡點:雲端工人 clone 拿得到 credential-store-migration.md,可就地改寫 SDD。 機敏掃描兩輪通過(新增 189 檔約 2.1MB,node_modules/dist/wasm 照舊排除)。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
145 lines
6.6 KiB
Markdown
145 lines
6.6 KiB
Markdown
# 官方 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。
|