Skip to content

Commit 7df4965

Browse files
fix(skillopt-sleep): surface Claude CLI spawn failures instead of silent zero scores (#126)
* fix(skillopt-sleep): surface Claude CLI spawn failures instead of silent zero scores In _call and attempt_with_tools, the bare 'except Exception: return ""' swallows FileNotFoundError (e.g. bare 'claude' on Windows with npm .cmd shim) and any other spawn failure, returning an empty string that the trainer treats as a legitimate model response that scores 0.0 everywhere. Now the exception is caught explicitly: last_call_error is set, a warning is logged, and the empty-string return is preserved for backward compatibility of the control flow. This mirrors the pattern from #92 (codex backend) which fixed the same class of 'dead CLI masquerades as nothing to learn' bug. Issue: #121 * test(skillopt-sleep): add tests verifying Claude CLI spawn failures are surfaced Add two tests to TestClaudeCliBackendBare: - test_spawn_failure_sets_last_call_error: _call sets last_call_error and returns '' when subprocess.run raises FileNotFoundError. - test_attempt_tools_spawn_failure_sets_last_call_error: same for attempt_with_tools. These prove the fix from the parent commit (surface spawn failures instead of silently scoring 0) and guard against regressions.
1 parent df94a91 commit 7df4965

2 files changed

Lines changed: 42 additions & 2 deletions

File tree

skillopt_sleep/backend.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,12 @@ def _call(self, prompt: str, *, max_tokens: int = 1024) -> str:
634634
cmd, capture_output=True, creationflags=_NO_WINDOW, text=True, timeout=self.timeout, cwd=clean_cwd,
635635
input=prompt,
636636
)
637-
except Exception:
637+
except Exception as exc:
638+
import logging
639+
self.last_call_error = f"Claude CLI spawn failed: {exc}"
640+
logging.getLogger("skillopt_sleep").warning(
641+
"Claude CLI could not be executed: %s", exc,
642+
)
638643
return ""
639644
finally:
640645
try:
@@ -698,7 +703,12 @@ def attempt_with_tools(self, task, skill, memory, tools):
698703
)
699704
resp = (proc.stdout or "").strip()
700705
self._detect_cli_error(resp, proc.stderr or "")
701-
except Exception:
706+
except Exception as exc:
707+
import logging
708+
self.last_call_error = f"Claude CLI spawn failed: {exc}"
709+
logging.getLogger("skillopt_sleep").warning(
710+
"Claude CLI could not be executed: %s", exc,
711+
)
702712
resp = ""
703713
self._tokens += len(prompt) // 4 + len(resp) // 4
704714
called: List[str] = []

tests/test_sleep_engine.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,6 +1118,36 @@ class FakeProc:
11181118
# But it's also recorded for detection
11191119
self.assertIn("Not logged in", getattr(be, "last_call_error", ""))
11201120

1121+
def test_spawn_failure_sets_last_call_error(self):
1122+
"""When subprocess.run raises FileNotFoundError, _call must set
1123+
last_call_error and log a warning instead of silently returning ''."""
1124+
from skillopt_sleep.backend import ClaudeCliBackend
1125+
be = ClaudeCliBackend(
1126+
claude_path="/nonexistent/claude-binary",
1127+
timeout=3,
1128+
)
1129+
result = be._call("test prompt")
1130+
self.assertEqual(result, "")
1131+
self.assertIn("Claude CLI spawn failed", be.last_call_error)
1132+
1133+
def test_attempt_tools_spawn_failure_sets_last_call_error(self):
1134+
"""When subprocess.run raises in attempt_with_tools, last_call_error
1135+
must be set and a warning logged."""
1136+
from skillopt_sleep.backend import ClaudeCliBackend
1137+
from skillopt_sleep.types import TaskRecord
1138+
be = ClaudeCliBackend(
1139+
claude_path="/nonexistent/claude-binary",
1140+
timeout=3,
1141+
)
1142+
task = TaskRecord(
1143+
id="t1", project="/p", intent="test",
1144+
reference="ref", reference_kind="exact",
1145+
tags=[], split="train",
1146+
)
1147+
resp, called = be.attempt_with_tools(task, "", "", tools=["search"])
1148+
self.assertEqual(resp, "")
1149+
self.assertIn("Claude CLI spawn failed", be.last_call_error)
1150+
11211151

11221152

11231153

0 commit comments

Comments
 (0)