Skip to content

Releases: CriandoGames/all_observer

Fixes for reactive failure recovery

Choose a tag to compare

@CriandoGames CriandoGames released this 17 Jul 11:15

Patch release focused on audit-confirmed correctness fixes for reactive failure recovery, closed async resources, and collection atomicity.

Computed now retries correctly after an initial compute error instead of leaving the derivation poisoned by the failed evaluation.
effect() now cleans up tracked dependencies when creation throws, avoiding inaccessible zombie effects that could run again on later dependency writes.
effect() scheduling now distinguishes direct self-invalidations from indirect same-flush invalidations, so chained effect/computed graphs converge to the latest value.
Failed Observable.batch() calls still discard queued direct notifications, but already-live computed dependents are marked stale so the next read reconciles with the mutated source value.
ObservableFuture.run() and ObservableStream.run() are no-ops after close(), preventing closed async resources from starting new work or stream subscriptions.
ObservableList.addAll(), insertAll(), assignAll(), and sort() are atomic when the source iterable or comparator throws; the list remains unchanged and no notification is emitted.
Added audit tests plus permanent regression coverage for the confirmed issues. Full suite now covers 389 tests.
No breaking changes and no new dependencies.

Engine v2

Choose a tag to compare

@CriandoGames CriandoGames released this 07 Jul 20:09
07ed6fc

all_observer now runs on its own push-pull reactive graph engine, built in-house from the ground up. It's the biggest change under the hood since the package's first release — and it costs you nothing: no breaking changes, no new dependencies, same public API. Every documented behavior contract (glitch-free two-phase batching, in-batch read staleness, eager per-flush settling, equals filtering, per-listener error isolation, inspectors) is preserved, and the pre-existing 286-test suite passes unmodified.

Why it matters: the new engine is O(1) on link/unlink, reuses links across re-tracks with zero allocation when your dependency set doesn't change, and propagates fully iteratively — so deeply nested reactive graphs are bounded by available heap instead of the call stack. It also now ships as its own public entry point, so you can build a custom reactive layer directly on top of the same core engine that powers all_observer itself.

New public entry point package:all_observer/engine.dart: a standalone, pure-Dart, policy-free reactive graph engine (ReactiveEngine, ReactiveNode, ReactiveLink, ReactiveFlags) designed for third parties to build their own reactive layers on — the same machinery all_observer itself now runs on. Dependencies are intrusive doubly-linked lists (O(1) link/unlink, links reused in place across re-tracks — zero allocation when the read set doesn't change), node state is bit flags in a single int (via a zero-cost extension type), and both propagation phases are fully iterative (explicit stack), so graph depth is bounded by heap instead of the call stack. Behavior is delegated to three hooks: update (recompute; its bool return is the propagation cut), notify (schedule a watcher) and unwatched (last-subscriber cleanup). Tutorial in documentation/*/engine.md; a minimal, runnable signals implementation built on it lives in test/engine/fixtures/mini_preset.dart.
CoreComputed rewired onto the engine (lib/src/core/engine_bridge .dart, exported by core.dart): dependency tracking moved from per-recompute registry subscriptions (clear-all + resubscribe, one closure disposer per dependency per run) to engine links, and invalidation became push-pull — a flushed notification only marks dependents stale (ListenerRegistry.notifyAll → propagate), and an internal WatcherNode (created on first evaluation, kept until close()) pulls the fresh value in phase 2 of the same BatchScope flush as always. Reads landing between marking and settling resolve lazily on the spot (checkDirty), which also settles deep computed cascades within a single flush wave instead of one wave per graph level. Integration rides entirely on DependencyTracker.reportRead and ListenerRegistry.notifyAll/notifyOrQueue, so CoreObservable, BatchScope, collections, async, workers and widgets are untouched. See ADR-0003 in ARCHITECTURE.md.
Observable.hasListeners now also counts engine-graph dependents (a Computed depending on the observable), preserving its long-standing meaning now that computeds are no longer plain registry listeners.
Self-dependency detection: a Computed whose compute() reads its own value (directly or through a chain) now throws a descriptive ObserverCycleError instead of overflowing the call stack.
TrackingContext gained a subscribes flag (default true, source-compatible): a recomputing CoreComputed pushes a non-subscribing context, keeping outer-context isolation, read counting and onTrack inspector events while the engine handles invalidation.
Engine test suites: test/engine/ (graph semantics: lazy pull, propagation cut via custom equals, link reuse identity, conditional branch switching, 50k-deep chains without stack overflow, batching, automatic unwatched cleanup) and test/core/engine_bridge_test.dart (bridge semantics against the package contracts).

all_observer 1.3.2

Choose a tag to compare

@CriandoGames CriandoGames released this 06 Jul 12:47

Documentation/example-only release — no code changes to lib/, no breaking changes, no new external dependencies.

Added real, runnable tests under example/test/ proving the library's testability: a widget test, a pure-Dart controller unit test, a measurable rebuild-granularity test, a debounce worker test using flutter_test's virtual time, a deterministic ObservableFuture test via injected fakes, and a strictMode misuse test.
Extracted the example demos' business logic into constructor-injectable controllers under example/lib/controllers/ (CounterController, FruitSearchController, FetchController) — the "testable architecture" pattern the new guide recommends.
New documentation/en/testing.md / documentation/pt-BR/testing.md guide, linking every snippet to the real test file it comes from; linked from both READMEs, both FAQs, and the doc navigation chain.
Added example/README.md and wired example/ into CI (flutter test now also runs there).