feat(kbdb): 藏書地圖 M1+M2 — library_map template+/map 三端點(聚合 SQL 住基本盤) #72

Merged
Leo merged 1 commits from feat/library-map-base into main 2026-07-19 08:42:43 +00:00
Owner

實作 library-map SDD(system-dev/docs/3-specs/library-map/,leo 已 confirm 可動工)的 M1+M2。關聯 #39。

M1 — library_map template(D6 零建表零 ALTER)

  • kbdb/migrations/0003_library_map.sql:templates 表 seed 一列(tpl-library-map,與 0001 recipe_stat 同模式,INSERT OR IGNORE 冪等);slots=design §1 的 library/narrative/top_entities/relation_profile/bridges/triplet_count/commit_hash/status
  • runtime 第二道保險:ensureLibraryMapTemplate(走既有 createTemplate 路徑),migration 未跑的自架 D1 首次 recompute 自建。
  • triplet 按庫定位核實(design §1「先核實」):對 prod 實查——triplet template(實名 triplet)有 source_urilibrary slot;entries 的 metadata.library 機制在(portal-auth P1)但既有資料未標記(?library=kb → 0 筆)。結論=不足,走 SDD 預案:recompute 時冪等在 triplet template 補 optional library slot(ensureTripletLibrarySlot,改 template 不動表);slot 值由 ingest 端補寫(M3)。核實結果已記入 design.md §1。

M2 — kbdb base 三端點(design §2 關鍵歸屬裁定:聚合 SQL 只准住基本盤)

  • POST /map/recompute?library=X:一段聚合 SQL——top_entities(subject+object 兩側 degree 排序 top-N)、relation_profile(predicate 分布)、bridges(同 entity 跨庫 join)、triplet_count(active-only,沿用 status slot 語意)。narrative 本輪收 request body 傳入值(wiki 首段抽取屬 ingest M3,不在本 PR)。寫入順序安全(D1 無跨語句交易):先建新 active map block+record,成功後才把舊 active 標 superseded;讀端一律取最新 active 自癒,不會出現地圖真空。
    • 過渡參數 source_prefix:M3 backfill 前,無 library 值的舊 triplet 以 source_uri LIKE 前綴 歸庫(前綴由 caller 提供,base 不寫死 URI 語意)。bridges 的「對面庫」只認 library slot 標記值 → backfill 前偏稀疏(誠實限制,記於 design §1)。
  • GET /map:全館地圖,每庫一行(library+narrative+top 3 entities+triplet_count),給 MCP instructions(數百 token 內)/GUI 共用。
  • GET /map/:library:該庫詳圖(完整 slots+record_id+content)。
  • map block 的 content=可嵌人話 {library}:{narrative}。核心:{top_entities 前 3}(design §5,M6 semantic 路由直接嵌);record_id=該 block entry id,block(人話)與 record(結構化)同一身分。
  • auth 照 base route 既有慣例:raw worker 不驗 key,owner 隔離走 cypher proxy 注入/owner_id 參數(聚合與讀端都支援 owner filter)。

測試

  • kbdb/tests/library-map.test.ts:聚合 SQL 用 node:sqlite 當真 SQLite 實跑(Node ≥22.5 內建、零新依賴;migrations 0001+0003 原檔 exec)——degree 排序/predicate 統計/跨庫 bridges/source_prefix fallback/owner 隔離/supersede 順序安全全部真 SQL 驗證;route 行為(400/404/回應形狀)走 Hono app.request(與既有測試同款)。
  • 實測結果:npx vitest run 45/45 過(含既有 4 檔不動);npx tsc --noEmit 乾淨。tests/node-builtins.d.ts 補 node 內建模組最小型別(tsconfig 只掛 workers-types)。
  • 未覆蓋:D1 remote 實機(本 PR 未部署);聚合 SQL 語意已由真 SQLite 等價驗證。

merge 後(leo 閘)

  1. gated redeploy kbdb(含 apply migration 0003)。
  2. 首次 backfill:逐庫呼 POST /map/recompute?library=X(舊 triplet 未帶 library slot 值 → 過渡期帶 source_prefix,如 kb 庫={"source_prefix":"gitea:Leo/kb@"})。
  3. M3(ingest 尾端接鏈+narrative 抽取+triplet library 值補寫)、M4(MCP)、M5(GUI)依 tasks 續行。

🤖 Generated with Claude Code

https://claude.ai/code/session_01JUmjwkHLVBHM3ydhT1WSW3

實作 library-map SDD(`system-dev/docs/3-specs/library-map/`,leo 已 confirm 可動工)的 **M1+M2**。關聯 #39。 ## M1 — `library_map` template(D6 零建表零 ALTER) - `kbdb/migrations/0003_library_map.sql`:templates 表 seed 一列(`tpl-library-map`,與 0001 recipe_stat 同模式,INSERT OR IGNORE 冪等);slots=design §1 的 `library/narrative/top_entities/relation_profile/bridges/triplet_count/commit_hash/status`。 - runtime 第二道保險:`ensureLibraryMapTemplate`(走既有 createTemplate 路徑),migration 未跑的自架 D1 首次 recompute 自建。 - **triplet 按庫定位核實(design §1「先核實」)**:對 prod 實查——triplet template(實名 `triplet`)有 `source_uri`、**無 `library` slot**;entries 的 `metadata.library` 機制在(portal-auth P1)但既有資料未標記(`?library=kb` → 0 筆)。**結論=不足,走 SDD 預案**:recompute 時冪等在 triplet template 補 optional `library` slot(`ensureTripletLibrarySlot`,改 template 不動表);slot 值由 ingest 端補寫(M3)。核實結果已記入 design.md §1。 ## M2 — kbdb base 三端點(design §2 關鍵歸屬裁定:聚合 SQL 只准住基本盤) - `POST /map/recompute?library=X`:一段聚合 SQL——top_entities(subject+object 兩側 degree 排序 top-N)、relation_profile(predicate 分布)、bridges(同 entity 跨庫 join)、triplet_count(active-only,沿用 status slot 語意)。narrative 本輪收 request body 傳入值(wiki 首段抽取屬 ingest M3,不在本 PR)。寫入**順序安全**(D1 無跨語句交易):先建新 active map block+record,成功後才把舊 active 標 `superseded`;讀端一律取最新 active 自癒,不會出現地圖真空。 - 過渡參數 `source_prefix`:M3 backfill 前,無 library 值的舊 triplet 以 `source_uri LIKE 前綴` 歸庫(前綴由 caller 提供,base 不寫死 URI 語意)。bridges 的「對面庫」只認 library slot 標記值 → backfill 前偏稀疏(誠實限制,記於 design §1)。 - `GET /map`:全館地圖,每庫一行(library+narrative+top 3 entities+triplet_count),給 MCP instructions(數百 token 內)/GUI 共用。 - `GET /map/:library`:該庫詳圖(完整 slots+record_id+content)。 - map block 的 `content`=可嵌人話 `{library}:{narrative}。核心:{top_entities 前 3}`(design §5,M6 semantic 路由直接嵌);record_id=該 block entry id,block(人話)與 record(結構化)同一身分。 - auth 照 base route 既有慣例:raw worker 不驗 key,owner 隔離走 cypher proxy 注入/`owner_id` 參數(聚合與讀端都支援 owner filter)。 ## 測試 - `kbdb/tests/library-map.test.ts`:聚合 SQL 用 **node:sqlite 當真 SQLite 實跑**(Node ≥22.5 內建、零新依賴;migrations 0001+0003 原檔 exec)——degree 排序/predicate 統計/跨庫 bridges/source_prefix fallback/owner 隔離/supersede 順序安全全部真 SQL 驗證;route 行為(400/404/回應形狀)走 Hono app.request(與既有測試同款)。 - 實測結果:`npx vitest run` **45/45 過**(含既有 4 檔不動);`npx tsc --noEmit` 乾淨。tests/node-builtins.d.ts 補 node 內建模組最小型別(tsconfig 只掛 workers-types)。 - 未覆蓋:D1 remote 實機(本 PR 未部署);聚合 SQL 語意已由真 SQLite 等價驗證。 ## merge 後(leo 閘) 1. **gated redeploy kbdb**(含 apply migration 0003)。 2. **首次 backfill**:逐庫呼 `POST /map/recompute?library=X`(舊 triplet 未帶 library slot 值 → 過渡期帶 `source_prefix`,如 kb 庫=`{"source_prefix":"gitea:Leo/kb@"}`)。 3. M3(ingest 尾端接鏈+narrative 抽取+triplet library 值補寫)、M4(MCP)、M5(GUI)依 tasks 續行。 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01JUmjwkHLVBHM3ydhT1WSW3
Leo added 1 commit 2026-07-19 08:41:08 +00:00
M1:library_map template(migration 0003 seed+runtime ensure,D6 零建表零 ALTER);
核實 triplet 按庫定位=不足(prod triplet template 無 library slot、entries
metadata.library 未標記)→ 走 SDD 預案:recompute 冪等補 optional library slot
(改 template 不動表),slot 值由 ingest 端(M3)補寫,核實結果記入 design §1。

M2:kbdb base 三端點(design §2 歸屬裁定:聚合 SQL 只准住基本盤):
- POST /map/recompute?library=X:degree top-N/predicate 分布/跨庫 bridges/
  triplet_count 一段 SQL 聚合;narrative 本輪收 body 傳入(wiki 抽取屬 M3);
  寫入順序安全(先建新 active map block 再標舊 superseded,讀端取最新 active 自癒);
  過渡 source_prefix fallback 讓無 library 值的舊 triplet 靠 source_uri 前綴歸庫。
- GET /map:全館地圖每庫一行(library+narrative+top 3 entities+triplet_count),
  MCP instructions/GUI 共用(數百 token 內)。
- GET /map/:library:該庫詳圖(完整 slots+可嵌人話 content,design §5 M6 直用)。

測試:node:sqlite(零新依賴)當真 SQLite 實跑 migrations+聚合 SQL,
Hono route 行為同款覆蓋;45/45 過、tsc --noEmit 乾淨。

關聯 #39

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUmjwkHLVBHM3ydhT1WSW3
Leo merged commit bdfc2e3e0b into main 2026-07-19 08:42:43 +00:00
Sign in to join this conversation.