fix(sandbox-driver): honor cwd + env passed to SubprocessSandboxDriver constructor#4
Merged
Merged
Conversation
…r constructor
The constructor accepted any-shape options (no declared interface) and
the exec() method only read cwd/env from the per-call HarnessConfig. That
made `new SubprocessSandboxDriver({ cwd })` a silent no-op — the subprocess
inherited the Node process cwd instead of the caller's intent.
This surfaced end-to-end in starter-foundry's promoter: Gen 8's strict
`pnpm exec tsc --noEmit` gate ran against starter-foundry's own (clean)
source tree instead of the composed scaffold being promoted, so every
build-gate scored 1.0 regardless of content. starter-foundry shipped
a workaround (spread cwd into HarnessConfig) but the underlying silent
drop belongs at this layer.
Changes:
- SubprocessSandboxDriverOptions interface documents constructor shape
- Constructor stores { cwd, env } as defaults
- exec() uses config.cwd ?? this.defaultCwd (per-call wins)
- exec() merges constructor env + per-call env (per-call wins on collision)
Backwards compatible: callers that only used config.cwd see no change
because the fallback is lower-priority.
Tests: +3 in tests/sandbox-harness.test.ts covering:
- constructor cwd is used when HarnessConfig.cwd is unset
- per-call HarnessConfig.cwd overrides constructor cwd
- constructor env merges with per-call env (per-call wins on collision)
All 322/322 tests pass (319 → 322).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
drewstone
added a commit
that referenced
this pull request
Apr 24, 2026
…r constructor (#4) The constructor accepted any-shape options (no declared interface) and the exec() method only read cwd/env from the per-call HarnessConfig. That made `new SubprocessSandboxDriver({ cwd })` a silent no-op — the subprocess inherited the Node process cwd instead of the caller's intent. This surfaced end-to-end in starter-foundry's promoter: Gen 8's strict `pnpm exec tsc --noEmit` gate ran against starter-foundry's own (clean) source tree instead of the composed scaffold being promoted, so every build-gate scored 1.0 regardless of content. starter-foundry shipped a workaround (spread cwd into HarnessConfig) but the underlying silent drop belongs at this layer. Changes: - SubprocessSandboxDriverOptions interface documents constructor shape - Constructor stores { cwd, env } as defaults - exec() uses config.cwd ?? this.defaultCwd (per-call wins) - exec() merges constructor env + per-call env (per-call wins on collision) Backwards compatible: callers that only used config.cwd see no change because the fallback is lower-priority. Tests: +3 in tests/sandbox-harness.test.ts covering: - constructor cwd is used when HarnessConfig.cwd is unset - per-call HarnessConfig.cwd overrides constructor cwd - constructor env merges with per-call env (per-call wins on collision) All 322/322 tests pass (319 → 322).
drewstone
added a commit
that referenced
this pull request
Apr 24, 2026
PR #4 shipped the same SubprocessSandboxDriver constructor-fallback fix while this branch was open. Resolved: - src/sandbox-harness.ts + tests/sandbox-harness.test.ts: take main's version (functionally equivalent; type named SubprocessSandboxDriverOptions instead of SubprocessDriverDefaults — main's name is better, already shipped) - src/index.ts: export SubprocessSandboxDriverOptions (main forgot to export the new type) - tests: also fix the env-merge test's printenv form — BSD printenv on macOS only prints the first matched var, making the test platform-flaky. Switch to env|grep which survives missing vars. Net: keep SKILL.md + README/CLAUDE pointers + version bump + type re-export + macOS test fix. All 322 tests pass.
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
SubprocessSandboxDriver's constructor accepted any-shaped options (no declared interface) and theexec()method only readcwd/envfrom the per-callHarnessConfig. Callingnew SubprocessSandboxDriver({ cwd })therefore silently did nothing — the subprocess inherited the Node process's cwd instead of the caller's intent.How this surfaced
End-to-end probing in
tangle-network/starter-foundry— the Gen 8 compile-gate thesis is "runpnpm exec tsc --noEmiton the composed scaffold to catch type errors at proposal time." The promoter did:HarnessConfigdid not setcwd. The driver readconfig.cwd→undefined→spawninherited the Node process cwd (the starter-foundry repo root). Everytsc --noEmitran against starter-foundry's own (clean) source tree, so the build-gate scored 1.0 on every proposal — including one with a verifiedTS2345error I planted as a probe.starter-foundry shipped a workaround (spread
cwdintoHarnessConfigat call sites — PR #53), but the silent-drop belongs at this layer: a constructor that accepts{ cwd }should honor it.Changes
SubprocessSandboxDriverOptionsinterface documents the constructor shape.{ cwd, env }as defaults.exec()usesconfig.cwd ?? this.defaultCwd— per-call wins, constructor is the fallback.exec()merges constructor env + per-call env (per-call wins on collision).Backwards-compatible: callers that only use
config.cwdsee no change because the fallback is lower-priority.Tests
+3 in
tests/sandbox-harness.test.tscovering:HarnessConfig.cwdis unsetHarnessConfig.cwdoverrides constructor cwd319/319 → 322/322. No existing tests changed.
Test plan
pnpm build— cleanpnpm test— 322/322