@@ -47,14 +47,30 @@ const TEST_MODULE = process.env.CODEFLASH_TEST_MODULE;
4747// Batch 1: Test1(5 loops) → Test2(5 loops) → Test3(5 loops)
4848// Batch 2: Test1(5 loops) → Test2(5 loops) → Test3(5 loops)
4949// ...until time budget exhausted
50- const PERF_LOOP_COUNT = parseInt ( process . env . CODEFLASH_PERF_LOOP_COUNT || '1' , 10 ) ;
51- const PERF_MIN_LOOPS = parseInt ( process . env . CODEFLASH_PERF_MIN_LOOPS || '5' , 10 ) ;
52- const PERF_TARGET_DURATION_MS = parseInt ( process . env . CODEFLASH_PERF_TARGET_DURATION_MS || '10000' , 10 ) ;
53- const PERF_BATCH_SIZE = parseInt ( process . env . CODEFLASH_PERF_BATCH_SIZE || '10' , 10 ) ;
54- const PERF_STABILITY_CHECK = ( process . env . CODEFLASH_PERF_STABILITY_CHECK || 'false' ) . toLowerCase ( ) === 'true' ;
50+ //
51+ // IMPORTANT: These are getter functions, NOT constants!
52+ // Vitest caches modules and may load this file before env vars are set.
53+ // Using getter functions ensures we read the env vars at runtime when they're actually needed.
54+ function getPerfLoopCount ( ) {
55+ return parseInt ( process . env . CODEFLASH_PERF_LOOP_COUNT || '1' , 10 ) ;
56+ }
57+ function getPerfMinLoops ( ) {
58+ return parseInt ( process . env . CODEFLASH_PERF_MIN_LOOPS || '5' , 10 ) ;
59+ }
60+ function getPerfTargetDurationMs ( ) {
61+ return parseInt ( process . env . CODEFLASH_PERF_TARGET_DURATION_MS || '10000' , 10 ) ;
62+ }
63+ function getPerfBatchSize ( ) {
64+ return parseInt ( process . env . CODEFLASH_PERF_BATCH_SIZE || '10' , 10 ) ;
65+ }
66+ function getPerfStabilityCheck ( ) {
67+ return ( process . env . CODEFLASH_PERF_STABILITY_CHECK || 'false' ) . toLowerCase ( ) === 'true' ;
68+ }
5569// Current batch number - set by loop-runner before each batch
5670// This allows continuous loop indices even when Jest resets module state
57- const PERF_CURRENT_BATCH = parseInt ( process . env . CODEFLASH_PERF_CURRENT_BATCH || '0' , 10 ) ;
71+ function getPerfCurrentBatch ( ) {
72+ return parseInt ( process . env . CODEFLASH_PERF_CURRENT_BATCH || '0' , 10 ) ;
73+ }
5874
5975// Stability constants (matching Python's config_consts.py)
6076const STABILITY_WINDOW_SIZE = 0.35 ;
@@ -86,7 +102,7 @@ function checkSharedTimeLimit() {
86102 return false ;
87103 }
88104 const elapsed = Date . now ( ) - sharedPerfState . startTime ;
89- if ( elapsed >= PERF_TARGET_DURATION_MS && sharedPerfState . totalLoopsCompleted >= PERF_MIN_LOOPS ) {
105+ if ( elapsed >= getPerfTargetDurationMs ( ) && sharedPerfState . totalLoopsCompleted >= getPerfMinLoops ( ) ) {
90106 sharedPerfState . shouldStop = true ;
91107 return true ;
92108 }
@@ -111,7 +127,7 @@ function getInvocationLoopIndex(invocationKey) {
111127 // Calculate global loop index using batch number from environment
112128 // PERF_CURRENT_BATCH is 1-based (set by loop-runner before each batch)
113129 const currentBatch = parseInt ( process . env . CODEFLASH_PERF_CURRENT_BATCH || '1' , 10 ) ;
114- const globalIndex = ( currentBatch - 1 ) * PERF_BATCH_SIZE + localIndex ;
130+ const globalIndex = ( currentBatch - 1 ) * getPerfBatchSize ( ) + localIndex ;
115131
116132 return globalIndex ;
117133}
@@ -606,7 +622,7 @@ function capture(funcName, lineId, fn, ...args) {
606622 */
607623function capturePerf ( funcName , lineId , fn , ...args ) {
608624 // Check if we should skip looping entirely (shared time budget exceeded)
609- const shouldLoop = PERF_LOOP_COUNT > 1 && ! checkSharedTimeLimit ( ) ;
625+ const shouldLoop = getPerfLoopCount ( ) > 1 && ! checkSharedTimeLimit ( ) ;
610626
611627 // Get test context (computed once, reused across batch)
612628 let testModulePath ;
@@ -636,9 +652,9 @@ function capturePerf(funcName, lineId, fn, ...args) {
636652 // If so, just execute the function once without timing (for test assertions)
637653 const peekLoopIndex = ( sharedPerfState . invocationLoopCounts [ invocationKey ] || 0 ) ;
638654 const currentBatch = parseInt ( process . env . CODEFLASH_PERF_CURRENT_BATCH || '1' , 10 ) ;
639- const nextGlobalIndex = ( currentBatch - 1 ) * PERF_BATCH_SIZE + peekLoopIndex + 1 ;
655+ const nextGlobalIndex = ( currentBatch - 1 ) * getPerfBatchSize ( ) + peekLoopIndex + 1 ;
640656
641- if ( shouldLoop && nextGlobalIndex > PERF_LOOP_COUNT ) {
657+ if ( shouldLoop && nextGlobalIndex > getPerfLoopCount ( ) ) {
642658 // All loops completed, just execute once for test assertion
643659 return fn ( ...args ) ;
644660 }
@@ -654,7 +670,7 @@ function capturePerf(funcName, lineId, fn, ...args) {
654670 // Batched looping: run BATCH_SIZE loops per capturePerf call when using loop-runner
655671 // For Vitest (no loop-runner), do all loops internally in a single call
656672 const batchSize = shouldLoop
657- ? ( hasExternalLoopRunner ? PERF_BATCH_SIZE : PERF_LOOP_COUNT )
673+ ? ( hasExternalLoopRunner ? getPerfBatchSize ( ) : getPerfLoopCount ( ) )
658674 : 1 ;
659675
660676 for ( let batchIndex = 0 ; batchIndex < batchSize ; batchIndex ++ ) {
@@ -667,7 +683,7 @@ function capturePerf(funcName, lineId, fn, ...args) {
667683 const loopIndex = getInvocationLoopIndex ( invocationKey ) ;
668684
669685 // Check if we've exceeded max loops for this invocation
670- if ( loopIndex > PERF_LOOP_COUNT ) {
686+ if ( loopIndex > getPerfLoopCount ( ) ) {
671687 break ;
672688 }
673689
@@ -872,7 +888,11 @@ module.exports = {
872888 LOOP_INDEX ,
873889 OUTPUT_FILE ,
874890 TEST_ITERATION ,
875- // Batch configuration
876- PERF_BATCH_SIZE ,
877- PERF_LOOP_COUNT ,
891+ // Batch configuration (getter functions for dynamic env var reading)
892+ getPerfBatchSize,
893+ getPerfLoopCount,
894+ getPerfMinLoops,
895+ getPerfTargetDurationMs,
896+ getPerfStabilityCheck,
897+ getPerfCurrentBatch,
878898} ;
0 commit comments