@@ -54,17 +54,76 @@ describe('Judge', () => {
5454
5555 describe ( 'constructor' , ( ) => {
5656 it ( 'initializes with proper configuration' , ( ) => {
57- const judge = new Judge ( judgeConfig , mockProvider , mockLogger ) ;
57+ const judge = new Judge ( judgeConfig , mockProvider , 1.0 , mockLogger ) ;
5858
5959 expect ( judge ) . toBeDefined ( ) ;
6060 } ) ;
61+
62+ it ( 'defaults sampleRate to 1.0 when omitted' , ( ) => {
63+ const judge = new Judge ( judgeConfig , mockProvider ) ;
64+ expect ( judge . sampleRate ) . toBe ( 1.0 ) ;
65+ } ) ;
66+
67+ it ( 'exposes the sampleRate provided to the constructor' , ( ) => {
68+ const judge = new Judge ( judgeConfig , mockProvider , 0.25 , mockLogger ) ;
69+ expect ( judge . sampleRate ) . toBe ( 0.25 ) ;
70+ } ) ;
71+
72+ it ( 'honors a sampleRate of 0' , ( ) => {
73+ const judge = new Judge ( judgeConfig , mockProvider , 0 , mockLogger ) ;
74+ expect ( judge . sampleRate ) . toBe ( 0 ) ;
75+ } ) ;
76+ } ) ;
77+
78+ describe ( 'sampling fallback in evaluate()' , ( ) => {
79+ it ( 'uses the constructor sampleRate when no per-call rate is supplied' , async ( ) => {
80+ // Force sampling to skip: math.random() returns 0.6, sampleRate 0.5 → 0.6 > 0.5 → skip.
81+ const randomSpy = jest . spyOn ( Math , 'random' ) . mockReturnValue ( 0.6 ) ;
82+
83+ const judge = new Judge ( judgeConfig , mockProvider , 0.5 , mockLogger ) ;
84+ const result = await judge . evaluate ( 'input' , 'output' ) ;
85+
86+ // Skipped due to sampling: sampled stays false (default), no provider call.
87+ expect ( result . sampled ) . toBe ( false ) ;
88+ expect ( mockProvider . invokeStructuredModel ) . not . toHaveBeenCalled ( ) ;
89+
90+ randomSpy . mockRestore ( ) ;
91+ } ) ;
92+
93+ it ( 'honors an explicit per-call samplingRate of 0 over the constructor default' , async ( ) => {
94+ // Even with Math.random() at 0, samplingRate=0 means 0 > 0 is false — skip path is
95+ // `Math.random() > rate`, so rate=0 + random=0 does NOT skip. Use random=0.5.
96+ const randomSpy = jest . spyOn ( Math , 'random' ) . mockReturnValue ( 0.5 ) ;
97+
98+ // Constructor rate is 1.0 (would normally always sample); per-call 0 overrides to skip.
99+ const judge = new Judge ( judgeConfig , mockProvider , 1.0 , mockLogger ) ;
100+ const result = await judge . evaluate ( 'input' , 'output' , 0 ) ;
101+
102+ expect ( result . sampled ) . toBe ( false ) ;
103+ expect ( mockProvider . invokeStructuredModel ) . not . toHaveBeenCalled ( ) ;
104+
105+ randomSpy . mockRestore ( ) ;
106+ } ) ;
107+
108+ it ( 'per-call samplingRate of undefined falls through to the constructor default' , async ( ) => {
109+ // Constructor 0 (always skip), per-call undefined → effective rate 0.
110+ const randomSpy = jest . spyOn ( Math , 'random' ) . mockReturnValue ( 0.5 ) ;
111+
112+ const judge = new Judge ( judgeConfig , mockProvider , 0 , mockLogger ) ;
113+ const result = await judge . evaluate ( 'input' , 'output' , undefined ) ;
114+
115+ expect ( result . sampled ) . toBe ( false ) ;
116+ expect ( mockProvider . invokeStructuredModel ) . not . toHaveBeenCalled ( ) ;
117+
118+ randomSpy . mockRestore ( ) ;
119+ } ) ;
61120 } ) ;
62121
63122 describe ( 'evaluate' , ( ) => {
64123 let judge : Judge ;
65124
66125 beforeEach ( ( ) => {
67- judge = new Judge ( judgeConfig , mockProvider , mockLogger ) ;
126+ judge = new Judge ( judgeConfig , mockProvider , 1.0 , mockLogger ) ;
68127 } ) ;
69128
70129 it ( 'evaluates AI response successfully' , async ( ) => {
@@ -205,7 +264,7 @@ describe('Judge', () => {
205264 evaluationMetricKey : undefined ,
206265 evaluationMetricKeys : [ ] ,
207266 } ;
208- const judgeWithoutMetrics = new Judge ( configWithoutMetrics , mockProvider , mockLogger ) ;
267+ const judgeWithoutMetrics = new Judge ( configWithoutMetrics , mockProvider , 1.0 , mockLogger ) ;
209268
210269 const result = await judgeWithoutMetrics . evaluate ( 'test input' , 'test output' ) ;
211270
@@ -227,7 +286,7 @@ describe('Judge', () => {
227286 evaluationMetricKey : 'relevance' ,
228287 evaluationMetricKeys : undefined ,
229288 } ;
230- const judgeWithSingleKey = new Judge ( configWithSingleKey , mockProvider , mockLogger ) ;
289+ const judgeWithSingleKey = new Judge ( configWithSingleKey , mockProvider , 1.0 , mockLogger ) ;
231290
232291 const mockStructuredResponse : StructuredResponse = {
233292 data : {
@@ -265,7 +324,7 @@ describe('Judge', () => {
265324 evaluationMetricKey : undefined ,
266325 evaluationMetricKeys : [ 'relevance' , 'accuracy' ] ,
267326 } ;
268- const judgeWithLegacyKeys = new Judge ( configWithLegacyKeys , mockProvider , mockLogger ) ;
327+ const judgeWithLegacyKeys = new Judge ( configWithLegacyKeys , mockProvider , 1.0 , mockLogger ) ;
269328
270329 const mockStructuredResponse : StructuredResponse = {
271330 data : {
@@ -303,7 +362,7 @@ describe('Judge', () => {
303362 evaluationMetricKey : undefined ,
304363 evaluationMetricKeys : [ '' , ' ' , 'relevance' , 'accuracy' ] ,
305364 } ;
306- const judgeWithInvalidKeys = new Judge ( configWithInvalidKeys , mockProvider , mockLogger ) ;
365+ const judgeWithInvalidKeys = new Judge ( configWithInvalidKeys , mockProvider , 1.0 , mockLogger ) ;
307366
308367 const mockStructuredResponse : StructuredResponse = {
309368 data : {
@@ -342,7 +401,7 @@ describe('Judge', () => {
342401 evaluationMetricKey : 'helpfulness' ,
343402 evaluationMetricKeys : [ 'relevance' , 'accuracy' ] ,
344403 } ;
345- const judgeWithBoth = new Judge ( configWithBoth , mockProvider , mockLogger ) ;
404+ const judgeWithBoth = new Judge ( configWithBoth , mockProvider , 1.0 , mockLogger ) ;
346405
347406 const mockStructuredResponse : StructuredResponse = {
348407 data : {
@@ -379,7 +438,7 @@ describe('Judge', () => {
379438 ...judgeConfig ,
380439 messages : undefined ,
381440 } ;
382- const judgeWithoutMessages = new Judge ( configWithoutMessages , mockProvider , mockLogger ) ;
441+ const judgeWithoutMessages = new Judge ( configWithoutMessages , mockProvider , 1.0 , mockLogger ) ;
383442
384443 const result = await judgeWithoutMessages . evaluate ( 'test input' , 'test output' ) ;
385444
@@ -488,7 +547,7 @@ describe('Judge', () => {
488547 let judge : Judge ;
489548
490549 beforeEach ( ( ) => {
491- judge = new Judge ( judgeConfig , mockProvider , mockLogger ) ;
550+ judge = new Judge ( judgeConfig , mockProvider , 1.0 , mockLogger ) ;
492551 } ) ;
493552
494553 it ( 'evaluates messages and response successfully' , async ( ) => {
@@ -573,7 +632,7 @@ describe('Judge', () => {
573632 let judge : Judge ;
574633
575634 beforeEach ( ( ) => {
576- judge = new Judge ( judgeConfig , mockProvider , mockLogger ) ;
635+ judge = new Judge ( judgeConfig , mockProvider , 1.0 , mockLogger ) ;
577636 } ) ;
578637
579638 it ( 'constructs evaluation messages correctly' , ( ) => {
@@ -598,7 +657,7 @@ describe('Judge', () => {
598657 let judge : Judge ;
599658
600659 beforeEach ( ( ) => {
601- judge = new Judge ( judgeConfig , mockProvider , mockLogger ) ;
660+ judge = new Judge ( judgeConfig , mockProvider , 1.0 , mockLogger ) ;
602661 } ) ;
603662
604663 it ( 'parses valid evaluation response correctly' , ( ) => {
@@ -669,7 +728,7 @@ describe('Judge', () => {
669728 evaluationMetricKey : undefined ,
670729 evaluationMetricKeys : [ ] ,
671730 } ;
672- const judgeWithEmptyKeys = new Judge ( configWithEmptyKeys , mockProvider , mockLogger ) ;
731+ const judgeWithEmptyKeys = new Judge ( configWithEmptyKeys , mockProvider , 1.0 , mockLogger ) ;
673732
674733 const result = await judgeWithEmptyKeys . evaluate ( 'test input' , 'test output' ) ;
675734
0 commit comments