SessionHandler Cohesion Split
Status: COMPLETE — shipped in commit e949984a (pushed and deployed with
the F5 dispatch-reply hardening group; certifying gate11 rc=0,
30,790 / 0 / 0 / 0 at a 265 s test phase). Packets P1–P4 all landed:
_session_kg.py (7 pure Cypher builder functions + SessionKgOps),
_session_events.py (SessionEventOps), session.py shrunk 731→444 lines /
13 methods, with 87/87 parity tests green throughout every packet. One
contract refinement vs the design: build_get_query kept the
(kg_key, raw_id) signature — the contract diagram was synced to match.
Design: plans/session-handler-split-design.md +
plans/contracts/session-handler-split.mmd.
Why
Code review flagged gateway/handlers/session.py::SessionHandler as a god class:
607 lines (limit 200) and 24 methods (limit 10). Governing ruling: refactor by
cohesion, not LOC — no new features, no schema changes, byte-identical behavior.
The cut
_session_kg.py— the entire session KG contract in one module: 6 pure Cypher-builder module functions (build_active/list/get/open/close_query,shape_get_result) +_deserialize_session. Pure builders become module functions, NOT methods — a singleSessionKgOpswith everything would re-trip both thresholds it exists to fix. Thecoalesce(s.id, s.session_id)schema-drift contract (previously scattered across four query texts) lives only here.class SessionKgOps(same module): stateful KG I/O + identity — call-timeproject_slug()(RUL-003), project-qualified session key,execute,persist_open/persist_close. Sole owner of_graph_repository._session_events.py—class SessionEventOps: thesession.eventsbroadcasts; sole owner of_processor.SessionHandlerstays the RPC facade: the 7handle_*methods are bound into the RPC registry by name and the 3set_*seams are production wiring — an 11-method frozen public surface. Result as shipped: 24→13 methods, module 731→444 lines; the residual WARNs are structural. User decision filed: facade-aware reviewer thresholds vs further splitting (the flat >10-method rule flags every RPC facade ingateway/handlers/by construction).
Safety rails (all held through landing)
- 76-test behavior floor passes unchanged (verified feasible: zero private reach-ins in the floor files).
- Exactly one mechanical assertion update outside the floor
(
tests/gateway/test_rpc_behavioral.py:125→rpc._session._events._processor). - Parity invariants: byte-identical Cypher (incl. the session-254
HAS_SESSIONroot-connectivity MERGE), identical envelopes/error strings/timeouts/log texts;@tracesmove with their methods, ids unchanged. - Packets P1→P2→P3 + hygiene P4 (+ optional P5 builder-level contract tests), each gated on the shared 4-module test gate.
Known defects (filed 2026-08-05)
Commit ac9b763f made the session-manager acceptance specs self-provisioning,
eliminating the suite's 4 standing skips (164/164 executed, 0 skipped) —
and in doing so surfaced two filed defects on the session RPC surface this
split owns:
- Deployed fleet
session.openis broken: the app container bind-mounts the checkout read-only, sosession.opendies withPermissionErroron.context.lock. Fix is deployment/config territory, filed. session.closehas git-remote side effects: it callsSessionController.end(), which unconditionallygit commit+tag+pushes againstSESSION_ROOT— an RPC that pushes to a remote. A policy seam decision is filed (whether/when an RPC may run git side effects).
Repo pointers
plans/session-handler-split-design.md ·
plans/contracts/session-handler-split.mmd ·
src/orchestrata_ultimate/gateway/handlers/session.py (facade) ·
gateway/handlers/_session_kg.py · gateway/handlers/_session_events.py ·
implementation commit e949984a (precursor SET-2 helper pass: 9914d662;
acceptance self-provisioning: ac9b763f).