ADR-019: SDK Telemetry for Prover and Solver
| Status | Proposed |
| Date | 2026-04-22 |
Context
The SDK runs on partner clients and we have no field visibility into prove/solve latencies, failure rates, or device mix. Our benchmarks are biased toward engineer machines. This ADR describes what the SDK reports to a telemetry backend operated by the SDK team (a Grafana stack, over OpenTelemetry), and what it deliberately does not.
Key constraint: No data identifying end-users, their activity, or any secrets may leave their device.
Proposal
What we collect
The SDK emits one event per call to solver.init, solver.solve, prover.prewarm, and prover.prove. Each event carries a duration, an ok/error outcome, and attributes drawn from a strict allowlist. No user identifier is emitted anywhere.
| Attribute | Type | Notes |
|---|---|---|
sdk.version | string | from the SDK package |
sdk.platform | enum | node / web / react-native |
partner.id | string | partnerTelemetryId from config |
environment | enum | production / staging / test |
proof.kind | enum | prover events only: encrypted_transfer / encrypted_to_public / epk_ownership |
solver.found | bool | solver.solve only |
solver.value_bucket | enum | solver.solve only: <100 / <1k / <10k / <100k / <1M / 1M+ |
device.* | bucketed | browser only: class, cores, memory_gb, connection |
browser.name / browser.major | enum / int | browser only |
os.name / os.major | enum / int | browser only |
wasm.simd / wasm.threads | bool | feature detection |
witness_build_ms / proof_generate_ms | int | prover.prove only, sub-stage durations flattened onto the parent event |
error.class | string | error outcomes only: the JS error constructor name, never the message |
What we deliberately don't collect
We do NOT collect raw navigator.userAgent (replaced by bucketed browser and OS fields), screen dimensions, timezone offset, client IP, any input to solve or prove, raw error messages.
No client timestamps: time is marked on receive of a batch of events. SDK does not log any timing data beyond the duration of each computation.
Opt-in
Telemetry is off by default. Activation requires an explicit partnerTelemetryId in the runtime config.
Batching
Events accumulate in an in-memory queue. A timer fires every 15 seconds: if the queue is non-empty, events are serialized into one batch and POSTed; if empty, no network call is made. Additional flushes happen on runtime destroy, page unload.
Flushes are fire-and-forget — a failing response drops the batch.