L1 · the SessionStore PORT, the event taxonomy, and the pure fold (02). The
loop talks to this protocol and nothing below it — swap MemoryStore for a
Phase-2 SQLiteStore with zero loop changes. apply-event is PURE (no IO):
store impls call it on the write path; a Phase-2 recovery path folds the log
with it. Depends only on the PURE payload ns (for payload-ref?), never on
payload-io — so there is no cycle.
L1 · the SessionStore PORT, the event taxonomy, and the pure fold (02). The loop talks to this protocol and nothing below it — swap MemoryStore for a Phase-2 SQLiteStore with zero loop changes. `apply-event` is PURE (no IO): store impls call it on the write path; a Phase-2 recovery path folds the log with it. Depends only on the PURE `payload` ns (for `payload-ref?`), never on `payload-io` — so there is no cycle.
(apply-event view {:keys [event/type] :as ev})(view event) → view'. PURE. The single source of truth for how an event
advances the view (02 §6). Events carry results, never recipes.
`(view event) → view'`. PURE. The single source of truth for how an event advances the view (02 §6). Events carry results, never recipes.
(assert-pin-head! store pin)When :pin/ref names a head ({:session/id … :head/id …}), that head must be published in that session's durable log. Mechanical existence — the engine still interprets nothing else about the ref. An UNKNOWN session is a dangling ref too (impls differ in how read-state fails on one — guard it).
When :pin/ref names a head ({:session/id … :head/id …}), that head must be
published in that session's durable log. Mechanical existence — the engine
still interprets nothing else about the ref. An UNKNOWN session is a
dangling ref too (impls differ in how read-state fails on one — guard it).(assert-resolvable-refs! store data)Every payload-ref reachable in data must already resolve in the store —
blobs persist BEFORE the facts/pins that reference them (the no-dangling-
refs invariant extended to the embedder fact layer).
Every payload-ref reachable in `data` must already resolve in the store — blobs persist BEFORE the facts/pins that reference them (the no-dangling- refs invariant extended to the embedder fact layer).
(collect-refs data)Every payload-ref reachable in data (a view, an event, an entity).
Every payload-ref reachable in `data` (a view, an event, an entity).
(current-head view)The folded current head map, or nil before the first published boundary.
The folded current head map, or nil before the first published boundary.
(current-resume-head view)The latest published head that is a valid DEFAULT basis for resume/attach/ fork — i.e. every head kind EXCEPT :turn-aborted (U2 wreckage). A wreckage head carries a dead turn's vars and is reachable only by an explicit :head/id; it must never silently become a restore source. (:heads is in publish order — the fold conj's.)
The latest published head that is a valid DEFAULT basis for resume/attach/ fork — i.e. every head kind EXCEPT :turn-aborted (U2 wreckage). A wreckage head carries a dead turn's vars and is reachable only by an explicit :head/id; it must never silently become a restore source. (:heads is in publish order — the fold conj's.)
(edge-with-id edge)Content-address a lineage edge. The id hashes the edge content without :edge/id, matching the immutable-head convention.
Content-address a lineage edge. The id hashes the edge content without :edge/id, matching the immutable-head convention.
(head-by-id view head-id)The immutable head with head-id in a folded view.
The immutable head with `head-id` in a folded view.
(head-with-id head)Build a content-addressed immutable head from head content. The id hashes the canonical head content without :head/id, so it is reproducible.
Build a content-addressed immutable head from head content. The id hashes the canonical head content without :head/id, so it is reproducible.
(kept-messages view)The messages surviving compaction (a PURE view derivation, shared by
request-assembly and compaction — 05 §4, 07 §4): the :message of every
message-bearing event (:message/appended | :session/compacted) in
(:events view) whose :event/id >= :compact-from-event-id (nil ⇒ all).
⛔ Pruned over the LOG, not over :messages — message entities carry no
:event/id, and the compact frame's own event-id == the boundary, so it and
everything after survive.
The messages surviving compaction (a PURE view derivation, shared by request-assembly and compaction — 05 §4, 07 §4): the `:message` of every message-bearing event (`:message/appended` | `:session/compacted`) in `(:events view)` whose `:event/id` >= `:compact-from-event-id` (nil ⇒ all). ⛔ Pruned over the LOG, not over `:messages` — message entities carry no `:event/id`, and the compact frame's own event-id == the boundary, so it and everything after survive.
(message-by-id view message-id)The message entity with message-id in a folded view.
The message entity with `message-id` in a folded view.
(next-head-range view to-event-id)The event range a newly published head should cover, ending at to-event-id.
The first head covers from event 1; later heads start after their basis range.
The event range a newly published head should cover, ending at `to-event-id`. The first head covers from event 1; later heads start after their basis range.
(pin-key pin)Pins are keyed by the STRING form of :pin/name (kw or string accepted).
Pins are keyed by the STRING form of :pin/name (kw or string accepted).
(prepare-head view sid head)Prepare a head for publication against the current folded view. Validates the optimistic basis when :head/expected-basis is present.
Prepare a head for publication against the current folded view. Validates the optimistic basis when :head/expected-basis is present.
(prepare-pin pin current now)CAS + stamp a pin against the current stored pin (mirrors prepare-head): when the incoming pin CARRIES :pin/expected-version it must equal the current version (nil ⇒ the pin must not exist) or :fractal/pin-cas-failed throws. Returns the stamped pin (version bumped, :pin/at = now).
CAS + stamp a pin against the current stored pin (mirrors prepare-head): when the incoming pin CARRIES :pin/expected-version it must equal the current version (nil ⇒ the pin must not exist) or :fractal/pin-cas-failed throws. Returns the stamped pin (version bumped, :pin/at = now).
(subscribe! store sid callback)→ unsubscribe fn. Delivers each event + transient delta (09).
→ unsubscribe fn. Delivers each event + transient delta (09).
(list-pins store)→ all current pins, sorted by name.
→ all current pins, sorted by name.
(peek-next-id store sid counter-key)The id append-event! WILL assign next for counter-key. VALID ONLY on the single writer thread.
The id append-event! WILL assign next for counter-key. VALID ONLY on the single writer thread.
(current-view store sid)STRONG read-your-writes snapshot of the folded view. MUST NOT delegate to read-state. The loop + api read state ONLY through this.
STRONG read-your-writes snapshot of the folded view. MUST NOT delegate to read-state. The loop + api read state ONLY through this.
(pin! store pin)Upsert the named durable pointer {:pin/name str|kw :pin/ref edn (+ optional :pin/meta)}. CAS like publish-head!: when the pin carries :pin/expected-version it must equal the current version (nil ⇒ the pin must not exist yet) or a typed :fractal/pin-cas-failed throws. Payload-refs inside :pin/ref must resolve; a {:session/id … :head/id …} ref must name a published head. Returns the stamped pin (with :pin/version, :pin/at).
Upsert the named durable pointer {:pin/name str|kw :pin/ref edn
(+ optional :pin/meta)}. CAS like publish-head!: when the pin carries
:pin/expected-version it must equal the current version (nil ⇒ the pin
must not exist yet) or a typed :fractal/pin-cas-failed throws. Payload-refs
inside :pin/ref must resolve; a {:session/id … :head/id …} ref must name a
published head. Returns the stamped pin (with :pin/version, :pin/at).(create-session! store session-map)Idempotent + atomic. Insert a fresh per-session slot keyed by :session/id IF ABSENT; a 2nd call returns the existing handle, never nuking state. Returns a SessionHandle (02 §5).
Idempotent + atomic. Insert a fresh per-session slot keyed by :session/id IF ABSENT; a 2nd call returns the existing handle, never nuking state. Returns a SessionHandle (02 §5).
(append-event! store sid event)THE write op. Under the per-session STORE LOCK: stamp :event/id + :event/at (always) and any creating-event entity id, PERSIST, then (on success) fold via apply-event into the view cache, then schedule a NON-BLOCKING live notification out of the lock. Returns the stamped event.
THE write op. Under the per-session STORE LOCK: stamp :event/id + :event/at (always) and any creating-event entity id, PERSIST, then (on success) fold via apply-event into the view cache, then schedule a NON-BLOCKING live notification out of the lock. Returns the stamped event.
(read-payload* store ref)Dereference a tagged ref to its value via global content lookup.
Dereference a tagged ref to its value via global content lookup.
(read-pin store pin-name)→ the current stamped pin for pin-name, or nil.
→ the current stamped pin for pin-name, or nil.
(append-fact! store fact)Append one store-scoped opaque fact {:fact/tag kw :fact/value edn} (+ optional keys, all opaque). The store stamps :fact/id (monotonic, store-scoped) + :fact/at. Payload-refs inside :fact/value must already resolve (blobs-before-facts — dangling refs are rejected).
Append one store-scoped opaque fact {:fact/tag kw :fact/value edn}
(+ optional keys, all opaque). The store stamps :fact/id (monotonic,
store-scoped) + :fact/at. Payload-refs inside :fact/value must already
resolve (blobs-before-facts — dangling refs are rejected).(append-lineage-edge! store sid edge)Phase 4: content-address and append one invocation/derivation lineage edge as a durable :lineage/edge-added event in session sid's log. Returns the stamped edge event.
Phase 4: content-address and append one invocation/derivation lineage edge as a durable :lineage/edge-added event in session sid's log. Returns the stamped edge event.
(intern-payload! store value opts)Content-address value into the GLOBAL blob store (id = sha256 over canonical-bytes). Returns a tagged opaque payload-ref. IDEMPOTENT (dedup). No sid: blobs are global Merkle nodes.
Content-address value into the GLOBAL blob store (id = sha256 over canonical-bytes). Returns a tagged opaque payload-ref. IDEMPOTENT (dedup). No sid: blobs are global Merkle nodes.
(publish-head! store sid head)Phase 4: atomically publish an immutable content-addressed head. Under the same per-session STORE LOCK as append-event!: validate optional :head/expected-basis against the folded :current-head, compute :head/basis, :head/event-range, and :head/id, persist a :head/published event, fold it, notify live, and return the head.
Phase 4: atomically publish an immutable content-addressed head. Under the same per-session STORE LOCK as append-event!: validate optional :head/expected-basis against the folded :current-head, compute :head/basis, :head/event-range, and :head/id, persist a :head/published event, fold it, notify live, and return the head.
(notify-transient store sid item)Publish a TRANSIENT live signal (no :event/id; never persisted/folded).
Publish a TRANSIENT live signal (no :event/id; never persisted/folded).
(facts-since store fact-id)→ ordered store-scoped facts with :fact/id > fact-id. THE read the disposable app projections fold from.
→ ordered store-scoped facts with :fact/id > fact-id. THE read the disposable app projections fold from.
(read-state store sid)RELAXED snapshot for external/cross-process consumers. Non-blocking.
RELAXED snapshot for external/cross-process consumers. Non-blocking.
(append-events! store sid events)Batch variant: assign consecutive ids + persist + fold in ONE critical section. MemoryStore may delegate to append-event! in a loop.
Batch variant: assign consecutive ids + persist + fold in ONE critical section. MemoryStore may delegate to append-event! in a loop.
(events-since store sid event-id)→ ordered events with :event/id > event-id (backlog catch-up, 09).
→ ordered events with :event/id > event-id (backlog catch-up, 09).
(snapshot-view view)qbu · the view value a head snapshot persists: the full fold state with (:events) PRUNED to exactly what later view derivations still need — the message-bearing events (:message/appended | :session/compacted) at or after the compact boundary (nil boundary ⇒ all message-bearing). That is the precise window kept-messages reads; entity vectors, counters, heads, edges, surface/leaf calls all survive whole. Reopen = this snapshot + a fold of the events after its counter watermark.
qbu · the view value a head snapshot persists: the full fold state with (:events) PRUNED to exactly what later view derivations still need — the message-bearing events (:message/appended | :session/compacted) at or after the compact boundary (nil boundary ⇒ all message-bearing). That is the precise window kept-messages reads; entity vectors, counters, heads, edges, surface/leaf calls all survive whole. Reopen = this snapshot + a fold of the events after its counter watermark.
bj1/88j · the advisory-lease scope for STORE-scoped writes (facts/pins) — part of the cross-impl contract, distinct from every per-session scope (a plain session id). Namespaced so a caller-supplied session id can't collide.
bj1/88j · the advisory-lease scope for STORE-scoped writes (facts/pins) — part of the cross-impl contract, distinct from every per-session scope (a plain session id). Namespaced so a caller-supplied session id can't collide.
(turn-by-id view turn-id)The turn entity with turn-id in a folded view.
The turn entity with `turn-id` in a folded view.
(validate-fact! fact)An appendable fact: a map with a keyword :fact/tag and a :fact/value key. The engine never interprets either — this is shape, not schema.
An appendable fact: a map with a keyword :fact/tag and a :fact/value key. The engine never interprets either — this is shape, not schema.
(verify-no-dangling-refs store sid)The (hopefully empty) vector of payload-refs in the session view that do not resolve in the store. A non-empty result violates the storage invariant — a blob write must precede the event that references it (02 §3, §8).
The (hopefully empty) vector of payload-refs in the session view that do not resolve in the store. A non-empty result violates the storage invariant — a blob write must precede the event that references it (02 §3, §8).
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |