engineering-refactor · git:20261018.e05a5c3 · 2026-10-18 · sha256 4ae8bc911135da1b
engineering-refactor git:20261018.e05a5c3A
Immutable. This exact content never changes and is served at /api/v1/blob/4ae8bc911135da1b.
--- 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`, `GLOSSARY.md` (or legacy `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-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-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-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-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. Credits and sources: [`references/CREDITS.md`](references/CREDITS.md).