From 091ee17f8b1a397053bece949bdd4d8d1d616df5 Mon Sep 17 00:00:00 2001 From: youzini Date: Tue, 9 Jun 2026 11:38:27 +0000 Subject: [PATCH] test(vector): lock authority protocol contracts --- docs/algorithms/vector-and-embedding.md | 4 ++++ docs/architecture/server-integration.md | 6 ++++++ tests/authority-vector-primary.mjs | 10 ++++++++++ tests/e2e/authority-server-primary.mjs | 9 +++++++++ 4 files changed, 29 insertions(+) diff --git a/docs/algorithms/vector-and-embedding.md b/docs/algorithms/vector-and-embedding.md index e777e8f..92bf065 100644 --- a/docs/algorithms/vector-and-embedding.md +++ b/docs/algorithms/vector-and-embedding.md @@ -51,6 +51,10 @@ HTTP 错误(400/401/403/429/502 等)会带状态码和响应体抛出,而 > BME 在 payload 里发送 `vectorSpaceId` 和 `observedDim`(顶层 + 每项元数据)。DOA 按批校验 vectorSpaceId/observedDim 一致性,拒绝混合维度,返回带类型的校验错误。失败/404/旧 DOA 时回退到旧 Authority Trivium 路径或本地。 +协议身份字段有严格分工:BME 节点 id 只作为 `externalId` / `nodeId` / `payload.nodeId` 发送;`id` 保留给 Trivium 内部 numeric id,BME 不会把字符串 node id 塞进顶层 `id`。边关系使用 Trivium public reference 形状:`src/dst = { externalId, namespace }`,由 Authority 解析到内部 id。 + +搜索请求也必须携带 `namespace` / `collectionId` / `chatId`。如果 Authority 返回带 namespace 的命中,BME 会保守过滤掉不属于当前 namespace 的结果;老后端不返回 namespace 时结果仍保留,以避免过度破坏兼容性。 + ## 连接测试 `testVectorConnection()` 测的是**真实批量 embedding 路径**(走 `embedBatch`),而不是单条短文本——因为"测试通过但实际 embedding 失败"的根因就是测试只测了单条短文本而运行时用的是批量长文本。 diff --git a/docs/architecture/server-integration.md b/docs/architecture/server-integration.md index c065354..97fe411 100644 --- a/docs/architecture/server-integration.md +++ b/docs/architecture/server-integration.md @@ -65,6 +65,12 @@ Authority 的后台 job 系统只支持特定 job 类型。ST-BME 不能盲目 > 该端点按批校验 `vectorSpaceId` / `observedDim` 一致性,拒绝混合维度,返回带类型的校验错误。 +BME → Authority 的向量协议约定: + +- 节点身份使用 `externalId` / `nodeId`;顶层 `id` 是 Trivium 内部 numeric id,BME 不发送字符串 node id 到该字段。 +- link 使用 `{ src: { externalId, namespace }, dst: { externalId, namespace }, label, weight }`,由 Authority 在服务端解析成 Trivium 内部 id。 +- search 请求携带 `namespace` / `collectionId` / `chatId`;返回结果若带 namespace,BME 会过滤掉非当前 namespace 的命中,避免多聊天/多集合污染。 + 向量空间身份和维度门禁的算法见 [`../algorithms/vector-and-embedding.md`](../algorithms/vector-and-embedding.md)。 ## Authority SQL 图谱存储选择 diff --git a/tests/authority-vector-primary.mjs b/tests/authority-vector-primary.mjs index 68dc8d8..f430767 100644 --- a/tests/authority-vector-primary.mjs +++ b/tests/authority-vector-primary.mjs @@ -267,6 +267,16 @@ assert.equal(isAuthorityVectorConfig(config), true); const applyCall = triviumClient.calls.find(([name]) => name === "bmeVectorApply")?.[1]; assert.equal(applyCall.items.length, 2); assert.equal(applyCall.links.length, 1); + assert.deepEqual(applyCall.links[0].src, { + externalId: "node-a", + namespace: "st-bme::chat-authority-vector", + }); + assert.deepEqual(applyCall.links[0].dst, { + externalId: "node-b", + namespace: "st-bme::chat-authority-vector", + }); + assert.equal(applyCall.links[0].label, "related"); + assert.equal(applyCall.links[0].weight, 0.75); assert.equal(applyCall.observedDim, 2); assert.equal(String(applyCall.vectorSpaceId || "").startsWith("vs_"), true); assert.equal(applyCall.items.every((item) => item.payload?.vectorSpaceId === applyCall.vectorSpaceId), true); diff --git a/tests/e2e/authority-server-primary.mjs b/tests/e2e/authority-server-primary.mjs index 0669ee5..1c879b8 100644 --- a/tests/e2e/authority-server-primary.mjs +++ b/tests/e2e/authority-server-primary.mjs @@ -158,6 +158,7 @@ await runAuthorityE2eStep("trivium", async () => { headerProvider, }); assert.equal(linkResult.linked, graph.edges.length); + assert.ok(linkResult.linked >= 1, "Authority Trivium link sync should create at least one edge"); const searchResults = await searchAuthorityTriviumNodes(graph, "Authority E2E Alpha", config, { namespace, @@ -169,6 +170,10 @@ await runAuthorityE2eStep("trivium", async () => { headerProvider, }); assert.ok(Array.isArray(searchResults)); + assert.ok( + searchResults.every((result) => typeof result?.nodeId === "string" && result.nodeId.trim()), + "Authority Trivium search results should expose external node ids", + ); const filteredIds = await filterAuthorityTriviumNodes(config, { namespace, @@ -191,6 +196,10 @@ await runAuthorityE2eStep("trivium", async () => { headerProvider, }); assert.ok(Array.isArray(neighborIds)); + assert.ok( + neighborIds.includes(graph.nodes[1].id), + "Authority Trivium neighbors should resolve links through external ids", + ); return { upserted: upsertResult.upserted,