diff --git a/docs/superpowers/plans/2026-06-21-cyclone-pipeline-agent.md b/docs/superpowers/plans/2026-06-21-cyclone-pipeline-agent.md index 14cca1e..f468ea6 100644 --- a/docs/superpowers/plans/2026-06-21-cyclone-pipeline-agent.md +++ b/docs/superpowers/plans/2026-06-21-cyclone-pipeline-agent.md @@ -980,7 +980,8 @@ Add the methods to the `CycloneClient` class (below `scheduler_status`): params: dict[str, str] = {"limit": str(limit)} if since: params["since"] = since - assert self._http is not None + if self._http is None: + raise RuntimeError("use `async with CycloneClient(...)`") last_exc: Exception | None = None for attempt in range(MAX_RETRIES): try: @@ -992,10 +993,15 @@ Add the methods to the `CycloneClient` class (below `scheduler_status`): ClaimSummary.model_validate(c) for c in _extract_items(resp.json()) ] - except (httpx.HTTPStatusError, httpx.RequestError) as e: + except httpx.HTTPStatusError as e: + # 4xx is terminal — surface immediately, do not retry + if e.response is not None and e.response.status_code < 500: + raise last_exc = e - if attempt < MAX_RETRIES - 1: - await asyncio.sleep(BACKOFF_S[attempt]) + except httpx.RequestError as e: + last_exc = e + if attempt < MAX_RETRIES - 1: + await asyncio.sleep(BACKOFF_S[attempt]) assert last_exc is not None raise last_exc @@ -1003,11 +1009,13 @@ Add the methods to the `CycloneClient` class (below `scheduler_status`): self, file_path, payer: str = "co_medicaid" ) -> ParseSummary: """POST the .edi/.txt file to cyclone's parse endpoint. - Returns a typed summary. + Returns a typed summary. POSTs are not retried on transport + failures (caller is responsible for dedup). """ from pathlib import Path # local import keeps the top of the file lean path = Path(file_path) - assert self._http is not None + if self._http is None: + raise RuntimeError("use `async with CycloneClient(...)`") with path.open("rb") as f: resp = await self._http.post( "/api/parse-837",