Skip to content

Commit 3ba84fc

Browse files
codeslakeclaude
andcommitted
fix(test): keep the microcompact scratch dirs off /tmp when a case fails
Fourteen cases each made their own `mc-` dir. Thirteen removed it on the last line of the test body, so an assertion that threw skipped the removal; the fourteenth (case 11) never removed it at all, so that one leaked on the green path too. None of the fourteen was inside a try/finally — the file's three `finally` blocks belong to withEnv, silenceStderr and silenceStderrAsync, and restore env and stderr rather than remove anything. Measured on this host: 750 `mc-*` dirs in /tmp, the largest single leak this repo's suite produces. Reproduced two ways — a clean run of the parent leaves 1 dir behind (case 11), and one injected assertion failure leaves 2. After this change both are 0. Registering the dir at creation and collecting in after() puts the cleanup in one place instead of fourteen, and covers the paths that were missing rather than the thirteen that already worked. The eager `rm` calls stay: they free disk during a long run, and after() is idempotent with force. after() does not cover SIGINT, SIGKILL, or a throw at import time — measured. The first matters: Ctrl-C on a long suite still leaks. The last is vacuous here, since every mcTemp() call is inside a test body. test/proxy-wrapper.test.mjs already carries this shape; this is that pattern, not a new one. Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 78ca948 commit 3ba84fc

1 file changed

Lines changed: 31 additions & 15 deletions

File tree

test/proxy-microcompact-stability.test.mjs

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { test } from "node:test";
1+
import { after, test } from "node:test";
22
import assert from "node:assert/strict";
33
import { mkdtemp, readFile, rm, stat } from "node:fs/promises";
44
import { tmpdir } from "node:os";
@@ -12,6 +12,22 @@ import ext, {
1212
runMicrocompactStability,
1313
} from "../proxy/extensions/microcompact-stability.mjs";
1414

15+
// EVERY SCRATCH DIR, EVEN THE RUNS THAT FAIL. The per-case `rm` calls sit on the
16+
// last line of the test body, so an assertion that throws skips them. They stay
17+
// as they are — they free disk during a long run — and this collects what they
18+
// miss.
19+
const scratch = [];
20+
async function mcTemp() {
21+
const d = await mkdtemp(join(tmpdir(), "mc-"));
22+
scratch.push(d);
23+
return d;
24+
}
25+
after(async () => {
26+
for (const d of scratch) {
27+
try { await rm(d, { recursive: true, force: true }); } catch { /* already gone */ }
28+
}
29+
});
30+
1531
// --- Fixture helpers ---
1632

1733
const SENTINEL_BARE = "[Old tool result content cleared]";
@@ -149,7 +165,7 @@ test("4. unrelated truncation message → no match in either mode (rejected from
149165
// --- Mode B ---
150166

151167
test("4a. sentinel + trailing text → Mode B match, body NOT mutated, prefix_64 only in dump", async () => {
152-
const dir = await mkdtemp(join(tmpdir(), "mc-"));
168+
const dir = await mcTemp();
153169
const dumpPath = join(dir, "dump.jsonl");
154170
const body = makeBody([
155171
assistantMsg("t1"),
@@ -182,7 +198,7 @@ test("4a. sentinel + trailing text → Mode B match, body NOT mutated, prefix_64
182198

183199
test("4b. long trailing → prefix_64 captures only first 64 chars, byte_length reports full size", async () => {
184200
const long = SENTINEL_TS + " " + "x".repeat(200);
185-
const dir = await mkdtemp(join(tmpdir(), "mc-"));
201+
const dir = await mcTemp();
186202
const dumpPath = join(dir, "dump.jsonl");
187203
const body = makeBody([
188204
assistantMsg("t1"),
@@ -201,7 +217,7 @@ test("4b. long trailing → prefix_64 captures only first 64 chars, byte_length
201217
});
202218

203219
test("4c. CACHE_FIX_MICROCOMPACT_REDACT_LEN=0 → prefix_64 absent", async () => {
204-
const dir = await mkdtemp(join(tmpdir(), "mc-"));
220+
const dir = await mcTemp();
205221
const dumpPath = join(dir, "dump.jsonl");
206222
const body = makeBody([
207223
assistantMsg("t1"),
@@ -237,7 +253,7 @@ test("5a. CACHE_FIX_MICROCOMPACT_SENTINEL_PATTERN_1 adds custom Mode A pattern",
237253
});
238254

239255
test("5b. custom Mode A regex + custom Mode B prefix → exact match goes to exact_matches", async () => {
240-
const dir = await mkdtemp(join(tmpdir(), "mc-"));
256+
const dir = await mcTemp();
241257
const dumpPath = join(dir, "dump.jsonl");
242258
// Exact match against a custom regex from a sentinel family that does NOT
243259
// share the built-in prefix. Verifies exact-match path for custom families.
@@ -269,7 +285,7 @@ test("5c. custom Mode B prefix → variant-of-custom-family captured redacted in
269285
// EXACTLY normalizes, but its prefix-only variant must also be captured
270286
// in Mode B (redacted) — not silently dropped just because the variant
271287
// doesn't share the built-in `[Old tool result content cleared` prefix.
272-
const dir = await mkdtemp(join(tmpdir(), "mc-"));
288+
const dir = await mcTemp();
273289
const dumpPath = join(dir, "dump.jsonl");
274290
const text = "[CC microcompact rev2 at 2026-04-30T17:00:00Z] (with trailing content)";
275291
const body = makeBody([
@@ -352,7 +368,7 @@ test("8. mixed array (text + image) — only the text matches → image untouche
352368
// --- Diagnostic dump ---
353369

354370
test("9. dump set + sentinel match → JSONL line; session_id is hashed (no plaintext)", async () => {
355-
const dir = await mkdtemp(join(tmpdir(), "mc-"));
371+
const dir = await mcTemp();
356372
const dumpPath = join(dir, "dump.jsonl");
357373
const body = makeBody([
358374
assistantMsg("t1"),
@@ -373,7 +389,7 @@ test("9. dump set + sentinel match → JSONL line; session_id is hashed (no plai
373389
});
374390

375391
test("10. dump unset → no fs activity", async () => {
376-
const dir = await mkdtemp(join(tmpdir(), "mc-"));
392+
const dir = await mcTemp();
377393
const dumpPath = join(dir, "dump.jsonl");
378394
const body = makeBody([
379395
assistantMsg("t1"),
@@ -395,7 +411,7 @@ test("10. dump unset → no fs activity", async () => {
395411
});
396412

397413
test("11. multiple matches in one request → ONE JSONL line with arrays split A/B", async () => {
398-
const dir = await mkdtemp(join(tmpdir(), "mc-"));
414+
const dir = await mcTemp();
399415
const dumpPath = join(dir, "dump.jsonl");
400416
const body = makeBody([
401417
assistantMsg("t1"),
@@ -455,7 +471,7 @@ test("13. normalize on + custom canonical → matched sentinel becomes the custo
455471
});
456472

457473
test("14. normalize disabled, dump enabled → matches recorded in dump but body NOT mutated", async () => {
458-
const dir = await mkdtemp(join(tmpdir(), "mc-"));
474+
const dir = await mcTemp();
459475
const dumpPath = join(dir, "dump.jsonl");
460476
const body = makeBody([
461477
assistantMsg("t1"),
@@ -500,7 +516,7 @@ test("15. two requests with different timestamps → byte-identical bodies after
500516
// --- Activation ---
501517

502518
test("16. both gates unset → extension fires but exits early; no telemetry, no mutation, no fs", async () => {
503-
const dir = await mkdtemp(join(tmpdir(), "mc-"));
519+
const dir = await mcTemp();
504520
const dumpPath = join(dir, "dump.jsonl");
505521
const body = makeBody([
506522
assistantMsg("t1"),
@@ -526,7 +542,7 @@ test("16. both gates unset → extension fires but exits early; no telemetry, no
526542
});
527543

528544
test("17. only diagnostic enabled → telemetry present, JSONL written, no mutation", async () => {
529-
const dir = await mkdtemp(join(tmpdir(), "mc-"));
545+
const dir = await mcTemp();
530546
const dumpPath = join(dir, "dump.jsonl");
531547
const body = makeBody([
532548
assistantMsg("t1"),
@@ -548,7 +564,7 @@ test("17. only diagnostic enabled → telemetry present, JSONL written, no mutat
548564
});
549565

550566
test("18. only normalize enabled → telemetry present, mutation happens, no JSONL", async () => {
551-
const dir = await mkdtemp(join(tmpdir(), "mc-"));
567+
const dir = await mcTemp();
552568
const dumpPath = join(dir, "dump.jsonl");
553569
const body = makeBody([
554570
assistantMsg("t1"),
@@ -568,7 +584,7 @@ test("18. only normalize enabled → telemetry present, mutation happens, no JSO
568584
});
569585

570586
test("19. both enabled → telemetry, mutation, AND JSONL all happen; raw text captured pre-normalization", async () => {
571-
const dir = await mkdtemp(join(tmpdir(), "mc-"));
587+
const dir = await mcTemp();
572588
const dumpPath = join(dir, "dump.jsonl");
573589
const body = makeBody([
574590
assistantMsg("t1"),
@@ -598,7 +614,7 @@ test("19. both enabled → telemetry, mutation, AND JSONL all happen; raw text c
598614
});
599615

600616
test("19a. CACHE_FIX_DUMP_MICROCOMPACT_INCLUDE_NORMALIZED=1 → adds normalized_text alongside raw sentinel_text", async () => {
601-
const dir = await mkdtemp(join(tmpdir(), "mc-"));
617+
const dir = await mcTemp();
602618
const dumpPath = join(dir, "dump.jsonl");
603619
const body = makeBody([
604620
assistantMsg("t1"),

0 commit comments

Comments
 (0)