Repository navigation
Conversation
session-sync-pull cleaned its temp tree with a bare
fs.rmSync(tmp, { recursive: true, force: true }). In the CI run for Tencent#1403 that
call failed on Node 20/ubuntu:
Error: ENOTEMPTY: directory not empty, rmdir '.../b/.git/objects/pack'
The test body passed in 153 ms. The error came from the afterEach hook, which
vitest reports under the test's name, so it reads like a failed assertion.
Every other test here that removes a temp tree containing a git repository
already retries that rmdir, and git-kind-learnings says why in as many words:
a push can leave a detached `git gc --auto` writing objects/pack after the
test returns, so a single rmdir races it. It passes maxRetries: 5 and
retryDelay: 100; so do learnings-import-remnants, reports-reader-lock,
deleted-worktree-scope-810, instruction-targets and slash-skill-paths. This
file was the only git-tree cleanup left on a single attempt, and it is the one
that failed.
Five of the six Lint & Test jobs in that run executed this same code and
passed (Node 20/22/24 on macOS, Node 22/24 on ubuntu), which is what a timing
race looks like rather than a broken assertion. I did not identify which
detached git process was writing in that particular run, so this does not
claim a new root cause: it applies the fix this repository already settled on
to the one cleanup that was missing it.
Test-only change: one call and its comment, no production code touched.
|
No findings in the specified diff.
Reviewed only the diff; did not run, build, or install PR code. |
SaulMoro
left a comment
There was a problem hiding this comment.
This was generated by AI during triage.
@Smilewithoutfalling Approving at 9a807ca. The failure this targets is real and matches: #1403's Node 20 ubuntu job failed with ENOTEMPTY: directory not empty, rmdir '.../b/.git/objects/pack', thrown from this file's afterEach, while the test body itself had passed. Bounded retries are what the other git-tree cleanups in the suite already use (maxRetries: 5, retryDelay: 100, e.g. deleted-worktree-scope-810, instruction-targets, slash-skill-paths). Tests-only, so no real-CLI record is needed.
The CI review reports no findings. We agree. All CI jobs pass; the GitHub-provider e2e job is skipped by the fork policy.
Summary
session-sync-pullcleaned its temp tree with a barefs.rmSync(tmp, { recursive: true, force: true }). That call failed in a CI run, and every other git-tree cleanup in this repository already guards against exactly this failure.The test body passed in 153 ms; the error came from the
afterEachhook, which vitest reports under the test's name — so it reads like a failed assertion for a merge that actually worked.Type of Change
Tests-only, per AGENTS.md: no real-CLI record needed.
Test Plan
The diff is one
fs.rmSynccall and the comment above it, insrc/__tests__/session-sync-pull.test.ts:node --check --experimental-strip-types src/__tests__/session-sync-pull.test.ts— parses cleannpx vitest run— full suite left to CI (this file is included in all sixLint & Testjobs)Notes for Reviewers
This is not a new fix, it is the missing instance of an existing one.
git-kind-learnings.test.tsalready states the mechanism in a comment:It passes
maxRetries: 5, retryDelay: 100. Three unit-test files already do the same on their temp tree —git-kind-learnings,learnings-import-remnants,reports-reader-lock— and three of the four e2e files do too (deleted-worktree-scope-810,instruction-targets,slash-skill-paths). This file still removed a tree holding a clone and a bare origin on a single attempt.Why I believe it is a timing race and not a broken assertion. The same commit produced six
Lint & Testjobs and five passed: Node 20/22/24 on macOS, Node 22/24 on ubuntu. Two of those are ubuntu and run the same file on a newer Node. A logic error would not be that selective.What I am not claiming. I did not identify which detached git process was writing in that particular run — the failing path is
b/.git/objects/packwhile the comment above names a push into the bare origin, and this fixture both commits intob(archive()) and pushes from it. So this PR does not assert a new root cause; it applies the retry this repository already relies on to the one cleanup that lacked it, and cites the observed failure as the reason.Scope. I deliberately left
helpers/isolate-home.tsalone. ItsafterAllalso calls a barefs.rmSync, but it removes the outer test directory after every per-testafterEachhas already emptied it, and the failure above is attributed to the per-test hook. Changing a setup file shared by 555 test files is a different decision from this one.