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
9 changes: 8 additions & 1 deletion inc/Cli/Commands/WorkspaceCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -2100,7 +2100,7 @@ private function renderGitOperationResult( string $operation, array $result, arr
* # Adopt/reconcile unmanaged worktree metadata before cleanup
* wp datamachine-code workspace worktree reconcile-metadata --dry-run --format=json
* wp datamachine-code workspace worktree reconcile-metadata --dry-run --limit=25 --offset=0 --format=json
* wp datamachine-code workspace worktree reconcile-metadata --apply --format=json
* wp datamachine-code workspace worktree reconcile-metadata --apply --limit=25 --offset=0 --format=json
*
* # Ignore dirty working-tree safety (caution)
* wp datamachine-code workspace worktree cleanup --force
Expand Down Expand Up @@ -3201,6 +3201,13 @@ private function render_worktree_metadata_reconciliation_result( array $result,
WP_CLI::success( sprintf( '%d metadata reconciliation proposal(s). Review JSON output before applying; --apply-plan remains a low-level escape hatch until DB-backed cleanup runs land.', count( $proposals ) ) );
return;
}
if ( isset( $result['pagination']['next_offset'] ) ) {
WP_CLI::log( sprintf(
'Next page: wp datamachine-code workspace worktree reconcile-metadata --apply --limit=%d --offset=%d --format=json',
(int) ( $result['pagination']['limit'] ?? 0 ),
(int) $result['pagination']['next_offset']
) );
}
WP_CLI::success( sprintf( 'Wrote metadata for %d worktree(s); %d skipped.', count( $written ), count( $skipped ) ) );
}

Expand Down
22 changes: 20 additions & 2 deletions inc/Workspace/Workspace.php
Original file line number Diff line number Diff line change
Expand Up @@ -3889,6 +3889,7 @@ public function worktree_reconcile_metadata( array $opts = array() ): array|\WP_
}

if ( $apply ) {
$plan['direct_apply'] = true;
return $this->apply_worktree_metadata_reconciliation_plan( $plan );
}

Expand Down Expand Up @@ -4426,19 +4427,36 @@ private function apply_worktree_metadata_reconciliation_plan( array $plan ): arr

$classified_skips = $this->classify_worktree_metadata_reconciliation_skips( $skipped );

return array(
$inspected = isset( $plan['summary']['inspected'] ) ? (int) $plan['summary']['inspected'] : count( (array) ( $listing['worktrees'] ?? array() ) );
$result = array(
'success' => true,
'dry_run' => false,
'applied' => true,
'direct_apply' => ! empty( $plan['direct_apply'] ),
'generated_at' => gmdate( 'c' ),
'workspace_path' => $this->workspace_path,
'proposals' => $planned,
'written' => $written,
'skipped' => $skipped,
'still_unsafe' => $classified_skips['still_unsafe'],
'external_worktrees' => $classified_skips['external_worktrees'],
'summary' => $this->build_worktree_metadata_reconciliation_summary( count( (array) ( $listing['worktrees'] ?? array() ) ), $planned, $written, $skipped ),
'summary' => $this->build_worktree_metadata_reconciliation_summary( $inspected, $planned, $written, $skipped ),
);

if ( isset( $plan['pagination'] ) && is_array( $plan['pagination'] ) ) {
$result['pagination'] = $plan['pagination'];
}
if ( isset( $plan['evidence'] ) && is_array( $plan['evidence'] ) ) {
$result['evidence'] = array_merge(
$plan['evidence'],
array(
'scope' => ! empty( $plan['direct_apply'] ) ? 'paginated metadata reconciliation direct apply' : (string) ( $plan['evidence']['scope'] ?? 'paginated metadata reconciliation apply-plan' ),
'apply_source' => ! empty( $plan['direct_apply'] ) ? 'direct_apply' : 'apply_plan',
)
);
}

return $result;
}

/**
Expand Down
8 changes: 8 additions & 0 deletions tests/smoke-worktree-metadata-reconcile.php
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,14 @@ function size_format( $bytes ): string {

$auto_apply = $ws->worktree_reconcile_metadata( array( 'apply' => true ) );
$assert( true, ! is_wp_error( $auto_apply ) && ( $auto_apply['success'] ?? false ), 'DMC-owned reconciliation apply path runs without a manual plan' );
$bounded_auto_apply = $ws->worktree_reconcile_metadata( array( 'apply' => true, 'limit' => 2, 'offset' => 2 ) );
$assert( true, ! is_wp_error( $bounded_auto_apply ) && ( $bounded_auto_apply['success'] ?? false ), 'bounded direct reconciliation apply runs without a manual plan file' );
$assert( true, (bool) ( $bounded_auto_apply['direct_apply'] ?? false ), 'bounded direct apply identifies direct apply source' );
$assert( false, (bool) ( $bounded_auto_apply['dry_run'] ?? true ), 'bounded direct apply is not a dry-run' );
$assert( 2, (int) ( $bounded_auto_apply['summary']['inspected'] ?? 0 ), 'bounded direct apply summary stays page-scoped' );
$assert( 2, (int) ( $bounded_auto_apply['pagination']['limit'] ?? 0 ), 'bounded direct apply preserves pagination limit' );
$assert( 2, (int) ( $bounded_auto_apply['pagination']['offset'] ?? 0 ), 'bounded direct apply preserves pagination offset' );
$assert( 'direct_apply', $bounded_auto_apply['evidence']['apply_source'] ?? '', 'bounded direct apply exposes evidence source' );

$inventory_after = $ws->worktree_cleanup_merged( array( 'dry_run' => true, 'inventory_only' => true, 'skip_github' => true ) );
$assert( 1, (int) ( $inventory_after['summary']['skipped_by_reason']['needs_metadata_reconcile'] ?? 0 ), 'inventory cleanup requires fewer metadata reconciliation passes after apply' );
Expand Down