Scopes

Reference · integrity · verify

Verify the record yourself

This is a walkthrough for a technical team. It shows how to prove four things about the Scopes record on your own machine, without using our application and without trusting us: that a day’s record existed and has not been altered, that a specific row is part of it, that it was timestamped to Bitcoin on or before a known date, and that nothing Scopes committed to capture was quietly dropped. Everything below runs against public endpoints and a public GitHub repository.

The examples use real, current values (confirmed day 2026-11-07 and the active coverage manifest), so you can copy and run them as written. You will need git, node, and the OpenTimestamps client (ots).

Get the public repository

git clone https://github.com/jonshields-twain/scopes-integrity.git
cd scopes-integrity
# index.jsonl    one line per day: root, status, anchor provenance, manifest_hash
# digests/       <date>.merkle (the root) and <date>.merkle.ots (the Bitcoin proof)
# manifests/     <hash>.json (the committed coverage set) and index.jsonl
1

A day existed and is unaltered

Recompute the day’s Merkle root and match it to the published one.

Each UTC day, Scopes folds that day’s append-only record (price snapshots, flags, reads, model reads, resolutions and corrections) into one Merkle root under canonicalization v1 (RFC 6962), frozen in docs/integrity-canonicalization-v1.md. With a copy of the day’s canonical rows (a data licensee holds these, or exports them), recompute the root with the reference verifier shipped in the repo and confirm it equals the published value.

Recompute and match

node scripts/verify-integrity.mjs <export-dir> 2026-11-07 bc2b62c0a01a1f8264d820de2dca2ffb…
# the published root for 2026-11-07 is in index.jsonl and on scopes.com/integrity:
# bc2b62c0a01a1f8264d820de2dca2ffb5faacf259ae32a693c3b3f56aa4411e2

If even one byte of one row had changed, the recomputed root would not match. The rules are fixed, so the computation is deterministic on any machine.

2

A single row is in that record

Re-fold one row’s inclusion proof up to the published root.

You do not need the whole day to check one row. Ask for that row’s inclusion proof: the endpoint returns the leaf hash, the audit path, and the day’s root (no row content, so no personal data is exposed). Recompute the leaf hash from your own copy of the row and fold it up the path. If it lands on the published root, that row was in the record on that date.

Fetch an inclusion proof

curl -s "https://scopes.com/api/integrity/proof?date=2026-11-07&table=price_snapshots&id=93760"
# returns { leafHash, proof: [...], merkleRoot }: fold leafHash up proof, confirm it equals merkleRoot.
# root_matches_digest also confirms merkleRoot is the root anchored for 2026-11-07.

The /verify page does this fold in your browser with Web Crypto, so you can watch it reach the root without writing any code.

3

The day was anchored in time

Verify the OpenTimestamps proof against the Bitcoin blockchain.

The root for each day is timestamped to Bitcoin via OpenTimestamps. The .ots proof in the repo, verified against the root, confirms the root was committed to the blockchain at or before a specific block time. Scopes cannot backdate it: the attestation is the Bitcoin chain, not our word.

Verify the timestamp

# the root must be in a file named exactly as it was stamped
printf '%s\n' bc2b62c0a01a1f8264d820de2dca2ffb5faacf259ae32a693c3b3f56aa4411e2 > 2026-11-07.merkle
curl -sL "https://raw.githubusercontent.com/jonshields-twain/scopes-integrity/main/digests/2026-11-07.merkle.ots" -o 2026-11-07.merkle.ots
ots verify 2026-11-07.merkle.ots
# -> "Success! Bitcoin block <N> attests existence as of <date>"

A note on honest provenance

Days anchored after the fact (the record predates when live anchoring began) prove existence as of the anchor date, not the record date. The integrity ledger marks each day same-day or retroactive, and index.jsonl carries the same distinction, so you are never asked to take a stronger claim than the proof supports.

4

Nothing committed was dropped

Recompute the coverage manifest, then reconcile it against what was captured.

The root proves the record was not altered. It does not, on its own, prove nothing was quietly dropped. So Scopes pre-registers what it commits to capture: a canonical, hashed list of every active contract, with its desk and declared cadence. That hash is published ahead of time and bound into the day’s anchored root. Fetch the committed set, recompute its hash, confirm it matches the one bound into the root, then reconcile it against what actually landed.

Recompute the committed set

curl -s "https://scopes.com/api/coverage-manifests?hash=0d1f440059572ed79b51d5d1bc6a4ca267d9dbaf540365077bba805e2de55dc6" -o manifest.json
node -e 'const m=require("./manifest.json"),{createHash}=require("crypto");\
const c=[...m.contractSet].sort((a,b)=>a[0]===b[0]?a[1].localeCompare(b[1]):a[0].localeCompare(b[0]))\
  .map(e=>JSON.stringify(e)).join("\n");\
console.log(createHash("sha256").update(c).digest("hex"))'
# -> must equal 0d1f440059572ed79b51d5d1bc6a4ca2…
# and that hash is the manifest_hash bound into the day’s row in index.jsonl (method coverage-v1)

Then reconcile the commitment against captures for a day. Every committed contract must be either captured, or have a disclosed gap. Any contract that is committed but produced nothing, with no disclosed gap, is the completeness failure this exists to surface.

Reconcile a day

curl -s "https://scopes.com/api/coverage-reconcile?date=2026-11-07"
# { committed, covered, partial, gappedDark, uncovered, reconciles, uncoveredContracts }
# reconciles:true means every commitment was captured or disclosed; uncovered:0

What the four proofs give you

Together: a given day’s record is fixed and unaltered (1), any row you hold is provably part of it (2), it existed by an externally attested date (3), and it is complete against a commitment Scopes made before the fact (4). None of this requires trusting Scopes, logging in, or using the application. The data stays yours; only hashes and proofs cross the wire.