-- 退役 credentials 表(D38 圍牆修復,總管交辦,2026-08-07) -- SDD:無專屬 SDD(D38 事故修復任務,見 system-dev/wiki/decisions-summary.md D38 段)。 -- -- 這是本次唯一真的需要動表結構的一支 migration,理由(不是繞過鐵律,是鐵律要求的收尾): -- D38 要求 KBDB 回到「只有三張核心表」的狀態。0002_credentials.sql 當初在 KBDB 裡多開了 -- 一張獨立表,是已知違規(kbdb-usage skill 明文列為反例)。要把違規清乾淨,唯一辦法就是 -- 真的把那張表拆掉——拆表本身不能只用 API 做(API 不提供「拆表」這種牆內維運操作, -- 也不該提供),所以下面兩句 SQL 標 kbdb-sql-ok:這不是繞過圍牆去存取資料,是圍牆施工 -- 本身(kbdb/migrations/ 就是牆內,本檔存在的唯一目的就是讓舊表退場)。 -- -- 冪等設計(deploy.ts 每次部署都會重跑這支檔案,沒有 migration 追蹤表): -- 1. 先補一份空表存在保底——self-hosted 各實例套用進度不一,有些從沒跑過 0002(表從不 -- 存在)、有些已經跑過本檔一次(表已被拆)。沒有這一步,下面的搬資料/退場語句會因表 -- 不存在直接整支失敗(D1 對不存在的表沒有條件式跳過語法)。 -- 2. 把舊表裡「entries 還沒有對應列」的 row 搬進 entries(entry_type='credential', -- page_name=name 冪等鍵,owner_id=api_key,其餘欄位打包進 metadata_json,欄位對應 -- 0005_credential_template.sql 定義的 slots)。NOT EXISTS 判斷防止重跑造成重複列。 -- 3. 搬完資料後表就沒有存在的理由,最後一步讓它退場。下次部署若又被步驟 1 重新墊一份 -- 空殼,也只是空表、立刻搬 0 筆、立刻退場,不影響任何人(真資料只會被搬一次,因為 -- 步驟 2 的判斷是看 entries 裡有沒有,不是看這是不是第一次跑)。 CREATE TABLE IF NOT EXISTS credentials ( -- kbdb-sql-ok: 表退場施工步驟①保底存在,非資料存取違規,理由見檔頭 api_key TEXT NOT NULL, name TEXT NOT NULL, service TEXT, sensitivity TEXT NOT NULL DEFAULT 'standard', secret_ref TEXT NOT NULL, created_at INTEGER NOT NULL, last_used_at INTEGER, PRIMARY KEY (api_key, name) ); INSERT INTO entries (id, entry_type, owner_id, page_name, metadata_json, created_at, updated_at) SELECT 'e_cred_' || lower(hex(randomblob(8))), 'credential', c.api_key, c.name, json_object('service', c.service, 'sensitivity', c.sensitivity, 'secret_ref', c.secret_ref, 'last_used_at', c.last_used_at), c.created_at, unixepoch() FROM credentials c WHERE NOT EXISTS ( SELECT 1 FROM entries e WHERE e.entry_type = 'credential' AND e.owner_id = c.api_key AND e.page_name = c.name ); DROP TABLE IF EXISTS credentials; -- kbdb-sql-ok: 表退場施工步驟③讓舊表退場,非資料存取違規,理由見檔頭