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-08-20 |
f0c9f12df80136202679f7f4… | 1,514 | 391 | 4,963 | 5,136 | DB only · onchain pending |
2026-08-19 |
876cd8316994b450efb2194e… | 4,446 | 508 | 5,924 | 5,098 | DB only · onchain pending |
2026-08-18 |
daaae52574166fbdcae66b87… | 3,897 | 648 | 7,748 | 5,050 | DB only · onchain pending |
2026-08-17 |
01bf7d0203e62d3bb53bae4c… | 611 | 458 | 5,286 | 5,000 | DB only · onchain pending |
2026-08-16 |
50aa65b76366d5fb4dc948b3… | 4,319 | 582 | 7,918 | 4,960 | DB only · onchain pending |
2026-08-15 |
2b323a750e7ef8899ac275e7… | 4,240 | 455 | 5,894 | 4,906 | DB only · onchain pending |
2026-08-14 |
c152d7b4c169538428688cd4… | 4,160 | 552 | 6,693 | 4,850 | DB only · onchain pending |
2026-08-13 |
b57e722f73e9d20c89638114… | 4,219 | 471 | 6,098 | 4,717 | DB only · onchain pending |
2026-08-12 |
8843876b39532bec281cf70f… | 4,172 | 463 | 6,017 | 4,613 | DB only · onchain pending |
2026-08-11 |
bb4db7aa57a68825e5c8d3c3… | 4,123 | 315 | 3,839 | 4,442 | DB only · onchain pending |
2026-08-10 |
645fab298124038e93d2b199… | 3,993 | 419 | 6,050 | 4,233 | DB only · onchain pending |
2026-08-09 |
5320edbfcd80d840749f5fe9… | 4,042 | 309 | 4,357 | 4,031 | DB only · onchain pending |
2026-08-08 |
833edef61a6db7e052e850b1… | 3,968 | 514 | 7,111 | 3,847 | DB only · onchain pending |
2026-08-07 |
1bb87ffbf2371ccef9712d9d… | 3,844 | 258 | 3,531 | 3,659 | DB only · onchain pending |
2026-08-06 |
e62d3d891c1c0cdcab8633dc… | 3,922 | 300 | 6,968 | 3,423 | DB only · onchain pending |
2026-08-05 |
f5cd300d51f8d04b87756d1b… | 3,893 | 359 | 8,397 | 3,137 | DB only · onchain pending |
2026-08-04 |
0f127d469516952601abf1a5… | 3,832 | 281 | 4,908 | 2,943 | DB only · onchain pending |
2026-08-03 |
6dfc18ada6511fd73a607186… | 3,611 | 250 | 4,293 | 2,661 | DB only · onchain pending |
2026-08-02 |
43d192074c633fbd0e7e64b4… | 3,764 | 449 | 6,588 | 2,403 | DB only · onchain pending |
2026-08-01 |
d30a9e03c8342be504addf3e… | 3,144 | 168 | 3,179 | 1,929 | DB only · onchain pending |
2026-07-31 |
fce0cf6132ea2c639bb70d86… | 1,112 | 231 | 4,362 | 1,051 | DB only · onchain pending |
2026-07-30 |
4bddf13b62baea95c6aeaa0f… | 1,066 | 235 | 6,479 | 867 | DB only · onchain pending |
2026-07-29 |
35b1a4387dc2ad6ebaff5628… | 839 | 241 | 4,322 | 405 | DB only · onchain pending |
2026-07-28 |
d971218938548202920adf3d… | 1,038 | 158 | 3,140 | 263 | DB only · onchain pending |
2026-07-27 |
6f0e46e2b70f4120504ca5f0… | 1,270 | 308 | 6,509 | 105 | DB only · onchain pending |
2026-07-26 |
167d3e2bbe5d6657d89b4351… | 3,162 | 243 | 6,087 | 105 | DB only · onchain pending |
2026-07-25 |
cb8281633dc6ed65444f0a12… | 1,027 | 234 | 7,722 | 105 | DB only · onchain pending |
2026-07-24 |
f7fa2ca6b7075fe6c0daccb7… | 1,064 | 286 | 8,120 | 104 | DB only · onchain pending |
2026-07-23 |
0441cee4cc3f1ef3d96666a1… | 976 | 170 | 5,601 | 104 | DB only · onchain pending |
2026-07-22 |
c59a422d5280783389989562… | 1,184 | 304 | 5,720 | 104 | 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.