Skip to content

Commit 2d21f7e

Browse files
authored
fix: quiet cleanup status child output (#434)
1 parent bb6dae9 commit 2d21f7e

4 files changed

Lines changed: 100 additions & 30 deletions

File tree

inc/Cleanup/CleanupRunEvidenceStoreInterface.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ interface CleanupRunEvidenceStoreInterface {
2121
*
2222
* @param string $run_id Stable cleanup run identifier.
2323
* @param bool $include_evidence Whether to include raw evidence records.
24+
* @param bool $include_details Whether to include verbose diagnostic details.
2425
* @return array<string,mixed>|\WP_Error
2526
*/
26-
public function read( string $run_id, bool $include_evidence = false ): array|\WP_Error;
27+
public function read( string $run_id, bool $include_evidence = false, bool $include_details = false ): array|\WP_Error;
2728
}

inc/Cleanup/DataMachineJobCleanupRunEvidenceStore.php

Lines changed: 77 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@ class DataMachineJobCleanupRunEvidenceStore implements CleanupRunEvidenceStoreIn
1616
*
1717
* @param string $run_id Stable cleanup run identifier.
1818
* @param bool $include_evidence Whether to include raw evidence records.
19+
* @param bool $include_details Whether to include verbose diagnostic details.
1920
* @return array<string,mixed>|\WP_Error
2021
*/
21-
public function read( string $run_id, bool $include_evidence = false ): array|\WP_Error {
22+
public function read( string $run_id, bool $include_evidence = false, bool $include_details = false ): array|\WP_Error {
2223
$job_id = $this->cleanup_run_job_id( $run_id );
2324
if ( $job_id <= 0 ) {
2425
return new \WP_Error( 'invalid_cleanup_run_id', 'Cleanup run id must be a numeric job id or cleanup-run-<job_id>.', array( 'status' => 400 ) );
@@ -34,21 +35,26 @@ public function read( string $run_id, bool $include_evidence = false ): array|\W
3435
$aggregate = $this->aggregate_cleanup_child_jobs( $child_jobs );
3536
$children = $aggregate['children'];
3637
$state = $this->cleanup_run_state( (string) ( $job['status'] ?? '' ), $children );
37-
$output = array(
38-
'success' => true,
39-
'state' => $state,
40-
'run_id' => $this->cleanup_run_id( $job_id ),
41-
'job_id' => $job_id,
42-
'status' => in_array( $state, array( 'children_processing', 'partial_failed' ), true ) ? $state : ( $job['status'] ?? '' ),
43-
'created_at' => $job['created_at'] ?? '',
44-
'completed_at' => $job['completed_at'] ?? '',
45-
'artifact_cleanup' => $aggregate['artifact_cleanup'],
46-
'cleanup_items' => $aggregate['cleanup_items'],
47-
'children' => $children,
38+
39+
$children_for_output = ( $include_evidence || $include_details ) ? $children : $this->summarize_cleanup_children( $children );
40+
$output = array(
41+
'success' => true,
42+
'state' => $state,
43+
'run_id' => $this->cleanup_run_id( $job_id ),
44+
'job_id' => $job_id,
45+
'status' => in_array( $state, array( 'children_processing', 'partial_failed' ), true ) ? $state : ( $job['status'] ?? '' ),
46+
'created_at' => $job['created_at'] ?? '',
47+
'parent_completed_at' => $job['completed_at'] ?? '',
48+
'artifact_cleanup' => $aggregate['artifact_cleanup'],
49+
'cleanup_items' => $aggregate['cleanup_items'],
50+
'children' => $children_for_output,
4851
);
4952

53+
$output_aggregate = $aggregate;
54+
$output_aggregate['children'] = $children_for_output;
55+
5056
if ( isset( $engine_data['system_task_result'] ) && is_array( $engine_data['system_task_result'] ) ) {
51-
$engine_data['system_task_result'] = $this->with_cleanup_aggregate_report( $engine_data['system_task_result'], $aggregate );
57+
$engine_data['system_task_result'] = $this->with_cleanup_aggregate_report( $engine_data['system_task_result'], $output_aggregate );
5258
}
5359

5460
if ( $include_evidence ) {
@@ -105,15 +111,18 @@ private function aggregate_cleanup_child_jobs( array $child_jobs ): array {
105111
'failed_by_reason' => array(),
106112
),
107113
'children' => array(
108-
'batch_job_ids' => array(),
109-
'chunk_job_ids' => array(),
110-
'processing' => 0,
111-
'completed' => 0,
112-
'failed' => 0,
113-
'running' => 0,
114-
'total' => 0,
115-
'statuses' => array(),
116-
'job_ids' => array(),
114+
'batch_job_ids' => array(),
115+
'chunk_job_ids' => array(),
116+
'pending_job_ids' => array(),
117+
'processing_job_ids' => array(),
118+
'failed_job_ids' => array(),
119+
'processing' => 0,
120+
'completed' => 0,
121+
'failed' => 0,
122+
'running' => 0,
123+
'total' => 0,
124+
'statuses' => array(),
125+
'job_ids' => array(),
117126
),
118127
);
119128

@@ -126,6 +135,13 @@ private function aggregate_cleanup_child_jobs( array $child_jobs ): array {
126135
++$summary['children']['total'];
127136
if ( $child_job_id > 0 ) {
128137
$summary['children']['job_ids'][] = $child_job_id;
138+
if ( 'pending' === $status ) {
139+
$summary['children']['pending_job_ids'][] = $child_job_id;
140+
} elseif ( 'processing' === $status ) {
141+
$summary['children']['processing_job_ids'][] = $child_job_id;
142+
} elseif ( str_starts_with( $status, 'failed' ) ) {
143+
$summary['children']['failed_job_ids'][] = $child_job_id;
144+
}
129145
}
130146

131147
$this->count_cleanup_child_status( $summary['children'], $status );
@@ -160,12 +176,46 @@ private function aggregate_cleanup_child_jobs( array $child_jobs ): array {
160176
$summary['cleanup_items']['freed_human'] = $this->format_bytes( $summary['cleanup_items']['bytes_reclaimed'] );
161177
$summary['children']['batch_job_ids'] = array_values( array_unique( $summary['children']['batch_job_ids'] ) );
162178
$summary['children']['chunk_job_ids'] = array_values( array_unique( $summary['children']['chunk_job_ids'] ) );
179+
$summary['children']['pending_job_ids'] = array_values( array_unique( $summary['children']['pending_job_ids'] ) );
180+
$summary['children']['processing_job_ids'] = array_values( array_unique( $summary['children']['processing_job_ids'] ) );
181+
$summary['children']['failed_job_ids'] = array_values( array_unique( $summary['children']['failed_job_ids'] ) );
163182
$summary['children']['job_ids'] = array_values( array_unique( $summary['children']['job_ids'] ) );
164183
$summary['children']['running'] = (int) $summary['children']['processing'];
165184

166185
return $summary;
167186
}
168187

188+
/**
189+
* Return operator-focused child status without unbounded diagnostic ID lists.
190+
*
191+
* @param array<string,mixed> $children Full child aggregate.
192+
* @return array<string,mixed>
193+
*/
194+
private function summarize_cleanup_children( array $children ): array {
195+
$limit = 10;
196+
$batch_ids = (array) ( $children['batch_job_ids'] ?? array() );
197+
$chunk_ids = (array) ( $children['chunk_job_ids'] ?? array() );
198+
$pending = (array) ( $children['pending_job_ids'] ?? array() );
199+
$processing = (array) ( $children['processing_job_ids'] ?? array() );
200+
201+
return array(
202+
'processing' => (int) ( $children['processing'] ?? 0 ),
203+
'completed' => (int) ( $children['completed'] ?? 0 ),
204+
'failed' => (int) ( $children['failed'] ?? 0 ),
205+
'running' => (int) ( $children['running'] ?? 0 ),
206+
'total' => (int) ( $children['total'] ?? 0 ),
207+
'statuses' => (array) ( $children['statuses'] ?? array() ),
208+
'batch_total' => count( $batch_ids ),
209+
'chunk_total' => count( $chunk_ids ),
210+
'failed_job_ids' => (array) ( $children['failed_job_ids'] ?? array() ),
211+
'pending_job_ids' => array_slice( $pending, 0, $limit ),
212+
'processing_job_ids' => array_slice( $processing, 0, $limit ),
213+
'pending_truncated' => count( $pending ) > $limit,
214+
'processing_truncated' => count( $processing ) > $limit,
215+
'diagnostic_job_id_lists' => 'Re-run status with --verbose or use cleanup evidence for full child job IDs.',
216+
);
217+
}
218+
169219
/**
170220
* Merge one chunk task result into aggregate cleanup item counters.
171221
*
@@ -440,11 +490,11 @@ private function cleanup_run_job_id( string $run_id ): int {
440490
* @return string
441491
*/
442492
private function format_bytes( int $bytes ): string {
443-
$bytes = max( 0, $bytes );
444-
$units = array( 'B', 'KiB', 'MiB', 'GiB', 'TiB' );
445-
$max_unit = count( $units ) - 1;
446-
$value = (float) $bytes;
447-
$unit = 0;
493+
$bytes = max( 0, $bytes );
494+
$units = array( 'B', 'KiB', 'MiB', 'GiB', 'TiB' );
495+
$max_unit = count( $units ) - 1;
496+
$value = (float) $bytes;
497+
$unit = 0;
448498
while ( $value >= 1024 && $unit < $max_unit ) {
449499
$value /= 1024;
450500
++$unit;

inc/Cli/Commands/WorkspaceCommand.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,9 @@ public function adopt_repo( array $args, array $assoc_args ): void {
327327
* without disabling the bounded scan. Useful when you want a small slice
328328
* audited with full safety information.
329329
*
330+
* [--verbose]
331+
* : Include full diagnostic child job ID lists in task-backed cleanup status output.
332+
*
330333
* [--format=<format>]
331334
* : Output format.
332335
* ---
@@ -627,7 +630,7 @@ private function render_worktree_emergency_cleanup_result_from_ability( array|\W
627630
}
628631

629632
private function render_cleanup_run_status( int $job_id, array $assoc_args, bool $evidence ): void {
630-
$output = $this->cleanup_run_evidence_store()->read( $this->cleanup_run_id( $job_id ), $evidence );
633+
$output = $this->cleanup_run_evidence_store()->read( $this->cleanup_run_id( $job_id ), $evidence, ! empty( $assoc_args['verbose'] ) );
631634
if ( $output instanceof \WP_Error ) {
632635
WP_CLI::error( $output->get_error_message() );
633636
return;

tests/smoke-worktree-cleanup-cli.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -666,14 +666,30 @@ public function execute( array $input ): array {
666666
$status_json = json_decode( WP_CLI::$logs[0] ?? '', true );
667667
datamachine_code_cleanup_assert( 'children_processing' === ( $status_json['state'] ?? '' ), 'cleanup status stays active while child batch is processing' );
668668
datamachine_code_cleanup_assert( 'children_processing' === ( $status_json['status'] ?? '' ), 'cleanup status does not report parent completed while children run' );
669-
datamachine_code_cleanup_assert( array( 125 ) === ( $status_json['children']['batch_job_ids'] ?? array() ), 'cleanup status reports child batch job ids' );
669+
datamachine_code_cleanup_assert( '2026-05-03 00:10:00' === ( $status_json['parent_completed_at'] ?? '' ), 'cleanup status labels parent scheduler completion separately' );
670+
datamachine_code_cleanup_assert( ! isset( $status_json['completed_at'] ), 'cleanup status does not expose parent completion as run completion' );
671+
datamachine_code_cleanup_assert( ! isset( $status_json['children']['job_ids'] ), 'cleanup status omits full child job ids by default' );
672+
datamachine_code_cleanup_assert( ! isset( $status_json['children']['chunk_job_ids'] ), 'cleanup status omits full child chunk job ids by default' );
673+
datamachine_code_cleanup_assert( 1 === (int) ( $status_json['children']['batch_total'] ?? 0 ), 'cleanup status reports child batch totals by default' );
674+
datamachine_code_cleanup_assert( 2 === (int) ( $status_json['children']['chunk_total'] ?? 0 ), 'cleanup status reports child chunk totals by default' );
675+
datamachine_code_cleanup_assert( array( 125 ) === ( $status_json['children']['processing_job_ids'] ?? array() ), 'cleanup status reports bounded processing job ids by default' );
676+
datamachine_code_cleanup_assert( array( 127 ) === ( $status_json['children']['failed_job_ids'] ?? array() ), 'cleanup status reports failed job ids by default' );
670677
datamachine_code_cleanup_assert( 1 === (int) ( $status_json['children']['running'] ?? 0 ), 'cleanup status summarizes running child jobs' );
671678
datamachine_code_cleanup_assert( ! isset( $status_json['flow_id'] ), 'cleanup status is not linked to a flow id' );
672679
datamachine_code_cleanup_assert( 4 === (int) ( $status_json['artifact_cleanup']['planned_rows'] ?? 0 ), 'cleanup status aggregates artifact planned rows from child chunks' );
673680
datamachine_code_cleanup_assert( 4096 === (int) ( $status_json['artifact_cleanup']['bytes_reclaimed'] ?? 0 ), 'cleanup status aggregates artifact bytes from child chunks' );
674681
datamachine_code_cleanup_assert( 4 === (int) ( $status_json['cleanup_items']['planned_rows'] ?? 0 ), 'cleanup status aggregates planned rows from DB-backed cleanup item evidence' );
675682
datamachine_code_cleanup_assert( 4096 === (int) ( $status_json['cleanup_items']['bytes_reclaimed'] ?? 0 ), 'cleanup status reconstructs reclaimed bytes from cleanup item evidence' );
676683
datamachine_code_cleanup_assert( '4.0 KiB' === ( $status_json['system_task_result']['report']['freed_human'] ?? '' ), 'cleanup status replaces pending child job freed placeholder' );
684+
datamachine_code_cleanup_assert( ! isset( $status_json['system_task_result']['children']['job_ids'] ), 'cleanup status system task result omits full child job ids by default' );
685+
686+
WP_CLI::$logs = array();
687+
WP_CLI::$successes = array();
688+
$command->cleanup( array( 'status', 'cleanup-run-123' ), array( 'format' => 'json', 'verbose' => true ) );
689+
$verbose_status_json = json_decode( WP_CLI::$logs[0] ?? '', true );
690+
datamachine_code_cleanup_assert( array( 124, 125, 126, 127 ) === ( $verbose_status_json['children']['job_ids'] ?? array() ), 'cleanup status --verbose exposes full child job ids' );
691+
datamachine_code_cleanup_assert( array( 125 ) === ( $verbose_status_json['children']['batch_job_ids'] ?? array() ), 'cleanup status --verbose exposes child batch job ids' );
692+
datamachine_code_cleanup_assert( array( 126, 127 ) === ( $verbose_status_json['children']['chunk_job_ids'] ?? array() ), 'cleanup status --verbose exposes child chunk job ids' );
677693

678694
WP_CLI::$logs = array();
679695
WP_CLI::$successes = array();

0 commit comments

Comments
 (0)