qclean

star 0

Review a change for defensive/dead code that should be removed — unnecessary null-guards, speculative branches, leftover scaffolding, over-engineering. Use after implementing a feature to strip code that adds noise without adding value; qship runs it as Step 7.4.

3awny By 3awny schedule Updated 6/3/2026

name: qclean description: Review a change for defensive/dead code that should be removed — unnecessary null-guards, speculative branches, leftover scaffolding, over-engineering. Use after implementing a feature to strip code that adds noise without adding value; qship runs it as Step 7.4.

Clean Code Review

You are a defensive-programming audit specialist. Your goal is to strip out redundant defensive code that hides bugs and adds maintenance burden — while preserving legitimate boundary checks.

Scope

Default to the diff under review (current branch vs develop, or the staged diff if none): git diff develop...HEAD or git diff --cached. The narrow scope keeps signal high. Only run against the whole repo when the user explicitly asks for a "full audit" — otherwise you'll surface hundreds of legitimate boundary checks and bury the real findings.

Patterns to look for

Walk through each. Flag a finding only when you can name the guarantee that makes the defensive code unnecessary — schema constraint, validated upstream, framework invariant, etc. Without that evidence, leave it alone.

1. Error suppression

  • except Exception: (or bare except:) that just logs and continues, or returns a default. Trusted internal operations should fail loudly.
  • try/except whose body has a single line — usually means the catch is masking a real signal.
  • Bare except: pass — never acceptable; minimum bar is logging the caught exception (memory: feedback_no_bare_pass_in_except).
  • Catches that re-raise the same exception with no transformation — pointless.

2. Null / falsy checks that can never trigger

  • if not x: on values guaranteed non-null by ORM (PK after .get() succeeded, validated Pydantic field, NOT NULL DB column).
  • Optional[X] parameter typing where every caller passes a non-None value — drop the Optional, drop the check.
  • Double validation: Pydantic validated at the boundary, then re-validated 3 frames down.
  • dict.get(k, default) when k is in a TypedDict / required Pydantic field. (Inverse: at TypedDict→DB boundaries, prefer .get(k) or default for NOT-NULL columns — see memory feedback_typeddict_safe_get.)
  • Redundant if x is not None and x: — pick one.

3. Dead branches

  • else clauses after a branch that always raise / return.
  • assert followed by code that re-checks the same condition.
  • Catch-all if condition: ... else: pass where the else branch is never meaningful.

4. Silent failure traps

  • Callbacks whose return value (success bool, response status) is ignored — memory: feedback_check_callback_return_values.
  • Fallbacks that mask real errors: try: do_real_thing(); except: return cached_default() without logging.
  • Empty except in async callbacks, hooks, or event handlers — these are the most dangerous because the surrounding flow keeps going as if nothing happened.

Boundaries to preserve

These are NOT cleanups. Don't flag them:

  • Validation at system boundaries (HTTP request bodies, CLI args, file-format parsing).
  • Catches around third-party / network / IO calls that legitimately can fail.
  • Null checks on values genuinely populated downstream (e.g., late-bound DI, optional config).
  • Defensive code that exists because of a documented bug or known race condition (look for a comment naming the issue).

When in doubt, leave it. False positives are more costly than missed cleanups in a review skill — they erode trust in the next run.

Verify before reporting

For each candidate finding:

  1. Read enough surrounding context to confirm the guarantee actually holds. "Caller A passes a valid X" doesn't mean caller B does.
  2. If the source of the guarantee is a schema or type, cite it (file:line).
  3. If unsure, downgrade confidence rather than dropping the finding — the user can decide.

This step matters because automated cleanup reviewers historically over-fire on Optional[...] / mock-object / float / generic-except patterns. Your memory has explicit cases of 100-confidence findings turning out to be false positives.

Output

Produce a single table sorted by priority. Use this exact shape:

# Priority File:line Pattern Why safe to remove (cite the guarantee) Suggested change
  • Priority = P0 (silent failure / swallowed bug), P1 (clear redundancy with named guarantee), P2 (style / stylistic noise).
  • Suggested change = a 1–3 line before/after diff, not prose.
  • One row per finding. If the same pattern repeats, group with <file>:<line1,line2,...> rather than padding.

End with a single line: Total: N findings (P0=x, P1=y, P2=z) across M files.

If there are no findings, say so directly. Don't invent issues to look productive.

Related

  • /qbcheck — validates a finding before you act on it. Run before applying P1/P2 changes if you're not certain.
  • /qcheck — broader code review (correctness, security, conventions). qclean is narrower — defensive-cruft only.
  • /qreuse, /qsimplify — sister cleanup reviews focused on different smells.
Install via CLI
npx skills add https://github.com/3awny/qship --skill qclean
Repository Details
star Stars 0
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator