Skip to content

YantrikDB

v0.7.19 Feature

This release adds 2 notable features for engineering teams evaluating rollout.

✓ No known CVEs patched
Read the diff → Tool health → What is this tool? →

✓ No known CVEs patched in this version

Topics

agent-memory ai-agents anthropic claude-code cognitive-memory database
+12 more
embeddings hnsw knowledge-graph llm llm-memory mcp memory persistent-memory python rust semantic-memory vector-db

Affected surfaces

breaking_upgrade

Summary

AI summary

Updates https://github.com/yantrikos/yantrikdb/releases/tag/v0.7.18, Backpressure, and orphans across a mixed release.

Changes in this release

Feature Medium

`replication_apply_log` audit table added in v29 migration to track replication-apply operations.

`replication_apply_log` audit table added in v29 migration to track replication-apply operations.

Source: granite4.1:8b-q6_K@2026-05-20

Confidence: high

Feature Medium

Three-population audit query distinguishes locally originated, replicated, and true orphan rows.

Three-population audit query distinguishes locally originated, replicated, and true orphan rows.

Source: granite4.1:8b-q6_K@2026-05-20

Confidence: high

Dependency Medium

Migration creates `replication_apply_log` table if not present; no data mutation required.

Migration creates `replication_apply_log` table if not present; no data mutation required.

Source: granite4.1:8b-q6_K@2026-05-20

Confidence: low

Performance Medium

Empirical bench shows memories=5889, oplog=5889, true_orphan=0 after fixes (vs 1203 orphans before).

Empirical bench shows memories=5889, oplog=5889, true_orphan=0 after fixes (vs 1203 orphans before).

Source: granite4.1:8b-q6_K@2026-05-20

Confidence: high

Bugfix Medium

Compensating DELETE on Backpressure closes orphan rows left by transient backpressure events.

Compensating DELETE on Backpressure closes orphan rows left by transient backpressure events.

Source: granite4.1:8b-q6_K@2026-05-20

Confidence: high

Bugfix Medium

Replication-apply paths now log an entry in `replication_apply_log` to prevent invisible replication orphans.

Replication-apply paths now log an entry in `replication_apply_log` to prevent invisible replication orphans.

Source: granite4.1:8b-q6_K@2026-05-20

Confidence: high

Refactor Medium

Wrapped `vec_index.append` in error handling to trigger compensating DELETE on failure.

Wrapped `vec_index.append` in error handling to trigger compensating DELETE on failure.

Source: granite4.1:8b-q6_K@2026-05-20

Confidence: high

Full changelog

Headline

Two postmortem-driven fixes from the 2026-05-20 CT 132 bench + trader-default SQL probe:

  1. Compensating DELETE on Backpressure — closes the orphan-on-Backpressure pattern that left 1203 orphan rows in CT 132's bench DB and 23k orphans on trader's default accumulating over 39 days.
  2. replication_apply_log audit table (v29 migration) — replication-apply paths now write an audit row. Operators can run a three-population query to distinguish "locally originated" / "received via replication" / "true orphan" — silent-shed becomes queryable.

Builds on v0.7.18 which fixed the compactor-spawn wedge. v0.7.18 made backpressure transient; v0.7.19 prevents leak on each transient event.

Empirically validated on yantrikdb-server's CT 132 LXC: post-v0.7.19 bench shows memories=5889, oplog=5889, true_orphan=0 (vs v0.7.18's memories=6937 oplog=5734 = 1203 orphans).

Problem 1 — Orphan-on-Backpressure

yantrikdb-server's v0.7.18 bench surfaced the smoking gun: memories(6937) − record_with_rid(5734) = 1203 = EXACTLY the 503 count.

Critical path that leaked:

  1. INSERT INTO memories ... — row committed
  2. vec_index.append(...) returns Err(Backpressure) (delta full)
  3. Error propagates up; handler returns 503
  4. log_op(record, ...) NEVER reached
  5. Memory row stays in SQL with no oplog provenance

Same pattern accumulated to 23,043 orphans on trader's default over 39 days. v0.7.18's wedge fix made the Backpressure transient (compactor drains), but each transient event still leaked a row.

Fix

Wrap vec_index.append in if let Err(e), run a compensating DELETE FROM memories WHERE rid = ? on the failure path, propagate the error. Only fires on rare failures. Caller sees a clean "write rejected" outcome; SQL state matches what the caller observes.

Applied to all three write paths:

  • record() — single rid, single DELETE
  • record_batch() — N rids, DELETE all on first failure (atomic batch contract)
  • record_with_rid() — only DELETE when was_new_row=true (replay path's INSERT OR IGNORE didn't create the row; we shouldn't yank a pre-existing one)

Problem 2 — Replication apply is invisible to oplog audit

Trader's default DB probe showed 23,043 memories with zero local oplog rows for record/record_with_rid/consolidate/correct. Root cause: replication-apply paths in distributed/replication.rs (materialize_record, materialize_consolidate, materialize_correct) INSERT into memories but deliberately do NOT log a local oplog row — that would create a replication loop.

Without a sibling audit table, "received via replication" is indistinguishable at SQL level from "true orphan (write-path bug)."

Fix

New v29 schema migration:

CREATE TABLE replication_apply_log (
    rid           TEXT PRIMARY KEY,
    op_type       TEXT NOT NULL,
    source_actor  TEXT NOT NULL,
    applied_at    REAL NOT NULL
);
CREATE INDEX idx_replication_apply_log_source_actor
    ON replication_apply_log(source_actor, applied_at);

Each replication-apply site writes a row at apply time:

  • materialize_recordop_type='record'
  • materialize_consolidateop_type='consolidate'
  • materialize_correctop_type='correct'

Three-population audit query

-- Locally originated
SELECT COUNT(*) FROM memories
WHERE rid IN (
  SELECT target_rid FROM oplog
  WHERE origin_actor = '<self_actor_id>'
    AND op_type IN ('record', 'record_with_rid', 'consolidate', 'correct')
);

-- Received via replication
SELECT COUNT(*) FROM memories WHERE rid IN (SELECT rid FROM replication_apply_log);

-- True orphan (post-v0.7.19, expected: 0 on healthy DBs)
SELECT COUNT(*) FROM memories
WHERE rid NOT IN (SELECT target_rid FROM oplog WHERE target_rid IS NOT NULL)
  AND rid NOT IN (SELECT rid FROM replication_apply_log);

For existing deployments (trader's 23k pre-v0.7.19 rows): historical rows do NOT auto-populate the audit log. Operators can run a one-off SQL to backfill suspected replication apply:

INSERT INTO replication_apply_log
SELECT rid, 'record', origin_actor, updated_at
FROM memories
WHERE rid NOT IN (SELECT target_rid FROM oplog WHERE target_rid IS NOT NULL);

A note on trader's mystery: sync_peers probe confirmed trader is NOT a replication follower (sync_peers=0 on both DBs). So those 23k pre-v0.7.19 orphans came from some non-oplog write path (suspected: pre-oplog migration data OR yantrikdb import CLI subcommand OR pyo3-direct pre-HTTP path). Investigation is queued for v0.7.20+; not blocking this release.

Validation

Empirically validated by yantrikdb-server on CT 132 LXC (Debian 13, 2-core, 4GB):

| Metric | v0.7.18 | v0.7.19 |
|---|---|---|
| ok writes (15s bench) | 5734 | 5889 |
| 503 responses | 1203 | 724 |
| memories — oplog rwr | 1203 (orphans) | 0 |
| true_orphan from audit query | n/a | 0 |
| yantrikdb-compa thread present | ✓ | ✓ |
| replication_apply_log table | n/a | ✓ |
| meta.schema_version | 28 | 29 |

503s during the bench are transient backpressure (compactor draining), not the wedge. Every accepted write has its oplog entry; every rejected write leaves no trace.

Test counts

| Build | Tests |
|---|---|
| cargo test --lib --release (default) | 1497 (1494 + 3 new) |
| cargo fmt --check --all | ✅ clean |

3 new regression tests:

  • record_with_rid_backpressure_does_not_leak_orphan_memories_row — pump past delta_max, catch Backpressure, assert no orphan row
  • schema_v29_fresh_install_has_replication_apply_log_table
  • test_materialize_record_writes_replication_apply_log (in replication.rs tests module — engine A records, engine B applies via apply_ops, B's audit log records source_actor='actor-A')

Migration

Backwards-compatible. CREATE TABLE IF NOT EXISTS is idempotent. No data mutation on existing rows. v28 → v29 migration runs once on next open; subsequent opens are no-op.

For downstream consumers (yantrikdb-server, plugin embedded mode, CLI):

# Bump dep
yantrikdb = "0.7.19"

No code change required — both fixes activate automatically.

Closes

References swarmcode threads with yantrikdb-server: 537ac7be, 36dcfaeb, 25192f6d, 278ab045, f2476f62, 45fdc641, 8bd002da, f6b5e15d, dd74a55b, 820a0aea, 449373ff, 3d1b84f1, 6103fbd7, 96a55603, 95ffb7ca, d43f9108, ac732cb1 (this PR locks the discussion).

Engine-side fix completes the v0.7.x reliability arc started by v0.7.18. yantrikdb-server v0.8.17 will bundle both engine fixes.

🤖 Generated with Claude Code

Weekly OSS security release digest.

The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.

No spam, unsubscribe anytime.

Share this release

Track YantrikDB

Get notified when new releases ship.

Sign up free

About YantrikDB

All releases →

Related context

Earlier breaking changes

  • v0.7.20 `correct()` now mutates in place, preserving rid and adding revision history (BREAKING CHANGE).
  • v0.7.9 Pure-additive; existing engines keep English models on v0.1.0.

Beta — feedback welcome: [email protected]