Telemetry you can prove.
A utility can prove a reading was authentic at the meter, and separately that a warehouse row hasn't changed. Nothing joins the two. meldra verifies telemetry at the ingestion boundary and writes the proof into the lakehouse, so an answer arrives with its evidence attached.
Example response GET /v1/query/submit
Settled consumption, feeder F‑4471, period 2026‑08‑01 to 2026‑08‑31
4,182,904kWh
- Iceberg snapshot
- 7742901883364117205
- Contributing rows
- 1,428,096 — all verified at ingest
- Merkle root
- a41f…9c02, anchored RFC 3161
- Status
- Reproducible. Re-run returns the same figure.
The gap is between the meter and the record
Encryption and authentication at the meter are solved problems — IEC 62351 and DLMS handle them. What isn't solved is integrity that survives into the data lake, and what you can hand a third party months later.
When Ofgem or a settlement counterparty challenges a figure today, substantiating it means pulling source readings, matching them to the aggregate and writing a narrative. That's days of senior analyst time, and what it produces is an argument rather than a proof.
meldra changes what you hand over. Every answer carries the exact data snapshot it was computed from and a verification that the contributing readings were checked at the gateway and unaltered since. Your counterparty re-runs it and gets the same number. The dispute ends in arithmetic instead of negotiation.
Two things happen at the wire
Ingress routes derive from a shared secret and a 60-second epoch window, with three windows valid at once to tolerate clock drift. There is no fixed endpoint to scan for.
Valid traffic is verified and recorded
Each block carries a hardware monotonic nonce and an ECDSA P‑256 signature. The gateway performs an atomic nonce compare-and-swap, recomputes the hash and verifies the signature before the reading is written. Verification state becomes a first-class column in Iceberg, not a log line. A broken chain link is flagged CHAIN_GAP rather than silently dropped, because a missing reading is evidence.
Invalid traffic is diverted, not blocked
Existing AMI standards respond to detected reconnaissance by blocking, which tells the attacker they've been seen. They rotate address and try again; you learn nothing. meldra sends an invalid or stale route to an isolated decoy that returns plausible synthetic telemetry, and flags the source. The attacker keeps probing a system that isn't real.
Every number here was measured
| Operation | Measured | Conditions |
|---|---|---|
| Verified ingest | 0.108 ms/block | 1,000 blocks, ECDSA P‑256 + SHA‑256 + nonce compare-and-swap |
| Throughput | 9,254 blocks/sec | Single thread |
| Route validation | 0.007 ms | HMAC‑SHA256, constant-time compare — 142,052/sec |
| Diversion to decoy | 0.020 ms | Invalid route path — 50,295/sec |
| Headroom, 3M-meter estate | 5.4× | Against roughly 1,700 blocks/sec sustained |
Where 1,700 comes from: 3,000,000 meters × 48 half-hourly readings ÷ 86,400 seconds = 1,667 blocks per second sustained. We're happy to show the arithmetic.
What we can't claim yet
These are unmeasured or unfinished. We publish them because you'd find them anyway, and because a vendor claiming a clean history isn't one you should believe.
-
Detection accuracy and false-positive rate
Not measured. Neither is attacker containment duration. We won't put a number on any of them until we've run it.
-
Multi-thread and multi-gateway throughput
Every figure above is single-thread. Horizontal scaling is designed but not benchmarked.
-
Nothing has run against real meters
All measurements come from a meter simulator producing signed blocks. No production AMI estate has been through this.
-
Scan pushdown needs explicit filters
SQL WHERE predicates aren't automatically translated into Iceberg expressions yet, so callers who need file pruning must populate filters themselves.
-
The fast scan path is conditional
The zero-materialisation Arrow path only engages when no access-control policy applies to the query. With masking in force, the data is materialised.
-
Two defects we found in our own gateway
One was an availability bug: the nonce counter advanced before signature verification, so a single unsigned packet could permanently lock out a meter. We exploit-tested it, fixed it and pinned it with regression tests. The write-up is public.
Your storage, your data, your exit
Tables are Apache Iceberg on your own object storage. Spark, Trino, DuckDB and Dremio can read every byte with us entirely out of the picture. If meldra disappears tomorrow, your data is untouched and readable.
Access control is enforced below the query engine. Masking is applied to the Arrow data before the relation is registered with DuckDB, so column aliasing, subqueries, CTEs and SELECT * cannot recover a masked value — the value was never in the relation the engine saw. That's a stronger property than rewriting SQL, which creative queries defeat.
The catalogue maps to the IEC Common Information Model: 61970‑301 for the base model, 61968 for distribution including part 9 for meter reading. A CIM RDF export is implemented and tested. CIM has no way to express provenance — no standard class for "this reading was verified at ingest, here's the proof, here's the anchor." That hole in the standard is where our work sits.
Come and break it
The most useful sixty seconds we can spend with you: two terminals, no slides. Meters posting signed readings. The route rotates and the meters follow it. A scanner hits the old route, receives a plausible response, and never learns it's talking to a decoy. Then we change one byte in a stored reading, run the verifier, and it names the block.