Skip to content

Commit 3d1d682

Browse files
zardusclaude
andcommitted
discord-feedback: self-heal a stale nix dev shell instead of dying
A long-lived `nix develop` shell can go stale: its PATH still points at an old-generation `pwnshop` wrapper whose launcher script no longer exists in the checkout, so every `pwnshop ...` exits 127 ("No such file or directory"). The bot trusted `IN_NIX_SHELL` and called the bare `pwnshop` unconditionally, so a stale shell made all validation attempts 127 with no per-challenge logs -- indistinguishable from "all tests failed", which sent the fix agent chasing a phantom breakage until the run died. Preflight the in-shell `pwnshop` with a cheap `--help`; if it can't even launch, fall back to `nix develop --command pwnshop` (a fresh flake eval that always resolves the repo's current pwnshop) for the rest of the run. The decision is cached so we probe at most once. A working in-shell pwnshop still takes the fast bare path -- no added `nix develop` overhead in the common case. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 1b06bb4 commit 3d1d682

1 file changed

Lines changed: 49 additions & 3 deletions

File tree

tools/feedback/discord-feedback

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1729,10 +1729,56 @@ def build_fallback_pr_body(
17291729
return "\n".join(body).rstrip() + "\n"
17301730

17311731

1732+
_PWNSHOP_PREFIX: Optional[list[str]] = None
1733+
1734+
1735+
def _pwnshop_prefix(repo: pathlib.Path) -> list[str]:
1736+
"""Decide how to invoke pwnshop, once per run, and cache it.
1737+
1738+
`nix develop --command pwnshop` re-evaluates the flake and always resolves the repo's
1739+
*current* pwnshop, but it's slow, so when we're already inside a dev shell we'd rather
1740+
call the bare `pwnshop` on PATH. The catch: a long-lived dev shell can go stale -- its
1741+
PATH still points at an old-generation pwnshop wrapper whose launcher script no longer
1742+
exists in the checkout, so every `pwnshop ...` exits 127 ("No such file or directory").
1743+
That looks exactly like "all tests failed with no logs", which sends the fix agent
1744+
chasing a phantom breakage until the run dies. So preflight the in-shell pwnshop with a
1745+
cheap `--help`; if it can't even launch, fall back to `nix develop --command` (a fresh
1746+
flake eval) instead of trusting the stale shell.
1747+
"""
1748+
global _PWNSHOP_PREFIX
1749+
if _PWNSHOP_PREFIX is not None:
1750+
return _PWNSHOP_PREFIX
1751+
fresh = ["nix", "develop", "--command", "pwnshop"]
1752+
if not os.environ.get("IN_NIX_SHELL"):
1753+
_PWNSHOP_PREFIX = fresh
1754+
return _PWNSHOP_PREFIX
1755+
try:
1756+
probe = subprocess.run(
1757+
["pwnshop", "--help"],
1758+
cwd=repo,
1759+
stdout=subprocess.DEVNULL,
1760+
stderr=subprocess.PIPE,
1761+
timeout=60,
1762+
)
1763+
ok = probe.returncode == 0
1764+
detail = probe.stderr.decode("utf-8", "replace").strip()
1765+
except (OSError, subprocess.SubprocessError) as error:
1766+
ok = False
1767+
detail = str(error)
1768+
if ok:
1769+
_PWNSHOP_PREFIX = ["pwnshop"]
1770+
else:
1771+
click.echo(
1772+
"Warning: the in-shell `pwnshop` failed to launch "
1773+
f"(stale nix dev shell?): {detail or 'exited nonzero'}. "
1774+
"Falling back to `nix develop --command pwnshop` for this run."
1775+
)
1776+
_PWNSHOP_PREFIX = fresh
1777+
return _PWNSHOP_PREFIX
1778+
1779+
17321780
def pwnshop_invocation(repo: pathlib.Path, args: list[str]) -> list[str]:
1733-
if os.environ.get("IN_NIX_SHELL"):
1734-
return ["pwnshop", *args]
1735-
return ["nix", "develop", "--command", "pwnshop", *args]
1781+
return [*_pwnshop_prefix(repo), *args]
17361782

17371783

17381784
def run_logged(

0 commit comments

Comments
 (0)