Lock in a verified performance win: ratchet its counter in CI with a checked-in ceiling, so a regression fails the build and a lower count proposes a lower ceiling by PR. Proposes files; a human approves and merges. Use when: 'protect this win', 'ratchet this counter', 'stop this regressing', 'add a performance guardrail to CI'. Runs once after /performance:verify reports MET on a counter. Skip when the result is a duration only, or NOT MET.
Pro scans all 2 files and shows the line behind each finding
Scanned 10/4/2026
npx -y skills add melodic-software/claude-code-plugins --skill protect --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Protect?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/melodic-software-protect)More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.
---
description: "Lock in a verified performance win: ratchet its counter in CI with a checked-in ceiling, so a regression fails the build and a lower count proposes a lower ceiling by PR. Proposes files; a human approves and merges. Use when: 'protect this win', 'ratchet this counter', 'stop this regressing', 'add a performance guardrail to CI'. Runs once after /performance:verify reports MET on a counter. Skip when the result is a duration only, or NOT MET."
user-invocable: true
argument-hint: "[<counter or claim>]"
disable-model-invocation: false
metadata:
workflow-stage: verify
summary: Hold a verified counter win with a CI ceiling a human merges
---
**Arguments.** `[<counter or claim>]`. e.g. /performance:protect the 4-to-1 spawn reduction
## Purpose
Answers **"what keeps this win from eroding?"**
Performance wins decay in a codebase that keeps moving: nothing asserts the new cost, so the next
change that adds it back passes every test. A checked-in counter ceiling, checked in CI, turns the
win into a build failure the next regression has to answer.
Run it once, after `/performance:verify` reports **MET** on a counter. For a change shipped behind
a flag, run it only after the field read that verify's Next routes to shows the gain; if the read
shows no gain, turn the flag off instead. It proposes files; a human approves them. It never
merges, and no model runs in CI: the check is a script and a number.
Read [`${CLAUDE_PLUGIN_ROOT}/reference/techniques.md#g-protect-the-win`](${CLAUDE_PLUGIN_ROOT}/reference/techniques.md#g-protect-the-win)
for the technique entries this skill applies.
## 1. Choose the counter
- **Counters only, never durations.** A duration ceiling moves with runner load, fails at random,
and teaches people to raise it. Ratchet the headline counter from the verify report.
- **Measure it in the state CI will see.** A counter behind a cache has a cold value and a warm
value; a guard with a per-user cache can count 6 spawns cold and 1 warm. CI runners start cold, so
a ceiling measured warm fails there. Pin the state in the command (unset or empty the cache
location), and measure that.
- **It must be deterministic.** `ratchet.py add` measures twice by default and refuses a counter
whose runs disagree (`${CLAUDE_PLUGIN_ROOT}/reference/harness-integrity.md` rule 1). `--runs N`
sets the run count, at least 1. Fix what varies before ratcheting.
- **A vendored copy may predate `--runs`.** A copy of `ratchet.py` from before plugin 0.5.0 exits 2
on it. Re-copy `ratchet.py`, `ab.sh` and `summarize.py` from `${CLAUDE_PLUGIN_ROOT}/scripts/`
before using the new flags.
## 2. The ceilings file
Propose `.performance/ratchets.json`, created by
`python3 ${CLAUDE_PLUGIN_ROOT}/scripts/ratchet.py add --name <n> --field <f> --goal <g> --command <cmd>`
from the repository root:
```json
{"counters": [{"name": "guard-spawns", "command": "<shell command>", "field": "spawns",
"ceiling": 6, "goal": "<the verified goal this protects>. Correlation: unproven: <reason>"}]}
```
- `command` runs through the shell from the repository root and prints a `<field>=<number>` token.
- `--goal` names the verified goal and ends with the goal's Correlation value, copied as
`Correlation: <pointer>` or `Correlation: unproven: <reason>`.
- **The command must exit non-zero when the subject fails.** A subject that errors out early spends
fewer spawns and passes any ceiling. `spawn-census.sh` exits 0 whatever the subject did and prints
`rc=<n>`, so append `| grep -F ' rc=0 '`.
- The ceiling is the measured value, never a round number above it. Headroom is room for a
regression.
- CI has no plugin installed, so the proposal vendors `ratchet.py` (one stdlib file) into the
repository, for example `.performance/ratchet.py`, unless the repository already carries it.
### Telemetry-derived counters
A count that lives in a telemetry store (spans, events, a log) is measured by a command that
flushes, queries, and prints the token itself; `ratchet.py` only runs the command and parses stdout.
```json
{"name": "tool-calls", "field": "calls", "ceiling": 12,
"goal": "<the verified goal this protects>. Correlation: <pointer>",
"command": "id=$(uuidgen); RUN_ID=$id ./run-subject.sh && ./flush-exporter.sh && ./count-run.sh $id"}
```
- **Scope the query to the run the command started**, by an id it generates, never a time window.
A late batch from the previous run lands in a window and inflates the count.
- **Exit non-zero when the run record is missing, not when the count is zero.** `count-run.sh` is
the counter's query step: it checks for a completion record the subject emits for that id and
exits non-zero without it, so lost telemetry fails the command instead of reading as 0. With the
record present it prints `calls=<n>`, and `calls=0` is valid, since a zero ceiling is legitimate.
The subject's own failure must also fail the command.
- **Force the exporter to flush, or poll until the run's record is complete, before printing.**
`add` and `propose-tighten` measure twice by default, and `--runs` tunes the count. A read taken
before the flush sees a partial count: the runs disagree and `add` refuses, or all read partial
values, agree, and set a ceiling that is too low.
- **CI needs the store.** `check` exits 2 when the command fails, and a runner with no telemetry
store fails it. Either the CI job stands up the store and exporter so the command is
self-contained, or the counter is re-expressed as a count the command prints directly. Otherwise
leave it out of the required ratchet.
- The store query lives in the counter command. `ratchet.py` takes no telemetry dependency.
## 3. The CI check
`ratchet.py check` exits `0` at or below every ceiling, `1` when a counter is above its ceiling
(naming it), and `2` when it could not measure. Any CI that runs a command and reads its exit status
can host it. GitHub Actions:
```yaml
- name: Check performance counter ceilings
run: python3 .performance/ratchet.py check --file .performance/ratchets.json
```
Put the step inside the check the repository already requires for merge. A ratchet outside the
required check reports red and blocks nothing.
## 4. Tightening
When a counter drops, the ceiling drops with it, or the next regression can climb back to the old
ceiling unnoticed. `check` prints `propose-tighten can lower it` whenever a counter sits below its
ceiling; `propose-tighten --write` records the lower value and never raises one.
- **Counter moves only when code changes it:** tighten in the same PR. No schedule is needed.
- **Counter can fall without a PR touching it** (a dependency upgrade, a data-driven count, a
nightly rig): propose a scheduled job that opens a draft PR and stops there.
The proposed workflow file is the setting: keep it to tighten on a schedule, delete it to tighten by
hand.
```yaml
on:
schedule:
- cron: "17 6 * * 1"
workflow_dispatch:
permissions: {}
jobs:
measure:
runs-on: ubuntu-24.04
permissions:
contents: read
outputs:
ceilings: ${{ steps.tighten.outputs.ceilings }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- id: tighten
run: |
python3 .performance/ratchet.py propose-tighten --write
git diff --quiet -- .performance/ratchets.json && exit 0
echo "ceilings=$(jq -c . .performance/ratchets.json)" >> "$GITHUB_OUTPUT"
open-pr:
needs: measure
if: needs.measure.outputs.ceilings != ''
runs-on: ubuntu-24.04
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- env:
GH_TOKEN: ${{ github.token }}
CEILINGS: ${{ needs.measure.outputs.ceilings }}
run: |
jq . <<<"$CEILINGS" > .performance/ratchets.json
git switch -c "ratchet/tighten-$GITHUB_RUN_ID"
git -c user.name="github-actions[bot]" \
-c user.email="41898282+github-actions[bot]@users.noreply.github.com" \
commit -am "perf: lower counter ceilings"
git push origin HEAD
gh pr create --draft --fill
```
The counter commands run in `measure`, which holds a read-only token and no stored git credentials,
because a counter can exercise third-party code; only `open-pr`, which runs no counter, can write.
A workflow's `GITHUB_TOKEN` can open that PR only when the repository setting "Allow GitHub Actions
to create and approve pull requests" is on, and it is off by default for a new personal-account
repository; the PR's `opened` event then creates workflow runs in an approval-required state, so a
human approves the checks as well as the merge. To have the checks start without that approval,
open the PR with a GitHub App installation token or a personal access token stored as a secret
instead of `GITHUB_TOKEN`. Verified 2026-09-24 against
`https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-github-actions-settings-for-a-repository`,
`https://docs.github.com/en/actions/concepts/security/github_token`, and
`https://docs.github.com/en/actions/how-tos/write-workflows/choose-when-workflows-run/trigger-a-workflow`.
Recheck when any of them stops naming that setting or changes what a `GITHUB_TOKEN`-created pull
request event triggers.
## 5. Guardrails for fragile optimizations
A ratchet guards a count, not correctness. Guardrails scale with how brittle the optimization is:
- **A fast path that copies a slow one** (a static placeholder, a precomputed table, a cache): generate
the copy from the source, and add a test that fails when the two drift.
- **A fast path that must match the real one:** keep verify's differential as a standing test, over
every mode and configuration it covered.
- **A handoff between two implementations:** a test that drives input through the switch and fails
on anything lost or reordered.
Propose these beside the ratchet. The ratchet alone passes a subject that got cheaper by breaking.
## 6. Win decay the ratchet does not see
- **A new path around the counted one.** The counter measures the path its command drives. Code
that reaches the same cost another way is invisible to it.
- **A command that drifts from production.** A counter command that copies a hook list or a config
keeps measuring the copy after production changes. Name the source it copies in `goal`.
- **A raised ceiling.** Raising one is a decision, stated with its reason in the PR body, never an
edit made to turn a build green.
## Output
```text
Counter: <name> = <measured> (<field>), deterministic across <runs> runs
Ceiling: <value> in .performance/ratchets.json Protects: <goal>. Correlation: <goal's value>
CI step: <workflow file and job> Required check: <name>
Tighten: same-PR | scheduled draft PR (<workflow file>)
Guardrails proposed: <tests, or none needed and why>
Awaiting: human approval of the files above
```
## Boundary
- **Does not measure the win.** `/performance:snapshot` captures and `/performance:verify` proves it;
this protects a result already MET.
- **Does not merge,** under any autonomy setting, and its scheduled job only opens a draft PR.
- **Does not commit durations.** Only counter ceilings are checked in.
- **Does not run a model in CI.**
## Next
`/source-control:pull-request` with the proposed files, once a human approves them.
## Gotchas
- **A ratchet on a counter measured warm fails on every fresh runner.** Measure in CI's cache state.
- **A command that swallows the subject's failure passes the ratchet.** Fewer spawns is also what a
crash looks like; make the command fail with the subject.
- **A ratchet outside the required check blocks nothing.** It turns red in the run list while the
merge gate stays green.
- **Headroom in a ceiling is a pre-approved regression.** Set it to the measured value.
- **A scheduled tighten job that merges is out of bounds.** It opens a draft PR; a human merges.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!