• v7.31.0 65cfd2cc6c

    dpsifr released this 2026-06-09 19:04:45 +02:00 | 305 commits to main since this release

    Highlights

    Per-entity optimistic concurrency, the read-then-CAS lock pattern, and idempotent-bootstrap singleton inserts.

    • entity._rev: number — monotonic per-entity counter, auto-bumped on every update(). Surfaced on get() / find() / search(). Pre-7.31.0 entities read as _rev: 1.
    • update({ ifRev: N }) — CAS check. Throws RevisionConflictError carrying { id, expected, actual } if the persisted _rev no longer matches.
    • add({ ifAbsent: true }) + addMany({ items, ifAbsent: true }) — by-ID idempotent insert. Returns the existing id if present, no throw, no overwrite.
    • RevisionConflictError exported from the public API.

    The full optimistic-concurrency guide walks through the lock pattern, read-modify-write retry, idempotent bootstrap, and how _rev interacts with branches, snapshots, and VFS file versioning.

    Why this scope (and why no brain.transaction())

    A public transaction wrapper was on the table but was cut. The internal TransactionManager exposes raw Operation classes that take a StorageAdapter constructor arg; a clean high-level facade in 7.31.0 was either (a) "delegate to brain.add() / update() / relate()" which each commit their own internal transaction before the closure returns (looks atomic, isn't), or (b) thread tx? through every internal write site (~2 days + regression surface). The SDK-scheduler use case driving this is the read-then-CAS lock pattern, fully solved by _rev + ifRev. Multi-write atomicity lands in 8.0's Datomic-style brain.transact() where it's atomic by construction.

    Cortex compatibility

    Zero changes required. _rev is a single integer field updated alongside every other metadata field; Cortex never sees the per-entity counter.

    Tests

    • New tests/integration/rev-and-ifabsent.test.ts (18 tests)
    • 1468 / 1468 unit suite passing

    See RELEASES.md for the full entry.

    Downloads