Files
Arcrun/kbdb/src/routes/map.ts
T
Claude 15fe012006 feat(kbdb): 藏書地圖 M1+M2 — library_map template+/map 端點(聚合 SQL 住基本盤)(#39)
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
2026-07-19 08:40:22 +00:00

49 lines
3.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Map route — 藏書地圖(library-map SDD M2;源頭 Arcrun#39)。
// 聚合 SQL 只准住基本盤(D6 推論,design §2 關鍵歸屬裁定)——本 route 是薄殼,SQL 全在
// actions/library-map.ts。auth 照 base route 既有慣例:raw worker 不驗 keyowner 隔離由
// cypher proxyX-Arcrun-API-Key → owner_id 注入)/caller 帶 owner_id 參數完成。
import { Hono } from 'hono';
import type { Bindings } from '../types';
import { getLibraryMapDetail, listLibraryMaps, recomputeLibraryMap } from '../actions/library-map';
export const mapRoutes = new Hono<{ Bindings: Bindings }>();
// POST /map/recompute?library=X — 對該庫重算地圖(ingest 尾端/backfill 呼叫;R2 增量重算)。
// body(皆選填):{ narrative, commit_hash, owner_id, source_prefix, triplet_template, top_n }
// - narrative:本輪由 caller 傳入(wiki 首段抽取屬 ingest 端 M3base 不抽取)。
// - source_prefix:舊 triplet(無 library slot 值)的 source_uri 前綴 fallbackM3 backfill 前過渡)。
// 寫入順序安全:先建新 active map block,再把舊 block 標 superseded(見 action 註解)。
mapRoutes.post('/recompute', async (c) => {
const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;
const library = c.req.query('library') || (typeof body.library === 'string' ? body.library : '');
if (!library || !library.trim()) return c.json({ success: false, error: 'library required' }, 400);
try {
const result = await recomputeLibraryMap(c.env.DB, {
library,
narrative: typeof body.narrative === 'string' ? body.narrative : undefined,
commit_hash: typeof body.commit_hash === 'string' ? body.commit_hash : undefined,
owner_id: typeof body.owner_id === 'string' ? body.owner_id : c.req.query('owner_id') || undefined,
source_prefix: typeof body.source_prefix === 'string' ? body.source_prefix : undefined,
triplet_template: typeof body.triplet_template === 'string' ? body.triplet_template : undefined,
top_n: typeof body.top_n === 'number' ? body.top_n : undefined,
});
return c.json({ success: true, ...result });
} catch (e) {
return c.json({ success: false, error: e instanceof Error ? e.message : String(e) }, 400);
}
});
// GET /map — 全館地圖:每庫一行(librarynarrativetop 3 entitiestriplet_count)。
// 形狀給 MCP instructionsGUI 首頁共用(R3/R4),設計在數百 token 內。
mapRoutes.get('/', async (c) => {
const libraries = await listLibraryMaps(c.env.DB, c.req.query('owner_id') || undefined);
return c.json({ success: true, libraries, count: libraries.length });
});
// GET /map/:library — 該庫詳圖(完整 slots+可嵌人話 content)。
mapRoutes.get('/:library', async (c) => {
const map = await getLibraryMapDetail(c.env.DB, c.req.param('library'), c.req.query('owner_id') || undefined);
if (!map) return c.json({ success: false, error: 'not found' }, 404);
return c.json({ success: true, map });
});