fix(#20): heid-bug-hunt fixups — admin-stream + bifrost hardening (slice-6)
Cold spec-free panel (Gróa + Hulda + Regin, source-verified by Heid): the adapter's
core re-wrap is sound, but 4 real hardening gaps the conformance CR couldn't see —
all in failure-path normalization + open-world degrade, judged against the general
ConnectFailed floor + the degrade-never-crash promise. All fixed:
- [bug, 3/3] `stream_admin_events` never mapped `ConnectFailed` — the SDK admin-stream
open raises it on a connect-time / auth-resolution failure (the general transport
floor; confirmed in the SDK source), and `stream_turn` + the bifrost GET both catch
it, and this endpoint's OWN comment claimed it did. An unmapped ConnectFailed escaped
the web gen's `except (Sse*)` and aborted the SSE with no `stream_error`. Now mapped
→ `SseConnectFailed`, mirroring stream_turn.
- [bug, 2/3] non-str `type` crashed the web filter — the re-wrap used `ev.type or ""`
(falsy-only), so a truthy non-str `type` (123, a list) reached `.startswith` →
AttributeError. Now `ev.type if isinstance(ev.type, str) else ""` (matches the
admin_id/data isinstance guards — same container-type class as slice-5).
- [robustness] `_session_bifrost_endpoint` did `dict(bstate)` on the open-world 200
body — a non-mapping (list/scalar) → TypeError/500. Now degrades to `{}` (I introduced
this in slice-6 by changing `JSONResponse(bstate)` → `dict(bstate)`).
- [robustness] `_admin_events_endpoint.gen` allocated the transport + built `_wt_client`
BEFORE the try/finally — a construction failure would leak the httpx transport. Moved
`_wt_client` inside the try so the finally always closes it.
Voided (Heid): Regin's `dict(ev.data)` TypeError — the `isinstance(_, Mapping)` guard
already routes non-mappings to `{}` before `dict()`.
Added adapter tests (ConnectFailed→SseConnectFailed; non-str type→"") + a web test
(non-mapping bifrost body → 200 {}). Suite 494 green; my code ruff-clean (13 E501/F841
in test_web_server.py are PRE-EXISTING, HEAD-identical, untouched); mypy clean on wt.py.
Live smoke re-run clean (real session.created event re-wrapped; bifrost 404 envelope).
Patch bump 0.21.19 → 0.21.20.
This commit is contained in: