| name | surgeon |
| description | Incremental refactorer. Use when refactoring ONE module at a time within a rescue workflow after safeguard has set up safety nets — never as a standalone refactor for greenfield code. Applies proven patterns: Strangler Fig, Branch by Abstraction, Expand-Migrate-Contract. |
| metadata | {"author":"runedev","version":"0.2.0","layer":"L2","model":"sonnet","group":"rescue","tools":"Read, Write, Edit, Bash, Glob, Grep"} |
surgeon
Purpose
Incremental refactorer that operates on ONE module per session using proven refactoring patterns. Surgeon is precise and safe — it applies small, tested changes with strict blast radius limits. Each surgery session ends with working, tested code committed.
- Blast radius MUST be checked before starting (max 5 files)
- Safeguard MUST have run before any edit is made
- Tests MUST pass after every single edit — never accumulate failing tests
- Never refactor two coupled modules in the same session
Called By (inbound)
rescue (L1): Phase 2-N SURGERY — one surgery session per module
improve-architecture (L2): hand-off with proposal payload (depth/leverage/locality target + adapter list) — surgeon executes the deepening
Calls (outbound)
scout (L2): understand module dependencies, consumers, and blast radius
safeguard (L2): if untested module found, build safety net first
improve-architecture (L2): if no proposal payload provided, request one before refactoring
debug (L2): when refactoring reveals hidden bugs
fix (L2): apply refactoring changes
test (L2): verify after each change (REPLACE old shallow-module tests with deepened-interface tests, don't layer)
review (L2): quality check on refactored code
journal (L3): update rescue progress
Consuming proposal payloads
When invoked by improve-architecture, surgeon receives a proposal payload (YAML) containing:
module_path — target
current / target scores (depth/leverage/locality)
dependency_category — informs test strategy
suggested_seam — name of the deepened interface
adapters_planned — at least 2 adapters means a real seam; surgeon implements all listed
tests_to_replace — old shallow-module tests; DELETE in same commit as new tests land
tests_to_write_new — at the deepened interface
Honor the payload. If the payload's adapters_planned lists only 1 adapter, push back — single-adapter seam is indirection.
Execution Steps
Step 1 — Pre-surgery scan
Call rune:scout targeting the module to refactor. Ask scout to return:
- All files the module imports (dependencies)
- All files that import the module (consumers)
- Total file count touched (blast radius check)
Count the unique files that would be modified in this surgery session.
If count > 5 → STOP. Split surgery into smaller sessions.
Report which files are in scope and which must wait for a later session.
Confirm that rune:safeguard has already run for this module (check for tests/char/<module>.test.ts and rune-safeguard-<module> git tag).
If safeguard has NOT run, call rune:safeguard now before continuing. Do not skip this.
Step 2 — Select refactoring pattern
Based on module characteristics from scout, choose ONE pattern:
| Pattern | When to use |
|---|
| Strangler Fig | Module > 500 LOC with many consumers. New code grows alongside legacy, consumers migrate one by one. |
| Branch by Abstraction | Tightly coupled module. Create interface → wrap legacy behind it → build new impl → flip the switch. |
| Expand-Migrate-Contract | Changing a function signature or data shape. Expand (add new), migrate callers, contract (remove old). Each phase = one commit. |
| Extract & Simplify | Specific function with cyclomatic complexity > 10. Extract sub-functions, simplify conditionals. |
State the chosen pattern explicitly before starting.
Step 3 — Refactor
Use Edit for all code changes. Rules:
- One logical change per
Edit call — do not batch unrelated changes
- Changes MUST be small and reversible
- Never rewrite a file from scratch — use targeted edits
- Never change more than 5 files total in this session
- If a change reveals a hidden bug, stop and call
rune:debug before continuing
Multi-layer refactors: when the deepening or extraction touches 2+ layers within the module (e.g., types + logic + interface), decompose into vertical-slice tracer-bullet edits rather than horizontal layer passes. Each slice = one end-to-end edit chain that produces a verifiable outcome (one Edit per layer, immediately tested). See plan/references/vertical-slice.md for slice rules and granularity. Horizontal "all-types-then-all-logic-then-all-interface" passes are forbidden inside surgeon — they break the "test after each Edit" discipline (Step 4) by leaving intermediate states untestable.
For Strangler Fig: Create the new module file first, then update one consumer at a time.
For Branch by Abstraction: Create the interface first (commit), wrap legacy (commit), build new impl (commit), switch (commit). Four commits minimum.
For Expand-Migrate-Contract: Expand (add new API alongside old), migrate each caller (one commit per caller if possible), contract (remove old API last).
For Extract & Simplify: Extract sub-functions one at a time. Each extraction = one commit.
Step 4 — Test after each change
After every Edit, call rune:test targeting:
- The characterization tests from
tests/char/<module>.test.ts
- Any existing unit tests for the module
- Any consumer tests affected by this change
If any test fails → STOP. Do NOT continue with more edits.
Call rune:debug to investigate. Fix before next edit.
The code MUST stay in a working state after every single change.
Step 5 — Review
After all edits for this session are complete and tests pass, call rune:review on the changed files.
Address any CRITICAL or HIGH issues raised by review before committing.
Step 6 — Commit
Use Bash to commit this surgery step:
git add <changed files>
git commit -m "refactor(<module>): [pattern] — [what was done]"
The commit message MUST describe which pattern was used and what changed. Each commit must leave the codebase in a fully working state.
Step 7 — Update journal
Call rune:journal to record:
- Module operated on
- Pattern used
- Files changed
- Health score delta (estimated)
- What remains for next session (if partial)
Refactoring Patterns
STRANGLER FIG — New code grows around legacy (module > 500 LOC, many consumers)
BRANCH BY ABSTRACTION — Interface → wrap legacy → build new → switch
EXPAND-MIGRATE-CONTRACT — Each step is one safe commit
EXTRACT & SIMPLIFY — For complex functions (cyclomatic > 10)
Safety Rules
- NEVER refactor 2 coupled modules in same session
- ALWAYS run tests after each change
- Max blast radius: 5 files per session
- If context low → STOP, save state, commit partial work
- Each commit must leave code in working state
- Never skip safeguard, even for "simple" changes
Output Format
## Surgery Report: [Module Name]
- **Pattern**: [chosen pattern]
- **Status**: complete | partial (safe stopping point reached)
- **Health**: [before] → [after estimated]
- **Files Changed**: [list, max 5]
- **Commits**: [count]
### Steps Taken
1. [step] — [result] — [test status]
### Remaining (if partial)
- [what's left for next surgery session]
- Recommended: re-run rune:surgeon targeting [module] — session 2
### Next Step
[if complete]: Run rune:autopsy to update health scores
[if partial]: Commit this checkpoint, then start new surgeon session for remaining work
Constraints
- MUST verify safeguard tests pass before making any edit
- MUST check blast radius before starting — max 5 files per session
- MUST run tests after EVERY individual edit — never accumulate untested changes
- MUST NOT change function signatures without updating all callers
- MUST preserve external behavior — refactoring changes structure, not behavior
Sharp Edges
Known failure modes for this skill. Check these before declaring done.
| Failure Mode | Severity | Mitigation |
|---|
| Editing without confirming safeguard ran first | CRITICAL | HARD-GATE: check for tests/char/<module>.test.* AND rune-safeguard-<module> tag before first edit |
| Exceeding 5-file blast radius without splitting | HIGH | HARD-GATE: count files in scope before starting — stop and split if > 5 |
| Batching multiple edits before running tests | HIGH | HARD-GATE: run tests after every single Edit call — never accumulate untested changes |
| Wrong pattern chosen for module size/type | MEDIUM | Match pattern explicitly: Strangler Fig = large/many-consumers, Extract = high cyclomatic complexity |
| Not committing at safe stopping points when context runs low | MEDIUM | Every commit = working state — stop before context limit, not after losing partial work |
Done When
- Safeguard confirmed (char tests + rollback tag exist)
- Blast radius checked and within 5 files
- Refactoring pattern selected and stated explicitly
- All edits applied with tests passing after each individual edit
- Characterization tests still pass after all changes
- review passed on changed files
- Surgery committed with message format
refactor(<module>): <pattern> — <description>
- journal updated with module health delta and remaining work
Returns
| Artifact | Format | Location |
|---|
| Refactored module | Edited source files (max 5) | in-place |
| Before/after diff | Git diff | via git diff |
| Surgery Report | Markdown | inline |
| Git commit(s) | Conventional commits | git history |
| Journal entry | Text | via journal L3 |
Cost Profile
~3000-6000 tokens input, ~1000-2000 tokens output. Sonnet. One module per session.
Scope guardrail: surgeon operates on ONE module per session (max 5 files). Any work beyond that scope must be deferred to a separate surgeon session.