Part of #589.
CONTEXT
SessionRecord (pkg/api/session_store.go:12-26) has no venue field, and closed sessions live only in an in-memory ring of 500 (newSessionStore(500), pkg/api/server.go:196-198), wiped on every restart or deploy. ExperienceName is declared on the struct and never populated anywhere (grep-confirmed). The dashboard needs durable, venue-attributed session history. History can only start when this ships; the ring buffer cannot be backfilled. Say so in the release notes.
SCOPE
- VENUE STAMP AT OPEN: add Venue string to SessionRecord. The session opens on a body stream-status transition (handlers_body.go:368-372); at that point the body's node record is at hand, so copy node.Venue into the session. Stamp at open, never rewrite later: this makes mobile-kit history correct across relocations, provided node.venue is kept current (see the node.venue integrity issue and its relocation runbook).
- EXPERIENCE NAME, VERIFY FIRST, DO NOT ASSUME: the maps do not establish that the session-open path knows which experience is streaming. Step one of this issue is verification: read the open path (handlers_body.go:368-372) and the stream_start event emission (pkg/api/event_log.go:12-34) and determine whether an experience name is available at open or at stream_start.
- If YES: stamp ExperienceName from that source and cover it with a test.
- If NO: do not fake it. Record the finding on this issue, leave ExperienceName unpopulated, and notify the dashboard issue so v1 acceptance drops per-experience session counts (the dashboard then shows experiences with deployment and live status only). Filing the plumbing needed to carry the experience to the open path becomes its own follow-up issue.
- DURABLE STORE: append every CLOSED session as one JSON line to daily files under ~/.hydracluster/data/sessions/YYYY-MM-DD.jsonl, atomic append, following the proven hydrastreamingmonitor transitions pattern (hydrastreamingmonitor/internal/history/store.go:16-48). Configurable retention (default 365 days) with a compact step like streamingmonitor's Compact(). Keep the in-memory ring for live views, unchanged.
- QUERY API: extend GET /api/v1/sessions/history with ?from=&to=&venue= reading the JSONL files, merged with the ring for recent data, behind the existing admin bearer auth (pkg/api/server.go:359-361). No org scoping here; the dashboard BFF filters by the org's venue IDs server-side.
- Tests: stamp at open, persistence across restart, date and venue filters, retention compaction.
ACCEPTANCE CRITERIA
- A session opened on a test body (bxl1-test, chunky-turnip-23; NEVER production bodies) closes and survives a service restart, and returns from /api/v1/sessions/history?venue=.
- The record carries the venue the body's node had at open time.
- The experience-name verification result is posted on this issue with file and line evidence, and the dashboard issue is updated with the outcome.
- Runbook documents the store location, retention, and the no-backfill fact.
FILES
- /home/claude-user/hydracluster/pkg/api/session_store.go
- /home/claude-user/hydracluster/pkg/api/handlers_body.go (:368-372 open path)
- /home/claude-user/hydracluster/pkg/api/handlers_sessions.go
- /home/claude-user/hydracluster/pkg/api/event_log.go
- /home/claude-user/hydracluster/pkg/api/server.go
- /home/claude-user/hydrastreamingmonitor/internal/history/store.go (pattern reference)
DEPLOY
Tag, push, CI, auto-update. Verify with hydrarelease verify --project hydracluster. Note the deploy date in the master issue: dashboard history starts here.