Skip to content

Commit 2f7564b

Browse files
authored
Merge pull request #670 from Extra-Chill/fix/issue-662-disk-budget-rebased
Fix worktree disk budget percentage refusal
2 parents fc9f0ac + 4789674 commit 2f7564b

4 files changed

Lines changed: 60 additions & 10 deletions

File tree

inc/Workspace/WorkspaceWorktreeLifecycle.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,7 @@ public function worktree_list( ?string $repo = null, ?string $state = null, arra
784784
$dirty_files = null;
785785
}
786786

787-
$metadata_key = null;
787+
$metadata_key = null;
788788
if ( ! $is_primary && $inside_ws ) {
789789
$metadata_key = $relative;
790790
} elseif ( ! $is_primary && ! $inside_ws ) {

inc/Workspace/WorktreeDiskBudget.php

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,10 @@ public static function evaluate( array $metrics, array $thresholds = array(), bo
9090
$warnings = array();
9191
$refused = false;
9292

93-
$effective_refuse_bytes = $thresholds['refuse_free_bytes'];
94-
$effective_warn_bytes = $thresholds['warn_free_bytes'];
93+
$effective_refuse_bytes = (int) $thresholds['refuse_free_bytes'];
94+
$effective_warn_bytes = (int) $thresholds['warn_free_bytes'];
9595
if ( null !== $total_bytes && $total_bytes > 0 ) {
96-
$effective_refuse_bytes = self::effective_free_bytes_threshold(
96+
$effective_refuse_bytes = self::effective_refuse_free_bytes_threshold(
9797
(int) $thresholds['refuse_free_bytes'],
9898
$thresholds['refuse_free_percent'],
9999
$total_bytes
@@ -109,11 +109,10 @@ public static function evaluate( array $metrics, array $thresholds = array(), bo
109109
if ( $free_bytes < $effective_refuse_bytes ) {
110110
$refused = ! $forced;
111111
$warnings[] = sprintf(
112-
'Free disk space is %.1f GiB%s, below the refusal threshold of %.1f GiB or %.1f%% free, whichever is stricter.',
112+
'Free disk space is %.1f GiB%s, below the refusal threshold of %.1f GiB.',
113113
self::bytes_to_gib($free_bytes),
114114
null === $free_percent ? '' : sprintf(' (%.1f%%)', $free_percent),
115-
self::bytes_to_gib( (int) $thresholds['refuse_free_bytes'] ),
116-
$thresholds['refuse_free_percent']
115+
self::bytes_to_gib($effective_refuse_bytes)
117116
);
118117
} elseif ( $free_bytes < $effective_warn_bytes ) {
119118
$warnings[] = sprintf(
@@ -381,6 +380,29 @@ private static function effective_free_bytes_threshold( int $absolute_bytes, flo
381380
return max($absolute_bytes, $percent_bytes);
382381
}
383382

383+
/**
384+
* Calculate the hard refusal threshold for a measured filesystem.
385+
*
386+
* Large filesystems can safely fall below a percentage threshold while still
387+
* having enough absolute free space for a bare worktree checkout. Keep the
388+
* percentage refusal only for filesystems smaller than the absolute floor,
389+
* where the absolute GiB floor is impossible to satisfy.
390+
*
391+
* @param int $absolute_bytes Absolute free-space threshold.
392+
* @param float $percent Percentage free-space threshold.
393+
* @param int $total_bytes Measured filesystem size.
394+
* @return int
395+
*/
396+
private static function effective_refuse_free_bytes_threshold( int $absolute_bytes, float $percent, int $total_bytes ): int {
397+
$percent_bytes = (int) ceil($total_bytes * ( $percent / 100 ));
398+
399+
if ( $total_bytes < $absolute_bytes ) {
400+
return $percent_bytes;
401+
}
402+
403+
return $absolute_bytes;
404+
}
405+
384406
/**
385407
* Convert bytes to GiB.
386408
*

tests/smoke-worktree-disk-budget.php

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ function datamachine_code_budget_assert( bool $condition, string $message ): voi
102102
datamachine_code_budget_assert(true === $budget['forced'], 'forced flag is recorded');
103103
datamachine_code_budget_assert(true === $budget['force_override_applied'], 'force override is visible in output data');
104104

105-
echo "\n[5] percent floor refuses even when absolute free space is above 10 GiB\n";
105+
echo "\n[5] percent floor warns when absolute free space is above 10 GiB\n";
106106
$budget = WorktreeDiskBudget::evaluate(
107107
array(
108108
'workspace_path' => '/tmp/workspace',
@@ -112,10 +112,25 @@ function datamachine_code_budget_assert( bool $condition, string $message ): voi
112112
),
113113
$thresholds
114114
);
115-
datamachine_code_budget_assert('refused' === $budget['status'], 'refused status below 10 percent free');
116-
datamachine_code_budget_assert(20.0 === $budget['effective_refuse_gib'], 'effective refusal floor uses stricter percentage threshold');
115+
datamachine_code_budget_assert('warning' === $budget['status'], 'warning status below 10 percent free but above absolute refusal floor');
116+
datamachine_code_budget_assert(10.0 === $budget['effective_refuse_gib'], 'effective refusal floor uses absolute threshold on normal filesystems');
117+
datamachine_code_budget_assert(30.0 === $budget['effective_warn_gib'], 'effective warning floor still uses stricter percentage threshold');
118+
datamachine_code_budget_assert(false === $budget['force_override_required'], 'substantial absolute free space does not require force');
117119
datamachine_code_budget_assert(7.5 === $budget['free_percent'], 'free percentage is reported');
118120

121+
echo "\n[5b] large filesystem below absolute floor still refuses\n";
122+
$budget = WorktreeDiskBudget::evaluate(
123+
array(
124+
'workspace_path' => '/tmp/workspace',
125+
'free_bytes' => 5 * $gib,
126+
'total_bytes' => 200 * $gib,
127+
'worktree_count' => 10,
128+
),
129+
$thresholds
130+
);
131+
datamachine_code_budget_assert('refused' === $budget['status'], 'large filesystem still refuses below absolute floor');
132+
datamachine_code_budget_assert(true === $budget['force_override_required'], 'low absolute free space still requires force');
133+
119134
echo "\n[6] high worktree count warns independently\n";
120135
$budget = WorktreeDiskBudget::evaluate(
121136
array(

tests/smoke-worktree-lifecycle-metadata.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,10 +360,23 @@ function () use ( $tmp ): void {
360360
$assert('unsupported_workspace_repo_argument', is_wp_error($bad_url_worktree) ? $bad_url_worktree->get_error_code() : null, 'missing URL primary returns a clear error code');
361361

362362
$GLOBALS['datamachine_code_test_filters']['datamachine_worktree_disk_budget_thresholds'] = function ( array $thresholds ): array {
363+
$thresholds['refuse_free_bytes'] = 1;
363364
$thresholds['refuse_free_percent'] = 100;
364365
$thresholds['warn_free_percent'] = 100;
365366
return $thresholds;
366367
};
368+
$percent_warning_worktree = $ws->worktree_add('demo', 'feature/percent-warning-skip-bootstrap', 'HEAD', false, false, true, false, false);
369+
unset($GLOBALS['datamachine_code_test_filters']['datamachine_worktree_disk_budget_thresholds']);
370+
$assert(false, is_wp_error($percent_warning_worktree), 'worktree_add with bootstrap disabled is not blocked by percentage threshold alone');
371+
$assert('warning', is_wp_error($percent_warning_worktree) ? null : ( $percent_warning_worktree['disk_budget']['status'] ?? null ), 'percentage-only disk pressure remains visible as a warning');
372+
373+
$GLOBALS['datamachine_code_test_filters']['datamachine_worktree_disk_budget_thresholds'] = function ( array $thresholds ): array {
374+
$thresholds['refuse_free_bytes'] = PHP_INT_MAX;
375+
$thresholds['refuse_free_percent'] = 100;
376+
$thresholds['warn_free_bytes'] = PHP_INT_MAX;
377+
$thresholds['warn_free_percent'] = 100;
378+
return $thresholds;
379+
};
367380
$refused = $ws->worktree_add('demo', 'feature/disk-budget-refusal', 'HEAD', true, true, true, false, false);
368381
unset($GLOBALS['datamachine_code_test_filters']['datamachine_worktree_disk_budget_thresholds']);
369382
$assert(true, is_wp_error($refused), 'worktree_add refuses before creation when disk budget is unsafe');

0 commit comments

Comments
 (0)