
Oma Refactor
- 17 installs
- 41 repo stars
- Updated August 4, 2026
- gracefullight/stock-checker
Plans and executes behavior-preserving refactorings as atomic, test-gated, refactor-only commits targeting code smells and churn-complexity hotspots.
About
A refactoring agent that restructures code without changing observable behavior, using characterization-test safety nets and one atomic transformation per commit. A developer uses it to modernize legacy code, decompose god classes, or prepare code before adding a feature.
- Mikado method: on repeated test failure, revert fully and attack the prerequisite first
- Two-hats rule keeps behavior changes out of refactor-only commits
Oma Refactor by the numbers
- 17 all-time installs (skills.sh)
- Ranked #760 of 1,352 Code Review & Quality skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/gracefullight/stock-checker --skill oma-refactorAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 17 |
|---|---|
| repo stars | ★ 41 |
| Last updated | August 4, 2026 |
| Repository | gracefullight/stock-checker ↗ |
What it does
Plans and executes behavior-preserving refactorings as atomic, test-gated, refactor-only commits targeting code smells and churn-complexity hotspots.
Files
Refactor Agent - Behavior-Preserving Restructuring Specialist
Scheduling
Goal
Improve internal code structure - readability first - without changing observable behavior, through small verified transformations, each gated by a safety net (tests / tooling / types) and committed separately from any behavior change.
Intent signature
- User asks to refactor, clean up, restructure, modernize, de-duplicate, or "make this code maintainable/readable".
- User mentions code smells, technical debt, legacy code, long methods/files, god classes, hotspots, characterization tests, or extract/move/rename transformations.
- User asks "where should we refactor first?" or wants a refactoring plan/priority for a codebase.
When to use
- Executing a refactoring on specific files/modules (extract, move, rename, decompose, pattern/idiom alignment)
- Preparatory refactoring before a feature ("make the change easy, then make the easy change")
- Legacy (brownfield) rescue: seam discovery + characterization tests, then restructuring
- Refactoring target selection and prioritization (smells + SATD + hotspot = churn x complexity)
- Auditing whether code is safe to refactor now (coverage breadth x mutation strength x flakiness)
When NOT to use
- Fixing a reported bug or failing behavior -> use
oma-debug(refactoring must not change behavior) - Security/performance/accessibility review or quality audit -> use
oma-qa - System design, module boundary decisions, ADRs, convention changes -> use
oma-architecture(a convention/pattern change is an architecture decision, not a local refactoring) - DB schema design or migration mechanics -> use
oma-db(this skill only plans the expand-contract sequence) - Commit splitting / staging mechanics -> use
oma-scm - Performance optimization as a goal -> out of scope by definition (tuning is a side effect, never the objective)
Expected inputs
target: file/module/path, smell report, SATD marker, or the feature request motivating preparatory refactoringverification: project test command(s) per the tool registry; coverage/mutation tooling if availableconstraints: coding guide / conventions, regulated-environment flags, merge-window concerns- Optional: prior metric reports, hotspot data, ADRs touching the target area
Expected outputs
- Refactored code as a sequence of atomic, refactor-only commits (no test changes mixed in)
- Safety-net additions when missing (characterization / golden-master tests) as separate commits
- Before/after report: metric delta (cyclomatic/cognitive complexity, size, coupling) + readability verdict
outputs:
- name: report
description: refactoring plan or before/after report
artifact: ".agents/results/refactor/*.md"
required: falseDependencies
resources/definition.md(invariant definition: 5 properties, boundaries, destination principle, inline evidence)resources/measurement.md(4-layer measurement + git forensics commands)resources/governance.md(org parameters: budget floor, 500-line gate, tool registry)- Serena MCP symbol/reference tools; project test runners per registry (vitest / pytest / flutter_test)
- Git history for churn/ownership/hotspot analysis
Control-flow features
- Branches by safety-net state (greenfield vs brownfield), statefulness (code-only vs expand-contract), and verification outcome (pass vs Mikado revert)
- Reads code/history/metrics; writes code, tests (in separate commits), and reports
- Stops and routes to
oma-architecturewhen the change requires a convention/boundary decision
Structural Flow
Entry
1. Establish what motivates the refactoring (smell, SATD, hotspot, or upcoming feature) and the target scope. 2. Diagnose the safety net for that scope: coverage of changed lines, test determinism (flakiness), mutation strength if measurable. 3. Identify the destination form: the language idiom and codebase convention the result must match.
Scenes
1. PREPARE: Classify greenfield (safety net exists) vs brownfield (build net first); check size gates and hotspot rank; confirm two-hats scope (no feature/bug work mixed in). 2. ACQUIRE: Read target code via symbol tools; collect metrics (complexity, size, coupling) and git signals (churn, ownership); read the coding guide for conventions. 3. REASON: Decompose the goal into a sequence of named atomic transformations; for stateful targets plan expand-contract; verify each step is independently verifiable and revertible. 4. ACT: Apply ONE transformation; prefer deterministic engines (IDE rename, codemod, ast-grep) over freehand edits. 5. VERIFY: Re-run existing tests unchanged. Pass -> commit (refactor-only) -> next transformation. Repeated failure -> Mikado: record the broken prerequisite, revert fully, recurse on the prerequisite first. 6. FINALIZE: Before/after metric delta + readability judgment (metric improvement alone is not success); report follow-ups discovered but deliberately not done.
Transitions
- If the safety net is missing or weak (low diff coverage, flaky, no assertions), write characterization / golden-master tests FIRST, committed separately, before touching production code.
- If verification fails repeatedly, switch to the Mikado method: never carry a half-broken tree forward.
- If the right fix is a convention or pattern change (new dialect), stop and route to
oma-architecturefor an ADR + ratchet plan. - If the target involves persisted state or external consumers, plan expand-contract (parallel change) with feature flags; deployment, not commit, becomes the unit of incrementality.
- If a behavior bug is discovered mid-refactoring, record it and route to
oma-debug; do not fix it in the refactor commit. - If the work is large enough to collide with teammates' branches, recommend announcement + short merge window; register bulk mechanical commits in
.git-blame-ignore-revs.
Failure and recovery
| Failure | Recovery |
|---|---|
| Tests fail after a transformation | Mikado: record prerequisite, revert all, attack prerequisite first |
| No tests and code is untestable | Find a seam; apply only minimal mechanical changes to inject test access, then characterize |
| Tests are flaky | Fix or quarantine flaky tests before refactoring - an unreliable net is no net |
| Metric improves but readability worsens | Reject the transformation; readability is the success criterion, metrics are proxies |
| Scope keeps growing | Stop; report the boundary issue and split into a Mikado graph or route to architecture |
| Refactoring engine/codemod produces wrong output | Engines are not infallible - tests re-run is mandatory; fall back to manual atomic edits |
Exit
- Success: behavior verified unchanged, structure measurably improved, readability confirmed, refactor-only commits, follow-ups reported.
- Partial success: safety net built but restructuring deferred; or prerequisites mapped (Mikado graph) with explicit blockers.
- Failure: blocking ambiguity (no verification path, regulated freeze, convention decision needed) reported with the recommended route.
Logical Operations
Actions
| Action | SSL primitive | Evidence |
|---|---|---|
| Diagnose safety net | VALIDATE | Coverage/flakiness/mutation state of target scope |
| Collect signals | READ | Metrics, git churn/ownership, smells, SATD |
| Rank targets | COMPARE | Hotspot = complexity x churn |
| Plan atomic sequence | INFER | Named transformations, Mikado graph |
| Write characterization tests | WRITE | Golden-master/snapshot tests (separate commit) |
| Apply transformation | WRITE / CALL_TOOL | One atomic refactor, engine-first |
| Verify preservation | VALIDATE | Existing tests re-run unchanged |
| Commit separately | UPDATE_STATE | refactor:-typed commits only |
| Report delta | NOTIFY | Metric + readability before/after |
Tools and instruments
- Serena MCP:
find_symbol,find_referencing_symbols,search_for_patternfor impact analysis - Deterministic transformers: IDE refactoring actions, codemods (jscodeshift / OpenRewrite / ast-grep / comby)
- Metrics: lizard / radon (complexity), per-language linters with
max-linesgates - Test stack per registry: vitest + StrykerJS / pytest + mutmut / flutter_test (see
resources/governance.md) - Git forensics one-liners (see
resources/measurement.md)
Canonical workflow path
1. Diagnose: run coverage on the target scope and check test determinism; classify green/brownfield. 2. If brownfield: find a seam, write characterization (golden-master) tests for CURRENT behavior, commit. 3. Select targets by hotspot rank (complexity x churn), not by smell aesthetics alone. 4. Plan a sequence of named atomic transformations toward the language-idiomatic, convention-conforming form. 5. Loop per transformation: apply (engine-first) -> re-run tests UNCHANGED -> commit refactor: only. On repeated failure: record prerequisite, revert fully, recurse (Mikado). 6. Finish: metric delta + readability verdict; list discovered-but-deferred work; never mix in behavior changes.
Resource scope
| Scope | Resource target |
|---|---|
CODEBASE | Target source, tests, coding guide, lint configs |
LOCAL_FS | Reports under .agents/results/refactor/, .git-blame-ignore-revs |
PROCESS | Test runners, coverage/mutation tools, codemod engines, git log analysis |
MEMORY | Mikado prerequisite graph, deferred follow-ups, metric baselines |
Preconditions
- A verification path exists or can be built (tests/types/tooling); otherwise the first deliverable is the safety net, not restructuring.
- The target's conventions are known (coding guide read) or explicitly absent.
Effects and side effects
- Mutates production code (structure only) and adds tests in separate commits.
- Runs test/coverage/mutation commands; reads git history.
- May write reports under
.agents/results/refactor/and entries to.git-blame-ignore-revs. - Never alters observable behavior, public contracts, or persisted data without an expand-contract plan.
Guardrails
1. Behavior-preserving: the consumer contract (Hyrum-aware) is inviolable; tuning is a side effect, never a goal. 2. Verifiable: never restructure without a net; during production refactoring tests are frozen, during test refactoring production is frozen - one side at a time. 3. Incremental: one named transformation per commit; revert is a navigation tool (Mikado), not an accident. 4. Economic: readability is the objective function's dominant term; do not refactor code slated for deletion or cold low-churn code. 5. Separated (two hats): never mix behavior changes into refactor commits; tangled changes are a measured quality risk. 6. Destination = f(language idiom, code layer, codebase convention); convention deviation requires the ADR route, not a local edit. 7. Abstraction timing follows the Rule of Three; speculative generality is itself a smell. 8. All metrics are proxies (Goodhart): a 499-line mechanical split, assertion-free coverage, or pattern-count gains are failures, not wins.
References
- Invariant definition (5 properties, boundaries, destination, contexts, D&C, inline evidence):
resources/definition.md - Measurement: 4 layers + git forensics commands:
resources/measurement.md - Org parameters: budget floor, 500-line gate, tool registry:
resources/governance.md - Context loading:
../_shared/core/context-loading.md - Quality principles:
../_shared/core/quality-principles.md - Adjacent skills:
oma-debug(bugs),oma-qa(audits),oma-architecture(boundaries/ADR),oma-db(schema),oma-scm(commits)
Refactoring - Invariant Definition
Part I of the refactoring doctrine. This file is timeless; org-specific parameters live in governance.md. Empirical evidence is noted inline where a claim depends on it.Core definition
Refactoring is the act of improving a system's internal structure toward its codebase's conventional form - without changing externally observable behavior (the contract its consumers depend on) - through small, revertible, named transformations whose behavior preservation is mechanically verifiable, in order to lower the future cost of change, whose dominant term is human comprehension cost.
The five mandatory properties
If any property is missing, the activity is not refactoring.
| # | Property | Meaning | Without it |
|---|---|---|---|
| 1 | Behavior-preserving | Consumer contract unchanged | Feature change / redesign |
| 2 | Verifiable | Preservation guaranteed by tests/tools/types | Risky edit |
| 3 | Incremental | Composition of small named transformations | Rewrite |
| 4 | Economically motivated | Lowers future change cost (~= comprehension cost) | Vanity polishing |
| 5 | Separated | Never mixed with behavior changes in a commit | Unreviewable tangle |
1. Behavior preservation - the boundary is contractual, not technical
- Preserved: input/output equivalence, public interface semantics, the meaning of side effects (records written, events emitted).
- Not preserved: internal call order, private structure, stack-trace shape.
- Gray zone (performance, log format, serialization): judged by Hyrum's Law - if someone actually depends on it, it is part of the contract.
- Performance (tuning) is allowed only as a side effect, never as the goal. If performance is contractual (SLA, real-time), preserve it too.
- Preservation is necessary but not sufficient: behavior can be preserved while readability worsens - that is a failed refactoring. (Empirical: LLM refactorings preserved behavior ~84% yet worsened readability in ~71% of cases while static metrics improved.)
2. Verifiability - the precondition
Guarantee mechanisms: (a) test suite - tests are FROZEN during refactoring; a failing test means behavior changed; (b) deterministic tool transformations - engines have bugs too (refactoring-engine bug studies exist), so re-run tests anyway; (c) type system / compiler; (d) differential testing and semantic equivalence checking (e.g., execution-driven differential testers, equivalence checkers).
- Symmetry rule: refactor production with tests frozen; refactor tests with production frozen. One side at a time.
- "Test failed = behavior changed" holds only for deterministic tests. Flaky tests destroy the signal itself.
- When no net exists: write characterization tests (pin CURRENT behavior, bugs included - Hyrum). Practical form: golden-master / approval / snapshot tests.
3. Incrementality - an open catalog
Composition of named transformations (Extract Function, Move Method, Rename, ...). Small enough to verify instantly, revert instantly, and review confidently. The standard catalog names only a fraction of real-world behavior-preserving changes (detector studies explain ~20% of real changesets with the standard catalog alone) - the test is the five properties, not catalog membership. Compound refactorings are where automated agents fail most; decompose to atomic steps.
4. Economics - readability is the dominant term
change cost = comprehension cost + ripple cost + verification cost. Most developer time goes to comprehension, so readability (analysability) is the primary objective; coupling-driven ripple radius (modifiability) is the second, independent lever. Kent Beck: "Make the change easy (warning: this may be hard), then make the easy change."
- Cognitive grounding: refactoring removes extraneous cognitive load; working-memory limits (chunking) justify small units; naming is the largest readability lever no metric measures.
- Debt vocabulary: Cunningham's debt metaphor is a communication device for non-engineers (interest = ongoing cost, principal = structural flaw). Fowler's quadrants (deliberate x prudent) split the prescription: prudent-deliberate debt is a repayment-planning problem; reckless-inadvertent debt is an education problem.
5. Separation - two hats
Never wear the feature hat and the refactoring hat simultaneously; mixed (tangled) commits make preservation unreviewable and are a measured quality risk (tangled refactorings in agent patches significantly reduce compilability). This is why refactor is a distinct commit type. Separation governs commits, not budgets - preparatory refactoring embedded in feature work is part of that feature's cost.
What refactoring is NOT
Bug fixing (intentional behavior change) / performance optimization (different goal, often anti-readability) / feature addition / rewrite (wholesale replacement without stepwise verification) / API-breaking change (= redesign/migration). Lifecycle home: ISO/IEC/IEEE 14764 perfective/preventive maintenance. Edge case: cross-language migration can satisfy all five properties but is conventionally named "migration".
When NOT to refactor
- Code about to be deleted or replaced (zero economics)
- Cold, low-churn stable code (touching it is pure risk)
- Right before a release (risk asymmetry: gains are future, risk is now)
- Without a safety net (build the net first)
- Know the risk: a fraction of refactorings induce defects and security regressions (both empirically documented); the five properties reduce risk, they do not zero it.
- Rewrite is right only when incremental-migration total cost exceeds rewrite + full re-verification cost (include feature-freeze cost and second-system risk in the comparison).
Triggers
- Code smells (qualitative heuristics: duplication, Long Method - long body, god class, Feature Envy, Shotgun Surgery, Speculative Generality): signals that change cost is rising, not defects.
- SATD (self-admitted technical debt): TODO/HACK/FIXME in comments/issues - a third signal independent of structure and history. Do not let the tone of the admission drive priority (negativity measurably skews developer prioritization even though most consider it wrong).
Destination - one principle, three axes
Reusability = context independence. Every pattern is a named technique for severing one kind of context dependency (Strategy: host vs algorithm; Facade: consumer vs subsystem internals; Adapter: new context vs existing interface; DI: unit vs dependency construction). Roots: Parnas information hiding, GoF's two meta-principles, OCP, SDP/SAP. Composition is the mother of patterns; FP (pure functions) is the limit case - the smallest reusable unit. Catalogs are fractal: GoF / PoEAA / EIP / DDD / cloud (Strangler Fig) / POSA.
Pattern choice = f(language expressiveness, code layer, codebase convention):
- Language axis: patterns compensate for what the language cannot express (Norvig: most GoF patterns evaporate into idioms). The destination is the language's idiom, not a GoF diagram.
- Layer axis: functional core vs imperative shell call for different forms and different test economics.
- Convention axis: in brownfield, the coding guide and framework conventions beat "theoretically better" patterns - consistency is a component of analysability. Changing a convention is an architecture decision (ADR + lint ratchet for new code + module-wise migration), never a boy-scout edit.
- Timing: Rule of Three - abstract after reuse evidence accumulates; speculative generality is a smell.
Execution contexts
- Greenfield: refactoring is the third beat of TDD (Red -> Green -> Refactor) - minute-scale hygiene, net already exists.
- Brownfield: order inverts - find a seam (minimal mechanical change to enable testing) -> characterization tests -> restructure. Large scale: Strangler Fig, Branch by Abstraction, Sprout Method - the system stays working at every point. The classification is per code fragment (coverage map), not per project.
- Stateful (data/API): git revert does not restore data. Mechanism: Expand-Contract (parallel change) - expand (old+new coexist) -> dual-write + backfill -> switch reads -> contract (remove old); feature flags are the standard switch. External consumers: semver + deprecation cycles as a staged contract-transfer protocol.
- Team concurrency: big renames collide with every open branch - another reason for "small and frequent". Announce large refactorings + short merge windows; register bulk mechanical commits in
.git-blame-ignore-revs; LSC (monorepo-wide atomic change + owner-split review) is incrementality at org scale. - Regulated environments: even behavior-preserving changes trigger re-verification/re-certification - economics invert; batch-per-release refactoring is the one legitimate exception to "continuous flow".
Architectural principle - refactoring enables divide and conquer
Functional core / imperative shell: pure-core unit tests cost ~0 and assert maximally -> "every step gets a unit test" is the rational default there; the shell gets few integration/contract tests. The test pyramid is D&C's verification form (unit = conquer, contract/integration = combine, E2E = divide). "All units pass therefore the system works" is the composition fallacy. Expensive, mock-heavy unit tests diagnose a failed decomposition - i.e., a refactoring target. Reusability and testability are the same coin: a test is the code's second consumption context.
Goodhart - every metric is a proxy
Complexity targets -> mechanical splits; coverage KPIs -> assertion-free tests; size gates -> boundary-dodging splits; pattern counts -> speculative generality; git metrics -> commit-habit gaming; SATD tone -> priority distortion. Metrics diagnose; they do not replace qualitative judgment on what they cannot see (bad names, wrong abstraction level, missing domain concepts). The only terminal criterion: can the next person understand and change this code more cheaply?
Standards anchors
ISO/IEC 25010 (maintainability - analysability is the standard vocabulary for the readability thesis) | ISO/IEC/IEEE 14764 (perfective/preventive) | ISO/IEC 25023, 5055 (automated measures) | ISO/IEC/IEEE 29119-4 (test design techniques, coverage criteria incl. MC/DC) | ISO 26262 / DO-178C (risk-tiered coverage; re-certification implications) | ISO/IEC 25051 (successor of withdrawn 12119). Standards are anchors for the doctrine, not its content.
Governance - Organization Parameters
Declaration: numeric values and tool names here (20% / 500 lines / vitest...) are THIS organization's chosen parameters - other orgs may fill in different values. The mechanisms themselves - a floor's existence, burden-of-proof inversion, registry unification, ratchet enforcement - are invariant doctrine.
G-1. Budget: 20% of capacity is a FLOOR
Every organization - including legacy orgs that never refactor - allocates at least 20 of every 100 units of engineering capacity to refactoring. This is an unconditional floor, not a recommendation for mature teams.
- Accounting-illusion correction: an org "too busy to refactor" is already paying 30-40% involuntarily (slowed delivery, repeated hotfixes, re-deciphering time) - it just appears as zero because no budget line captures it. The real choice is "20 deliberately vs 30-40 haphazardly".
- Bootstrap order from zero: (1) instrument - install Layer 1-4 measurement first; (2) safety net - kill flaky tests, characterize hotspots; (3) only then repay principal. The first spending is the infrastructure that makes refactoring possible; skipping this order is how adoption fails.
- The floor is permanent: "debt is low, cut the budget" reverses causality - low debt is the state that spending maintains. The control loop adjusts upward only; the sole exception below the floor is regulated-environment rhythm reallocation.
- Enforcement is org-level: a capacity-planning line item + quarterly consumption reporting. Team-level budgets are always eaten by feature pressure.
G-2. Budget usage restriction
The budget covers only what feature flow cannot reach: hotspot principal repayment, test infrastructure (flaky eradication, mutation strengthening, framework migration), large-scale restructuring, state migrations. Preparatory refactoring embedded in a feature is that feature's cost - absorbing it into the budget creates "we have a budget, so no refactoring during features".
G-3. Control loop + outcome accounting
Layer-2 signals worsening (velocity decline, revert/hotfix rise, flakiness rise, SATD accumulation) -> raise above the floor; on recovery -> return to the floor (one-way). Close the loop with DORA outcomes (lead time, change failure rate) reviewed quarterly next to budget consumption.
G-4. Goodhart defense
The budget must not become ritual: spending targets come from hotspot rank (Layer 3); effects close via the procedure's final verification step plus DORA.
G-5. File size gate: 500 lines, burden of proof inverted
A file exceeding 500 lines is a refactoring target by default; KEEPING it requires a documented justification. The point is the default inversion, not the number.
- Closed justification list: generated code / data tables / cohesive state machines or parsers where splitting hurts readability (requires ADR-grade record - the most abused item) / vendored code / regulated freeze.
- Ratchet enforcement: lint rule (
max-lines: 500ESLint,max-module-lines=500Pylint, metric tooling for Dart) - new files hard-fail in CI; existing violations frozen in a baseline and forbidden to grow (shrink updates the baseline). Suppression comments must state the reason; permanent exemptions need an ADR. - Caution: LOC is the weakest metric - the gate's virtue is enforceable simplicity. Splits follow responsibility boundaries, never line counts; a split producing mutually-importing tightly-coupled halves is void.
G-6. Per-language tool registry
One test framework per language per repo, declared here; changing it follows the convention-change procedure (ADR + ratchet migration) and is a typical G-1 budget expenditure. All Layer-4 instrumentation stacks on the runner - dual runners split coverage, mutation, CI gates, and agent output.
| Language | Test | Coverage (breadth) | Mutation (strength) | Notes |
|---|---|---|---|---|
| TS/JS | vitest | @vitest/coverage-v8 | StrykerJS | residual jest requires a migration ADR |
| Python | pytest | pytest-cov | mutmut / cosmic-ray | no unittest-style mixing |
| Dart/Flutter | flutter_test | flutter test --coverage | (ecosystem gap - compensate with assertion review) | includes golden tests |
This registry is part of the coding guide and therefore part of any coding agent's effective system prompt; ecosystem gaps are recorded with their compensation rule.
Measurement - Four Layers + Commands
Operationalizes target selection and effect verification. All values are diagnostic proxies (Goodhart) - never evaluation KPIs.
Layer 1 - Static structure: "where change is hard"
| Metric | Reading | Thresholds |
|---|---|---|
| McCabe V(G) = E - N + 2P (~ branch points + 1) | Min. test-case lower bound for branch coverage | <=10 ok / 11-20 caution / 21-50 high risk / 50+ untestable |
| Cognitive Complexity | Human reading difficulty (nesting-weighted) | Primary indicator for the readability objective |
| CK suite (CBO, LCOM, WMC) | Coupling/cohesion at class/module boundary | Triggers for Move/Extract Class |
| Duplication % | Token/AST clone ratio | Duplicate Code smell, quantified |
# Python
radon cc -s -a <path> # cyclomatic
lizard <path> # multi-language CC + NLOC + params
# Any language with lizard support
lizard -l <lang> --CCN 10 <path>Layer 2 - Git forensics: "where change actually happens"
# High-churn files (exclude lock/generated noise)
git log --format=format: --name-only --since="1 year ago" \
| grep -vE '(^$|lock|generated|\.snap|\.min\.)' | sort | uniq -c | sort -nr | head -20
# Bug hotspots (message-quality dependent; approximate is still useful)
git log -i -E --grep="fix|bug|broken" --name-only --format='' \
| grep -v '^$' | sort | uniq -c | sort -nr | head -20
# Ownership / bus factor (squash merges distort this)
git shortlog -sn --no-merges
# Velocity trend (interpret as trend only, never absolute)
git log --format='%ad' --date=format:'%Y-%m' | sort | uniq -c
# Firefighting signal (safety-net trust diagnosis)
git log --oneline --since="1 year ago" | grep -icE 'revert|hotfix|emergency|rollback'Corrections: use --follow for single-file rename history; register bulk mechanical commits in .git-blame-ignore-revs; squash merges flatten authorship.
+ SATD signal (admitted debt, independent of structure and history):
rg -c 'TODO|FIXME|HACK|XXX' --type-add 'src:*.{ts,tsx,py,dart,go,java,kt}' -t src | sort -t: -k2 -nr | head -20Layer 3 - Hotspot: "what to fix first"
hotspot = complexity (L1) x change frequency (L2) - the quantified form of the economic property and the budget's spending rank.
# Recipe: top-churn files joined with complexity
git log --format=format: --name-only --since="1 year ago" | grep -vE '(^$|lock)' \
| sort | uniq -c | sort -nr | head -30 | awk '{print $2}' \
| xargs -I{} sh -c 'echo "$(lizard -C 999 {} 2>/dev/null | tail -1) {}"'
# Or use code-maat / CodeScene for the full joinLayer 4 - Safety-net instrumentation: "where refactoring is safe NOW"
net = breadth x strength x reliability - if any factor is zero, there is no net.
| Dimension | Metric | Notes |
|---|---|---|
| Breadth | Coverage (statement < branch < condition < MC/DC) | Coverage measures executed, not verified. Prefer diff coverage gates over global targets |
| Strength | Mutation score (PIT / StrykerJS / mutmut) | The true measure of "will the net catch a behavior change" |
| Reliability | Flakiness rate | Non-deterministic tests destroy the "failure = behavior changed" signal; fix or quarantine first |
# Per-registry commands (see governance.md for the registry)
vitest run --coverage # TS/JS breadth
stryker run # TS/JS strength
pytest --cov=<pkg> --cov-report=term-missing
mutmut run # Python strength
flutter test --coverage # Dart breadth (strength gap: compensate with assertion review)Tier by layer: dense unit tests on the pure core, few integration/contract tests on the shell, MC/DC only for safety-critical modules.
When the net is missing, LLM-assisted test generation is viable for seeding characterization suites - prefer approaches guided by coverage or mutation feedback, and review generated assertions manually (generation quality is bounded by the feedback signal).
Outcome accounting (org level)
Budget effectiveness closes with DORA: deployment frequency, change lead time, change failure rate, MTTR. Investment hypothesis: structural improvement -> lead time down + change failure rate down. Review budget consumption alongside DORA trends quarterly; Layer-2 signals are proxies, DORA is the outcome.