diff --git a/inc/Cli/Commands/WorkspaceCommand.php b/inc/Cli/Commands/WorkspaceCommand.php index dd13e9f7..12a2c0bc 100644 --- a/inc/Cli/Commands/WorkspaceCommand.php +++ b/inc/Cli/Commands/WorkspaceCommand.php @@ -3519,7 +3519,7 @@ public function worktree( array $args, array $assoc_args ): void { private function run_worktree_abandoned_orchestration( array $assoc_args ): array|\WP_Error { $apply = ! empty($assoc_args['apply']); $force = ! empty($assoc_args['force']); - $limit = isset($assoc_args['limit']) ? max(1, min(100, (int) $assoc_args['limit'])) : 100; + $limit = isset($assoc_args['limit']) ? max(1, min(1000, (int) $assoc_args['limit'])) : 100; $passes = isset($assoc_args['passes']) ? max(1, min(25, (int) $assoc_args['passes'])) : 5; $offset = isset($assoc_args['offset']) ? max(0, (int) $assoc_args['offset']) : 0; $stage = isset($assoc_args['stage']) ? strtolower( (string) preg_replace('/[^a-zA-Z0-9_-]/', '', (string) $assoc_args['stage']) ) : 'reconcile'; @@ -3580,6 +3580,7 @@ private function run_worktree_abandoned_orchestration( array $assoc_args ): arra 'steps' => array(), 'blocked' => array(), 'summary' => array( + 'scanned' => 0, 'reconciled' => 0, 'marked_cleanup_eligible' => 0, 'would_mark_cleanup_eligible' => 0, @@ -3633,6 +3634,7 @@ private function run_worktree_abandoned_orchestration( array $assoc_args ): arra return $reconcile; } $result['steps']['reconcile_metadata'] = $this->summarize_worktree_abandoned_step($reconcile); + $result['summary']['scanned'] += (int) ( $result['steps']['reconcile_metadata']['inspected'] ?? 0 ); $result['summary']['reconciled'] = (int) ( $reconcile['summary']['written'] ?? 0 ); $result['summary']['would_reconcile'] = (int) ( $reconcile['summary']['proposed'] ?? 0 ); @@ -3696,6 +3698,7 @@ private function run_worktree_abandoned_orchestration( array $assoc_args ): arra $step_key = sprintf('%s_pass_%d', $key, $pass); $result['steps'][ $step_key ] = $this->summarize_worktree_abandoned_step($step); + $result['summary']['scanned'] += (int) ( $result['steps'][ $step_key ]['inspected'] ?? 0 ); $written = (int) ( $step['summary']['written'] ?? 0 ); $planned = (int) ( $step['summary']['planned'] ?? 0 ); $pass_marked += $apply ? $written : $planned; @@ -3837,6 +3840,7 @@ private function run_worktree_abandoned_bounded_apply( object $ability, array &$ $result['summary']['removed'] += (int) ( $bounded['summary']['removed'] ?? 0 ); $result['summary']['would_remove'] += (int) ( $bounded['summary']['would_remove'] ?? 0 ); $result['summary']['bytes_reclaimed'] += (int) ( $bounded['summary']['bytes_reclaimed'] ?? 0 ); + $result['summary']['scanned'] += (int) ( $result['steps'][ sprintf('bounded_apply_%s', $step_label) ]['inspected'] ?? 0 ); $result['blocked'] = $this->merge_worktree_abandoned_blockers($result['blocked'], (array) ( $bounded['skipped'] ?? array() )); return $bounded; @@ -4089,6 +4093,10 @@ private function render_worktree_abandoned_result( array $result, array $assoc_a 'metric' => 'applied', 'value' => ! empty($result['applied']) ? 'yes' : 'no', ), + array( + 'metric' => 'scanned', + 'value' => (string) ( $summary['scanned'] ?? 0 ), + ), array( 'metric' => 'reconciled', 'value' => (string) ( $summary['reconciled'] ?? 0 ), diff --git a/tests/smoke-worktree-cleanup-cli.php b/tests/smoke-worktree-cleanup-cli.php index a85c88c0..cceb88c7 100644 --- a/tests/smoke-worktree-cleanup-cli.php +++ b/tests/smoke-worktree-cleanup-cli.php @@ -1644,6 +1644,15 @@ public function execute( array $input ): array datamachine_code_cleanup_assert(2 === (int) ( $abandoned_json['summary']['removed'] ?? 0 ), 'abandoned summary reports removed rows from initial and post-classifier drains'); datamachine_code_cleanup_assert(2 === (int) ( $abandoned_json['summary']['blocked'] ?? 0 ), 'abandoned summary reports blocked rows'); datamachine_code_cleanup_assert(1 === (int) ( $abandoned_json['summary']['blocked_by_reason']['unpushed_commits'] ?? 0 ), 'abandoned preserves unpushed-commit blocker evidence'); + datamachine_code_cleanup_assert(16 === (int) ( $abandoned_json['summary']['scanned'] ?? 0 ), 'abandoned summary reports aggregate scanned rows across classifier and bounded cleanup stages'); + + WP_CLI::$logs = array(); + WP_CLI::$successes = array(); + $command->worktree(array( 'abandoned' ), array( 'apply' => true, 'force' => true, 'stage' => 'bounded', 'limit' => 500, 'passes' => 1, 'format' => 'json' )); + $abandoned_bulk_limit_json = json_decode(WP_CLI::$logs[0] ?? '', true); + datamachine_code_cleanup_assert(JSON_ERROR_NONE === json_last_error(), 'abandoned bulk-limit JSON output parses cleanly'); + datamachine_code_cleanup_assert(500 === (int) ( $abandoned_bulk_limit_json['limit'] ?? 0 ), 'abandoned honors operator bulk limit above the old 100-row cap'); + datamachine_code_cleanup_assert(500 === (int) ( $bounded_apply_ability->last_input['limit'] ?? 0 ), 'abandoned forwards operator bulk limit to bounded cleanup apply'); $bounded_apply_ability->extra_skipped = 30; WP_CLI::$logs = array();