@@ -225,8 +225,9 @@ function recordResult(funcName, args, returnValue, error, durationNs) {
225225/**
226226 * Capture a function call with full behavior tracking.
227227 *
228- * This is the main API for instrumenting function calls.
229- * It captures inputs, outputs, errors, and timing for every call.
228+ * This is the main API for instrumenting function calls for BEHAVIOR verification.
229+ * It captures inputs (after call, to detect mutations), outputs, errors, and timing.
230+ * Results are written to SQLite for comparison between original and optimized code.
230231 *
231232 * @param {string } funcName - Name of the function being tested
232233 * @param {Function } fn - The function to call
@@ -251,6 +252,7 @@ function capture(funcName, fn, ...args) {
251252 ( resolved ) => {
252253 const endTime = performance . now ( ) ;
253254 const durationNs = ( endTime - startTime ) * 1_000_000 ;
255+ // Note: args is captured AFTER the call to detect mutations
254256 recordResult ( funcName , args , resolved , null , durationNs ) ;
255257 return resolved ;
256258 } ,
@@ -268,12 +270,83 @@ function capture(funcName, fn, ...args) {
268270
269271 const endTime = performance . now ( ) ;
270272 const durationNs = ( endTime - startTime ) * 1_000_000 ;
273+ // Note: args is captured AFTER the call to detect mutations (same as Python)
271274 recordResult ( funcName , args , returnValue , error , durationNs ) ;
272275
273276 if ( error ) throw error ;
274277 return returnValue ;
275278}
276279
280+ /**
281+ * Capture a function call for PERFORMANCE benchmarking only.
282+ *
283+ * This is a lightweight instrumentation that only measures timing.
284+ * It prints start/end tags to stdout (no SQLite writes, no serialization overhead).
285+ * Used when we've already verified behavior and just need accurate timing.
286+ *
287+ * Output format matches Python's codeflash_performance wrapper:
288+ * Start: !$######test_module:test_class.test_name:func_name:loop_index:invocation_id######$!
289+ * End: !######test_module:test_class.test_name:func_name:loop_index:invocation_id:duration_ns######!
290+ *
291+ * @param {string } funcName - Name of the function being tested
292+ * @param {Function } fn - The function to call
293+ * @param {...any } args - Arguments to pass to the function
294+ * @returns {any } - The function's return value
295+ * @throws {Error } - Re-throws any error from the function
296+ */
297+ function capturePerf ( funcName , fn , ...args ) {
298+ const invocationId = `${ lineId } _${ invocationCounter } ` ;
299+ invocationCounter ++ ;
300+
301+ // Get test context
302+ const testModulePath = TEST_MODULE || currentTestName || 'unknown' ;
303+ const testClassName = '' ; // Jest doesn't use classes like Python
304+
305+ // Format: test_module:test_class.test_name:func_name:loop_index:invocation_id
306+ const testStdoutTag = `${ testModulePath } :${ testClassName } ${ currentTestName } :${ funcName } :${ LOOP_INDEX } :${ invocationId } ` ;
307+
308+ // Print start tag
309+ console . log ( `!$######${ testStdoutTag } ######$!` ) ;
310+
311+ const startTime = performance . now ( ) ;
312+ let returnValue ;
313+ let error = null ;
314+
315+ try {
316+ returnValue = fn ( ...args ) ;
317+
318+ // Handle promises (async functions)
319+ if ( returnValue instanceof Promise ) {
320+ return returnValue . then (
321+ ( resolved ) => {
322+ const endTime = performance . now ( ) ;
323+ const durationNs = Math . round ( ( endTime - startTime ) * 1_000_000 ) ;
324+ // Print end tag with timing
325+ console . log ( `!######${ testStdoutTag } :${ durationNs } ######!` ) ;
326+ return resolved ;
327+ } ,
328+ ( err ) => {
329+ const endTime = performance . now ( ) ;
330+ const durationNs = Math . round ( ( endTime - startTime ) * 1_000_000 ) ;
331+ // Print end tag with timing even on error
332+ console . log ( `!######${ testStdoutTag } :${ durationNs } ######!` ) ;
333+ throw err ;
334+ }
335+ ) ;
336+ }
337+ } catch ( e ) {
338+ error = e ;
339+ }
340+
341+ const endTime = performance . now ( ) ;
342+ const durationNs = Math . round ( ( endTime - startTime ) * 1_000_000 ) ;
343+ // Print end tag with timing
344+ console . log ( `!######${ testStdoutTag } :${ durationNs } ######!` ) ;
345+
346+ if ( error ) throw error ;
347+ return returnValue ;
348+ }
349+
277350/**
278351 * Capture multiple invocations for benchmarking.
279352 *
@@ -372,7 +445,8 @@ if (typeof afterAll !== 'undefined') {
372445
373446// Export public API
374447module . exports = {
375- capture,
448+ capture, // Behavior verification (writes to SQLite)
449+ capturePerf, // Performance benchmarking (prints to stdout only)
376450 captureMultiple,
377451 writeResults,
378452 clearResults,
0 commit comments