|
| 1 | +--- |
| 2 | +name: deslop-comments |
| 3 | +description: Rewrite code comments and docs touched during the current conversation into Simple English, stripping AI-slop / AI-lingo vocabulary and negative framing. Use when the user says "deslop these comments", "clean up the comments we just wrote", "rewrite this in plain English", or after a review flags comments as convoluted/AI-sounding. Comment-only - never changes function names, APIs, or behavior. |
| 4 | +--- |
| 5 | + |
| 6 | +# Deslop comments |
| 7 | + |
| 8 | +Rewrites comments and doc blocks into short, direct Simple English. This is a comment-only pass: no renames, no logic changes, no behavior changes. |
| 9 | + |
| 10 | +## Scope |
| 11 | + |
| 12 | +Default scope is **files the current task actually created or edited** - find the candidate set with `git diff --name-only` / `git status --short` against the base the conversation started from. If the user names specific files, a directory, or a Pull Request instead, use that scope. |
| 13 | + |
| 14 | +Do not expand scope to a file just because the agent `Read` it or reviewed it in passing - a debugging or review session routinely reads many unrelated files, and reading one is not authorization to rewrite its comments. If there is no edited-file set and no explicit scope from the user, ask which files to cover. |
| 15 | + |
| 16 | +## What counts as slop |
| 17 | + |
| 18 | +Rewrite a comment if it has any of: |
| 19 | + |
| 20 | +1. **Dense, multi-clause sentences** that try to explain everything at once instead of one idea per sentence. |
| 21 | +2. **Negative / before-state framing** - describing removed code, or leading with "not X" when X was never the point. Keep "not X, it's Y" only for a genuine edge case, a non-obvious gotcha, or bug-fix rationale worth flagging; otherwise state the current behavior directly. |
| 22 | +3. **AI buzzwords** in place of plain software engineering vocabulary. Common offenders and their replacements: |
| 23 | + - `gate` / `gates` / `gating` → "check", "decides whether to show...", "authentication check", "feature check" |
| 24 | + - `guard` → "check" / "prevent" |
| 25 | + - `backstop` → "handles the case where..." / "protects us either way" |
| 26 | + - `load-bearing` → "useful" |
| 27 | + - `predicate` → "helper" |
| 28 | + - `presentational` (component) → "this component only displays the result" |
| 29 | + - "flattens to a bare new Error" → "turns into a plain new Error" |
| 30 | + - `harness` → name the concrete thing: "test setup", "test wrapper", "fixture", "mock server", or "runner" |
| 31 | + - `realm` → "environment", "runtime", or "context" (unless it's the precise JS-realm technical term) |
| 32 | + - `landed` → "implemented" |
| 33 | + - `mint` → "created" |
| 34 | + - `leverage` → "use" |
| 35 | + - `utilize` → "use" |
| 36 | + - `surface` → "show" / "return" / "report" |
| 37 | + - `plumb` / `wire` → "pass" / "connect" / "call" |
| 38 | + - `broker` → "handle" / "route" / name the service/helper (keep broker if that's the concept name in some architecture, library, service, etc.) |
| 39 | + - `canonical` → "shared" / "standard" |
| 40 | + - `churn` → "unnecessary changes" |
| 41 | + - `invariant` → "rule" / "condition" / "constraint" / or something like "state that must stay true" |
| 42 | + |
| 43 | + Do not apply this as a blind blacklist. Keep the original word when it is the precise domain term, especially for security, type-system, React, database, FHIR, or JavaScript runtime concepts. For example, `opaque` is a precise security/API term for an id, token, or string whose structure and meaning a caller must not depend on ("recipient is an opaque viewer-supplied string; never log it"); it is not on the replacement list above, so leave it — "generic" would drop that contract. |
| 44 | +4. **Undocumented return shapes.** A function returning an object or union should say what each field/variant means, not just that it "returns a result." |
| 45 | +5. **Any other AI-slop or AI-lingo words, framing, structure.** |
| 46 | + |
| 47 | +## What to leave alone |
| 48 | + |
| 49 | +- Function, type, and API names - this is a comment-only pass. |
| 50 | +- Log strings and error messages shown to users. |
| 51 | +- Generated files (e.g. `*.gen.ts`, Prisma client output). |
| 52 | +- Genuine security markers or contracts written as caps-negatives (`NEVER log PHI`, `Does NOT upsert`) - these are useful warnings, not slop. |
| 53 | +- User-facing UI copy (JSX text nodes rendered to the browser) - that's product copy, not a code comment. |
| 54 | +- Already-clear one-liners that don't exhibit any of the problems above. Don't rewrite for the sake of rewriting. |
| 55 | + |
| 56 | +## Process |
| 57 | + |
| 58 | +1. Build the file list per Scope above. |
| 59 | +2. For each file, read every comment/doc block (`//`, `/* */`, `/** */`, `#`, `%`, depending on the language) and check it against "What counts as slop." Skip anything covered by "What to leave alone." |
| 60 | +3. Rewrite in place with `Edit`. Prefer one idea per sentence. When a function's return type is a union or object with meaningful fields, spell out what each branch/field means using the comment body or JSDoc (or similar) if it's a project pattern. |
| 61 | +4. After editing, confirm the diff is comment-only: `git diff -- <files>` should show no code-line changes, only comment text. |
| 62 | +5. Run the project's lint/typecheck on touched files (e.g. `pnpm biome check <files>`, `pnpm --filter <pkg> typecheck`) to confirm nothing broke. |
| 63 | +6. Summarize what changed in 1-2 sentences - don't restate every line edited. |
| 64 | + |
| 65 | +## Example |
| 66 | + |
| 67 | +Bad (dense, negative framing, buzzwords): |
| 68 | +``` |
| 69 | +// Server-to-server auth gate. Fail closed if the token is unconfigured. |
| 70 | +try { |
| 71 | + if (!verifyServiceAuth(request)) { ... } |
| 72 | +} |
| 73 | +``` |
| 74 | + |
| 75 | +Good (Simple English, positive framing, no AI-lingo structure): |
| 76 | +``` |
| 77 | +// Server-to-server authentication check. Deny the request if the token is unconfigured. |
| 78 | +try { |
| 79 | + if (!verifyServiceAuth(request)) { ... } |
| 80 | +} |
| 81 | +``` |
| 82 | + |
| 83 | +Bad: |
| 84 | +``` |
| 85 | +// NOTE: this forward-block is a UI courtesy only, not a per-step gate. |
| 86 | +// `currentStepIndex` derives from the current URL path — not from saved |
| 87 | +// progress — so navigating to a later step's URL directly bypasses it |
| 88 | +// entirely. The template deliberately ships no per-step route guards |
| 89 | +// (forks may want different ordering/skipping rules); the integrity |
| 90 | +// backstop is the server-side readiness check at intake completion, |
| 91 | +// which refuses to finalize while any step is missing. |
| 92 | +const canNavigateToStep = useCallback(...) |
| 93 | +``` |
| 94 | + |
| 95 | +Good: |
| 96 | +``` |
| 97 | +// This limits forward navigation in the UI only. `currentStepIndex` comes from |
| 98 | +// the current URL path, not from saved progress, so visiting a later step's URL |
| 99 | +// directly still works. The template intentionally ships no per-step route |
| 100 | +// checks, since forks may want different ordering or skipping rules. The real |
| 101 | +// safeguard is the server-side check at intake completion, which refuses to |
| 102 | +// finalize while any step is missing. |
| 103 | +const canNavigateToStep = useCallback(...) |
| 104 | +``` |
| 105 | + |
| 106 | +Bad: |
| 107 | +``` |
| 108 | +// Throttle first — cheapest gate. Bounds Argon2 CPU amplification and |
| 109 | +// request flooding on this public endpoint (best-effort, per-instance). |
| 110 | +const rate = await checkRateLimit(getClientKey(request)) |
| 111 | +``` |
| 112 | + |
| 113 | +Good: |
| 114 | +``` |
| 115 | +// Check the rate limit first, since it's the cheapest check to run. Bounds |
| 116 | +// Argon2 CPU amplification and request flooding on this public endpoint. |
| 117 | +const rate = await checkRateLimit(getClientKey(request)) |
| 118 | +``` |
| 119 | + |
| 120 | +Bad: |
| 121 | +``` |
| 122 | +/** |
| 123 | + * Whether the patient may finalize their intake: every required step must be |
| 124 | + * validly filled and one of the payment steps must have a saved response. |
| 125 | + * Server-authoritative — `completeIntake` enforces the same rule, so a client |
| 126 | + * skipping this check cannot complete a partial intake. |
| 127 | + * |
| 128 | + * Required steps are validated (not presence-checked) so a Save-for-later draft |
| 129 | + * counts as still-missing: the patient is sent back to the earliest unfinished |
| 130 | + * step (e.g. Demographics) rather than skipped past it to a later one. |
| 131 | + */ |
| 132 | +export async function getIntakeReadiness(headers: Headers): Promise<IntakeReadiness> { ... } |
| 133 | +``` |
| 134 | + |
| 135 | +Good: |
| 136 | +``` |
| 137 | +/** |
| 138 | + * Returns whether the patient can finalize their intake: every required step |
| 139 | + * must pass its schema, and one of the payment steps must have a saved |
| 140 | + * response. `completeIntake` enforces the same rule on the server, so a |
| 141 | + * client cannot complete a partial intake by skipping this check. A |
| 142 | + * Save-for-later draft counts as missing, which sends the patient back to |
| 143 | + * the earliest unfinished step (e.g. Demographics) instead of skipping past |
| 144 | + * it. In the returned object, `ready` tells whether the intake can be |
| 145 | + * completed, and `missingSteps` lists the keys of the steps still missing. |
| 146 | + */ |
| 147 | +export async function getIntakeReadiness(headers: Headers): Promise<IntakeReadiness> { ... } |
| 148 | +``` |
0 commit comments