Use when writing or debugging tests that pass alone but fail (or mutate the repo) in a full-suite run — enforce per-test isolation and environment-aware gating so tests never share state or depend on excluded trees.
Scanned 9/11/2026
Install to Claude Code
npx -y skills add SkyyRoseLLC/DevSkyy --skill test-isolation --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Test Isolation?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/skyyrosellc-test-isolation)More formats (shields.io, HTML) on the badges page.
---
name: test-isolation
description: Use when writing or debugging tests that pass alone but fail (or mutate the repo) in a full-suite run — enforce per-test isolation and environment-aware gating so tests never share state or depend on excluded trees.
origin: SkyyRose
---
# Test Isolation
The most dangerous test in this codebase is not one that fails — it is one that passes
**only because of who ran before it**. A test that is green alone but red in the full
suite is not tested, it is lucky. Worse: a test that silently rewrites tracked files isn't
a test at all, it's an uncommitted mutation wearing a green checkmark. This is **bug-231**
(recurred ×4) — shared-state pollution surfacing only in full-suite runs — and **bug-257**
(today) — a `test_verify_drift` run that executed the collection-SOT builder IN-TREE and
silently rewrote tracked `wordpress-theme/.../collections/*/sot.json`.
> **Boot first:** read the canonical sources — `SOT.md` → `.wolf/anatomy.md` →
> `.wolf/cerebrum.md` → `.wolf/buglog.json` (grep `bug-231` and `bug-257` — the leak may
> already be logged) → `CLAUDE.md`. Do not fix an isolation bug from memory.
## When to Use
- A test passes with `pytest tests/test_x.py -v` but fails inside `pytest tests/ -v`.
- Any test that reads/writes `/tmp` directly, sets `os.environ[...]`, or touches a module-
level cache, singleton, or class attribute.
- Any test that reads `assets/`, `archive/`, `renders/`, or `screenshots/` — sparse
worktrees deliberately exclude these trees; see [[fail-closed-audit]] for why an absent
path must not silently mean "skip everywhere."
- Before trusting a green test that runs a generator/builder against real repo files —
pair with [[fail-closed-audit]]'s rule on never regenerating-then-verifying its own output.
- After any session where you edited the same test file more than twice to get it green.
## Method
1. **Per-test `tmp_path`, never a hardcoded path.** Use the `tmp_path` / `tmp_path_factory`
fixture for every file the test writes. A literal `/tmp/...` string is shared across
parallel test workers and across runs — that's the bug-231 signature.
2. **`monkeypatch.setenv` / `monkeypatch.delenv`, never `os.environ[...] = ...`.** Direct
environment mutation leaks into every test that runs after it in the same process;
`monkeypatch` reverts automatically at test teardown even on failure.
3. **Reset shared singletons and caches in a fixture, not by convention.** If a module
holds a cache, a connection pool, or a class-level registry, the fixture must reset it
on setup (and ideally teardown) — "the next test will probably reset it" is how bug-231
recurred four times.
4. **Sparse-aware skips must stay fail-closed.** A test that needs `assets/`, `archive/`,
`renders/`, or `screenshots/` may skip **only** when `git config core.sparseCheckout`
is `true` **and** the path is genuinely absent — use `tests/sparse_guard.py::requires_tree`
for this check. A full checkout or CI runner with a genuinely missing tree must still
**fail**, not skip. Skipping unconditionally on "path not found" hides real regressions
the moment someone runs the suite from a non-sparse clone. This is the fail-closed rule
from [[fail-closed-audit]] applied to test collection itself.
5. **Never write to the tracked tree from a test.** If a test exercises a builder/generator
that writes to a real repo path (e.g. `collections/*/sot.json`), redirect its output to
`tmp_path` via a fixture-injected output root or dependency override — do not let it run
against the live working tree, in-place, ever. bug-257 is what happens when this is
skipped: a "verify drift" test became a silent write.
## Loop until isolated
Bounded, like [[drive-to-green]] — never more than 5 turns, stop if the same result
repeats twice (that is guessing, not isolating):
```
1. Run the test ALONE (pytest tests/test_x.py::test_name -v) → read the result.
2. Run the FULL suite (pytest tests/ -v) → read the result for the same test.
3. Run `git status --short` after the full suite → must be empty. Non-empty = mutation.
4. If alone≠full-suite or git status is dirty → find the leak (env, cache, file, order
dependency) and fix it per Method above.
5. Repeat 1-3. Stop when alone == full-suite AND git status --short is clean.
```
## Verify from an authoritative source
The fix is only real if both runs are **observed**, never assumed:
- **Run the test both ways and READ both results** — don't infer full-suite behavior from
the isolated pass. `rtk proxy pytest` gives the true exit code; a bare `pytest` can
falsely report "no tests collected" on a broken collection.
- **Run twice** — a fix that isolates state should be deterministic; if the second run
differs from the first, the leak isn't fixed, it's relocated.
- **`git status --short` after the full suite must show zero tracked-file changes.** Any
diff — even a whitespace-only rewrite of a generated file — is a hard fail. This is the
check that would have caught bug-257 before it shipped.
- **Cite `file:line`** for the fixture or `monkeypatch` call that closed the leak; quote
the actual code, not a paraphrase.
## Adversarial pass
- **After** the fix: [[adversarial-verification]] — try to REFUTE "it's isolated now." Run
the suite in a different order (`pytest tests/ -p no:randomly` vs. shuffled), from a
non-sparse clone, and from a fresh `tmp_path` root. Default to "still leaking" until
independently proven otherwise.
## Guardrails · Handoff · Log
- Never hardcode `/tmp` or a literal path a test writes to — `tmp_path` only.
- Never mutate the real environment or the tracked working tree from a test — `monkeypatch`
and injected output roots only.
- Fail-open skip logic (a sparse-tree skip that also skips in full checkouts) is a
[[fail-closed-audit]] defect — audit it there, fix it here.
- A test-isolation fix that leaves the suite green only by accident → drive it properly
with [[drive-to-green]], then re-verify with this skill.
- Log every isolation leak or tree-mutation to `.wolf/buglog.json` under the `bug-231` (or
`bug-257`) lineage — bump `occurrences`, never duplicate — run
`scripts/wolf_recurring_sync.py`, and record the lesson via [[continuous-learning]].
- Handoff per `CROSS-PLUGIN.md`: isolation defects that trace to backend/service code go to
`skyyrose-core`; theme/build-output defects go to `skyyrose-design` — then **re-verify
here** before calling the suite closed.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!