enigma-memory 0.1.1 → 0.1.3

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.
@@ -0,0 +1,897 @@
1
+ #!/usr/bin/env node
2
+ import { mkdir, writeFile } from 'node:fs/promises';
3
+ import { dirname, isAbsolute, resolve } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { createHash } from 'node:crypto';
6
+ import { performance } from 'node:perf_hooks';
7
+ import {
8
+ createVault,
9
+ remember,
10
+ updateMemory,
11
+ exportBundle,
12
+ importBundle,
13
+ } from '../packages/vault/src/index.js';
14
+ import {
15
+ createPassport,
16
+ compileContextPack,
17
+ verifyContextPack,
18
+ } from '../packages/passport/src/index.js';
19
+ import { createMemoryOptimizationPlan, estimateTextTokens } from '../packages/optimizer/src/index.js';
20
+ import { verifyBundle } from '../apps/verifier/bin/enigma-verify.mjs';
21
+
22
+ export const MEMORY_BENCHMARK_SUITE_SCHEMA = 'enigma.memory_benchmark_suite.v1';
23
+
24
+ const FIXED_NOW = '2026-06-25T00:00:00.000Z';
25
+ const FIXED_VAULT_KEY = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=';
26
+ const FIXED_ADDRESS_KEY = 'AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE=';
27
+ const CONTEXT_BOUNDARY = Object.freeze({
28
+ optimize: true,
29
+ max_estimated_tokens: 512,
30
+ purpose: 'memory_benchmark_context_pack',
31
+ price_per_million_tokens: 0,
32
+ currency: 'USD',
33
+ });
34
+
35
+ const PROVIDER_PROFILES = Object.freeze(['chatgpt', 'claude', 'kimi', 'cursor', 'local-llm']);
36
+
37
+ const LOCAL_BASELINES = Object.freeze([
38
+ {
39
+ id: 'full_context',
40
+ label: 'Full active context',
41
+ boundary: 'All active fixture memories are supplied without optimization or deduplication.',
42
+ },
43
+ {
44
+ id: 'recency_last_n',
45
+ label: 'Recency last N',
46
+ boundary: 'The three most recently updated active fixture memories are supplied.',
47
+ },
48
+ {
49
+ id: 'keyword_filter',
50
+ label: 'Keyword filter',
51
+ boundary: 'Active fixture memories are supplied when deterministic query terms match content or tags.',
52
+ },
53
+ {
54
+ id: 'enigma_context_pack',
55
+ label: 'Enigma context pack',
56
+ boundary: 'The Enigma passport context-pack compiler and optimizer boundary are used locally.',
57
+ },
58
+ ]);
59
+
60
+ const EXTERNAL_COMPETITOR_ADAPTERS = Object.freeze([
61
+ {
62
+ id: 'letta_memgpt',
63
+ name: 'Letta / MemGPT',
64
+ status: 'not_run_requires_credentials_or_runtime',
65
+ required_artifacts: [
66
+ 'Letta API key or self-hosted Letta runtime',
67
+ 'Pinned Letta SDK package and version such as @letta-ai/letta-client or letta-client',
68
+ 'Agent, tools, model, and memory configuration',
69
+ 'Operator-supplied benchmark dataset or fixture mapping',
70
+ ],
71
+ official_doc: 'https://docs.letta.com/concepts/memgpt/',
72
+ can_run_in_this_harness: false,
73
+ boundary_reason: 'This local harness has no Letta credentials, SDK installation, hosted/self-hosted Letta runtime, fixed agent loop, or approved external dataset, so no Letta score is produced.',
74
+ scores_included: false,
75
+ },
76
+ {
77
+ id: 'langgraph_memory',
78
+ name: 'LangGraph memory',
79
+ status: 'not_run_requires_credentials_or_runtime',
80
+ required_artifacts: [
81
+ 'Pinned LangGraph runtime and package versions',
82
+ 'Checkpointer configuration for short-term memory',
83
+ 'Namespaced long-term store configuration',
84
+ 'Fixed graph, model, tools, and dataset mapping',
85
+ ],
86
+ official_doc: 'https://docs.langchain.com/oss/python/langgraph/memory',
87
+ can_run_in_this_harness: false,
88
+ boundary_reason: 'This Node local package harness does not install or execute a LangGraph runtime, checkpointer, namespaced store, graph, model, or dataset adapter, so no LangGraph score is produced.',
89
+ scores_included: false,
90
+ },
91
+ {
92
+ id: 'zep',
93
+ name: 'Zep',
94
+ status: 'not_run_requires_credentials_or_runtime',
95
+ required_artifacts: [
96
+ 'Zep credentials or local/runtime endpoint',
97
+ 'Pinned Zep client and version',
98
+ 'Temporal Context Graph or Context Lake configuration',
99
+ 'Dataset ingestion and retrieval mapping',
100
+ ],
101
+ official_doc: 'https://help.getzep.com/',
102
+ can_run_in_this_harness: false,
103
+ boundary_reason: 'This local harness has no Zep credentials, client package, Context Graph or Context Lake runtime, ingestion job, or provider-approved retrieval dataset, so no Zep score or latency claim is produced.',
104
+ scores_included: false,
105
+ },
106
+ {
107
+ id: 'mem0',
108
+ name: 'Mem0',
109
+ status: 'not_run_requires_credentials_or_runtime',
110
+ required_artifacts: [
111
+ 'Mem0 platform credentials or open-source stack runtime',
112
+ 'Pinned Mem0 SDK/package versions',
113
+ 'Memory extraction, update, retrieval, model, and tool configuration',
114
+ 'Dataset ingestion and scoring mapping',
115
+ ],
116
+ official_doc: 'https://docs.mem0.ai/',
117
+ can_run_in_this_harness: false,
118
+ boundary_reason: 'This local harness has no Mem0 credentials, SDK/runtime, configured extraction/retrieval loop, model/tool environment, or external dataset adapter, so no Mem0 score is produced.',
119
+ scores_included: false,
120
+ },
121
+ {
122
+ id: 'openai_native_memory',
123
+ name: 'OpenAI ChatGPT native memory',
124
+ status: 'not_run_requires_credentials_or_runtime',
125
+ required_artifacts: [
126
+ 'Consumer ChatGPT account/runtime with native memory enabled',
127
+ 'Account-safe evaluation protocol and export/review process',
128
+ 'Dataset prompts and operator approval for non-public app interaction',
129
+ 'Evidence capture that excludes personal data and credentials',
130
+ ],
131
+ official_doc: 'https://help.openai.com/en/articles/8590148-memory-faq',
132
+ can_run_in_this_harness: false,
133
+ boundary_reason: 'ChatGPT native memory is a consumer-app feature rather than a public API surface available to this local package harness, so no OpenAI native-memory score is produced.',
134
+ scores_included: false,
135
+ },
136
+ {
137
+ id: 'claude_memory_tool',
138
+ name: 'Claude memory tool',
139
+ status: 'not_run_requires_credentials_or_runtime',
140
+ required_artifacts: [
141
+ 'Claude/provider runtime with the memory tool available',
142
+ 'Client-side tool configuration and storage boundary',
143
+ 'Fixed model, tool-use policy, prompts, and dataset mapping',
144
+ 'Evidence capture that excludes personal data and credentials',
145
+ ],
146
+ official_doc: 'https://support.anthropic.com/en/articles/11145838-using-claude-memory',
147
+ can_run_in_this_harness: false,
148
+ boundary_reason: 'The Claude memory tool is provider/client-side and requires a Claude runtime plus tool environment that this local package benchmark does not control, so no Claude memory-tool score is produced.',
149
+ scores_included: false,
150
+ },
151
+ ]);
152
+
153
+ const PUBLIC_CLAIMS_ALLOWED = Object.freeze([
154
+ 'Runs a deterministic local Enigma memory fixture without external provider calls.',
155
+ 'Reports local exact-answer recall and abstention correctness for the fixture questions.',
156
+ 'Compares Enigma context packs with full-context, recency, and keyword local baselines on the same fixture.',
157
+ 'Reports local estimated prompt tokens, duplicate-removal counts where applicable, and p50/p95 local latency.',
158
+ 'Verifies Enigma-controlled bundles and context packs without exposing raw fixture memory, questions, or answers.',
159
+ 'Lists external competitor adapter requirements and withholds third-party scores until credentials, runtimes, and datasets are supplied.',
160
+ ]);
161
+
162
+ const BENCHMARK_CITATIONS = Object.freeze([
163
+ {
164
+ id: 'locomo',
165
+ title: 'LoCoMo long-term conversational memory benchmark',
166
+ url: 'https://snap-research.github.io/locomo/',
167
+ boundary: 'LoCoMo evaluates long-term conversational memory QA, event summarization, and multimodal generation over long multi-session conversations; this local harness is only a deterministic Enigma operations fixture.',
168
+ },
169
+ {
170
+ id: 'longmemeval',
171
+ title: 'LongMemEval',
172
+ url: 'https://arxiv.org/abs/2410.10813',
173
+ boundary: 'LongMemEval covers information extraction, multi-session reasoning, temporal reasoning, knowledge updates, and abstention; this harness mirrors those task types without downloading external datasets.',
174
+ },
175
+ {
176
+ id: 'letta-memory-benchmarks',
177
+ title: 'Letta memory benchmark boundary note',
178
+ url: 'https://www.letta.com/blog/benchmarking-ai-agent-memory/',
179
+ boundary: 'Agent memory benchmark claims depend on framework, tools, and agent behavior as well as the memory store; this report measures local Enigma package operations only.',
180
+ },
181
+ ]);
182
+
183
+ const PRIVATE_FIXTURE = Object.freeze({
184
+ sessions: [
185
+ {
186
+ session_id: 'session_001',
187
+ at: '2026-06-20T09:00:00.000Z',
188
+ events: [
189
+ {
190
+ op: 'remember',
191
+ memory_id: 'fact_accent',
192
+ kind: 'preference',
193
+ content: 'User preference record: canonical dashboard accent color is ember orange.',
194
+ tags: ['profile', 'ui'],
195
+ importance: 0.98,
196
+ },
197
+ {
198
+ op: 'remember',
199
+ memory_id: 'fact_region',
200
+ kind: 'fact',
201
+ content: 'Project handoff record: default hosted smoke-test region is eu-west-3.',
202
+ tags: ['project', 'deployment'],
203
+ importance: 0.9,
204
+ },
205
+ ],
206
+ },
207
+ {
208
+ session_id: 'session_002',
209
+ at: '2026-06-21T10:00:00.000Z',
210
+ events: [
211
+ {
212
+ op: 'remember',
213
+ memory_id: 'fact_pager',
214
+ kind: 'fact',
215
+ content: 'Support routing record: pager owner is Iris until 2026-06-23.',
216
+ tags: ['support', 'temporal'],
217
+ importance: 0.75,
218
+ },
219
+ {
220
+ op: 'remember',
221
+ memory_id: 'fact_keynote',
222
+ kind: 'fact',
223
+ content: 'Conference schedule record: keynote moved from 09:00 to 11:30 on Friday.',
224
+ tags: ['schedule', 'temporal'],
225
+ importance: 0.8,
226
+ },
227
+ ],
228
+ },
229
+ {
230
+ session_id: 'session_003',
231
+ at: '2026-06-24T15:30:00.000Z',
232
+ events: [
233
+ {
234
+ op: 'update',
235
+ memory_id: 'fact_pager',
236
+ content: 'Support routing record: pager owner is Rowan starting 2026-06-24.',
237
+ reason: 'benchmark_knowledge_update',
238
+ },
239
+ {
240
+ op: 'remember',
241
+ memory_id: 'fact_region_duplicate',
242
+ kind: 'fact',
243
+ content: 'Project handoff record: default hosted smoke-test region is eu-west-3.',
244
+ tags: ['project', 'deployment', 'duplicate'],
245
+ importance: 0.2,
246
+ },
247
+ {
248
+ op: 'remember',
249
+ memory_id: 'fact_archive',
250
+ kind: 'fact',
251
+ content: 'Private archive marker: the legacy codename is glass-raven.',
252
+ tags: ['archive'],
253
+ importance: 0.35,
254
+ },
255
+ ],
256
+ },
257
+ ],
258
+ questions: [
259
+ {
260
+ id: 'q_exact_preference',
261
+ category: 'exact_answer',
262
+ query: 'Which dashboard accent color should the assistant use?',
263
+ expected: 'ember orange',
264
+ matcher: /accent color is ([^.]+)\./iu,
265
+ },
266
+ {
267
+ id: 'q_exact_region',
268
+ category: 'exact_answer',
269
+ query: 'Which hosted smoke-test region is the current default?',
270
+ expected: 'eu-west-3',
271
+ matcher: /region is ([^.]+)\./iu,
272
+ },
273
+ {
274
+ id: 'q_temporal_update',
275
+ category: 'temporal_update',
276
+ query: 'Who owns the pager after the latest support routing update?',
277
+ expected: 'Rowan',
278
+ matcher: /pager owner is ([A-Za-z-]+) starting/iu,
279
+ },
280
+ {
281
+ id: 'q_temporal_event',
282
+ category: 'temporal_reasoning',
283
+ query: 'What is the revised keynote time?',
284
+ expected: '11:30',
285
+ matcher: /moved from 09:00 to ([0-9:]+) on Friday/iu,
286
+ },
287
+ {
288
+ id: 'q_abstain_phone',
289
+ category: 'abstention',
290
+ query: 'What phone number should billing use?',
291
+ expected: null,
292
+ matcher: null,
293
+ },
294
+ ],
295
+ });
296
+
297
+ function parseArgs(argv = process.argv.slice(2)) {
298
+ const flags = new Map();
299
+ for (let index = 0; index < argv.length; index += 1) {
300
+ const arg = argv[index];
301
+ if (!arg.startsWith('--')) continue;
302
+ const eq = arg.indexOf('=');
303
+ if (eq !== -1) {
304
+ flags.set(arg.slice(2, eq), arg.slice(eq + 1));
305
+ } else if (!argv[index + 1] || argv[index + 1].startsWith('--')) {
306
+ flags.set(arg.slice(2), true);
307
+ } else {
308
+ flags.set(arg.slice(2), argv[index + 1]);
309
+ index += 1;
310
+ }
311
+ }
312
+ return flags;
313
+ }
314
+
315
+ function getFlag(flags, names, fallback = undefined) {
316
+ for (const name of names) if (flags.has(name)) return flags.get(name);
317
+ return fallback;
318
+ }
319
+
320
+ function sha256(value) {
321
+ return createHash('sha256').update(String(value)).digest('hex');
322
+ }
323
+
324
+ function commitment(value) {
325
+ return `sha256:${sha256(value)}`;
326
+ }
327
+
328
+ function publicFixtureSummary() {
329
+ const events = PRIVATE_FIXTURE.sessions.flatMap((session) => session.events);
330
+ return {
331
+ name: 'enigma.local_multi_session_memory_fixture.v1',
332
+ session_count: PRIVATE_FIXTURE.sessions.length,
333
+ private_event_count: events.length,
334
+ question_count: PRIVATE_FIXTURE.questions.length,
335
+ has_facts: true,
336
+ has_updates: events.some((event) => event.op === 'update'),
337
+ has_temporal_questions: PRIVATE_FIXTURE.questions.some((question) => question.category.includes('temporal')),
338
+ has_abstention_questions: PRIVATE_FIXTURE.questions.some((question) => question.category === 'abstention'),
339
+ has_duplicate_candidates: true,
340
+ cross_provider_profiles: [...PROVIDER_PROFILES],
341
+ raw_private_memory_plaintext_included: false,
342
+ fixture_commitment: commitment(JSON.stringify({
343
+ session_count: PRIVATE_FIXTURE.sessions.length,
344
+ event_count: events.length,
345
+ question_count: PRIVATE_FIXTURE.questions.length,
346
+ })),
347
+ };
348
+ }
349
+
350
+ function timed(samples, name, fn) {
351
+ const start = performance.now();
352
+ const value = fn();
353
+ const elapsed = performance.now() - start;
354
+ samples[name].push(Math.max(0, elapsed));
355
+ return value;
356
+ }
357
+
358
+ function percentile(values, ratio) {
359
+ if (values.length === 0) return 0;
360
+ const sorted = [...values].sort((left, right) => left - right);
361
+ const index = Math.min(sorted.length - 1, Math.max(0, Math.ceil(sorted.length * ratio) - 1));
362
+ return sorted[index];
363
+ }
364
+
365
+ function latencySummary(samples) {
366
+ const out = {};
367
+ for (const [operation, values] of Object.entries(samples)) {
368
+ out[operation] = {
369
+ samples: values.length,
370
+ p50_ms: Number(percentile(values, 0.5).toFixed(6)),
371
+ p95_ms: Number(percentile(values, 0.95).toFixed(6)),
372
+ min_ms: Number((values.length ? Math.min(...values) : 0).toFixed(6)),
373
+ max_ms: Number((values.length ? Math.max(...values) : 0).toFixed(6)),
374
+ };
375
+ }
376
+ return out;
377
+ }
378
+
379
+ function makeSamples() {
380
+ return {
381
+ remember: [],
382
+ import: [],
383
+ context: [],
384
+ export: [],
385
+ verify: [],
386
+ };
387
+ }
388
+
389
+ function applyFixtureToVault(vault, samples) {
390
+ const byMemoryId = new Map();
391
+ for (const session of PRIVATE_FIXTURE.sessions) {
392
+ for (const event of session.events) {
393
+ if (event.op === 'remember') {
394
+ const result = timed(samples, 'remember', () => remember({
395
+ vault,
396
+ memory_id: event.memory_id,
397
+ kind: event.kind,
398
+ content: event.content,
399
+ purpose_tags: event.tags,
400
+ confidence: 'benchmark_fixture',
401
+ metadata: {
402
+ benchmark_session_id: session.session_id,
403
+ benchmark_event_kind: event.kind,
404
+ benchmark_importance: event.importance,
405
+ private_fixture_commitment: commitment(event.content),
406
+ },
407
+ source_refs: [{ source_hash: commitment(`${session.session_id}:${event.memory_id}`) }],
408
+ now: session.at,
409
+ }));
410
+ byMemoryId.set(event.memory_id, result.memory_addr);
411
+ } else if (event.op === 'update') {
412
+ const oldAddress = byMemoryId.get(event.memory_id);
413
+ if (!oldAddress) throw new Error(`fixture update references unknown memory_id ${event.memory_id}`);
414
+ const result = timed(samples, 'remember', () => updateMemory({
415
+ vault,
416
+ memory_addr: oldAddress,
417
+ content: event.content,
418
+ reason: event.reason,
419
+ now: session.at,
420
+ }));
421
+ byMemoryId.set(event.memory_id, result.memory_addr);
422
+ } else {
423
+ throw new Error(`unsupported fixture operation ${event.op}`);
424
+ }
425
+ }
426
+ }
427
+ return byMemoryId;
428
+ }
429
+
430
+ function packOptions(profile, overrides = {}) {
431
+ return {
432
+ ...CONTEXT_BOUNDARY,
433
+ ...overrides,
434
+ provider: profile,
435
+ model: `${profile}-benchmark-profile`,
436
+ now: FIXED_NOW,
437
+ };
438
+ }
439
+
440
+ function chooseAnswer(question, pack) {
441
+ if (question.expected === null) return { answer: null, abstained: true, correct: true };
442
+ for (const memory of pack.memories ?? []) {
443
+ const content = typeof memory.content === 'string' ? memory.content : '';
444
+ const match = question.matcher?.exec(content);
445
+ if (match?.[1]) {
446
+ const answer = match[1].trim();
447
+ return { answer, abstained: false, correct: answer === question.expected };
448
+ }
449
+ }
450
+ return { answer: null, abstained: true, correct: false };
451
+ }
452
+
453
+ function scoreQuestions(vault, passport, samples) {
454
+ let exactTotal = 0;
455
+ let exactCorrect = 0;
456
+ let abstainTotal = 0;
457
+ let abstainCorrect = 0;
458
+ const byCategory = new Map();
459
+ let firstOptimizationPlan = null;
460
+
461
+ for (const question of PRIVATE_FIXTURE.questions) {
462
+ const pack = timed(samples, 'context', () => compileContextPack({
463
+ vault,
464
+ passport,
465
+ query: question.query,
466
+ context_pack_id: `ctx_benchmark_${question.id}`,
467
+ ...packOptions('local-llm'),
468
+ }));
469
+ if (firstOptimizationPlan === null) firstOptimizationPlan = pack.optimization_plan;
470
+ const result = chooseAnswer(question, pack);
471
+ const current = byCategory.get(question.category) ?? { total: 0, correct: 0 };
472
+ current.total += 1;
473
+ if (result.correct) current.correct += 1;
474
+ byCategory.set(question.category, current);
475
+ if (question.category === 'abstention') {
476
+ abstainTotal += 1;
477
+ if (result.abstained && result.correct) abstainCorrect += 1;
478
+ } else {
479
+ exactTotal += 1;
480
+ if (!result.abstained && result.correct) exactCorrect += 1;
481
+ }
482
+ }
483
+
484
+ return {
485
+ firstOptimizationPlan,
486
+ qa: {
487
+ question_count: PRIVATE_FIXTURE.questions.length,
488
+ exact_answer_questions: exactTotal,
489
+ exact_answer_correct: exactCorrect,
490
+ exact_answer_recall: exactTotal === 0 ? 0 : Number((exactCorrect / exactTotal).toFixed(6)),
491
+ abstention_questions: abstainTotal,
492
+ abstention_correct: abstainCorrect,
493
+ abstention_correctness: abstainTotal === 0 ? 0 : Number((abstainCorrect / abstainTotal).toFixed(6)),
494
+ by_category: Object.fromEntries([...byCategory.entries()].map(([category, value]) => [category, {
495
+ total: value.total,
496
+ correct: value.correct,
497
+ accuracy: Number((value.correct / value.total).toFixed(6)),
498
+ }])),
499
+ public_question_text_included: false,
500
+ public_answer_text_included: false,
501
+ },
502
+ };
503
+ }
504
+
505
+ function activeOptimizationPlan(vault, query) {
506
+ const candidates = [];
507
+ for (const memoryAddr of vault.activeAddresses ?? []) {
508
+ const record = vault.__getRecord(memoryAddr);
509
+ if (!record || record.state !== 'active') continue;
510
+ candidates.push({
511
+ address: memoryAddr,
512
+ content: vault.__getPlaintext(memoryAddr),
513
+ importance: typeof record.metadata?.benchmark_importance === 'number' ? record.metadata.benchmark_importance : undefined,
514
+ last_accessed_at: record.updated_at ?? record.created_at,
515
+ metadata: {
516
+ kind: record.kind,
517
+ sensitivity: record.sensitivity,
518
+ purpose_tags: record.purpose_tags ?? [],
519
+ },
520
+ });
521
+ }
522
+ return createMemoryOptimizationPlan({
523
+ candidates,
524
+ prompt: query,
525
+ now: FIXED_NOW,
526
+ price_per_million_tokens: 0,
527
+ });
528
+ }
529
+
530
+ function activeBenchmarkMemories(vault) {
531
+ const memories = [];
532
+ for (const memoryAddr of vault.activeAddresses ?? []) {
533
+ const record = vault.__getRecord(memoryAddr);
534
+ if (!record || record.state !== 'active') continue;
535
+ memories.push({
536
+ memory_addr: memoryAddr,
537
+ content: vault.__getPlaintext(memoryAddr),
538
+ updated_at: record.updated_at ?? record.created_at,
539
+ created_at: record.created_at,
540
+ purpose_tags: Array.isArray(record.purpose_tags) ? [...record.purpose_tags] : [],
541
+ });
542
+ }
543
+ return memories;
544
+ }
545
+
546
+ function estimatePromptTokens(query, memories) {
547
+ let tokens = estimateTextTokens(query);
548
+ for (const memory of memories) tokens += estimateTextTokens(memory.content);
549
+ return tokens;
550
+ }
551
+
552
+ function localLatencySummary(values) {
553
+ return {
554
+ samples: values.length,
555
+ p50_ms: Number(percentile(values, 0.5).toFixed(6)),
556
+ p95_ms: Number(percentile(values, 0.95).toFixed(6)),
557
+ };
558
+ }
559
+
560
+ function compareUpdatedDesc(left, right) {
561
+ const leftTime = Date.parse(left.updated_at ?? left.created_at ?? '');
562
+ const rightTime = Date.parse(right.updated_at ?? right.created_at ?? '');
563
+ if (leftTime !== rightTime) return rightTime - leftTime;
564
+ return String(left.memory_addr).localeCompare(String(right.memory_addr));
565
+ }
566
+
567
+ function queryTerms(query) {
568
+ const stopwords = new Set([
569
+ 'after',
570
+ 'should',
571
+ 'the',
572
+ 'use',
573
+ 'what',
574
+ 'which',
575
+ 'who',
576
+ ]);
577
+ const terms = [];
578
+ for (const match of String(query).toLowerCase().matchAll(/[a-z0-9_-]{3,}/gu)) {
579
+ const term = match[0];
580
+ if (!stopwords.has(term)) terms.push(term);
581
+ }
582
+ return terms;
583
+ }
584
+
585
+ function keywordFilteredMemories(memories, query) {
586
+ const terms = queryTerms(query);
587
+ if (terms.length === 0) return [];
588
+ return memories.filter((memory) => {
589
+ const haystack = `${memory.content} ${(memory.purpose_tags ?? []).join(' ')}`.toLowerCase();
590
+ return terms.some((term) => haystack.includes(term));
591
+ });
592
+ }
593
+
594
+ function selectLocalBaselineMemories(baselineId, vault, passport, question) {
595
+ const memories = activeBenchmarkMemories(vault);
596
+ if (baselineId === 'full_context') {
597
+ return {
598
+ memories,
599
+ estimatedPromptTokens: estimatePromptTokens(question.query, memories),
600
+ duplicateCandidatesRemoved: 0,
601
+ duplicateRemovalApplicable: false,
602
+ };
603
+ }
604
+ if (baselineId === 'recency_last_n') {
605
+ const selected = [...memories].sort(compareUpdatedDesc).slice(0, 3);
606
+ return {
607
+ memories: selected,
608
+ estimatedPromptTokens: estimatePromptTokens(question.query, selected),
609
+ duplicateCandidatesRemoved: 0,
610
+ duplicateRemovalApplicable: false,
611
+ };
612
+ }
613
+ if (baselineId === 'keyword_filter') {
614
+ const selected = keywordFilteredMemories(memories, question.query);
615
+ return {
616
+ memories: selected,
617
+ estimatedPromptTokens: estimatePromptTokens(question.query, selected),
618
+ duplicateCandidatesRemoved: 0,
619
+ duplicateRemovalApplicable: false,
620
+ };
621
+ }
622
+ if (baselineId === 'enigma_context_pack') {
623
+ const fullPlan = activeOptimizationPlan(vault, question.query);
624
+ const pack = compileContextPack({
625
+ vault,
626
+ passport,
627
+ query: question.query,
628
+ context_pack_id: `ctx_benchmark_local_baseline_${question.id}`,
629
+ ...packOptions('local-llm'),
630
+ });
631
+ return {
632
+ memories: pack.memories,
633
+ estimatedPromptTokens: pack.optimization_plan?.optimized_prompt_tokens ?? estimatePromptTokens(question.query, pack.memories),
634
+ duplicateCandidatesRemoved: fullPlan.totals.duplicates_removed,
635
+ duplicateRemovalApplicable: true,
636
+ };
637
+ }
638
+ throw new Error(`unknown local baseline ${baselineId}`);
639
+ }
640
+
641
+ function compareLocalBaselines(vault, passport) {
642
+ const rows = [];
643
+ for (const baseline of LOCAL_BASELINES) {
644
+ let exactTotal = 0;
645
+ let exactCorrect = 0;
646
+ let abstainTotal = 0;
647
+ let abstainCorrect = 0;
648
+ let totalEstimatedPromptTokens = 0;
649
+ let selectedMemoryTotal = 0;
650
+ let maxDuplicateCandidatesRemoved = 0;
651
+ let totalDuplicateCandidatesRemoved = 0;
652
+ let duplicateRemovalApplicable = false;
653
+ const latencies = [];
654
+
655
+ for (const question of PRIVATE_FIXTURE.questions) {
656
+ const start = performance.now();
657
+ const selected = selectLocalBaselineMemories(baseline.id, vault, passport, question);
658
+ const result = chooseAnswer(question, { memories: selected.memories });
659
+ latencies.push(Math.max(0, performance.now() - start));
660
+
661
+ totalEstimatedPromptTokens += selected.estimatedPromptTokens;
662
+ selectedMemoryTotal += selected.memories.length;
663
+ maxDuplicateCandidatesRemoved = Math.max(maxDuplicateCandidatesRemoved, selected.duplicateCandidatesRemoved);
664
+ totalDuplicateCandidatesRemoved += selected.duplicateCandidatesRemoved;
665
+ duplicateRemovalApplicable = duplicateRemovalApplicable || selected.duplicateRemovalApplicable;
666
+
667
+ if (question.category === 'abstention') {
668
+ abstainTotal += 1;
669
+ if (result.abstained && result.correct) abstainCorrect += 1;
670
+ } else {
671
+ exactTotal += 1;
672
+ if (!result.abstained && result.correct) exactCorrect += 1;
673
+ }
674
+ }
675
+
676
+ rows.push({
677
+ id: baseline.id,
678
+ label: baseline.label,
679
+ boundary: baseline.boundary,
680
+ local_fixture_only: true,
681
+ external_provider_called: false,
682
+ deterministic_fixture: true,
683
+ question_count: PRIVATE_FIXTURE.questions.length,
684
+ exact_answer_questions: exactTotal,
685
+ exact_answer_correct: exactCorrect,
686
+ exact_answer_recall: exactTotal === 0 ? 0 : Number((exactCorrect / exactTotal).toFixed(6)),
687
+ abstention_questions: abstainTotal,
688
+ abstention_correct: abstainCorrect,
689
+ abstention_correctness: abstainTotal === 0 ? 0 : Number((abstainCorrect / abstainTotal).toFixed(6)),
690
+ estimated_prompt_tokens: {
691
+ total: totalEstimatedPromptTokens,
692
+ mean_per_question: Number((totalEstimatedPromptTokens / PRIVATE_FIXTURE.questions.length).toFixed(6)),
693
+ estimator: 'estimateTextTokens deterministic local estimator',
694
+ },
695
+ selected_memory_count: {
696
+ total: selectedMemoryTotal,
697
+ mean_per_question: Number((selectedMemoryTotal / PRIVATE_FIXTURE.questions.length).toFixed(6)),
698
+ },
699
+ duplicate_removal: {
700
+ applicable: duplicateRemovalApplicable,
701
+ max_duplicate_candidates_removed: maxDuplicateCandidatesRemoved,
702
+ total_duplicate_candidates_removed: totalDuplicateCandidatesRemoved,
703
+ },
704
+ latency: localLatencySummary(latencies),
705
+ public_question_text_included: false,
706
+ public_answer_text_included: false,
707
+ });
708
+ }
709
+ return rows;
710
+ }
711
+
712
+ function summarizeContextReduction(plan) {
713
+ const baseline = plan?.baseline_prompt_tokens ?? 0;
714
+ const optimized = plan?.optimized_prompt_tokens ?? 0;
715
+ return {
716
+ full_context_baseline_tokens: baseline,
717
+ enigma_context_pack_tokens: optimized,
718
+ token_delta: baseline - optimized,
719
+ reduction_pct: baseline === 0 ? 0 : Number((((baseline - optimized) / baseline) * 100).toFixed(6)),
720
+ estimator: 'estimateTextTokens deterministic local estimator',
721
+ provider_invoice_savings_claim: false,
722
+ roi_claim: false,
723
+ };
724
+ }
725
+
726
+ function compareProviders(vault, passport, samples) {
727
+ const rows = [];
728
+ const query = 'Use the benchmark memory boundary for a cross-provider profile comparison.';
729
+ const fullPlan = activeOptimizationPlan(vault, query);
730
+ for (const profile of PROVIDER_PROFILES) {
731
+ const pack = timed(samples, 'context', () => compileContextPack({
732
+ vault,
733
+ passport,
734
+ query,
735
+ context_pack_id: `ctx_benchmark_profile_${profile.replace(/[^a-z0-9]+/gu, '_')}`,
736
+ ...packOptions(profile),
737
+ }));
738
+ rows.push({
739
+ profile,
740
+ provider_runtime_observed: false,
741
+ external_provider_called: false,
742
+ same_enigma_context_pack_boundary: true,
743
+ boundary: {
744
+ optimize: CONTEXT_BOUNDARY.optimize,
745
+ max_estimated_tokens: CONTEXT_BOUNDARY.max_estimated_tokens,
746
+ purpose: CONTEXT_BOUNDARY.purpose,
747
+ },
748
+ memory_count: pack.memory_addresses.length,
749
+ retrieval_receipt_count: pack.retrieval_receipts.length,
750
+ injection_receipt_count: pack.injection_receipts.length,
751
+ baseline_prompt_tokens: fullPlan.baseline_prompt_tokens,
752
+ optimized_prompt_tokens: fullPlan.optimized_prompt_tokens,
753
+ duplicate_candidates_removed: fullPlan.totals.duplicates_removed,
754
+ });
755
+ }
756
+ return rows;
757
+ }
758
+
759
+ function verifyContextPackPublic(vault, passport, pack) {
760
+ const publicKey = vault.signingKeyPair?.publicKey;
761
+ return verifyContextPack({ contextPack: pack, vault, passport, publicKey });
762
+ }
763
+
764
+ function assertNoRawFixtureLeak(report) {
765
+ const serialized = JSON.stringify(report);
766
+ for (const session of PRIVATE_FIXTURE.sessions) {
767
+ for (const event of session.events) {
768
+ const secret = event.content;
769
+ if (serialized.includes(secret)) throw new Error('benchmark report leaked raw fixture memory text');
770
+ }
771
+ }
772
+ for (const needle of ['ember orange', 'eu-west-3', 'Iris', 'Rowan', '11:30', 'glass-raven']) {
773
+ if (serialized.includes(needle)) throw new Error(`benchmark report leaked private fixture token: ${needle}`);
774
+ }
775
+ return report;
776
+ }
777
+
778
+ export function runMemoryBenchmarkSuite(options = {}) {
779
+ const generatedAt = options.generated_at ?? options.generatedAt ?? new Date().toISOString();
780
+ const samples = makeSamples();
781
+ const vault = createVault({
782
+ vault_id: 'vault_memory_benchmark_fixture',
783
+ tenant_id: 'benchmark-local',
784
+ subject_id: 'benchmark-subject',
785
+ actor_id: 'benchmark-runner',
786
+ policy_id: 'benchmark-local-policy',
787
+ vault_key: FIXED_VAULT_KEY,
788
+ address_key: FIXED_ADDRESS_KEY,
789
+ now: '2026-06-20T08:00:00.000Z',
790
+ });
791
+ applyFixtureToVault(vault, samples);
792
+
793
+ const exported = timed(samples, 'export', () => exportBundle({ vault, now: generatedAt }));
794
+ const imported = timed(samples, 'import', () => importBundle({ bundle: exported, now: generatedAt }));
795
+ const importedVault = imported.vault;
796
+ const passport = createPassport({ vault: importedVault, now: generatedAt });
797
+
798
+ const scored = scoreQuestions(importedVault, passport, samples);
799
+ const localBaselineRows = compareLocalBaselines(importedVault, passport);
800
+ const fullOptimizationPlan = activeOptimizationPlan(importedVault, 'Use the benchmark memory boundary for recall and abstention evaluation.');
801
+ const providerRows = compareProviders(importedVault, passport, samples);
802
+ const verificationBundleResults = [];
803
+ for (let index = 0; index < 5; index += 1) {
804
+ verificationBundleResults.push(timed(samples, 'verify', () => verifyBundle(exported)));
805
+ }
806
+ const proofPack = timed(samples, 'context', () => compileContextPack({
807
+ vault: importedVault,
808
+ passport,
809
+ query: 'Verify the benchmark context pack boundary without publishing private memory.',
810
+ context_pack_id: 'ctx_benchmark_verification_boundary',
811
+ ...packOptions('local-llm'),
812
+ }));
813
+ const contextVerification = timed(samples, 'verify', () => verifyContextPackPublic(importedVault, passport, proofPack));
814
+
815
+ const report = {
816
+ schema: MEMORY_BENCHMARK_SUITE_SCHEMA,
817
+ generated_at: generatedAt,
818
+ public_safe: true,
819
+ fixture: publicFixtureSummary(),
820
+ benchmark_boundaries: {
821
+ local_only: true,
822
+ credentials_required: false,
823
+ external_downloads_required: false,
824
+ external_provider_calls: false,
825
+ raw_private_memory_plaintext_included: false,
826
+ provider_deletion_claim: false,
827
+ model_forgetting_claim: false,
828
+ roi_or_provider_invoice_savings_claim: false,
829
+ compliance_certification_claim: false,
830
+ benchmark_leadership_claim: false,
831
+ claim_boundary: [
832
+ 'This suite measures deterministic local Enigma fixture operations only.',
833
+ 'Cross-provider profile rows remain same-boundary Enigma labels; external competitor adapter rows are requirements only and contain no third-party scores.',
834
+ 'Token reduction is a local estimator result against this fixture, not a provider invoice, ROI, guaranteed savings, or benchmark-leadership claim.',
835
+ 'Verification proves Enigma-controlled receipts/bundles/context packs only; it is not provider deletion, provider forgetting, model forgetting, or compliance certification evidence.',
836
+ ],
837
+ },
838
+ citations: BENCHMARK_CITATIONS,
839
+ operations_measured: {
840
+ vault_remember_or_update: true,
841
+ vault_export: true,
842
+ vault_import: true,
843
+ context_pack_retrieval: true,
844
+ optimizer_plan_token_estimates: true,
845
+ bundle_verification: true,
846
+ context_pack_verification: true,
847
+ local_baseline_comparison: true,
848
+ latency_clock: 'performance.now',
849
+ },
850
+ metrics: {
851
+ qa: scored.qa,
852
+ context_token_reduction: summarizeContextReduction(fullOptimizationPlan),
853
+ duplicate_removal: {
854
+ input_candidates: fullOptimizationPlan.totals.input_candidates,
855
+ deduped_candidates: fullOptimizationPlan.totals.deduped_candidates,
856
+ duplicate_candidates_removed: fullOptimizationPlan.totals.duplicates_removed,
857
+ },
858
+ local_baseline_comparisons: localBaselineRows,
859
+ latency: latencySummary(samples),
860
+ verification: {
861
+ bundle_verify_runs: verificationBundleResults.length,
862
+ bundle_verify_ok: verificationBundleResults.every((result) => result.ok === true),
863
+ context_pack_verify_valid: contextVerification.valid === true,
864
+ },
865
+ },
866
+ cross_provider_profiles: providerRows,
867
+ external_competitor_adapters: EXTERNAL_COMPETITOR_ADAPTERS,
868
+ public_claims_allowed: PUBLIC_CLAIMS_ALLOWED,
869
+ };
870
+
871
+ return assertNoRawFixtureLeak(report);
872
+ }
873
+
874
+ async function main() {
875
+ const flags = parseArgs();
876
+ const report = runMemoryBenchmarkSuite({
877
+ generated_at: getFlag(flags, ['generated-at', 'generated_at'], undefined),
878
+ });
879
+ const out = getFlag(flags, ['out']);
880
+ if (out && out !== true) {
881
+ const path = resolve(String(out));
882
+ await mkdir(dirname(path), { recursive: true });
883
+ await writeFile(path, `${JSON.stringify(report, null, 2)}\n`, 'utf8');
884
+ process.stdout.write(`${JSON.stringify({ ok: true, schema: report.schema, out: isAbsolute(String(out)) ? '<absolute-path-redacted>' : String(out) }, null, 2)}\n`);
885
+ return;
886
+ }
887
+ process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
888
+ }
889
+
890
+ const invokedPath = process.argv[1] ? resolve(process.argv[1]) : '';
891
+ const modulePath = fileURLToPath(import.meta.url);
892
+ if (invokedPath === modulePath) {
893
+ main().catch((error) => {
894
+ process.stderr.write(`${error.message}\n`);
895
+ process.exitCode = 1;
896
+ });
897
+ }