From c6336cc133d000035fae101b6139700654e3e20c Mon Sep 17 00:00:00 2001 From: Chris Huber Date: Tue, 25 Aug 2026 10:32:43 -0400 Subject: [PATCH] perf(workspace): bound targeted show probes --- .../WorkspaceRepositoryLifecycle.php | 28 ++++++++++++- inc/Workspace/WorktreeDiskBudget.php | 12 +++--- inc/Workspace/workspace-target-probe.php | 22 ++++++---- tests/workspace-command-startup-bounds.php | 40 ++++++++++++++++++- tests/workspace-show-cli-format-contract.php | 1 + 5 files changed, 86 insertions(+), 17 deletions(-) diff --git a/inc/Workspace/WorkspaceRepositoryLifecycle.php b/inc/Workspace/WorkspaceRepositoryLifecycle.php index fa9e2f21..632f3602 100644 --- a/inc/Workspace/WorkspaceRepositoryLifecycle.php +++ b/inc/Workspace/WorkspaceRepositoryLifecycle.php @@ -1000,10 +1000,13 @@ public function remove_repo( string $handle ): array|\WP_Error { * @return array{success: bool, name?: string, repo?: string, is_worktree?: bool, is_context?: bool, path?: string|null, branch?: string|null, remote?: string|null, commit?: string|null, dirty?: int, workspace_capacity?: array, primary_freshness?: array|null, workspace_policy?: array}|\WP_Error */ public function show_repo( string $handle, bool $refresh = false ): array|\WP_Error { + $show_started = microtime(true); + $registry_lookup_started = microtime(true); $requested_handle = $handle; $context_policy = null; $parsed = $this->parse_handle($handle); $repo_path = $this->workspace_path . '/' . $parsed['dir_name']; + $registry_lookup_ms = (int) round(( microtime(true) - $registry_lookup_started ) * 1000); $inspection = WorkspaceTargetInspector::inspect($repo_path, $parsed['dir_name']); if ( is_wp_error($inspection) ) { return $inspection; @@ -1066,10 +1069,15 @@ public function show_repo( string $handle, bool $refresh = false ): array|\WP_Er : null ) : null; + $remote_freshness_started = microtime(true); if ( $refresh && is_array($primary_freshness) ) { $primary_freshness = $this->refresh_primary_freshness_report($repo_path, $parsed['dir_name'], $primary_freshness); } + $remote_freshness_ms = (int) round(( microtime(true) - $remote_freshness_started ) * 1000); + $capacity_started = microtime(true); + $capacity = WorktreeDiskBudget::inspect($this->workspace_path); + $capacity_ms = (int) round(( microtime(true) - $capacity_started ) * 1000); $result = array( 'success' => true, 'name' => null !== $context_policy ? (string) $context_policy['alias'] : $parsed['dir_name'], @@ -1081,15 +1089,33 @@ public function show_repo( string $handle, bool $refresh = false ): array|\WP_Er 'remote' => $inspection['remote'] ?? null, 'commit' => $inspection['commit'] ?? null, 'dirty' => (int) ( $inspection['dirty'] ?? 0 ), - 'workspace_capacity' => WorktreeDiskBudget::inspect($this->workspace_path), + 'workspace_capacity' => $capacity, 'primary_freshness' => $primary_freshness, ); + $optional_enrichments_started = microtime(true); if ( $parsed['is_worktree'] ) { $result['readiness'] = WorktreeContextInjector::bootstrap_readiness(WorktreeContextInjector::get_metadata($parsed['dir_name'])); } if ( null !== $context_policy ) { $result['workspace_policy'] = WorkspaceAliasResolver::policy_attestation($handle); } + if ( function_exists('do_action') ) { + $probe_timings = is_array($inspection['probe_timings_ms'] ?? null) ? $inspection['probe_timings_ms'] : array(); + do_action( + 'datamachine_code_workspace_show_profiled', + array( + 'handle' => $requested_handle, + 'timings_ms' => array( + 'registry_lookup' => $registry_lookup_ms, + 'capacity' => $capacity_ms, + 'git_status' => array_sum(array_map('intval', array_intersect_key($probe_timings, array_flip(array( 'branch', 'remote', 'commit', 'status' ))))), + 'remote_freshness' => $remote_freshness_ms, + 'optional_enrichments' => (int) round(( microtime(true) - $optional_enrichments_started ) * 1000), + 'total' => (int) round(( microtime(true) - $show_started ) * 1000), + ), + ) + ); + } return $result; } diff --git a/inc/Workspace/WorktreeDiskBudget.php b/inc/Workspace/WorktreeDiskBudget.php index 5af72436..4c2dd6b2 100644 --- a/inc/Workspace/WorktreeDiskBudget.php +++ b/inc/Workspace/WorktreeDiskBudget.php @@ -1001,7 +1001,11 @@ private static function format_bytes( int|float $bytes ): string { } /** - * Count worktree-like directories cheaply without consulting every primary. + * Count managed worktree names without probing every workspace entry. + * + * Workspace lifecycle owns the `@` directory convention. Counting + * its names from the root snapshot avoids one remote-filesystem stat per + * unrelated worktree while preserving the existing aggregate evidence. * * @param string $workspace_path Workspace root path. * @return int @@ -1018,11 +1022,7 @@ private static function count_worktree_like_dirs( string $workspace_path ): int $count = 0; foreach ( $entries as $entry ) { - if ( '.' === $entry || '..' === $entry || ! str_contains($entry, '@') ) { - continue; - } - - if ( is_dir($workspace_path . '/' . $entry) ) { + if ( '.' !== $entry && '..' !== $entry && str_contains($entry, '@') ) { ++$count; } } diff --git a/inc/Workspace/workspace-target-probe.php b/inc/Workspace/workspace-target-probe.php index 12d73674..ca4255fa 100644 --- a/inc/Workspace/workspace-target-probe.php +++ b/inc/Workspace/workspace-target-probe.php @@ -15,6 +15,7 @@ $git_command = (string) ( $argv[3] ?? 'git' ); $probe_group_pid = 0; $probe_process = null; +$probe_timings_ms = array(); // ProcessRunner normally creates this group. Establish it here as well so its // direct-process fallback can interrupt this worker without orphaning a probe. @@ -86,22 +87,26 @@ static function () use ( &$probe_process, $probe_group_pid ): void { }; fwrite(STDERR, "DMC_BOUNDARY:filesystem:is_dir\n"); +$filesystem_started = microtime(true); if ( '' !== $filesystem_probe ) { $result = $run_probe($filesystem_probe . ' ' . escapeshellarg($workspace_path)); $exists = 0 === $result['exit'] && '1' === trim(implode("\n", $result['output'])); } else { $exists = is_dir($workspace_path); } +$probe_timings_ms['filesystem'] = (int) round(( microtime(true) - $filesystem_started ) * 1000); if ( ! $exists ) { - fwrite(STDOUT, (string) json_encode(array( 'exists' => false ), JSON_UNESCAPED_SLASHES)); + fwrite(STDOUT, (string) json_encode(array( 'exists' => false, 'probe_timings_ms' => $probe_timings_ms ), JSON_UNESCAPED_SLASHES)); exit(0); } /** @return string|null */ -$git_probe = static function ( string $operation, string $args ) use ( $workspace_path, $git_command, $run_probe ): ?string { +$git_probe = static function ( string $operation, string $args ) use ( $workspace_path, $git_command, $run_probe, &$probe_timings_ms ): ?string { fwrite(STDERR, 'DMC_BOUNDARY:git:' . $operation . "\n"); + $started = microtime(true); $command = $git_command . ' --no-optional-locks -C ' . escapeshellarg($workspace_path) . ' ' . $args; $result = $run_probe($command, true); + $probe_timings_ms[ $operation ] = (int) round(( microtime(true) - $started ) * 1000); if ( 0 !== $result['exit'] ) { return null; } @@ -123,13 +128,14 @@ static function () use ( &$probe_process, $probe_group_pid ): void { STDOUT, (string) json_encode( array( - 'exists' => true, - 'branch' => '' !== (string) $branch ? $branch : null, - 'remote' => '' !== (string) $remote ? $remote : null, - 'commit' => '' !== (string) $commit ? $commit : null, - 'dirty' => $dirty, - 'branch_status' => $branch_status, + 'exists' => true, + 'branch' => '' !== (string) $branch ? $branch : null, + 'remote' => '' !== (string) $remote ? $remote : null, + 'commit' => '' !== (string) $commit ? $commit : null, + 'dirty' => $dirty, + 'branch_status' => $branch_status, 'tracking_ref_observed_at' => $tracking_ref_observed_at, + 'probe_timings_ms' => $probe_timings_ms, ), JSON_UNESCAPED_SLASHES ) diff --git a/tests/workspace-command-startup-bounds.php b/tests/workspace-command-startup-bounds.php index ea8f506e..f9f28b59 100644 --- a/tests/workspace-command-startup-bounds.php +++ b/tests/workspace-command-startup-bounds.php @@ -7,6 +7,13 @@ class BaseCommand {} } namespace DataMachineCode\Workspace { + function is_dir( string $path ): bool { + if ( ! empty($GLOBALS['dmc_test_record_workspace_is_dir']) ) { + $GLOBALS['dmc_test_workspace_is_dir_paths'][] = $path; + } + return \is_dir($path); + } + function disk_free_space( string $path ): float|false { return $GLOBALS['dmc_test_disk_free_bytes'] ?? \disk_free_space($path); } @@ -50,12 +57,15 @@ public static function error( string $message ): void { throw new \RuntimeExcept /** @var array> */ $GLOBALS['dmc_test_actions'] = array(); + $GLOBALS['dmc_test_emitted_actions'] = array(); $GLOBALS['dmc_test_get_option_calls'] = 0; $GLOBALS['dmc_test_mutation_calls'] = 0; $GLOBALS['dmc_test_options'] = array(); $GLOBALS['dmc_test_filters'] = array(); $GLOBALS['dmc_test_disk_free_bytes'] = null; $GLOBALS['dmc_test_disk_total_bytes'] = null; + $GLOBALS['dmc_test_record_workspace_is_dir'] = false; + $GLOBALS['dmc_test_workspace_is_dir_paths'] = array(); function startup_bounds_assert( bool $condition, string $message ): void { if ( ! $condition ) { @@ -91,6 +101,7 @@ function apply_filters( string $hook, mixed $value, mixed ...$args ): mixed { return $value; } function do_action( string $hook, mixed ...$args ): void { + $GLOBALS['dmc_test_emitted_actions'][ $hook ][] = $args; $callbacks = $GLOBALS['dmc_test_actions'][ $hook ] ?? array(); usort($callbacks, static fn ( array $left, array $right ): int => $left['priority'] <=> $right['priority']); foreach ( $callbacks as $entry ) { @@ -190,12 +201,20 @@ function startup_bounds_remove_tree( string $path ): void { // Make capacity pressure deterministic while retaining the actual CLI -> // WorkspaceAbilities -> Workspace show path. The warning/refusal output may // only consume this already-measured capacity result, not bootstrap hygiene. - for ( $index = 0; $index < 101; ++$index ) { + for ( $index = 0; $index < 176; ++$index ) { mkdir($workspace . '/unrelated@' . str_pad((string) $index, 4, '0', STR_PAD_LEFT)); } $GLOBALS['dmc_test_disk_total_bytes'] = (float) ( 100 * 1024 * 1024 * 1024 ); $GLOBALS['dmc_test_disk_free_bytes'] = (float) ( 15 * 1024 * 1024 * 1024 ); + $git_probe_log = $workspace . '/target-git-probes'; + $git_probe = $workspace . '/target-git-probe.sh'; + file_put_contents($git_probe, "#!/bin/sh\nprintf '%s\\n' \"\$*\" >> " . escapeshellarg($git_probe_log) . "\nexec git \"\$@\"\n"); + chmod($git_probe, 0755); + $GLOBALS['dmc_test_filters']['datamachine_code_workspace_target_git_command'] = escapeshellarg($git_probe); + $GLOBALS['dmc_test_record_workspace_is_dir'] = true; $produced_show = \DataMachineCode\Abilities\WorkspaceAbilities::showRepo(array( 'name' => 'target' )); + $GLOBALS['dmc_test_record_workspace_is_dir'] = false; + unset($GLOBALS['dmc_test_filters']['datamachine_code_workspace_target_git_command']); startup_bounds_assert(! is_wp_error($produced_show), 'WorkspaceAbilities::showRepo did not produce the bounded local result.'); $produced_capacity = $produced_show['workspace_capacity'] ?? null; startup_bounds_assert(is_array($produced_capacity), 'WorkspaceAbilities::showRepo did not emit workspace_capacity.'); @@ -203,7 +222,24 @@ function startup_bounds_remove_tree( string $path ): void { startup_bounds_assert(array_key_exists($field, $produced_capacity), sprintf('WorkspaceAbilities::showRepo emitted an incomplete workspace_capacity: missing %s.', $field)); } startup_bounds_assert($workspace === $produced_capacity['workspace_path'], 'WorkspaceAbilities::showRepo emitted capacity for the wrong workspace.'); - startup_bounds_assert(101 === $produced_capacity['worktree_count'], 'WorkspaceAbilities::showRepo did not measure the bounded worktree fixture.'); + startup_bounds_assert(176 === $produced_capacity['worktree_count'], 'WorkspaceAbilities::showRepo did not preserve the large-workspace capacity count.'); + $unrelated_probes = array_filter( + $GLOBALS['dmc_test_workspace_is_dir_paths'], + static fn ( string $path ): bool => str_starts_with($path, $workspace . '/unrelated@') + ); + startup_bounds_assert(array() === array_values($unrelated_probes), 'Targeted show enumerated unrelated worktree paths during capacity inspection.'); + $git_probes = file($git_probe_log, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) ?: array(); + startup_bounds_assert(4 === count($git_probes), 'Targeted show did not retain its four bounded local Git probes.'); + foreach ( $git_probes as $git_probe_args ) { + startup_bounds_assert(str_starts_with($git_probe_args, '--no-optional-locks -C ' . $workspace . '/target '), 'Targeted show ran Git against an unrelated checkout.'); + } + $profiles = $GLOBALS['dmc_test_emitted_actions']['datamachine_code_workspace_show_profiled'] ?? array(); + $profile = end($profiles)[0] ?? null; + startup_bounds_assert(is_array($profile) && 'target' === ($profile['handle'] ?? null), 'Targeted show did not emit its phase timing profile.'); + startup_bounds_assert( + array( 'registry_lookup', 'capacity', 'git_status', 'remote_freshness', 'optional_enrichments', 'total' ) === array_keys((array) ($profile['timings_ms'] ?? array())), + 'Targeted show timing profile did not retain every required phase.' + ); startup_bounds_assert('warning' === $produced_capacity['status'], 'WorkspaceAbilities::showRepo did not preserve the fixture capacity status.'); startup_bounds_assert(in_array('worktree_count_warning_threshold', $produced_capacity['trigger_reasons'], true), 'WorkspaceAbilities::showRepo did not emit the worktree capacity trigger.'); $produced_reasons = \DataMachineCode\Workspace\WorktreeDiskBudget::format_trigger_reasons($produced_capacity); diff --git a/tests/workspace-show-cli-format-contract.php b/tests/workspace-show-cli-format-contract.php index d6357cf5..e8b6f1a1 100644 --- a/tests/workspace-show-cli-format-contract.php +++ b/tests/workspace-show-cli-format-contract.php @@ -113,6 +113,7 @@ function workspace_show_cli_assert( bool $condition, string $message ): void { ); WP_CLI::$logs = array(); + unset(WorkspaceAbilities::$result['primary_freshness']); WorkspaceAbilities::$result['workspace_capacity'] = array( 'status' => 'warning', 'creation_allowed' => true,