swarm repositories / source
aboutsummaryrefslogtreecommitdiff
path: root/skills/exterminate-slop/SKILL.md
diff options
context:
space:
mode:
Diffstat (limited to 'skills/exterminate-slop/SKILL.md')
-rw-r--r--skills/exterminate-slop/SKILL.md381
1 files changed, 140 insertions, 241 deletions
diff --git a/skills/exterminate-slop/SKILL.md b/skills/exterminate-slop/SKILL.md
index a6b572b..4d15305 100644
--- a/skills/exterminate-slop/SKILL.md
+++ b/skills/exterminate-slop/SKILL.md
@@ -1,32 +1,48 @@
---
name: exterminate-slop
-description: Perform an exhaustive Rust-only subtree audit and refactor pass for primitive obsession, under-abstraction, and DRY violations. Use when Codex needs to inspect every Rust file in a requested code subtree for strings, bools, tuples, parameter clumps, duplicated logic, repeated field bundles, or weak abstractions, and must follow a rigid ledgerized process instead of a loose best-effort review.
+description: "Perform an exhaustive language-aware subtree audit and refactor pass for primitive obsession, under-abstraction, duplicated logic, defensive ceremony, and code-volume bloat. Use when Codex needs to inspect every source file in a requested scope, keep a persisted worklog/ledger, and refactor toward strong types, DRY abstractions, and sharply reduced code without behavior drift."
---
# Exterminate Slop
-Read the repo's [AGENTS.md](../../AGENTS.md) first.
+Read the target repo's AGENTS.md files first.
-Rust only. Do not spend context on language-agnostic framing.
+This is a slop extermination pass, not a style review. The objective is to crush code volume and ceremony while increasing semantic density. Preserve externally observable behavior unless the user explicitly asks for behavior change. Do not preserve backward compatibility by default.
+
+## Language Lens
+
+Before the first source read, determine the dominant implementation language for the requested scope and read exactly one note:
+
+- Rust: [references/languages/rust.md](references/languages/rust.md)
+- Java: [references/languages/java.md](references/languages/java.md)
+- Python: [references/languages/python.md](references/languages/python.md)
+- TypeScript: [references/languages/typescript.md](references/languages/typescript.md)
+
+If the scope truly crosses language boundaries, start with the dominant language and load a second note only when edits must cross that boundary. If no note exists for the dominant language, proceed with this generic core and record the missing note in the worklog.
## Contract
-- Require a concrete Rust subtree. If the user names only a repo, choose the smallest plausible subtree and state the assumption.
+- Require a concrete source subtree. If the user names only a repo, choose the smallest plausible subtree and state the assumption.
- Default to `audit_plus_refactor` unless the user clearly wants findings only.
-- Inspect every `*.rs` file in scope. No sampling and no “representative files.”
-- Create one persistent `/tmp` worklog before the first code read. Chat is summary only; the worklog is the durable source of truth.
+- Build a full manifest of in-scope source files for the chosen language. No sampling and no "representative files."
+- Exclude generated, vendored, build-output, fixture, snapshot, and dependency files unless the user explicitly includes them.
+- Create one persistent `/tmp` worklog before the first source read. Chat is summary only; the worklog is the durable source of truth.
+- Take a cheap code-volume baseline for the manifest before edits. At minimum count lines; token count is welcome when cheap.
- Partition the manifest into intentional logical cliques before deep reading.
- Read at most 8 files per wave.
- Write a `/tmp` checkpoint after every wave before reading more files.
- Record raw suspects during coverage, then promote only threshold-clearing suspects into the formal ledger after full coverage.
- Force a decision on every promoted ledger row.
- Do not edit until the promoted ledger exists, unless the user explicitly asked for a narrow hotfix instead of a full extermination pass.
+- Refactor in abstraction batches, not in arbitrary file order.
+- Run the narrowest meaningful checks after edits, then widen if the abstraction crosses boundaries.
+- Re-scan the manifest and record residual slop plus code-volume delta.
Files may be re-read. Re-reading is expected when a file belongs to multiple logical cliques or when a later duplication cluster changes the correct abstraction boundary.
## Flow
-### 0. Create the worklog
+### 0. Create The Worklog
Create a path shaped like:
@@ -34,155 +50,145 @@ Create a path shaped like:
/tmp/exterminate-slop-<repo-or-dir>-<subtree-slug>.md
```
-Seed it with the embedded worklog skeleton from `Embedded Forms`.
-
-The worklog must hold:
+Seed it with the worklog skeleton below.
-- the manifest
-- the clique plan
-- every wave checkpoint
-- the rejected clusters
-- the promoted ledger
-- the residual sweep
+The worklog must hold the language lens, manifest, volume baseline, clique plan, wave checkpoints, rejected clusters, promoted ledger, edits, verification, residual sweep, and volume delta.
If interrupted or resumed, reopen the same worklog before continuing.
-### 1. Lock scope and manifest
+### 1. Lock Scope And Manifest
-Enumerate the full Rust-file manifest, for example with:
+Enumerate the full source manifest using the loaded language note. Examples:
```bash
rg --files <subtree> -g '*.rs'
+rg --files <subtree> -g '*.java'
+rg --files <subtree> -g '*.py'
+rg --files <subtree> -g '*.ts' -g '*.tsx' -g '*.mts' -g '*.cts'
```
-Write the manifest in the embedded form from `Embedded Forms` and persist it into the `/tmp` worklog immediately.
+Persist the manifest and baseline immediately. If the note gives different inclusion rules, follow the note.
-### 2. Plan logical cliques
+### 2. Plan Logical Cliques
-Before deep reading, group manifest files into small logical cliques using the embedded clique-wave form from `Embedded Forms`.
+Before deep reading, group manifest files into small logical cliques.
Good clique causes:
-- shared domain types
-- repeated parse / validate / normalize flows
-- repeated rendering / formatting flows
+- shared domain concepts or latent domain objects
+- repeated parse, validate, normalize, or coercion flows
+- repeated rendering, formatting, serialization, or transport mapping
+- repeated construction, patch, query, or conversion logic
- repeated control-flow skeletons
-- repeated construction / patch / conversion logic
+- parameter clumps, field bundles, or option bags crossing boundaries
- module-boundary interactions
- suspected duplication clusters
Cliques may overlap. A file may appear in multiple cliques. Keep cliques to 2-8 files; split larger conceptual groups into multiple related waves.
-### 3. Run bounded coverage waves
+### 3. Run Coverage Waves
For each clique wave:
- read at most 8 files
-- use `rust_analyzer` aggressively for definitions, references, rename feasibility, and boundary understanding
-- prefer `rust_analyzer` from live use sites in the current clique, not blind declaration-first jumps
-- update the manifest coverage
-- write a `/tmp` checkpoint containing:
+- use the language's semantic navigation tools aggressively when available
+- anchor from live use sites before declaration spelunking
+- update manifest coverage
+- write a checkpoint containing:
- clique id and purpose
- - files inspected in the wave
+ - files inspected
- raw suspects
- duplication hypotheses strengthened or weakened
- files worth re-reading in later cliques
+ - abstraction pressure
+ - code-volume pressure
Do not read a 9th file until that checkpoint exists. A file counts as covered once it has been read in at least one wave.
-Concrete `rust_analyzer` pattern:
-
-- start at a live use site: field access, constructor call, function call, match arm, or repeated conversion site
-- use hover or definition there to anchor the actual symbol in play
-- then expand with references once the anchor is correct
-- use rename feasibility only after the symbol has been anchored from a concrete use site
-
-If declaration-first references are noisy or incomplete, return to a concrete use site and trace outward again.
-
-### 4. Run smell passes
+### 4. Run Smell Passes
Run distinct passes over the manifest and checkpointed suspects. If a pass needs more context, form another clique and respect the 8-file cap again.
-#### String suspicion
-
-Interrogate meaningful `String`, `&str`, string discriminators, and stringly keys.
-
-Ask whether the value is really an id, slug, path, URL, email, unit, currency, locale, timestamp, status, or other validated domain token; whether normalization or parsing repeats at call sites; whether the value set is finite; and whether multiple strings travel together as a latent record.
+#### Primitive Semantics
-#### Bool suspicion
+Interrogate strings, numbers, booleans, nulls, sentinels, loose maps, loose objects, tuple-ish sequences, and raw identifiers. Ask whether the value is really an id, slug, path, URL, unit, currency, status, mode, phase, capability, policy, timestamp, validated token, finite world, or richer domain object.
-Interrogate meaningful `bool`.
+#### Bundles And Bags
-Ask whether it is really a mode, strategy, phase, policy, capability, or tri-state; whether call sites become unreadable because the meaning is positional; and whether correlated bools are encoding illegal states that want an enum or policy type.
+Interrogate tuples, argument clumps, option bags, repeated object shapes, repeated field bundles, parallel collections, public optional walls, and correlated primitive sets. Ask whether the same values travel together, whether invalid states are currently representable, and whether one named representation would delete the surrounding ceremony.
-#### Tuple suspicion
+#### Duplication And Under-Abstraction
-Interrogate tuple types, tuple returns, and repeated destructuring.
+Search for repeated parse, validate, normalize, default-fill, render, serialize, authorize, query, convert, patch, compare, and error-shaping logic. Search for branch skeletons with only small local differences. Treat DRY as stronger than YAGNI.
-Ask whether the order is accidental, whether the elements have stable names in human discussion, whether the tuple crosses module boundaries, and whether the same shape is repeatedly rebuilt or unpacked.
+#### Defensive Theater
-#### Parameter-clump and field-bundle suspicion
+Interrogate checks, wrappers, fallbacks, compatibility shims, exception laundering, nil/null/undefined handling, default values, and "safe" access paths. If static structure, construction flow, or local dominance proves the value exists, delete the ceremony. If the fallback has no honest semantics, fail fast.
-Interrogate functions, constructors, builders, and repeated local bundles.
+#### Code-Volume Bloat
-Ask whether the same 2-5 values travel together repeatedly, whether repeated bundles imply invariants, and whether an argument list wants a domain struct or value object.
+Interrogate code whose main sin is existing: pass-through layers, one-line wrappers, adapter twins, DTO mirrors, getter/setter husks, scattered casts, repeated fixtures, duplicated builders, commented-out compatibility, and explanatory locals that only compensate for weak structure. The pass has an explicit line/token reduction objective.
-#### Duplication and under-abstraction
-
-Search for repeated parse / validate / normalize pipelines, repeated format / render / serialize logic, repeated match skeletons, repeated field-by-field copying, repeated conversions, repeated error shaping, and repeated query predicates.
-
-#### Primitive control encodings
-
-Interrogate string discriminators, integer type codes, sentinel values, parallel collections implying a missing domain object, and repeated `Option` / `bool` combinations that really encode richer states.
-
-### 5. Promote suspects
+### 5. Promote Suspects
During coverage, keep only raw suspects. After every manifest file has been inspected at least once, promote a suspect into the formal ledger only if at least one is true:
- it appears in more than one file or module
-- it crosses a crate or module boundary
-- it shows invariant pressure rather than mere cosmetic repetition
+- it crosses a meaningful boundary
+- it shows invariant pressure rather than cosmetic repetition
+- it deletes code volume while preserving or strengthening semantics
- the fix is locally actionable now
-Anything not promoted must still be accounted for as a short rejected cluster using the embedded rejected-cluster form from `Embedded Forms`. Persist both promoted and rejected outcomes in the `/tmp` worklog.
+Anything not promoted must still be accounted for as a short rejected cluster. Persist both promoted and rejected outcomes in the worklog.
+
+### 6. Populate And Adjudicate The Ledger
-### 6. Populate and adjudicate the promoted ledger
+Populate the formal ledger with one row per promoted candidate.
-Populate the formal ledger with the embedded ledger form from `Embedded Forms`. Only promoted candidates belong there.
+Allowed `kind` values:
-For every row, run the embedded adjudication checklist and choose exactly one:
+- `primitive_semantics`
+- `weak_type`
+- `boolean_mode`
+- `tuple_or_sequence`
+- `clump_or_bag`
+- `duplicate_logic`
+- `primitive_control_encoding`
+- `defensive_theater`
+- `ceremonial_layer`
+- `volume_bloat`
+
+Allowed `decision` values:
- `refactor_now`
- `defer`
- `false_positive`
- `needs_broader_design`
-Keep the authoritative ledger in the `/tmp` worklog even if chat shows only a condensed view.
+For every row, choose exactly one decision. The ledger is authoritative even if chat shows only a condensed view.
-### 7. Refactor in batches
+### 7. Refactor In Batches
-Group work by abstraction move rather than by file.
+Group work by semantic move:
-Preferred moves:
+- primitive semantics → domain type, literal world, enum, opaque/branded type, value object, validated constructor, or parser boundary
+- primitive control encoding → closed variant, state type, policy object, dispatch table, or sealed/discriminated hierarchy
+- tuple or clump → named domain object with the invariant in one place
+- loose bag → precise typed record, variant, or boundary DTO converted immediately
+- duplicate logic → one owner function, constructor, trait/protocol/interface, table, macro, generator, or module
+- defensive theater → static proof, fail-fast access, or single boundary check
+- volume bloat → deletion, fusion, abstraction, or mechanical modernization
-- primitive id or validated token → newtype / value object
-- string or bool discriminator → enum
-- tuple or clump → named struct
-- repeated validation or parsing → constructor or smart parser
-- repeated conversion or patch logic → dedicated helper, trait, or module
-- repeated branch skeleton → extracted abstraction
+Prefer the clean shape over compatibility. Apply the language note's sharper moves where it speaks.
-Apply the more specific move guidance in `Embedded Refactor Playbook`.
-
-Preserve public API compatibility only if the user asked for it. Otherwise prefer the clean shape.
-
-### 8. Verify and sweep
+### 8. Verify And Sweep
After edits:
- run relevant checks on the touched surface
- re-scan the same manifest
-- update the worklog with eliminated rows, deferred rows, false positives, and residual hotspots
+- measure code-volume delta
+- update the worklog with eliminated rows, deferred rows, false positives, residual hotspots, verification, and volume results
Prefer the narrowest checks that still validate the changed surface, then widen if needed.
@@ -190,14 +196,16 @@ Prefer the narrowest checks that still validate the changed surface, then widen
### Worklog Skeleton
-Create one persistent worklog file per extermination run.
-
```text
worklog_path:
scope_root:
inspection_mode: audit_only | audit_plus_refactor
+language:
+language_note:
wave_size_limit: 8
+volume_baseline:
+
manifest:
clique_plan:
@@ -208,35 +216,34 @@ rejected_clusters:
promoted_ledger:
-residual_sweep:
-```
+edits:
-Rules:
+verification:
-- create this file before the first code read
-- update it after every 8-file wave before reading more files
-- treat it as the durable source of truth for the run
-- if chat summaries are shorter, the worklog still must remain complete
-- report the final worklog path in the user-facing response
+residual_sweep:
-### File Manifest
+volume_after:
+volume_delta:
+```
-Build this before analysis starts.
+### File Manifest
```text
scope_root:
inspection_mode: audit_only | audit_plus_refactor
+language:
+language_note:
wave_size_limit: 8
files:
-- [ ] path/to/file_a.rs
-- [ ] path/to/file_b.rs
-- [ ] path/to/file_c.rs
+- [ ] path/to/file_a
+- [ ] path/to/file_b
+- [ ] path/to/file_c
```
Rules:
-- include every `*.rs` file in the requested subtree
+- include every source file in the requested subtree for the selected language
- mark files as inspected only after reading them
- allow files to appear in multiple clique waves
- do not delete rows from the manifest during refactoring
@@ -244,8 +251,6 @@ Rules:
### Clique Wave Checkpoint
-Plan and checkpoint every bounded read wave with this format.
-
```text
clique_id:
purpose:
@@ -253,35 +258,32 @@ why_these_files_belong_together:
wave_size:
files:
-- path/to/file_a.rs
-- path/to/file_b.rs
+- path/to/file_a
+- path/to/file_b
checkpoint:
- raw suspects:
- duplication hypotheses:
- likely rereads:
- abstraction pressure:
+- code-volume pressure:
```
Rules:
- `wave_size` must never exceed `8`
-- write a checkpoint into the `/tmp` worklog after every wave before reading more files
+- write a checkpoint into the worklog after every wave before reading more files
- keep the checkpoint terse and raw; do not inflate every suspect into a formal ledger row yet
-- a file may appear in multiple cliques when duplication or boundary reasoning demands it
-- split oversized conceptual groups into multiple related cliques rather than inflating one wave
- name the clique by the suspected relationship, not by arbitrary adjacency
### Rejected Cluster
-Use this for suspect clusters that were noticed during coverage but did not earn formal ledger rows.
-
```text
cluster_id:
kind:
sites:
-- path/to/file_a.rs :: short note
-- path/to/file_b.rs :: short note
+- path/to/file_a :: short note
+- path/to/file_b :: short note
rejection_reason:
still_watch_for:
@@ -295,158 +297,56 @@ Good rejection reasons:
- local-only pattern with no cross-site duplication
- abstraction name still too foggy to justify extraction
-Rules:
-
-- keep this short
-- account for every non-promoted suspect cluster somewhere
-- do not use rejected clusters to hide real actionable refactors
-
### Promoted Ledger
-Use one row per promoted candidate site.
-
```text
-| row_id | path | symbol_or_site | kind | evidence | suspected_abstraction | duplication_cluster | confidence | decision | decision_reason |
-|--------|------|----------------|------|----------|-----------------------|---------------------|------------|----------|-----------------|
-| S001 | crates/foo/src/bar.rs | User.id: String | string | parsed, validated, and compared in 3 places | UserId newtype | id-handling-1 | high | refactor_now | domain identifier with repeated normalization |
-| B001 | crates/foo/src/baz.rs | frobnicate(..., dry_run: bool) | bool | positional flag controls strategy | ExecutionMode enum | mode-flags-1 | high | refactor_now | bool hides a mode split |
-| T001 | crates/foo/src/qux.rs | (start, end, step) | tuple | repeated destructuring across module boundary | RangeSpec struct | tuple-shapes-2 | medium | defer | local only today, but cluster suggests future extraction |
+| row_id | path | symbol_or_site | kind | evidence | suspected_abstraction | duplication_cluster | volume_effect | confidence | decision | decision_reason |
+|--------|------|----------------|------|----------|-----------------------|---------------------|---------------|------------|----------|-----------------|
+| S001 | src/foo | User.id: string | primitive_semantics | parsed, validated, and compared in 3 places | UserId domain type | id-handling-1 | deletes repeated validation | high | refactor_now | domain identifier with repeated normalization |
+| B001 | src/bar | run(..., dryRun: boolean) | boolean_mode | positional flag controls strategy | ExecutionMode variant | mode-flags-1 | removes branch duplication | high | refactor_now | bool hides a mode split |
+| D001 | src/baz | copy/update loop | duplicate_logic | same field-by-field patch in 4 sites | owned patch function | patching-2 | deletes 40 lines | medium | refactor_now | one owner is obvious |
```
-Allowed `kind` values:
-
-- `string`
-- `bool`
-- `tuple`
-- `parameter_clump`
-- `field_bundle`
-- `duplicate_logic`
-- `primitive_control_encoding`
-
-Allowed `confidence` values:
-
-- `high`
-- `medium`
-- `low`
-
-Allowed `decision` values:
-
-- `refactor_now`
-- `defer`
-- `false_positive`
-- `needs_broader_design`
-
Requirements:
- `evidence` must name the concrete smell, not a vague feeling
- `suspected_abstraction` must be specific
+- `volume_effect` must state deletion/compression potential when relevant
- `duplication_cluster` must group related rows when applicable
- `decision_reason` must explain why the row did or did not graduate into an edit
- do not create rows for suspects that failed promotion; summarize those as rejected clusters instead
-## Embedded Adjudication Checklist
-
-Run this checklist for every ledger row.
-
-### Semantic Pressure
-
-- Does this primitive carry domain semantics rather than mere transport?
-- Does it have validation, normalization, parsing, or formatting rules?
-- Does the code rely on an implied finite value set?
-- Would naming the concept clarify the surrounding code immediately?
-
-### Invariant Pressure
-
-- Are some values invalid but still representable today?
-- Are correlated values allowed to drift apart?
-- Does ordering matter only because a tuple hid the field names?
-- Are impossible states currently encoded with primitive combinations?
-
-### Boundary Pressure
-
-- Does the primitive cross module or crate boundaries?
-- Does it appear in public APIs, trait methods, or repeated call chains?
-- Is the same primitive interpretation duplicated at multiple boundaries?
-
-### Duplication Pressure
+## Adjudication Checklist
-- Is the same parse, validate, normalize, compare, or convert logic repeated?
-- Does the same field bundle move together repeatedly?
-- Is there a repeated branch skeleton with only small local differences?
+For every ledger row, ask:
-### Refactor Readiness
+- Does this primitive or shape carry domain semantics rather than mere transport?
+- Are invalid states representable today?
+- Does validation, normalization, parsing, formatting, or defaulting repeat?
+- Do correlated values drift apart because no one object owns them?
+- Does this cross a boundary where the weak shape becomes contagious?
+- Would a stronger type or abstraction delete nearby code?
+- Is the abstraction name sharp enough to carry the invariant?
+- Can the fix be made locally, or does it require a broader design cut?
-- Can a local type or helper eliminate repetition immediately?
-- Will the fix cascade cleanly through references if renamed mechanically?
-- Is there a natural owner module for the new abstraction?
-- Does the change need a broader domain redesign first?
-
-### Decision Mapping
-
-Choose exactly one:
+Decision mapping:
- `refactor_now`: the abstraction is clear and locally actionable now
- `defer`: the smell is real but the present diff would be premature
-- `false_positive`: the primitive is genuinely incidental or boundary-shaped
+- `false_positive`: the shape is genuinely incidental or boundary-correct
- `needs_broader_design`: the smell is real but the right abstraction spans a larger domain cut
-## Embedded Refactor Playbook
-
-Prefer these moves when the ledger supports them.
-
-### String
-
-- identifiers → newtypes
-- finite tags / statuses / modes → enums
-- validated textual concepts → smart constructors plus opaque wrappers
-- repeated path / URL / email / locale handling → dedicated domain type or parser boundary
-
-### Bool
-
-- mode switches → enums
-- policy flags → policy types
-- correlated bool sets → state enum or config struct with named fields
-- public boolean parameters → named option type unless the meaning is truly trivial
-
-### Tuple
-
-- cross-module tuples → named structs
-- repeated destructuring → named fields
-- semantically rich returns → domain object instead of positional packs
-
-### Parameter Clumps And Bundles
-
-- repeated argument groups → parameter object
-- repeated local field packs → extracted struct
-- repeated construction/update logic → dedicated constructor or helper module
-
-### Duplicate Logic
-
-- repeated validation → single constructor / validator
-- repeated conversions → `From` / `TryFrom` / dedicated conversion function
-- repeated branch skeletons → extracted helper, trait, or dispatch enum
-- repeated formatting → single renderer / formatter
-
-### Rejection Criteria
-
-Do not introduce an abstraction merely because a primitive exists.
-
-Reject or defer when:
-
-- the primitive is truly incidental and carries no stable semantics
-- the abstraction name is still foggy
-- the same concept appears only once and shows no invariant pressure
-- the code is at a serialization boundary where the primitive form is the correct external shape
-
## Final Response
Always include:
- the `/tmp` worklog path
+- language note used
- manifest coverage summary
- clique-wave summary
- rejected-cluster summary
- promoted-ledger summary
+- volume baseline and delta
If you edited code, also include:
@@ -454,19 +354,18 @@ If you edited code, also include:
- verification summary
- residual sweep summary
-If you did not edit code, include:
-
-- highest-value next moves
+If you did not edit code, include the highest-value next moves.
## Hard Failure Modes
-- do not inspect only “important” files
+- do not inspect only "important" files
- do not skip the `/tmp` worklog or keep checkpoint state only in chat
- do not read more than 8 files without a persisted checkpoint
-- do not silently compact a wave because you feel you “basically got it”
+- do not silently compact a wave because you feel you "basically got it"
- do not treat one clique as if it exhausts all duplication relationships
- do not promote everything into the formal ledger just to feel exhaustive
- do not drop non-promoted suspects on the floor; summarize them as rejected clusters
- do not jump into edits before the promoted ledger exists
- do not propose generic cleanup without row-level evidence
-- do not treat Clippy output as a substitute for this pass
+- do not preserve compatibility unless the user asked for it
+- do not let tests, lint, or formatters substitute for the extermination pass