@@ -195,6 +195,34 @@ def signoff_batch(cfg: Config, bundles: list[Path]) -> None:
195195 self .assertEqual (set (results ), {"BATCH1" , "BATCH2" })
196196 self .assertTrue (all (s == state .COMPLETE for s in results .values ()))
197197
198+ def test_batch_iterate_plan_then_complete (self ) -> None :
199+ # iterate-plan re-opens a batch member to UNPLANNED (archiving its attempt to
200+ # iteration-v1/); the sweep must keep looping so a LATER pass re-plans + rebuilds
201+ # it, rather than break at UNPLANNED when nothing is awaiting sign-off (#105).
202+ iterated = {"done" : False }
203+
204+ def signoff_batch (cfg : Config , bundles : list [Path ]) -> None :
205+ for d in bundles :
206+ summ = d / "SUMMARY.md"
207+ if d .name == "issue_BATCH1" and not iterated ["done" ]:
208+ iterated ["done" ] = True
209+ (d / leaves .SIGNOFF_DECISION ).write_text ("iterate-plan\n " , encoding = "utf-8" )
210+ continue
211+ summ .write_text (summ .read_text ().replace ("- [ ]" , "- [x]" ), encoding = "utf-8" )
212+ (d / leaves .SIGNOFF_DECISION ).write_text ("accept\n " , encoding = "utf-8" )
213+
214+ orig = leaves .run_signoff_batch
215+ leaves .run_signoff_batch = signoff_batch
216+ try :
217+ results = flow .flow_batch (self .cfg , today = "2026-06-04" , max_passes = 6 )
218+ finally :
219+ leaves .run_signoff_batch = orig
220+ self .assertTrue (iterated ["done" ])
221+ self .assertEqual (set (results ), {"BATCH1" , "BATCH2" })
222+ self .assertTrue (all (s == state .COMPLETE for s in results .values ()))
223+ # the re-opened bundle re-planned, rebuilt, and preserved its first attempt
224+ self .assertTrue ((self .cfg .bundle ("BATCH1" ) / "iteration-v1" ).is_dir ())
225+
198226 def test_batch_signoff_chunks_into_sessions (self ) -> None :
199227 # The cheap-first queue is signed off in ONE session per chunk of
200228 # SIGNOFF_BATCH_SIZE (=5): six halted bundles → sessions of 5 then 1, all
0 commit comments