engineering-refactor · diff
git:20261013.ae762a8 to git:20261013.4072684
4 added, 4 removed. Audit A to A.
---
name: engineering-refactor
description: Restructure modules, consolidate shallow wrappers, align package layout, and add tests at module interfaces to move a codebase toward the house stack (uv + ruff + pyrefly) and deep-module architecture. Use when the user asks to refactor, restructure, reorganize, clean up architecture, tidy up code, modernize a Python project, or adapt a repo to these practices.
---
# Engineering Refactor
Move an existing codebase toward the house engineering standard **without bulldozing local
project contracts**.
## Required: the ruleset
This skill carries the **workflow**, not the rules. The rules live in the `engineering-rules`
skill — the Python toolchain, package layout, deep-module architecture (Matt Pocock's
vocabulary), testing, and the stack-specific patterns (FastAPI, Prefect, LLM/AI, ASR, Next.js,
k8s).
**Invoke `engineering-rules` first** and follow its reading protocol. Every rule id cited below
resolves through it — including its `applies-to` / `status` fields, which decide whether a rule
applies to this repo at all.
> If `engineering-rules` is not available, **stop and say so**. Do not refactor from a
> remembered standard. Install it with
> `npx skills add collectiveai-team/botica --skill engineering-rules`.
**Follow the local repo over the direction** unless the user explicitly asked to modernize.
## Workflow
### 1. Establish the baseline
Read the `engineering-rules` index, then inspect the repo's local contracts: `pyproject.toml`,
lockfiles, Makefiles, CI workflows, existing tests, package layout, `README`, `CONTEXT.md`,
and ADRs if present. Determine, citing evidence:
- Package manager + build backend (`py-package-manager`, `py-build-backend`).
- - Toolchain era — the house stack (uv + ruff + ruff-format + pyrefly + botica via prek) or a legacy poetry+black/isort/mypy setup (`py-ruff-format-modern`, `py-legacy-lint-stack`).
+ - Toolchain era — the house stack (uv + ruff + ruff-format + pyrefly + botica via prek) or a legacy poetry+black/isort/mypy setup (`py-ruff-format-modern`, `py-legacy-lint-migration`).
- Python version, package layout, test layout, logging, runtime entrypoints, frontend (if any).
Preserve the existing toolchain unless the user asked to migrate it (`general-respect-local-repo`).
### 2. Find refactor targets
Read the architecture rules — `arch-deep-modules`, `arch-deletion-test`,
`arch-adapter-discipline` — and the `spaghetti-*` rules. Look for:
- Shallow wrappers whose interface is nearly as complex as their implementation (apply the **deletion test**).
- Logic spread across callers that should live behind one module interface.
- Files over 400 lines receiving unrelated behavior; files over 700 lines (`file-size-guard`).
- - Orchestration mixing transport, validation, domain logic, persistence, formatting (`spaghetti-mixed-orchestration`).
+ - Orchestration mixing transport, validation, domain logic, persistence, formatting (`spaghetti-mixed-concerns`).
- Slices that don't match the conventions (`pylayout-meta-slice`, `pylayout-adapters-slices`, `log-get-logger`).
- Tests asserting internals instead of behavior at the interface (`test-through-interface`).
- Use the exact vocabulary from `arch-vocabulary`: module, interface, implementation, depth,
+ Use the exact vocabulary from `arch-deep-modules`: module, interface, implementation, depth,
seam, adapter, leverage, locality.
### 3. Refactor in small slices
- Keep behavior stable unless the user asked for a behavior change.
- Move code toward domain-named modules / existing package slices; replace shallow layers with one deeper module rather than adding another abstraction (`arch-adapter-discipline`).
- Add or update tests at the module interface before risky movement (`test-in-memory-adapters`).
- No formatting churn outside touched code (`py-no-formatter-churn`).
- Keep public imports and entrypoints compatible unless the task includes a breaking change.
- For stack-specific code, pull the matching rules: `prefect-*`, `llm-*`, `asr-*`, `api-*`, `fe-*`, `k8s-*`.
### 4. Verify
Run the narrowest useful checks first, then broaden (`pr-run-checks`). Note that Makefiles here
are docker-only — run linters/pytest directly (`infra-makefile-docker`).
- House stack: `ruff check`, `ruff format --check`, `pyrefly check`, `botica lint`, `pytest`
(via `uv run` / `uvx`), or the whole hook set with `uvx prek run --all-files`.
- Legacy repos: run what the repo actually has (`black`, `isort`, `pylint`/`flake8`, `mypy`,
- `pytest`) — don't introduce the house stack mid-refactor (`py-legacy-lint-stack`).
+ `pytest`) — don't introduce the house stack mid-refactor (`py-legacy-lint-migration`).
- Always run relevant pytest tests for behavior changes; report checks that could not run.
## Output
When finished, report: what changed, which rules drove each change (cite rule ids), which
tests/checks ran and their results, and any remaining architecture risks (large files,
shallow modules, missing tests) left behind.