dsh-session-projection
Session Projection Rules
Summary
Keep recoverable session facts in Projection and expose them through their owning services. Read the API and lifecycle for the supported preparation, registration, read, and cleanup contracts.
-
Put all persisted or restorable session-derived state in Projection, including host-only state. Reuse an existing owner when suitable. Keep external resources and process-scoped ownership outside persisted state. Persist facts, not registration handles, promises, or runtime resources.
-
Do not expose projection definitions or handles as production read APIs. Keep the ready handle private; consumers use the owning service's domain methods. A handle is a process-local reader, recreated during activation. Require
sessionProjectionswhen the service depends on it; optional registration is only for optional contributions. Do not hide a missing required dependency with another recovery path.A runtime that needs several projected states receives one typed object of callbacks created with
handle.readerFor(session). Add properties instead of a constructor parameter or feature-specific reader for each state. Each callback has type() => S; single-purpose collaborators receive it directly. These host-state readers are separate from wire snapshots and live Cordis Context; they own no registration, disposal, cache or I/O. Registration, Session preparation and handle lifetimes stay with their owners. Rule 9 defines synchronous API compatibility. -
State recovery through
initandapplyis synchronous and deterministic. Do not perform I/O or trigger Cordis hooks, models, or tools. Runtime hooks own those effects. Replay must not repeat them. Return the same state reference for unrelated events. Keep views synchronous and preserve their references when visible values do not change. -
Persist JSON state that its schema accepts. Follow the README's state-version and checkpoint-watermark rules. Restoring a checkpoint and replaying its suffix must match full replay. Change the version when state fields or recovery semantics change.
-
Prefer fixed-size or sublinear state. Growth is acceptable only when slow enough to remain negligible. Necessary linear state must have a current use and explicit memory, replay, and per-event costs. Do not retain history-sized indexes, including event sequence collections, by habit. Do not discard required data or change behavior to reduce size. Start with a complete implementation; optimize for a concrete need.
-
Caches must be discardable and rebuildable without changing behavior. A sequence reference alone is insufficient when a synchronous consumer needs the referenced payload. Store the required current value within rule 5, or prepare the payload through an explicit asynchronous path. Do not hide full-log reads in a cache miss. Do not add
snapshotEvents,eventAt,ownEvents, or equivalent wrappers: history need not stay in memory. An async wrapper does not make synchronous history reads asynchronous. Existing host replay may remain for named supported callers, with an owner and removal condition; this does not permit Client cache-miss full-log reads. Remove superseded recovery helpers; cache reconstruction must not duplicate recovery rules.