Skip to content

Session Projection

pawaca edited this page Aug 30, 2026 · 2 revisions

Session Projection

Edge adaptation of the upstream log-derived state projection system.

Upstream reference: Session Projection documentation

What Upstream Provides

Session projection is a capability seam that lets domain plugins supply clients with derived state values computed from the committed session event log. It has two services:

  • SessionProjectionRegistry (ctx.sessionProjections) — drives computation: subscribes once to session/event, calls each registered unit's synchronous apply() on every committed event. Provides snapshot() for consistent reads, checkpoint() for persistence, and restore() for cold-log refolding.
  • SessionProjectionCache (ctx.sessionProjectionCache) — persistence layer: throttled write-behind checkpointing, zero-I/O listing reads via cachedSnapshot(), and cold-session tail-read + refold via coldSnapshot(). Cleans up on session/disposed.

Domain plugins register projection units (e.g., GoalService registers 'goal', SessionTitleService registers 'title'). Each unit's apply() must be synchronous, return plain JSON, and preserve reference identity when the event doesn't affect its state.

What Edge Changed

Direct Reuse Both services

SessionProjectionRegistry and SessionProjectionCache are installed as-is. The registry drives computation, the cache handles persistence via storageDomain (backed by DurableObjectStorageBackend). All projection unit registrations (goal, title, sessionListMetadata) come from upstream plugins.

Transport Bridge WebSocket projection push

Upstream clients read projections from in-process memory. Edge captures changes via sessionProjections.onChanged() and delivers them as session/projection WebSocket frames. The bridge buffers entries synchronously at event time and drains them by seq-match in publishSessionEvent() after flush — ensuring projections arrive after their backing events are durable.

sessionListMetadata is the sole exception: it uses a dedicated push with its own fold logic in publishSessionEvent(), because its computation depends on Edge-specific session-list metadata not managed by the registry.

Transport Bridge Initial baseline

session.history and session.list include projection values in their responses. For live sessions, Edge reads projectionSnapshot(). For cold sessions, it falls back to projectionCachedSnapshot() (synchronous domain read from the cache service).

What Edge Did NOT Change

  • Projection unit contract (synchronous apply, plain JSON state, reference identity)
  • Registry drive mechanism (session/event subscription)
  • Cache write timing (throttled write-behind), lifecycle cleanup, cold-snapshot restoration
  • Snapshot/checkpoint/restore API semantics

Performance Characteristics

Per-event drive cost

drive() iterates all registered units (currently: goal, title, sessionListMetadata) and calls each unit's apply(). Each apply is a constant-time last-wins fold. The onChanged callback fires only when a value's reference changes (identity check), so non-affecting events produce zero downstream work.

Push timing

Projection frames are captured synchronously at event time (correct value + correct seq) and drained after the event's flush completes (durable delivery guarantee). The buffer is filtered by entry.seq <= event.seq to prevent later-seq projections from arriving before their events.

Cold-session reads

Path Cost Used By
projectionSnapshot() O(1) — memory read Live sessions
projectionCachedSnapshot() O(1) — synchronous domain read Cold session list + history
coldSnapshot() O(tail events) — tail-read + refold History when cache misses

Architecture Summary

Component Category Edge Code
SessionProjectionRegistry Reuse One ctx.plugin() call
SessionProjectionCache Reuse One ctx.plugin() call
WebSocket projection push Bridge onChanged → buffer → seq-matched drain
Initial baseline merge Bridge summaryProjections() merges cache values

Key observation: The projection system is the connective tissue between upstream business plugins and the Edge transport layer. Upstream plugins register units and compute values; Edge only adds the network delivery channel. The computation engine and persistence cache are fully upstream.

English

中文

Clone this wiki locally