Vix.cpp v2.8.5
Vix.cpp v2.8.5 stabilizes the Realtime module and strengthens the dependency model used by modular Vix applications.
The release focuses on two areas that become increasingly important as projects grow. Realtime applications need reliable persistence, recovery, session handling, packaging, and concurrency behavior. Modular applications need equally reliable dependency ownership, graph validation, lockfile behavior, and project mutations.
v2.8.5 brings those concerns under stricter contracts.
Git dependencies can now belong to individual application modules, module relationships are validated through a canonical graph before CMake generation, dependency conflicts are detected across the application and its active modules, and project metadata changes are applied transactionally so partial failures do not leave vix.app, vix.module, or vix.lock in inconsistent states.
At the same time, Vix Realtime has completed another stabilization pass across persistence, recovery, presence, session resume, SDK packaging, PostgreSQL support, protocol integration, and concurrency behavior.
Release focus
Application modules give larger C++ projects a clearer internal structure. Once modules can own their own dependencies, however, package management can no longer treat the project as one flat list of libraries.
The build system needs to know which module owns a dependency, whether two modules request compatible versions of the same package, whether a dependency belongs to the root application or a child module, and whether the resulting module graph can be built deterministically.
Those checks should happen before generated CMake files are produced.
The same problem exists when changing project metadata. Installing or removing a dependency can affect several files at once. If one write succeeds and a later operation fails, a project can be left with a manifest that no longer matches its lockfile.
v2.8.5 addresses both problems by giving module structure and project mutations explicit models rather than relying on command-specific behavior.
Vix Realtime stabilization
vix::realtime continues to provide the authoritative state model introduced in the v2.8 line.
The module includes stateful rooms, serialized command execution, persisted events, snapshots, event replay, logical sessions, reconnection, presence, persistence abstractions, and optional WebSocket and PostgreSQL integrations.
v2.8.5 focuses on stabilizing how these pieces behave together.
Authoritative room state can be reconstructed from persisted history, snapshots are handled transactionally, replay continues from deterministic event positions, and session resume restores the state needed for a client to continue after disconnection.
Presence lifecycle behavior has also been tightened around connection attachment, detachment, expiration, and session recovery.
The release validates both in-memory and PostgreSQL persistence paths so application behavior does not depend on which store is selected.
Realtime persistence and recovery
Realtime persistence is designed around events and snapshots rather than direct mutation of stored room state.
Accepted commands produce authoritative events. Those events are persisted in order, applied to the room, and used later when the room must be reconstructed.
Snapshots reduce the cost of restoring long histories. Recovery can load the latest valid snapshot and replay only the events that follow it.
v2.8.5 strengthens the contracts around that process.
Snapshot creation, persistence, replay, room version restoration, and session resume are validated together rather than as isolated features. Recovery paths are expected to preserve the same authoritative state, room version, and event ordering that existed before the room was stopped.
The PostgreSQL implementation follows the same model as the in-memory stores so applications can move between local and persistent environments without changing room logic.
Session resume and presence
Realtime sessions remain separate from individual network connections.
A temporary transport failure can detach a connection while the logical session, room memberships, acknowledgement positions, and resume information remain available.
When a client reconnects, session resume can restore its relationship with the rooms it previously joined and replay events that were not acknowledged before the disconnection.
Presence follows the same lifecycle.
A session can become detached without immediately being treated as gone. Expiration and cleanup rules determine when stale presence should be removed, while successful session recovery can restore active presence without creating a second logical participant.
v2.8.5 validates these transitions more strictly across connection loss, resume, room membership, replay, and presence recovery.
Realtime SDK packaging
Realtime is now treated as a first-class installable Vix module.
Its public SDK surface is packaged with isolated headers and the module can be consumed without depending on private build-tree layout.
This matters for two different workflows.
Applications using the complete Vix SDK need the realtime headers and CMake targets to behave like other Vix modules. Standalone package consumers need the module to expose only what belongs to its public contract.
The packaging work in v2.8.5 validates both cases and checks that Realtime remains usable when installed independently from the development source tree.
Metrics and health APIs
The Realtime module now exposes metrics and health interfaces for observing runtime state.
These APIs provide a stable place for applications and infrastructure tooling to inspect the runtime without reaching into internal room, store, or connection implementation.
They are intended to support operational checks around room activity, persistence, recovery, and runtime health while keeping those concerns separate from application command handlers.
Module-scoped Git dependencies
Git dependencies can now be assigned directly to an application module.
For example:
vix install https://github.com/gabime/spdlog \
--tag v1.15.3 \
--target spdlog::spdlog \
--module authThe dependency is written to the target module's vix.module rather than to the root application manifest.
The project still uses one root vix.lock and the shared Vix dependency cache.
This separation is deliberate. Dependency ownership belongs to the module that uses the package, while dependency resolution and reproducibility remain project-wide concerns.
A module therefore does not receive its own independent lockfile or duplicate Git checkout simply because it owns a dependency.
Dependency ownership
v2.8.5 introduces explicit dependency ownership across the application and its modules.
A dependency can belong to the root application or to one of its active modules. That information is carried into graph analysis and generated integration.
This prevents one module from accidentally inheriting a sibling module's private dependency simply because both are part of the same project.
For example, if auth declares a Git dependency, another module does not automatically receive that target unless the application architecture makes the relationship explicit.
The build graph can therefore reflect the project structure rather than flattening every dependency into one global CMake target list.
Shared dependencies across modules
Isolation does not require duplication.
Two modules can depend on the same package when their requirements are compatible. Vix can resolve the package once, record it once in the root lockfile, and reuse the same cached checkout and resolved target for both module owners.
This gives the project one deterministic dependency graph while preserving ownership information.
The important distinction is between package identity and package ownership.
The resolved dependency can be shared, but Vix still knows which modules requested it and can validate whether their requirements agree.
Canonical module manifests
vix.module is now represented through a canonical ModuleManifest model.
Instead of individual commands parsing module metadata differently, the CLI has one normalized representation for module identity, paths, dependencies, and configuration.
This reduces a class of inconsistencies where one command could accept a module declaration that another interpreted differently.
The canonical model also provides the input needed for architecture validation before generated build files are written.
Canonical module graph
The application module structure is now represented through a canonical ModuleGraph.
The graph tracks module identity, normalized paths, dependencies between modules, cycles, and deterministic dependency ordering.
This means module validation is no longer limited to checking whether a directory or manifest exists.
Vix can reason about the architecture as a complete graph before build generation begins.
The graph detects:
- normalized module-name collisions;
- module path collisions;
- references to invalid modules;
- dependencies on disabled modules;
- self-dependencies;
- dependency cycles.
The resulting module order is deterministic, so equivalent project metadata produces the same dependency ordering across runs.
Cross-module dependency constraints
Module dependency requirements are now analyzed together.
If the root application and one or more modules request the same dependency with incompatible constraints, Vix reports the conflict before generated CMake integration is created.
The same applies when two modules disagree about a Git dependency, target, revision, or other requirement that cannot be satisfied by one shared resolution.
Earlier behavior could allow one declaration to overwrite another depending on processing order.
v2.8.5 replaces that last-write-wins behavior with explicit conflict detection.
This makes dependency resolution a property of the complete application graph rather than an accidental result of command ordering.
Git dependency identity
Git dependency identity has been normalized more carefully.
Repository-root subdirectories that are omitted and subdirectories written as . now represent the same source location.
This matters because two otherwise identical dependency declarations should not produce separate lock entries or cache identities only because one command serialized the repository root differently.
The normalized identity is used when reconciling manifests, lockfiles, ownership, and cached Git checkouts.
CMake dependency options
CMake options associated with Git dependencies are now preserved through the lockfile and generated integration.
A dependency that requires a particular configuration can therefore be resolved once and regenerated later without losing the options that were part of its original installation contract.
This is particularly important for dependencies whose exported targets or generated headers depend on CMake configuration.
The lockfile records enough information for Vix to reconstruct the same dependency integration rather than only remembering the repository and revision.
Atomic project mutations
Dependency and module changes now use project-scoped transactional mutations.
Commands such as vix add, vix remove, vix update, vix install, and module mutation commands can update several project files as one logical operation.
Before changing those files, Vix acquires a project mutation lock.
The lock prevents two commands from modifying project metadata concurrently and silently overwriting each other's changes.
Writes are staged before they replace the active project files. If a later step fails, the previous metadata can be restored instead of leaving only part of the mutation applied.
Transaction rollback
Failed project mutations restore the previous metadata byte-for-byte.
This matters because a rollback should not merely create a logically similar manifest. It should restore the project state that existed before the command began.
A failed Git resolution, invalid module target, incompatible dependency constraint, lockfile error, or other mutation failure therefore does not leave behind a partially changed vix.app, vix.module, or vix.lock.
Direct Git installations use the same transactional behavior.
The command can perform remote work, validate the result, and only commit the project metadata changes once the operation is known to be valid.
Interrupted transaction recovery
Project transactions are recorded under:
.vix/transactionsIf a mutation is interrupted after staging project changes, Vix can use the transaction state to recover the project rather than assuming that the partially written metadata is authoritative.
This protects against a different class of failure than ordinary command errors.
Rollback handles known failures inside a running command. Transaction recovery handles operations that did not get a chance to complete their own cleanup.
Both paths use the same project mutation model.
Safer module installation
A module-scoped Git install validates the target module before performing remote work.
For example, Vix checks that the module exists, is active, and can participate in the current graph before cloning or resolving the requested repository.
This avoids downloading and preparing a dependency only to discover afterward that the module declaration itself is invalid.
The same principle applies to dependency conflicts.
Architecture and ownership checks are performed as early as possible so expensive remote operations are not used to discover problems that can already be determined from local project metadata.
Smarter vix install
vix install now reconciles vix.app and vix.lock instead of resolving the entire dependency set unconditionally.
Only new or changed dependencies need remote resolution.
Unchanged dependencies can reuse their existing resolved state, cached checkout, and generated integration.
This improves both speed and predictability.
An install command should not contact remote Git repositories or recreate links simply because another unrelated dependency was added to the project.
When the lockfile already proves that a dependency matches its manifest declaration, Vix can preserve that result.
Git cache reuse
Resolved Git checkouts are reused directly from the Vix dependency cache.
Multiple compatible module owners can reference the same cached dependency, and repeated installs can avoid downloading repositories that have already been resolved.
This reuse remains tied to the normalized dependency identity and lockfile state.
The cache is therefore an implementation optimization around deterministic dependency resolution rather than an alternative source of truth.
Installation without a build-complete application
Dependency operations performed by vix install no longer require a fully buildable vix.app.
A project can install and reconcile dependencies while its application sources or other build-specific fields are still incomplete.
This is useful during project setup, dependency recovery, and repository initialization where dependency metadata may need to be established before the application itself is ready to compile.
Manifest syntax and dependency validity are still checked. The change is that dependency management is no longer unnecessarily coupled to build completeness.
Git progress reporting
Git installation progress now reflects actual remote activity.
Vix reports remote work as it begins and surfaces real Git receiving progress instead of inventing a global percentage that cannot accurately represent the complete operation.
This gives developers useful feedback during large clones or slow network operations without pretending that unrelated installation phases can be measured as one precise percentage.
Install compatibility contracts
v2.8.5 adds deterministic compatibility coverage for Git-hosted CMake dependencies.
The contracts cover common layouts and behaviors that dependency installation must preserve, including:
- header-only packages;
- static libraries;
- shared libraries;
- alias targets;
- generated headers;
- nested source subdirectories;
- CMake options;
- compile features;
- transitive dependencies.
These tests are important because a Git dependency cannot be treated as only a repository checkout.
The package's exported build contract must remain correct after Vix resolves it, records it in the lockfile, and integrates it into the application or module that owns it.
Module installation contracts
The release also adds stricter contracts around module-scoped Git dependencies.
Coverage includes ownership, graph validation, dependency constraints, rollback, transaction behavior, and installation into valid and invalid module targets.
These tests verify the complete workflow rather than only checking whether a dependency can be cloned.
A successful installation must leave the correct module manifest, root lockfile, ownership information, generated integration, and cached dependency state.
A failed installation must leave the previous project state intact.
Internal dependency isolation
Vix no longer leaks its internal SPDLOG_FMT_EXTERNAL configuration into user dependencies.
Internal build choices should not silently alter the configuration of unrelated third-party packages compiled as part of an application.
v2.8.5 tightens that boundary so Vix's own logging configuration remains scoped to the targets that require it.
Compiler warning flags have also been corrected so GCC-specific and Clang-specific options are applied only to the compiler that understands them.
This reduces toolchain noise and avoids dependency builds being affected by unrelated Vix implementation settings.
Validation
The release was validated across Realtime, Git dependency installation, module ownership, graph construction, dependency constraints, transactional mutations, and generated CMake integration.
Realtime validation covered authoritative rooms, persisted events, snapshots, replay, recovery, session resume, presence lifecycle, in-memory persistence, PostgreSQL persistence, WebSocket integration, protocol handling, metrics, health APIs, SDK packaging, and concurrency behavior.
Dependency tests covered header-only, static, shared, and alias targets, generated headers, nested subdirectories, CMake options, compile features, and transitive dependencies.
Module-scoped installation was tested with valid ownership, shared compatible dependencies, conflicting requirements, invalid modules, disabled modules, path and name collisions, self-dependencies, dependency cycles, and deterministic graph ordering.
Transaction tests covered successful multi-file mutations, failures during dependency installation, rollback, concurrent mutation protection, and recovery from interrupted transaction state under .vix/transactions.
Install reconciliation was also verified so unchanged dependencies can reuse lockfile and cache state without unnecessary remote Git resolution or identical generated CMake rewrites.
Compatibility
Existing application-level dependencies continue to work.
Module-scoped ownership adds a more precise model for projects that use vix.module, but it does not require every existing dependency to move into a module.
Projects continue to use one root vix.lock even when several modules own dependencies.
Compatible shared dependencies can therefore remain resolved once for the complete application.
The stricter graph and constraint checks may reject project states that older versions allowed through last-write-wins behavior. Those failures indicate an ambiguous or incompatible dependency model that should be resolved explicitly rather than deferred to CMake or the linker.
Transaction infrastructure changes how project files are mutated, not the public manifest formats developers work with.
Realtime remains compatible with the architecture introduced earlier in the v2.8 line while tightening recovery, persistence, packaging, and integration contracts.
Release summary
Vix.cpp v2.8.5 makes two parts of the platform substantially more dependable.
Realtime now has stronger guarantees around persistence, recovery, session resume, presence, PostgreSQL integration, SDK packaging, health, metrics, and concurrency.
Modular applications now have an explicit dependency architecture.
Git dependencies can belong to individual modules, compatible dependencies can still be shared through one root lockfile and cache, module relationships are validated as a deterministic graph, and incompatible requirements are reported before build generation.
Project mutations are also transactional. Commands that change manifests and lockfiles either complete as one operation or restore the previous state, including recovery support for interrupted transactions.
The result is a more reliable foundation for Vix projects that are growing beyond a single application target, particularly projects that combine multiple modules, third-party Git dependencies, and stateful realtime systems.