code-design-refactor — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited code-design-refactor (Agent Skill) and scored it 96/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 1 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 1 flagged
The text {match} tells the agent to skip the normal "ask the user first" gate. Used adversarially it removes the human-in-the-loop check before destructive or sensitive actions, turning a normally-gated agent into a fire-and-forget executor.
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
The design-level rung of the refactoring ladder. Tighter scope than improve-codebase-architecture (which surveys friction across the whole codebase), broader than logic-cleaner (which polishes inside a function). When a class is doing too much, when a function takes a tuple of primitives that ought to be a value object, when two modules know too much about each other — that's this skill's job.
| Skill | Operates on | Asks |
|---|---|---|
| logic-cleaner | Expressions, single function bodies | "Is this branch readable? Is this conditional negated?" |
| `code-design-refactor` | Functions, classes, modules within one package | "Does this thing have one reason to change? Is the seam in the right place?" |
| improve-codebase-architecture | The whole codebase, multiple modules, deep architectural drift | "Where are the shallow modules across the project? Where's the friction?" |
If a finding requires renaming a primitive boolean variable, use logic-cleaner. If it requires moving responsibilities between modules across the codebase, use improve-codebase-architecture. This skill handles the middle.
Three rules that govern every refactor, regardless of which specific move:
refactor(scope): <move>.The most common move. Pull a coherent chunk into its own named thing.
is_eligible_for_discount), not mechanics (check_status_and_total).When two modules know more about each other than they should.
service = SomeRegistry.get() with def __init__(self, service: SomeService). Makes testing trivial and dependencies visible.The classic rule, sharpened: one reason to change. A class with three reasons to change has three responsibilities, even if they all "look related."
Signs a thing has too many responsibilities:
<Noun>Manager, <Noun>Service, <Noun>Helper — the suffix is hiding what it actually does.The fix is extract class per §4, with the new classes named after the responsibilities you discovered.
Restrict access to internal state; force callers through the methods.
user.setStatus("active"); do user.activate(). The method enforces the rule that comes with the state change.if order.status == "draft": order.confirm(), write order.confirm_if_draft() and let the aggregate enforce its own invariants. Aligns with ddd-architect: behavior on the aggregate, not on the caller.When a primitive carries hidden meaning across the codebase, make it a value object (per ddd-architect §3).
Symptoms:
string named email is created.string currency_code is occasionally passed as a country_code because the type system can't tell them apart.int, int, int and only the parameter names tell you which is year, month, day.The fix is a tiny immutable type:
@dataclass(frozen=True, slots=True)
class Email:
value: str
def __post_init__(self) -> None:
if "@" not in self.value:
raise ValueError(f"invalid email: {self.value!r}")type Email string
func NewEmail(s string) (Email, error) {
if !strings.Contains(s, "@") {
return "", fmt.Errorf("invalid email: %q", s)
}
return Email(s), nil
}The validation now lives at construction; every call site receives an Email that's been validated; type confusion (Email passed where Username is expected) is a compile error in Go, a clear runtime error in Python.
Not every refactor is worth doing.
Each refactor is a tiny loop, not a big-bang change.
When a refactor reveals a deeper structural problem (port belongs in a different module; the responsibility split spans several packages), stop and hand off to improve-codebase-architecture. Don't expand scope.
refactor(scope): commit.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.