enigma-memory 0.1.18 → 0.1.22

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 (276) hide show
  1. package/README.md +76 -24
  2. package/apps/cli/bin/enigma-desktop.mjs +140 -0
  3. package/apps/cli/bin/enigma-terminal.mjs +78 -0
  4. package/apps/cli/bin/enigma.mjs +1923 -285
  5. package/apps/desktop/electron-main.cjs +217 -0
  6. package/apps/desktop/package.json +12 -0
  7. package/apps/desktop/src/app.js +264 -7
  8. package/apps/desktop/src/index.html +3514 -1373
  9. package/apps/desktop/src/launch-electron.mjs +51 -0
  10. package/apps/desktop/src/server.mjs +2914 -0
  11. package/apps/desktop/src/styles.css +2972 -260
  12. package/apps/desktop/src/zk-browser-prove.mjs +53 -0
  13. package/apps/desktop/src/zk-state.mjs +1789 -0
  14. package/apps/gateway/bin/enigma-gateway.mjs +102 -5
  15. package/apps/gateway/src/server.mjs +271 -8
  16. package/apps/ios/EnigmaCore/Package.swift +12 -0
  17. package/apps/ios/EnigmaCore/Sources/EnigmaCore/EnigmaAPIClient.swift +227 -0
  18. package/apps/ios/EnigmaCore/Sources/EnigmaCore/Models.swift +278 -0
  19. package/apps/ios/EnigmaCore/Sources/EnigmaCore/PKCE.swift +96 -0
  20. package/apps/ios/EnigmaCore/Sources/EnigmaCore/PrivacyMinimizer.swift +187 -0
  21. package/apps/ios/EnigmaCore/Sources/EnigmaCore/ToolModels.swift +129 -0
  22. package/apps/ios/EnigmaCore/Tests/EnigmaCoreTests/EnigmaCoreTests.swift +42 -0
  23. package/apps/ios/EnigmaIOS/Enigma/AppModel.swift +346 -0
  24. package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AccentColor.colorset/Contents.json +12 -0
  25. package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AppIcon.appiconset/Contents.json +11 -0
  26. package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AppIcon.appiconset/EnigmaAppIcon.png +0 -0
  27. package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/Contents.json +3 -0
  28. package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/LaunchBackground.colorset/Contents.json +12 -0
  29. package/apps/ios/EnigmaIOS/Enigma/ChatView.swift +181 -0
  30. package/apps/ios/EnigmaIOS/Enigma/CouncilView.swift +78 -0
  31. package/apps/ios/EnigmaIOS/Enigma/CreateView.swift +152 -0
  32. package/apps/ios/EnigmaIOS/Enigma/EnigmaApp.swift +52 -0
  33. package/apps/ios/EnigmaIOS/Enigma/Info.plist +52 -0
  34. package/apps/ios/EnigmaIOS/Enigma/NaturalLanguagePrivacyTagger.swift +26 -0
  35. package/apps/ios/EnigmaIOS/Enigma/OAuthClient.swift +321 -0
  36. package/apps/ios/EnigmaIOS/Enigma/OnboardingView.swift +105 -0
  37. package/apps/ios/EnigmaIOS/Enigma/PrivateVaultView.swift +275 -0
  38. package/apps/ios/EnigmaIOS/Enigma/SecureStore.swift +76 -0
  39. package/apps/ios/EnigmaIOS/Enigma/SettingsView.swift +60 -0
  40. package/apps/ios/EnigmaIOS/Enigma/Theme.swift +80 -0
  41. package/apps/ios/EnigmaIOS/EnigmaIOS.xcodeproj/project.pbxproj +211 -0
  42. package/apps/ios/EnigmaIOS/EnigmaIOS.xcodeproj/xcshareddata/xcschemes/Enigma.xcscheme +23 -0
  43. package/apps/native-host/README.md +19 -8
  44. package/apps/native-host/bin/enigma-native-host.mjs +229 -13
  45. package/apps/relay/bin/enigma-relay.mjs +103 -5
  46. package/apps/relay/src/federation-runtime.mjs +618 -0
  47. package/apps/relay/src/server.mjs +310 -9
  48. package/apps/verifier/bin/enigma-verify.mjs +327 -11
  49. package/cortex-v3/circuits/build/intent_vk_bytes.json +35 -0
  50. package/cortex-v3/circuits/build/sale_vk_bytes.json +35 -0
  51. package/cortex-v3/circuits/build/vk_bytes.json +32 -0
  52. package/cortex-v3/proving-assets.json +64 -0
  53. package/cortex-v3/zk/BUILD-CONTRACT.md +87 -0
  54. package/cortex-v3/zk/action-transition-vk.json +119 -0
  55. package/cortex-v3/zk/alias-adversarial.test.mjs +220 -0
  56. package/cortex-v3/zk/groth16-verify-child.mjs +17 -0
  57. package/cortex-v3/zk/intent-witness.mjs +365 -0
  58. package/cortex-v3/zk/intent-witness.test.mjs +485 -0
  59. package/cortex-v3/zk/proving-assets.mjs +203 -0
  60. package/cortex-v3/zk/sale-witness.mjs +783 -0
  61. package/cortex-v3/zk/sale-witness.test.mjs +784 -0
  62. package/cortex-v3/zk/sealed-sale-release-vk.json +119 -0
  63. package/cortex-v3/zk/settlement-evidence.mjs +722 -0
  64. package/cortex-v3/zk/setup-intent.mjs +688 -0
  65. package/cortex-v3/zk/setup-sale.mjs +666 -0
  66. package/cortex-v3/zk/setup.mjs +594 -0
  67. package/cortex-v3/zk/witness.mjs +184 -0
  68. package/cortex-v3/zk/zk-codec.mjs +232 -0
  69. package/cortex-v3/zk/zk-codec.test.mjs +293 -0
  70. package/cortex-v3/zk/zk-settle.mjs +370 -0
  71. package/cortex-v3/zk/zk-tree.mjs +256 -0
  72. package/cortex-v3/zk/zk-tree.test.mjs +419 -0
  73. package/deploy/docker-compose.local-production-simulation.yml +36 -0
  74. package/docs/browser-extension-install.md +8 -6
  75. package/docs/client-connectors.md +15 -11
  76. package/docs/developer-ecosystem.md +15 -13
  77. package/docs/enigma-memory-ready-conformance.md +11 -9
  78. package/docs/install-anywhere.md +61 -28
  79. package/docs/installers-and-desktop.md +8 -7
  80. package/docs/novelty-invention-candidates.md +161 -161
  81. package/docs/proof-network-claim-boundaries.md +320 -318
  82. package/examples/01-quickstart-agent/index.mjs +49 -0
  83. package/examples/01_agent_memory_quickstart.mjs +57 -0
  84. package/examples/02-multi-agent-swarm/index.mjs +57 -0
  85. package/examples/02_cross_model_passport.mjs +64 -0
  86. package/examples/03-langchain-memory/index.mjs +41 -0
  87. package/examples/03_poseidon_commitment_verification.mjs +71 -0
  88. package/examples/04-python-trading-agent/trader.py +49 -0
  89. package/examples/README.md +27 -0
  90. package/examples/ci/github-actions.yml +7 -2
  91. package/package.json +142 -11
  92. package/packages/adapters/PACKAGE_CONTRACT.md +1 -1
  93. package/packages/connectors/src/index.js +196 -4
  94. package/packages/connectors/swarm-router.mjs +168 -0
  95. package/packages/core/src/index.js +248 -1
  96. package/packages/core/src/version.mjs +7 -0
  97. package/packages/dev-tools/package.json +19 -0
  98. package/packages/dev-tools/src/index.js +4 -0
  99. package/packages/dev-tools/src/memory-benchmark-suite.js +112 -0
  100. package/packages/dev-tools/src/swarm-simulator.js +101 -0
  101. package/packages/dev-tools/src/vault-inspector.js +114 -0
  102. package/packages/dev-tools/src/vector-benchmark.js +100 -0
  103. package/packages/developer-platform/src/access-credentials.js +341 -0
  104. package/packages/developer-platform/src/http.js +132 -0
  105. package/packages/developer-platform/src/index.js +4 -0
  106. package/packages/developer-platform/src/usage-http.js +60 -0
  107. package/packages/developer-platform/src/usage.js +295 -0
  108. package/packages/enclave-runtime/attestation.mjs +159 -0
  109. package/packages/enclave-runtime/index.mjs +47 -0
  110. package/packages/enclave-runtime/session-manager.mjs +253 -0
  111. package/packages/enclave-runtime/zeroization-proof.mjs +227 -0
  112. package/packages/enigma-reflex/package.json +14 -0
  113. package/packages/enigma-reflex/src/index.js +204 -0
  114. package/packages/enigma-reflex/training/generate-dataset.mjs +40 -0
  115. package/packages/enigma-reflex/training/requirements.txt +8 -0
  116. package/packages/enigma-reflex/training/train.py +314 -0
  117. package/packages/enigma-weave/LICENSE +22 -0
  118. package/packages/enigma-weave/UPSTREAM.json +21 -0
  119. package/packages/enigma-weave/package.json +14 -0
  120. package/packages/enigma-weave/src/index.js +286 -0
  121. package/packages/hosted-cloud/src/index.js +80 -5
  122. package/packages/importers/src/index.js +432 -0
  123. package/packages/inference-runtime/src/browser.js +401 -0
  124. package/packages/inference-runtime/src/chat.js +265 -0
  125. package/packages/inference-runtime/src/code.js +407 -0
  126. package/packages/inference-runtime/src/contracts.js +162 -0
  127. package/packages/inference-runtime/src/http.js +232 -0
  128. package/packages/inference-runtime/src/image.js +186 -0
  129. package/packages/inference-runtime/src/index.js +10 -0
  130. package/packages/inference-runtime/src/model-router.js +320 -0
  131. package/packages/inference-runtime/src/platform.js +125 -0
  132. package/packages/inference-runtime/src/privacy.js +400 -0
  133. package/packages/inference-runtime/src/video.js +253 -0
  134. package/packages/mcp-server/README.md +22 -6
  135. package/packages/mcp-server/bin/enigma-mcp.mjs +2 -1
  136. package/packages/mcp-server/src/index.js +1418 -105
  137. package/packages/mcp-server/src/oauth.js +561 -0
  138. package/packages/mcp-server/src/private-handoff.js +84 -0
  139. package/packages/mcp-server/src/remote-http.js +273 -0
  140. package/packages/mcp-server/src/remote-policy.js +72 -0
  141. package/packages/mcp-server/swarm-bridge.mjs +361 -0
  142. package/packages/mesh/index.d.ts +283 -0
  143. package/packages/mesh/package.json +23 -0
  144. package/packages/mesh/src/crypto.js +189 -0
  145. package/packages/mesh/src/federation-packets.js +353 -0
  146. package/packages/mesh/src/gossip.js +311 -0
  147. package/packages/mesh/src/index.js +6 -0
  148. package/packages/mesh/src/protocol.js +255 -0
  149. package/packages/mesh/src/router.js +279 -0
  150. package/packages/mesh/src/transport.js +306 -0
  151. package/packages/passport/src/index.js +426 -1
  152. package/packages/private-economy/src/credits-http.js +100 -0
  153. package/packages/private-economy/src/credits.js +447 -0
  154. package/packages/private-economy/src/index.js +5 -0
  155. package/packages/private-economy/src/payments-http.js +120 -0
  156. package/packages/private-economy/src/payments.js +509 -0
  157. package/packages/private-economy/src/x402.js +346 -0
  158. package/packages/proof-network/PACKAGE_CONTRACT.md +21 -0
  159. package/packages/rag/index.d.ts +182 -0
  160. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/THIRD_PARTY_LICENSES.txt +207 -0
  161. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/config.json +25 -0
  162. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/onnx/model_quantized.onnx +0 -0
  163. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/sha256-manifest.json +28 -0
  164. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/tokenizer.json +30686 -0
  165. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/tokenizer_config.json +15 -0
  166. package/packages/rag/package.json +27 -0
  167. package/packages/rag/src/blinded-search.js +109 -0
  168. package/packages/rag/src/bm25.js +169 -0
  169. package/packages/rag/src/embeddings.js +459 -0
  170. package/packages/rag/src/hybrid.js +76 -0
  171. package/packages/rag/src/index.js +38 -0
  172. package/packages/rag/src/reranker.js +61 -0
  173. package/packages/rag/src/research.js +107 -0
  174. package/packages/rag/src/vector-store.js +430 -0
  175. package/packages/rag/src/verify-model-artifacts.mjs +4 -0
  176. package/packages/sdk/index.d.ts +760 -0
  177. package/packages/sdk/package.json +33 -0
  178. package/packages/sdk/python/README.md +24 -0
  179. package/packages/sdk/python/enigma_sdk.py +250 -0
  180. package/packages/sdk/python/pyproject.toml +34 -0
  181. package/packages/sdk/python/requirements.txt +1 -0
  182. package/packages/sdk/python/setup.py +20 -0
  183. package/packages/sdk/src/federation/capability-grant.js +389 -0
  184. package/packages/sdk/src/federation/federation-router.js +360 -0
  185. package/packages/sdk/src/federation/ghostmesh-bridge.js +497 -0
  186. package/packages/sdk/src/federation/index.js +3 -0
  187. package/packages/sdk/src/index.js +1796 -0
  188. package/packages/sdk/src/intelligence/contradiction.js +337 -0
  189. package/packages/sdk/src/intelligence/decision-engine.js +155 -0
  190. package/packages/sdk/src/intelligence/index.js +4 -0
  191. package/packages/sdk/src/intelligence/ontology.js +122 -0
  192. package/packages/sdk/src/intelligence/temporal.js +123 -0
  193. package/packages/sdk/src/market-client.js +142 -0
  194. package/packages/sdk/src/mesh-client.js +110 -0
  195. package/packages/sdk/src/middleware/index.js +3 -0
  196. package/packages/sdk/src/middleware/langchain.js +159 -0
  197. package/packages/sdk/src/middleware/llamaindex.js +101 -0
  198. package/packages/sdk/src/middleware/vercel-ai.js +112 -0
  199. package/packages/sdk/src/rag-client.js +85 -0
  200. package/packages/sdk/src/swarm-orchestrator.js +260 -0
  201. package/packages/settlement/PACKAGE_CONTRACT.md +1 -1
  202. package/packages/snapcompact/THIRD_PARTY_LICENSES.txt +40 -0
  203. package/packages/snapcompact/assets/8x13-latin1.bdf +3837 -0
  204. package/packages/snapcompact/index.d.ts +284 -0
  205. package/packages/snapcompact/package.json +25 -0
  206. package/packages/snapcompact/src/index.js +716 -0
  207. package/packages/storage/PACKAGE_CONTRACT.md +1 -1
  208. package/packages/terminal-console/animations.mjs +240 -0
  209. package/packages/terminal-console/auto-anchor.mjs +220 -0
  210. package/packages/terminal-console/banner.mjs +91 -0
  211. package/packages/terminal-console/commands.mjs +459 -0
  212. package/packages/terminal-console/delegation.mjs +152 -0
  213. package/packages/terminal-console/index.mjs +5 -0
  214. package/packages/terminal-console/outbox.mjs +143 -0
  215. package/packages/terminal-console/phantom-bridge.mjs +637 -0
  216. package/packages/terminal-console/repl.mjs +136 -0
  217. package/packages/terminal-console/signer-store.mjs +130 -0
  218. package/packages/terminal-console/solana-rpc.mjs +214 -0
  219. package/packages/terminal-console/solana-transport.mjs +189 -0
  220. package/packages/terminal-tui/dashboard.mjs +214 -0
  221. package/packages/terminal-tui/index.mjs +28 -0
  222. package/packages/terminal-tui/merkle-tree-renderer.mjs +268 -0
  223. package/packages/terminal-tui/telemetry-hud.mjs +137 -0
  224. package/packages/vault/index.d.ts +449 -0
  225. package/packages/vault/package.json +27 -0
  226. package/packages/vault/src/e2ee.mjs +393 -0
  227. package/packages/vault/src/enclave.js +481 -0
  228. package/packages/vault/src/erasure.js +207 -0
  229. package/packages/vault/src/index.js +1018 -155
  230. package/packages/vault/src/persistence.js +307 -0
  231. package/packages/vault/src/poseidon.js +354 -0
  232. package/packages/vault/src/receipt.js +459 -0
  233. package/scripts/benchmark-optical-context.mjs +166 -0
  234. package/scripts/bootstrap-enigma.mjs +502 -0
  235. package/scripts/build-edge-backend-workers.mjs +20 -5
  236. package/scripts/build-goal-completion-audit.mjs +72 -25
  237. package/scripts/build-hosted-api-key-lifecycle.mjs +26 -8
  238. package/scripts/build-hosted-customer-lifecycle.mjs +20 -3
  239. package/scripts/build-hosted-probe-worker.mjs +19 -4
  240. package/scripts/build-installer-assets.mjs +41 -21
  241. package/scripts/build-operator-evidence-starter.mjs +59 -1
  242. package/scripts/build-production-backend-env-kit.mjs +2 -0
  243. package/scripts/build-production-unblocker.mjs +3 -0
  244. package/scripts/check.mjs +17 -3
  245. package/scripts/collect-hosted-backend-live-evidence.mjs +49 -12
  246. package/scripts/install-enigma-local.mjs +18 -5
  247. package/scripts/release-audit.mjs +65 -109
  248. package/scripts/release-provenance.mjs +6 -0
  249. package/scripts/run-backend-readiness-smoke.mjs +112 -10
  250. package/scripts/scan-secrets.mjs +1 -0
  251. package/scripts/simulate-production-env.mjs +7 -2
  252. package/scripts/validate-hosted-backend-live.mjs +112 -1
  253. package/specs/antibody-pack-v1.schema.json +95 -0
  254. package/specs/antigen-envelope-v1.schema.json +81 -0
  255. package/specs/boundary-manifest-v1.schema.json +35 -35
  256. package/specs/capsule-v1.schema.json +55 -55
  257. package/specs/claim-boundary-manifest-v1.schema.json +22 -22
  258. package/specs/claim-ledger-v1.schema.json +291 -0
  259. package/specs/context-passport-v1.schema.json +59 -0
  260. package/specs/deletion-tombstone-v1.schema.json +26 -26
  261. package/specs/evidence-packet-v1.schema.json +177 -0
  262. package/specs/hosted-backend-live-evidence-v1.schema.json +72 -3
  263. package/specs/immune-scan-report-v1.schema.json +112 -0
  264. package/specs/lifecycle-receipt-log-v1.schema.json +67 -0
  265. package/specs/memory-atom-v1.schema.json +59 -0
  266. package/specs/memory-event-v1.schema.json +42 -42
  267. package/specs/passport-v1.schema.json +50 -50
  268. package/specs/proof-of-non-use-v1.schema.json +65 -0
  269. package/specs/quarantine-record-v1.schema.json +126 -0
  270. package/specs/receipt-v1.schema.json +61 -61
  271. package/specs/state-checkpoint-v1.schema.json +37 -37
  272. package/specs/trust-bundle-v1.schema.json +56 -56
  273. package/specs/trust-card-v1.schema.json +119 -0
  274. package/docs/proof-network-launch-plan.md +0 -421
  275. package/packages/metering/PACKAGE_CONTRACT.md +0 -20
  276. package/scripts/build-ai-orchestration-plan.mjs +0 -248
@@ -0,0 +1,459 @@
1
+ // Enigma Cryptographic Memory Receipt Standard (v2).
2
+ // Provides verifiable, portable, offline-provable state transition receipts
3
+ // with cryptographically hiding commitments, Merkle inclusion/removal proofs,
4
+ // operation-specific state transition consistency witnesses, and Ed25519 digital signatures.
5
+ import crypto from 'node:crypto';
6
+ import { MerkleSet, sha256Hex } from '../../core/src/index.js';
7
+
8
+ export const MEMORY_RECEIPT_SCHEMA = 'enigma.memory_receipt.v2';
9
+
10
+ const ED25519_SPKI_PREFIX = Buffer.from('302a300506032b6570032100', 'hex');
11
+ const ED25519_PKCS8_PREFIX = Buffer.from('302e020100300506032b657004220420', 'hex');
12
+
13
+ /**
14
+ * Computes a cryptographically hiding leaf commitment from a memory plaintext and random blinding factor.
15
+ * Commitment = SHA-256(SHA-256(plaintext) || blinding_factor)
16
+ * @param {string} plaintext
17
+ * @param {Buffer|string} [blindingFactor] - 32-byte cryptographically random blinding factor
18
+ * @returns {{ commitment: string, blindingFactor: string, contentHash: string }}
19
+ */
20
+ export function computeHidingCommitment(plaintext, blindingFactor = null) {
21
+ if (typeof plaintext !== 'string' || plaintext.length === 0) {
22
+ throw new TypeError('plaintext must be a non-empty string');
23
+ }
24
+
25
+ let r;
26
+ if (blindingFactor == null) {
27
+ r = crypto.randomBytes(32);
28
+ } else if (Buffer.isBuffer(blindingFactor)) {
29
+ if (blindingFactor.length !== 32) {
30
+ throw new TypeError(`blindingFactor Buffer must be exactly 32 bytes (received ${blindingFactor.length})`);
31
+ }
32
+ r = blindingFactor;
33
+ } else if (typeof blindingFactor === 'string') {
34
+ if (!/^[0-9a-fA-F]{64}$/.test(blindingFactor)) {
35
+ throw new TypeError('blindingFactor string must be exactly 64 hex characters (32 bytes)');
36
+ }
37
+ r = Buffer.from(blindingFactor, 'hex');
38
+ } else {
39
+ throw new TypeError('blindingFactor must be a 32-byte Buffer, 64-hex string, or null/undefined');
40
+ }
41
+
42
+ const contentHash = crypto.createHash('sha256').update(plaintext, 'utf8').digest('hex');
43
+ const commitment = crypto
44
+ .createHash('sha256')
45
+ .update(Buffer.from(contentHash, 'hex'))
46
+ .update(r)
47
+ .digest('hex');
48
+
49
+ return {
50
+ commitment,
51
+ blindingFactor: r.toString('hex'),
52
+ contentHash,
53
+ };
54
+ }
55
+
56
+ /**
57
+ * Verifies that a plaintext and blinding factor open to the given commitment.
58
+ * @param {string} plaintext
59
+ * @param {string} blindingFactorHex
60
+ * @param {string} expectedCommitmentHex
61
+ * @returns {boolean}
62
+ */
63
+ export function verifyCommitmentOpening(plaintext, blindingFactorHex, expectedCommitmentHex) {
64
+ if (typeof blindingFactorHex !== 'string' || !/^[0-9a-fA-F]{64}$/.test(blindingFactorHex)) {
65
+ return false;
66
+ }
67
+ if (typeof expectedCommitmentHex !== 'string' || !/^[0-9a-fA-F]{64}$/.test(expectedCommitmentHex)) {
68
+ return false;
69
+ }
70
+ try {
71
+ const { commitment } = computeHidingCommitment(plaintext, blindingFactorHex);
72
+ return commitment === expectedCommitmentHex.toLowerCase();
73
+ } catch {
74
+ return false;
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Computes canonical signable string for a memory receipt (excluding signature field).
80
+ * @param {Object} receipt
81
+ * @returns {string}
82
+ */
83
+ export function getReceiptSignablePayload(receipt) {
84
+ return JSON.stringify({
85
+ schema: receipt.schema || MEMORY_RECEIPT_SCHEMA,
86
+ version: receipt.version || 2,
87
+ receipt_id: receipt.receipt_id,
88
+ memory_id: receipt.memory_id,
89
+ operation: receipt.operation,
90
+ commitment: receipt.commitment,
91
+ previous_root: receipt.previous_root,
92
+ new_root: receipt.new_root,
93
+ leaf_index: typeof receipt.leaf_index === 'number' ? receipt.leaf_index : 0,
94
+ timestamp: receipt.timestamp,
95
+ agent_pubkey: receipt.agent_pubkey,
96
+ metadata: receipt.metadata || {},
97
+ });
98
+ }
99
+
100
+ /**
101
+ * Creates and cryptographically signs a portable MemoryReceipt with Merkle state transition consistency.
102
+ * Supports append, revoke, and update operations with mathematical consistency witnesses.
103
+ * @param {Object} params
104
+ * @param {string} params.memoryId - Unique memory atom identifier
105
+ * @param {'append'|'update'|'revoke'} [params.operation='append']
106
+ * @param {string} params.plaintext - Raw memory text (used to derive hiding commitment)
107
+ * @param {Buffer|string} [params.blindingFactor] - Optional custom blinding factor
108
+ * @param {string} [params.previousRoot] - Prior Merkle root hash (must match computed root if priorCommitments given)
109
+ * @param {Array<string>} [params.priorCommitments=[]] - List of prior commitments to compute MerkleSet transition
110
+ * @param {string} [params.priorCommitment] - Required for 'update': the prior commitment being replaced
111
+ * @param {Buffer|string} params.signingSecretKey - 32-byte Ed25519 private key
112
+ * @param {Buffer|string} params.signingPublicKey - 32-byte Ed25519 public key
113
+ * @param {Object} [params.metadata]
114
+ * @returns {{ receipt: Object, opening: { blindingFactor: string, contentHash: string } }}
115
+ */
116
+ export function createMemoryReceipt(params) {
117
+ if (!params.memoryId) throw new Error('memoryId is required');
118
+ if (!params.plaintext) throw new Error('plaintext is required to compute hiding commitment');
119
+ if (!params.signingSecretKey || !params.signingPublicKey) {
120
+ throw new Error('signingSecretKey and signingPublicKey are required');
121
+ }
122
+
123
+ const operation = params.operation || 'append';
124
+ if (!['append', 'update', 'revoke'].includes(operation)) {
125
+ throw new Error(`Unsupported receipt operation: "${operation}". Must be "append", "update", or "revoke".`);
126
+ }
127
+
128
+ // 1. Compute cryptographically hiding commitment
129
+ const { commitment, blindingFactor, contentHash } = computeHidingCommitment(
130
+ params.plaintext,
131
+ params.blindingFactor
132
+ );
133
+
134
+ // 2. Normalize and compute prior Merkle state
135
+ const priorCommitments = (params.priorCommitments || []).map(c => String(c).replace(/^sha256:/, '').toLowerCase());
136
+ const priorSet = new MerkleSet(priorCommitments);
137
+ const computedPreviousRoot = priorSet.root();
138
+ if (params.previousRoot && params.previousRoot !== computedPreviousRoot) {
139
+ throw new Error(`previousRoot mismatch: expected ${computedPreviousRoot}, got ${params.previousRoot}`);
140
+ }
141
+ const previousRoot = computedPreviousRoot;
142
+
143
+ let newCommitments;
144
+ let newSet;
145
+ let newRoot;
146
+ let leafIndex;
147
+ let inclusionProof = null;
148
+ let transitionProof;
149
+
150
+ if (operation === 'append') {
151
+ if (priorCommitments.includes(commitment)) {
152
+ throw new Error(`Cannot append existing commitment: ${commitment}`);
153
+ }
154
+ newCommitments = [...priorCommitments, commitment];
155
+ newSet = new MerkleSet(newCommitments);
156
+ newRoot = newSet.root();
157
+ inclusionProof = newSet.proveMembership(commitment);
158
+ leafIndex = inclusionProof.index;
159
+
160
+ transitionProof = {
161
+ type: 'merkle_set_consistency_witness',
162
+ operation: 'append',
163
+ prior_size: priorCommitments.length,
164
+ new_size: newCommitments.length,
165
+ prior_commitments: priorCommitments,
166
+ };
167
+ } else if (operation === 'revoke') {
168
+ if (!priorCommitments.includes(commitment)) {
169
+ throw new Error(`Cannot revoke commitment not present in prior commitments: ${commitment}`);
170
+ }
171
+ const priorInclusionProof = priorSet.proveMembership(commitment);
172
+ newCommitments = priorCommitments.filter(c => c !== commitment);
173
+ newSet = new MerkleSet(newCommitments);
174
+ newRoot = newSet.root();
175
+ leafIndex = priorInclusionProof.index;
176
+
177
+ let newNonMembershipProof = null;
178
+ if (newCommitments.length > 0) {
179
+ newNonMembershipProof = newSet.proveNonMembership(commitment);
180
+ }
181
+
182
+ transitionProof = {
183
+ type: 'merkle_set_consistency_witness',
184
+ operation: 'revoke',
185
+ prior_size: priorCommitments.length,
186
+ new_size: newCommitments.length,
187
+ prior_commitments: priorCommitments,
188
+ prior_inclusion_proof: priorInclusionProof,
189
+ new_non_membership_proof: newNonMembershipProof,
190
+ };
191
+ } else if (operation === 'update') {
192
+ const priorCommitment = params.priorCommitment
193
+ ? String(params.priorCommitment).replace(/^sha256:/, '').toLowerCase()
194
+ : null;
195
+ if (!priorCommitment || !priorCommitments.includes(priorCommitment)) {
196
+ throw new Error('Update operation requires a valid priorCommitment present in prior commitments');
197
+ }
198
+ const priorInclusionProof = priorSet.proveMembership(priorCommitment);
199
+ newCommitments = priorCommitments.filter(c => c !== priorCommitment).concat(commitment);
200
+ newSet = new MerkleSet(newCommitments);
201
+ newRoot = newSet.root();
202
+ inclusionProof = newSet.proveMembership(commitment);
203
+ leafIndex = inclusionProof.index;
204
+ transitionProof = {
205
+ type: 'merkle_set_consistency_witness',
206
+ operation: 'update',
207
+ prior_size: priorCommitments.length,
208
+ new_size: newCommitments.length,
209
+ prior_commitments: priorCommitments,
210
+ prior_commitment: priorCommitment,
211
+ prior_inclusion_proof: priorInclusionProof,
212
+ };
213
+ }
214
+
215
+ const receiptId = `rcpt_${Date.now()}_${crypto.randomBytes(4).toString('hex')}`;
216
+ const pubHex = Buffer.isBuffer(params.signingPublicKey)
217
+ ? params.signingPublicKey.toString('hex')
218
+ : params.signingPublicKey;
219
+ const privBuf = Buffer.isBuffer(params.signingSecretKey)
220
+ ? params.signingSecretKey
221
+ : Buffer.from(params.signingSecretKey, 'hex');
222
+
223
+ const unsignedReceipt = {
224
+ schema: MEMORY_RECEIPT_SCHEMA,
225
+ version: 2,
226
+ receipt_id: receiptId,
227
+ memory_id: params.memoryId,
228
+ operation,
229
+ commitment,
230
+ previous_root: previousRoot,
231
+ new_root: newRoot,
232
+ leaf_index: leafIndex,
233
+ inclusion_proof: inclusionProof,
234
+ transition_proof: transitionProof,
235
+ timestamp: new Date().toISOString(),
236
+ agent_pubkey: pubHex,
237
+ metadata: params.metadata || {},
238
+ };
239
+
240
+ const signable = getReceiptSignablePayload(unsignedReceipt);
241
+ const der = Buffer.concat([ED25519_PKCS8_PREFIX, privBuf]);
242
+ const privKeyObj = crypto.createPrivateKey({ key: der, format: 'der', type: 'pkcs8' });
243
+ const signature = crypto.sign(null, Buffer.from(signable, 'utf8'), privKeyObj);
244
+
245
+ return {
246
+ receipt: {
247
+ ...unsignedReceipt,
248
+ signature: signature.toString('hex'),
249
+ },
250
+ opening: {
251
+ blindingFactor,
252
+ contentHash,
253
+ },
254
+ };
255
+ }
256
+
257
+ /**
258
+ * Completely offline, zero-dependency verification of a MemoryReceipt.
259
+ * Validates schema, Ed25519 signature, operation-specific Merkle inclusion/removal, state transition consistency, and optional plaintext opening.
260
+ * @param {Object} receipt
261
+ * @param {Object} [options]
262
+ * @param {string} [options.expectedAgentPubkey]
263
+ * @param {string} [options.plaintext] - If provided with blindingFactor, verifies hiding opening
264
+ * @param {string} [options.blindingFactor]
265
+ * @returns {{ ok: boolean, verified: boolean, receipt_id: string, memory_id: string, commitment: string, signatureValid: boolean, inclusionValid: boolean, transitionValid: boolean, openingValid?: boolean, errors: string[] }}
266
+ */
267
+ export function verifyMemoryReceipt(receipt, options = {}) {
268
+ const errors = [];
269
+ if (!receipt || typeof receipt !== 'object') {
270
+ return { ok: false, verified: false, receipt_id: '', memory_id: '', commitment: '', signatureValid: false, inclusionValid: false, transitionValid: false, errors: ['Invalid receipt object'] };
271
+ }
272
+
273
+ if (receipt.schema !== MEMORY_RECEIPT_SCHEMA && receipt.schema !== 'enigma.memory_receipt.v1') {
274
+ errors.push(`Unrecognized receipt schema: ${receipt.schema}`);
275
+ }
276
+ if (!receipt.receipt_id) errors.push('Missing receipt_id');
277
+ if (!receipt.memory_id) errors.push('Missing memory_id');
278
+ const HASH_OR_PREFIX_RE = /^(sha256:)?[0-9a-fA-F]{64}$/;
279
+ if (!receipt.commitment || !/^[0-9a-fA-F]{64}$/.test(receipt.commitment)) errors.push('Invalid 64-hex commitment hash');
280
+ if (!receipt.previous_root || !HASH_OR_PREFIX_RE.test(receipt.previous_root)) errors.push('Invalid previous_root format');
281
+ if (!receipt.new_root || !HASH_OR_PREFIX_RE.test(receipt.new_root)) errors.push('Invalid new_root format');
282
+ if (!receipt.agent_pubkey || !/^[0-9a-fA-F]{64}$/.test(receipt.agent_pubkey)) errors.push('Invalid 64-hex agent_pubkey');
283
+ if (!receipt.signature || !/^[0-9a-fA-F]{128}$/.test(receipt.signature)) errors.push('Invalid 128-hex signature length');
284
+
285
+ const operation = receipt.operation || 'append';
286
+ if (!['append', 'update', 'revoke'].includes(operation)) {
287
+ errors.push(`Invalid receipt operation: ${operation}`);
288
+ }
289
+
290
+ if (options.expectedAgentPubkey && receipt.agent_pubkey !== options.expectedAgentPubkey) {
291
+ errors.push(`agent_pubkey mismatch: expected ${options.expectedAgentPubkey}, got ${receipt.agent_pubkey}`);
292
+ }
293
+
294
+ const normCommitment = String(receipt.commitment || '').replace(/^sha256:/, '').toLowerCase();
295
+
296
+ // 1. Verify Merkle Proof (inclusion for append/update, non-membership / removal for revoke)
297
+ let inclusionValid = false;
298
+ if (operation === 'append' || operation === 'update') {
299
+ if (!receipt.inclusion_proof || typeof receipt.inclusion_proof !== 'object') {
300
+ errors.push(`Missing or invalid Merkle inclusion_proof object for "${operation}" receipt`);
301
+ } else {
302
+ const proof = receipt.inclusion_proof;
303
+ const normProofVal = String(proof.value || '').replace(/^sha256:/, '').toLowerCase();
304
+
305
+ if (normProofVal !== normCommitment) {
306
+ errors.push(`Inclusion proof value substitution detected: proof.value (${proof.value}) does not match receipt.commitment (${receipt.commitment})`);
307
+ }
308
+
309
+ const valid = MerkleSet.verifyMembership(proof, receipt.new_root);
310
+ if (!valid) {
311
+ errors.push(`Merkle inclusion proof verification failed for root ${receipt.new_root}`);
312
+ } else if (normProofVal === normCommitment) {
313
+ if (typeof receipt.leaf_index === 'number' && typeof proof.index === 'number' && receipt.leaf_index !== proof.index) {
314
+ errors.push(`receipt.leaf_index mismatch: receipt signed index ${receipt.leaf_index}, but Merkle membership proof index is ${proof.index}`);
315
+ } else {
316
+ inclusionValid = true;
317
+ }
318
+ }
319
+ }
320
+ } else if (operation === 'revoke') {
321
+ // For revoke, inclusionValid signifies removal correctness
322
+ if (receipt.inclusion_proof !== null && receipt.inclusion_proof !== undefined) {
323
+ errors.push('Revoke receipt must not contain an active inclusion_proof in new_root');
324
+ } else {
325
+ inclusionValid = true;
326
+ }
327
+ }
328
+
329
+ // 2. Verify State Transition Consistency Witness (Operation-Specific)
330
+ let transitionValid = false;
331
+ if (!receipt.transition_proof || typeof receipt.transition_proof !== 'object') {
332
+ errors.push('Missing transition_proof in state transition receipt');
333
+ } else {
334
+ const tp = receipt.transition_proof;
335
+ if (tp.type === 'merkle_set_consistency_witness') {
336
+ if (tp.operation !== operation) {
337
+ errors.push(`Transition proof operation mismatch: receipt specifies "${operation}", witness specifies "${tp.operation}"`);
338
+ } else if (!Array.isArray(tp.prior_commitments)) {
339
+ errors.push('Missing or invalid prior_commitments array in transition_proof');
340
+ } else {
341
+ const priorCommitments = tp.prior_commitments.map(c => String(c).replace(/^sha256:/, '').toLowerCase());
342
+ const priorSet = new MerkleSet(priorCommitments);
343
+ const computedPriorRoot = priorSet.root();
344
+
345
+ if (computedPriorRoot !== receipt.previous_root) {
346
+ errors.push(`State transition root mismatch: recomputed prior root (${computedPriorRoot}) does not match receipt.previous_root (${receipt.previous_root})`);
347
+ } else if (operation === 'append') {
348
+ if (priorCommitments.includes(normCommitment)) {
349
+ errors.push(`State transition violation: appended commitment (${receipt.commitment}) already exists in prior_commitments`);
350
+ } else {
351
+ const expectedNewSet = new MerkleSet([...priorCommitments, normCommitment]);
352
+ const computedNewRoot = expectedNewSet.root();
353
+ if (computedNewRoot !== receipt.new_root) {
354
+ errors.push(`State transition continuity failed: recomputed new root (${computedNewRoot}) does not match receipt.new_root (${receipt.new_root})`);
355
+ } else if (receipt.inclusion_proof?.size !== (priorCommitments.length + 1)) {
356
+ errors.push(`State transition size mismatch: expected size ${priorCommitments.length + 1}, got ${receipt.inclusion_proof?.size}`);
357
+ } else {
358
+ transitionValid = true;
359
+ }
360
+ }
361
+ } else if (operation === 'revoke') {
362
+ if (!priorCommitments.includes(normCommitment)) {
363
+ errors.push(`State transition violation: revoked commitment (${receipt.commitment}) does not exist in prior_commitments`);
364
+ } else if (!tp.prior_inclusion_proof || typeof tp.prior_inclusion_proof !== 'object') {
365
+ errors.push('Missing prior_inclusion_proof in revoke transition_proof');
366
+ } else {
367
+ const priorMemValid = MerkleSet.verifyMembership(tp.prior_inclusion_proof, receipt.previous_root);
368
+ const expectedNewCommitments = priorCommitments.filter(c => c !== normCommitment);
369
+ const expectedNewSet = new MerkleSet(expectedNewCommitments);
370
+ const computedNewRoot = expectedNewSet.root();
371
+
372
+ if (!priorMemValid) {
373
+ errors.push(`Revoke state transition failed: prior_inclusion_proof invalid under previous_root ${receipt.previous_root}`);
374
+ } else if (typeof receipt.leaf_index === 'number' && typeof tp.prior_inclusion_proof?.index === 'number' && receipt.leaf_index !== tp.prior_inclusion_proof.index) {
375
+ errors.push(`receipt.leaf_index mismatch: revoke receipt signed index ${receipt.leaf_index}, but prior Merkle proof index is ${tp.prior_inclusion_proof.index}`);
376
+ } else if (computedNewRoot !== receipt.new_root) {
377
+ errors.push(`Revoke state transition failed: recomputed new root (${computedNewRoot}) does not match receipt.new_root (${receipt.new_root})`);
378
+ } else {
379
+ transitionValid = true;
380
+ }
381
+ }
382
+ } else if (operation === 'update') {
383
+ const priorComm = String(tp.prior_commitment || '').replace(/^sha256:/, '').toLowerCase();
384
+ if (!priorComm || !priorCommitments.includes(priorComm)) {
385
+ errors.push(`Update state transition violation: prior_commitment (${priorComm}) does not exist in prior_commitments`);
386
+ } else if (!tp.prior_inclusion_proof || typeof tp.prior_inclusion_proof !== 'object') {
387
+ errors.push('Missing prior_inclusion_proof in update transition_proof');
388
+ } else {
389
+ const priorMemValid = MerkleSet.verifyMembership(tp.prior_inclusion_proof, receipt.previous_root);
390
+ const expectedNewCommitments = priorCommitments.filter(c => c !== priorComm).concat(normCommitment);
391
+ const expectedNewSet = new MerkleSet(expectedNewCommitments);
392
+ const computedNewRoot = expectedNewSet.root();
393
+
394
+ if (!priorMemValid) {
395
+ errors.push(`Update state transition failed: prior_inclusion_proof invalid under previous_root ${receipt.previous_root}`);
396
+ } else if (computedNewRoot !== receipt.new_root) {
397
+ errors.push(`Update state transition failed: recomputed new root (${computedNewRoot}) does not match receipt.new_root (${receipt.new_root})`);
398
+ } else {
399
+ transitionValid = true;
400
+ }
401
+ }
402
+ }
403
+ }
404
+ } else {
405
+ errors.push(`Unrecognized transition_proof type: ${tp.type}`);
406
+ }
407
+ }
408
+
409
+ // 3. Verify Optional Plaintext & Blinding Factor Opening (must be provided as a pair if either is supplied)
410
+ let openingValid;
411
+ const hasPlaintext = options.plaintext !== undefined && options.plaintext !== null;
412
+ const hasBlindingFactor = options.blindingFactor !== undefined && options.blindingFactor !== null;
413
+
414
+ if (hasPlaintext || hasBlindingFactor) {
415
+ if (!hasPlaintext || !hasBlindingFactor) {
416
+ openingValid = false;
417
+ errors.push('Opening verification requires both plaintext and blindingFactor to be provided together');
418
+ } else {
419
+ openingValid = verifyCommitmentOpening(options.plaintext, options.blindingFactor, receipt.commitment);
420
+ if (!openingValid) {
421
+ errors.push('Provided plaintext and blinding factor do not open to receipt commitment');
422
+ }
423
+ }
424
+ }
425
+ // 4. Verify Cryptographic Ed25519 Signature
426
+ let signatureValid = false;
427
+ try {
428
+ const signable = getReceiptSignablePayload(receipt);
429
+ const pubBuf = Buffer.from(receipt.agent_pubkey, 'hex');
430
+ const der = Buffer.concat([ED25519_SPKI_PREFIX, pubBuf]);
431
+ const pubKeyObj = crypto.createPublicKey({ key: der, format: 'der', type: 'spki' });
432
+ const sigBuf = Buffer.from(receipt.signature, 'hex');
433
+
434
+ signatureValid = crypto.verify(null, Buffer.from(signable, 'utf8'), pubKeyObj, sigBuf);
435
+ if (!signatureValid) {
436
+ errors.push('Cryptographic Ed25519 signature verification failed');
437
+ }
438
+ } catch (err) {
439
+ errors.push(`Signature verification exception: ${err.message}`);
440
+ }
441
+
442
+ const ok = errors.length === 0 && signatureValid && inclusionValid && transitionValid && (openingValid === undefined || openingValid);
443
+
444
+ return {
445
+ ok,
446
+ verified: ok,
447
+ receipt_id: receipt.receipt_id || '',
448
+ memory_id: receipt.memory_id || '',
449
+ operation,
450
+ commitment: receipt.commitment || '',
451
+ previous_root: receipt.previous_root,
452
+ new_root: receipt.new_root,
453
+ signatureValid,
454
+ inclusionValid,
455
+ transitionValid,
456
+ openingValid,
457
+ errors,
458
+ };
459
+ }
@@ -0,0 +1,166 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import process from 'node:process';
5
+ import crypto from 'node:crypto';
6
+
7
+ import {
8
+ countFrames,
9
+ decideContextTransport,
10
+ renderBitmapContext,
11
+ resolveProviderProfile,
12
+ } from '../packages/snapcompact/src/index.js';
13
+
14
+ const CLAIM_BOUNDARY = 'This deterministic transport benchmark reports layout, byte, token-heuristic, and caller-priced cost estimates only. It does not invoke a model and does not measure OCR accuracy, semantic recall, F1, latency, or provider delivery.';
15
+
16
+ function usage() {
17
+ return [
18
+ 'Usage: node scripts/benchmark-optical-context.mjs --fixture <text-file> --profile <json-file>',
19
+ '',
20
+ 'The profile JSON must explicitly provide provider, model, vision, and costs with',
21
+ 'textInputUsdPerMillion and imageInputUsdPerMillion. No credentials are read.',
22
+ ].join('\n');
23
+ }
24
+
25
+ function parseArguments(argv) {
26
+ const parsed = {};
27
+ for (let index = 0; index < argv.length; index += 1) {
28
+ const argument = argv[index];
29
+ if (argument === '--help' || argument === '-h') return { help: true };
30
+ if (argument !== '--fixture' && argument !== '--profile') {
31
+ throw new Error(`Unknown argument: ${argument}`);
32
+ }
33
+ const value = argv[index + 1];
34
+ if (!value || value.startsWith('--')) throw new Error(`${argument} requires a path`);
35
+ parsed[argument.slice(2)] = value;
36
+ index += 1;
37
+ }
38
+ if (!parsed.fixture || !parsed.profile) {
39
+ throw new Error('Both --fixture and --profile are required');
40
+ }
41
+ return parsed;
42
+ }
43
+
44
+ function requireFiniteNonNegative(value, field) {
45
+ if (typeof value !== 'number' || !Number.isFinite(value) || value < 0) {
46
+ throw new Error(`Profile ${field} must be a finite non-negative number`);
47
+ }
48
+ return value;
49
+ }
50
+
51
+ function loadProfile(profilePath) {
52
+ const profile = JSON.parse(fs.readFileSync(profilePath, 'utf8'));
53
+ if (!profile || typeof profile !== 'object' || Array.isArray(profile)) {
54
+ throw new Error('Profile must be a JSON object');
55
+ }
56
+ if (typeof profile.provider !== 'string' || !profile.provider.trim()) {
57
+ throw new Error('Profile provider is required');
58
+ }
59
+ if (typeof profile.model !== 'string' || !profile.model.trim()) {
60
+ throw new Error('Profile model is required');
61
+ }
62
+ if (typeof profile.vision !== 'boolean') {
63
+ throw new Error('Profile vision must be an explicit boolean');
64
+ }
65
+ if (!profile.costs || typeof profile.costs !== 'object') {
66
+ throw new Error('Profile costs are required for a cost decision');
67
+ }
68
+ requireFiniteNonNegative(profile.costs.textInputUsdPerMillion, 'costs.textInputUsdPerMillion');
69
+ requireFiniteNonNegative(profile.costs.imageInputUsdPerMillion, 'costs.imageInputUsdPerMillion');
70
+ for (const field of ['outputUsdPerMillion', 'decodeOutputTokens', 'decodeFixedUsd']) {
71
+ if (profile.costs[field] !== undefined) requireFiniteNonNegative(profile.costs[field], `costs.${field}`);
72
+ }
73
+ const provider = profile.provider.trim();
74
+ const model = profile.model.trim();
75
+ const resolved = resolveProviderProfile(provider, model);
76
+ if (!resolved) {
77
+ throw new Error(`No allowlisted bitmap profile exists for provider "${provider}" and model "${model}"`);
78
+ }
79
+ return { ...profile, provider, model, resolved };
80
+ }
81
+
82
+ function safeDecision(decision) {
83
+ return {
84
+ selected: decision.selected,
85
+ eligible: decision.eligible,
86
+ reason: decision.reason,
87
+ profile: decision.profile,
88
+ expectedReuse: decision.expectedReuse ?? null,
89
+ frameCount: decision.frameCount ?? null,
90
+ estimates: decision.estimates ?? null,
91
+ };
92
+ }
93
+
94
+ function main() {
95
+ const arguments_ = parseArguments(process.argv.slice(2));
96
+ if (arguments_.help) {
97
+ process.stdout.write(`${usage()}\n`);
98
+ return;
99
+ }
100
+ const fixturePath = path.resolve(arguments_.fixture);
101
+ const profilePath = path.resolve(arguments_.profile);
102
+ const source = fs.readFileSync(fixturePath, 'utf8');
103
+ const profile = loadProfile(profilePath);
104
+ const renderOptions = {
105
+ limits: profile.limits,
106
+ tabWidth: profile.tabWidth,
107
+ collapseRepeatedLines: profile.collapseRepeatedLines,
108
+ repetition: profile.repetition,
109
+ };
110
+ const plan = countFrames(source, profile.resolved, renderOptions);
111
+ const decision = decideContextTransport({
112
+ source,
113
+ provider: profile.provider,
114
+ model: profile.model,
115
+ vision: profile.vision,
116
+ costs: profile.costs,
117
+ expectedReuse: profile.expectedReuse,
118
+ tokenEstimates: profile.tokenEstimates,
119
+ ...renderOptions,
120
+ });
121
+
122
+ let rendered;
123
+ try {
124
+ rendered = renderBitmapContext(source, { profile: profile.resolved, ...renderOptions });
125
+ const report = {
126
+ schema: 'enigma.optical_context_benchmark.v1',
127
+ deterministic: true,
128
+ credentialFree: true,
129
+ claimBoundary: CLAIM_BOUNDARY,
130
+ fixture: {
131
+ sha256: crypto.createHash('sha256').update(source, 'utf8').digest('hex'),
132
+ utf8Bytes: Buffer.byteLength(source, 'utf8'),
133
+ characters: source.length,
134
+ },
135
+ profile: {
136
+ id: profile.resolved.id,
137
+ provider: profile.provider,
138
+ model: profile.model,
139
+ vision: profile.vision,
140
+ },
141
+ layout: {
142
+ frames: plan.frameCount,
143
+ totalPixels: plan.pixelCount,
144
+ columns: plan.columns,
145
+ rowsPerFrame: plan.rowsPerFrame,
146
+ },
147
+ bitmap: {
148
+ bytes: rendered.receipt.byteCount,
149
+ frameBytes: rendered.pages.map((page) => page.bytes),
150
+ payloadDigest: rendered.receipt.payloadDigest,
151
+ },
152
+ decision: safeDecision(decision),
153
+ };
154
+ process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
155
+ } finally {
156
+ for (const page of rendered?.pages || []) page.png.fill(0);
157
+ rendered = null;
158
+ }
159
+ }
160
+
161
+ try {
162
+ main();
163
+ } catch (error) {
164
+ process.stderr.write(`Optical context benchmark refused to run: ${error.message}\n\n${usage()}\n`);
165
+ process.exitCode = 1;
166
+ }