-- 0007 — record 有身分,關係是唯一機制(樹狀 record 模型第一刀) -- 規格:system-dev/docs/3-specs/pending-changes.md「record 要有身分」v7 定稿(leo 2026-08-15 confirm) -- -- 模型一句話(leo 定案):「真身在 pool 的 entry 裡,所有的虛擬表虛擬欄位都是指向這個 entry 的指標。」 -- · record = 池中一顆有身分的 entry(沿用原 record_id 字串當 id,既有引用不失效) -- · 欄位是關係、歸屬也是關係——同一種機制:一列關係 = src/rel/dst 三個型別化指標欄 -- (「池上型別化指標欄」,parent_id 是這族欄位的既有先例。紅線:不准用關係實作關係、 -- 不准把指標塞回 content/JSON——那是 D91 的位置換個門進來) -- · 舊 entry_values 四欄的下場:record_id → record entry 自己的 id/entry_id → 指標終點(dst) -- /slot_name → 指標謂詞(rel = field entry)/template_id → 一條屬於關係(rel = sys_belongs) -- · 那張表該死的理由:它是「關係」的第二套實作——同一件事兩個實作必然漂移(D92) -- -- 資料遷移形狀(v7 §3):既有 value entries 一列都不動(id 穩定、向量索引不失效)、 -- 全部純 INSERT、零 UPDATE。以舊儲存格列 id 衍生關係列 id ⇒ INSERT OR IGNORE 天然冪等。 -- -- 冪等設計(三條套用路徑:官方 wrangler migrations/cli deploy.ts 每次重跑/安裝器逐句重放): -- · 除了三句 ADD COLUMN 之外,每一句都是語句級冪等(IF NOT EXISTS/INSERT OR IGNORE) -- · SQLite 沒有「ADD COLUMN IF NOT EXISTS」——重跑時那三句會報 duplicate column, -- 套用端必須把「duplicate column」視為已套用(cli deploy.ts 的 applyD1MigrationTolerant、 -- 安裝器逐句 try/catch 本就容錯)。官方路徑走 wrangler migrations 追蹤表,只跑一次。 -- · 不走「重建整張 entries」的做法:那雖然能純語句冪等,但 deploy.ts 每次部署都重跑 -- migration ⇒ 每次部署全表複製一輪,直接吃掉 D1 每日列寫入額度。 -- · entry_values 拆表用 0006 的「墊表、搬、拆」手法:重跑時先墊一份空殼,搬 0 筆,再拆,無害。 -- -- 施工窗口注意:本檔跑完 entry_values 就不存在了,必須與讀寫端改版(kbdb/src 同一批)一起部署。 -- 舊 worker 碰新庫會炸 entry_values 不存在——這是刻意的(leo:「不做長期雙讀相容層,一次翻」)。 -- ============================================================ -- 1. 關係的物理載體:池上型別化指標欄 + 一對方向索引 -- ============================================================ ALTER TABLE entries ADD COLUMN src_id TEXT; -- kbdb-sql-ok: 牆內 migration 本體(v7 定案載體「池上型別化指標欄」),重跑由套用端容錯 duplicate column ALTER TABLE entries ADD COLUMN rel_id TEXT; -- kbdb-sql-ok: 同上 ALTER TABLE entries ADD COLUMN dst_id TEXT; -- kbdb-sql-ok: 同上 -- 一對方向索引(v7 §2-1):src 端服務「r1 的所有欄位」,(dst,rel) 端服務 -- 「某張 sheet 的所有 record」(rel=屬於, dst=sheet)與「誰指到 e1」(dst=e1)。 -- partial index:內容 entry(指標欄全 NULL)不進索引,索引大小 ≈ 關係列數。 CREATE INDEX IF NOT EXISTS idx_entries_rel_src ON entries(src_id) WHERE src_id IS NOT NULL; -- kbdb-sql-ok: 牆內 migration 本體,普通欄位索引(0001 十條索引的同族) CREATE INDEX IF NOT EXISTS idx_entries_rel_dst ON entries(dst_id, rel_id) WHERE dst_id IS NOT NULL; -- kbdb-sql-ok: 同上 -- ============================================================ -- 2. 啟動常數(v7 §2-3:一組、極小、只讀) -- ============================================================ -- 保留根:屬於鏈的終點。某顆 entry ─屬於→ sys_root = 它是一張 sheet。 INSERT OR IGNORE INTO entries (id, content, entry_type, owner_id) VALUES ('sys_root', 'root', 'system', NULL); -- 「屬於」謂詞:record ─屬於→ sheet(歸屬關係的 rel)。 INSERT OR IGNORE INTO entries (id, content, entry_type, owner_id) VALUES ('sys_belongs', 'belongs', 'system', NULL); -- 「欄位屬於表」謂詞:field ─field_of→ sheet(sheet 的欄位名冊,與 record 歸屬分開, -- 免得「某張 sheet 的所有 record」把欄位也撈進來)。 INSERT OR IGNORE INTO entries (id, content, entry_type, owner_id) VALUES ('sys_field_of', 'field_of', 'system', NULL); -- ============================================================ -- 3. 墊表(0006 手法):本檔尾端會拆掉 entry_values,重跑時先墊空殼 -- 讓下面的搬遷語句永遠合法(搬 0 筆),最後再拆一次。 -- ============================================================ CREATE TABLE IF NOT EXISTS entry_values ( -- kbdb-sql-ok: 表退場施工步驟①保底存在(0006 同款),非資料存取違規 id TEXT PRIMARY KEY, record_id TEXT NOT NULL, template_id TEXT NOT NULL, slot_name TEXT NOT NULL, entry_id TEXT NOT NULL, created_at INTEGER DEFAULT (unixepoch()), UNIQUE(record_id, slot_name) ); -- ============================================================ -- 4. sheet/field 落池(templates 表遷移期雙軌:欄位定義的真相源暫仍在 templates 表, -- sheet/field entry 是它在池中的身分——第二刀把 templates 表整個退役) -- ============================================================ -- 每個 template 一顆 sheet entry(id 沿用 template id,既有引用不失效) INSERT OR IGNORE INTO entries (id, content, entry_type, owner_id, created_at, updated_at) SELECT t.id, t.name, 'sheet', NULL, t.created_at, t.updated_at FROM templates t; -- sheet ─屬於→ 保留根(「什麼讓一顆 entry 成為 sheet」的答案:這條關係) INSERT OR IGNORE INTO entries (id, entry_type, src_id, rel_id, dst_id) SELECT 'relb_' || t.id, 'relation', t.id, 'sys_belongs', 'sys_root' FROM templates t; -- 每個 slot 一顆 field entry(id 決定性衍生:fld_