* fix(fuse-test): harden ensureMountClone to verify .git/HEAD
On FUSE, the kernel dcache can retain a stale directory entry after
heavy git operations. Checking only os.Stat(mountClone) may find
the top-level directory but the clone internals (.git/HEAD) are gone.
Now ensureMountClone verifies .git/HEAD exists, cleans up stale
remnants with os.RemoveAll before re-cloning, and adds a brief
settle delay for the FUSE metadata cache.
* fix(fuse-test): add pull recovery loop for Phase 6 git operations
After git reset --hard on a FUSE mount, the kernel dcache can
permanently lose the clone directory entry. The existing retry logic
polls for 60+ seconds but the directory never recovers.
Add pullFromCommitWithRecovery which wraps the Phase 6 pull in a
recovery loop: if the clone directory vanishes, it removes the stale
clone, re-creates it from the bare repo, resets to the target commit,
and retries the pull (up to 3 attempts).
Also adds tryGitCommand, a non-fatal git runner that returns
(output, error) instead of calling require.NoError, enabling the
recovery loop to handle failures gracefully without aborting the test.
Fixes flaky TestGitOperations/CloneAndPull on CI.
* fix(fuse-test): make recovery loop fully non-fatal
Address review feedback:
- Extract tryEnsureMountClone (returns error) so a transient FUSE
failure during re-clone doesn't abort the test — the recovery loop
can retry instead.
- Check waitForDirEventually return after git reset --hard and return
a specific error if the directory doesn't recover.
* style(fuse-test): simplify ensureMountClone error check
* fix(fuse-test): recover bare repo when FUSE mount loses it
CI showed that not just the working clone but also the bare repo on
the FUSE mount can vanish after heavy git operations. The recovery
loop now re-creates the bare repo from the local clone (which lives
on local disk and is always available) before attempting to re-clone.
Adds tryEnsureBareRepo: checks HEAD exists in the bare repo, and if
not, re-inits and force-pushes from the local clone.