test harnesses leak an untrapped mktemp scratch dir per new_project() call (3223 accumulated) #514

Open
opened 2026-09-01 19:28:15 +00:00 by jbr870 · 0 comments
Owner

What

new_project() in the shell test harnesses opens a second, untrapped mktemp -d. Each suite
traps only its own $TMP:

TMP="$(mktemp -d)"
trap 'rm -rf "$TMP"' EXIT      # covers $TMP …

new_project() {
  proj="$(mktemp -d)"          # … but not this one
  ...
}

Nothing removes $proj, so every new_project call leaks a directory for the life of the box.

Evidence

Measured on the dev host during QA round 1 of #45 (/tmp):

  • 3223 tmp.* directories accumulated in total
  • 151 of them created in the preceding 90 minutes — a single QA round
  • sampled leaked directories are non-empty (feature folders with planted comment files)

Scope — pre-existing, but recently amplified

new_project() is present at bd2532c in provenance.sh, typed-scan.sh and
typed-scan-family.sh, so this is a house pattern, not a defect #45 invented. #45 replicated it
and materially widened the blast radius: 37 new call sites across supersede-read.sh (24) and
supersede-flow.sh (13), plus roll-call.sh.

Why it is worth a ticket rather than a shrug

This is exactly the class run-resource-claims.md §2 singles out as "the one that costs a day"
a shared writable scratch surface, invisible to both a file-boundary rule (which compares writer
against writer) and to the four suite-owned resource classes (which contain no such class). It is
also the one resource an actor's claims: block cannot express today, which is why it went unnoticed
through several features.

Nothing is currently broken by it — the leak is disk, not correctness — so this is priority:low.
But an unbounded per-run leak on a long-lived dev box or a CI runner eventually is a correctness
problem, and it is one line to close.

Suggested fix

Either allocate the project dir under the already-trapped $TMP:

proj="$(mktemp -d -p "$TMP")"

…or accumulate the extra dirs and extend the trap. The first is smaller and needs no bookkeeping.
Apply it to all six suites that define new_project(), not only #45's two.

Provenance

Found by the driver's quiesce check at the RELEASE of qa-testwriter-r1 during QA round 1 on
issue #45run-resource-claims.md §5 requires confirming resources are freed before a release
entry is written, and this is what that check exists to catch. Recorded as finding CR-20 on
qa-report domain=code phase=validate (comment 2582) and dispositioned defer-to-issue by
disposition-recommend.sh.

## What `new_project()` in the shell test harnesses opens a **second, untrapped** `mktemp -d`. Each suite traps only its own `$TMP`: ```sh TMP="$(mktemp -d)" trap 'rm -rf "$TMP"' EXIT # covers $TMP … new_project() { proj="$(mktemp -d)" # … but not this one ... } ``` Nothing removes `$proj`, so every `new_project` call leaks a directory for the life of the box. ## Evidence Measured on the dev host during QA round 1 of #45 (`/tmp`): - **3223** `tmp.*` directories accumulated in total - **151** of them created in the preceding 90 minutes — a single QA round - sampled leaked directories are non-empty (feature folders with planted comment files) ## Scope — pre-existing, but recently amplified `new_project()` is present at `bd2532c` in `provenance.sh`, `typed-scan.sh` and `typed-scan-family.sh`, so this is a **house pattern, not a defect #45 invented**. #45 replicated it and materially widened the blast radius: **37 new call sites** across `supersede-read.sh` (24) and `supersede-flow.sh` (13), plus `roll-call.sh`. ## Why it is worth a ticket rather than a shrug This is exactly the class `run-resource-claims.md` §2 singles out as *"the one that costs a day"* — a **shared writable scratch surface**, invisible to both a file-boundary rule (which compares writer against writer) and to the four suite-owned resource classes (which contain no such class). It is also the one resource an actor's `claims:` block cannot express today, which is why it went unnoticed through several features. Nothing is currently *broken* by it — the leak is disk, not correctness — so this is `priority:low`. But an unbounded per-run leak on a long-lived dev box or a CI runner eventually is a correctness problem, and it is one line to close. ## Suggested fix Either allocate the project dir **under** the already-trapped `$TMP`: ```sh proj="$(mktemp -d -p "$TMP")" ``` …or accumulate the extra dirs and extend the trap. The first is smaller and needs no bookkeeping. Apply it to all six suites that define `new_project()`, not only #45's two. ## Provenance Found by the **driver's quiesce check** at the `RELEASE` of `qa-testwriter-r1` during QA round 1 on issue #45 — `run-resource-claims.md` §5 requires confirming resources are freed before a release entry is written, and this is what that check exists to catch. Recorded as finding **CR-20** on qa-report `domain=code phase=validate` (comment 2582) and dispositioned `defer-to-issue` by `disposition-recommend.sh`.
Sign in to join this conversation.
No description provided.