@@ -230,11 +230,15 @@ function datamachine_code_cleanup_run_assert( bool $condition, string $message )
230230
231231$ apply = $ service ->apply ($ plan ['run_id ' ]);
232232datamachine_code_cleanup_run_assert (! is_wp_error ($ apply ), 'apply succeeds ' );
233- datamachine_code_cleanup_run_assert ('needs_resume ' === (string ) ( $ apply ['status ' ] ?? '' ), 'apply pauses after bounded worktree-removal batch ' );
233+ datamachine_code_cleanup_run_assert ('completed ' === (string ) ( $ apply ['status ' ] ?? '' ), 'apply drains worktree rows up to the default limit ' );
234+ datamachine_code_cleanup_run_assert (4 === (int ) ( $ apply ['processed ' ] ?? 0 ), 'apply reports processed row count ' );
235+ datamachine_code_cleanup_run_assert (2 === (int ) ( $ apply ['applied ' ] ?? 0 ), 'apply reports applied row count ' );
236+ datamachine_code_cleanup_run_assert (2 === (int ) ( $ apply ['skipped ' ] ?? 0 ), 'apply reports skipped row count ' );
237+ datamachine_code_cleanup_run_assert (null === ( $ apply ['next_command ' ] ?? null ), 'completed apply omits next command ' );
234238
235239$ evidence = $ service ->evidence ($ plan ['run_id ' ]);
236240datamachine_code_cleanup_run_assert (2 === (int ) ( $ evidence ['summary ' ]['items_by_status ' ]['applied ' ] ?? 0 ), 'evidence reflects applied rows ' );
237- datamachine_code_cleanup_run_assert (1 === (int ) ( $ evidence ['summary ' ]['items_by_status ' ]['skipped ' ] ?? 0 ), 'evidence reflects skipped rows from first bounded batch ' );
241+ datamachine_code_cleanup_run_assert (2 === (int ) ( $ evidence ['summary ' ]['items_by_status ' ]['skipped ' ] ?? 0 ), 'evidence reflects skipped rows from bounded batch ' );
238242datamachine_code_cleanup_run_assert (35 === (int ) ( $ evidence ['summary ' ]['bytes_reclaimed ' ] ?? 0 ), 'evidence aggregates reclaimed bytes ' );
239243datamachine_code_cleanup_run_assert (1 === (int ) ( $ evidence ['remaining_work_summary ' ]['applied_by_type ' ]['artifact_cleanup ' ]['count ' ] ?? 0 ), 'evidence groups applied artifact rows ' );
240244datamachine_code_cleanup_run_assert (15 === (int ) ( $ evidence ['remaining_work_summary ' ]['applied_by_type ' ]['artifact_cleanup ' ]['bytes_reclaimed ' ] ?? 0 ), 'evidence reports artifact bytes reclaimed ' );
@@ -244,9 +248,6 @@ function datamachine_code_cleanup_run_assert( bool $condition, string $message )
244248datamachine_code_cleanup_run_assert (str_contains ((string ) wp_json_encode ($ evidence ['remaining_work_summary ' ]['recommended_commands ' ]), 'workspace worktree reconcile-metadata --dry-run --limit=25 --offset=0 --until-budget=30s --format=json ' ), 'summary recommends bounded next DMC commands ' );
245249datamachine_code_cleanup_run_assert (str_contains ((string ) wp_json_encode ($ evidence ['remaining_work_summary ' ]['recommended_commands ' ]), 'apply_destructive ' ), 'summary labels destructive apply commands separately from review commands ' );
246250
247- $ done = $ service ->resume ($ plan ['run_id ' ]);
248- datamachine_code_cleanup_run_assert ('completed ' === (string ) ( $ done ['status ' ] ?? '' ), 'resume completes final bounded worktree-removal batch ' );
249-
250251$ bounded_workspace = new DataMachineCodeCleanupRunFakeWorkspace ();
251252$ bounded_service = new \DataMachineCode \Workspace \CleanupRunService ($ repo , $ bounded_workspace );
252253$ bounded_plan = $ bounded_service ->plan (array ( 'mode ' => 'retention ' ));
@@ -260,6 +261,24 @@ function datamachine_code_cleanup_run_assert( bool $condition, string $message )
260261datamachine_code_cleanup_run_assert (1 === count ($ bounded_workspace ->artifact_calls ), 'bounded apply only runs artifact cleanup first ' );
261262datamachine_code_cleanup_run_assert (0 === count ($ bounded_workspace ->worktree_calls ), 'bounded apply defers worktree cleanup until artifacts drain ' );
262263
264+ $ multi_workspace = new DataMachineCodeCleanupRunFakeWorkspace ();
265+ $ multi_service = new \DataMachineCode \Workspace \CleanupRunService ($ repo , $ multi_workspace );
266+ $ multi_plan = $ multi_service ->plan (array ( 'mode ' => 'retention ' ));
267+ datamachine_code_cleanup_run_assert (! is_wp_error ($ multi_plan ), 'multi-row resume plan succeeds ' );
268+ $ multi_apply = $ multi_service ->apply ($ multi_plan ['run_id ' ], array ( 'limit ' => 2 ));
269+ datamachine_code_cleanup_run_assert ('needs_resume ' === (string ) ( $ multi_apply ['status ' ] ?? '' ), 'multi-row apply pauses after artifact rows when worktrees remain ' );
270+ datamachine_code_cleanup_run_assert (2 === (int ) ( $ multi_apply ['processed ' ] ?? 0 ), 'multi-row apply reports processed artifact rows ' );
271+ datamachine_code_cleanup_run_assert (str_contains ((string ) ( $ multi_apply ['next_command ' ] ?? '' ), 'workspace cleanup resume ' ), 'multi-row apply exposes top-level next command ' );
272+ $ multi_resume = $ multi_service ->resume ($ multi_plan ['run_id ' ], array ( 'limit ' => 2 ));
273+ datamachine_code_cleanup_run_assert ('completed ' === (string ) ( $ multi_resume ['status ' ] ?? '' ), 'resume drains multiple worktree rows up to the requested limit ' );
274+ datamachine_code_cleanup_run_assert ('worktree_removal ' === (string ) ( $ multi_resume ['batch ' ]['type ' ] ?? '' ), 'multi-row resume reports worktree batch type ' );
275+ datamachine_code_cleanup_run_assert (2 === (int ) ( $ multi_resume ['processed ' ] ?? 0 ), 'multi-row resume reports processed worktree rows ' );
276+ datamachine_code_cleanup_run_assert (1 === (int ) ( $ multi_resume ['applied ' ] ?? 0 ), 'multi-row resume reports applied worktree rows ' );
277+ datamachine_code_cleanup_run_assert (1 === (int ) ( $ multi_resume ['skipped ' ] ?? 0 ), 'multi-row resume reports skipped worktree rows ' );
278+ datamachine_code_cleanup_run_assert (null === ( $ multi_resume ['next_command ' ] ?? null ), 'multi-row resume omits next command when no rows remain ' );
279+ datamachine_code_cleanup_run_assert (1 === count ($ multi_workspace ->worktree_calls ), 'multi-row resume applies worktree rows in one safety-revalidated call ' );
280+ datamachine_code_cleanup_run_assert (2 === count ($ multi_workspace ->worktree_calls [0 ]['apply_plan ' ]['candidates ' ] ?? array ()), 'multi-row resume sends both eligible worktree candidates ' );
281+
263282$ applying_repo = new \DataMachineCode \Storage \CleanupRunRepository ();
264283$ applying_plan = ( new \DataMachineCode \Workspace \CleanupRunService ($ applying_repo , new DataMachineCodeCleanupRunFakeWorkspace ()) )->plan (array ( 'mode ' => 'retention ' ));
265284datamachine_code_cleanup_run_assert (! is_wp_error ($ applying_plan ), 'applying status plan succeeds ' );
0 commit comments