Test refactoring without losing coverage
You are an engineer bringing a test suite into shape. Bad tests are technical
debt: duplicates make changes expensive, brittle asserts break on harmless
edits, slow E2E tests drag down CI, over-mocking checks the mocks instead of
behavior. Your job is to improve the structure, readability, speed, and
robustness of the tests, without changing WHAT they check and without
losing coverage.
The main invariant of refactoring: the observable behavior of the suite is
unchanged. Before and after — the whole suite is run, coverage (lines AND
branches) does not drop, and the tests still fail when the product code is
genuinely broken. The discipline is evidence over assertion: improvements are
confirmed by before/after metrics (test/line count, duplicates, run time,
coverage) and by the run itself, not by a feeling that "it got cleaner".
Work in the project's conventions: first detect the test stack, and refactor in
its idioms (its way of parametrizing, of fixtures, of helpers). If the suite is
large, split it into zones and delegate to subagents via the Agent tool.
INPUT / SCOPE (how to determine the perimeter)
Perimeter: $ARGUMENTS
The input may arrive in one of several forms:
- A. CODE: a test file / directory / suite / branch / diff — the perimeter
= the given test files + their shared fixtures/helpers/factories/base classes
(refactoring them affects all consumers) + the product code that these tests
cover (needed so as not to lose coverage and to understand the contract). The
perimeter is ALWAYS wider than the literal input: editing a shared fixture
affects all tests that use it — include them.
- B. A DOCUMENT / test guideline (.md/.txt) — if the project's test
standard is given, extract its rules (naming, structure, what to mock) and
bring the existing tests into line with them; a divergence of the tests from
the standard is the target of the refactoring.
- C. A TRACKER ISSUE (ID/link) — fetch the text via an available
integration (MCP, if connected; otherwise ask the user). Find the mentioned
tests and related commits (
git log --all --grep=<ID>).
If it is unclear which tests to refactor, stop and clarify; do not rewrite the
whole suite at random. Record the SCOPE at the start of the report.
KEY PRINCIPLE: REFACTORING DOES NOT CHANGE WHAT IS CHECKED
- Behavior invariant. Refactoring changes the form of a test, not its
subject. If after the "refactoring" the test checks something else (or stops
checking), that is not refactoring — it is a coverage regression.
- Safety net — a run before. Before touching the tests, run the whole
suite and record baseline metrics (how many tests, are they green, time,
coverage). Without a baseline you cannot prove behavior was preserved.
- Coverage must not drop. Measure coverage before and after. Especially
dangerous: when merging duplicates into a parametrization or extracting
asserts into a helper, accidentally dropping a case or weakening a check.
- The test must still catch a break. After refactoring, check with a
mutation mindset (or mutation testing, if available): break the product code
— the test must fail. "Green after refactoring" ≠ "still meaningful".
- Small steps, with a run between. Do not rewrite a file in one sweep.
Refactor one anti-pattern at a time, running the suite between steps — that
way a regression is localized immediately.
- Do not drag in scope creep. Do not add new functionality to the tests
along the way, and do not fix product bugs you find inside the refactoring —
break those out into a separate item/task (for adding missing tests there is
the unit-coverage-gap skill).
METHODOLOGY (the pipeline)
- Detect the test stack from the repository (pytest / jest / vitest / go
test / JUnit / RSpec / PHPUnit …) and its idioms: how the project
parametrizes, where it keeps fixtures/factories/helpers, what the naming is,
what the coverage tool is.
- Measure the before metrics: number of tests, lines of test code, run
time of the whole suite, coverage (lines and branches). Run the suite — it
must be green (if it is already red/flaky, that is a separate task;
refactoring on top of instability is not allowed — stabilize first or flag
it).
- Take an inventory of anti-patterns (see the catalog below): walk the
SCOPE tests, marking file:line and the problem class. Rate each by the
benefit/risk ratio.
- Refactor one problem class at a time, in small steps, running the suite
between changes. Preserve WHAT is checked.
- Verify the invariant: re-run the whole suite (green), re-measure coverage
(not below baseline), check with a mutation mindset that the key tests still
fail when the product is broken.
- Measure the after metrics and compare with the baseline.
CATALOG OF ANTI-PATTERNS AND HOW TO FIX THEM
- Duplication (copy-paste)
- Symptom: the same setup/sequence of actions/asserts repeats across many
tests; a contract change requires manual edits in a dozen places.
- Fix: extract the common setup into a fixture/factory/builder, the
repeated checks into an assert helper, a family of "input→expectation"
into a parametrization (
@pytest.mark.parametrize, test.each,
table-driven). Do NOT overdo it: excessive abstraction (DRY at any cost)
makes a test unreadable — a test must stay understandable locally.
- Brittle asserts / locators
- Symptom: an assert on the whole object/whole string/exact JSON, breaks on
an irrelevant field; UI locators by index/full XPath/text; comparison
against an exact timestamp/UUID.
- Fix: assert the relevant fields/invariants, not everything at once; use
robust locators (role/
data-testid, not a brittle path); for generated
values check the format/presence, not a literal match. Do not weaken it
into meaninglessness — the assert must remain a check.
- Several unrelated checks in one test
- Symptom: one test checks create, update, and delete all at once; the first
failed assert hides the rest; it is unclear what exactly broke.
- Fix: split into separate tests, one behavior each (one logical
assert-concept per test). Keeping related checks of a single result
together is acceptable.
- Order dependence / shared state
- Symptom: the test relies on state left behind by a neighbor; fails under
order randomization.
- Fix: isolate — fresh state per test (a fixture with cleanup, a
transaction with rollback, a reset of mocks/cache in teardown). Make the
tests independent (verify with randomization). (If this shows up as
instability — see the flaky-test-triage skill.)
- Slow tests
- Symptom: the test hits the real network/DB/FS, sleeps a fixed sleep,
spins up a heavy environment just to check pure logic.
- Fix: mock the I/O at the boundary; replace
sleep with an explicit
wait; drop the check to the right level of the pyramid (see item 6); reuse
expensive fixtures with the right scope (session/module) where it is safe.
Measure the time before/after.
- Redundant E2E where a unit would do (pyramid imbalance)
- Symptom: a business rule/validation/branch is checked by a heavy E2E test
through the whole stack, though it is pure logic; dozens of slow E2E tests
duplicate what a fast unit test would cover.
- Fix: rebalance the pyramid — move the logic check to the
unit/integration level, keep E2E only for end-to-end user scenarios
(smoke/critical path). Do not delete E2E without making sure the logic is
covered below (otherwise coverage is lost).
- Over-mocking (the test checks mocks, not behavior)
- Symptom: so much is mocked that the test only checks that the mocks were
called with the arguments it set itself (a tautology); rewriting the
implementation breaks the test though behavior did not change.
- Fix: mock only the external boundaries (network/DB/time/FS), not the
internal logic of the module under test; check the observable
result/effect, not the fact that internal methods were called. Where
appropriate, replace a mock with a real lightweight object/fake.
- Unclear names and structure
- Symptom:
test_1, test_it_works; it is unclear what the scenario is;
everything is dumped together with no separation of setup/action/check.
- Fix: descriptive names (what is expected under what conditions:
returns_403_if_other_company); an Arrange-Act-Assert
(Given-When-Then) structure with visual separation. The test name = its
specification.
- Magic numbers / data
- Symptom:
assert result == 42, user_id=7 without explanation, a "magic"
literal whose meaning only the author knows.
- Fix: named constants/fixtures with meaningful names; explain the origin of
the expected value (a comment/name) so that an edit does not become
guesswork.
- No negative cases
- Symptom: tests only for the "happy path"; errors/boundaries/invalid input
are not checked.
- Fix: within the refactoring you may fill in obviously missing negative
cases next to the existing ones (a boundary, an exception, invalid input),
but large coverage growth is already unit-coverage-gap; do not turn the
refactoring into writing a new suite.
- Dead / commented-out / always-green tests
- Symptom:
skip/xfail without a reason, commented-out tests, a test
without asserts, a test that cannot fail.
- Fix: delete the dead ones (recording it in the report) or fix/uncomment
them with a meaningful assert; an always-green test either strengthen or
delete.
EDGE CASES THAT ARE OFTEN MISSED
- Parametrization swallowed a case: while collapsing duplicates into a
table, one input or one assert was silently lost — coverage/behavior sagged
unnoticed. Check the number of logical checks before/after.
- An extracted assert helper got weaker: the shared helper checks less than
the original copies checked separately.
- A fixture scope change broke isolation: you moved a fixture from function
to module/session for speed — and got state leakage/flakiness.
- You deleted E2E but the logic did not go down — coverage is formally the
same by lines, but no one checks the end-to-end scenario anymore.
- You removed a "duplicate" test that actually checked a different case —
outwardly similar, semantically distinct.
- Refactoring under an unstable suite: if the tests are already flaky,
"before" and "after" are not comparable — stabilize first.
- Replacing a mock with a real object dragged the network/DB into the test
— it became "more honest" but slower/less stable; watch the boundary.
- Snapshot tests: a mass update of snapshots "so it goes green" may cement
broken behavior as the reference — update consciously.
- You changed the naming/file structure — and broke the runner's test
discovery (name pattern, discovery).
- A shared builder with defaults hid important differences in the inputs —
tests came to look the same where the difference is essential.
- Loss of a comment that explained a non-obvious expected result — while
rewriting, the knowledge of why exactly this value is expected disappeared.
DEFINITION OF DONE (DoD)
- The before baseline metrics are taken (test/line count, run time, line and
branch coverage) on a green suite.
- The eliminated anti-patterns are listed with file:line and the fix method.
- WHAT is checked is preserved: coverage (lines AND branches) is not below
baseline; the number of logical checks did not decrease covertly (deliberate
deletions of dead tests — as a separate item).
- The whole suite is run after refactoring and is green; the key tests still
fail when the product is genuinely broken (checked with a mutation mindset /
mutation testing).
- The after metrics are taken and compared with before (fewer
duplicates/lines, faster run, coverage not dropped).
- The refactoring is in the project's idioms; no scope creep was introduced
(new functionality/product bug fixes are broken out separately).
REPORT FORMAT
- One-line summary: the suite is refactored — N anti-patterns eliminated,
duplicates/lines/run time reduced, coverage preserved (X% lines / Y branches
→ not below).
- SCOPE — which tests were refactored and how the perimeter was
determined; what was left out of the perimeter.
- Test stack and coverage tool — what was detected and by which commands
it was measured/run.
- Before/after metrics — a table: number of tests, lines of test code,
(approximate) number of duplicates, run time, line coverage, branch
coverage.
- What was changed and why — a list of edits: file:line, anti-pattern
class, what was done, how the behavior invariant was preserved.
- Proof that behavior was preserved — the "after" run is green (output),
coverage did not drop (numbers), the result of the mutation-mindset/mutation
testing check on the key tests.
- Deliberate deletions — which dead/duplicate/always-green tests were
deleted and why this is not a loss of coverage.
- Broken out separately (scope creep, not done here) — product bugs found,
large coverage gaps (→ unit-coverage-gap), instability (→ flaky-test-triage).
- What could not be verified — limitations (no environment for some
integration/E2E, mutation testing not set up, etc.).
EXECUTION (practical instructions)
- YOURSELF, in the main thread, perform the SCOPE block — determine the suite
to refactor from
$ARGUMENTS/context. Do not delegate: a subagent does not
see the dialog context. Record the SCOPE.
- YOURSELF detect the test stack and take the before baseline metrics on a
green run — this is the invariant's baseline.
- Take an inventory of anti-patterns across the SCOPE. If the suite is large
and the Agent tool is available, split it into independent zones (by
file/directory) and launch a subagent per zone. Give each: the specific
paths, the detected test stack and the run/coverage commands, the relevant
sections of this skill (the anti-pattern catalog, edge cases, DoD — the
subagent does not see the file itself) and the requirement: refactor in
small steps, run the suite between steps, return the "before/after" metrics
and confirmation that coverage did not drop.
- Refactor one problem class at a time, running the suite between changes.
- When done, run the whole SCOPE suite in full, re-measure coverage, compare
with the baseline metrics.
- Consolidate into a report per the format above. Store the inventory and
metrics in a file, not only in context.
This is an authoring skill: edit the tests so as to preserve the checked
behavior and coverage, and make the tests readable, fast, and robust in the
project's idioms. If the refactoring uncovered a real product bug — do not
"paper over" it by tuning the test, break it out as a separate item.
1---2name: en-73description: Test refactoring without losing coverage4---5# Test refactoring without losing coverage67You are an engineer bringing a test suite into shape. Bad tests are technical8debt: duplicates make changes expensive, brittle asserts break on harmless9edits, slow E2E tests drag down CI, over-mocking checks the mocks instead of10behavior. Your job is to improve the structure, readability, speed, and11robustness of the tests, **without changing WHAT they check** and without12losing coverage.1314The main invariant of refactoring: the observable behavior of the suite is15unchanged. Before and after — the whole suite is run, coverage (lines AND16branches) does not drop, and the tests still fail when the product code is17genuinely broken. The discipline is evidence over assertion: improvements are18confirmed by before/after metrics (test/line count, duplicates, run time,19coverage) and by the run itself, not by a feeling that "it got cleaner".2021Work in the project's conventions: first detect the test stack, and refactor in22its idioms (its way of parametrizing, of fixtures, of helpers). If the suite is23large, split it into zones and delegate to subagents via the Agent tool.2425## INPUT / SCOPE (how to determine the perimeter)2627Perimeter: `$ARGUMENTS`2829The input may arrive in one of several forms:3031- **A. CODE: a test file / directory / suite / branch / diff** — the perimeter32 = the given test files + their shared fixtures/helpers/factories/base classes33 (refactoring them affects all consumers) + the product code that these tests34 cover (needed so as not to lose coverage and to understand the contract). The35 perimeter is ALWAYS wider than the literal input: editing a shared fixture36 affects all tests that use it — include them.37- **B. A DOCUMENT / test guideline** (.md/.txt) — if the project's test38 standard is given, extract its rules (naming, structure, what to mock) and39 bring the existing tests into line with them; a divergence of the tests from40 the standard is the target of the refactoring.41- **C. A TRACKER ISSUE** (ID/link) — fetch the text via an available42 integration (MCP, if connected; otherwise ask the user). Find the mentioned43 tests and related commits (`git log --all --grep=<ID>`).4445If it is unclear which tests to refactor, stop and clarify; do not rewrite the46whole suite at random. Record the SCOPE at the start of the report.4748## KEY PRINCIPLE: REFACTORING DOES NOT CHANGE WHAT IS CHECKED49501. **Behavior invariant.** Refactoring changes the form of a test, not its51 subject. If after the "refactoring" the test checks something else (or stops52 checking), that is not refactoring — it is a coverage regression.532. **Safety net — a run before.** Before touching the tests, run the whole54 suite and record baseline metrics (how many tests, are they green, time,55 coverage). Without a baseline you cannot prove behavior was preserved.563. **Coverage must not drop.** Measure coverage before and after. Especially57 dangerous: when merging duplicates into a parametrization or extracting58 asserts into a helper, accidentally dropping a case or weakening a check.594. **The test must still catch a break.** After refactoring, check with a60 mutation mindset (or mutation testing, if available): break the product code61 — the test must fail. "Green after refactoring" ≠ "still meaningful".625. **Small steps, with a run between.** Do not rewrite a file in one sweep.63 Refactor one anti-pattern at a time, running the suite between steps — that64 way a regression is localized immediately.656. **Do not drag in scope creep.** Do not add new functionality to the tests66 along the way, and do not fix product bugs you find inside the refactoring —67 break those out into a separate item/task (for adding missing tests there is68 the unit-coverage-gap skill).6970## METHODOLOGY (the pipeline)71721. **Detect the test stack** from the repository (pytest / jest / vitest / go73 test / JUnit / RSpec / PHPUnit …) and its idioms: how the project74 parametrizes, where it keeps fixtures/factories/helpers, what the naming is,75 what the coverage tool is.762. **Measure the before metrics**: number of tests, lines of test code, run77 time of the whole suite, coverage (lines and branches). Run the suite — it78 must be green (if it is already red/flaky, that is a separate task;79 refactoring on top of instability is not allowed — stabilize first or flag80 it).813. **Take an inventory of anti-patterns** (see the catalog below): walk the82 SCOPE tests, marking file:line and the problem class. Rate each by the83 benefit/risk ratio.844. **Refactor one problem class at a time**, in small steps, running the suite85 between changes. Preserve WHAT is checked.865. **Verify the invariant**: re-run the whole suite (green), re-measure coverage87 (not below baseline), check with a mutation mindset that the key tests still88 fail when the product is broken.896. **Measure the after metrics** and compare with the baseline.9091## CATALOG OF ANTI-PATTERNS AND HOW TO FIX THEM92931. **Duplication (copy-paste)**94 - Symptom: the same setup/sequence of actions/asserts repeats across many95 tests; a contract change requires manual edits in a dozen places.96 - Fix: extract the common setup into a **fixture/factory/builder**, the97 repeated checks into an **assert helper**, a family of "input→expectation"98 into a **parametrization** (`@pytest.mark.parametrize`, `test.each`,99 table-driven). Do NOT overdo it: excessive abstraction (DRY at any cost)100 makes a test unreadable — a test must stay understandable locally.1012. **Brittle asserts / locators**102 - Symptom: an assert on the whole object/whole string/exact JSON, breaks on103 an irrelevant field; UI locators by index/full XPath/text; comparison104 against an exact timestamp/UUID.105 - Fix: assert the **relevant** fields/invariants, not everything at once; use106 robust locators (role/`data-testid`, not a brittle path); for generated107 values check the format/presence, not a literal match. Do not weaken it108 into meaninglessness — the assert must remain a check.1093. **Several unrelated checks in one test**110 - Symptom: one test checks create, update, and delete all at once; the first111 failed assert hides the rest; it is unclear what exactly broke.112 - Fix: **split** into separate tests, one behavior each (one logical113 assert-concept per test). Keeping related checks of a single result114 together is acceptable.1154. **Order dependence / shared state**116 - Symptom: the test relies on state left behind by a neighbor; fails under117 order randomization.118 - Fix: **isolate** — fresh state per test (a fixture with cleanup, a119 transaction with rollback, a reset of mocks/cache in teardown). Make the120 tests independent (verify with randomization). (If this shows up as121 instability — see the flaky-test-triage skill.)1225. **Slow tests**123 - Symptom: the test hits the real network/DB/FS, sleeps a fixed sleep,124 spins up a heavy environment just to check pure logic.125 - Fix: **mock the I/O** at the boundary; replace `sleep` with an explicit126 wait; drop the check to the right level of the pyramid (see item 6); reuse127 expensive fixtures with the right scope (session/module) where it is safe.128 Measure the time before/after.1296. **Redundant E2E where a unit would do (pyramid imbalance)**130 - Symptom: a business rule/validation/branch is checked by a heavy E2E test131 through the whole stack, though it is pure logic; dozens of slow E2E tests132 duplicate what a fast unit test would cover.133 - Fix: **rebalance the pyramid** — move the logic check to the134 unit/integration level, keep E2E only for end-to-end user scenarios135 (smoke/critical path). Do not delete E2E without making sure the logic is136 covered below (otherwise coverage is lost).1377. **Over-mocking (the test checks mocks, not behavior)**138 - Symptom: so much is mocked that the test only checks that the mocks were139 called with the arguments it set itself (a tautology); rewriting the140 implementation breaks the test though behavior did not change.141 - Fix: mock only the **external boundaries** (network/DB/time/FS), not the142 internal logic of the module under test; check the observable143 **result/effect**, not the fact that internal methods were called. Where144 appropriate, replace a mock with a real lightweight object/fake.1458. **Unclear names and structure**146 - Symptom: `test_1`, `test_it_works`; it is unclear what the scenario is;147 everything is dumped together with no separation of setup/action/check.148 - Fix: **descriptive names** (what is expected under what conditions:149 `returns_403_if_other_company`); an **Arrange-Act-Assert**150 (Given-When-Then) structure with visual separation. The test name = its151 specification.1529. **Magic numbers / data**153 - Symptom: `assert result == 42`, `user_id=7` without explanation, a "magic"154 literal whose meaning only the author knows.155 - Fix: named constants/fixtures with meaningful names; explain the origin of156 the expected value (a comment/name) so that an edit does not become157 guesswork.15810. **No negative cases**159 - Symptom: tests only for the "happy path"; errors/boundaries/invalid input160 are not checked.161 - Fix: within the refactoring you may **fill in** obviously missing negative162 cases next to the existing ones (a boundary, an exception, invalid input),163 but large coverage growth is already unit-coverage-gap; do not turn the164 refactoring into writing a new suite.16511. **Dead / commented-out / always-green tests**166 - Symptom: `skip`/`xfail` without a reason, commented-out tests, a test167 without asserts, a test that cannot fail.168 - Fix: delete the dead ones (recording it in the report) or fix/uncomment169 them with a meaningful assert; an always-green test either strengthen or170 delete.171172## EDGE CASES THAT ARE OFTEN MISSED173174- **Parametrization swallowed a case**: while collapsing duplicates into a175 table, one input or one assert was silently lost — coverage/behavior sagged176 unnoticed. Check the number of logical checks before/after.177- **An extracted assert helper got weaker**: the shared helper checks less than178 the original copies checked separately.179- **A fixture scope change broke isolation**: you moved a fixture from function180 to module/session for speed — and got state leakage/flakiness.181- **You deleted E2E but the logic did not go down** — coverage is formally the182 same by lines, but no one checks the end-to-end scenario anymore.183- **You removed a "duplicate" test that actually checked a different case** —184 outwardly similar, semantically distinct.185- **Refactoring under an unstable suite**: if the tests are already flaky,186 "before" and "after" are not comparable — stabilize first.187- **Replacing a mock with a real object dragged the network/DB into the test**188 — it became "more honest" but slower/less stable; watch the boundary.189- **Snapshot tests**: a mass update of snapshots "so it goes green" may cement190 broken behavior as the reference — update consciously.191- **You changed the naming/file structure — and broke the runner's test192 discovery** (name pattern, discovery).193- **A shared builder with defaults hid important differences in the inputs** —194 tests came to look the same where the difference is essential.195- **Loss of a comment that explained a non-obvious expected result** — while196 rewriting, the knowledge of why exactly this value is expected disappeared.197198## DEFINITION OF DONE (DoD)199200- The before baseline metrics are taken (test/line count, run time, line and201 branch coverage) on a green suite.202- The eliminated anti-patterns are listed with file:line and the fix method.203- WHAT is checked is preserved: coverage (lines AND branches) is not below204 baseline; the number of logical checks did not decrease covertly (deliberate205 deletions of dead tests — as a separate item).206- The whole suite is run after refactoring and is green; the key tests still207 fail when the product is genuinely broken (checked with a mutation mindset /208 mutation testing).209- The after metrics are taken and compared with before (fewer210 duplicates/lines, faster run, coverage not dropped).211- The refactoring is in the project's idioms; no scope creep was introduced212 (new functionality/product bug fixes are broken out separately).213214## REPORT FORMAT2152161. **One-line summary**: the suite is refactored — N anti-patterns eliminated,217 duplicates/lines/run time reduced, coverage preserved (X% lines / Y branches218 → not below).2192. **SCOPE** — which tests were refactored and how the perimeter was220 determined; what was left out of the perimeter.2213. **Test stack and coverage tool** — what was detected and by which commands222 it was measured/run.2234. **Before/after metrics** — a table: number of tests, lines of test code,224 (approximate) number of duplicates, run time, line coverage, branch225 coverage.2265. **What was changed and why** — a list of edits: file:line, anti-pattern227 class, what was done, how the behavior invariant was preserved.2286. **Proof that behavior was preserved** — the "after" run is green (output),229 coverage did not drop (numbers), the result of the mutation-mindset/mutation230 testing check on the key tests.2317. **Deliberate deletions** — which dead/duplicate/always-green tests were232 deleted and why this is not a loss of coverage.2338. **Broken out separately (scope creep, not done here)** — product bugs found,234 large coverage gaps (→ unit-coverage-gap), instability (→ flaky-test-triage).2359. **What could not be verified** — limitations (no environment for some236 integration/E2E, mutation testing not set up, etc.).237238## EXECUTION (practical instructions)2392401. YOURSELF, in the main thread, perform the SCOPE block — determine the suite241 to refactor from `$ARGUMENTS`/context. Do not delegate: a subagent does not242 see the dialog context. Record the SCOPE.2432. YOURSELF detect the test stack and take the before baseline metrics on a244 green run — this is the invariant's baseline.2453. Take an inventory of anti-patterns across the SCOPE. If the suite is large246 and the Agent tool is available, split it into independent zones (by247 file/directory) and launch a subagent per zone. Give each: the specific248 paths, the detected test stack and the run/coverage commands, the relevant249 sections of this skill (the anti-pattern catalog, edge cases, DoD — the250 subagent does not see the file itself) and the requirement: refactor in251 small steps, run the suite between steps, return the "before/after" metrics252 and confirmation that coverage did not drop.2534. Refactor one problem class at a time, running the suite between changes.2545. When done, run the whole SCOPE suite in full, re-measure coverage, compare255 with the baseline metrics.2566. Consolidate into a report per the format above. Store the inventory and257 metrics in a file, not only in context.258259This is an authoring skill: edit the tests so as to preserve the checked260behavior and coverage, and make the tests readable, fast, and robust in the261project's idioms. If the refactoring uncovered a real product bug — do not262"paper over" it by tuning the test, break it out as a separate item.