LearnNewsExamplesServices
Frontmatter
id16439
titleworkspaceSafety teardown races itself: ENOTEMPTY rmdir on the temp workspace
stateClosed
labels
bugaitesting
assigneesneo-opus-ada
createdAtAug 3, 2026, 3:21 PM
updatedAtAug 4, 2026, 7:35 AM
githubUrlhttps://github.com/neomjs/neo/issues/16439
authorneo-fable-clio
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtAug 4, 2026, 7:35 AM

workspaceSafety teardown races itself: ENOTEMPTY rmdir on the temp workspace

Closed Backlog/active-chunk-12 bugaitesting
neo-fable-clio
neo-fable-clio commented on Aug 3, 2026, 3:21 PM

Context

Observed 2026-08-03 on PR #16437's CI (an unrelated diff: fleet-cockpit view + Electron harness files; nothing in ai/daemons/**), which makes the failure environmental rather than change-driven:

✘ test/playwright/integration/ai/daemons/workspaceSafety.spec.mjs:388:5
  › Orchestrator workspace-safety integration (#11948 / Sub-5 AC5 of #11837)
  › AC4 — swarm-heartbeat target resolver degrades-with-log when selfIdentity is missing (2.8s)
Error: ENOTEMPTY: directory not empty, rmdir '/tmp/neo-workspace-safety-XCsynB'

Job: https://github.com/neomjs/neo/actions/runs/30816553986/job/91695664038 — 49/50 passed; only this teardown failed. The same suite was green on the branch's previous head 40 minutes earlier, same base. Live latest-open sweep: checked latest 10 open issues at 2026-08-03T13:15Z; no equivalent found. A2A claim scan: no overlapping lane.

The Problem

The AC4 case exercises the degrade-with-log path — the resolver keeps running and WRITES A LOG when selfIdentity is missing — and the failure is ENOTEMPTY on removing the spec's temp workspace. That is the classic teardown race genre: the recursive removal walks the directory while the still-settling subject (or its logger) creates one more entry, so rmdir on the parent fires against a directory that just became non-empty again. The assertion half of the test passed; only cleanup lost the race. Every occurrence taxes an entire CI round (~13 min unit + the integration wall-clock) on an unrelated PR.

The Architectural Reality

  • The spec provisions a per-test workspace under /tmp/neo-workspace-safety-* and removes it in teardown.
  • The AC4 subject is precisely the one path guaranteed to still be producing filesystem writes at assertion time (its contract IS "degrades with log"), which makes this test the racy one out of the 50 — consistent with 49/50 green.
  • Node's own answer to this genre exists: fs.rm(dir, {recursive: true, force: true, maxRetries, retryDelay}) retries ENOTEMPTY/EBUSY internally — or the teardown awaits the subject's settle (close/flush) before removal.

The Fix

Owner verifies which half is cheapest and correct:

  1. Settle-then-remove (preferred if the seam exists): await the daemon/logger handle the AC4 case opened (close/flush) before the workspace removal — teardown ordering, not tolerance.
  2. Tolerant removal: switch the teardown to fs.rm with maxRetries/retryDelay (or an equivalent bounded retry) so a last-instant write cannot fail the case that already passed its assertions.

Acceptance Criteria

  • The AC4 case's teardown cannot fail with ENOTEMPTY while the degrade-with-log subject settles (whichever mechanism, asserted by the repair's own reasoning or a targeted stress loop).
  • No behavioral change to the AC4 assertion itself — it passes today and must keep asserting the degrade-with-log contract.

Out of Scope

  • The workspace-safety behavior under test (all 50 assertions pass); this ticket is teardown-only.
  • CI retry machinery — the fix belongs in the spec's cleanup, not in workflow-level retries.

Related

  • Observed on: PR #16437 (unrelated diff, evidence anchor only)
  • Suite provenance: #11948 / #11837 (workspace-safety integration)

Origin Session ID: 65e414e1-48a4-49a0-a430-70a81911f9fc Retrieval Hint: "workspaceSafety ENOTEMPTY teardown race"