Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 33 additions & 9 deletions inc/Cleanup/DataMachineJobCleanupRunEvidenceStore.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,12 @@ public function read( string $run_id, bool $include_evidence = false, bool $incl
return new \WP_Error( 'cleanup_run_not_found', sprintf( 'Cleanup run not found: %s', $this->cleanup_run_id( $job_id ) ), array( 'status' => 404 ) );
}

$engine_data = $this->normalize_engine_data( $job['engine_data'] ?? array() );
$child_jobs = $this->get_cleanup_run_descendant_jobs( $job_id );
$aggregate = $this->aggregate_cleanup_child_jobs( $child_jobs );
$children = $aggregate['children'];
$state = $this->cleanup_run_state( (string) ( $job['status'] ?? '' ), $children );
$engine_data = $this->normalize_engine_data( $job['engine_data'] ?? array() );
$parent_result = $this->extract_system_task_result( $engine_data );
$child_jobs = $this->get_cleanup_run_descendant_jobs( $job_id );
$aggregate = $this->aggregate_cleanup_child_jobs( $child_jobs );
$children = $aggregate['children'];
$state = $this->cleanup_run_state( (string) ( $job['status'] ?? '' ), $children );

$children_for_output = ( $include_evidence || $include_details ) ? $children : $this->summarize_cleanup_children( $children );
$output = array(
Expand All @@ -53,8 +54,8 @@ public function read( string $run_id, bool $include_evidence = false, bool $incl
$output_aggregate = $aggregate;
$output_aggregate['children'] = $children_for_output;

if ( isset( $engine_data['system_task_result'] ) && is_array( $engine_data['system_task_result'] ) ) {
$engine_data['system_task_result'] = $this->with_cleanup_aggregate_report( $engine_data['system_task_result'], $output_aggregate );
if ( array() !== $parent_result ) {
$engine_data['system_task_result'] = $this->with_cleanup_aggregate_report( $parent_result, $output_aggregate );
}

if ( $include_evidence ) {
Expand Down Expand Up @@ -130,7 +131,7 @@ private function aggregate_cleanup_child_jobs( array $child_jobs ): array {
$child_job_id = (int) ( $child['job_id'] ?? 0 );
$status = (string) ( $child['status'] ?? '' );
$engine_data = $this->normalize_engine_data( $child['engine_data'] ?? array() );
$result = is_array( $engine_data['system_task_result'] ?? null ) ? $engine_data['system_task_result'] : array();
$result = $this->extract_system_task_result( $engine_data );

++$summary['children']['total'];
if ( $child_job_id > 0 ) {
Expand Down Expand Up @@ -161,13 +162,16 @@ private function aggregate_cleanup_child_jobs( array $child_jobs ): array {
if ( 'worktree_cleanup_chunk' !== (string) ( $engine_data['task_type'] ?? '' ) && ! isset( $result['chunk_type'] ) ) {
continue;
}
if ( array() === $result ) {
continue;
}

if ( $child_job_id > 0 ) {
$summary['children']['chunk_job_ids'][] = $child_job_id;
}

$this->merge_cleanup_item_result( $summary['cleanup_items'], $result );
if ( 'artifacts' === (string) ( $result['chunk_type'] ?? '' ) ) {
if ( in_array( (string) ( $result['chunk_type'] ?? '' ), array( 'artifacts', 'artifact_discovery' ), true ) ) {
$this->merge_cleanup_item_result( $summary['artifact_cleanup'], $result );
}
}
Expand Down Expand Up @@ -373,6 +377,26 @@ private function normalize_engine_data( mixed $engine_data ): array {
return array();
}

/**
* Extract a task result from either nested packets or direct task engine data.
*
* @param array $engine_data Job engine data.
* @return array<string,mixed>
*/
private function extract_system_task_result( array $engine_data ): array {
if ( isset( $engine_data['system_task_result'] ) && is_array( $engine_data['system_task_result'] ) ) {
return $engine_data['system_task_result'];
}

foreach ( array( 'chunk_type', 'planned_count', 'applied_count', 'skipped_count', 'failed_count', 'bytes_reclaimed', 'report', 'job_backed' ) as $key ) {
if ( array_key_exists( $key, $engine_data ) ) {
return $engine_data;
}
}

return array();
}

/**
* Count a child job status into stable status buckets.
*
Expand Down
63 changes: 30 additions & 33 deletions tests/smoke-worktree-cleanup-cli.php
Original file line number Diff line number Diff line change
Expand Up @@ -472,20 +472,18 @@ public function execute( array $input ): array {
'source' => 'system',
'status' => 'completed',
'engine_data' => array(
'task_type' => 'worktree_cleanup_chunk',
'system_task_result' => array(
'success' => true,
'chunk_type' => 'artifacts',
'planned_count' => 3,
'applied_count' => 2,
'skipped_count' => 1,
'failed_count' => 0,
'bytes_reclaimed' => 4096,
'skipped' => array(
array( 'handle' => 'repo@dirty', 'reason_code' => 'dirty_worktree' ),
),
'failed' => array(),
'task_type' => 'worktree_cleanup_chunk',
'success' => true,
'chunk_type' => 'artifact_discovery',
'planned_count' => 3,
'applied_count' => 2,
'skipped_count' => 1,
'failed_count' => 0,
'bytes_reclaimed' => 4096,
'skipped' => array(
array( 'handle' => 'repo@dirty', 'reason_code' => 'dirty_worktree' ),
),
'failed' => array(),
),
),
array(
Expand All @@ -494,19 +492,17 @@ public function execute( array $input ): array {
'source' => 'system',
'status' => 'failed - apply_failed',
'engine_data' => array(
'task_type' => 'worktree_cleanup_chunk',
'system_task_result' => array(
'success' => false,
'chunk_type' => 'artifacts',
'planned_count' => 1,
'applied_count' => 0,
'skipped_count' => 0,
'failed_count' => 1,
'bytes_reclaimed' => 0,
'skipped' => array(),
'failed' => array(
array( 'handle' => 'repo@failed', 'reason_code' => 'apply_failed' ),
),
'task_type' => 'worktree_cleanup_chunk',
'success' => false,
'chunk_type' => 'artifacts',
'planned_count' => 1,
'applied_count' => 0,
'skipped_count' => 0,
'failed_count' => 1,
'bytes_reclaimed' => 0,
'skipped' => array(),
'failed' => array(
array( 'handle' => 'repo@failed', 'reason_code' => 'apply_failed' ),
),
),
),
Expand Down Expand Up @@ -542,13 +538,11 @@ public function execute( array $input ): array {
'mode' => 'retention',
'source' => 'workspace_cleanup_cli',
),
'system_task_result' => array(
'success' => true,
'job_backed' => true,
'report' => array(
'bytes_reclaimed' => 0,
'freed_human' => 'pending child jobs',
),
'success' => true,
'job_backed' => true,
'report' => array(
'bytes_reclaimed' => 0,
'freed_human' => 'pending child jobs',
),
),
),
Expand Down Expand Up @@ -680,6 +674,9 @@ public function execute( array $input ): array {
datamachine_code_cleanup_assert( 4096 === (int) ( $status_json['artifact_cleanup']['bytes_reclaimed'] ?? 0 ), 'cleanup status aggregates artifact bytes from child chunks' );
datamachine_code_cleanup_assert( 4 === (int) ( $status_json['cleanup_items']['planned_rows'] ?? 0 ), 'cleanup status aggregates planned rows from DB-backed cleanup item evidence' );
datamachine_code_cleanup_assert( 4096 === (int) ( $status_json['cleanup_items']['bytes_reclaimed'] ?? 0 ), 'cleanup status reconstructs reclaimed bytes from cleanup item evidence' );
datamachine_code_cleanup_assert( 3 === (int) ( $status_json['cleanup_items']['by_type']['artifact_discovery']['planned_rows'] ?? 0 ), 'cleanup status preserves artifact discovery chunk type aggregation' );
datamachine_code_cleanup_assert( 1 === (int) ( $status_json['cleanup_items']['by_type']['artifacts']['planned_rows'] ?? 0 ), 'cleanup status preserves artifact apply chunk type aggregation' );
datamachine_code_cleanup_assert( ! isset( $status_json['cleanup_items']['by_type']['unknown'] ), 'cleanup status does not aggregate completed chunks under unknown type' );
datamachine_code_cleanup_assert( '4.0 KiB' === ( $status_json['system_task_result']['report']['freed_human'] ?? '' ), 'cleanup status replaces pending child job freed placeholder' );
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' );

Expand Down
Loading