Uses an existing test suite as the behavioral oracle during a migration, tracking which tests pass at each step and localizing regressions to specific migration changes. Use when porting or refactoring code that has tests, when the user wants to migrate incrementally with a safety net, or when a migration broke something and you need to find which step did it.
Install with Tessl CLI
npx tessl i github:santosomar/general-secure-coding-agent-skills --skill test-guided-migration-assistant97
Quality
96%
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
The test suite is a specification in executable form. During a migration, it's the oracle: if the tests pass, the migration preserved behavior (as far as the tests know).
At every step of the migration: tests pass. If a step breaks a test, either:
Never proceed with a red test. Red accumulates.
Before migrating, know what you're working with:
| Metric | Command | Threshold |
|---|---|---|
| Line coverage | pytest --cov / jacoco / etc | > 70% for comfort |
| Branch coverage | Same tools, --cov-branch | > 60% for comfort |
| Test speed | How long does the full suite take? | < 5 min → run after every step. > 30 min → you'll need prioritization (→ test-suite-prioritizer) |
| Flakes | Run the suite 3× — do the same tests pass each time? | Zero flakes, or quarantine them |
If coverage is low: the tests are a weak oracle. Migration steps that touch uncovered code are flying blind. Either write characterization tests for the gaps first, or flag those steps as high-risk.
Before touching anything:
@pytest.mark.skip(reason="pre-existing — issue #123")). Start green.Pick migration steps small enough that at most a handful of tests could plausibly be affected. One function, one class, one config block.
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Step N │────►│ Run tests│────►│ Green? │
│ (small) │ │ (fast │ │ │ │
└──────────┘ │ subset) │ │ Y │ N │
└──────────┘ └──┬─┴──┬──┘
│ │
┌────────▼┐ ┌▼────────────────┐
│ Commit │ │ Bisect: which │
│ Step N+1│ │ part of step N? │
└─────────┘ └─────────────────┘Fast subset: don't run the whole suite after every step. Run the tests that cover the code you touched (pytest --testmon, or manually: pytest tests/test_foo.py if you changed foo.py). Full suite at milestones.
Don't guess. Localize:
git bisect finds the bad step mechanically.Suite: 340 tests, 78% line coverage, 4 min full run.
Baseline: 337 pass, 3 fail (pre-existing — skipped with issue refs). Green.
Step 1: __future__ imports everywhere. → 337 pass. Green, commit.
Step 2: dict.iteritems() → .items(). → 337 pass. Green, commit.
Step 3: / → // for integer division (12 sites). → 331 pass, 6 fail.
Bisect within step 3: revert 6 sites, keep 6 → still fails. Revert 3 more → passes. Narrowed to 3 sites. One at a time:
pagination.py:42 → total / per_page was float in Py2 for total=10, per_page=3 → 3.33, and the code did ceil() on it. Changing to // gives 3, not 3.33, and ceil(3) is 3 not 4. Migration error. Should be total / per_page (true division — the Py2 code was already using float division via from __future__ import division, which I missed). Revert this site.Lesson: the test caught a real behavior regression. The mechanical / → // rule was wrong for this site because of a __future__ import I hadn't noticed.
Test that will break legitimately:
def test_cache_uses_lru(self):
cache = Cache()
cache.get("a"); cache.get("b"); cache.get("a")
assert cache._order == ["b", "a"] # ← asserting internal list orderMigrating Cache to use OrderedDict changes _order from a list to dict keys. Test fails. But the behavior (LRU eviction order) is preserved.
Fix the test first, in its own commit:
def test_cache_evicts_lru(self):
cache = Cache(maxsize=2)
cache.get("a"); cache.get("b"); cache.get("a")
cache.get("c") # should evict "b", not "a" — "a" was used more recently
assert "a" in cache and "c" in cache and "b" not in cacheNow it tests the behavior. Commit that. Then do the migration step — it passes.
## Baseline
Tests: <N> passing, <M> skipped (pre-existing: <issues>)
Coverage: <line%> / <branch%>
Uncovered risk areas: <modules with low coverage>
## Migration log
| Step | Change | Tests run | Result | Commit |
| ---- | ------ | --------- | ------ | ------ |
| 1 | <what> | <subset> | ✓ | <sha> |
| 2 | <what> | <subset> | ✗ → <test> | — |
| 2a | <localized fix> | ... | ✓ | <sha> |
## Tests modified (before-migration commits)
| Test | Why it was implementation-coupled | New assertion |
| ---- | --------------------------------- | ------------- |
## Final
Tests: <N> passing, <M> skipped
Behavior regressions found and fixed: <count>47d56bb
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.