fix(harness): an adapter exit 127 names the program that wasn't found (#1873) #1964

Merged
jason.woltje merged 2 commits from r127 into refactor 2026-11-15 03:29:32 +00:00
Owner

An adapter exit 127 now names the program that wasn't found (#1873, lane r127).

Jason hit "The assistant couldn't reply. Details: adapter exited 127" on the dev instance. Cause: the Console there ran without MOSAIC_CLAUDE_BIN, so a claude-code session ran /usr/bin/claude, a wrapper that execs /opt/claude-code/bin/claude. The sandbox binds /usr and not /opt, so the exec failed and the shell exited 127. The dev deploy script now sets MOSAIC_CLAUDE_BIN (outside the repo).

This change makes the message say what was missing. On exit 127 the runner reads the last 16 KiB of the turn's stderr and, when a shell or env printed its own not-found line, the reason becomes adapter exited 127 (command not found: claude). It returns a basename only, never a host path, and refuses names that look like a key. Other exit codes are unchanged.

Tests: four new tests in packages/harness/tests/runner.test.mjs, red before the fix (0/3, then 2/2 on the review round). Lane gate 14 files, 274/0. Lead check at 387f73a7a: 16 files that import runner.mjs or mention the text, 285/0.

Reviews (fresh Opus 5.5 delegates): review approved with 6 P3, five fixed in 387f73a7a. Re-check approved with 4 P3, left as follow-ups.

Follow-ups:

  • A launch refused at start writes nothing to the thread, so the person waits with no reply.
  • claude-code preflight checks the binary on the host, not inside the sandbox. A claude outside /usr with MOSAIC_CLAUDE_BIN unset fails with a bare "adapter exited 254".
  • A short key-shaped token, or a bash redirect to a missing file, can still be named as the program.
An adapter exit 127 now names the program that wasn't found (#1873, lane r127). Jason hit "The assistant couldn't reply. Details: adapter exited 127" on the dev instance. Cause: the Console there ran without `MOSAIC_CLAUDE_BIN`, so a claude-code session ran `/usr/bin/claude`, a wrapper that execs `/opt/claude-code/bin/claude`. The sandbox binds /usr and not /opt, so the exec failed and the shell exited 127. The dev deploy script now sets `MOSAIC_CLAUDE_BIN` (outside the repo). This change makes the message say what was missing. On exit 127 the runner reads the last 16 KiB of the turn's stderr and, when a shell or env printed its own not-found line, the reason becomes `adapter exited 127 (command not found: claude)`. It returns a basename only, never a host path, and refuses names that look like a key. Other exit codes are unchanged. Tests: four new tests in `packages/harness/tests/runner.test.mjs`, red before the fix (0/3, then 2/2 on the review round). Lane gate 14 files, 274/0. Lead check at 387f73a7a: 16 files that import runner.mjs or mention the text, 285/0. Reviews (fresh Opus 5.5 delegates): review approved with 6 P3, five fixed in 387f73a7a. Re-check approved with 4 P3, left as follow-ups. Follow-ups: - A launch refused at start writes nothing to the thread, so the person waits with no reply. - claude-code preflight checks the binary on the host, not inside the sandbox. A `claude` outside /usr with `MOSAIC_CLAUDE_BIN` unset fails with a bare "adapter exited 254". - A short key-shaped token, or a bash redirect to a missing file, can still be named as the program.
jason.woltje added 2 commits 2026-11-15 03:29:21 +00:00
A claude-code turn on a Console started without MOSAIC_CLAUDE_BIN failed
with a bare "adapter exited 127". The sandbox binds /usr, so the wrapper
/usr/bin/claude is visible, but its exec target /opt/claude-code/bin/claude
isn't bound, and the shell exits 127.

On exit 127 the runner now reads the tail of the turn's stderr, finds the
shell's "not found" line (bash, dash, env) and adds the program's basename:
"adapter exited 127 (command not found: claude)". It never shows a host
path or anything that isn't a plain program name; a 127 without such a
line keeps the bare reason.

The deploy side (MOSAIC_CLAUDE_BIN on the Console unit) is a Lead-owned
script change, written up in the lane report.
Review P3-1: a "No such file or directory" line from another program
(cat, ls) no longer counts. Only bash's "line N:", dash's "N:" and env's
quoted form do.
P3-2: a name with a run of 16 letters and digits looks like a key, so it
stays in the run's private stderr instead of the reply.
P3-3: a 16 KiB stderr window that starts mid-file drops its partial first
line, so a cut name ("aude") isn't reported.
P3-4: CRLF lines read the same as LF lines.
P3-5: tests for the name check (tokens without spaces, key-shaped names),
for a cat line, and for the window boundary through the runner.
jason.woltje merged commit 387f73a7a4 into refactor 2026-11-15 03:29:32 +00:00
Sign in to join this conversation.