Daily measurement roots
Every UTC day, Agenstry computes a SHA-256 Merkle root over four classes of measurement we recorded that day. Anyone with read access to the same source rows on the same date can re-compute the same root. If our DB ever diverged from a published root, the discrepancy would surface in seconds.
Algorithm
- For each UTC day, collect rows from four append-only tables:
agents(live-probe snapshot perlast_seen_okin window),agent_card_snapshots(every card change),probe_runs(every probe),agent_revenue_snapshots(every per-window revenue settlement). - Hash each row into a 32-byte leaf using SHA-256 over a NUL-separated, domain-prefixed serialisation of its key columns. The prefix (
agent\0…,snapshot\0…, …) prevents cross-table collision. - Compute a Merkle root per sub-tree using the RFC-6962 odd-leaf-carry variant (no duplication, which avoids the second-preimage attack on classic Merkle).
- Concatenate the four sub-roots in fixed order (
agents→snaps→probes→revenue) with their domain separator prefix, then Merkle-fold once more for the day's top-level root. - Persist the root, the row counts, and
computed_atintransparency_roots. The row is never updated; a mismatch on recompute is a flag, not a silent fix. - Coming next: publish the root onchain (Base contract
setRoot(date, root)) so even an attacker with DB write access cannot rewrite history. The schema'sonchain_anchor_*columns are already shaped for that path; today's column values are NULL.
Reproducibility kit
The reference implementation is at app/transparency.py. The JSON API at /api/transparency/daily-root.json returns the latest root + row counts; per-date lookup at /api/transparency/<date>.json (replace <date> with any ISO YYYY-MM-DD).
Published roots · last 30 days
| Date | Merkle root | Agents | Snaps | Probes | Revenue rows | Onchain anchor |
|---|---|---|---|---|---|---|
2026-07-06 |
474ec85b9f4885e70f5a4208… | 2,529 | 235 | 7,682 | 100 | DB only · onchain pending |
2026-07-05 |
0cbe2920170541efd087e1ab… | 1,018 | 138 | 6,840 | 98 | DB only · onchain pending |
2026-07-04 |
d006eb0ca25d7e467bd78596… | 830 | 113 | 4,860 | 97 | DB only · onchain pending |
2026-07-03 |
c7dfca677a7d785ea689dada… | 859 | 156 | 8,784 | 97 | DB only · onchain pending |
2026-07-02 |
04fb6e334c34030617993c08… | 991 | 180 | 7,783 | 97 | DB only · onchain pending |
2026-07-01 |
0170ddc652625eee177672f6… | 974 | 150 | 6,946 | 96 | DB only · onchain pending |
2026-06-30 |
3065cf257e8e8de68b92b989… | 903 | 116 | 3,268 | 96 | DB only · onchain pending |
2026-06-29 |
1aeab61a88dc54ec71965f6a… | 930 | 84 | 2,845 | 96 | DB only · onchain pending |
2026-06-28 |
cdd58573358e4c6b60eb02be… | 905 | 101 | 2,722 | 96 | DB only · onchain pending |
2026-06-27 |
e60dc989e35e23bfd9e6d352… | 920 | 117 | 2,647 | 96 | DB only · onchain pending |
2026-06-26 |
d5f42dc5c7ef29fa253dd097… | 924 | 137 | 3,861 | 96 | DB only · onchain pending |
2026-06-25 |
b1e571cd11609d8b7035b187… | 748 | 106 | 3,485 | 96 | DB only · onchain pending |
2026-06-24 |
f356c9f0578ff72f4689ed51… | 915 | 168 | 7,946 | 96 | DB only · onchain pending |
2026-06-23 |
857f957f94e86851db764061… | 925 | 170 | 7,292 | 96 | DB only · onchain pending |
2026-06-22 |
8ba47da0b562d03c236aacc5… | 916 | 141 | 7,460 | 95 | DB only · onchain pending |
2026-06-21 |
f6e84c4535f558d7f53c9ccf… | 901 | 151 | 8,690 | 95 | DB only · onchain pending |
2026-06-20 |
6a41816db9c0637cee28c8ba… | 890 | 146 | 7,558 | 95 | DB only · onchain pending |
2026-06-19 |
159a22bb48a4c3baaf28d638… | 854 | 159 | 7,681 | 95 | DB only · onchain pending |
2026-06-18 |
15041030a9c271b6049aef2c… | 840 | 140 | 8,286 | 93 | DB only · onchain pending |
2026-06-17 |
cd1012c5f355dc94529215bf… | 856 | 167 | 8,520 | 93 | DB only · onchain pending |
2026-06-16 |
8e39d0f9ac7939844498a186… | 838 | 182 | 7,791 | 93 | DB only · onchain pending |
2026-06-15 |
0cf7d447666765f81d3ade79… | 834 | 125 | 6,878 | 93 | DB only · onchain pending |
2026-06-14 |
67cad3dc1655742773722c82… | 702 | 144 | 7,616 | 92 | DB only · onchain pending |
2026-06-13 |
a052155e8f0c38b65f4fad9e… | 689 | 112 | 6,561 | 92 | DB only · onchain pending |
2026-06-12 |
10147bc8e72cf0cd5d4a3d1a… | 777 | 141 | 7,732 | 92 | DB only · onchain pending |
2026-06-11 |
b4f721e1305a85daa2f9cd27… | 786 | 143 | 6,227 | 92 | DB only · onchain pending |
2026-06-10 |
707a20cc7e06f9f005dc2326… | 774 | 173 | 8,079 | 92 | DB only · onchain pending |
2026-06-09 |
9cddf83c3337a6f5483d9772… | 770 | 154 | 7,572 | 92 | DB only · onchain pending |
2026-06-08 |
1f4659f264b9c413e45e1c77… | 756 | 118 | 6,535 | 92 | DB only · onchain pending |
2026-06-07 |
2218682fb4d55b6d9aab2e6a… | 626 | 117 | 7,178 | 92 | DB only · onchain pending |
Same data, machine-readable: /api/transparency/daily-root.json. Want to verify? Pull the source rows for a date via the federation feed (/api/feed/all.jsonl.gz), run the algorithm in app/transparency.py, compare the root you compute with the row above.