From c6041d218127779ecd48b8c6840827804886ef75 Mon Sep 17 00:00:00 2001 From: Maximilian Roos Date: Fri, 3 Jul 2026 16:54:19 -0700 Subject: [PATCH 1/5] WIP: prune bench, fixture helpers, removal trace spans Session in progress on wt-remove; committed to hand the fixture fix to a dispatched session. Co-Authored-By: Claude Fable 5 --- Cargo.toml | 4 + benches/CLAUDE.md | 70 +++++++++++ benches/prune.rs | 178 +++++++++++++++++++++++++++ src/commands/process.rs | 7 ++ src/commands/step/prune.rs | 12 +- src/git/fsmonitor.rs | 10 ++ tests/helpers/wt-perf/src/lib.rs | 195 ++++++++++++++++++++++++++++++ tests/helpers/wt-perf/src/main.rs | 40 +++--- 8 files changed, 499 insertions(+), 17 deletions(-) create mode 100644 benches/prune.rs diff --git a/Cargo.toml b/Cargo.toml index a791d4b400..23e50fdc91 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -341,6 +341,10 @@ harness = false name = "remove" harness = false +[[bench]] +name = "prune" +harness = false + [[bench]] name = "picker_preview" harness = false diff --git a/benches/CLAUDE.md b/benches/CLAUDE.md index f00966c0cd..e30b0f82cc 100644 --- a/benches/CLAUDE.md +++ b/benches/CLAUDE.md @@ -23,6 +23,10 @@ cargo bench --bench list cargo bench --bench time_to_first_output # all commands cargo bench --bench time_to_first_output remove # just remove +# wt step prune (scan + removal on the squash-merged fixture) +cargo bench --bench prune # all variants +cargo bench --bench prune dry_run # scan-only variants + # Picker preview pre-compute (wt switch preview workload) cargo bench --bench picker_preview # all variants cargo bench --bench picker_preview warm # warm only @@ -57,6 +61,12 @@ startup latency without output rendering or post-output work (mismatch warnings, Supported commands: `switch`, `remove`, `list`. +`wt step prune` deliberately has no `WORKTRUNK_FIRST_OUTPUT` hook: its first +output is data-dependent (the dry-run path collects and sorts every check +result before printing anything, so e2e ≈ time-to-first-output already; the +live path streams whichever check lands first). Use `benches/prune.rs` for +cadence-tracked numbers and the `prune-*` spans (below) for phase attribution. + ## WORKTRUNK_PREVIEW_BENCH Setting `WORKTRUNK_PREVIEW_BENCH=1` runs `wt switch`'s interactive picker prelude @@ -119,6 +129,7 @@ setup). |---------|------------|-------| | `wt list` | Yes | Post-skeleton tasks. Exits early under `WORKTRUNK_SKELETON_ONLY=1` / `WORKTRUNK_FIRST_OUTPUT=1` — those skip the writing phase. | | `wt remove` | Yes | `prepare_worktree_removal` → `compute_integration_lazy` writes `is-ancestor` / `has-added-changes` / `merge-add-probe` whenever `BranchDeletionMode` is not `ForceDelete` (CLI `--force` is `force_worktree`, not `--force-delete`). | +| `wt step prune` | Yes | Every scanned worktree/branch runs `integration_reason` → the same probe writes as `wt remove`. First scan after new commits is cold; re-runs are warm (`prune_e2e/dry_run_cold` vs `dry_run_warm`). | | `wt switch ` | No | No sha_cache writers on the direct-switch path. | | `wt switch` (picker) | Yes | Preview pre-compute writes `picker-preview/{log,branch-diff,upstream-diff}-…` entries. Exercised under `WORKTRUNK_PREVIEW_BENCH=1` / `WORKTRUNK_PICKER_DRY_RUN=1`. | | `wt` (completion via `COMPLETE=$SHELL`) | No | Only `for-each-ref` + worktree list. | @@ -146,6 +157,63 @@ worth measuring at CI cadence. - Cold cache penalty: ~4x slower for single worktree - Scaling: Warm cache shows superlinear degradation, cold cache scales better +## Recording `wt remove` / `wt step prune` staging + +The removal commands interleave serial per-target work with parallel scans and +detached background processes; a single e2e number hides which phase moved. +Record them in two layers: + +**Criterion cadence** — `benches/remove.rs` and `benches/prune.rs`. Expected +numbers on an M-series Mac (`prune-4-8` fixture: 4 squash-merged worktrees + +4 squash-merged branches as candidates, 8 unmerged worktrees + 8 unmerged +branches as backdrop, 200 commits, 100 files): + +| Variant | Expected | What it measures | +|---------|----------|------------------| +| `prune_e2e/dry_run_cold` | ~153 ms | full parallel scan, integration probes uncached | +| `prune_e2e/dry_run_warm` | ~87 ms | steady-state re-scan, probes hit sha_cache | +| `prune_e2e/live` | ~670 ms | cold scan + serial removal of the 8 candidates (~60 ms each, under the scan write lock) | +| `remove_e2e/first_output` | ~86 ms | single-target validation up to first output | + +Cold prune benches pair `invalidate_caches_auto` with `restore_worktree_indexes`: +deleting a worktree's index makes `git status` report every tracked file as a +staged deletion, which flips prune's clean-worktree removability gate and +silently drops all worktree candidates from the run. The dry-run variants +assert the listed candidate count so that degradation can't come back +unnoticed. + +**Phase attribution** — `wt-perf timeline` plus the removal spans. Prune emits +`prune-gather` (worktree+branch enumeration), `prune-scan` (the whole parallel +check region), one `prune-check:` per scanned item, and one +`prune-remove: