1- import { test } from "node:test" ;
1+ import { after , test } from "node:test" ;
22import assert from "node:assert/strict" ;
33import { mkdtemp , readFile , rm , stat } from "node:fs/promises" ;
44import { tmpdir } from "node:os" ;
@@ -12,6 +12,25 @@ import ext, {
1212 runMicrocompactStability ,
1313} from "../proxy/extensions/microcompact-stability.mjs" ;
1414
15+ // EVERY SCRATCH DIR, EVEN THE RUNS THAT FAIL. Thirteen cases remove theirs on the
16+ // last line of the test body, so an assertion that throws skips it, and the
17+ // fourteenth removes nothing at all — that one leaked on the green path too.
18+ // Those calls stay as they are, since they free disk during a long run; this
19+ // collects what they miss.
20+ const scratch = [ ] ;
21+ async function mcTemp ( ) {
22+ const d = await mkdtemp ( join ( tmpdir ( ) , "mc-" ) ) ;
23+ scratch . push ( d ) ;
24+ return d ;
25+ }
26+ after ( async ( ) => {
27+ for ( const d of scratch ) {
28+ // Per dir, so one refused removal cannot strand the rest. `force` already
29+ // swallows a missing dir; this is for EPERM and EBUSY.
30+ try { await rm ( d , { recursive : true , force : true } ) ; } catch { /* see above */ }
31+ }
32+ } ) ;
33+
1534// --- Fixture helpers ---
1635
1736const SENTINEL_BARE = "[Old tool result content cleared]" ;
@@ -149,7 +168,7 @@ test("4. unrelated truncation message → no match in either mode (rejected from
149168// --- Mode B ---
150169
151170test ( "4a. sentinel + trailing text → Mode B match, body NOT mutated, prefix_64 only in dump" , async ( ) => {
152- const dir = await mkdtemp ( join ( tmpdir ( ) , "mc-" ) ) ;
171+ const dir = await mcTemp ( ) ;
153172 const dumpPath = join ( dir , "dump.jsonl" ) ;
154173 const body = makeBody ( [
155174 assistantMsg ( "t1" ) ,
@@ -182,7 +201,7 @@ test("4a. sentinel + trailing text → Mode B match, body NOT mutated, prefix_64
182201
183202test ( "4b. long trailing → prefix_64 captures only first 64 chars, byte_length reports full size" , async ( ) => {
184203 const long = SENTINEL_TS + " " + "x" . repeat ( 200 ) ;
185- const dir = await mkdtemp ( join ( tmpdir ( ) , "mc-" ) ) ;
204+ const dir = await mcTemp ( ) ;
186205 const dumpPath = join ( dir , "dump.jsonl" ) ;
187206 const body = makeBody ( [
188207 assistantMsg ( "t1" ) ,
@@ -201,7 +220,7 @@ test("4b. long trailing → prefix_64 captures only first 64 chars, byte_length
201220} ) ;
202221
203222test ( "4c. CACHE_FIX_MICROCOMPACT_REDACT_LEN=0 → prefix_64 absent" , async ( ) => {
204- const dir = await mkdtemp ( join ( tmpdir ( ) , "mc-" ) ) ;
223+ const dir = await mcTemp ( ) ;
205224 const dumpPath = join ( dir , "dump.jsonl" ) ;
206225 const body = makeBody ( [
207226 assistantMsg ( "t1" ) ,
@@ -237,7 +256,7 @@ test("5a. CACHE_FIX_MICROCOMPACT_SENTINEL_PATTERN_1 adds custom Mode A pattern",
237256} ) ;
238257
239258test ( "5b. custom Mode A regex + custom Mode B prefix → exact match goes to exact_matches" , async ( ) => {
240- const dir = await mkdtemp ( join ( tmpdir ( ) , "mc-" ) ) ;
259+ const dir = await mcTemp ( ) ;
241260 const dumpPath = join ( dir , "dump.jsonl" ) ;
242261 // Exact match against a custom regex from a sentinel family that does NOT
243262 // share the built-in prefix. Verifies exact-match path for custom families.
@@ -269,7 +288,7 @@ test("5c. custom Mode B prefix → variant-of-custom-family captured redacted in
269288 // EXACTLY normalizes, but its prefix-only variant must also be captured
270289 // in Mode B (redacted) — not silently dropped just because the variant
271290 // doesn't share the built-in `[Old tool result content cleared` prefix.
272- const dir = await mkdtemp ( join ( tmpdir ( ) , "mc-" ) ) ;
291+ const dir = await mcTemp ( ) ;
273292 const dumpPath = join ( dir , "dump.jsonl" ) ;
274293 const text = "[CC microcompact rev2 at 2026-04-30T17:00:00Z] (with trailing content)" ;
275294 const body = makeBody ( [
@@ -352,7 +371,7 @@ test("8. mixed array (text + image) — only the text matches → image untouche
352371// --- Diagnostic dump ---
353372
354373test ( "9. dump set + sentinel match → JSONL line; session_id is hashed (no plaintext)" , async ( ) => {
355- const dir = await mkdtemp ( join ( tmpdir ( ) , "mc-" ) ) ;
374+ const dir = await mcTemp ( ) ;
356375 const dumpPath = join ( dir , "dump.jsonl" ) ;
357376 const body = makeBody ( [
358377 assistantMsg ( "t1" ) ,
@@ -373,7 +392,7 @@ test("9. dump set + sentinel match → JSONL line; session_id is hashed (no plai
373392} ) ;
374393
375394test ( "10. dump unset → no fs activity" , async ( ) => {
376- const dir = await mkdtemp ( join ( tmpdir ( ) , "mc-" ) ) ;
395+ const dir = await mcTemp ( ) ;
377396 const dumpPath = join ( dir , "dump.jsonl" ) ;
378397 const body = makeBody ( [
379398 assistantMsg ( "t1" ) ,
@@ -395,7 +414,7 @@ test("10. dump unset → no fs activity", async () => {
395414} ) ;
396415
397416test ( "11. multiple matches in one request → ONE JSONL line with arrays split A/B" , async ( ) => {
398- const dir = await mkdtemp ( join ( tmpdir ( ) , "mc-" ) ) ;
417+ const dir = await mcTemp ( ) ;
399418 const dumpPath = join ( dir , "dump.jsonl" ) ;
400419 const body = makeBody ( [
401420 assistantMsg ( "t1" ) ,
@@ -455,7 +474,7 @@ test("13. normalize on + custom canonical → matched sentinel becomes the custo
455474} ) ;
456475
457476test ( "14. normalize disabled, dump enabled → matches recorded in dump but body NOT mutated" , async ( ) => {
458- const dir = await mkdtemp ( join ( tmpdir ( ) , "mc-" ) ) ;
477+ const dir = await mcTemp ( ) ;
459478 const dumpPath = join ( dir , "dump.jsonl" ) ;
460479 const body = makeBody ( [
461480 assistantMsg ( "t1" ) ,
@@ -500,7 +519,7 @@ test("15. two requests with different timestamps → byte-identical bodies after
500519// --- Activation ---
501520
502521test ( "16. both gates unset → extension fires but exits early; no telemetry, no mutation, no fs" , async ( ) => {
503- const dir = await mkdtemp ( join ( tmpdir ( ) , "mc-" ) ) ;
522+ const dir = await mcTemp ( ) ;
504523 const dumpPath = join ( dir , "dump.jsonl" ) ;
505524 const body = makeBody ( [
506525 assistantMsg ( "t1" ) ,
@@ -526,7 +545,7 @@ test("16. both gates unset → extension fires but exits early; no telemetry, no
526545} ) ;
527546
528547test ( "17. only diagnostic enabled → telemetry present, JSONL written, no mutation" , async ( ) => {
529- const dir = await mkdtemp ( join ( tmpdir ( ) , "mc-" ) ) ;
548+ const dir = await mcTemp ( ) ;
530549 const dumpPath = join ( dir , "dump.jsonl" ) ;
531550 const body = makeBody ( [
532551 assistantMsg ( "t1" ) ,
@@ -548,7 +567,7 @@ test("17. only diagnostic enabled → telemetry present, JSONL written, no mutat
548567} ) ;
549568
550569test ( "18. only normalize enabled → telemetry present, mutation happens, no JSONL" , async ( ) => {
551- const dir = await mkdtemp ( join ( tmpdir ( ) , "mc-" ) ) ;
570+ const dir = await mcTemp ( ) ;
552571 const dumpPath = join ( dir , "dump.jsonl" ) ;
553572 const body = makeBody ( [
554573 assistantMsg ( "t1" ) ,
@@ -568,7 +587,7 @@ test("18. only normalize enabled → telemetry present, mutation happens, no JSO
568587} ) ;
569588
570589test ( "19. both enabled → telemetry, mutation, AND JSONL all happen; raw text captured pre-normalization" , async ( ) => {
571- const dir = await mkdtemp ( join ( tmpdir ( ) , "mc-" ) ) ;
590+ const dir = await mcTemp ( ) ;
572591 const dumpPath = join ( dir , "dump.jsonl" ) ;
573592 const body = makeBody ( [
574593 assistantMsg ( "t1" ) ,
@@ -598,7 +617,7 @@ test("19. both enabled → telemetry, mutation, AND JSONL all happen; raw text c
598617} ) ;
599618
600619test ( "19a. CACHE_FIX_DUMP_MICROCOMPACT_INCLUDE_NORMALIZED=1 → adds normalized_text alongside raw sentinel_text" , async ( ) => {
601- const dir = await mkdtemp ( join ( tmpdir ( ) , "mc-" ) ) ;
620+ const dir = await mcTemp ( ) ;
602621 const dumpPath = join ( dir , "dump.jsonl" ) ;
603622 const body = makeBody ( [
604623 assistantMsg ( "t1" ) ,
0 commit comments