@@ -362,4 +362,37 @@ static function () use ( &$clock_index ): float {
362362abandoned_cleanup_assert (0 === count ($ zero_yield_equivalent ->calls ), 'zero-yield stop avoids advancing into later active/no-signal stages ' );
363363abandoned_cleanup_assert (0 === count ($ zero_yield_abilities ['datamachine-code/workspace-worktree-prune ' ]->calls ), 'zero-yield stop skips prune while continuation remains ' );
364364
365+ $ abandoned_zero_yield_finalized = new AbandonedCleanupQueuedAbility (
366+ array (
367+ array (
368+ 'mode ' => 'finalized ' ,
369+ 'summary ' => array ( 'inspected ' => 10 , 'written ' => 0 ),
370+ 'pagination ' => array ( 'offset ' => 0 , 'limit ' => 10 , 'scanned ' => 10 , 'partial ' => true , 'complete ' => false , 'next_offset ' => 10 , 'total ' => 30 ),
371+ ),
372+ )
373+ );
374+ $ abandoned_zero_yield_equivalent = new AbandonedCleanupFakeAbility ('equivalent_clean ' , array ( 'inspected ' => 10 , 'written ' => 1 ), array ( 'complete ' => true ));
375+ $ abandoned_zero_yield_abilities = array (
376+ 'datamachine-code/workspace-worktree-reconcile-metadata ' => new AbandonedCleanupFakeAbility ('reconcile_metadata ' , array (), array ( 'complete ' => true )),
377+ 'datamachine-code/workspace-worktree-active-no-signal-finalized-apply ' => $ abandoned_zero_yield_finalized ,
378+ 'datamachine-code/workspace-worktree-active-no-signal-equivalent-clean-apply ' => $ abandoned_zero_yield_equivalent ,
379+ 'datamachine-code/workspace-worktree-active-no-signal-merged-apply ' => new AbandonedCleanupFakeAbility ('merged ' , array (), array ( 'complete ' => true )),
380+ 'datamachine-code/workspace-worktree-active-no-signal-remote-clean-apply ' => new AbandonedCleanupFakeAbility ('remote_clean ' , array (), array ( 'complete ' => true )),
381+ 'datamachine-code/workspace-worktree-bounded-cleanup-eligible-apply ' => new AbandonedCleanupFakeAbility ('bounded ' , array ( 'processed ' => 0 , 'removed ' => 0 ), array ( 'complete ' => true )),
382+ 'datamachine-code/workspace-worktree-prune ' => new AbandonedCleanupFakeAbility ('prune ' ),
383+ );
384+ $ orchestrator = new DataMachineCode \Workspace \WorkspaceAbandonedCleanupOrchestrator (
385+ static fn ( string $ name ) => $ abandoned_zero_yield_abilities [ $ name ] ?? null ,
386+ static fn (): float => 1000.0
387+ );
388+ $ abandoned_zero_yield_result = $ orchestrator ->run (array ( 'apply ' => true , 'limit ' => 10 , 'passes ' => 3 , 'until_budget ' => '300s ' ));
389+ abandoned_cleanup_assert (! is_wp_error ($ abandoned_zero_yield_result ), 'abandoned zero-yield result succeeds ' );
390+ abandoned_cleanup_assert ('abandoned_worktree_cleanup ' === $ abandoned_zero_yield_result ['mode ' ], 'abandoned zero-yield keeps abandoned mode ' );
391+ abandoned_cleanup_assert ('no_progress_in_stage ' === $ abandoned_zero_yield_result ['continuation ' ]['reason ' ], 'abandoned zero-yield continuation uses no-progress reason ' );
392+ abandoned_cleanup_assert ('no_progress_in_stage ' === ( $ abandoned_zero_yield_result ['summary ' ]['stop_reason ' ] ?? null ), 'abandoned zero-yield summary exposes stop reason ' );
393+ abandoned_cleanup_assert (str_contains ((string ) $ abandoned_zero_yield_result ['continuation ' ]['recommendation ' ], 'Stop this drain ' ), 'abandoned zero-yield continuation recommends stopping ' );
394+ abandoned_cleanup_assert (str_contains ((string ) $ abandoned_zero_yield_result ['continuation ' ]['next_command ' ], ' worktree abandoned --apply --stage=finalized --offset=10 ' ), 'abandoned zero-yield continuation resumes same stage next page ' );
395+ abandoned_cleanup_assert (0 === count ($ abandoned_zero_yield_equivalent ->calls ), 'abandoned zero-yield stop avoids advancing into later active/no-signal stages ' );
396+ abandoned_cleanup_assert (0 === count ($ abandoned_zero_yield_abilities ['datamachine-code/workspace-worktree-prune ' ]->calls ), 'abandoned zero-yield stop skips prune while continuation remains ' );
397+
365398fwrite (STDOUT , 'abandoned cleanup orchestrator smoke passed ' . PHP_EOL );
0 commit comments