@@ -19,9 +19,11 @@ import {
1919 dashboardAgentModelKey ,
2020 dashboardAgentStoreKey ,
2121 dashboardAgentToolsKey ,
22+ DEFAULT_CI_EVAL_SAMPLE_RATE ,
2223 DEFAULT_EVAL_SAMPLE_RATE ,
2324 evalSampleRate ,
2425 extractToolActivity ,
26+ isCiEvalContext ,
2527 MAX_EVAL_TOOL_OUTPUT_CHARS ,
2628 sanitizeReplayedToolInputs ,
2729 truncateEvalToolOutput ,
@@ -515,6 +517,63 @@ describe("per-turn eval sampling", () => {
515517 } ) ;
516518} ) ;
517519
520+ describe ( "the CI sample rate" , ( ) => {
521+ const original = {
522+ context : process . env . DASHBOARD_AGENT_EVAL_CONTEXT ,
523+ ci : process . env . DASHBOARD_AGENT_EVAL_SAMPLE_RATE_CI ,
524+ production : process . env . DASHBOARD_AGENT_EVAL_SAMPLE_RATE ,
525+ } ;
526+
527+ function restore ( name : string , value : string | undefined ) {
528+ if ( value === undefined ) delete process . env [ name ] ;
529+ else process . env [ name ] = value ;
530+ }
531+
532+ afterEach ( ( ) => {
533+ restore ( "DASHBOARD_AGENT_EVAL_CONTEXT" , original . context ) ;
534+ restore ( "DASHBOARD_AGENT_EVAL_SAMPLE_RATE_CI" , original . ci ) ;
535+ restore ( "DASHBOARD_AGENT_EVAL_SAMPLE_RATE" , original . production ) ;
536+ } ) ;
537+
538+ it ( "judges every turn in the CI lane" , ( ) => {
539+ process . env . DASHBOARD_AGENT_EVAL_CONTEXT = "ci" ;
540+ delete process . env . DASHBOARD_AGENT_EVAL_SAMPLE_RATE_CI ;
541+ expect ( isCiEvalContext ( ) ) . toBe ( true ) ;
542+ expect ( evalSampleRate ( ) ) . toBe ( DEFAULT_CI_EVAL_SAMPLE_RATE ) ;
543+ expect ( DEFAULT_CI_EVAL_SAMPLE_RATE ) . toBe ( 1 ) ;
544+ } ) ;
545+
546+ it ( "does not let the CI rate reach production" , ( ) => {
547+ delete process . env . DASHBOARD_AGENT_EVAL_CONTEXT ;
548+ delete process . env . DASHBOARD_AGENT_EVAL_SAMPLE_RATE ;
549+ process . env . DASHBOARD_AGENT_EVAL_SAMPLE_RATE_CI = "1" ;
550+ expect ( isCiEvalContext ( ) ) . toBe ( false ) ;
551+ expect ( evalSampleRate ( ) ) . toBe ( DEFAULT_EVAL_SAMPLE_RATE ) ;
552+ } ) ;
553+
554+ it ( "does not let the production rate de-sample CI" , ( ) => {
555+ process . env . DASHBOARD_AGENT_EVAL_CONTEXT = "ci" ;
556+ process . env . DASHBOARD_AGENT_EVAL_SAMPLE_RATE = "0" ;
557+ delete process . env . DASHBOARD_AGENT_EVAL_SAMPLE_RATE_CI ;
558+ expect ( evalSampleRate ( ) ) . toBe ( 1 ) ;
559+ } ) ;
560+
561+ it ( "honours a parseable CI rate, and falls back to full on a bad one" , ( ) => {
562+ process . env . DASHBOARD_AGENT_EVAL_CONTEXT = "ci" ;
563+ process . env . DASHBOARD_AGENT_EVAL_SAMPLE_RATE_CI = "0.25" ;
564+ expect ( evalSampleRate ( ) ) . toBe ( 0.25 ) ;
565+ process . env . DASHBOARD_AGENT_EVAL_SAMPLE_RATE_CI = "nope" ;
566+ expect ( evalSampleRate ( ) ) . toBe ( DEFAULT_CI_EVAL_SAMPLE_RATE ) ;
567+ } ) ;
568+
569+ it ( "only the exact context value selects the CI lane" , ( ) => {
570+ for ( const raw of [ "CI" , "true" , "1" , "golden" , "" ] ) {
571+ process . env . DASHBOARD_AGENT_EVAL_CONTEXT = raw ;
572+ expect ( isCiEvalContext ( ) ) . toBe ( false ) ;
573+ }
574+ } ) ;
575+ } ) ;
576+
518577describe ( "the per-org opt-out" , ( ) => {
519578 let harness : MockChatAgentHarness | undefined ;
520579 const originalRate = process . env . DASHBOARD_AGENT_EVAL_SAMPLE_RATE ;
0 commit comments