description: "The persisted session-projection cache for deployments and maintainers choosing, configuring, or debugging durable checkpoints, zero-I/O list reads, and accelerated cold projection folds."
English | 中文
dsh-session-projection-cache persists the state checkpoints of every registered projection unit (ctx.sessionProjectionCache) as one versioned document per session in the session_projcache storage domain's per-record layout. The shipped JSON backend stores each record at <root>/session_projcache/sessions/<id>.json, and the cache never reads the session-persistence layer. A stored row is a fold shortcut, never an authority: it may be stale — its seq says exactly how stale — but never wrong. Three mandatory checkpoints (session creation, turn/end, and session disposal) plus configurable count and interval throttles keep the cache fresh. Choose it when list views need synchronous cached values or cold projection folds should skip an already-checkpointed prefix.
Mount this package beside the projection registry and the storage stack when clients should list projection values for cold sessions without loading their logs. Without it, consumers must obtain the log before they can reconstruct cold projection values.
Choose it when a deployment restarts sessions and needs durable projection values for history lists, statistics, or goal snapshots. Skip it when projections serve only live sessions, or when the extra storage writes cost more than the saved projection work.
Both throttle fields are required — flush cadence is a deployment choice with no universally correct value:
The cache opens its domain through the storage stack, so base mounts storage, storage-json (root dshHomePath('storages')), and storage-domain (backend: json) before it:
- id: session-projection-cache
name: '@deepseek-ai/dsh-session-projection-cache'
config:
writeEveryEvents: 200
writeIntervalMs: 5000
| Field | Default | Meaning |
|---|---|---|
writeEveryEvents |
required | Committed events per session that force a durable checkpoint write between mandatory points |
writeIntervalMs |
required | Longest time a dirty checkpoint may stay unwritten between mandatory points |
The plugin injects storageDomain, sessionProjections, and sessions. The generated configuration catalog is the exhaustive source for every accepted field and its JSDoc.
Three mandatory points always write: session creation persists the seed-derived cut, turn/end persists the value that listing reads want, and session disposal persists the final live cut. Between them, the configured count and interval throttles write as events accumulate. Every write atomically replaces the session's complete record through the domain write chain; a failure logs a warning and keeps the cache stale, and the next write self-heals.
cachedSnapshot(meta, inheritedEventCount) synchronously serves client values from the storage domain's in-memory tables with zero I/O. It accepts only an identity-matching record and version- and schema-matching keys, then returns a { asOfSeq, values } cut at the lowest served-row watermark. cachedPredecessorTitle(meta, inheritedEventCount) is the narrower listing-only exception: a structurally admitted predecessor record whose lifecycle matches may expose only a current-version-compatible title row. The title is a possibly stale fact from a durable prefix, not a fold seed; it carries the sentinel asOfSeq: -1 because a cardinality-changing Session migration can invalidate the predecessor row's numeric sequence. All other predecessor rows remain unavailable. An unseeded listing knows that its cut is zero; a seeded header-only listing does not know the numeric cut and skips both fast paths until an authoritative body read supplies it. coldSnapshot(meta, inheritedEventCount, events) accepts the exact cut with a complete ordered log, skips the checkpointed prefix while folding, and refreshes the record without reading persistence itself.
The log leads and the cache follows: a live checkpoint flushes the session's buffered events durably before the cache row lands, so a crash can leave the cache behind the log but never ahead of it. Reads and writes share the storage domain's coherent in-memory state; the per-unit write chain mutates memory only after durability. Each version-stamped record must match the live unit schema and complete lifecycle identity (formatVersion, createdAt, cwd, isSeeded, and inheritedEventCount), so a row folded from another Session format generation or fork cut cannot seed the caller. The JSON backend stores each record at <root>/session_projcache/sessions/<id>.json in an owner-only directory tree.
Upgrades never cost the boot or expose an unproven fold. Records stamped with a version in the spec's compatibleVersions remain structurally readable for a current checkpoint rewrite, but a missing or older formatVersion never matches a current Session and therefore cannot seed hydration. A lifecycle-matching predecessor title remains available only through the listing hint above because title text is invariant across the adjacent Session-format edges and its row still passes the current projection stateVersion and schema. Once the format matches, absent lineage fields decode as the unseeded lineage — exact for unseeded sessions, while a seeded caller fails the identity match and refolds cold. A stored record that still fails schema validation is moved aside as <id>.json.bak.<stamp> under the domain's invalidRecords: 'backup-and-skip' policy, logged with its cause, and rebuilt by the next checkpoint.
Read these pages when the package-level contract is not enough. They move from the cache to the registry it checkpoints and the storage domain that holds its records.
ctx.sessionProjections service whose checkpoints this cache persists.None, as the persisted cache accelerates host-side reads of projection state and registers nothing model-facing.
None; the cache never assembles or sends provider requests.
These limits define where the cache needs operational care. They are current package constraints, not a task backlog.
tests/fixtures/ and test cases in tests/fixtures.spec.ts proving the chosen disposition: read-compat recovery (compatibleVersions), current-version rewrite, or backup-and-skip salvage. A bump whose old records are simply discarded still proves that the discard neither fails the boot nor poisons the tree.