enigma-memory 0.1.0

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 (105) hide show
  1. package/LICENSE +55 -0
  2. package/README.md +379 -0
  3. package/apps/cli/bin/enigma.mjs +1117 -0
  4. package/apps/desktop/src/app.js +1327 -0
  5. package/apps/desktop/src/index.html +1373 -0
  6. package/apps/desktop/src/styles.css +386 -0
  7. package/apps/gateway/bin/enigma-gateway.mjs +52 -0
  8. package/apps/gateway/src/server.mjs +1403 -0
  9. package/apps/native-host/README.md +265 -0
  10. package/apps/native-host/bin/enigma-native-host.mjs +499 -0
  11. package/apps/native-host/manifests/com.enigma.native_host.chrome.json +9 -0
  12. package/apps/native-host/manifests/com.enigma.native_host.edge.json +9 -0
  13. package/apps/native-host/manifests/com.enigma.native_host.firefox.json +9 -0
  14. package/apps/relay/bin/enigma-relay.mjs +52 -0
  15. package/apps/relay/src/server.mjs +1571 -0
  16. package/apps/verifier/bin/enigma-verify.mjs +240 -0
  17. package/deploy/docker-compose.production.example.yml +150 -0
  18. package/deploy/kubernetes/enigma-backend.example.yaml +580 -0
  19. package/package.json +196 -0
  20. package/packages/adapters/PACKAGE_CONTRACT.md +47 -0
  21. package/packages/adapters/src/index.js +183 -0
  22. package/packages/boundary/src/index.js +468 -0
  23. package/packages/connectors/src/index.js +533 -0
  24. package/packages/core/src/index.js +766 -0
  25. package/packages/enterprise/src/index.js +505 -0
  26. package/packages/importers/src/index.js +1083 -0
  27. package/packages/mcp-server/bin/enigma-mcp.mjs +19 -0
  28. package/packages/mcp-server/src/index.js +1185 -0
  29. package/packages/mesh/src/index.js +531 -0
  30. package/packages/metering/PACKAGE_CONTRACT.md +20 -0
  31. package/packages/metering/src/index.js +246 -0
  32. package/packages/optimizer/src/index.js +707 -0
  33. package/packages/passport/src/index.js +651 -0
  34. package/packages/settlement/PACKAGE_CONTRACT.md +28 -0
  35. package/packages/settlement/src/index.js +369 -0
  36. package/packages/storage/PACKAGE_CONTRACT.md +23 -0
  37. package/packages/storage/src/index.js +392 -0
  38. package/packages/vault/src/index.js +904 -0
  39. package/scripts/build-ai-orchestration-plan.mjs +248 -0
  40. package/scripts/build-cloudflare-pages-release-packet.mjs +287 -0
  41. package/scripts/build-cloudflare-token-policy.mjs +239 -0
  42. package/scripts/build-cloudflare-token-request.mjs +314 -0
  43. package/scripts/build-demo-assets.mjs +263 -0
  44. package/scripts/build-edge-backend-workers.mjs +353 -0
  45. package/scripts/build-goal-completion-audit.mjs +398 -0
  46. package/scripts/build-hosted-probe-worker.mjs +191 -0
  47. package/scripts/build-operator-acceptance-packet.mjs +254 -0
  48. package/scripts/build-operator-evidence-starter.mjs +525 -0
  49. package/scripts/build-production-backend-env-kit.mjs +384 -0
  50. package/scripts/build-production-dependency-report.mjs +369 -0
  51. package/scripts/build-production-handoff-packet.mjs +475 -0
  52. package/scripts/build-production-readiness-manifest.mjs +209 -0
  53. package/scripts/build-production-status-board.mjs +297 -0
  54. package/scripts/build-production-storage-migration.mjs +86 -0
  55. package/scripts/build-production-workplan.mjs +371 -0
  56. package/scripts/build-review-packet.mjs +594 -0
  57. package/scripts/check.mjs +419 -0
  58. package/scripts/cloudflare-ops.mjs +1672 -0
  59. package/scripts/cloudflare-secret-env.mjs +128 -0
  60. package/scripts/collect-hosted-backend-live-evidence.mjs +263 -0
  61. package/scripts/infrastructure-readiness.mjs +944 -0
  62. package/scripts/install-enigma-local.mjs +270 -0
  63. package/scripts/memory-optimization-benchmark.mjs +242 -0
  64. package/scripts/monitor-live-endpoints.mjs +358 -0
  65. package/scripts/release-audit.mjs +5588 -0
  66. package/scripts/release-provenance.mjs +250 -0
  67. package/scripts/run-backend-readiness-smoke.mjs +220 -0
  68. package/scripts/validate-backup-restore-drill.mjs +166 -0
  69. package/scripts/validate-cloudflare-credentials.mjs +112 -0
  70. package/scripts/validate-cloudflare-worker-inspect.mjs +179 -0
  71. package/scripts/validate-domain-tls.mjs +248 -0
  72. package/scripts/validate-hosted-backend-live.mjs +319 -0
  73. package/scripts/validate-incident-drill.mjs +221 -0
  74. package/scripts/validate-kms-custody.mjs +235 -0
  75. package/scripts/validate-legal-compliance-approval.mjs +274 -0
  76. package/scripts/validate-monitoring-alerting.mjs +263 -0
  77. package/scripts/validate-network-access-policy.mjs +285 -0
  78. package/scripts/validate-operator-acceptance.mjs +298 -0
  79. package/scripts/validate-production-manifests.mjs +325 -0
  80. package/scripts/validate-public-site-security.mjs +252 -0
  81. package/scripts/validate-security-threat-model.mjs +285 -0
  82. package/scripts/validate-service-settlement.mjs +256 -0
  83. package/scripts/validate-support-sla.mjs +190 -0
  84. package/scripts/validate-tenant-policy-approval.mjs +228 -0
  85. package/scripts/validate-usage-metering.mjs +224 -0
  86. package/scripts/validate-whitepaper-claims.mjs +166 -0
  87. package/specs/boundary-manifest-v1.schema.json +35 -0
  88. package/specs/capsule-v1.schema.json +55 -0
  89. package/specs/claim-boundary-manifest-v1.schema.json +22 -0
  90. package/specs/connector-profile-v1.schema.json +62 -0
  91. package/specs/deletion-tombstone-v1.schema.json +26 -0
  92. package/specs/enterprise-policy-v1.schema.json +59 -0
  93. package/specs/gateway-request-v1.schema.json +32 -0
  94. package/specs/goal-completion-audit-v1.schema.json +70 -0
  95. package/specs/hosted-backend-live-evidence-v1.schema.json +147 -0
  96. package/specs/import-report-v1.schema.json +214 -0
  97. package/specs/infrastructure-readiness-manifest-v1.schema.json +130 -0
  98. package/specs/memory-event-v1.schema.json +42 -0
  99. package/specs/mesh-node-v1.schema.json +126 -0
  100. package/specs/passport-v1.schema.json +50 -0
  101. package/specs/production-handoff-packet-v1.schema.json +149 -0
  102. package/specs/receipt-v1.schema.json +61 -0
  103. package/specs/relay-record-v1.schema.json +43 -0
  104. package/specs/state-checkpoint-v1.schema.json +37 -0
  105. package/specs/trust-bundle-v1.schema.json +56 -0
@@ -0,0 +1,707 @@
1
+ import { createHash } from 'node:crypto';
2
+
3
+ const SHA256_PREFIX = 'sha256:';
4
+ const HASH_RE = /^(?:sha256:)?[a-f0-9]{64}$/i;
5
+ const PLAN_SCHEMA_ID = 'enigma.memory_optimization_plan.v1';
6
+ const RECEIPT_SCHEMA_ID = 'enigma.memory_access_receipt.v1';
7
+ const DEFAULT_POINTER_TOKENS = 24;
8
+ const DEFAULT_PROOF_TOKENS = 8;
9
+ const DEFAULT_WARM_RATIO = 0.35;
10
+ const TIER_ORDER = Object.freeze(['hot', 'warm', 'cold', 'proof_only']);
11
+ const TIER_RANK = Object.freeze({ hot: 0, warm: 1, cold: 2, proof_only: 3 });
12
+ const DISALLOWED_PUBLIC_KEYS = new Set([
13
+ 'body',
14
+ 'candidate',
15
+ 'candidates',
16
+ 'content',
17
+ 'contents',
18
+ 'document',
19
+ 'documents',
20
+ 'message',
21
+ 'messages',
22
+ 'metadata',
23
+ 'plain_text',
24
+ 'plaintext',
25
+ 'prompt',
26
+ 'prompts',
27
+ 'raw',
28
+ 'raw_content',
29
+ 'raw_memory',
30
+ 'response',
31
+ 'responses',
32
+ 'text',
33
+ 'transcript',
34
+ 'value'
35
+ ]);
36
+ const SAFE_PUBLIC_KEYS = new Set([
37
+ 'content_hash',
38
+ 'metadata_commitment',
39
+ 'commitment',
40
+ 'commitments',
41
+ 'commitment_scheme',
42
+ 'estimated_cost',
43
+ 'estimated_tokens',
44
+ 'baseline_prompt_tokens',
45
+ 'optimized_prompt_tokens',
46
+ 'total_estimated_tokens'
47
+ ]);
48
+
49
+ export const MEMORY_OPTIMIZATION_PRODUCT_THESIS = 'Centralized high-performance memory optimization service; blockchain and permissionless rails are access, settlement, and proof anchoring boundaries only, not decentralized inference or decentralized memory storage.';
50
+
51
+ export const MEMORY_OPTIMIZATION_PLAN_SCHEMA = Object.freeze({
52
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
53
+ $id: PLAN_SCHEMA_ID,
54
+ type: 'object',
55
+ additionalProperties: false,
56
+ required: [
57
+ 'schema',
58
+ 'product_thesis',
59
+ 'plan_id',
60
+ 'commitment_scheme',
61
+ 'baseline_prompt_tokens',
62
+ 'optimized_prompt_tokens',
63
+ 'savings_pct',
64
+ 'tiers',
65
+ 'items',
66
+ 'totals'
67
+ ],
68
+ properties: {
69
+ schema: { const: PLAN_SCHEMA_ID },
70
+ product_thesis: { const: MEMORY_OPTIMIZATION_PRODUCT_THESIS },
71
+ plan_id: { type: 'string', pattern: '^mopt_[a-f0-9]{32}$' },
72
+ commitment_scheme: { const: 'sha256-canonical-json-v1' },
73
+ pricing: {
74
+ anyOf: [
75
+ { type: 'null' },
76
+ {
77
+ type: 'object',
78
+ additionalProperties: false,
79
+ required: ['currency', 'price_per_million_tokens'],
80
+ properties: {
81
+ currency: { type: 'string', minLength: 1 },
82
+ price_per_million_tokens: { type: 'number', minimum: 0 }
83
+ }
84
+ }
85
+ ]
86
+ },
87
+ baseline_prompt_tokens: { type: 'integer', minimum: 0 },
88
+ optimized_prompt_tokens: { type: 'integer', minimum: 0 },
89
+ baseline_cost: { anyOf: [{ type: 'null' }, { type: 'number', minimum: 0 }] },
90
+ optimized_cost: { anyOf: [{ type: 'null' }, { type: 'number', minimum: 0 }] },
91
+ savings_pct: { type: 'number', minimum: 0, maximum: 100 },
92
+ tiers: {
93
+ type: 'object',
94
+ additionalProperties: false,
95
+ required: ['hot', 'warm', 'cold', 'proof_only'],
96
+ properties: {
97
+ hot: { type: 'array', items: { $ref: '#/$defs/item' } },
98
+ warm: { type: 'array', items: { $ref: '#/$defs/item' } },
99
+ cold: { type: 'array', items: { $ref: '#/$defs/item' } },
100
+ proof_only: { type: 'array', items: { $ref: '#/$defs/item' } }
101
+ }
102
+ },
103
+ items: { type: 'array', items: { $ref: '#/$defs/item' } },
104
+ totals: {
105
+ type: 'object',
106
+ additionalProperties: false,
107
+ required: ['input_candidates', 'deduped_candidates', 'duplicates_removed', 'total_estimated_tokens'],
108
+ properties: {
109
+ input_candidates: { type: 'integer', minimum: 0 },
110
+ deduped_candidates: { type: 'integer', minimum: 0 },
111
+ duplicates_removed: { type: 'integer', minimum: 0 },
112
+ total_estimated_tokens: { type: 'integer', minimum: 0 }
113
+ }
114
+ }
115
+ },
116
+ $defs: {
117
+ item: {
118
+ type: 'object',
119
+ additionalProperties: false,
120
+ required: ['address', 'content_hash', 'commitment', 'tier', 'estimated_tokens', 'optimized_prompt_tokens'],
121
+ properties: {
122
+ address: { type: 'string', minLength: 1 },
123
+ content_hash: { type: 'string', pattern: '^sha256:[a-f0-9]{64}$' },
124
+ commitment: { type: 'string', pattern: '^sha256:[a-f0-9]{64}$' },
125
+ metadata_commitment: { type: 'string', pattern: '^sha256:[a-f0-9]{64}$' },
126
+ tier: { enum: TIER_ORDER },
127
+ estimated_tokens: { type: 'integer', minimum: 0 },
128
+ optimized_prompt_tokens: { type: 'integer', minimum: 0 }
129
+ }
130
+ }
131
+ }
132
+ });
133
+
134
+ export const MEMORY_ACCESS_RECEIPT_SCHEMA = Object.freeze({
135
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
136
+ $id: RECEIPT_SCHEMA_ID,
137
+ type: 'object',
138
+ additionalProperties: false,
139
+ required: [
140
+ 'schema',
141
+ 'product_thesis',
142
+ 'receipt_id',
143
+ 'operation',
144
+ 'commitment_scheme',
145
+ 'address',
146
+ 'content_hash',
147
+ 'commitment',
148
+ 'access_boundary'
149
+ ],
150
+ properties: {
151
+ schema: { const: RECEIPT_SCHEMA_ID },
152
+ product_thesis: { const: MEMORY_OPTIMIZATION_PRODUCT_THESIS },
153
+ receipt_id: { type: 'string', pattern: '^mar_[a-f0-9]{32}$' },
154
+ operation: { const: 'memory.access.receipt_anchor' },
155
+ commitment_scheme: { const: 'sha256-canonical-json-v1' },
156
+ address: { type: 'string', minLength: 1 },
157
+ content_hash: { type: 'string', pattern: '^sha256:[a-f0-9]{64}$' },
158
+ commitment: { type: 'string', pattern: '^sha256:[a-f0-9]{64}$' },
159
+ plan_hash: { type: 'string', pattern: '^sha256:[a-f0-9]{64}$' },
160
+ timestamp: { anyOf: [{ type: 'null' }, { type: 'string' }] },
161
+ sequence: { type: 'integer', minimum: 0 },
162
+ estimated_prompt_tokens: { type: 'integer', minimum: 0 },
163
+ estimated_cost: { anyOf: [{ type: 'null' }, { type: 'number', minimum: 0 }] },
164
+ pricing: {
165
+ anyOf: [
166
+ { type: 'null' },
167
+ {
168
+ type: 'object',
169
+ additionalProperties: false,
170
+ required: ['currency', 'price_per_million_tokens'],
171
+ properties: {
172
+ currency: { type: 'string', minLength: 1 },
173
+ price_per_million_tokens: { type: 'number', minimum: 0 }
174
+ }
175
+ }
176
+ ]
177
+ },
178
+ access_boundary: {
179
+ type: 'object',
180
+ additionalProperties: false,
181
+ required: ['permissionless_access', 'settlement', 'proof_anchor', 'decentralized_storage_claim'],
182
+ properties: {
183
+ permissionless_access: { const: true },
184
+ settlement: { const: 'external_or_offline_receipt_settlement' },
185
+ proof_anchor: { const: 'content_hash_and_commitment_only' },
186
+ decentralized_storage_claim: { const: false }
187
+ }
188
+ }
189
+ }
190
+ });
191
+
192
+ export function estimateTextTokens(text) {
193
+ if (text === null || text === undefined) return 0;
194
+ const source = String(text);
195
+ let tokens = 0;
196
+ let inAsciiWord = false;
197
+ let asciiWordLength = 0;
198
+
199
+ for (let index = 0; index < source.length; index += 1) {
200
+ const code = source.charCodeAt(index);
201
+ const isAsciiWord = (code >= 48 && code <= 57) || (code >= 65 && code <= 90) || (code >= 97 && code <= 122) || code === 95;
202
+ if (isAsciiWord) {
203
+ inAsciiWord = true;
204
+ asciiWordLength += 1;
205
+ continue;
206
+ }
207
+ if (inAsciiWord) {
208
+ tokens += Math.max(1, Math.ceil(asciiWordLength / 4));
209
+ inAsciiWord = false;
210
+ asciiWordLength = 0;
211
+ }
212
+ if (code > 32) tokens += 1;
213
+ }
214
+
215
+ if (inAsciiWord) tokens += Math.max(1, Math.ceil(asciiWordLength / 4));
216
+ return tokens;
217
+ }
218
+
219
+ export function estimateTokenCost(tokensOrArgs, maybePricePerMillionTokens) {
220
+ const args = isPlainObject(tokensOrArgs)
221
+ ? tokensOrArgs
222
+ : { tokens: tokensOrArgs, price_per_million_tokens: maybePricePerMillionTokens };
223
+ const tokens = nonNegativeInteger(args.tokens ?? args.prompt_tokens ?? args.input_tokens, 'tokens');
224
+ const price = nonNegativeNumber(
225
+ args.price_per_million_tokens ?? args.pricePerMillionTokens ?? args.input_price_per_million_tokens ?? args.inputPricePerMillionTokens,
226
+ 'price_per_million_tokens'
227
+ );
228
+ const currency = stringOrDefault(args.currency, 'USD');
229
+ return Object.freeze({
230
+ tokens,
231
+ currency,
232
+ price_per_million_tokens: price,
233
+ estimated_cost: (tokens / 1_000_000) * price
234
+ });
235
+ }
236
+
237
+ export function createMemoryOptimizationPlan(input = {}) {
238
+ const args = Array.isArray(input) ? { candidates: input } : input;
239
+ if (!isPlainObject(args)) throw new TypeError('createMemoryOptimizationPlan requires an options object or candidate array');
240
+ const candidates = requiredArray(args.candidates, 'candidates');
241
+ const options = normalizePlanOptions(args);
242
+ const inputCandidates = candidates.length;
243
+ const deduped = dedupeCandidates(candidates, options);
244
+ const items = deduped.map((candidate) => planItemFromCandidate(candidate, options));
245
+ items.sort(comparePlanItems);
246
+
247
+ const tiers = { hot: [], warm: [], cold: [], proof_only: [] };
248
+ const basePromptTokens = args.prompt_tokens ?? args.promptTokens ?? args.base_prompt_tokens ?? args.basePromptTokens;
249
+ const sharedPromptTokens = basePromptTokens === undefined
250
+ ? estimateTextTokens(args.prompt ?? args.base_prompt ?? args.basePrompt ?? '')
251
+ : nonNegativeInteger(basePromptTokens, 'prompt_tokens');
252
+ let baselinePromptTokens = sharedPromptTokens;
253
+ let optimizedPromptTokens = sharedPromptTokens;
254
+ for (const item of items) {
255
+ baselinePromptTokens += item.estimated_tokens;
256
+ optimizedPromptTokens += item.optimized_prompt_tokens;
257
+ tiers[item.tier].push(item);
258
+ }
259
+
260
+ const pricing = normalizePricing(args.pricing ?? args.price ?? args.price_per_million_tokens ?? args.pricePerMillionTokens, false);
261
+ const baselineCost = pricing === null ? null : estimateTokenCost({ tokens: baselinePromptTokens, ...pricing }).estimated_cost;
262
+ const optimizedCost = pricing === null ? null : estimateTokenCost({ tokens: optimizedPromptTokens, ...pricing }).estimated_cost;
263
+ const planBody = {
264
+ schema: PLAN_SCHEMA_ID,
265
+ product_thesis: MEMORY_OPTIMIZATION_PRODUCT_THESIS,
266
+ commitment_scheme: 'sha256-canonical-json-v1',
267
+ pricing,
268
+ baseline_prompt_tokens: baselinePromptTokens,
269
+ optimized_prompt_tokens: optimizedPromptTokens,
270
+ baseline_cost: baselineCost,
271
+ optimized_cost: optimizedCost,
272
+ savings_pct: percentReduction(baselinePromptTokens, optimizedPromptTokens),
273
+ tiers,
274
+ items,
275
+ totals: {
276
+ input_candidates: inputCandidates,
277
+ deduped_candidates: items.length,
278
+ duplicates_removed: inputCandidates - items.length,
279
+ total_estimated_tokens: baselinePromptTokens
280
+ }
281
+ };
282
+ const derivedPlanId = `mopt_${sha256Hex(canonicalize(planBody)).slice(0, 32)}`;
283
+ const plan = {
284
+ ...planBody,
285
+ plan_id: normalizePrefixedId(args.plan_id ?? args.planId ?? derivedPlanId, 'mopt', 'plan_id')
286
+ };
287
+ const ordered = orderPlan(plan);
288
+ assertNoRawMemoryOutput(ordered);
289
+ return ordered;
290
+ }
291
+
292
+ export function createMemoryAccessReceipt(input = {}) {
293
+ if (!isPlainObject(input)) throw new TypeError('createMemoryAccessReceipt requires an options object');
294
+ const source = normalizeReceiptSource(input);
295
+ const pricing = normalizePricing(input.pricing ?? input.price ?? input.price_per_million_tokens ?? input.pricePerMillionTokens, false);
296
+ const estimatedTokens = nonNegativeInteger(
297
+ input.estimated_prompt_tokens ?? input.estimatedTokens ?? input.optimized_prompt_tokens ?? source.optimized_prompt_tokens ?? source.estimated_tokens ?? 0,
298
+ 'estimated_prompt_tokens'
299
+ );
300
+ const body = {
301
+ schema: RECEIPT_SCHEMA_ID,
302
+ product_thesis: MEMORY_OPTIMIZATION_PRODUCT_THESIS,
303
+ operation: 'memory.access.receipt_anchor',
304
+ commitment_scheme: 'sha256-canonical-json-v1',
305
+ address: source.address,
306
+ content_hash: source.content_hash,
307
+ commitment: source.commitment ?? commitmentFor({ address: source.address, content_hash: source.content_hash }),
308
+ plan_hash: input.plan_hash ?? input.planHash ?? planHashOrUndefined(input.plan),
309
+ timestamp: input.timestamp ?? input.accessed_at ?? input.accessedAt ?? input.now ?? null,
310
+ sequence: nonNegativeInteger(input.sequence ?? 0, 'sequence'),
311
+ estimated_prompt_tokens: estimatedTokens,
312
+ pricing,
313
+ estimated_cost: pricing === null ? null : estimateTokenCost({ tokens: estimatedTokens, ...pricing }).estimated_cost,
314
+ access_boundary: Object.freeze({
315
+ permissionless_access: true,
316
+ settlement: 'external_or_offline_receipt_settlement',
317
+ proof_anchor: 'content_hash_and_commitment_only',
318
+ decentralized_storage_claim: false
319
+ })
320
+ };
321
+ if (body.plan_hash === undefined) delete body.plan_hash;
322
+ const derivedReceiptId = `mar_${sha256Hex(canonicalize(body)).slice(0, 32)}`;
323
+ const receipt = {
324
+ ...body,
325
+ receipt_id: normalizePrefixedId(input.receipt_id ?? input.receiptId ?? derivedReceiptId, 'mar', 'receipt_id')
326
+ };
327
+ const ordered = orderReceipt(receipt);
328
+ assertNoRawMemoryOutput(ordered);
329
+ return ordered;
330
+ }
331
+
332
+ export function assertNoRawMemoryOutput(value) {
333
+ scanPublicOutput(value, '$', new WeakSet());
334
+ return value;
335
+ }
336
+
337
+ function dedupeCandidates(candidates, options) {
338
+ const byHash = new Map();
339
+ for (let index = 0; index < candidates.length; index += 1) {
340
+ const normalized = normalizeCandidate(candidates[index], index, options);
341
+ const current = byHash.get(normalized.content_hash);
342
+ if (current === undefined || compareCandidatePreference(normalized, current) < 0) {
343
+ byHash.set(normalized.content_hash, normalized);
344
+ }
345
+ }
346
+ return [...byHash.values()];
347
+ }
348
+
349
+ function normalizeCandidate(candidate, index, options) {
350
+ if (!isPlainObject(candidate)) throw new TypeError(`candidate ${index} must be an object`);
351
+ const contentHash = normalizeContentHash(candidate.content_hash ?? candidate.contentHash, candidate.content);
352
+ const address = candidate.address === undefined || candidate.address === null || candidate.address === ''
353
+ ? `mem_${contentHash.slice(SHA256_PREFIX.length, SHA256_PREFIX.length + 16)}`
354
+ : String(candidate.address);
355
+ const metadataCommitment = candidate.metadata === undefined
356
+ ? undefined
357
+ : prefixedSha256(canonicalize(redactForCommitment(candidate.metadata)));
358
+ const estimatedTokens = estimateCandidateTokens(candidate);
359
+ const importance = clamp01(numberOrDefault(candidate.importance, options.defaultImportance));
360
+ const lastAccessedAt = candidate.last_accessed_at ?? candidate.lastAccessedAt ?? null;
361
+ return Object.freeze({
362
+ address,
363
+ content_hash: contentHash,
364
+ metadata_commitment: metadataCommitment,
365
+ estimated_tokens: estimatedTokens,
366
+ importance,
367
+ last_accessed_at: lastAccessedAt === undefined ? null : lastAccessedAt,
368
+ recency_score: recencyScore(lastAccessedAt, options.referenceTimeMs)
369
+ });
370
+ }
371
+
372
+ function planItemFromCandidate(candidate, options) {
373
+ const score = combinedScore(candidate.importance, candidate.recency_score);
374
+ const tier = tierForScore(score, options);
375
+ const body = {
376
+ address: candidate.address,
377
+ content_hash: candidate.content_hash,
378
+ metadata_commitment: candidate.metadata_commitment,
379
+ tier,
380
+ estimated_tokens: candidate.estimated_tokens,
381
+ optimized_prompt_tokens: optimizedTokensForTier(candidate.estimated_tokens, tier, options)
382
+ };
383
+ if (body.metadata_commitment === undefined) delete body.metadata_commitment;
384
+ return Object.freeze({
385
+ ...body,
386
+ commitment: commitmentFor(body)
387
+ });
388
+ }
389
+
390
+ function normalizeReceiptSource(input) {
391
+ const source = input.item ?? input.accessed ?? input.access ?? input.memory ?? input.candidate ?? input;
392
+ if (!isPlainObject(source)) throw new TypeError('receipt source must be an object');
393
+ const contentHash = normalizeContentHash(source.content_hash ?? source.contentHash, source.content);
394
+ const address = requiredString(source.address ?? input.address, 'address');
395
+ const commitment = source.commitment ?? input.commitment;
396
+ return {
397
+ ...source,
398
+ address,
399
+ content_hash: contentHash,
400
+ commitment: commitment === undefined ? undefined : normalizeSha256Root(commitment, 'commitment')
401
+ };
402
+ }
403
+
404
+ function normalizePlanOptions(args) {
405
+ return Object.freeze({
406
+ defaultImportance: clamp01(numberOrDefault(args.default_importance ?? args.defaultImportance, 0.5)),
407
+ referenceTimeMs: referenceTimeMs(args.reference_time ?? args.referenceTime ?? args.now),
408
+ hotThreshold: clamp01(numberOrDefault(args.hot_threshold ?? args.hotThreshold, 0.72)),
409
+ warmThreshold: clamp01(numberOrDefault(args.warm_threshold ?? args.warmThreshold, 0.45)),
410
+ coldThreshold: clamp01(numberOrDefault(args.cold_threshold ?? args.coldThreshold, 0.2)),
411
+ warmTokenRatio: nonNegativeNumber(args.warm_token_ratio ?? args.warmTokenRatio ?? DEFAULT_WARM_RATIO, 'warm_token_ratio'),
412
+ coldPointerTokens: nonNegativeInteger(args.cold_pointer_tokens ?? args.coldPointerTokens ?? DEFAULT_POINTER_TOKENS, 'cold_pointer_tokens'),
413
+ proofOnlyTokens: nonNegativeInteger(args.proof_only_tokens ?? args.proofOnlyTokens ?? DEFAULT_PROOF_TOKENS, 'proof_only_tokens')
414
+ });
415
+ }
416
+
417
+ function normalizePricing(value, required) {
418
+ if (value === undefined || value === null) {
419
+ if (required) throw new TypeError('pricing requires price_per_million_tokens');
420
+ return null;
421
+ }
422
+ if (typeof value === 'number') {
423
+ return Object.freeze({ currency: 'USD', price_per_million_tokens: nonNegativeNumber(value, 'price_per_million_tokens') });
424
+ }
425
+ if (!isPlainObject(value)) throw new TypeError('pricing must be an object or number');
426
+ return Object.freeze({
427
+ currency: stringOrDefault(value.currency, 'USD'),
428
+ price_per_million_tokens: nonNegativeNumber(
429
+ value.price_per_million_tokens ?? value.pricePerMillionTokens ?? value.input_price_per_million_tokens ?? value.inputPricePerMillionTokens,
430
+ 'price_per_million_tokens'
431
+ )
432
+ });
433
+ }
434
+
435
+ function estimateCandidateTokens(candidate) {
436
+ const explicit = candidate.estimated_tokens ?? candidate.estimatedTokens ?? candidate.token_count ?? candidate.tokenCount ?? candidate.metadata?.estimated_tokens ?? candidate.metadata?.token_count;
437
+ if (explicit !== undefined) return nonNegativeInteger(explicit, 'estimated_tokens');
438
+ if (candidate.content !== undefined && candidate.content !== null) return estimateTextTokens(candidate.content);
439
+ return 0;
440
+ }
441
+
442
+ function normalizeContentHash(value, content) {
443
+ if (value !== undefined && value !== null && value !== '') return normalizeSha256Root(value, 'content_hash');
444
+ if (content !== undefined && content !== null) return prefixedSha256(String(content));
445
+ throw new TypeError('candidate requires content_hash or local content for hashing');
446
+ }
447
+
448
+ function normalizeSha256Root(value, name) {
449
+ const text = String(value);
450
+ if (!HASH_RE.test(text)) throw new TypeError(`${name} must be a sha256 hash`);
451
+ return text.startsWith(SHA256_PREFIX) ? `${SHA256_PREFIX}${text.slice(SHA256_PREFIX.length).toLowerCase()}` : `${SHA256_PREFIX}${text.toLowerCase()}`;
452
+ }
453
+
454
+ function normalizePrefixedId(value, prefix, name) {
455
+ const text = requiredString(value, name);
456
+ const pattern = new RegExp(`^${prefix}_[a-f0-9]{32}$`);
457
+ if (!pattern.test(text)) throw new TypeError(`${name} must match ${prefix}_[a-f0-9]{32}`);
458
+ return text;
459
+ }
460
+
461
+ function optimizedTokensForTier(tokens, tier, options) {
462
+ if (tier === 'hot') return tokens;
463
+ if (tier === 'warm') return Math.min(tokens, Math.ceil(tokens * options.warmTokenRatio));
464
+ if (tier === 'cold') return Math.min(tokens, options.coldPointerTokens);
465
+ return Math.min(tokens, options.proofOnlyTokens);
466
+ }
467
+
468
+ function tierForScore(score, options) {
469
+ if (score >= options.hotThreshold) return 'hot';
470
+ if (score >= options.warmThreshold) return 'warm';
471
+ if (score >= options.coldThreshold) return 'cold';
472
+ return 'proof_only';
473
+ }
474
+
475
+ function combinedScore(importance, recency) {
476
+ return clamp01((importance * 0.7) + (recency * 0.3));
477
+ }
478
+
479
+ function recencyScore(value, referenceTime) {
480
+ if (value === null || value === undefined || value === '') return 0;
481
+ const accessed = Date.parse(String(value));
482
+ if (!Number.isFinite(accessed)) return 0;
483
+ const ageMs = Math.max(0, referenceTime - accessed);
484
+ const ageDays = ageMs / 86_400_000;
485
+ if (ageDays <= 1) return 1;
486
+ if (ageDays >= 90) return 0;
487
+ return round6(1 - (ageDays / 90));
488
+ }
489
+
490
+ function referenceTimeMs(value) {
491
+ if (value === undefined || value === null || value === '') return Date.UTC(2026, 0, 1, 0, 0, 0, 0);
492
+ const parsed = Date.parse(String(value));
493
+ if (!Number.isFinite(parsed)) throw new TypeError('reference_time must be an ISO timestamp');
494
+ return parsed;
495
+ }
496
+
497
+ function compareCandidatePreference(left, right) {
498
+ const leftScore = combinedScore(left.importance, left.recency_score);
499
+ const rightScore = combinedScore(right.importance, right.recency_score);
500
+ if (leftScore !== rightScore) return rightScore - leftScore;
501
+ if (left.estimated_tokens !== right.estimated_tokens) return right.estimated_tokens - left.estimated_tokens;
502
+ return compareStrings(left.address, right.address);
503
+ }
504
+
505
+ function comparePlanItems(left, right) {
506
+ const tierDiff = TIER_RANK[left.tier] - TIER_RANK[right.tier];
507
+ if (tierDiff !== 0) return tierDiff;
508
+ if (left.optimized_prompt_tokens !== right.optimized_prompt_tokens) return right.optimized_prompt_tokens - left.optimized_prompt_tokens;
509
+ if (left.estimated_tokens !== right.estimated_tokens) return right.estimated_tokens - left.estimated_tokens;
510
+ return compareStrings(left.content_hash, right.content_hash);
511
+ }
512
+
513
+ function planHashOrUndefined(plan) {
514
+ if (plan === undefined || plan === null) return undefined;
515
+ if (typeof plan === 'string') return normalizeSha256Root(plan, 'plan_hash');
516
+ return prefixedSha256(canonicalize(plan));
517
+ }
518
+
519
+ function commitmentFor(value) {
520
+ return prefixedSha256(canonicalize(value));
521
+ }
522
+
523
+ function prefixedSha256(value) {
524
+ return `${SHA256_PREFIX}${sha256Hex(value)}`;
525
+ }
526
+
527
+ function sha256Hex(value) {
528
+ return createHash('sha256').update(String(value)).digest('hex');
529
+ }
530
+
531
+ function canonicalize(value) {
532
+ return canonicalizeValue(value, new WeakSet());
533
+ }
534
+
535
+ function canonicalizeValue(value, seen) {
536
+ if (value === null) return 'null';
537
+ if (typeof value === 'string') return JSON.stringify(value);
538
+ if (typeof value === 'number') {
539
+ if (!Number.isFinite(value)) throw new TypeError('canonical JSON cannot encode non-finite numbers');
540
+ return JSON.stringify(Object.is(value, -0) ? 0 : value);
541
+ }
542
+ if (typeof value === 'boolean') return value ? 'true' : 'false';
543
+ if (typeof value !== 'object') throw new TypeError(`canonical JSON cannot encode ${typeof value}`);
544
+ if (seen.has(value)) throw new TypeError('canonical JSON cannot encode circular structures');
545
+ seen.add(value);
546
+ try {
547
+ if (Array.isArray(value)) {
548
+ const out = new Array(value.length);
549
+ for (let index = 0; index < value.length; index += 1) {
550
+ if (!Object.prototype.hasOwnProperty.call(value, index)) throw new TypeError('canonical JSON cannot encode sparse arrays');
551
+ out[index] = canonicalizeValue(value[index], seen);
552
+ }
553
+ return `[${out.join(',')}]`;
554
+ }
555
+ if (!isPlainObject(value)) throw new TypeError('canonical JSON only accepts plain objects, arrays, and primitives');
556
+ const keys = Object.keys(value).sort();
557
+ const out = new Array(keys.length);
558
+ for (let index = 0; index < keys.length; index += 1) {
559
+ const key = keys[index];
560
+ if (value[key] === undefined) throw new TypeError('canonical JSON cannot encode undefined');
561
+ out[index] = `${JSON.stringify(key)}:${canonicalizeValue(value[key], seen)}`;
562
+ }
563
+ return `{${out.join(',')}}`;
564
+ } finally {
565
+ seen.delete(value);
566
+ }
567
+ }
568
+
569
+ function redactForCommitment(value) {
570
+ if (value === null || typeof value !== 'object') return value;
571
+ if (Array.isArray(value)) return value.map((item) => redactForCommitment(item));
572
+ if (!isPlainObject(value)) return String(value);
573
+ const out = {};
574
+ for (const key of Object.keys(value).sort()) {
575
+ const normalized = normalizePublicKey(key);
576
+ if (DISALLOWED_PUBLIC_KEYS.has(normalized) && !SAFE_PUBLIC_KEYS.has(normalized)) {
577
+ out[key] = prefixedSha256(canonicalize(value[key]));
578
+ } else {
579
+ out[key] = redactForCommitment(value[key]);
580
+ }
581
+ }
582
+ return out;
583
+ }
584
+
585
+ function scanPublicOutput(value, path, seen) {
586
+ if (value === null || value === undefined) return;
587
+ if (typeof value !== 'object') return;
588
+ if (seen.has(value)) throw new TypeError('public output cannot be circular');
589
+ seen.add(value);
590
+ try {
591
+ if (Array.isArray(value)) {
592
+ for (let index = 0; index < value.length; index += 1) scanPublicOutput(value[index], `${path}[${index}]`, seen);
593
+ return;
594
+ }
595
+ if (!isPlainObject(value)) throw new TypeError(`public output contains unsupported object at ${path}`);
596
+ for (const [key, child] of Object.entries(value)) {
597
+ const normalized = normalizePublicKey(key);
598
+ if (DISALLOWED_PUBLIC_KEYS.has(normalized) && !SAFE_PUBLIC_KEYS.has(normalized)) {
599
+ throw new TypeError(`public output contains raw memory field at ${path}.${key}`);
600
+ }
601
+ scanPublicOutput(child, `${path}.${key}`, seen);
602
+ }
603
+ } finally {
604
+ seen.delete(value);
605
+ }
606
+ }
607
+
608
+ function normalizePublicKey(key) {
609
+ return String(key).replace(/([a-z0-9])([A-Z])/g, '$1_$2').replace(/[^a-zA-Z0-9]+/g, '_').replace(/^_+|_+$/g, '').toLowerCase();
610
+ }
611
+
612
+ function orderPlan(plan) {
613
+ return Object.freeze({
614
+ schema: plan.schema,
615
+ product_thesis: plan.product_thesis,
616
+ plan_id: plan.plan_id,
617
+ commitment_scheme: plan.commitment_scheme,
618
+ pricing: plan.pricing,
619
+ baseline_prompt_tokens: plan.baseline_prompt_tokens,
620
+ optimized_prompt_tokens: plan.optimized_prompt_tokens,
621
+ baseline_cost: plan.baseline_cost,
622
+ optimized_cost: plan.optimized_cost,
623
+ savings_pct: plan.savings_pct,
624
+ tiers: plan.tiers,
625
+ items: plan.items,
626
+ totals: plan.totals
627
+ });
628
+ }
629
+
630
+ function orderReceipt(receipt) {
631
+ const out = {
632
+ schema: receipt.schema,
633
+ product_thesis: receipt.product_thesis,
634
+ receipt_id: receipt.receipt_id,
635
+ operation: receipt.operation,
636
+ commitment_scheme: receipt.commitment_scheme,
637
+ address: receipt.address,
638
+ content_hash: receipt.content_hash,
639
+ commitment: receipt.commitment
640
+ };
641
+ if (receipt.plan_hash !== undefined) out.plan_hash = receipt.plan_hash;
642
+ out.timestamp = receipt.timestamp;
643
+ out.sequence = receipt.sequence;
644
+ out.estimated_prompt_tokens = receipt.estimated_prompt_tokens;
645
+ out.pricing = receipt.pricing;
646
+ out.estimated_cost = receipt.estimated_cost;
647
+ out.access_boundary = receipt.access_boundary;
648
+ return Object.freeze(out);
649
+ }
650
+
651
+ function percentReduction(baseline, optimized) {
652
+ if (baseline === 0) return 0;
653
+ return round6(Math.max(0, Math.min(100, ((baseline - optimized) / baseline) * 100)));
654
+ }
655
+
656
+
657
+ function round6(value) {
658
+ return Math.round((value + Number.EPSILON) * 1_000_000) / 1_000_000;
659
+ }
660
+
661
+ function clamp01(value) {
662
+ return Math.max(0, Math.min(1, value));
663
+ }
664
+
665
+ function numberOrDefault(value, fallback) {
666
+ if (value === undefined || value === null || value === '') return fallback;
667
+ const number = Number(value);
668
+ if (!Number.isFinite(number)) throw new TypeError('value must be a finite number');
669
+ return number;
670
+ }
671
+
672
+ function nonNegativeInteger(value, name) {
673
+ const number = Number(value);
674
+ if (!Number.isInteger(number) || number < 0) throw new TypeError(`${name} must be a non-negative integer`);
675
+ return number;
676
+ }
677
+
678
+ function nonNegativeNumber(value, name) {
679
+ const number = Number(value);
680
+ if (!Number.isFinite(number) || number < 0) throw new TypeError(`${name} must be a non-negative number`);
681
+ return number;
682
+ }
683
+
684
+ function requiredArray(value, name) {
685
+ if (!Array.isArray(value)) throw new TypeError(`${name} must be an array`);
686
+ return value;
687
+ }
688
+
689
+ function requiredString(value, name) {
690
+ if (typeof value !== 'string' || value.length === 0) throw new TypeError(`${name} must be a non-empty string`);
691
+ return value;
692
+ }
693
+
694
+ function stringOrDefault(value, fallback) {
695
+ if (value === undefined || value === null || value === '') return fallback;
696
+ return String(value);
697
+ }
698
+
699
+ function isPlainObject(value) {
700
+ if (value === null || typeof value !== 'object' || Array.isArray(value)) return false;
701
+ const prototype = Object.getPrototypeOf(value);
702
+ return prototype === Object.prototype || prototype === null;
703
+ }
704
+
705
+ function compareStrings(left, right) {
706
+ return left < right ? -1 : left > right ? 1 : 0;
707
+ }