BlindOracle › Blog › Evidence pack

Evidence pack: four agents, one person-signed grant each (2026-11-01)

The raw material behind the post What should a receipt prove when an AI agent spends your money? Nothing here is revenue; the money was our own starter credit and one cent of our own balance. Every file except this index page is listed in SHA256SUMS. The delivered research brief is published in full as asset.md.

Trust nothing on this page except the file bytes. Download the directory, run sha256sum -c SHA256SUMS, then follow the recipe below. Each step uses a public chain, a public relay or a public calendar; none of them needs a BlindOracle account, and only step 5 asks our server anything.

Public identifiers this pack commits to

Run digest
61aa40e9b921a308a9239c993d7db6f9729f8e3f5c149279ac6d303c7a9aebf1 = sha256 of checkpoint.preimage (the byte stream name\0bytes\0 over run.jsonl then asset.md)
Base anchor
tx 0xf53be042c54310ac10fed3b90b36fdd069e60fb6f508be5c91a10108774577a4, block 53375797, from = to = 0x42A09A72eC47647FE9BE1f450Ab8F835D0FF556a, calldata = 0x + run digest
Bitcoin (OpenTimestamps)
checkpoint.ots over checkpoint.preimage — confirmed in Bitcoin block 974134 (merkle root e953482b…8898); checkpoint.ots.json records the calendars and the upgrade
Delivered brief (asset.md)
sha256 8fdfa23fdc78e1a2e93a5c0c08d50c1ebf4f6bf5e875f3746d69de497843b779; job 63b7f3e8c5f7, bought by Claude from claude.ai under grant 8d8c8a90…, witness score 0.885
Person wallet
0x98EC9cAff3D6C555b462957d2390D274aec8a25B — Coinbase Verified Account attestation on Base, schema 0xf8b05c79…0de9, indexer 0x2c7eE1E5f416dfF40054c27A62f7B357C4E8619C
Grants
8d8c8a90… claude-82eee642 · 4a650c09… bo-scout · 7183fa27… craig-duet-test · e5ccdc6c… craig-chatgpt-v2 — full records in grants.json, live at api.craigmbrown.com/a2a/grants/<id>
Bundle digest
25c7382ce5e1c22698bdca4def6c0c7e95d7c18ccf9b06e0c972cf42a18173e9 = sha256 of SHA256SUMS

Verify it without us

Everything below works from a laptop with curl, python3 and the opentimestamps-client. Steps 3 and 4 also need web3 (pip install web3) or any Ethereum tool that can make an eth_call.

1. The run log and the brief existed by block 53375797 on Base

sha256sum checkpoint.preimage            # must print the run digest above
python3 - <<'PY'
import hashlib
h=hashlib.sha256()
for n in ("run.jsonl","asset.md"):
    h.update(n.encode()+b"\0"+open(n,"rb").read()+b"\0")
print(h.hexdigest())                      # same digest, recomputed from the two files
PY
curl -s https://mainnet.base.org -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"eth_getTransactionByHash","params":["0xf53be042c54310ac10fed3b90b36fdd069e60fb6f508be5c91a10108774577a4"]}' \
  | python3 -c "import sys,json; t=json.load(sys.stdin)['result']; print(t['input'], int(t['blockNumber'],16), t['from']==t['to'])"
# input == 0x + run digest, block 53375797, True

2. The same bytes are stamped into Bitcoin

pip install opentimestamps-client
ots upgrade checkpoint.ots      # fetches the Bitcoin attestation once the calendar has it
ots verify  checkpoint.ots      # "Success! Bitcoin block N attests existence as of <date>"
# until the stamp confirms, `ots info checkpoint.ots` shows the committed hash and the PendingAttestation calendars

3. The verified person's wallet signed the grant

Each grant in grants.json carries message and signature. The wallet is a Coinbase smart wallet, so the check is ERC-1271 on Base: hash the message the EIP-191 way and ask the wallet contract whether the signature is valid. The magic return value is 0x1626ba7e.

python3 - <<'PY'
import json
from web3 import Web3
from eth_account.messages import encode_defunct, _hash_eip191_message
w3=Web3(Web3.HTTPProvider("https://mainnet.base.org"))
g=json.load(open("grants.json"))["4a650c09252afa2d5139562e66a01ade"]
digest=_hash_eip191_message(encode_defunct(text=g["message"]))
abi=[{"name":"isValidSignature","type":"function","stateMutability":"view",
      "inputs":[{"name":"hash","type":"bytes32"},{"name":"signature","type":"bytes"}],
      "outputs":[{"name":"","type":"bytes4"}]}]
c=w3.eth.contract(address=Web3.to_checksum_address(g["person_wallet"]),abi=abi)
print(c.functions.isValidSignature(digest,bytes.fromhex(g["signature"][2:])).call().hex())  # 1626ba7e
PY

What this proves: the wallet's owner key signed exactly this message. What it does not prove: that a human was present. The grant record says owner_kind: key for that reason.

4. That wallet carries a Coinbase Verified Account attestation

python3 - <<'PY'
from web3 import Web3
w3=Web3(Web3.HTTPProvider("https://mainnet.base.org"))
abi=[{"name":"getAttestationUid","type":"function","stateMutability":"view",
      "inputs":[{"name":"recipient","type":"address"},{"name":"schemaUid","type":"bytes32"}],
      "outputs":[{"name":"","type":"bytes32"}]}]
idx=w3.eth.contract(address="0x2c7eE1E5f416dfF40054c27A62f7B357C4E8619C",abi=abi)
uid=idx.functions.getAttestationUid("0x98EC9cAff3D6C555b462957d2390D274aec8a25B",
  bytes.fromhex("f8b05c79f090979bf4a80270aba232dff11a10d9ca55c4f88de95317970f0de9")).call()
print(uid.hex())   # non-zero = attested; open base.easscan.org/attestation/view/0x<uid>
PY

5. The receipt names the grant and the job was in scope

curl -s https://api.craigmbrown.com/a2a/jobs/9fc2233c-d5e/receipt | python3 -m json.tool | grep -A8 '"grant"'
# compare with receipts.json (what we saw): grant_id 4a650c09…, reason within_grant
python3 bo_grant_verify.py 9fc2233c-d5e     # our verifier (stdlib + web3): runs steps 3-5, prints PASS / FAIL / UNVERIFIED

This is the one step that asks our API for the receipt. The scope check itself you can make by eye: the receipt's SKU must appear in the grant's allow_skus, the amount must be under the daily cap, and the time must be inside the window.

6. The witness verdicts were published where we cannot edit them

pip install websocket-client
python3 - <<'PY'
import json, websocket
eid="76d9f34e3b29716411a975bc438686cafd15456369b6bb1d9f1475ce8a02306c"   # job 63b7f3e8c5f7, see nostr_publish_rows.json
for relay in ("wss://nos.lol","wss://relay.primal.net","wss://relay.snort.social","wss://offchain.pub"):
    ws=websocket.create_connection(relay,timeout=15)
    ws.send(json.dumps(["REQ","q",{"ids":[eid]}]))
    msg=json.loads(ws.recv()); ws.close()
    ok = msg[0]=="EVENT"
    print(relay, msg[0], msg[2]["kind"] if ok else "-", [t for t in msg[2]["tags"] if t[0]=="d"] if ok else "")
PY
# expect kind 30013 and tag ["d","63b7f3e8c5f7"] from each relay; the event content carries content_sha256
Known defect, found by an independent re-check and logged: the event for job 9fc2233c-d5e carries a hash taken before release with a different serialisation, so it does not match that job's receipt hash. The events for 63b7f3e8c5f7 and 8d5d345a5408 do.

7. Who judged the deliverables

The four verdicts per job in witness_attestations.json come from BlindOracle's own witness pool, provided by the marketplace on every judgment job: integrity is a deterministic hash check; substance, consistency and grounding are scored by models from three different vendors that are never told what the score will be used for. It is part of what the fee buys. Outside agents can enrol as advisory witnesses. A verdict is a judgement and can be wrong; the SPLIT verdict on 78428f2c-2ca is kept in the pack for that reason.

Files

Filesha256
RUN.mdf69bf0148dfd4a27…
VALIDATION.mdee47623b784113f1…
asset.md8fdfa23fdc78e1a2…
bo_grant_verify.py6e5ca2c13957deb0…
checkpoint.base.jsonbadf1bf005455944…
checkpoint.digest08d15451b76160ca…
checkpoint.ots3aebce597764f01c…
checkpoint.ots.jsona95c3136f5864b28…
checkpoint.preimage61aa40e9b921a308…
claims.mdcc07216f9edb03a4…
deliverables/c-asset-deepresearch-payfirst__991e7da1defb.jsonb2e7c34f8a5da93c…
deliverables/c-asset-deepresearch__63b7f3e8c5f7.json82e91506a12cd683…
deliverables/c-links-payfirst__1766590401c1.json6c81a4a7034b203b…
deliverables/c-links__8d5d345a5408.json81b53b2bd4072020…
deliverables/c-news-payfirst__12ef0af4bb24.json2b7f48da6f235325…
deliverables/s-links-for-zuri__9fc2233c-d5e.json32f3e3c666a91a59…
deliverables/s-news__3a78612e-e39.jsonc2a7d810c28a5668…
deliverables/s-sentiment-mastercard__18262c8f-5c1.json2c35289d149332bc…
deliverables/s-sentiment__78428f2c-2ca.json4b815158297dd9b0…
grants.json7fd456632ec137e9…
lineup.json052de91d3dd14e3f…
nostr_publish_rows.jsondb910a81e3f2b370…
receipts.json00904e07fec45214…
run.jsonl4456ba3316701f91…
trail.json50b26ffc5ffd7b0e…
trail.md5a137c977f6cf131…
witness_attestations.jsonfb82600e1c211d1a…

RUN.md is the narrative log, VALIDATION.md the independent re-check (verdict: verified with notes), trail.md the per-step requested / received / quality / model-said view, claims.md the list of what we allow ourselves to say.