Skip to content

createSandbox + sandbox.run() never captures session, so context window size is not shown #717

Description

@rkibistu

Bug

When using createSandbox() + sandbox.run(), the "Context window: NNNk" line is never printed after iterations, even though it works correctly with the top-level run().

Root cause

createSandbox.ts builds its own reuseFactoryLayer that calls makeEffect without passing bindMountHandle:

// createSandbox.ts ~L294
const reuseFactoryLayer = Layer.succeed(SandboxFactory, {
  withSandbox: (makeEffect) =>
    makeEffect({
      hostWorktreePath: worktreePath,
      sandboxRepoPath: sandboxRepoDir,
      applyToHost,
      // bindMountHandle is never passed here
    })
});

But in Orchestrator.ts, session capture (and therefore usage parsing) only runs when bindMountHandle is present:

// Orchestrator.ts ~L371
if (provider.captureSessions && sessionId && bindMountHandle) {
  // capture session, parse usage ...
}

Since bindMountHandle is always undefined in the createSandbox path, usage stays undefined on every IterationResult, and buildContextWindowLines returns nothing.

The top-level run() uses WorktreeDockerSandboxFactory which does pass bindMountHandle, so context window output works there.

Why it's an oversight

The usage capture was added in #406 and the display in #459 — both only touched run.ts. createSandbox.ts was never updated to forward providerHandle through the factory.

Fix

In createSandbox.ts, pass providerHandle as bindMountHandle in the makeEffect call:

const reuseFactoryLayer = Layer.succeed(SandboxFactory, {
  withSandbox: (makeEffect) =>
    makeEffect({
      hostWorktreePath: worktreePath,
      sandboxRepoPath: sandboxRepoDir,
      applyToHost,
      bindMountHandle: providerHandle as BindMountSandboxHandle | undefined,
    })
});

providerHandle is already available in the closure via SandboxHandleContext.

Workaround

Use two separate top-level sandcastle.run() calls with branchStrategy: { type: "branch", branch } instead of createSandbox + sandbox.run(). This uses the full factory which passes bindMountHandle correctly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions