architecture-rescue
Diagnose a tangled codebase. Find deepening opportunities — places where a thin module should be thicker, a missing seam should be drawn, or a leaky abstraction should be sealed. You output numbered candidates; you do not propose interfaces yet — that comes after a grilling session.
Glossary (in passing — full defs in references/architecture-language.md)
- Module — a unit of code that hides a decision behind a name.
- Interface — the surface a caller sees; everything that isn't implementation.
- Depth — interface-to-implementation ratio. Deep = small interface, large implementation. Shallow = the inverse, and usually a smell.
- Seam — a place you can substitute behavior (for testing, swapping, isolating).
- Adapter — a thin shim translating between two interfaces.
- Leverage — change one place, many callers benefit.
- Locality — related decisions live next to each other.
The reference doc carries an _Avoid_: alias list for each term — stay inside the canonical vocabulary in everything you write.
The deletion test
Imagine deleting this module. If complexity vanishes, it was a pass-through. If complexity reappears across N callers, the module was earning its keep.
Example: a UserService whose every method is return userRepo.findX(...) — delete it and callers just call the repo. Complexity vanishes. It's a pass-through. Contrast: a BillingService that delete-tests into 40 callers each redoing tax + proration logic. Complexity reappears. The module was concentrating something.
The two-adapter rule
One adapter = a hypothetical seam. Two adapters = a real seam — promote it to an explicit interface.
Example: S3Storage alone is a wrapper around one SDK. Two implementations — S3Storage and LocalDiskStorage — and there is now a real BlobStore interface hiding in the codebase. Name it. Make it explicit. Stop pretending the second adapter is incidental.
Process
- Survey the tree.
Glob the source roots, count files per module, note the top-level decomposition. Read 3–5 modules end-to-end — pick ones the user names as "messy" or, lacking that, the largest and most-imported.
- Apply the tests. For each candidate, run the deletion test in your head. Look for two-adapter pairs (search for
class.*implements, parallel filenames like *Memory.* / *Postgres.*, or duplicated method shapes across files).
- Write up numbered candidates. Each candidate: file references, problem statement, plain-English solution, locality benefit, leverage benefit. Be specific — line numbers, not vibes.
- Hand off to
grill-me. The candidate list is the agenda. Invoke grill-me to walk the design tree on whichever candidate the user picks. Do not skip to interface design — the grilling reveals the third option you couldn't see from one design.
- If grilling introduces a new term (a renamed concept, a domain noun the codebase didn't have), invoke
maintain-context so the new term lands in CONTEXT.md / the project glossary before code changes.
- Only after grilling, propose the explicit interface. Use the Design It Twice pattern in
references/interface-design.md — sketch two genuinely different interfaces, compare, pick or merge.
Candidate output format
### N. <short name>
- **Files:** path/to/foo.ts:120-180, path/to/bar.ts
- **Problem:** <one or two sentences — what's shallow, leaky, or missing>
- **Solution (plain English):** <what you'd do, not how>
- **Locality:** <what moves closer together>
- **Leverage:** <who benefits, and how many callers>
Keep findings tight. A page of well-aimed candidates beats a 30-page report no one reads.
1---2name: architecture-rescue3description: Find deepening opportunities in a codebase — shallow modules, missing seams, leaky abstractions — and present them as numbered candidates ready for a grilling session before any interface is proposed. Use when the codebase feels tangled, tests are hard to write, modules feel 'shallow', or it's quarterly-architecture-review time. Trigger on: 'improve architecture', 'rescue this codebase', 'find refactoring opportunities', 'this is a mess', 'ball of mud', 'consolidate modules', 'make it testable', 'shallow modules', 'deepen modules', 'leaky abstraction', 'two-adapter rule', 'deletion test'.4---56# architecture-rescue78Diagnose a tangled codebase. Find *deepening opportunities* — places where a thin module should be thicker, a missing seam should be drawn, or a leaky abstraction should be sealed. You output numbered candidates; you do **not** propose interfaces yet — that comes after a grilling session.910## Glossary (in passing — full defs in `references/architecture-language.md`)1112- **Module** — a unit of code that hides a decision behind a name.13- **Interface** — the surface a caller sees; everything that isn't implementation.14- **Depth** — interface-to-implementation ratio. Deep = small interface, large implementation. Shallow = the inverse, and usually a smell.15- **Seam** — a place you can substitute behavior (for testing, swapping, isolating).16- **Adapter** — a thin shim translating between two interfaces.17- **Leverage** — change one place, many callers benefit.18- **Locality** — related decisions live next to each other.1920The reference doc carries an `_Avoid_:` alias list for each term — stay inside the canonical vocabulary in everything you write.2122## The deletion test2324> *Imagine deleting this module. If complexity vanishes, it was a pass-through. If complexity reappears across N callers, the module was earning its keep.*2526Example: a `UserService` whose every method is `return userRepo.findX(...)` — delete it and callers just call the repo. Complexity vanishes. It's a pass-through. Contrast: a `BillingService` that delete-tests into 40 callers each redoing tax + proration logic. Complexity reappears. The module *was* concentrating something.2728## The two-adapter rule2930> *One adapter = a hypothetical seam. Two adapters = a real seam — promote it to an explicit interface.*3132Example: `S3Storage` alone is a wrapper around one SDK. Two implementations — `S3Storage` and `LocalDiskStorage` — and there is now a real `BlobStore` interface hiding in the codebase. Name it. Make it explicit. Stop pretending the second adapter is incidental.3334## Process35361. **Survey the tree.** `Glob` the source roots, count files per module, note the top-level decomposition. Read 3–5 modules end-to-end — pick ones the user names as "messy" or, lacking that, the largest and most-imported.372. **Apply the tests.** For each candidate, run the deletion test in your head. Look for two-adapter pairs (search for `class.*implements`, parallel filenames like `*Memory.*` / `*Postgres.*`, or duplicated method shapes across files).383. **Write up numbered candidates.** Each candidate: file references, problem statement, plain-English solution, **locality** benefit, **leverage** benefit. Be specific — line numbers, not vibes.394. **Hand off to `grill-me`.** The candidate list is the *agenda*. Invoke `grill-me` to walk the design tree on whichever candidate the user picks. Do not skip to interface design — the grilling reveals the third option you couldn't see from one design.405. **If grilling introduces a new term** (a renamed concept, a domain noun the codebase didn't have), invoke `maintain-context` so the new term lands in `CONTEXT.md` / the project glossary before code changes.416. **Only after grilling, propose the explicit interface.** Use the *Design It Twice* pattern in `references/interface-design.md` — sketch two genuinely different interfaces, compare, pick or merge.4243## Candidate output format4445```text46### N. <short name>4748- **Files:** path/to/foo.ts:120-180, path/to/bar.ts49- **Problem:** <one or two sentences — what's shallow, leaky, or missing>50- **Solution (plain English):** <what you'd do, not how>51- **Locality:** <what moves closer together>52- **Leverage:** <who benefits, and how many callers>53```5455Keep findings tight. A page of well-aimed candidates beats a 30-page report no one reads.