First slice-2 increment: the presenter-independent sessions routes, additive and
non-breaking (no surface rewired, no hand-rolled path deleted yet — the cli/web
rewire + deletions + live smoke land in part 2).
- create_session / list_sessions / get_session_messages / get_session_tools over
WorldtreeClient.sessions.*, each building the request from ratatoskr's domain
params and mapping the SDK's ApiError floor by ROUTE (INV-CUT-2): create 404 →
AgentNotFound, bound 502 → BifrostHandshakeFailed, list 422 cursor_invalid →
InvalidCursor, else the SessionApiFailed default.
- Open-world reads returned VERBATIM (parity-pass posture): the routes return the
SDK's open dicts, not ratatoskr's typed SessionInfo/SessionPage — those typed
result shapes retire when the presenters are rewired to read mappings (adopt the
dep's canonical open-world way, reference-impl doctrine).
- Transitional: wt imports the caller-semantic exceptions + BifrostBinding from the
retiring sessions module (one-way, no cycle); they relocate into the adapter as
their call-sites are rewired.
- Cancel + the resilient turn STREAM are deferred to part 2, where they wire into
the async presenter loop and are validated by the live smoke.
Suite 555 green (541 + 14); mypy strict + ruff clean. Patch (internal, additive).
Slice-1 of the SDK cutover (docs/contracts/worldtree_sdk_cutover.contract.md):
the adapter chokepoint onto worldtree-sdk 1.0.0, unit-tested but not yet wired
to any surface (that is slice-2).
- build_client(base_url, *, api_key, admin_key=None, transport) constructs the
single WorldtreeClient over a ratatoskr-owned injected httpx.AsyncClient.
INV-CUT-1: the SDK is given the transport (_owns_client=False) and never closes
it — proven by a test asserting aclose() leaves ratatoskr's transport open.
- translate_error implements the § Error map DEFAULT: SDK ApiError → the adapter's
SessionApiFailed (carrying the SDK's parsed status/error_code/body); every
discriminated WorldtreeError subclass passes through by identity. Route-specific
rows land at their call-sites in later slices (the route is the discriminator).
- SessionApiFailed gains error_code vs the retiring sessions.py copy (extends it
per the contract error-map row); the two coexist transiently and reconcile in
slice-2 (DEC-4 incremental cutover — nothing wires the adapter this slice, so
they never meet at runtime).
Deletes no hand-rolled path, so DEC-4's live-smoke bar does not apply yet.
Suite 541 green (534 + 7 new); mypy + ruff clean. Patch (internal foundation;
the cutover's minor bump is DEC-6 at slice-7 ship).