@@ -299,6 +299,57 @@ def test_concurrent_flush_no_lost_updates(self, data_dir):
299299 assert on_disk ["tool_names" ]["Bash" ] == expected
300300
301301
302+ class TestHookTimingWiring :
303+ """Regression test: hook scripts record timing via time_hook context manager (#1494)."""
304+
305+ def test_time_hook_records_timing (self , data_dir ):
306+ """time_hook should record elapsed_ms to disk hook_timings."""
307+ from hook_runtime import time_hook
308+
309+ session_id = "timing-test"
310+ SessionStats (session_id = session_id , data_dir = data_dir )
311+
312+ with time_hook ("PostToolUse" , session_id = session_id , data_dir = data_dir ):
313+ time .sleep (0.01 )
314+
315+ s = SessionStats (session_id = session_id , data_dir = data_dir )
316+ data = s ._locked_read ()
317+ assert "PostToolUse" in data ["hook_timings" ]
318+ assert len (data ["hook_timings" ]["PostToolUse" ]) >= 1
319+ assert data ["hook_timings" ]["PostToolUse" ][0 ] >= 5 # at least ~5ms
320+
321+ def test_time_hook_records_even_on_inner_exception (self , data_dir ):
322+ """Timing is recorded even when inner code raises."""
323+ from hook_runtime import time_hook
324+
325+ session_id = "exc-test"
326+ SessionStats (session_id = session_id , data_dir = data_dir )
327+
328+ with pytest .raises (ValueError ):
329+ with time_hook ("PostToolUse" , session_id = session_id , data_dir = data_dir ):
330+ raise ValueError ("intentional error inside hook" )
331+
332+ s = SessionStats (session_id = session_id , data_dir = data_dir )
333+ data = s ._locked_read ()
334+ assert "PostToolUse" in data ["hook_timings" ]
335+ assert len (data ["hook_timings" ]["PostToolUse" ]) >= 1
336+
337+ def test_time_hook_records_multiple (self , data_dir ):
338+ """Multiple time_hook invocations accumulate timings."""
339+ from hook_runtime import time_hook
340+
341+ session_id = "multi-timing"
342+ SessionStats (session_id = session_id , data_dir = data_dir )
343+
344+ for _ in range (3 ):
345+ with time_hook ("PreToolUse" , session_id = session_id , data_dir = data_dir ):
346+ pass
347+
348+ s = SessionStats (session_id = session_id , data_dir = data_dir )
349+ data = s ._locked_read ()
350+ assert len (data ["hook_timings" ]["PreToolUse" ]) == 3
351+
352+
302353class TestCleanup :
303354 def test_cleanup_stale_removes_old_files (self , data_dir ):
304355 # Create a stale file
0 commit comments