Summary
Create a performance plugin whose skill drives a measurement-first optimization workflow end to end: pick targets, construct a goal with realistic and ideal tiers, take a baseline snapshot, change something, take a post snapshot, and refuse to claim a win the data does not support.
This issue is written from a real end-to-end run of that workflow, done by hand in one session against the disk-hygiene destructive-guard hook (PR #3523, issues #3527 / #3528). Everything below is a generalization of something that actually happened, including four places where the naive version of the workflow produced a confidently wrong answer.
This issue REQUIRES a /planning:interview session with the user before implementation. The workflow has real design forks (see "Open questions") and the transcript this is drawn from is one domain — a Windows hook launcher. Do not build from this issue alone.
Why a skill, not a checklist
The session it came from had a competent operator and a strong initial prompt, and it still produced these, each caught only by an explicit verification step:
- A benchmark harness that silently measured itself. Its shim directory was
mktemp -d, and the thing under test cached on PATH — so every run was a forced cache miss and the "after" looked identical to the "before". The harness was measuring its own randomization.
- A probe that proved nothing while reporting success. It tested a hard-link case;
os.link failed cross-volume on Windows, the code fell back to shutil.copyfile, and a copy is a different file — so the probe reported "0 gaps" for a case it never exercised. A green result from a check that did not run.
- A "before/after" comparison invalidated by drift. Bare
bash -c true measured 1825 ms and 283 ms in the same hour at ~10% CPU. Any two-pass measurement attributes that 6x to the change. Only interleaving old/new within one run survives it.
- A root cause asserted from a plausible mechanism instead of from data. A parallel session diagnosed WDAC code-integrity enforcement (real,
CodeIntegrityPolicyEnforcementStatus = 2) as the cause of slow spawns, then had to retract it: a 7-sample spread of min 180.5ms / median 1107.7ms / max 2841.3ms, spread ratio 15.74, at 501 concurrent processes, is a contention signature. The bimodality was the diagnosis; the plausible mechanism was a distraction.
None of these are knowledge gaps. They are all "the measurement was wrong in a way that looked right", which is exactly what a skill with enforced gates prevents and a checklist does not.
Proposed workflow
Phase 0 — target identification
Accept targets from any of: the current session's own pain, a named path/component, a telemetry store, or a broad "what is slow here". Rank candidates by evidence quality, not by suspicion. If nothing is measured yet, the top recommendation is "instrument this first" rather than a guess.
Phase 1 — goal construction (interview-gated, user in the loop)
This is where the user is REQUIRED. Produce, together:
- the metric and the exact command that produces it;
- a realistic target and an ideal target, held separately;
- the floor: the irreducible cost the target cannot go below, computed before any work. In the source session this was one process spawn; the goal asked for p50 ≤ 250 ms on a host charging 0.3–0.9 s per spawn, so the goal was unreachable by any code change and knowing that up front would have reframed the whole task;
- what counts as done, including whether merge is in scope.
The skill must be able to say "your target is below the measured floor" and make the user decide, rather than silently failing the goal at the end.
Phase 2 — baseline snapshot
Refuse to proceed without: sample count, p50 AND p95 (never a single sample or a bare mean), the environment's own noise characterization, and a drift-immune counter alongside the wall clock wherever one exists (spawn count, syscall count, query count, allocation count). In the source run the spawn census 4 → 1 was the number that survived review; the milliseconds were not reproducible even by an independent verifier on the same machine an hour later.
Phase 3 — change
Ordinary implementation, with one rule carried over: re-measure the drift-immune counter after every change, because it catches harness bugs immediately. Both harness bugs above surfaced as a counter that did not move when it should have.
Phase 4 — post snapshot
Interleaved A/B by default: alternate arms within one run, flip the order each iteration, report the median of per-pair ratios alongside per-arm percentiles. Under concurrency, report per-arm percentiles ONLY and suppress the paired ratio — the arms are no longer load-matched, and pairing by index compares samples that never shared conditions.
Phase 5 — verification (fresh context)
Dispatch a verifier that does not inherit the implementer's numbers and re-derives them from the trees. In the source session this caught two blocking correctness defects that the implementer, the implementer's own 143-test suite, and a full green CI run had all missed.
Phase 6 — report
State the target as met or not met, with the measurement that explains why. Never round a miss into a win. Separately state any behavior change the optimization introduced.
Non-negotiable gates the skill should enforce
These are the specific things that went wrong, as rules:
- A harness must prove it is not measuring itself. Anything the harness injects into the environment under test (PATH entries, temp dirs, env vars) must be stable across runs, or keyed out of the subject's caching.
- A probe must assert its own precondition. If a test depends on a hard link, a symlink, a specific filesystem, or a permission, it must FAIL when that precondition is unmet, never silently degrade into a weaker test that passes.
- Never compare two separate passes on a drifting host. Characterize drift first (repeat the no-op baseline); if the spread ratio exceeds a threshold, force interleaving.
- A drift-immune counter outranks wall clock in the report whenever one exists.
- p50 and p95 over ≥20 samples, never a single sample, never a bare mean.
- Optimizing a guard requires a differential, not a passing test suite. A suite proves nothing asserted broke; it does not prove behavior is unchanged. And the differential must cover every MODE the subject runs in — the source session's differential ran one of two modes and missed a real deny→ask downgrade in the other.
- Correctness regressions outrank any speedup. If the change alters behavior, that is a first-class finding stated separately, never folded into the performance claim.
Composition with existing plugins
Should reuse rather than reinvent: /planning:interview for Phase 1 (this is the required user-in-the-loop gate), /verification:measure and /verification:confirm if they already cover snapshot mechanics, /discovery:explore for Phase 0 on an unfamiliar codebase, /implementation:implement for Phase 3, review:fanout or a dedicated verifier agent for Phase 5, and /claude-ops:observability / /claude-ops:audit-performance as telemetry sources for Phase 0. The audit-performance engine already reaches bimodal-spawn-latency, which is exactly the Phase 2 noise characterization this skill needs — worth wiring rather than duplicating.
Scope boundary to settle in the interview: /claude-ops:audit-performance diagnoses a slow Claude Code installation. This skill optimizes an arbitrary target and owns the before/after discipline. They overlap at noise characterization and should share it.
Open questions for the interview
- Scope. Any code, or start narrow (hooks and CLI tools, where spawn-count metrics are well-defined) and widen?
- Where do baselines live? Committed artifacts, a plugin data dir, or ephemeral? Committed baselines enable regression detection over time but go stale across machines — and given the drift measured here, a baseline is arguably only valid on the machine and hour that produced it.
- How hard are the gates? Hard-block on a missing baseline, or warn? The source session's value came from gates that actually blocked.
- Cross-machine claims. Is the skill allowed to report a number from a host whose noise it has characterized as pathological, or must it refuse and say "measure elsewhere"?
- Metric catalog. Which drift-immune counters ship built-in (process spawns, syscalls, queries, allocations, bytes) and how are per-domain ones declared?
- Does it own the fix, or only the measurement? Cleanest split is probably measurement + goal + verification, delegating the change to the implementation lane.
- Autonomy. The user-in-the-loop requirement is firm for Phase 1. Are Phases 2–6 allowed to run unattended?
Source material
The transcript this is drawn from covers the whole arc and is worth reading before the interview: target identification from live session pain, goal construction (including a target that turned out to be below the floor), baseline, root-cause confirmation before any edit, implementation, two self-inflicted harness bugs and how each was caught, interleaved A/B, concurrent measurement, a differential correctness proof, independent verification by two fresh-context agents, and two blocking defects found only at that last step.
Concrete artifacts from that run, usable as reference implementations:
- spawn-census via a PATH shim directory (the drift-immune counter);
- interleaved A/B harness with order flipping and a paired-ratio summarizer that suppresses itself under concurrency;
- a differential harness comparing a pre-change and post-change binary over a harvested corpus, requiring byte-identical output;
- the two verifier agent prompts, which are written to be adversarial and to distrust the implementer's numbers.
Related
Summary
Create a
performanceplugin whose skill drives a measurement-first optimization workflow end to end: pick targets, construct a goal with realistic and ideal tiers, take a baseline snapshot, change something, take a post snapshot, and refuse to claim a win the data does not support.This issue is written from a real end-to-end run of that workflow, done by hand in one session against the
disk-hygienedestructive-guard hook (PR #3523, issues #3527 / #3528). Everything below is a generalization of something that actually happened, including four places where the naive version of the workflow produced a confidently wrong answer.This issue REQUIRES a
/planning:interviewsession with the user before implementation. The workflow has real design forks (see "Open questions") and the transcript this is drawn from is one domain — a Windows hook launcher. Do not build from this issue alone.Why a skill, not a checklist
The session it came from had a competent operator and a strong initial prompt, and it still produced these, each caught only by an explicit verification step:
mktemp -d, and the thing under test cached onPATH— so every run was a forced cache miss and the "after" looked identical to the "before". The harness was measuring its own randomization.os.linkfailed cross-volume on Windows, the code fell back toshutil.copyfile, and a copy is a different file — so the probe reported "0 gaps" for a case it never exercised. A green result from a check that did not run.bash -c truemeasured 1825 ms and 283 ms in the same hour at ~10% CPU. Any two-pass measurement attributes that 6x to the change. Only interleaving old/new within one run survives it.CodeIntegrityPolicyEnforcementStatus = 2) as the cause of slow spawns, then had to retract it: a 7-sample spread ofmin 180.5ms / median 1107.7ms / max 2841.3ms, spread ratio 15.74, at 501 concurrent processes, is a contention signature. The bimodality was the diagnosis; the plausible mechanism was a distraction.None of these are knowledge gaps. They are all "the measurement was wrong in a way that looked right", which is exactly what a skill with enforced gates prevents and a checklist does not.
Proposed workflow
Phase 0 — target identification
Accept targets from any of: the current session's own pain, a named path/component, a telemetry store, or a broad "what is slow here". Rank candidates by evidence quality, not by suspicion. If nothing is measured yet, the top recommendation is "instrument this first" rather than a guess.
Phase 1 — goal construction (interview-gated, user in the loop)
This is where the user is REQUIRED. Produce, together:
The skill must be able to say "your target is below the measured floor" and make the user decide, rather than silently failing the goal at the end.
Phase 2 — baseline snapshot
Refuse to proceed without: sample count, p50 AND p95 (never a single sample or a bare mean), the environment's own noise characterization, and a drift-immune counter alongside the wall clock wherever one exists (spawn count, syscall count, query count, allocation count). In the source run the spawn census 4 → 1 was the number that survived review; the milliseconds were not reproducible even by an independent verifier on the same machine an hour later.
Phase 3 — change
Ordinary implementation, with one rule carried over: re-measure the drift-immune counter after every change, because it catches harness bugs immediately. Both harness bugs above surfaced as a counter that did not move when it should have.
Phase 4 — post snapshot
Interleaved A/B by default: alternate arms within one run, flip the order each iteration, report the median of per-pair ratios alongside per-arm percentiles. Under concurrency, report per-arm percentiles ONLY and suppress the paired ratio — the arms are no longer load-matched, and pairing by index compares samples that never shared conditions.
Phase 5 — verification (fresh context)
Dispatch a verifier that does not inherit the implementer's numbers and re-derives them from the trees. In the source session this caught two blocking correctness defects that the implementer, the implementer's own 143-test suite, and a full green CI run had all missed.
Phase 6 — report
State the target as met or not met, with the measurement that explains why. Never round a miss into a win. Separately state any behavior change the optimization introduced.
Non-negotiable gates the skill should enforce
These are the specific things that went wrong, as rules:
Composition with existing plugins
Should reuse rather than reinvent:
/planning:interviewfor Phase 1 (this is the required user-in-the-loop gate),/verification:measureand/verification:confirmif they already cover snapshot mechanics,/discovery:explorefor Phase 0 on an unfamiliar codebase,/implementation:implementfor Phase 3,review:fanoutor a dedicated verifier agent for Phase 5, and/claude-ops:observability//claude-ops:audit-performanceas telemetry sources for Phase 0. The audit-performance engine already reachesbimodal-spawn-latency, which is exactly the Phase 2 noise characterization this skill needs — worth wiring rather than duplicating.Scope boundary to settle in the interview:
/claude-ops:audit-performancediagnoses a slow Claude Code installation. This skill optimizes an arbitrary target and owns the before/after discipline. They overlap at noise characterization and should share it.Open questions for the interview
Source material
The transcript this is drawn from covers the whole arc and is worth reading before the interview: target identification from live session pain, goal construction (including a target that turned out to be below the floor), baseline, root-cause confirmation before any edit, implementation, two self-inflicted harness bugs and how each was caught, interleaved A/B, concurrent measurement, a differential correctness proof, independent verification by two fresh-context agents, and two blocking defects found only at that last step.
Concrete artifacts from that run, usable as reference implementations:
Related
bimodal-spawn-latencysignature this skill should reuse for noise characterization.