Skip to content

Refused clone-mount sandbox creation on a shallow repository with an actionable message instead of a silent empty workspace (FR-058) - #28

Merged
dzykovic merged 3 commits into
mainfrom
feature/clone-mount-preflight
Aug 10, 2026
Merged

Refused clone-mount sandbox creation on a shallow repository with an actionable message instead of a silent empty workspace (FR-058)#28
dzykovic merged 3 commits into
mainfrom
feature/clone-mount-preflight

Conversation

@dzykovic

@dzykovic dzykovic commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Risk & Size

Risk: Medium
Size: Medium

What & Why

A sandbox with mount: clone created on a shallow repository came up with an empty
workspace and said nothing: sbx copies the repo in with
git clone --reference <read-only host mount>, git refuses a shallow source
(fatal: reference repository '/run/sandbox/source' is shallow), and the failure happens
inside the sandbox at start-up — sbx create itself exits 0. Worse, it never self-heals:
once the agent writes into the empty directory sbx pre-created, every later start fails on
already exists and is not an empty directory and the original cause is gone.

FR-058 refuses that create before the first sbx call and names the fix. Spec:
docs/specs/completed/015 - Clone Mount Preflight.md (shipped); canonical docs updated in
the same change — Features FR-058 (+ notes on FR-003/FR-052) and Architecture §4/§5/§9/§13/§14.

Changes

  • src/git.ts (new): read-only host git probes — isShallowRepository(dir) via
    git -C <dir> rev-parse --is-shallow-repository, run through the log.ts runner. -C
    rather than a spawn cwd so a workspace inside a repository resolves the containing
    repo, matching sbx's own precondition. Fails open on any error.
  • src/ops.ts: assertMountUsable() on every create path (createOrAttach, rebuildRef,
    shellRef), gated on mount: clone; attaching to an existing sandbox is untouched. The
    refusal is a modal dialog — it ends the action the user just asked for, and the
    explanation does not survive a notification's one-line clamp — naming the cause,
    git fetch --unshallow and what running it does, plus the mount: direct alternative.
  • Open Terminal hand-off: terminal.ts gained openHostCommandTerminal, which opens a
    host terminal in the repository with git fetch --unshallow typed but not executed.
    The extension never runs it — fetching history changes what the user's working copy
    contains — but the user does not have to type it either.
  • Shared ops.HandledError sentinel: raised after the dialog, skipped by the error
    reporters in extension.ts, tree.ts and form.ts (form's local HandledError now
    extends it), so the dialog is never chased by a duplicate toast.
  • src/ops.ts (Rebuild): workspace resolution, the UNC translation and the new preflight
    moved to the top of the operation. They previously ran after docker build and
    sbx rm, so a workspace problem surfaced once the old instance was already destroyed; a
    refusal now leaves the sandbox intact.
  • src/script.ts: the same guard rendered into the generated project CLI's
    create_instance (FR-052 parity), same message, same fail-open rule.
  • Docs: Features FR-058 + FR-003/FR-052 notes; Architecture §4 (module + dependency
    direction), §5 (preflight before the first sbx call), §9 (why clone mode needs full
    history), §13 (CLI parity), §14 (the general silent-clone-failure limitation and why a
    post-create probe was not built); CLAUDE.md module map.

How to Verify

  1. npm run verify — exits 0 (tsc strict + esbuild bundle).
  2. Shallow refusal (the behaviour): open a repository where
    git rev-parse --is-shallow-repository prints true, define a sandbox with
    mount: clone, press Connect. Expected: a modal explaining the shallow history and
    naming git fetch --unshallow, and no sandbox created (sbx ls unchanged). Before
    this change the sandbox was created and the agent landed in an empty workspace.
    Open Terminal must open a host terminal in the repository with the command typed in
    and not run, and no second error toast may appear behind the dialog.
  3. Same repo, mount: direct — Connect still works (nothing is cloned).
  4. After git fetch --unshallow in that repository, Connect on the clone-mount sandbox
    creates it and the in-sandbox workspace holds a real clone (.git present).
  5. Rebuild ordering: with a clone-mount sandbox on a shallow repo, Rebuild refuses
    without removing the existing instance.
  6. Generated CLI parity: the rendered .sandbox/scripts/sbx.sh passes bash -n, and its
    connect/create path dies with the same message on a shallow repo.

The shallow failure and its fix were reproduced against sbx v0.31.3 on a real shallow
repository (probe sandbox created and removed); the author has run the manual acceptance.

…actionable message instead of a silent empty workspace (FR-058)
Copilot AI lite review requested due to automatic review settings August 10, 2026 15:37

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds an FR-058 preflight to prevent creating mount: clone sandboxes from shallow Git repositories, avoiding the “empty workspace + silent failure” mode caused by git clone --reference refusing shallow sources. This is implemented consistently across the VS Code extension create paths and the generated project CLI, with accompanying documentation/spec updates.

Changes:

  • Added a new src/git.ts module for read-only host git probes (isShallowRepository) used to gate clone-mount creation.
  • Added assertMountUsable() checks in src/ops.ts on all sandbox create paths (Connect/Create, Shell-create, Rebuild before destructive steps).
  • Added clone-mount shallow-repo refusal to the generated .sandbox/scripts/sbx.sh template and updated canonical docs + spec.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/script.ts Adds a shallow-repo preflight for clone-mount sandbox creation in the generated CLI template.
src/ops.ts Refuses clone-mount creation on shallow repos before any sbx mutation; reorders rebuild checks ahead of destructive steps.
src/git.ts Introduces a read-only git probe (rev-parse --is-shallow-repository) via the existing log.run runner.
docs/specs/completed/015 - Clone Mount Preflight.md Documents the iteration’s rationale/behavior and tradeoffs (preflight only, fail-open probe).
docs/Features.md Adds FR-058 feature documentation and notes on create preconditions.
docs/Architecture.md Updates module map/dependency direction and documents the new preflight behavior and limitations.
CLAUDE.md Updates module map/dependency direction to include git.ts.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/script.ts
@dzykovic
dzykovic merged commit 33178e1 into main Aug 10, 2026
1 check passed
@dzykovic
dzykovic deleted the feature/clone-mount-preflight branch August 10, 2026 16:11
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