Skip to content

Commit 4131848

Browse files
author
StackMemory Bot (CLI)
committed
test(provenant): add database and confidence scoring test suites
- 18 database tests: nodes, edges, sources, rejection log, searchNodesByKeywords (including LIKE escape edge cases), getStatus - 10 confidence tests: default signals, custom signals/thresholds, negative weights, score clamping, signal details
1 parent 957b76b commit 4131848

2 files changed

Lines changed: 405 additions & 0 deletions

File tree

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import { describe, it, expect } from 'vitest';
2+
import { scoreRecord } from '../scoring/confidence.js';
3+
import type { RawRecord, SignalWeight } from '../adapters/adapter.js';
4+
5+
function makeRecord(content: string, actor?: string): RawRecord {
6+
return {
7+
external_id: 'test-1',
8+
content,
9+
raw_payload: JSON.stringify({ content }),
10+
actor,
11+
};
12+
}
13+
14+
describe('scoreRecord — default signals', () => {
15+
it('auto-accepts strong decision language with actor', () => {
16+
const result = scoreRecord(
17+
makeRecord(
18+
'We decided to use SQLite. Going with the simpler option.',
19+
'Alice'
20+
)
21+
);
22+
expect(result.action).toBe('auto_accept');
23+
expect(result.score).toBeGreaterThanOrEqual(0.7);
24+
});
25+
26+
it('discards content with no decision signals', () => {
27+
const result = scoreRecord(makeRecord('lol ok'));
28+
expect(result.action).toBe('discard');
29+
expect(result.score).toBeLessThan(0.4);
30+
});
31+
32+
it('queues content with moderate signals', () => {
33+
// trigger_phrase 'shipping' (0.3) + explicit_actor (0.1) = 0.4 → review
34+
const result = scoreRecord(
35+
makeRecord('Shipping the feature next week', 'Bob')
36+
);
37+
expect(result.action).toBe('review');
38+
});
39+
40+
it('applies negative weights for questions', () => {
41+
const withQuestion = scoreRecord(
42+
makeRecord('Should we use SQLite? We decided yes.')
43+
);
44+
const withoutQuestion = scoreRecord(
45+
makeRecord('We decided to use SQLite.')
46+
);
47+
expect(withQuestion.score).toBeLessThan(withoutQuestion.score);
48+
});
49+
50+
it('applies negative weights for hedge language', () => {
51+
const hedged = scoreRecord(
52+
makeRecord('We decided maybe we should use SQLite')
53+
);
54+
const confident = scoreRecord(makeRecord('We decided to use SQLite'));
55+
expect(hedged.score).toBeLessThan(confident.score);
56+
});
57+
58+
it('clamps score to [0, 1]', () => {
59+
// All negative signals, no positive
60+
const result = scoreRecord(
61+
makeRecord('Should we maybe possibly consider this?')
62+
);
63+
expect(result.score).toBeGreaterThanOrEqual(0);
64+
expect(result.score).toBeLessThanOrEqual(1);
65+
});
66+
67+
it('returns signal details', () => {
68+
const result = scoreRecord(makeRecord('We decided to ship it'));
69+
expect(result.signals).toBeInstanceOf(Array);
70+
expect(result.signals.length).toBeGreaterThan(0);
71+
for (const s of result.signals) {
72+
expect(s).toHaveProperty('name');
73+
expect(s).toHaveProperty('weight');
74+
expect(s).toHaveProperty('matched');
75+
}
76+
});
77+
});
78+
79+
describe('scoreRecord — custom signals', () => {
80+
it('uses adapter-provided signals', () => {
81+
const signals: SignalWeight[] = [
82+
{ name: 'always', weight: 0.8, detect: () => true },
83+
];
84+
const result = scoreRecord(makeRecord('anything'), signals);
85+
expect(result.score).toBe(0.8);
86+
expect(result.action).toBe('auto_accept');
87+
});
88+
89+
it('respects custom thresholds', () => {
90+
const signals: SignalWeight[] = [
91+
{ name: 'medium', weight: 0.5, detect: () => true },
92+
];
93+
// Default threshold: autoAccept=0.7, review=0.4
94+
const defaultResult = scoreRecord(makeRecord('x'), signals);
95+
expect(defaultResult.action).toBe('review');
96+
97+
// Custom threshold: autoAccept=0.3
98+
const customResult = scoreRecord(makeRecord('x'), signals, {
99+
autoAccept: 0.3,
100+
});
101+
expect(customResult.action).toBe('auto_accept');
102+
});
103+
104+
it('handles all-negative signals', () => {
105+
const signals: SignalWeight[] = [
106+
{ name: 'bad', weight: -0.5, detect: () => true },
107+
];
108+
const result = scoreRecord(makeRecord('x'), signals);
109+
expect(result.score).toBe(0);
110+
expect(result.action).toBe('discard');
111+
});
112+
});

0 commit comments

Comments
 (0)