Skip to content

fix(loop-audit,loop-sandbox): correct gate.yaml auto-fix schema and Windows spawn ENOENT#382

Merged
cobusgreyling merged 1 commit into
cobusgreyling:mainfrom
KhaiTrang1995:fix/gate-schema-and-sandbox-shell
Jul 25, 2026
Merged

fix(loop-audit,loop-sandbox): correct gate.yaml auto-fix schema and Windows spawn ENOENT#382
cobusgreyling merged 1 commit into
cobusgreyling:mainfrom
KhaiTrang1995:fix/gate-schema-and-sandbox-shell

Conversation

@KhaiTrang1995

Copy link
Copy Markdown
Contributor

Summary

Two independent, real bugs found while surveying recent upstream work
(loop-sandbox, MCP loop-gate/loop-audit integration, --auto-fix).

What

1. loop-audit --auto-fix generated a gate.yaml that loop-gate rejects.

loop-gate check requires { version: 1, denylist: string[], maxFiles?, autoMergeAllowlist? } and throws on anything else. The auto-fix template
instead wrote { gates: [{ name, description, required_approvers }] } -- a
shape loop-gate has never understood. Since loop-audit's own gateYaml
signal only checks that the file exists (not its contents), this passed
audit cleanly while silently breaking loop-gate check downstream. Fixed
GATE_YAML_TEMPLATE in tools/loop-audit/src/autofixer.ts to emit the real
schema, mirroring templates/gate.yaml.template.

2. loop-sandbox run fails on Windows for any npm-installed CLI.

loop-sandbox spawns the user's command with shell: false by default. On
Windows, npm .cmd/.bat shims (npx, tsc, eslint, ...) can't be
exec'd directly without a shell and fail with ENOENT -- the package's own
README example (loop-sandbox run -- npx my-agent) doesn't work as written.
Fixed by retrying once with shell: true specifically on ENOENT +
Windows, rather than forcing shell: true unconditionally (which breaks
commands relying on exact argv quoting, e.g. node -e "...", since cmd.exe
reparses the command line differently).

Tested

Both packages: full clean rebuild (rm -rf node_modules dist && npm install) + npm test, all green.

Added a regression test for the gate.yaml fix (tools/loop-audit/test/autofixer.test.mjs)
asserting the generated file actually parses to the schema loop-gate
expects.

The sandbox fix went through two more rounds after the first version looked
done: the initial "always use shell:true on Windows" attempt broke an
existing test (node -e "..." with embedded quotes), so it was narrowed to
retry-on-ENOENT only. Then, testing the retry path directly against a real
Windows machine turned up a second bug: the failed first attempt's close
event still fires a few milliseconds after its error event, and without a
guard it would resolve the run's promise with the failed attempt's bogus
exit code before the retry (still running) produced its real result --
meaning cleanup could run while the actual command was still executing
against the worktree. Fixed with a small flag that ignores the superseded
first attempt's late events once a retry is in flight, and reproduced the
race locally both before and after the fix to confirm it's actually closed.

…indows spawn ENOENT

loop-audit --auto-fix generated a gate.yaml shaped { gates: [...] },
which loop-gate check's loadGateConfig rejects outright (it requires
{ version: 1, denylist: string[], ... }). The auto-fix silently produced
a file that broke the tool it was meant to satisfy. Now emits the real
schema, mirroring templates/gate.yaml.template.

loop-sandbox run spawns an arbitrary user command; on Windows, npm .cmd/
.bat shims (npx, tsc, ...) fail with ENOENT without shell: true, but
forcing shell: true unconditionally breaks commands relying on exact
argv quoting (node -e "..."). Now retries once with a shell only after
an ENOENT on Windows, guarding against the failed attempt's late 'close'
event resolving the run with a stale exit code ahead of the retry.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@cobusgreyling cobusgreyling left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

LGTM — real bugs: gate.yaml auto-fix schema now matches loop-gate; Windows ENOENT retry for npm shims with superseded-close race guarded. Regression test added. CI green.

@cobusgreyling
cobusgreyling merged commit 5bd6c18 into cobusgreyling:main Jul 25, 2026
2 checks passed
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