Files
kbdb-ingest-plugin/tests/harvest.test.ts
T
Leo 16ad1cb208 feat(ingest): T0.5–T5 純餵食器管線實作(issue #2)
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>
2026-06-26 20:40:53 +08:00

69 lines
2.4 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.
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([]);
});
});