Prevent regression
Skill KhurrumMahmood/senior-vibe-engineer/.claude/skills/prevent-regression
Router-first engineering skills for AI coding agents: deliberate refactoring, architectural hygiene, ADRs, and bounded multi-language tooling.
npx -y skills add KhurrumMahmood/senior-vibe-engineer --skill prevent-regressionAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Turn a closed cleanup cluster into a permanent guardrail: diff-scoped lint when the invariant is lexical/AST-shaped, or focused regression tests when the invariant is behavioral/contract-shaped. Accepts a cluster ID from a recent scan (`cluster:<id>`, `delete:<id>`, `semantic:<id>`, `dormant:<id>`), a free-form pattern description with optional `path:<glob>` qualifier, a product-topology template (`topology:<route-ownership|workflow-registry|frontend-boot|site-endpoints|doc-route-drift>`), or `--dogfood <rule-name>` to rewire an existing rule. Emits a proposal at `reports/prevent-regression/<id>/` containing the guard artifacts, canonical-pattern/testing guidance when needed, and a verification recipe. Read-only against production code — never installs the guard unilaterally; the human reviews and executes.
SKILL.md
23.9 KB, ~5.5k tokens by cl100k_base, as published. Nobody here has run it
/prevent-regression
Swift 6.3.3 exact-property-type guard
Use scripts/stage_swift_state_guard.py only after a fresh accepted Swift enum
proposal and a second content-addressed acceptance of the migrated tree and
exact buildable String reversion. Keep sibling _swift-semantic-readonly. The
skill stages but never installs one same-module compile-time property-type
guard derived from the accepted owner, member, and existing enum identity. It
proves the accepted migrated tree passes build/check/smoke and guard typecheck,
then proves the accepted reversion still passes native gates without the guard
but fails with it. Case/raw mappings remain proposal evidence rather than a
guard claim; runtime behavior, Codable/reflection, dynamic/protocol dispatch,
frameworks, generated inputs, external variants, and compatibility remain
outside the guard.
C# staged exact-property-type guard
Use scripts/stage_csharp_state_guard.py only after a fresh accepted C# enum
migration and current sibling _csharp-semantic facts. Read
knowledge/csharp-v1.md for the exact command. The skill stages but never
installs one exact property-type compile guard and proves a disposable string
reversion fails. Wire values, runtime behavior, other properties, generated
code, frameworks, external callers, and binary compatibility remain outside
the claim.
Kotlin/JVM 2.4.10 exact-type guard
Trigger this branch only from a fresh accepted Kotlin enum proposal and a
second content-addressed migration acceptance. Keep sibling
_kotlin-semantic, read
../_kotlin-semantic/GUIDE.md, and enter through
scripts/stage_kotlin_state_guard.py. It stages but never installs one
compile-time exact-property-type assertion and proves an accepted buildable
String reversion fails with the guard. It does not protect wire values,
reflection, delegation, generated/plugin sources, Gradle variants,
Java/framework/external callers, runtime behavior, JVM ABI, or general Kotlin
lint coverage.
C++20 branch
Use scripts/stage_cpp_state_guard.py with a fresh accepted migration and all
five human approvals; run it with --help for the exact CLI. It stages, but
never installs, one std::is_same_v guard for an exact namespace-qualified
field and proves one disposable type regression fails. It makes no broader
ODR/ABI, specialization, overload/dispatch, external-variant, or runtime claim.
C17 branch
Use scripts/generate_c_state_guard.py on an accepted C enum proposal, then
verify the staged bundle with scripts/verify_c_state_guard.py; run each with
--help for the exact CLI. This branch stages but never installs one exact-
field _Static_assert/_Generic type guard; values, assignments, aliases,
runtime behavior, other fields, and general lint coverage remain unresolved.
PHP and Ruby
For an accepted PHP enum proposal, read _php-proposal/GUIDE.md. For an
accepted Ruby RBS proposal, read _ruby-semantic/PROPOSAL-GUIDE.md. Both
branches stage and verify one exact reviewed field guard; neither installs it.
Dart exact-field guard
After a human accepts the Dart enum proposal, stage—not install—a dependency-free project-owned guard for that exact reviewed public field. The verifier proves a good disposable tree passes and a buildable String reversion fails specifically because of the staged guard.
SKILL_ROOT=".agents/skills/on-demand/prevent-regression"
python3 "${SKILL_ROOT}/scripts/generate_dart_state_guard.py" \
--project-root "$PWD" --evidence-dir reports/implicit-state/dart \
--acceptance reports/implicit-state/dart/acceptance.json \
--targets reports/extract-enum/dart/targets.json \
--accepted-review reports/extract-enum/dart/accepted-review.json \
--output-root "$PWD/reports/prevent-regression/dart-state"
python3 "${SKILL_ROOT}/scripts/verify_dart_state_guard.py" \
--project-root "$PWD" --stage reports/prevent-regression/dart-state
This is one field guard, not a universal lint or a runtime/serialization invariant. Audited host source is never modified.
Rust exact-field guard
After a human accepts an extract-enum proposal, require a SHA-bound
rust-enum-review-v1 acceptance artifact. Stage—not install—a project-owned
Cargo integration test that asserts one public owner/public field has the
reviewed enum type, then verify it with locked/offline metadata, check, test,
Clippy, and rustfmt. Private fields abstain; this is not a general Rust lint.
SKILL_ROOT=".agents/skills/on-demand/prevent-regression"
OUT="$PWD/reports/prevent-regression/rust-state"
python3 "${SKILL_ROOT}/scripts/generate_rust_state_guard.py" \
--targets "$PWD/reports/extract-enum/rust/targets.json" \
--accepted-review "$PWD/reports/extract-enum/rust/accepted-review.json" \
--project-root "$PWD" --output-root "$OUT"
python3 "${SKILL_ROOT}/scripts/verify_rust_state_guard.py" \
--stage "$OUT" --project-root "$PWD" \
--output "$OUT/verification.json"
You are the orchestrator for turning a closed cleanup into a permanent
guardrail. Invocation only stages a proposal below
reports/prevent-regression/<id>/; it never authorizes rollout. Stage rule,
fixture, and ready-to-apply wiring at their repo-relative destination paths,
then let the human install or discard them.
How success is judged
- Emit, never install, the artifact and verification recipe.
- Paste the real verifier result: BAD_RC=1 and GOOD_RC=0 for lint guards, or focused test output for behavioral guards.
- Prove the historical fire and current clean result; fixtures cover every matched anti-pattern plus legitimate forms.
- Use
_common/skill-conventions.md,agents/rule-designer.md, and the bundled generation/verifier helpers for the shared report shape.
Closed-state guard
For the reviewed first-party status / phase / state path, use the
bundled guard directly after installation:
python3 scripts/stringly_status_guard.py <file-or-directory>
It blocks a bare string Django field, comparison, or assignment and accepts
only a reasoned # noqa: stringly-status: <reason> vendor boundary. This is a
family-local reference guard; it does not generate or install unrelated
general-purpose rules.
TypeScript closed-state guard
Stage—not install—the family-local Compiler API guard for a reviewed closed
TypeScript field. It covers direct/reversed comparisons, one-hop const aliases,
plain/??=/chained assignments, and transparent parentheses. A pinned host
TypeScript package plus tsconfig are required; unsupported general dataflow,
ORM behavior, and root lint wiring remain out of scope.
ID="typescript-state"
OUT="reports/prevent-regression/$ID"
node .claude/skills/prevent-regression/scripts/generate_typescript_state_guard.mjs \
--id "$ID" \
--project-root "$(pwd)" \
--tsconfig "$(pwd)/tsconfig.json" \
--output-root "$OUT"
node .claude/skills/prevent-regression/scripts/verify_typescript_state_guard.mjs \
--rule "$OUT/scripts/lint/no_stringly_state.mjs" \
--bad "$OUT/tests/lint/no_stringly_state_bad.ts" \
--bad-tsx "$OUT/tests/lint/no_stringly_state_bad.tsx" \
--good "$OUT/tests/lint/no_stringly_state_good.ts" \
--good-tsx "$OUT/tests/lint/no_stringly_state_good.tsx"
The report stages guard, TS/TSX fixture pairs, and host-wiring.diff; paste
BAD_RC=1/GOOD_RC=0. A reasoned noqa only suppresses a Compiler-resolved vendor
receiver, never a filename or forged first-party comment. The serial integrator
owns staged wiring.
Checked-JavaScript closed-state guard
Retain complete checked-JavaScript detector evidence and manifest first. The
generator accepts only at least one proven first-party operation from an
allowJs + checkJs host Compiler API run; partial/unsupported evidence exits
2 rather than fabricating findings.
ID="javascript-state"
OUT="reports/prevent-regression/$ID"
node .claude/skills/prevent-regression/scripts/generate_javascript_state_guard.mjs \
--id "$ID" \
--project-root "$(pwd)" \
--config "$(pwd)/jsconfig.json" \
--findings reports/implicit-state/findings.jsonl \
--manifest reports/implicit-state/manifest.json \
--output-root "$OUT"
node .claude/skills/prevent-regression/scripts/verify_javascript_state_guard.mjs \
--rule "$OUT/scripts/lint/no_stringly_state_javascript.mjs" \
--bad "$OUT/tests/lint/no_stringly_state_bad.js" \
--bad "$OUT/tests/lint/no_stringly_state_bad.jsx" \
--bad "$OUT/tests/lint/no_stringly_state_bad.mjs" \
--bad "$OUT/tests/lint/no_stringly_state_bad.cjs" \
--good "$OUT/tests/lint/no_stringly_state_good.js" \
--good "$OUT/tests/lint/no_stringly_state_good.jsx" \
--good "$OUT/tests/lint/no_stringly_state_good.mjs" \
--good "$OUT/tests/lint/no_stringly_state_good.cjs"
The proposal stages four fixture pairs and wiring; paste BAD_RC=1/GOOD_RC=0. Coverage is direct/reversed comparison, assignment, and one-hop const aliases on JSDoc-closed fields; vendor noqa requires Compiler API evidence. The serial integrator owns installation.
Go closed-state guard
After a human accepts a Go proposal, read and follow knowledge/go-state.md.
Load that file only for Go work. Never weaken an unavailable semantic closure
to a field-name regex.
Java 17 exact-authority guard
After a human accepts a Java enum proposal, stage—not install—a guard from its
targets.json. It copies the accepted qualified owner, field, source
fingerprint, and family-local JDK compiler helper. The staged rule checks only
that compiler-resolved direct String field; it does not broadly match every
field named state, status, or phase. It catches bare assignments,
String.equals/Objects.equals, and unsafe ==/!= while that exact field
is still String.
OUT="${OUT:-reports/prevent-regression/java-job-status}"
TARGETS="${TARGETS:-reports/extract-enum/java-job-status/targets.json}"
SKILL_ROOT=""
for SKILL_CANDIDATE in \
".agents/skills/on-demand/prevent-regression" \
".agents/skills/prevent-regression" \
".claude/skills/prevent-regression"
do
if [ -f "${SKILL_CANDIDATE}/SKILL.md" ]; then
SKILL_ROOT="$(cd "${SKILL_CANDIDATE}" && pwd)"
break
fi
done
if [ -z "${SKILL_ROOT}" ]; then
printf '%s\n' "prevent-regression is not installed in .agents/skills/on-demand, .agents/skills, or .claude/skills" >&2
exit 2
fi
python3 "${SKILL_ROOT}/scripts/generate_java_state_guard.py" \
--targets "$TARGETS" \
--project-root "$(pwd)" --output-root "$OUT"
RULE="$(find "$OUT/scripts/lint" -maxdepth 1 -name 'no_stringly_state.py' -print -quit)"
python3 "${SKILL_ROOT}/scripts/verify_java_state_guard.py" \
--rule "$RULE" --authority "$OUT/authority.json" \
--bad "$OUT/tests/lint/bad/Job.java" --good "$OUT/tests/lint/good/Job.java" \
--project-root "$(pwd)"
<!-- installed-command:java-state-guard:end -->
Install find-implicit-state alongside this skill so the generator can copy
its helper; a missing helper or JDK 17 exits 2 rather than falling back to a
name regex. The verifier pastes BAD_RC=1, GOOD_RC=0 and compiles both fixtures
with javac --release 17 -proc:none. This branch modifies only the staged
proposal directory, never host guard files; a human integrator owns any later
installation, native check, and rollback.
Argument parsing
Four forms. Detect and route:
Form A — Cluster ID from a recent scan
Pattern: cluster:<id>, delete:<id>, fix:<id>, semantic:<id>,
dormant:<id> — anything /fix-workflow accepts.
Load the corresponding triage entry from
reports/<scan>/latest/report.md or triage.md and extract:
- files touched
- fix shape (e.g.
quasi_dead_broken,extract_helper) - the git commit(s) that landed the fix (from the learnings log or
git log --grep=<id>)
Form B — Explicit pattern description
A sentence plus an optional path:<regex> qualifier. Example:
"bare
int(request.POST.get(...))withoutsafe_intin views"path:core/views/**/*.py
Treat the sentence as the rule intent. Before producing a proposal, ask for one clarification round if the path scope or anti-pattern AST shape is ambiguous.
Form C — --dogfood <rule-name>
Used when the rule script already exists under scripts/lint/ and
you only need to (re)wire it, regenerate fixtures, or refresh the
CLAUDE.md entry. Skip Phase 1 and start at Phase 2.
Form D — Product-topology guard template
Pattern: topology:<route-ownership|workflow-registry|frontend-boot|site-endpoints|doc-route-drift>.
Use this when a workflow cleanup has already landed and the user wants to prevent drift from returning. The skill should start from the corresponding product-topology report, not from a raw grep:
route-ownership: block new workflow routes from being added to the global root URL file once an include boundary exists.workflow-registry: block new sidebar/dashboard step definitions outside the canonical registry.frontend-boot: block new template-levelwindow.*globals outside the canonical boot payload.site-endpoints: block hardcoded registry-owned/api/sites/<site_id>/...consumer strings once the workflow boot payload exposes endpoint keys.doc-route-drift: add a scheduled or diff-scoped docs-vs-routes check when route docs repeatedly drift.
Core beliefs
- Ruff first. Use a custom rule only where Ruff is silent or too broad.
- Diff-scope and reasoned escapes. Hooks inspect changed files; custom noqa markers require a non-empty reason.
- Fixture truth. Every matcher branch fires in bad fixtures and stays quiet in good fixtures; the verifier is the proof.
- One invariant, one commit. Bundle rule/test, fixtures, verifier, and staged wiring so a revert and bisect remain meaningful.
- Choose the right peer. Use lint for local shape, tests for behavioral contracts, and audit bands only when neighbor/path context is essential.
- Protect an accepted convention. Derive registry facts where possible; do not guard topology before its canonical shape exists.
New-Feature Guardrail Prompts
When a feature establishes a reusable convention, ask whether a lightweight guard belongs with it: reverse-backed route tests before endpoint lints; one boot payload plus a retired-global check; typed state authority from creation; a dormant sweep or quarantine for prototype remnants; endpoint/credential tests before bespoke lints; and broker-failure cleanup tests for safe dispatch.
Phase 1 — Pattern discovery
Pre: argument resolved.
Post: reports/prevent-regression/<id>/pattern.md exists with
the rule intent, path scope, file suffixes, and match shape.
Run git show <commit> for the fix commit(s). Read the diff. Classify:
- Ruff-coverable: the pattern corresponds to an existing ruff rule
(consult https://docs.astral.sh/ruff/rules/). Emit a
pyproject.tomldiff that enables the rule and optionally narrowsper-file-ignores. Skip to Phase 4. - Custom rule: the pattern is narrower, domain-specific, spans a non-Python language, or requires looking at source comments (e.g. the allow-list shape). Proceed to Phase 2.
Record the classification, rule name, path scope, file suffixes, and
anti-pattern shape. For Python, describe the AST shape (what
ast.walk looks for). For JS/templates/docs, describe the lexical or
parser shape and the false-positive boundaries. Use symbolic names in
prose — see _common/skill-conventions.md "No raw line numbers".
Phase 2 — Rule script
Pre: classified as custom rule.
Post: scripts/lint/<rule>.py exists and is smoke-tested.
Contract for every custom rule:
- Stdlib-only. Runs under bare
python3(no.venvrequired). - CLI: accepts
<file>/<directory>positionals OR--stdin --filename=<name>; exit 0 on clean, 1 on violations, 2 on invocation error. Directory scans usescripts/lint/path_utils.pyfor skip directories and expand only the rule's suffixes. - Output: one line per violation, format
<path>:<line>:<col>: <rule>: <message>. - Allow-list:
<comment> noqa: <rule>: <reason>on any line of the matched span, reason regex\S(non-empty). Use#for Python and//for JS.
silent_catch.py is the Python reference implementation. For JS
lexical guards (no_site_endpoint_sprawl.py was the source host's
exemplar — not shipped in this ecosystem;
keep this shape: suffix expansion, template-literal/string-concat
matching, blockable comments, and a reason-required // noqa.
Phase 3 — Fixtures
Pre: rule script works on synthetic input.
Post: tests/lint/<rule>_bad.<ext> + tests/lint/<rule>_good.<ext>
exist and verify_rule.py passes.
<rule>_bad.<ext> must contain every variant of the anti-pattern the
rule is supposed to catch — at minimum one example per branch of the
rule's matcher. <rule>_good.<ext> must contain the legitimate
patterns the rule must NOT flag: narrow exceptions, logged paths,
re-raises, allow-listed cases.
Python fixtures carry # ruff: noqa at the top so they don't
double-fail the standard ruff pass. Non-Python fixtures use the normal
comment style for explanatory fixture comments.
Run:
python3 .claude/skills/prevent-regression/scripts/verify_rule.py \
--rule scripts/lint/<rule>.py \
--bad tests/lint/<rule>_bad.<ext> \
--good tests/lint/<rule>_good.<ext>
It must report BAD_RC=1 (violations fired) and GOOD_RC=0 (no false positives). If either is wrong, iterate on the rule or fixtures.
Phase 3b — Test-only guard
Use this when a focused test expresses the invariant better than a lint: import-path stability, retired files, endpoint/auth/CSRF contracts, credential absence, removed fake fallbacks, or dispatch cleanup. Write the smallest test, derive canonical routes/keys where practical, run it plus baseline, and retain the proposal's pattern, verification, and follow-on sections.
Phase 4 — Wire into pre-commit + CI
Pre: verify_rule.py passes.
Post: .pre-commit-config.yaml has a local hook entry for the
rule; .github/workflows/ci.yml has a diff-scoped step that runs the
rule on the same file set.
Hook shape. Keep pre-commit broad and put the real rule scope in
scripts/lint/run.py so local hooks and CI share the same filter:
- repo: local
hooks:
- id: <rule>
name: "<rule> (<short rationale>)"
entry: python3 scripts/lint/run.py --rule <rule>
language: system
types: [python]
files: '^core/.*\.py$'
For non-Python guards, set types and files to the broad staged-file
surface for that language, and add a RuleSpec.suffixes entry in
scripts/lint/run.py so --staged, --changed-from, and explicit
paths all collect the same file types.
CI runs python3 scripts/lint/run.py --changed-from "$BASE" --rule all.
When adding a rule, add one RuleSpec in the runner; do not duplicate
the scope regex in workflow shell.
Phase 5 — Canonical Patterns entry
Pre: rule wired.
Post: .claude/CLAUDE.md has a new bullet under "Canonical
Patterns" naming the rule, its intent, and the allow-list shape.
Entry template (one bullet, ≤4 lines):
- **`<rule>` / `scripts/lint/<rule>.py`** — <one-line intent>. The
allow-list is `<comment> noqa: <rule>: <reason>` (reason required).
See `tests/lint/<rule>_{bad,good}.<ext>` for the canonical examples.
Match the existing "Canonical Patterns" list's voice — imperative, no emoji.
Phase 6 — Proposal + report
Pre: Phases 1–5 complete.
Post: reports/prevent-regression/<id>/proposal.md written,
reports/_meta/effectiveness.jsonl appended, user notified.
proposal.md structure:
# Rule proposal: <rule>
## Source cluster
<cluster id + commit ref>
## Pattern
<match shape + path scope + rationale>
## Artifacts
- lint guard: scripts/lint/<rule>.py (new),
tests/lint/<rule>_{bad,good}.<ext> (new),
.pre-commit-config.yaml (modified),
.github/workflows/ci.yml (modified),
.claude/CLAUDE.md (modified — Canonical Patterns entry)
- test-only guard: focused regression test module(s) plus any
Canonical Patterns / testing-doc entry needed to explain the
invariant
## Verification
- `verify_rule.py`: BAD_RC=1 with <N> hits, GOOD_RC=0.
- Historical regression: rule fires on
`git show <anchor>^:<file>` for each pre-fix site.
- Clean on current HEAD: <list files checked>.
## Follow-on findings
<violations surfaced on other in-scope files that this cluster
did NOT fix — these become new /fix-workflow or /find-dormant
candidates, not Phase 1 work>
Append to reports/_meta/effectiveness.jsonl using the shared
scripts/log_effectiveness.py:
python3 scripts/log_effectiveness.py \
--skill prevent-regression \
--scan-id "prevent-regression-${TS}" \
--target "scripts/lint/<rule>.py" \
--findings-total N \
--buckets '{"<rule>": N}' \
--notes "<optional>"
Step 7 — Summarize
Report to the user in ≤10 lines:
- Rule name + AST shape.
- Files created/modified (1 line each).
- Verification results (pass/fail).
- Follow-on findings count (if any).
- Path to
proposal.md. - Next recommended action: human reviews the proposal, installs the staged artifacts and wiring diffs, and commits — or abort if verification failed.
Non-goals
- Fixing pre-existing violations on unrelated files — that's
/fix-workflowwork, surfaced here as follow-on findings. - Broadening the rule's AST shape beyond what the source cluster demonstrated — two clusters justify one rule, not a family.
- Running full-repo lint — the rule is diff-scoped by design.
Repository layout
.claude/skills/prevent-regression/
├── SKILL.md # this file — orchestrator
├── agents/
│ └── rule-designer.md # pattern-shape scout brief
├── knowledge/ # host-overlay slot — ships empty;
│ # conventions live in _common/skill-conventions.md
└── scripts/
├── generate_rule.py # rule scaffold generator (Phase 2)
└── verify_rule.py # fixture-pair verifier (Phase 3)