Bug fixes
This commit is contained in:
104
__tests__/server/scanReview.test.js
Normal file
104
__tests__/server/scanReview.test.js
Normal file
@@ -0,0 +1,104 @@
|
||||
const { decideReviewOutcome, reviewAgreesWithPrimary } = require('../../server/lib/scanReview');
|
||||
|
||||
const ai = (name, botanicalName, confidence) => ({ name, botanicalName, confidence });
|
||||
|
||||
describe('reviewAgreesWithPrimary', () => {
|
||||
it('agrees on matching botanical names regardless of casing/accents', () => {
|
||||
expect(reviewAgreesWithPrimary(
|
||||
ai('Swiss Cheese Plant', 'Monstera deliciosa', 0.7),
|
||||
ai('Fensterblatt', 'MONSTERA DELICIOSA', 0.6),
|
||||
)).toBe(true);
|
||||
});
|
||||
|
||||
it('agrees on matching common names when botanicals differ', () => {
|
||||
expect(reviewAgreesWithPrimary(
|
||||
ai('Rose', 'Rosa chinensis', 0.5),
|
||||
ai('Rose', 'Rosa hybrida', 0.5),
|
||||
)).toBe(true);
|
||||
});
|
||||
|
||||
it('does not agree for different species in the same genus', () => {
|
||||
// Regression: post-grounding comparison used to collapse these onto the
|
||||
// same catalog entry and fake an agreement.
|
||||
expect(reviewAgreesWithPrimary(
|
||||
ai('Fiddle Leaf Fig', 'Ficus lyrata', 0.7),
|
||||
ai('Rubber Plant', 'Ficus elastica', 0.7),
|
||||
)).toBe(false);
|
||||
});
|
||||
|
||||
it('never agrees when either side is missing', () => {
|
||||
expect(reviewAgreesWithPrimary(null, ai('Rose', 'Rosa chinensis', 0.5))).toBe(false);
|
||||
expect(reviewAgreesWithPrimary(ai('Rose', 'Rosa chinensis', 0.5), null)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('decideReviewOutcome', () => {
|
||||
it('rejects a disagreeing review at lower confidence', () => {
|
||||
const decision = decideReviewOutcome({
|
||||
primaryResult: ai('Swiss Cheese Plant', 'Monstera deliciosa', 0.85),
|
||||
reviewResult: ai('Rose', 'Rosa chinensis', 0.55),
|
||||
agrees: false,
|
||||
});
|
||||
expect(decision).toEqual({ accept: false, replace: false, reason: 'review-rejected-low-confidence' });
|
||||
});
|
||||
|
||||
it('accepts a disagreeing review at higher confidence', () => {
|
||||
const decision = decideReviewOutcome({
|
||||
primaryResult: ai('Rose', 'Rosa chinensis', 0.55),
|
||||
reviewResult: ai('Swiss Cheese Plant', 'Monstera deliciosa', 0.8),
|
||||
agrees: false,
|
||||
});
|
||||
expect(decision).toEqual({ accept: true, replace: true, reason: 'review-overrode-primary' });
|
||||
});
|
||||
|
||||
it('accepts a disagreeing stronger-model review within the 0.05 calibration margin', () => {
|
||||
// Models are not calibrated against each other: an honest gpt-5 answer at
|
||||
// 0.75 must not lose to an overconfident gpt-5-mini answer at 0.79.
|
||||
const decision = decideReviewOutcome({
|
||||
primaryResult: ai('Rose', 'Rosa chinensis', 0.79),
|
||||
reviewResult: ai('Swiss Cheese Plant', 'Monstera deliciosa', 0.75),
|
||||
agrees: false,
|
||||
});
|
||||
expect(decision).toEqual({ accept: true, replace: true, reason: 'review-overrode-primary' });
|
||||
});
|
||||
|
||||
it('still rejects a disagreeing review clearly below the margin', () => {
|
||||
const decision = decideReviewOutcome({
|
||||
primaryResult: ai('Rose', 'Rosa chinensis', 0.79),
|
||||
reviewResult: ai('Swiss Cheese Plant', 'Monstera deliciosa', 0.73),
|
||||
agrees: false,
|
||||
});
|
||||
expect(decision.accept).toBe(false);
|
||||
});
|
||||
|
||||
it('keeps the higher-confidence primary when the review agrees at lower confidence', () => {
|
||||
const decision = decideReviewOutcome({
|
||||
primaryResult: ai('Swiss Cheese Plant', 'Monstera deliciosa', 0.85),
|
||||
reviewResult: ai('Swiss Cheese Plant', 'Monstera deliciosa', 0.6),
|
||||
agrees: true,
|
||||
});
|
||||
expect(decision.accept).toBe(true);
|
||||
expect(decision.replace).toBe(false);
|
||||
expect(decision.reason).toBe('review-confirmed-primary');
|
||||
});
|
||||
|
||||
it('replaces with the agreeing review on a confidence tie (stronger model wins ties)', () => {
|
||||
const decision = decideReviewOutcome({
|
||||
primaryResult: ai('Swiss Cheese Plant', 'Monstera deliciosa', 0.7),
|
||||
reviewResult: ai('Swiss Cheese Plant', 'Monstera deliciosa', 0.7),
|
||||
agrees: true,
|
||||
});
|
||||
expect(decision.accept).toBe(true);
|
||||
expect(decision.replace).toBe(true);
|
||||
});
|
||||
|
||||
it('treats missing confidences as 0 without crashing', () => {
|
||||
const decision = decideReviewOutcome({
|
||||
primaryResult: ai('Rose', 'Rosa chinensis', undefined),
|
||||
reviewResult: ai('Swiss Cheese Plant', 'Monstera deliciosa', 0.5),
|
||||
agrees: false,
|
||||
});
|
||||
expect(decision.accept).toBe(true);
|
||||
expect(decision.replace).toBe(true);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user