Every Action Leaves a Trace. For an agent, provenance is a usable evidence record, not an adjective attached to an answer.

Ask for the exact identity and window

After a successful read, keep its bound-function ID, returned field names, and resolved half-open block interval. Invoke provenance with the same identity and window. It takes no attribute or key selector; the evidence describes the bound function's window. A different window is a different evidence request.

{"tool":"provenance","arguments":{"bound_function_id":"<BOUND_FUNCTION_ID>","from_block":100,"to_block":110}}

Provenance is a separate tool call. Do not claim that every read automatically contains the expanded source-block list.

What to preserve

The implementation expands contributing blocks into an ordered list with block numbers and hashes, a block count, and a recomputed digest when the contributing list is non-empty. An empty blocks list means enumeration found nothing; missing blocks means evidence is not enumerated. Do not invent absent digests. When a result supplies a compact digest-bound ChainRange, compare the expanded digest with that corresponding ChainRange.digest. A REST data row carries provenance.digest for its own block; expand [block, block+1) to compare it.

Persist the identity, chain, measure, window, compact record where supplied, expanded source list, digest, and comparison outcome. Preserve the algorithm and encoding supplied by the contract if independently recomputing; an invented concatenation of hashes is not a valid verification procedure.

Canonical source-digest encoding

The observed implementation sorts contributing pairs by ascending block number, then hashes UTF-8 lines in this exact form:

{chain_id}:{block_number}:{lowercase_0x_block_hash}\n

The result is sha256: followed by lowercase SHA-256 hex. The newline is one actual LF byte per pair, including the final pair. Chain ID and block number are decimal integers. Use the exact contributing set returned by the contract; do not add every block in the enclosing span.

A verifier can reproduce that digest locally:

import hashlib

def source_digest(chain_id, blocks):
    ordered = sorted(blocks, key=lambda block: block["number"])
    encoded = "".join(
        f"{chain_id}:{block['number']}:{block['block_hash'].lower()}\n"
        for block in ordered
    ).encode("utf-8")
    return "sha256:" + hashlib.sha256(encoded).hexdigest()

This verifies encoding consistency for the supplied list. For independent source verification, obtain the corresponding canonical block hashes independently as well.

Two range conventions differ: tool requests use the exclusive to_block, while a compact ChainRange citation's from and to are the inclusive minimum and maximum contributing block numbers. Its block_count is the actual contributing count and may be smaller than the enclosing span because of gaps. Do not pass the citation's inclusive end directly into a half-open tool request.

Source evidence and computation evidence

Matching source hashes establishes the requested source evidence's consistency with its digest. It does not, by itself, prove the metric definition matches the operator's intent or independently replay the computation. Distinguish source verification, definition review, and independent recomputation in the final answer.

Missing coverage and empty blocks

A block with no matching event can be legitimate evidence. A missing block is unavailable coverage. Do not conflate them or collapse both into a zero value. Provenance requires its stated window to be covered; inspect the reported geometry and complete missing work before asserting verification.

Bounded expansion

Expansion is limited to 10,000 contributing blocks per response. For larger requests, use smaller meaningful windows and retain the boundaries of each verification record. Do not claim that independently expanded subwindows match one whole-window digest unless the contract supplies a valid composition rule.

Credentials stay out of evidence

Agent-facing source descriptions should identify providers or chains without exposing credential-bearing RPC URLs. Block numbers, hashes, function identity, and reproducible definitions are more useful evidence than a secret endpoint string.