Skip to content

test(dashboard): quiesce background algo-sweep before TempDir cleanup (Windows CI)#5896

Merged
cajasmota merged 1 commit into
mainfrom
worktree-agent-a81194be856e0a73d
Jul 22, 2026
Merged

test(dashboard): quiesce background algo-sweep before TempDir cleanup (Windows CI)#5896
cajasmota merged 1 commit into
mainfrom
worktree-agent-a81194be856e0a73d

Conversation

@cajasmota

Copy link
Copy Markdown
Owner

Fixes the sole windows-latest failure in the v0.1.9 3-OS acceptance CI: TestHandleRepoRelationships_NoRefTempDir RemoveAll cleanup: ...refs\_unknown: The directory is not empty. Refs #5850.

Root cause (empirically confirmed — NOT mmap): the ref-endpoint fixture is graph.json-only, so no memory mapping is ever held. The failure is a deferred background algo-sweep goroutine (schedulePendingAlgo) writing graph-algo.json into the state dir after the triggering HTTP request returns, racing Go's automatic RemoveAll of the t.TempDir. On Windows a file created concurrently with directory removal makes RemoveAll fail; on Unix unlink-while-open is legal, so it only reddens Windows. Timing-flake shared by ~20 fixture siblings; this one lost the race that run. Production state dirs are durable (never swept), so this is a test gap, not a product leak.

Fix: new quiesceGraphCache(t, srv) helper parks the sweep via the existing backgroundAlgoGate hook (no graph-algo.json written under the temp dir) and, in t.Cleanup (LIFO before RemoveAll), restores the gate + calls srv.graphs.InvalidateAll() (production reader-eviction, defense for the mmap-default-on path). Wired into buildRefEndpointFixture (the failing test + ~19 siblings) and setupDiffTest (second instance). Whole-internal/dashboard audit found no other fixture holds a reader or spawns the sweep over a temp dir.

Test-only; full suite 11547 pass. Real proof is the Windows CI re-run (can't red→green on macOS — Unix allows unlink-while-open).

🤖 Generated with Claude Code

https://claude.ai/code/session_017quGgaqK7NRoxGT6BTqV2o

…rdown (fix Windows RemoveAll)

TestHandleRepoRelationships_NoRef (and its ~19 buildRefEndpointFixture
siblings, plus the handlers_v2_diff setupDiffTest fixture) can red the
v0.1.9 3-OS acceptance run on windows-latest with a "TempDir RemoveAll
cleanup: unlinkat <...>\refs\_unknown: The directory is not empty" error.

Root cause is NOT the mmap-default-on / generation-fb change: the fixture
writes graph.json only, so CurrentGraphPath resolves the (absent) flat
graph.fb, fbreader.Open fails, and DashRepo.Reader stays nil -- no mapping
is held. The real hazard is the deferred Pass-4 sweep. A cache load of a
non-empty graph (loadGroupForRef -> applyAlgorithmsOnLoad) schedules
schedulePendingAlgo, which runs on a BACKGROUND goroutine and writes
graph-algo.json (os.CreateTemp + rename) into the repo's state dir AFTER
the triggering request already returned. When that state dir is a
t.TempDir, the write races Go's automatic RemoveAll teardown; on Windows a
file created/opened concurrently with a directory removal fails RemoveAll.
On Unix unlink-while-open is legal, so it only ever reddens Windows --
same class as PR #5893.

This is a test-teardown gap, not a product handle leak: in production the
state dir is the durable daemon root, never removed out from under the
sweep, so writing graph-algo.json there is correct.

Fix: add quiesceGraphCache(t, srv) -- sets backgroundAlgoGate so every
scheduled sweep parks BEFORE touching the filesystem (no graph-algo.json,
nor its temp handle, is ever created under the temp dir), and registers a
cleanup that restores the prior gate and calls graphs.InvalidateAll() (the
production reader-eviction primitive, closing any mmap fbreader.Reader as
defence for the mmap-default-on path). Wired into the two confirmed
cache-load-over-temp-dir fixtures: buildRefEndpointFixture and setupDiffTest.

Audited the whole internal/dashboard test package: no other fixture holds a
reader or spawns the sweep over a temp dir (others seed the cache directly,
stat-only, close their readers, or use empty/invalid graphs). The
background-sweep goroutine is dashboard-only.

Gates: gofmt -l clean, go build, go vet, go test ./internal/dashboard/ (942
pass) and full go test ./... (11547 pass, 128 packages) all green on macOS.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017quGgaqK7NRoxGT6BTqV2o
@cajasmota
cajasmota merged commit 9b90a0c into main Jul 22, 2026
1 of 2 checks passed
@cajasmota
cajasmota deleted the worktree-agent-a81194be856e0a73d branch July 22, 2026 02:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants