Skip to content

opencode live gate: which() finds broken shims — probe that the binary actually runs so a dead install skips instead of failing #294

Description

@dracic

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions