Follow-up to #85. The TestTempDir guard from ce676f6d works, and its design anticipated this problem — dirs go under one subc-tests/ parent precisely so "a future orphan population is one directory listing away from attribution". But most temp-dir creation in the workspace cannot reach the guard, and those sites still land at /tmp top level.
Measured on this box today, before I reclaimed them:
/tmp/subc-tests/ 24 dirs 119 MB ← the guard's population, attributable
/tmp/subc-*, fake-aft-* 436 dirs ~800 MB ← hand-rolled, top level, no common parent
The top-level population is 18x the guarded one by count. It is also the one that cannot be swept safely, because /tmp/subc-* has no owner marker — a cleanup pass matching that glob also matches subc-<token>.connection.json and anything else a future site names similarly.
The cause is structural, not negligence. TestTempDir lives in crates/subc-core/src/test_support.rs, reachable only via subc-core's self dev-dependency. But subc-core depends on subc-transport and subc-protocol, so those crates cannot dev-depend on subc-core to get the guard — it is a cycle. subc-client-rs and agent-token-vectors have no subc-core edge at all. Only subc-mcp can currently reach it:
| crate |
can reach TestTempDir? |
why |
subc-core |
yes |
self dev-dependency |
subc-mcp |
yes |
already dev-depends on subc-core |
subc-transport |
no |
subc-core depends on it — cycle |
subc-protocol |
no |
subc-core depends on it — cycle |
subc-client-rs |
no |
no edge |
agent-token-vectors |
no |
no edge |
Current split is 32 call sites on the guard, 21 hand-rolled. The hand-rolled ones that create directories:
crates/subc-client-rs/tests/liveness_probe.rs:390 {name}-{pid}-{nonce}
crates/subc-client-rs/tests/real_daemon.rs:2191 {name}-{pid}-{nonce}
crates/subc-mcp/tests/phase1_integration.rs:4758 sc-{label}-{pid}-{nonce}
crates/agent-token-vectors/tests/generator.rs:5 agent-token-vectors-{pid}
crates/subc-transport/src/connection_file.rs:454 subc-sweep-{pid}
crates/subc-core/src/control.rs:6181, 6223
crates/subc-core/src/setup/components.rs:239
crates/subc-core/src/setup/release_index.rs:356
crates/subc-core/src/setup/upgrade_assets.rs:197
(The bootstrap.rs / ck.rs / subc-mcp subc-{token}.connection.json sites are production files, not test dirs, and are out of scope.)
Suggested fix: move the guard to a leaf dev-only crate — say crates/subc-test-support, depending on nothing in the workspace — so every crate can dev-depend on it regardless of direction. That is the only option that reaches subc-transport and subc-protocol at all. Per-crate copies would work mechanically but reproduce the failure mode already documented in this repo for sentinel lists: independent copies agree today by coincidence, not contract, and drift silently in the honest-looking direction.
Two smaller notes:
- Retention. Preserve-on-panic is correct and I would not change it, but it has no bound, so a red gate's residue is permanent. Once the guard is reachable everywhere and all dirs share the
subc-tests/ parent, a bound becomes trivial — e.g. TestTempDir::new reaping guard-owned dirs older than N days on first construction. That is worth doing after the move, not instead of it.
keep() already exists as the escape hatch for handing a dir to a child process, so migrating the hand-rolled sites should not need new API.
Happy to do the move if you want it — it is mechanical, and the acceptance test is that no env::temp_dir() call outside the new crate creates a directory.
Follow-up to #85. The
TestTempDirguard fromce676f6dworks, and its design anticipated this problem — dirs go under onesubc-tests/parent precisely so "a future orphan population is one directory listing away from attribution". But most temp-dir creation in the workspace cannot reach the guard, and those sites still land at/tmptop level.Measured on this box today, before I reclaimed them:
The top-level population is 18x the guarded one by count. It is also the one that cannot be swept safely, because
/tmp/subc-*has no owner marker — a cleanup pass matching that glob also matchessubc-<token>.connection.jsonand anything else a future site names similarly.The cause is structural, not negligence.
TestTempDirlives incrates/subc-core/src/test_support.rs, reachable only viasubc-core's self dev-dependency. Butsubc-coredepends onsubc-transportandsubc-protocol, so those crates cannot dev-depend onsubc-coreto get the guard — it is a cycle.subc-client-rsandagent-token-vectorshave nosubc-coreedge at all. Onlysubc-mcpcan currently reach it:TestTempDir?subc-coresubc-mcpsubc-coresubc-transportsubc-coredepends on it — cyclesubc-protocolsubc-coredepends on it — cyclesubc-client-rsagent-token-vectorsCurrent split is 32 call sites on the guard, 21 hand-rolled. The hand-rolled ones that create directories:
(The
bootstrap.rs/ck.rs/subc-mcpsubc-{token}.connection.jsonsites are production files, not test dirs, and are out of scope.)Suggested fix: move the guard to a leaf dev-only crate — say
crates/subc-test-support, depending on nothing in the workspace — so every crate can dev-depend on it regardless of direction. That is the only option that reachessubc-transportandsubc-protocolat all. Per-crate copies would work mechanically but reproduce the failure mode already documented in this repo for sentinel lists: independent copies agree today by coincidence, not contract, and drift silently in the honest-looking direction.Two smaller notes:
subc-tests/parent, a bound becomes trivial — e.g.TestTempDir::newreaping guard-owned dirs older than N days on first construction. That is worth doing after the move, not instead of it.keep()already exists as the escape hatch for handing a dir to a child process, so migrating the hand-rolled sites should not need new API.Happy to do the move if you want it — it is mechanical, and the acceptance test is that no
env::temp_dir()call outside the new crate creates a directory.