4ba143c563
Implements docs/contracts/issues/2.contract.md. Two functions (create_session, list_sessions), two frozen dataclasses (SessionInfo, SessionPage), three exception types (AgentNotFound, InvalidCursor, SessionApiFailed). 19 contract-listed tests cover every TESTS: entry verbatim per the tracer-bullet vertical-slice ordering. SessionInfo uses one shape across both endpoints with origin- conditional defaults per INV-001 (create) and INV-002 (list). create- origin always sets list-only fields to (name=None, archived=False, tags=[]); list-origin reads them from the response item with absent/null treated as those same defaults — keeps the dataclass uniform without forcing callers to handle two types. Spotted an internal-inconsistency in the contract at TDD start — POST-003 and happy_create's test description still said "archived is None, tags is None" while the freshly-applied Volva amendment had moved INV-001 to (archived=False, tags=[]). Fixed in-place before writing any tests so the spec stayed coherent. SessionApiFailed.body truncates to <= 1024 bytes at construction, matching the SseConnectFailed / CancelFailed precedent from issue #1. No code shared with sse_client.py (convention-dependency only per issue #2's dependencies: block). 62 tests GREEN total (42 sse_client + 19 sessions + 1 boundary smoke). Ruff clean. No refactor pass — the two functions are ~25 LOC each with distinct error-routing branches that don't naturally share more than they already do.