@claude-flow/memory 3.0.0-alpha.24 → 3.0.0-alpha.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/agentdb-adapter-key-isolation.test.d.ts +2 -0
  2. package/dist/agentdb-adapter-key-isolation.test.d.ts.map +1 -0
  3. package/dist/agentdb-adapter-key-isolation.test.js +175 -0
  4. package/dist/agentdb-adapter-key-isolation.test.js.map +1 -0
  5. package/dist/agentdb-adapter-upsert.test.d.ts +2 -0
  6. package/dist/agentdb-adapter-upsert.test.d.ts.map +1 -0
  7. package/dist/agentdb-adapter-upsert.test.js +216 -0
  8. package/dist/agentdb-adapter-upsert.test.js.map +1 -0
  9. package/dist/agentdb-adapter.d.ts +10 -0
  10. package/dist/agentdb-adapter.d.ts.map +1 -1
  11. package/dist/agentdb-adapter.js +115 -26
  12. package/dist/agentdb-adapter.js.map +1 -1
  13. package/dist/consolidator.d.ts.map +1 -1
  14. package/dist/consolidator.js +6 -3
  15. package/dist/consolidator.js.map +1 -1
  16. package/dist/controller-registry.d.ts +20 -0
  17. package/dist/controller-registry.d.ts.map +1 -1
  18. package/dist/controller-registry.js +79 -5
  19. package/dist/controller-registry.js.map +1 -1
  20. package/dist/controller-registry.test.js +113 -0
  21. package/dist/controller-registry.test.js.map +1 -1
  22. package/dist/learning-bridge.d.ts.map +1 -1
  23. package/dist/learning-bridge.js +9 -4
  24. package/dist/learning-bridge.js.map +1 -1
  25. package/dist/learning-bridge.test.js +33 -0
  26. package/dist/learning-bridge.test.js.map +1 -1
  27. package/dist/memory-key.d.ts +3 -0
  28. package/dist/memory-key.d.ts.map +1 -0
  29. package/dist/memory-key.js +5 -0
  30. package/dist/memory-key.js.map +1 -0
  31. package/dist/smart-retrieval-scores.test.d.ts +2 -0
  32. package/dist/smart-retrieval-scores.test.d.ts.map +1 -0
  33. package/dist/smart-retrieval-scores.test.js +75 -0
  34. package/dist/smart-retrieval-scores.test.js.map +1 -0
  35. package/dist/smart-retrieval.d.ts +8 -1
  36. package/dist/smart-retrieval.d.ts.map +1 -1
  37. package/dist/smart-retrieval.js +1 -0
  38. package/dist/smart-retrieval.js.map +1 -1
  39. package/package.json +1 -1
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=agentdb-adapter-key-isolation.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agentdb-adapter-key-isolation.test.d.ts","sourceRoot":"","sources":["../src/agentdb-adapter-key-isolation.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,175 @@
1
+ /** Regression coverage for #3358: distinct namespace/key tuples must not evict each other. */
2
+ import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
3
+ import { tmpdir } from 'node:os';
4
+ import { join } from 'node:path';
5
+ import { afterEach, describe, expect, it } from 'vitest';
6
+ import { AgentDBAdapter } from './agentdb-adapter.js';
7
+ import { MemoryConsolidator } from './consolidator.js';
8
+ import { createDefaultEntry } from './types.js';
9
+ const vector = () => Float32Array.of(1, 0, 0, 0, 0, 0, 0, 0);
10
+ function pair() {
11
+ const a = createDefaultEntry({ namespace: 'team:alice', key: 'profile', content: 'Alice profile' });
12
+ const b = createDefaultEntry({ namespace: 'team', key: 'alice:profile', content: 'Other profile' });
13
+ a.embedding = vector();
14
+ b.embedding = vector();
15
+ return [a, b];
16
+ }
17
+ const adapters = [];
18
+ const directories = [];
19
+ async function open(config = {}) {
20
+ const adapter = new AgentDBAdapter({ dimensions: 8, cacheEnabled: true, ...config });
21
+ adapters.push(adapter);
22
+ await adapter.initialize();
23
+ return adapter;
24
+ }
25
+ function persistence() {
26
+ const dir = mkdtempSync(join(tmpdir(), 'memory-key-isolation-'));
27
+ directories.push(dir);
28
+ return { persistenceEnabled: true, persistencePath: join(dir, 'store') };
29
+ }
30
+ async function expectPair(adapter, a, b) {
31
+ expect((await adapter.get(a.id))?.id).toBe(a.id);
32
+ expect((await adapter.get(b.id))?.id).toBe(b.id);
33
+ expect((await adapter.getByKey(a.namespace, a.key))?.id).toBe(a.id);
34
+ expect((await adapter.getByKey(b.namespace, b.key))?.id).toBe(b.id);
35
+ expect((await adapter.search(vector(), { k: 10 })).map(r => r.entry.id).sort()).toEqual([a.id, b.id].sort());
36
+ for (const entry of [a, b]) {
37
+ expect((await adapter.query({ type: 'prefix', namespace: entry.namespace, keyPrefix: '', limit: 10 })).map(e => e.id)).toEqual([entry.id]);
38
+ expect((await adapter.query({ type: 'exact', namespace: entry.namespace, key: entry.key, limit: 10 })).map(e => e.id)).toEqual([entry.id]);
39
+ }
40
+ }
41
+ afterEach(async () => {
42
+ for (const adapter of adapters.splice(0))
43
+ await adapter.shutdown();
44
+ for (const dir of directories.splice(0))
45
+ rmSync(dir, { recursive: true, force: true });
46
+ });
47
+ describe('namespace/key isolation (#3358)', () => {
48
+ it.each(['scalar', 'batch', 'pre-existing then batch'])('preserves colliding legacy tuples through %s writes', async (mode) => {
49
+ const adapter = await open();
50
+ const [a, b] = pair();
51
+ if (mode === 'batch')
52
+ await adapter.bulkInsert([a, b]);
53
+ else {
54
+ await adapter.store(a);
55
+ if (mode === 'scalar')
56
+ await adapter.store(b);
57
+ else
58
+ await adapter.bulkInsert([b]);
59
+ }
60
+ await expectPair(adapter, a, b);
61
+ });
62
+ it.each(['scalar', 'batch'])('still replaces an identical tuple through %s writes without deleting the neighboring tuple', async (mode) => {
63
+ const adapter = await open();
64
+ const [a, b] = pair();
65
+ await adapter.store(a);
66
+ await adapter.store(b);
67
+ const replacement = createDefaultEntry({ namespace: a.namespace, key: a.key, content: 'Updated Alice profile' });
68
+ replacement.embedding = vector();
69
+ if (mode === 'scalar')
70
+ await adapter.store(replacement);
71
+ else
72
+ await adapter.bulkInsert([replacement]);
73
+ expect(await adapter.get(a.id)).toBeNull();
74
+ await expectPair(adapter, replacement, b);
75
+ });
76
+ it.each(['delete', 'bulkDelete', 'clearNamespace'])('%s removes only the requested tuple and clears its lookup', async (mode) => {
77
+ const adapter = await open();
78
+ const [a, b] = pair();
79
+ await adapter.bulkInsert([a, b]);
80
+ if (mode === 'delete')
81
+ await adapter.delete(a.id);
82
+ else if (mode === 'bulkDelete')
83
+ await adapter.bulkDelete([a.id]);
84
+ else
85
+ await adapter.clearNamespace(a.namespace);
86
+ expect(await adapter.get(a.id)).toBeNull();
87
+ expect(await adapter.getByKey(a.namespace, a.key)).toBeNull();
88
+ expect((await adapter.getByKey(b.namespace, b.key))?.id).toBe(b.id);
89
+ expect((await adapter.search(vector(), { k: 10 })).map(r => r.entry.id)).toEqual([b.id]);
90
+ });
91
+ it('matches prefixes against raw keys, including quotes, slashes and Unicode', async () => {
92
+ const adapter = await open();
93
+ const namespace = 'team:"\\雪';
94
+ const matching = createDefaultEntry({ namespace, key: '"\\雪:profile', content: 'matching' });
95
+ const otherKey = createDefaultEntry({ namespace, key: 'elsewhere', content: 'other key' });
96
+ const otherNamespace = createDefaultEntry({ namespace: `${namespace}:child`, key: matching.key, content: 'other namespace' });
97
+ await adapter.bulkInsert([matching, otherKey, otherNamespace]);
98
+ expect((await adapter.getByKey(namespace, matching.key))?.id).toBe(matching.id);
99
+ expect((await adapter.query({ type: 'prefix', namespace, keyPrefix: '"\\雪:', limit: 10 })).map(e => e.id)).toEqual([matching.id]);
100
+ });
101
+ it('preserves both tuples and subsequent same-tuple replacement across restarts', async () => {
102
+ const config = persistence();
103
+ const first = await open(config);
104
+ const [a, b] = pair();
105
+ await first.bulkInsert([a, b]);
106
+ await first.shutdown();
107
+ const reloaded = await open(config);
108
+ await expectPair(reloaded, a, b);
109
+ const replacement = createDefaultEntry({ namespace: a.namespace, key: a.key, content: 'Updated Alice profile' });
110
+ replacement.embedding = vector();
111
+ await reloaded.store(replacement);
112
+ await reloaded.shutdown();
113
+ const again = await open(config);
114
+ expect(await again.get(a.id)).toBeNull();
115
+ await expectPair(again, replacement, b);
116
+ });
117
+ it.each(['delete', 'bulkDelete'])('loads v1 colliding keys and preserves the saved winner when %s removes a stale duplicate', async (mode) => {
118
+ const config = persistence();
119
+ const first = await open(config);
120
+ const [a, b] = pair();
121
+ const winner = createDefaultEntry({ namespace: 'dup', key: 'duplicate', content: 'winner' });
122
+ const stale = createDefaultEntry({ namespace: 'dup', key: 'temporary', content: 'stale' });
123
+ // Persisted entry order must not accidentally choose the intended winner.
124
+ winner.id = 'a-winner';
125
+ stale.id = 'z-stale';
126
+ await first.bulkInsert([a, b, winner, stale]);
127
+ await first.shutdown();
128
+ const metaPath = `${config.persistencePath}.meta.json`;
129
+ const meta = JSON.parse(readFileSync(metaPath, 'utf8'));
130
+ meta.version = 1;
131
+ meta.entries.find((e) => e.id === stale.id).key = winner.key;
132
+ // An authentic v1 index could only retain B for the colliding pair,
133
+ // while same-tuple orphans remained in entries under distinct IDs.
134
+ meta.keyIndex = { 'team:alice:profile': b.id, 'dup:duplicate': winner.id };
135
+ writeFileSync(metaPath, JSON.stringify(meta));
136
+ const reloaded = await open(config);
137
+ await expectPair(reloaded, a, b);
138
+ expect((await reloaded.getByKey('dup', 'duplicate'))?.id).toBe(winner.id);
139
+ expect((await reloaded.get(stale.id))?.id).toBe(stale.id);
140
+ if (mode === 'delete')
141
+ await reloaded.delete(stale.id);
142
+ else
143
+ await reloaded.bulkDelete([stale.id]);
144
+ expect(await reloaded.get(stale.id)).toBeNull();
145
+ expect((await reloaded.getByKey('dup', 'duplicate'))?.id).toBe(winner.id);
146
+ await reloaded.shutdown();
147
+ expect(JSON.parse(readFileSync(metaPath, 'utf8')).version).toBe(2);
148
+ const again = await open(config);
149
+ await expectPair(again, a, b);
150
+ expect((await again.getByKey('dup', 'duplicate'))?.id).toBe(winner.id);
151
+ });
152
+ it.each(['sweep', 'dedup'])('clears the encoded lookup during consolidator %s', async (mode) => {
153
+ const adapter = await open();
154
+ const [a, b] = pair();
155
+ if (mode === 'sweep')
156
+ a.expiresAt = Date.now() - 1000;
157
+ else {
158
+ a.content = b.content;
159
+ a.updatedAt = 1;
160
+ b.updatedAt = 2;
161
+ }
162
+ await adapter.bulkInsert([a, b]);
163
+ const consolidator = new MemoryConsolidator({ getAdapter: () => adapter }, { similarityThreshold: 1 });
164
+ if (mode === 'sweep')
165
+ expect((await consolidator.sweepExpired()).removed).toBe(1);
166
+ else
167
+ expect((await consolidator.dedup('keep-newest')).merged).toBe(1);
168
+ // Both values were cached on insert; a stale keyIndex pointer would
169
+ // incorrectly return the removed entry from cache even after cleanup.
170
+ expect(await adapter.getByKey(a.namespace, a.key)).toBeNull();
171
+ expect((await adapter.getByKey(b.namespace, b.key))?.id).toBe(b.id);
172
+ expect((await adapter.search(vector(), { k: 10 })).map(r => r.entry.id)).toEqual([b.id]);
173
+ });
174
+ });
175
+ //# sourceMappingURL=agentdb-adapter-key-isolation.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agentdb-adapter-key-isolation.test.js","sourceRoot":"","sources":["../src/agentdb-adapter-key-isolation.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=agentdb-adapter-upsert.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agentdb-adapter-upsert.test.d.ts","sourceRoot":"","sources":["../src/agentdb-adapter-upsert.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,216 @@
1
+ /**
2
+ * Dream Cycle 2026-09-18 (memory) — regression tests for AgentDBAdapter.store()
3
+ * same-(namespace,key) idempotency.
4
+ *
5
+ * Baseline bug: store() minted a fresh random id per call (createDefaultEntry ->
6
+ * generateMemoryId()) and never looked up an existing entry under the same
7
+ * (namespace, key) before writing. The prior occupant was left as an orphan:
8
+ * unreachable via getByKey()/keyIndex, but still present in entries/
9
+ * namespaceIndex/tagIndex, and — for embedded entries — still a live point in
10
+ * the HNSW index, so search()/semanticSearch() returned stale duplicates
11
+ * forever. Fixed by evicting the prior (namespace,key) occupant via a shared
12
+ * evictEntry() primitive (also used by delete() and bulkInsert()) before
13
+ * storing the new entry.
14
+ *
15
+ * Post-review hardening (same night): an adversarial human review found two
16
+ * further public-path gaps the first pass missed — bulkInsert() bypassed the
17
+ * same-key dedup entirely, and store() originally evicted the prior occupant
18
+ * BEFORE validating the replacement's embedding, so a rejected addPoint()
19
+ * (dimension mismatch, index full) would delete the old value and still fail,
20
+ * losing data outright. Both are fixed below; the tests in this second block
21
+ * cover exactly the five cases the review asked for.
22
+ */
23
+ import { existsSync, mkdtempSync, rmSync } from 'node:fs';
24
+ import { tmpdir } from 'node:os';
25
+ import { join } from 'node:path';
26
+ import { describe, it, expect, beforeEach } from 'vitest';
27
+ import { AgentDBAdapter } from './agentdb-adapter.js';
28
+ import { createDefaultEntry } from './types.js';
29
+ function unitVector(dims, hotIndex) {
30
+ const v = new Float32Array(dims);
31
+ v[hotIndex % dims] = 1;
32
+ return v;
33
+ }
34
+ function allInNamespace(namespace) {
35
+ return { type: 'prefix', keyPrefix: '', namespace, limit: 1000 };
36
+ }
37
+ describe('AgentDBAdapter.store() — same-key upsert idempotency (Dream Cycle 2026-09-18)', () => {
38
+ let adapter;
39
+ beforeEach(async () => {
40
+ adapter = new AgentDBAdapter({ dimensions: 8, cacheEnabled: true });
41
+ await adapter.initialize();
42
+ });
43
+ it('a second store() under the same (namespace,key) does not leave two entries reachable', async () => {
44
+ const first = createDefaultEntry({ key: 'profile', namespace: 'ns1', content: 'v1' });
45
+ await adapter.store(first);
46
+ const second = createDefaultEntry({ key: 'profile', namespace: 'ns1', content: 'v2' });
47
+ await adapter.store(second);
48
+ expect(first.id).not.toBe(second.id); // ids are independently random, as today
49
+ const byKey = await adapter.getByKey('ns1', 'profile');
50
+ expect(byKey?.content).toBe('v2');
51
+ // The prior occupant must be fully gone, not just unreachable via getByKey.
52
+ const stale = await adapter.get(first.id);
53
+ expect(stale).toBeNull();
54
+ const all = await adapter.query(allInNamespace('ns1'));
55
+ expect(all.filter((e) => e.key === 'profile')).toHaveLength(1);
56
+ });
57
+ it('a second store() under the same (namespace,key) evicts the stale HNSW point, so search() never returns the old content', async () => {
58
+ const first = createDefaultEntry({ key: 'fact', namespace: 'ns1', content: 'stale-fact' });
59
+ first.embedding = unitVector(8, 0);
60
+ await adapter.store(first);
61
+ const second = createDefaultEntry({ key: 'fact', namespace: 'ns1', content: 'fresh-fact' });
62
+ second.embedding = unitVector(8, 0); // same embedding direction, different content/id
63
+ await adapter.store(second);
64
+ const results = await adapter.search(unitVector(8, 0), { k: 10 });
65
+ const contents = results.map((r) => r.entry.content);
66
+ expect(contents).toContain('fresh-fact');
67
+ expect(contents).not.toContain('stale-fact');
68
+ expect(contents.filter((c) => c === 'fresh-fact')).toHaveLength(1);
69
+ });
70
+ it('storing a genuinely new (namespace,key) is unaffected (no eviction, both entries reachable)', async () => {
71
+ const a = createDefaultEntry({ key: 'a', namespace: 'ns1', content: 'A' });
72
+ const b = createDefaultEntry({ key: 'b', namespace: 'ns1', content: 'B' });
73
+ await adapter.store(a);
74
+ await adapter.store(b);
75
+ expect((await adapter.get(a.id))?.content).toBe('A');
76
+ expect((await adapter.get(b.id))?.content).toBe('B');
77
+ expect(await adapter.query(allInNamespace('ns1'))).toHaveLength(2);
78
+ });
79
+ it('the same (namespace,key) in two different namespaces are independent (no cross-namespace eviction)', async () => {
80
+ const a = createDefaultEntry({ key: 'shared', namespace: 'ns1', content: 'from-ns1' });
81
+ const b = createDefaultEntry({ key: 'shared', namespace: 'ns2', content: 'from-ns2' });
82
+ await adapter.store(a);
83
+ await adapter.store(b);
84
+ expect((await adapter.getByKey('ns1', 'shared'))?.content).toBe('from-ns1');
85
+ expect((await adapter.getByKey('ns2', 'shared'))?.content).toBe('from-ns2');
86
+ });
87
+ });
88
+ describe('AgentDBAdapter same-key upsert — post-review hardening (Dream Cycle 2026-09-18)', () => {
89
+ let adapter;
90
+ beforeEach(async () => {
91
+ adapter = new AgentDBAdapter({ dimensions: 8, cacheEnabled: true });
92
+ await adapter.initialize();
93
+ });
94
+ it('a replacement rejected by HNSWIndex.addPoint() (dimension mismatch) leaves the prior value intact', async () => {
95
+ const first = createDefaultEntry({ key: 'k', namespace: 'ns1', content: 'original' });
96
+ first.embedding = unitVector(8, 0);
97
+ await adapter.store(first);
98
+ const bad = createDefaultEntry({ key: 'k', namespace: 'ns1', content: 'malformed' });
99
+ bad.embedding = new Float32Array(4); // wrong dimension for this 8-dim adapter
100
+ await expect(adapter.store(bad)).rejects.toThrow(/dimension mismatch/i);
101
+ // The prior value must survive a rejected replacement -- not be deleted
102
+ // and then fail to be replaced (the exact data-loss bug the review found).
103
+ const byKey = await adapter.getByKey('ns1', 'k');
104
+ expect(byKey?.content).toBe('original');
105
+ expect(byKey?.id).toBe(first.id);
106
+ expect(await adapter.get(first.id)).not.toBeNull();
107
+ });
108
+ it('bulkInsert() evicts a duplicate key within the same batch, last entry wins', async () => {
109
+ const loser = createDefaultEntry({ key: 'k', namespace: 'ns1', content: 'first-in-batch' });
110
+ const winner = createDefaultEntry({ key: 'k', namespace: 'ns1', content: 'last-in-batch' });
111
+ await adapter.bulkInsert([loser, winner]);
112
+ const byKey = await adapter.getByKey('ns1', 'k');
113
+ expect(byKey?.content).toBe('last-in-batch');
114
+ expect(byKey?.id).toBe(winner.id);
115
+ expect(await adapter.get(loser.id)).toBeNull();
116
+ expect(await adapter.query(allInNamespace('ns1'))).toHaveLength(1);
117
+ });
118
+ it('bulkInsert() evicts a pre-existing store()d entry that a batch replaces', async () => {
119
+ const preExisting = createDefaultEntry({ key: 'k', namespace: 'ns1', content: 'pre-existing' });
120
+ preExisting.embedding = unitVector(8, 0);
121
+ await adapter.store(preExisting);
122
+ const replacement = createDefaultEntry({ key: 'k', namespace: 'ns1', content: 'from-batch' });
123
+ replacement.embedding = unitVector(8, 0);
124
+ await adapter.bulkInsert([replacement]);
125
+ expect(await adapter.get(preExisting.id)).toBeNull();
126
+ const results = await adapter.search(unitVector(8, 0), { k: 10 });
127
+ const contents = results.map((r) => r.entry.content);
128
+ expect(contents).toContain('from-batch');
129
+ expect(contents).not.toContain('pre-existing');
130
+ expect(await adapter.query(allInNamespace('ns1'))).toHaveLength(1);
131
+ });
132
+ it('a same-key replacement survives a persisted save/reload -- only the winner comes back', async () => {
133
+ const dir = mkdtempSync(join(tmpdir(), 'agentdb-adapter-upsert-'));
134
+ const persistencePath = join(dir, 'store');
135
+ try {
136
+ const first = new AgentDBAdapter({
137
+ dimensions: 8,
138
+ cacheEnabled: true,
139
+ persistenceEnabled: true,
140
+ persistencePath,
141
+ });
142
+ await first.initialize();
143
+ const original = createDefaultEntry({ key: 'k', namespace: 'ns1', content: 'v1' });
144
+ await first.store(original);
145
+ const replacement = createDefaultEntry({ key: 'k', namespace: 'ns1', content: 'v2' });
146
+ await first.store(replacement);
147
+ await first.shutdown(); // persists to disk
148
+ const reloaded = new AgentDBAdapter({
149
+ dimensions: 8,
150
+ cacheEnabled: true,
151
+ persistenceEnabled: true,
152
+ persistencePath,
153
+ });
154
+ await reloaded.initialize(); // loads from disk
155
+ const byKey = await reloaded.getByKey('ns1', 'k');
156
+ expect(byKey?.content).toBe('v2');
157
+ expect(await reloaded.get(original.id)).toBeNull();
158
+ expect(await reloaded.query(allInNamespace('ns1'))).toHaveLength(1);
159
+ }
160
+ finally {
161
+ if (existsSync(dir))
162
+ rmSync(dir, { recursive: true, force: true });
163
+ }
164
+ });
165
+ it('KNOWN LIMITATION (disclosed, not fixed tonight): truly concurrent store() calls for the same key can both proceed and leave two reachable entries', async () => {
166
+ // No mutex/lock exists around the keyIndex.get() check + writes. Two
167
+ // store() calls for the same (namespace,key), both parked mid-flight on
168
+ // an embeddingGenerator await and released in the same tick, can each
169
+ // resume and read keyIndex before the other has written to it, so
170
+ // neither evicts the other. A plain setTimeout-based delay does NOT
171
+ // reliably reproduce this: Node drains the microtask queue (including
172
+ // every further await inside one resumed call) before the next timer
173
+ // macrotask runs, so two independently-timed calls tend to fully
174
+ // serialize instead of interleaving at the check (confirmed: an earlier
175
+ // version of this test using setTimeout could not reproduce the gap).
176
+ // Two externally-controlled gates, released back-to-back in the same
177
+ // synchronous tick after both calls are already parked, force the
178
+ // actual interleaving this test needs to demonstrate.
179
+ let releaseA;
180
+ let releaseB;
181
+ const gateA = new Promise((resolve) => { releaseA = resolve; });
182
+ const gateB = new Promise((resolve) => { releaseB = resolve; });
183
+ const raced = new AgentDBAdapter({
184
+ dimensions: 8,
185
+ cacheEnabled: true,
186
+ embeddingGenerator: (content) => (content === 'from-a' ? gateA : gateB).then(() => unitVector(8, 0)),
187
+ });
188
+ await raced.initialize();
189
+ const a = createDefaultEntry({ key: 'k', namespace: 'ns1', content: 'from-a' });
190
+ const b = createDefaultEntry({ key: 'k', namespace: 'ns1', content: 'from-b' });
191
+ // Both calls run synchronously up to their embeddingGenerator await and
192
+ // are now genuinely parked -- store() hasn't read keyIndex yet for
193
+ // either. Releasing both gates back-to-back interleaves their resumption.
194
+ const pA = raced.store(a);
195
+ const pB = raced.store(b);
196
+ releaseA();
197
+ releaseB();
198
+ await Promise.all([pA, pB]);
199
+ // query()'s prefix search iterates keyIndex, which by construction holds
200
+ // exactly one id per (namespace,key) -- it structurally cannot see an
201
+ // orphan still sitting in `entries` under a different id, so it's the
202
+ // wrong probe here (an earlier version of this test used it and always
203
+ // saw "1", regardless of whether the race actually happened). get(id)
204
+ // against each participant's own id is the correct probe, matching how
205
+ // this file's very first test detects the sequential-case orphan.
206
+ const aStillPresent = (await raced.get(a.id)) !== null;
207
+ const bStillPresent = (await raced.get(b.id)) !== null;
208
+ // Today: both survive concurrently (the bug this test documents) --
209
+ // neither call's isReplacement check saw the other's write in time. If
210
+ // this assertion ever starts failing because only one is still present,
211
+ // the concurrency gap has been fixed -- update this test to assert the
212
+ // fixed behavior instead of loosening it.
213
+ expect([aStillPresent, bStillPresent]).toEqual([true, true]);
214
+ });
215
+ });
216
+ //# sourceMappingURL=agentdb-adapter-upsert.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agentdb-adapter-upsert.test.js","sourceRoot":"","sources":["../src/agentdb-adapter-upsert.test.ts"],"names":[],"mappings":"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"}
@@ -84,6 +84,16 @@ export declare class AgentDBAdapter extends EventEmitter implements IMemoryBacke
84
84
  * Delete a memory entry
85
85
  */
86
86
  delete(id: string): Promise<boolean>;
87
+ /**
88
+ * Shared eviction primitive behind delete() and the same-key upsert paths
89
+ * in store()/bulkInsert() (Dream Cycle 2026-09-18, post-review). Removes
90
+ * an entry from entries/namespaceIndex/tagIndex/HNSW/cache. touchKeyIndex
91
+ * is false when the caller is itself about to overwrite the
92
+ * (namespace,key) -> id mapping to point at a replacement entry —
93
+ * clearing it here first would either be redone work or, if the mapping
94
+ * had already been repointed, would incorrectly delete the new mapping.
95
+ */
96
+ private evictEntry;
87
97
  /**
88
98
  * Query memory entries with filters
89
99
  */
@@ -1 +1 @@
1
- {"version":3,"file":"agentdb-adapter.d.ts","sourceRoot":"","sources":["../src/agentdb-adapter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agentdb-adapter.d.ts","sourceRoot":"","sources":["../src/agentdb-adapter.ts"],"names":[],"mappings":"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"}