@@ -2868,6 +2868,10 @@ private function run_worktree_abandoned_orchestration( array $assoc_args ): arra
28682868 $ result ['summary ' ]['would_reconcile ' ] = (int ) ( $ reconcile ['summary ' ]['proposed ' ] ?? 0 );
28692869
28702870 if ( $ this ->worktree_abandoned_stage_incomplete ($ reconcile ) ) {
2871+ $ bounded = $ this ->run_worktree_abandoned_bounded_apply ($ abilities ['bounded_apply ' ], $ result , $ apply , $ force , $ limit , 'reconcile ' );
2872+ if ( is_wp_error ($ bounded ) ) {
2873+ return $ bounded ;
2874+ }
28712875 $ result ['evidence ' ]['budget_exhausted ' ] = $ this ->worktree_abandoned_budget_expired ($ deadline );
28722876 $ result ['continuation ' ] = $ this ->build_worktree_abandoned_continuation ('reconcile ' , $ reconcile , $ limit , $ passes , $ force , $ until_budget );
28732877 $ result ['next_commands ' ][] = (string ) $ result ['continuation ' ]['next_command ' ];
@@ -2930,32 +2934,22 @@ private function run_worktree_abandoned_orchestration( array $assoc_args ): arra
29302934 $ result ['summary ' ]['would_mark_cleanup_eligible ' ] += $ planned ;
29312935
29322936 if ( $ this ->worktree_abandoned_stage_incomplete ($ step ) ) {
2937+ $ bounded = $ this ->run_worktree_abandoned_bounded_apply ($ abilities ['bounded_apply ' ], $ result , $ apply , $ force , $ limit , $ step_stage );
2938+ if ( is_wp_error ($ bounded ) ) {
2939+ return $ bounded ;
2940+ }
29332941 $ result ['evidence ' ]['budget_exhausted ' ] = $ this ->worktree_abandoned_budget_expired ($ deadline );
29342942 $ result ['continuation ' ] = $ this ->build_worktree_abandoned_continuation ($ step_stage , $ step , $ limit , $ passes , $ force , $ until_budget );
29352943 $ result ['next_commands ' ][] = (string ) $ result ['continuation ' ]['next_command ' ];
29362944 break 2 ;
29372945 }
29382946 }
29392947
2940- $ bounded_input = array (
2941- 'dry_run ' => ! $ apply ,
2942- 'force ' => $ force ,
2943- 'limit ' => $ limit ,
2944- 'source ' => self ::CLEANUP_CLI_SOURCE ,
2945- );
2946- $ bounded = $ abilities ['bounded_apply ' ]->execute ($ bounded_input );
2948+ $ bounded = $ this ->run_worktree_abandoned_bounded_apply ($ abilities ['bounded_apply ' ], $ result , $ apply , $ force , $ limit , sprintf ('pass_%d ' , $ pass ));
29472949 if ( is_wp_error ($ bounded ) ) {
29482950 return $ bounded ;
29492951 }
29502952
2951- $ result ['steps ' ][ sprintf ('bounded_apply_pass_%d ' , $ pass ) ] = $ this ->summarize_worktree_abandoned_step ($ bounded );
2952-
2953- $ result ['summary ' ]['removed ' ] += (int ) ( $ bounded ['summary ' ]['removed ' ] ?? 0 );
2954- $ result ['summary ' ]['would_remove ' ] += (int ) ( $ bounded ['summary ' ]['would_remove ' ] ?? 0 );
2955- $ result ['summary ' ]['bytes_reclaimed ' ] += (int ) ( $ bounded ['summary ' ]['bytes_reclaimed ' ] ?? 0 );
2956-
2957- $ result ['blocked ' ] = $ this ->merge_worktree_abandoned_blockers ($ result ['blocked ' ], (array ) ( $ bounded ['skipped ' ] ?? array () ));
2958-
29592953 $ removed_or_would = (int ) ( $ bounded ['summary ' ]['removed ' ] ?? 0 ) + (int ) ( $ bounded ['summary ' ]['would_remove ' ] ?? 0 );
29602954 if ( 0 === $ pass_marked && 0 === $ removed_or_would ) {
29612955 break ;
@@ -3040,6 +3034,45 @@ private function worktree_abandoned_stage_incomplete( array $step ): bool {
30403034 return $ next_offset > $ current ;
30413035 }
30423036
3037+ /**
3038+ * Run bounded cleanup removal and merge its accounting into the abandoned result.
3039+ *
3040+ * @param object $ability Bounded cleanup ability.
3041+ * @param array<string,mixed> $result Abandoned cleanup result accumulator.
3042+ * @param bool $apply Whether apply mode is active.
3043+ * @param bool $force Whether force mode is active.
3044+ * @param int $limit Removal page size.
3045+ * @param string $step_label Step label suffix.
3046+ * @return array<string,mixed>|\WP_Error
3047+ */
3048+ private function run_worktree_abandoned_bounded_apply ( object $ ability , array &$ result , bool $ apply , bool $ force , int $ limit , string $ step_label ): array |\WP_Error {
3049+ $ execute = array ( $ ability , 'execute ' );
3050+ if ( ! is_callable ($ execute ) ) {
3051+ return new \WP_Error ('worktree_abandoned_ability_invalid ' , 'Worktree abandoned cleanup ability is not executable. ' , array ( 'status ' => 500 ));
3052+ }
3053+
3054+ $ bounded = $ execute (
3055+ array (
3056+ 'dry_run ' => ! $ apply ,
3057+ 'force ' => $ force ,
3058+ 'limit ' => $ limit ,
3059+ 'source ' => self ::CLEANUP_CLI_SOURCE ,
3060+ )
3061+ );
3062+ if ( is_wp_error ($ bounded ) ) {
3063+ return $ bounded ;
3064+ }
3065+
3066+ $ result ['steps ' ][ sprintf ('bounded_apply_%s ' , $ step_label ) ] = $ this ->summarize_worktree_abandoned_step ($ bounded );
3067+
3068+ $ result ['summary ' ]['removed ' ] += (int ) ( $ bounded ['summary ' ]['removed ' ] ?? 0 );
3069+ $ result ['summary ' ]['would_remove ' ] += (int ) ( $ bounded ['summary ' ]['would_remove ' ] ?? 0 );
3070+ $ result ['summary ' ]['bytes_reclaimed ' ] += (int ) ( $ bounded ['summary ' ]['bytes_reclaimed ' ] ?? 0 );
3071+ $ result ['blocked ' ] = $ this ->merge_worktree_abandoned_blockers ($ result ['blocked ' ], (array ) ( $ bounded ['skipped ' ] ?? array () ));
3072+
3073+ return $ bounded ;
3074+ }
3075+
30433076 /**
30443077 * Build continuation evidence for a partially drained abandoned-cleanup stage.
30453078 *
0 commit comments