Skip to content

Tolerate host mounts where a create is not immediately visible to lookup - #160

Open
ezufelt wants to merge 3 commits into
vercel-labs:mainfrom
ezufelt:fix/fs-settle-non-coherent-mounts
Open

Tolerate host mounts where a create is not immediately visible to lookup#160
ezufelt wants to merge 3 commits into
vercel-labs:mainfrom
ezufelt:fix/fs-settle-non-coherent-mounts

Conversation

@ezufelt

@ezufelt ezufelt commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

On a Docker Desktop / virtiofs bind mount of a macOS host, mkdir,
writeFile, and symlink return success but lstat/realpath/existsSync on
the path they just created report ENOENT for the next 1-2ms. open, read,
and write on that path work immediately -- the lookup path lags, not the
data. Measured visibility after mkdir: 0/10 at 0ms, 9/10 at 1ms, 10/10 at
2ms. Sandboxed agent environments commonly mount the workspace this way.

deepsec assumed POSIX durability-on-return in a few places, so init
failed with "ENOENT: no such file or directory, mkdir 'data/'"
-- recursive mkdir creates data/, then cannot see it when it looks up the
child.

Adds settleFs, existsSettled, and mkdirSettled: a flat 100ms wait after
creating a path, tunable via DEEPSEC_FS_SETTLE_MS (0 opts out). Not a
poll-until-visible loop -- this is a handful of call sites on one code
path, and the simplicity is worth more than the milliseconds. mkdirSettled
retries the mkdir once on ENOENT, since that is where the failure
surfaces; any other errno is a real error and is rethrown untouched.

Used only where this process just created the path: ensureProject's data
dir, the init workspace dir, init-project's data dir, and the post-install
node_modules probe. Resume detection, atomic-file temp cleanup, and the
mkdir lock primitive are left alone -- those paths were created by an
earlier process or are legitimately absent most of the time, where
waiting is pure cost.

Refs #159

Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com

On a Docker Desktop / virtiofs bind mount of a macOS host, mkdir,
writeFile, and symlink return success but lstat/realpath/existsSync on
the path they just created report ENOENT for the next 1-2ms. open, read,
and write on that path work immediately -- the lookup path lags, not the
data. Measured visibility after mkdir: 0/10 at 0ms, 9/10 at 1ms, 10/10 at
2ms. Sandboxed agent environments commonly mount the workspace this way.

deepsec assumed POSIX durability-on-return in a few places, so init
failed with "ENOENT: no such file or directory, mkdir 'data/<projectId>'"
-- recursive mkdir creates data/, then cannot see it when it looks up the
child.

Adds settleFs, existsSettled, and mkdirSettled: a flat 100ms wait after
creating a path, tunable via DEEPSEC_FS_SETTLE_MS (0 opts out). Not a
poll-until-visible loop -- this is a handful of call sites on one code
path, and the simplicity is worth more than the milliseconds. mkdirSettled
retries the mkdir once on ENOENT, since that is where the failure
surfaces; any other errno is a real error and is rethrown untouched.

Used only where this process just created the path: ensureProject's data
dir, the init workspace dir, init-project's data dir, and the post-install
node_modules probe. Resume detection, atomic-file temp cleanup, and the
mkdir lock primitive are left alone -- those paths were created by an
earlier process or are legitimately absent most of the time, where
waiting is pure cost.

Refs vercel-labs#159

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

@ezufelt is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

@cramforce

Copy link
Copy Markdown
Contributor

Clanker feedback: • Found one blocking issue:

  • [P1] Settling occurs before installation, not before the post-install probe. existsSettled
    (
    if (
    // The installer is a child process that just finished writing this
    // tree, so a lagging mount can still report it missing.
    !isCheckpointCurrent(state, "install", installInput, () =>
    existsSettled("node_modules/deepsec"),
    )
    ) {
    )
    only runs when an install checkpoint already exists. On fresh initialization it is skipped, then ensureWorkspaceInstall
    (
    const after = probeWorkspaceInstall(workspaceDir);
    if (!after.ok) throw new Error(`Install completed but workspace is unusable: ${after.reason}`);
    )
    immediately probes the newly created node_modules using raw existsSync. The same metadata lag can therefore still report “workspace is
    unusable.” Settle immediately after the installer exits, before probeWorkspaceInstall, and add a regression test for that sequence.

The new core tests pass locally, but they don’t exercise this installer path. The PR is currently blocked by unauthorized Vercel deployment
checks; Socket and Vercel Agent Review pass. PR #160 (#160)

@vercel vercel Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Suggestion:

On a lagging/non-coherent mount, ensureWorkspaceInstall's post-install probe uses raw existsSync on files the install child just wrote, so a fresh deepsec init can spuriously throw "Install completed but workspace is unusable".

Fix on Vercel

existsSettled only guarded the install checkpoint check, which runs when
a checkpoint already exists -- so a fresh init skipped it and then probed
the just-written node_modules with a raw existsSync, where the same
create-to-lookup lag reports "Install completed but workspace is
unusable" for a good install.

probeWorkspaceInstall takes a settle option that routes its existence
checks through existsSettled; the post-install call passes it. The
pre-install probe keeps the raw check, since an absent node_modules is
the normal case there and waiting on it is pure cost.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ezufelt

ezufelt commented Aug 25, 2026

Copy link
Copy Markdown
Contributor Author

Clanker feedback: • Found one blocking issue:

  • [P1] Settling occurs before installation, not before the post-install probe. existsSettled
    (
    if (
    // The installer is a child process that just finished writing this
    // tree, so a lagging mount can still report it missing.
    !isCheckpointCurrent(state, "install", installInput, () =>
    existsSettled("node_modules/deepsec"),
    )
    ) {

    )
    only runs when an install checkpoint already exists. On fresh initialization it is skipped, then ensureWorkspaceInstall
    (
    const after = probeWorkspaceInstall(workspaceDir);
    if (!after.ok) throw new Error(`Install completed but workspace is unusable: ${after.reason}`);

    )
    immediately probes the newly created node_modules using raw existsSync. The same metadata lag can therefore still report “workspace is
    unusable.” Settle immediately after the installer exits, before probeWorkspaceInstall, and add a regression test for that sequence.

The new core tests pass locally, but they don’t exercise this installer path. The PR is currently blocked by unauthorized Vercel deployment checks; Socket and Vercel Agent Review pass. PR #160 (#160)

Thanks for the feedback, I pushed a new commit.

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