Skip to content

Commit dfe290d

Browse files
Fix hygiene cleanup candidate terminology
1 parent 4d5c2fa commit dfe290d

4 files changed

Lines changed: 58 additions & 23 deletions

File tree

inc/Tasks/WorkspaceHygieneReportTask.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,17 +112,19 @@ public function executeTask( int $jobId, array $params ): void {
112112
$this->failJob($jobId, $result->get_error_message());
113113
return;
114114
}
115-
$worktrees = (array) ( $result['worktrees'] ?? array() );
116-
$cleanup = (array) ( $result['cleanup']['summary'] ?? array() );
115+
$worktrees = (array) ( $result['worktrees'] ?? array() );
116+
$cleanup = (array) ( $result['cleanup']['summary'] ?? array() );
117+
$fast_counts = (array) ( $result['fast_stats']['counts'] ?? array() );
118+
$inventory_cleanup_candidates = (int) ( $cleanup['inventory_cleanup_candidate_count'] ?? $fast_counts['cleanup_eligible_unprobed_count'] ?? 0 );
117119
do_action(
118120
'datamachine_log',
119121
'info',
120122
sprintf(
121-
'Workspace hygiene report: %s used, %s free, %d worktree(s), %d cleanup candidate(s).',
123+
'Workspace hygiene report: %s used, %s free, %d worktree(s), %d inventory cleanup candidate(s) pending fresh safety probes.',
122124
$result['size']['total_human'] ?? 'unknown size',
123125
$result['disk']['free_human'] ?? 'unknown disk',
124126
(int) ( $worktrees['worktrees'] ?? 0 ),
125-
(int) ( $cleanup['would_remove'] ?? 0 )
127+
$inventory_cleanup_candidates
126128
),
127129
array(
128130
'task' => $this->getTaskType(),

inc/Workspace/WorkspaceWorktreeCleanupEngine.php

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1842,22 +1842,25 @@ private function build_worktree_cleanup_summary(
18421842
arsort($size_by_repo);
18431843
arsort($artifact_by_repo);
18441844

1845-
$summary = array(
1846-
'would_remove' => count($candidates),
1847-
'removed' => count($removed),
1848-
'skipped' => count($skipped),
1849-
'skipped_by_reason' => $skipped_by_reason,
1850-
'skipped_next_commands' => $this->worktree_cleanup_skipped_next_commands($skipped_by_reason),
1851-
'cleanup_buckets' => $this->worktree_cleanup_buckets(count($candidates), $candidates_by_signal, $skipped_by_reason, $candidate_bucket),
1852-
'candidates_by_signal' => $candidates_by_signal,
1853-
'stale_reasons' => $stale_reasons,
1854-
'liveness' => $liveness,
1855-
'total_size_bytes' => $total_size_bytes,
1856-
'artifact_size_bytes' => $total_artifact_bytes,
1857-
'size_by_repo' => $size_by_repo,
1858-
'artifact_size_by_repo' => $artifact_by_repo,
1859-
'top_by_size' => $this->summarize_top_worktree_rows($all_rows, 'size_bytes'),
1860-
'top_by_age' => $this->summarize_top_worktree_rows($all_rows, 'age_days'),
1845+
$candidate_count = count($candidates);
1846+
$summary = array(
1847+
'would_remove' => $candidate_count,
1848+
'inventory_cleanup_candidate_count' => WorktreeCleanupClassifier::BUCKET_CLEANUP_ELIGIBLE_UNPROBED === $candidate_bucket ? $candidate_count : 0,
1849+
'fresh_safe_removable_count' => WorktreeCleanupClassifier::BUCKET_SAFE_TO_REMOVE_NOW === $candidate_bucket ? $candidate_count : 0,
1850+
'removed' => count($removed),
1851+
'skipped' => count($skipped),
1852+
'skipped_by_reason' => $skipped_by_reason,
1853+
'skipped_next_commands' => $this->worktree_cleanup_skipped_next_commands($skipped_by_reason),
1854+
'cleanup_buckets' => $this->worktree_cleanup_buckets($candidate_count, $candidates_by_signal, $skipped_by_reason, $candidate_bucket),
1855+
'candidates_by_signal' => $candidates_by_signal,
1856+
'stale_reasons' => $stale_reasons,
1857+
'liveness' => $liveness,
1858+
'total_size_bytes' => $total_size_bytes,
1859+
'artifact_size_bytes' => $total_artifact_bytes,
1860+
'size_by_repo' => $size_by_repo,
1861+
'artifact_size_by_repo' => $artifact_by_repo,
1862+
'top_by_size' => $this->summarize_top_worktree_rows($all_rows, 'size_bytes'),
1863+
'top_by_age' => $this->summarize_top_worktree_rows($all_rows, 'age_days'),
18611864
);
18621865

18631866
if ( null !== $age_filter ) {

tests/workspace-compact-output.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,11 @@ function compact_output_large_rows( int $count ): array {
174174
'locks' => array( 'active' => 2, 'stale' => 40, 'database' => array( 'locks' => $large_rows ) ),
175175
'cleanup' => array(
176176
'summary' => array(
177-
'would_remove' => 40,
178-
'artifact_size_bytes' => 654321,
179-
'cleanup_buckets' => array(
177+
'would_remove' => 40,
178+
'inventory_cleanup_candidate_count' => 40,
179+
'fresh_safe_removable_count' => 0,
180+
'artifact_size_bytes' => 654321,
181+
'cleanup_buckets' => array(
180182
'cleanup_eligible_pending_revalidation' => 40,
181183
'safe_to_remove_now' => 0,
182184
),
@@ -195,6 +197,8 @@ function compact_output_large_rows( int $count ): array {
195197
compact_output_assert(40 === ( $hygiene['worktrees']['worktrees'] ?? null ), 'Compact hygiene output must preserve worktree counts.');
196198
compact_output_assert(40 === ( $hygiene['fast_stats']['counts']['cleanup_eligible_unprobed_count'] ?? null ), 'Compact hygiene output must label cheap cleanup candidates as unprobed.');
197199
compact_output_assert(! isset($hygiene['fast_stats']['counts']['safe_removable_count']), 'Compact hygiene output must not expose misleading safe_removable_count for cheap inventory.');
200+
compact_output_assert(40 === ( $hygiene['cleanup']['summary']['inventory_cleanup_candidate_count'] ?? null ), 'Compact cleanup summary must expose inventory cleanup candidates separately.');
201+
compact_output_assert(0 === ( $hygiene['cleanup']['summary']['fresh_safe_removable_count'] ?? null ), 'Compact cleanup summary must not mark inventory cleanup candidates as fresh safe removals.');
198202
compact_output_assert(40 === ( $hygiene['cleanup']['summary']['cleanup_buckets']['cleanup_eligible_pending_revalidation'] ?? null ), 'Compact cleanup summary must preserve pending-revalidation bucket.');
199203
compact_output_assert(0 === ( $hygiene['cleanup']['summary']['cleanup_buckets']['safe_to_remove_now'] ?? null ), 'Compact cleanup summary must not mark unprobed inventory candidates safe.');
200204
compact_output_assert(123456 === ( $hygiene['size']['total_bytes'] ?? null ), 'Compact hygiene output must preserve size bytes.');

tests/worktree-cleanup-candidate-classifier.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
require_once dirname(__DIR__) . '/inc/Workspace/WorktreeCleanupSignal.php';
1111
require_once dirname(__DIR__) . '/inc/Workspace/WorktreeCleanupClassifier.php';
1212
require_once dirname(__DIR__) . '/inc/Workspace/WorktreeCleanupCandidateClassifier.php';
13+
require_once dirname(__DIR__) . '/inc/Workspace/WorkspaceWorktreeCleanupEngine.php';
1314

1415
use DataMachineCode\Workspace\WorktreeAgeFilter;
1516
use DataMachineCode\Workspace\WorktreeCleanupClassifier;
@@ -100,4 +101,29 @@ function (): array {
100101
$probed_buckets = WorktreeCleanupClassifier::buckets(2, array(), array());
101102
worktree_cleanup_candidate_assert_same(2, $probed_buckets['safe_to_remove_now'], 'probed cleanup candidates keep the safe-to-remove bucket');
102103

104+
$engine = new class {
105+
use DataMachineCode\Workspace\WorkspaceWorktreeCleanupEngine;
106+
107+
public function summary( array $candidates, string $bucket ): array {
108+
$method = new ReflectionMethod($this, 'build_worktree_cleanup_summary');
109+
return $method->invoke($this, $candidates, array(), array(), null, $bucket);
110+
}
111+
112+
private function worktree_cleanup_skipped_next_commands( array $skipped_by_reason ): array {
113+
return array();
114+
}
115+
116+
private function summarize_top_worktree_rows( array $rows, string $field ): array {
117+
return array();
118+
}
119+
};
120+
121+
$inventory_summary = $engine->summary(array( array( 'signal' => 'cleanup_eligible' ) ), WorktreeCleanupClassifier::BUCKET_CLEANUP_ELIGIBLE_UNPROBED);
122+
worktree_cleanup_candidate_assert_same(1, $inventory_summary['inventory_cleanup_candidate_count'], 'inventory summary exposes cheap cleanup candidates separately');
123+
worktree_cleanup_candidate_assert_same(0, $inventory_summary['fresh_safe_removable_count'], 'inventory summary does not label unprobed candidates fresh safe');
124+
125+
$fresh_summary = $engine->summary(array( array( 'signal' => 'github-merged-pr' ) ), WorktreeCleanupClassifier::BUCKET_SAFE_TO_REMOVE_NOW);
126+
worktree_cleanup_candidate_assert_same(0, $fresh_summary['inventory_cleanup_candidate_count'], 'fresh summary does not count inventory-only candidates');
127+
worktree_cleanup_candidate_assert_same(1, $fresh_summary['fresh_safe_removable_count'], 'fresh summary exposes freshly probed safe removals');
128+
103129
echo "worktree-cleanup-candidate-classifier: ok\n";

0 commit comments

Comments
 (0)