Skip to content

Changelog — page 11

New features, improvements, and fixes in the Fluxzero SDK.

GitHub

1.248.0 (2026-09-01)

Dependency updates
  • bump io.fluxzero.tools:fluxzero-maven-plugin from 1.16.1 to 1.17.0 (GitHub)

    io.fluxzero.tools:fluxzero-maven-plugin: 1.16.1 -> 1.17.0 changelog

GitHub

Symmetric document-based Models

RC3 is a focused correctness release on top of RC2. Document-authoritative Models now use the configured DocumentSerializer for both storage and reconstruction, so the Model repository obeys the same complete-document contract as ordinary Document Store reads.

What changed

For @Model(eventSourced = false), every repository read now passes the complete SerializedDocument to DocumentSerializer.fromDocument(...). This applies consistently to direct and current loads, batched loads, cache refresh after a miss or restart, Graph reconstruction, and namespaced repositories.

That makes document-level transformations truly round-trip capable:

  • encryption and decryption;
  • compression;
  • signing and integrity verification;
  • custom envelopes;
  • transformations that depend on document ID, collection, timestamps, or metadata.
Fluxzero.builder()
        .replaceDocumentSerializer(myDocumentSerializer)
        .build();
Compatibility

There is no persisted- or wire-format change. The default document serializer produces the same result as before, and event-sourced Model reconstruction is untouched. Existing custom serializers only gain the missing symmetric read callback.

Use SDK and Runtime 2.0.0-RC3 as a matching pair.

Full comparison: 2.0.0-RC2...2.0.0-RC3

GitHub

Fluxzero 2.0.0-RC2 — Sharper Models, Reliable Dev Startup

Fluxzero 2.0 is about modeling independent domain lifecycles directly: every independently living object is a @Model, durable @Parent relationships connect those Models, and Graph<T> restores coherent context only where an application needs it.

RC2 keeps that Model/Graph foundation intact and makes the release considerably easier to adopt. The embedded Dev Server can now retain a wider startup window for brand-new consumers, while the human guides, public Javadocs and Java/Kotlin agent manuals have been brought onto the same current API and design language.

Model the lifecycle, then choose storage

The central 2.0 rule is now expressed consistently throughout the documentation:

@Model(materializeGraph = true)
record Project(
        @EntityId ProjectId projectId,
        ProjectDetails details) {
}

@Model
record Task(
        @EntityId TaskId taskId,
        @Parent(pathInParent = "tasks") ProjectId projectId,
        TaskDetails details) {
}

Task is independent because it has its own identity and lifecycle—not because it is large, searchable or awkward to embed. It can have its own history, retention, deletion and concurrency while still appearing naturally below a Project:

Graph<Project> project = Fluxzero.loadGraph(projectId);
List<Task> tasks = project.childModels("tasks", Task.class);

List<Graph<Project>> activeProjects = Fluxzero.searchGraph(Project.class)
        .whereDescendant(Task.class, MatchConstraint.match(false, "completed"))
        .fetchAll();

The revised guides cover the complete current contract: typed Model and Graph search, lazy and historical Graph loading, pinned state boundaries, polymorphic and recursive relationships, Graph context and derived properties, direct Model search versus Graph materialization, event publication, event sourcing and the forward-only Aggregate-to-Model migration path.

The bundled Java and Kotlin project files now teach exactly the same capabilities and use the same public type catalogue as the human documentation.

Reliable startup commands in the Dev Server

An embedded Test Server previously started a new consumer one second before the current end of its log. That default is safe and remains unchanged, but it was too narrow for development tools that may publish startup commands before application handlers finish registering.

Embedded owners can now choose the initial look-back explicitly:

Server server = TestServer.startServer(0, Duration.ofSeconds(10));

The duration applies only when a consumer has no stored or client-controlled position. Existing durable positions are never moved backwards, and every existing startServer(port) and local-client entry point retains the one-second default. Embedded tooling can also observe typed consumer readiness instead of confusing an open connection with a registered message handler.

Compatibility and RC status

  • RC2 introduces no new Model persisted or wire format compared with RC1.
  • Existing Aggregate, messaging, search, scheduling and web applications remain supported.
  • Runtime 2.0 remains compatible with 1.x SDK clients.
  • SDK 2.0 can use a 1.x Runtime for existing non-Model capabilities; new Model persistence requires Runtime 2.0.
  • RC2 artefacts are immutable prereleases. Stable latest images, stable Javadocs and stable site signals remain untouched.
Component Release
Maven BOM io.fluxzero:fluxzero-bom:2.0.0-RC2
Test Server image ghcr.io/fluxzero-io/fluxzero-sdk-java/fluxzero-test:2.0.0-RC2
Proxy image ghcr.io/fluxzero-io/fluxzero-sdk-java/fluxzero-proxy:2.0.0-RC2
Javadocs 2.0.0-RC2

Explore the current 2.0 API

GitHub

1.247.0 (2026-08-31)

Dependency updates
  • bump io.fluxzero.tools:fluxzero-maven-plugin from 1.16.0 to 1.16.1 (GitHub)

    io.fluxzero.tools:fluxzero-maven-plugin: 1.16.0 -> 1.16.1 changelog

GitHub

1.246.0 (2026-08-28)

Features
  • test-server: configure initial consumer look-back (#308) (GitHub)

    * feat(test-server): expose consumer readiness observation

    Allow embedded runtime owners to observe registered typed consumers so local tooling can distinguish connection from actual message consumption readiness. Observer failures remain isolated and existing start behavior keeps its no-op default.

    * feat(test-server): configure initial consumer look-back

    Keep the existing one-second default while allowing embedded runtimes to retain a wider startup window for consumers without stored positions. Preserve existing positions and local client constructor contracts.

GitHub

1.245.0 (2026-08-28)

Dependency updates
  • bump io.fluxzero:lychee-maven-plugin from 0.2.9 to 0.2.10 (GitHub)

    io.fluxzero:lychee-maven-plugin: 0.2.9 -> 0.2.10 changelog

Continuous Integration
  • release: establish major release trains [skip ci] (GitHub)

    Prepare protected 2.0 integration and maintenance lines without publishing a release for this infrastructure-only change.

  • release: establish major release trains (GitHub)

    Keep stable updates automatic on main while making 2.0 milestones explicit and isolated from stable package tags, documentation, and site notifications.

GitHub

Fluxzero 2.0.0-RC1 — Independent Models and Graphs

Fluxzero 2.0 introduces a new foundation for persisted domain state: independent Models connected by durable relationships and exposed as coherent Graphs.

In Fluxzero 1.x, an Aggregate root was often forced to own much more than the business domain required. Identity, persistence, history, caching, concurrency and deletion of independently living children all ended up behind one root and usually in one ever-growing stream.

Fluxzero 2.0 separates those concerns:

  • every domain object with its own lifecycle becomes an independent @Model;
  • @Parent records relationships without embedding or duplicating child state in the parent;
  • Graph<T> reconstructs the coherent domain view when code actually needs the surrounding context;
  • one command can assert and change multiple Models in one atomic commit;
  • event sourcing, document loading, caching, snapshots, direct search and Graph materialization become storage choices made after the domain boundary is correct.

The familiar Fluxzero programming model remains: immutable messages, annotated handlers, automatic dependency injection, event publication, upcasting and the TestFixture. The major change is that storage shape no longer has to dictate domain shape.

Model the lifecycle, not the container

If a Task can be created, changed, retained or deleted independently, it is a Model—even when users normally see it inside a Project:

@Model(materializeGraph = true)
public record Project(
        @EntityId ProjectId projectId,
        ProjectDetails details) {
}

@Model
public record Task(
        @EntityId TaskId taskId,
        @Parent(pathInParent = "tasks") ProjectId projectId,
        TaskDetails details,
        boolean completed) {
}

ProjectId and TaskId carry their Model type, so Fluxzero can resolve command targets, loads and relationships without class arguments or casts.

Project and Task now have separate streams, histories, caches and lifecycles. Moving a Task only changes its projectId; Fluxzero updates the durable relationship without loading or rewriting either Project. Because ProjectId is typed, @Parent infers Project.class. Parent-scoped IDs, recursive relationships such as Folder → Folder, polymorphic parents, aliases and configurable cascade deletion are supported.

Use @Member only when a nested value deliberately shares all creation, change, history, retention and deletion with its root.

Commands become atomic Model transitions

Commands can carry their assertions and state transition directly:

public record CompleteTask(TaskId taskId) {
    @AssertLegal
    void assertOpen(Task task) {
        if (task.completed()) {
            throw new IllegalStateException("Task is already complete");
        }
    }

    @Apply
    Task apply(Task task) {
        return new Task(
                task.taskId(), task.projectId(),
                task.details(), true);
    }
}

Publishing CompleteTask is enough. Fluxzero resolves the target, runs interceptors and assertions, applies the transition and durably commits the result. No boilerplate command handler or aggregate lookup is required.

One payload may read, create, update, move or delete several independent Models in the same atomic commit. Payload-side handlers run first; Model-side @InterceptApply, @AssertLegal and @Apply methods then add reusable domain-wide behavior against the intermediate state. Conflict retries, replay and live handling use that same deterministic reducer. Commands in one ordered batch also get read-your-writes without making unrelated Model chains wait for each other.

Graphs restore context without restoring coupling

Graph<T> is a typed, lazy view over one Model and its relationships:

ProjectId projectId = new ProjectId("1");
Graph<Project> project = Fluxzero.loadGraph(projectId);

List<Task> tasks = project.childModels("tasks", Task.class);
Graph<Project> before = project.previous();

The root Model is loaded only when its value is requested; parents, children, descendants and history are resolved lazily at one pinned state boundary. A Graph can:

  • navigate parents, children and descendants;
  • expose the complete state before a change;
  • load an exact historical boundary or play back to an event;
  • stage updates and deletions;
  • serialize as a nested response through explicit pathInParent relationships;
  • filter or select response branches without copying Model values;
  • add derived @GraphProperty values;
  • be injected directly into command, query, event, document and web handlers.

A sole Graph<Project> parameter on an event or notification handler subscribes to durable changes anywhere below that root. Fluxzero supplies the exact before and after Graph and also handles child moves and root deletion coherently.

Search live or materialized Graphs

Graph search uses the regular typed Search API:

List<Graph<Project>> projects = Fluxzero.searchGraph(Project.class)
        .whereDescendant(
                Task.class,
                MatchConstraint.match(false, "completed"))
        .fetchAll();

Fluxzero uses a configured materialized projection when available and otherwise composes the Graph live. A materialized Graph is a derived search document; the independent Models and their relationships remain authoritative. Direct Model search is configured separately.

Current point reads always use the committed Model state, even while asynchronous Graph materialization is catching up. Materialized Graphs retain the concrete type and revision of every node, so the ordinary serializer can upcast each Model independently. @HandleDocument(modelGraph = ...) can persist evolved node schemas back into the derived projection without rewriting authoritative Model history.

Event sourcing without giant root streams

Models are event-sourced by default. Because every independently living Model has its own stream, a short-lived Task no longer inflates the lifetime history of its Organisation or Project. Snapshotting and bounded reconstruction remain available for genuinely long streams.

Document-based loading is also supported for Models that should read their current state directly. This changes the load strategy—not whether their updates can be stored and published as events. Search documents, cache retention, snapshots, event publication and Graph materialization are independently configurable.

Model and Graph injection into event handlers is pinned to the exact durable Model commit that produced the event. Historical relations therefore cannot accidentally observe a newer cached parent or child.

A gradual path from Aggregates to Models

Changing @Aggregate to @Model is deliberately not treated as a persistence migration. Fluxzero 2.0 instead provides a controlled, forward-only migration path:

  1. replay published legacy events into shadow Models;
  2. catch up continuously while the legacy application remains the only write owner;
  3. validate and adopt the reconstructed state;
  4. move queries and read-only listeners to Models and Graphs incrementally;
  5. transfer command ownership per Model boundary only after every check reports GO.

The migration runner preserves the link between a legacy global event and the Model state created from it. Converted event handlers can therefore inject the exact new Model or Graph state for that old event. Multiple migration instances use one durable single-tracker consumer for safe failover, and document-backed state is staged outside normal reads until adoption. Legacy STORE_ONLY events are outside this global-log replay source.

This lets applications validate the new representation under real event traffic without committing to a big-bang cutover.

Built as a production path, not an adapter layer

Models use a dedicated high-throughput SDK/Runtime commit protocol with bounded batching, compact binary framing, durable receipts, conflict-aware retries, cache coherence and restart-safe projection processing. Direct Model changes, atomic multi-Model actions, Graph reads and asynchronous materialization all share the same authoritative commit boundary.

The complete command → result, command → Model and command → Model → Graph routes were characterized throughout development, alongside the existing non-Model routes. The design keeps unrelated Models parallel and avoids rebuilding or serializing a complete Graph when only one Model changes.

Compatibility and RC status

  • Existing messaging, handler, Aggregate, search, scheduling and web APIs remain available for 1.x applications.
  • New persisted state should use @Model; the legacy Aggregate API remains for existing applications and deliberate migrations.
  • Runtime 2.0 remains compatible with 1.x SDK clients.
  • SDK 2.0 can continue to use a 1.x Runtime for existing non-Model capabilities; new Model persistence requires Runtime 2.0.
  • This is the first release candidate. It is intended for realistic application migration, performance and deployment validation before 2.0 GA.

Use the matching immutable RC for SDK and Runtime:

Component Release
Maven BOM io.fluxzero:fluxzero-bom:2.0.0-RC1
Runtime image ghcr.io/fluxzero-io/fluxzero-runtime/fluxzero-runtime:2.0.0-RC1
Test Server image ghcr.io/fluxzero-io/fluxzero-sdk-java/fluxzero-test:2.0.0-RC1
Proxy image ghcr.io/fluxzero-io/fluxzero-sdk-java/fluxzero-proxy:2.0.0-RC1

Start exploring

Fluxzero 2.0 is the point where the code can finally say what the domain already knew: an entity is independent because it has its own life—not because it happens to fit inside somebody else's list.

GitHub

1.244.0 (2026-08-27)

Features
  • web: attach outbound query metric metadata (GitHub)

    Preserve the original raw query under a stable metadata key for both native and proxy metrics while keeping handler payload types unchanged. Keep userinfo and fragments excluded and retain the proxy formatType extension point.

  • web: include request targets in outbound metrics (GitHub)

    Expose the original normalized scheme, hostname, effective port, and raw path for native requests and proxy handler metrics. Keep userinfo, query, fragment, headers, bodies, and exception details outside the metric payload.

  • proxy: enforce outbound redirect policies (GitHub)

    Materialize the application redirect default into proxy-routed messages and enforce NEVER, SAME_ORIGIN, and ALLOW in the forward proxy with bounded same-origin hops. Preserve compatibility for old DEFAULT messages and remove destinations from proxy handler metric types.

  • web: harden native redirects and metrics (GitHub)

    Add versioned redirect policies for native outbound requests and emit privacy-safe transport outcomes through the metrics gateway.

    Bound same-origin redirect forwarding before sensitive headers or bodies are reused while preserving compatibility-mode JDK redirects.

Bug Fixes
  • proxy: keep handler metrics destination-free (GitHub)

    Keep the existing proxy HandleMessageEvent limited to the request method because proxied WebRequests are already observable in their own message log. Target fields and raw-query metadata remain exclusive to native outbound metrics.

Continuous Integration
  • repo: enforce canonical line endings (GitHub)

    Normalize the Maven Windows wrapper in Git while retaining CRLF checkouts through .gitattributes. Fail PR and main builds early when tracked blobs bypass repository normalization.

Tests
  • proxy: await retry delay cancellation (GitHub)

    Observe the cancellation callback instead of sampling the retry future immediately after shutdown handoff. This preserves the shutdown contract while removing the scheduler race from the assertion.

GitHub

1.243.0 (2026-08-27)

Features
  • proxy: schedule asynchronous forwards by segment (GitHub)

    Execute forwarded HTTP calls through one proxy-wide bounded asynchronous scheduler. Preserve exact-segment serial order and durable backpressure, and return unfinished HTTP work to the WebRequest log only when a hard shutdown deadline expires.

Dependency updates
  • bump actions/setup-java from 5 to 6 (GitHub)

    actions/setup-java: 5 -> 6 changelog

GitHub

1.242.0 (2026-08-26)

Tests
  • concurrency: remove async fixture races (GitHub)

    Move active timeout interruption coverage to the timebox owner with an explicit start barrier, and hold the cache-filler tracker out of the delegate-fallback scenario. This preserves cancellation and caching assertions without relying on scheduler order.

GitHub

1.241.0 (2026-08-26)

Features
  • web: support native requests and configurable retries (GitHub)

    Allow outbound web requests to use a lifecycle-managed native HTTP client and configure bounded retries while preserving proxy defaults. Keep fixture endpoint mocks effective and propagate asynchronous cancellation to active native operations.

GitHub

1.240.1 (2026-08-26)

Dependency updates
  • bump io.fluxzero.tools:fluxzero-maven-plugin from 1.15.2 to 1.16.0 (GitHub)

    io.fluxzero.tools:fluxzero-maven-plugin: 1.15.2 -> 1.16.0 changelog

GitHub

1.240.0 (2026-08-25)

Features
  • correlation: add deployed application version metadata (GitHub)

    Resolve the optional application version once from the configured property source and attach it through the existing correlation provider. Preserve custom providers and the prepared local dispatch path while making the deployed value authoritative.

GitHub

1.239.12 (2026-08-24)

Dependency updates
  • bump org.springframework:spring-framework-bom from 7.0.8 to 7.0.9 (GitHub)

    org.springframework:spring-framework-bom: 7.0.8 -> 7.0.9 changelog

GitHub

1.239.11 (2026-08-22)

Bug Fixes
  • modeling: retain untyped aggregate type on delete (GitHub)

    Persist the inferred concrete type after untyped aggregate transitions and fall back to the previous type when committing deletions. This lets type-specific searchable repositories remove documents for cached and uncached aggregates.

Tests
  • websocket: await all dispatcher submissions (GitHub)

    Retain both independently admitted staged completions in the callback-failure interleaving before asserting global empty state. This removes a valid completion-order race without changing dispatcher behavior.

GitHub

1.239.10 (2026-08-22)

Bug Fixes
  • modeling: guard delayed aggregate index update (GitHub)

    Guard event-index assignment when a delayed own notification refers to a revision that is no longer retained. Preserve conservative eviction and codify empty cache-value behavior after functional deletes for event-sourced and non-event-sourced aggregates.

GitHub

1.239.9 (2026-08-20)

Dependency updates
  • bump io.fluxzero.tools:fluxzero-maven-plugin from 1.15.0 to 1.15.2 (GitHub)

    io.fluxzero.tools:fluxzero-maven-plugin: 1.15.0 -> 1.15.2 changelog

  • bump com.github.luben:zstd-jni from 1.5.7-13 to 1.5.7-15 (GitHub)

    com.github.luben:zstd-jni: 1.5.7-13 -> 1.5.7-15

GitHub

1.239.8 (2026-08-20)

Dependency updates
  • bump com.fasterxml.jackson:jackson-bom from 2.22.1 to 2.22.2 (GitHub)

    com.fasterxml.jackson:jackson-bom: 2.22.1 -> 2.22.2

GitHub

1.239.7 (2026-08-18)

Dependency updates
  • bump ch.qos.logback:logback-classic from 1.6.2 to 1.6.3 (GitHub)

    ch.qos.logback:logback-classic: 1.6.2 -> 1.6.3 changelog

GitHub

1.239.6 (2026-08-17)

Bug Fixes
  • websocket: isolate liveness with staged runtime dispatch (#286) (GitHub)

    fix(websocket): isolate liveness with bounded runtime ingress

    Replace overflow-triggered reconnects with receive-demand backpressure. Separate WebSocket protocol handling, runtime-message decoding, and functional result completion so slow customer callbacks cannot block pong handling or decode progress.

    Process result batches incrementally through a fair, bounded dispatcher. Preserve the existing worker policy: virtual threads on Java 25+ and a lazy platform-thread pool on Java 21–24.

    Introduce these defaults:

    - fluxzero.runtime.ingress.maxConcurrency=3 per session
    - fluxzero.runtime.ingress.maxRetainedMessages=128 per session
    - fluxzero.runtime.ingress.maxRetainedBytes=67108864 per session
    - fluxzero.runtime.ingress.maxCompletionConcurrency=8 per client
    - fluxzero.runtime.ingress.stallCloseTimeout=PT0S (disabled)

    Retain compressed-wire credit through functional completion while releasing compressed payloads after dispatcher admission. Allow a sole oversized message to progress. No activation property is required; applications with measured workloads can override the bounded defaults explicitly.

    Finalize opt-in WebsocketTransportMetric diagnostics, that when enabled with:

    - fluxzero.websocket.transportMetrics.enabled=true

    will report:

    - PING_TIMEOUT
    - RUNTIME_INGRESS_BACKPRESSURED
    - RUNTIME_INGRESS_STALLED
    - RUNTIME_INGRESS_RECOVERED
    - RUNTIME_INGRESS_OVERFLOW
    - RUNTIME_EXECUTOR_REJECTED

    Avoid per-message, ping, or pong metric publication on the healthy path. Suppress transport diagnostics for the metrics WebSocket itself to prevent recursive pressure.

    Document the configuration, liveness policy, diagnostics, and compatibility considerations. Add regression and load coverage for protocol liveness, backpressure, failure recovery, large tracking responses, result ordering, and bounded resource use.

    Co-authored-by: Michel Tiemens <michel@flux.host>


© 2026 Fluxzero