Skip to content
Back to skills

Dry

ASecurity

Find the subsystems that should be one subsystem. Traces a codebase resource-first instead of subject-first, then reports every place N independent paths reach the same table, file, env var, endpoint, binary, or config key without ever meeting — or where N places define the same decision with different answers — the "we built four of these and none of them know about each other" failure that stays invisible until the bug count spikes. Produces a ranked Convergence Map naming the single gatewa...

  • 5 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 25, 2026
businesspythonrustgosqlnodecode-reviewgit

Works with

  • cli

Security analysis

A100/100

Scanned September 25, 2026

npx -y skills add HiQS-Labs/XYZ-forge --skill dry --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Dry?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Dry
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/hiqs-labs-dry/badge)](https://www.skillsdirectory.com/skills/hiqs-labs-dry)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: dry
description: >-
  Find the subsystems that should be one subsystem. Traces a codebase resource-first
  instead of subject-first, then reports every place N independent paths reach the same
  table, file, env var, endpoint, binary, or config key without ever meeting — or where N
  places define the same decision with different answers — the
  "we built four of these and none of them know about each other" failure that stays
  invisible until the bug count spikes. Produces a ranked Convergence Map naming the
  single gateway each cluster is missing. Trigger on /dry, and on "do we have duplicate
  subsystems", "why are there four of these", "these should go through one place",
  "find the near-duplicates", "is this already implemented somewhere", "we keep
  reimplementing this", "these paths should share a gateway", "DRY audit". Do NOT fire
  to grade one diff (that is /code-review), to trace one subject's blast radius (that
  is /recon), or to cluster recurring defects (that is /radar).
argument-hint: "[path or subsystem] [--depth quick|full]"
---

# DRY

Most duplication that hurts is not duplicated text. It is **duplicated knowledge**: four code
paths that each know how to reach the same resource, none of which know about the other three.
Text-similarity tools miss it — the four rarely look alike — and they drown the real finding in
near-miss noise until people stop reading the report.

This skill inverts the usual trace. Recon asks *"what does my subject touch?"* DRY asks the same
question backwards: **"for each resource, who touches it, and do those touchers ever meet?"**

## The one rule

**A finding must name a shared *resource* or a shared *policy*, never a shared *syntax*.** Two
functions that look alike are not a finding. Two functions that both write `users.credits` by
different paths are, whether or not they share a line of text — and so are two modules that both
define what counts as a paid order, with different value sets.

The rule forbids clustering on how code *reads*. It does not forbid clustering on what code
*decides*.

## When NOT to fire

- Grading one diff or PR → `/code-review`.
- Tracing one subject's blast radius before a change → [recon](https://github.com/HiQS-Labs/XYZ-forge/blob/development/skills/1-hourly/recon/SKILL.md).
- Clustering recurring *defects* rather than structures → [radar](../radar/SKILL.md).
- A repo under ~30 source files. Read it; you do not need a report to see four of anything.
- Deliberate parallelism: N adapters behind one interface, N drivers registered to one registry,
  N tests of one unit. **That is the gateway pattern working.** Report it only if the adapters
  bypass their own interface.

## Step 1 — Scope and resource classes

Name the root and the change budget in one line. Then pick which resource classes to index — all
of them for a full audit, two or three for a quick pass:

| Class | What to extract |
|---|---|
| **Store** | table/collection names, SQL targets, ORM models, key prefixes, bucket names |
| **File** | concrete paths and path-building patterns, lockfiles, state dirs, log destinations |
| **Config** | env vars, config keys, feature flags, secrets names |
| **Network** | hosts, base URLs, endpoint paths, queue/topic names |
| **Process** | external binaries invoked, subprocess/`exec` targets, CLI names |
| **Boundary** | first-party references pointing *into* an excluded, vendored, or generated tree, and module-path surgery that makes them work — `sys.path` inserts, `PYTHONPATH`, `NODE_PATH`, classpath tweaks. **Reportable at any toucher count:** excluding a tree hides its contents, not the reaches into it, so this shape sits below every threshold and must be exempt from them. |
| **Policy** | named constants and the *values* they carry — status/enum value sets, thresholds, byte and row ceilings, timeouts, retry counts and backoff formulas, truncation limits, allowlists |

**Policy is the class most often missed and most often expensive.** Index the *name and its value
set together* — rival definitions of one concept rarely share a name, so identifier matching will not
group them. Use this test instead:

> **Could one real-world event — a single order, request, upload — be classified differently by the
> two value sets?**

Yes → one decision split across N sites. No → different policies, however alike they look. When the
read site is hard to follow, the cheap proxy is whether the predicates reference the same entity and
field (`order.status`, `payment.state`).

**Disagreeing values are a defect only where one owner should answer.** Touchers serving different
operations or failure domains may rightly disagree — a health probe's 2-second connect timeout and a
bulk uploader's 60-second one are not a cluster, and merging them is the wrong DRY. Say why the
decision should be single before filing it.

Language does not matter — every class above is a *literal* in almost every language, which is why
this works on a polyglot tree with no parser, no index, and no git history.

## Step 1b — Read the repo's own rules first

Before indexing, read `AGENTS.md`, `CLAUDE.md`, `ARCHITECTURE.md`, `CONTRIBUTING.md`, and any
`GUIDING-PRINCIPLES` file. Ten minutes, and it changes what every later finding means:

- A rule the repo already states turns a finding from an opinion into a **violation**. "Keep
  BigQuery access behind one thin wrapper" quoted from `AGENTS.md` beside six scattered call sites is
  an argument nobody has to win.
- A **recorded decision** turns an apparent defect into house style. Contradicting one is the most
  expensive mistake this skill can make — check the docs and the inline comments before you file.

Quote the rule in the finding. Do not paraphrase it.

## Step 2 — Build the resource index (the recon half, inverted)

Sweep the tree once and emit `resource -> [file:line, ...]`. Exclude vendor, build, and dependency
directories, and say which you excluded.

Do it with the cheapest tool that holds: `rg` with a pattern per class, one pass each. If a
`codebase-memory` graph is installed, seed from it — but every edge a finding rests on is confirmed
by reading the file, exactly as in [recon](https://github.com/HiQS-Labs/XYZ-forge/blob/development/skills/1-hourly/recon/SKILL.md). Graph-only edges are marked and never ranked.

An empty class is a finding, not a failure: a repo with no config-key duplication should say so.

## Step 2b — Audit the guards, do not trust them

If the repo ships a CI check, lint rule, or script that guards a duplication class — a
`check_no_*.sh`, a banned-import checker, a contract test — **run it, then check its coverage against
your index.** A guard is a claim, and this skill exists to test claims.

- Read its target list. Does it walk every directory the violations live in?
- Read its pattern. Does it match the identifier names the code actually uses, or only the ones its
  author had in mind?
- Compare its result to your own index for the same class. **Green plus violations in your index is a
  finding, and usually the most urgent one in the report** — because a green guard is read as
  evidence, and everyone downstream stops looking.

## Step 3 — Pivot: group, then test for disjointness

For each resource with **≥3 touching files** (**≥2** if any toucher *writes* it — write paths
diverge faster and hurt sooner; **for Policy, a definer counts as a writer**, so two rival
definitions of one decision clear the threshold), ask the question that separates a finding from a
coincidence:

> **Do these files ever meet?**

They meet if they share an import, extend a common base, or route through a common module. Resolve
it by reading the imports of each toucher — not by proximity in the tree.

- **They all meet** → not a finding. One gateway already exists; note it in *Already converged*.
- **Some meet, some do not** → **bypass finding.** A shared owner exists and part of the tree routes
  around it — including files that import it and do the job themselves anyway. This is the most
  common shape in a maturing codebase and the one `converge` expects this skill to emit; do not let
  the existence of a gateway close the question.
- **None meet** → **convergence target.** N independent paths to one resource is the shape the user
  feels as "these should all go through one place."

## Step 4 — Corroborate — two signals or it is not reported

Disjoint-touchers alone over-reports. A target ships only with a **second independent signal**:

1. **Parallel vocabulary** — same noun, different qualifier: `*-turn.sh` ×8, `fooV2`, `new_foo`,
   `enhanced_foo`, `foo_helper` beside `foo_utils`. High signal in LLM-built trees specifically,
   because a model names the sixth implementation rather than finding the first.
2. **Literal constellation** — the same 2–3 literals (a URL *and* a magic key *and* a field name)
   co-occurring in files that do not import each other. That is copied knowledge, not coincidence.
3. **Same-shape entry** — N callables with near-identical parameters and the same output contract.
4. **Divergence evidence** — the touchers already disagree: different retry counts, different
   timeouts, one validates and the others do not. This is the strongest corroborator, because it
   is the bug the cluster will produce, already visible.

Signal 4 promotes a target to the top of the ranking on its own.

## Step 5 — Rank by what one fix retires

For each surviving target: **how many call sites collapse into the gateway, and what breaks today
because they have not?** Rank by that, not by cluster size — a 3-file cluster that already
disagrees on validation outranks an 8-file cluster that agrees on everything.

Mark each target's cost honestly: introducing a gateway is a **crossing** change, and if any
toucher is consumed by another repo it is **irreversible**. Hand the classification to
[triangulate](https://github.com/HiQS-Labs/XYZ-forge/blob/development/skills/1-hourly/triangulate/SKILL.md) rather than deciding the fix's size here.

## Step 6 — Write the Convergence Map

Long output belongs in a file: write `convergence-<repo-or-subsystem>.md` at the root of what you
scanned. Chat gets the verdict line, the path, and the top target.

```markdown
# Convergence Map — <scope>
Scanned: <N files, M excluded dirs> · Mode: <rg-only | graph+read> · Classes: <which>

## Verdict
<N convergence targets, ranked. The one-line headline.>

## Targets
### T1 — <resource> · <N paths, disjoint> · retires <M call sites>
| Path | Where | Reads/Writes | Disagrees on |
|---|---|---|---|
| <name> | file:line | W | retry=3 |
**Missing gateway:** <the one module these should route through, and where it should live>
**Evidence:** <which corroborating signals fired>
**Cost:** <contained|crossing> x <reversible|irreversible> — hand to /triangulate

## Already converged
<resources with ≥3 touchers that DO meet — proof the audit is not trigger-happy>

## Unknowns
| Unknown | Why it matters | What would settle it |
```

The **Already converged** section is load-bearing. An audit that only reports sins reads as a tool
with its thumb on the scale, and it is the section that tells you whether the sweep was honest.

## Honesty rules

- **Search the issue tracker before reporting.** For each target, search open *and* closed issues for
  the resource or constant name, and label it `new`, `tracked (#N)`, or `closed-but-present (#N)`.
  That last label is its own finding: work that was closed without landing. Re-filing tracked work is
  how an audit loses its reader.
- Every path in a target cites `file:line`. No `file:line`, no row.
- Never claim two files "don't talk" without having read both import blocks. Say `unverified`.
- Zero targets is a real result on a small or well-factored tree. Say which, rather than
  manufacturing a cluster to look thorough.
- Do not propose the gateway's implementation. DRY names what should converge and stops;
  [triangulate](https://github.com/HiQS-Labs/XYZ-forge/blob/development/skills/1-hourly/triangulate/SKILL.md) sizes the change and `/ponytail` shrinks it.

## Neighbors

- [recon](https://github.com/HiQS-Labs/XYZ-forge/blob/development/skills/1-hourly/recon/SKILL.md) — traces one subject outward. DRY runs the same trace resource-first.
- [triangulate](https://github.com/HiQS-Labs/XYZ-forge/blob/development/skills/1-hourly/triangulate/SKILL.md) — sizes and paces the convergence work this skill finds.
- [radar](../radar/SKILL.md) — clusters recurring defects; DRY clusters structures. A repo that keeps producing the
  same bug class is often a DRY target radar has already noticed from the other end.
- [ponytail](https://github.com/HiQS-Labs/XYZ-forge/blob/development/skills/1-hourly/ponytail/SKILL.md) — a gateway is machinery; make it the smallest one that works.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…