---
name: refactor
description: "Orchestrates safe, large-scale structural changes across a codebase — symbol renames, API migrations, pattern standardizations, layer restructurings. Enumerates all affected sites, groups them into dependency layers via the DAG executor, applies changes in parallel per layer with worktree isolation, and verifies behavioral preservation at each layer boundary before proceeding. Exits immediately on first regression, surfacing the exact site, diff, and behavioral delta before any commit."
argument-hint: "<refactor goal> [--scope <glob-or-path>]"
failure_modes:
  - bad decomposition
  - dependency blindness
  - false completeness
  - premature execution
context: fork
---

## Sub-agent contract
/contract

**Skip when:** the change touches ≤3 files and no dependency ordering is required — just edit directly. Also skip when the codebase has no test coverage at all (behavioral preservation cannot be verified; ask the user to add tests first or proceed manually).

---

### Triage (inline, before dispatching any sub-agent)

Parse `$ARGUMENT` to extract:
- **Change type**: rename | api-migration | pattern-standardization | layer-restructure | dependency-upgrade | other
- **Target symbol / path / pattern** (what is changing)
- **Destination** (what it becomes)
- **Scope**: default to the entire repo; narrow if `--scope` is provided

If `$ARGUMENT` is ambiguous on any of the above, stop and ask exactly one question.

---

### Wave 1 — Scope enumeration (parallel, `subagent_type: "research-agent"`)

Dispatch both agents simultaneously in a single response turn.

**Site-finder agent**
- goal: Enumerate every file and symbol that must change for the refactor to be complete and correct.
- inputs: change type, target symbol/pattern, scope glob
- artifacts:
  - `sites`: array of `{file, line_range, site_type: "definition"|"import"|"usage"|"type-ref"|"test", change_required: string}`
  - `dependency_graph`: for each site, which other sites must be changed first (a site depends on its callers if it exports a symbol; a definition must be changed before its imports)
  - `site_count`: integer
  - `confidence`: low | medium | high
  - `coverage_gaps`: what the agent couldn't search (generated files, third-party vendored code, etc.)
- non_goals: Do not apply any changes. Do not read unrelated files.
- failure_modes: If grep tooling is unavailable, return `confidence: low` and list what was searched manually.

**Contract-extractor agent**
- goal: Identify the public interfaces and test commands that verify behavioral preservation for the affected API surface.
- inputs: site list (from site-finder, passed inline if available; if not yet available, derive from change type + scope)
- artifacts:
  - `contracts`: array of `{symbol, signature_before, exported_by, consumed_by[]}`
  - `test_commands`: array of shell commands that SCOPE to the affected contracts — target the specific test files or a name pattern, never the whole suite (e.g., `pnpm test src/auth/auth-service.test.ts` or `pnpm test -t "AuthService"`). Under pnpm, `pnpm test -- <file>` drops the file arg and runs the entire suite — never emit that form.
  - `test_coverage_verdict`: "adequate" | "partial" | "absent"
  - `confidence`: low | medium | high
  - `coverage_gaps`: test paths not reachable by the identified commands
- non_goals: Do not run tests. Do not read unrelated files.

**Scope gate (after Wave 1):**
- `site_count > 50` → warn the user: "This refactor touches N sites. Recommend scoping down with `--scope` or batching via `/parallelize`. Proceeding, but each layer will take longer."
- `test_coverage_verdict == "absent"` → hard stop: "No tests cover the affected contracts. Behavioral preservation cannot be verified. Add tests before proceeding, or explicitly confirm you accept unverified risk."
- Either agent returns `confidence: low` → surface the coverage gaps and ask the user to confirm before proceeding.

---

### Synthesize: Build the layer map (inline)

From `dependency_graph`, compute a topological sort into layers using Kahn's algorithm:
- **Layer 0** — leaf sites with no dependents (definitions that nothing imports, or sites that depend on nothing else changing first)
- **Layer N** — sites whose dependencies are all in layers 0…N-1

If the graph has cycles (rare but possible in circular-import codebases), surface them explicitly: "Cycle detected between [A, B, C]. Manual intervention required before automation can proceed." Do not continue.

---

### Wave 2 — Layer-by-layer application (sequential between layers, parallel within each layer)

For **each layer** (starting at Layer 0):

Dispatch one sub-agent per site in this layer, all in parallel, each in a worktree-isolated environment:

**Layer applicator agent** (per site, `isolation: "worktree"`)
- goal: Apply the transformation at exactly this site and verify it passes its targeted tests.
- inputs: site descriptor `{file, line_range, change_required}`, full transformation spec (target → destination), test commands that cover this site
- artifacts:
  - `site`: `{file, line_range}`
  - `status`: "green" | "red" | "skipped"
  - `diff_applied`: the exact unified diff applied (≤30 lines; truncate with `...` if longer)
  - `test_output`: truncated stdout of the targeted test run (last 20 lines)
  - `failure_reason`: populated only if `status == "red"` — the first failing assertion + the file:line where it fired
- non_goals: Do not change any file other than the one in your site descriptor. Do not run the full test suite.
- IMPORTANT: this sub-agent MAY call `edit_file` and run bash commands; `isolation: "worktree"` is required.

**Layer gate — hard stop before proceeding to the next layer:**
- All sites in this layer `status == "green"` → proceed to the next layer.
- Any site `status == "red"` → **abort the entire refactor immediately**. Do NOT apply any more changes. Surface:
  - The failing site (`file:line_range`)
  - The `diff_applied` for that site
  - The `failure_reason`
  - The current layer number and which layers (if any) already completed successfully
  - Recommendation: "Revert layer N changes manually or run `git stash` in each affected worktree, then diagnose with `/diagnose`."

---

### Wave 3 — Behavioral diff verification (after all layers green, `subagent_type: "research-agent"` or Bash-capable)

Dispatch a single behavioral-diff agent:

**Behavioral-diff agent** (`isolation: "worktree"`, Bash-capable)
- goal: Run the full test suite and compare observable behavior at the API boundary before vs. after.
- inputs: `test_commands` from the contract-extractor, plus any project-wide test command (inferred from `package.json`, `Makefile`, etc.)
- artifacts:
  - `full_suite_status`: "all-green" | "failures"
  - `failing_tests`: array of `{test_name, file, failure_reason}` (empty if all-green)
  - `behavioral_deltas`: array of `{symbol, before_behavior, after_behavior, expected: true|false}` — note only deltas, not noise
  - `unexpected_deltas`: subset of `behavioral_deltas` where `expected == false`
  - `confidence`: low | medium | high
- non_goals: Do not commit. Do not push.

**Post-Wave 3 decision:**
- `full_suite_status == "all-green"` AND `unexpected_deltas` is empty → proceed to synthesis, recommend commit.
- `full_suite_status == "failures"` OR `unexpected_deltas` is non-empty → surface the unexpected deltas for human review. Do NOT commit. Recommend: "Review unexpected behavioral changes before committing. If intentional, update tests to reflect new contracts. If not, route to `/diagnose`."

---

### Synthesis: Change report

Emit a structured change report:

```
## Refactor Report

**Goal:** <change type> — <target> → <destination>

**Scope:**
- Sites enumerated: N
- Layers processed: M (of M total)
- Status: COMPLETE | ABORTED AT LAYER N

**Changes applied:**
| File | Lines | Type | Status |
|------|-------|------|--------|

**Tests run:**
- Targeted (per-site): N runs, N green, N red
- Full suite: all-green | N failures

**Behavioral deltas:**
- Expected: N
- Unexpected: N (see below if non-zero)

**Recommendation:** COMMIT | REVIEW REQUIRED | ABORT
```

If recommendation is COMMIT, offer to invoke `/ship` for the final commit + PR. If REVIEW REQUIRED or ABORT, do not invoke `/ship` and do not commit.
