@@ -200,7 +200,7 @@ def _payload(self, **extra):
200200 return {"cwd" : self .tmpdir , ** extra }
201201
202202 def test_all_completed_allows_stop (self ):
203- """When all tasks are completed, stop is allowed."""
203+ """When all tasks are completed, stop is allowed and .harness-reflect created ."""
204204 write_tasks (self .root , [
205205 {"id" : "t1" , "status" : "completed" },
206206 {"id" : "t2" , "status" : "completed" },
@@ -209,6 +209,10 @@ def test_all_completed_allows_stop(self):
209209 self .assertEqual (code , 0 )
210210 self .assertEqual (stdout , "" )
211211 self .assertFalse ((self .root / ".harness-active" ).exists ())
212+ self .assertTrue (
213+ (self .root / ".harness-reflect" ).exists (),
214+ ".harness-reflect should be created when all tasks complete" ,
215+ )
212216
213217 def test_pending_with_unmet_deps_allows_stop (self ):
214218 """Pending tasks with unmet dependencies don't block stop."""
@@ -644,7 +648,7 @@ def test_tasks_not_a_list(self):
644648
645649
646650class TestSelfReflectStopHook (unittest .TestCase ):
647- """self-reflect-stop.py must only trigger when harness was used and completed ."""
651+ """self-reflect-stop.py must only trigger when . harness-reflect marker exists ."""
648652
649653 def setUp (self ):
650654 self .tmpdir = tempfile .mkdtemp ()
@@ -663,14 +667,18 @@ def tearDown(self):
663667 def _payload (self , session_id = "test-reflect-001" , ** extra ):
664668 return {"cwd" : self .tmpdir , "session_id" : session_id , ** extra }
665669
670+ def _set_reflect (self ):
671+ """Create .harness-reflect marker (simulates harness completion)."""
672+ (self .root / ".harness-reflect" ).touch ()
673+
666674 def test_no_harness_root_is_noop (self ):
667675 """When harness-tasks.json doesn't exist, hook is a complete no-op."""
668676 code , stdout , stderr = run_hook (REFLECT_HOOK , self ._payload ())
669677 self .assertEqual (code , 0 )
670678 self .assertEqual (stdout , "" , "Should produce no output when harness never used" )
671679
672- def test_harness_active_defers (self ):
673- """When .harness-active exists, hook defers to harness-stop.py ."""
680+ def test_harness_active_no_reflect_marker (self ):
681+ """When .harness-active exists but no .harness-reflect , hook is no-op ."""
674682 write_tasks (self .root , [
675683 {"id" : "t1" , "status" : "pending" , "depends_on" : []},
676684 ])
@@ -679,12 +687,24 @@ def test_harness_active_defers(self):
679687 self .assertEqual (code , 0 )
680688 self .assertEqual (stdout , "" , "Should not self-reflect while harness is active" )
681689
690+ def test_stale_tasks_without_reflect_marker_is_noop (self ):
691+ """Stale harness-tasks.json without .harness-reflect does NOT trigger (fixes false positive)."""
692+ write_tasks (self .root , [
693+ {"id" : "t1" , "status" : "completed" },
694+ ])
695+ deactivate (self .root )
696+ # No .harness-reflect marker — this is a stale file from a previous run
697+ code , stdout , _ = run_hook (REFLECT_HOOK , self ._payload (session_id = "test-stale" ))
698+ self .assertEqual (code , 0 )
699+ self .assertEqual (stdout , "" , "Stale harness-tasks.json should NOT trigger self-reflect" )
700+
682701 def test_harness_completed_triggers_reflection (self ):
683- """When harness-tasks.json exists but . harness-active removed , triggers self-reflection."""
702+ """When . harness-reflect marker exists , triggers self-reflection."""
684703 write_tasks (self .root , [
685704 {"id" : "t1" , "status" : "completed" },
686705 ])
687706 deactivate (self .root )
707+ self ._set_reflect ()
688708 sid = "test-reflect-trigger"
689709 code , stdout , _ = run_hook (REFLECT_HOOK , self ._payload (session_id = sid ))
690710 self .assertEqual (code , 0 )
@@ -696,6 +716,7 @@ def test_counter_increments(self):
696716 """Each invocation increments the iteration counter."""
697717 write_tasks (self .root , [{"id" : "t1" , "status" : "completed" }])
698718 deactivate (self .root )
719+ self ._set_reflect ()
699720 sid = "test-reflect-counter"
700721
701722 # First call: iteration 1
@@ -708,10 +729,11 @@ def test_counter_increments(self):
708729 data = json .loads (stdout )
709730 self .assertIn ("2/5" , data ["reason" ])
710731
711- def test_max_iterations_allows_stop (self ):
712- """After max iterations, hook allows stop (no output) ."""
732+ def test_max_iterations_allows_stop_and_cleans_marker (self ):
733+ """After max iterations, hook allows stop and removes .harness-reflect ."""
713734 write_tasks (self .root , [{"id" : "t1" , "status" : "completed" }])
714735 deactivate (self .root )
736+ self ._set_reflect ()
715737 sid = "test-reflect-max"
716738
717739 # Write counter at max
@@ -721,11 +743,16 @@ def test_max_iterations_allows_stop(self):
721743 code , stdout , _ = run_hook (REFLECT_HOOK , self ._payload (session_id = sid ))
722744 self .assertEqual (code , 0 )
723745 self .assertEqual (stdout , "" , "Should allow stop after max iterations" )
746+ self .assertFalse (
747+ (self .root / ".harness-reflect" ).exists (),
748+ ".harness-reflect should be cleaned up after max iterations" ,
749+ )
724750
725751 def test_disabled_via_env (self ):
726752 """REFLECT_MAX_ITERATIONS=0 disables self-reflection."""
727753 write_tasks (self .root , [{"id" : "t1" , "status" : "completed" }])
728754 deactivate (self .root )
755+ self ._set_reflect ()
729756 code , stdout , _ = run_hook (
730757 REFLECT_HOOK ,
731758 self ._payload (session_id = "test-reflect-disabled" ),
@@ -738,14 +765,15 @@ def test_no_session_id_is_noop(self):
738765 """Missing session_id makes hook a no-op."""
739766 write_tasks (self .root , [{"id" : "t1" , "status" : "completed" }])
740767 deactivate (self .root )
768+ self ._set_reflect ()
741769 code , stdout , _ = run_hook (REFLECT_HOOK , {"cwd" : self .tmpdir })
742770 self .assertEqual (code , 0 )
743771 self .assertEqual (stdout , "" )
744772
745773 def test_empty_stdin_no_crash (self ):
746774 """Empty stdin doesn't crash."""
747775 write_tasks (self .root , [{"id" : "t1" , "status" : "completed" }])
748- activate ( self .root )
776+ self ._set_reflect ( )
749777 proc = subprocess .run (
750778 [sys .executable , str (REFLECT_HOOK )],
751779 input = "" ,
@@ -760,6 +788,7 @@ def test_harness_state_root_env_respected(self):
760788 """HARNESS_STATE_ROOT env var is used for root discovery."""
761789 write_tasks (self .root , [{"id" : "t1" , "status" : "completed" }])
762790 deactivate (self .root )
791+ self ._set_reflect ()
763792 sid = "test-reflect-env"
764793 code , stdout , _ = run_hook (
765794 REFLECT_HOOK ,
0 commit comments