test harness
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
// Reciprocal Rank Fusion — tests the REAL fuseEpisodeResults from the orchestration
|
||||
// chat pipeline (previously test-fusion.js reimplemented the math, which could drift).
|
||||
const { test } = require('node:test');
|
||||
const assert = require('node:assert');
|
||||
const { fuseEpisodeResults } = require('../packages/orchestration-service/src/chat/index');
|
||||
|
||||
// fuseEpisodeResults returns {episode, score}[]; map to episodes for readability
|
||||
const fuse = (sem, kw, opts) => fuseEpisodeResults(sem, kw, opts).map(r => r.episode);
|
||||
|
||||
const semantic = [
|
||||
{ id: 1, user_message: 'ep1 — semantic only, rank 1' },
|
||||
{ id: 2, user_message: 'ep2 — in both lists, rank 2 semantic' },
|
||||
{ id: 3, user_message: 'ep3 — in both lists, rank 3 semantic' },
|
||||
];
|
||||
const keyword = [
|
||||
{ id: 3, user_message: 'ep3 — rank 1 FTS' },
|
||||
{ id: 2, user_message: 'ep2 — rank 2 FTS' },
|
||||
{ id: 4, user_message: 'ep4 — FTS only, rank 3' },
|
||||
];
|
||||
|
||||
test('episodes appearing in both lists rank highest', () => {
|
||||
const r = fuse(semantic, keyword, { semanticWeight: 1, keywordWeight: 1, limit: 5 });
|
||||
assert.ok([2, 3].includes(r[0].id), 'a dual-list episode should be rank 1');
|
||||
const idx = id => r.findIndex(e => e.id === id);
|
||||
assert.ok(idx(1) > idx(2), 'ep1 (semantic-only) should rank below ep2 (both lists)');
|
||||
});
|
||||
|
||||
test('keywordWeight:0 → pure semantic passthrough in original order', () => {
|
||||
const r = fuse(semantic, keyword, { semanticWeight: 1, keywordWeight: 0, limit: 5 });
|
||||
assert.strictEqual(r.length, 3, 'only the 3 semantic episodes survive');
|
||||
assert.strictEqual(r[0].id, 1);
|
||||
assert.strictEqual(r[1].id, 2);
|
||||
});
|
||||
|
||||
test('limit is respected', () => {
|
||||
const r = fuse(semantic, keyword, { semanticWeight: 1, keywordWeight: 1, limit: 2 });
|
||||
assert.strictEqual(r.length, 2);
|
||||
});
|
||||
|
||||
test('no overlap → both episodes appear, semantic tie-breaks first', () => {
|
||||
const r = fuse(
|
||||
[{ id: 10, user_message: 'sem' }],
|
||||
[{ id: 20, user_message: 'fts' }],
|
||||
{ semanticWeight: 1, keywordWeight: 1, limit: 5 },
|
||||
);
|
||||
assert.strictEqual(r.length, 2);
|
||||
assert.strictEqual(r[0].id, 10, 'equal rank+weight: semantic inserted first, so it tie-breaks ahead');
|
||||
});
|
||||
|
||||
test('raising keywordWeight lifts a keyword-only hit above a weak semantic tail', () => {
|
||||
// ep4 is keyword-only at FTS rank 3; with a high keyword weight it should
|
||||
// outrank ep1 (semantic rank 1) once keywordWeight dominates.
|
||||
const lowKw = fuse(semantic, keyword, { semanticWeight: 1, keywordWeight: 0.1, limit: 5 });
|
||||
const highKw = fuse(semantic, keyword, { semanticWeight: 1, keywordWeight: 5, limit: 5 });
|
||||
const rank = (list, id) => list.findIndex(e => e.id === id);
|
||||
assert.ok(rank(highKw, 4) < rank(lowKw, 4), 'ep4 should climb as keywordWeight increases');
|
||||
});
|
||||
Reference in New Issue
Block a user