Summary
tests/test_opencode_live.py gates on shutil.which("opencode") is not None. That only proves a file resolves on PATH, not that it runs. On a WSL environment where opencode had been installed via the Windows npm, which() found a WSL-visible wrapper whose target no longer exists:
/bin/sh: 0: cannot open /mnt/c/Users/dracic/AppData/Roaming/npm/node_modules/opencode-ai/bin/opencode: No such file
Every attempt to opencode serve then exits rc=2 during startup and the module reports 1 failure + 4 errors:
bmad_loop.adapters.opencode_http.OpencodeServerError: could not start `opencode serve` after 3 attempts (server exited rc=2 during startup)
The module's own contract is "a newer opencode that breaks the contract surfaces here as a loud — but cleanly skippable — failure". A broken install is not contract drift, but it currently produces the loud failure instead of the clean skip, polluting local baselines on any machine with a stale shim (stale npm symlinks through the WSL mount are a common way to get one).
Suggested fix
Harden the gate to require a runnable binary, keeping the loud-on-contract-drift behavior for installs that do run:
def _opencode_runs() -> bool:
if sys.platform == "win32" or shutil.which("opencode") is None:
return False
try:
return subprocess.run(["opencode", "--version"], capture_output=True, timeout=10).returncode == 0
except (OSError, subprocess.SubprocessError):
return False
HAVE_OPENCODE = _opencode_runs()
A shim that cannot even print its version skips with the existing reason; a live server that then violates the pinned API contract still fails loudly, as designed.
Observed on WSL (Ubuntu on Windows 11) during the #254 full-suite verification; the failures reproduce identically on the merge base, so they are unrelated to that change.
Summary
tests/test_opencode_live.pygates onshutil.which("opencode") is not None. That only proves a file resolves on PATH, not that it runs. On a WSL environment where opencode had been installed via the Windows npm,which()found a WSL-visible wrapper whose target no longer exists:Every attempt to
opencode servethen exits rc=2 during startup and the module reports 1 failure + 4 errors:The module's own contract is "a newer opencode that breaks the contract surfaces here as a loud — but cleanly skippable — failure". A broken install is not contract drift, but it currently produces the loud failure instead of the clean skip, polluting local baselines on any machine with a stale shim (stale npm symlinks through the WSL mount are a common way to get one).
Suggested fix
Harden the gate to require a runnable binary, keeping the loud-on-contract-drift behavior for installs that do run:
A shim that cannot even print its version skips with the existing reason; a live server that then violates the pinned API contract still fails loudly, as designed.
Observed on WSL (Ubuntu on Windows 11) during the #254 full-suite verification; the failures reproduce identically on the merge base, so they are unrelated to that change.