diff --git a/tests/scanners/token-hotspots.test.mjs b/tests/scanners/token-hotspots.test.mjs index 4c29eda..4b19523 100644 --- a/tests/scanners/token-hotspots.test.mjs +++ b/tests/scanners/token-hotspots.test.mjs @@ -5,6 +5,7 @@ import { fileURLToPath } from 'node:url'; import { resetCounter } from '../../scanners/lib/output.mjs'; import { scan } from '../../scanners/token-hotspots.mjs'; import { discoverConfigFiles } from '../../scanners/lib/file-discovery.mjs'; +import { withHermeticHome } from '../helpers/hermetic-home.mjs'; const __dirname = fileURLToPath(new URL('.', import.meta.url)); const FIXTURES = resolve(__dirname, '../fixtures'); @@ -17,7 +18,16 @@ async function runScanner(fixtureName) { resetCounter(); const path = resolve(FIXTURES, fixtureName); const discovery = await fixtureDiscovery(fixtureName); - return scan(path, discovery); + // Hermetic HOME: scan() calls readActiveConfig, which resolves the user + // ~/.claude/CLAUDE.md cascade + plugins/MCP from process.env.HOME. Without + // this override the developer's real ~/.claude leaks into every fixture + // result — small-cascade tips past the 10k-token threshold and sonnet-era + // picks up ambient MCP findings — making assertions machine-dependent + // (green on a clean HOME, red on a populated one). Mirrors the OST test. + // NOTE: residual coupling — the cascade's ancestor walk still climbs from + // the fixture path through the real repo CLAUDE.md (an ancestor of tests/), + // but that contribution is deterministic per-checkout, not user-dependent. + return withHermeticHome(() => scan(path, discovery)); } describe('TOK scanner — healthy-project', () => {