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
31 changes: 27 additions & 4 deletions inc/Cleanup/CleanupRemainingWorkSummary.php
Original file line number Diff line number Diff line change
Expand Up @@ -220,30 +220,53 @@ function ( array $command ) use ( &$seen ): bool {
private static function command_for_reason( string $reason, string $bucket ): array {
$command = match ( $reason ) {
'needs_metadata_reconcile', 'lifecycle_reconciliation_candidate', 'repaired_metadata' => self::METADATA_RECONCILE_COMMAND,
'dirty_worktree', 'unpushed_commits', 'probe_timeout', 'plan_mismatch' => 'studio wp datamachine-code workspace cleanup run --mode=retention --dry-run --format=json',
'dirty_worktree' => 'git -C <worktree-path> status --short --branch --untracked-files=normal',
'unpushed_commits' => 'git -C <worktree-path> log --oneline --decorate @{u}..HEAD',
'stale_worktree_marker' => 'git -C <primary-path> worktree prune --dry-run --verbose',
'primary_missing' => 'studio wp datamachine-code workspace show <repo>',
'probe_timeout', 'plan_mismatch' => 'studio wp datamachine-code workspace cleanup run --mode=retention --dry-run --format=json',
'artifact_already_removed', 'artifact_plan_mismatch' => 'studio wp datamachine-code workspace cleanup run --mode=artifacts --dry-run --format=json',
default => 'studio wp datamachine-code workspace cleanup run --mode=retention --dry-run --format=json',
};

return array(
$entry = array(
'bucket' => $bucket . ':' . $reason,
'command' => $command,
'destructive' => false,
'apply_destructive' => false,
'why' => self::reason_remediation($reason),
);

$alternative = self::reason_alternative($reason);
if ( '' !== $alternative ) {
$entry['alternative'] = $alternative;
}

return $entry;
}

private static function reason_remediation( string $reason ): string {
return match ( $reason ) {
'dirty_worktree' => 'Inspect dirty files before applying cleanup; artifact-only dirt may be removable through artifact cleanup, source dirt needs review.',
'dirty_worktree' => 'Inspect dirty files before applying cleanup; classify artifact-only dirt versus source edits before preserving, committing, or cleaning up.',
'artifact_plan_mismatch', 'plan_mismatch' => 'Regenerate a fresh plan because the saved row no longer matches current filesystem or branch state.',
'artifact_plan_not_current', 'artifact_already_removed' => 'Regenerate artifact cleanup evidence; the saved artifact row is no longer a current candidate.',
'needs_metadata_reconcile' => 'Run metadata reconciliation so DMC can classify the worktree without a full cleanup scan.',
'lifecycle_reconciliation_candidate' => 'Run lifecycle reconciliation to collect PR/merge signals before emitting removal rows.',
'unpushed_commits' => 'Push, merge, or intentionally abandon commits before retrying cleanup.',
'unpushed_commits' => 'Inspect commits ahead of upstream so the operator can push, merge, preserve, or intentionally abandon before retrying cleanup.',
'stale_worktree_marker' => 'Preview stale git worktree metadata pruning and repair registry metadata only after confirming the marker is stale.',
'primary_missing' => 'Recover, adopt, or recreate the missing primary checkout before worktree removal can be routed through git safely.',
'probe_timeout' => 'Retry the review path with a smaller bounded page or investigate the git probe timeout.',
default => 'Run the review command to refresh evidence before applying cleanup.',
};
}

private static function reason_alternative( string $reason ): string {
return match ( $reason ) {
'dirty_worktree' => 'studio wp datamachine-code workspace cleanup run --mode=retention --dry-run --only=dirty_worktree --verbose --format=json',
'unpushed_commits' => 'studio wp datamachine-code workspace cleanup run --mode=retention --dry-run --only=unpushed_commits --verbose --format=json',
'stale_worktree_marker' => self::METADATA_RECONCILE_COMMAND,
'primary_missing' => 'If the checkout is gone, recreate it with `studio wp datamachine-code workspace clone <remote-url> --name=<repo>` or adopt the existing primary checkout with `studio wp datamachine-code workspace adopt <path> --name=<repo>`.',
default => '',
};
}
}
28 changes: 28 additions & 0 deletions inc/Workspace/WorkspaceWorktreeCleanupEngine.php
Original file line number Diff line number Diff line change
Expand Up @@ -1729,6 +1729,34 @@ private function worktree_cleanup_skipped_next_commands( array $skipped_by_reaso
'why' => 'Dirty paths are limited to declared reconstructable artifact directories, so artifact cleanup can shed them without force-removing source worktrees.',
'destructive' => false,
),
'dirty_worktree' => array(
'label' => 'Inspect dirty files before retrying cleanup',
'command' => 'git -C <worktree-path> status --short --branch --untracked-files=normal',
'alternative' => 'studio wp datamachine-code workspace cleanup run --mode=retention --dry-run --only=dirty_worktree --verbose --format=json',
'why' => 'Shows the exact dirty paths so operators can distinguish generated artifacts from source edits and decide whether to clean, commit, or preserve the worktree.',
'destructive' => false,
),
'unpushed_commits' => array(
'label' => 'Inspect commits ahead of upstream before cleanup',
'command' => 'git -C <worktree-path> log --oneline --decorate @{u}..HEAD',
'alternative' => 'studio wp datamachine-code workspace cleanup run --mode=retention --dry-run --only=unpushed_commits --verbose --format=json',
'why' => 'Lists the protected commits so operators can push, merge, preserve, or intentionally abandon them before retrying cleanup.',
'destructive' => false,
),
'stale_worktree_marker' => array(
'label' => 'Preview stale git worktree marker pruning',
'command' => 'git -C <primary-path> worktree prune --dry-run --verbose',
'alternative' => 'studio wp datamachine-code workspace worktree reconcile-metadata --dry-run --format=json',
'why' => 'Confirms stale git metadata before any prune or registry repair, keeping cleanup non-destructive by default.',
'destructive' => false,
),
'primary_missing' => array(
'label' => 'Recover or adopt the missing primary checkout',
'command' => 'studio wp datamachine-code workspace show <repo>',
'alternative' => 'Recreate with `studio wp datamachine-code workspace clone <remote-url> --name=<repo>` or adopt an existing checkout with `studio wp datamachine-code workspace adopt <path> --name=<repo>`.',
'why' => 'Git worktree removal must be routed through the primary checkout, so operators need primary path and remote evidence before repairing or preserving rows.',
'destructive' => false,
),
'lifecycle_reconciliation_candidate' => array(
'label' => 'Run DMC-owned lifecycle reconciliation before cleanup eligibility',
'command' => 'studio wp datamachine-code workspace worktree cleanup --dry-run --format=json',
Expand Down
Loading
Loading