|
| 1 | +## REVIEW REPORT — P2-T4: Broker unavailability JSON-RPC error |
| 2 | + |
| 3 | +**Scope:** origin/main..HEAD |
| 4 | +**Files:** 3 changed (proxy.py, test_broker_proxy.py, test_broker_stubs.py) |
| 5 | +**Date:** 2026-03-01 |
| 6 | + |
| 7 | +### Summary Verdict |
| 8 | +- [ ] Approve |
| 9 | +- [x] Approve with comments |
| 10 | +- [ ] Request changes |
| 11 | +- [ ] Block |
| 12 | + |
| 13 | +--- |
| 14 | + |
| 15 | +### Critical Issues |
| 16 | + |
| 17 | +None. |
| 18 | + |
| 19 | +--- |
| 20 | + |
| 21 | +### Secondary Issues |
| 22 | + |
| 23 | +**[Low] `except Exception` is broad in `run()`** |
| 24 | + |
| 25 | +The connect-phase catch uses `except Exception`, which captures all non-`BaseException` |
| 26 | +exceptions including unexpected ones (e.g., `MemoryError` is not an issue, but e.g., a |
| 27 | +programming error in `_spawn_broker_if_needed` that raises `AttributeError` would be silently |
| 28 | +swallowed). The guard prevents the client from hanging, so the trade-off is acceptable, but a |
| 29 | +future refinement could narrow the catch to `(TimeoutError, OSError)` — the only exception |
| 30 | +types that legitimately arise from the connect path. |
| 31 | + |
| 32 | +**Suggested fix (optional):** Narrow to `except (TimeoutError, OSError)` with a fallback |
| 33 | +`logger.exception` for anything else. Not a blocker; the current behaviour is safe. |
| 34 | + |
| 35 | +**[Low] `id: null` in error response may confuse some clients** |
| 36 | + |
| 37 | +JSON-RPC 2.0 §5 permits `null` for error responses when the request id is unknown. However, |
| 38 | +some strict clients may log a warning or discard the response entirely if they cannot match it |
| 39 | +to an outstanding request. Consider a future enhancement to read the pending request's `id` |
| 40 | +from stdin with a short timeout (e.g., 0.5s) and use it in the error response. Not a blocker |
| 41 | +for current acceptance criteria. |
| 42 | + |
| 43 | +--- |
| 44 | + |
| 45 | +### Architectural Notes |
| 46 | + |
| 47 | +- The `_send_broker_error` method is a clean, focused helper: <30 lines, single responsibility, |
| 48 | + reused for both spawn and connect failure paths. |
| 49 | +- The inner guard in `_send_broker_error` (catching `_make_stdout_writer()` failure) is the |
| 50 | + right defensive posture — in non-pipe test environments the writer setup fails, and the guard |
| 51 | + ensures the error path doesn't itself raise. |
| 52 | +- Existing tests that previously expected `run()` to raise `TimeoutError` have been correctly |
| 53 | + updated to verify the JSON-RPC error payload instead. The intent of those tests is preserved. |
| 54 | + |
| 55 | +--- |
| 56 | + |
| 57 | +### Tests |
| 58 | + |
| 59 | +- Added `TestBrokerProxyUnavailableError` (5 tests): |
| 60 | + - `test_connect_timeout_sends_jsonrpc_error` — full payload verification |
| 61 | + - `test_error_code_is_minus_32001` — code field check |
| 62 | + - `test_error_message_includes_reason` — prefix + exception text |
| 63 | + - `test_run_does_not_raise_on_connect_failure` — clean return |
| 64 | + - `test_spawn_failure_sends_jsonrpc_error` — spawn-phase error path |
| 65 | +- Updated 2 existing tests (`test_broker_proxy.py` and `test_broker_stubs.py`) that previously |
| 66 | + expected `run()` to raise; now they verify the JSON-RPC error payload. |
| 67 | +- Coverage: 91.59% (≥ 90% required). ✅ |
| 68 | +- All 732 tests pass, 5 skipped. ✅ |
| 69 | + |
| 70 | +--- |
| 71 | + |
| 72 | +### Next Steps |
| 73 | + |
| 74 | +- **Optional FU:** Narrow `except Exception` to `(TimeoutError, OSError)` in `run()` for |
| 75 | + tighter exception scope. Low priority — current behaviour is safe and correct. |
| 76 | +- **Optional FU:** Attempt to read the pending request's `id` from stdin with a short timeout, |
| 77 | + to use a real request id in the error response instead of `null`. Improves client |
| 78 | + compatibility. Low priority — JSON-RPC 2.0 permits `null`. |
| 79 | +- No documentation changes required (this is an internal error-handling improvement with no |
| 80 | + user-visible configuration surface). |
| 81 | + |
| 82 | +**VERDICT: PASS — no blockers; two low-severity observations documented above.** |
0 commit comments