WooCommerce Code Review
woocommerce/woocommerce
Reviews WooCommerce code changes against the project's standards, flagging backend PHP architecture, naming, documentation, data integrity and testing violations.
Code QUALITY of what YOU just wrote, before you commit or say 'done', or verifying a cleanup: --quality-delta lists what got WORSE in 11 kinds and exits 2 only when pre-existing code got materially…
$ npx skills add redhat-et/ripwire --skill ripwire-quality-bar -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install redhat-et/ripwire ripwire-quality-bar --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/redhat-et/ripwire.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/ripwire-quality-bar .claude/skills/ripwire-quality-bar && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "ripwire-quality-bar" agent skill from https://github.com/redhat-et/ripwire/tree/main/skills/ripwire-quality-bar into .claude/skills/ripwire-quality-bar/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ripwire-quality-bar", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/redhat-et/ripwire/tree/main/skills/ripwire-quality-barType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add redhat-et/ripwire --skill ripwire-quality-bar -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install redhat-et/ripwire ripwire-quality-bar --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/redhat-et/ripwire.git skills-src && mkdir -p .agents/skills && cp -r skills-src/skills/ripwire-quality-bar .agents/skills/ripwire-quality-bar && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "ripwire-quality-bar" agent skill from https://github.com/redhat-et/ripwire/tree/main/skills/ripwire-quality-bar into .agents/skills/ripwire-quality-bar/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ripwire-quality-bar", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add redhat-et/ripwire --skill ripwire-quality-bar -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install redhat-et/ripwire ripwire-quality-bar --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/redhat-et/ripwire.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/skills/ripwire-quality-bar .cursor/skills/ripwire-quality-bar && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "ripwire-quality-bar" agent skill from https://github.com/redhat-et/ripwire/tree/main/skills/ripwire-quality-bar into .cursor/skills/ripwire-quality-bar/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ripwire-quality-bar", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/redhat-et/ripwire.git --path skills/ripwire-quality-bar--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add redhat-et/ripwire --skill ripwire-quality-bar -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install redhat-et/ripwire ripwire-quality-bar --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/redhat-et/ripwire.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/skills/ripwire-quality-bar .gemini/skills/ripwire-quality-bar && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "ripwire-quality-bar" agent skill from https://github.com/redhat-et/ripwire/tree/main/skills/ripwire-quality-bar into .gemini/skills/ripwire-quality-bar/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ripwire-quality-bar", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install redhat-et/ripwire ripwire-quality-barInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add redhat-et/ripwire --skill ripwire-quality-bar -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/redhat-et/ripwire.git skills-src && mkdir -p .github/skills && cp -r skills-src/skills/ripwire-quality-bar .github/skills/ripwire-quality-bar && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "ripwire-quality-bar" agent skill from https://github.com/redhat-et/ripwire/tree/main/skills/ripwire-quality-bar into .github/skills/ripwire-quality-bar/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ripwire-quality-bar", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add redhat-et/ripwire --skill ripwire-quality-bar -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install redhat-et/ripwire ripwire-quality-bar --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/redhat-et/ripwire.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/skills/ripwire-quality-bar .opencode/skills/ripwire-quality-bar && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "ripwire-quality-bar" agent skill from https://github.com/redhat-et/ripwire/tree/main/skills/ripwire-quality-bar into .opencode/skills/ripwire-quality-bar/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "ripwire-quality-bar", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
ripwire-quality-barCode QUALITY of what YOU just wrote, before you commit or say 'done', or verifying a cleanup: --quality-delta lists what got WORSE in 11 kinds and exits 2 only when pre-existing code got materially…
Ripwire Quality Bar is an agent skill from redhat-et/ripwire. Code QUALITY of what YOU just wrote, before you commit or say 'done', or verifying a cleanup: --quality-delta lists what got WORSE in 11 kinds and exits 2 only when pre-existing code got materially worse; which restructuring a measured shape (humps/deep, a tangle) calls for. Merge safety → change-check. Even a single-line leaf fix runs it.
Its SKILL.md is about 8.4k tokens, which your agent loads only when the skill is triggered. The skill folder holds 1 other file (for example `quality-metrics.md`).
It sits in Development, covering Code quality. The repository describes itself as: The ripgrep of AI context: a zero-dependency C++23 CLI + MCP server for coding agents. Find what you want without reading the repo, then check you built what you meant — blast… The licence is Apache-2.0.
5 steps, taken from the first numbered list in SKILL.md.
Read from SKILL.md and the folder at commit 60dd3b3. It shows what the files ask for, not the result of running them.
Pre-approves these tools, so the agent can use them without asking each time:
BashReadFrom allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
gitFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md. Its commands use git, which can reach the network depending on how they are called.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Ripwire Quality Bar loads about 8.4k tokens when it runs. Until then it costs about 90 tokens; SKILL.md has 4,743 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check noted patterns worth knowing about, such as sudo or a known installer.
allowed-tools: Bash, ReadAutomated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from redhat-et/ripwire at commit 60dd3b3, republished under its Apache-2.0 licence (© redhat-et). 4,743 words, ~8,390 tokens.
.claude/skills/ripwire-quality-bar/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.Routing: • PR-submission readiness — tests to run, blast radius, "safe to merge?" → ripwire-change-check — run
--quality-deltaFIRST, then its--test-gate: clean code that runs the wrong tests still regresses. • Reusing before you write the code in the first place → ripwire-reuse-first. • Wide-angle "where does this still look rotten" read across a whole file/subsystem (not a before/after delta) → the panel below, or ripwire-fresh-eyes for the full six-family breakdown. • You have the measurement and need the FIX — for your own diff or for a subsystem ripwire-fresh-eyes just measured → the shape → refactor playbook, the closed fix loop and the debt fix loop are all on this page, below. • The regression is a MEMORY-layout hypothesis, not one of the 11 quality kinds —--lint's built-in cache-* pack (8 static data-layout checks) is a normal part of a lint pass;--field-affinity[=STRUCT]is the deeper struct-level lens once a profile implicates a specific aggregate → ripwire-perf-target. • Not sure which skill? → ripwire-router.
Don't eyeball quality — measure the delta your change introduced, with a deterministic oracle, in a bounded loop. A file that was already complex is not your regression.
Apply the "non-trivial work" trigger to the LOOP, not the check. --quality-delta warm-runs in well under a
second — cheaper than deciding by eye whether a fix "counts" as trivial, and that eyeball judgment is
precisely where a leaf-looking edit that quietly changed a signature or added a branch slips through
unmeasured. Run it. What a single-line leaf fix that preserves the signature and adds no branch, symbol,
dependency, or abstraction gets to skip is everything AFTER a clean run: the drill-down table, --dmm,
acking, a second round. This skill (and this file) earns its cost when the one-shot delta actually reports
something — a clean gating="0" run on a leaf fix is confirmation, not ceremony you were right to skip.
--quality-panelripwire <dir> --quality-panel[=strict|default|lenient] --legend=compact is THE SINGLE COMMAND for "does what I just
touched still look rotten" — one ranked report over six evidence families (the four --ensemble
joins — structural, lexical, confusion, historical — plus colocation and state; the full
per-family breakdown lives in ripwire-fresh-eyes). Point it at the file or symbol you just edited for
a multi-angle second opinion the single --quality-delta number can't give you on its own.
Read it correctly: it is a lens, never a gate. --help says so in the flag's own text and the
contract is enforced in code — --quality-panel exits 0 unconditionally, on every preset, on every repo.
It does not compare against a baseline and it cannot fail a commit. The gate for "did MY change make this
WORSE" is Step 3 below (--quality-delta) — that is the only pass in this skill (or in ripwire) with an
exit code that means something. Run --quality-panel for the wide-angle read, converge with
--quality-delta, never the other way round.
Pick the preset by what "rotten" needs to mean right now: lenient (all six families, 1 must agree) is a
reading order, roughly a third of any tree; default (all six, 2 must agree) is a review list; strict
(only the four families measured stable enough to stand behind repeatedly — historical and colocation
are fixed-size worst-40 cuts over a ranking whose population moves, so both re-shuffle release to release
on code that never changed) is the rung closest to something CI-shaped, but it is still a lens — nothing
here plugs into an exit code the way --quality-delta does.
nest= alone is a max, and misleads solonest= reports the single deepest line in a function. One line at depth 9 and a thousand lines at depth 9
report the same number, so nest=9 cannot tell a tangled body from a long blocked-sequential one
whose max was set by one inner loop nobody has to hold in their head. Acting on nest= alone is how an
agent guard-clauses a dispatch table. --metrics (and the structural family's why= string in
--quality-panel / --ensemble) now carry the profile beside the max:
<e f="structural" counted="1" why="ccx=724 loc=1244 nest=9 humps=30 deep=308 rrank=1"/>Every concrete number on this page is ILLUSTRATIVE OF A SHAPE, never a value to expect. The counters
themselves are under active calibration — an else-clause over-count fix in flight moves humps= down by a
large fraction, and ccx=/nest= with it, on else-heavy functions. What is durable is what you do with
the row: humps=1 vs many, the two ratios below, and the semantics (regions vs lines, absence below the
bar, deep < humps legal). Read the row in front of you; never carry a remembered number to it.
humps= — how many maximal control-nesting regions reach the nesting bar (bar_nest= on the panel
root; CodeScene's "bumpy road": a rise above the threshold then a fall). One deep tangle is 1; repeated
missing abstractions are many. EXACT, not a floor.deep= — how many LINES lie inside those regions, read against the loc= already on the row. A
disclosed FLOOR (deep_floor="1").nest < the bar — not-deep, never a hidden 0.deep below humps is legal output, not a defect. deep counts lines and humps counts regions, and
two regions can share a line: a one-line if(c){x;}else{y;} at the bar is 2 regions on 1 line. Three
reviewers have read that shape as a bug; it isn't.Two ratios do the actual discriminating, and you compute them yourself from the row:
| Ratio | High says | Low says |
|---|---|---|
deep/loc | tangled — the body sustains depth, so most of what you read is nested | blocked-sequential — a long run of shallow steps (a dispatch table, a switch, a setup block); the max is one inner loop |
deep/humps | few giant tangles — one region holds depth for a long stretch; the expensive fix | many tiny touches — repeated missing abstractions, each hump its own cheap extraction |
Three shapes off this repo's own source — read the pattern, not the digits, which move with calibration:
a ~1000-line function at a low deep/loc (main, roughly a tenth) sits beside one at ~2.5× that
fraction (buildGraph) once loc/nest have declared them equivalent; and a function far too small for
any size bar to fire can carry the highest deep/loc in the table (ur_walkTree, loc=87, near half
its body deep in a single hump). The first is blocked-sequential, the second tangled, the third dense —
three different fixes, one indistinguishable nest=.
locals= rides the same row: the count of local-variable declarations, a FLOOR (locals_floor="1"),
C/C++ only and absent — never a bare 0 — for every other language. It measures the working set a
reader must hold at once, which is the thing extraction is actually supposed to shrink; a "split" that leaves
locals where it was mostly moved braces.
join="deep+untested" on a --quality-panel row is a conjunction of two facts the report already
holds — this row carries deep= and no indexed test reaches it — annotated, not a seventh family. It
changes nothing: not fam=, not of=, not the ordering, not which rows appear. It is the pair where a
refactor is most wanted and least safe, so it routes straight to test first, refactor second in the
playbook below. It is suppressed on every row when tested_scope="0", because on a corpus whose tests
were never crawled "untested" would be a fact about the crawl, not about the code — read tested_scope= on
the root before you read the absence of the annotation as good news. deep_untested= on the root counts them
across the WHOLE row set, which the limit= window does not change.
The per-file churn caveat. The historical family's churn= and hrank= are FILE facts, inherited
verbatim by every symbol in the file — a symbol in a churny file collects that family without any property
of its own. Discount it accordingly: on a row whose other evidence is thin, historical may be saying only
"this file is busy", not "this function is." (hrank= is also a relative decile cut over this corpus, so
something always fires.)
Zero-setup path: just make your change, then run ripwire <dir> --quality-delta --legend=compact
before you call it done — add --legend=compact every time you run this in a loop: on a CLEAN report the
legend is nearly the whole payload (2,776 B to 454 B measured on a small fixture, 15,601 B to 8,775 B on
a mid-change repo), the rows are byte-identical either way, and you have already read the dictionary — in a git repo it auto-compares the working tree vs git HEAD (<quality-delta baseline="git-HEAD"> confirms it), no start-of-task action needed. Tighter loop on a long change: run
ripwire <dir> --quality-baseline FIRST — on a clean tree — to pin an explicit floor (takes
precedence over HEAD) so each edit deltas against the original start, not the last commit. On a tree that
already differs from HEAD the pin refuses, naming the gating findings it would have swallowed into the
floor: commit first, or pass --allow-dirty to pin anyway, which stamps the absorbed count so every later
report carries baseline_absorbed="N" and a green exit beside it reads "clean since the pin".
Make your change.
Measure the delta — ripwire <dir> --quality-delta --legend=compact → only the regressions you
introduced, across the
11 kinds in the table below. Each emits <r kind="…" sym=… was=… now=…> (members= for duplication).
Test-fixture dirs are exempt from dead-code; short-horizon-churn ignores your own current edit and
exempts brand-new symbols/markdown/fixtures. Two exemptions are DISCLOSED on the report rather than
silent, and both change how you read a zero: a symbol defined by a self-registering test/benchmark
macro (doctest TEST_CASE, gtest TEST/TEST_F/TEST_P, Catch2, Google Benchmark, plus anything in
.ripwire_config's register_macros) is never dead-code — a static initializer is invisible to a
name-based call graph — and the header's register-macro-excluded="N" counts how many were dropped
that way, printed even at 0. A duplication row whose members share only a recognized idiom — a
scalar threshold ladder, an enum-to-string switch table, a builder chain — and share no domain
identifiers across different scopes is demoted to sev="minor" with idiom="…" and stops gating.
The idiom name is there so you can overrule it by reading: a demotion is a judgement the tool is
showing its work on, not a row it hid. Watch verbosity hardest — LOC growth is the single
most-measured agent failure mode, the one most likely to hide in an otherwise-clean diff.
Read the exit code correctly — it is narrower than it looks. Findings are sorted on three independent axes, and only one combination gates:
acked="N").origin= attribute on the row); one that exists only because the code is NEW carries
origin="new-symbol".sev="minor".--quality-delta exits 2 ONLY on preexisting-worse AND major AND unacked — exactly the
gating="N" count in the header. Read gating=, not regressions=. A real header looks like:
<quality-delta baseline="git-HEAD" regressions="0" minor="0" acked="0"
preexisting-worse="0" new-symbol="0" gating="0" at="f0a45e43d">origin="new-symbol" rows are PRINTED but NEVER gate. They are the debt you are adding — read
them; nothing else will make you. And --help is explicit that exit 0 means "nothing that already
existed got worse", NOT "clean": a change that is entirely new code can add unbounded new-symbol
debt and still exit 0. Never report "quality-delta passed" as "no new debt" — open the rows.
Two more contract details worth knowing: clone kinds classify by member set (a group is new-symbol
only if EVERY member is new), and short-horizon-churn is preexisting by construction.
LIMIT: origin is canonId (path::scope::name) identity, so a RENAMED or MOVED symbol reads as
new — a genuine regression carried in with a move classifies new-symbol and will not gate. If your
diff moves code, the exit code is especially weak evidence; read the rows.
Fix the REAL ones, re-run, converge. Which fix a row calls for is the shape → refactor playbook
below; proving the fix landed is the closed fix loop below that. Repeat until clean or the remainder
are conscious trade-offs.
Record a trade-off instead of re-reading it forever: ripwire <dir> --quality-ack="why it's accepted"
writes the currently-visible findings into .ripwire_quality_acks (committable) — later runs suppress
them honestly (acked="N") and a finding REAPPEARS the moment it worsens past its acked size.
Ack a SUBSET, never the screen. Bare --quality-ack accepts every finding currently visible, so
using it to accept one deliberate change silently accepts the rest too — that is how a ratchet turns into
a rubber stamp. Narrow it with --ack-only=SUBSTR[,SUBSTR], which matches a finding's kind, its canonical
id, or its facet:
ripwire <dir> --quality-delta --ack-only=contract-change --quality-ack="arity change required by <fix>"Prefer the facet over the kind when one exists: api-surface also covers the never-gating new-symbol
rows, so acking by kind can sweep in dozens of findings to accept a handful. --ack-only=gating selects
exactly what would exit 2. A pattern matching nothing refuses (exit 1) rather than acking everything.
Whatever you leave unacked stays visible — that is the point; an exit 2 you have explained in a commit
message is worth more than an exit 0 you bought with a blanket ack.
Sharing the working tree with other sessions? Then --ack-only is not enough — add --scope=.
--quality-delta compares the working tree against HEAD, so in a checkout several agents are editing
at once, every sibling's uncommitted rows land in your report. Bare --quality-ack there accepts
the whole screen, which writes another session's debt into a committed ledger under your reason
string: that is how the ratchet becomes a rubber stamp, and no amount of care reading the report
prevents it. --scope=GLOB[,GLOB...] files each finding by its p= path:
ripwire <dir> --quality-delta --legend=compact --scope=src/render,src/render_gl.h # gate on MY subtree only
ripwire <dir> --quality-delta --scope=src/render --quality-ack="deliberate" # …and ack only my rowsRows outside the scope are still printed, under an <out-of-scope> element with a do-not-ack
banner, and never gate; the header's scoped-out-gating= says how many of them would have gated, so
a scoped exit 0 means "nothing of mine is broken", never "the tree is clean". The ack cannot write an
out-of-scope row at all, and an --ack-only= that names one refuses (exit 1). Each row you write
records by=<scope>, so a later run can flag an ack that suppressed a path its author never owned
(foreign-acks=). A pattern with no wildcard is a root-anchored path prefix; */? match the whole
path, with * spanning /. A scope that names nothing indexed refuses rather than reporting you clean.
One reserved word: --scope=diff is whatever the working tree changed vs the baseline, expanded to
one path per changed indexed file. It is sugar for the single-writer case — in the shared tree
this flag exists for, a sibling's edits are "changed" too, so name your own paths there.
Want ONE number instead of a list — ripwire <dir> --dmm --legend=compact. --quality-delta says which kinds got
worse; it has no scale, so "is this change better than my last one?" has no answer. --dmm is that scale:
the Delta Maintainability Model (di Biase, Rastogi, Bruntink & van Deursen, TechDebt 2019; thresholds and
arithmetic from PyDriller's reference implementation) scores the share of the volume your change moved
that landed in — or freed from — risky units.
<dmm base="2edbb46c…" target="working-tree" available="1" combine="pooled" size_metric="physical-loc"
dmm="0.436" good="462" bad="597" base_units="4759" target_units="4780">
<p k="size" dmm="0.184" good="65" bad="288" d_low="65" d_high="288"/>…A unit (a function/method definition with a body) is low risk iff loc<=15 (size), cyclomatic<=5
(complexity), params<=2 (interfacing). good = low-risk volume added plus high-risk volume
removed; bad = the reverse; dmm = good/(good+bad). Deleting a god function scores 1.000;
growing one scores 0.000. The three sub-scores are separately actionable — a low size with a healthy
interfacing says split the function, not change the signature.
Three things to carry. It is a DELTA, never a level: editing bad code without changing its size,
complexity or parameter count contributes nothing — you are not punished for touching a mess, which is
deliberate. dmm="UNAVAILABLE" is not a score of 1.0 or 0.0 — it means good+bad was 0 (a rename, a
literal edit, a comment reflow), i.e. the change is outside what the model measures; the same token can
appear per property. And it never gates (always exit 0): use it to trend — --dmm=REV scores one
commit against its parent and --dmm=A..B scores a range, so a series of commits is a series of numbers.
Thresholds/definitions are the catalog in quality-metrics.md — this is just drill-down + fix:
| Regression | Drill-down | Fix |
|---|---|---|
complexity | --expand=SYM | split the fn · early-return · lift the nested branch out |
verbosity | --expand=SYM | the #1 agent failure mode (below) — cut boilerplate, don't just reformat |
nesting | --expand=SYM · --metrics for the humps=/deep= profile | guard clauses · invert the condition · extract the nested block — but read the profile first: which of those three it is depends on deep/loc and deep/humps (playbook below) |
params | --expand=SYM | bundle related params into a struct, or split the function |
duplication | --clones | reuse the existing body — Rule of Three; wrong abstraction beats two honest copies |
dead-code | — | delete what you orphaned, or wire the caller you forgot |
api-surface (new public symbol) | --callers=SYM | intentional? keep it. Accidental? narrow it (should've been file-local) |
error-masking (empty catch / bare except: pass / swallowed .catch; a broad handler that only logs and never names the error; a sole handler that re-throws it unchanged) | --expand=SYM | handle it, log the error itself, or drop the try — AI code adds these +47% vs human (GitClear 2026). The two widened shapes gate only in Python (measured precision); elsewhere sev="minor" |
short-horizon-churn | --hotspots · git log -p <file> | rewritten again inside 2 weeks (+15% AI) — is the design unsettled? consolidate |
new-clone-of-reused-helper | --clones · --callers=HELPER | call the existing well-reused helper — reuse is declining in AI code (GitClear) |
placeholder (an added stub or TODO: todo!(), NotImplementedException, a "not implemented" throw/panic, a TODO/FIXME naming no issue) | --expand=SYM | finish it, or name the issue that tracks it — never gates, but do not call the work done over it |
These 11 kinds aren't a generic lint list — ten target a large-N-validated agent-code degradation mode (the
eleventh, placeholder, is an honesty check on your own "done")
(verbosity, structural erosion, smell rate, contract drift; passing tests ≠ clean design). Numbers + why the
loop must be continuous, not a one-time prompt → quality-metrics.md.
Read the Fix column as DIRECTION, not a computed answer. None of these 11 kinds has a corpus-derivable
correct replacement — "split the fn" names a move, not a target function shape, and you still judge it. That
is deliberate: complexity, coupling, and colocation don't have a computable right answer the way a naming
CONVENTION does. The one exception in this whole tool is --naming-consistency (→ ripwire-fresh-eyes),
which proposes an actual propose= value because case-style consistency is Tier A — the corpus's own
majority IS the answer, mechanically recombined from the name's own subtokens, no judgment call involved.
Don't expect that anywhere else, and don't invent a "the fix is X" claim here that this tool doesn't itself
compute.
The table above maps a regression kind to a direction. This maps a measured shape to the named refactor and — the part agents skip — that refactor's precondition. Same doctrine as everything else here: these are facts plus options, never verdicts. The tool measures the shape; which option is right is still your call, and "leave it alone" is always on the menu.
| Measured shape | The named fix | Its precondition — check this FIRST |
|---|---|---|
Many shallow humps — humps high, deep/humps small, deep/loc low | Extract each hump. The bumpy-road fix: every region that rises to the bar and falls back is one missing abstraction with its own name. Cheap, mechanical, one hump at a time. | Nothing structural blocks it — but each extraction is a new symbol, so re-run the loop below: extraction that lands as origin="new-symbol" api-surface debt should be file-local, not public. |
One deep tangle — humps=1 (or few) with high deep/loc | Guard-clause inversion, then state extraction: invert the conditions that hold the depth, return early, and lift the sustained region's working set into a named struct or its own function. Expensive and genuinely risky — a rewrite, not a move. | locals= tells you what you're really moving; a big locals means the region's working set, not just its braces, has to travel. Check --callers=SYM/--impact=SYM before starting, and never do it in the same diff as a behavior change. |
Deciding whether an extract-method is mechanical or a rewrite — check ev= before picking a fix off this table | ev= absent (or ev="1") on a cx= row means every region is single-entry/single-exit: extract-method applies mechanically, anywhere. ev>=2 means a jump gave some region a second exit — the same extraction is now the "one deep tangle" row above, not a cheap lift. | ev_why=tag:count (guard-return, loop-escape, goto, ...) names which jumps raised it — a guard-return-heavy row is visibly not a knot. A FLOOR (ev_floor="1"): noreturn calls and macro-hidden exits can only push the true value higher. |
Small AND dense — small loc, but deep is a large fraction of it (roughly half or more), typically in one hump | Read it before you prescribe anything. Numeric kernels, tree walks, and state machines are legitimately dense: the depth is the algorithm. Often the right fix is a comment or a named constant, not a split. | This row is where a metric-driven agent does the most damage. --expand=SYM first. If the density is the algorithm, ack it (--ack-only=) and move on. |
High fan-in AND untested — big in=/amp=, tested="0", or a --quality-panel row carrying join="deep+untested" | Test first, refactor second. The safety net is the fix's precondition, not its follow-up. → ripwire-write-tests (--seams, the tested= lens, --callers=SYM for the outside contract). | Confirm the annotation is real: join= is suppressed entirely at tested_scope="0", so on an uncrawled-test corpus its absence proves nothing. |
Duplication — a --quality-delta duplication / new-clone-of-reused-helper row, or a --clones group | Consolidate through the repo's own exemplar — ripwire <dir> --exemplar="<what this code does>" --legend=compact names the best-in-class instance to converge on (chosen by ROLE, not text similarity), so the survivor matches house patterns instead of being whichever copy you happened to open. | Rule of Three — extract on the third occurrence, not the second; a wrong abstraction is worse than two honest copies. Check type= on the clone group: type="3" members are gapped near-misses and may differ on purpose. |
Churn-flagged, structurally quiet — historical fires with thin other evidence | Probably nothing here. churn=/hrank= are FILE facts inherited by every symbol in the file. | Confirm at the symbol before acting: git log -p <file> or --hotspots --since= to see whether this function is what keeps moving. |
None of these has a corpus-derivable "correct" answer — see the paragraph above the table. The playbook names a move and the condition that makes the move safe; it does not compute a target shape, and any of these rows can honestly end in "measured, understood, left alone."
Fixing without verifying is how a refactor trades one regression for two. Four steps, in this order; each answers a question the previous one cannot:
# 1. make the fix (playbook above)
ripwire <dir> --quality-delta --legend=compact # 2. did the TARGETED kind improve, and did nothing else regress?
ripwire <dir> --edit-check=SYM --legend=compact # 3. is the CONTRACT intact?
ripwire <dir> --affected=F1,F2 --legend=compact # 4. which tests PROVE it? (then run them)--quality-delta — the only step with a meaningful exit code, and it is doing two jobs here, not
one: the row you were chasing should be gone, and nothing new should have appeared. A "split the
function" fix that drops complexity while adding api-surface + duplication is a lateral move.
Read gating=, but also read the origin="new-symbol" rows — extraction always creates new symbols and
those never gate, so exit 0 is not the same as "the fix was free."--edit-check=SYM — unchanged / new-symbol / contract-change for the symbol you just edited:
param count and publicness NOW vs git HEAD, plus its 1-hop callers with any call site provably
incompatible with the new arity flagged. A refactor is supposed to be unchanged here; a
contract-change you did not intend is the finding. Cheap enough (~ms warm) that skipping it is never the
economical choice. It refuses (exit 1) if SYM matches several definition sites — a contract is per
definition, so pass the file:name spelling it lists.--affected=F1,F2 (or --affected=SYM) — the test files that transitively reach what you changed.
Metrics improving is not evidence the code still works; this names what to run, and then you run it.
Mid-task, --situ is the same answer over the whole git diff plus co-change partners; at PR time
--test-gate is the gating form (exit 4 when tests-to-run or the untested blast radius is non-empty).Done means: the targeted kind is gone from --quality-delta, nothing else regressed, --edit-check
reports the contract you intended, and the --affected tests pass. Anything short of all four and the fix is
still a hypothesis.
The loop above converges on debt you just added. When the task is debt that was already there ("clean up this module", "fix the worst of it"), run this instead — bounded, one finding at a time:
gating=, then origin="new-symbol"); otherwise row 1 of
ripwire <dir> --quality-panel=strict --legend=compact pointed at the area you were asked about. The panel orders
by how many independent families agree, not by payoff — no validated value × cost ranking ships yet — so between
near-ties take the cheapest: small, tested, few --callers=SYM.join="deep+untested" on the row, or ripwire <dir> --affected=SYM --legend=compact
naming no <test> row that carries hops= (a partner="1" row without hops= is co-change, not reach), means
the refactor has no safety net. Write one against the UNCHANGED code
(→ ripwire-write-tests), see it pass, commit it alone. A test written after the refactor pins the new
behavior, not the old.--lint --lint-select=magic-number finding (C/C++/ObjC) → a named constant. "Leave it alone" is still on the menu.--quality-delta
(working tree vs git HEAD; re-pin after each commit if you pinned --quality-baseline) covers exactly this fix — after the commit it reads regressions="0" trivially
(head_basis="identity"); to check a fix already committed, run ripwire <dir> --quality-delta=HEAD --legend=compact
(that commit vs its parent). Then regressions= must be 0, not just gating=, and acked= must not rise (a
pre-ack hides a row). The one exemption: a kind="short-horizon-churn" row with churn="self" on a function this
session already fixed is the loop's own commits, not a regression — better, take the next row from a different
function. A fix that trades its target for a row of any other kind — a duplication, a params, a public
api-surface helper that should have been file-local — is a lateral move: revert it, don't ack it.
--quality-delta only lists what got worse, so confirm the target moved by re-running the command that ranked it.--quality-delta exits 2 only when a finding is preexisting-worse AND major AND unacked — the
gating="N" header count. Minor-tier, acked, and origin="new-symbol" findings all report but never gate,
so a green hook does not mean the diff added no debt — it means nothing that already existed got worse.
Non-zero is the hook contract, no wrapper needed: ripwire <dir> --quality-delta --legend=compact || exit 1. If you want CI
to also block on the debt a change ADDS, exit 2 will not do it for you — parse new-symbol="N" from the
header (--json is supported for this verb) and apply your own policy. Chain the
other deterministic gates in the same hook: det-gate (diff <(ripwire <dir>) <(ripwire <dir>), must be
byte-identical) and ripwire <dir> | xmllint --noout - (valid XML) — any non-zero exit blocks the commit.
ripwire measures STRUCTURE (complexity / duplication / reachability), not data flow — it cedes
use-after-move / taint / type / null errors to the compiler. A high amb= symbol can be a dispatch hub, not
a bug. Thresholds are heuristics: trust coupling/churn hardest, complexity as size-correlated (not
independent), and Martin I/A/D/nccd as descriptive only — never proof. Full catalog (definition · why it
predicts defects · evidence tier · the verb) → quality-metrics.md.
© redhat-et, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 1 other file in skills/ripwire-quality-bar of redhat-et/ripwire.
Open the folder on GitHubat commit 60dd3b3
Ripwire Quality Bar next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Ripwire Quality Bar this skillredhat-et/ripwire | 2.4k | — | ~8.4k | Automated safety check: Notes | Apache-2.0 | |
| WooCommerce Code Reviewwoocommerce/woocommerce | 11k | 3 repos | ~1.1k | Automated safety check: Pass | Custom licence | |
| Systematic Code Refactoringluongnv89/claude-howto | 42k | — | ~3k | Automated safety check: Pass | MIT | |
| Install Anti-Slop Oxlint Rulesdmmulroy/anti-slop | 5.3k | — | ~2.2k | Automated safety check: Pass | MIT | |
| Constraint-Driven Developmentaddyosmani/agent-skills | 103k | 2 repos | ~5.2k | Automated safety check: Pass | MIT | |
| Skill Doli Code ReviewDolibarr/dolibarr | 7.7k | 1 repos | ~1.1k | Automated safety check: Pass | MIT |
woocommerce/woocommerce
Reviews WooCommerce code changes against the project's standards, flagging backend PHP architecture, naming, documentation, data integrity and testing violations.
luongnv89/claude-howto
Guides refactoring in phases based on Martin Fowler's method: research, test coverage check, planning and small tested steps, with your approval at each phase.
dmmulroy/anti-slop
Installs, updates or migrates the vendored anti-slop Oxlint plugin in a repository, keeping local rule changes and the plugin's license and provenance files.
addyosmani/agent-skills
Records a project's quality bar in CONSTRAINTS.md and watches diffs for signs an agent quietly weakened it, such as suppressions, skipped tests or lowered thresholds.
Dolibarr/dolibarr
Reviews Dolibarr PHP code for compliance with coding standards and security best practices, and fixes identified issues.
DietrichGebert/ponytail
Makes the agent pick the laziest solution that works: skip unneeded work, reuse what exists, prefer the standard library and platform features, and keep diffs small.
redhat-et/ripwire
Rules for writing and converting formatted output in ripwire's C++ source with its emit helpers, keeping every printed byte identical to the old printf output.
redhat-et/ripwire
Checks whether a working-tree diff or a pull request is safe to merge: blast radius, tests to run, contract breaks, branch conflicts and stranded work.
redhat-et/ripwire
Answers call-graph questions that combine several conditions, such as complex functions that reach a target or untested symbols near main, using ripwire's graph-query mode.
redhat-et/ripwire
Produces a short brief for handing a code subsystem to a teammate or fresh session, using ripwire to rank symbols, expand bodies and surface design docs.
redhat-et/ripwire
Answers questions about a named symbol, such as its callers, what it calls, the path between two symbols or the downstream impact of changing it, using the ripwire CLI.
redhat-et/ripwire
Contributor guide for reading clang optimization remarks while editing ripwire's own C++, deciding between a source change and a build change such as LTO or PGO.
Categories
Code QUALITY of what YOU just wrote, before you commit or say 'done', or verifying a cleanup: --quality-delta lists what got WORSE in 11 kinds and exits 2 only when pre-existing code got materially…. Ripwire Quality Bar is an agent skill from redhat-et/ripwire. Code QUALITY of what YOU just wrote, before you commit or say 'done', or verifying a cleanup: --quality-delta lists what got WORSE in 11 kinds and exits 2 only when pre-existing code got materially worse; which restructuring a measured shape (humps/deep, a tangle) calls for.
Ripwire Quality Bar fits situations like: tasks that involve Code quality.
Run `npx skills add redhat-et/ripwire --skill ripwire-quality-bar -a claude-code`. Or copy the skill folder (skills/ripwire-quality-bar in redhat-et/ripwire) into .claude/skills/ripwire-quality-bar in your project. Claude Code loads it when a task matches its description.
Run `npx skills add redhat-et/ripwire --skill ripwire-quality-bar -a codex`. Or copy the skill folder (skills/ripwire-quality-bar in redhat-et/ripwire) into .agents/skills/ripwire-quality-bar in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add redhat-et/ripwire --skill ripwire-quality-bar -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/ripwire-quality-bar, .gemini/skills/ripwire-quality-bar, .github/skills/ripwire-quality-bar and .opencode/skills/ripwire-quality-bar in your project.
Going by SKILL.md and its folder, Ripwire Quality Bar needs the command-line tools its instructions call (git). Its frontmatter pre-approves these tools: Bash, Read.
SKILL.md contains no URLs. Its commands use git, which can reach the network depending on how they are called. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found notes only (pre-approves every shell command (allowed-tools: bash)), nothing it rates as a warning. It is not a guarantee. Review the folder before installing.
Ripwire Quality Bar is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 8.4k tokens (SKILL.md is roughly 34k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Ripwire Quality Bar: WooCommerce Code Review (woocommerce/woocommerce, 11k stars), Systematic Code Refactoring (luongnv89/claude-howto, 42k stars), Install Anti-Slop Oxlint Rules (dmmulroy/anti-slop, 5.3k stars) and Constraint-Driven Development (addyosmani/agent-skills, 103k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
redhat-et (a GitHub organization) maintains it in redhat-et/ripwire, which has 2,428 GitHub stars. The repository holds 19 skills in this directory. The repository was last updated on October 9, 2026.
Source: redhat-et/ripwire on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.