16ad1cb208
ingest 全管線(採取優先、extract fallback、跨庫織網、POST envelope): - T0.5 骨架:Hono + zod-openapi,無 D1/Vectorize/AI 綁定(不碰儲存鐵律) - T1 SourceAdapter:GitHub runtime API 拉 + per-file sha256 content-hash + /refresh 受理端 - T2 採取(路徑 A 優先):harvest template 1.8.0+ 卡(gloss/實體/typed-edge) - T3 extract(路徑 B fallback):LlmCaller 可選模型 + JSON-fail 升級閘 + 端點對齊硬自檢護欄;第一版不 embed(只打標) - T4 跨庫織網(主職):匯總多 repo → 偵測跨庫橋/異見,不算 bridge_score(graph 領域) - T5 輸出:buildEnvelope strict + 顯式禁送欄位自檢;graph-client 純 POST(cherry-pick _kbdb_client.py 改不碰 base);薄 ops CLI(不帶查詢 MCP) envelope 對齊 full contract(embed/id/aliases/predicate_embed);同步 contract 向量化欄位升格。 gate:vitest 28 passed / tsc clean / wrangler dry-run 乾淨(只 env-var 綁定)。 端到端 ingest→graph:graph receiver 已補對齊 → 待 ingest 部署 + GRAPH_BASE_URL → 待部署驗,未假綠。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
69 lines
2.4 KiB
TypeScript
69 lines
2.4 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
||
import { harvestCard, parseEntities, parseEdges, parseFrontmatter } from '../src/lib/harvest';
|
||
|
||
const CARD = `---
|
||
tags: [掛載架構, 架構設計]
|
||
gloss: ingest 在 KBDB 堆疊裡的位置。
|
||
---
|
||
# 掛載架構
|
||
|
||
← [[ingest/00-INDEX]]
|
||
|
||
## 摘要
|
||
KBDB 是三層堆疊。
|
||
|
||
## 實體
|
||
- **kbdb-ingest-plugin**(餵食器) — 最薄一層,純 POST 候選。
|
||
- **base KBDB**(arcrun/kbdb/基本盤) — 最底儲存層。
|
||
|
||
## 關聯
|
||
### 內文知識關係
|
||
- kbdb-ingest-plugin >> 掛載於 >> base KBDB
|
||
### 卡片關係
|
||
- [[掛載架構]] >> 受約束於 >> [[envelope-契約]]
|
||
`;
|
||
|
||
describe('parseFrontmatter', () => {
|
||
it('抽出 gloss', () => {
|
||
const { fm, body } = parseFrontmatter(CARD);
|
||
expect(fm.gloss).toBe('ingest 在 KBDB 堆疊裡的位置。');
|
||
expect(body).toContain('# 掛載架構');
|
||
});
|
||
});
|
||
|
||
describe('parseEntities', () => {
|
||
it('解析正規名 + aliases + gloss', () => {
|
||
const { body } = parseFrontmatter(CARD);
|
||
const nodes = parseEntities(body);
|
||
expect(nodes.map((n) => n.name)).toEqual(['kbdb-ingest-plugin', 'base KBDB']);
|
||
expect(nodes[1].aliases).toEqual(['arcrun/kbdb', '基本盤']);
|
||
expect(nodes[0].gloss).toBe('最薄一層,純 POST 候選。');
|
||
expect(nodes[0].embed).toBe(true);
|
||
});
|
||
});
|
||
|
||
describe('parseEdges', () => {
|
||
it('解析 typed-edge、去 [[ ]]、標記卡對卡', () => {
|
||
const { body } = parseFrontmatter(CARD);
|
||
const edges = parseEdges(body);
|
||
expect(edges).toContainEqual({ subject: 'kbdb-ingest-plugin', predicate: '掛載於', object: 'base KBDB', predicate_embed: true, subjectIsCard: false, objectIsCard: false });
|
||
expect(edges).toContainEqual({ subject: '掛載架構', predicate: '受約束於', object: 'envelope-契約', predicate_embed: true, subjectIsCard: true, objectIsCard: true });
|
||
});
|
||
});
|
||
|
||
describe('harvestCard', () => {
|
||
it('卡標題 node 帶 frontmatter gloss、含內文 node', () => {
|
||
const r = harvestCard(CARD);
|
||
const titleNode = r.nodes.find((n) => n.name === '掛載架構');
|
||
expect(titleNode?.gloss).toBe('ingest 在 KBDB 堆疊裡的位置。');
|
||
expect(r.nodes.some((n) => n.name === 'base KBDB')).toBe(true);
|
||
expect(r.triplets.length).toBe(2);
|
||
});
|
||
|
||
it('內文端點對齊(無對不齊)', () => {
|
||
const r = harvestCard(CARD);
|
||
// kbdb-ingest-plugin / base KBDB 都在 ## 實體;卡對卡端點不要求
|
||
expect(r.unalignedEndpoints).toEqual([]);
|
||
});
|
||
});
|