Skip to content

Refactor Workflow Design

Workflow and domain design for the refactor action loop.

Layer Document
Platform Multi-Branch Loops Design
Caller shell Loop Caller Workflows Design
Invariants Loop Engineering Design
Skill spec Refactor skill & loop design

Artifacts: on-loop-refactor.yaml · skill refactor · refactor/scripts/detect_refactor.sh

Shared caller keys: Loop Caller Inputs Reference.

Purpose

Detect mechanical structure hints on integration branches and open fix PRs after bounded O1/O2 refactors. Each loop run surveys all hints in the detection envelope, then applies every actionable candidate in one Agent→Verify cycle.

Supported use cases

  • Cron scan of integration branches for H1 hints (duplication_block, oversized_unit)
  • Apply all actionable structural refactors from the surveyed hint set with stack validation (A')
  • Open an L2 review PR to the watch integration branch
  • Coordinate with peer loops via workflow concurrency

Out of scope

  • PR head healing (pr_enabled default off)
  • Interactive or architecture-improvement intent (O3 proposal path) — use skill refactor manually
  • Lint/SAST smell scores as primary detect or repair mission
  • tech-debt report input or Apply under report-* names
  • Sonar CPD default-on (future caller opt-in for duplication only)

| refactor (in common) | Interactive / loop structural O1/O2 apply | User or on-loop-refactor.yaml |

Separation from refactor skill

Detect script path: refactor/scripts/detect_refactor.sh (under common package).

Entry skill (refactor) handles interactive and loop paths: loop runs use structural intent only, survey all hints[], apply every apply candidate, O2 cap. Architecture-improvement language in user prompts is out of scope for this loop.

Modes

Mode Default Behavior
integration on Detect on watch branch → fix PR to same branch
pull_request off not supported for this loop

Caller inputs

Keys are passed in on-loop-refactor.yaml via with: on ci-loop-caller.yaml (alphabetically ordered). Multiline values (agent_checker_instructions, agent_maker_instructions) are defined inline in the caller workflow.

Shared semantics: Loop Caller Inputs Reference. Platform branch/finalize caps: canonical table.

Input / JSON key Description Dogfood value
agent_maker_max_turns Max maker agent turns per loop attempt (one Agent→Verify cycle). 100
agent_maker_model Maker model ID. Cursor: agent --list-models. claude-sonnet-5
agent_maker_effort Maker reasoning effort. Only engines with an effort flag (claude) consume it medium
agent_loop_max_attempts Max Agent→Verify retry cycles before finalize records failure. 3
agent_checker_instructions Checker APPROVE/REJECT rubric. Local/same-package structural edits only; no architecture/GoF/cross-package diffs. Inline in caller workflow
agent_checker_max_turns Max checker agent turns per verification. 100
agent_checker_model Checker model ID. Cursor: agent --list-models. claude-opus-5
agent_checker_effort Checker reasoning effort. Only engines with an effort flag (claude) consume it medium
allowlist Comma-separated globs the maker may modify. Tight dogfood scope. .apm/packages/**,scripts/**
branch_match Comma-separated integration branch patterns to watch. main
branch_state Branch for .loop/* persistence, state migration, and watch fallback. main
budget_max_runs_per_day Daily run cap keyed by loop_name. 1
budget_max_tokens_per_day Daily aggregated token cap across loops. 1000000
detect_script Domain detect script path. .agents/skills/refactor/scripts/detect_refactor.sh
engine AI engine (claude, copilot, codex, cursor). claude
delivery Platform delivery after APPROVE (open_pr for dogfood). open_pr
infer_files_pattern Extended regex to infer file paths from checker text. See caller workflow
level Autonomy level (L1, L2, L3). L2 opens review PR. L2
loop_name Loop identifier; state file .loop/state-refactor.json. refactor
max_targets_per_schedule Max hints processed per cron tick. 1
may_edit Agent worktree edit gate (true for dogfood). true
no_changes_verdict APPROVE or REJECT when maker produces no file diff. REJECT
pr_body Optional static prefix (dogfood: ""). ""
pr_title PR title when finalize strategy is open_pr. chore(refactor): structural improvement (loop-refactor)
agent_maker_instructions Domain instructions: invoke refactor survey-then-apply-all path; stack validation via A'. Inline in caller workflow
pr_enabled Enumerate open PR heads. Refactor loop uses integration branches only. false
agent_maker_skill_name Skill package to invoke. refactor

Domain detect environment (detect_domain_env_json)

JSON key / env var Description Dogfood value
REFACTOR_DUP_MIN_LINES Minimum consecutive non-empty lines for duplication_block 8
REFACTOR_OVERSIZED_FILE_LINES File line count threshold for oversized_unit (size only) 400
REFACTOR_SCAN_GLOBS Comma-separated globs for scan roots .apm/packages/**,scripts/**

| write_target | Agent artifact when may_edit is true (fix for dogfood). | fix |

Detect

Integration mode only

Per watch branch, loop-detect checks out the branch and invokes detect_refactor.sh with targets["integration:<branch>"].last_sha.

Detect script outputs facts (not semantic repair decisions):

Field Role
hints[] Mechanical H1 hints (duplication_block, oversized_unit)
hint.kind Closed set only
hint.path Primary file path for the hint
hint.detail Locator (line range, duplicate peer path, line count)
commit_range Passed through prompt context when scope is range
skip true when no hints after allowlist filter

Skill (refactor) maps every hints[] entry to survey rows; at L2/L3 applies all candidates marked apply in one run.

loop-detect emits per-branch target_json:

  • from.ref = HEAD on watch branch
  • to.branch = watch branch
  • finalize = open_pr

Stable filters (detect only)

  • Circuit breaker on targets[key].consecutive_failures
  • Budget (platform)
  • Prune generated trees, docs/report/**, node_modules/**, secrets paths

No infra/env classification — not applicable.

State fields (per target key)

Field Role
last_sha Scan cursor; advances when fix PR merges (on-loop-state-promote)
pending Written at finalize on open_pr; promoted to last_sha on merge
outcome pr-created, rejected, no-op, …
consecutive_failures Circuit breaker

Execute

  • Worktree from target.from on integration branch
  • Checker diff baseline: to.branch
  • verifier_context: detect hint summary (kind, path, detail)
  • Intent: always structural — O2 cap; no architecture Phase A/B
  • Survey all hints; apply every apply candidate; follow refactor skill contract via caller agent_maker_instructions (A')

Finalize

PR body is composed by loop-finalize from agent ## Overview / ## Summary (skill-owned) plus mechanical sections. Dogfood sets pr_body: "". See Loop PR Body Skill Contract.

Always open_pr to to.branch at L2.

No domain_persistence_script.

Merge-gated cursor: Same platform rule as all L2 open_pr loops — pending at finalize, last_sha on fix PR merge via on-loop-state-promote.yaml.

State delivery

See State delivery philosophy for platform rules.

Target (dogfood): merge-gated pending + on-loop-state-promote — same as docs-updater.

Persistence: state-refactor.json on branch_state via finalize inside ci-loop-agent.

Implementation Checklist

Shared platform: Multi-Branch — Shared platform checklist.

Loop-specific

  • [x] refactor/scripts/detect_refactor.sh (H1 facts output)
  • [x] on-loop-refactor.yaml dogfood caller via ci-loop-caller
  • [x] verifier_context on execute path (build_verifier_context_from_result .hints branch)
  • [x] refactor skill + references
  • [x] Bats suite for detect script (TEST-00)

Cross-Loop Note

refactor is orthogonal to ci-sweeper and tech-debt. It does not consume tech-debt reports. If CI fails during a refactor PR, ci-sweeper owns repair.

References