Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libs/knowledge-graph/graph-context/graph-rank.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ function applyPostGraphThreshold(
): RankedContextDocument[] {
return ranked.filter((document) =>
document.signals.semantic_score >= config.ranking.semanticThreshold ||
document.signals.bm25_score >= config.ranking.semanticThreshold ||
document.signals.graph_score >= config.ranking.semanticThreshold ||
document.signals.coherence_score >= config.ranking.semanticThreshold,
);
Expand Down
37 changes: 37 additions & 0 deletions scripts/check-bm25-tokenizer.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import assert from "node:assert/strict";
const root = new URL("..", import.meta.url);
const { tokenize, scoreBm25 } = await import(new URL("dist/libs/knowledge-graph/graph-context/bm25.js", root));
const { graphContextConfig } = await import(new URL("dist/libs/knowledge-graph/graph-context/config.js", root));
const { applyGraphRanking } = await import(new URL("dist/libs/knowledge-graph/graph-context/graph-rank.js", root));
const { rankContextDocuments } = await import(new URL("dist/libs/knowledge-graph/graph-context/rank.js", root));

assert.ok(tokenize("handleUserAuth").includes("user"), "camelCase should emit sub-token user");
assert.ok(tokenize("handleUserAuth").includes("auth"), "camelCase should emit sub-token auth");
Expand All @@ -25,4 +27,39 @@ const documents = [{ key: "doc:auth", text: "The handleUserAuth function validat
const ranked = scoreBm25("user auth validation", documents, graphContextConfig);
assert.equal(ranked[0]?.id, "doc:auth", "BM25 should match camelCase doc tokens to spaced query terms");

const lexicalClaim = {
id: "claim.lexical_match",
kind: "fact",
text: "The processRareIdentifier function handles this workflow.",
truth: "unknown",
intent: "unknown",
};
const lexicalDocument = {
key: "claim:claim.lexical_match",
type: "claim",
id: lexicalClaim.id,
text: lexicalClaim.text,
object: lexicalClaim,
about: [],
};
const lexicalScores = scoreBm25("process rare identifier", [lexicalDocument], graphContextConfig);
const baseRanked = rankContextDocuments(
[lexicalDocument],
[{ id: lexicalDocument.key, score: 0, raw_score: 0, rank: 1 }],
lexicalScores,
graphContextConfig,
);
const graphRanked = applyGraphRanking(
{ claims: baseRanked, components: [], flows: [] },
{ claims: [lexicalClaim], components: [], flows: [], sources: [], edges: [] },
graphContextConfig,
);
assert.equal(baseRanked[0]?.signals.bm25_score, 1, "lexical match should have the strongest normalized BM25 score");
assert.equal(baseRanked[0]?.signals.semantic_score, 0, "regression fixture must not rely on semantic similarity");
assert.equal(
graphRanked.claims[0]?.document.id,
lexicalClaim.id,
"post-graph filtering should preserve a strong BM25-only match",
);

console.log("BM25 tokenizer checks passed.");