xyzDB

Agentic — envelope capacity matrix

The full envelope-capacity matrix — every tier, every scale, not just the collapsed grid. See the narrative version at Benchmarks → Agentic; this is the complete record.

Full data

Capacity + latency of an agent-memory deployment across hardware envelopes: does each deployment fit a given tier, and how fast does it serve? Corpus A = LongMemEval (bge-large, 1024d; buckets = real conversational sessions). Harness benchmarks/agentic/run_envelope_full.sh + cell_watchdog.py.

Status: complete — 256/256 cells. AWS m6a.xlarge (x86-64-v3 / AVX2), data on the real SSD (/mnt/ssd, bind-mounted), real swap (4 GB swapfile, verified with swapon — an earlier pass ran silently swapless; every number below is from the corrected, swap-true run). xyzDB image xyzdb:0.9.7-x86v3 (budget-governed ingest — the engine bounds its own build against --memory-budget-mb); rivals at their latest images. One engine at a time, per-cell fresh container + wiped data dir, BUILD_TIMEOUT=1200s, hard cell wall 1400s, live fall-detection with reasons (OOM-kill / crashed / thrash).

2.1 Setup

TierCPUsRAMSwap--memory-swap (total)xyz --memory-budget-mb
T11256M256M512M256
T22512M512M1,024M512
T322G512M2,560M2,048
T424G512M4,608M4,096

Docker --memory-swap is the total (DRAM + swap), so the effective swap is --memory-swap − DRAM: T1 = 256M, T2/T3/T4 = 512M. Host-backed by a real 4G swapfile (EC2 has none by default). The lean store in the 2-container deployments is fixed at 1c / 256M DRAM + 256M swap.

Deployments: xyz (1 container: vector + structured), pg (1: pgvector does both), qdrant+pg / chroma+pg(2: vector engine at the tier envelope + a fixed lean Postgres store, 1c/256M, on :5433). Scales 30k / 100k / 246k (full corpus). RAM peak = combined across the deployment's containers, with the per-container split. Every engine runs its own idiomatic best form.

2.2 Scenarios

Six agent-memory workloads, each the same business question posed to every engine in its idiomatic shape. Corpus A = LongMemEval, bge-large 1024d; the retrieval bucket is question_id, a session is sid.

S1 retrieve-and-expandthe k nearest memories, then expand each to its full session (the conversation, not a lone turn)

e2e latency, session_recall (fraction of the oracle top-k found — xyz exact = ceiling, HNSW rivals < 1.0), expand_complete_frac (correctness: exactly the hit sessions' turns, no drop/bleed), roundtrips, disk (payload-dup tax).

S2 live sessionan agent that saves one memory and searches 2–3× per turn (sustained ~30% write / 70% read, deterministic replay of corpus turns)

online insert latency, query p50/p99 under concurrent writes, degradation (late vs early window — where a maintenance cycle shows: LSM compaction / optimizer), visibility (a write at t is a candidate at t+1). Durable-strict, equalised across engines.

S3 multi-agent fleetN agents = N tenants (buckets); the fleet is born, grows, and dies (PURGE), each engine in its best tenant form

cost to create/destroy the Nth tenant (not the first), RAM vs #tenants curve, filtered-query recall at each step; steps 10/100/1000 (if an engine can't hold 1000 in the tier, that OOM is the result). Run once per tier.

S4 serverless wakebuild the index → restart the container cleanly → TTFQ = restart → first successful query

cold-start readiness: xyz serves from the LSM (little to warm); rivals load the graph/collections into RAM on first access. Composes with at-rest footprint.

S5 hybrid search"of the memories matching topic < T, give the k nearest" — exact structured filter + NEAREST, selectivity swept 50% → 0.1%

recall@k vs the f64 oracle over the filtered set (tie-aware); deterministic metadata → all engines filter the identical universe (the parity gate).

S6 composite turnone engine for the whole agent: write vector+fields → update structured → NEAREST, then the AGGREGATE (count topic X active + avg importance)

per-op latency, the +store inconsistency window (0 for one-system xyz/pg; non-zero for the 2-container stacks), the aggregate, summed footprint. Cells here are deployments, not binaries.

2.3 Capacity map (S1 — building and serving the base index)

DeploymentT1:30kT1:100kT1:246kT2:30kT2:100kT2:246kT3:30kT3:100kT3:246kT4:30kT4:100kT4:246k
xyzFITFITFITFITFITFITFITFITFITFITFITFIT
pgFITBTXXFITBTXXFITFITXXFITFITXX
qdrant+pgFITFITFITFITFITFITFITFITFITFITFITFIT
chroma+pgFITTHTHFITFIT*XXFITFITFITFITFITFIT

BT = build did not complete in 20 min · XX = crash/OOM during load · TH = OOM-thrash (pinned + no progress, watchdog-verdicted) · FIT* = completes but degraded (see per-tier tables).

2.4 Headline

  • xyz is the only single-container deployment that fits everywhere — and its latency is flat across envelopes. At the full corpus (246k), S1 p50 is 15.0 / 15.9 / 19.3 / 17.8 ms across T1→T4 and the build takes 206–220 s whether the box has 256 MB or 4 GB. The envelope changes what xyz uses (RAM peak 251 MB at T1 → 1,539 MB at T4, elastic), not how it behaves. Recall 1.0 in every cell (exact NEAREST, never approximate).
  • qdrant+pg also fits everywhere and posts the best roomy-tier scan p50 (4.4–7.9 ms, resident HNSW) — but it pays where an agent feels it: TTFQ is 1.2–8.4 seconds in every cell (xyz: 22–434 ms), the tight tier degrades it (26.9/52.2 ms at T1/246k, worse than xyz), live-session queries drop to 18–29 ms p50 at 246k (xyz 4.5–14), and it is two systems.
  • pg never loads the full corpus— 246k OOMs during the HNSW build at every tier, including 4G+swap; 100k builds only at ≥2G (T1/T2 exceed the 20-min budget). Where it fits it is fast and lean on point queries (S2 q50 1.3 ms), and its T1/30k “fit” is heavily degraded: the build pages for 1,043 s vs 95 s on a roomy tier (11×).
  • chroma+pg is the slowest at every size (S1 p50 36 → 290 ms as N grows; S5 up to 552 ms; S2 q50 265 ms at 246k) with brutal tails (S1 p99 4.0 s at T3/246k), needs ≥2G for the full corpus, and thrashes at T1 beyond 30k.
  • Fleet (S3): creating the 1000th tenant costs xyz/qdrant ~150–190 ms; pg ~1.0 s (DDL per tenant); chroma never reached 1000 tenants at any tier.
  • The lean second DB works: the +pg store stays at 23–57 MB in every cell — the stack tax is operational (two systems, double write, TTFQ), not RAM.

2.5 Per-tier tables

Latency in ms. S1 load s = corpus build wall-clock (the fits-degraded signal). S6 near/agg = composite-turn vector read / structured aggregate.

T1 — vector 1c/256M + 256M swap · store 1c/256M + 256M swap

DeployNS1 p50/p99S1 load sRecallS2 q50S4 TTFQ msS5 p50S6 near/aggRAM peak (split)Verdict
xyz30k16.2/25.923.31.001.1224.915.31.4/1.77155 (xyzdb 155)FIT
xyz100k17.3/24.883.81.001.4230.817.15.3/0.30217 (xyzdb 217)FIT
xyz246k15.0/26.4220.41.0014.0433.617.45.8/0.36251 (xyzdb 251)FIT
pg30k14.6/27.91,043.21.001.3277.613.81.5/15.67256 (pgvector 256)FIT
pg100k-/-------/-256 (pgvector 256)build-timeout
pg246k-/-------/-105 (pgvector 105)OOM-load
qdrant+pg30k8.9/36.423.71.002.51,638.98.03.0/0.76290 (qdrant 253, store 37)FIT
qdrant+pg100k12.0/31.878.01.002.83,083.524.713.5/0.85244 (qdrant 221, store 25)FIT
qdrant+pg246k26.9/52.2192.31.0029.38,106.625.926.4/1.06274 (qdrant 248, store 26)FIT
chroma+pg30k42.1/512.098.11.004.8912.949.329.4/0.94256 (chroma 230, store 26)FIT
chroma+pg100k-/-------/-282 (chroma 256, store 26)thrash
chroma+pg246k-/-------/-282 (chroma 256, store 26)thrash

T2 — vector 2c/512M + 512M swap · store 1c/256M + 256M swap

DeployNS1 p50/p99S1 load sRecallS2 q50S4 TTFQ msS5 p50S6 near/aggRAM peak (split)Verdict
xyz30k16.1/24.222.91.001.0223.314.51.4/0.33223 (xyzdb 223)FIT
xyz100k18.7/31.780.81.001.3227.917.14.6/0.28282 (xyzdb 282)FIT
xyz246k15.9/25.1212.31.0012.4231.117.25.1/0.30325 (xyzdb 325)FIT
pg30k15.2/27.5102.41.001.3277.313.81.4/7.70327 (pgvector 327)FIT
pg100k-/-------/-512 (pgvector 512)build-timeout
pg246k-/-------/-179 (pgvector 179)OOM-load
qdrant+pg30k4.4/7.626.81.002.42,763.26.95.2/1.33214 (qdrant 191, store 23)FIT
qdrant+pg100k7.4/13.381.51.002.61,910.97.05.2/0.77405 (qdrant 380, store 25)FIT
qdrant+pg246k7.9/19.1196.91.0018.17,179.98.310.6/1.29423 (qdrant 398, store 26)FIT
chroma+pg30k36.0/104.429.01.004.9385.947.529.3/0.94271 (chroma 248, store 23)FIT
chroma+pg100k117.7/2,126.4529.31.0013.43,002.1193.063.6/0.96538 (chroma 512, store 26)FIT
chroma+pg246k-/-------/-538 (chroma 512, store 26)OOM-load

T3 — vector 2c/2G + 512M swap · store 1c/256M + 256M swap

DeployNS1 p50/p99S1 load sRecallS2 q50S4 TTFQ msS5 p50S6 near/aggRAM peak (split)Verdict
xyz30k11.2/16.423.01.001.022.114.61.4/0.29340 (xyzdb 340)FIT
xyz100k16.9/26.279.21.001.323.615.15.0/0.37762 (xyzdb 762)FIT
xyz246k19.3/29.5209.11.005.2418.517.95.0/0.35882 (xyzdb 882)FIT
pg30k5.9/9.294.41.001.3220.34.41.4/0.67462 (pgvector 462)FIT
pg100k15.0/21.5375.11.001.4252.1--/-1,153 (pgvector 1,153)FIT
pg246k-/-------/-618 (pgvector 618)OOM-load
qdrant+pg30k4.3/7.726.91.002.42,540.12.94.4/1.34219 (qdrant 196, store 23)FIT
qdrant+pg100k4.4/7.9104.51.003.36,708.02.73.6/1.48493 (qdrant 468, store 26)FIT
qdrant+pg246k7.4/13.4269.81.006.31,183.82.93.7/1.671,305 (qdrant 1,280, store 26)FIT
chroma+pg30k36.5/104.625.41.004.9392.248.029.8/0.93255 (chroma 233, store 23)FIT
chroma+pg100k114.3/322.5109.41.0012.5657.6191.160.0/0.99585 (chroma 560, store 26)FIT
chroma+pg246k289.3/3,987.4388.51.00263.46,115.7544.8148.5/1.111,296 (chroma 1,271, store 26)FIT

T4 — vector 2c/4G + 512M swap · store 1c/256M + 256M swap

DeployNS1 p50/p99S1 load sRecallS2 q50S4 TTFQ msS5 p50S6 near/aggRAM peak (split)Verdict
xyz30k15.7/24.423.01.001.021.614.81.4/0.31342 (xyzdb 342)FIT
xyz100k16.7/25.980.11.001.3226.015.14.9/0.301,403 (xyzdb 1,403)FIT
xyz246k17.8/24.7206.41.004.5412.216.05.0/0.381,539 (xyzdb 1,539)FIT
pg30k5.9/9.195.41.001.3220.24.31.4/0.69472 (pgvector 472)FIT
pg100k6.3/9.3375.71.001.4220.9--/-1,701 (pgvector 1,701)FIT
pg246k-/-------/-1,164 (pgvector 1,164)OOM-load
qdrant+pg30k4.4/10.127.61.002.42,768.82.85.5/1.45228 (qdrant 205, store 23)FIT
qdrant+pg100k4.7/11.1105.31.005.58,387.22.93.3/2.79494 (qdrant 469, store 26)FIT
qdrant+pg246k4.6/10.0277.41.005.82,320.22.83.8/1.59634 (qdrant 609, store 26)FIT
chroma+pg30k36.8/109.825.91.004.9389.948.029.8/0.93242 (chroma 219, store 23)FIT
chroma+pg100k115.4/322.5109.61.0012.6661.3192.360.4/0.98586 (chroma 561, store 26)FIT
chroma+pg246k289.9/1,316.1311.11.00265.51,942.3551.9143.0/1.101,296 (chroma 1,270, store 26)FIT

2.6 Fleet (S3) — 10/100/1000 tenants, once per tier

DeployT1T2T3T4
xyz177.2 / 199187.9 / 271184.9 / 817190.1 / 1,467
pg1,036.8 / 1291,016.5 / 2031,011.6 / 6481,012.6 / 1,213
qdrant+pg158.8 / 123156.2 / 311286.7 / 258161.6 / 214
chroma+pgno t1000no t1000no t1000no t1000

create-nth ms / RAM MiB at 1000 tenants. chroma+pg's fleet loop never completed the 1000-tenant step inside the cell wall at any tier (it reaches ~100).

2.7 Notes

  • Fits vs fits-degraded. A FIT verdict says the cell completed; the degradation shows in S1 load s and the latencies. Clear degraded fits: pg T1/30k (build 1,043 s vs 95 s roomy), chroma T2/100k (build 529 s, S1 p99 2.1 s). xyz shows no degraded fit anywhere (load 23/80/210 s at 30k/100k/246k, constant across tiers).
  • pg S6 cells at 100k/246k appear as “fall (base build)”: the composite scenario rebuilds the base index first, which is exactly what fails at those scales — same root as its S1 verdicts, not an extra failure mode.
  • Why xyz fits T1 now: engine 0.9.7 derives a global memtable ceiling from --memory-budget-mb and stalls ingest for background flush at the ceiling — a tight container bounds its own build instead of OOM-ing (0.9.6 died building 246k at T1).
  • Verdicts are watchdog-attributed, with reasons (e.g. chroma T1: mem pinned 256/256MiB and cpu <20% sustained 300s -> paging, no progress). A container must stay down >90 s to be declared fallen (the settle restart comes back; a real OOM does not).
  • Mac/OrbStack runs of this matrix are direction only; this AWS dataset is the publishable one.