From bfacfe0974c71e9e61c0c767203fc28af39f7ce0 Mon Sep 17 00:00:00 2001 From: Artur Shiriev Date: Sat, 13 Jun 2026 11:23:13 +0300 Subject: [PATCH] docs(claude): update Seam B summary for 0.9.0 multi-decoder routing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CLAUDE.md's Seam B bullet still described the pre-0.9.0 single-decoder contract (a single ResponseDecoder, decode(content, model) only) with no can_decode dispatch, decoders=[...] list, or MissingDecoderError pre-flight. An agent implementing a decoder from it ships an interface that AttributeErrors at dispatch. Rewritten to match the live contract and engineering.md §Seam B. Closes the High finding in planning/audit/2026-06-12-delta-audit.md. Co-Authored-By: Claude Fable 5 --- CLAUDE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index ab03891..7068a2d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -81,7 +81,7 @@ src/httpware/ Three documented internal boundaries. AI agents must respect them — never cross a seam except through its documented protocol. 1. **Seam A** — `Client`/`AsyncClient` ↔ `Middleware`/`AsyncMiddleware` — middleware chain composed at `Client.__init__` and `AsyncClient.__init__`, frozen for the client's lifetime. Internal terminal calls `httpx2.Client.send` or `httpx2.AsyncClient.send`, maps exceptions, raises `StatusError` on 4xx/5xx. Sync and async surfaces are kept at parity. -2. **Seam B** — `Client`/`AsyncClient` ↔ `ResponseDecoder` — called when `response_model` is provided. Signature: `decode(content: bytes, model: type[T]) -> T`. Implementations of both `send` methods call the decoder identically. +2. **Seam B** — `Client`/`AsyncClient` ↔ `ResponseDecoder` list — both clients take `decoders: Sequence[ResponseDecoder] | None` (a *list*, not a single decoder; `None` resolves against installed extras, pydantic-first). When `response_model` is provided, `send`/`send_with_response` (sync and async alike) walk the list and the first decoder whose `can_decode(model: type) -> bool` returns True runs `decode(content: bytes, model: type[T]) -> T`; if no decoder claims the model, `MissingDecoderError` is raised *before* the HTTP call. Decoder exceptions are wrapped as `DecodeError` at the seam. Full contract: [`engineering.md`](planning/engineering.md) §Seam B. 3. **Seam C** — `httpware` ↔ optional extras — each opt-in dependency imported only inside its dedicated module. ## Testing