@intentsolutionsio/zero-tech-debt 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "zero-tech-debt",
3
+ "version": "1.0.0",
4
+ "description": "Rebuild a feature as if the correct product architecture existed from day one. Removes compatibility cruft, dead abstractions, and historical compromises instead of preserving them. Methodology-only — no destructive actions without operator approval.",
5
+ "author": {
6
+ "name": "Jeremy Longshore",
7
+ "email": "jeremy@intentsolutions.io"
8
+ },
9
+ "repository": "https://github.com/jeremylongshore/claude-code-plugins-plus-skills",
10
+ "license": "MIT",
11
+ "keywords": [
12
+ "refactoring",
13
+ "tech-debt",
14
+ "architecture",
15
+ "cleanup",
16
+ "modernization",
17
+ "code-quality"
18
+ ]
19
+ }
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Intent Solutions
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,53 @@
1
+ # zero-tech-debt
2
+
3
+ > Build toward the intended product shape — not the historical sequence of patches.
4
+
5
+ A methodology skill for Claude Code that guides structural refactors: rebuild the feature as if the correct architecture existed from day one. Removes compatibility cruft, dead abstractions, and historical compromises instead of preserving them.
6
+
7
+ ## When to invoke
8
+
9
+ Strong signals from the operator:
10
+
11
+ - "refactor properly" / "clean up" / "rewrite" / "modernize"
12
+ - "remove legacy" / "simplify" / "rethink" / "pay down tech debt"
13
+ - Frustration with accumulated complexity
14
+ - Multiple parallel implementations for the same logical operation
15
+ - New features keep routing around old scaffolding instead of through it
16
+
17
+ ## When NOT to invoke
18
+
19
+ - Production hotfixes (minimize diff, preserve blast radius)
20
+ - Security backports (preserve audit clarity)
21
+ - Time-boxed patches before a release cut
22
+ - Code owned by another team without prior coordination
23
+ - Anywhere the cost of being wrong exceeds the cost of staying messy
24
+
25
+ ## How it loads (progressive disclosure)
26
+
27
+ The main `SKILL.md` is short. The deep methodology lives in `references/`:
28
+
29
+ | File | What's in it |
30
+ |---|---|
31
+ | [`01-when-to-use.md`](skills/zero-tech-debt/references/01-when-to-use.md) | Trigger signals + non-triggers |
32
+ | [`02-preflight-checklist.md`](skills/zero-tech-debt/references/02-preflight-checklist.md) | Pre-flight requirements before touching code |
33
+ | [`03-workflow.md`](skills/zero-tech-debt/references/03-workflow.md) | The 7-step refactor workflow |
34
+ | [`04-audit-patterns.md`](skills/zero-tech-debt/references/04-audit-patterns.md) | Concrete grep targets for finding debt |
35
+ | [`05-decision-filters.md`](skills/zero-tech-debt/references/05-decision-filters.md) | Tiebreakers + anti-patterns |
36
+ | [`06-outcomes-and-reporting.md`](skills/zero-tech-debt/references/06-outcomes-and-reporting.md) | Success criteria + how to summarize the result |
37
+
38
+ Claude reads `SKILL.md` first, then pulls the references it needs as the work unfolds. You don't have to read them all up front.
39
+
40
+ ## Scope discipline
41
+
42
+ A zero-tech-debt refactor will tempt unbounded scope. The skill explicitly:
43
+
44
+ - Holds to **one coherent end state per refactor** — not three loosely related ones
45
+ - Stops and documents deeper rot rather than chaining refactors mid-flight
46
+ - Refuses "while I'm here" additions unrelated to the deletion path
47
+ - Splits oversized work along ownership boundaries, never along file counts
48
+
49
+ If the operator wants a hotfix, this skill is the wrong tool — recommend a targeted patch instead.
50
+
51
+ ## License
52
+
53
+ MIT
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@intentsolutionsio/zero-tech-debt",
3
+ "version": "1.0.2",
4
+ "description": "Rebuild a feature as if the correct product architecture existed from day one. Removes compatibility cruft, dead abstractions, and historical compromises instead of preserving them. Methodology-only —",
5
+ "keywords": [
6
+ "refactoring",
7
+ "tech-debt",
8
+ "architecture",
9
+ "cleanup",
10
+ "modernization",
11
+ "code-quality",
12
+ "claude-code",
13
+ "claude-plugin",
14
+ "tonsofskills"
15
+ ],
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/jeremylongshore/claude-code-plugins-plus-skills.git",
19
+ "directory": "plugins/skill-enhancers/zero-tech-debt"
20
+ },
21
+ "homepage": "https://tonsofskills.com/plugins/zero-tech-debt",
22
+ "bugs": "https://github.com/jeremylongshore/claude-code-plugins-plus-skills/issues",
23
+ "license": "MIT",
24
+ "author": {
25
+ "name": "Jeremy Longshore",
26
+ "email": "jeremy@intentsolutions.io"
27
+ },
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "files": [
32
+ "README.md",
33
+ ".claude-plugin",
34
+ "skills"
35
+ ],
36
+ "scripts": {
37
+ "postinstall": "node -e \"console.log(\\\"\\\\n→ This npm package is a tracking/proof artifact. Install the plugin via:\\\\n ccpi install zero-tech-debt\\\\n or /plugin install zero-tech-debt@claude-code-plugins-plus in Claude Code\\\\n\\\")\""
38
+ }
39
+ }
@@ -0,0 +1,55 @@
1
+ ---
2
+ name: zero-tech-debt
3
+ description: |
4
+ Rebuild a feature as if the correct product architecture existed from day one — remove compatibility cruft, dead abstractions, and historical compromises instead of preserving them. Use when the operator says "refactor properly," "clean up," "rewrite," "modernize," "remove legacy," "simplify," "rethink," "pay down tech debt," or signals frustration with accumulated complexity. Do NOT use for hotfixes, bug repros, surgical patches, or security backports — blast-radius minimization wins there. Trigger with "/zero-tech-debt", "do it right this time", "the way it should have been built", "refactor toward intent".
5
+ allowed-tools: Read, Edit, Glob, Grep, Bash(git:*), Bash(rg:*), Bash(fd:*)
6
+ version: 1.0.0
7
+ author: Jeremy Longshore <jeremy@intentsolutions.io>
8
+ license: MIT
9
+ compatibility: Designed for Claude Code
10
+ tags: [refactoring, tech-debt, architecture, cleanup, modernization, code-quality]
11
+ user-invocable: true
12
+ ---
13
+
14
+ # Zero Tech Debt
15
+
16
+ Build toward the intended product shape — not the historical sequence of patches, migrations, wrappers, aliases, and temporary decisions that created the current implementation.
17
+
18
+ The goal is not "minimal diff."
19
+ The goal is a cleaner, more coherent system with fewer moving parts, fewer hidden assumptions, and lower long-term operational cost.
20
+
21
+ ## Core Principle
22
+
23
+ Treat the current implementation as evidence, not authority.
24
+
25
+ Preserve only the parts that still serve the intended architecture, UX, reliability model, and operational constraints. Everything else is eligible for deletion.
26
+
27
+ ## Operating Mode (read this section every invocation)
28
+
29
+ 1. **Confirm scope** — `Read` [`references/01-when-to-use.md`](references/01-when-to-use.md). If the request smells like a hotfix, security backport, or time-boxed patch, stop and recommend a targeted change instead.
30
+ 2. **Pre-flight** — walk [`references/02-preflight-checklist.md`](references/02-preflight-checklist.md). Every box must be checked before touching code. Tests, callers, rollback path, single-paragraph end-state description, no in-flight migration, telemetry accounted for. Use `Glob` to locate test files and `Grep` / `Bash(rg:*)` to enumerate external callers of the surface being changed.
31
+ 3. **Run the 7-step workflow** — [`references/03-workflow.md`](references/03-workflow.md). Define end state → audit reality → delete before adding → optimize around final shape → collapse duplicate decision logic → remove historical leakage → validate.
32
+ 4. **Use the audit patterns** — [`references/04-audit-patterns.md`](references/04-audit-patterns.md) lists the concrete `Grep` / `Bash(rg:*)` / `Bash(fd:*)` targets (TODO/DEPRECATED markers, `_v2`/`_old` suffixes, stale feature flags, dual-mode forks, etc.). Each match is a *candidate*, not an automatic deletion.
33
+ 5. **Apply decision filters when choices tie** — [`references/05-decision-filters.md`](references/05-decision-filters.md) covers tiebreakers and named anti-patterns to avoid.
34
+ 6. **Apply edits with `Edit`** — once a deletion / rename / consolidation is approved, use `Edit` to apply the change atomically. Stage with `Bash(git:*)` so the operator can review per commit before push.
35
+ 7. **Report back in shape-change terms** — [`references/06-outcomes-and-reporting.md`](references/06-outcomes-and-reporting.md). The diff lists every line; the summary makes the architectural delta legible.
36
+
37
+ ## Scope Discipline (this is the most common failure mode)
38
+
39
+ A zero-tech-debt refactor will tempt unbounded scope. Hold the line:
40
+
41
+ - **One coherent end state per refactor** — not three loosely related ones
42
+ - If deletion reveals deeper rot, document it and stop; do not chain refactors mid-flight
43
+ - Resist "while I'm here" additions unrelated to the deletion path
44
+ - New features wait for a separate change
45
+ - If the work cannot fit in a single reviewable unit, split along ownership boundaries — never along file counts
46
+
47
+ ## Final Rule
48
+
49
+ Do not optimize for preserving the past.
50
+
51
+ Optimize for making the next 2 years of development simpler.
52
+
53
+ ---
54
+
55
+ See [`references/`](references/) for the full methodology — each file is a single concern, loadable on demand.
@@ -0,0 +1,33 @@
1
+ # When to Use (and Not Use) zero-tech-debt
2
+
3
+ The most expensive failure mode of this skill is misclassification: applying a structural refactor where a surgical patch was wanted, or applying a hotfix where rot needed to be removed at the root. Get this judgment right *before* anything else.
4
+
5
+ ## Strong signals — proceed with zero-tech-debt
6
+
7
+ - Operator explicitly names tech debt, legacy code, or accumulated complexity
8
+ - Operator says "do it right this time" / "the way it should have been built" / "rethink this" / "refactor properly" / "modernize"
9
+ - **Multiple parallel implementations exist** for the same logical operation (two routes that do the same thing, two state containers holding overlapping fields, two functions whose only difference is one was added later)
10
+ - **Naming no longer matches what the code actually does** — the function called `processOrder` now handles refunds, subscriptions, and gift cards because nobody renamed it
11
+ - **Onboarding requires explaining "why we have both X and Y"** — a near-perfect tech-debt detector
12
+ - **Feature work keeps routing around old scaffolding** instead of through it — every new ticket has a "but first, work around this" step
13
+
14
+ ## Weak signals — clarify intent before invoking
15
+
16
+ - Generic "improve this code" with no scope — ask: *what specific shape do you want the end state to have?*
17
+ - Bug reports that merely touch legacy paths — usually a targeted patch is the right answer
18
+ - Performance work where structural cleanup is incidental — split the work; performance fix lands first, structural cleanup separately
19
+ - "Refactor" used loosely — could mean rename-only, could mean rebuild — disambiguate before committing scope
20
+
21
+ ## Hard non-triggers — recommend a surgical patch instead
22
+
23
+ - **Production hotfixes** — minimize diff, preserve blast radius, ship the fix, log the rot for later
24
+ - **Security backports** — preserve audit clarity and reviewer focus; reviewers need to see exactly what changed and nothing else
25
+ - **Time-boxed patches before a release cut** — the cost of being wrong exceeds the cost of staying messy
26
+ - **Code owned by another team without prior coordination** — you can write the refactor; you can't make it land
27
+ - **Anywhere blast-radius matters more than long-term coherence** — payments, auth, anything with a regulatory or contractual surface
28
+
29
+ ## The escape valve
30
+
31
+ If any non-trigger condition applies, the right move is to **stop and recommend a targeted patch**. Document the rot you noticed in a follow-up ticket so it doesn't get lost — but don't expand the current change to fix it.
32
+
33
+ This is the discipline that keeps zero-tech-debt from becoming "every change is a giant refactor."
@@ -0,0 +1,42 @@
1
+ # Pre-Flight Checklist
2
+
3
+ Refactoring without these creates the next generation of tech debt. Every box must be checked **before** touching code. If any item is unchecked, resolve it before proceeding — even if that means asking the operator to write a test, identify a caller, or confirm a rollback path.
4
+
5
+ ## The six checks
6
+
7
+ - [ ] **Tests exist (or can be written) for behavior worth preserving**
8
+ Without tests, you can't tell the difference between "I removed a bug" and "I removed a load-bearing accident." Don't refactor a system whose tests assert the historical bug shape — fix those tests first, against intended behavior, then refactor.
9
+
10
+ - [ ] **Every external caller of the surface being changed has been identified**
11
+ Use `rg` / `grep` / IDE call-graph tools across the whole repo. For library exports, also check downstream consumers if you can reach them. A refactor that breaks an unknown caller is worse than no refactor.
12
+
13
+ - [ ] **A rollback path exists** — branch, feature flag, or staged rollout
14
+ If the change ships and breaks something subtle in production, what's the un-stuck plan? "Revert the merge commit" only works if the merge commit is reachable and the code that depended on the new shape hasn't shipped on top of it. For larger refactors, prefer a feature flag with a clean off-position.
15
+
16
+ - [ ] **The intended end state fits in 1-3 paragraphs**
17
+ See workflow step 1 ([`03-workflow.md`](03-workflow.md)). If you can't describe the end state in plain prose, the refactor is not yet well-defined — and an under-defined refactor will drift into unbounded scope. Stop and clarify.
18
+
19
+ - [ ] **No active migration is in flight against the same code**
20
+ Two simultaneous structural changes on overlapping surface area produce merge conflicts you can't resolve and behavior changes you can't attribute. If a migration is already running, defer the refactor or coordinate with the migration owner.
21
+
22
+ - [ ] **Telemetry, logging, and alerts tied to deleted code are accounted for**
23
+ Dashboards, alert rules, log queries, and on-call runbooks may reference function names, log strings, or metric keys you're about to delete. Identify these *first*. Either update them in the same change or document the breakage explicitly and notify the on-call.
24
+
25
+ ## Why this checklist is hard rules, not advice
26
+
27
+ Each item is the missing-step from a failure pattern that's already happened. The checklist exists because skipping any of them *predictably* produces:
28
+
29
+ - a refactor that ships against an unknown caller and breaks production
30
+ - a "successful" refactor whose tests passed because they were asserting the wrong behavior
31
+ - a refactor with no rollback path that has to be hot-patched at 2 AM
32
+ - a refactor that grows from "clean up one flow" to "rewrite three subsystems" mid-PR
33
+ - a refactor that merge-conflicts with someone else's in-flight migration
34
+ - a refactor whose deletion silently broke the on-call alerting
35
+
36
+ If you skip a check and the failure happens anyway, you don't get to claim it was unforeseeable.
37
+
38
+ ## When the operator pushes to skip
39
+
40
+ If the operator says "we don't have tests for this, just refactor it" — that's a signal to write the characterization tests first, *as part of this work*, then refactor against them. The cost of writing one test is much lower than the cost of an undetected behavior change.
41
+
42
+ If the operator says "no time for a rollback path" — that's a signal that this isn't actually a zero-tech-debt refactor; it's a time-boxed patch, and you should switch tools.
@@ -0,0 +1,122 @@
1
+ # The 7-Step Workflow
2
+
3
+ This is the operational core of zero-tech-debt. Walk the steps in order. Don't skip step 1.
4
+
5
+ ## 1. Define the Intended End State
6
+
7
+ Before touching code, describe in 1-3 concise paragraphs:
8
+
9
+ - **What the final UX should feel like** — what the user / operator / caller sees and does
10
+ - **What the clean architecture should look like** — one coherent flow, one source of truth, one ownership boundary
11
+ - **What the public surface area actually needs to be** — every other function/route/export is private
12
+ - **What developers should intuitively expect** — what a new hire would guess without reading the code
13
+
14
+ If the intended end state is unclear, **stop and clarify before refactoring**. Code is the wrong medium for thinking through architecture; prose is faster and revisable.
15
+
16
+ ## 2. Audit Reality Against Intent
17
+
18
+ Identify everything in the current implementation that doesn't serve the end state:
19
+
20
+ - Compatibility shims, legacy wrappers, route aliases, duplicate flows
21
+ - Feature flags that became permanent architecture
22
+ - State duplicated across layers
23
+ - "Just in case" abstractions that turned out never to be needed
24
+ - Dead props, modes, handlers, and APIs
25
+ - Historical naming that no longer reflects product intent
26
+
27
+ Document, for each candidate for removal:
28
+
29
+ - **Why it exists** — what problem was it solving when it was written?
30
+ - **Who currently calls it** — is anyone still using it, or is it cargo-culted?
31
+ - **Whether it still provides real value** — does the user-visible behavior change if it's gone?
32
+
33
+ See [`04-audit-patterns.md`](04-audit-patterns.md) for concrete grep targets.
34
+
35
+ ## 3. Delete Before Adding
36
+
37
+ Before introducing **a new abstraction / hook / config layer / flag / adapter / state container**, attempt to:
38
+
39
+ - Remove obsolete logic
40
+ - Collapse duplicated paths
41
+ - Simplify ownership boundaries
42
+ - Unify flows
43
+ - Flatten unnecessary indirection
44
+
45
+ **Prefer subtraction over architecture theater.** A refactor that adds three new abstractions to "fix" tech debt has not paid down debt — it has moved it.
46
+
47
+ Important: don't introduce a new abstraction in the *same change* that removes an old one. Split into two reviewable steps so the reviewer can evaluate the deletion separately from the addition.
48
+
49
+ ## 4. Optimize Around the Final Shape
50
+
51
+ Refactor toward the system that **should exist today**, not the system that minimizes diff.
52
+
53
+ Do not preserve bad boundaries simply because:
54
+
55
+ - They existed historically
56
+ - They reduced diff size
57
+ - They avoided touching multiple files
58
+ - They were once needed during migration
59
+
60
+ Prefer:
61
+
62
+ - One coherent flow
63
+ - One authoritative source of truth
64
+ - One obvious ownership boundary
65
+ - One naming system
66
+ - One predictable state model
67
+
68
+ ## 5. Collapse Duplicate Decision Logic
69
+
70
+ Rules should exist in one place. Don't duplicate:
71
+
72
+ - Permission checks
73
+ - Feature gating
74
+ - Route logic
75
+ - URL parsing
76
+ - State derivation
77
+ - Validation rules
78
+ - Retry behavior
79
+ - Command naming
80
+ - Orchestration logic
81
+
82
+ **View components should not secretly own domain policy.** If your React component has a permission check inline, that policy is now duplicated wherever else the resource is accessed. Lift it to one authoritative location.
83
+
84
+ ## 6. Remove Historical Leakage
85
+
86
+ The codebase should describe **current product intent**, **current domain language**, **current operational reality** — not old implementation history.
87
+
88
+ Rename:
89
+
90
+ - Legacy terminology that no longer matches the product
91
+ - Migration-oriented naming (`*_v2`, `*_new`, `Legacy*`)
92
+ - Implementation-leaked concepts (e.g., a class called `MongoOrderStore` when Mongo was replaced with Postgres last year)
93
+ - Misleading abstractions whose names suggest one responsibility but implement another
94
+
95
+ Prefer names aligned with:
96
+
97
+ - User behavior
98
+ - Domain intent
99
+ - System responsibility
100
+
101
+ A rename without redirecting callers leaves a search-and-find trail of broken references. Always update every caller in the same commit as the rename.
102
+
103
+ ## 7. Validate the New Shape
104
+
105
+ After refactoring, verify:
106
+
107
+ - **Deleted paths truly have no callers** — re-grep, including in test files, config files, docs, and CI
108
+ - **Navigation still works** — for UI work, click through the affected flows manually, don't rely on snapshot tests
109
+ - **Persisted state still behaves correctly** — for storage refactors, migrate-up then migrate-down then migrate-up again on a real database snapshot
110
+ - **Permission boundaries remain correct** — re-walk the auth flow with a non-admin account
111
+ - **APIs remain coherent** — for public surfaces, run any contract tests; for internal APIs, walk the call graph
112
+ - **Tests validate intended behavior** rather than historical quirks — if a test references a deleted concept, the test was probably wrong, not the refactor
113
+
114
+ Add regression coverage for:
115
+
116
+ - Removed assumptions
117
+ - State transitions
118
+ - Orchestration boundaries
119
+ - Routing behavior
120
+ - Migration-sensitive logic
121
+
122
+ The new tests should describe the *intended shape*, not the historical shape. If you find yourself writing a test that asserts the old behavior, stop and ask whether the old behavior was actually correct.
@@ -0,0 +1,126 @@
1
+ # Audit Patterns — Concrete Things to Grep For
2
+
3
+ This is the hands-on toolkit for step 2 of the workflow (Audit Reality Against Intent). Each pattern below is a *candidate* for deletion, not an automatic delete. Examine the context, then decide.
4
+
5
+ ## Marker comments
6
+
7
+ The most reliable signal of intentional debt: someone already flagged it.
8
+
9
+ ```
10
+ rg -n "TODO: remove after|DEPRECATED|legacy|temp:|hack:|XXX:|FIXME"
11
+ ```
12
+
13
+ Look especially for `// TODO: remove after <date>` where the date is past, and `// temporary` comments that have been there for over a year.
14
+
15
+ ## Versioned identifiers
16
+
17
+ Functions, files, classes, types, or modules whose name encodes a version or generation:
18
+
19
+ ```
20
+ rg -n "_v2|_v3|_new|_old|_legacy|V2$|V3$|Legacy[A-Z]"
21
+ fd -e ts -e tsx -e py -e go -e rs "(_v2|_new|_old|_legacy)"
22
+ ```
23
+
24
+ These are usually one of three things:
25
+ 1. A successful migration where the `_old` should be deleted
26
+ 2. A failed migration where the `_new` should be deleted
27
+ 3. An in-flight migration — confirm with the owner before touching
28
+
29
+ ## Stale feature flags
30
+
31
+ Feature flags older than ~6 months that still default to a single branch:
32
+
33
+ - Check the flag-management system's "default value never changed" view
34
+ - Grep for `if (flags.<flagName>)` and check how many code paths each side has
35
+ - A flag with a one-line `else` branch (or no `else` at all) is a candidate for inlining
36
+
37
+ ## Pass-through wrappers
38
+
39
+ Wrappers whose only job is renaming arguments or repackaging return values:
40
+
41
+ ```python
42
+ def get_user(user_id):
43
+ return fetch_user(user_id)
44
+
45
+ def fetch_user(user_id):
46
+ return _user_repo.find(user_id)
47
+ ```
48
+
49
+ Three layers, one operation. Collapse to one.
50
+
51
+ ## Delegating route handlers
52
+
53
+ Route handlers that only delegate to other route handlers (often a legacy URL alias kept "just in case"):
54
+
55
+ ```js
56
+ app.get('/api/v1/users', (req, res) => app._router.handle({...req, url: '/api/users'}, res))
57
+ ```
58
+
59
+ Either kill the alias or document why it's load-bearing.
60
+
61
+ ## Dual-mode forks
62
+
63
+ `if (env === 'old' || env === 'legacy')` or `if (clientVersion < N)` branches:
64
+
65
+ - The "old mode" path is rarely tested
66
+ - It accumulates new bugs because nobody exercises it
67
+ - Killing it requires confirming all consumers are off the old mode — but the data to confirm is usually accessible
68
+
69
+ ## Duplicate config keys
70
+
71
+ Config keys with near-identical names that diverged over time:
72
+
73
+ - `database_url` and `db_url`
74
+ - `retry_count` and `max_retries`
75
+ - `enabled` and `is_enabled`
76
+
77
+ Pick one, alias the other for one release, then remove.
78
+
79
+ ## Naming-vs-behavior mismatches
80
+
81
+ Comments explaining why a name is "actually" different from its behavior:
82
+
83
+ ```js
84
+ // note: getUser actually returns a UserProfile, not a User
85
+ ```
86
+
87
+ The comment is telling you to rename the function.
88
+
89
+ ## Tests asserting historical bugs
90
+
91
+ Tests whose assertions describe behavior the operator/user never wanted:
92
+
93
+ ```js
94
+ it('returns null when input is empty (legacy behavior)', () => { ... })
95
+ ```
96
+
97
+ Either the legacy behavior was correct (then drop the parenthetical) or it wasn't (then the test is wrong, not the candidate refactor).
98
+
99
+ ## Indirection without callers
100
+
101
+ Abstract classes / interfaces / factories with exactly one implementation. Often introduced "in case we need to swap implementations later" — and we never did. Inline them.
102
+
103
+ ## Configuration-driven chaos
104
+
105
+ Code shaped like:
106
+
107
+ ```python
108
+ HANDLERS = {
109
+ "type_a": handle_a,
110
+ "type_b": handle_b,
111
+ "type_c": handle_c, # only used by one old code path
112
+ }
113
+ ```
114
+
115
+ If `type_c` has one caller and no plans to grow, inline it and delete the registry entry.
116
+
117
+ ## What to do with each match
118
+
119
+ For each candidate:
120
+
121
+ 1. **Find every caller** (workflow step 2)
122
+ 2. **Decide**: keep / delete / rename
123
+ 3. **If deleting**: confirm no telemetry references the names you're removing (workflow pre-flight)
124
+ 4. **Document** in the PR summary as one line: `deleted: <name> — <one-sentence reason>`
125
+
126
+ A clean audit produces a punch list. The workflow turns that punch list into commits.
@@ -0,0 +1,54 @@
1
+ # Decision Filters + Anti-Patterns
2
+
3
+ When the audit has produced candidates and the workflow is in motion, choices accumulate fast. These filters resolve them. The anti-patterns at the bottom name the failure modes to refuse on sight.
4
+
5
+ ## Decision Filters — when choosing between implementations
6
+
7
+ Prefer the option that:
8
+
9
+ - **Removes more complexity** — fewer concepts to memorize
10
+ - **Reduces future branching** — fewer `if (mode === ...)` paths
11
+ - **Reduces special cases** — fewer "this is true except when"
12
+ - **Improves discoverability** — a new hire finds it without being told where to look
13
+ - **Eliminates hidden behavior** — no surprise side effects, no shared mutable state
14
+ - **Centralizes ownership** — one module owns one concept
15
+ - **Lowers operational ambiguity** — on-call can act on the alert without paging the author
16
+ - **Makes intent obvious from structure** — the directory layout tells you what's where
17
+
18
+ ## Tiebreakers — when the filters above are equal
19
+
20
+ - **Prefer the option a new hire would understand without a meeting.**
21
+ - **Prefer the option that fails loudly over one that fails silently.** Silent fallbacks are how production gets weirder over time.
22
+ - **Prefer the option with fewer configuration knobs.** Every config key is a future bug surface.
23
+ - **Prefer the option that does not need a comment to justify its existence.** Comments are a code smell when they're load-bearing.
24
+ - **Prefer the option that survives unchanged when the next adjacent feature ships.** Tight coupling to the next feature means you'll be back here in two months.
25
+
26
+ ## Anti-Patterns — refuse on sight
27
+
28
+ These appear under different names but are the same shape: complexity preserved as an end in itself.
29
+
30
+ ### Architectural anti-patterns
31
+
32
+ - **Preserving dead compatibility paths forever** — "we might need it" without a concrete caller is not a reason
33
+ - **"Safe" wrappers that hide bad architecture** — moving the smell behind a facade doesn't remove it
34
+ - **Generic frameworks for single-use problems** — the YAGNI principle, lived
35
+ - **Feature flags that became permanent architecture** — a flag with no plan to remove it is a config knob in disguise
36
+ - **Duplicated state ownership** — two stores believing they own the same field is a recipe for divergence
37
+ - **Configuration-driven chaos** — when every value is in a YAML, refactoring the code doesn't help; the YAML *is* the code
38
+ - **Indirection without operational value** — if removing the abstraction doesn't make anything worse, the abstraction wasn't doing work
39
+ - **Abstractions created solely to avoid touching old code** — the abstraction is the debt
40
+
41
+ ### Process anti-patterns specific to this skill
42
+
43
+ - **Treating `git blame` as architectural authority.** *Who wrote this* is not *why it should stay*. The original author may have been correcting an even worse decision that's since been undone.
44
+ - **Refactoring tests to match the new code instead of validating intended behavior.** If the test breaks, the test might be right and the refactor wrong. Don't assume.
45
+ - **Introducing a new abstraction in the same change that removes an old one** — split into two reviewable steps. Reviewers cannot evaluate "remove A and add B" as cleanly as "remove A" then "add B".
46
+ - **Renaming without redirecting callers** — leaving a search-and-find trail of broken references. Every rename updates every caller in the same commit.
47
+ - **Deleting telemetry, metrics, or alerts along with the code they instrumented** without acknowledging it. The dashboard breaks silently and on-call learns about it the hard way.
48
+ - **Confusing "fewer lines" with "simpler."** Density is not clarity. A 200-line function can be simpler than ten 20-line ones that pass state through a chain.
49
+
50
+ ## When the operator pushes back on a filter
51
+
52
+ The filters are heuristics, not laws. If the operator has context you don't have — a regulatory requirement, a contract with a downstream consumer, a known-bug they're tracking — the operator wins. Document the deviation in the PR summary so the next reader doesn't undo it.
53
+
54
+ But: if the operator's pushback amounts to "this is how we've always done it," that's not context, that's inertia. Push back politely with the filter that resolves the choice and let them decide.
@@ -0,0 +1,101 @@
1
+ # Preferred Outcomes + Reporting Back
2
+
3
+ This file describes what a successful zero-tech-debt refactor looks like, and how to summarize the result so reviewers and future readers can evaluate the *shape change* rather than re-reading the diff.
4
+
5
+ ## What success looks like
6
+
7
+ A successful refactor produces:
8
+
9
+ - **Fewer files** — collapsed wrappers, deleted dead modules
10
+ - **Fewer modes** — `if (legacyMode)` branches removed, one path through the code
11
+ - **Fewer flags** — feature flags that became permanent are inlined
12
+ - **Fewer state transitions** — the state machine has fewer arrows on the diagram
13
+ - **Fewer routing paths** — aliases removed, one URL per resource
14
+ - **Fewer adapters** — pass-through layers flattened
15
+ - **Fewer abstractions** — single-implementation interfaces inlined
16
+ - **Fewer concepts developers must memorize** — fewer "you also need to know about X" caveats
17
+
18
+ ...while improving:
19
+
20
+ - **Clarity** — a new hire reads the code and understands the intent
21
+ - **Reliability** — fewer paths means fewer untested paths means fewer bugs
22
+ - **Maintainability** — the next change is cheaper because there's less to navigate around
23
+ - **Onboarding speed** — measured in "minutes to first useful PR," not "weeks to feel comfortable"
24
+ - **Operational confidence** — on-call can act on alerts without paging the original author
25
+ - **Implementation velocity** — features land faster because there's less scaffolding to route around
26
+
27
+ If the refactor produced more of any of the first list and didn't improve any of the second list, it wasn't a zero-tech-debt refactor — it was reshuffling.
28
+
29
+ ## How to summarize the result
30
+
31
+ The diff lists every line. The summary exists to make the architectural delta legible to reviewers and future readers. A good summary fits in five sections:
32
+
33
+ ### 1. Deleted
34
+
35
+ Counts, not lists. The reviewer can `git log` for the names.
36
+
37
+ ```
38
+ Deleted:
39
+ - 12 files
40
+ - 47 functions
41
+ - 3 feature flags (NEW_USER_FLOW, ENABLE_V2_PRICING, USE_OLD_AUTH)
42
+ - 5 route aliases (/api/v1/users → /api/users, etc.)
43
+ - 8 config keys (consolidated into `service.retry`)
44
+ ```
45
+
46
+ ### 2. Unified
47
+
48
+ Before/after shape, not before/after diff. One line per consolidated flow.
49
+
50
+ ```
51
+ Unified:
52
+ - 3 user-lookup paths → 1 (UserService.findById is the single entry point)
53
+ - 2 retry implementations → 1 (utils/retry.ts; the http/retry.ts and queue/retry.ts variants are gone)
54
+ - 4 permission checks scattered across UI components → 1 (PolicyService.canUserAccess)
55
+ ```
56
+
57
+ ### 3. Renamed
58
+
59
+ Old name → new name, with the domain reason. The reason matters more than the names.
60
+
61
+ ```
62
+ Renamed:
63
+ - MongoOrderStore → OrderRepository
64
+ (we replaced Mongo with Postgres in 2024; the class name leaked the old infra)
65
+ - processOrder → fulfillOrder
66
+ (function handles fulfillment, payment is now in PaymentService)
67
+ ```
68
+
69
+ ### 4. Intentionally Left Alone
70
+
71
+ Things the audit flagged but you chose not to touch, with the reason. This prevents the next refactor from re-noticing the same items.
72
+
73
+ ```
74
+ Intentionally left alone:
75
+ - LegacyExportAdapter — still has 3 enterprise customers on the old schema; sunset is on the Q3 roadmap
76
+ - the `mode` parameter on Search — used by the analytics pipeline, removal would require a coordinated change with that team
77
+ ```
78
+
79
+ ### 5. Deferred
80
+
81
+ Scoped as separate follow-up tickets, not buried in this change. This is the single most important section — it's where you preserve the rot you noticed but chose not to fix.
82
+
83
+ ```
84
+ Deferred (filed as separate tickets):
85
+ - #1234 — consolidate notification dispatch (3 paths, but each has independent retry/dedup logic)
86
+ - #1235 — remove DUAL_WRITE flag (still needed until the Postgres backfill completes Q1)
87
+ - #1236 — rename ProductCatalog (now handles services + bundles + products)
88
+ ```
89
+
90
+ ## Why this format
91
+
92
+ Reviewers reading a 2,000-line diff need to understand the *shape* of the change in 60 seconds. The summary is that 60-second read. If it doesn't fit on one screen, the refactor was too big — split it.
93
+
94
+ Future readers (including future you) come back to figure out "why did we have X and now we have Y?" The summary is the answer. Make it good.
95
+
96
+ ## The thing that does NOT belong in the summary
97
+
98
+ - Apologies for breaking changes ("sorry, this was unavoidable") — if it's unavoidable, just say what broke and how to migrate; no apology
99
+ - A diff narrative ("first I deleted X, then I noticed Y, so I refactored Z") — the diff has the history; the summary has the shape
100
+ - Marketing language ("dramatically improves," "industry-leading," "significantly cleaner") — the reviewer can evaluate; don't editorialize
101
+ - Speculation about future benefits ("this will make adding new features easier") — sometimes true, often not; prove it with the next feature, don't promise it in the summary