molecule-core/workspace-template/tests
rabbitblood 0f2ed6bf0a fix(claude-sdk): #160 — probe CLI directly when SDK swallowed the real stderr
Context: when the claude-agent-sdk wraps a stream error from the CLI
subprocess that it can't categorize (rate limit, auth, network), it
raises a bare `Exception("Command failed with exit code 1\nError output:
Check stderr output for details")`. The exception has no `.stderr` or
`.exit_code` attributes, so #66's `_format_process_error` — which reads
those attributes — has nothing to surface. The log line becomes:

    SDK agent error [claude-code]: Exception: Command failed with exit
    code 1 (exit code: 1)\nError output: Check stderr output for details

That's the placeholder text from the SDK's error path, not the actual
error. Operators chasing a stuck workspace are forced to `docker exec
ws-xxx claude --print` manually to discover the real cause. Observed
today during the rate-limit incident: every PM error line was identical
"Check stderr output for details" while the real cause ("You've hit
your limit · resets Apr 17, 11pm (UTC)") was only visible via manual
reproduction — that cost ~20 minutes of diagnosis time.

## Fix

Add `_probe_claude_cli_error()`: a best-effort subprocess call that runs
`claude --print` with a small probe input, captures stderr+stdout, and
returns the real error string. Bounded by 30s timeout so a hung CLI
can't stall the error path.

Extend `_format_process_error` with ONE narrow fallback: if the
exception has no stderr/exit_code AND its message contains the specific
"Check stderr output for details" marker, call the probe and append
`probed_cli_error=<real error>` to the formatted line.

Critically: the probe only runs in the narrow case where we have
nothing else to log. If `.stderr` or `.exit_code` are present (the
normal ProcessError path from #66), the probe is skipped — no wasted
subprocess, no 30s latency on every error.

## Test coverage

`workspace-template/tests/test_claude_sdk_executor.py` adds 3 new tests:
- `test_format_process_error_probes_cli_when_stderr_swallowed` — the
  happy path: exception matches the marker, probe runs, result appears
  in the formatted line. Probe is monkeypatched so no subprocess spawns
  in the test.
- `test_format_process_error_does_not_probe_when_stderr_already_present` —
  negative: regular ProcessError with `.stderr` set does NOT trigger
  the probe (skip the wasted call).
- `test_format_process_error_does_not_probe_without_swallowed_marker` —
  negative: unrelated plain exceptions (e.g. RuntimeError) do NOT
  trigger the probe (so the common-case error path stays fast).

All 7 `_format_process_error` tests pass locally (4 existing + 3 new):
\`\`\`
pytest tests/test_claude_sdk_executor.py -k format_process_error
======================= 7 passed in 0.06s ========================
\`\`\`

## Impact

Next time the SDK swallows a real error (rate limit, auth failure,
network outage), the workspace log will contain the actual error string
alongside the generic placeholder:

    SDK agent error [claude-code]: Exception: Command failed with exit
    code 1 ... | probed_cli_error="You've hit your limit · resets Apr
    17, 11pm (UTC)"

Diagnosis time drops from "docker exec each ws, run claude --print,
read stderr" (~20 min) to "grep probed_cli_error in platform logs"
(~10 seconds).

Closes #160.
2026-04-15 11:50:55 -07:00
..
__init__.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
conftest.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_a2a_cli.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_a2a_client.py fix(security): complete Phase 30.6 auth headers in a2a_client get_peers and discover_peer 2026-04-14 13:23:44 +00:00
test_a2a_executor.py fix(a2a): cancel() event, stateTransitionHistory capability, wire push store (#173 #174 #175) 2026-04-15 17:58:10 +00:00
test_a2a_mcp_server.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_a2a_tools_impl.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_a2a_tools_module.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_adapters.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_agent_base_urls.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_agent.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_approval.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_audit.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_awareness_client_full.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_claude_sdk_executor.py fix(claude-sdk): #160 — probe CLI directly when SDK swallowed the real stderr 2026-04-15 11:50:55 -07:00
test_cli_executor.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_common_setup.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_compliance.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_config.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_consolidation.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_coordinator_parent.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_coordinator_routing.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_delegation.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_events.py fix(security): Cycle 5 — auth middleware, injection hardening, skill sandbox 2026-04-14 04:44:42 +00:00
test_executor_helpers.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_first_party_plugins.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_governance.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_heartbeat.py fix(security): Cycle 5 — auth middleware, injection hardening, skill sandbox 2026-04-14 04:44:42 +00:00
test_hermes_adapter.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_hermes_providers.py feat(hermes): Phase 1 — multi-provider registry (15 providers, back-compat preserved) 2026-04-15 11:14:35 -07:00
test_hermes_smoke.py feat: implement Hermes adapter create_executor() with OpenRouter fallback 2026-04-13 16:47:29 -07:00
test_hitl.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_main_initial_prompt.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_mcp_memory.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_medo.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_memory.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_molecule_ai_status.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_namespaces.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_openclaw_adapter.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_platform_auth.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_plugins_builtins_drift.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_plugins_builtins.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_plugins_registry.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_plugins.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_preflight.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_prompt.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_qianfan_provider.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_routing_policy.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_sandbox.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_security_scan.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_shared_runtime.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_skills_loader.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_skills_watcher.py fix(security): H1 — replace MD5 with SHA-256 in config/skill watchers 2026-04-14 07:52:07 +00:00
test_telemetry.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_temporal_workflow.py initial commit — Molecule AI platform 2026-04-13 11:55:37 -07:00
test_watcher.py fix(gate-3): update watcher test to expect SHA-256 hash 2026-04-14 01:21:35 -07:00