Skip to content

feat(performance): add the measurement-first optimization plugin - #3561

Open
kyle-sexton wants to merge 7 commits into
mainfrom
feat/performance-plugin
Open

feat(performance): add the measurement-first optimization plugin#3561
kyle-sexton wants to merge 7 commits into
mainfrom
feat/performance-plugin

Conversation

@kyle-sexton

@kyle-sexton kyle-sexton commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds the performance plugin: a measurement-first optimization workflow for an arbitrary target,
built around refusing to report what the data does not support.

Generalized from one end-to-end run of that workflow done by hand against the disk-hygiene
destructive-guard hook (#3523). That session had a competent operator and a strong prompt, and it
still produced five verification harnesses that each returned a confident wrong answer rather than
an error
. Four of the five were checks written specifically to avoid being fooled. That
disproportion is the plugin's whole reason for existing: a workflow that measures without enforcing
harness-integrity rules mostly generates confident numbers, which is worse than generating none.

The design was settled by the /planning:interview #3530 requires. Nine questions answered by the
user, three deferred to planning, all recorded in docs/topics/performance-plugin/PLAN.md and
summarized on the issue.

Fix

Four skills, each naming its successor rather than routing through a hub, the way the planning
pipeline already chains:

Skill Owns
target Ranks candidates by evidence quality (E1 attributed measurement to E4 suspicion). Nothing above E3 means the recommendation is "instrument this first", not a ranked guess.
goal Human-gated always. Computes the irreducible floor before the target is agreed, and stops when the target sits below it.
snapshot Qualifies the host, then captures. Interleaved or duet A/B, counter ranked above duration, and the refusal.
verify Fresh-context re-derivation that does not inherit the implementer's numbers, plus a report that never rounds a miss into a win.

Named snapshot, not measure: Q2 locked "depend + route" on /verification:measure, and two
skills called measure is that routing line failing to route. measure keeps baseline capture,
storage and compare mechanics, and gains one gotcha pointing here for hosts a noise-floor warning
cannot describe.

The shared lib becomes a registered cluster. A cross-plugin runtime import was never available,
since plugins install independently. So lib/spawn_noise.py is carried as a byte-identical copy with
scripts/sync-spawn-noise.sh, a registry entry, and the spawn-noise-sync CI lane, the mechanism
this repo already uses for six clusters. The canonical gains is_measurable() (the refusal verdict)
and percentile_floor() (the 1/(1-p) sample floor).

Two places the research contradicted the issue, and the code follows the evidence

Three claims the literature does not ground, labelled rather than dressed up

  • Sample count. No benchmarking-community figure exists beyond the derivable 1/(1-p) floor. The
    p50/p95-over-20 default is a labelled house convention; only the arithmetic floor is enforced.
  • p95 itself. "Median plus a high-order percentile" is grounded (SRE Book ch. 4), but the
    percentiles that chapter names are the 99th and 99.9th.
  • Counts over wall clock is grounded only for instruction counts. Extending it to process
    spawns is this plugin's own generalization, and it is load-bearing here because spawn count is the
    headline metric and Valgrind does not run on Windows.

Two citation traps the skill bodies avoid on purpose: benchstat is unpaired (it recommends
interleaved collection but analyzes with Mann-Whitney U), and coordinated omission is a
load-generator problem, so citing Tene for a synchronous harness would miscite the field's
best-known source.

Verification

  • All four skills PASS check-skill.sh with 0 errors and 0 warnings.
  • scripts/sync-spawn-noise.test.sh — 7 assertions, passing.
  • plugins/claude-ops/lib/spawn_noise.test.sh — 9 assertions, passing.
  • audit_performance.test.sh — 45 tests, passing, unmodified.
  • scripts/check-lane-coverage.sh --check — all 50 lanes reachable from ci-status.needs, including
    the new one.
  • scripts/check-cross-plugin-source-drift.sh --check — no unregistered or drifted clusters.
  • run-ruff.sh clean on both lib copies; markdownlint clean; no em dashes in any new surface.

The gates were proven to discriminate, not assumed to. This is the plugin's own doctrine applied
to its own code, and it matters because four of the five catalogued harness failures were checks that
exited identically in both arms and reported a confident verdict:

  • The sync gate. Its suite drifts a copy's BIMODAL_SPREAD_RATIO and asserts the clean and
    drifted arms return different verdicts, not merely that each printed its expected string.
  • The two-part bimodal predicate. Deleted the high >= SLOW_SPAWN_FLOOR_MS clause by hand; the
    suite failed with the assertion it was written to produce; restored; confirmed with an empty
    git diff rather than trusting the restore. Done after committing, because harness defect feat(hook-telemetry): marketplace-wide telemetry contract + markdown-formatter producer #5
    in the catalogue was a git checkout -- restore over uncommitted work that destroyed it.
  • The refusal itself. test_a_quiet_host_is_measurable_and_a_contended_one_is_not runs both a
    low-variance and a high-variance host and asserts the verdicts differ, because a refusal that fires
    on every host refuses nothing. The snapshot eval suite carries the same positive/negative pair.

The harnesses

Nine scripts under plugins/performance/scripts/, each with a co-located suite, 200 assertions
total. Ported from the source run's scratch tree, which lived on local disk only and would have died
with that directory.

spawn-census.sh / run-spawn-census.sh use a stable shim dir, closing the defect where a
mktemp -d shim put a fresh path on PATH every run against a PATH-keyed cache, so the census
measured its own randomization and reported "no improvement". ab.sh + summarize.py + ratio.py
interleave the arms and flip order per iteration. differential.py proves behavior over an argv
matrix. discriminate.py consolidates five variants, four of which were broken.

The verifiers found seven real defects between them, all fixed. The two that matter most:

  • discriminate.py scored a check that never ran. With no signal configured the signal is the
    exit code, so any shared non-zero rc reported NOT DISCRIMINATING with an affirmatively false
    explanation. It now splits identical-failing (HARNESS BROKEN, exit 2) from identical-passing
    (NOT DISCRIMINATING, exit 1). The four original harness failures that exited 127 in both arms
    would now be caught rather than reported clean.
  • The sample floor guarded one statistic out of three. Two identical true arms produced
    median_paired_ratio=1.06x beside ratio_of_p50=12.08x, so a reader could quote a 12x speedup
    between true and true. All three are gated now.

Also fixed: a 126 subject censused as spawns=0 exit 0; a spliced row ratio.py accepted that
summarize.py rejects; printf | subject under pipefail fabricating exit 141 intermittently on a
pipe-buffer race; and an os reference with no import on a line no test reached, which is exactly
the "check that never ran" shape that harness exists to detect.

Rule 4 is proven behaviorally, not asserted: the target is committed, the fix applied and left
uncommitted, and the fix is still present after the run. A git checkout -- restore would have
destroyed it, which is what defect #5 in the source catalogue actually did.

Related

Closes #3530. Depends on #3553 (merged), which promoted the lib.

Every acceptance criterion on that issue is met: the manifest validates, all four skills pass
check-skill.sh with zero warnings, the refusal is asserted with both a high-variance and a
low-variance arm shown to differ, the drift-immune counter is ranked above any duration in the
emitted report, the design questions were answered by the user in a /planning:interview
linked from the issue,
and every normative claim carries a source tier with the ungrounded ones labelled as house rules.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 1, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-01T11:11:01.037553Z eeceb80 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: eeceb808ad

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +117 to +118
committed**, matching `/verification:measure`, which owns baseline capture and storage mechanics.
This skill depends on it rather than reimplementing it.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Declare verification as a hard dependency

When a user installs performance by itself, /verification:measure is unavailable, yet this skill delegates the baseline capture and storage mechanics to it and provides no fallback. The new plugin.json declares no dependencies, so the primary target → goal → snapshot workflow cannot complete in a standalone installation; either add the native dependency or presence-gate this invocation and provide local baseline mechanics.

Useful? React with 👍 / 👎.

Comment on lines +23 to +26
```python
from spawn_noise import spawn_probe, is_measurable
summary = spawn_probe()
measurable, why = is_measurable(summary)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Anchor the spawn-noise import to the plugin root

When this snippet runs from the consuming project's normal working directory, spawn_noise is neither an installed module nor on sys.path, because it lives under ${CLAUDE_PLUGIN_ROOT}/lib; executing the documented code from the repository root raises ModuleNotFoundError. Since host qualification is the mandatory first snapshot step, the skill should explicitly load the module from the plugin's lib directory rather than relying on the current directory.

Useful? React with 👍 / 👎.

Comment on lines +149 to +153
if "bimodal-spawn-latency" in findings:
return False, (
f"spawn cost spread {summary.get('spread_ratio')}x across identical no-op spawns "
f"(min {summary.get('min_ms')} ms, max {summary.get('max_ms')} ms), with the slow mode "
f"above the {SLOW_SPAWN_FLOOR_MS} ms floor: the bimodal contention signature"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Prioritize timeout evidence over bimodality

When a probe has both successful samples and at least one timeout, summarize_spawn_samples() commonly adds both bimodal-spawn-latency and spawn-probe-timed-out, but this earlier branch wins. The resulting reason presents the timeout ceiling as a measured finite maximum and omits that the tail is actually unbounded, undermining the evidence attached to the refusal; handle the timeout finding before constructing the bimodal min/max explanation.

Useful? React with 👍 / 👎.

@kyle-sexton
kyle-sexton force-pushed the feat/performance-plugin branch from eeceb80 to 4ca4a09 Compare September 1, 2026 14:32
@claude

claude Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 3m 53s —— View job


/review:code-review — code-review lane

Followed plugins/review/skills/code-review/SKILL.md directly (invoking it via the Skill tool errored with no output, so I read the skill body and applied it manually). Scope: files changed in this PR (git diff origin/main...HEAD), against CLAUDE.md/repo conventions. Security is out of scope for this lane per the skill's gotchas.

  • Gather context
  • Review changed skill/lib/CI files
  • Post inline findings
  • Post summary

Findings (posted inline)

  1. snapshot/SKILL.md:118 and goal/SKILL.md:113-114 — both skills state an unconditional dependency on /verification:measure for baseline storage, and plugin.json declares no dependency. This diverges from the repo's own established pattern for identical coupling: verification/skills/measure/SKILL.md:67 gates its reciprocal route with "when the performance plugin is installed", and planning/skills/plan/SKILL.md:126 gates its call to /verification:measure with "if installed... Or measure manually". performance doesn't reciprocate either pattern, so a standalone performance install (which the plugin's own README treats as a real usage mode) has no fallback for target → goal → snapshot.
  2. snapshot/SKILL.md:23-27 — the documented host-qualification step (from spawn_noise import spawn_probe, is_measurable) has no path anchoring to ${CLAUDE_PLUGIN_ROOT}/lib, unlike every other cross-plugin script reference in this repo (plugins/claude-ops/skills/*/SKILL.md all anchor via ${CLAUDE_PLUGIN_ROOT}). Following the step as written raises ModuleNotFoundError.
  3. lib/spawn_noise.py:146-156is_measurable() checks bimodal-spawn-latency before spawn-probe-timed-out. When a probe has both a real bimodal spread and a timeout, the reported reason presents the timeout ceiling as a measured finite max and omits that the tail is unbounded. The verdict doesn't change, but the stated basis does — and this module's whole design point is that the basis is what a reader acts on. The new TestMeasurabilityVerdict cases in test_spawn_noise.py don't cover this combined case either.

Findings 1-2 substantively overlap with Codex's automated review on this PR (same two lines); I independently confirmed both by checking actual repo precedent (grep-ing for a real dependencies field in any plugin.json, and comparing against planning:plan's and verification:measure's own gating conventions) rather than taking the automated finding at face value. Finding 3 is additional, not previously flagged.

Everything else checked and clean

  • plugins/performance/lib/spawn_noise.py is byte-identical to the canonical plugins/claude-ops/lib/spawn_noise.py copy (confirmed with diff), matching the PR's sync-cluster claim.
  • scripts/sync-spawn-noise.sh, the CI spawn-noise-sync job, and the cross-plugin-source-registry.txt entry follow the existing sync-cluster pattern used by the other five clusters.
  • target/SKILL.md and verify/SKILL.md — no issues found; evidence-tier and fresh-context-verification discipline is coherent and well-grounded.
  • reference/harness-integrity.md and skills/snapshot/evals/evals.json — solid, and the eval set includes the negative/positive discrimination pair the PR body describes.
  • marketplace.json / docs/CATALOG.md / version bumps on claude-ops and verification — consistent with repo conventions.
  • I did not run check-skill.sh, run-ruff.sh, or the test suites myself (sandboxed Bash required approval I didn't have in this run) — the PR body's verification claims (0 errors/warnings, passing test counts) are author-claimed and unverified by me, not independently confirmed.

Not evaluated: PLAN.md content, README.md/CHANGELOG.md prose, and the citation/grounding claims in the SKILL.md bodies (Duet Benchmarking, SRE Book, coordinated omission) — these are outside the code-review lane's high-signal bar (no correctness bug attaches to them) and security is scoped to the separate security-review lane.

@claude

claude Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 1m 24s —— View job


Claude finished the security review

  • Gather context (PR body, diff, review comments)
  • Run /review:security-review per custom instructions
  • Post findings

CI security review (/review:security-review)

Reviewed the full diff (origin/main...HEAD, 24 files) for logic, trust-boundary, and GitHub Actions security issues (static-analysis-adjacent findings like unpinned actions or pull_request_target misuse are zizmor's lane, not this one).

No security issues found.

What I checked:

  • New spawn-noise-sync CI job (.github/workflows/ci.yml): checkout is SHA-pinned, persist-credentials: false is set, and the job runs no pull_request_target / workflow_run with secrets over untrusted code. No permission widening.
  • plugins/performance/lib/spawn_noise.py and its canonical twin in claude-ops: subprocess.run is called with a fixed argv list (["/bin/sh", "-c", "exit 0"] / ["cmd", "/c", "exit"]), never shell=True, and never with any value derived from user/host input — no command-injection surface. The module's own docstring makes this an explicit design constraint ("Never runs a discovered hook, statusline command, or MCP server").
  • scripts/sync-spawn-noise.sh and scripts/sync-spawn-noise.test.sh: follow the existing sync-cluster.sh pattern used by the other five clusters; no unsanitized interpolation into shell commands, test fixtures build in mktemp -d temp trees.
  • Manifest/registry changes (marketplace.json, plugin.json files, cross-plugin-source-registry.txt): metadata only, no allowed-tools or permission grants added on any of the four new skills (target, goal, snapshot, verify all ship with no allowed-tools frontmatter).
  • New SKILL.md / reference docs: no network calls, eval/exec, or shell-command construction from external input.

Two non-security review comments already posted by Codex on this PR (/verification:measure dependency declaration on snapshot, and the plugin-root import path) are correctness/packaging concerns, not security findings, so they're out of scope for this lane.

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

Last security-reviewed head: 20e9433ec992b861da107591ed8ba1d7ff091f1a. On the next push, the relevance gate compares only the commits since this SHA; delete this comment to force a full re-review.


Baselines live in the memory tier, `.work/<topic-slug>/baselines/`, machine-bound, **never
committed**, matching `/verification:measure`, which owns baseline capture and storage mechanics.
This skill depends on it rather than reimplementing it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness/architecture: unconditional dependency on /verification:measure with no gate or fallback, and no manifest declaration.

plugins/performance/.claude-plugin/plugin.json declares no dependencies. This line and goal/SKILL.md's boundary section (This plugin depends on it rather than reimplementing it., line ~114) state the dependency as unconditional, with no "if installed" check and no manual fallback.

That's inconsistent with how this repo already handles the same coupling elsewhere:

  • verification/skills/measure/SKILL.md:67 routes to /performance:snapshot gated with "when the performance plugin is installed".
  • planning/skills/plan/SKILL.md:126 invokes /verification:measure ... via the Skill tool if installed. ... Or measure the pre-change state manually.

performance doesn't reciprocate either pattern: if someone installs performance standalone (a real path — the plugin's own README lists it as usable on its own), target → goal → snapshot has no way to complete the baseline-storage step, and no fallback is offered.

Confirmed via grep -rn '"dependencies"' plugins/*/.claude-plugin/plugin.json — no plugin.json in this repo actually uses a manifest dependency field (the one hit was a keyword string, not a real field), so a soft "if installed, else fallback" gate — matching the two examples above — is the house convention to follow here, not a new manifest field.

Comment on lines +23 to +27
```python
from spawn_noise import spawn_probe, is_measurable
summary = spawn_probe()
measurable, why = is_measurable(summary)
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness: this import example has no path anchoring, so it fails as documented.

from spawn_noise import spawn_probe, is_measurable

spawn_noise lives at ${CLAUDE_PLUGIN_ROOT}/lib/spawn_noise.py. It's neither installed nor on sys.path when run from a consuming project's working directory (the normal execution context for skill-invoked code in this repo). Every other cross-plugin script reference in this codebase anchors to ${CLAUDE_PLUGIN_ROOT} explicitly — e.g. plugins/claude-ops/skills/*/SKILL.md invoke scripts as python3 "${CLAUDE_PLUGIN_ROOT}/skills/.../scripts/x.py". This snippet should do the equivalent, e.g.:

import sys
sys.path.insert(0, f"{plugin_root}/lib")
from spawn_noise import spawn_probe, is_measurable

or invoke it as a subprocess against the anchored path. As written, following this step literally (host qualification, which the skill calls mandatory and first) raises ModuleNotFoundError.

Comment on lines +146 to +156
findings = summary.get("findings", [])
if "no-spawn-samples-captured" in findings:
return False, "no spawn samples were captured, so the host was never characterized"
if "bimodal-spawn-latency" in findings:
return False, (
f"spawn cost spread {summary.get('spread_ratio')}x across identical no-op spawns "
f"(min {summary.get('min_ms')} ms, max {summary.get('max_ms')} ms), with the slow mode "
f"above the {SLOW_SPAWN_FLOOR_MS} ms floor: the bimodal contention signature"
)
if "spawn-probe-timed-out" in findings:
return False, "at least one no-op spawn hit the probe timeout, so the tail is unbounded"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness: bimodal-spawn-latency is checked before spawn-probe-timed-out, so a co-occurring timeout is silently absorbed into a finite-max explanation.

summarize_spawn_samples can append both findings for the same probe: a timed-out sample is recorded as timeout_s * 1000.0 in durations_ms (line ~113), which can itself trip the bimodal spread/floor predicate, and the timeouts counter is checked independently and unconditionally appends spawn-probe-timed-out too. When both are present, this branch order means is_measurable() returns the bimodal reason — reporting max {max_ms} ms as a real measured ceiling — and never mentions that the tail is actually unbounded (a timeout, not a real sample).

The verdict (False) doesn't change either way, but the reason does, and this module's whole design point (per the module docstring and harness-integrity.md) is that the refusal's stated basis is what a reader acts on. Swapping the order so the timeout check runs first would fix it:

if "spawn-probe-timed-out" in findings:
    return False, "at least one no-op spawn hit the probe timeout, so the tail is unbounded"
if "bimodal-spawn-latency" in findings:
    ...

test_spawn_noise.py's new TestMeasurabilityVerdict cases don't exercise a combined bimodal+timeout sample set, so this ordering wasn't caught by the added tests either.

Comment on lines +113 to +114
- **Does not store baselines.** `/verification:measure` owns baseline capture and storage; this
plugin depends on it rather than reimplementing it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same unconditional-dependency issue as snapshot/SKILL.md:118 (see that comment for the full analysis): "/verification:measure owns baseline capture and storage; this plugin depends on it rather than reimplementing it." No "if installed" gate, no fallback, and plugin.json declares no dependency — inconsistent with how verification:measure and planning:plan gate this same coupling elsewhere in the repo.

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

Claude has reviewed this PR 3 times. The lane skips further automatic reviews after 5; deleting this comment resets the count.

@claude

claude Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 3m 15s —— View job


/review:code-review — code-review lane

  • Gather context (PR body, diff, prior reviews)
  • Determine review scope: 3 new commits since the last code-review pass (898309b, e40c23d, 94f9db7) added the entire plugins/performance/scripts/ harness directory (~2,500 lines), which has not been reviewed yet
  • Review new scripts/ harness content
  • Re-check status of previously-flagged findings (dependency gating, import anchoring, bimodal/timeout ordering)
  • Post inline findings
  • Post summary

@claude

claude Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 2m 6s —— View job


/review:security-review — security-review lane

  • Gather context (PR diff via gh pr diff, since git diff origin/main...HEAD has no local merge base under this checkout)
  • Invoke /review:security-review (Skill tool errored with no output as it did on the prior run for this PR; read plugins/review/skills/security-review/SKILL.md directly and followed it)
  • Post findings

Result: No security issues found.

This run's HEAD (94f9db7) supersedes the previously security-reviewed commit (4ca4a09) with substantial new content — the entire plugins/performance/scripts/ directory (ab.sh, harness-lib.sh, spawn-census.sh, run-spawn-census.sh, differential.py, discriminate.py, pathfix.py, ratio.py, summarize.py, plus their test files) that wasn't in scope for the prior review. I reviewed that new surface in full, in addition to re-confirming the previously-reviewed files are unchanged in a way that matters here.

What I checked:

  • All subprocess/bash -c call sites in the new scripts (ab.sh, spawn-census.sh, differential.py, discriminate.py, pathfix.py) — every Python subprocess.run call uses an argv list, never shell=True, and every value passed is either a fixed literal or an operator-supplied path/config value, never externally-attacker-controlled input. ab.sh/spawn-census.sh do run bash -c "$CMD_A" etc., but that's the tool's actual purpose (an A/B and spawn-census harness for arbitrary local commands the operator supplies, same trust model as hyperfine/benchstat) — not an injection surface from any untrusted source.
  • discriminate.py's file-patching flow (writes/restores a target file via a byte-verified sidecar, never git checkout --) — no unsafe deserialization, no path traversal beyond operator-supplied config, restore-verification is defense-in-depth for correctness rather than a security boundary.
  • pathfix.py's cygpath invocation — resolved via shutil.which(), invoked as an argv list with a fixed -w flag, no shell.
  • New spawn-noise-sync CI job (.github/workflows/ci.yml) — checkout is SHA-pinned, persist-credentials: false, no pull_request_target/workflow_run with secrets over untrusted code, no permission widening. Matches the existing five sync-cluster jobs' pattern exactly.
  • marketplace.json / .claude/settings.json / plugin manifest changes — metadata and enablement flags only; no allowed-tools or permission grants added on any of the four new skills.
  • plugins/performance/lib/spawn_noise.py — re-confirmed byte-identical to the canonical claude-ops copy; same fixed-argv, no-shell=True design as previously reviewed.

Two non-security findings already posted on this PR (unconditional /verification:measure dependency with no fallback; unanchored spawn_noise import path) are correctness/packaging concerns from the code-review lane, out of scope here.

kyle-sexton and others added 7 commits September 1, 2026 20:28
Records the outcome of the /planning:interview that issue #3530 requires
before implementation. Twelve questions registered, nine answered by the
user, three deferred to planning with arbiter tags.

Two decisions diverge from #3530's own text and say so:

- Phase 4's "suppress the paired ratio under concurrency" is corrected.
  Duet Benchmarking (Bulej et al., ICPE 2020) measured 5.03x and 37.4x
  accuracy improvements from running arms in parallel on shared machines,
  because both arms absorb the same interference. Sequential interleaving
  keeps the suppression rule; simultaneous paired arms do not.
- The unmeasurable-host refusal ships as a house rule, not as field
  consensus. No benchmarking tool surveyed refuses above a variance
  threshold; they warn and print anyway.

The brief also records that the plugin's headline metric, a process-spawn
count, rests on a rationale the literature grounds only for instruction
counts. That gap is labelled rather than smoothed over.

Refs #3530

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDkZJ87i7h8J9KzDNruvuS
Q11 — four skills, no router: target, goal, snapshot, verify, each naming
its successor the way the planning pipeline already chains. Named
`snapshot` rather than `measure` because Q2 locked "depend + route" on
/verification:measure and two skills called `measure` is that routing line
failing to route. Harness integrity ships as a shared reference plus a
script rather than a fifth skill; it is a discipline applied inside the
other skills, not a standalone invocation.

Q10 — a cross-plugin runtime import is not available, since plugins
install independently. The interview's "shared lib" answer is implemented
through the mechanism this repo already uses for six other clusters:
canonical source at lib/, byte-identical plugin copies, a dedicated
sync-*.sh gate, a registry entry, and a CI job. One home for the
threshold, loud drift, no runtime coupling.

Recorded while resolving it: the noise threshold is a two-part predicate
(spread ratio >= 3.0 AND max >= the slow-spawn floor), not a bare ratio. A
cold-then-warm spawn pair clears 3x while every sample is still fast, so a
consumer that re-derives a verdict from the ratio alone would report
contention on a healthy host.

Split into two PRs: the lib promotion and claude-ops refactor first, the
new plugin second. The refactor is test-invisible — audit-performance
re-exports the promoted names, so its six existing cases prove it.

Q12 (sample count and percentile choice) stays USER-RESERVED and is
surfaced at the approval gate, not resolved here.

Refs #3530

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDkZJ87i7h8J9KzDNruvuS
Partial scaffold. Skills, lib copy, sync gate, and marketplace entry still
to come.

Refs #3530

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDkZJ87i7h8J9KzDNruvuS
Implements #3530 to the contract the required /planning:interview settled
(docs/topics/performance-plugin/PLAN.md).

Four skills, each naming its successor rather than routing through a hub:
target ranks candidates by evidence quality (an unmeasured system yields
"instrument this first", not a guess); goal is human-gated and computes the
irreducible floor BEFORE the target is agreed; snapshot qualifies the host
before measuring anything; verify re-derives the result in fresh context and
reports it without rounding a miss into a win.

Named `snapshot`, not `measure`. Q2 of the interview locked "depend + route"
on /verification:measure, and two skills called `measure` is that routing
line failing to route. That skill keeps baseline capture, storage, and the
compare mechanics; this plugin adds what it does not cover and gains a
gotcha pointing here for hosts a noise-floor warning cannot describe.

The lib gains is_measurable() and percentile_floor(), and performance now
carries lib/spawn_noise.py as a registered cross-plugin cluster with a
dedicated sync gate and CI lane, so the bimodal threshold keeps one home.
Plugins install independently, so a runtime import across the boundary was
never available; the byte-identical-copy mechanism this repo already uses
for six clusters is how the constraint is actually met.

Two places where the research contradicted the issue, and the code follows
the evidence:

- #3530 says to suppress the paired ratio under concurrency. Duet
  Benchmarking (Bulej et al., ICPE 2020) measured 5.03x and 37.4x accuracy
  gains from running arms in PARALLEL on shared machines, because both arms
  absorb the same interference. Both modes ship; the suppression rule is
  scoped to the sequential form, and that reconciliation is labelled as this
  plugin's reading rather than a sourced claim.
- The unmeasurable-host refusal ships as a house rule. No surveyed tool
  refuses above a variance threshold; pyperf, Criterion, JMH and benchstat
  all warn and print anyway.

Three claims the literature does not ground are labelled rather than
dressed as consensus: the p50/p95-over-20 sample default (only the derivable
1/(1-p) floor is real, and only that floor is enforced), p95 itself (the SRE
Book names the 99th and 99.9th), and counts-over-wall-clock for anything but
instruction counts, which is load-bearing here because process-spawn count
is the headline metric and Valgrind does not run on Windows.

Verification: all four skills PASS check-skill.sh with zero warnings; the
sync gate's own suite proves --check DISCRIMINATES by asserting the clean
and drifted arms return DIFFERENT verdicts, not merely that each printed its
expected string; ruff clean; markdownlint clean; no em dashes in any new
surface.

Refs #3530

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDkZJ87i7h8J9KzDNruvuS
Two CI gates, both real:

plugin-catalog-enablement required an enabledPlugins key. .claude/cloud-bootstrap.sh
computes what it installs from that file, so a catalogued plugin with no key
never loads in a session here.

contract-slice-prune required docs/topics/performance-plugin/ to go. That tree
is contract tier: committed on a task branch, pruned before merge. Its durable
outcomes graduated to issue #3530 first (comment 5501823163) — the Q10/Q11/Q12
resolutions, the two-part bimodal predicate, and why a cross-plugin runtime
import was never available. The interview ledger was already linked there.

Refs #3530

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDkZJ87i7h8J9KzDNruvuS
…ites

Completes the plugin. Two parallel workers, each gated by its own
fresh-context verifier that executed rather than read.

## Harnesses (plugins/performance/scripts/)

Nine scripts, each with a co-located test suite, 200 assertions total.
Ported from the source run's scratch tree, which lived on local disk only
and would have died with that directory.

spawn-census.sh / run-spawn-census.sh use a STABLE shim dir, closing the
defect where a mktemp -d shim put a fresh path on PATH every run against a
PATH-keyed cache, so the census measured its own randomization and reported
"no improvement". ab.sh + summarize.py + ratio.py interleave the arms and
flip order per iteration, suppressing the paired ratio under concurrency.
differential.py proves behavior over an argv matrix. discriminate.py
consolidates five variants, four of which were broken.

The verifiers found seven real defects between them, all fixed:

- discriminate.py scored a check that never ran. Any shared non-zero exit
  read as NOT DISCRIMINATING with an affirmatively false explanation. It now
  splits identical-failing (HARNESS BROKEN, exit 2) from identical-passing
  (NOT DISCRIMINATING, exit 1), so the four original harness failures that
  exited 127 in both arms would now be caught rather than reported clean.
- ratio.py printed a headline ratio with no sample floor: two identical arms
  measured 0.78x to 17.12x at five pairs.
- The floor then guarded only the headline. Two identical `true` arms gave
  median_paired_ratio=1.06x beside ratio_of_p50=12.08x, so a reader could
  quote a 12x speedup between `true` and `true`. All three statistics are
  gated now.
- spawn-census.sh censused a 126 subject as spawns=0, exit 0.
- ratio.py accepted a spliced row summarize.py rejects.
- printf | subject under pipefail fabricated exit 141 intermittently on a
  pipe-buffer race whenever the subject did not drain stdin.
- discriminate.py referenced os with no import, on a line no test reached.
  A line no test executes is the exact shape that harness exists to detect.

Rule 4 is proven behaviorally, not asserted: the target is committed, the
fix applied and left uncommitted, and the fix is still present after the run.
A git checkout restore would have destroyed it, which is what defect #5 in
the source catalogue actually did.

## Evals

target (5 cases), goal (6), verify (7), joining snapshot (5). Each case pins
a specific gate whose removal would reintroduce a real failure: E4 suspicion
never outranking E1 measurement, STOP when the target is below the floor,
the differential covering every mode, a miss never rounded into a win.

Refs #3530

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDkZJ87i7h8J9KzDNruvuS
The undrained-stdin assertion searched the whole ab.sh output for the
string "141" to prove no fabricated exit code. That collides with timing
data: a legitimate 141ms sample prints min=141ms and fails the assertion
for a reason unrelated to what it tests. An exit code only ever appears as
a dict key, so "141:" is the form that means what was meant.

Adds a positive companion asserting both arms report a clean rc census,
since not-containing a failure string is weaker evidence than containing
the success one.

Refs #3530

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RDkZJ87i7h8J9KzDNruvuS
@kyle-sexton
kyle-sexton force-pushed the feat/performance-plugin branch from 94f9db7 to 20e9433 Compare September 2, 2026 00:35
@claude

claude Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 3m 16s —— View job


/review:code-review — code-review lane

  • Gather context (PR diff, prior reviews, custom instructions)
  • Invoke /review:code-review skill and follow it exactly
  • Confirm status of previously-flagged findings — all three still unresolved at HEAD 20e9433
  • Manually review the new plugins/performance/scripts/** harness content (differential.py, discriminate.py, pathfix.py, ratio.py, summarize.py, ab.sh, harness-lib.sh, spawn-census.sh, run-spawn-census.sh) — found one new correctness issue in differential.py
  • Independent second pass over the same scripts/ surface, adversarial check
  • Post inline findings
  • Post summary

@claude

claude Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Claude finished @kyle-sexton's task in 2m 11s —— View job


/review:security-review — security-review lane

  • Gather context (PR body, diff, prior reviews)
  • Invoke /review:security-review per custom instructions
  • Post findings

Result: skip gate hit — no new security-relevant surface since the last full pass

This PR has already had two full security-review passes on this thread: one against the initial skill/lib/manifest surface, and a follow-up that covered the entire plugins/performance/scripts/ harness directory (ab.sh, harness-lib.sh, spawn-census.sh, run-spawn-census.sh, differential.py, discriminate.py, pathfix.py, ratio.py, summarize.py, and their tests) once that directory landed. Both concluded no security issues.

The only commit added since that last full pass is 20e9433, which touches exactly one file:

  • plugins/performance/scripts/ab.test.sh (+10/-1) — swaps a bare "141" substring match for the stricter "141:" rc-census-key match in an existing test assertion, and adds a positive companion assertion that both arms report a clean rc={0: 4} census. Pure test-assertion tightening; no new code path, no subprocess/shell call, no CI workflow or permission change.

Per the skill's skip gate ("this head already has a successful security review that still applies"), there's no new security-relevant surface to review at this head. No security issues found.

Two non-security findings from the earlier code-review pass remain open on this PR (unconditional /verification:measure dependency with no fallback gate; unanchored spawn_noise import path) — those are correctness/packaging concerns from the /review:code-review lane, not security, and are unaffected by this commit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

New plugin: performance — measurement-first optimization workflow (baseline/post snapshots, realistic vs ideal goal tiers, drift-immune metrics)

1 participant