lazily

package module
v0.25.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 29, 2026 License: MIT Imports: 27 Imported by: 0

README

lazily (Go)

Lazy reactive primitives for Go — the Cell kernel (Source / Computed / Effect, all cells guarded; eager via Computed.Eager()) with automatic dependency tracking and cache invalidation, plus the full lazily-spec wire protocol, CRDT collection types, keyed cell collections, Harel state charts, and the distributed CRDT plane.

A Go port of the lazily reactive family (lazily-rs, lazily-py, lazily-kt, lazily-js, lazily-dart, lazily-zig) — conformant with lazily-spec and lazily-formal. The concurrency surfaces (async reactive context, signaling room, CRDT anti-entropy plane) are built on goroutines and channels: share state by communicating, not by locking.

go get github.com/lazily-hub/lazily-go

The reactive family — the Cell kernel

Two value kinds, named without collision (design #lzcellkernel). Cell is a conceptual word for a value-bearing reactive node, not a Go type — the two kinds are two concrete handle structs, and write protection lives in the type:

  • Source[T] — a value written from outside the graph; the only kind with Set/Merge. It folds writes under a MergePolicy (KeepLatest by default = a plain cell; Sum/Max = the former MergeCell). Cell ≡ Source<KeepLatest>. Constructors: NewSource / NewSourceWithPolicy.
  • Computed[T] — a value computed from upstream; lazily cached and dependency-tracking, with neither Set nor Merge. NewComputed(f) is guarded (an ==-guard suppresses equal recomputes) — the sole derived constructor now that the former Memo is removed: a Computed is the guarded form. computed.Eager() makes it eager (which replaces the former Signal), returning the same handle; computed.Lazy() reverses it.
  • Effect — a side-effect sink (ctx.effect), outside the Cell hierarchy.

The T comparable bound is what the guard needs. For a value type that is not comparable, drop to NewSlot(f) — the bound-free storage-sense primitive (T any, no guard), the escape hatch mirroring lazily-rs's slot().

The v1 Cell[T] read-genus interface is dropped: no Go generic code used it as a bound, and v2 no longer needs a genus for write protection.

Write protection lives in the types: because Computed has no Set, computed.Set(…) does not compile. Values are lazy by default; call Eager on a Computed for eager push-style semantics. Use Effect for side effects (a sink, outside the Cell hierarchy).

Usage

import lazily "github.com/lazily-hub/lazily-go"

ctx := lazily.NewContext()
a := lazily.NewSource(ctx, 2)
b := lazily.NewSource(ctx, 3)

// Lazy: computes on first read, caches, recomputes only when a or b changes.
sum := lazily.NewComputed(ctx, func(c *lazily.Context) int { return a.Get() + b.Get() })
sum.Get() // 5

a.Set(10)
sum.Get() // 13

// Eager: Eager() attaches a puller so the computed re-materializes on every change.
parity := lazily.NewComputed(ctx, func(c *lazily.Context) string {
	if a.Get()%2 == 0 {
		return "even"
	}
	return "odd"
}).Eager()
parity.Get() // "even"
a.Set(11)
parity.Get() // "odd" (already updated before the read)

To react to a Cell from outside the graph (the hook for UI bridges), declare a dependency edge with an Effect — a Cell has no callback registry:

count := lazily.NewSource(ctx, 0)
effect := lazily.NewEffect(ctx, func(*lazily.Context) func() {
	fmt.Println("now", count.Get()) // the Get is what subscribes
	return nil
})
count.Set(1) // prints "now 1"
effect.Dispose()

An Effect runs once at creation and then once per settled cascade, so under Batch it observes the settled value rather than each intermediate write. When you need every individual transition delivered as a stream, use TopicCell.

Batch coalesces cascades so dependent Effects flush once:

ctx.Batch(func() {
	a.Set(1)
	b.Set(2)
}) // a single coalesced cascade

Competing-consumer work queue

WorkQueueCell[T] provides exclusive FIFO claims, visibility deadlines, worker-scoped acknowledgements, tail retries, and bounded dead-letter handling. Item ids remain stable across retries; every claim gets a fresh delivery id. The same contract is available as ThreadSafeWorkQueueCell for competing goroutines and AsyncWorkQueueCell for composition on an AsyncContext; queue and topic equivalents follow the same ThreadSafe* / Async* naming.

work := lazily.NewWorkQueueCell[string](ctx, 10, 3)
work.Push("job")
delivery, _ := work.Claim("worker-a", 100)
if !work.Ack("worker-a", delivery.DeliveryID) {
    panic("ack rejected")
}

Context

All reactives that react to each other must share a Context. It holds an identity-keyed cache and the computation stack used for automatic dependency tracking. Context is single-goroutine; for concurrent access use the lock-backed ThreadSafeContext or drive the graph from one owner goroutine via the channel-serialized AsyncContext.

Reactive members on a struct

Go has no decorators, so there is no direct analog of lazily-py's @slot / @cell on a method. The idiomatic Go equivalent of a lazily-decorated method is to wire the reactive members as Source / Computed fields in the constructor and expose thin accessor methods. The accessor reads like a plain method but is lazy, cached, and dependency-tracked:

type Greeter struct {
	Name     *lazily.Source[string]
	greeting *lazily.Computed[string] // the "decorated" lazy member
}

func NewGreeter(ctx *lazily.Context) *Greeter {
	g := &Greeter{Name: lazily.NewSource(ctx, "")}
	// greeting tracks Name automatically; it recomputes only after Name changes.
	g.greeting = lazily.NewComputed(ctx, func(*lazily.Context) string {
		return "Hello, " + g.Name.Get() + "!"
	})
	return g
}

// Greeting reads like a normal method but is lazy + cached + reactive.
func (g *Greeter) Greeting() string { return g.greeting.Get() }
ctx := lazily.NewContext()
g := NewGreeter(ctx)
g.Name.Set("World")
g.Greeting() // "Hello, World!" (computed on first read, then cached)
g.Name.Set("Go")
g.Greeting() // "Hello, Go!"  (recomputed once, because Name changed)

NewComputed is guarded by default (it suppresses the downstream cascade when the recomputed value is unchanged); chain .Eager() for eager recomputation. A runnable version of this pattern lives in example_test.go.

State machine

StateMachine is a finite state machine backed by a Source, so any Computed reading its state is invalidated on transition.

State chart

StateChart is a full Harel/SCXML hierarchical state machine — the native counterpart of lazily-formal's LazilyFormal.StateChart. It is compute, not protocol (never serialized as a distinct wire kind). Built from the declarative JSON form via ChartDefFromJSON. Implements compound states, orthogonal (parallel) regions, shallow and deep history, entry/exit/transition actions, and named fail-closed guards.

Collections & CRDTs

Keyed cell collections (SourceMap, SourceTree) with LIS move-minimized reconciliation, the memoized semantic tree (SemTree), stable-id alignment, the reactive queue (QueueCell — a FIFO collection whose shell invalidates by reader kind: a push invalidates Len/IsEmpty (and Head when transitioning from empty), a pop invalidates Head/Len/IsEmpty, and a bounded queue's IsFull is the reactive backpressure signal; SPSC primitive with MPSC via Batch, over a pluggable QueueStorage backend with the default VecDequeStorage), and the CRDT family: free-text character CRDT (TextCrdt, with delta sync), move-aware sequence CRDT (SeqCrdt), the lossless tree CRDT (LosslessTreeCrdt — a single rooted concrete-syntax tree whose leaves own every rendered byte, with op-based delta sync over a dotted non-contiguous version frontier), registers (MvRegister, PnCounter, CellCrdt), and the distributed CRDT plane (CrdtPlane, CrdtPlaneRuntime) with anti-entropy and WebRTC transport + signaling.

Keyed reactive maps

ReactiveMap[K, V, H] is the unified keyed reactive collection (#reactivemap): keys map to independently-tracked per-entry reactive nodes over a handle kind H (*Source[V] input cells or *Computed[V] derived computeds), with reactive membership and order. Go generics can't add methods to a type alias, so its two specializations are thin distinct structs embedding *ReactiveMap with the handle kind fixed:

  • SourceMap[K, V] — input-cell entries. Adds the source-only Set and eager value-minting (Entry / EntryWith). Every entry is a writable *Source[V].
  • ComputedMap[K, V] — derived-slot entries. GetOrInsertWith mints a slot on first access (lazy materialization); MaterializeAll pre-mints the keyset (eager). A slot's value is derived, so ComputedMap has no Set. There is no eager/lazy mode flag — eager is a pre-mint loop, lazy is mint-on-access.

These were named CellMap / SlotMap before the v2 kernel renamed the node kinds to Source and Computed. The old spellings remain as deprecated generic type aliases (CellMap = SourceMap, SlotMap = ComputedMap, plus the Async* / ThreadSafe* flavors, and CellTree = SourceTree for the ordered keyed tree) with deprecated constructor wrappers, so existing callers keep compiling. Generic type aliases require Go 1.24+.

The shared surface — GetOrInsertWith / Remove / Move* / Keys / Len / ContainsKey / membership + order signals — lives on the generic ReactiveMap.

ctx := lazily.NewContext()
// Lazy derived-slot map over a large keyed space; only read keys are allocated.
sheet := lazily.NewComputedMap[Key, int](ctx)
sheet.GetOrInsertWith(k, func(k Key) int { return recompute(k) }) // mint on first pull
sheet.PresentCount()                                              // grows only with reads

Eager (MaterializeAll pre-mint) and lazy (GetOrInsertWith mint-on-access) return identical values for every key (observational transparency); the strategy changes allocation timing and memory, never results. The laws — observe_canonical, eager_lazy_observationally_equivalent, materialize_present_monotone / lazy_present_subset_eager, and entry-kind orthogonality (cell_entries_materialized_in_every_mode / slot_entries_deferred_under_lazy) — are proven in lazily-formal's Materialization module and pinned by the conformance/materialization/*.json fixtures. The Send + Sync (ThreadSafeSourceMap / ThreadSafeComputedMap) and async (AsyncSourceMap / AsyncComputedMap) flavors mirror the same surface.

lazily-spec IPC

The IPC types (Snapshot, Delta, CrdtSync, NodeState, ...) implement the language-agnostic lazily-spec wire protocol so a Go graph's state can be mirrored to remote observers across processes and languages. They round-trip the canonical fixtures from lazily-spec/conformance/. The C-ABI FFI boundary (cgo) exposes the state plane to in-process native embedders.

The additive command / RPC message plane (command-plane-v1) — CommandSubmit / CommandCancel / CommandEvents / CommandProjection plus the CommandRpcClient facade — rides the same wire envelope. Terminal command authority folds through a CausalReceipt, so a unary call resolves only on a terminal receipt (never on a transport ACK or accepted/queued event).

Cross-process zero-copy transport

Large cell/slot payloads cross the IPC plane as descriptors, not copies (#lzzcpy). The producer spills an oversized payload to a pluggable BlobBackend and ships a small ShmBlobRef descriptor; the receiver resolves the descriptor against the same backend and reads the bytes in place — no copy, no checksum recompute. Three backends ship:

  • InProcessBackend wraps a ShmBlobArena — the single-address-space case (the cgo FFI host / an in-process embedder).
  • ArrowBackend holds Apache Arrow IPC stream bytes — the descriptor's bytes are an Arrow IPC stream a columnar consumer imports zero-copy.
  • ShmBackend (Linux) is a genuine POSIX shm_open + mmap region with an atomic bump allocator — the cross-process backend: a descriptor minted by one mapping resolves zero-copy against an independent mapping of the same region.

SpillMessage replaces oversized Inline/Payload sites across a Snapshot/Delta/CrdtSync with descriptors above a deployment threshold; a receiver-side BlobRouter resolves any descriptor by its backend discriminator (a shm descriptor never resolves in an Arrow backend, and vice versa). The backend field is optional and defaults to shm, so legacy descriptors validate unchanged — the transport is a strict superset of the shared-memory blob path. The backend-agnostic invariants (spill-then-resolve identity, backend isolation, ABA generation safety, checksum integrity) are proven in lazily-formal's ZeroCopyTransport.lean and pinned by the delta_zero_copy_arrow conformance fixture.

Conformance

lazily-go replays the shared lazily-spec conformance fixtures (IPC, keyed collections, Harel state charts, the lossless-tree CRDT, and the command-plane message family) — asserting identical behavior to every other binding. Run make check (fmt + vet + build + test) locally; CI also runs the race detector.

Benchmarks

See BENCHMARKS.md for micro-benchmark results on the hot paths — reactive core read/write, slot/memo recompute, batch coalescing, keyed collections, and CRDT construction — with ns/op / B/op / allocs/op and what each case measures. The reactive steady state (Cell read/write, SourceMap insert/read) is zero-allocation. Benchmarks are defined as Go testing.B cases in bench_test.go (mirroring the in-library RunBenchmarkSuite) and reproducible with make bench (go test -bench=. -benchmem ./...).

BENCHMARKS.md also includes a spreadsheet-scale benchmark (make bench-scale) on a graph of N input cells + N formula slots (=A_i + A_{i-1}): ~2M nodes at the default N=1M, up to a full 10M-cell Google Sheets workbook at LAZILY_SCALE_N=5000000. It builds the full workbook in under a second and — via the lazy pull-based model — a one-cell edit + bounded-viewport read recomputes only the viewport (~2 formulas), staying orders of magnitude cheaper than a full recalc regardless of sheet size.

Feature coverage

The full lazily capability set across every binding. Legend: ✅ shipped · ~ partial · absent or not applicable. The canonical matrix with per-cell notes and platform carve-outs lives in lazily-spec § Cross-Language Coverage.

Feature Rust Python Kotlin JS Dart Zig Go C++ C#
Reactive graph — two cell kinds (nodes SourceCell / ComputedCell; handles Source<T, M> / Computed<T>) + Effect sink + eager Computed (computed().eager()) / all cells guarded / batch
Keyed-map materialization (ComputedMap) — mint-on-access derived slots: transparency + deferral (#lzmatmode)
Thread-safe keyed map (ThreadSafeComputedMap) — Send + Sync + materialization confluence (#lzmatmode)
Async keyed map (AsyncComputedMap) — eventual transparency (#lzmatmode)
Keyed-map sync — membership propagation + materialize-on-ingest + derived-aggregate transparency (#lzfamilysync)
Thread-safe context (lock-backed)
Async reactive context
Flat state machine
Harel state charts
Keyed reactive maps (ReactiveMap: SourceMap / ComputedMap) + SourceTree + reconcile
ReactiveMap Core surface — single-threaded flavor (cell-model.md § Core surface vs. binding extensions) ~
ReactiveMap Core surface — thread-safe flavor (ordering + membership reactivity)
ReactiveMap Core surface — async flavor (ordering + membership reactivity)
Atomic ordered move replayed against all three flavors (cellmap_atomic_move + cellmap_independence)
Memoized semantic tree (SemTree)
Stable-id alignment (manufactured identity)
Reactive queue (QueueCell SPSC/MPSC + QueueStorage adapter) Core surface — single-threaded flavor ~ ~
Reactive queue (QueueCell SPSC/MPSC + QueueStorage adapter) Core surface — thread-safe flavor (reader kinds + closure lifecycle)
Reactive queue (QueueCell SPSC/MPSC + QueueStorage adapter) Core surface — async flavor (reader kinds + eventual transparency)
Broadcast topic (TopicCell) Core surface — single-threaded flavor — independent cursors + durable replay + safe GC (#lztopiccell) ~ ~
Broadcast topic (TopicCell) Core surface — thread-safe flavor (reader kinds + closure lifecycle)
Broadcast topic (TopicCell) Core surface — async flavor (reader kinds + eventual transparency)
Competing-consumer work queue (WorkQueueCell) Core surface — single-threaded flavor — exclusive leases + ack/nack + redelivery + DLQ (#lzworkqueue) ~ ~
Competing-consumer work queue (WorkQueueCell) Core surface — thread-safe flavor (reader kinds + closure lifecycle)
Competing-consumer work queue (WorkQueueCell) Core surface — async flavor (reader kinds + eventual transparency)
Merge algebra + Source<T, M> — associative MergePolicy (KeepLatest/Sum/Max/SetUnion/RawFifo), Cell ≡ Source<KeepLatest>, read-any-cell/write-Source split (#relaycell)
RelayCell — conflating relay + BackpressurePolicy + SpillStore + Transport + Inbox/Outbox + Rate/Window/Expiry/Priority/keyed policies (#relaycell)
Free-text character CRDT (TextCrdt)
TextCrdt delta sync (version_vector / delta_since / apply_delta)
CrdtTree lossless document contract (#lzcrdttree)
Move-aware sequence CRDT (SeqCrdt)
Lossless tree CRDT core (LosslessTreeCrdt, M1)
Lossless tree — dotted-frontier anti-entropy
Lossless tree — concurrent merge convergence
Registers (LWW / MV) + PnCounter + CellCrdt
IPC wire — Snapshot + Delta + CrdtSync
Shared-memory blob path (ShmBlobArena)
Cross-process zero-copy transport (BlobBackend / shm / arrow)
Distributed CRDT plane (CrdtPlaneRuntime / anti-entropy)
Reliable sync — resync coordinator + at-least-once durable outbox + OR-set/LWW liveness (#lzsync)
Storage-independent durable outbox (OutboxStore + shared outbox protocol; SQLite/Room/IndexedDB/file adapters)
Reliable-sync transport seam + full-duplex SyncDriver loop (IpcSink/IpcSource, #sync-driver)
Distributed plane — WebRTC transport + signaling
State projection / mirror
Causal receipts (CausalReceipts outcome projection)
Message-passing + RPC command plane (command-plane-v1)
C-ABI FFI boundary
Permission boundary (PeerPermissions / RemoteOp)
Capability negotiation (SessionHandshake)
Instrumentation / benchmarks
Temporal sources — TimerCell / IntervalCell / CronCell / DeadlineCell over a logical clock (#lztime)
Rate-shaping operators — DebounceCell / ThrottleCell / SampleCell / ProbabilisticSampleCell (#lzrateshape)
Membership + failure detection — MembershipCell (SWIM + Phi-accrual) / PeerSet / PeerChangeEvent (#lzmemb)
Distributed coordination — LeaseCell / LeaderCell / LockCell / SemaphoreCell / BarrierCell+QuorumCell (#lzcoord)
Presence + ephemeral plane — PresenceCell / AwarenessCell / EphemeralCell + Ephemeral/Durable markers (#lzpresence)
Stream windowing — TumblingWindow / SlidingWindow / SessionWindow over the merge algebra (#lzwindow)
Fault tolerance — CircuitBreakerCell / RetryPolicyCell / BulkheadCell / TimeoutCell (#lzresilience)
Portable stdlib Timer (stdlib_timer_v1) — canonical fixture + mutation-gate verified
Portable stdlib caller-driven Timeout<T> (stdlib_timeout_v1) — distinct from reactive TimeoutCell
Portable stdlib RevisionBarrier (stdlib_revision_barrier_v1) — register/recheck lost-wakeup guard
Embedded-service plane — HealthCell / ReadinessCell / DiscoveryCell / ServiceRegistry (#lzservice)

Documentation

Overview

Async reactive context — a Go port of lazily-dart's lib/src/async_context.dart (docs/async.md).

This is a separate reactive surface for computations whose values are produced by blocking / future-returning functions. It is NOT an overload of the synchronous Context (see core.go); it is a distinct graph with its own handles, because async computes introduce in-flight state, cancellation, stale completion, and dependency tracking across suspension points that the synchronous graph does not have. Only resolved slot values would ever cross IPC/FFI — this file is compute, not protocol.

Channel-first architecture (share by communicating)

The whole graph is owned by a SINGLE owner goroutine (AsyncContext.loop). Every graph mutation and read is serialized as a command func() sent over the command channel; the loop executes them one at a time, so no per-field mutex is needed and there are no data races on graph state. Callers that need a result capture it in closure variables and wait for the command to run (AsyncContext.do). Compute results are posted back to the loop by the compute goroutine (AsyncContext.post).

Async compute functions themselves run in their own goroutines (they may block), mirroring how Dart's futures run "concurrently" on the event loop while all synchronous state transitions happen on the single thread between await points. A compute reads its dependencies through an AsyncComputeContext whose TrackSource / TrackComputed helpers register dependency edges (via the loop) before the awaited read.

Supersession (Dart's _Superseded) == context cancellation

When a slot's dependency changes, the in-flight compute is superseded: its per-compute context.Context is cancelled and every current waiter is told to re-resolve (asyncResult.superseded). The re-resolve loop in AsyncComputed.GetAsync observes that and starts over from the current slot state, exactly like Dart's re-resolve loop catching _Superseded. The stale compute goroutine may still finish, but its completion is discarded because the slot's in-flight token no longer matches (identity gate in onComplete).

Lifecycle

DisposeAsync / Close mark the context disposed, cancel every in-flight compute, deliver a disposed error to blocked waiters, run and await effect cleanups, then tear down the owner goroutine. No goroutine is leaked: compute and effect goroutines observe their cancelled context or post through a stop-aware channel, and blocked callers unblock on the loop's stop signal.

Disposal, teardown scopes, and edge-degree introspection for the *async* reactive graph (#lzspecedgeindex).

The synchronous plane's counterpart lives in disposal.go, and the three semantics it documents hold here unchanged:

  1. Disposal dirties the surviving dependent cone. The async graph makes this even sharper than the sync one: GetAsync short-circuits on AsyncComputedResolved, so a downstream slot left Resolved serves its cached value forever and no later pull can rescue it. This is the same shape as the cascade defect fixed in bdfdbce, reached by a different route. Teardown reuses AsyncContext.propagate — the very walk that fix installed — rather than adding a second one.

  2. Effects reached by that walk are marked, not rerun. propagate's schedule=false branch is that rule.

  3. Scope teardown is reverse creation order, for effect cleanups.

Everything here runs inside the owner goroutine via AsyncContext.do, so the loop-owned graph state stays single-threaded exactly as the rest of the file assumes.

Keyed cell collections — SourceMap, SourceTree, and keyed reconciliation (cell-model.md § Keyed cell collections).

A keyed cell collection is a *composition of cells*, not a new cell kind. It maps keys K to per-entry Cells and adds dedicated membership and order reactive signals so the three reactivity planes stay independent:

  • writing one entry's value invalidates only that entry's value readers;
  • adding/removing a key invalidates membership readers (Len / ContainsKey) and order readers (Keys), but not unrelated entry value readers;
  • a pure reorder (atomic move) invalidates order readers only.

Ported from lazily-dart lib/src/collections.dart, mirroring lazily-rs/src/cell_family.rs (reactive) and lazily-rs/src/reconcile.rs (LIS). Validated against lazily-spec/conformance/collections/{cellmap_independence, cellmap_atomic_move,keyed_reconciliation_lis}.json.

Semantic note on the `comparable` constraint: core.go's Cell[T] requires a comparable T for the PartialEq guard, and keyed reconciliation compares entry values for the Update op. Both mean the value type V must support ==, so this module constrains V to `comparable` and stores per-key values in a plain Cell[V] (no boxing needed). This matches the Dart port's use of Dart `==` / PartialEq exactly, and gives real handle stability: an atomic move never re-mints the entry's *Cell, so the same pointer (and its dependents) survive.

Package lazily provides lazy reactive primitives for Go — the Cell kernel (#lzcellkernel) — plus the lazily-spec wire protocol, CRDT collection types, keyed cell collections, state machines/charts, and the distributed CRDT plane.

A Go port of the lazily reactive family (lazily-rs, lazily-py, lazily-kt, lazily-js, lazily-dart, lazily-zig), conformant with lazily-spec and lazily-formal.

The reactive family (v2 kernel). "Cell" is a conceptual word for a value-bearing reactive node, not a Go type — the two kinds are two concrete handle structs, and write protection lives in the type (design §3/§4):

  • Source[T] — a value written from outside; the only kind with Set/Merge. Folds writes under a MergePolicy (KeepLatest by default = a plain cell; Sum/Max = the former MergeCell). Constructors: NewSource / NewSourceWithPolicy.
  • Computed[T] — a value computed from upstream; lazily cached and dependency-tracking, with neither Set nor Merge (so computed.Set(…) does not compile). NewComputed(f) is GUARDED by default: a recompute yielding an equal value suppresses the downstream cascade. NewSlot(f) is the bound-free storage-sense primitive (T any, no guard) for non-comparable values. computed.Eager() makes it eager (the former Signal), returning the same handle; computed.Lazy() reverses it. The former Memo is removed — a Computed IS the guarded form.
  • Effect — a side-effect sink (ctx.effect); outside the Cell hierarchy.

The v1 `Cell[T]` read-genus interface is dropped: no Go generic code used it as a bound, and v2 no longer needs a genus for write protection.

Values are lazy by default: dependents are marked dirty on invalidation but only recompute when read. For eager push-style semantics, call Eager on a Computed.

A Context is the shared scope. Dependency tracking is value-threaded through a per-recompute Compute view — there is no ambient recompute stack — and cached slot values live on the nodes themselves, not in a shared Context table, so reads stay O(1) regardless of graph size. All reactives that react to each other must share a Context. Context is not safe for concurrent use by multiple goroutines; use ThreadSafeContext (see thread_safe.go) or the channel-serialized AsyncContext (see async_context.go) for concurrent access.

Disposal, teardown scopes, and edge-degree introspection for the synchronous reactive graph (#lzspecedgeindex).

Why this exists: a Go handle is a pointer, and dropping the last pointer to a *Slot reclaims nothing reactive. The node's edge on each of its dependencies is a *strong* reference held by the context's graph, so a long-lived source retains every node that ever read it. Under subscribe/unsubscribe churn the dependent set grows without bound even though the live subscriber count is constant, and the cost is paid twice — memory, and propagation, since every write walks the whole list. Explicit disposal is the fix, exactly as in lazily-rs (`Context::dispose_slot` / `dispose_cell`) and lazily-js (`disposeSlot`).

Three semantics this file must preserve

  1. Disposal dirties the surviving dependent cone. Detaching edges without marking dependents leaves a live reader frozen on the value it cached before the disposal — the defect fixed in lazily-rs 5db90d2 and lazily-js 4d20670. The cone walk here reuses reactiveBase.invalidate (core.go) rather than adding a second walk that could drift from it.

  2. Effects (and other eager nodes) reached by that walk are marked, not run. Disposal is not a publish: running an effect mid-teardown re-enters a compute that reads the node being disposed, which breaks idempotence. Context.disposing gates this; see Effect.onInvalidate and Memo.invalidate in core.go. A Signal's eager pull is an ordinary Effect, so it is covered by the Effect case rather than needing a rule of its own.

  3. Scope teardown is reverse creation order. Graph state is order independent, but effect *cleanups* are side effects with an observable order, and ending a scope is proved observationally equal to disposing each member individually (lazily-formal `disposeScope_eq_disposeAll`).

Why reads of a disposed node panic

A compute closure has signature `func(*Compute) T`. There is no error channel through it, so a nested read of a disposed dependency cannot be reported by a return value without changing every user compute's signature. Panic/recover is the only mechanism that crosses an arbitrary closure, and it matches the reference binding: lazily-rs panics on a read of a torn-down node too. Disposal is a caller contract ("nothing may still read it"), and Go already uses panic for contract violations. TryGet is the checked form at the boundary; Get is unchanged on the hot path.

Instrumentation — benchmark harness for reactive operations.

Lightweight micro-benchmarks for the reactive core, keyed collections, and CRDT types. This is the in-library instrumentation API (not Go `testing.B` benchmarks); drive it from a `main` or a tool.

Ported from lazily-dart lib/src/instrumentation.dart. Semantics match the Dart harness: each scenario is executed `iterations` times and the total wall-clock time is recorded in microseconds.

Reactive queue — QueueCell (SPSC primitive with MPSC usage rule) plus the pluggable QueueStorage backend (cell-model.md § Reactive queues).

A reactive queue is a FIFO collection *composed of cells* — not a new cell kind — that adds queue semantics (push to tail, pop from head) to the reactive graph. It adds no new merge unit; each element is an ordinary value subject to the same single-writer / multi-write classification.

The distinguishing property of a reactive queue is that invalidation is scoped to **reader kind**, not to individual positions:

  • a push invalidates length/is_empty (and head when transitioning from empty), plus is_full when it fills a bounded queue;
  • a pop invalidates head/length/is_empty (plus is_full when it un-fills);
  • neither push nor pop touches the closed reader; only Close does;
  • a no-op (push at capacity → Full, pop on empty → Empty/Closed, close of an already-closed queue) invalidates nothing.

QueueCell is specified as a single-producer, single-consumer (SPSC) primitive: one writer owns the tail, one reader owns the head, so the producer is the natural FIFO sequencer (push order = delivery order). MPSC (multi-producer, single-consumer) is a *usage rule on the same primitive*, not a separate type: multiple producers push to the same tail inside a Context.Batch boundary; the batch serializes the pushes into a deterministic order and coalesces the cascade into one observable transition. There is no MPSCQueueCell type — introducing one would imply SPMC/MPMC siblings that in fact differ in semantics, not cardinality (see TopicCell / WorkQueueCell).

The shell / storage split: the reactive shell owns the demand-driven reader-kinds and the invalidation logic (storage-agnostic — this is what the formal model LazilyFormal.QueueCell pins); the storage backend owns the FIFO data structure and is pluggable via the QueueStorage interface. The default VecDequeStorage is an unbounded slice-backed queue; a bounded one exposes a capacity and reactive backpressure via IsFull. Distribution is a storage-backend property, not a shell property.

Ported from lazily-rs/src/queue.rs, mirroring lazily-kt Queue.kt, lazily-cpp queue.hpp, lazily-js queue.js, and lazily-zig queue.zig. Validated against lazily-spec/conformance/collections/queuecell_*.json.

Memoized semantic tree — a reactive, incrementally-memoized fold tree.

One Memo slot per node folds (node value, [child derived values]). Editing one node recomputes only its ANCESTOR CHAIN; a sibling subtree's derived slot stays cached. A node edit that does not change the folded value does not re-run a downstream consumer (the Memo equality guard).

Composes over the reactive Context/Cell/Memo primitives in core.go. Ported from lazily-dart lib/src/sem_tree.dart (which mirrors lazily-js src/sem-tree.js). Conforms to lazily-spec conformance/collections/semtree_incremental.json.

Harel/SCXML hierarchical state chart — compound + parallel (orthogonal) regions, shallow + deep history, entry/exit/transition action ordering, named guards (fail-closed), and external + internal transitions.

Ported from lazily-dart lib/src/state_chart.dart (feature row "Harel state charts"). The native counterpart of lazily-formal's LazilyFormal.StateChart and lazily-rs/lazily-kt state charts. It is COMPUTE, not protocol: a chart is never serialized as a distinct wire kind — only its converged active configuration crosses the wire as an ordinary cell payload.

The active configuration is backed by a Cell so any Slot/Signal/Memo/observer reading Configuration, ActiveLeaves, or Matches is invalidated on a real transition; a no-op (configuration unchanged) is suppressed by the cell's structural-equality guard. Because Cell requires a comparable value type and a set of active states is not comparable, the cell holds a canonical sorted-and-joined configuration key (structural equality on that string == structural equality on the set); the authoritative set is kept alongside.

Send is deterministic by construction — a total function of (chart, configuration, history, guards, event), mirroring the Lean StateChart.send. The declarative chart form is parsed from JSON conforming to lazily-spec/schemas/statechart.json via ChartDefFromJSON. `run` actions and {"expr": …} context guards are rejected explicitly; `final` states are accepted as leaves without raising completion (done) events, matching lazily-py and lazily-kt.

Thread-safe reactive context — a lock-serialized batch boundary.

The Go counterpart of lazily-py's ThreadSafeContext and the Lean LazilyFormal.ThreadSafe model (lazily-spec § "Concurrency layers are required"). The behavioral contract: serializing concurrent cell writes through a batch boundary coalesces them into one invalidation pass whose result is a deterministic function of the writes — independent of the interleaving the lock happened to pick.

Go has real threads (goroutines), so this layer is required (feature row "Thread-safe context (lock-backed)" is ✅ for Go, unlike the single-isolate JS/Dart runtimes). ThreadSafeContext wraps a single-threaded Context with a reentrant lock and reuses the core batch coalescing, so a one-write section is observationally identical to a plain Cell.Set — the thread-safe context refines the single-threaded kernel.

Index

Constants

View Source
const (
	// Deprecated: use AsyncComputedEmpty.
	AsyncSlotEmpty = AsyncComputedEmpty
	// Deprecated: use AsyncComputedComputing.
	AsyncSlotComputing = AsyncComputedComputing
	// Deprecated: use AsyncComputedResolved.
	AsyncSlotResolved = AsyncComputedResolved
	// Deprecated: use AsyncComputedError.
	AsyncSlotError = AsyncComputedError
)
View Source
const AnchorPrefix = "a:"

AnchorPrefix is the anchored-key wire prefix.

View Source
const BindingName = "lazily-go"

BindingName is this binding's name.

View Source
const ContentPrefix = "c:"

ContentPrefix is the content-key wire prefix.

View Source
const DefaultBenchmarkIterations = 10000

DefaultBenchmarkIterations is the iteration count used when a caller does not specify one, matching the Dart harness default.

View Source
const DefaultCodec = "json"

DefaultCodec is the default codec negotiation token.

View Source
const DefaultMaxFrameSize int64 = 1 << 20

DefaultMaxFrameSize is the default maximum frame size (1 MiB).

View Source
const DefaultSpillThreshold = 512

DefaultSpillThreshold is the default byte size at or above which SpillValue / SpillMessage spill an inline payload to a backend. It is a deployment knob, not a protocol constant: payloads below the threshold stay Inline (copying a tiny value through the codec is cheaper than a backend round-trip). Callers pass their own threshold to the Spill* functions.

View Source
const EditThreshold = 0.5

EditThreshold is the edit-similarity threshold below which a match is treated as an insert.

View Source
const EntryKindCell = EntryKindSource

EntryKindCell is the pre-v2-kernel name for EntryKindSource, kept as an alias so existing callers keep compiling. The v2 kernel renamed the node kinds to Source and Computed; the entry kinds follow. The underlying value and its wire string ("cell") are unchanged.

Deprecated: renamed to EntryKindSource.

View Source
const EntryKindSlot = EntryKindComputed

EntryKindSlot is the pre-v2-kernel name for EntryKindComputed. The underlying value and its wire string ("slot") are unchanged.

Deprecated: renamed to EntryKindComputed.

View Source
const FFIHasCABI = true

FFIHasCABI reports whether the native C-ABI export layer is compiled into this build. True under CGO_ENABLED=1.

View Source
const ProtocolID = "lazily-ipc"

ProtocolID is the protocol identifier every lazily-ipc peer must advertise.

View Source
const ProtocolMajorVersion = 1

ProtocolMajorVersion is the current protocol major version.

Variables

View Source
var ErrAsyncContextDisposed = errors.New("lazily: async context disposed")

ErrAsyncContextDisposed is returned by async reads once the owning AsyncContext has been disposed (Dart threw a StateError here).

View Source
var ErrConflateNotBounding = &RelayConfigError{msg: "ConflateNotBounding"}

ErrConflateNotBounding is returned when Conflate is chosen for a non-conflating policy (e.g. RawFifo).

View Source
var ErrConnAlreadyExists = errors.New("signaling connection already exists")

ErrConnAlreadyExists is returned by Connect when connID is already connected.

View Source
var ErrDisposed = errors.New("lazily: read of a disposed reactive node")

ErrDisposed is the sentinel behind every *DisposedError, for errors.Is.

View Source
var ErrSignalingRoomClosed = errors.New("signaling room is closed")

ErrSignalingRoomClosed is returned by SignalingRoom methods after Close.

View Source
var TreeRoot = OpId{}

TreeRoot is the sentinel id of the document root: {counter: 0, peer: 0}. Reuses OpId; the zero value is the root.

Functions

func ApplyBatch

func ApplyBatch(nodes map[any]NodeEntry, batch []BatchWrite) (map[any]NodeEntry, []any)

ApplyBatch applies the batch's value updates (with the PartialEq guard) to a copy of nodes and returns the new table plus the list of source ids that actually changed. A faithful port of the Lean applyBatch.

func AssignStableKeys

func AssignStableKeys(oldBlocks, newBlocks []Block) []string

AssignStableKeys assigns stable keys to newBlocks by flowing identity through the alignment with oldBlocks. Same/Edited inherit the predecessor's key; Inserted get a fresh key.

func BuildStateEvent

func BuildStateEvent(docHash, eventType string, fields map[string]any, eventSuffix string) map[string]any

BuildStateEvent builds a state-backbone event for the agent-doc ledger. The eventType and document_hash seed the fact; entries in fields are merged over them (so fields may override), mirroring the Dart map-spread semantics.

func CheckedDeadline added in v0.25.0

func CheckedDeadline(now, duration uint64) (uint64, error)

CheckedDeadline returns now+duration or a typed overflow error.

func ContentHash

func ContentHash(text string) uint64

ContentHash computes the FNV-1a 64-bit content hash of the UTF-8 bytes of Normalize(text). Cross-language stable (NOT Go's hash/fnv is equivalent, but the byte source mirrors the Dart code-unit encoding exactly).

func DocumentHash

func DocumentHash(path string) uint64

DocumentHash computes the FNV-1a 64-bit document hash for a file path or string.

Cross-language stable (NOT Dart's hashCode). The Dart original hashes over String.codeUnits (UTF-16 code units), so this port hashes the UTF-16 encoding of path — not its UTF-8 bytes — to reproduce the same digest. Used as the canonical document key for the state backbone.

func FlushBatch

func FlushBatch(nodes map[any]NodeEntry, dependents map[any][]any, batch []BatchWrite) map[any]NodeEntry

FlushBatch applies the batch's values, then marks the coalesced union of changed sources' dependents dirty in one pass — a faithful port of the Lean flushBatch (the coalesced frontier: each dependent appears at most once).

func Get added in v0.21.0

func Get[T any](c ComputeOps, h Trackable[T]) T

Get reads a reactive handle through a compute surface (#lzcellkernel). When c is a *Compute, the read registers a dependency edge against the recomputing node; when c is a *Context (or c.Untracked()), it registers none. This is the value-threaded replacement for the ambient zero-argument handle.Get(): the node to attribute to is threaded through c, never read from a shared stack.

func Normalize

func Normalize(text string) string

Normalize collapses whitespace: split on \s+, drop empties, join with a single space.

func Own added in v0.20.0

func Own[N GraphNode](s *TeardownScope, n N) N

Own places n under s's ownership and returns it, so a node can be created and scoped in one expression:

total := lazily.Own(scope, lazily.NewSlot(ctx, compute))

It is a free function rather than a method because Go methods cannot take type parameters — and being generic in the *node* type rather than in the value type means this one function covers Slot, Cell, Signal, Memo, and Effect, instead of mirroring every constructor onto the scope the way lazily-rs must.

func OwnAsync added in v0.20.0

func OwnAsync[N AsyncGraphNode](s *AsyncTeardownScope, n N) N

OwnAsync places n under s's ownership and returns it.

A free function for the same reason as the synchronous Own: Go methods cannot take type parameters, and being generic in the node type lets one function cover cells, slots, and effects.

func Read

func Read[T any](t *ThreadSafeContext, fn func(ctx *Context) T) T

Read runs fn under the lock and returns its result — the read-oriented convenience over WithLock.

func ResolveValue added in v0.4.0

func ResolveValue(value IpcValue, backend BlobBackend) ([]byte, bool)

ResolveValue resolves an IpcValue against a single backend: Inline bytes are returned directly (ok=true), a SharedBlob is resolved zero-copy against backend. Returns (nil, false) when a SharedBlob fails to resolve (unknown / stale / corrupt). The returned slice aliases whichever of value or backend owns the bytes.

func RetainLive added in v0.11.0

func RetainLive[T any](e *ExpiryPolicy, batch []TimedValue[T]) []T

RetainLive returns only the live elements of a timestamped batch (drops the aged tail). A free function because Go methods cannot carry their own type parameters.

func Similarity

func Similarity(a, b string) float64

Similarity returns a value in [0, 1]: 2*|word-LCS| / (|a| + |b|). Both-empty is 1.0; exactly-one-empty is 0.0.

func TSSetCell

func TSSetCell[T comparable](t *ThreadSafeContext, cell *Source[T], value T)

TSSetCell writes a cell's value under the lock. Outside a batch it applies immediately (a singleton batch ≡ Cell.Set); inside a Batch it defers to the coalesced flush. It is a free function because Go methods cannot be generic.

func TrackAsync deprecated

func TrackAsync[T any](cc *AsyncComputeContext, computed *AsyncComputed[T]) (T, error)

TrackAsync is the deprecated v1 computed-read helper.

Deprecated: use TrackComputed.

func TrackCell deprecated

func TrackCell[T any](cc *AsyncComputeContext, source *AsyncSource[T]) T

TrackCell is the deprecated v1 source-read helper.

Deprecated: use TrackSource.

func TrackComputed added in v0.24.0

func TrackComputed[T any](cc *AsyncComputeContext, computed *AsyncComputed[T]) (T, error)

TrackComputed awaits a computed inside an async compute/effect, registering a dependency edge before the awaited read (Dart AsyncComputeContext.getAsync). The nested await uses this compute's cancellation context, so supersession unwinds nested reads too.

func TrackSource added in v0.24.0

func TrackSource[T any](cc *AsyncComputeContext, cell *AsyncSource[T]) T

TrackSource reads a cell inside an async compute/effect, registering a dependency edge before returning the value (Dart AsyncComputeContext.getCell).

func UnionDependents

func UnionDependents(dependents map[any][]any, sources []any) []any

UnionDependents is the flat union of dependents over a list of source nodes — a faithful port of the Lean unionDependents.

func UnlinkShmBackend added in v0.4.0

func UnlinkShmBackend(name string)

UnlinkShmBackend removes the named region so it is reclaimed once all mappings are unmapped. It is a no-op if the region does not exist.

func ValidateBlobRef

func ValidateBlobRef(ref ShmBlobRef, maxLen *int64) bool

ValidateBlobRef validates a ShmBlobRef descriptor against expected bounds: all header fields must be non-negative, and Len must not exceed maxLen when maxLen is non-nil. Mirrors Dart `validateBlobRef({int? maxLen})`.

Types

type Alignment

type Alignment struct {
	NewMatches []Match // one per new block
	Removed    []int   // old indices not matched
}

Alignment is the alignment of new blocks against old, plus the set of removed old indices.

func Align

func Align(oldBlocks, newBlocks []Block) Alignment

Align aligns newBlocks against oldBlocks: exact-key match first, then similarity (>= threshold) with nearest-index tiebreak.

func (Alignment) String

func (a Alignment) String() string

type ArrowBackend added in v0.4.0

type ArrowBackend struct {
	// contains filtered or unexported fields
}

ArrowBackend is the Apache Arrow blob backend: it holds spilled payloads as Arrow IPC stream bytes and resolves a descriptor to the buffer's raw bytes with no copy. The descriptor's bytes ARE an Arrow IPC stream — a columnar consumer imports them as an Array / RecordBatch zero-copy (the Arrow IPC format is itself zero-copy across a shared buffer). This adapter stores the raw stream bytes and tags the descriptor Backend = BackendArrow; bring your own Arrow reader to wrap the resolved []byte into typed Arrow.

Because Arrow's IPC format is zero-copy over a shared buffer, shm and arrow compose: an Arrow batch can live in a ShmBackend region and be resolved by either backend. New backends (RDMA/verbs, CUDA IPC) plug in by implementing BlobBackend and adding a BlobBackendKind value.

func NewArrowBackend added in v0.4.0

func NewArrowBackend() *ArrowBackend

NewArrowBackend creates an Arrow backend over a fresh arena at epoch 0.

func (*ArrowBackend) AdvanceEpoch added in v0.4.0

func (b *ArrowBackend) AdvanceEpoch()

AdvanceEpoch advances the backing arena's epoch, invalidating prior descriptors.

func (*ArrowBackend) Arena added in v0.4.0

func (b *ArrowBackend) Arena() *ShmBlobArena

Arena returns the backing arena.

func (*ArrowBackend) Epoch added in v0.4.0

func (b *ArrowBackend) Epoch() int64

Epoch returns the backend's current validity epoch.

func (*ArrowBackend) Kind added in v0.4.0

func (b *ArrowBackend) Kind() BlobBackendKind

Kind reports BackendArrow.

func (*ArrowBackend) ReadView added in v0.4.0

func (b *ArrowBackend) ReadView(descriptor ShmBlobRef) ([]byte, bool)

ReadView resolves the descriptor zero-copy against the backing arena.

func (*ArrowBackend) Write added in v0.4.0

func (b *ArrowBackend) Write(bytes []byte) (ShmBlobRef, error)

Write stores the Arrow IPC stream bytes and stamps the descriptor with the Arrow backend discriminator.

type AsyncCellHandle deprecated

type AsyncCellHandle[T any] = AsyncSource[T]

AsyncCellHandle is the deprecated v1 name for AsyncSource.

Deprecated: use AsyncSource.

type AsyncCellMap deprecated added in v0.7.0

type AsyncCellMap[K comparable, V comparable] = AsyncSourceMap[K, V]

AsyncCellMap is the pre-v2-kernel name for AsyncSourceMap, kept as an alias so existing callers keep compiling.

Deprecated: renamed to AsyncSourceMap.

type AsyncComputeContext

type AsyncComputeContext struct {
	// contains filtered or unexported fields
}

AsyncComputeContext is handed to an async compute/effect body. Dependencies are registered through TrackSource / TrackComputed (free functions, because Go methods cannot be generic) which record the edge before the awaited read.

func (*AsyncComputeContext) Context

func (cc *AsyncComputeContext) Context() context.Context

Context returns the per-compute cancellation context. It is cancelled when this compute is superseded or the AsyncContext is disposed; long-running compute bodies should observe Context().Done().

type AsyncComputed added in v0.24.0

type AsyncComputed[T any] struct {
	// contains filtered or unexported fields
}

AsyncComputed is a computed async slot: a blocking/future-returning computation that recomputes when its dependencies change.

func NewAsyncComputed added in v0.24.0

func NewAsyncComputed[T any](c *AsyncContext, compute func(cc *AsyncComputeContext) (T, error)) *AsyncComputed[T]

NewAsyncComputed creates an async computed slot (Dart AsyncContext.computedAsync). compute reads its dependencies through the AsyncComputeContext and returns a value or an error.

func NewAsyncComputedRippleWhen added in v0.21.0

func NewAsyncComputedRippleWhen[T any](c *AsyncContext, compute func(cc *AsyncComputeContext) (T, error), changed func(old, next T) bool) *AsyncComputed[T]

NewAsyncComputedRippleWhen is the async mirror of NewComputedRippleWhen (#lzcellkernel): a guarded async computed whose downstream propagation is gated by an explicit, PURE predicate changed(old, next) — true propagates the recompute to dependents, false suppresses it. It installs the engine's equality guard as its negation (equal => suppress), so NewAsyncComputedWithEquals(f, eq) and NewAsyncComputedRippleWhen(f, func(o, n) bool { return !eq(o, n) }) are the same. changed MUST be pure in (old, next); value-carried state is fine, external mutable state is not.

func NewAsyncComputedWithEquals added in v0.24.0

func NewAsyncComputedWithEquals[T any](c *AsyncContext, compute func(cc *AsyncComputeContext) (T, error), eq Equals[T]) *AsyncComputed[T]

NewAsyncComputedWithEquals is like NewAsyncComputed but with an equality memo guard: a recompute that yields an equal value (per eq) keeps the cached value and suppresses the dependency cascade (Dart AsyncContext.memoAsync).

func NewAsyncMemo deprecated

func NewAsyncMemo[T any](
	c *AsyncContext,
	compute func(cc *AsyncComputeContext) (T, error),
	eq Equals[T],
) *AsyncComputed[T]

NewAsyncMemo is the deprecated guarded-computed constructor. Memo is not a separate node kind.

Deprecated: use NewAsyncComputedWithEquals.

func NewAsyncSlot deprecated

func NewAsyncSlot[T any](
	c *AsyncContext,
	compute func(cc *AsyncComputeContext) (T, error),
) *AsyncComputed[T]

NewAsyncSlot is the deprecated v1 computed constructor.

Deprecated: use NewAsyncComputed.

func (*AsyncComputed[T]) Dispose added in v0.24.0

func (s *AsyncComputed[T]) Dispose()

Dispose is an alias for DisposeAsync.

func (*AsyncComputed[T]) DisposeAsync added in v0.24.0

func (s *AsyncComputed[T]) DisposeAsync()

DisposeAsync tears down this async slot: it cancels any in-flight compute, detaches both edge directions, and dirties the surviving dependent cone. Idempotent.

Blocked waiters and any later reader receive a *DisposedError — the same "errors on next recompute" contract as the synchronous Slot.Dispose.

func (*AsyncComputed[T]) Get added in v0.24.0

func (s *AsyncComputed[T]) Get() (T, bool)

Get is the synchronous cached read (Dart get()): it returns (value, true) when the slot is resolved, else (zero, false). It does not spawn a compute.

func (*AsyncComputed[T]) GetAsync added in v0.24.0

func (s *AsyncComputed[T]) GetAsync(ctx context.Context) (T, error)

GetAsync awaits the slot's value. Resolved slots return immediately; otherwise the caller attaches to the in-flight compute (spawning one if none is running — in-flight deduplication). ctx cancels this waiter only: dropping one waiter never cancels a shared in-flight compute (cancellation contract point 1). Supersession causes a transparent re-resolve.

func (*AsyncComputed[T]) Revision added in v0.24.0

func (s *AsyncComputed[T]) Revision() int

Revision reports the current revision (incremented on each invalidation; a completion whose revision is stale is discarded).

func (*AsyncComputed[T]) State added in v0.24.0

func (s *AsyncComputed[T]) State() AsyncComputedState

State reports the current state-machine state.

func (*AsyncComputed[T]) Value added in v0.24.0

func (s *AsyncComputed[T]) Value() (T, bool)

Value returns the cached value when resolved, else (zero, false) (Dart value getter).

type AsyncComputedMap added in v0.22.0

type AsyncComputedMap[K comparable, V comparable] struct {
	*AsyncReactiveMap[K, V, asyncComputedNodeHandle]
}

AsyncComputedMap is the derived-slot specialization of AsyncReactiveMap: entries are minted pending and driven to resolution via Drive; MaterializeAll pre-mints the keyset (still pending until driven). No Set.

func NewAsyncComputedMap added in v0.22.0

func NewAsyncComputedMap[K comparable, V comparable](c *AsyncContext) *AsyncComputedMap[K, V]

NewAsyncComputedMap creates an empty async derived-slot map.

func NewAsyncSlotMap deprecated added in v0.7.0

func NewAsyncSlotMap[K comparable, V comparable](c *AsyncContext) *AsyncComputedMap[K, V]

NewAsyncSlotMap creates an empty async derived-slot map through the v1 name.

Deprecated: renamed to NewAsyncComputedMap.

func (*AsyncComputedMap[K, V]) MaterializeAll added in v0.22.0

func (m *AsyncComputedMap[K, V]) MaterializeAll(keys []K, factory func(K) V)

MaterializeAll eagerly pre-mints (allocates, still pending) a derived slot for every key. Drive each to resolution. Observationally identical (once driven) to minting lazily on first access.

type AsyncComputedState added in v0.24.0

type AsyncComputedState string

AsyncComputedState is the public projection of an async computed's finite-state machine. The formal model retains the storage-oriented AsyncSlotState theorem/module name.

const (
	// AsyncComputedEmpty: no cached value, no in-flight computation. Entered on
	// creation and after a hard clear.
	AsyncComputedEmpty AsyncComputedState = "empty"
	// AsyncComputedComputing: a compute is in flight for the current revision.
	// Concurrent GetAsync callers attach as waiters instead of spawning
	// duplicate computations.
	AsyncComputedComputing AsyncComputedState = "computing"
	// AsyncComputedResolved: the cached value is fresh, until dependency
	// invalidation transitions back to computing.
	AsyncComputedResolved AsyncComputedState = "resolved"
	// AsyncComputedError: the last computation failed. Waiters on that attempt
	// receive its error; the error is not cached. The next GetAsync re-spawns
	// (Error -> Computing), per docs/async.md § Async slot state machine and
	// LazilyFormal.AsyncSlotState SlotEvent.retry.
	AsyncComputedError AsyncComputedState = "error"
)

type AsyncContext

type AsyncContext struct {
	// contains filtered or unexported fields
}

AsyncContext is the async reactive surface: a distinct graph owned by a single goroutine that serializes all mutations and reads over a command channel. Unlike core Context, AsyncContext is safe for concurrent use.

func NewAsyncContext

func NewAsyncContext() *AsyncContext

NewAsyncContext creates an async reactive context and starts its owner goroutine. Call DisposeAsync or Close to tear it down.

func (*AsyncContext) Batch

func (c *AsyncContext) Batch(run func())

Batch delimits a synchronous batch on the calling goroutine. Cell writes made during run queue their invalidation roots; at the outermost batch exit the queued roots propagate once. Async reruns fire after run returns. Re-entrant.

Note: because the batch flag is loop-owned, cell writes from other goroutines during the batch are also coalesced; batch from a single goroutine.

func (*AsyncContext) Close

func (c *AsyncContext) Close() error

Close disposes the context (io.Closer-style). It always returns nil.

func (*AsyncContext) DependencyCount added in v0.20.0

func (c *AsyncContext) DependencyCount(n AsyncGraphNode) int

DependencyCount reports how many nodes n currently depends on — the size of its forward edge set. Returns 0 for a disposed node and for a cell, which is a pure source.

func (*AsyncContext) DependentCount added in v0.20.0

func (c *AsyncContext) DependentCount(n AsyncGraphNode) int

DependentCount reports how many nodes currently depend on n — the size of its reverse edge set (#lzspecedgeindex). Returns 0 for a disposed node and for an effect, which is a pure sink.

As on the synchronous plane, this counts *live* edges: invalidation consumes the reverse edge and each dependent re-registers when it recomputes, so a degree read between a write and the pull that follows it reports the post-cascade state.

func (*AsyncContext) DisposeAsync

func (c *AsyncContext) DisposeAsync()

DisposeAsync disposes the context: cancels all in-flight computations, delivers a disposed error to blocked waiters, runs and awaits every active effect cleanup, then stops the owner goroutine. Subsequent operations are no-ops / disposed errors. Idempotent.

func (*AsyncContext) EffectAsync

func (c *AsyncContext) EffectAsync(body func(cc *AsyncComputeContext) func()) *AsyncEffectHandle

EffectAsync creates an async effect. The body receives a compute context and returns an optional cleanup callback run before the next body and on disposal. Reruns are serialized: a rerun does not start until the prior cleanup runs.

func (*AsyncContext) IsDisposed added in v0.20.0

func (c *AsyncContext) IsDisposed(n AsyncGraphNode) bool

IsDisposed reports whether n has been torn down.

func (*AsyncContext) Scope added in v0.20.0

func (c *AsyncContext) Scope() *AsyncTeardownScope

Scope opens a teardown scope on this async context.

func (*AsyncContext) WithScope added in v0.20.0

func (c *AsyncContext) WithScope(fn func(s *AsyncTeardownScope))

WithScope runs fn with a fresh async teardown scope and closes it on return, including on panic.

type AsyncEffectHandle

type AsyncEffectHandle struct {
	// contains filtered or unexported fields
}

AsyncEffectHandle is an async effect returned by AsyncContext.EffectAsync. Reruns are serialized per effect (a rerun does not start until the previous cleanup completes), and disposal awaits the current cleanup.

func (*AsyncEffectHandle) Dispose

func (e *AsyncEffectHandle) Dispose()

Dispose is an alias for DisposeAsync.

func (*AsyncEffectHandle) DisposeAsync

func (e *AsyncEffectHandle) DisposeAsync()

DisposeAsync disposes the effect: cancels any in-flight body and runs its pending cleanup. Idempotent.

func (*AsyncEffectHandle) IsActive added in v0.20.0

func (e *AsyncEffectHandle) IsActive() bool

IsActive reports whether this effect is still registered (not disposed).

type AsyncGraphNode added in v0.20.0

type AsyncGraphNode interface {
	// contains filtered or unexported methods
}

AsyncGraphNode is any node in an AsyncContext's graph: *AsyncSource, *AsyncComputed, or *AsyncEffectHandle.

Sealed by an unexported method, and — like the synchronous GraphNode — it exposes counts only, never the edge sets.

type AsyncMapHandle added in v0.7.0

type AsyncMapHandle interface {
	// contains filtered or unexported methods
}

AsyncMapHandle is the entry-handle kind an AsyncReactiveMap abstracts over — the async analog of the Rust AsyncMapHandle trait. Sealed to the two node kinds of the cell model. resolvedOnMint reports whether a freshly-minted entry is resolved (a cell — always resolved) or pending (a derived slot).

type AsyncQueueCell added in v0.24.0

type AsyncQueueCell[T comparable, S QueueStorage[T]] struct {
	// contains filtered or unexported fields
}

AsyncQueueCell is the AsyncContext FIFO flavor. Storage is serialized by mu; changed reader kinds are invalidated together through AsyncContext.Batch.

func NewAsyncQueueCell added in v0.24.0

func NewAsyncQueueCell[T comparable](ctx *AsyncContext) *AsyncQueueCell[T, *VecDequeStorage[T]]

func NewAsyncQueueCellWithStorage added in v0.24.0

func NewAsyncQueueCellWithStorage[T comparable, S QueueStorage[T]](
	ctx *AsyncContext,
	storage S,
) *AsyncQueueCell[T, S]

func NewBoundedAsyncQueueCell added in v0.24.0

func NewBoundedAsyncQueueCell[T comparable](
	ctx *AsyncContext,
	capacity int,
) *AsyncQueueCell[T, *VecDequeStorage[T]]

func (*AsyncQueueCell[T, S]) Capacity added in v0.24.0

func (q *AsyncQueueCell[T, S]) Capacity() (int, bool)

func (*AsyncQueueCell[T, S]) Close added in v0.24.0

func (q *AsyncQueueCell[T, S]) Close()

func (*AsyncQueueCell[T, S]) Elements added in v0.24.0

func (q *AsyncQueueCell[T, S]) Elements() []T

func (*AsyncQueueCell[T, S]) Head added in v0.24.0

func (q *AsyncQueueCell[T, S]) Head(cc *AsyncComputeContext) (T, bool)

func (*AsyncQueueCell[T, S]) IsClosed added in v0.24.0

func (q *AsyncQueueCell[T, S]) IsClosed(cc *AsyncComputeContext) bool

func (*AsyncQueueCell[T, S]) IsEmpty added in v0.24.0

func (q *AsyncQueueCell[T, S]) IsEmpty(cc *AsyncComputeContext) bool

func (*AsyncQueueCell[T, S]) IsFull added in v0.24.0

func (q *AsyncQueueCell[T, S]) IsFull(cc *AsyncComputeContext) bool

func (*AsyncQueueCell[T, S]) Len added in v0.24.0

func (q *AsyncQueueCell[T, S]) Len(cc *AsyncComputeContext) int

func (*AsyncQueueCell[T, S]) ReaderHandles added in v0.24.0

func (q *AsyncQueueCell[T, S]) ReaderHandles() AsyncQueueReaderHandles[T]

func (*AsyncQueueCell[T, S]) TryPop added in v0.24.0

func (q *AsyncQueueCell[T, S]) TryPop() (T, QueuePopError)

func (*AsyncQueueCell[T, S]) TryPush added in v0.24.0

func (q *AsyncQueueCell[T, S]) TryPush(value T) QueuePushError

type AsyncQueueReaderHandles added in v0.24.0

type AsyncQueueReaderHandles[T comparable] struct {
	Head     *AsyncComputed[queueHead[T]]
	Len      *AsyncComputed[int]
	IsEmpty  *AsyncComputed[bool]
	IsFull   *AsyncComputed[bool]
	IsClosed *AsyncSource[bool]
}

AsyncQueueReaderHandles exposes the five queue reader kinds on the async graph. The content readers are memoized derives; Closed is a direct input.

type AsyncReactiveMap added in v0.7.0

type AsyncReactiveMap[K comparable, V comparable, H AsyncMapHandle] struct {
	// contains filtered or unexported fields
}

AsyncReactiveMap is the async keyed reactive map (#reactivemap) generic over the entry handle kind H, each entry carrying a resolution flag. V is comparable to mirror the single-threaded map.

Once built its address is stable, so concurrent readers may share a *AsyncReactiveMap. See the package doc for the eager/lazy contract, present-set monotonicity, and the eventual-transparency law.

func (*AsyncReactiveMap[K, V, H]) ContainsKey added in v0.23.0

func (m *AsyncReactiveMap[K, V, H]) ContainsKey(cc *AsyncComputeContext, key K) bool

ContainsKey reports the reactive membership test for key.

func (*AsyncReactiveMap[K, V, H]) Drive added in v0.7.0

func (m *AsyncReactiveMap[K, V, H]) Drive(key K, factory func(K) V) V

Drive drives key to resolution — the analog of AsyncContext.GetAsync: allocate if absent, resolve if pending (produce + cache the canonical value via factory), and return the resolved value. A warm-resolved key returns its cached value unchanged. The eventual-transparency completion.

func (*AsyncReactiveMap[K, V, H]) Entry added in v0.23.0

func (m *AsyncReactiveMap[K, V, H]) Entry(key K) *AsyncSource[V]

Entry returns key's node on the async graph, or nil. Reading it through TrackSource inside an async compute registers a per-entry dependency edge.

func (*AsyncReactiveMap[K, V, H]) EntryID added in v0.23.0

func (m *AsyncReactiveMap[K, V, H]) EntryID(key K) (uint64, bool)

EntryID returns key's stable birth identity — the async analog of a node handle. It survives a reorder and changes only on a re-mint.

func (*AsyncReactiveMap[K, V, H]) EntryKind added in v0.7.0

func (m *AsyncReactiveMap[K, V, H]) EntryKind() EntryKind

EntryKind returns this map's entry kind.

func (*AsyncReactiveMap[K, V, H]) GetOrInsertWith added in v0.7.0

func (m *AsyncReactiveMap[K, V, H]) GetOrInsertWith(key K, factory func(K) V) (V, bool)

GetOrInsertWith mints key on first access and returns the current observation: (value, true) for a cell or a warm-resolved slot, (_, false) for a freshly pending slot. Mint-on-access; drive a pending slot with Drive.

func (*AsyncReactiveMap[K, V, H]) IsEmpty added in v0.23.0

func (m *AsyncReactiveMap[K, V, H]) IsEmpty(cc *AsyncComputeContext) bool

IsEmpty reports the reactive emptiness check.

func (*AsyncReactiveMap[K, V, H]) IsPresent added in v0.7.0

func (m *AsyncReactiveMap[K, V, H]) IsPresent(key K) bool

IsPresent reports whether key is currently allocated (present). Non-reactive.

func (*AsyncReactiveMap[K, V, H]) IsResolved added in v0.7.0

func (m *AsyncReactiveMap[K, V, H]) IsResolved(key K) bool

IsResolved reports whether key is allocated AND resolved (a non-blocking Observe would return a value).

func (*AsyncReactiveMap[K, V, H]) Keys added in v0.23.0

func (m *AsyncReactiveMap[K, V, H]) Keys(cc *AsyncComputeContext) []K

Keys returns a reactive snapshot of the keys in their current order. Subscribes the caller to order changes when read inside an async compute.

func (*AsyncReactiveMap[K, V, H]) Len added in v0.23.0

func (m *AsyncReactiveMap[K, V, H]) Len(cc *AsyncComputeContext) int

Len reports the reactive entry count. Subscribes to membership changes only.

func (*AsyncReactiveMap[K, V, H]) LenUntracked added in v0.23.0

func (m *AsyncReactiveMap[K, V, H]) LenUntracked() int

LenUntracked reports the non-reactive count.

func (*AsyncReactiveMap[K, V, H]) MoveAfter added in v0.23.0

func (m *AsyncReactiveMap[K, V, H]) MoveAfter(key, anchor K) bool

MoveAfter atomically moves key to just after anchor (#lzcellmove).

func (*AsyncReactiveMap[K, V, H]) MoveBefore added in v0.23.0

func (m *AsyncReactiveMap[K, V, H]) MoveBefore(key, anchor K) bool

MoveBefore atomically moves key to just before anchor (#lzcellmove).

func (*AsyncReactiveMap[K, V, H]) MoveTo added in v0.23.0

func (m *AsyncReactiveMap[K, V, H]) MoveTo(key K, index int) bool

MoveTo atomically moves key to index in the order (#lzcellmove). The entry keeps its identity and its resolution state; only the order signal is bumped, so Keys readers recompute while Len / ContainsKey readers stay cached. index is clamped to [0, len).

func (*AsyncReactiveMap[K, V, H]) Observe added in v0.7.0

func (m *AsyncReactiveMap[K, V, H]) Observe(key K, factory func(K) V) (V, bool)

Observe is a non-blocking read: (value, true) once resolved, (_, false) while pending. Allocates the entry via factory if absent — a freshly allocated slot is pending, so a first Observe of a slot returns (_, false) until Driven; a cell is resolved at allocation, so it returns (value, true) immediately.

func (*AsyncReactiveMap[K, V, H]) ObserveTracked added in v0.23.0

func (m *AsyncReactiveMap[K, V, H]) ObserveTracked(cc *AsyncComputeContext, key K) (V, bool)

ObserveTracked is the reactive per-entry read: inside an async compute it registers an edge against that entry's node, so a later write to this key invalidates the reader and a write to any OTHER key does not.

func (*AsyncReactiveMap[K, V, H]) Position added in v0.23.0

func (m *AsyncReactiveMap[K, V, H]) Position(key K) (int, bool)

Position reports key's current 0-based position in the order. Non-reactive.

func (*AsyncReactiveMap[K, V, H]) PresentCount added in v0.7.0

func (m *AsyncReactiveMap[K, V, H]) PresentCount() int

PresentCount returns the number of currently-allocated entries.

func (*AsyncReactiveMap[K, V, H]) PresentKeys added in v0.7.0

func (m *AsyncReactiveMap[K, V, H]) PresentKeys() []K

PresentKeys returns a stable snapshot of the currently-allocated keys, in first-materialization order (a copy — the internal order must not escape the lock).

func (*AsyncReactiveMap[K, V, H]) Remove added in v0.23.0

func (m *AsyncReactiveMap[K, V, H]) Remove(key K) bool

Remove removes key's entry and bumps reactive membership. Returns whether the key was present. The removed entry's cached value goes with it, so a later read cannot serve a stale resolution.

type AsyncSlotHandle deprecated

type AsyncSlotHandle[T any] = AsyncComputed[T]

AsyncSlotHandle is the deprecated v1 name for AsyncComputed.

Deprecated: use AsyncComputed.

type AsyncSlotMap deprecated added in v0.7.0

type AsyncSlotMap[K comparable, V comparable] = AsyncComputedMap[K, V]

AsyncSlotMap is the pre-v2-kernel name for AsyncComputedMap, kept as an alias so existing callers keep compiling.

Deprecated: renamed to AsyncComputedMap.

type AsyncSlotState deprecated

type AsyncSlotState = AsyncComputedState

AsyncSlotState is the deprecated v1 name for AsyncComputedState.

Deprecated: use AsyncComputedState.

type AsyncSource added in v0.24.0

type AsyncSource[T any] struct {
	// contains filtered or unexported fields
}

AsyncSource is a mutable input cell on the async graph. Reads registered inside an async compute/effect (via TrackSource) create a dependency edge; writes invalidate dependents.

func NewAsyncCell deprecated

func NewAsyncCell[T any](c *AsyncContext, value T) *AsyncSource[T]

NewAsyncCell is the deprecated v1 source constructor.

Deprecated: use NewAsyncSource.

func NewAsyncSource added in v0.24.0

func NewAsyncSource[T any](c *AsyncContext, value T) *AsyncSource[T]

NewAsyncSource creates a mutable input cell bound to c (Dart AsyncContext.cell).

func (*AsyncSource[T]) Dispose added in v0.24.0

func (h *AsyncSource[T]) Dispose()

Dispose is an alias for DisposeAsync.

func (*AsyncSource[T]) DisposeAsync added in v0.24.0

func (h *AsyncSource[T]) DisposeAsync()

DisposeAsync tears down this async cell: it detaches its dependents and dirties the surviving cone. Cells are pure sources, so only downstream edges need detaching. Idempotent.

func (*AsyncSource[T]) Get added in v0.24.0

func (h *AsyncSource[T]) Get() T

Get returns the current value. It does NOT register a dependency (there is no ambient compute outside a goroutine in Go); use TrackSource inside an async compute for reactive reads. Kept for parity with the Dart surface.

func (*AsyncSource[T]) Peek added in v0.24.0

func (h *AsyncSource[T]) Peek() T

Peek returns the current value without registering a dependency (non-reactive). Use TrackSource to read reactively inside an async compute.

func (*AsyncSource[T]) Set added in v0.24.0

func (h *AsyncSource[T]) Set(value T)

Set assigns a new value. If it differs from the current value, dependent async slots/effects are invalidated (or queued when inside Batch).

func (*AsyncSource[T]) TryGet added in v0.24.0

func (h *AsyncSource[T]) TryGet() (T, error)

TryGet is the checked read: it returns a *DisposedError instead of panicking when this cell has been disposed.

type AsyncSourceMap added in v0.22.0

type AsyncSourceMap[K comparable, V comparable] struct {
	*AsyncReactiveMap[K, V, asyncSourceNodeHandle]
}

AsyncSourceMap is the input-cell specialization of AsyncReactiveMap: every entry is an always-resolved input cell. Adds the cell-only Set.

func NewAsyncCellMap deprecated added in v0.7.0

func NewAsyncCellMap[K comparable, V comparable](c *AsyncContext) *AsyncSourceMap[K, V]

NewAsyncCellMap creates an empty async input-cell map through the v1 name.

Deprecated: renamed to NewAsyncSourceMap.

func NewAsyncSourceMap added in v0.22.0

func NewAsyncSourceMap[K comparable, V comparable](c *AsyncContext) *AsyncSourceMap[K, V]

NewAsyncSourceMap creates an empty async input-cell map.

func (*AsyncSourceMap[K, V]) Set added in v0.22.0

func (m *AsyncSourceMap[K, V]) Set(key K, value V)

Set overwrites key's value (cells are writable, always resolved), materializing the entry if absent. Cell-only: a derived AsyncComputedMap slot is not settable.

type AsyncTeardownScope added in v0.20.0

type AsyncTeardownScope struct {
	// contains filtered or unexported fields
}

AsyncTeardownScope groups async nodes so they can be torn down together. The Close/Disarm/Own shape and its rationale are identical to the synchronous TeardownScope; see disposal.go.

func (*AsyncTeardownScope) Close added in v0.20.0

func (s *AsyncTeardownScope) Close()

Close tears down every node this scope owns, in reverse creation order. Idempotent.

func (*AsyncTeardownScope) Disarm added in v0.20.0

func (s *AsyncTeardownScope) Disarm()

Disarm cancels this scope's teardown: Close then disposes nothing and the nodes revert to plain context ownership, untouched and individually disposable.

func (*AsyncTeardownScope) Len added in v0.20.0

func (s *AsyncTeardownScope) Len() int

Len reports how many nodes this scope currently owns.

type AsyncTopicCell added in v0.24.0

type AsyncTopicCell[T any] struct {
	// contains filtered or unexported fields
}

AsyncTopicCell is the AsyncContext broadcast-log flavor.

func NewAsyncTopicCell added in v0.24.0

func NewAsyncTopicCell[T any](ctx *AsyncContext) *AsyncTopicCell[T]

func NewAsyncTopicCellFromSnapshot added in v0.24.0

func NewAsyncTopicCellFromSnapshot[T any](
	ctx *AsyncContext,
	snapshot TopicSnapshot[T],
) *AsyncTopicCell[T]

func (*AsyncTopicCell[T]) Advance added in v0.24.0

func (t *AsyncTopicCell[T]) Advance(id string, count int) int

func (*AsyncTopicCell[T]) BaseOffset added in v0.24.0

func (t *AsyncTopicCell[T]) BaseOffset() int

func (*AsyncTopicCell[T]) Disconnect added in v0.24.0

func (t *AsyncTopicCell[T]) Disconnect(id string)

func (*AsyncTopicCell[T]) Elements added in v0.24.0

func (t *AsyncTopicCell[T]) Elements() []T

func (*AsyncTopicCell[T]) GC added in v0.24.0

func (t *AsyncTopicCell[T]) GC() int

func (*AsyncTopicCell[T]) Publish added in v0.24.0

func (t *AsyncTopicCell[T]) Publish(value T) int

func (*AsyncTopicCell[T]) Read added in v0.24.0

func (t *AsyncTopicCell[T]) Read(cc *AsyncComputeContext, id string) (T, bool)

func (*AsyncTopicCell[T]) ReadStream added in v0.24.0

func (t *AsyncTopicCell[T]) ReadStream(cc *AsyncComputeContext, id string) ([]T, bool)

func (*AsyncTopicCell[T]) ReaderHandle added in v0.24.0

func (t *AsyncTopicCell[T]) ReaderHandle(id string) *AsyncComputed[TopicRead[T]]

func (*AsyncTopicCell[T]) Reconnect added in v0.24.0

func (t *AsyncTopicCell[T]) Reconnect(id string)

func (*AsyncTopicCell[T]) Restart added in v0.24.0

func (t *AsyncTopicCell[T]) Restart()

func (*AsyncTopicCell[T]) Snapshot added in v0.24.0

func (t *AsyncTopicCell[T]) Snapshot() TopicSnapshot[T]

func (*AsyncTopicCell[T]) Subscribe added in v0.24.0

func (t *AsyncTopicCell[T]) Subscribe(
	id string,
	durability TopicDurability,
) TopicSubscribeOutcome

func (*AsyncTopicCell[T]) Subscription added in v0.24.0

func (t *AsyncTopicCell[T]) Subscription(id string) (TopicSubscriptionSnapshot, bool)

func (*AsyncTopicCell[T]) TailOffset added in v0.24.0

func (t *AsyncTopicCell[T]) TailOffset() int

type AsyncWorkQueueCell added in v0.24.0

type AsyncWorkQueueCell[T any] struct {
	// contains filtered or unexported fields
}

AsyncWorkQueueCell is the AsyncContext competing-consumer flavor.

func NewAsyncWorkQueueCell added in v0.24.0

func NewAsyncWorkQueueCell[T any](
	ctx *AsyncContext,
	visibilityTimeout int64,
	maxDeliveries uint64,
) *AsyncWorkQueueCell[T]

func (*AsyncWorkQueueCell[T]) Ack added in v0.24.0

func (q *AsyncWorkQueueCell[T]) Ack(worker string, deliveryID uint64) bool

func (*AsyncWorkQueueCell[T]) Claim added in v0.24.0

func (q *AsyncWorkQueueCell[T]) Claim(worker string, now int64) (WorkQueueDelivery[T], bool)

func (*AsyncWorkQueueCell[T]) DeadLetterItems added in v0.24.0

func (q *AsyncWorkQueueCell[T]) DeadLetterItems() []WorkQueueDeadLetter[T]

func (*AsyncWorkQueueCell[T]) DeadLetterLen added in v0.24.0

func (q *AsyncWorkQueueCell[T]) DeadLetterLen(cc *AsyncComputeContext) int

func (*AsyncWorkQueueCell[T]) InFlightDeliveries added in v0.24.0

func (q *AsyncWorkQueueCell[T]) InFlightDeliveries() []WorkQueueDelivery[T]

func (*AsyncWorkQueueCell[T]) InFlightLen added in v0.24.0

func (q *AsyncWorkQueueCell[T]) InFlightLen(cc *AsyncComputeContext) int

func (*AsyncWorkQueueCell[T]) IsEmpty added in v0.24.0

func (q *AsyncWorkQueueCell[T]) IsEmpty(cc *AsyncComputeContext) bool

func (*AsyncWorkQueueCell[T]) Nack added in v0.24.0

func (q *AsyncWorkQueueCell[T]) Nack(worker string, deliveryID uint64) bool

func (*AsyncWorkQueueCell[T]) PendingItems added in v0.24.0

func (q *AsyncWorkQueueCell[T]) PendingItems() []WorkQueueItem[T]

func (*AsyncWorkQueueCell[T]) PendingLen added in v0.24.0

func (q *AsyncWorkQueueCell[T]) PendingLen(cc *AsyncComputeContext) int

func (*AsyncWorkQueueCell[T]) Push added in v0.24.0

func (q *AsyncWorkQueueCell[T]) Push(value T) uint64

func (*AsyncWorkQueueCell[T]) ReaderHandles added in v0.24.0

func (q *AsyncWorkQueueCell[T]) ReaderHandles() AsyncWorkQueueReaderHandles

func (*AsyncWorkQueueCell[T]) ReapExpired added in v0.24.0

func (q *AsyncWorkQueueCell[T]) ReapExpired(now int64) int

type AsyncWorkQueueReaderHandles added in v0.24.0

type AsyncWorkQueueReaderHandles struct {
	PendingLen    *AsyncComputed[int]
	IsEmpty       *AsyncComputed[bool]
	InFlightLen   *AsyncComputed[int]
	DeadLetterLen *AsyncComputed[int]
}

AsyncWorkQueueReaderHandles exposes the four lifecycle derives.

type AwarenessCell added in v0.15.0

type AwarenessCell[K comparable, V comparable] struct {
	// contains filtered or unexported fields
}

AwarenessCell is a reactive typed ephemeral broadcast (cursors / selections): last-writer-per-peer with a TTL. Values do NOT merge.

func NewAwarenessCell added in v0.15.0

func NewAwarenessCell[K comparable, V comparable](ctx *Context, ttl uint64) *AwarenessCell[K, V]

NewAwarenessCell builds an awareness cell with a TTL.

func (*AwarenessCell[K, V]) Get added in v0.15.0

func (c *AwarenessCell[K, V]) Get(peer K, now uint64) (V, bool)

Get returns a peer's live value (respecting now).

func (*AwarenessCell[K, V]) Present added in v0.15.0

func (c *AwarenessCell[K, V]) Present() map[K]V

Present returns the live peer -> value snapshot.

func (*AwarenessCell[K, V]) PresentCell added in v0.15.0

func (c *AwarenessCell[K, V]) PresentCell() *Source[uint64]

PresentCell exposes the internal version cell backing the present projection.

func (*AwarenessCell[K, V]) Set added in v0.15.0

func (c *AwarenessCell[K, V]) Set(peer K, value V, now uint64)

Set a peer's awareness value (last-writer wins, no merge).

func (*AwarenessCell[K, V]) Tick added in v0.15.0

func (c *AwarenessCell[K, V]) Tick(now uint64)

Tick evicts expired entries.

type BackpressurePolicy added in v0.11.0

type BackpressurePolicy struct {
	Dimension *Source[BoundDim]
	HighWater *Source[uint64]
	LowWater  *Source[uint64]
	Overflow  *Source[Overflow]
}

BackpressurePolicy holds reactive backpressure limits (analysis §4.4). Every field is a cell, so an operator or adaptive controller retunes it live and dependent relays react. Hysteresis (HighWater ≠ LowWater) prevents flapping.

func NewBackpressurePolicy added in v0.11.0

func NewBackpressurePolicy(ctx *Context, dimension BoundDim, highWater, lowWater uint64, overflow Overflow) BackpressurePolicy

NewBackpressurePolicy builds a reactive backpressure policy over ctx.

type BarrierCell added in v0.15.0

type BarrierCell[P comparable] struct {
	// contains filtered or unexported fields
}

BarrierCell is a reactive wait-for-N gate. Quorum is a barrier with required = total/2 + 1.

func NewBarrierCell added in v0.15.0

func NewBarrierCell[P comparable](ctx *Context, required uint64) *BarrierCell[P]

NewBarrierCell constructs a reactive wait-for-N gate.

func Quorum added in v0.15.0

func Quorum[P comparable](ctx *Context, total uint64) *BarrierCell[P]

Quorum constructs a quorum gate: opens at strict majority of total.

func (*BarrierCell[P]) Arrive added in v0.15.0

func (c *BarrierCell[P]) Arrive(peer P) bool

Arrive registers an arrival / vote; returns whether the gate is open after.

func (*BarrierCell[P]) Count added in v0.15.0

func (c *BarrierCell[P]) Count() uint64

Count returns the number of distinct arrivals.

func (*BarrierCell[P]) IsOpen added in v0.15.0

func (c *BarrierCell[P]) IsOpen() bool

IsOpen reports whether the gate has opened.

func (*BarrierCell[P]) IsOpenCell added in v0.15.0

func (c *BarrierCell[P]) IsOpenCell() *Source[bool]

IsOpenCell exposes the reactive is_open projection.

type BarrierCore added in v0.15.0

type BarrierCore[P comparable] struct {
	// contains filtered or unexported fields
}

BarrierCore is a wait-for-N gate compute core over distinct arriving peers.

func NewBarrierCore added in v0.15.0

func NewBarrierCore[P comparable](required uint64) *BarrierCore[P]

NewBarrierCore returns a barrier that opens once required distinct peers arrive.

func (*BarrierCore[P]) Arrive added in v0.15.0

func (c *BarrierCore[P]) Arrive(peer P) bool

Arrive registers a distinct arrival; returns whether the gate is open after.

func (*BarrierCore[P]) Count added in v0.15.0

func (c *BarrierCore[P]) Count() uint64

Count returns the number of distinct arrivals.

func (*BarrierCore[P]) IsOpen added in v0.15.0

func (c *BarrierCore[P]) IsOpen() bool

IsOpen reports whether the gate has opened.

type BatchFlush

type BatchFlush struct {
	// ChangedCells are the cells that changed in this batch (informational; not
	// serialized).
	ChangedCells []NodeId
	// Frontier is the coalesced, duplicate-free invalidation frontier.
	Frontier []NodeId
	// Ops is Frontier mapped to DeltaOpInvalidate (theorem
	// `batch_flush_ops_are_frontier_invalidations`).
	Ops []DeltaOp
}

BatchFlush is lean `BatchFlush` + theorems `batch_frontier_is_coalesced`, `batch_flush_advances_epoch_once`, `batch_flush_ops_are_frontier_invalidations`.

One outermost batch-flush invalidation pass produces a no-duplicate frontier (Frontier) and emits exactly one delta that advances the IPC epoch once. The frontier is coalesced: a dependent reached through many changed cells appears at most once.

func NewBatchFlush

func NewBatchFlush(changedCells, frontier []NodeId) BatchFlush

NewBatchFlush coalesces frontier and derives the invalidation ops.

func (BatchFlush) ToDelta

func (b BatchFlush) ToDelta(baseEpoch Epoch) Delta

ToDelta builds the single delta this flush emits, advancing the epoch exactly once (theorem `batch_flush_advances_epoch_once`).

type BatchWrite

type BatchWrite struct {
	NodeID any
	Value  any
}

BatchWrite is a (nodeID, value) write in the pure kernel.

type BenchmarkResult

type BenchmarkResult struct {
	Name       string
	Iterations int
	// TotalMicros is the total elapsed time across all iterations, in
	// microseconds.
	TotalMicros int64
}

BenchmarkResult is a single benchmark measurement.

func Benchmark

func Benchmark(name string, body func(), iterations int) BenchmarkResult

Benchmark runs body iterations times and measures the total elapsed time.

func RunBenchmarkSuite

func RunBenchmarkSuite(iterations int) []BenchmarkResult

RunBenchmarkSuite runs the full benchmark suite and returns every result. Pass DefaultBenchmarkIterations to match the Dart default.

func (BenchmarkResult) AvgMicros

func (r BenchmarkResult) AvgMicros() float64

AvgMicros returns the average time per iteration in microseconds.

func (BenchmarkResult) OpsPerSecond

func (r BenchmarkResult) OpsPerSecond() float64

OpsPerSecond returns the operations per second.

func (BenchmarkResult) String

func (r BenchmarkResult) String() string

String renders the result the same way the Dart toString does.

type BindingCapabilities

type BindingCapabilities struct {
	Binding               string
	Ffi                   FfiCapability
	ReactiveCore          bool
	Collections           bool
	StateMachine          bool
	StateCharts           bool
	Ipc                   bool
	Crdt                  bool
	Permissions           bool
	CapabilityNegotiation bool
	Async                 bool
}

BindingCapabilities is the lazily-go binding's conformance declaration (protocol.md § Binding Conformance Matrix). This binding implements every MUST layer.

The Dart original models this as a class of static consts; in Go the canonical declaration is a value returned by NewBindingCapabilities. The `Ffi` capability is `host` because Go can host a native C ABI via cgo; never `none` (the `none` carve-out is reserved for platforms with no shared in-process address space, e.g. browser/Worker JS).

func NewBindingCapabilities

func NewBindingCapabilities() BindingCapabilities

NewBindingCapabilities returns the canonical lazily-go conformance declaration (every MUST layer implemented, ffi = host).

func (BindingCapabilities) MarshalJSON

func (b BindingCapabilities) MarshalJSON() ([]byte, error)

MarshalJSON emits the conformance declaration with the spec field order.

func (BindingCapabilities) ToWire

func (b BindingCapabilities) ToWire() any

ToWire returns the JSON object (as an ordered marshaling struct) a peer introspects at build/link time.

type BlobBackend added in v0.4.0

type BlobBackend interface {
	// Kind reports which backend discriminator this adapter serves.
	Kind() BlobBackendKind
	// Write mints a fresh descriptor for bytes: it stores the bytes immutably
	// and returns a descriptor whose Checksum is the bytes' FNV-1a-64, tagged
	// with this backend's Kind.
	Write(bytes []byte) (ShmBlobRef, error)
	// ReadView resolves descriptor zero-copy: it returns the stored bytes and
	// ok=true iff generation + epoch + len + checksum all match; (nil, false)
	// otherwise. No copy, no checksum recompute. The returned slice aliases the
	// backend's storage and is valid only while the backend holds the entry.
	ReadView(descriptor ShmBlobRef) ([]byte, bool)
	// AdvanceEpoch advances the validity epoch. Descriptors minted before an
	// epoch advance no longer resolve (models compaction / restart).
	AdvanceEpoch()
}

BlobBackend is the adapter seam: a backend mints descriptors via Write and resolves them zero-copy via ReadView. Entries are immutable and stably addressed for any descriptor's lifetime, so the transport laws (resolve_write identity, backend isolation, ABA generation safety, checksum rejection) hold for every backend by construction.

type BlobBackendKind added in v0.4.0

type BlobBackendKind string

BlobBackendKind selects which pluggable blob backend resolves a descriptor (cross-process zero-copy transport, #lzzcpy). A receiver routes resolution by this discriminator: a `shm` descriptor never resolves in an Arrow backend and vice versa (the resolve_wrong_backend theorem). It is the wire mirror of the Rust `BlobBackendKind` enum; the `arena` itself is backend-agnostic and does not store it — the discriminator is wire-level routing only.

The zero value ("") is the default backend, Shm, so a legacy descriptor with no `backend` field resolves unchanged. Unknown strings also fall back to Shm (never a hard failure), matching the Rust `from_str`.

const (
	// BackendShm is the POSIX shared-memory backend (shm_open + mmap) — the
	// default cross-process backend (same host). Omitted on the wire.
	BackendShm BlobBackendKind = "shm"
	// BackendArrow holds Apache Arrow IPC stream bytes — the descriptor's bytes
	// are an Arrow IPC stream the receiver imports zero-copy.
	BackendArrow BlobBackendKind = "arrow"
	// BackendInProcess is an in-process arena (single address space — the FFI
	// host / an editor plugin loaded in the same process).
	BackendInProcess BlobBackendKind = "in_process"
)

func (BlobBackendKind) IsDefault added in v0.4.0

func (k BlobBackendKind) IsDefault() bool

IsDefault reports whether this is the default backend (Shm). Used to omit the `backend` field on the wire so legacy descriptors validate unchanged.

func (BlobBackendKind) Normalized added in v0.4.0

func (k BlobBackendKind) Normalized() BlobBackendKind

Normalized collapses the zero value and any unknown discriminator to the default backend (Shm), so resolution never hard-fails on a legacy or forward-compatible descriptor.

type BlobRouter added in v0.4.0

type BlobRouter struct {
	// contains filtered or unexported fields
}

BlobRouter is the receiver-side multi-backend resolver. It holds backends by BlobBackendKind and resolves any descriptor by its Backend discriminator — a shm descriptor routes to the shm backend, an arrow descriptor to the arrow backend, etc. This is the resolve_wrong_backend theorem in practice: a descriptor never resolves against a backend of the wrong kind (an unregistered kind resolves to nothing).

The zero value is a ready empty router; NewBlobRouter is the explicit constructor.

func NewBlobRouter added in v0.4.0

func NewBlobRouter() *BlobRouter

NewBlobRouter creates an empty router with no backends registered.

func (*BlobRouter) ReadView added in v0.4.0

func (r *BlobRouter) ReadView(descriptor ShmBlobRef) ([]byte, bool)

ReadView resolves a descriptor by routing to its Backend kind. Returns (nil, false) if no backend is registered for this kind, or the descriptor did not resolve.

func (*BlobRouter) Register added in v0.4.0

func (r *BlobRouter) Register(backend BlobBackend) *BlobRouter

Register installs backend for its Kind, replacing any previously-registered backend of the same kind. It returns the router for chaining.

func (*BlobRouter) Resolve added in v0.4.0

func (r *BlobRouter) Resolve(value IpcValue) ([]byte, bool)

Resolve resolves an IpcValue: Inline bytes are returned directly, a SharedBlob is routed by its Backend discriminator and resolved zero-copy.

type Block

type Block struct {
	Text   string
	Anchor *string // nil when the block is not anchored
}

Block is a text block, optionally anchored.

func NewAnchoredBlock

func NewAnchoredBlock(anchor, text string) Block

NewAnchoredBlock constructs an anchored block (Dart Block.anchored).

func NewBlock

func NewBlock(text string) Block

NewBlock constructs an unanchored text block (Dart Block.text).

func (Block) String

func (b Block) String() string

type BlockKey

type BlockKey struct {
	Kind         string // "anchored" | "content"
	AnchorValue  string // valid when Kind == "anchored"
	ContentValue uint64 // valid when Kind == "content"
	// contains filtered or unexported fields
}

BlockKey is a manufactured block key: either anchored or content-derived. Anchored keys carry a string value; content keys carry a 64-bit FNV-1a hash.

func AnchoredBlockKey

func AnchoredBlockKey(value string) BlockKey

AnchoredBlockKey constructs an anchored key (Dart BlockKey.anchored).

func BlockKeyOf

func BlockKeyOf(block Block) BlockKey

BlockKeyOf computes the manufactured key for block: anchor wins, else content hash (Dart blockKey).

func ContentBlockKey

func ContentBlockKey(value uint64) BlockKey

ContentBlockKey constructs a content-derived key (Dart BlockKey.content).

func (BlockKey) AsString

func (k BlockKey) AsString() string

AsString renders the wire form: "a:<anchor>" or "c:" + 16-char zero-padded hex of the 64-bit content hash.

func (BlockKey) Equals

func (k BlockKey) Equals(other BlockKey) bool

Equals reports structural equality with other.

func (BlockKey) IsAnchored

func (k BlockKey) IsAnchored() bool

IsAnchored reports whether this is an anchored key.

func (BlockKey) IsContent

func (k BlockKey) IsContent() bool

IsContent reports whether this is a content-derived key.

func (BlockKey) String

func (k BlockKey) String() string

type BoundDim added in v0.11.0

type BoundDim string

BoundDim is what a bound measures (analysis §4.4). The core meters Count.

const (
	BoundCount BoundDim = "Count"
	BoundBytes BoundDim = "Bytes"
	BoundKeys  BoundDim = "Keys"
	BoundAge   BoundDim = "Age"
)

type BoundedStorage added in v0.9.0

type BoundedStorage interface {
	// Capacity reports the bound and true for a bounded backend, or 0 and
	// false for the unbounded default.
	Capacity() (int, bool)
}

BoundedStorage is the OPTIONAL bound capability. A backend implementing it and reporting a bound gains a reactive IsFull backpressure reader; a backend without it is treated as unbounded (IsFull is always false).

type BreakerState added in v0.15.0

type BreakerState int

BreakerState is the circuit-breaker state.

const (
	// BreakerClosed — calls pass; failures accumulate in the window.
	BreakerClosed BreakerState = iota
	// BreakerOpen — fast-fail until the reset deadline.
	BreakerOpen
	// BreakerHalfOpen — allow a single probe.
	BreakerHalfOpen
)

func (BreakerState) String added in v0.15.0

func (s BreakerState) String() string

type BulkheadCell added in v0.15.0

type BulkheadCell struct {
	// contains filtered or unexported fields
}

BulkheadCell is a reactive bulkhead: projects permitsInUse onto a Cell.

func NewBulkheadCell added in v0.15.0

func NewBulkheadCell(ctx *Context, capacity uint64) *BulkheadCell

NewBulkheadCell builds a reactive bulkhead.

func (*BulkheadCell) Acquire added in v0.15.0

func (b *BulkheadCell) Acquire() bool

Acquire takes a permit if one is free, updating the projection.

func (*BulkheadCell) PermitsInUse added in v0.15.0

func (b *BulkheadCell) PermitsInUse() uint64

PermitsInUse returns the projected number of permits in use.

func (*BulkheadCell) PermitsInUseCell added in v0.15.0

func (b *BulkheadCell) PermitsInUseCell() *Source[uint64]

PermitsInUseCell returns the reactive permits-in-use reader.

func (*BulkheadCell) Release added in v0.15.0

func (b *BulkheadCell) Release()

Release frees a permit, updating the projection.

type BulkheadCore added in v0.15.0

type BulkheadCore struct {
	// contains filtered or unexported fields
}

BulkheadCore is a bounded isolation-pool compute core.

func NewBulkheadCore added in v0.15.0

func NewBulkheadCore(capacity uint64) *BulkheadCore

NewBulkheadCore builds a core.

func (*BulkheadCore) Acquire added in v0.15.0

func (b *BulkheadCore) Acquire() bool

Acquire takes a permit if one is free.

func (*BulkheadCore) InUse added in v0.15.0

func (b *BulkheadCore) InUse() uint64

InUse returns the number of permits in use.

func (*BulkheadCore) Release added in v0.15.0

func (b *BulkheadCore) Release()

Release frees a permit.

type CallState added in v0.2.0

type CallState struct {
	Kind  CallStateKind
	Entry CommandProjectionEntry // populated when Kind == Resolved
}

CallState is the unary-RPC resolution state. A call resolves only when the command projection reaches a terminal causal receipt.

type CallStateKind added in v0.2.0

type CallStateKind string

CallStateKind enumerates the unary-RPC resolution states.

const (
	CallStateKindPending  CallStateKind = "pending"
	CallStateKindResolved CallStateKind = "resolved"
	CallStateKindConflict CallStateKind = "conflict"
)

type CapabilityCheck

type CapabilityCheck struct {
	Ok     bool
	Field  string
	Reason string
}

CapabilityCheck is the result of CapabilityHandshake.CheckCompatible. On failure, Field is the offending handshake field and Reason the human-readable fail-closed cause; both are empty on success.

func CapabilityCheckFail

func CapabilityCheckFail(field, reason string) CapabilityCheck

CapabilityCheckFail builds a failed check for the offending field.

func CapabilityCheckOk

func CapabilityCheckOk() CapabilityCheck

CapabilityCheckOk builds a successful check.

func (CapabilityCheck) IsOk

func (c CapabilityCheck) IsOk() bool

IsOk reports whether the handshake is compatible.

func (CapabilityCheck) String

func (c CapabilityCheck) String() string

type CapabilityHandshake

type CapabilityHandshake struct {
	ProtocolID             string
	ProtocolMajorVersion   int
	Codec                  string
	MaxFrameSize           int64
	FragmentationSupported bool
	OrderedReliable        bool
	PeerID                 PeerId
	SessionID              string
	Features               []string
}

CapabilityHandshake is the compatibility handshake exchanged before any graph state flows (protocol.md § Capability Negotiation). It is serialized as a plain JSON object (NOT externally tagged — a standalone frame, not an IpcMessage variant).

func DecodeCapabilityHandshakeJSON

func DecodeCapabilityHandshakeJSON(data []byte) (CapabilityHandshake, error)

DecodeCapabilityHandshakeJSON decodes UTF-8 JSON bytes into a handshake.

func NewCapabilityHandshake

func NewCapabilityHandshake(peerID PeerId, sessionID string) CapabilityHandshake

NewCapabilityHandshake builds a handshake with protocol defaults (JSON codec, 1 MiB frame, ordered-reliable, no features). Mirrors the Dart `CapabilityHandshake.defaults` factory; customize with the With* builders.

func (CapabilityHandshake) CheckCompatible

func (h CapabilityHandshake) CheckCompatible(other CapabilityHandshake, requiredFeatures ...string) CapabilityCheck

CheckCompatible is a structured compatibility check. It returns the offending field (and reason) on mismatch so a caller can produce a clean fail-closed diagnostic — mirrors `lazily-js::SessionHandshake.checkCompatible`.

requiredFeatures are checked against the OTHER peer's offered set: if this peer requires a feature the other does not offer, the handshake fails closed on `features`.

func (CapabilityHandshake) EncodeJSON

func (h CapabilityHandshake) EncodeJSON() ([]byte, error)

EncodeJSON returns the UTF-8 JSON bytes of the plain-JSON wire form.

func (CapabilityHandshake) HasFeature

func (h CapabilityHandshake) HasFeature(feature string) bool

HasFeature reports whether this peer advertises feature.

func (CapabilityHandshake) IsCompatibleWith

func (h CapabilityHandshake) IsCompatibleWith(other CapabilityHandshake) bool

IsCompatibleWith reports whether this handshake is mutually compatible with other.

Peers are compatible when both advertise ProtocolID, both advertise ProtocolMajorVersion, their major versions and codecs agree, and both require ordered-reliable delivery. Feature negotiation is caller-driven via HasFeature / CheckCompatible's requiredFeatures argument.

func (CapabilityHandshake) MarshalJSON

func (h CapabilityHandshake) MarshalJSON() ([]byte, error)

MarshalJSON emits the plain-JSON wire object with the spec field order, always rendering `features` as an array (never null).

func (CapabilityHandshake) String

func (h CapabilityHandshake) String() string

func (CapabilityHandshake) ToWire

func (h CapabilityHandshake) ToWire() any

ToWire returns the plain-JSON wire shape (a standalone frame, NOT externally tagged) as an ordered marshaling struct.

func (*CapabilityHandshake) UnmarshalJSON

func (h *CapabilityHandshake) UnmarshalJSON(b []byte) error

UnmarshalJSON decodes a plain-JSON wire object. It defaults fragmentation_supported = false, ordered_reliable = true, codec = "json", protocol_id = "lazily-ipc", protocol_major_version = 1, max_frame_size = 1 MiB, and features = [] when absent (mirrors the lazily-rs serde defaults and the Dart fromWire). peer_id is required and must be a non-negative integer; max_frame_size, when present, must be non-negative.

func (CapabilityHandshake) WithCodec

func (h CapabilityHandshake) WithCodec(codec string) CapabilityHandshake

WithCodec returns a copy with the codec negotiation token set.

func (CapabilityHandshake) WithFeatures

func (h CapabilityHandshake) WithFeatures(features []string) CapabilityHandshake

WithFeatures returns a copy with the features list set.

func (CapabilityHandshake) WithFragmentation

func (h CapabilityHandshake) WithFragmentation(supported bool) CapabilityHandshake

WithFragmentation returns a copy with fragmentation support set.

func (CapabilityHandshake) WithMaxFrameSize

func (h CapabilityHandshake) WithMaxFrameSize(maxFrameSize int64) CapabilityHandshake

WithMaxFrameSize returns a copy with the max frame size set.

func (CapabilityHandshake) WithOrderedReliable

func (h CapabilityHandshake) WithOrderedReliable(orderedReliable bool) CapabilityHandshake

WithOrderedReliable returns a copy with ordered-reliable set.

type CausalReceipt

type CausalReceipt struct {
	// ReceiptId is the idempotency key for this receipt event.
	ReceiptId string `json:"receipt_id"`
	// CausationId is the stable id of the command/effect this receipt observes.
	CausationId string `json:"causation_id"`
	// Observer is the peer, process, or subsystem that produced the receipt.
	Observer string `json:"observer"`
	// Generation is the producer/editor generation. Consumers discard receipts
	// outside the current generation for the causation id.
	Generation int64 `json:"generation"`
	// Outcome is the receipt lifecycle outcome.
	Outcome ReceiptOutcome `json:"outcome"`
	// Reason is an optional human/debug rejection reason (null when absent).
	Reason *string `json:"reason"`
	// PayloadHash is an optional hash of the observed state/payload (null when
	// absent).
	PayloadHash *string `json:"payload_hash"`
}

CausalReceipt is one receipt event for a command/effect causation id.

Reason and PayloadHash are nullable wire fields: they marshal to JSON null when nil (the schema lists both as required), so they carry no `omitempty`.

func AcceptedReceipt

func AcceptedReceipt(receiptId, causationId, observer string, generation int64) CausalReceipt

AcceptedReceipt constructs an `accepted` receipt.

func AppliedReceipt

func AppliedReceipt(receiptId, causationId, observer string, generation int64) CausalReceipt

AppliedReceipt constructs an `applied` (terminal) receipt.

func CausalReceiptFromWire

func CausalReceiptFromWire(data []byte) (CausalReceipt, error)

CausalReceiptFromWire decodes a single receipt from JSON bytes.

func NewCausalReceipt

func NewCausalReceipt(receiptId, causationId, observer string, generation int64, outcome ReceiptOutcome) CausalReceipt

NewCausalReceipt constructs a receipt with the given outcome and no reason or payload hash.

func ObservedReceipt

func ObservedReceipt(receiptId, causationId, observer string, generation int64) CausalReceipt

ObservedReceipt constructs an `observed` receipt.

func RejectedReceipt

func RejectedReceipt(receiptId, causationId, observer string, generation int64) CausalReceipt

RejectedReceipt constructs a `rejected` (terminal) receipt.

func (CausalReceipt) IsTerminal

func (r CausalReceipt) IsTerminal() bool

IsTerminal reports whether this receipt's outcome is terminal.

func (*CausalReceipt) UnmarshalJSON

func (r *CausalReceipt) UnmarshalJSON(b []byte) error

UnmarshalJSON decodes a receipt and validates the outcome enum.

func (CausalReceipt) WithPayloadHash

func (r CausalReceipt) WithPayloadHash(hash string) CausalReceipt

WithPayloadHash returns a copy of the receipt carrying a payload hash.

func (CausalReceipt) WithReason

func (r CausalReceipt) WithReason(reason string) CausalReceipt

WithReason returns a copy of the receipt carrying a debug/rejection reason.

type CausalReceipts

type CausalReceipts struct {
	// Receipts is the receipt batch.
	Receipts []CausalReceipt `json:"receipts"`
}

CausalReceipts is the wire body for a batch of receipts.

func CausalReceiptsFromWire

func CausalReceiptsFromWire(data []byte) (CausalReceipts, error)

CausalReceiptsFromWire decodes a receipt batch from JSON bytes.

func NewCausalReceipts

func NewCausalReceipts(receipts []CausalReceipt) CausalReceipts

NewCausalReceipts constructs a receipt batch, copying the input slice.

func (CausalReceipts) MarshalJSON

func (c CausalReceipts) MarshalJSON() ([]byte, error)

MarshalJSON emits { receipts } with receipts always an array (never null).

type CellCrdt

type CellCrdt[T comparable] struct {
	// contains filtered or unexported fields
}

CellCrdt is a reactive cell whose value is resolved by merging concurrent writes. Backed by a Cell[T] and a pluggable merge function (LWW, MV, or custom). Reads are reactive; writes fold the incoming value into the current one via the merge function.

T must be comparable because the backing Cell uses the == PartialEq guard.

func NewCellCrdt

func NewCellCrdt[T comparable](ctx *Context, initial T, merge func(current, incoming T) T) *CellCrdt[T]

NewCellCrdt creates a CRDT-backed cell with initial value and merge function.

func (*CellCrdt[T]) Cell

func (c *CellCrdt[T]) Cell() *Source[T]

Cell returns the underlying reactive cell.

func (*CellCrdt[T]) Value

func (c *CellCrdt[T]) Value() T

Value returns the current merged value (reactive read).

func (*CellCrdt[T]) Write

func (c *CellCrdt[T]) Write(incoming T)

Write merges incoming into the current value.

type CellMap deprecated

type CellMap[K comparable, V comparable] = SourceMap[K, V]

CellMap is the pre-v2-kernel name for SourceMap, kept as an alias so existing callers keep compiling. The v2 kernel renamed the node kinds to Source and Computed; the keyed collections follow.

Deprecated: renamed to SourceMap.

type CellTree deprecated

type CellTree[K comparable, V comparable] = SourceTree[K, V]

CellTree is the pre-v2-kernel name for SourceTree, kept as an alias so existing callers keep compiling. The v2 kernel renamed the node kinds to Source and Computed; the keyed collections follow.

Deprecated: renamed to SourceTree.

type ChartDef

type ChartDef struct {
	// contains filtered or unexported fields
}

ChartDef is a parsed, immutable chart definition — the node-labeled functions of the declarative JSON form materialized as maps for deterministic descent. Build it via ChartDefFromJSON and hand it to NewStateChart.

func ChartDefFromJSON

func ChartDefFromJSON(data []byte) (*ChartDef, error)

ChartDefFromJSON parses a chart definition from the declarative JSON form (lazily-spec/schemas/statechart.json). `run` actions and {"expr": …} context guards are rejected explicitly.

type CircuitBreakerCell added in v0.15.0

type CircuitBreakerCell struct {
	// contains filtered or unexported fields
}

CircuitBreakerCell is a reactive circuit breaker: projects the state onto a Cell.

func NewCircuitBreakerCell added in v0.15.0

func NewCircuitBreakerCell(ctx *Context, window, failureThreshold int, resetTimeout uint64) *CircuitBreakerCell

NewCircuitBreakerCell builds a reactive circuit breaker.

func (*CircuitBreakerCell) Allow added in v0.15.0

func (c *CircuitBreakerCell) Allow(now uint64) bool

Allow reports whether a call is permitted, updating the projected state.

func (*CircuitBreakerCell) Record added in v0.15.0

func (c *CircuitBreakerCell) Record(success bool, now uint64)

Record feeds a call outcome, updating the projected state.

func (*CircuitBreakerCell) State added in v0.15.0

func (c *CircuitBreakerCell) State() BreakerState

State returns the current breaker state.

func (*CircuitBreakerCell) StateCell added in v0.15.0

func (c *CircuitBreakerCell) StateCell() *Source[BreakerState]

StateCell returns the reactive state reader.

type CircuitBreakerCore added in v0.15.0

type CircuitBreakerCore struct {
	// contains filtered or unexported fields
}

CircuitBreakerCore is the circuit-breaker compute core: a sliding window of outcomes trips Closed->Open at failureThreshold; Open->HalfOpen at the deadline; a HalfOpen success closes, a failure re-opens.

func NewCircuitBreakerCore added in v0.15.0

func NewCircuitBreakerCore(window, failureThreshold int, resetTimeout uint64) *CircuitBreakerCore

NewCircuitBreakerCore builds a core; window and failureThreshold clamp to >= 1.

func (*CircuitBreakerCore) Allow added in v0.15.0

func (c *CircuitBreakerCore) Allow(now uint64) bool

Allow reports whether a call is permitted; performs the Open->HalfOpen transition at the deadline.

func (*CircuitBreakerCore) Record added in v0.15.0

func (c *CircuitBreakerCore) Record(success bool, now uint64)

Record feeds a call outcome and drives the state machine.

func (*CircuitBreakerCore) State added in v0.15.0

func (c *CircuitBreakerCore) State() BreakerState

State returns the current breaker state.

type ClientAnswer

type ClientAnswer struct {
	To  PeerId
	Sdp string
}

ClientAnswer carries a WebRTC SDP answer to a target peer.

func (ClientAnswer) MarshalJSON

func (m ClientAnswer) MarshalJSON() ([]byte, error)

func (ClientAnswer) Type

func (ClientAnswer) Type() string

type ClientConn

type ClientConn struct {
	// contains filtered or unexported fields
}

ClientConn is a per-connection handle into a SignalingRoom. Send client frames on the inbound channel (Inbound) and read server frames from the outbound channel (Outbound). The outbound channel is closed when the connection is disconnected or the room is closed.

func (*ClientConn) ConnID

func (c *ClientConn) ConnID() any

ConnID returns the opaque connection id.

func (*ClientConn) Inbound

func (c *ClientConn) Inbound() chan<- ClientMessage

Inbound is the send side for client -> room frames.

func (*ClientConn) Outbound

func (c *ClientConn) Outbound() <-chan ServerMessage

Outbound is the receive side for room -> client frames. It is closed when the connection is torn down.

type ClientIce

type ClientIce struct {
	To        PeerId
	Candidate string
}

ClientIce carries an ICE candidate to a target peer.

func (ClientIce) MarshalJSON

func (m ClientIce) MarshalJSON() ([]byte, error)

func (ClientIce) Type

func (ClientIce) Type() string

type ClientJoin

type ClientJoin struct {
	Peer         PeerId
	Capabilities []string
}

ClientJoin registers a connection with the session under a peer id. The optional Capabilities list is omitted from the wire when nil (an explicit empty list is preserved).

func (ClientJoin) MarshalJSON

func (m ClientJoin) MarshalJSON() ([]byte, error)

func (ClientJoin) Type

func (ClientJoin) Type() string

type ClientLeave

type ClientLeave struct{}

ClientLeave disconnects the connection from the session.

func (ClientLeave) MarshalJSON

func (ClientLeave) MarshalJSON() ([]byte, error)

func (ClientLeave) Type

func (ClientLeave) Type() string

type ClientMessage

type ClientMessage interface {
	// Type returns the wire discriminant.
	Type() string
	MarshalJSON() ([]byte, error)
	// contains filtered or unexported methods
}

ClientMessage is a client -> server signaling frame. It is a sealed union (mirroring the Dart `sealed class ClientMessage`); concrete variants are ClientJoin/ClientOffer/ClientAnswer/ClientIce/ClientRelay/ClientLeave. Decode wire bytes with ParseClientMessage; each variant implements MarshalJSON.

func ParseClientMessage

func ParseClientMessage(data []byte) (ClientMessage, error)

ParseClientMessage decodes an internally-tagged client frame from JSON bytes.

type ClientOffer

type ClientOffer struct {
	To  PeerId
	Sdp string
}

ClientOffer carries a WebRTC SDP offer to a target peer.

func (ClientOffer) MarshalJSON

func (m ClientOffer) MarshalJSON() ([]byte, error)

func (ClientOffer) Type

func (ClientOffer) Type() string

type ClientRelay

type ClientRelay struct {
	To      PeerId
	Payload json.RawMessage
}

ClientRelay relays an opaque JSON payload to a target peer. Payload is kept as json.RawMessage so it round-trips byte-for-byte through the server.

func (ClientRelay) MarshalJSON

func (m ClientRelay) MarshalJSON() ([]byte, error)

func (ClientRelay) Type

func (ClientRelay) Type() string

type Clock added in v0.8.0

type Clock interface {
	// NowMillis returns milliseconds from an arbitrary fixed origin; monotonic,
	// non-decreasing.
	NowMillis() int64
}

Clock is the monotonic clock seam (spec § SyncDriver — policy injected, no runtime in core). The driver never schedules itself; the host calls Tick on its own cadence and supplies wall-free monotonic millis so the driver can timestamp progress and expose a stall signal without owning a clock source.

type CommandApplyStatus added in v0.2.0

type CommandApplyStatus interface {
	// contains filtered or unexported methods
}

CommandApplyStatus is the result of folding a frame into a CommandProjection.

type CommandApplyStatusKind added in v0.2.0

type CommandApplyStatusKind string

CommandApplyStatusKind enumerates the result variants.

const (
	CommandApplyStatusRecorded         CommandApplyStatusKind = "recorded"
	CommandApplyStatusDuplicate        CommandApplyStatusKind = "duplicate"
	CommandApplyStatusUnknown          CommandApplyStatusKind = "unknown"
	CommandApplyStatusStaleGeneration  CommandApplyStatusKind = "stale_generation"
	CommandApplyStatusTerminalConflict CommandApplyStatusKind = "terminal_conflict"
)

type CommandCancel added in v0.2.0

type CommandCancel struct {
	CommandId           string  `json:"command_id"`
	CausationId         string  `json:"causation_id"`
	Source              string  `json:"source"`
	AuthorityGeneration int64   `json:"authority_generation"`
	Reason              *string `json:"reason"`
}

CommandCancel preempts a still-non-terminal command by command_id at a given authority_generation, with an optional reason. A stale-generation cancel is ignored. A cancel after a terminal outcome never rewrites it.

type CommandEvent added in v0.2.0

type CommandEvent struct {
	EventId    string           `json:"event_id"`
	CommandId  string           `json:"command_id"`
	Kind       CommandEventKind `json:"kind"`
	Generation int64            `json:"generation"`
	Detail     *string          `json:"detail"`
}

CommandEvent is one progress/detail event keyed by command_id.

func (*CommandEvent) UnmarshalJSON added in v0.2.0

func (e *CommandEvent) UnmarshalJSON(b []byte) error

UnmarshalJSON decodes a CommandEvent, validating the kind enum.

type CommandEventKind added in v0.2.0

type CommandEventKind string

CommandEventKind is a progress/detail event kind. These are UX/diagnostics only and are NEVER terminal proof; terminal proof folds through CausalReceipt. cancelled/superseded/timed_out are surfaced here for UX but their terminal authority is a matching rejected receipt.

const (
	CommandEventKindObserved   CommandEventKind = "observed"
	CommandEventKindAccepted   CommandEventKind = "accepted"
	CommandEventKindStarted    CommandEventKind = "started"
	CommandEventKindProgress   CommandEventKind = "progress"
	CommandEventKindCancelled  CommandEventKind = "cancelled"
	CommandEventKindSuperseded CommandEventKind = "superseded"
	CommandEventKindTimedOut   CommandEventKind = "timed_out"
)

type CommandEvents added in v0.2.0

type CommandEvents struct {
	Events []CommandEvent `json:"events"`
}

CommandEvents is a batch of progress/detail events.

func (CommandEvents) MarshalJSON added in v0.2.0

func (c CommandEvents) MarshalJSON() ([]byte, error)

MarshalJSON emits { events } with events always an array (never null).

type CommandMessage added in v0.2.0

type CommandMessage struct {
	Tag        CommandMessageTag
	Submit     *CommandSubmit
	Cancel     *CommandCancel
	Events     *CommandEvents
	Projection *CommandProjectionImage
}

CommandMessage is one externally-tagged frame of the command plane.

func CommandMessageFromWire added in v0.2.0

func CommandMessageFromWire(data []byte) (CommandMessage, error)

CommandMessageFromWire decodes a CommandMessage from JSON bytes.

func NewCommandMessageCancel added in v0.2.0

func NewCommandMessageCancel(c CommandCancel) CommandMessage

NewCommandMessageCancel wraps a CommandCancel frame.

func NewCommandMessageEvents added in v0.2.0

func NewCommandMessageEvents(e CommandEvents) CommandMessage

NewCommandMessageEvents wraps a CommandEvents frame.

func NewCommandMessageProjection added in v0.2.0

func NewCommandMessageProjection(p CommandProjectionImage) CommandMessage

NewCommandMessageProjection wraps a CommandProjection frame.

func NewCommandMessageSubmit added in v0.2.0

func NewCommandMessageSubmit(s CommandSubmit) CommandMessage

NewCommandMessageSubmit wraps a CommandSubmit frame.

func (CommandMessage) MarshalJSON added in v0.2.0

func (m CommandMessage) MarshalJSON() ([]byte, error)

MarshalJSON renders the externally-tagged wire form {"<Tag>": body}.

func (*CommandMessage) UnmarshalJSON added in v0.2.0

func (m *CommandMessage) UnmarshalJSON(b []byte) error

UnmarshalJSON decodes an externally-tagged CommandMessage.

type CommandMessageTag added in v0.2.0

type CommandMessageTag string

CommandMessageTag identifies the frame variant.

const (
	CommandMessageTagSubmit     CommandMessageTag = "CommandSubmit"
	CommandMessageTagCancel     CommandMessageTag = "CommandCancel"
	CommandMessageTagEvents     CommandMessageTag = "CommandEvents"
	CommandMessageTagProjection CommandMessageTag = "CommandProjection"
)

type CommandPolicy added in v0.2.0

type CommandPolicy struct {
	Dedupe          DedupePolicy `json:"dedupe"`
	Supersede       bool         `json:"supersede"`
	CancelOnPreempt bool         `json:"cancel_on_preempt"`
}

CommandPolicy is the per-submit admission policy.

type CommandProjection added in v0.2.0

type CommandProjection struct {
	// contains filtered or unexported fields
}

CommandProjection is the folded, queryable image of known command state. It is the reducer over CommandMessage frames and CausalReceipt events.

Projection rules (lazily-spec § Command / RPC Message Plane):

  • Terminal authority is the causal receipt, not the event or the transport.
  • Generation guards: events/receipts outside the command's current authority generation are ignored and retained only as audit data.
  • Idempotency: a replayed submit/event/receipt (same id) is a no-op.
  • Cancel before terminal only: a cancel terminally rejects a non-terminal command; a cancel after applied is ignored.
  • Terminal conflict fails closed: two terminal receipts at the same generation with different outcomes is a conflict; consumers fail closed rather than pick a winner.
  • Reconnect equivalence: folding a CommandProjection image is equivalent to folding the events and receipts it summarizes.

Not safe for concurrent use.

func NewCommandProjection added in v0.2.0

func NewCommandProjection() *CommandProjection

NewCommandProjection creates an empty projection.

func (*CommandProjection) ApplyMessage added in v0.2.0

func (p *CommandProjection) ApplyMessage(message CommandMessage) CommandApplyStatus

ApplyMessage dispatches a CommandMessage frame to the matching fold method.

func (*CommandProjection) ApplyProjection added in v0.2.0

ApplyProjection folds a reconnect resync image. Equivalent to folding the events and receipts it summarizes.

func (*CommandProjection) Cancel added in v0.2.0

Cancel records a cancel request. A cancel is non-terminal by itself; the rejected receipt makes it terminal. Stale-generation and duplicate cancel causation_ids are no-ops.

func (*CommandProjection) Entry added in v0.2.0

func (p *CommandProjection) Entry(commandId string) (CommandProjectionEntry, bool)

Entry returns the folded entry for commandId, or false if unknown.

func (*CommandProjection) Event added in v0.2.0

Event folds one progress/detail event. Stale-generation and duplicate event_ids are no-ops. Status advances monotonically (never backward, never on a terminal command).

func (*CommandProjection) Generation added in v0.2.0

func (p *CommandProjection) Generation() int64

Generation is the highest authority generation observed so far.

func (*CommandProjection) HasConflict added in v0.2.0

func (p *CommandProjection) HasConflict(commandId string) bool

HasConflict reports whether commandId has a terminal conflict.

func (*CommandProjection) ObserveReceipt added in v0.2.0

func (p *CommandProjection) ObserveReceipt(r CausalReceipt) CommandApplyStatus

ObserveReceipt folds a causal receipt. This is the sole terminal authority: a terminal receipt (applied/rejected) flips the command to terminal. A differing terminal outcome at the same generation is a conflict (fail-closed).

func (*CommandProjection) Submit added in v0.2.0

Submit admits a command. A duplicate command_id is an idempotent no-op.

func (*CommandProjection) TerminalFor added in v0.2.0

func (p *CommandProjection) TerminalFor(commandId string) (CommandProjectionEntry, bool)

TerminalFor returns the terminal entry for commandId, or false if the command is unknown or not yet terminal.

func (*CommandProjection) ToImage added in v0.2.0

ToImage returns a snapshot of the projection sorted by command_id.

type CommandProjectionEntry added in v0.2.0

type CommandProjectionEntry struct {
	CommandId         string        `json:"command_id"`
	Status            CommandStatus `json:"status"`
	Terminal          bool          `json:"terminal"`
	Generation        int64         `json:"generation"`
	Reason            *string       `json:"reason"`
	TerminalReceiptId *string       `json:"terminal_receipt_id"`
	LastEventId       *string       `json:"last_event_id"`
}

CommandProjectionEntry is the folded, queryable image of one command's state. Reason, TerminalReceiptId, and LastEventId are nullable wire fields: they marshal to JSON null when nil (the schema lists them as required), so they carry no `omitempty`.

func (*CommandProjectionEntry) UnmarshalJSON added in v0.2.0

func (e *CommandProjectionEntry) UnmarshalJSON(b []byte) error

UnmarshalJSON decodes an entry, validating the status enum.

type CommandProjectionImage added in v0.2.0

type CommandProjectionImage struct {
	Generation int64                    `json:"generation"`
	Commands   []CommandProjectionEntry `json:"commands"`
}

CommandProjectionImage is the resync snapshot: an authority generation plus the per-command folded entries.

func (CommandProjectionImage) MarshalJSON added in v0.2.0

func (i CommandProjectionImage) MarshalJSON() ([]byte, error)

MarshalJSON emits commands always as an array (never null).

type CommandRpcClient added in v0.2.0

type CommandRpcClient struct {
	Projection *CommandProjection
	// contains filtered or unexported fields
}

CommandRpcClient is the RPC facade over the command plane. It builds and sends CommandSubmit/CommandCancel frames, folds replies into its projection, and exposes a polled unary-call resolution that completes only on a terminal causal receipt.

func NewCommandRpcClient added in v0.2.0

func NewCommandRpcClient(transport CommandTransport) *CommandRpcClient

NewCommandRpcClient constructs an RPC client over the given transport.

func (*CommandRpcClient) Cancel added in v0.2.0

func (c *CommandRpcClient) Cancel(cancel CommandCancel)

Cancel builds and sends a CommandCancel and folds it into the projection.

func (*CommandRpcClient) IngestCommand added in v0.2.0

func (c *CommandRpcClient) IngestCommand(message CommandMessage) CommandApplyStatus

IngestCommand folds an inbound CommandMessage into the projection.

func (*CommandRpcClient) IngestReceipt added in v0.2.0

func (c *CommandRpcClient) IngestReceipt(receipt CausalReceipt) CommandApplyStatus

IngestReceipt folds an inbound causal receipt into the projection.

func (*CommandRpcClient) PollCall added in v0.2.0

func (c *CommandRpcClient) PollCall(commandId string) CallState

PollCall returns the current resolution state of a unary call. Resolves only when the command projection reaches a terminal causal receipt — a transport ACK, controller admission, or accepted/queued event never resolves it.

func (*CommandRpcClient) Submit added in v0.2.0

func (c *CommandRpcClient) Submit(s CommandSubmit) string

Submit builds and sends a CommandSubmit, folds it into the projection, and returns the command id.

type CommandStatus added in v0.2.0

type CommandStatus string

CommandStatus is the folded projection status. Submitted/Accepted/Running are non-terminal; Applied/Rejected/Cancelled/Superseded/TimedOut are terminal and backed by a terminal CausalReceipt.

const (
	CommandStatusSubmitted  CommandStatus = "submitted"
	CommandStatusAccepted   CommandStatus = "accepted"
	CommandStatusRunning    CommandStatus = "running"
	CommandStatusApplied    CommandStatus = "applied"
	CommandStatusRejected   CommandStatus = "rejected"
	CommandStatusCancelled  CommandStatus = "cancelled"
	CommandStatusSuperseded CommandStatus = "superseded"
	CommandStatusTimedOut   CommandStatus = "timed_out"
)

type CommandStatusDuplicate added in v0.2.0

type CommandStatusDuplicate struct{}

CommandStatusDuplicate means the frame was an idempotent no-op (duplicate command_id / event_id / receipt_id / cancel causation_id).

func (CommandStatusDuplicate) Kind added in v0.2.0

Kind returns the result variant tag.

type CommandStatusRecorded added in v0.2.0

type CommandStatusRecorded struct{}

CommandStatusRecorded means the frame updated the projection.

func (CommandStatusRecorded) Kind added in v0.2.0

Kind returns the result variant tag.

type CommandStatusStaleGeneration added in v0.2.0

type CommandStatusStaleGeneration struct {
	Expected int64
	Actual   int64
}

CommandStatusStaleGeneration means the frame's generation did not match the command's current authority generation; the frame was ignored.

func (CommandStatusStaleGeneration) Kind added in v0.2.0

Kind returns the result variant tag.

type CommandStatusTerminalConflict added in v0.2.0

type CommandStatusTerminalConflict struct {
	CommandId string
	Existing  CommandStatus
	Incoming  CommandStatus
}

CommandStatusTerminalConflict means a different terminal outcome already exists for this command_id (fail-closed).

func (CommandStatusTerminalConflict) Kind added in v0.2.0

Kind returns the result variant tag.

type CommandStatusUnknown added in v0.2.0

type CommandStatusUnknown struct{}

CommandStatusUnknown means the command_id was not in the projection.

func (CommandStatusUnknown) Kind added in v0.2.0

Kind returns the result variant tag.

type CommandSubmit added in v0.2.0

type CommandSubmit struct {
	CommandId           string        `json:"command_id"`
	CausationId         string        `json:"causation_id"`
	Source              string        `json:"source"`
	Target              string        `json:"target"`
	Namespace           string        `json:"namespace"`
	Name                string        `json:"name"`
	AuthorityGeneration int64         `json:"authority_generation"`
	IdempotencyKey      string        `json:"idempotency_key"`
	DeadlineMs          int64         `json:"deadline_ms"`
	Policy              CommandPolicy `json:"policy"`
	PayloadType         string        `json:"payload_type"`
	PayloadHash         string        `json:"payload_hash"`
	Payload             IpcValue      `json:"payload"`
	RequiredFeatures    []string      `json:"required_features"`
}

CommandSubmit admits a command. Lazily owns the envelope (command_id, correlation, idempotency, generation, policy, payload framing); the namespace owns the payload body, which lazily never interprets.

func (CommandSubmit) MarshalJSON added in v0.2.0

func (s CommandSubmit) MarshalJSON() ([]byte, error)

MarshalJSON renders the canonical wire object with required_features always an array (never null).

func (*CommandSubmit) UnmarshalJSON added in v0.2.0

func (s *CommandSubmit) UnmarshalJSON(b []byte) error

UnmarshalJSON decodes a CommandSubmit, validating the dedupe policy and the payload's externally-tagged IpcValue form.

type CommandTransport added in v0.2.0

type CommandTransport interface {
	Send(message CommandMessage)
}

CommandTransport is the outbound sink for command frames.

type CommandTransportFunc added in v0.2.0

type CommandTransportFunc func(message CommandMessage)

CommandTransportFunc adapts a function into a CommandTransport.

func (CommandTransportFunc) Send added in v0.2.0

Send satisfies CommandTransport.

type Compute added in v0.21.0

type Compute struct {
	// contains filtered or unexported fields
}

Compute is the per-recompute view handed to a value-threaded compute/effect closure. It carries the recomputing node id AS A VALUE (node), so a tracked read — Get(c, handle) — attributes the edge to that node by construction, never to ambient state. It is the sole tracking surface: reading a handle through the owning Context (or Compute.Untracked()) forms no edge.

Fortification, and its Go limits. lazily-rs makes the view non-escapable by construction — a lifetime binds it to the recompute and !Send stops it moving to another thread — so it is impossible to store and replay against the wrong node. Go has neither lifetimes nor a compile-time move check, so non-escapability is by convention, backed by a RUNTIME guard: each Compute is generation-stamped (gen) and marked dead (live=false) the instant its recompute returns. Any trackNode() on a dead or superseded Compute panics rather than silently registering an edge against a node that is no longer recomputing. That converts the rust compile-time guarantee into a fail-fast runtime one — the strongest fortification Go allows.

func (*Compute) Batch added in v0.21.0

func (cv *Compute) Batch(fn func())

Batch runs fn inside a coalescing batch on the owning scope.

func (*Compute) Untracked added in v0.21.0

func (cv *Compute) Untracked() *Context

Untracked returns the owning Context, the explicit untracked escape. A read through it registers no dependency edge.

type ComputeOps added in v0.21.0

type ComputeOps interface {

	// Batch runs fn inside a coalescing batch on the owning scope.
	Batch(fn func())
	// Untracked returns the untracked read surface (the owning *Context). A read
	// through it — Get(c.Untracked(), handle) — forms no dependency edge. It is
	// the sole, explicit escape from tracking, mirroring rs Compute::untracked.
	Untracked() *Context
	// contains filtered or unexported methods
}

ComputeOps is the compute-time operations subset shared by the two read surfaces (#lzcellkernel). It is the Go analogue of lazily-rs's `ComputeOps` trait, implemented by exactly two types:

  • *Context — the owning scope, whose reads are UNTRACKED (trackNode is nil).
  • *Compute — the per-recompute view handed to a compute/effect closure, whose reads register a dependency edge against the recomputing node.

Go methods cannot be generic, so the value-carrying operations of the rs trait (get/source/cell/computed/slot) are expressed as free generic functions that take a ComputeOps — Get(c, handle) for tracked reads, and the New*C constructors for building nodes. This interface carries only the non-generic operations plus the tracking identity itself; it mirrors the same split the async surface already uses (AsyncComputeContext + free TrackSource/TrackComputed).

There is deliberately no GetRc: Rc handles are a rust ownership device with no Go analogue (the runtime is garbage-collected), exactly as on the async side.

type Computed added in v0.21.0

type Computed[T any] struct {
	Name string
	// contains filtered or unexported fields
}

Computed is a lazy, cached, dependency-tracking computation.

Get returns the cached value if present; otherwise it computes the value (tracking every Cell, Signal, or Computed read during computation as a dependency), caches it, and returns it. When any dependency changes, the cached value is invalidated and the next Get recomputes.

The cached value lives on the Computed itself (value/cached fields), not in a shared Context map — so a Get is a direct field read on the node you already hold, and read latency does not grow with the total number of nodes. The cache is three-state, which pull-time checking requires and a lone `cached bool` cannot express:

hasValue=false                — no value has ever been computed.
hasValue=true,  cached=false  — a PREVIOUS value is still held, but it is
                                stale. The value is kept precisely so a
                                recompute can compare against it (the
                                equality guard) instead of blindly
                                cascading.
hasValue=true,  cached=true   — the value is current.

`cached` keeps its original meaning — "this value is current" — so Peek, cachedNow, Context.Size, and every collection layer built on them are unchanged. `hasValue` is the added state.

func NewComputed added in v0.21.0

func NewComputed[T comparable](ctx *Context, compute func(c *Compute) T) *Computed[T]

NewComputed creates a guarded Computed cell bound to ctx — the design's computed(f), guarded by default (§9.3). All computed cells are guarded: a recompute yielding a value equal (==) to the previous one suppresses the downstream cascade. This is the sole derived constructor now that the former Memo is removed — a computed cell IS the guarded form.

The `T comparable` bound is what the guard needs (Go ==). For a value type that is not comparable, drop to NewSlot, the bound-free storage-sense primitive (T any, no guard) — the escape hatch that mirrors lazily-rs's slot(). The guard is a pull-time check (see Computed.refresh), so it recomputes nothing during invalidation.

func NewComputedRippleWhen added in v0.21.0

func NewComputedRippleWhen[T any](ctx *Context, compute func(c *Compute) T, changed func(old, next T) bool) *Computed[T]

NewComputedRippleWhen creates a guarded Computed cell with an explicit change predicate (#lzcellkernel). Like NewComputed, but downstream propagation is gated by changed(old, new) instead of the value's natural == : changed returns true to PROPAGATE (ripple) the recompute to dependents, and false to SUPPRESS it (treat it as "no meaningful change"). So NewComputed(f) is exactly NewComputedRippleWhen(f, func(o, n T) bool { return o != n }), and an unguarded NewSlot(f) is NewComputedRippleWhen(f, func(_, _ T) bool { return true }) (always propagate).

Because the predicate is supplied, T carries no comparable bound: this is the guarded escape for non-comparable derived values — e.g. a []string / map computed guarded via func(o, n []string) bool { return !slices.Equal(o, n) }. It also serves a custom significance policy: dedup a large value by a version/hash field, epsilon float compare, hysteresis, a monotonic gate, or "propagate every N" when the counter lives in the value.

The value is ALWAYS computed (the predicate needs new); changed gates only the downstream cascade, not the computation. changed MUST be a pure function of (old, new) — reading value-carried state (version/counter/sequence) is fine and stays deterministic; capturing external mutable state is not (it keys off recompute/read frequency under laziness and breaks determinism).

The engine guards on equality (equal => suppress), so this installs equals = !changed(old, new).

func NewNamedComputedRippleWhen added in v0.21.0

func NewNamedComputedRippleWhen[T any](ctx *Context, name string, compute func(c *Compute) T, changed func(old, next T) bool) *Computed[T]

NewNamedComputedRippleWhen is NewComputedRippleWhen with a debug name.

func NewNamedSlot

func NewNamedSlot[T any](ctx *Context, name string, compute func(c *Compute) T) *Computed[T]

NewNamedSlot creates a lazy slot with a debug name.

func NewSlot

func NewSlot[T any](ctx *Context, compute func(c *Compute) T) *Computed[T]

NewSlot creates a lazy slot bound to ctx. Its closure receives the per-recompute Compute view and reads its dependencies via Get(c, handle) — the value-threaded tracking surface (#lzcellkernel). No ambient frame is pushed, so Compute.Untracked() is genuinely untracked.

func (*Computed[T]) Dispose added in v0.21.0

func (s *Computed[T]) Dispose()

Dispose tears down this slot: detaches both edge directions, drops the cached value, and dirties the surviving dependent cone. Idempotent.

Callers must ensure nothing still reads the slot in a live compute. A reader that still names it errors on its next recompute — the same contract as Effect.Dispose and lazily-rs's dispose_slot.

func (*Computed[T]) DisposeNode added in v0.21.0

func (m *Computed[T]) DisposeNode()

DisposeNode tears down this memoized slot. Same contract as Computed.Dispose.

func (*Computed[T]) Eager added in v0.21.0

func (s *Computed[T]) Eager() *Computed[T]

Eager makes this Computed eager and returns the same handle (design §9.3.1).

Eager is a state a Computed is in, not a separate kind: Eager attaches a puller Effect that reads the computed now — materializing its value and its dependency edges immediately — and again after every invalidation, from inside the invalidating write's effect flush. Because the puller is an ordinary Effect and effects are scheduled rather than inline, N invalidations inside a Batch coalesce into a single scheduled pull at the flush: the value re-materializes once at batch exit, not once per write (#lzsignaleager clause 3). The former Signal built the same slot+puller pair as a bespoke type that could, and in lazily-go once did, weld a per-write puller into invalidation. Composing it out of computed().Eager() makes that bug structurally unwritable.

Eager is idempotent — the eager bit short-circuits a second call, so f.Eager().Eager() attaches exactly one puller. It returns f itself (mutated), not a driver handle, so the caller holds the thing it reads via ordinary Get.

func (*Computed[T]) Get added in v0.21.0

func (s *Computed[T]) Get() T

Get reads (and caches if needed) the value.

Panics with a *DisposedError if this slot has been disposed. Use TryGet for the checked form; see disposal.go for why a read of a torn-down node is a panic rather than a returned error.

func (*Computed[T]) IsEager added in v0.21.0

func (s *Computed[T]) IsEager() bool

IsEager reports whether this Computed is eager (has a live puller).

func (*Computed[T]) Lazy added in v0.21.0

func (s *Computed[T]) Lazy()

Lazy reverts an eager Computed to lazy: it disposes the puller Effect and clears the eager bit and side-table entry. The value remains readable and recomputes on demand. Idempotent; a no-op on a lazy computed. This is the reverse transition that replaces the old dispose_signal.

func (*Computed[T]) Peek added in v0.21.0

func (s *Computed[T]) Peek() (T, bool)

Peek returns the cached value without recomputing, and whether it was cached.

func (*Computed[T]) TryGet added in v0.21.0

func (s *Computed[T]) TryGet() (v T, err error)

TryGet reads the slot, returning a *DisposedError instead of panicking when this slot — or any node it reads while recomputing — has been disposed.

This is the boundary form: use it where a read may race a teardown. It recovers the *DisposedError panic and returns it. Dependency tracking is value-threaded through a per-recompute Compute view (there is no ambient stack to unwind), so a read that panics out of a half-finished compute strands no frame; the superseded view is simply discarded.

type ComputedMap added in v0.22.0

type ComputedMap[K comparable, V comparable] struct {
	*ReactiveMap[K, V, *Computed[V]]
}

ComputedMap is the derived-slot specialization of ReactiveMap: every entry is a derived *Slot[V]. GetOrInsertWith mints a slot on first access (lazy materialization); MaterializeAll pre-mints the keyset (eager). A slot's value is derived, so ComputedMap has no Set.

func NewComputedMap added in v0.22.0

func NewComputedMap[K comparable, V comparable](ctx *Context) *ComputedMap[K, V]

NewComputedMap creates an empty derived-slot map bound to ctx.

func NewSlotMap deprecated added in v0.7.0

func NewSlotMap[K comparable, V comparable](ctx *Context) *ComputedMap[K, V]

NewSlotMap creates an empty derived-slot map bound to ctx.

Deprecated: renamed to NewComputedMap.

func (*ComputedMap[K, V]) MaterializeAll added in v0.22.0

func (m *ComputedMap[K, V]) MaterializeAll(c ComputeOps, keys []K, factory func(K) V)

MaterializeAll eagerly pre-mints a derived slot for every key via factory, up front. Observationally identical to minting each key lazily on first read (GetOrInsertWith) — it only changes when the nodes are allocated.

func (*ComputedMap[K, V]) Slot added in v0.22.0

func (m *ComputedMap[K, V]) Slot(key K) *Computed[V]

Slot returns the derived slot handle for key (nil if not materialized). Non-reactive.

type Configuration

type Configuration struct {
	// contains filtered or unexported fields
}

Configuration is the active configuration: the set of active states (atomic leaves plus all active ancestors). It holds a sorted, unique snapshot.

func (Configuration) Contains

func (c Configuration) Contains(id string) bool

Contains reports whether id is in the active configuration.

func (Configuration) IsEmpty

func (c Configuration) IsEmpty() bool

IsEmpty reports whether the configuration is empty.

func (Configuration) ToSet

func (c Configuration) ToSet() []string

ToSet returns a sorted snapshot of the active states.

type Context

type Context struct {
	// contains filtered or unexported fields
}

Context is a reactive scope: batch/effect scheduling plus the node registry. Dependency tracking is value-threaded through the per-recompute Compute view (there is no ambient recompute stack); a read attributes to the recomputing node only when it goes through that view (Get(c, handle)). Cached slot values are stored on the nodes themselves, not here. All Slots, Cells, and Signals that should react to each other must be created with (and thus share) the same Context.

Context is not safe for concurrent use. Wrap it with ThreadSafeContext for lock-backed concurrency, or drive it from a single goroutine via AsyncContext.

func NewContext

func NewContext() *Context

NewContext creates an empty reactive scope.

func (*Context) Batch

func (c *Context) Batch(fn func())

Batch runs fn inside a batch. Cell writes inside the batch defer their invalidation cascades until the outermost batch exits, at which point a single coalesced cascade fires and pending Effects flush once. Re-entrant.

func (*Context) Clear

func (c *Context) Clear()

Clear drops every cached slot value. Dependency edges are re-established lazily as slots are read again. Cell values are unaffected.

func (*Context) DependencyCount added in v0.20.0

func (c *Context) DependencyCount(n GraphNode) int

DependencyCount reports how many nodes n currently depends on — the size of its forward edge set (#lzspecedgeindex).

Counterpart to DependentCount: disposal must detach both directions, and a binding that detaches only one leaves a dangling half-edge visible here. Returns 0 for a disposed node and for *Cell, which is a pure source.

func (*Context) DependentCount added in v0.20.0

func (c *Context) DependentCount(n GraphNode) int

DependentCount reports how many nodes currently depend on n — the size of its reverse edge set (#lzspecedgeindex).

This is the observable the disposal contract is written against: a subscribe/unsubscribe cycle that disposes what it creates must leave this at its starting value no matter how many cycles run. A binding that leaks shows total-ever-created here instead of live-subscriber count.

Returns 0 for a disposed node, and for *Effect, which is a pure sink.

Note that this counts *live* edges. Invalidation does not consume them: the cascade is a non-consuming mark-frontier walk (core.go, markCone), so a degree read immediately after a write and before the dependents are pulled reports the same edges as before the write. An edge changes only when a node recomputes and re-tracks, or when disposal detaches it.

func (*Context) IsBatching

func (c *Context) IsBatching() bool

IsBatching reports whether a Batch is currently active.

func (*Context) IsDisposed added in v0.20.0

func (c *Context) IsDisposed(n GraphNode) bool

IsDisposed reports whether n has been torn down.

func (*Context) Scope added in v0.20.0

func (c *Context) Scope() *TeardownScope

Scope opens a teardown scope. Nodes added with Own are disposed by Close.

func (*Context) Size

func (c *Context) Size() int

Size reports the number of slots currently holding a cached value.

func (*Context) Untracked added in v0.21.0

func (c *Context) Untracked() *Context

Untracked on *Context returns itself — the context is already the untracked surface, so this is idempotent and lets *Context satisfy ComputeOps uniformly.

func (*Context) WithScope added in v0.20.0

func (c *Context) WithScope(fn func(s *TeardownScope))

WithScope runs fn with a fresh teardown scope and closes it on return, including on panic — the callback form of Scope/Close.

type ConvergedEntry

type ConvergedEntry struct {
	Node  NodeId
	Key   *string
	State IpcValue
}

ConvergedEntry is the converged state of a single node: its id, the winning op's optional wire-stable key (the bare NodeKey path string, nil when the node is addressed only by id), and the winning op's state payload.

Mirrors Dart `ConvergedEntry`; Key is the `String?` the Dart plane tracks in `_nodeToKey`, and State is the winning op's IpcValue (Dart stores the already-wire `IpcValue.toWire()` result; ToWire / MarshalJSON here produce the identical wire shape via the IpcValue codec).

func (ConvergedEntry) MarshalJSON

func (e ConvergedEntry) MarshalJSON() ([]byte, error)

MarshalJSON emits { node[, key], state }, omitting key when nil. The State is serialized through the IpcValue codec (e.g. {"Inline":[66]}).

func (ConvergedEntry) String

func (e ConvergedEntry) String() string

func (ConvergedEntry) ToWire

func (e ConvergedEntry) ToWire() map[string]any

ToWire returns the { node, state[, key] } wire map, omitting key when nil (mirrors Dart `ConvergedEntry.toWire`).

type CrdtOp

type CrdtOp struct {
	Node  NodeId
	Key   *NodeKey
	Stamp WireStamp
	State IpcValue
}

CrdtOp is one CRDT cell op on the wire (state-based / CvRDT): the converged State for Node, tagged with the WireStamp that produced it and an optional wire-stable NodeKey.

Wire note (mirrors lazily-rs derived serde and every sibling): Key is ALWAYS present in the wire object (null when unset), unlike NodeSnapshot / DeltaOpNodeAdd which omit it. The decoder also accepts an absent field.

func NewCrdtOp

func NewCrdtOp(node NodeId, stamp WireStamp, state IpcValue) CrdtOp

NewCrdtOp constructs a keyless op (addressed only by node).

func NewKeyedCrdtOp

func NewKeyedCrdtOp(node NodeId, key NodeKey, stamp WireStamp, state IpcValue) CrdtOp

NewKeyedCrdtOp constructs an op carrying a wire-stable NodeKey.

func (CrdtOp) MarshalJSON

func (o CrdtOp) MarshalJSON() ([]byte, error)

func (CrdtOp) TargetReadable

func (o CrdtOp) TargetReadable(permissions *PeerPermissions, peer PeerId) bool

TargetReadable reports whether peer may read Node. Filtered ops are omitted (not redacted) from a permission-filtered CrdtSync.

func (*CrdtOp) UnmarshalJSON

func (o *CrdtOp) UnmarshalJSON(b []byte) error

type CrdtPlane

type CrdtPlane struct {
	// contains filtered or unexported fields
}

CrdtPlane is the CRDT plane: an Hlc + a StampFrontier + the live membership set.

This is the runtime hub a `merge: crdt` root cell drives. Local edits (Tick) and remote observations (ObserveRemote) both fold into the frontier; the StabilityWatermark is what the tombstone-GC contract consumes.

func NewCrdtPlane

func NewCrdtPlane(self PeerId) *CrdtPlane

NewCrdtPlane creates a plane for the given self peer id.

func (*CrdtPlane) Clock

func (p *CrdtPlane) Clock() *Hlc

Clock returns the HLC (wall time is caller-supplied via Tick/ObserveRemote).

func (*CrdtPlane) Frontier

func (p *CrdtPlane) Frontier() *StampFrontier

Frontier returns the stamp frontier (highest observed stamp per peer).

func (*CrdtPlane) IsCollectable

func (p *CrdtPlane) IsCollectable(stamp HlcStamp) bool

IsCollectable reports whether stamp is collectable: its delete stamp is <= the stability watermark (so every replica has provably observed it).

func (*CrdtPlane) Membership

func (p *CrdtPlane) Membership() []PeerId

Membership returns the live membership set (peers this plane has observed, including self), sorted by peer id for deterministic iteration.

func (*CrdtPlane) ObserveRemote

func (p *CrdtPlane) ObserveRemote(remote HlcStamp, nowMicros int64) HlcStamp

ObserveRemote observes a remote stamp: expand membership, fold into the frontier, and advance the HLC. Returns the new local stamp.

func (*CrdtPlane) Self

func (p *CrdtPlane) Self() PeerId

Self returns this peer's id.

func (*CrdtPlane) StabilityWatermark

func (p *CrdtPlane) StabilityWatermark() (HlcStamp, bool)

StabilityWatermark is the causal-stability watermark: min over membership of the frontier. The second return is false until every member has been observed.

func (*CrdtPlane) Tick

func (p *CrdtPlane) Tick(nowMicros int64) HlcStamp

Tick records a local event: tick the clock and fold the result into the frontier. Self is added to the membership on first use.

type CrdtPlaneRuntime

type CrdtPlaneRuntime struct {
	// contains filtered or unexported fields
}

CrdtPlaneRuntime is a state-based CRDT plane runtime with anti-entropy. A single owner goroutine owns the plane state; public methods serialize their work over an inbound command channel (blocking until the owner replies), and converged entries are fanned out over an optional outbound stream (ConvergedStream). Call Close (or cancel the context passed to NewCrdtPlaneRuntimeWithContext) to stop the owner goroutine; no goroutine is leaked.

func NewCrdtPlaneRuntime

func NewCrdtPlaneRuntime(peer PeerId) *CrdtPlaneRuntime

NewCrdtPlaneRuntime creates a runtime for the given local peer id and starts its owner goroutine. Call Close to release it.

func NewCrdtPlaneRuntimeWithContext

func NewCrdtPlaneRuntimeWithContext(ctx context.Context, peer PeerId) *CrdtPlaneRuntime

NewCrdtPlaneRuntimeWithContext creates a runtime that also stops when ctx is cancelled (in addition to Close). Either signal cleanly tears the owner goroutine down.

func (*CrdtPlaneRuntime) Close

func (r *CrdtPlaneRuntime) Close()

Close stops the owner goroutine and closes the converged stream (if any). It is idempotent and safe to call from any goroutine.

func (*CrdtPlaneRuntime) Converged

func (r *CrdtPlaneRuntime) Converged() []ConvergedEntry

Converged returns the full converged state: one entry per node (ascending). Mirrors Dart `converged`.

func (*CrdtPlaneRuntime) ConvergedStream

func (r *CrdtPlaneRuntime) ConvergedStream() <-chan ConvergedEntry

ConvergedStream returns the outbound channel on which converged entries are emitted as ops are applied (one entry per node whose winning op changed in each ingest, ascending). Only one subscriber is supported — the most recent call wins. The channel is closed when the runtime closes. If the runtime is already closed, a closed channel is returned.

func (*CrdtPlaneRuntime) FamilyKeys added in v0.6.0

func (r *CrdtPlaneRuntime) FamilyKeys(namespace string) []NodeKey

FamilyKeys returns the materialized keys of family namespace, in first-materialization order.

func (*CrdtPlaneRuntime) FamilySetLww added in v0.6.0

func (r *CrdtPlaneRuntime) FamilySetLww(namespace, keySuffix string, state IpcValue, nowMicros int64) (CrdtOp, bool)

FamilySetLww inserts or updates the local LWW family entry namespace/<keySuffix> to state at nowMicros, materializing it (and bumping the membership epoch) on first insert. Returns the broadcast op and true, or a zero op and false if the key is invalid or the write was stamp-dominated. The converged entry is fanned out on ConvergedStream.

func (*CrdtPlaneRuntime) FamilyValueLww added in v0.6.0

func (r *CrdtPlaneRuntime) FamilyValueLww(namespace, keySuffix string) (IpcValue, bool)

FamilyValueLww returns the current converged state of family entry namespace/<keySuffix>, and whether the key is present.

func (*CrdtPlaneRuntime) FrontierEntries

func (r *CrdtPlaneRuntime) FrontierEntries() []StampFrontierEntry

FrontierEntries returns the per-peer frontier as wire entries (ascending by peer). Mirrors Dart `frontierEntries` (which returns MapEntry pairs; the Go wire type StampFrontierEntry carries the same (peer, stamp) pair).

func (*CrdtPlaneRuntime) Ingest

func (r *CrdtPlaneRuntime) Ingest(sync CrdtSync) int

Ingest folds a CrdtSync frame (observe frontier, then apply ops) and returns the number of newly applied ops. Mirrors Dart `ingest`.

func (*CrdtPlaneRuntime) IngestOps

func (r *CrdtPlaneRuntime) IngestOps(ops []CrdtOp) int

IngestOps applies a batch of ops and returns the number of newly applied ops (0 = idempotent re-delivery). Converged entries for changed nodes are fanned out on ConvergedStream. Mirrors Dart `ingestOps` (whose unused `nowMicros` parameter is omitted).

func (*CrdtPlaneRuntime) IsEmpty

func (r *CrdtPlaneRuntime) IsEmpty() bool

IsEmpty reports whether no node has converged yet. Mirrors Dart `isEmpty`.

func (*CrdtPlaneRuntime) Membership

func (r *CrdtPlaneRuntime) Membership() []PeerId

Membership returns the known peer ids (ascending). Mirrors Dart `membership`.

func (*CrdtPlaneRuntime) MembershipEpoch added in v0.6.0

func (r *CrdtPlaneRuntime) MembershipEpoch() uint64

MembershipEpoch returns the reactive membership signal (#lzfamilysync): a derived aggregate over a family depends on it so a remote-materialized key forces a recompute. Bumped whenever a family entry materializes.

func (*CrdtPlaneRuntime) Nodes

func (r *CrdtPlaneRuntime) Nodes() []NodeId

Nodes returns all winning node ids ascending. Mirrors Dart `nodes`.

func (*CrdtPlaneRuntime) Ops

func (r *CrdtPlaneRuntime) Ops() []CrdtOp

Ops returns a copy of the full op log in insertion order. Mirrors Dart `ops`.

func (*CrdtPlaneRuntime) Peer

func (r *CrdtPlaneRuntime) Peer() PeerId

Peer returns the local peer id.

func (*CrdtPlaneRuntime) RegisterFamilyLww added in v0.6.0

func (r *CrdtPlaneRuntime) RegisterFamilyLww(namespace string)

RegisterFamilyLww registers a last-writer-wins family under namespace so an inbound keyed op for an unregistered entry of this family materializes on ingest instead of being dropped. Replicas sharing a session must register the same namespace.

func (*CrdtPlaneRuntime) Size

func (r *CrdtPlaneRuntime) Size() int

Size returns the number of converged nodes. Mirrors Dart `size`.

func (*CrdtPlaneRuntime) Value

func (r *CrdtPlaneRuntime) Value(node NodeId) (IpcValue, bool)

Value returns the winning state payload for node, and whether the node is present. Mirrors Dart `value` (which returns the wire form; here the IpcValue itself, whose codec produces that wire form).

func (*CrdtPlaneRuntime) WinningOp

func (r *CrdtPlaneRuntime) WinningOp(node NodeId) (CrdtOp, bool)

WinningOp returns the winning op for node, and whether the node is present. Mirrors Dart `winningOp`.

type CrdtSync

type CrdtSync struct {
	Frontier []StampFrontierEntry
	Ops      []CrdtOp
}

CrdtSync is a CRDT anti-entropy sync frame (the multi-writer plane). The sender advertises its per-peer stamp Frontier (the highest WireStamp observed from each peer) and ships a batch of Ops. The exchange is bounded, idempotent, and resumable; re-sending a frame the receiver already has is a no-op.

func (CrdtSync) FilterReadable

func (c CrdtSync) FilterReadable(permissions *PeerPermissions, peer PeerId) CrdtSync

FilterReadable returns a peer-specific frame that omits ops for non-readable nodes entirely (omission, not redaction — mirroring Delta.FilterReadable). The Frontier advertisement is retained in full: it names peers and stamps, not node content, and the receiver needs the whole frontier to compute a sound causal-stability watermark.

func (CrdtSync) MarshalJSON

func (c CrdtSync) MarshalJSON() ([]byte, error)

func (*CrdtSync) UnmarshalJSON

func (c *CrdtSync) UnmarshalJSON(b []byte) error

type CrdtTree added in v0.13.0

type CrdtTree[V any, D any, T any] interface {
	VersionVector() V
	DeltaSince(V) D
	ApplyDelta(D) bool
	Text() string
	Value() T
	MergeFrom(CrdtTree[V, D, T]) bool
}

CrdtTree is the lossless mergeable document contract (#lzcrdttree).

Snapshot and incremental replication use the same identity-preserving delta: DeltaSince(empty frontier) is the whole-state snapshot. MergeFrom and ApplyDelta must therefore be commutative, associative, and idempotent.

type CronCell added in v0.15.0

type CronCell struct {
	// contains filtered or unexported fields
}

CronCell is a reactive cron source: same reactive contract as IntervalCell.

func NewCronCell added in v0.15.0

func NewCronCell(ctx *Context, cycle uint64, offsets []uint64) *CronCell

NewCronCell creates a reactive cron source.

func (*CronCell) Count added in v0.15.0

func (c *CronCell) Count() uint64

Count reports the total fires so far (reactive read).

func (*CronCell) CountCell added in v0.15.0

func (c *CronCell) CountCell() *Source[uint64]

CountCell returns the backing count cell.

func (*CronCell) NextFire added in v0.15.0

func (c *CronCell) NextFire() (uint64, bool)

NextFire reports the next matching time.

func (*CronCell) Tick added in v0.15.0

func (c *CronCell) Tick(now uint64) bool

Tick advances to logical time now; returns whether a match fired.

type CronCore added in v0.15.0

type CronCore struct {
	// contains filtered or unexported fields
}

CronCore is a pattern-periodic compute core: a tick m >= 1 fires iff m mod cycle is in offsets. The match count in (cursor, now] is computed arithmetically, so a large now jump is O(offsets).

func NewCronCore added in v0.15.0

func NewCronCore(cycle uint64, offsets []uint64) *CronCore

NewCronCore creates a cron core. offsets are reduced mod cycle, sorted, and deduped; cycle is clamped to >=1; empty offsets means the source never fires.

func (*CronCore) Count added in v0.15.0

func (c *CronCore) Count() uint64

Count reports the total number of fires so far.

func (*CronCore) NextFire added in v0.15.0

func (c *CronCore) NextFire() (uint64, bool)

NextFire reports the smallest m > cursor with m mod cycle in offsets, or ok=false when offsets is empty.

func (*CronCore) Tick added in v0.15.0

func (c *CronCore) Tick(now uint64) bool

Tick advances to now; returns whether at least one pattern match fired.

type DeadlineCell added in v0.15.0

type DeadlineCell[T any] struct {
	// contains filtered or unexported fields
}

DeadlineCell is a reactive value + deadline: flips Live(v) -> Expired(v) at the deadline, preserving the value; the state reader invalidates only on the expiry edge.

func NewDeadlineCell added in v0.15.0

func NewDeadlineCell[T any](ctx *Context, value T, deadline uint64) *DeadlineCell[T]

NewDeadlineCell creates a reactive value + deadline pair.

func (*DeadlineCell[T]) ExpiredCell added in v0.15.0

func (d *DeadlineCell[T]) ExpiredCell() *Source[bool]

ExpiredCell returns the backing expiry cell.

func (*DeadlineCell[T]) IsExpired added in v0.15.0

func (d *DeadlineCell[T]) IsExpired() bool

IsExpired reports whether the deadline has passed (reactive read).

func (*DeadlineCell[T]) NextFire added in v0.15.0

func (d *DeadlineCell[T]) NextFire() (uint64, bool)

NextFire reports the deadline, or ok=false once expired.

func (*DeadlineCell[T]) State added in v0.15.0

func (d *DeadlineCell[T]) State() Deadlined[T]

State returns the current state, preserving the value (reactive read).

func (*DeadlineCell[T]) Tick added in v0.15.0

func (d *DeadlineCell[T]) Tick(now uint64) bool

Tick advances to logical time now; returns the expiry edge.

type DeadlineCore added in v0.15.0

type DeadlineCore struct {
	// contains filtered or unexported fields
}

DeadlineCore is a deadline compute core (bytes-eligible): a TimerCore over the deadline. The value lives in the reactive cell.

func NewDeadlineCore added in v0.15.0

func NewDeadlineCore(deadline uint64) *DeadlineCore

NewDeadlineCore creates a deadline core expiring at deadline.

func (*DeadlineCore) IsExpired added in v0.15.0

func (d *DeadlineCore) IsExpired() bool

IsExpired reports whether the deadline has passed.

func (*DeadlineCore) NextFire added in v0.15.0

func (d *DeadlineCore) NextFire() (uint64, bool)

NextFire reports the deadline, or ok=false once expired.

func (*DeadlineCore) Tick added in v0.15.0

func (d *DeadlineCore) Tick(now uint64) bool

Tick advances to now; returns the expiry edge.

type Deadlined added in v0.15.0

type Deadlined[T any] struct {
	// contains filtered or unexported fields
}

Deadlined pairs a value with a liveness state: Live until its deadline, then Expired — the value is preserved across the flip.

func Expired added in v0.15.0

func Expired[T any](v T) Deadlined[T]

Expired wraps a value in the expired state.

func Live added in v0.15.0

func Live[T any](v T) Deadlined[T]

Live wraps a value in the live state.

func (Deadlined[T]) IsExpired added in v0.15.0

func (d Deadlined[T]) IsExpired() bool

IsExpired reports whether the value's deadline has passed.

func (Deadlined[T]) Value added in v0.15.0

func (d Deadlined[T]) Value() T

Value returns the preserved value (present in both Live and Expired).

type DebounceCell added in v0.15.0

type DebounceCell[T comparable] struct {
	// contains filtered or unexported fields
}

DebounceCell is the reactive debounce over any comparable-valued source.

func NewDebounceCell added in v0.15.0

func NewDebounceCell[T comparable](ctx *Context, quiet uint64) *DebounceCell[T]

NewDebounceCell builds a reactive debounce bound to ctx.

func (*DebounceCell[T]) Input added in v0.15.0

func (c *DebounceCell[T]) Input(now uint64, v T)

Input buffers an input; does not emit.

func (*DebounceCell[T]) Output added in v0.15.0

func (c *DebounceCell[T]) Output() Opt[T]

Output returns the last emitted value (subscribes the current computation).

func (*DebounceCell[T]) OutputCell added in v0.15.0

func (c *DebounceCell[T]) OutputCell() *Source[Opt[T]]

OutputCell exposes the reader cell for invalidation observation.

func (*DebounceCell[T]) Tick added in v0.15.0

func (c *DebounceCell[T]) Tick(now uint64) Opt[T]

Tick advances the clock and returns the emitted value (if any), projecting it onto the output reader.

type DebounceCore added in v0.15.0

type DebounceCore[T comparable] struct {
	// contains filtered or unexported fields
}

DebounceCore coalesces inputs (KeepLatest) and emits the latest value only after `quiet` ticks with no new input — every input resets the deadline.

func NewDebounceCore added in v0.15.0

func NewDebounceCore[T comparable](quiet uint64) *DebounceCore[T]

NewDebounceCore builds a debounce core with the given quiet period.

func (*DebounceCore[T]) Input added in v0.15.0

func (d *DebounceCore[T]) Input(now uint64, v T)

Input records an input; resets the quiet deadline to now + quiet.

func (*DebounceCore[T]) Tick added in v0.15.0

func (d *DebounceCore[T]) Tick(now uint64) Opt[T]

Tick advances; emits the latest value once the quiet period has elapsed.

type DedupePolicy added in v0.2.0

type DedupePolicy string

DedupePolicy is how the admitter collapses concurrent/duplicate submits.

const (
	// DedupePolicyNone performs no dedupe.
	DedupePolicyNone DedupePolicy = "none"
	// DedupePolicySameIdempotencyKey collapses by idempotency_key.
	DedupePolicySameIdempotencyKey DedupePolicy = "same_idempotency_key"
	// DedupePolicySameCommandId collapses by command_id.
	DedupePolicySameCommandId DedupePolicy = "same_command_id"
)

type Delta

type Delta struct {
	BaseEpoch Epoch
	Epoch     Epoch
	Ops       []DeltaOp
}

Delta is an incremental change set.

func DeltaNext

func DeltaNext(baseEpoch Epoch, ops []DeltaOp) Delta

DeltaNext builds the next sequential delta after baseEpoch carrying ops.

lean theorem `nextDelta_epoch`: the returned Epoch is always baseEpoch + 1.

func (Delta) ApplyStatus

func (d Delta) ApplyStatus(lastEpoch Epoch) DeltaApplyStatus

ApplyStatus applies iff sequential, otherwise fails closed (lean `applyDelta`).

func (Delta) FilterReadable

func (d Delta) FilterReadable(permissions *PeerPermissions, peer PeerId) Delta

FilterReadable drops ops whose target node(s) are unreadable by peer.

func (Delta) IsNextAfter

func (d Delta) IsNextAfter(lastEpoch Epoch) bool

IsNextAfter reports whether this delta continues immediately after lastEpoch (lean `isSequentialAfter`).

func (Delta) MarshalJSON

func (d Delta) MarshalJSON() ([]byte, error)

func (Delta) Span added in v0.8.0

func (d Delta) Span() Epoch

Span returns the number of epochs an applied Delta advances (epoch - base_epoch); 1 for an ordinary delta, > 1 for a coalesced multi-epoch flush.

func (*Delta) UnmarshalJSON

func (d *Delta) UnmarshalJSON(b []byte) error

type DeltaApplyStatus

type DeltaApplyStatus interface {
	IsApply() bool
	IsResyncRequired() bool
	// contains filtered or unexported methods
}

DeltaApplyStatus is the outcome of attempting to apply a Delta.

type DeltaApplyStatusApply

type DeltaApplyStatusApply struct {
	NewEpoch Epoch
}

DeltaApplyStatusApply means the delta was sequential and may be applied; the new epoch is NewEpoch.

func (DeltaApplyStatusApply) IsApply

func (DeltaApplyStatusApply) IsApply() bool

func (DeltaApplyStatusApply) IsResyncRequired

func (DeltaApplyStatusApply) IsResyncRequired() bool

type DeltaApplyStatusResyncRequired

type DeltaApplyStatusResyncRequired struct {
	LastEpoch Epoch
	BaseEpoch Epoch
	Epoch     Epoch
}

DeltaApplyStatusResyncRequired means a gap, reorder, or sender restart was detected; request a fresh snapshot.

func (DeltaApplyStatusResyncRequired) IsApply

func (DeltaApplyStatusResyncRequired) IsResyncRequired

func (DeltaApplyStatusResyncRequired) IsResyncRequired() bool

type DeltaOp

type DeltaOp interface {
	MarshalJSON() ([]byte, error)
	// TargetReadable reports whether peer may read every node this op names. Ops
	// targeting an unreadable node are omitted from a permission-filtered delta.
	TargetReadable(permissions *PeerPermissions, peer PeerId) bool
	// contains filtered or unexported methods
}

DeltaOp is one incremental operation in a Delta. All variants are externally tagged; DeltaOpNodeAdd carries the optional wire-stable NodeKey.

func CellSetOps

func CellSetOps(node NodeId, oldValue, newValue IpcValue) []DeltaOp

CellSetOps is lean `cellSetOps` + theorems `equal_cell_set_is_silent` / `changed_cell_set_emits_cell_set`: the PartialEq cell guard. An equal write emits no op; a changed write emits exactly one DeltaOpCellSet.

func DownstreamInvalidations

func DownstreamInvalidations(downstream []NodeId) []DeltaOp

DownstreamInvalidations is lean `downstreamInvalidations`: each downstream node becomes a DeltaOpInvalidate, preserving order.

func MemoOps

func MemoOps(node NodeId, oldValue, newValue IpcValue, downstream []NodeId) []DeltaOp

MemoOps is lean `memoOps` + theorems `equal_memo_suppresses_downstream` / `changed_memo_publishes_then_invalidates`: memo equality suppression. An equal recompute is silent; a changed recompute publishes a DeltaOpSlotValue then invalidates the downstream frontier.

func SignalOps

func SignalOps(node NodeId, oldValue, newValue IpcValue) []DeltaOp

SignalOps is lean `signalOps` + theorems `equal_signal_is_silent` / `changed_signal_materializes_slot_value` / `signal_never_emits_bare_invalidate`: a changed eager Signal materializes a concrete DeltaOpSlotValue for its backing slot — never a bare DeltaOpInvalidate.

type DeltaOpCellSet

type DeltaOpCellSet struct {
	Node    NodeId
	Payload IpcValue
}

DeltaOpCellSet is a changed-value cell write, PartialEq-guarded at the source.

func (DeltaOpCellSet) MarshalJSON

func (o DeltaOpCellSet) MarshalJSON() ([]byte, error)

func (DeltaOpCellSet) TargetReadable

func (o DeltaOpCellSet) TargetReadable(p *PeerPermissions, peer PeerId) bool

type DeltaOpEdgeAdd

type DeltaOpEdgeAdd struct {
	Dependent  NodeId
	Dependency NodeId
}

DeltaOpEdgeAdd adds a new dependency edge.

func (DeltaOpEdgeAdd) MarshalJSON

func (o DeltaOpEdgeAdd) MarshalJSON() ([]byte, error)

func (DeltaOpEdgeAdd) TargetReadable

func (o DeltaOpEdgeAdd) TargetReadable(p *PeerPermissions, peer PeerId) bool

type DeltaOpEdgeRemove

type DeltaOpEdgeRemove struct {
	Dependent  NodeId
	Dependency NodeId
}

DeltaOpEdgeRemove removes a dependency edge.

func (DeltaOpEdgeRemove) MarshalJSON

func (o DeltaOpEdgeRemove) MarshalJSON() ([]byte, error)

func (DeltaOpEdgeRemove) TargetReadable

func (o DeltaOpEdgeRemove) TargetReadable(p *PeerPermissions, peer PeerId) bool

type DeltaOpInvalidate

type DeltaOpInvalidate struct {
	Node NodeId
}

DeltaOpInvalidate marks a node dirtied but not yet recomputed (lazy).

func (DeltaOpInvalidate) MarshalJSON

func (o DeltaOpInvalidate) MarshalJSON() ([]byte, error)

func (DeltaOpInvalidate) TargetReadable

func (o DeltaOpInvalidate) TargetReadable(p *PeerPermissions, peer PeerId) bool

type DeltaOpNodeAdd

type DeltaOpNodeAdd struct {
	Node    NodeId
	TypeTag string
	State   NodeState
	Key     *NodeKey
}

DeltaOpNodeAdd adds a new node (optional wire-stable Key, omitted when nil).

func (DeltaOpNodeAdd) MarshalJSON

func (o DeltaOpNodeAdd) MarshalJSON() ([]byte, error)

func (DeltaOpNodeAdd) TargetReadable

func (o DeltaOpNodeAdd) TargetReadable(p *PeerPermissions, peer PeerId) bool

type DeltaOpNodeRemove

type DeltaOpNodeRemove struct {
	Node NodeId
}

DeltaOpNodeRemove removes a node (free-list reuse: Remove then Add).

func (DeltaOpNodeRemove) MarshalJSON

func (o DeltaOpNodeRemove) MarshalJSON() ([]byte, error)

func (DeltaOpNodeRemove) TargetReadable

func (o DeltaOpNodeRemove) TargetReadable(p *PeerPermissions, peer PeerId) bool

type DeltaOpSlotValue

type DeltaOpSlotValue struct {
	Node    NodeId
	Payload IpcValue
}

DeltaOpSlotValue signals that a recompute published a new value.

func (DeltaOpSlotValue) MarshalJSON

func (o DeltaOpSlotValue) MarshalJSON() ([]byte, error)

func (DeltaOpSlotValue) TargetReadable

func (o DeltaOpSlotValue) TargetReadable(p *PeerPermissions, peer PeerId) bool

type DiffOp

type DiffOp[K comparable, V comparable] interface {
	// contains filtered or unexported methods
}

DiffOp is a keyed reconciliation op (cell-model.md § Keyed reconciliation): one of DiffOpInsert, DiffOpRemove, DiffOpMove, or DiffOpUpdate. It is a sealed union — only the four concrete types in this package implement it.

func ReconcileDiff

func ReconcileDiff[K comparable, V comparable](
	prior []KeyValue[K, V],
	target []KeyValue[K, V],
) []DiffOp[K, V]

ReconcileDiff computes the move-minimized keyed reconciliation (cell-model.md § Keyed reconciliation).

Diffs two keyed sequences by stable key, not position, emitting the minimal {insert, remove, move, update} op set: removes, then inserts + moves (in target order), then updates. Moves are move-minimized: the longest-increasing-subsequence (LIS) over prior indices of the common keys is held fixed, and only the remainder move. O(n log n) via patience sorting (strictly increasing), mirroring lazily-rs/src/reconcile.rs::longest_increasing_subsequence.

type DiffOpInsert

type DiffOpInsert[K comparable, V comparable] struct {
	Key   K
	Value V
	Index int
}

DiffOpInsert inserts a brand-new key (not present in prior) at Index (its final position in the target sequence).

type DiffOpMove

type DiffOpMove[K comparable, V comparable] struct {
	Key K
	To  int
}

DiffOpMove atomic-moves a common key from its prior position to To (the target index). Keeps the entry's same cell handle, dependents, and lineage.

type DiffOpRemove

type DiffOpRemove[K comparable, V comparable] struct {
	Key K
}

DiffOpRemove removes a key present in prior but absent in target.

type DiffOpUpdate

type DiffOpUpdate[K comparable, V comparable] struct {
	Key   K
	Value V
}

DiffOpUpdate updates an existing key's value (PartialEq-guarded at the cell).

type DiscoveryCell added in v0.15.0

type DiscoveryCell[P comparable] struct {
	// contains filtered or unexported fields
}

DiscoveryCell is the reactive service discovery. The discovery map is a collection reader, so it uses the version-cell pattern: bump version only when the projected map structurally changes.

func NewDiscoveryCell added in v0.15.0

func NewDiscoveryCell[P comparable](ctx *Context) *DiscoveryCell[P]

NewDiscoveryCell creates a reactive discovery cell bound to ctx.

func (*DiscoveryCell[P]) Deregister added in v0.15.0

func (d *DiscoveryCell[P]) Deregister(service string)

Deregister removes a service and refreshes the map.

func (*DiscoveryCell[P]) Discovery added in v0.15.0

func (d *DiscoveryCell[P]) Discovery() map[string]string

Discovery returns the live service -> endpoint map, subscribing the reader to the version cell.

func (*DiscoveryCell[P]) DiscoveryCell added in v0.15.0

func (d *DiscoveryCell[P]) DiscoveryCell() *Source[uint64]

DiscoveryCell returns the underlying version cell (the reactive handle).

func (*DiscoveryCell[P]) Evict added in v0.15.0

func (d *DiscoveryCell[P]) Evict(peer P)

Evict removes all endpoints owned by peer and refreshes the map.

func (*DiscoveryCell[P]) Register added in v0.15.0

func (d *DiscoveryCell[P]) Register(service string, endpoint string, peer P)

Register records a service endpoint owned by peer and refreshes the map.

func (*DiscoveryCell[P]) Resolve added in v0.15.0

func (d *DiscoveryCell[P]) Resolve(service string) (string, bool)

Resolve returns the endpoint for a service without changing the map.

type DiscoveryCore added in v0.15.0

type DiscoveryCore[P comparable] struct {
	// contains filtered or unexported fields
}

DiscoveryCore is the service-discovery core: service -> (endpoint, owner). A peer's departure (Evict) removes its endpoints.

func NewDiscoveryCore added in v0.15.0

func NewDiscoveryCore[P comparable]() *DiscoveryCore[P]

NewDiscoveryCore creates an empty discovery core.

func (*DiscoveryCore[P]) Deregister added in v0.15.0

func (c *DiscoveryCore[P]) Deregister(service string)

Deregister removes a service.

func (*DiscoveryCore[P]) Discovery added in v0.15.0

func (c *DiscoveryCore[P]) Discovery() map[string]string

Discovery returns the live service -> endpoint map.

func (*DiscoveryCore[P]) Evict added in v0.15.0

func (c *DiscoveryCore[P]) Evict(peer P)

Evict removes all endpoints owned by peer (membership loss).

func (*DiscoveryCore[P]) Register added in v0.15.0

func (c *DiscoveryCore[P]) Register(service string, endpoint string, peer P)

Register records a service endpoint owned by peer.

func (*DiscoveryCore[P]) Resolve added in v0.15.0

func (c *DiscoveryCore[P]) Resolve(service string) (string, bool)

Resolve returns the endpoint for a service, if present.

type DisposedError added in v0.20.0

type DisposedError struct {
	// Name is the node's debug name when it has one (NewNamedSlot).
	Name string
	// Kind is "slot", "cell", or "signal".
	Kind string
}

DisposedError is the panic value raised by a read of a disposed node, and the error returned by TryGet.

func (*DisposedError) Error added in v0.20.0

func (e *DisposedError) Error() string

func (*DisposedError) Unwrap added in v0.20.0

func (e *DisposedError) Unwrap() error

Unwrap makes errors.Is(err, ErrDisposed) work.

type DriverError added in v0.8.0

type DriverError struct {
	// Source is the inbound source read failure that stalled the tick.
	Source error
}

DriverError is a transport error surfaced by SyncDriver.Tick.

A sink failure is not fatal — the frame is retained in the outbox and replayed on the next SyncDriver.OnReconnect, so it is reported as a stall, not an error. Only a source read failure is returned as a DriverError, signalling the host to re-establish the transport and call OnReconnect.

func (*DriverError) Error added in v0.8.0

func (e *DriverError) Error() string

Error implements the error interface.

func (*DriverError) Unwrap added in v0.8.0

func (e *DriverError) Unwrap() error

Unwrap exposes the underlying source error.

type DurableOutbox added in v0.8.0

type DurableOutbox interface {
	// Append persists msg at epoch before it is handed to the transport.
	Append(epoch Epoch, msg IpcMessage)
	// AckThrough records that the peer proved receipt through epoch; retained
	// frames <= epoch MAY be pruned.
	AckThrough(epoch Epoch)
	// ReplayFrom returns retained frames with epoch > cursor, ascending.
	ReplayFrom(cursor Epoch) []OutboxEntry
	// RetainedEpochs lists epochs still retained (not yet acked), ascending.
	RetainedEpochs() []Epoch
}

DurableOutbox is the sender-side at-least-once outbox contract (spec § DurableOutbox).

Every frame is durably Appended BEFORE it is sent, retained until the peer proves receipt (AckThrough), and ReplayFrom a reconnect cursor re-sends everything the peer has not yet acked. Combined with the receiver's idempotent Ignore of already-applied deltas, this is at-least-once delivery with exactly-once effect.

type DurableStoreOutbox added in v0.13.0

type DurableStoreOutbox[S OutboxStore] struct {
	// contains filtered or unexported fields
}

DurableStoreOutbox is Go's storage-independent outbox. The longer name avoids colliding with RelayCell's established Outbox role facade.

func NewDurableStoreOutbox added in v0.13.0

func NewDurableStoreOutbox[S OutboxStore](store S) *DurableStoreOutbox[S]

NewDurableStoreOutbox loads the durable cursor from store.

func (*DurableStoreOutbox[S]) AckThrough added in v0.13.0

func (o *DurableStoreOutbox[S]) AckThrough(epoch Epoch)

AckThrough advances the monotonic cursor and prunes the acknowledged prefix.

func (*DurableStoreOutbox[S]) AckedThrough added in v0.13.0

func (o *DurableStoreOutbox[S]) AckedThrough() Epoch

AckedThrough returns the highest loaded or observed peer acknowledgement.

func (*DurableStoreOutbox[S]) Append added in v0.13.0

func (o *DurableStoreOutbox[S]) Append(epoch Epoch, msg IpcMessage)

Append serializes and stores a frame before transport send.

func (*DurableStoreOutbox[S]) Err added in v0.13.0

func (o *DurableStoreOutbox[S]) Err() error

Err returns the most recent frame serialization/decoding error.

func (*DurableStoreOutbox[S]) ReplayFrom added in v0.13.0

func (o *DurableStoreOutbox[S]) ReplayFrom(cursor Epoch) []OutboxEntry

ReplayFrom returns decoded frames after both the caller and durable cursors.

func (*DurableStoreOutbox[S]) RetainedEpochs added in v0.13.0

func (o *DurableStoreOutbox[S]) RetainedEpochs() []Epoch

RetainedEpochs lists the unacknowledged suffix in ascending order.

func (*DurableStoreOutbox[S]) Store added in v0.13.0

func (o *DurableStoreOutbox[S]) Store() S

Store returns the byte adapter owned by the shared protocol.

type EdgeSnapshot

type EdgeSnapshot struct {
	Dependent  NodeId `json:"dependent"`
	Dependency NodeId `json:"dependency"`
}

EdgeSnapshot is a dependency edge: Dependent reads Dependency.

func (EdgeSnapshot) IsReadableBy

func (e EdgeSnapshot) IsReadableBy(permissions *PeerPermissions, peer PeerId) bool

IsReadableBy reports whether both endpoints are readable by peer (so the edge is observable).

func (EdgeSnapshot) String

func (e EdgeSnapshot) String() string

type Effect

type Effect struct {
	// contains filtered or unexported fields
}

Effect is a side-effect observer that reruns whenever a tracked dependency changes. It is the eager-push primitive for side effects (logging, I/O). Any Cell, Slot, or Signal read inside run becomes a dependency; when any changes, the effect is scheduled and reruns after the current cascade (or at Batch exit).

func NewEffect

func NewEffect(ctx *Context, run EffectRun) *Effect

NewEffect creates and immediately runs a side-effect observer whose body receives the per-recompute Compute view and tracks via Get(c, handle) — the fortified, value-threaded surface (#lzcellkernel).

func (*Effect) Dispose

func (e *Effect) Dispose()

Dispose removes the eager observer. Invokes the last cleanup, then unsubscribes from all dependencies. Idempotent.

func (*Effect) IsActive

func (e *Effect) IsActive() bool

IsActive reports whether the effect is still active (not disposed).

type EffectRun

type EffectRun func(c *Compute) (cleanup func())

EffectRun is a side-effect function that may return a cleanup callback. It receives the per-recompute Compute view and reads its dependencies via Get(c, handle) — the value-threaded tracking surface (#lzcellkernel). The cleanup (if non-nil) is invoked before the next rerun and on Dispose.

type EntryKind added in v0.5.0

type EntryKind int

EntryKind is which kind of reactive node a ReactiveMap entry is — the handle-kind axis the map abstracts over. Mirrors EntryKind in lazily-formal's Materialization module and the Rust MapHandle::KIND.

const (
	// EntryKindSource is an input cell (*Source[V]) — always materialized on read.
	EntryKindSource EntryKind = iota
	// EntryKindComputed is a derived slot (*Computed[V]) — materialized eagerly
	// (pre-mint) or lazily on first read.
	EntryKindComputed
)

func (EntryKind) String added in v0.5.0

func (k EntryKind) String() string

String renders the entry kind for diagnostics. The rendered strings are the wire spelling shared with the conformance fixtures and the other bindings; the Go identifier rename does not change them.

type EphemeralCell added in v0.15.0

type EphemeralCell[V comparable] struct {
	// contains filtered or unexported fields
}

EphemeralCell is a reactive single-value ephemeral cell. Value() invalidates only when the live value changes (the Cell == guard).

func NewEphemeralCell added in v0.15.0

func NewEphemeralCell[V comparable](ctx *Context) *EphemeralCell[V]

NewEphemeralCell builds an empty ephemeral cell in ctx.

func (*EphemeralCell[V]) Set added in v0.15.0

func (c *EphemeralCell[V]) Set(value V, now, ttl uint64)

Set stamps the value with expiry = now + ttl.

func (*EphemeralCell[V]) Tick added in v0.15.0

func (c *EphemeralCell[V]) Tick(now uint64)

Tick clears the value at now >= expiry.

func (*EphemeralCell[V]) Value added in v0.15.0

func (c *EphemeralCell[V]) Value() (V, bool)

Value returns the live value and whether one is present.

func (*EphemeralCell[V]) ValueCell added in v0.15.0

func (c *EphemeralCell[V]) ValueCell() *Source[Opt[V]]

ValueCell exposes the underlying reactive reader (Option scalar).

type EphemeralCore added in v0.15.0

type EphemeralCore[V comparable] struct {
	// contains filtered or unexported fields
}

EphemeralCore is the single-value auto-expiry compute core — "the last value seen in window N".

func NewEphemeralCore added in v0.15.0

func NewEphemeralCore[V comparable]() *EphemeralCore[V]

NewEphemeralCore returns an empty core.

func (*EphemeralCore[V]) Set added in v0.15.0

func (c *EphemeralCore[V]) Set(value V, now, ttl uint64)

Set the value, expiring at now + ttl.

func (*EphemeralCore[V]) Tick added in v0.15.0

func (c *EphemeralCore[V]) Tick(now uint64)

Tick clears the value once now >= expiry.

func (*EphemeralCore[V]) Value added in v0.15.0

func (c *EphemeralCore[V]) Value() (V, bool)

Value returns the live value (respecting the last tick).

type EphemeralMapCore added in v0.15.0

type EphemeralMapCore[K comparable, V any] struct {
	// contains filtered or unexported fields
}

EphemeralMapCore is a per-key ephemeral map with TTL eviction — the shared core behind presence and awareness. Each entry carries an expiry; Tick evicts lapsed entries.

func NewEphemeralMapCore added in v0.15.0

func NewEphemeralMapCore[K comparable, V any]() *EphemeralMapCore[K, V]

NewEphemeralMapCore returns an empty core.

func (*EphemeralMapCore[K, V]) Evict added in v0.15.0

func (c *EphemeralMapCore[K, V]) Evict(key K)

Evict drops key immediately (membership Dead/Left).

func (*EphemeralMapCore[K, V]) Get added in v0.15.0

func (c *EphemeralMapCore[K, V]) Get(key K, now uint64) (V, bool)

Get returns the live value for key (respecting now).

func (*EphemeralMapCore[K, V]) Present added in v0.15.0

func (c *EphemeralMapCore[K, V]) Present(now uint64) map[K]V

Present returns the live key -> value map at now.

func (*EphemeralMapCore[K, V]) Set added in v0.15.0

func (c *EphemeralMapCore[K, V]) Set(key K, value V, now, ttl uint64)

Set/refresh key's value (last-writer wins), expiring at now + ttl.

func (*EphemeralMapCore[K, V]) Tick added in v0.15.0

func (c *EphemeralMapCore[K, V]) Tick(now uint64)

Tick evicts entries whose TTL has lapsed (now >= expiry).

type Epoch

type Epoch = int64

Epoch is the monotonically increasing snapshot/delta sequence number.

type Equals

type Equals[T any] func(a, b T) bool

Equals is an equality predicate for async memo guards (Dart typedef Equals).

type ExpiryPolicy added in v0.11.0

type ExpiryPolicy struct {
	// contains filtered or unexported fields
}

ExpiryPolicy — Case 10, TTL / deadline expiry. Drops elements whose age exceeds ttl against a logical clock. Lossy-by-age (explicit); used to shed cold data.

func NewExpiryPolicy added in v0.11.0

func NewExpiryPolicy(ttl uint64) *ExpiryPolicy

NewExpiryPolicy creates a TTL policy with the given time-to-live.

func (*ExpiryPolicy) Advance added in v0.11.0

func (e *ExpiryPolicy) Advance(by uint64)

Advance advances the logical clock.

func (*ExpiryPolicy) IsLive added in v0.11.0

func (e *ExpiryPolicy) IsLive(stampedAt uint64) bool

IsLive reports whether an element stamped at stampedAt is still live.

func (*ExpiryPolicy) Now added in v0.11.0

func (e *ExpiryPolicy) Now() uint64

Now is the current logical time.

type FfiCapability

type FfiCapability string

FfiCapability is the `ffi` capability declaration. Its string value is the wire token.

const (
	// FfiCapabilityHost means this binding hosts a native C ABI and may be
	// loaded in-process.
	FfiCapabilityHost FfiCapability = "host"

	// FfiCapabilityNone means this binding's runtime cannot host a native C ABI
	// (e.g. browser/Worker JS). It conforms to the interop contract but NOT the
	// in-process embedding contract, and MUST NOT advertise itself as
	// embeddable.
	FfiCapabilityNone FfiCapability = "none"
)

func ParseFfiCapability

func ParseFfiCapability(s string) (FfiCapability, error)

ParseFfiCapability parses a wire token into an FfiCapability.

func (FfiCapability) Wire

func (f FfiCapability) Wire() string

Wire returns the wire token for this capability.

type FileOutbox added in v0.13.0

type FileOutbox struct {
	*DurableStoreOutbox[*FileOutboxStore]
}

FileOutbox is the ready-to-use durable filesystem adapter.

func NewFileOutbox added in v0.13.0

func NewFileOutbox(path string) (*FileOutbox, error)

NewFileOutbox opens a durable outbox journal.

type FileOutboxStore added in v0.13.0

type FileOutboxStore struct {
	// contains filtered or unexported fields
}

FileOutboxStore is a durable append-only journal adapter. Cursor records are folded with max, rather than overwritten, so stale writers cannot regress the persisted acknowledgement. O_APPEND also gives separate handles one serialized record boundary without a shared in-memory lock.

func NewFileOutboxStore added in v0.13.0

func NewFileOutboxStore(path string) (*FileOutboxStore, error)

NewFileOutboxStore opens (or creates) an append-only outbox journal.

func (*FileOutboxStore) DeleteThrough added in v0.13.0

func (s *FileOutboxStore) DeleteThrough(epoch Epoch)

func (*FileOutboxStore) Err added in v0.13.0

func (s *FileOutboxStore) Err() error

Err returns the latest journal I/O or decoding error.

func (*FileOutboxStore) LoadCursor added in v0.13.0

func (s *FileOutboxStore) LoadCursor() Epoch

func (*FileOutboxStore) Put added in v0.13.0

func (s *FileOutboxStore) Put(epoch Epoch, frame []byte)

func (*FileOutboxStore) SaveCursor added in v0.13.0

func (s *FileOutboxStore) SaveCursor(epoch Epoch)

func (*FileOutboxStore) ScanAfter added in v0.13.0

func (s *FileOutboxStore) ScanAfter(cursor Epoch) []StoredOutboxEntry

type FoldFn

type FoldFn[V, D any] func(value V, childDerived []D) D

FoldFn combines a node's value with its children's derived values.

type FramedTransport added in v0.11.0

type FramedTransport[T any] struct {
	// contains filtered or unexported fields
}

FramedTransport models CrossThread/Ipc/Ws: ops are delivered in bounded frames of at most frameSize (an MTU / batch boundary). Different frameSizes are different framings of the same op stream.

func NewFramedTransport added in v0.11.0

func NewFramedTransport[T any](frameSize int) *FramedTransport[T]

NewFramedTransport creates a framed transport with the given frame size.

func (*FramedTransport[T]) Deliver added in v0.11.0

func (t *FramedTransport[T]) Deliver(op T)

func (*FramedTransport[T]) HasPending added in v0.11.0

func (t *FramedTransport[T]) HasPending() bool

func (*FramedTransport[T]) Poll added in v0.11.0

func (t *FramedTransport[T]) Poll() []T

type GraphNode added in v0.20.0

type GraphNode interface {
	// contains filtered or unexported methods
}

GraphNode is any node in a Context's reactive graph: *Slot, *Cell, *Signal, *Memo, or *Effect.

Sealed — its only method is unexported, so it cannot be implemented outside this package. It exists so the degree accessors and TeardownScope.Own take any node kind without exposing the edge sets themselves. The accessors return *counts*, never the sets: there is no path from here to a node's internals and no way to mutate the graph through it.

type Health added in v0.15.0

type Health int

Health is the composed health status (worst component dominates).

const (
	Healthy Health = iota
	Degraded
	Unhealthy
)

func (Health) String added in v0.15.0

func (h Health) String() string

type HealthCell added in v0.15.0

type HealthCell struct {
	// contains filtered or unexported fields
}

HealthCell is the reactive health projection onto a Cell for /health.

func NewHealthCell added in v0.15.0

func NewHealthCell(ctx *Context) *HealthCell

NewHealthCell creates a reactive health cell bound to ctx.

func (*HealthCell) Health added in v0.15.0

func (h *HealthCell) Health() Health

Health returns the current aggregate health.

func (*HealthCell) HealthCell added in v0.15.0

func (h *HealthCell) HealthCell() *Source[Health]

HealthCell returns the underlying reactive cell for /health.

func (*HealthCell) Set added in v0.15.0

func (h *HealthCell) Set(name string, up bool, critical bool)

Set sets or refreshes a probe and refreshes the projection.

type HealthCore added in v0.15.0

type HealthCore struct {
	// contains filtered or unexported fields
}

HealthCore is the composed liveness-probe core. Each probe reports up and whether it is critical.

func NewHealthCore added in v0.15.0

func NewHealthCore() *HealthCore

NewHealthCore creates an empty health core.

func (*HealthCore) Health added in v0.15.0

func (c *HealthCore) Health() Health

Health is the aggregate: Unhealthy if any critical probe is down, else Degraded if any is down, else Healthy.

func (*HealthCore) Set added in v0.15.0

func (c *HealthCore) Set(name string, up bool, critical bool)

Set sets or refreshes a probe.

type Hlc

type Hlc struct {
	// contains filtered or unexported fields
}

Hlc is a hybrid logical clock. Wall time is caller-supplied (Tick/Observe take nowMicros) so the clock is deterministic and never reads the system clock.

func NewHlc

func NewHlc(peer PeerId) *Hlc

NewHlc creates a clock for the given peer id.

func (*Hlc) Observe

func (h *Hlc) Observe(remote HlcStamp, nowMicros int64) HlcStamp

Observe folds a remote stamp: the returned local stamp is strictly greater than remote (the standard HLC recv rule).

func (*Hlc) Peer

func (h *Hlc) Peer() PeerId

Peer returns this clock's peer id (the final tiebreak component).

func (*Hlc) Tick

func (h *Hlc) Tick(nowMicros int64) HlcStamp

Tick records a local event, advancing the clock, and returns the new stamp. Strictly increasing on this peer.

type HlcStamp

type HlcStamp struct {
	WallTime int64 // microseconds
	Logical  int64
	Peer     PeerId
}

HlcStamp is a runtime HLC stamp — a total order (WallTime, Logical, Peer). Order is lexicographic, so equal (wall, logical) from different peers is still totally ordered by Peer. HlcStamp is a comparable value type.

func HlcStampFromWire

func HlcStampFromWire(stamp WireStamp) HlcStamp

HlcStampFromWire converts a wire WireStamp back to the runtime HlcStamp.

func MaxStamp

func MaxStamp(a, b HlcStamp) HlcStamp

MaxStamp returns the lexicographically larger stamp (LWW winner).

func MinStamp

func MinStamp(a, b HlcStamp) HlcStamp

MinStamp returns the lexicographically smaller stamp (stability watermark).

func NewHlcStamp

func NewHlcStamp(wallTime, logical int64, peer PeerId) HlcStamp

NewHlcStamp constructs a stamp.

func (HlcStamp) Compare

func (s HlcStamp) Compare(other HlcStamp) int

Compare returns -1, 0, or +1 for the lexicographic (wall, logical, peer) order.

func (HlcStamp) Greater

func (s HlcStamp) Greater(other HlcStamp) bool

func (HlcStamp) GreaterEqual

func (s HlcStamp) GreaterEqual(o HlcStamp) bool

func (HlcStamp) Less

func (s HlcStamp) Less(other HlcStamp) bool

func (HlcStamp) LessEqual

func (s HlcStamp) LessEqual(other HlcStamp) bool

func (HlcStamp) ToWire

func (s HlcStamp) ToWire() WireStamp

ToWire converts a runtime HlcStamp to its wire mirror (WireStamp, owned by ipc.go). The two are isomorphic and convert losslessly at the boundary.

type InMemoryOutbox added in v0.8.0

type InMemoryOutbox struct {
	*DurableStoreOutbox[*InMemoryStore]
}

InMemoryOutbox preserves the established default constructor and API while delegating all protocol behavior to DurableStoreOutbox.

func NewInMemoryOutbox added in v0.8.0

func NewInMemoryOutbox() *InMemoryOutbox

NewInMemoryOutbox returns an empty outbox.

type InMemoryStore added in v0.13.0

type InMemoryStore struct {
	// contains filtered or unexported fields
}

InMemoryStore is an ordered process-local OutboxStore.

func NewInMemoryStore added in v0.13.0

func NewInMemoryStore() *InMemoryStore

NewInMemoryStore returns an empty byte store.

func (*InMemoryStore) DeleteThrough added in v0.13.0

func (s *InMemoryStore) DeleteThrough(epoch Epoch)

func (*InMemoryStore) LoadCursor added in v0.13.0

func (s *InMemoryStore) LoadCursor() Epoch

func (*InMemoryStore) Put added in v0.13.0

func (s *InMemoryStore) Put(epoch Epoch, frame []byte)

func (*InMemoryStore) SaveCursor added in v0.13.0

func (s *InMemoryStore) SaveCursor(epoch Epoch)

func (*InMemoryStore) ScanAfter added in v0.13.0

func (s *InMemoryStore) ScanAfter(cursor Epoch) []StoredOutboxEntry

type InProcTransport added in v0.11.0

type InProcTransport[T any] struct {
	// contains filtered or unexported fields
}

InProcTransport is direct delivery: every buffered op is handed over in one frame.

func NewInProcTransport added in v0.11.0

func NewInProcTransport[T any]() *InProcTransport[T]

NewInProcTransport creates a direct in-process transport.

func (*InProcTransport[T]) Deliver added in v0.11.0

func (t *InProcTransport[T]) Deliver(op T)

func (*InProcTransport[T]) HasPending added in v0.11.0

func (t *InProcTransport[T]) HasPending() bool

func (*InProcTransport[T]) Poll added in v0.11.0

func (t *InProcTransport[T]) Poll() []T

type InProcessBackend added in v0.4.0

type InProcessBackend struct {
	// contains filtered or unexported fields
}

InProcessBackend is the default in-process backend: it wraps a ShmBlobArena for the single-address-space case (the FFI host ↔ a binding loaded in the same process, an editor plugin). Descriptors carry Backend = BackendInProcess. For a genuine cross-process store, spill to a ShmBackend (linux) instead.

func InProcessBackendFromArena added in v0.4.0

func InProcessBackendFromArena(arena *ShmBlobArena) *InProcessBackend

InProcessBackendFromArena wraps an existing arena.

func NewInProcessBackend added in v0.4.0

func NewInProcessBackend() *InProcessBackend

NewInProcessBackend creates an in-process backend over a fresh arena at epoch 0.

func (*InProcessBackend) AdvanceEpoch added in v0.4.0

func (b *InProcessBackend) AdvanceEpoch()

AdvanceEpoch advances the backing arena's epoch, invalidating prior descriptors.

func (*InProcessBackend) Arena added in v0.4.0

func (b *InProcessBackend) Arena() *ShmBlobArena

Arena returns the backing arena.

func (*InProcessBackend) Epoch added in v0.4.0

func (b *InProcessBackend) Epoch() int64

Epoch returns the backend's current validity epoch.

func (*InProcessBackend) Kind added in v0.4.0

Kind reports BackendInProcess.

func (*InProcessBackend) ReadView added in v0.4.0

func (b *InProcessBackend) ReadView(descriptor ShmBlobRef) ([]byte, bool)

ReadView resolves the descriptor zero-copy against the backing arena.

func (*InProcessBackend) Write added in v0.4.0

func (b *InProcessBackend) Write(bytes []byte) (ShmBlobRef, error)

Write stores bytes in the arena and stamps the descriptor with the in-process backend discriminator.

type Inbox added in v0.11.0

type Inbox[T comparable] struct {
	// contains filtered or unexported fields
}

Inbox is the transport → app receive side (§4.7). Cannot block the remote directly; backpressure is a credit meter the app replenishes.

func NewInbox added in v0.11.0

func NewInbox[T comparable](ctx *Context, highWater, maxCredits uint64, merge MergePolicy[T]) (*Inbox[T], error)

NewInbox builds an inbox bounded by highWater with the role default overflow (Conflate for inbound state) and a credit budget of maxCredits.

func NewInboxWithOverflow added in v0.11.0

func NewInboxWithOverflow[T comparable](ctx *Context, highWater uint64, overflow Overflow, maxCredits uint64, merge MergePolicy[T]) (*Inbox[T], error)

NewInboxWithOverflow builds an inbox with an explicit overflow policy.

func (*Inbox[T]) Consume added in v0.11.0

func (i *Inbox[T]) Consume(replenish uint64) (T, bool)

Consume has the app consume the coalesced window and replenish n credits (up to the budget), re-opening the remote's flow.

func (*Inbox[T]) Credits added in v0.11.0

func (i *Inbox[T]) Credits() uint64

Credits are the credits currently available to the remote.

func (*Inbox[T]) Ready added in v0.11.0

func (i *Inbox[T]) Ready() bool

Ready reports whether the transport may deliver another message (a credit is available). When false, the transport must stop reading → the remote throttles.

func (*Inbox[T]) Receive added in v0.11.0

func (i *Inbox[T]) Receive(op T) IngressOutcome

Receive has the transport deliver a received op. Consumes a credit; the caller MUST have checked Ready (a delivery without credit still applies but drives credits to zero, signalling the remote to stop).

type IngressOutcome added in v0.11.0

type IngressOutcome string

IngressOutcome is the outcome of a single ingress op.

const (
	// IngressAccepted — merged into an empty window (window depth was 0).
	IngressAccepted IngressOutcome = "Accepted"
	// IngressConflated — merged into a non-empty window (coalesced with prior).
	IngressConflated IngressOutcome = "Conflated"
	// IngressDropped — dropped by DropNewest/DropOldest overflow.
	IngressDropped IngressOutcome = "Dropped"
	// IngressBlocked — refused by Block overflow; retry after a drain.
	IngressBlocked IngressOutcome = "Blocked"
)

type InsertAt

type InsertAt string

InsertAt is the position specifier for SourceMap.Insert (mirrors lazily-kt::InsertAt). The string values are the normative wire tokens.

const (
	// InsertAtEnd appends at the end (default).
	InsertAtEnd InsertAt = "end"
	// InsertAtIndex inserts at an absolute index (use SourceMap.MoveTo after
	// insert to position).
	InsertAtIndex InsertAt = "at"
	// InsertAtBefore inserts just before the anchor.
	InsertAtBefore InsertAt = "before"
	// InsertAtAfter inserts just after the anchor.
	InsertAtAfter InsertAt = "after"
)

type IntervalCell added in v0.15.0

type IntervalCell struct {
	// contains filtered or unexported fields
}

IntervalCell is a reactive periodic interval: projects IntervalCore's fire count onto a cell (invalidates only when count changes).

func NewIntervalCell added in v0.15.0

func NewIntervalCell(ctx *Context, period uint64) *IntervalCell

NewIntervalCell creates a reactive periodic interval with the given period.

func (*IntervalCell) Count added in v0.15.0

func (iv *IntervalCell) Count() uint64

Count reports the total fires so far (reactive read).

func (*IntervalCell) CountCell added in v0.15.0

func (iv *IntervalCell) CountCell() *Source[uint64]

CountCell returns the backing count cell.

func (*IntervalCell) NextFire added in v0.15.0

func (iv *IntervalCell) NextFire() (uint64, bool)

NextFire reports the next boundary.

func (*IntervalCell) Tick added in v0.15.0

func (iv *IntervalCell) Tick(now uint64) bool

Tick advances to logical time now; returns whether a boundary fired. The count cell mirrors the core's total fire count.

type IntervalCore added in v0.15.0

type IntervalCore struct {
	// contains filtered or unexported fields
}

IntervalCore is a periodic compute core: fire boundaries at period, 2*period, … A tick counts every boundary in (frontier, now], so a jump past several boundaries counts them all.

func NewIntervalCore added in v0.15.0

func NewIntervalCore(period uint64) *IntervalCore

NewIntervalCore creates a periodic core with the given period (clamped to >=1).

func (*IntervalCore) Count added in v0.15.0

func (iv *IntervalCore) Count() uint64

Count reports the total number of fires so far.

func (*IntervalCore) NextFire added in v0.15.0

func (iv *IntervalCore) NextFire() (uint64, bool)

NextFire reports the next boundary (always present for an interval).

func (*IntervalCore) Tick added in v0.15.0

func (iv *IntervalCore) Tick(now uint64) bool

Tick advances to now; returns whether a boundary fired.

type IpcMessage

type IpcMessage interface {
	MarshalJSON() ([]byte, error)
	// EncodeJSON returns the UTF-8 JSON bytes of the tagged wire form.
	EncodeJSON() ([]byte, error)
	// contains filtered or unexported methods
}

IpcMessage is a length-prefixed, tagged Snapshot, Delta, CrdtSync, or one of the reliable-sync reverse-channel control frames (ResyncRequest / OutboxAck). The CrdtSync variant carries multi-writer plane traffic alongside the single-producer mirror. Externally tagged: {"Snapshot": ...} / {"Delta": ...} / {"CrdtSync": ...} / {"ResyncRequest": ...} / {"OutboxAck": ...}.

func DecodeIpcMessageJSON

func DecodeIpcMessageJSON(data []byte) (IpcMessage, error)

DecodeIpcMessageJSON decodes UTF-8 JSON bytes into an IpcMessage.

func IpcMessageFromWire

func IpcMessageFromWire(data []byte) (IpcMessage, error)

IpcMessageFromWire decodes an externally-tagged IpcMessage from JSON bytes.

func SpillMessage added in v0.4.0

func SpillMessage(message IpcMessage, backend BlobBackend, threshold int) (IpcMessage, int)

SpillMessage spills large payloads across an IpcMessage's value/state sites — Snapshot node states, Delta CellSet/SlotValue payloads + NodeAdd states, and CrdtSync op states — returning a message whose oversized payloads are replaced by SharedBlob descriptors, plus the total bytes spilled. The message stays small on the wire. Sites already carrying a descriptor are left untouched. The input message is not mutated; the returned message shares unspilled substructure.

type IpcMessageCrdtSync

type IpcMessageCrdtSync struct{ Value CrdtSync }

IpcMessageCrdtSync wraps a CrdtSync.

func (IpcMessageCrdtSync) EncodeJSON

func (m IpcMessageCrdtSync) EncodeJSON() ([]byte, error)

func (IpcMessageCrdtSync) MarshalJSON

func (m IpcMessageCrdtSync) MarshalJSON() ([]byte, error)

type IpcMessageDelta

type IpcMessageDelta struct{ Value Delta }

IpcMessageDelta wraps a Delta.

func (IpcMessageDelta) EncodeJSON

func (m IpcMessageDelta) EncodeJSON() ([]byte, error)

func (IpcMessageDelta) MarshalJSON

func (m IpcMessageDelta) MarshalJSON() ([]byte, error)

type IpcMessageOutboxAck added in v0.8.0

type IpcMessageOutboxAck struct{ Value OutboxAck }

IpcMessageOutboxAck wraps an OutboxAck control frame (#lzsync).

func (IpcMessageOutboxAck) EncodeJSON added in v0.8.0

func (m IpcMessageOutboxAck) EncodeJSON() ([]byte, error)

func (IpcMessageOutboxAck) MarshalJSON added in v0.8.0

func (m IpcMessageOutboxAck) MarshalJSON() ([]byte, error)

type IpcMessageResyncRequest added in v0.8.0

type IpcMessageResyncRequest struct{ Value ResyncRequest }

IpcMessageResyncRequest wraps a ResyncRequest control frame (#lzsync).

func (IpcMessageResyncRequest) EncodeJSON added in v0.8.0

func (m IpcMessageResyncRequest) EncodeJSON() ([]byte, error)

func (IpcMessageResyncRequest) MarshalJSON added in v0.8.0

func (m IpcMessageResyncRequest) MarshalJSON() ([]byte, error)

type IpcMessageSnapshot

type IpcMessageSnapshot struct{ Value Snapshot }

IpcMessageSnapshot wraps a Snapshot.

func (IpcMessageSnapshot) EncodeJSON

func (m IpcMessageSnapshot) EncodeJSON() ([]byte, error)

func (IpcMessageSnapshot) MarshalJSON

func (m IpcMessageSnapshot) MarshalJSON() ([]byte, error)

type IpcSink added in v0.8.0

type IpcSink interface {
	Send(msg IpcMessage) error
}

IpcSink is the outbound transport seam. Send returns a non-nil error when the frame could not be handed to the transport; the driver treats that as a stall (retain-and-retry), not a fatal error.

type IpcSource added in v0.8.0

type IpcSource interface {
	Recv() (msg IpcMessage, present bool, err error)
}

IpcSource is the inbound transport seam. Recv returns (msg, true, nil) for a frame, (_, false, nil) when the inbound queue is momentarily empty, and a non-nil error on a read failure (which the driver surfaces as DriverError).

type IpcValue

type IpcValue interface {
	MarshalJSON() ([]byte, error)
	// contains filtered or unexported methods
}

IpcValue is a DeltaOp / CrdtOp cell payload. Externally tagged: {"Inline": [u8]} or {"SharedBlob": ShmBlobRef}.

func IpcValueOf

func IpcValueOf(value any) (IpcValue, error)

IpcValueOf normalizes an IpcValue, ShmBlobRef, []byte, or []int into an IpcValue (mirrors `IpcValue.of` in the sibling bindings).

func SpillValue added in v0.4.0

func SpillValue(value IpcValue, backend BlobBackend, threshold int) (IpcValue, int)

SpillValue spills an IpcValue to backend when it is Inline and >= threshold bytes: it writes the bytes and returns a SharedBlob descriptor value plus the number of bytes spilled. Otherwise it returns the value unchanged and 0. Payloads below the threshold stay inline — cheaper than a backend round-trip for tiny values. A backend write failure leaves the value inline (returns 0).

type IpcValueInline

type IpcValueInline struct {
	Bytes []byte
}

IpcValueInline is an inline byte-array payload ({"Inline": [u8]}).

func (IpcValueInline) MarshalJSON

func (v IpcValueInline) MarshalJSON() ([]byte, error)

type IpcValueSharedBlob

type IpcValueSharedBlob struct {
	Blob ShmBlobRef
}

IpcValueSharedBlob is a payload descriptor into shared memory ({"SharedBlob": ShmBlobRef}).

func (IpcValueSharedBlob) MarshalJSON

func (v IpcValueSharedBlob) MarshalJSON() ([]byte, error)

type KeyValue

type KeyValue[K comparable, V comparable] struct {
	Key   K
	Value V
}

KeyValue is an ordered key/value pair, the input unit for ReconcileDiff (mirrors Dart's MapEntry<K, V>).

type KeyedRelay added in v0.11.0

type KeyedRelay[K comparable, T comparable] struct {
	// contains filtered or unexported fields
}

KeyedRelay — Case 18, keyed sharding. N independent relays keyed by K; an op routes to its key's shard. Merging across shards requires a commutative merge. The converged per-key state equals a single relay per key.

func NewKeyedRelay added in v0.11.0

func NewKeyedRelay[K comparable, T comparable](ctx *Context, highWater uint64, overflow Overflow, merge MergePolicy[T]) (*KeyedRelay[K, T], error)

NewKeyedRelay creates a keyed relay. Returns ErrConflateNotBounding if overflow is Conflate on a non-conflating policy (same guard as RelayCell).

func (*KeyedRelay[K, T]) Drain added in v0.11.0

func (k *KeyedRelay[K, T]) Drain(key K) (T, bool)

Drain drains a key's coalesced window (false when the key has no shard/window).

func (*KeyedRelay[K, T]) Ingress added in v0.11.0

func (k *KeyedRelay[K, T]) Ingress(key K, op T) IngressOutcome

Ingress routes op to key's shard, creating the shard on first use.

func (*KeyedRelay[K, T]) Keys added in v0.11.0

func (k *KeyedRelay[K, T]) Keys() []K

Keys returns the shard keys in first-use order.

type LazilyFfiBytes

type LazilyFfiBytes struct {
	// Bytes is the owned byte buffer.
	Bytes []byte
}

LazilyFfiBytes is an owned byte buffer crossing the FFI boundary. On the real C ABI this is `{ uint8_t* ptr; size_t len; }` with explicit allocation ownership: the caller owns input bytes; the host owns output buffers until the paired free function (`lazily_ffi_bytes_free`) is called. This pure-Go mirror carries the bytes inline; the ownership contract is realized in ffi_cgo.go, which marshals to/from C-allocated buffers.

func LazilyFfiBytesFromOwned

func LazilyFfiBytesFromOwned(b []byte) LazilyFfiBytes

LazilyFfiBytesFromOwned wraps an already-owned buffer without copying.

func NewLazilyFfiBytes

func NewLazilyFfiBytes(b []byte) LazilyFfiBytes

NewLazilyFfiBytes copies b into a newly-owned LazilyFfiBytes buffer.

func (LazilyFfiBytes) AsJSON

func (b LazilyFfiBytes) AsJSON() string

AsJSON decodes the buffer as UTF-8 JSON text.

func (LazilyFfiBytes) Len

func (b LazilyFfiBytes) Len() int

Len returns the buffer length in bytes.

type LazilyFfiChannel

type LazilyFfiChannel struct {
	// contains filtered or unexported fields
}

LazilyFfiChannel is an in-process FFI message channel that mirrors the C-ABI `lazily_ffi_channel_send_json` / `lazily_ffi_channel_recv_json` pair. Each accepted frame is decoded as IpcMessage and re-encoded to canonical JSON bytes on the way in, so a round-trip exercises the same "decode + re-encode canonical JSON" contract regardless of the sender's codec.

It is a local ownership/ABI adapter, not a second graph-state model. Unlike the Dart original, this channel is safe for concurrent use (the C-ABI handle may be shared across goroutines).

func NewLazilyFfiChannel

func NewLazilyFfiChannel() *LazilyFfiChannel

NewLazilyFfiChannel creates an empty channel. Mirrors `lazily_ffi_channel_new`.

func (*LazilyFfiChannel) IsEmpty

func (c *LazilyFfiChannel) IsEmpty() bool

IsEmpty reports whether the channel has no pending frame.

func (*LazilyFfiChannel) Len

func (c *LazilyFfiChannel) Len() int

Len returns the number of queued frames. Mirrors `lazily_ffi_channel_len`.

func (*LazilyFfiChannel) Recv

Recv dequeues and decodes the next message. Returns LazilyFfiStatusEmpty (and a nil message) if the queue is empty. Mirrors `lazily_ffi_channel_recv_json`.

func (*LazilyFfiChannel) RecvJSONFrame

func (c *LazilyFfiChannel) RecvJSONFrame() (LazilyFfiBytes, LazilyFfiStatus)

RecvJSONFrame dequeues the next canonical frame bytes. Returns LazilyFfiStatusEmpty when the queue is empty. Mirrors `lazily_ffi_channel_recv_json`.

func (*LazilyFfiChannel) Send

func (c *LazilyFfiChannel) Send(message IpcMessage) LazilyFfiStatus

Send encodes message to canonical JSON and queues it. Returns LazilyFfiStatusOk on success or LazilyFfiStatusEncodeFailed if encoding fails. Mirrors `lazily_ffi_channel_send_json` with an already-typed message.

func (*LazilyFfiChannel) SendJSONFrame

func (c *LazilyFfiChannel) SendJSONFrame(frame LazilyFfiBytes) (status LazilyFfiStatus)

SendJSONFrame accepts raw frame bytes, decoding and re-encoding to canonical form on the way in so the recv side always sees canonical bytes. Mirrors `lazily_ffi_channel_send_json`.

type LazilyFfiClassification

type LazilyFfiClassification struct {
	Status LazilyFfiStatus
	Kind   LazilyFfiMessageKind
}

LazilyFfiClassification is the result of a frame classification: the status plus (on success) the decoded message kind.

func LazilyFfiKindJSON

func LazilyFfiKindJSON(frame LazilyFfiBytes) (result LazilyFfiClassification)

LazilyFfiKindJSON classifies a frame: decode it and return the variant kind. On a decode failure the status is LazilyFfiStatusInvalidMessage and the kind is LazilyFfiMessageKindUnknown. Mirrors `lazily_ffi_ipc_message_kind_json`.

func (LazilyFfiClassification) IsOk

func (c LazilyFfiClassification) IsOk() bool

IsOk reports whether classification succeeded.

type LazilyFfiCloneResult

type LazilyFfiCloneResult struct {
	Status LazilyFfiStatus
	// Output is the re-encoded canonical JSON bytes (nil unless Status is ok).
	Output *LazilyFfiBytes
}

LazilyFfiCloneResult is the result of cloning a frame through the channel: decode as IpcMessage, then re-encode canonical JSON bytes. Output is set iff Status is ok.

func LazilyFfiCloneJSON

func LazilyFfiCloneJSON(frame LazilyFfiBytes) (result LazilyFfiCloneResult)

LazilyFfiCloneJSON clones a frame: decode the bytes as IpcMessage, then re-encode canonical JSON bytes. Mirrors `lazily_ffi_ipc_message_clone_json`. This is the contract pin: the channel decodes each accepted frame and re-encodes canonical JSON bytes.

type LazilyFfiMessageKind

type LazilyFfiMessageKind int

LazilyFfiMessageKind is the IPC message kind discriminant, derived by decoding a frame as IpcMessage and matching on the variant. CrdtSync = 3 is normative.

const (
	// LazilyFfiMessageKindUnknown is the unknown / unset zero value.
	LazilyFfiMessageKindUnknown LazilyFfiMessageKind = 0
	// LazilyFfiMessageKindSnapshot classifies an IpcMessageSnapshot.
	LazilyFfiMessageKindSnapshot LazilyFfiMessageKind = 1
	// LazilyFfiMessageKindDelta classifies an IpcMessageDelta.
	LazilyFfiMessageKindDelta LazilyFfiMessageKind = 2
	// LazilyFfiMessageKindCrdtSync classifies an IpcMessageCrdtSync (the
	// multi-writer CRDT plane).
	LazilyFfiMessageKindCrdtSync LazilyFfiMessageKind = 3
	// LazilyFfiMessageKindResyncRequest classifies an IpcMessageResyncRequest
	// (the reliable-sync reverse-channel gap-recovery frame, #lzsync).
	LazilyFfiMessageKindResyncRequest LazilyFfiMessageKind = 4
	// LazilyFfiMessageKindOutboxAck classifies an IpcMessageOutboxAck (the
	// reliable-sync reverse-channel ack/resume-cursor frame, #lzsync).
	LazilyFfiMessageKindOutboxAck LazilyFfiMessageKind = 5
)

func LazilyFfiMessageKindFromCode

func LazilyFfiMessageKindFromCode(code int) LazilyFfiMessageKind

LazilyFfiMessageKindFromCode decodes the integer discriminant, returning LazilyFfiMessageKindUnknown for an out-of-range value (matches the C enum's zero-default).

type LazilyFfiStatus

type LazilyFfiStatus int

LazilyFfiStatus is the FFI operation status code. Errors return one of the non-zero codes; recovered panics surface as LazilyFfiStatusPanic before crossing the C ABI. The integer values are the normative C-ABI wire discriminants (0..5).

const (
	// LazilyFfiStatusOk is success.
	LazilyFfiStatusOk LazilyFfiStatus = 0
	// LazilyFfiStatusEmpty means no message was available (empty channel read).
	LazilyFfiStatusEmpty LazilyFfiStatus = 1
	// LazilyFfiStatusNullPointer means a required pointer argument was null.
	LazilyFfiStatusNullPointer LazilyFfiStatus = 2
	// LazilyFfiStatusInvalidMessage means the frame did not decode as a valid
	// IpcMessage.
	LazilyFfiStatusInvalidMessage LazilyFfiStatus = 3
	// LazilyFfiStatusEncodeFailed means the frame decoded but could not be
	// re-encoded as canonical bytes.
	LazilyFfiStatusEncodeFailed LazilyFfiStatus = 4
	// LazilyFfiStatusPanic means a panic was caught before crossing the C ABI.
	LazilyFfiStatusPanic LazilyFfiStatus = 5
)

func LazilyFfiStatusFromCode

func LazilyFfiStatusFromCode(code int) (LazilyFfiStatus, bool)

LazilyFfiStatusFromCode decodes the integer discriminant, returning ok=false for an unknown value (mirrors the Dart/Rust enum's strictness on out-of-range discriminants).

func LazilyFfiValidateJSON

func LazilyFfiValidateJSON(frame LazilyFfiBytes) (status LazilyFfiStatus)

LazilyFfiValidateJSON validates a frame: decode the bytes as IpcMessage and confirm the result is well-formed. Returns LazilyFfiStatusOk on success. Mirrors `lazily_ffi_ipc_message_validate_json`.

func (LazilyFfiStatus) IsOk

func (s LazilyFfiStatus) IsOk() bool

IsOk reports whether this status represents success.

type Lcg added in v0.15.0

type Lcg struct {
	// contains filtered or unexported fields
}

Lcg is a small deterministic SplitMix64-style generator — no external dependency, reproducible for the distribution property test.

func NewLcg added in v0.15.0

func NewLcg(seed uint64) *Lcg

NewLcg builds a deterministic generator seeded with `seed`.

func (*Lcg) NextFloat64 added in v0.15.0

func (l *Lcg) NextFloat64() float64

NextFloat64 returns the next draw in [0, 1). Go unsigned arithmetic wraps, so this matches rs `wrapping_add`/`wrapping_mul` bit-for-bit.

type LeaderCell added in v0.15.0

type LeaderCell[P comparable] struct {
	// contains filtered or unexported fields
}

LeaderCell is reactive leadership over a lease from node me's perspective.

func NewLeaderCell added in v0.15.0

func NewLeaderCell[P comparable](ctx *Context, me P) *LeaderCell[P]

NewLeaderCell constructs reactive leadership for node me.

func (*LeaderCell[P]) Campaign added in v0.15.0

func (c *LeaderCell[P]) Campaign(now, ttl uint64) LeaderRole

Campaign tries to acquire leadership for me.

func (*LeaderCell[P]) Contend added in v0.15.0

func (c *LeaderCell[P]) Contend(peer P, now, ttl uint64) LeaderRole

Contend simulates another peer contending (for tests / co-hosted nodes).

func (*LeaderCell[P]) CurrentLeader added in v0.15.0

func (c *LeaderCell[P]) CurrentLeader(now uint64) (P, bool)

CurrentLeader returns the live leader at now.

func (*LeaderCell[P]) CurrentLeaderCell added in v0.15.0

func (c *LeaderCell[P]) CurrentLeaderCell() *Source[Opt[P]]

CurrentLeaderCell exposes the reactive current-leader projection.

func (*LeaderCell[P]) Role added in v0.15.0

func (c *LeaderCell[P]) Role(now uint64) LeaderRole

Role derives the local node's role at now.

func (*LeaderCell[P]) Tick added in v0.15.0

func (c *LeaderCell[P]) Tick(now uint64) LeaderRole

Tick advances the logical clock, expiring the lease if due.

type LeaderRole added in v0.15.0

type LeaderRole int

LeaderRole is the local node's role, derived from lease ownership.

const (
	// Leader — the local node holds the lease.
	Leader LeaderRole = iota
	// Follower — another peer holds the lease.
	Follower
	// Candidate — the lease is free.
	Candidate
)

func (LeaderRole) String added in v0.15.0

func (r LeaderRole) String() string

String renders the role name (matches fixture strings).

type LeafKind added in v0.2.0

type LeafKind string

LeafKind classifies a leaf's exact source span. Every rendered byte belongs to a leaf; unknown/invalid spans are Raw/Error so nothing is discarded. Serialized as the PascalCase wire string.

const (
	// LeafKindToken is a syntax delimiter or marker.
	LeafKindToken LeafKind = "Token"
	// LeafKindTrivia is whitespace, blank lines, indentation, comments.
	LeafKindTrivia LeafKind = "Trivia"
	// LeafKindRaw is valid text the adapter deliberately keeps opaque.
	LeafKindRaw LeafKind = "Raw"
	// LeafKindError is invalid/ambiguous text that must still round-trip.
	LeafKindError LeafKind = "Error"
)

type LeaseCell added in v0.15.0

type LeaseCell[P comparable] struct {
	// contains filtered or unexported fields
}

LeaseCell is a reactive lease: projects the holder onto a Cell (invalidates on holder change).

func NewLeaseCell added in v0.15.0

func NewLeaseCell[P comparable](ctx *Context) *LeaseCell[P]

NewLeaseCell constructs a reactive lease.

func (*LeaseCell[P]) Acquire added in v0.15.0

func (c *LeaseCell[P]) Acquire(peer P, now, ttl uint64) Opt[uint64]

Acquire grants the lease, returning the fencing token (present=false if denied).

func (*LeaseCell[P]) Fence added in v0.15.0

func (c *LeaseCell[P]) Fence() uint64

Fence returns the current fencing token.

func (*LeaseCell[P]) Holder added in v0.15.0

func (c *LeaseCell[P]) Holder(now uint64) (P, bool)

Holder returns the live holder at now.

func (*LeaseCell[P]) HolderCell added in v0.15.0

func (c *LeaseCell[P]) HolderCell() *Source[Opt[P]]

HolderCell exposes the reactive holder projection.

func (*LeaseCell[P]) IsHeld added in v0.15.0

func (c *LeaseCell[P]) IsHeld(now uint64) bool

IsHeld reports whether the lease is currently held at now.

func (*LeaseCell[P]) Release added in v0.15.0

func (c *LeaseCell[P]) Release(peer P, now uint64)

Release drops the grant if peer holds it.

func (*LeaseCell[P]) Renew added in v0.15.0

func (c *LeaseCell[P]) Renew(peer P, now, ttl uint64) bool

Renew extends the expiry if peer is the live holder.

func (*LeaseCell[P]) Tick added in v0.15.0

func (c *LeaseCell[P]) Tick(now uint64) bool

Tick expires the grant when now >= expiry; returns the expiry edge.

type LeaseCore added in v0.15.0

type LeaseCore[P comparable] struct {
	// contains filtered or unexported fields
}

LeaseCore is a single-writer lease authority with a monotone fencing token.

func NewLeaseCore added in v0.15.0

func NewLeaseCore[P comparable]() *LeaseCore[P]

NewLeaseCore returns an empty lease core.

func (*LeaseCore[P]) Acquire added in v0.15.0

func (c *LeaseCore[P]) Acquire(peer P, now, ttl uint64) (uint64, bool)

Acquire grants if free/expired (new grant increments fence); renew by the holder keeps the same fence; held by another -> (0, false). The bool reports whether a token was granted.

func (*LeaseCore[P]) Fence added in v0.15.0

func (c *LeaseCore[P]) Fence() uint64

Fence returns the current fencing token.

func (*LeaseCore[P]) Holder added in v0.15.0

func (c *LeaseCore[P]) Holder(now uint64) (P, bool)

Holder returns the live holder at now.

func (*LeaseCore[P]) IsHeld added in v0.15.0

func (c *LeaseCore[P]) IsHeld(now uint64) bool

IsHeld reports whether the lease is currently held (and not expired at now).

func (*LeaseCore[P]) Release added in v0.15.0

func (c *LeaseCore[P]) Release(peer P)

Release drops the grant if peer holds it.

func (*LeaseCore[P]) Renew added in v0.15.0

func (c *LeaseCore[P]) Renew(peer P, now, ttl uint64) bool

Renew extends the expiry if peer is the live holder.

func (*LeaseCore[P]) Tick added in v0.15.0

func (c *LeaseCore[P]) Tick(now uint64) bool

Tick expires the grant when now >= expiry; returns the expiry edge.

type LockCell added in v0.15.0

type LockCell[P comparable] struct {
	// contains filtered or unexported fields
}

LockCell is a reactive distributed mutex over a lease + fencing token.

func NewLockCell added in v0.15.0

func NewLockCell[P comparable](ctx *Context) *LockCell[P]

NewLockCell constructs a reactive distributed lock.

func (*LockCell[P]) Acquire added in v0.15.0

func (c *LockCell[P]) Acquire(peer P, now, ttl uint64) Opt[uint64]

Acquire acquires the lock, returning a fencing token (present=false if held).

func (*LockCell[P]) Fence added in v0.15.0

func (c *LockCell[P]) Fence() uint64

Fence returns the current fencing token.

func (*LockCell[P]) IsLocked added in v0.15.0

func (c *LockCell[P]) IsLocked(now uint64) bool

IsLocked reports whether the lock is held at now.

func (*LockCell[P]) IsLockedCell added in v0.15.0

func (c *LockCell[P]) IsLockedCell() *Source[bool]

IsLockedCell exposes the reactive is_locked projection.

func (*LockCell[P]) Release added in v0.15.0

func (c *LockCell[P]) Release(peer P, now uint64)

Release drops the lock if peer holds it.

func (*LockCell[P]) Tick added in v0.15.0

func (c *LockCell[P]) Tick(now uint64) bool

Tick expires the lock when now >= expiry; returns the expiry edge.

func (*LockCell[P]) Validate added in v0.15.0

func (c *LockCell[P]) Validate(fence uint64) bool

Validate reports whether fence is the current (non-stale) fencing token.

type LosslessTreeCrdt added in v0.2.0

type LosslessTreeCrdt struct {
	// contains filtered or unexported fields
}

LosslessTreeCrdt is a lossless concrete-syntax tree CRDT (M1 core).

Not safe for concurrent use; share across goroutines via a single owner goroutine or wrap in a lock.

func NewLosslessTreeCrdt added in v0.2.0

func NewLosslessTreeCrdt(peer PeerId) *LosslessTreeCrdt

NewLosslessTreeCrdt creates an empty replica for the given peer id, seeded with just the document root element.

func (*LosslessTreeCrdt) ApplyUpdate added in v0.2.0

func (t *LosslessTreeCrdt) ApplyUpdate(update TreeUpdate)

ApplyUpdate applies a batch of remote ops. Idempotent (already-held ops skipped) and order-tolerant (an op whose target/parent has not arrived is buffered and retried). Advances the Lamport counter past every observed op.

func (*LosslessTreeCrdt) Children added in v0.2.0

func (t *LosslessTreeCrdt) Children(parent OpId) []OpId

Children returns the live children of parent in rendered order.

func (*LosslessTreeCrdt) CreateNode added in v0.2.0

func (t *LosslessTreeCrdt) CreateNode(parent OpId, after *OpId, seed TreeNodeSeed) OpId

CreateNode creates a node under parent, positioned after after (front when nil), and returns the new node's id.

func (*LosslessTreeCrdt) Diff added in v0.2.0

Diff returns the ops this replica holds that their frontier lacks, ordered by dotted id.

func (*LosslessTreeCrdt) EditLeaf added in v0.2.0

func (t *LosslessTreeCrdt) EditLeaf(node OpId, atByte, deleteBytes int, insert string)

EditLeaf edits a leaf's text: delete deleteBytes and insert insert at UTF-8 byte offset atByte (leaf-local). Offsets must land on rune boundaries.

func (*LosslessTreeCrdt) ElementKind added in v0.2.0

func (t *LosslessTreeCrdt) ElementKind(node OpId) string

ElementKind returns the kind of an element node, or "" if absent or a leaf.

func (*LosslessTreeCrdt) Fork added in v0.2.0

func (t *LosslessTreeCrdt) Fork(peer PeerId) *LosslessTreeCrdt

Fork deep-copies this replica's full state under a new owning peer (new identity).

func (*LosslessTreeCrdt) Frontier added in v0.2.0

func (t *LosslessTreeCrdt) Frontier() *TreeVersionFrontier

Frontier returns this replica's dotted version frontier (what to advertise to a partner).

func (*LosslessTreeCrdt) LeafKind added in v0.2.0

func (t *LosslessTreeCrdt) LeafKind(node OpId) LeafKind

LeafKind returns the kind of a leaf node, or "" if absent or an element.

func (*LosslessTreeCrdt) LeafText added in v0.2.0

func (t *LosslessTreeCrdt) LeafText(node OpId) string

LeafText returns a leaf's current text. Panics if node is absent or an element.

func (*LosslessTreeCrdt) LiveNodeCount added in v0.2.0

func (t *LosslessTreeCrdt) LiveNodeCount() int

LiveNodeCount returns the live nodes excluding the root — grows by one on split, restored on merge.

func (*LosslessTreeCrdt) MergeAdjacentLeaves added in v0.2.0

func (t *LosslessTreeCrdt) MergeAdjacentLeaves(left, right OpId)

MergeAdjacentLeaves merges right into left when they are adjacent live leaf siblings.

func (*LosslessTreeCrdt) Render added in v0.2.0

func (t *LosslessTreeCrdt) Render() string

Render returns the whole document by concatenating live-leaf text in tree order (depth-first over live children).

func (*LosslessTreeCrdt) ReorderChild added in v0.2.0

func (t *LosslessTreeCrdt) ReorderChild(node OpId, after *OpId)

ReorderChild reorders node within its parent to just after after (front when nil).

func (*LosslessTreeCrdt) SplitLeaf added in v0.2.0

func (t *LosslessTreeCrdt) SplitLeaf(node OpId, atByte int) OpId

SplitLeaf splits a leaf at UTF-8 byte offset atByte into two adjacent leaves of the same kind (head keeps node, tail is a fresh node returned here).

func (*LosslessTreeCrdt) TombstoneNode added in v0.2.0

func (t *LosslessTreeCrdt) TombstoneNode(node OpId)

TombstoneNode tombstones a node (its subtree renders away once the ancestor is gone).

type LwwRegister

type LwwRegister[V any] struct {
	Value V
	Stamp HlcStamp
}

LwwRegister is a last-writer-wins register. Ties (equal stamps) are broken in favor of the incumbent (Set requires a strictly greater stamp).

func NewLwwRegister

func NewLwwRegister[V any](value V, stamp HlcStamp) *LwwRegister[V]

NewLwwRegister creates a register holding value stamped at stamp.

func (*LwwRegister[V]) Copy

func (r *LwwRegister[V]) Copy() *LwwRegister[V]

Copy returns a shallow copy of the register.

func (*LwwRegister[V]) MergeFrom

func (r *LwwRegister[V]) MergeFrom(other *LwwRegister[V]) bool

MergeFrom merges another register into this one. Returns whether the value changed.

func (*LwwRegister[V]) Set

func (r *LwwRegister[V]) Set(newValue V, newStamp HlcStamp) bool

Set assigns newValue if newStamp is strictly greater than the current stamp. Returns whether the value was updated.

type ManifestEntry added in v0.11.0

type ManifestEntry struct {
	ID    uint64
	Bytes uint64
}

ManifestEntry is a bounded per-page metadata record (page id, bytes).

type ManualClock added in v0.15.0

type ManualClock struct {
	// contains filtered or unexported fields
}

ManualClock is a monotone logical clock a manual runtime (game loop, test) can own to drive sources. Advance clamps backwards moves so now is always non-decreasing.

func NewManualClock added in v0.15.0

func NewManualClock() *ManualClock

NewManualClock creates a clock at logical time 0.

func (*ManualClock) Advance added in v0.15.0

func (c *ManualClock) Advance(now uint64) uint64

Advance moves to now (monotone: a smaller value is clamped to the current time). Returns the effective now a source should be ticked with.

func (*ManualClock) Now added in v0.15.0

func (c *ManualClock) Now() uint64

Now reports the current logical time.

type Match

type Match struct {
	Kind       string // "same" | "edited" | "inserted"
	OldIndex   int    // -1 for inserted
	Similarity float64
}

Match is the kind of match for a new block against the old set.

func MatchEdited

func MatchEdited(oldIndex int, similarity float64) Match

MatchEdited constructs an Edited match.

func MatchInserted

func MatchInserted() Match

MatchInserted constructs an Inserted match.

func MatchSame

func MatchSame(oldIndex int) Match

MatchSame constructs a Same match.

func (Match) String

func (m Match) String() string

type MembershipCell added in v0.15.0

type MembershipCell[P cmp.Ordered] struct {
	// contains filtered or unexported fields
}

MembershipCell is the reactive membership view: it drives a MembershipCore and projects the alive set onto a version Cell so PeerSet invalidates only on a set change (mirrors the rs Cell<BTreeSet<P>> PartialEq guard).

func NewMembershipCell added in v0.15.0

func NewMembershipCell[P cmp.Ordered](ctx *Context, config MembershipConfig) *MembershipCell[P]

NewMembershipCell builds a reactive membership cell bound to ctx.

func (*MembershipCell[P]) Heartbeat added in v0.15.0

func (c *MembershipCell[P]) Heartbeat(peer P, now uint64) []PeerChangeEvent[P]

Heartbeat records a heartbeat, then refreshes the projection.

func (*MembershipCell[P]) Join added in v0.15.0

func (c *MembershipCell[P]) Join(peer P, now uint64) []PeerChangeEvent[P]

Join adds/refreshes a peer, then refreshes the projection.

func (*MembershipCell[P]) Leave added in v0.15.0

func (c *MembershipCell[P]) Leave(peer P, now uint64) []PeerChangeEvent[P]

Leave records a graceful departure, then refreshes the projection.

func (*MembershipCell[P]) PeerSet added in v0.15.0

func (c *MembershipCell[P]) PeerSet() []P

PeerSet returns a fresh snapshot of the alive peer set (sorted). Reading it inside a computation subscribes the reader to the alive-set version, so it invalidates only when the set changes.

func (*MembershipCell[P]) State added in v0.15.0

func (c *MembershipCell[P]) State(peer P) (PeerState, bool)

State returns the state of a known peer.

func (*MembershipCell[P]) Tick added in v0.15.0

func (c *MembershipCell[P]) Tick(now uint64) []PeerChangeEvent[P]

Tick advances the clock, then refreshes the projection.

func (*MembershipCell[P]) VersionCell added in v0.15.0

func (c *MembershipCell[P]) VersionCell() *Source[uint64]

VersionCell exposes the backing version Cell for direct subscription.

type MembershipConfig added in v0.15.0

type MembershipConfig struct {
	// PhiThreshold — phi > PhiThreshold marks a peer Suspect.
	PhiThreshold float64
	// SuspectTimeout — ticks a peer stays Suspect before being declared Dead.
	SuspectTimeout uint64
	// MaxSamples — sliding window size for heartbeat inter-arrival samples.
	MaxSamples int
	// MinStd — floor on the sample standard deviation (avoids div-by-zero).
	MinStd float64
}

MembershipConfig holds the failure-detector + SWIM tunables.

func DefaultMembershipConfig added in v0.15.0

func DefaultMembershipConfig() MembershipConfig

DefaultMembershipConfig returns the standard tunables.

type MembershipCore added in v0.15.0

type MembershipCore[P cmp.Ordered] struct {
	// contains filtered or unexported fields
}

MembershipCore is the pure SWIM state machine over a keyed peer map, driven by heartbeats and a logical clock. It emits PeerChangeEvent diffs.

func NewMembershipCore added in v0.15.0

func NewMembershipCore[P cmp.Ordered](config MembershipConfig) *MembershipCore[P]

NewMembershipCore builds an empty core with the given config.

func (*MembershipCore[P]) AliveSet added in v0.15.0

func (m *MembershipCore[P]) AliveSet() []P

AliveSet returns the current alive peer set as a sorted slice (the reactive PeerSet).

func (*MembershipCore[P]) Heartbeat added in v0.15.0

func (m *MembershipCore[P]) Heartbeat(peer P, now uint64) []PeerChangeEvent[P]

Heartbeat records a heartbeat. An unknown peer is a join; a Suspect/Dead peer returns to Alive (SWIM refutation).

func (*MembershipCore[P]) Join added in v0.15.0

func (m *MembershipCore[P]) Join(peer P, now uint64) []PeerChangeEvent[P]

Join adds a peer (or refreshes a re-joining one): Alive with a fresh detector.

func (*MembershipCore[P]) Leave added in v0.15.0

func (m *MembershipCore[P]) Leave(peer P, _ uint64) []PeerChangeEvent[P]

Leave records a graceful departure.

func (*MembershipCore[P]) State added in v0.15.0

func (m *MembershipCore[P]) State(peer P) (PeerState, bool)

State returns the state of a known peer.

func (*MembershipCore[P]) Tick added in v0.15.0

func (m *MembershipCore[P]) Tick(now uint64) []PeerChangeEvent[P]

Tick advances the clock: escalate Alive -> Suspect (phi crossed) and Suspect -> Dead (timeout elapsed).

type MergePolicy added in v0.10.0

type MergePolicy[T any] struct {
	Name        string
	Merge       func(old, op T) T
	Commutative bool
	Idempotent  bool
	Conflates   bool
}

MergePolicy is an associative merge ⊕ with its transport-selected property flags. Associativity ((a⊕b)⊕c == a⊕(b⊕c)) is a law, verified by the law-tests, not a flag. Commutative is the reordering tax; Idempotent the durability tax; Conflates gates the Conflate overflow (Phase 2 — only RawFifo cannot bound).

func KeepLatest added in v0.10.0

func KeepLatest[T any]() MergePolicy[T]

KeepLatest is the keep-latest band (old ⊕ op = op) — the policy behind a plain Cell. Associative and idempotent, not commutative.

func Max added in v0.10.0

func Max[T Number]() MergePolicy[T]

Max is the max semilattice (max(old, op)). Associative, commutative, idempotent.

func RawFifo added in v0.10.0

func RawFifo[E any]() MergePolicy[[]E]

RawFifo is raw FIFO append over []E (old ++ op). Order + multiplicity are meaning — associative only; cannot conflate.

func SetUnion added in v0.10.0

func SetUnion[E comparable]() MergePolicy[map[E]struct{}]

SetUnion is the grow-only set-union semilattice over map[E]struct{}.

func Sum added in v0.10.0

func Sum[T Number]() MergePolicy[T]

Sum is the additive commutative monoid (old + op). Not idempotent.

type MvRegister

type MvRegister[V any] struct {
	// contains filtered or unexported fields
}

MvRegister is a multi-value register. Concurrent writes surface as a set of values; a write that observes all prior values collapses back to a singleton.

stamps and values are kept index-parallel: entry i is the value written under stamp i. HLC stamps are unique per event, so no de-duplication of stamps is required on write.

func NewMvRegister

func NewMvRegister[V any]() *MvRegister[V]

NewMvRegister creates an empty multi-value register.

func (*MvRegister[V]) Copy

func (r *MvRegister[V]) Copy() *MvRegister[V]

Copy returns a deep copy of the register.

func (*MvRegister[V]) Merge

func (r *MvRegister[V]) Merge(other *MvRegister[V])

Merge folds another MV register into this one (state-based, idempotent).

func (*MvRegister[V]) ObservedStamps

func (r *MvRegister[V]) ObservedStamps() map[HlcStamp]struct{}

ObservedStamps returns a copy of the stamps observed by this register.

func (*MvRegister[V]) Values

func (r *MvRegister[V]) Values() []V

Values returns the current visible values (concurrent writes = multiple, causal write = one). The returned slice is a copy.

func (*MvRegister[V]) Write

func (r *MvRegister[V]) Write(value V, stamp HlcStamp, observedStamps map[HlcStamp]struct{})

Write adds value under stamp. If observedStamps covers every current stamp, the register collapses to the singleton being written. A nil observedStamps means the write observed nothing prior.

type NodeEntry

type NodeEntry struct {
	Value any
	State string
}

NodeEntry is a node's (value, state) pair in the pure kernel. State is one of "clean" / "dirty".

type NodeId

type NodeId = int64

NodeId identifies a reactive node in a Snapshot/Delta graph.

type NodeKey

type NodeKey struct {
	// contains filtered or unexported fields
}

NodeKey is a validated `/`-joined path addressing a keyed collection entry.

It is an additive, optional wire-stable address: unlike the volatile NodeId (which a producer may re-mint after a resync or a remove-then-readd), a key is producer-defined and stable across NodeId churn. Serialized as a bare JSON string; the containing field is omitted when the key is absent (see NodeSnapshot / DeltaOpNodeAdd).

Bounds, enforced on construction:

  • path <= 1024 bytes (UTF-8);
  • <= 32 `/`-separated segments;
  • no empty path and no empty segments (leading/trailing/double `/`).

func NewNodeKey

func NewNodeKey(path string) (NodeKey, error)

NewNodeKey validates and constructs a NodeKey.

func NodeKeyFromWire

func NodeKeyFromWire(value string) (NodeKey, error)

NodeKeyFromWire parses and re-validates a wire path string.

func (NodeKey) MarshalJSON

func (k NodeKey) MarshalJSON() ([]byte, error)

MarshalJSON emits the bare path string.

func (NodeKey) Path

func (k NodeKey) Path() string

Path returns the canonical path string.

func (NodeKey) Segments

func (k NodeKey) Segments() []string

Segments returns the `/`-separated path segments.

func (NodeKey) String

func (k NodeKey) String() string

func (NodeKey) ToWire

func (k NodeKey) ToWire() string

ToWire returns the bare path string (the JSON shape of a NodeKey).

func (*NodeKey) UnmarshalJSON

func (k *NodeKey) UnmarshalJSON(b []byte) error

UnmarshalJSON parses a JSON string and re-validates the NodeKey bounds.

type NodeSnapshot

type NodeSnapshot struct {
	Node    NodeId
	TypeTag string
	State   NodeState
	Key     *NodeKey
}

NodeSnapshot is a serialized node in a Snapshot. The optional Key is a wire-stable NodeKey, omitted from JSON when nil.

func (NodeSnapshot) MarshalJSON

func (n NodeSnapshot) MarshalJSON() ([]byte, error)

MarshalJSON emits { node, type_tag, state[, key] }, omitting key when nil.

func (*NodeSnapshot) UnmarshalJSON

func (n *NodeSnapshot) UnmarshalJSON(b []byte) error

type NodeState

type NodeState interface {
	MarshalJSON() ([]byte, error)
	// contains filtered or unexported methods
}

NodeState is the body of a NodeSnapshot / NodeAdd. Externally tagged: a single-key object keyed by the PascalCase variant name, except Opaque which is the bare unit string "Opaque".

type NodeStateOpaque

type NodeStateOpaque struct{}

NodeStateOpaque is a visible node whose value cannot be serialized (the bare unit string "Opaque").

func (NodeStateOpaque) MarshalJSON

func (NodeStateOpaque) MarshalJSON() ([]byte, error)

type NodeStatePayload

type NodeStatePayload struct {
	Bytes []byte
}

NodeStatePayload holds concrete serialized value bytes ({"Payload": [u8]}).

func (NodeStatePayload) MarshalJSON

func (p NodeStatePayload) MarshalJSON() ([]byte, error)

MarshalJSON emits {"Payload": [u8]} with bytes as a JSON u8 array (not base64).

type NodeStateSharedBlob

type NodeStateSharedBlob struct {
	Blob ShmBlobRef
}

NodeStateSharedBlob is a concrete value stored in shared memory ({"SharedBlob": ShmBlobRef}).

func (NodeStateSharedBlob) MarshalJSON

func (s NodeStateSharedBlob) MarshalJSON() ([]byte, error)

type Number added in v0.10.0

type Number interface {
	~int | ~int8 | ~int16 | ~int32 | ~int64 |
		~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 |
		~float32 | ~float64
}

Number constrains the additive/ordered policies (Sum, Max).

type OpId

type OpId struct {
	Counter int64  `json:"counter"`
	Peer    PeerId `json:"peer"`
}

OpId is a globally-unique operation identifier for a character CRDT op.

Ordered ascending by (Counter, Peer) so later ops sort after earlier ones from the same peer, and ties between peers break deterministically. OpId is a comparable value type, usable directly as a map key.

func OpIdFromWire

func OpIdFromWire(v any) OpId

OpIdFromWire parses an OpId from its decoded-JSON map form.

func (OpId) Compare

func (id OpId) Compare(other OpId) int

Compare returns -1, 0, or +1 for the ascending (counter, peer) order.

func (OpId) String

func (id OpId) String() string

String renders the Dart-style debug form OpId(counter,peer).

func (OpId) ToWire

func (id OpId) ToWire() map[string]any

ToWire renders the snake_case wire map {counter, peer}.

type OpKind

type OpKind string

OpKind is one of the three independently-gated remote operation kinds. A read grant never implies write or effect.

const (
	// OpKindRead is the read grant.
	OpKindRead OpKind = "read"
	// OpKindWrite is the write grant.
	OpKindWrite OpKind = "write"
	// OpKindTriggerEffect is the effect-trigger grant.
	OpKindTriggerEffect OpKind = "trigger_effect"
)

type Opt added in v0.15.0

type Opt[T comparable] struct {
	Present bool
	Value   T
}

Opt is a comparable optional value. Present distinguishes a set value from the zero value. Comparable whenever T is comparable, so it can back a Cell.

func None added in v0.15.0

func None[T comparable]() Opt[T]

None builds an absent Opt.

func Some added in v0.15.0

func Some[T comparable](v T) Opt[T]

Some builds a present Opt.

type OptStr added in v0.15.0

type OptStr = Opt[string]

OptStr is the Option<string> projection several fixtures exercise.

type OrSet added in v0.8.0

type OrSet struct {
	// contains filtered or unexported fields
}

OrSet is an observed-remove set (OR-set) liveness cell.

It models one entry's presence via add/remove tags: a (doc, pid) is present iff some add-tag is not shadowed by a remove that observed it. This gives the add-wins-over-stale-remove bias liveness needs (a re-open concurrent with a lagging close keeps the doc open). Join is the union of both tag sets, so it is a semilattice — out-of-order and duplicate delivery converge.

func NewOrSet added in v0.8.0

func NewOrSet() *OrSet

NewOrSet returns an empty OR-set.

func (*OrSet) Add added in v0.8.0

func (s *OrSet) Add(tag string)

Add mints a presence tag (an editor open / attach event mints a fresh tag).

func (*OrSet) Join added in v0.8.0

func (s *OrSet) Join(other *OrSet)

Join folds another replica's OR-set (union of adds and of removes).

func (*OrSet) Present added in v0.8.0

func (s *OrSet) Present() bool

Present reports whether the entry is currently present (some add-tag not shadowed).

func (*OrSet) RemoveObserved added in v0.8.0

func (s *OrSet) RemoveObserved(tags []string)

RemoveObserved removes, observing tags — only the add-tags this remove saw are shadowed.

type Outbox added in v0.11.0

type Outbox[T comparable] struct {
	// contains filtered or unexported fields
}

Outbox is the app → transport send side (§4.7). Backpressures the local producer directly via IsFull. Default overflow Conflate (state broadcast).

func NewOutbox added in v0.11.0

func NewOutbox[T comparable](ctx *Context, highWater uint64, merge MergePolicy[T]) (*Outbox[T], error)

NewOutbox builds an outbox bounded by highWater with the role default overflow (Conflate — the state-broadcast case). Validates the policy flags.

func NewOutboxWithOverflow added in v0.11.0

func NewOutboxWithOverflow[T comparable](ctx *Context, dimension BoundDim, highWater uint64, overflow Overflow, merge MergePolicy[T]) (*Outbox[T], error)

NewOutboxWithOverflow builds an outbox with an explicit dimension/overflow (e.g. Spill for a lossless event channel).

func (*Outbox[T]) Drain added in v0.11.0

func (o *Outbox[T]) Drain() (T, bool)

Drain has the transport drain the coalesced window for egress.

func (*Outbox[T]) IsFull added in v0.11.0

func (o *Outbox[T]) IsFull() bool

IsFull is the producer-facing backpressure signal (window at/over watermark).

func (*Outbox[T]) IsFullSlot added in v0.11.0

func (o *Outbox[T]) IsFullSlot() *Computed[bool]

IsFullSlot exposes the backpressure reader slot.

func (*Outbox[T]) Relay added in v0.11.0

func (o *Outbox[T]) Relay() *RelayCell[T]

Relay accesses the underlying relay (for wiring extra egress stages).

func (*Outbox[T]) Send added in v0.11.0

func (o *Outbox[T]) Send(op T) IngressOutcome

Send has the local producer send an op. A Blocked outcome is the producer's backpressure signal — it should await a drain before retrying.

type OutboxAck added in v0.8.0

type OutboxAck struct {
	// ThroughEpoch is the highest epoch the receiver has fully applied.
	ThroughEpoch Epoch `json:"through_epoch"`
}

OutboxAck is a reliable-sync reverse-channel control frame: prove receipt through ThroughEpoch (#lzsync, spec § DurableOutbox). It advances the sender's outbox retention cursor and doubles as the reconnect resume cursor; it carries no node content. Wire form: {"through_epoch": N}.

type OutboxEntry added in v0.8.0

type OutboxEntry struct {
	Epoch Epoch
	Msg   IpcMessage
}

OutboxEntry pairs a retained frame with its outbox retention key (the frame's accepted-event count).

type OutboxStore added in v0.13.0

type OutboxStore interface {
	Put(epoch Epoch, frame []byte)
	DeleteThrough(epoch Epoch)
	ScanAfter(cursor Epoch) []StoredOutboxEntry
	LoadCursor() Epoch
	SaveCursor(epoch Epoch)
}

OutboxStore is dumb ordered byte storage for the durable outbox protocol. Serialization, cursor monotonicity, pruning, and replay ordering belong to DurableStoreOutbox; adapters implement only these five operations.

type Overflow added in v0.11.0

type Overflow string

Overflow is the action taken when the hot head crosses high_water (§4.4).

const (
	// OverflowBlock refuses ingress; the producer backpressures (observes
	// IsFull). Lossless.
	OverflowBlock Overflow = "Block"
	// OverflowDropNewest discards the incoming op. Lossy.
	OverflowDropNewest Overflow = "DropNewest"
	// OverflowDropOldest resets the window to the incoming op, discarding what
	// accumulated. Lossy.
	OverflowDropOldest Overflow = "DropOldest"
	// OverflowConflate keeps merging — the coalescence *is* the bound. Requires
	// the policy's Conflates flag.
	OverflowConflate Overflow = "Conflate"
	// OverflowSpill pages the accumulated window to a durable tail (Phase 3).
	OverflowSpill Overflow = "Spill"
)

type PeekableStorage added in v0.9.0

type PeekableStorage[T any] interface {
	// Peek returns the current head element and true, or the zero T and false
	// when empty. Non-mutating.
	Peek() (T, bool)
}

PeekableStorage is the OPTIONAL peek capability. A backend implementing it gains a reactive Head reader; a backend without it has no Head (Head returns the zero value and false), exactly as an unbounded backend has no IsFull.

type PeerChangeEvent added in v0.15.0

type PeerChangeEvent[P cmp.Ordered] struct {
	Kind PeerChangeKind
	Peer P
	From PeerState
	To   PeerState
}

PeerChangeEvent is a diff event over the membership cell. For PeerJoined and PeerDeparted, only Peer is meaningful; for PeerStateChanged, From/To carry the transition.

type PeerChangeKind added in v0.15.0

type PeerChangeKind int

PeerChangeKind discriminates the PeerChangeEvent variants.

const (
	// PeerJoined — a previously unknown peer joined.
	PeerJoined PeerChangeKind = iota
	// PeerDeparted — a peer gracefully left.
	PeerDeparted
	// PeerStateChanged — a known peer transitioned between states.
	PeerStateChanged
)

type PeerId

type PeerId = int64

PeerId identifies a replica/peer in the distributed plane.

type PeerPermissions

type PeerPermissions struct {
	// contains filtered or unexported fields
}

PeerPermissions is a default-deny, per-peer allowlist of RemoteOp grants. The three OpKinds are gated independently. Non-allowlisted nodes are omitted entirely from a permission-filtered snapshot/delta (not redacted).

Like the Dart original, PeerPermissions is not safe for concurrent use.

func NewPeerPermissions

func NewPeerPermissions() *PeerPermissions

NewPeerPermissions creates an empty allowlist.

func (*PeerPermissions) Allow

func (p *PeerPermissions) Allow(peer PeerId, op RemoteOp) bool

Allow grants peer the op; returns whether this added a new grant.

func (*PeerPermissions) AllowMany

func (p *PeerPermissions) AllowMany(peer PeerId, kind OpKind, nodes []NodeId)

AllowMany grants peer every node in nodes for kind.

func (*PeerPermissions) CanRead

func (p *PeerPermissions) CanRead(peer PeerId, node NodeId) bool

CanRead reports whether peer may read node.

func (*PeerPermissions) Check

func (p *PeerPermissions) Check(peer PeerId, op RemoteOp) error

Check returns a *PermissionDenied error unless peer holds op.

func (*PeerPermissions) FilterReadable

func (p *PeerPermissions) FilterReadable(peer PeerId, nodes []NodeId) []NodeId

FilterReadable returns the readable subset of nodes for peer.

func (*PeerPermissions) IsAllowed

func (p *PeerPermissions) IsAllowed(peer PeerId, op RemoteOp) bool

IsAllowed reports whether peer holds op.

func (*PeerPermissions) PeerCount

func (p *PeerPermissions) PeerCount() int

PeerCount reports the number of peers with at least one grant.

func (*PeerPermissions) Revoke

func (p *PeerPermissions) Revoke(peer PeerId, op RemoteOp) bool

Revoke removes a single grant; returns whether anything was removed.

func (*PeerPermissions) RevokePeer

func (p *PeerPermissions) RevokePeer(peer PeerId) bool

RevokePeer drops every grant for peer; returns whether the peer was present.

type PeerState added in v0.15.0

type PeerState int

PeerState is the per-peer liveness state (SWIM).

const (
	// Alive — heartbeats current; a valid CRDT sync target.
	Alive PeerState = iota
	// Suspect — phi crossed the threshold; awaiting a refuting heartbeat or the
	// suspect timeout.
	Suspect
	// Dead — suspect long enough to be declared failed.
	Dead
	// Left — gracefully departed.
	Left
)

func (PeerState) String added in v0.15.0

func (s PeerState) String() string

String renders the SWIM state name (matches the conformance fixture labels).

type PermissionDenied

type PermissionDenied struct {
	Peer PeerId
	Op   RemoteOp
}

PermissionDenied is returned by PeerPermissions.Check when Peer lacks Op.

func (*PermissionDenied) Error

func (e *PermissionDenied) Error() string

type PhiAccrual added in v0.15.0

type PhiAccrual struct {
	// contains filtered or unexported fields
}

PhiAccrual is a Phi-accrual failure detector over a sliding window of heartbeat inter-arrival times. phi is bit-portable across bindings via the Akka-style logistic approximation of the normal CDF.

func NewPhiAccrual added in v0.15.0

func NewPhiAccrual(maxSamples int, minStd float64) *PhiAccrual

NewPhiAccrual builds a detector with the given window bound and std floor.

func (*PhiAccrual) Heartbeat added in v0.15.0

func (d *PhiAccrual) Heartbeat(now uint64)

Heartbeat records a heartbeat arrival, appending its inter-arrival sample.

func (*PhiAccrual) Phi added in v0.15.0

func (d *PhiAccrual) Phi(now uint64) float64

Phi is the suspicion level at now. 0.0 when there is no estimate yet.

type Plane added in v0.15.0

type Plane int

Plane marks which plane a value lives on. Ephemeral values MUST NOT be persisted; Durable values may be written to the durable outbox. In lazily-rs these are the `Ephemeral`/`Durable` marker traits (a durable sink statically rejects an ephemeral value — a compile-fail doctest). Go has no equivalent static rejection, so the markers are exposed as simple plane constants.

const (
	// Ephemeral tags values that MUST NOT be persisted.
	Ephemeral Plane = iota
	// Durable tags values that may be written to the durable outbox.
	Durable
)

type PnCounter

type PnCounter struct {
	// contains filtered or unexported fields
}

PnCounter is a positive-negative counter (state-based CvRDT). Each peer owns its own positive and negative components; the value is the sum of all positives minus the sum of all negatives. Merge is component-wise max.

func NewPnCounter

func NewPnCounter(peer PeerId) *PnCounter

NewPnCounter creates a counter owned by peer.

func (*PnCounter) Copy

func (c *PnCounter) Copy() *PnCounter

Copy returns a deep copy of the counter.

func (*PnCounter) Decrement

func (c *PnCounter) Decrement()

Decrement adds 1 to this peer's negative component.

func (*PnCounter) DecrementBy

func (c *PnCounter) DecrementBy(amount int64)

DecrementBy adds amount to this peer's negative component.

func (*PnCounter) Increment

func (c *PnCounter) Increment()

Increment adds 1 to this peer's positive component.

func (*PnCounter) IncrementBy

func (c *PnCounter) IncrementBy(amount int64)

IncrementBy adds amount to this peer's positive component.

func (*PnCounter) Merge

func (c *PnCounter) Merge(other *PnCounter)

Merge folds another PN counter in via component-wise max (idempotent).

func (*PnCounter) Peer

func (c *PnCounter) Peer() PeerId

Peer returns the peer that owns this counter's local components.

func (*PnCounter) ToWire

func (c *PnCounter) ToWire() map[string]any

ToWire renders the counter to its spec wire form: positive/negative maps keyed by stringified peer id.

func (*PnCounter) Value

func (c *PnCounter) Value() int64

Value returns the current counter value: sum(positive) - sum(negative).

type Position

type Position struct {
	Frac []byte
	Peer PeerId
}

Position is a fractional-index position: (frac bytes, peer) ordered lexicographically. Frac bytes are 0..255.

func (Position) Compare

func (p Position) Compare(other Position) int

Compare returns -1, 0, or +1 for the lexicographic order over (frac, peer): byte-wise on the shared prefix, then shorter frac first, then peer.

type PresenceCell added in v0.15.0

type PresenceCell[K comparable, V comparable] struct {
	// contains filtered or unexported fields
}

PresenceCell is reactive per-peer presence: heartbeat-kept, membership- and TTL-evicted. Present() is the live peer -> value map, invalidating only when the live view changes.

func NewPresenceCell added in v0.15.0

func NewPresenceCell[K comparable, V comparable](ctx *Context, ttl uint64) *PresenceCell[K, V]

NewPresenceCell builds a presence cell with a heartbeat TTL.

func (*PresenceCell[K, V]) Evict added in v0.15.0

func (c *PresenceCell[K, V]) Evict(peer K, now uint64)

Evict a peer on membership loss.

func (*PresenceCell[K, V]) Heartbeat added in v0.15.0

func (c *PresenceCell[K, V]) Heartbeat(peer K, value V, now uint64)

Heartbeat a peer's presence (expiring at now + ttl).

func (*PresenceCell[K, V]) Present added in v0.15.0

func (c *PresenceCell[K, V]) Present() map[K]V

Present returns the live peer -> value snapshot.

func (*PresenceCell[K, V]) PresentCell added in v0.15.0

func (c *PresenceCell[K, V]) PresentCell() *Source[uint64]

PresentCell exposes the internal version cell backing the present projection.

func (*PresenceCell[K, V]) Tick added in v0.15.0

func (c *PresenceCell[K, V]) Tick(now uint64)

Tick evicts peers whose TTL has lapsed.

type PriorityStorage added in v0.11.0

type PriorityStorage[T any] struct {
	// contains filtered or unexported fields
}

PriorityStorage — Case 11, priority egress. Ingress carries a priority; egress pops the highest priority first (not FIFO), FIFO within equal priority. Reordering, so sound for a commutative merge downstream (reorder_adjacent).

func NewPriorityStorage added in v0.11.0

func NewPriorityStorage[T any]() *PriorityStorage[T]

NewPriorityStorage creates an empty priority storage.

func (*PriorityStorage[T]) IsEmpty added in v0.11.0

func (p *PriorityStorage[T]) IsEmpty() bool

IsEmpty reports whether the storage is empty.

func (*PriorityStorage[T]) Len added in v0.11.0

func (p *PriorityStorage[T]) Len() int

Len is the number of stored elements.

func (*PriorityStorage[T]) Pop added in v0.11.0

func (p *PriorityStorage[T]) Pop() (T, bool)

Pop removes and returns the highest-priority element (FIFO within equal priority). The second return is false when empty.

func (*PriorityStorage[T]) Push added in v0.11.0

func (p *PriorityStorage[T]) Push(priority uint64, value T)

Push adds a value at the given priority.

type ProbabilisticSampleCell added in v0.15.0

type ProbabilisticSampleCell[T comparable] struct {
	// contains filtered or unexported fields
}

ProbabilisticSampleCell is the reactive probabilistic sampler; it owns an injectable SampleRng.

func NewProbabilisticSampleCell added in v0.15.0

func NewProbabilisticSampleCell[T comparable](ctx *Context, rate float64, rng SampleRng) *ProbabilisticSampleCell[T]

NewProbabilisticSampleCell builds a reactive probabilistic sampler bound to ctx.

func (*ProbabilisticSampleCell[T]) Input added in v0.15.0

func (c *ProbabilisticSampleCell[T]) Input(v T) Opt[T]

Input samples an input using the owned RNG.

func (*ProbabilisticSampleCell[T]) InputWithDraw added in v0.15.0

func (c *ProbabilisticSampleCell[T]) InputWithDraw(v T, draw float64) Opt[T]

InputWithDraw samples an input against an explicit draw (deterministic / conformance). Emits iff draw < rate.

func (*ProbabilisticSampleCell[T]) Output added in v0.15.0

func (c *ProbabilisticSampleCell[T]) Output() Opt[T]

Output returns the last emitted value (subscribes the current computation).

func (*ProbabilisticSampleCell[T]) OutputCell added in v0.15.0

func (c *ProbabilisticSampleCell[T]) OutputCell() *Source[Opt[T]]

OutputCell exposes the reader cell for invalidation observation.

type ProbabilisticSampleCore added in v0.15.0

type ProbabilisticSampleCore struct {
	// contains filtered or unexported fields
}

ProbabilisticSampleCore is the tail-sampling compute core. A draw in [0, 1) passes iff draw < rate.

func NewProbabilisticSampleCore added in v0.15.0

func NewProbabilisticSampleCore(rate float64) ProbabilisticSampleCore

NewProbabilisticSampleCore builds a core with rate clamped to [0, 1].

func (ProbabilisticSampleCore) Decide added in v0.15.0

func (c ProbabilisticSampleCore) Decide(draw float64) bool

Decide reports whether an input with this random draw is sampled.

func (ProbabilisticSampleCore) Rate added in v0.15.0

Rate returns the (clamped) sampling rate.

type Progress added in v0.8.0

type Progress struct {
	// Sent is the count of data frames pushed to the sink this tick (fresh
	// enqueues + reconnect replays).
	Sent int
	// Applied are inbound frames the host must fold into its projection.
	Applied []IpcMessage
	// ResyncRequested reports that a gap was detected inbound and a
	// ResyncRequest was emitted to the peer.
	ResyncRequested bool
	// SnapshotsServed is the count of inbound ResyncRequests answered with a
	// provider snapshot this tick.
	SnapshotsServed int
	// PeerAckedThrough is the peer's ack cursor after this tick (our outbox
	// retention / resume point).
	PeerAckedThrough Epoch
	// Retained is the count of outbox frames still unacked (retained for
	// reconnect replay).
	Retained int
}

Progress is what one SyncDriver.Tick accomplished (spec § SyncDriver).

Applied are the inbound Snapshot/Delta/CrdtSync frames the host MUST fold into its projection this tick — the driver has already advanced the receiver cursor for them, so folding is the caller's remaining obligation.

type QueueCell added in v0.3.0

type QueueCell[T comparable, S QueueStorage[T]] struct {
	// contains filtered or unexported fields
}

QueueCell is a reactive FIFO queue — a shell of reader-kind version cells layered over a pluggable QueueStorage backend (cell-model.md § Reactive queues).

The shell owns five reader-kind cells whose values are re-derived from storage after each successful op:

  • Head — the current head value, or none when empty. Invalidated on every pop (the head value always changes) and on a push that transitions the queue from empty to non-empty (the head appears for the first time); NOT invalidated by a push to a non-empty queue (the head is unchanged).
  • Len — the element count. Invalidated on every push and every pop that changes the count.
  • IsEmpty — the emptiness flag. Invalidated when the queue transitions between empty and non-empty.
  • IsFull — the fullness flag (bounded queues only). Invalidated when the queue transitions across the capacity boundary in either direction, so a consumer's pop that makes room wakes a producer's IsFull subscription (reactive backpressure).
  • IsClosed — the closed flag. Invalidated only by the first Close (a terminal false→true transition); neither push nor pop touches it.

Reader-kind independence comes "for free" from the host Cell's PartialEq guard: after each op the shell re-derives all four content cells and writes them back inside one Context.Batch; a cell whose value did not change suppresses its cascade, so a push to a non-empty queue (head unchanged) invalidates Len/IsEmpty but not Head.

T must be comparable so the head cell's PartialEq guard can detect a head change; storage itself needs no equality. SPSC by construction; for MPSC, push inside Context.Batch.

func NewBoundedQueueCell added in v0.3.0

func NewBoundedQueueCell[T comparable](ctx *Context, capacity int) *QueueCell[T, *VecDequeStorage[T]]

NewBoundedQueueCell builds a bounded QueueCell with a VecDequeStorage of the given capacity. The queue exposes IsFull as a reactive reader (the backpressure signal): a pop that makes room invalidates IsFull readers. Panics if capacity <= 0.

func NewQueueCell added in v0.3.0

func NewQueueCell[T comparable](ctx *Context) *QueueCell[T, *VecDequeStorage[T]]

NewQueueCell builds an unbounded QueueCell with the default VecDequeStorage backend. The queue can grow without bound and has no IsFull reader to invalidate.

func NewQueueCellWithStorage added in v0.3.0

func NewQueueCellWithStorage[T comparable, S QueueStorage[T]](ctx *Context, storage S) *QueueCell[T, S]

NewQueueCellWithStorage builds a QueueCell over an arbitrary QueueStorage backend (custom ring buffer, broker client, consensus log, ...). The shell is storage-agnostic: it reads Len / IsClosed (the required contract) and, when the backend offers them, the optional PeekableStorage / BoundedStorage capabilities. Pass a pointer to your storage so the shell observes mutations.

func (*QueueCell[T, S]) Capacity added in v0.3.0

func (q *QueueCell[T, S]) Capacity() (int, bool)

Capacity reports the bound and true for a bounded backend, or 0 and false for the unbounded default. Non-reactive (a queue's capacity never changes after construction).

func (*QueueCell[T, S]) Close added in v0.3.0

func (q *QueueCell[T, S]) Close()

Close marks the queue closed. Idempotent: closing an already-closed queue is a no-op that invalidates nothing. Terminal: a closed queue cannot reopen (the formal Closed_then_stays_Closed invariant). Neither push nor pop can change the closed flag.

func (*QueueCell[T, S]) Head added in v0.3.0

func (q *QueueCell[T, S]) Head() (T, bool)

Head is the reactive head read. Subscribes the caller to the head reader-kind cell: it recomputes (is invalidated) on every pop and on a push that transitions empty→non-empty, but not on a push to a non-empty queue. Returns the head value and true, or the zero T and false when empty.

func (*QueueCell[T, S]) IsClosed added in v0.3.0

func (q *QueueCell[T, S]) IsClosed() bool

IsClosed is the reactive closed flag. Subscribes the caller to the closed reader-kind cell, which transitions only once (the first Close).

func (*QueueCell[T, S]) IsClosedUntracked added in v0.3.0

func (q *QueueCell[T, S]) IsClosedUntracked() bool

IsClosedUntracked reports the closed flag without subscribing the caller. Non-reactive.

func (*QueueCell[T, S]) IsEmpty added in v0.3.0

func (q *QueueCell[T, S]) IsEmpty() bool

IsEmpty is the reactive emptiness flag. Subscribes the caller to the emptiness reader-kind cell.

func (*QueueCell[T, S]) IsFull added in v0.3.0

func (q *QueueCell[T, S]) IsFull() bool

IsFull is the reactive fullness flag (bounded queues only). Subscribes the caller to the fullness reader-kind cell — the backpressure signal: a consumer's pop that makes room invalidates this reader so a push-side effect can resume without polling. An unbounded queue's IsFull is always false and never invalidates.

func (*QueueCell[T, S]) Len added in v0.3.0

func (q *QueueCell[T, S]) Len() int

Len is the reactive element count. Subscribes the caller to the length reader-kind cell.

func (*QueueCell[T, S]) LenUntracked added in v0.3.0

func (q *QueueCell[T, S]) LenUntracked() int

LenUntracked reports the current element count without subscribing the caller to the length reader-kind cell. Non-reactive.

func (*QueueCell[T, S]) ReaderHandles added in v0.3.0

func (q *QueueCell[T, S]) ReaderHandles() QueueReaderHandles[T]

ReaderHandles returns the five reader-kinds backing the reactive reads.

func (*QueueCell[T, S]) Storage added in v0.3.0

func (q *QueueCell[T, S]) Storage() S

Storage returns the backing QueueStorage. Exposed so callers can reach a backend-specific surface (e.g. (*VecDequeStorage[T]).Elements() for a snapshot, or a consensus backend's anti-entropy handle).

func (*QueueCell[T, S]) TryPop added in v0.3.0

func (q *QueueCell[T, S]) TryPop() (T, QueuePopError)

TryPop removes and returns the head element. A closed non-empty queue keeps draining (returns the next element); only a closed empty queue returns QueuePopClosed, and only an open empty queue returns QueuePopEmpty. On success the reader-kind cells are synced; a failed pop invalidates nothing.

func (*QueueCell[T, S]) TryPush added in v0.3.0

func (q *QueueCell[T, S]) TryPush(value T) QueuePushError

TryPush appends value to the tail. On success it syncs the reader-kind cells and returns QueuePushOk. On reject (Full / Closed) it leaves all readers untouched — a failed push invalidates nothing.

For MPSC, call TryPush inside a Context.Batch so the per-producer pushes appear as one atomic, coalesced transition to concurrent observers.

type QueuePopError added in v0.3.0

type QueuePopError string

QueuePopError is the failure mode of a pop attempt. The zero value (QueuePopOk, the empty string) means a value was returned.

  • Empty — the queue is open but holds no elements.
  • Closed — the queue is closed and empty. This is distinct from Empty so a consumer can tell "no work right now" from "no work will ever arrive" (the drain-completion signal).
const (
	// QueuePopOk is the zero-value success sentinel (a value was popped).
	QueuePopOk QueuePopError = ""
	// QueuePopEmpty means the open queue had no element to pop.
	QueuePopEmpty QueuePopError = "Empty"
	// QueuePopClosed means a closed, empty queue was popped (drain complete).
	QueuePopClosed QueuePopError = "Closed"
)

func (QueuePopError) Ok added in v0.3.0

func (e QueuePopError) Ok() bool

Ok reports whether the pop succeeded (the error is the zero value).

func (QueuePopError) String added in v0.3.0

func (e QueuePopError) String() string

String renders the fixture/wire label ("Empty" / "Closed"; "" for success).

type QueuePushError added in v0.3.0

type QueuePushError string

QueuePushError is the outcome of a push attempt. The zero value (QueuePushOk, the empty string) means success; the sentinels distinguish the two failure modes the observable contract separates.

  • Full — the bounded queue is at capacity (overflow policy = reject, the default VecDequeStorage behavior; other backends may block / drop-oldest / drop-newest, but the shell only distinguishes Full from Empty/Closed).
  • Closed — the queue is closed; push after close is an error.
const (
	// QueuePushOk is the zero-value success sentinel (push accepted).
	QueuePushOk QueuePushError = ""
	// QueuePushFull means a bounded queue rejected the push at capacity.
	QueuePushFull QueuePushError = "Full"
	// QueuePushClosed means the push was rejected because the queue is closed.
	QueuePushClosed QueuePushError = "Closed"
)

func (QueuePushError) Ok added in v0.3.0

func (e QueuePushError) Ok() bool

Ok reports whether the push succeeded (the error is the zero value).

func (QueuePushError) String added in v0.3.0

func (e QueuePushError) String() string

String renders the fixture/wire label ("Full" / "Closed"; "" for success).

type QueueReaderHandles added in v0.3.0

type QueueReaderHandles[T comparable] struct {
	Head     *Computed[queueHead[T]]
	Len      *Computed[int]
	IsEmpty  *Computed[bool]
	IsFull   *Computed[bool]
	IsClosed *Source[bool]
}

QueueReaderHandles exposes the underlying reader-kinds directly, for advanced wiring (custom slots, effect dependency tracking, graph bridges). The four derived reader-kinds are demand-driven Slots; IsClosed is the Cell backing the closed flag (a direct input).

type QueueStorage added in v0.3.0

type QueueStorage[T any] interface {
	// TryPush appends value to the tail. Returns QueuePushOk on success,
	// QueuePushFull if a bounded queue is at capacity, or QueuePushClosed if
	// the queue is closed (push after close is rejected regardless of
	// capacity).
	TryPush(value T) QueuePushError
	// TryPop removes and returns the head element. On success it returns the
	// value and QueuePopOk. On an open empty queue it returns the zero T and
	// QueuePopEmpty; on a closed empty queue it returns the zero T and
	// QueuePopClosed (drain-complete). Pop on a closed non-empty queue keeps
	// draining — it returns the next element, not Closed.
	TryPop() (T, QueuePopError)
	// Len reports the number of elements currently held.
	Len() int
	// IsClosed reports whether the queue has been closed. Closure is monotonic
	// (once closed, stays closed).
	IsClosed() bool
	// Close marks the queue closed. Idempotent: closing an already-closed
	// queue is a no-op. Close is terminal: a closed queue cannot reopen.
	Close()
}

QueueStorage is the backend contract a QueueCell reactive shell sits over (cell-model.md § Storage backend contract). A conforming backend:

  1. preserves FIFO order — TryPop returns elements in the order they were TryPush-ed (no reordering, no silent drops);
  2. exposes a native producer/consumer shape that is a superset of the shell's required SPSC shape (MPSC usage needs a multi-writer backend);
  3. optionally exposes a capacity: TryPush returns QueuePushFull when at capacity. The overflow policy is a backend property;
  4. phrases state over reader kind (head/len/empty/full), never exposing storage indices that could cause spurious invalidations when (say) a ring-buffer slot index wraps.

Invalidation is the shell's job, not the backend's: the backend reports raw state (Len / IsClosed) and the shell layers its own demand-driven reader-kinds above it.

Minimal required contract (Phase 0, #relaycell): TryPush / TryPop / Len / IsClosed / Close. Peek and Capacity are OPTIONAL capabilities — a backend that implements PeekableStorage[T] gains a Head reader; one that implements BoundedStorage gains an IsFull reader. A raw-channel-style backend that satisfies only QueueStorage is fully conforming (no Head, never full).

Implement QueueStorage with a pointer receiver so mutation is visible to the owning shell; pass that pointer as the QueueCell's S.

type RatePolicy added in v0.11.0

type RatePolicy struct {
	// contains filtered or unexported fields
}

RatePolicy — Case 9, rate-limited egress (token bucket). A drain is permitted only when a token is available. Refilled refillPerTick tokens per logical tick, capped at capacity.

func NewRatePolicy added in v0.11.0

func NewRatePolicy(capacity, refillPerTick uint64) *RatePolicy

NewRatePolicy creates a token bucket that starts full.

func (*RatePolicy) Tick added in v0.11.0

func (r *RatePolicy) Tick()

Tick advances the logical clock, refilling the bucket (saturating at capacity).

func (*RatePolicy) Tokens added in v0.11.0

func (r *RatePolicy) Tokens() uint64

Tokens are the tokens currently available.

func (*RatePolicy) TryEgress added in v0.11.0

func (r *RatePolicy) TryEgress() bool

TryEgress consumes one token for an egress; returns true if paced through.

type ReactiveMap added in v0.7.0

type ReactiveMap[K comparable, V comparable, H any] struct {
	// contains filtered or unexported fields
}

ReactiveMap is a keyed reactive collection generic over the entry handle kind H (*Cell[V] input cells or *Slot[V] derived slots): a hash map of K -> H with reactive membership and independently-tracked per-entry nodes.

Operations run against the owning Context, single-goroutine like the rest of lazily (the reactive graph is not itself synchronized). The three reactivity planes stay independent: writing one entry's value invalidates only that entry's readers; add/remove invalidates membership readers (Len / ContainsKey) and order readers (Keys); a pure reorder (atomic move) invalidates order readers only.

The handle-kind operations (mint / observe / clear) are supplied by the SourceMap / ComputedMap constructor — the Go analog of the Rust MapHandle trait.

func (*ReactiveMap[K, V, H]) ContainsKey added in v0.7.0

func (m *ReactiveMap[K, V, H]) ContainsKey(c ComputeOps, key K) bool

ContainsKey reports the reactive membership test for key. Subscribes the caller to membership changes (add/remove of any key), not to value changes.

func (*ReactiveMap[K, V, H]) EntryKind added in v0.7.0

func (m *ReactiveMap[K, V, H]) EntryKind() EntryKind

EntryKind returns this map's entry kind (EntryKindSource for a SourceMap, EntryKindComputed for a ComputedMap).

func (*ReactiveMap[K, V, H]) GetOrInsertWith added in v0.7.0

func (m *ReactiveMap[K, V, H]) GetOrInsertWith(c ComputeOps, key K, factory func(K) V) V

GetOrInsertWith returns the value at key, minting the entry via factory(key) first if absent — the mint-on-access recipe. For a ComputedMap this is the lazy materialization pull; for a SourceMap it seeds an input cell. Bumps reactive membership only on insert; an existing key returns its current value without re-running the factory.

func (*ReactiveMap[K, V, H]) Handle added in v0.7.0

func (m *ReactiveMap[K, V, H]) Handle(key K) (H, bool)

Handle returns the existing entry handle for key, or (zero, false). Non-reactive: does not subscribe the caller to membership.

func (*ReactiveMap[K, V, H]) IsEmpty added in v0.7.0

func (m *ReactiveMap[K, V, H]) IsEmpty(c ComputeOps) bool

IsEmpty reports the reactive emptiness check. Subscribes the caller to membership changes.

func (*ReactiveMap[K, V, H]) IsPresent added in v0.7.0

func (m *ReactiveMap[K, V, H]) IsPresent(key K) bool

IsPresent reports whether key is currently materialized (present in the allocated set). Non-reactive.

func (*ReactiveMap[K, V, H]) Keys added in v0.7.0

func (m *ReactiveMap[K, V, H]) Keys(c ComputeOps) []K

Keys returns a reactive snapshot of the keys in their current order. Subscribes the caller to order changes (add/remove and move/reorder), not to per-entry value changes.

func (*ReactiveMap[K, V, H]) Len added in v0.7.0

func (m *ReactiveMap[K, V, H]) Len(c ComputeOps) int

Len reports the reactive entry count. Subscribes the caller to membership changes only.

func (*ReactiveMap[K, V, H]) LenUntracked added in v0.7.0

func (m *ReactiveMap[K, V, H]) LenUntracked() int

LenUntracked reports the non-reactive count. Does not subscribe the caller to anything.

func (*ReactiveMap[K, V, H]) MoveAfter added in v0.7.0

func (m *ReactiveMap[K, V, H]) MoveAfter(key, anchor K) bool

MoveAfter atomically moves key to just after anchor (#lzcellmove).

func (*ReactiveMap[K, V, H]) MoveBefore added in v0.7.0

func (m *ReactiveMap[K, V, H]) MoveBefore(key, anchor K) bool

MoveBefore atomically moves key to just before anchor (#lzcellmove). Returns whether the move could be expressed.

func (*ReactiveMap[K, V, H]) MoveTo added in v0.7.0

func (m *ReactiveMap[K, V, H]) MoveTo(key K, index int) bool

MoveTo atomically moves key to index in the order (#lzcellmove).

This is the atomic, optimized reorder: the entry keeps the same node, the same dependents, and its CRDT lineage — unlike the naive Remove + re-mint which re-allocates the node and bumps membership twice. Only the order signal is bumped (once), so Keys readers recompute but Len / ContainsKey readers stay cached.

index is clamped to [0, len). A no-op move (already at position) bumps nothing. Returns whether key was present.

func (*ReactiveMap[K, V, H]) Observe added in v0.7.0

func (m *ReactiveMap[K, V, H]) Observe(c ComputeOps, key K) (V, bool)

Observe reads the value at key if present, subscribing the caller to that entry's node (reactive on that entry only). Returns (zero, false) if absent.

func (*ReactiveMap[K, V, H]) Position added in v0.7.0

func (m *ReactiveMap[K, V, H]) Position(key K) (int, bool)

Position reports the current 0-based position of key in the order, or false if absent. Non-reactive.

func (*ReactiveMap[K, V, H]) PresentCount added in v0.7.0

func (m *ReactiveMap[K, V, H]) PresentCount() int

PresentCount returns the number of currently-materialized entries. Non-reactive.

func (*ReactiveMap[K, V, H]) PresentKeys added in v0.7.0

func (m *ReactiveMap[K, V, H]) PresentKeys() []K

PresentKeys returns the currently-materialized keys in first-materialization order. Non-reactive; the present set only grows (deferral, not de-allocation).

func (*ReactiveMap[K, V, H]) Remove added in v0.7.0

func (m *ReactiveMap[K, V, H]) Remove(key K) bool

Remove removes key's entry. Bumps reactive membership and clears the removed entry's dependents. Returns whether the key was present.

The orphaned node stops driving any dependents; the runtime exposes no node-recycle yet (mirrors lazily-rs).

type ReadinessCell added in v0.15.0

type ReadinessCell struct {
	// contains filtered or unexported fields
}

ReadinessCell is the reactive readiness projection onto a Cell for /ready.

func NewReadinessCell added in v0.15.0

func NewReadinessCell(ctx *Context) *ReadinessCell

NewReadinessCell creates a reactive readiness cell bound to ctx.

func (*ReadinessCell) Ready added in v0.15.0

func (r *ReadinessCell) Ready() bool

Ready reports whether the service is ready.

func (*ReadinessCell) ReadyCell added in v0.15.0

func (r *ReadinessCell) ReadyCell() *Source[bool]

ReadyCell returns the underlying reactive cell for /ready.

func (*ReadinessCell) Set added in v0.15.0

func (r *ReadinessCell) Set(name string, ready bool)

Set sets or refreshes a condition and refreshes the projection.

type ReadinessCore added in v0.15.0

type ReadinessCore struct {
	// contains filtered or unexported fields
}

ReadinessCore is the composed readiness-probe core: ready iff every condition holds.

func NewReadinessCore added in v0.15.0

func NewReadinessCore() *ReadinessCore

NewReadinessCore creates an empty readiness core.

func (*ReadinessCore) Ready added in v0.15.0

func (c *ReadinessCore) Ready() bool

Ready reports whether every condition is ready.

func (*ReadinessCore) Set added in v0.15.0

func (c *ReadinessCore) Set(name string, ready bool)

Set sets or refreshes a condition.

type ReceiptApplyStatus

type ReceiptApplyStatus interface {
	// contains filtered or unexported methods
}

ReceiptApplyStatus is the result of observing a receipt into a ReceiptProjection. It is a sealed union realized as an interface with the concrete variants ReceiptRecorded / ReceiptDuplicate / ReceiptStaleGeneration / ReceiptTerminalConflict.

type ReceiptDuplicate

type ReceiptDuplicate struct{}

ReceiptDuplicate means the receipt id was already seen (idempotent no-op).

type ReceiptOutcome

type ReceiptOutcome string

ReceiptOutcome is the lifecycle outcome of a receipt. Serialized as its bare wire string; `observed`/`accepted` are non-terminal, `applied`/`rejected` are terminal.

const (
	// ReceiptOutcomeObserved: a peer/process observed the causation request.
	ReceiptOutcomeObserved ReceiptOutcome = "observed"
	// ReceiptOutcomeAccepted: a peer/process accepted or queued the request.
	ReceiptOutcomeAccepted ReceiptOutcome = "accepted"
	// ReceiptOutcomeApplied: the requested effect/state change was applied
	// (terminal).
	ReceiptOutcomeApplied ReceiptOutcome = "applied"
	// ReceiptOutcomeRejected: the requested effect/state change was rejected
	// (terminal).
	ReceiptOutcomeRejected ReceiptOutcome = "rejected"
)

func ReceiptOutcomeFromWire

func ReceiptOutcomeFromWire(v string) (ReceiptOutcome, error)

ReceiptOutcomeFromWire parses a wire string into a ReceiptOutcome, rejecting unknown values.

func (ReceiptOutcome) IsTerminal

func (o ReceiptOutcome) IsTerminal() bool

IsTerminal reports whether this outcome is terminal (no further transitions expected).

func (ReceiptOutcome) Wire

func (o ReceiptOutcome) Wire() string

Wire returns the bare wire string of this outcome.

type ReceiptProjection

type ReceiptProjection struct {
	// contains filtered or unexported fields
}

ReceiptProjection is the folded receipt ledger: it tracks the latest and terminal receipt per causation id, deduplicates by receipt id, and retains stale (out-of-generation) receipt ids separately.

Like the sibling bindings, ReceiptProjection is not safe for concurrent use.

func NewReceiptProjection

func NewReceiptProjection() *ReceiptProjection

NewReceiptProjection creates an empty projection.

func (*ReceiptProjection) ContainsReceipt

func (p *ReceiptProjection) ContainsReceipt(receiptId string) bool

ContainsReceipt reports whether receiptId has been observed (recorded or stale).

func (*ReceiptProjection) CurrentGeneration

func (p *ReceiptProjection) CurrentGeneration() int64

CurrentGeneration is the highest current generation observed so far.

func (*ReceiptProjection) LatestFor

func (p *ReceiptProjection) LatestFor(causationId string) (CausalReceipt, bool)

LatestFor returns the latest recorded receipt for causationId, terminal or not, and whether one exists.

func (*ReceiptProjection) Observe

func (p *ReceiptProjection) Observe(currentGeneration *int64, receipt CausalReceipt) ReceiptApplyStatus

Observe applies one receipt and returns its ReceiptApplyStatus.

When currentGeneration is non-nil, a receipt whose generation differs from it is retained only as a stale id and does not update the projection. When nil, the generation check is skipped (mirrors the canonical Option<u64> semantics).

Ordering (mirrors the Rust/JS reference):

  1. Duplicate: a receipt id already recorded or already stale is a no-op.
  2. StaleGeneration: generation mismatch -> record the id as stale.
  3. TerminalConflict: a differing terminal outcome for the same causation id fails closed and is not recorded.
  4. Otherwise: set terminal (first terminal wins), set latest, record by id.

func (*ReceiptProjection) ReceiptCount

func (p *ReceiptProjection) ReceiptCount() int

ReceiptCount is the number of tracked receipts (recorded plus stale).

func (*ReceiptProjection) StaleReceiptIds

func (p *ReceiptProjection) StaleReceiptIds() []string

StaleReceiptIds returns the receipt ids observed outside the current generation.

func (*ReceiptProjection) TerminalFor

func (p *ReceiptProjection) TerminalFor(causationId string) (CausalReceipt, bool)

TerminalFor returns the terminal receipt for causationId and whether one exists.

type ReceiptRecorded

type ReceiptRecorded struct{}

ReceiptRecorded means the receipt was recorded into the projection.

type ReceiptStaleGeneration

type ReceiptStaleGeneration struct {
	// Expected is the current authority generation.
	Expected int64
	// Actual is the generation carried by the receipt.
	Actual int64
}

ReceiptStaleGeneration means the receipt's generation did not match the current authority generation; the receipt is retained only as a stale id and does not update the projection.

type ReceiptTerminalConflict

type ReceiptTerminalConflict struct {
	// CausationId is the causation id with conflicting terminal receipts.
	CausationId string
	// Existing is the already-recorded terminal outcome.
	Existing ReceiptOutcome
	// Incoming is the conflicting incoming terminal outcome.
	Incoming ReceiptOutcome
}

ReceiptTerminalConflict means a different terminal outcome already exists for this causation id (fail-closed).

type RelayCell added in v0.11.0

type RelayCell[T comparable] struct {
	// contains filtered or unexported fields
}

RelayCell is the algebra-typed conflating relay (Phase 2, in-proc core). The hot head is a cell; Depth/IsFull/IsEmpty are demand-driven slots, so an unobserved relay costs N·⊕ and no more (the merge cost law).

func NewRelayCell added in v0.11.0

func NewRelayCell[T comparable](ctx *Context, policy BackpressurePolicy, merge MergePolicy[T]) (*RelayCell[T], error)

NewRelayCell builds a relay over policy, validating the initial overflow against the merge policy's algebra flags (§4.3): Conflate requires merge.Conflates. Returns ErrConflateNotBounding otherwise.

func (*RelayCell[T]) Depth added in v0.11.0

func (r *RelayCell[T]) Depth() uint64

Depth is the demand-driven reader: current window depth (Count).

func (*RelayCell[T]) DepthSlot added in v0.11.0

func (r *RelayCell[T]) DepthSlot() *Computed[uint64]

DepthSlot / IsFullSlot / IsEmptySlot expose the reader slots for wiring into effects and computations.

func (*RelayCell[T]) Drain added in v0.11.0

func (r *RelayCell[T]) Drain() (T, bool)

Drain takes the hot head's value and resets the window. The second return is false for an empty window. relay_converges guarantees the egress fold equals the flat fold of every ingested op, for any drain schedule.

func (*RelayCell[T]) Ingress added in v0.11.0

func (r *RelayCell[T]) Ingress(op T) IngressOutcome

Ingress ingests one op. Applies the reactive overflow policy when the window is at HighWater; otherwise merges the op into the hot head under the merge policy.

func (*RelayCell[T]) IsEmpty added in v0.11.0

func (r *RelayCell[T]) IsEmpty() bool

IsEmpty is the demand-driven reader: window is empty (nothing to drain).

func (*RelayCell[T]) IsEmptySlot added in v0.11.0

func (r *RelayCell[T]) IsEmptySlot() *Computed[bool]

func (*RelayCell[T]) IsFull added in v0.11.0

func (r *RelayCell[T]) IsFull() bool

IsFull is the demand-driven reader: window is at/over HighWater.

func (*RelayCell[T]) IsFullSlot added in v0.11.0

func (r *RelayCell[T]) IsFullSlot() *Computed[bool]

func (*RelayCell[T]) OverflowIsLegal added in v0.11.0

func (r *RelayCell[T]) OverflowIsLegal() bool

OverflowIsLegal reports whether the current overflow choice is legal for the merge policy — a runtime guard mirroring NewRelayCell's construction check (the overflow cell is reactive).

func (*RelayCell[T]) Peek added in v0.11.0

func (r *RelayCell[T]) Peek() (T, bool)

Peek returns the current coalesced window without draining.

type RelayConfigError added in v0.11.0

type RelayConfigError struct {
	// contains filtered or unexported fields
}

RelayConfigError is why a construction/merge-swap was rejected (§4.3).

func (*RelayConfigError) Error added in v0.11.0

func (e *RelayConfigError) Error() string

type RemoteOp

type RemoteOp struct {
	Kind OpKind `json:"kind"`
	Node NodeId `json:"node"`
}

RemoteOp is a { kind, node } gated remote operation.

func ReadOp

func ReadOp(node NodeId) RemoteOp

ReadOp constructs a read RemoteOp.

func TriggerEffectOp

func TriggerEffectOp(node NodeId) RemoteOp

TriggerEffectOp constructs a trigger_effect RemoteOp.

func WriteOp

func WriteOp(node NodeId) RemoteOp

WriteOp constructs a write RemoteOp.

func (RemoteOp) String

func (o RemoteOp) String() string

type ResyncAction added in v0.8.0

type ResyncAction int

ResyncAction is the receiver decision for an inbound frame (spec § ResyncCoordinator). When the action is ResyncActionRequestSnapshot the ingest method also returns the from-epoch the sender must cover; the from-epoch is zero and meaningless for the other actions.

const (
	// ResyncActionApply means apply the frame and advance the receiver epoch.
	ResyncActionApply ResyncAction = iota
	// ResyncActionRequestSnapshot means a gap was detected; request a fresh
	// Snapshot covering the returned from-epoch.
	ResyncActionRequestSnapshot
	// ResyncActionIgnore means drop the frame (already-applied re-delivery,
	// malformed, a duplicate request suppressed while resyncing, or a
	// reverse-channel control frame arriving at a data receiver).
	ResyncActionIgnore
)

func (ResyncAction) String added in v0.8.0

func (a ResyncAction) String() string

String renders the action name (parity with the fixture expect_action words).

type ResyncCoordinator added in v0.8.0

type ResyncCoordinator struct {
	// contains filtered or unexported fields
}

ResyncCoordinator is the receiver-side reliable-sync coordinator.

It holds lastEpoch (the highest epoch fully applied) and a resyncing flag (a RequestSnapshot is outstanding until a covering Snapshot lands, so further ahead-of-cursor deltas are ignored instead of re-requesting).

Ingest advances lastEpoch on Apply — the caller MUST fold the frame's ops into its projection on Apply. This mirrors the ReliableSync.step Lean model.

func NewResyncCoordinator added in v0.8.0

func NewResyncCoordinator() *ResyncCoordinator

NewResyncCoordinator returns a coordinator at epoch 0 (fresh; a Snapshot seeds the first real epoch).

func NewResyncCoordinatorWithEpoch added in v0.8.0

func NewResyncCoordinatorWithEpoch(lastEpoch Epoch) *ResyncCoordinator

NewResyncCoordinatorWithEpoch returns a coordinator that has already applied through lastEpoch.

func (*ResyncCoordinator) Ack added in v0.8.0

func (c *ResyncCoordinator) Ack() IpcMessage

Ack returns the OutboxAck control frame that advertises this receiver's resume cursor on reconnect (and for periodic retention advance).

func (*ResyncCoordinator) Ingest added in v0.8.0

func (c *ResyncCoordinator) Ingest(msg IpcMessage) (ResyncAction, Epoch)

Ingest classifies an inbound IpcMessage. CrdtSync is handled by the CRDT plane, and the reverse-channel control frames (ResyncRequest / OutboxAck) are for the sender's driver, not this data receiver, so both are Ignored here.

func (*ResyncCoordinator) IngestDelta added in v0.8.0

func (c *ResyncCoordinator) IngestDelta(delta Delta) (ResyncAction, Epoch)

IngestDelta classifies and folds an inbound Delta. On Apply this advances lastEpoch to delta.Epoch (multi-epoch-span aware) and clears resyncing. The second return value is the request-from epoch (only meaningful for ResyncActionRequestSnapshot).

func (*ResyncCoordinator) IngestSnapshot added in v0.8.0

func (c *ResyncCoordinator) IngestSnapshot(snapshotEpoch Epoch) (ResyncAction, Epoch)

IngestSnapshot adopts a Snapshot at snapshotEpoch — a full-state frame always applies, setting lastEpoch and clearing resyncing.

func (*ResyncCoordinator) IsResyncing added in v0.8.0

func (c *ResyncCoordinator) IsResyncing() bool

IsResyncing reports whether a resync request is outstanding (awaiting a covering snapshot).

func (*ResyncCoordinator) LastEpoch added in v0.8.0

func (c *ResyncCoordinator) LastEpoch() Epoch

LastEpoch returns the highest epoch fully applied.

type ResyncRequest added in v0.8.0

type ResyncRequest struct {
	// FromEpoch is the requesting receiver's last_epoch; the sender replies with
	// a Snapshot { epoch >= from_epoch }.
	FromEpoch Epoch `json:"from_epoch"`
}

ResyncRequest is a reliable-sync reverse-channel control frame: request a covering Snapshot on a detected gap (#lzsync, spec § ResyncCoordinator). It carries no node content, so it is permission-filter- and blob-spill- transparent. Wire form: {"from_epoch": N}.

type RetryPolicyCell added in v0.15.0

type RetryPolicyCell struct {
	// contains filtered or unexported fields
}

RetryPolicyCell is a reactive retry policy: projects the current delay onto a Cell.

func NewRetryPolicyCell added in v0.15.0

func NewRetryPolicyCell(ctx *Context, base, capacity uint64) *RetryPolicyCell

NewRetryPolicyCell builds a reactive retry policy.

func (*RetryPolicyCell) Delay added in v0.15.0

func (r *RetryPolicyCell) Delay() uint64

Delay returns the current projected delay.

func (*RetryPolicyCell) DelayCell added in v0.15.0

func (r *RetryPolicyCell) DelayCell() *Source[uint64]

DelayCell returns the reactive delay reader.

func (*RetryPolicyCell) NextDelay added in v0.15.0

func (r *RetryPolicyCell) NextDelay() uint64

NextDelay returns the current attempt's delay, advances, and projects it.

func (*RetryPolicyCell) Reset added in v0.15.0

func (r *RetryPolicyCell) Reset()

Reset resets the attempt counter and the projected delay.

type RetryPolicyCore added in v0.15.0

type RetryPolicyCore struct {
	// contains filtered or unexported fields
}

RetryPolicyCore is the exponential-backoff compute core: delay(attempt) = min(cap, base*2^attempt), saturating to cap on shift overflow.

func NewRetryPolicyCore added in v0.15.0

func NewRetryPolicyCore(base, capacity uint64) *RetryPolicyCore

NewRetryPolicyCore builds a core.

func (*RetryPolicyCore) Delay added in v0.15.0

func (r *RetryPolicyCore) Delay(attempt uint32) uint64

Delay returns the delay for attempt, saturating at cap.

func (*RetryPolicyCore) NextDelay added in v0.15.0

func (r *RetryPolicyCore) NextDelay() uint64

NextDelay returns the current attempt's delay, then advances.

func (*RetryPolicyCore) Reset added in v0.15.0

func (r *RetryPolicyCore) Reset()

Reset resets the attempt counter.

type RevisionBarrier added in v0.25.0

type RevisionBarrier struct {
	// contains filtered or unexported fields
}

RevisionBarrier separates the authoritative revision from its wake generation. Receipts may wake a waiter, but only an accepted revision advance mutates either observable counter.

func NewRevisionBarrier added in v0.25.0

func NewRevisionBarrier(revision, requiredRevision uint64, deadline *uint64) *RevisionBarrier

func (*RevisionBarrier) Advance added in v0.25.0

func (b *RevisionBarrier) Advance(revision uint64, predicate bool) RevisionBarrierObservation

func (*RevisionBarrier) Dispose added in v0.25.0

func (*RevisionBarrier) Observe added in v0.25.0

func (b *RevisionBarrier) Observe(
	now uint64,
	predicate bool,
	cancellation func() TimeoutCancellation,
) RevisionBarrierObservation

func (*RevisionBarrier) Receipt added in v0.25.0

Receipt is deliberately not an authority for barrier progress.

func (*RevisionBarrier) RegisterRecheck added in v0.25.0

func (b *RevisionBarrier) RegisterRecheck(
	now, observedRevision uint64,
	predicate bool,
) RevisionBarrierObservation

RegisterRecheck models register-then-recheck: a revision accepted during registration is applied before the predicate is checked.

type RevisionBarrierObservation added in v0.25.0

type RevisionBarrierObservation struct {
	Outcome    string
	Reason     string
	Revision   uint64
	Generation uint64
}

RevisionBarrierObservation is the portable logical observation of a barrier.

type RoutedFrame

type RoutedFrame struct {
	ConnID  any
	Message ServerMessage
}

RoutedFrame pairs a target connection id with the ServerMessage to deliver on that connection. ConnID is an opaque, caller-supplied handle (mirroring the Dart `Object connId`); it must be a comparable value (usable as a map key).

func NewRoutedFrame

func NewRoutedFrame(connID any, message ServerMessage) RoutedFrame

NewRoutedFrame constructs a RoutedFrame.

type SampleCell added in v0.15.0

type SampleCell[T comparable] struct {
	// contains filtered or unexported fields
}

SampleCell is the reactive sampler over any comparable-valued source.

func NewSampleCell added in v0.15.0

func NewSampleCell[T comparable](ctx *Context, mode SampleMode) *SampleCell[T]

NewSampleCell builds a reactive sampler bound to ctx.

func (*SampleCell[T]) Input added in v0.15.0

func (c *SampleCell[T]) Input(v T) Opt[T]

Input records an input, returning the emitted value (if any).

func (*SampleCell[T]) Output added in v0.15.0

func (c *SampleCell[T]) Output() Opt[T]

Output returns the last emitted value (subscribes the current computation).

func (*SampleCell[T]) OutputCell added in v0.15.0

func (c *SampleCell[T]) OutputCell() *Source[Opt[T]]

OutputCell exposes the reader cell for invalidation observation.

func (*SampleCell[T]) Tick added in v0.15.0

func (c *SampleCell[T]) Tick(now uint64) Opt[T]

Tick advances the clock, returning the emitted value (if any).

type SampleCore added in v0.15.0

type SampleCore[T comparable] struct {
	// contains filtered or unexported fields
}

SampleCore is the deterministic sampling compute core.

func NewSampleCore added in v0.15.0

func NewSampleCore[T comparable](mode SampleMode) *SampleCore[T]

NewSampleCore builds a sampling core.

func (*SampleCore[T]) Input added in v0.15.0

func (c *SampleCore[T]) Input(v T) Opt[T]

Input records an input. Count mode emits on every n-th; Time mode holds the latest for the next boundary.

func (*SampleCore[T]) Tick added in v0.15.0

func (c *SampleCore[T]) Tick(now uint64) Opt[T]

Tick advances. Time mode emits the held latest once per period boundary crossed.

type SampleKind added in v0.15.0

type SampleKind int

SampleKind selects count-based vs time-based sampling.

const (
	// SampleCountKind: emit every n-th input.
	SampleCountKind SampleKind = iota
	// SampleTimeKind: emit the held latest at each period boundary.
	SampleTimeKind
)

type SampleMode added in v0.15.0

type SampleMode struct {
	Kind   SampleKind
	N      uint64
	Period uint64
}

SampleMode is the sampling mode for SampleCore — the Go analogue of rs `SampleMode::Count(n)` / `SampleMode::Time(period)`.

func SampleCount added in v0.15.0

func SampleCount(n uint64) SampleMode

SampleCount builds a count-based mode (emit every n-th input).

func SampleTime added in v0.15.0

func SampleTime(period uint64) SampleMode

SampleTime builds a time-based mode (emit at each period boundary).

type SampleRng added in v0.15.0

type SampleRng interface {
	NextFloat64() float64
}

SampleRng is an injectable RNG so probabilistic sampling is deterministic under a fixed seed. NextFloat64 yields a draw in [0, 1).

type SemTree

type SemTree[V comparable, D comparable] struct {
	// contains filtered or unexported fields
}

SemTree is a memoized semantic tree.

Build via BuildSemTree. The child-slot map is fixed at build time; inserting a brand-new child requires a fresh build (mirrors lazily-rs/lazily-kt). Removals mutate the parent's child-keys cell.

func BuildSemTree

func BuildSemTree[V comparable, D comparable](
	ctx *Context,
	rootSpec TreeNodeSpec[V],
	fold FoldFn[V, D],
) *SemTree[V, D]

BuildSemTree builds a SemTree from rootSpec using fold.

func (*SemTree[V, D]) IsCached

func (t *SemTree[V, D]) IsCached(id string) bool

IsCached reports whether node id's derived value is currently cached.

func (*SemTree[V, D]) NodeHandle

func (t *SemTree[V, D]) NodeHandle(id string) (*Computed[D], bool)

NodeHandle returns the slot handle for node id and true, or nil and false if the node is absent.

func (*SemTree[V, D]) NodeValue

func (t *SemTree[V, D]) NodeValue(id string) (D, bool)

NodeValue returns the derived value of node id and true, or the zero value and false if the node is absent.

func (*SemTree[V, D]) RemoveChild

func (t *SemTree[V, D]) RemoveChild(parentID, childID string) error

RemoveChild removes childID from parentID's ordered children. Returns an error if the parent is absent.

func (*SemTree[V, D]) RootHandle

func (t *SemTree[V, D]) RootHandle() *Computed[D]

RootHandle returns the root slot handle.

func (*SemTree[V, D]) SetValue

func (t *SemTree[V, D]) SetValue(id string, value V) error

SetValue sets the value of node id. Returns an error if the node is absent.

func (*SemTree[V, D]) Value

func (t *SemTree[V, D]) Value() D

Value returns the root's derived value (reactive read).

type SemaphoreCell added in v0.15.0

type SemaphoreCell struct {
	// contains filtered or unexported fields
}

SemaphoreCell is a reactive semaphore: projects permits_available onto a Cell.

func NewSemaphoreCell added in v0.15.0

func NewSemaphoreCell(ctx *Context, capacity uint64) *SemaphoreCell

NewSemaphoreCell constructs a reactive semaphore of the given capacity.

func (*SemaphoreCell) Acquire added in v0.15.0

func (c *SemaphoreCell) Acquire() bool

Acquire takes a permit if one is available.

func (*SemaphoreCell) PermitsAvailable added in v0.15.0

func (c *SemaphoreCell) PermitsAvailable() uint64

PermitsAvailable returns the number of free permits.

func (*SemaphoreCell) PermitsAvailableCell added in v0.15.0

func (c *SemaphoreCell) PermitsAvailableCell() *Source[uint64]

PermitsAvailableCell exposes the reactive permits_available projection.

func (*SemaphoreCell) Release added in v0.15.0

func (c *SemaphoreCell) Release()

Release returns a permit, saturating at capacity.

type SemaphoreCore added in v0.15.0

type SemaphoreCore struct {
	// contains filtered or unexported fields
}

SemaphoreCore is a bounded permit pool compute core.

func NewSemaphoreCore added in v0.15.0

func NewSemaphoreCore(capacity uint64) *SemaphoreCore

NewSemaphoreCore returns a permit pool of the given capacity.

func (*SemaphoreCore) Acquire added in v0.15.0

func (c *SemaphoreCore) Acquire() bool

Acquire takes a permit if one is available.

func (*SemaphoreCore) Available added in v0.15.0

func (c *SemaphoreCore) Available() uint64

Available returns the number of free permits.

func (*SemaphoreCore) Release added in v0.15.0

func (c *SemaphoreCore) Release()

Release returns a permit, saturating at capacity.

type SeqCrdt

type SeqCrdt[Id comparable, V any] struct {
	// contains filtered or unexported fields
}

SeqCrdt is a move-aware sequence CRDT. IDs are caller-supplied. Id must be comparable (it keys the entry map); V is unconstrained.

func NewSeqCrdt

func NewSeqCrdt[Id comparable, V any](peer PeerId) *SeqCrdt[Id, V]

NewSeqCrdt creates an empty sequence CRDT for the given peer.

func (*SeqCrdt[Id, V]) Clone

func (s *SeqCrdt[Id, V]) Clone() *SeqCrdt[Id, V]

Clone deep-copies the CRDT with the same peer id.

func (*SeqCrdt[Id, V]) Contains

func (s *SeqCrdt[Id, V]) Contains(id Id) bool

Contains reports whether id exists and is not tombstoned.

func (*SeqCrdt[Id, V]) EntryCount

func (s *SeqCrdt[Id, V]) EntryCount() int

EntryCount returns the total entry count including tombstones.

func (*SeqCrdt[Id, V]) Fork

func (s *SeqCrdt[Id, V]) Fork(peer PeerId) *SeqCrdt[Id, V]

Fork deep-copies the CRDT with a new peer id, preserving the clock state.

func (*SeqCrdt[Id, V]) Gc

func (s *SeqCrdt[Id, V]) Gc(watermark HlcStamp) int

Gc garbage-collects entries tombstoned at or before watermark.

func (*SeqCrdt[Id, V]) GcWith

func (s *SeqCrdt[Id, V]) GcWith(isStable func(stamp HlcStamp) bool) int

GcWith garbage-collects entries whose tombstone is stable per isStable. Returns the number of removed entries.

func (*SeqCrdt[Id, V]) Get

func (s *SeqCrdt[Id, V]) Get(id Id) (V, bool)

Get returns the value for id and true, or the zero value and false if the element is absent or tombstoned.

func (*SeqCrdt[Id, V]) InsertBack

func (s *SeqCrdt[Id, V]) InsertBack(id Id, value V, nowMicros int64)

InsertBack inserts at the back (+∞).

func (*SeqCrdt[Id, V]) InsertBetween

func (s *SeqCrdt[Id, V]) InsertBetween(id Id, value V, left, right *Id, nowMicros int64)

InsertBetween inserts a new element between left and right (nil means -∞/+∞). No-op if id already exists.

func (*SeqCrdt[Id, V]) InsertFront

func (s *SeqCrdt[Id, V]) InsertFront(id Id, value V, nowMicros int64)

InsertFront inserts at the front (-∞).

func (*SeqCrdt[Id, V]) Len

func (s *SeqCrdt[Id, V]) Len() int

Len returns the count of live elements.

func (*SeqCrdt[Id, V]) Merge

func (s *SeqCrdt[Id, V]) Merge(other *SeqCrdt[Id, V], nowMicros int64) bool

Merge folds another replica's state into this one. Returns whether anything changed. The clock is advanced past every remote stamp first.

func (*SeqCrdt[Id, V]) MoveAfter

func (s *SeqCrdt[Id, V]) MoveAfter(id, anchor Id, nowMicros int64) bool

MoveAfter moves id to just after anchor.

func (*SeqCrdt[Id, V]) MoveBefore

func (s *SeqCrdt[Id, V]) MoveBefore(id, anchor Id, nowMicros int64) bool

MoveBefore moves id to just before anchor.

func (*SeqCrdt[Id, V]) MoveBetween

func (s *SeqCrdt[Id, V]) MoveBetween(id Id, left, right *Id, nowMicros int64) bool

MoveBetween moves id between left and right (nil means -∞/+∞) via a single LWW reassignment of the position register. Returns whether the move applied.

func (*SeqCrdt[Id, V]) Order

func (s *SeqCrdt[Id, V]) Order() []Id

Order returns the live element ids in position order.

func (*SeqCrdt[Id, V]) Peer

func (s *SeqCrdt[Id, V]) Peer() PeerId

Peer returns this replica's peer id.

func (*SeqCrdt[Id, V]) Remove

func (s *SeqCrdt[Id, V]) Remove(id Id, nowMicros int64) bool

Remove tombstones id. Returns whether the removal applied.

func (*SeqCrdt[Id, V]) SetValue

func (s *SeqCrdt[Id, V]) SetValue(id Id, value V, nowMicros int64) bool

SetValue updates the value of id. Returns whether it changed.

func (*SeqCrdt[Id, V]) TombstoneCount

func (s *SeqCrdt[Id, V]) TombstoneCount() int

TombstoneCount returns the count of tombstoned elements.

func (*SeqCrdt[Id, V]) Values

func (s *SeqCrdt[Id, V]) Values() []SeqValue[Id, V]

Values returns the live (id, value) pairs in position order.

type SeqValue

type SeqValue[Id comparable, V any] struct {
	Id    Id
	Value V
}

SeqValue is a live (id, value) pair in position order, returned by SeqCrdt.Values.

type ServerAnswer

type ServerAnswer struct {
	From PeerId
	Sdp  string
}

ServerAnswer is a forwarded WebRTC SDP answer, stamped with the sender's From.

func (ServerAnswer) MarshalJSON

func (m ServerAnswer) MarshalJSON() ([]byte, error)

func (ServerAnswer) Type

func (ServerAnswer) Type() string

type ServerError

type ServerError struct {
	Code    string
	Message string
}

ServerError reports a rejected client frame. Code is the wire string form of a SignalingErrorCode.

func (ServerError) MarshalJSON

func (m ServerError) MarshalJSON() ([]byte, error)

func (ServerError) Type

func (ServerError) Type() string

type ServerIce

type ServerIce struct {
	From      PeerId
	Candidate string
}

ServerIce is a forwarded ICE candidate, stamped with the sender's From.

func (ServerIce) MarshalJSON

func (m ServerIce) MarshalJSON() ([]byte, error)

func (ServerIce) Type

func (ServerIce) Type() string

type ServerMessage

type ServerMessage interface {
	// Type returns the wire discriminant.
	Type() string
	MarshalJSON() ([]byte, error)
	// contains filtered or unexported methods
}

ServerMessage is a server -> client signaling frame. It is a sealed union (mirroring the Dart `sealed class ServerMessage`); concrete variants are ServerWelcome/ServerPeerJoined/ServerPeerLeft/ServerOffer/ServerAnswer/ ServerIce/ServerRelay/ServerError. Decode wire bytes with ParseServerMessage; each variant implements MarshalJSON.

func ParseServerMessage

func ParseServerMessage(data []byte) (ServerMessage, error)

ParseServerMessage decodes an internally-tagged server frame from JSON bytes.

type ServerOffer

type ServerOffer struct {
	From PeerId
	Sdp  string
}

ServerOffer is a forwarded WebRTC SDP offer, stamped with the sender's From.

func (ServerOffer) MarshalJSON

func (m ServerOffer) MarshalJSON() ([]byte, error)

func (ServerOffer) Type

func (ServerOffer) Type() string

type ServerPeerJoined

type ServerPeerJoined struct {
	Peer PeerId
}

ServerPeerJoined notifies existing peers that a new peer joined.

func (ServerPeerJoined) MarshalJSON

func (m ServerPeerJoined) MarshalJSON() ([]byte, error)

func (ServerPeerJoined) Type

func (ServerPeerJoined) Type() string

type ServerPeerLeft

type ServerPeerLeft struct {
	Peer PeerId
}

ServerPeerLeft notifies remaining peers that a peer disconnected.

func (ServerPeerLeft) MarshalJSON

func (m ServerPeerLeft) MarshalJSON() ([]byte, error)

func (ServerPeerLeft) Type

func (ServerPeerLeft) Type() string

type ServerRelay

type ServerRelay struct {
	From    PeerId
	Payload json.RawMessage
}

ServerRelay is a forwarded opaque payload, stamped with the sender's From.

func (ServerRelay) MarshalJSON

func (m ServerRelay) MarshalJSON() ([]byte, error)

func (ServerRelay) Type

func (ServerRelay) Type() string

type ServerWelcome

type ServerWelcome struct {
	Peer  PeerId
	Peers []PeerId
}

ServerWelcome is sent to a joiner with the roster (excluding self). Peers is always emitted, as [] when empty.

func (ServerWelcome) MarshalJSON

func (m ServerWelcome) MarshalJSON() ([]byte, error)

func (ServerWelcome) Type

func (ServerWelcome) Type() string

type ServiceRegistry added in v0.15.0

type ServiceRegistry struct {
	// contains filtered or unexported fields
}

ServiceRegistry is the reactive durable service registry. The projection is a collection reader, so it uses the version-cell pattern.

func NewServiceRegistry added in v0.15.0

func NewServiceRegistry(ctx *Context) *ServiceRegistry

NewServiceRegistry creates a reactive durable registry bound to ctx.

func (*ServiceRegistry) Deregister added in v0.15.0

func (r *ServiceRegistry) Deregister(service string)

Deregister appends a deregister op and refreshes the projection.

func (*ServiceRegistry) Projection added in v0.15.0

func (r *ServiceRegistry) Projection() map[string]string

Projection returns the current projection, subscribing the reader to the version cell.

func (*ServiceRegistry) ProjectionCell added in v0.15.0

func (r *ServiceRegistry) ProjectionCell() *Source[uint64]

ProjectionCell returns the underlying version cell (the reactive handle).

func (*ServiceRegistry) Register added in v0.15.0

func (r *ServiceRegistry) Register(service string, endpoint string)

Register appends a register op and refreshes the projection.

func (*ServiceRegistry) Replay added in v0.15.0

func (r *ServiceRegistry) Replay()

Replay rebuilds the projection from the durable log and refreshes.

type ServiceRegistryCore added in v0.15.0

type ServiceRegistryCore struct {
	// contains filtered or unexported fields
}

ServiceRegistryCore is the durable service-registry core: an ordered log (the DurableOutbox pattern) whose left-fold is the projection, so replay reconstructs it.

func NewServiceRegistryCore added in v0.15.0

func NewServiceRegistryCore() *ServiceRegistryCore

NewServiceRegistryCore creates an empty durable registry core.

func (*ServiceRegistryCore) Deregister added in v0.15.0

func (c *ServiceRegistryCore) Deregister(service string)

Deregister appends a deregister op to the log and updates the projection.

func (*ServiceRegistryCore) Projection added in v0.15.0

func (c *ServiceRegistryCore) Projection() map[string]string

Projection returns a snapshot of the current projection.

func (*ServiceRegistryCore) Register added in v0.15.0

func (c *ServiceRegistryCore) Register(service string, endpoint string)

Register appends a register op to the log and updates the projection.

func (*ServiceRegistryCore) Replay added in v0.15.0

func (c *ServiceRegistryCore) Replay()

Replay rebuilds the projection from the durable log (restart / crash-replay).

type SessionCore added in v0.15.0

type SessionCore[T comparable] struct {
	// contains filtered or unexported fields
}

SessionCore is the gap-based sessionization compute core.

func NewSessionCore added in v0.15.0

func NewSessionCore[T comparable](gap uint64, policy MergePolicy[T]) *SessionCore[T]

NewSessionCore builds a session core closing sessions after an idle `gap`.

func (*SessionCore[T]) Flush added in v0.15.0

func (c *SessionCore[T]) Flush(now uint64) Opt[T]

Flush closes the open session if it has been idle longer than `gap`.

func (*SessionCore[T]) Push added in v0.15.0

func (c *SessionCore[T]) Push(now uint64, v T) Opt[T]

Push adds an element; a gap larger than `gap` closes the current session (emitting its fold) and opens a new one.

type SessionWindow added in v0.15.0

type SessionWindow[T comparable] struct {
	// contains filtered or unexported fields
}

SessionWindow is a reactive gap-based session window (Push(now,v) + Flush(now)).

func Session added in v0.15.0

func Session[T comparable](ctx *Context, gap uint64, policy MergePolicy[T]) *SessionWindow[T]

Session constructs a reactive session window over ctx.

func (*SessionWindow[T]) Flush added in v0.15.0

func (w *SessionWindow[T]) Flush(now uint64) Opt[T]

Flush closes an idle-open session, projecting its fold onto output.

func (*SessionWindow[T]) Output added in v0.15.0

func (w *SessionWindow[T]) Output() Opt[T]

Output reads the last emitted aggregate (subscribes in a computation).

func (*SessionWindow[T]) OutputCell added in v0.15.0

func (w *SessionWindow[T]) OutputCell() *Source[Opt[T]]

OutputCell returns the reactive cell holding the last emitted aggregate.

func (*SessionWindow[T]) Push added in v0.15.0

func (w *SessionWindow[T]) Push(now uint64, v T) Opt[T]

Push adds an element; a large idle gap closes the session (projecting its fold onto output) and opens a new one.

type ShmBackend added in v0.4.0

type ShmBackend struct {
	// contains filtered or unexported fields
}

ShmBackend is a POSIX shared-memory blob backend backed by a named /dev/shm region. It implements BlobBackend with cross-process resolution: a descriptor minted by Create's handle resolves against any Open handle mapping the same region. Not safe to use after Close.

func CreateShmBackend added in v0.4.0

func CreateShmBackend(name string, capacity int) (*ShmBackend, error)

CreateShmBackend creates (or truncates) a named POSIX shared-memory region of capacity bytes and maps it MAP_SHARED. The caller owns unlink timing — call UnlinkShmBackend(name) once no further readers/writers remain.

func OpenShmBackend added in v0.4.0

func OpenShmBackend(name string) (*ShmBackend, error)

OpenShmBackend opens (without creating) an existing named POSIX shared-memory region and maps it at the capacity recorded in its header. A distinct process uses this to resolve descriptors minted by the creator.

func (*ShmBackend) AdvanceEpoch added in v0.4.0

func (b *ShmBackend) AdvanceEpoch()

AdvanceEpoch advances the region's validity epoch, invalidating every prior descriptor across all mappings.

func (*ShmBackend) Capacity added in v0.4.0

func (b *ShmBackend) Capacity() int

Capacity returns the region's total byte capacity.

func (*ShmBackend) Close added in v0.4.0

func (b *ShmBackend) Close() error

Close unmaps the region and closes the descriptor. It does not unlink the name; call UnlinkShmBackend for that.

func (*ShmBackend) Epoch added in v0.4.0

func (b *ShmBackend) Epoch() int64

Epoch returns the backend's current validity epoch.

func (*ShmBackend) Kind added in v0.4.0

func (b *ShmBackend) Kind() BlobBackendKind

Kind reports BackendShm.

func (*ShmBackend) ReadView added in v0.4.0

func (b *ShmBackend) ReadView(descriptor ShmBlobRef) ([]byte, bool)

ReadView resolves a descriptor zero-copy against the shared region: it returns a slice aliasing the mapped bytes iff the slot header's generation / len / checksum and the region's current epoch all match; (nil, false) otherwise.

func (*ShmBackend) Write added in v0.4.0

func (b *ShmBackend) Write(bytes []byte) (ShmBlobRef, error)

Write bump-allocates a slot, copies bytes into shared memory, and returns a descriptor tagged BackendShm. The bump/generation counters are advanced with atomics, so concurrent writers across mappings never overlap.

type ShmBlobArena

type ShmBlobArena struct {
	// contains filtered or unexported fields
}

ShmBlobArena is an in-process shared-memory blob arena. It manages blob storage with generation/epoch tracking and header validation, handing out ShmBlobRef descriptors that callers exchange over the control transport in place of large inline payloads.

The zero value is not usable; construct one with NewShmBlobArena.

func NewShmBlobArena

func NewShmBlobArena(epoch int64) *ShmBlobArena

NewShmBlobArena creates an empty arena starting at the given epoch (Dart's `ShmBlobArena({this.epoch = 0})`; pass 0 for the default).

func (*ShmBlobArena) AdvanceEpoch

func (a *ShmBlobArena) AdvanceEpoch()

AdvanceEpoch bumps the arena epoch and restamps every live entry, so all previously-minted descriptors become stale (their Epoch no longer matches). Mirrors Dart `advanceEpoch`.

func (*ShmBlobArena) Epoch

func (a *ShmBlobArena) Epoch() int64

Epoch returns the arena's current epoch. All descriptors carry the epoch that was current when they were minted; AdvanceEpoch invalidates them.

func (*ShmBlobArena) Free

func (a *ShmBlobArena) Free(ref ShmBlobRef) bool

Free drops one reference to a blob and reports whether the reference was released. When the reference count reaches zero the slot is reclaimed (its descriptor becomes permanently stale); the offset index is preserved so other descriptors keep resolving to the correct slots. Returns false if ref is stale or already freed. This is a genuine-arena extension with no Dart equivalent (Dart's arena never frees).

func (*ShmBlobArena) IsEmpty

func (a *ShmBlobArena) IsEmpty() bool

IsEmpty reports whether the arena holds no live blobs (Dart `isEmpty`).

func (*ShmBlobArena) Length

func (a *ShmBlobArena) Length() int

Length returns the number of live (unfreed) stored blobs. With no Free calls this equals the number of Write calls, matching the Dart `length` getter.

func (*ShmBlobArena) Read

func (a *ShmBlobArena) Read(ref ShmBlobRef) []byte

Read returns a blob's payload by descriptor, or nil if header validation fails (out-of-range offset, freed slot, or a mismatched generation, epoch, length, or checksum). The returned slice is a defensive copy. Mirrors Dart `read`, which returns null on validation failure.

func (*ShmBlobArena) ReadView added in v0.4.0

func (a *ShmBlobArena) ReadView(ref ShmBlobRef) ([]byte, bool)

ReadView resolves a descriptor zero-copy: it returns the arena's own backing payload slice (NOT a defensive copy) and ok=true iff the descriptor passes full header validation (offset in range, slot live, matching generation / epoch / len / checksum); otherwise (nil, false). This is the transport read_view primitive — the caller reads the backend's bytes in place. The returned slice aliases arena storage; the arena entry is immutable for the lifetime a descriptor may reference it (Write never mutates a stored buffer; Update/Free bump the generation, invalidating the descriptor), so the view is stable. Callers that intend to retain the bytes past a possible Free should copy. Contrast Read, which always copies.

func (*ShmBlobArena) Retain

func (a *ShmBlobArena) Retain(ref ShmBlobRef) bool

Retain increments a live blob's reference count and reports success. It fails (returns false) when ref is stale or the slot is freed. This is a genuine-arena extension with no Dart equivalent.

func (*ShmBlobArena) Update

func (a *ShmBlobArena) Update(ref ShmBlobRef, bytes []byte) *ShmBlobRef

Update rewrites an existing blob in place (bumping its generation) and returns the new descriptor, or nil if ref is stale. Mirrors Dart `update`: the payload buffer is overwritten from offset 0 and keeps its original length, so the new descriptor's Len matches the stored buffer, not len(bytes). bytes longer than the stored payload are truncated (Go copy semantics) instead of raising, keeping the operation recoverable.

func (*ShmBlobArena) Write

func (a *ShmBlobArena) Write(bytes []byte) ShmBlobRef

Write allocates a blob and returns its descriptor. The payload bytes are copied into the arena; the returned ShmBlobRef is the header a reader validates. The blob starts with a reference count of one (mirrors Dart's `write`, which has no free path).

type ShmBlobRef

type ShmBlobRef struct {
	Offset     int64           `json:"offset"`
	Len        int64           `json:"len"`
	Generation int64           `json:"generation"`
	Epoch      int64           `json:"epoch"`
	Checksum   int64           `json:"checksum"`
	Backend    BlobBackendKind `json:"backend,omitempty"`
}

ShmBlobRef is a descriptor into a blob backend (zero-copy transport). The arena writes a fixed header { generation, epoch, length, checksum } before each payload; this struct is the wire mirror of that descriptor. The optional Backend discriminator selects which pluggable backend resolves it; it defaults to Shm and is omitted on the wire when default, so legacy descriptors validate unchanged (a strict superset of the pre-existing shared-memory blob path).

func NewShmBlobRef

func NewShmBlobRef(offset, length, generation, epoch, checksum int64) (ShmBlobRef, error)

NewShmBlobRef constructs a ShmBlobRef, rejecting negative fields.

func (ShmBlobRef) MarshalJSON added in v0.4.0

func (r ShmBlobRef) MarshalJSON() ([]byte, error)

MarshalJSON emits the descriptor with fields in schema order, omitting the `backend` field when it is the default (Shm) so the wire form is a strict superset of the legacy backend-absent descriptor.

func (ShmBlobRef) String

func (r ShmBlobRef) String() string

func (*ShmBlobRef) UnmarshalJSON

func (r *ShmBlobRef) UnmarshalJSON(b []byte) error

UnmarshalJSON validates non-negative fields to match the Dart fromWire and normalizes the optional `backend` discriminator (absent or unknown → Shm).

func (ShmBlobRef) WithBackend added in v0.4.0

func (r ShmBlobRef) WithBackend(kind BlobBackendKind) ShmBlobRef

WithBackend returns a copy of the descriptor tagged with the given backend discriminator (the producer stamps this when spilling to a non-default backend; the receiver routes resolution by it).

type SignalingErrorCode

type SignalingErrorCode string

SignalingErrorCode is the `code` of a ServerError frame. The string value is the wire form (snake_case), matching lazily-dart's enum wire tags.

const (
	// SignalingErrorBadMessage is an unparseable / malformed client frame.
	SignalingErrorBadMessage SignalingErrorCode = "bad_message"
	// SignalingErrorNotJoined is a signaling frame from a connection that has
	// not joined the session.
	SignalingErrorNotJoined SignalingErrorCode = "not_joined"
	// SignalingErrorAlreadyJoined is a join from a connection that already
	// joined.
	SignalingErrorAlreadyJoined SignalingErrorCode = "already_joined"
	// SignalingErrorDuplicatePeer is a join for a peer id already present in the
	// session.
	SignalingErrorDuplicatePeer SignalingErrorCode = "duplicate_peer"
	// SignalingErrorUnknownTarget is a directed frame to a peer not in the
	// session.
	SignalingErrorUnknownTarget SignalingErrorCode = "unknown_target"
	// SignalingErrorPermissionDenied is an allowlist-gated join or directed
	// frame that was not granted.
	SignalingErrorPermissionDenied SignalingErrorCode = "permission_denied"
)

func (SignalingErrorCode) Wire

func (c SignalingErrorCode) Wire() string

Wire returns the on-wire string form of the error code.

type SignalingMode

type SignalingMode string

SignalingMode is the permission mode for a signaling room.

const (
	// SignalingModeOpen lets any peer join and signal any other joined peer.
	SignalingModeOpen SignalingMode = "open"
	// SignalingModeAllowlist is default-deny: peers require explicit grants, and
	// directed frames only reach allowed targets.
	SignalingModeAllowlist SignalingMode = "allowlist"
)

type SignalingRoom

type SignalingRoom struct {
	// contains filtered or unexported fields
}

SignalingRoom is a transport-agnostic signaling room. A single owner goroutine owns all room and per-connection state; callers interact only through channels and the (channel-backed) methods below. It never interprets CRDT state.

func NewSignalingRoom

func NewSignalingRoom(mode SignalingMode) *SignalingRoom

NewSignalingRoom starts a signaling room in the given mode and launches its owner goroutine. Call Close to stop the room and release its goroutines.

func (*SignalingRoom) AllowJoin

func (r *SignalingRoom) AllowJoin(peer PeerId) error

AllowJoin grants peer permission to join in allowlist mode (no-op semantics in open mode, where every peer may already join).

func (*SignalingRoom) AllowSignal

func (r *SignalingRoom) AllowSignal(from, target PeerId) error

AllowSignal grants from permission to send directed frames to target in allowlist mode.

func (*SignalingRoom) Close

func (r *SignalingRoom) Close()

Close stops the room. It tears down every connection (closing outbound channels) and blocks until all owner/reader/pump goroutines have exited.

func (*SignalingRoom) Connect

func (r *SignalingRoom) Connect(connID any) (*ClientConn, error)

Connect registers a connection under connID and returns its *ClientConn. The connID must be a comparable value. It errors if the room is closed or connID is already connected.

func (*SignalingRoom) Disconnect

func (r *SignalingRoom) Disconnect(connID any) error

Disconnect tears down the connection connID, emitting peer-left to remaining peers and closing the connection's outbound channel.

func (*SignalingRoom) Roster

func (r *SignalingRoom) Roster() []PeerId

Roster returns the joined peer ids, sorted ascending.

func (*SignalingRoom) Size

func (r *SignalingRoom) Size() int

Size returns the number of joined peers.

type SlidingCore added in v0.15.0

type SlidingCore[T comparable] struct {
	// contains filtered or unexported fields
}

SlidingCore is the count-based sliding window compute core (fold-recompute, correct for any associative merge).

func NewSlidingCore added in v0.15.0

func NewSlidingCore[T comparable](size int, slide uint64, policy MergePolicy[T]) *SlidingCore[T]

NewSlidingCore builds a sliding core retaining `size` elements, emitting every `slide` pushes.

func (*SlidingCore[T]) Push added in v0.15.0

func (c *SlidingCore[T]) Push(v T) Opt[T]

Push adds an element; every `slide` pushes emit the fold over the last `size`.

type SlidingWindow added in v0.15.0

type SlidingWindow[T comparable] struct {
	// contains filtered or unexported fields
}

SlidingWindow is a reactive count-based sliding window projecting the last emitted aggregate.

func Sliding added in v0.15.0

func Sliding[T comparable](ctx *Context, size int, slide uint64, policy MergePolicy[T]) *SlidingWindow[T]

Sliding constructs a reactive sliding window over ctx.

func (*SlidingWindow[T]) Output added in v0.15.0

func (w *SlidingWindow[T]) Output() Opt[T]

Output reads the last emitted aggregate (subscribes in a computation).

func (*SlidingWindow[T]) OutputCell added in v0.15.0

func (w *SlidingWindow[T]) OutputCell() *Source[Opt[T]]

OutputCell returns the reactive cell holding the last emitted aggregate.

func (*SlidingWindow[T]) Push added in v0.15.0

func (w *SlidingWindow[T]) Push(v T) Opt[T]

Push adds an element, projecting the fold onto output on a slide boundary.

type SlotMap deprecated added in v0.7.0

type SlotMap[K comparable, V comparable] = ComputedMap[K, V]

SlotMap is the pre-v2-kernel name for ComputedMap, kept as an alias so existing callers keep compiling.

Deprecated: renamed to ComputedMap.

type Snapshot

type Snapshot struct {
	Epoch Epoch
	Nodes []NodeSnapshot
	Edges []EdgeSnapshot
	Roots []NodeId
}

Snapshot is the full graph state, sent on connect and on resync.

func (Snapshot) FilterReadable

func (s Snapshot) FilterReadable(permissions *PeerPermissions, peer PeerId) Snapshot

FilterReadable drops non-readable nodes/edges/roots before serialization (omission, not redaction — protocol.md § Permission Boundary).

func (Snapshot) MarshalJSON

func (s Snapshot) MarshalJSON() ([]byte, error)

MarshalJSON emits { epoch, nodes, edges, roots }, always as arrays (never null) to match the Dart toWire.

func (*Snapshot) UnmarshalJSON

func (s *Snapshot) UnmarshalJSON(b []byte) error

type SnapshotProvider added in v0.8.0

type SnapshotProvider interface {
	// Snapshot returns a full-state IpcMessageSnapshot covering fromEpoch (its
	// epoch MUST be >= fromEpoch).
	Snapshot(fromEpoch Epoch) IpcMessage
}

SnapshotProvider is the sender-side answer to a peer's ResyncRequest (spec § SyncDriver). When a receiver detects a gap it can no longer close from retained deltas, it asks for a covering Snapshot; the host plugs its projection in here to produce one at epoch >= fromEpoch.

type Source added in v0.10.0

type Source[T comparable] struct {
	// contains filtered or unexported fields
}

Source is a value written from outside the graph; it invalidates its dependents when it changes. It is the source kind of the Cell genus (Cell[T]): the only kind that carries Set/Merge. A Computed computes from upstream and has neither, so `formulaCell.Set(…)` does not compile — the write protection the Cell kernel design (§3/§4) puts in the type rather than a runtime gate.

A Source folds writes under a MergePolicy M. The default policy is KeepLatest, so a plain Source is exactly the old plain Cell; a Source with M ≠ KeepLatest is the old MergeCell. One kind, the policy in a field — the Go analogue of the design's Source<T, M>.

Reading Get inside a Computed/Effect computation registers a dependency. Set triggers a cascade only when the new value is not equal to the old one — the ==-guard. Source uses Go == for equality, so T must be comparable.

func NewSource added in v0.21.0

func NewSource[T comparable](ctx *Context, initial T) *Source[T]

NewSource creates a mutable source cell bound to ctx under the default KeepLatest policy (the plain cell). This is the design's source(v).

func NewSourceWithPolicy added in v0.21.0

func NewSourceWithPolicy[T comparable](ctx *Context, initial T, policy MergePolicy[T]) *Source[T]

NewSourceWithPolicy creates a source cell whose Merge folds under policy — the design's source::<M>(v). With KeepLatest it is a plain cell; with Sum/Max it is the former MergeCell.

func (*Source[T]) Dispose added in v0.21.0

func (c *Source[T]) Dispose()

Dispose tears down this source cell: detaches its dependents and dirties the surviving cone. Cells have no dependencies, so only downstream edges need detaching. Same contract as Slot.Dispose. Idempotent.

func (*Source[T]) Get added in v0.21.0

func (c *Source[T]) Get() T

Get reads the value. Reading inside a computation subscribes the reader.

Panics with a *DisposedError if this cell has been disposed; use TryGet for the checked form.

func (*Source[T]) Invalidate added in v0.21.0

func (c *Source[T]) Invalidate()

Invalidate force-invalidates this cell's dependents without changing the value. Used by collection layers when an entry is removed.

func (*Source[T]) Merge added in v0.10.0

func (c *Source[T]) Merge(op T)

Merge folds op into the current value under this cell's policy and writes the result through the ==-guarded Set, so an idempotent policy's no-op merge fires no cascade (free dedup). Reads the current value untracked (Peek). Merge, like Set, exists only on Source — the write half of the Cell genus.

func (*Source[T]) Peek added in v0.21.0

func (c *Source[T]) Peek() T

Peek returns the current value without registering a dependency.

func (*Source[T]) Policy added in v0.21.0

func (c *Source[T]) Policy() MergePolicy[T]

Policy returns this cell's merge policy.

func (*Source[T]) Set added in v0.10.0

func (c *Source[T]) Set(newValue T)

Set assigns a new value. If newValue != old, dependents are invalidated. Writing a disposed cell is a no-op: it has no dependents left to notify.

func (*Source[T]) TryGet added in v0.21.0

func (c *Source[T]) TryGet() (T, error)

TryGet reads the cell, returning a *DisposedError if it has been disposed.

type SourceMap added in v0.22.0

type SourceMap[K comparable, V comparable] struct {
	*ReactiveMap[K, V, *Source[V]]
}

SourceMap is the input-cell specialization of ReactiveMap: a keyed collection of reactive cells with independent value / membership / order reactivity (cell-model.md § Keyed cell collections).

Each entry is an ordinary Cell[V]; the collection adds no new merge unit. The shared reactive-membership / order / move / remove surface is inherited from the embedded ReactiveMap; SourceMap adds the cell-only Set and eager value-minting (Entry / EntryWith), plus the Go-specific Insert / Reconcile keyed-reconciliation helpers.

  • Keys subscribes only to the order signal;
  • Len / ContainsKey subscribe only to the membership signal;
  • a value read subscribes only to that entry's cell.

An atomic move (MoveTo / MoveBefore / MoveAfter, inherited) bumps only the order signal once and keeps the moved entry's same Cell handle, dependents, and lineage — it is not a remove + re-mint.

func NewCellMap deprecated

func NewCellMap[K comparable, V comparable](ctx *Context) *SourceMap[K, V]

NewCellMap creates an empty keyed cell collection bound to ctx.

Deprecated: renamed to NewSourceMap.

func NewSourceMap added in v0.22.0

func NewSourceMap[K comparable, V comparable](ctx *Context) *SourceMap[K, V]

NewSourceMap creates an empty keyed cell collection bound to ctx.

func (*SourceMap[K, V]) Cell added in v0.22.0

func (m *SourceMap[K, V]) Cell(key K) *Source[V]

Cell returns the existing value cell for key, or nil. Non-reactive: does not subscribe the caller to membership.

func (*SourceMap[K, V]) Entry added in v0.22.0

func (m *SourceMap[K, V]) Entry(key K, defaultValue V) *Source[V]

Entry returns the value cell for key, minting it with defaultValue on first access. Convenience wrapper over EntryWith.

func (*SourceMap[K, V]) EntryWith added in v0.22.0

func (m *SourceMap[K, V]) EntryWith(key K, defaultValue func() V) *Source[V]

EntryWith returns the value cell for key, minting it with defaultValue() on first access. Adding a new key bumps reactive membership; re-fetching an existing key does not.

func (*SourceMap[K, V]) Get added in v0.22.0

func (m *SourceMap[K, V]) Get(key K) (V, bool)

Get reads the value at key if present (peek). Non-reactive.

func (*SourceMap[K, V]) Insert added in v0.22.0

func (m *SourceMap[K, V]) Insert(key K, value V, at InsertAt, anchor K) bool

Insert inserts key with value at the position specified by at (relative to anchor for InsertAtBefore / InsertAtAfter; anchor is ignored otherwise). Bumps membership + order. Returns whether the key was newly inserted (false if it already existed; in that case the value is updated in place and only the entry's value readers invalidate).

Go lacks Dart's optional named args: pass InsertAtEnd with a zero anchor for the common append case.

func (*SourceMap[K, V]) Read added in v0.22.0

func (m *SourceMap[K, V]) Read(key K) (V, bool)

Read reads the value at key if present, subscribing the caller to that entry's cell (reactive inside a Slot / Signal computation).

func (*SourceMap[K, V]) Reconcile added in v0.22.0

func (m *SourceMap[K, V]) Reconcile(targetOrder []K, targetValues map[K]V)

Reconcile reconciles to targetOrder + targetValues: compute the minimal diff and apply it per-cell. Stable entries (unchanged value, in the LIS) keep their cell handles and stay cached.

func (*SourceMap[K, V]) Set added in v0.22.0

func (m *SourceMap[K, V]) Set(key K, value V)

Set assigns the value at key, inserting a new entry (and bumping membership) if it does not exist yet. Updating an existing entry leaves membership untouched and invalidates only that entry's dependents.

Cell-only: an input is settable; a derived ComputedMap slot is not.

type SourceTree added in v0.23.0

type SourceTree[K comparable, V comparable] struct {
	ID       K
	Value    *Source[V]
	Children *SourceMap[K, *SourceTree[K, V]]
	// contains filtered or unexported fields
}

SourceTree is an ordered keyed tree (cell-model.md § Ordered keyed tree).

Each node is (stable id, value cell, ordered keyed child collection). A node's children are a SourceMap keyed by child id, so per-level membership/order reactivity and the atomic-move guarantee are inherited. The tree is still a composition of cells — not a new cell kind — so per-cell merge applies node-by-node. Recursive, mirroring lazily-rs/src/cell_tree.rs.

func NewCellTree deprecated

func NewCellTree[K comparable, V comparable](ctx *Context, id K, initialValue V) *SourceTree[K, V]

NewCellTree creates a tree node with id and initialValue and an empty child collection.

Deprecated: renamed to NewSourceTree.

func NewSourceTree added in v0.23.0

func NewSourceTree[K comparable, V comparable](ctx *Context, id K, initialValue V) *SourceTree[K, V]

NewSourceTree creates a tree node with id and initialValue and an empty child collection.

func (*SourceTree[K, V]) Child added in v0.23.0

func (t *SourceTree[K, V]) Child(id K) *SourceTree[K, V]

Child returns the child node for id, or nil. Non-reactive.

func (*SourceTree[K, V]) ChildCount added in v0.23.0

func (t *SourceTree[K, V]) ChildCount(c ComputeOps) int

ChildCount returns the reactive child count for this node.

func (*SourceTree[K, V]) ChildIDs added in v0.23.0

func (t *SourceTree[K, V]) ChildIDs(c ComputeOps) []K

ChildIDs returns a reactive snapshot of this node's child ids in order.

func (*SourceTree[K, V]) Get added in v0.23.0

func (t *SourceTree[K, V]) Get() V

Get reads this node's value (reactive).

func (*SourceTree[K, V]) HasChild added in v0.23.0

func (t *SourceTree[K, V]) HasChild(c ComputeOps, id K) bool

HasChild reports the reactive membership test for a child of this node.

func (*SourceTree[K, V]) InsertChild added in v0.23.0

func (t *SourceTree[K, V]) InsertChild(id K, value V) *SourceTree[K, V]

InsertChild inserts a fresh child id with value, returning the child node. If the child already exists, its value is updated and the existing node returned.

func (*SourceTree[K, V]) MoveChildAfter added in v0.23.0

func (t *SourceTree[K, V]) MoveChildAfter(id, anchor K) bool

MoveChildAfter atomically moves child id to just after anchor.

func (*SourceTree[K, V]) MoveChildBefore added in v0.23.0

func (t *SourceTree[K, V]) MoveChildBefore(id, anchor K) bool

MoveChildBefore atomically moves child id to just before anchor.

func (*SourceTree[K, V]) MoveChildTo added in v0.23.0

func (t *SourceTree[K, V]) MoveChildTo(id K, index int) bool

MoveChildTo atomically moves child id to index within this node's children.

func (*SourceTree[K, V]) NodeID added in v0.23.0

func (t *SourceTree[K, V]) NodeID() K

NodeID returns the id of this node (stable handle).

func (*SourceTree[K, V]) RemoveChild added in v0.23.0

func (t *SourceTree[K, V]) RemoveChild(id K) bool

RemoveChild removes the child id. Returns whether it was present.

func (*SourceTree[K, V]) Set added in v0.23.0

func (t *SourceTree[K, V]) Set(next V)

Set sets this node's value (PartialEq-guarded).

type SpillMode added in v0.11.0

type SpillMode string

SpillMode is how spilled windows are laid out on the durable tail (§6).

const (
	// SpillCompactOnWrite merges each spilled window into the open page until it
	// fills — minimizes disk (keep-latest / semilattice). One page holds a
	// coalesced run.
	SpillCompactOnWrite SpillMode = "CompactOnWrite"
	// SpillAppendCompact appends each spilled window as its own page — preserves
	// increments for an accumulating (non-idempotent) policy that must not
	// double-count.
	SpillAppendCompact SpillMode = "AppendCompact"
)

type SpillPage added in v0.11.0

type SpillPage[T any] struct {
	ID      uint64
	Summary T
	Bytes   uint64
}

SpillPage is one immutable cold page: a coalesced window summary plus its manifest entry.

type SpillStore added in v0.11.0

type SpillStore[T any] struct {
	// contains filtered or unexported fields
}

SpillStore is a paged durable tail for a RelayCell (Phase 3, in-memory reference backend). Holds immutable cold pages, a bounded manifest, an egress cursor, and ack-before-reclaim. Memory is O(hot) + O(manifest).

func NewSpillStore added in v0.11.0

func NewSpillStore[T any](mode SpillMode, pageSize uint64, merge MergePolicy[T]) *SpillStore[T]

NewSpillStore creates a spill store in the given mode with the given page size.

func (*SpillStore[T]) AckThrough added in v0.11.0

func (s *SpillStore[T]) AckThrough(id uint64)

AckThrough acks every page through id (inclusive), advancing the reclaim cursor.

func (*SpillStore[T]) FoldPages added in v0.11.0

func (s *SpillStore[T]) FoldPages(s0 T) T

FoldPages folds every live cold page (oldest first) into s0 — the durable tail's contribution to the converged state.

func (*SpillStore[T]) Manifest added in v0.11.0

func (s *SpillStore[T]) Manifest() []ManifestEntry

Manifest returns (id, bytes) for every live page (bounded metadata).

func (*SpillStore[T]) PageCount added in v0.11.0

func (s *SpillStore[T]) PageCount() int

PageCount is the number of live pages.

func (*SpillStore[T]) PendingPages added in v0.11.0

func (s *SpillStore[T]) PendingPages() []SpillPage[T]

PendingPages returns the pages the egress has not yet acked (at/after cursor).

func (*SpillStore[T]) Reclaim added in v0.11.0

func (s *SpillStore[T]) Reclaim()

Reclaim drops acked pages (durable reclaim). Manifest/cursor stay consistent.

func (*SpillStore[T]) Reconstruct added in v0.11.0

func (s *SpillStore[T]) Reconstruct(s0 T, hot T, hasHot bool) T

Reconstruct (spill_lossless) folds the cold tail then the hot head, reproducing the flat fold of every op the relay ever ingested. hasHot=false means an empty hot window.

func (*SpillStore[T]) ReplayUnacked added in v0.11.0

func (s *SpillStore[T]) ReplayUnacked(downstream T) T

ReplayUnacked (crash replay) re-delivers every unacked page from the ack cursor into downstream. For an idempotent policy re-applying an already-delivered page is a no-op (spill_replay_idempotent), so at-least-once replay converges.

func (*SpillStore[T]) Spill added in v0.11.0

func (s *SpillStore[T]) Spill(window T, bytes uint64)

Spill writes one coalesced window summary to the durable tail. AppendCompact always opens a new page; CompactOnWrite merges into the open page until it reaches pageSize, then seals it.

type StaleComputeError added in v0.21.0

type StaleComputeError struct {
	// contains filtered or unexported fields
}

StaleComputeError is raised when a Compute view is used outside the recompute it belongs to — the runtime half of the non-escapability guarantee (Go cannot bind the view by lifetime the way lazily-rs does).

func (*StaleComputeError) Error added in v0.21.0

func (e *StaleComputeError) Error() string

type StampFrontier

type StampFrontier struct {
	// contains filtered or unexported fields
}

StampFrontier is the per-peer stamp frontier: the highest HlcStamp observed from each peer.

Mirrors lazily-rs StampFrontier (a BTreeMap<PeerId, HlcStamp>). The merge laws (commutative, associative, idempotent) are formally proven (stampJoin_{comm,assoc,idem}): fold Observe over an incoming frontier in any order and the result is identical.

func NewStampFrontier

func NewStampFrontier() *StampFrontier

NewStampFrontier creates an empty frontier.

func StampFrontierFromWire

func StampFrontierFromWire(entries []StampFrontierEntry) *StampFrontier

StampFrontierFromWire builds a frontier from (peer, stamp) wire entries.

func (*StampFrontier) Get

func (f *StampFrontier) Get(peer PeerId) (HlcStamp, bool)

Get returns the highest stamp observed for peer, and whether it was observed.

func (*StampFrontier) Knows

func (f *StampFrontier) Knows(peer PeerId) bool

Knows reports whether peer has been observed.

func (*StampFrontier) Merge

func (f *StampFrontier) Merge(other *StampFrontier) bool

Merge folds Observe over other. Commutative, associative, idempotent. Returns whether anything changed.

func (*StampFrontier) Observe

func (f *StampFrontier) Observe(peer PeerId, stamp HlcStamp) bool

Observe folds one observation: keep the per-peer max. Idempotent — older or equal stamps are ignored. Returns whether the frontier changed.

func (*StampFrontier) Peers

func (f *StampFrontier) Peers() []PeerId

Peers returns the set of peers this frontier has observed, sorted by peer id for deterministic iteration.

func (*StampFrontier) ToWire

func (f *StampFrontier) ToWire() []StampFrontierEntry

ToWire emits the wire form: one StampFrontierEntry per observed peer, sorted by peer id for deterministic output.

func (*StampFrontier) Watermark

func (f *StampFrontier) Watermark(membership []PeerId) (HlcStamp, bool)

Watermark is the causal-stability watermark: the min over the given membership's observed stamps. The second return is false until every member has been observed — a single unseen member means the frontier is not yet causally complete (formally: collectable_implies_observed_everywhere).

type StampFrontierEntry

type StampFrontierEntry struct {
	Peer  PeerId
	Stamp WireStamp
}

StampFrontierEntry is a (peer, WireStamp) entry in the per-peer stamp frontier. On the wire this is a 2-tuple array [peer, stamp] (per distributed.json#/$defs/StampFrontierEntry prefixItems), not a {peer, stamp} object — mirroring lazily-rs's Vec<(u64, WireStamp)> serde representation.

func (StampFrontierEntry) MarshalJSON

func (e StampFrontierEntry) MarshalJSON() ([]byte, error)

func (StampFrontierEntry) String

func (e StampFrontierEntry) String() string

func (*StampFrontierEntry) UnmarshalJSON

func (e *StampFrontierEntry) UnmarshalJSON(b []byte) error

type StateChart

type StateChart struct {
	// contains filtered or unexported fields
}

StateChart is a reactive full-Harel state chart backed by a configuration Cell.

Construct via NewStateChart (descending the root's initial configuration, recording initial entry actions). Drive with Send; query with Configuration, ActiveLeaves, Matches; inspect the last step's action trace with LastActions.

func NewStateChart

func NewStateChart(ctx *Context, def *ChartDef) *StateChart

NewStateChart creates a chart bound to ctx that enters the initial configuration by descending from def's root.

func (*StateChart) ActiveLeaves

func (sc *StateChart) ActiveLeaves() []string

ActiveLeaves returns the active atomic leaves, sorted (one per parallel region; one for a single-region chart).

func (*StateChart) Configuration

func (sc *StateChart) Configuration() Configuration

Configuration returns the full active configuration (active leaves plus all active ancestors). Reading inside a computation subscribes the reader.

func (*StateChart) Ctx

func (sc *StateChart) Ctx() *Context

Ctx returns the reactive context this chart belongs to.

func (*StateChart) Def

func (sc *StateChart) Def() *ChartDef

Def returns the parsed chart definition.

func (*StateChart) LastActions

func (sc *StateChart) LastActions() []string

LastActions returns the ordered action names fired by the initial entry or the most recent Send (exit innermost-first -> transition -> entry outermost-first).

func (*StateChart) Matches

func (sc *StateChart) Matches(id string) bool

Matches is the hierarchical "state-in" predicate: true iff id is in the active configuration. Reading inside a computation subscribes the reader.

func (*StateChart) Send

func (sc *StateChart) Send(event string, guards map[string]bool) bool

Send delivers an event (run-to-completion). It returns true if any transition was taken, false if rejected (configuration unchanged, no actions fired).

guards resolves named guards for this send (absent/unknown name -> fail-closed false). Pass nil for no guards.

func (*StateChart) String

func (sc *StateChart) String() string

String renders the chart as its active leaves.

type StateMachine

type StateMachine[S comparable, E comparable] struct {
	// contains filtered or unexported fields
}

StateMachine is a flat finite state machine whose current state lives in a reactive Cell. Reading State inside a computation subscribes the reader, so downstream reactives recompute when the machine transitions to a different state.

func NewStateMachine

func NewStateMachine[S comparable, E comparable](ctx *Context, initial S, transition Transition[S, E]) *StateMachine[S, E]

NewStateMachine creates a machine bound to ctx with the given initial state and transition function.

func (*StateMachine[S, E]) Cell

func (m *StateMachine[S, E]) Cell() *Source[S]

Cell returns the underlying Cell holding the state value.

func (*StateMachine[S, E]) OnTransition

func (m *StateMachine[S, E]) OnTransition(handler func(oldState, newState S)) func()

OnTransition registers a handler fired with (old, new) on a transition to a different state. It is not called on registration. It returns a disposer; call it to stop observing.

This is an EFFECT, not a callback registered on the Cell — observation in a reactive graph is a declared dependency edge. The effect reads the state cell, which is what makes it a dependent; a captured `prev` turns the level-triggered rerun into an edge-triggered (old, new) pair. Mirrors lazily-rs StateMachine::on_transition (src/state_machine.rs).

Batching consequence: an effect reruns once per settled cascade, so a batch that walks A -> B -> C reports the single transition (A, C) rather than (A, B) and (B, C). That is intended — a batch asserts atomicity, and the intermediate B was never an observable state of the graph.

func (*StateMachine[S, E]) Send

func (m *StateMachine[S, E]) Send(event E) bool

Send delivers an event to the machine. It returns true if the transition function accepted the event (ok == true), false if it was rejected. A self-transition that returns an equal state returns true but does not invalidate dependents (the != guard on the cell).

func (*StateMachine[S, E]) State

func (m *StateMachine[S, E]) State() S

State returns the current state. Reading inside a computation subscribes the reader.

type StateProjectionMirror

type StateProjectionMirror struct {
	// contains filtered or unexported fields
}

StateProjectionMirror tracks which slots are dirty and produces a coalesced flush Delta.

The caller marks slots dirty as the reactive graph invalidates them. At flush, the mirror collects the resolved values and builds a single Delta (DeltaNext) with one DeltaOpSlotValue per resolved slot; slots still dirty at flush are emitted as DeltaOpInvalidate (the mirror-lazy path).

Like the Dart original, StateProjectionMirror is not safe for concurrent use.

func NewStateProjectionMirror

func NewStateProjectionMirror() *StateProjectionMirror

NewStateProjectionMirror constructs an empty mirror at base epoch 0.

func (*StateProjectionMirror) BaseEpoch

func (m *StateProjectionMirror) BaseEpoch() Epoch

BaseEpoch returns the current base epoch.

func (*StateProjectionMirror) DirtyNodes

func (m *StateProjectionMirror) DirtyNodes() []NodeId

DirtyNodes returns all dirty node ids, sorted ascending.

func (*StateProjectionMirror) Flush

func (m *StateProjectionMirror) Flush() Delta

Flush produces a Delta with one DeltaOpInvalidate per still-dirty slot (ascending) followed by one DeltaOpSlotValue per resolved slot (ascending), then clears the pending state and advances the base epoch once.

func (*StateProjectionMirror) IsDirty

func (m *StateProjectionMirror) IsDirty(node NodeId) bool

IsDirty reports whether node is currently dirty.

func (*StateProjectionMirror) MarkDirty

func (m *StateProjectionMirror) MarkDirty(node NodeId)

MarkDirty marks slot node as dirty.

func (*StateProjectionMirror) Resolve

func (m *StateProjectionMirror) Resolve(node NodeId, value IpcValue)

Resolve records a dirty slot's value (called by the graph at flush time) and clears its dirty mark.

type StoredOutboxEntry added in v0.13.0

type StoredOutboxEntry struct {
	Epoch Epoch
	Frame []byte
}

StoredOutboxEntry is one serialized frame returned by an OutboxStore.

type SyncDriver added in v0.8.0

type SyncDriver struct {
	// contains filtered or unexported fields
}

SyncDriver is the full-duplex reliable-sync loop driver (spec § SyncDriver).

One driver drives one peer connection over a caller-supplied IpcSink/IpcSource pair (agent-doc wraps its Unix-domain socket). It composes the three pure-protocol pieces into the loop shape the spec pins:

  1. drain — pop host-enqueued outbound data frames, Append each to the DurableOutbox before sending (at-least-once durability), send via the sink;
  2. retain-on-fail — a send error leaves the frame in the outbox (unacked) and stops the drain; it is re-sent on the next reconnect;
  3. receive — read inbound frames, route control frames (OutboxAck → advance retention; ResyncRequest → answer with a provider snapshot) and feed data frames through the ResyncCoordinator (Apply → hand to the host + owe an ack; RequestSnapshot → emit a ResyncRequest; Ignore → drop);
  4. resync-on-reconnect — OnReconnect replays the unacked outbox suffix from the peer's ack cursor and re-advertises our own receiver cursor, so a dropped-frame gap converges.

The driver owns no goroutines, no clock source, and no storage engine — the host injects all three and decides the tick cadence.

func NewSyncDriver added in v0.8.0

func NewSyncDriver(sink IpcSink, source IpcSource, outbox DurableOutbox, clock Clock, provider SnapshotProvider) *SyncDriver

NewSyncDriver returns a fresh driver at receiver epoch 0 (a Snapshot seeds the first epoch).

func NewSyncDriverWithEpoch added in v0.8.0

func NewSyncDriverWithEpoch(sink IpcSink, source IpcSource, outbox DurableOutbox, clock Clock, provider SnapshotProvider, lastEpoch Epoch) *SyncDriver

NewSyncDriverWithEpoch returns a driver whose receiver has already applied through lastEpoch (resume).

func (*SyncDriver) Enqueue added in v0.8.0

func (d *SyncDriver) Enqueue(epoch Epoch, msg IpcMessage)

Enqueue stages an outbound data frame at epoch for the next tick's drain. epoch is the frame's accepted-event count (Delta.Epoch / Snapshot.Epoch); it becomes the outbox retention key.

func (*SyncDriver) IsStalled added in v0.8.0

func (d *SyncDriver) IsStalled() bool

IsStalled reports whether the sink is currently stalled (last send failed, awaiting reconnect).

func (*SyncDriver) LastEpoch added in v0.8.0

func (d *SyncDriver) LastEpoch() Epoch

LastEpoch returns the receiver's current applied epoch.

func (*SyncDriver) OnReconnect added in v0.8.0

func (d *SyncDriver) OnReconnect()

OnReconnect signals that the transport was re-established; the next Tick replays the unacked outbox suffix and re-advertises our receiver cursor.

func (*SyncDriver) Outbox added in v0.8.0

func (d *SyncDriver) Outbox() DurableOutbox

Outbox borrows the underlying outbox (diagnostics / durable-store flush).

func (*SyncDriver) StalledFor added in v0.8.0

func (d *SyncDriver) StalledFor(now int64) int64

StalledFor returns the millis the sink has been stalled as of now, or 0 when healthy — a backoff signal for the host scheduler.

func (*SyncDriver) Tick added in v0.8.0

func (d *SyncDriver) Tick() (Progress, error)

Tick runs one loop pass. See the type docs for the drain → retain → receive → resync shape. Sink failures retain-and-stall (not an error); only an inbound source read failure returns a *DriverError.

type TeardownScope added in v0.20.0

type TeardownScope struct {
	// contains filtered or unexported fields
}

TeardownScope groups nodes so they can be torn down together.

Why Close, and not a destructor

lazily-rs ends a scope when it drops. Go has no destructors, so the end of a scope has to be a call. Close is that call, named for `defer scope.Close()` — the Go idiom that already means "this ends when the enclosing function does", which is precisely Rust's Drop timing expressed in the language Go actually has. It returns nothing: teardown cannot fail, and an error return would make every `defer scope.Close()` an unchecked-error lint. Context.WithScope wraps the same thing as a callback for the common lexical case.

Grouping bounds *teardown*, not visibility: a scoped node reads unscoped or sibling-scope nodes freely, and an unscoped node may read a scoped one. Same caveat as Slot.Dispose — closing a scope tears down its members even if something outside still reads them, and that reader errors on its next recompute.

func (*TeardownScope) Close added in v0.20.0

func (s *TeardownScope) Close()

Close tears down every node this scope owns, in reverse creation order, then marks the scope closed. Idempotent.

Reverse order matters for effect cleanups, which are observable side effects; graph state alone is order independent. It also keeps a scope from transiently dangling inside itself, since dependents go before what they read.

func (*TeardownScope) Disarm added in v0.20.0

func (s *TeardownScope) Disarm()

Disarm cancels this scope's teardown: it releases every node it owns back to plain context ownership, so Close disposes nothing. The nodes themselves are untouched — no disposal, no detachment — and each stays individually disposable. Same sense as defusing a scope guard.

func (*TeardownScope) Len added in v0.20.0

func (s *TeardownScope) Len() int

Len reports how many nodes this scope currently owns.

type TextCrdt

type TextCrdt struct {
	// contains filtered or unexported fields
}

TextCrdt is a Fugue/RGA-style free-text character CRDT.

func NewTextCrdt

func NewTextCrdt(peer PeerId) *TextCrdt

NewTextCrdt creates an empty replica for the given peer id.

func TextCrdtFromStr

func TextCrdtFromStr(peer PeerId, s string) *TextCrdt

TextCrdtFromStr seeds a new CRDT from s as if a single peer typed it sequentially.

func (*TextCrdt) ApplyDelta

func (t *TextCrdt) ApplyDelta(ops []TextOp) bool

ApplyDelta applies a delta with the same commutative/associative/idempotent algebra as Merge. Returns whether the visible text changed.

func (*TextCrdt) Clock

func (t *TextCrdt) Clock() OpId

Clock returns the current clock position.

func (*TextCrdt) Clone

func (t *TextCrdt) Clone() *TextCrdt

Clone deep-copies this replica with the same peer.

func (*TextCrdt) Delete

func (t *TextCrdt) Delete(index int)

Delete tombstones the visible character at index. No-op if out of range.

func (*TextCrdt) DeltaSince

func (t *TextCrdt) DeltaSince(theirVv map[PeerId]int64) []TextOp

DeltaSince returns the elements whose insert id or tombstone delete id is newer than theirVv. A whole-state snapshot is DeltaSince(nil).

func (*TextCrdt) Fork

func (t *TextCrdt) Fork(peer PeerId) *TextCrdt

Fork deep-copies this replica under a new peer, adopting the same element set and copying the counter so future ops don't collide with prior ones.

func (*TextCrdt) GcWith

func (t *TextCrdt) GcWith(isStable func(deleteOpId OpId) bool) int

GcWith collects stable tombstones. An element is collectable when it is deleted, isStable confirms its delete op is stable, AND nothing references it as a left-origin. Runs to a fixpoint (collecting a leaf may expose its parent). Returns the number removed.

func (*TextCrdt) Insert

func (t *TextCrdt) Insert(index int, ch string)

Insert inserts a single character ch at the visible index.

func (*TextCrdt) InsertStr

func (t *TextCrdt) InsertStr(index int, s string)

InsertStr inserts a multi-character string at the visible index with origin chaining (#lztextinsertchain): one `orderedIds()` pass + N chain appends instead of N full-tree rebuilds. Sequential chars chain naturally — char i+1's left-origin is char i's just-minted OpId — so DFS visits them in chain order (counter strictly increases under one peer). Concurrent inserts at the same point still sort by peer tiebreak (standard CRDT convergence).

func (*TextCrdt) IsEmpty

func (t *TextCrdt) IsEmpty() bool

IsEmpty reports whether there are no live elements.

func (*TextCrdt) Len

func (t *TextCrdt) Len() int

Len returns the count of live (non-deleted) elements.

func (*TextCrdt) Merge

func (t *TextCrdt) Merge(other *TextCrdt) bool

Merge folds another replica's state into this one. Returns whether the visible text changed.

func (*TextCrdt) MergeFrom added in v0.13.0

func (t *TextCrdt) MergeFrom(other CrdtTree[map[PeerId]int64, []TextOp, string]) bool

MergeFrom joins another CrdtTree through the identity-preserving delta path.

func (*TextCrdt) Peer

func (t *TextCrdt) Peer() PeerId

Peer returns the peer id of this replica.

func (*TextCrdt) Text

func (t *TextCrdt) Text() string

Text returns the visible text.

func (*TextCrdt) TombstoneCount

func (t *TextCrdt) TombstoneCount() int

TombstoneCount returns the count of tombstoned (deleted) elements.

func (*TextCrdt) Value added in v0.13.0

func (t *TextCrdt) Value() string

Value returns the visible lossless-tree value.

func (*TextCrdt) VersionVector

func (t *TextCrdt) VersionVector() map[PeerId]int64

VersionVector returns {peer -> max counter} taken over BOTH insert ids and tombstone delete ids. An absent peer implies 0. Serializes to JSON with string peer keys (e.g. {"1":4}), matching the spec fixtures.

type TextOp

type TextOp struct {
	Id      OpId   `json:"id"`
	Ch      string `json:"ch"`
	Origin  *OpId  `json:"origin"`
	Deleted *OpId  `json:"deleted"`
}

TextOp is a single text-CRDT operation in delta-sync wire form. Origin and Deleted serialize as JSON null when absent (matching the Dart toWire, which always emits all four keys).

func TextOpFromWire

func TextOpFromWire(v any) TextOp

TextOpFromWire parses a TextOp from its decoded-JSON map form.

func (TextOp) ToWire

func (op TextOp) ToWire() map[string]any

ToWire renders the wire map {id, ch, origin, deleted}. Absent origin/deleted map to nil (JSON null), matching Dart.

type ThreadSafeCellMap deprecated added in v0.7.0

type ThreadSafeCellMap[K comparable, V comparable] = ThreadSafeSourceMap[K, V]

ThreadSafeCellMap is the pre-v2-kernel name for ThreadSafeSourceMap.

Deprecated: renamed to ThreadSafeSourceMap.

type ThreadSafeComputedMap added in v0.22.0

type ThreadSafeComputedMap[K comparable, V comparable] struct {
	*ThreadSafeReactiveMap[K, V, *Computed[V]]
}

ThreadSafeComputedMap is the derived-slot specialization: GetOrInsertWith mints a slot on first access (lazy); MaterializeAll pre-mints the keyset (eager). No Set.

func NewThreadSafeComputedMap added in v0.22.0

func NewThreadSafeComputedMap[K comparable, V comparable](ts *ThreadSafeContext) *ThreadSafeComputedMap[K, V]

NewThreadSafeComputedMap creates an empty thread-safe derived-slot map.

func NewThreadSafeSlotMap deprecated added in v0.7.0

func NewThreadSafeSlotMap[K comparable, V comparable](ts *ThreadSafeContext) *ThreadSafeComputedMap[K, V]

NewThreadSafeSlotMap creates an empty thread-safe derived-slot map.

Deprecated: renamed to NewThreadSafeComputedMap.

func (*ThreadSafeComputedMap[K, V]) MaterializeAll added in v0.22.0

func (m *ThreadSafeComputedMap[K, V]) MaterializeAll(keys []K, factory func(K) V)

MaterializeAll eagerly pre-mints every key via factory. Observationally identical to minting each lazily on first read.

func (*ThreadSafeComputedMap[K, V]) Slot added in v0.23.0

func (m *ThreadSafeComputedMap[K, V]) Slot(key K) *Computed[V]

Slot returns key's derived slot handle, or nil. Non-reactive.

type ThreadSafeContext

type ThreadSafeContext struct {
	// contains filtered or unexported fields
}

ThreadSafeContext serializes all access to an underlying Context behind a reentrant lock. Build reactives and read/write cells only inside WithLock or Batch (or via TSSetCell); concurrent callers are linearized by the lock, so every batch flush is glitch-free.

func NewThreadSafeContext

func NewThreadSafeContext() *ThreadSafeContext

NewThreadSafeContext creates a lock-backed reactive context.

func (*ThreadSafeContext) Batch

func (t *ThreadSafeContext) Batch(fn func())

Batch runs fn under the lock inside an underlying Context batch, so all cell writes queued in fn flush in a single coalesced invalidation pass at the outermost boundary. Nested Batch calls only flush at the outermost boundary.

func (*ThreadSafeContext) Context

func (t *ThreadSafeContext) Context() *Context

Context returns the underlying single-threaded Context. Only touch it while holding the lock (inside WithLock/Batch) — direct concurrent use is unsafe.

func (*ThreadSafeContext) WithLock

func (t *ThreadSafeContext) WithLock(fn func(ctx *Context))

WithLock runs fn while holding the lock, giving it exclusive, race-free access to the reactive graph (build nodes, read slots, write cells). Reentrant: fn may itself call WithLock/Batch/TSSetCell.

type ThreadSafeQueueCell added in v0.24.0

type ThreadSafeQueueCell[T comparable, S QueueStorage[T]] struct {
	// contains filtered or unexported fields
}

ThreadSafeQueueCell is the lock-serialized QueueCell flavor.

func NewBoundedThreadSafeQueueCell added in v0.24.0

func NewBoundedThreadSafeQueueCell[T comparable](ts *ThreadSafeContext, capacity int) *ThreadSafeQueueCell[T, *VecDequeStorage[T]]

NewBoundedThreadSafeQueueCell creates a bounded thread-safe queue.

func NewThreadSafeQueueCell added in v0.24.0

func NewThreadSafeQueueCell[T comparable](ts *ThreadSafeContext) *ThreadSafeQueueCell[T, *VecDequeStorage[T]]

NewThreadSafeQueueCell creates an unbounded thread-safe queue.

func NewThreadSafeQueueCellWithStorage added in v0.24.0

func NewThreadSafeQueueCellWithStorage[T comparable, S QueueStorage[T]](
	ts *ThreadSafeContext,
	storage S,
) *ThreadSafeQueueCell[T, S]

NewThreadSafeQueueCellWithStorage creates a thread-safe queue over storage.

func (*ThreadSafeQueueCell[T, S]) Capacity added in v0.24.0

func (q *ThreadSafeQueueCell[T, S]) Capacity() (int, bool)

func (*ThreadSafeQueueCell[T, S]) Close added in v0.24.0

func (q *ThreadSafeQueueCell[T, S]) Close()

func (*ThreadSafeQueueCell[T, S]) Elements added in v0.24.0

func (q *ThreadSafeQueueCell[T, S]) Elements() []T

func (*ThreadSafeQueueCell[T, S]) Head added in v0.24.0

func (q *ThreadSafeQueueCell[T, S]) Head() (T, bool)

func (*ThreadSafeQueueCell[T, S]) IsClosed added in v0.24.0

func (q *ThreadSafeQueueCell[T, S]) IsClosed() bool

func (*ThreadSafeQueueCell[T, S]) IsEmpty added in v0.24.0

func (q *ThreadSafeQueueCell[T, S]) IsEmpty() bool

func (*ThreadSafeQueueCell[T, S]) IsFull added in v0.24.0

func (q *ThreadSafeQueueCell[T, S]) IsFull() bool

func (*ThreadSafeQueueCell[T, S]) Len added in v0.24.0

func (q *ThreadSafeQueueCell[T, S]) Len() int

func (*ThreadSafeQueueCell[T, S]) ReaderHandles added in v0.24.0

func (q *ThreadSafeQueueCell[T, S]) ReaderHandles() QueueReaderHandles[T]

func (*ThreadSafeQueueCell[T, S]) TryPop added in v0.24.0

func (q *ThreadSafeQueueCell[T, S]) TryPop() (T, QueuePopError)

func (*ThreadSafeQueueCell[T, S]) TryPush added in v0.24.0

func (q *ThreadSafeQueueCell[T, S]) TryPush(value T) QueuePushError

type ThreadSafeReactiveMap added in v0.7.0

type ThreadSafeReactiveMap[K comparable, V comparable, H any] struct {
	// contains filtered or unexported fields
}

ThreadSafeReactiveMap is the thread-safe keyed reactive map (#reactivemap), generic over the entry handle kind H, with all present-set mutation serialized by an internal mutex and all graph work serialized by the owning ThreadSafeContext's lock.

It is graph-backed. Before the Core-surface work this map stored plain values in a map[K]V with no reactive nodes at all, no context, and no ordering surface: it had PresentKeys and PresentCount and nothing else. "Thread-safe map" was a mutex-guarded cache wearing the reactive family's name. Entries are now real nodes on the underlying graph, and membership and order are real signals minted on that same graph — the ordering plane binds this flavor exactly as it binds the single-threaded one, because a move touches no entry handle and awaits nothing.

Reads take a ComputeOps read surface (#lzcellkernel). A *Compute registers a dependency edge; a *Context registers none. A read spellable only as a zero-argument call could never subscribe from inside a derived node — which is precisely how the single-threaded map's Keys/Len/ContainsKey silently registered no edge at all.

V is constrained comparable to mirror the single-threaded map (an input entry needs an equality guard). Once built its address is stable, so concurrent readers may share a *ThreadSafeReactiveMap.

func (*ThreadSafeReactiveMap[K, V, H]) ContainsKey added in v0.23.0

func (m *ThreadSafeReactiveMap[K, V, H]) ContainsKey(c ComputeOps, key K) bool

ContainsKey reports the reactive membership test for key. Subscribes the caller to membership changes (add/remove of any key), not to value changes.

func (*ThreadSafeReactiveMap[K, V, H]) EntryKind added in v0.7.0

func (m *ThreadSafeReactiveMap[K, V, H]) EntryKind() EntryKind

EntryKind returns this map's entry kind.

func (*ThreadSafeReactiveMap[K, V, H]) GetOrInsertWith added in v0.7.0

func (m *ThreadSafeReactiveMap[K, V, H]) GetOrInsertWith(c ComputeOps, key K, factory func(K) V) V

GetOrInsertWith returns key's value, minting the entry via factory(key) on first access (the lazy pull). An existing key returns its current value without re-running the factory.

func (*ThreadSafeReactiveMap[K, V, H]) Handle added in v0.23.0

func (m *ThreadSafeReactiveMap[K, V, H]) Handle(key K) (H, bool)

Handle returns key's existing entry handle, or (zero, false). Non-minting.

func (*ThreadSafeReactiveMap[K, V, H]) IsEmpty added in v0.23.0

func (m *ThreadSafeReactiveMap[K, V, H]) IsEmpty(c ComputeOps) bool

IsEmpty reports the reactive emptiness check.

func (*ThreadSafeReactiveMap[K, V, H]) IsPresent added in v0.7.0

func (m *ThreadSafeReactiveMap[K, V, H]) IsPresent(key K) bool

IsPresent reports whether key is currently materialized. Non-reactive.

func (*ThreadSafeReactiveMap[K, V, H]) Keys added in v0.23.0

func (m *ThreadSafeReactiveMap[K, V, H]) Keys(c ComputeOps) []K

Keys returns a reactive snapshot of the keys in their current order. Subscribes the caller to order changes (add/remove and move/reorder), not to per-entry value changes.

func (*ThreadSafeReactiveMap[K, V, H]) Len added in v0.23.0

func (m *ThreadSafeReactiveMap[K, V, H]) Len(c ComputeOps) int

Len reports the reactive entry count. Subscribes the caller to membership changes only.

func (*ThreadSafeReactiveMap[K, V, H]) LenUntracked added in v0.23.0

func (m *ThreadSafeReactiveMap[K, V, H]) LenUntracked() int

LenUntracked reports the non-reactive count.

func (*ThreadSafeReactiveMap[K, V, H]) MoveAfter added in v0.23.0

func (m *ThreadSafeReactiveMap[K, V, H]) MoveAfter(key, anchor K) bool

MoveAfter atomically moves key to just after anchor (#lzcellmove).

func (*ThreadSafeReactiveMap[K, V, H]) MoveBefore added in v0.23.0

func (m *ThreadSafeReactiveMap[K, V, H]) MoveBefore(key, anchor K) bool

MoveBefore atomically moves key to just before anchor (#lzcellmove).

func (*ThreadSafeReactiveMap[K, V, H]) MoveTo added in v0.23.0

func (m *ThreadSafeReactiveMap[K, V, H]) MoveTo(key K, index int) bool

MoveTo atomically moves key to index in the order (#lzcellmove). The entry keeps the same node, the same dependents, and its CRDT lineage — unlike a Remove + re-mint, which re-allocates and bumps membership twice. Only the order signal is bumped, so Keys readers recompute while Len / ContainsKey readers stay cached. index is clamped to [0, len).

func (*ThreadSafeReactiveMap[K, V, H]) Observe added in v0.7.0

func (m *ThreadSafeReactiveMap[K, V, H]) Observe(c ComputeOps, key K) (V, bool)

Observe reads key's value if the entry is present, subscribing the caller to that entry's node. Returns (zero, false) if absent. Non-minting.

func (*ThreadSafeReactiveMap[K, V, H]) Position added in v0.23.0

func (m *ThreadSafeReactiveMap[K, V, H]) Position(key K) (int, bool)

Position reports key's current 0-based position in the order. Non-reactive.

func (*ThreadSafeReactiveMap[K, V, H]) PresentCount added in v0.7.0

func (m *ThreadSafeReactiveMap[K, V, H]) PresentCount() int

PresentCount returns the number of currently-materialized entries.

func (*ThreadSafeReactiveMap[K, V, H]) PresentKeys added in v0.7.0

func (m *ThreadSafeReactiveMap[K, V, H]) PresentKeys() []K

PresentKeys returns a snapshot of the currently-materialized keys, in current order. Non-reactive — see Keys for the tracked read.

func (*ThreadSafeReactiveMap[K, V, H]) Remove added in v0.23.0

func (m *ThreadSafeReactiveMap[K, V, H]) Remove(key K) bool

Remove removes key's entry, detaching the removed node so no reader is left on a stale value, and bumps reactive membership. Returns whether the key was present.

type ThreadSafeSlotMap deprecated added in v0.7.0

type ThreadSafeSlotMap[K comparable, V comparable] = ThreadSafeComputedMap[K, V]

ThreadSafeSlotMap is the pre-v2-kernel name for ThreadSafeComputedMap.

Deprecated: renamed to ThreadSafeComputedMap.

type ThreadSafeSourceMap added in v0.22.0

type ThreadSafeSourceMap[K comparable, V comparable] struct {
	*ThreadSafeReactiveMap[K, V, *Source[V]]
}

ThreadSafeSourceMap is the input-cell specialization of ThreadSafeReactiveMap: every entry is a settable input cell. Adds the cell-only Set.

func NewThreadSafeCellMap deprecated added in v0.7.0

func NewThreadSafeCellMap[K comparable, V comparable](ts *ThreadSafeContext) *ThreadSafeSourceMap[K, V]

NewThreadSafeCellMap creates an empty thread-safe input-cell map.

Deprecated: renamed to NewThreadSafeSourceMap.

func NewThreadSafeSourceMap added in v0.22.0

func NewThreadSafeSourceMap[K comparable, V comparable](ts *ThreadSafeContext) *ThreadSafeSourceMap[K, V]

NewThreadSafeSourceMap creates an empty thread-safe input-cell map bound to ts.

func (*ThreadSafeSourceMap[K, V]) Cell added in v0.23.0

func (m *ThreadSafeSourceMap[K, V]) Cell(key K) *Source[V]

Cell returns key's existing input cell, or nil. Non-reactive.

func (*ThreadSafeSourceMap[K, V]) Set added in v0.22.0

func (m *ThreadSafeSourceMap[K, V]) Set(key K, value V)

Set overwrites key's value, materializing the entry if absent. Cell-only: a derived ComputedMap slot is not settable. Updating an existing entry leaves membership and order untouched and invalidates only that entry's dependents.

type ThreadSafeTopicCell added in v0.24.0

type ThreadSafeTopicCell[T any] struct {
	// contains filtered or unexported fields
}

ThreadSafeTopicCell is the lock-serialized TopicCell flavor.

func NewThreadSafeTopicCell added in v0.24.0

func NewThreadSafeTopicCell[T any](ts *ThreadSafeContext) *ThreadSafeTopicCell[T]

func NewThreadSafeTopicCellFromSnapshot added in v0.24.0

func NewThreadSafeTopicCellFromSnapshot[T any](
	ts *ThreadSafeContext,
	snapshot TopicSnapshot[T],
) *ThreadSafeTopicCell[T]

func (*ThreadSafeTopicCell[T]) Advance added in v0.24.0

func (t *ThreadSafeTopicCell[T]) Advance(id string, count int) int

func (*ThreadSafeTopicCell[T]) BaseOffset added in v0.24.0

func (t *ThreadSafeTopicCell[T]) BaseOffset() int

func (*ThreadSafeTopicCell[T]) Disconnect added in v0.24.0

func (t *ThreadSafeTopicCell[T]) Disconnect(id string)

func (*ThreadSafeTopicCell[T]) Elements added in v0.24.0

func (t *ThreadSafeTopicCell[T]) Elements() []T

func (*ThreadSafeTopicCell[T]) GC added in v0.24.0

func (t *ThreadSafeTopicCell[T]) GC() int

func (*ThreadSafeTopicCell[T]) Publish added in v0.24.0

func (t *ThreadSafeTopicCell[T]) Publish(value T) int

func (*ThreadSafeTopicCell[T]) Read added in v0.24.0

func (t *ThreadSafeTopicCell[T]) Read(id string) (T, bool)

func (*ThreadSafeTopicCell[T]) ReadStream added in v0.24.0

func (t *ThreadSafeTopicCell[T]) ReadStream(id string) ([]T, bool)

func (*ThreadSafeTopicCell[T]) ReaderHandle added in v0.24.0

func (t *ThreadSafeTopicCell[T]) ReaderHandle(id string) *Computed[TopicRead[T]]

func (*ThreadSafeTopicCell[T]) Reconnect added in v0.24.0

func (t *ThreadSafeTopicCell[T]) Reconnect(id string)

func (*ThreadSafeTopicCell[T]) Restart added in v0.24.0

func (t *ThreadSafeTopicCell[T]) Restart()

func (*ThreadSafeTopicCell[T]) Snapshot added in v0.24.0

func (t *ThreadSafeTopicCell[T]) Snapshot() TopicSnapshot[T]

func (*ThreadSafeTopicCell[T]) Subscribe added in v0.24.0

func (t *ThreadSafeTopicCell[T]) Subscribe(id string, durability TopicDurability) TopicSubscribeOutcome

func (*ThreadSafeTopicCell[T]) Subscription added in v0.24.0

func (t *ThreadSafeTopicCell[T]) Subscription(id string) (TopicSubscriptionSnapshot, bool)

func (*ThreadSafeTopicCell[T]) TailOffset added in v0.24.0

func (t *ThreadSafeTopicCell[T]) TailOffset() int

type ThreadSafeWorkQueueCell added in v0.24.0

type ThreadSafeWorkQueueCell[T any] struct {
	// contains filtered or unexported fields
}

ThreadSafeWorkQueueCell is the lock-serialized WorkQueueCell flavor.

func NewThreadSafeWorkQueueCell added in v0.24.0

func NewThreadSafeWorkQueueCell[T any](
	ts *ThreadSafeContext,
	visibilityTimeout int64,
	maxDeliveries uint64,
) *ThreadSafeWorkQueueCell[T]

func (*ThreadSafeWorkQueueCell[T]) Ack added in v0.24.0

func (q *ThreadSafeWorkQueueCell[T]) Ack(worker string, deliveryID uint64) bool

func (*ThreadSafeWorkQueueCell[T]) Claim added in v0.24.0

func (q *ThreadSafeWorkQueueCell[T]) Claim(worker string, now int64) (WorkQueueDelivery[T], bool)

func (*ThreadSafeWorkQueueCell[T]) DeadLetterItems added in v0.24.0

func (q *ThreadSafeWorkQueueCell[T]) DeadLetterItems() []WorkQueueDeadLetter[T]

func (*ThreadSafeWorkQueueCell[T]) DeadLetterLen added in v0.24.0

func (q *ThreadSafeWorkQueueCell[T]) DeadLetterLen() int

func (*ThreadSafeWorkQueueCell[T]) InFlightDeliveries added in v0.24.0

func (q *ThreadSafeWorkQueueCell[T]) InFlightDeliveries() []WorkQueueDelivery[T]

func (*ThreadSafeWorkQueueCell[T]) InFlightLen added in v0.24.0

func (q *ThreadSafeWorkQueueCell[T]) InFlightLen() int

func (*ThreadSafeWorkQueueCell[T]) IsEmpty added in v0.24.0

func (q *ThreadSafeWorkQueueCell[T]) IsEmpty() bool

func (*ThreadSafeWorkQueueCell[T]) Nack added in v0.24.0

func (q *ThreadSafeWorkQueueCell[T]) Nack(worker string, deliveryID uint64) bool

func (*ThreadSafeWorkQueueCell[T]) PendingItems added in v0.24.0

func (q *ThreadSafeWorkQueueCell[T]) PendingItems() []WorkQueueItem[T]

func (*ThreadSafeWorkQueueCell[T]) PendingLen added in v0.24.0

func (q *ThreadSafeWorkQueueCell[T]) PendingLen() int

func (*ThreadSafeWorkQueueCell[T]) Push added in v0.24.0

func (q *ThreadSafeWorkQueueCell[T]) Push(value T) uint64

func (*ThreadSafeWorkQueueCell[T]) ReaderHandles added in v0.24.0

func (q *ThreadSafeWorkQueueCell[T]) ReaderHandles() WorkQueueReaderHandles

func (*ThreadSafeWorkQueueCell[T]) ReapExpired added in v0.24.0

func (q *ThreadSafeWorkQueueCell[T]) ReapExpired(now int64) int

type ThrottleCell added in v0.15.0

type ThrottleCell[T comparable] struct {
	// contains filtered or unexported fields
}

ThrottleCell is the reactive throttle over any comparable-valued source.

func NewThrottleCell added in v0.15.0

func NewThrottleCell[T comparable](ctx *Context, edge ThrottleEdge, window uint64) *ThrottleCell[T]

NewThrottleCell builds a reactive throttle bound to ctx.

func (*ThrottleCell[T]) Input added in v0.15.0

func (c *ThrottleCell[T]) Input(now uint64, v T) Opt[T]

Input records an input, returning the emitted value (if any).

func (*ThrottleCell[T]) Output added in v0.15.0

func (c *ThrottleCell[T]) Output() Opt[T]

Output returns the last emitted value (subscribes the current computation).

func (*ThrottleCell[T]) OutputCell added in v0.15.0

func (c *ThrottleCell[T]) OutputCell() *Source[Opt[T]]

OutputCell exposes the reader cell for invalidation observation.

func (*ThrottleCell[T]) Tick added in v0.15.0

func (c *ThrottleCell[T]) Tick(now uint64) Opt[T]

Tick advances the clock, returning the emitted value (if any).

type ThrottleCore added in v0.15.0

type ThrottleCore[T comparable] struct {
	// contains filtered or unexported fields
}

ThrottleCore emits at most one value per `window`.

func NewThrottleCore added in v0.15.0

func NewThrottleCore[T comparable](edge ThrottleEdge, window uint64) *ThrottleCore[T]

NewThrottleCore builds a throttle core.

func (*ThrottleCore[T]) Input added in v0.15.0

func (c *ThrottleCore[T]) Input(now uint64, v T) Opt[T]

Input records an input. Leading emits (or drops); Trailing coalesces and holds.

func (*ThrottleCore[T]) Tick added in v0.15.0

func (c *ThrottleCore[T]) Tick(now uint64) Opt[T]

Tick advances. Trailing emits the coalesced latest at the window boundary.

type ThrottleEdge added in v0.15.0

type ThrottleEdge int

ThrottleEdge selects which edge of the window a ThrottleCore emits on.

const (
	// ThrottleLeading: first input of a window passes immediately; rest dropped.
	ThrottleLeading ThrottleEdge = iota
	// ThrottleTrailing: first input opens the window; the latest is emitted at
	// the window boundary.
	ThrottleTrailing
)

type TimedValue added in v0.11.0

type TimedValue[T any] struct {
	At    uint64
	Value T
}

TimedValue is a (timestamp, value) pair for RetainLive.

type TimelineSource added in v0.15.0

type TimelineSource interface {
	// Tick advances to logical time now (callers must not go backwards).
	// Returns true on a fire edge — a fire happened on this tick.
	Tick(now uint64) bool
	// NextFire reports the logical time of the next fire; ok is false when the
	// source is exhausted (models Option<u64> as (uint64, bool)).
	NextFire() (fire uint64, ok bool)
}

TimelineSource is a pure temporal compute core driven by a monotone logical clock. A runtime advances any source uniformly via Tick; NextFire lets a scheduler compute the delay to the next wake-up.

type Timeout added in v0.25.0

type Timeout[T any] struct {
	// contains filtered or unexported fields
}

func NewTimeout added in v0.25.0

func NewTimeout[T any](now, duration uint64) (*Timeout[T], error)

func (*Timeout[T]) Poll added in v0.25.0

func (t *Timeout[T]) Poll(
	now uint64,
	operation func() TimeoutOperation[T],
	cancellation func() TimeoutCancellation,
) TimeoutObservation[T]

Poll invokes both adapters exactly once before the deadline. Precedence is completion, unavailable operation, cancellation, then pending. At or after the deadline neither adapter is called. Terminal reads also call neither.

type TimeoutCancellation added in v0.25.0

type TimeoutCancellation string

TimeoutCancellation is returned by a cancellation adapter owned by the caller. "unavailable" represents a foreign or unreadable cancellation seam.

const (
	CancellationPending     TimeoutCancellation = "pending"
	CancellationCancelled   TimeoutCancellation = "cancelled"
	CancellationUnavailable TimeoutCancellation = "unavailable"
)

type TimeoutCell added in v0.15.0

type TimeoutCell struct {
	// contains filtered or unexported fields
}

TimeoutCell is a reactive timeout: projects isTimedOut onto a Cell.

func NewTimeoutCell added in v0.15.0

func NewTimeoutCell(ctx *Context) *TimeoutCell

NewTimeoutCell builds a reactive timeout.

func (*TimeoutCell) Arm added in v0.15.0

func (t *TimeoutCell) Arm(now, timeout uint64)

Arm arms the timeout with deadline = now + timeout.

func (*TimeoutCell) IsTimedOut added in v0.15.0

func (t *TimeoutCell) IsTimedOut() bool

IsTimedOut reports the projected timeout state.

func (*TimeoutCell) IsTimedOutCell added in v0.15.0

func (t *TimeoutCell) IsTimedOutCell() *Source[bool]

IsTimedOutCell returns the reactive is-timed-out reader.

func (*TimeoutCell) Tick added in v0.15.0

func (t *TimeoutCell) Tick(now uint64) bool

Tick fast-fails when now >= deadline; returns the timeout edge (once).

type TimeoutCore added in v0.15.0

type TimeoutCore struct {
	// contains filtered or unexported fields
}

TimeoutCore is a deadline-bounded call compute core.

func NewTimeoutCore added in v0.15.0

func NewTimeoutCore() *TimeoutCore

NewTimeoutCore builds a core.

func (*TimeoutCore) Arm added in v0.15.0

func (t *TimeoutCore) Arm(now, timeout uint64)

Arm arms the timeout with deadline = now + timeout.

func (*TimeoutCore) IsTimedOut added in v0.15.0

func (t *TimeoutCore) IsTimedOut() bool

IsTimedOut reports whether the timeout has fired.

func (*TimeoutCore) Tick added in v0.15.0

func (t *TimeoutCore) Tick(now uint64) bool

Tick fast-fails when now >= deadline; returns the timeout edge (once).

type TimeoutObservation added in v0.25.0

type TimeoutObservation[T any] struct {
	Outcome  string
	Deadline uint64
	Value    T
	Reason   string
}

TimeoutObservation is the deterministic, terminal-latching timeout result.

type TimeoutOperation added in v0.25.0

type TimeoutOperation[T any] struct {
	State string
	Value T
}

TimeoutOperation is the result returned by one operation adapter poll.

func CompletedOperation added in v0.25.0

func CompletedOperation[T any](value T) TimeoutOperation[T]

func PendingOperation added in v0.25.0

func PendingOperation[T any]() TimeoutOperation[T]

func UnavailableOperation added in v0.25.0

func UnavailableOperation[T any]() TimeoutOperation[T]

type Timer added in v0.25.0

type Timer struct {
	// contains filtered or unexported fields
}

Timer is a deterministic single-shot timer driven by caller-supplied ticks. Its mutex makes concurrent observations race-free while preserving the no-state-change rule for a regressing clock.

func NewTimer added in v0.25.0

func NewTimer(now, duration uint64) (*Timer, error)

func (*Timer) Observe added in v0.25.0

func (t *Timer) Observe(now uint64) (TimerObservation, error)

type TimerCell added in v0.15.0

type TimerCell struct {
	// contains filtered or unexported fields
}

TimerCell is a reactive single-shot timer: projects TimerCore's fire edge onto a cell so HasFired/Value dependents invalidate only on the fire (idempotent).

func NewTimerCell added in v0.15.0

func NewTimerCell(ctx *Context, fireAt uint64) *TimerCell

NewTimerCell creates a reactive single-shot timer firing at fireAt.

func (*TimerCell) FiredCell added in v0.15.0

func (t *TimerCell) FiredCell() *Source[bool]

FiredCell returns the backing cell for dependents that subscribe directly.

func (*TimerCell) HasFired added in v0.15.0

func (t *TimerCell) HasFired() bool

HasFired reports whether the timer has fired (reactive read).

func (*TimerCell) NextFire added in v0.15.0

func (t *TimerCell) NextFire() (uint64, bool)

NextFire reports the next fire time, or ok=false once fired.

func (*TimerCell) Tick added in v0.15.0

func (t *TimerCell) Tick(now uint64) bool

Tick advances to logical time now; returns the fire edge. The backing cell is set to the projected fired state each tick, so the == store-guard makes a repeat tick a no-op and dependents invalidate exactly once (on the edge).

func (*TimerCell) Value added in v0.15.0

func (t *TimerCell) Value() (struct{}, bool)

Value models Option<()>: ok is false before the fire, true after (reactive read).

type TimerCore added in v0.15.0

type TimerCore struct {
	// contains filtered or unexported fields
}

TimerCore is a single-shot compute core: fires exactly once at the first tick with now >= fireAt (idempotent thereafter).

func NewTimerCore added in v0.15.0

func NewTimerCore(fireAt uint64) *TimerCore

NewTimerCore creates a single-shot core firing at fireAt.

func (*TimerCore) Fired added in v0.15.0

func (t *TimerCore) Fired() bool

Fired reports whether the timer has fired.

func (*TimerCore) NextFire added in v0.15.0

func (t *TimerCore) NextFire() (uint64, bool)

NextFire reports the fire time, or ok=false once fired.

func (*TimerCore) Tick added in v0.15.0

func (t *TimerCore) Tick(now uint64) bool

Tick advances to now; returns the fire edge.

type TimerError added in v0.25.0

type TimerError string

TimerError is a typed failure reported by the portable logical-clock timer.

const (
	TimerDeadlineOverflow TimerError = "deadline_overflow"
	TimerClockRegression  TimerError = "clock_regression"
)

func (TimerError) Error added in v0.25.0

func (e TimerError) Error() string

type TimerObservation added in v0.25.0

type TimerObservation struct {
	Outcome  string
	Deadline uint64
	FiredAt  uint64
}

TimerObservation is the externally observable state of Timer.

type TopicCell added in v0.12.0

type TopicCell[T any] struct {
	// contains filtered or unexported fields
}

TopicCell is a broadcast log with one absolute reactive cursor per subscriber. Durable offline subscribers retain their cursor; ephemeral ones disappear on disconnect. GC drops only the prefix below the slowest durable cursor.

func NewTopicCell added in v0.12.0

func NewTopicCell[T any](ctx *Context) *TopicCell[T]

NewTopicCell creates an empty broadcast topic.

func NewTopicCellFromSnapshot added in v0.12.0

func NewTopicCellFromSnapshot[T any](ctx *Context, snapshot TopicSnapshot[T]) *TopicCell[T]

NewTopicCellFromSnapshot restores retained elements and absolute cursors.

func (*TopicCell[T]) Advance added in v0.12.0

func (t *TopicCell[T]) Advance(id string, count int) int

Advance moves only the named subscriber's absolute cursor.

func (*TopicCell[T]) BaseOffset added in v0.12.0

func (t *TopicCell[T]) BaseOffset() int

func (*TopicCell[T]) Disconnect added in v0.12.0

func (t *TopicCell[T]) Disconnect(id string)

Disconnect retains durable cursors and removes ephemeral subscriptions.

func (*TopicCell[T]) Elements added in v0.12.0

func (t *TopicCell[T]) Elements() []T

func (*TopicCell[T]) GC added in v0.12.0

func (t *TopicCell[T]) GC() int

GC drops only the prefix below every durable cursor and invalidates nothing.

func (*TopicCell[T]) Publish added in v0.12.0

func (t *TopicCell[T]) Publish(value T) int

Publish appends a value and invalidates each connected reader independently.

func (*TopicCell[T]) Read added in v0.12.0

func (t *TopicCell[T]) Read(id string) (T, bool)

Read reactively reads the next value without advancing the cursor.

func (*TopicCell[T]) ReadStream added in v0.12.0

func (t *TopicCell[T]) ReadStream(id string) ([]T, bool)

ReadStream reactively reads the complete retained suffix at this cursor.

func (*TopicCell[T]) ReaderHandle added in v0.12.0

func (t *TopicCell[T]) ReaderHandle(id string) *Computed[TopicRead[T]]

func (*TopicCell[T]) Reconnect added in v0.12.0

func (t *TopicCell[T]) Reconnect(id string)

Reconnect resumes an offline durable subscription at its saved cursor.

func (*TopicCell[T]) Restart added in v0.12.0

func (t *TopicCell[T]) Restart()

Restart models a process restart; persisted state and reader values are stable.

func (*TopicCell[T]) Snapshot added in v0.12.0

func (t *TopicCell[T]) Snapshot() TopicSnapshot[T]

Snapshot copies the retained log and stable subscription table.

func (*TopicCell[T]) Subscribe added in v0.12.0

func (t *TopicCell[T]) Subscribe(id string, durability TopicDurability) TopicSubscribeOutcome

Subscribe starts a new cursor at the current tail, or resumes an offline durable cursor with the same stable id.

func (*TopicCell[T]) Subscription added in v0.12.0

func (t *TopicCell[T]) Subscription(id string) (TopicSubscriptionSnapshot, bool)

Subscription reports a copy of a subscriber's current state.

func (*TopicCell[T]) TailOffset added in v0.12.0

func (t *TopicCell[T]) TailOffset() int

type TopicDurability added in v0.12.0

type TopicDurability string

TopicDurability controls whether a subscription survives disconnect and participates in the retained-log GC frontier.

const (
	TopicDurable   TopicDurability = "durable"
	TopicEphemeral TopicDurability = "ephemeral"
)

type TopicRead added in v0.12.0

type TopicRead[T any] struct {
	Elements []T
	Exists   bool
}

TopicRead is the memoized per-subscriber suffix returned by a reader Slot.

type TopicSnapshot added in v0.12.0

type TopicSnapshot[T any] struct {
	BaseOffset    int
	Elements      []T
	Subscriptions []TopicSubscriptionSnapshot
}

TopicSnapshot is a portable TopicCell retained-log snapshot.

type TopicSubscribeOutcome added in v0.12.0

type TopicSubscribeOutcome string

TopicSubscribeOutcome describes whether Subscribe minted or resumed a cursor.

const (
	TopicSubscribed        TopicSubscribeOutcome = "subscribed"
	TopicReconnected       TopicSubscribeOutcome = "reconnected"
	TopicAlreadySubscribed TopicSubscribeOutcome = "already_subscribed"
)

type TopicSubscriptionSnapshot added in v0.12.0

type TopicSubscriptionSnapshot struct {
	ID         string
	Cursor     int
	Durability TopicDurability
	Connected  bool
}

TopicSubscriptionSnapshot is the persistent state for one stable subscriber.

type Trackable added in v0.21.0

type Trackable[T any] interface {
	// contains filtered or unexported methods
}

Trackable is any value-bearing node that can be read through a ComputeOps. Both *Computed[T] and *Source[T] implement it, so a single generic Get serves slots, computed cells, and source cells alike.

type Transition

type Transition[S comparable, E comparable] func(state S, event E) (next S, ok bool)

Transition is the pure transition function for a StateMachine. Given the current state and an incoming event it returns the next state and whether the event was accepted. Returning ok == false rejects the event (acts as a guard); the machine's state is left unchanged.

type Transport added in v0.11.0

type Transport[T any] interface {
	Deliver(op T)
	Poll() []T
	HasPending() bool
}

Transport is a pluggable delivery mechanism for relay ops. Deliver enqueues; Poll pulls the next transport-defined frame (a batch of ready ops). Framing is the transport's business; the relay merges whatever each frame delivers.

type TreeDotRange added in v0.2.0

type TreeDotRange struct {
	Contiguous int64
	Sparse     map[int64]struct{}
}

TreeDotRange is the observed dots for one peer: a contiguous prefix plus out-of-order holes. Never a per-peer max — a hole above Contiguous stays representable in Sparse so it is re-requested rather than skipped.

func NewTreeDotRange added in v0.2.0

func NewTreeDotRange() *TreeDotRange

NewTreeDotRange returns an empty dot range.

func (*TreeDotRange) Contains added in v0.2.0

func (r *TreeDotRange) Contains(counter int64) bool

Contains reports whether counter is held.

func (*TreeDotRange) Copy added in v0.2.0

func (r *TreeDotRange) Copy() *TreeDotRange

Copy returns a deep copy.

func (*TreeDotRange) Observe added in v0.2.0

func (r *TreeDotRange) Observe(counter int64)

Observe records a counter, collapsing the contiguous prefix forward.

type TreeNodeChildren

type TreeNodeChildren[V any] struct {
	Order  []string
	Values map[string]TreeNodeSpec[V]
}

TreeNodeChildren describes the ordered children of a TreeNodeSpec. Order is optional; when nil the child keys of Values are used (sorted for determinism — see note in BuildSemTree).

type TreeNodeSeed added in v0.2.0

type TreeNodeSeed interface {
	// contains filtered or unexported methods
}

TreeNodeSeed is what a CreateNode materializes: an element shell or a text leaf seeded from exact text. Externally tagged on the wire ({"Element": {"kind": ...}} or {"Leaf": {"kind": ..., "text": ...}}).

type TreeNodeSeedElement added in v0.2.0

type TreeNodeSeedElement struct {
	Kind string
}

TreeNodeSeedElement is an internal semantic node with a kind and ordered children. Owns structure only, never text.

func (TreeNodeSeedElement) MarshalJSON added in v0.2.0

func (s TreeNodeSeedElement) MarshalJSON() ([]byte, error)

MarshalJSON renders the externally-tagged wire form.

type TreeNodeSeedLeaf added in v0.2.0

type TreeNodeSeedLeaf struct {
	Kind LeafKind
	Text string
}

TreeNodeSeedLeaf is a leaf seeded from exact source text.

func (TreeNodeSeedLeaf) MarshalJSON added in v0.2.0

func (s TreeNodeSeedLeaf) MarshalJSON() ([]byte, error)

MarshalJSON renders the externally-tagged wire form.

type TreeNodeSpec

type TreeNodeSpec[V any] struct {
	ID       string
	Value    V
	Children *TreeNodeChildren[V]
}

TreeNodeSpec is a node spec for building a SemTree.

type TreeOp added in v0.2.0

type TreeOp struct {
	Id   OpId
	Kind TreeOpKind
}

TreeOp is a transport-ready tree operation: its dotted id plus the change it encodes.

func (TreeOp) MarshalJSON added in v0.2.0

func (op TreeOp) MarshalJSON() ([]byte, error)

MarshalJSON renders {"id": ..., "kind": <externally-tagged kind>}.

func (*TreeOp) UnmarshalJSON added in v0.2.0

func (op *TreeOp) UnmarshalJSON(b []byte) error

UnmarshalJSON decodes a TreeOp from its externally-tagged kind form.

type TreeOpCreateNode added in v0.2.0

type TreeOpCreateNode struct {
	Id     OpId
	Parent OpId
	Sort   TreeSortKey
	Seed   TreeNodeSeed
}

TreeOpCreateNode materializes an element shell or a text leaf seeded from exact text.

func (TreeOpCreateNode) MarshalJSON added in v0.2.0

func (k TreeOpCreateNode) MarshalJSON() ([]byte, error)

MarshalJSON renders the externally-tagged wire form for an op kind.

type TreeOpKind added in v0.2.0

type TreeOpKind interface {
	// contains filtered or unexported methods
}

TreeOpKind is the M1 op vocabulary: CreateNode / Tombstone / Reorder / LeafEdit / SplitLeaf / MergeLeaves. Externally tagged on the wire. Positions and seed text travel inside the op so both replicas store byte-identical keys and converge without consulting local clocks.

type TreeOpLeafEdit added in v0.2.0

type TreeOpLeafEdit struct {
	Node OpId
	Prev OpId
	Ops  []TextOp
}

TreeOpLeafEdit applies an embedded text-CRDT delta to one leaf. Prev is the prior text-op id (the leaf's textHead), forming a per-leaf causal chain.

func (TreeOpLeafEdit) MarshalJSON added in v0.2.0

func (k TreeOpLeafEdit) MarshalJSON() ([]byte, error)

MarshalJSON renders the externally-tagged wire form for an op kind.

type TreeOpMergeLeaves added in v0.2.0

type TreeOpMergeLeaves struct {
	Left      OpId
	Right     OpId
	PrevLeft  OpId
	PrevRight OpId
}

TreeOpMergeLeaves merges two adjacent leaf siblings; total text unchanged.

func (TreeOpMergeLeaves) MarshalJSON added in v0.2.0

func (k TreeOpMergeLeaves) MarshalJSON() ([]byte, error)

MarshalJSON renders the externally-tagged wire form for an op kind.

type TreeOpReorder added in v0.2.0

type TreeOpReorder struct {
	Node OpId
	Sort TreeSortKey
}

TreeOpReorder is a LWW position reassignment within the parent (identity + payload preserved).

func (TreeOpReorder) MarshalJSON added in v0.2.0

func (k TreeOpReorder) MarshalJSON() ([]byte, error)

MarshalJSON renders the externally-tagged wire form for an op kind.

type TreeOpSplitLeaf added in v0.2.0

type TreeOpSplitLeaf struct {
	Node   OpId
	NewId  OpId
	Sort   TreeSortKey
	AtChar int
	Prev   OpId
}

TreeOpSplitLeaf splits a leaf at a char boundary into two adjacent leaves of the same kind. AtChar is a Unicode scalar count (binding-stable).

func (TreeOpSplitLeaf) MarshalJSON added in v0.2.0

func (k TreeOpSplitLeaf) MarshalJSON() ([]byte, error)

MarshalJSON renders the externally-tagged wire form for an op kind.

type TreeOpTombstone added in v0.2.0

type TreeOpTombstone struct {
	Node OpId
}

TreeOpTombstone tombstones a node (sticky; smaller op id wins concurrently).

func (TreeOpTombstone) MarshalJSON added in v0.2.0

func (k TreeOpTombstone) MarshalJSON() ([]byte, error)

MarshalJSON renders the externally-tagged wire form for an op kind.

type TreeSortKey added in v0.2.0

type TreeSortKey struct {
	Frac []int  `json:"frac"`
	Peer PeerId `json:"peer"`
}

TreeSortKey is a fractional-index child position: orderable bytes (0..255) tiebroken by the minting peer. Frac is a []int (not []byte) so it marshals as a JSON number array, never base64.

type TreeUpdate added in v0.2.0

type TreeUpdate struct {
	Ops []TreeOp
}

TreeUpdate is the op-delta wire message: the output of Diff and the input to ApplyUpdate. Ops are ordered by dotted id; dependencies are buffered on apply until they arrive, so delivery need not be contiguous.

func TreeUpdateFromWire added in v0.2.0

func TreeUpdateFromWire(data []byte) (TreeUpdate, error)

TreeUpdateFromWire decodes a TreeUpdate from JSON bytes.

func (TreeUpdate) MarshalJSON added in v0.2.0

func (u TreeUpdate) MarshalJSON() ([]byte, error)

MarshalJSON renders {"ops": [...]} with ops always an array (never null).

func (*TreeUpdate) UnmarshalJSON added in v0.2.0

func (u *TreeUpdate) UnmarshalJSON(b []byte) error

UnmarshalJSON decodes a TreeUpdate.

type TreeVersionFrontier added in v0.2.0

type TreeVersionFrontier struct {
	// contains filtered or unexported fields
}

TreeVersionFrontier is a dotted version frontier: per peer, exactly which op dots are held. Unlike a version vector (per-peer max), this represents non-contiguous delivery so Diff never omits a missing interior op.

func NewTreeVersionFrontier added in v0.2.0

func NewTreeVersionFrontier() *TreeVersionFrontier

NewTreeVersionFrontier returns an empty frontier.

func (*TreeVersionFrontier) Contains added in v0.2.0

func (f *TreeVersionFrontier) Contains(id OpId) bool

Contains reports whether id is held by this frontier.

func (*TreeVersionFrontier) Copy added in v0.2.0

Copy returns a deep copy.

func (*TreeVersionFrontier) Observe added in v0.2.0

func (f *TreeVersionFrontier) Observe(id OpId)

Observe records id as held.

type TumblingCountCore added in v0.15.0

type TumblingCountCore[T comparable] struct {
	// contains filtered or unexported fields
}

TumblingCountCore is the count-based tumbling window compute core.

func NewTumblingCountCore added in v0.15.0

func NewTumblingCountCore[T comparable](n uint64, policy MergePolicy[T]) *TumblingCountCore[T]

NewTumblingCountCore builds a count-tumbling core emitting every n elements.

func (*TumblingCountCore[T]) Push added in v0.15.0

func (c *TumblingCountCore[T]) Push(v T) Opt[T]

Push accumulates an element; on the n-th it emits the window fold and resets.

type TumblingCountWindow added in v0.15.0

type TumblingCountWindow[T comparable] struct {
	// contains filtered or unexported fields
}

TumblingCountWindow is a reactive count-tumbling window projecting the last emitted aggregate.

func TumblingCount added in v0.15.0

func TumblingCount[T comparable](ctx *Context, n uint64, policy MergePolicy[T]) *TumblingCountWindow[T]

TumblingCount constructs a reactive count-tumbling window over ctx.

func (*TumblingCountWindow[T]) Output added in v0.15.0

func (w *TumblingCountWindow[T]) Output() Opt[T]

Output reads the last emitted aggregate (subscribes in a computation).

func (*TumblingCountWindow[T]) OutputCell added in v0.15.0

func (w *TumblingCountWindow[T]) OutputCell() *Source[Opt[T]]

OutputCell returns the reactive cell holding the last emitted aggregate.

func (*TumblingCountWindow[T]) Push added in v0.15.0

func (w *TumblingCountWindow[T]) Push(v T) Opt[T]

Push accumulates an element, projecting the aggregate onto the output cell when the window emits. Returns the emitted aggregate (absent if none).

type TumblingTimeCore added in v0.15.0

type TumblingTimeCore[T comparable] struct {
	// contains filtered or unexported fields
}

TumblingTimeCore is the time-based tumbling window compute core.

func NewTumblingTimeCore added in v0.15.0

func NewTumblingTimeCore[T comparable](period uint64, policy MergePolicy[T]) *TumblingTimeCore[T]

NewTumblingTimeCore builds a time-tumbling core with the given period.

func (*TumblingTimeCore[T]) Push added in v0.15.0

func (c *TumblingTimeCore[T]) Push(_ uint64, v T)

Push accumulates an element into the current window (no emit).

func (*TumblingTimeCore[T]) Tick added in v0.15.0

func (c *TumblingTimeCore[T]) Tick(now uint64) Opt[T]

Tick emits the window fold at a period boundary (empty window emits absent).

type TumblingTimeWindow added in v0.15.0

type TumblingTimeWindow[T comparable] struct {
	// contains filtered or unexported fields
}

TumblingTimeWindow is a reactive time-tumbling window (Push(now,v) + Tick(now)).

func TumblingTime added in v0.15.0

func TumblingTime[T comparable](ctx *Context, period uint64, policy MergePolicy[T]) *TumblingTimeWindow[T]

TumblingTime constructs a reactive time-tumbling window over ctx.

func (*TumblingTimeWindow[T]) Output added in v0.15.0

func (w *TumblingTimeWindow[T]) Output() Opt[T]

Output reads the last emitted aggregate (subscribes in a computation).

func (*TumblingTimeWindow[T]) OutputCell added in v0.15.0

func (w *TumblingTimeWindow[T]) OutputCell() *Source[Opt[T]]

OutputCell returns the reactive cell holding the last emitted aggregate.

func (*TumblingTimeWindow[T]) Push added in v0.15.0

func (w *TumblingTimeWindow[T]) Push(now uint64, v T)

Push accumulates an element into the current window (no emit).

func (*TumblingTimeWindow[T]) Tick added in v0.15.0

func (w *TumblingTimeWindow[T]) Tick(now uint64) Opt[T]

Tick emits the window fold at a period boundary, projecting it onto output.

type VecDequeStorage added in v0.3.0

type VecDequeStorage[T any] struct {
	// contains filtered or unexported fields
}

VecDequeStorage is the reference QueueStorage backend: an unbounded (or optionally bounded) slice-backed FIFO. This is the default and the storage form the conformance fixtures serialize — element order is FIFO order.

The overflow policy is reject: TryPush on a bounded, full queue returns QueuePushFull and leaves the queue unchanged.

func NewBoundedVecDequeStorage added in v0.3.0

func NewBoundedVecDequeStorage[T any](n int) *VecDequeStorage[T]

NewBoundedVecDequeStorage returns a bounded VecDequeStorage with capacity n. Panics if n <= 0 (a zero-capacity queue can never accept an element and has no meaningful backpressure signal).

func NewVecDequeStorage added in v0.3.0

func NewVecDequeStorage[T any]() *VecDequeStorage[T]

NewVecDequeStorage returns an unbounded VecDequeStorage.

func (*VecDequeStorage[T]) Capacity added in v0.3.0

func (s *VecDequeStorage[T]) Capacity() (int, bool)

Capacity reports the bound and true for a bounded storage, or 0 and false.

func (*VecDequeStorage[T]) Close added in v0.3.0

func (s *VecDequeStorage[T]) Close()

Close marks the queue closed. Idempotent and terminal.

func (*VecDequeStorage[T]) Elements added in v0.3.0

func (s *VecDequeStorage[T]) Elements() []T

Elements returns a copy of the FIFO contents in delivery order (head first). Used by the conformance harness and for snapshot serialization; production code may choose a more efficient binary encoding.

func (*VecDequeStorage[T]) IsClosed added in v0.3.0

func (s *VecDequeStorage[T]) IsClosed() bool

IsClosed reports whether the queue has been closed.

func (*VecDequeStorage[T]) Len added in v0.3.0

func (s *VecDequeStorage[T]) Len() int

Len reports the number of elements held.

func (*VecDequeStorage[T]) Peek added in v0.3.0

func (s *VecDequeStorage[T]) Peek() (T, bool)

Peek returns the head element and true, or the zero T and false when empty.

func (*VecDequeStorage[T]) TryPop added in v0.3.0

func (s *VecDequeStorage[T]) TryPop() (T, QueuePopError)

TryPop removes and returns the head element. A closed non-empty queue keeps draining; only a closed empty queue returns Closed.

func (*VecDequeStorage[T]) TryPush added in v0.3.0

func (s *VecDequeStorage[T]) TryPush(value T) QueuePushError

TryPush appends value, or returns Full/Closed without mutating on reject.

type WindowPolicy added in v0.11.0

type WindowPolicy struct {
	// contains filtered or unexported fields
}

WindowPolicy — Case 8, time-windowed coalescence (debounce/throttle). Flushes when it reaches windowOps ops or on an explicit Tick. Because a window is just a flush group, associativity keeps the converged state unchanged.

func NewWindowPolicy added in v0.11.0

func NewWindowPolicy(windowOps uint64) *WindowPolicy

NewWindowPolicy creates a window that flushes every windowOps ops (min 1).

func (*WindowPolicy) OnIngress added in v0.11.0

func (w *WindowPolicy) OnIngress() bool

OnIngress records one ingress; returns true when the window is full and should flush.

func (*WindowPolicy) Tick added in v0.11.0

func (w *WindowPolicy) Tick() bool

Tick signals the debounce/throttle interval elapsed: flush whatever is pending.

type WireLwwRegister added in v0.8.0

type WireLwwRegister[V any] struct {
	// contains filtered or unexported fields
}

WireLwwRegister is a last-writer-wins register liveness cell (per-pid alive, owner lease).

Keyed by WireStamp ((wall_time, logical, peer) total order): the highest stamp wins, so an OS process-exit write (alive = false at a fresh stamp) dominates a stale re-assert. Join is the stamp-max, a semilattice.

func NewWireLwwRegister added in v0.8.0

func NewWireLwwRegister[V any](stamp WireStamp, value V) *WireLwwRegister[V]

NewWireLwwRegister returns a register holding value written at stamp.

func (*WireLwwRegister[V]) Join added in v0.8.0

func (r *WireLwwRegister[V]) Join(other *WireLwwRegister[V])

Join folds another replica's register (keep the higher stamp).

func (*WireLwwRegister[V]) Set added in v0.8.0

func (r *WireLwwRegister[V]) Set(stamp WireStamp, value V)

Set writes value at stamp iff it dominates the current stamp.

func (*WireLwwRegister[V]) Stamp added in v0.8.0

func (r *WireLwwRegister[V]) Stamp() WireStamp

Stamp returns the current decisive stamp.

func (*WireLwwRegister[V]) Value added in v0.8.0

func (r *WireLwwRegister[V]) Value() V

Value returns the current value.

type WireStamp

type WireStamp struct {
	WallTime int64  `json:"wall_time"`
	Logical  int64  `json:"logical"`
	Peer     PeerId `json:"peer"`
}

WireStamp is the codec-stable wire mirror of the runtime HLC stamp — a total order (wall_time, logical, peer). It is all plain integers so the wire format is stable whether or not a peer compiles the CRDT runtime in; the runtime representation is HlcStamp (hlc.go). Conversion HlcStamp<->WireStamp is owned by crdt.go.

func NewWireStamp

func NewWireStamp(wallTime, logical int64, peer PeerId) WireStamp

NewWireStamp constructs a WireStamp.

func (WireStamp) Greater added in v0.8.0

func (s WireStamp) Greater(other WireStamp) bool

Greater reports whether s dominates other in the (wall_time, logical, peer) total order used by the reliable-sync LWW liveness cells. It reuses the HLC stamp comparison so the wire and runtime orders agree.

func (WireStamp) String

func (s WireStamp) String() string

type WorkQueueCell added in v0.14.0

type WorkQueueCell[T any] struct {
	VisibilityTimeout int64
	MaxDeliveries     uint64
	// contains filtered or unexported fields
}

WorkQueueCell is a process-local competing-consumer work queue.

Item ids survive retries while every claim receives a fresh delivery id. Nack and expired deliveries requeue at the tail until MaxDeliveries is reached, then move to the dead-letter list. A lease is live at its deadline and expires strictly after it.

This object is a local serialization point. Distributed/HA deployments must place a consensus-backed leader or adapter in front of it.

func NewWorkQueueCell added in v0.14.0

func NewWorkQueueCell[T any](ctx *Context, visibilityTimeout int64, maxDeliveries uint64) *WorkQueueCell[T]

NewWorkQueueCell creates an empty queue. It panics for invalid configuration.

func (*WorkQueueCell[T]) Ack added in v0.14.0

func (q *WorkQueueCell[T]) Ack(worker string, deliveryID uint64) bool

func (*WorkQueueCell[T]) Claim added in v0.14.0

func (q *WorkQueueCell[T]) Claim(worker string, now int64) (WorkQueueDelivery[T], bool)

func (*WorkQueueCell[T]) DeadLetterItems added in v0.14.0

func (q *WorkQueueCell[T]) DeadLetterItems() []WorkQueueDeadLetter[T]

func (*WorkQueueCell[T]) DeadLetterLen added in v0.14.0

func (q *WorkQueueCell[T]) DeadLetterLen() int

func (*WorkQueueCell[T]) InFlightDeliveries added in v0.14.0

func (q *WorkQueueCell[T]) InFlightDeliveries() []WorkQueueDelivery[T]

func (*WorkQueueCell[T]) InFlightLen added in v0.14.0

func (q *WorkQueueCell[T]) InFlightLen() int

func (*WorkQueueCell[T]) IsEmpty added in v0.14.0

func (q *WorkQueueCell[T]) IsEmpty() bool

func (*WorkQueueCell[T]) Nack added in v0.14.0

func (q *WorkQueueCell[T]) Nack(worker string, deliveryID uint64) bool

func (*WorkQueueCell[T]) PendingItems added in v0.14.0

func (q *WorkQueueCell[T]) PendingItems() []WorkQueueItem[T]

func (*WorkQueueCell[T]) PendingLen added in v0.14.0

func (q *WorkQueueCell[T]) PendingLen() int

func (*WorkQueueCell[T]) Push added in v0.14.0

func (q *WorkQueueCell[T]) Push(value T) uint64

func (*WorkQueueCell[T]) ReaderHandles added in v0.14.0

func (q *WorkQueueCell[T]) ReaderHandles() WorkQueueReaderHandles

func (*WorkQueueCell[T]) ReapExpired added in v0.14.0

func (q *WorkQueueCell[T]) ReapExpired(now int64) int

type WorkQueueDeadLetter added in v0.14.0

type WorkQueueDeadLetter[T any] struct {
	ItemID   uint64
	Value    T
	Attempts uint64
	Reason   WorkQueueDeadLetterReason
}

type WorkQueueDeadLetterReason added in v0.14.0

type WorkQueueDeadLetterReason string
const (
	WorkQueueDeadLetterNack    WorkQueueDeadLetterReason = "nack"
	WorkQueueDeadLetterExpired WorkQueueDeadLetterReason = "expired"
)

type WorkQueueDelivery added in v0.14.0

type WorkQueueDelivery[T any] struct {
	DeliveryID uint64
	ItemID     uint64
	Value      T
	Worker     string
	Attempt    uint64
	Deadline   int64
}

WorkQueueDelivery is one exclusive leased delivery to a worker.

type WorkQueueItem added in v0.14.0

type WorkQueueItem[T any] struct {
	ItemID   uint64
	Value    T
	Attempts uint64
}

WorkQueueItem is a stable logical item. Attempts counts completed claims.

type WorkQueueReaderHandles added in v0.14.0

type WorkQueueReaderHandles struct {
	PendingLen    *Computed[int]
	IsEmpty       *Computed[bool]
	InFlightLen   *Computed[int]
	DeadLetterLen *Computed[int]
}

Directories

Path Synopsis
cmd
lazily-interop-peer command
Command lazily-interop-peer is NDJSON test infrastructure for the cross-binding Lazily interoperability suite.
Command lazily-interop-peer is NDJSON test infrastructure for the cross-binding Lazily interoperability suite.
internal
goid
Package goid provides a fast goroutine-id lookup for reentrant locking.
Package goid provides a fast goroutine-id lookup for reentrant locking.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL