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.
- package/LICENSE +55 -0
- package/README.md +379 -0
- package/apps/cli/bin/enigma.mjs +1117 -0
- package/apps/desktop/src/app.js +1327 -0
- package/apps/desktop/src/index.html +1373 -0
- package/apps/desktop/src/styles.css +386 -0
- package/apps/gateway/bin/enigma-gateway.mjs +52 -0
- package/apps/gateway/src/server.mjs +1403 -0
- package/apps/native-host/README.md +265 -0
- package/apps/native-host/bin/enigma-native-host.mjs +499 -0
- package/apps/native-host/manifests/com.enigma.native_host.chrome.json +9 -0
- package/apps/native-host/manifests/com.enigma.native_host.edge.json +9 -0
- package/apps/native-host/manifests/com.enigma.native_host.firefox.json +9 -0
- package/apps/relay/bin/enigma-relay.mjs +52 -0
- package/apps/relay/src/server.mjs +1571 -0
- package/apps/verifier/bin/enigma-verify.mjs +240 -0
- package/deploy/docker-compose.production.example.yml +150 -0
- package/deploy/kubernetes/enigma-backend.example.yaml +580 -0
- package/package.json +196 -0
- package/packages/adapters/PACKAGE_CONTRACT.md +47 -0
- package/packages/adapters/src/index.js +183 -0
- package/packages/boundary/src/index.js +468 -0
- package/packages/connectors/src/index.js +533 -0
- package/packages/core/src/index.js +766 -0
- package/packages/enterprise/src/index.js +505 -0
- package/packages/importers/src/index.js +1083 -0
- package/packages/mcp-server/bin/enigma-mcp.mjs +19 -0
- package/packages/mcp-server/src/index.js +1185 -0
- package/packages/mesh/src/index.js +531 -0
- package/packages/metering/PACKAGE_CONTRACT.md +20 -0
- package/packages/metering/src/index.js +246 -0
- package/packages/optimizer/src/index.js +707 -0
- package/packages/passport/src/index.js +651 -0
- package/packages/settlement/PACKAGE_CONTRACT.md +28 -0
- package/packages/settlement/src/index.js +369 -0
- package/packages/storage/PACKAGE_CONTRACT.md +23 -0
- package/packages/storage/src/index.js +392 -0
- package/packages/vault/src/index.js +904 -0
- package/scripts/build-ai-orchestration-plan.mjs +248 -0
- package/scripts/build-cloudflare-pages-release-packet.mjs +287 -0
- package/scripts/build-cloudflare-token-policy.mjs +239 -0
- package/scripts/build-cloudflare-token-request.mjs +314 -0
- package/scripts/build-demo-assets.mjs +263 -0
- package/scripts/build-edge-backend-workers.mjs +353 -0
- package/scripts/build-goal-completion-audit.mjs +398 -0
- package/scripts/build-hosted-probe-worker.mjs +191 -0
- package/scripts/build-operator-acceptance-packet.mjs +254 -0
- package/scripts/build-operator-evidence-starter.mjs +525 -0
- package/scripts/build-production-backend-env-kit.mjs +384 -0
- package/scripts/build-production-dependency-report.mjs +369 -0
- package/scripts/build-production-handoff-packet.mjs +475 -0
- package/scripts/build-production-readiness-manifest.mjs +209 -0
- package/scripts/build-production-status-board.mjs +297 -0
- package/scripts/build-production-storage-migration.mjs +86 -0
- package/scripts/build-production-workplan.mjs +371 -0
- package/scripts/build-review-packet.mjs +594 -0
- package/scripts/check.mjs +419 -0
- package/scripts/cloudflare-ops.mjs +1672 -0
- package/scripts/cloudflare-secret-env.mjs +128 -0
- package/scripts/collect-hosted-backend-live-evidence.mjs +263 -0
- package/scripts/infrastructure-readiness.mjs +944 -0
- package/scripts/install-enigma-local.mjs +270 -0
- package/scripts/memory-optimization-benchmark.mjs +242 -0
- package/scripts/monitor-live-endpoints.mjs +358 -0
- package/scripts/release-audit.mjs +5588 -0
- package/scripts/release-provenance.mjs +250 -0
- package/scripts/run-backend-readiness-smoke.mjs +220 -0
- package/scripts/validate-backup-restore-drill.mjs +166 -0
- package/scripts/validate-cloudflare-credentials.mjs +112 -0
- package/scripts/validate-cloudflare-worker-inspect.mjs +179 -0
- package/scripts/validate-domain-tls.mjs +248 -0
- package/scripts/validate-hosted-backend-live.mjs +319 -0
- package/scripts/validate-incident-drill.mjs +221 -0
- package/scripts/validate-kms-custody.mjs +235 -0
- package/scripts/validate-legal-compliance-approval.mjs +274 -0
- package/scripts/validate-monitoring-alerting.mjs +263 -0
- package/scripts/validate-network-access-policy.mjs +285 -0
- package/scripts/validate-operator-acceptance.mjs +298 -0
- package/scripts/validate-production-manifests.mjs +325 -0
- package/scripts/validate-public-site-security.mjs +252 -0
- package/scripts/validate-security-threat-model.mjs +285 -0
- package/scripts/validate-service-settlement.mjs +256 -0
- package/scripts/validate-support-sla.mjs +190 -0
- package/scripts/validate-tenant-policy-approval.mjs +228 -0
- package/scripts/validate-usage-metering.mjs +224 -0
- package/scripts/validate-whitepaper-claims.mjs +166 -0
- package/specs/boundary-manifest-v1.schema.json +35 -0
- package/specs/capsule-v1.schema.json +55 -0
- package/specs/claim-boundary-manifest-v1.schema.json +22 -0
- package/specs/connector-profile-v1.schema.json +62 -0
- package/specs/deletion-tombstone-v1.schema.json +26 -0
- package/specs/enterprise-policy-v1.schema.json +59 -0
- package/specs/gateway-request-v1.schema.json +32 -0
- package/specs/goal-completion-audit-v1.schema.json +70 -0
- package/specs/hosted-backend-live-evidence-v1.schema.json +147 -0
- package/specs/import-report-v1.schema.json +214 -0
- package/specs/infrastructure-readiness-manifest-v1.schema.json +130 -0
- package/specs/memory-event-v1.schema.json +42 -0
- package/specs/mesh-node-v1.schema.json +126 -0
- package/specs/passport-v1.schema.json +50 -0
- package/specs/production-handoff-packet-v1.schema.json +149 -0
- package/specs/receipt-v1.schema.json +61 -0
- package/specs/relay-record-v1.schema.json +43 -0
- package/specs/state-checkpoint-v1.schema.json +37 -0
- package/specs/trust-bundle-v1.schema.json +56 -0
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
|
|
3
|
+
export const PERMISSIONLESS_MEMORY_JOB_SCHEMA = 'enigma.permissionless_memory_job.v1';
|
|
4
|
+
export const CONSUMER_GPU_CAPACITY_PROFILE_SCHEMA = 'enigma.consumer_gpu_capacity_profile.v1';
|
|
5
|
+
export const OPERATOR_SERVICE_QUOTE_SCHEMA = 'enigma.operator_service_quote.v1';
|
|
6
|
+
export const SERVICE_SETTLEMENT_RECEIPT_SCHEMA = 'enigma.service_settlement_receipt.v1';
|
|
7
|
+
export const SETTLEMENT_BATCH_SCHEMA = 'enigma.settlement_batch.v1';
|
|
8
|
+
|
|
9
|
+
export const SETTLEMENT_PRODUCT_THESIS = 'Use permissionless rails for access, service accountability, and settlement while keeping raw memory and hot-path optimization centralized or BYOC-controlled.';
|
|
10
|
+
export const CONSUMER_GPU_MEMORY_MARKET_THESIS = 'Use consumer and workstation GPU operators for priced memory-optimization capacity only when they can prove bounded service receipts; do not decentralize raw memory or claim provider-wide discounts without measured evidence.';
|
|
11
|
+
|
|
12
|
+
const SHA256_PREFIX = 'sha256:';
|
|
13
|
+
const ROOT_RE = /^sha256:[a-f0-9]{64}$/;
|
|
14
|
+
const ACCEPTED_JOB_TYPES = new Set(['memory.read', 'memory.write', 'memory.delete', 'context.pack', 'relay.store', 'witness.checkpoint', 'gateway.evaluate']);
|
|
15
|
+
const ACCEPTED_SERVICE_KINDS = new Set(['relay', 'witness', 'gateway', 'memory_optimizer', 'settlement_gateway']);
|
|
16
|
+
const ACCEPTED_ASSETS = new Set(['USD', 'USDC', 'SOL', 'ENIGMA', 'CREDITS']);
|
|
17
|
+
const ACCEPTED_ACCELERATOR_CLASSES = new Set(['consumer_gpu', 'workstation_gpu', 'edge_gpu']);
|
|
18
|
+
const ACCEPTED_MODEL_FAMILIES = new Set(['small-context', 'medium-context', 'long-context', 'embedding', 'reranker', 'memory-optimizer']);
|
|
19
|
+
const FORBIDDEN_KEY_RE = /(?:^|_)(?:raw|plaintext|plain_text|prompt|prompts|message|messages|text|content|document|documents|transcript|response|responses|provider_response|response_body|credential|credentials|api_key|secret|password|private_key|seed|mnemonic)(?:$|_)/iu;
|
|
20
|
+
const SECRET_VALUE_RE = /(?:Bearer\s+[A-Za-z0-9._~+/=-]{12,}|Basic\s+[A-Za-z0-9+/=-]{12,}|-----BEGIN [A-Z ]*PRIVATE KEY-----|https?:\/\/[^\s/@]+:[^\s/@]+@|raw memory|private prompt|full transcript|decrypted capsule|sk-[A-Za-z0-9_-]{16,}|AKIA[0-9A-Z]{16})/iu;
|
|
21
|
+
const SAFE_FIELD_NAMES = new Set(['raw_memory_on_chain', 'raw_memory_in_job', 'raw_memory_in_receipt', 'raw_memory_access_required']);
|
|
22
|
+
|
|
23
|
+
function isPlainObject(value) {
|
|
24
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function canonicalize(value) {
|
|
28
|
+
if (Array.isArray(value)) return value.map(canonicalize);
|
|
29
|
+
if (isPlainObject(value)) {
|
|
30
|
+
const out = {};
|
|
31
|
+
for (const key of Object.keys(value).sort()) out[key] = canonicalize(value[key]);
|
|
32
|
+
return out;
|
|
33
|
+
}
|
|
34
|
+
return value;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function digest(value) {
|
|
38
|
+
return `${SHA256_PREFIX}${createHash('sha256').update(JSON.stringify(canonicalize(value))).digest('hex')}`;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function requiredString(value, field) {
|
|
42
|
+
if (typeof value !== 'string' || value.trim().length === 0) throw new TypeError(`${field} must be a non-empty string`);
|
|
43
|
+
return value.trim();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function optionalString(value, fallback) {
|
|
47
|
+
if (value === undefined || value === null || value === '') return fallback;
|
|
48
|
+
return requiredString(String(value), 'string');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function nonNegativeNumber(value, field) {
|
|
52
|
+
const number = Number(value ?? 0);
|
|
53
|
+
if (!Number.isFinite(number) || number < 0) throw new TypeError(`${field} must be a non-negative number`);
|
|
54
|
+
return number;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function positiveNumber(value, field) {
|
|
58
|
+
const number = Number(value);
|
|
59
|
+
if (!Number.isFinite(number) || number <= 0) throw new TypeError(`${field} must be a positive number`);
|
|
60
|
+
return number;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function positiveInteger(value, field) {
|
|
64
|
+
const number = Number(value);
|
|
65
|
+
if (!Number.isInteger(number) || number <= 0) throw new TypeError(`${field} must be a positive integer`);
|
|
66
|
+
return number;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function boundedStringArray(value, field, { max = 8 } = {}) {
|
|
70
|
+
if (!Array.isArray(value) || value.length === 0 || value.length > max) throw new TypeError(`${field} must be a non-empty array with at most ${max} entries`);
|
|
71
|
+
return Object.freeze(value.map((item, index) => requiredString(item, `${field}[${index}]`)));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function isoTimestamp(value, field, fallback = new Date(0).toISOString()) {
|
|
75
|
+
const timestamp = optionalString(value, fallback);
|
|
76
|
+
if (Number.isNaN(Date.parse(timestamp))) throw new TypeError(`${field} must be ISO-parseable`);
|
|
77
|
+
return timestamp;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function root(value, field) {
|
|
81
|
+
const string = requiredString(value, field);
|
|
82
|
+
if (!ROOT_RE.test(string)) throw new TypeError(`${field} must be a sha256-prefixed digest`);
|
|
83
|
+
return string;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function asset(value, field = 'asset') {
|
|
87
|
+
const string = requiredString(value, field).toUpperCase();
|
|
88
|
+
if (!ACCEPTED_ASSETS.has(string)) throw new TypeError(`${field} is not an accepted settlement asset`);
|
|
89
|
+
return string;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function assertNoSensitivePayload(value, path = 'settlement') {
|
|
93
|
+
if (typeof value === 'string') {
|
|
94
|
+
if (!/\.(claim_boundary\[\d+\]|product_thesis)$/.test(path) && SECRET_VALUE_RE.test(value)) throw new TypeError(`${path} contains secret-looking data`);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (Array.isArray(value)) {
|
|
98
|
+
value.forEach((item, index) => assertNoSensitivePayload(item, `${path}[${index}]`));
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (!isPlainObject(value)) return;
|
|
102
|
+
for (const [key, child] of Object.entries(value)) {
|
|
103
|
+
if (FORBIDDEN_KEY_RE.test(key) && !SAFE_FIELD_NAMES.has(key)) throw new TypeError(`${path}.${key} is not allowed in settlement artifacts`);
|
|
104
|
+
assertNoSensitivePayload(child, `${path}.${key}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function jobIdFrom(body) {
|
|
109
|
+
return `pjob_${digest(body).slice(SHA256_PREFIX.length, SHA256_PREFIX.length + 32)}`;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function quoteIdFrom(body) {
|
|
113
|
+
return `quote_${digest(body).slice(SHA256_PREFIX.length, SHA256_PREFIX.length + 32)}`;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function receiptIdFrom(body) {
|
|
117
|
+
return `settle_${digest(body).slice(SHA256_PREFIX.length, SHA256_PREFIX.length + 32)}`;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function batchIdFrom(body) {
|
|
121
|
+
return `batch_${digest(body).slice(SHA256_PREFIX.length, SHA256_PREFIX.length + 32)}`;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function createPermissionlessMemoryJob(input = {}) {
|
|
125
|
+
if (!isPlainObject(input)) throw new TypeError('createPermissionlessMemoryJob requires an options object');
|
|
126
|
+
assertNoSensitivePayload(input, 'input');
|
|
127
|
+
const jobType = requiredString(input.job_type ?? input.jobType, 'job_type');
|
|
128
|
+
if (!ACCEPTED_JOB_TYPES.has(jobType)) throw new TypeError('job_type is not accepted');
|
|
129
|
+
const maxPriceAmount = positiveNumber(input.max_price_amount ?? input.maxPriceAmount, 'max_price_amount');
|
|
130
|
+
const paymentAsset = asset(input.payment_asset ?? input.paymentAsset, 'payment_asset');
|
|
131
|
+
const body = {
|
|
132
|
+
schema: PERMISSIONLESS_MEMORY_JOB_SCHEMA,
|
|
133
|
+
product_thesis: SETTLEMENT_PRODUCT_THESIS,
|
|
134
|
+
tenant_id: requiredString(input.tenant_id ?? input.tenantId, 'tenant_id'),
|
|
135
|
+
job_type: jobType,
|
|
136
|
+
memory_commitment_root: root(input.memory_commitment_root ?? input.memoryCommitmentRoot, 'memory_commitment_root'),
|
|
137
|
+
policy_hash: root(input.policy_hash ?? input.policyHash, 'policy_hash'),
|
|
138
|
+
usage_event_hash: root(input.usage_event_hash ?? input.usageEventHash, 'usage_event_hash'),
|
|
139
|
+
requested_at: isoTimestamp(input.requested_at ?? input.requestedAt, 'requested_at'),
|
|
140
|
+
expires_at: isoTimestamp(input.expires_at ?? input.expiresAt, 'expires_at', '2100-01-01T00:00:00.000Z'),
|
|
141
|
+
max_price: {
|
|
142
|
+
amount: maxPriceAmount,
|
|
143
|
+
asset: paymentAsset,
|
|
144
|
+
},
|
|
145
|
+
access_boundary: {
|
|
146
|
+
permissionless_submission: true,
|
|
147
|
+
raw_memory_on_chain: false,
|
|
148
|
+
raw_memory_in_job: false,
|
|
149
|
+
centralized_or_byoc_hot_path: true,
|
|
150
|
+
token_roi_claim: false,
|
|
151
|
+
provider_invoice_savings_claim: false,
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
if (Date.parse(body.expires_at) <= Date.parse(body.requested_at)) throw new RangeError('expires_at must be after requested_at');
|
|
155
|
+
const job = Object.freeze({ ...body, job_id: jobIdFrom(body), job_hash: digest(body) });
|
|
156
|
+
assertNoSensitivePayload(job, 'job');
|
|
157
|
+
return job;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function createConsumerGpuCapacityProfile(input = {}) {
|
|
161
|
+
if (!isPlainObject(input)) throw new TypeError('createConsumerGpuCapacityProfile requires an options object');
|
|
162
|
+
assertNoSensitivePayload(input, 'input');
|
|
163
|
+
const acceleratorClass = requiredString(input.accelerator_class ?? input.acceleratorClass, 'accelerator_class');
|
|
164
|
+
if (!ACCEPTED_ACCELERATOR_CLASSES.has(acceleratorClass)) throw new TypeError('accelerator_class is not accepted');
|
|
165
|
+
const modelFamily = requiredString(input.model_family ?? input.modelFamily, 'model_family');
|
|
166
|
+
if (!ACCEPTED_MODEL_FAMILIES.has(modelFamily)) throw new TypeError('model_family is not accepted');
|
|
167
|
+
const priceAmount = positiveNumber(input.price_per_million_context_tokens ?? input.pricePerMillionContextTokens, 'price_per_million_context_tokens');
|
|
168
|
+
const profileAsset = asset(input.asset ?? input.settlement_asset ?? input.settlementAsset, 'asset');
|
|
169
|
+
const body = {
|
|
170
|
+
schema: CONSUMER_GPU_CAPACITY_PROFILE_SCHEMA,
|
|
171
|
+
product_thesis: CONSUMER_GPU_MEMORY_MARKET_THESIS,
|
|
172
|
+
operator_id: requiredString(input.operator_id ?? input.operatorId, 'operator_id'),
|
|
173
|
+
accelerator_class: acceleratorClass,
|
|
174
|
+
hardware_ref: requiredString(input.hardware_ref ?? input.hardwareRef, 'hardware_ref'),
|
|
175
|
+
region: requiredString(input.region, 'region'),
|
|
176
|
+
model_family: modelFamily,
|
|
177
|
+
model_refs: boundedStringArray(input.model_refs ?? input.modelRefs, 'model_refs', { max: 12 }),
|
|
178
|
+
observed_at: isoTimestamp(input.observed_at ?? input.observedAt, 'observed_at'),
|
|
179
|
+
expires_at: isoTimestamp(input.expires_at ?? input.expiresAt, 'expires_at', '2100-01-01T00:00:00.000Z'),
|
|
180
|
+
capacity: {
|
|
181
|
+
vram_gb: positiveNumber(input.vram_gb ?? input.vramGb, 'vram_gb'),
|
|
182
|
+
max_context_window_tokens: positiveInteger(input.max_context_window_tokens ?? input.maxContextWindowTokens, 'max_context_window_tokens'),
|
|
183
|
+
available_context_tokens_per_minute: positiveInteger(input.available_context_tokens_per_minute ?? input.availableContextTokensPerMinute, 'available_context_tokens_per_minute'),
|
|
184
|
+
p95_latency_ms: positiveNumber(input.p95_latency_ms ?? input.p95LatencyMs, 'p95_latency_ms'),
|
|
185
|
+
},
|
|
186
|
+
price_per_million_context_tokens: {
|
|
187
|
+
amount: priceAmount,
|
|
188
|
+
asset: profileAsset,
|
|
189
|
+
},
|
|
190
|
+
service_boundary: {
|
|
191
|
+
permissionless_discovery: true,
|
|
192
|
+
permissionless_settlement: true,
|
|
193
|
+
centralized_operator_hot_path: true,
|
|
194
|
+
raw_memory_access_required: false,
|
|
195
|
+
decentralization_claim: false,
|
|
196
|
+
provider_discount_claim: false,
|
|
197
|
+
measured_receipt_required: true,
|
|
198
|
+
},
|
|
199
|
+
capacity_ref: requiredString(input.capacity_ref ?? input.capacityRef, 'capacity_ref'),
|
|
200
|
+
terms_ref: requiredString(input.terms_ref ?? input.termsRef, 'terms_ref'),
|
|
201
|
+
};
|
|
202
|
+
if (Date.parse(body.expires_at) <= Date.parse(body.observed_at)) throw new RangeError('capacity expires_at must be after observed_at');
|
|
203
|
+
const profile = Object.freeze({ ...body, capacity_profile_hash: digest(body) });
|
|
204
|
+
assertNoSensitivePayload(profile, 'capacity_profile');
|
|
205
|
+
return profile;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export function createOperatorServiceQuote(input = {}) {
|
|
209
|
+
if (!isPlainObject(input)) throw new TypeError('createOperatorServiceQuote requires an options object');
|
|
210
|
+
assertNoSensitivePayload(input, 'input');
|
|
211
|
+
const job = input.job;
|
|
212
|
+
if (!isPlainObject(job) || job.schema !== PERMISSIONLESS_MEMORY_JOB_SCHEMA) throw new TypeError('job must be an Enigma permissionless memory job');
|
|
213
|
+
const serviceKind = requiredString(input.service_kind ?? input.serviceKind, 'service_kind');
|
|
214
|
+
if (!ACCEPTED_SERVICE_KINDS.has(serviceKind)) throw new TypeError('service_kind is not accepted');
|
|
215
|
+
const priceAmount = positiveNumber(input.price_amount ?? input.priceAmount, 'price_amount');
|
|
216
|
+
const quoteAsset = asset(input.asset ?? input.payment_asset ?? input.paymentAsset ?? job.max_price.asset, 'asset');
|
|
217
|
+
if (quoteAsset !== job.max_price.asset) throw new TypeError('quote asset must match job max_price asset');
|
|
218
|
+
if (priceAmount > job.max_price.amount) throw new RangeError('quote price exceeds job max_price');
|
|
219
|
+
const capacityProfile = input.capacity_profile ?? input.capacityProfile ?? null;
|
|
220
|
+
const body = {
|
|
221
|
+
schema: OPERATOR_SERVICE_QUOTE_SCHEMA,
|
|
222
|
+
product_thesis: SETTLEMENT_PRODUCT_THESIS,
|
|
223
|
+
job_id: job.job_id,
|
|
224
|
+
job_hash: job.job_hash,
|
|
225
|
+
tenant_id: job.tenant_id,
|
|
226
|
+
operator_id: requiredString(input.operator_id ?? input.operatorId, 'operator_id'),
|
|
227
|
+
service_kind: serviceKind,
|
|
228
|
+
quoted_at: isoTimestamp(input.quoted_at ?? input.quotedAt, 'quoted_at'),
|
|
229
|
+
expires_at: isoTimestamp(input.expires_at ?? input.expiresAt, 'expires_at', job.expires_at),
|
|
230
|
+
price: {
|
|
231
|
+
amount: priceAmount,
|
|
232
|
+
asset: quoteAsset,
|
|
233
|
+
},
|
|
234
|
+
capacity_ref: capacityProfile ? requiredString(capacityProfile.capacity_ref, 'capacity_profile.capacity_ref') : requiredString(input.capacity_ref ?? input.capacityRef, 'capacity_ref'),
|
|
235
|
+
terms_ref: requiredString(input.terms_ref ?? input.termsRef, 'terms_ref'),
|
|
236
|
+
accountability_boundary: {
|
|
237
|
+
service_receipt_required: true,
|
|
238
|
+
raw_memory_access_required: false,
|
|
239
|
+
operator_controls_hot_path: false,
|
|
240
|
+
token_profit_claim: false,
|
|
241
|
+
},
|
|
242
|
+
};
|
|
243
|
+
if (capacityProfile !== null) {
|
|
244
|
+
if (!isPlainObject(capacityProfile) || capacityProfile.schema !== CONSUMER_GPU_CAPACITY_PROFILE_SCHEMA) throw new TypeError('capacity_profile must be an Enigma consumer GPU capacity profile');
|
|
245
|
+
if (serviceKind !== 'memory_optimizer') throw new TypeError('capacity_profile quotes must use service_kind memory_optimizer');
|
|
246
|
+
if (capacityProfile.operator_id !== body.operator_id) throw new TypeError('capacity_profile operator must match quote operator');
|
|
247
|
+
if (capacityProfile.price_per_million_context_tokens.asset !== quoteAsset) throw new TypeError('capacity_profile asset must match quote asset');
|
|
248
|
+
body.capacity_ref = capacityProfile.capacity_ref;
|
|
249
|
+
body.capacity_profile_hash = capacityProfile.capacity_profile_hash;
|
|
250
|
+
body.consumer_gpu_boundary = capacityProfile.service_boundary;
|
|
251
|
+
}
|
|
252
|
+
if (Date.parse(body.expires_at) <= Date.parse(body.quoted_at)) throw new RangeError('quote expires_at must be after quoted_at');
|
|
253
|
+
const quote = Object.freeze({ ...body, quote_id: quoteIdFrom(body), quote_hash: digest(body) });
|
|
254
|
+
assertNoSensitivePayload(quote, 'quote');
|
|
255
|
+
return quote;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export function createServiceSettlementReceipt(input = {}) {
|
|
259
|
+
if (!isPlainObject(input)) throw new TypeError('createServiceSettlementReceipt requires an options object');
|
|
260
|
+
assertNoSensitivePayload(input, 'input');
|
|
261
|
+
const job = input.job;
|
|
262
|
+
const quote = input.quote;
|
|
263
|
+
if (!isPlainObject(job) || job.schema !== PERMISSIONLESS_MEMORY_JOB_SCHEMA) throw new TypeError('job must be an Enigma permissionless memory job');
|
|
264
|
+
if (!isPlainObject(quote) || quote.schema !== OPERATOR_SERVICE_QUOTE_SCHEMA) throw new TypeError('quote must be an Enigma operator service quote');
|
|
265
|
+
if (quote.job_hash !== job.job_hash || quote.job_id !== job.job_id) throw new TypeError('quote must reference job');
|
|
266
|
+
const settledAmount = nonNegativeNumber(input.settled_amount ?? input.settledAmount ?? quote.price.amount, 'settled_amount');
|
|
267
|
+
if (settledAmount > quote.price.amount) throw new RangeError('settled_amount exceeds quoted price');
|
|
268
|
+
const body = {
|
|
269
|
+
schema: SERVICE_SETTLEMENT_RECEIPT_SCHEMA,
|
|
270
|
+
product_thesis: SETTLEMENT_PRODUCT_THESIS,
|
|
271
|
+
job_id: job.job_id,
|
|
272
|
+
job_hash: job.job_hash,
|
|
273
|
+
quote_id: quote.quote_id,
|
|
274
|
+
quote_hash: quote.quote_hash,
|
|
275
|
+
tenant_id: job.tenant_id,
|
|
276
|
+
operator_id: quote.operator_id,
|
|
277
|
+
service_kind: quote.service_kind,
|
|
278
|
+
completed_at: isoTimestamp(input.completed_at ?? input.completedAt, 'completed_at'),
|
|
279
|
+
usage_event_hash: job.usage_event_hash,
|
|
280
|
+
memory_commitment_root: job.memory_commitment_root,
|
|
281
|
+
policy_hash: job.policy_hash,
|
|
282
|
+
settled_price: {
|
|
283
|
+
amount: settledAmount,
|
|
284
|
+
asset: quote.price.asset,
|
|
285
|
+
},
|
|
286
|
+
settlement_ref: requiredString(input.settlement_ref ?? input.settlementRef, 'settlement_ref'),
|
|
287
|
+
service_receipt_ref: requiredString(input.service_receipt_ref ?? input.serviceReceiptRef, 'service_receipt_ref'),
|
|
288
|
+
settlement_boundary: {
|
|
289
|
+
permissionless_access: true,
|
|
290
|
+
raw_memory_on_chain: false,
|
|
291
|
+
raw_memory_in_receipt: false,
|
|
292
|
+
provider_invoice_savings_claim: false,
|
|
293
|
+
token_roi_claim: false,
|
|
294
|
+
token_profit_claim: false,
|
|
295
|
+
model_forgetting_claim: false,
|
|
296
|
+
provider_deletion_claim: false,
|
|
297
|
+
},
|
|
298
|
+
};
|
|
299
|
+
const receipt = Object.freeze({ ...body, settlement_receipt_id: receiptIdFrom(body), settlement_receipt_hash: digest(body) });
|
|
300
|
+
assertNoSensitivePayload(receipt, 'receipt');
|
|
301
|
+
return receipt;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
export function verifyServiceSettlementReceipt(input = {}) {
|
|
305
|
+
const errors = [];
|
|
306
|
+
const job = input.job;
|
|
307
|
+
const quote = input.quote;
|
|
308
|
+
const receipt = input.receipt;
|
|
309
|
+
try {
|
|
310
|
+
assertNoSensitivePayload(input, 'verification');
|
|
311
|
+
} catch (error) {
|
|
312
|
+
errors.push(error.message);
|
|
313
|
+
}
|
|
314
|
+
if (!isPlainObject(job) || job.schema !== PERMISSIONLESS_MEMORY_JOB_SCHEMA) errors.push('job schema mismatch');
|
|
315
|
+
if (!isPlainObject(quote) || quote.schema !== OPERATOR_SERVICE_QUOTE_SCHEMA) errors.push('quote schema mismatch');
|
|
316
|
+
if (!isPlainObject(receipt) || receipt.schema !== SERVICE_SETTLEMENT_RECEIPT_SCHEMA) errors.push('receipt schema mismatch');
|
|
317
|
+
if (errors.length === 0) {
|
|
318
|
+
if (receipt.job_hash !== job.job_hash || receipt.job_id !== job.job_id) errors.push('receipt job reference mismatch');
|
|
319
|
+
if (receipt.quote_hash !== quote.quote_hash || receipt.quote_id !== quote.quote_id) errors.push('receipt quote reference mismatch');
|
|
320
|
+
if (quote.job_hash !== job.job_hash || quote.job_id !== job.job_id) errors.push('quote job reference mismatch');
|
|
321
|
+
if (receipt.usage_event_hash !== job.usage_event_hash) errors.push('usage event reference mismatch');
|
|
322
|
+
if (receipt.memory_commitment_root !== job.memory_commitment_root) errors.push('memory commitment reference mismatch');
|
|
323
|
+
if (receipt.policy_hash !== job.policy_hash) errors.push('policy hash reference mismatch');
|
|
324
|
+
if (receipt.settled_price.asset !== quote.price.asset) errors.push('settlement asset mismatch');
|
|
325
|
+
if (receipt.settled_price.amount > quote.price.amount) errors.push('settlement amount exceeds quote');
|
|
326
|
+
if (receipt.settlement_boundary?.raw_memory_on_chain !== false) errors.push('receipt must not put raw memory on-chain');
|
|
327
|
+
if (receipt.settlement_boundary?.token_roi_claim !== false) errors.push('receipt must not claim token ROI');
|
|
328
|
+
const { settlement_receipt_id: _id, settlement_receipt_hash: _hash, ...receiptBody } = receipt;
|
|
329
|
+
if (receipt.settlement_receipt_id !== receiptIdFrom(receiptBody)) errors.push('settlement receipt id mismatch');
|
|
330
|
+
if (receipt.settlement_receipt_hash !== digest(receiptBody)) errors.push('settlement receipt hash mismatch');
|
|
331
|
+
}
|
|
332
|
+
return Object.freeze({ ok: errors.length === 0, valid: errors.length === 0, errors });
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
export function createSettlementBatch(input = {}) {
|
|
336
|
+
if (!isPlainObject(input)) throw new TypeError('createSettlementBatch requires an options object');
|
|
337
|
+
assertNoSensitivePayload(input, 'input');
|
|
338
|
+
const receipts = Array.isArray(input.receipts) ? input.receipts : [];
|
|
339
|
+
if (receipts.length === 0) throw new TypeError('receipts must be non-empty');
|
|
340
|
+
const assetName = asset(input.asset ?? receipts[0]?.settled_price?.asset, 'asset');
|
|
341
|
+
let total = 0;
|
|
342
|
+
const operatorTotals = new Map();
|
|
343
|
+
for (const [index, receipt] of receipts.entries()) {
|
|
344
|
+
if (!isPlainObject(receipt) || receipt.schema !== SERVICE_SETTLEMENT_RECEIPT_SCHEMA) throw new TypeError(`receipts[${index}] must be a service settlement receipt`);
|
|
345
|
+
assertNoSensitivePayload(receipt, `receipts[${index}]`);
|
|
346
|
+
if (receipt.settled_price.asset !== assetName) throw new TypeError('all receipts must use the batch asset');
|
|
347
|
+
total += receipt.settled_price.amount;
|
|
348
|
+
operatorTotals.set(receipt.operator_id, (operatorTotals.get(receipt.operator_id) ?? 0) + receipt.settled_price.amount);
|
|
349
|
+
}
|
|
350
|
+
const body = {
|
|
351
|
+
schema: SETTLEMENT_BATCH_SCHEMA,
|
|
352
|
+
product_thesis: SETTLEMENT_PRODUCT_THESIS,
|
|
353
|
+
generated_at: isoTimestamp(input.generated_at ?? input.generatedAt, 'generated_at'),
|
|
354
|
+
batch_ref: requiredString(input.batch_ref ?? input.batchRef, 'batch_ref'),
|
|
355
|
+
asset: assetName,
|
|
356
|
+
receipt_count: receipts.length,
|
|
357
|
+
receipt_hashes: receipts.map((receipt) => receipt.settlement_receipt_hash),
|
|
358
|
+
total_settled_amount: total,
|
|
359
|
+
operator_totals: Array.from(operatorTotals, ([operator_id, amount]) => ({ operator_id, amount, asset: assetName })).sort((a, b) => a.operator_id.localeCompare(b.operator_id)),
|
|
360
|
+
claim_boundary: [
|
|
361
|
+
'Settlement batches aggregate service receipts only; they are not investment, profit, yield, equity, or provider invoice evidence.',
|
|
362
|
+
'Permissionless access means open job submission/settlement boundary, not decentralized raw-memory inference.',
|
|
363
|
+
'Raw memory, prompts, transcripts, provider responses, credentials, keys, seed phrases, and decrypted content are forbidden in settlement artifacts.',
|
|
364
|
+
],
|
|
365
|
+
};
|
|
366
|
+
const batch = Object.freeze({ ...body, batch_id: batchIdFrom(body), batch_hash: digest(body) });
|
|
367
|
+
assertNoSensitivePayload(batch, 'batch');
|
|
368
|
+
return batch;
|
|
369
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Production storage contract
|
|
2
|
+
|
|
3
|
+
`@enigma-ai/enigma/storage` defines the production storage schema contract for relay/gateway deployments. It is pure local code: no sockets, no provider SDKs, no environment loading, and no secret handling.
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
The package emits a PostgreSQL migration for durable backend state:
|
|
8
|
+
|
|
9
|
+
- relay records with encrypted payload hashes and opaque storage refs,
|
|
10
|
+
- relay witness checkpoints,
|
|
11
|
+
- relay pairings with hashed client public keys,
|
|
12
|
+
- gateway policy versions,
|
|
13
|
+
- gateway decisions with decision hashes,
|
|
14
|
+
- gateway SIEM events with event hashes,
|
|
15
|
+
- public-safe readiness evidence refs.
|
|
16
|
+
|
|
17
|
+
The package also emits parameterized SQL operation objects for the same tables. Operation builders return SQL text plus `$n` values only; they do not connect to a database, load credentials, or execute mutations.
|
|
18
|
+
|
|
19
|
+
## Boundary
|
|
20
|
+
|
|
21
|
+
The schema intentionally excludes raw prompts, transcripts, decrypted memory, provider response bodies, embeddings, API keys, tokens, passwords, and private keys.
|
|
22
|
+
|
|
23
|
+
The storage contract is not a live database and does not make `hosted_live_ready` true. Operators still need provisioned database infrastructure, credentials in a secret manager, KMS/secret custody, backups, restore checks, monitoring, SIEM/log routing, private ingress, auth, and operator acceptance.
|