@@ -386,6 +386,57 @@ def test_concurrent_flush_no_lost_updates(self, data_dir):
386386 assert on_disk ["tool_names" ]["Bash" ] == expected
387387
388388
389+ class TestHookTimingWiring :
390+ """Regression test: hook scripts record timing via time_hook context manager (#1494)."""
391+
392+ def test_time_hook_records_timing (self , data_dir ):
393+ """time_hook should record elapsed_ms to disk hook_timings."""
394+ from hook_runtime import time_hook
395+
396+ session_id = "timing-test"
397+ SessionStats (session_id = session_id , data_dir = data_dir )
398+
399+ with time_hook ("PostToolUse" , session_id = session_id , data_dir = data_dir ):
400+ time .sleep (0.01 )
401+
402+ s = SessionStats (session_id = session_id , data_dir = data_dir )
403+ data = s ._locked_read ()
404+ assert "PostToolUse" in data ["hook_timings" ]
405+ assert len (data ["hook_timings" ]["PostToolUse" ]) >= 1
406+ assert data ["hook_timings" ]["PostToolUse" ][0 ] >= 5 # at least ~5ms
407+
408+ def test_time_hook_records_even_on_inner_exception (self , data_dir ):
409+ """Timing is recorded even when inner code raises."""
410+ from hook_runtime import time_hook
411+
412+ session_id = "exc-test"
413+ SessionStats (session_id = session_id , data_dir = data_dir )
414+
415+ with pytest .raises (ValueError ):
416+ with time_hook ("PostToolUse" , session_id = session_id , data_dir = data_dir ):
417+ raise ValueError ("intentional error inside hook" )
418+
419+ s = SessionStats (session_id = session_id , data_dir = data_dir )
420+ data = s ._locked_read ()
421+ assert "PostToolUse" in data ["hook_timings" ]
422+ assert len (data ["hook_timings" ]["PostToolUse" ]) >= 1
423+
424+ def test_time_hook_records_multiple (self , data_dir ):
425+ """Multiple time_hook invocations accumulate timings."""
426+ from hook_runtime import time_hook
427+
428+ session_id = "multi-timing"
429+ SessionStats (session_id = session_id , data_dir = data_dir )
430+
431+ for _ in range (3 ):
432+ with time_hook ("PreToolUse" , session_id = session_id , data_dir = data_dir ):
433+ pass
434+
435+ s = SessionStats (session_id = session_id , data_dir = data_dir )
436+ data = s ._locked_read ()
437+ assert len (data ["hook_timings" ]["PreToolUse" ]) == 3
438+
439+
389440class TestCleanup :
390441 def test_cleanup_stale_removes_old_files (self , data_dir ):
391442 # Create a stale file
0 commit comments