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>
44 lines
1.7 KiB
TypeScript
44 lines
1.7 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { makeGraphClient } from '../src/lib/graph-client';
|
|
import type { Envelope } from '../src/types';
|
|
|
|
const env: Envelope = {
|
|
source: { uri: 'github:o/r@a.md', content_hash: 'abc' },
|
|
extractor: { model: 'local-harvest', tier: 'shallow' },
|
|
triplets: [{ subject: 'A', predicate: 'p', object: 'B' }],
|
|
};
|
|
|
|
function mockFetch(status: number, body: unknown): typeof fetch {
|
|
return (async () =>
|
|
new Response(JSON.stringify(body), { status, headers: { 'Content-Type': 'application/json' } })) as any;
|
|
}
|
|
|
|
describe('makeGraphClient', () => {
|
|
it('GRAPH_BASE_URL 未設 → 誠實回 ok:false,不假綠、不打網路', async () => {
|
|
let called = false;
|
|
const client = makeGraphClient(undefined, undefined, (async () => {
|
|
called = true;
|
|
return new Response('{}');
|
|
}) as any);
|
|
const r = await client.postEnvelope(env);
|
|
expect(r.ok).toBe(false);
|
|
expect(r.error).toContain('未設');
|
|
expect(called).toBe(false);
|
|
});
|
|
|
|
it('200 → ok + 帶 graph 回的 {skipped,ingested,deprecated}', async () => {
|
|
const client = makeGraphClient('https://graph.example', 'tok', mockFetch(200, { skipped: false, ingested: 1, deprecated: 0 }));
|
|
const r = await client.postEnvelope(env);
|
|
expect(r.ok).toBe(true);
|
|
expect((r.body as any).ingested).toBe(1);
|
|
});
|
|
|
|
it('422 → ok:false 帶 issues(供修禁送欄位)', async () => {
|
|
const client = makeGraphClient('https://graph.example', undefined, mockFetch(422, { error: 'invalid envelope', issues: [{ path: ['bridge_score'] }] }));
|
|
const r = await client.postEnvelope(env);
|
|
expect(r.ok).toBe(false);
|
|
expect(r.status).toBe(422);
|
|
expect((r.body as any).issues).toBeDefined();
|
|
});
|
|
});
|