From 45efed3dbfd8c36c23ef7297cc7319dae45876ad Mon Sep 17 00:00:00 2001 From: Kjell Tore Guttormsen Date: Wed, 24 Jun 2026 10:04:47 +0200 Subject: [PATCH] fix(tok): live-session caveat in Pattern H stale-cache recommendation Pattern H ("Stale plugin-cache versions") recommended deleting stale version dirs under ~/.claude/plugins/cache with no warning that a currently-running session may still hold one of those versions for its whole lifetime. "Stale" is judged against installed_plugins.json (what NEW sessions load), so the recommendation could reproduce the exact footgun that broke a live session during C4: deleting the dir pulls the files out from under the running session, which then breaks and must /exit + restart. Extend the recommendation text with the live-session caveat. No new finding ID/scanner, no token counts changed (recommendation string only) -> --json/--raw stay byte-stable, frozen v5.0.0 + SC-5 + default-output snapshots untouched. +1 test (1297). Co-Authored-By: Claude Opus 4.8 (1M context) --- scanners/token-hotspots.mjs | 9 +++++++-- tests/scanners/token-hotspots.test.mjs | 10 ++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/scanners/token-hotspots.mjs b/scanners/token-hotspots.mjs index 1dc9eae..87efcbe 100644 --- a/scanners/token-hotspots.mjs +++ b/scanners/token-hotspots.mjs @@ -579,8 +579,13 @@ export async function scan(targetPath, discovery) { '(installed_plugins.json points at newer versions)', recommendation: 'Delete the listed stale version directories under ~/.claude/plugins/cache to reclaim ' + - 'disk (reinstall/prune via the plugin manager, or remove the dirs directly). Re-run ' + - 'with --no-exclude-cache to include cached versions in the token/conflict scan.', + 'disk (reinstall/prune via the plugin manager, or remove the dirs directly). ' + + 'Caution: do NOT delete a version a running session is still using — "stale" is judged ' + + 'against installed_plugins.json (what NEW sessions load), but an already-running session ' + + 'can hold an older version for its whole lifetime. Removing it mid-session pulls the files ' + + 'out from under that session, which then breaks and must /exit + restart to pick up the ' + + 'active version. Run with --no-exclude-cache to include cached versions in the ' + + 'token/conflict scan.', category: 'plugin-cache-hygiene', })); } diff --git a/tests/scanners/token-hotspots.test.mjs b/tests/scanners/token-hotspots.test.mjs index 039103b..bb42ed9 100644 --- a/tests/scanners/token-hotspots.test.mjs +++ b/tests/scanners/token-hotspots.test.mjs @@ -383,6 +383,16 @@ describe('TOK scanner — H stale plugin-cache versions (v5.9 B3)', () => { assert.match(f.evidence, /mkt\/config-audit\/5\.6\.0/); }); + it('warns against deleting a version a running session still uses (/exit caveat)', async () => { + resetCounter(); + const result = await withHermeticHome(() => scan('/tmp/x', staleDiscovery)); + const f = result.findings.find(x => /stale plugin-cache/i.test(x.title || '')); + assert.match(f.recommendation, /running session|active session/i, + 'recommendation must caution about sessions still using a version'); + assert.match(f.recommendation, /\/exit/, + 'recommendation must tell affected sessions to /exit + restart'); + }); + it('does NOT fire when there are no stale versions', async () => { resetCounter(); const result = await withHermeticHome(() => scan('/tmp/x', { files: [], staleCacheVersions: [] }));