776c43befe
`_prune_stale_worktrees` runs synchronously before the banner on every `hermes -w` launch and shells out to git several times per candidate worktree. On a repo with dozens of accumulated worktrees this dominated startup: measured 18.5s of a 20.6s cold start, 11.6s on warm repeats. The `git cherry` patch-equivalence probe was the single largest cost (9.4s of 11.5s across 24 trees). It is also pure waste on repeat runs: a tree preserved because it holds unpushed work is re-diff-hashed on every launch, forever, always reaching the same verdict. On this repo 19 of 24 aged trees were unreapable, so ~11s per launch bought zero reaps. Two changes, both verdict-preserving: - Split the loop into a stat-only age filter, a parallel read-only classification phase (thread pool, bounded to min(8, cpu_count)), and a serial mutation phase. Only reads are concurrent; unlock/remove/ branch -D stay ordered, so log output and removal order are unchanged. A pool failure falls back to serial rather than blocking startup. - Memoize `git cherry` verdicts to $HERMES_HOME/cache/worktree_merge_verdicts.json, keyed on the exact `(base_sha, head_sha, max_ahead)` range the verdict was computed from. Because that key is the complete input to the git call, a cache hit is identical to recomputation by construction: if either ref moves, the key changes and real git runs again. Bounded to 1000 entries, written atomically, and a corrupt/hand-edited cache degrades to recomputation. Measured on a 44-worktree repo (24 aged candidates): _prune_stale_worktrees before 11.5s after 2.05s cold / 0.42s warm hermes -w to banner before 13.9s after 1.79s Work-preservation is unchanged: all 44 worktrees survived, and every dirty/unpushed/live-locked guard still fires. Verified the 24 real-tree verdicts are byte-identical across serial, cold-cache, and warm-cache runs. Tests: 75/75 in tests/cli/test_worktree.py (67 existing + 8 new). The new cache tests were sabotage-verified — swapping the exact-sha key for a naive path-only key makes two of them fail by deleting a worktree that had gained unmerged work, which is the data-loss case the key prevents.