CHAINVERDICT PURCHASE EVIDENCE — experimental v1

Purpose: compare selected advertised terms with a caller-owned policy and sampled
history. No signing, payment, credential verification or automatic retry. The kit
never authorizes a purchase. No affiliated endorsement or unique moat is claimed.

Python3.10+. Install requirements.txt in your normal isolated environment.
The libraries are pinned, free and identical to the existing archive checker.

1. Copy purchase-input.example.json to input.json. Replace every synthetic value
with your own policy and captured x402-v2 response. Select exactly one offer index.
Amount is an integer string in atomic USDC units (6 decimals); no floating-point
USD conversion is done. Only exact/Base/canonical USDC are supported in this v1.
Set actual UTC now and caller-observed receivedAt; they are assertions, not proof.
Set minimumDays, maxHistoryAgeDays and maxQuoteAgeSeconds explicitly.

2. Read https://pulse.chainverdict.xyz/v1/purchase-evidence/manifest. This NEW
collection does not backfill old Pulse history. Its first UTC day is excluded.
Choose actual completed days; max7days per free capture. If no complete day exists,
there is nothing to verify yet. Do not manufacture a passing day.

python purchase_evidence.py capture evidence --from YYYY-MM-DD --to YYYY-MM-DD

Capture downloads only the free fixed Pulse URLs and external Bitcoin headers
from Blockstream. It never follows URLs supplied by the capture. It never overwrites
an earlier directory. Verification and evaluation are offline; capture is separate.

3. Verify with the actual current UTC date, not an anticipated date:
python purchase_evidence.py verify evidence/bundle.json --headers evidence/bitcoin-headers.json --as-of YYYY-MM-DD --from YYYY-MM-DD --to YYYY-MM-DD

Default assurance is bitcoin: pinned publisher, exact root/count, intact chain,
completed and available days, and timestamp proof against supplied Bitcoin headers.
Headers are an external trust input, not Bitcoin best-chain/consensus verification.
Pending timestamps are not verified. --assurance signed is explicitly weaker:
publisher authentication and root/chain only, without independent existence time.

4. Evaluate your local quote against that evidence:
python purchase_evidence.py evaluate input.json evidence/bundle.json --headers evidence/bitcoin-headers.json --from YYYY-MM-DD --to YYYY-MM-DD

Decisions: within_policy / outside_policy / insufficient_evidence / unsupported.
Exit0 only on within_policy (or successful capture/usable verifier result);2 means
no pass;1 means input or operational failure. Missing data, unknown schemas,
unsupported currencies, ambiguous selection, self-observed endpoints and suspended
collection never supply positive historical evidence. x401 is not evaluated by the
policy engine. The separate Inspector diagnoses transport only.

Input/output files remain local. Unlike the value-free Inspector reports, these
reports include endpoint observations and deterministic hashes. Treat them as
private if the inputs are private. Hashes are commitments, not anonymization.

Canonicalisation test vectors are in purchase-vectors.json (synthetic only).

NEW DATASET CANONICAL RULES
One row/endpoint/UTC day; exact UTF-8 JSON record strings in JavaScript UTF-16 sort
order; SHA256 leaves and binary Merkle tree, odd leaf promoted. Own root/chain and
own checkpoint type, separate from x402pulse.dataset.v1. No old roots are changed.
Selected offer fields: [scheme,network,asset,payTo,amount], exact strings and order;
SHA256(JSON.stringify(tuple)) is an option hash. Deduplicate/sort option hashes;
SHA256(JSON.stringify(hashes)) is the set hash. Version x402-v2-option-set-1.
Resource URL is not inside the hash: resource equality with the probed URL is counted
separately. Current quote resource, policy target and evidence endpoint must agree.
New payment options do not invalidate a selected unchanged option. Unknown fields,
credential nonces and tokens are not fingerprinted. This is selected-field matching,
not full x402 conformance, seller authenticity or fulfilment verification.
Daily sets cap32; option hashes cap256. A saturated row is marked suspended and is
unusable. Purchase-summary storage caps64MiB; earlier records are never deleted to
fit. The existing journal/checkpoint replays counts exactly once. No new probes.
Only recent raw tuples remain in the existing capped raw journal; the new long-run
hash dataset cannot reconstruct historical prices or recipients from hashes alone.

PRICING / LIMITS
Local kit, manifest and latest7collected UTC days: free. Existing /v1/feed includes
latest completed new-schema day; /v1/archive/full offers retained new-schema days via ?purchaseDay=YYYY-MM-DD, one per response.
Read the live unpaid402quote before any paid call. Cache permitted bundles and make
many local comparisons; do not buy one check per agent action. No SLA or subscription
is introduced. A signed statement proves its publisher, not observation truth.

Original ChainVerdict code: ISC (repository LICENSE). Underlying verification
libraries keep their own licences. No third-party datasets or AGPL code bundled.

COVERAGE AND TEACHING CASES
python run_purchase_cases.py
python purchase_coverage.py evidence/bundle.json --headers evidence/bitcoin-headers.json --as-of YYYY-MM-DD --from YYYY-MM-DD --to YYYY-MM-DD

All18 catalogue cases are synthetic, fixed-clock teaching regressions. The runner
uses a deliberately public test key, confined to that runner; production verification
keeps its pinned issuer and rejects these fixtures. No key override is available
on the production CLI. Never use catalogue success as production evidence.
Coverage exit0 means a report was generated, not that history passed. Each day names
its assurance status and reasons. Missing/invalid exports have null counts. A candidate
row is only structurally comparable; it does not establish selected-option stability
or a policy pass. Reports include URLs and stay local; inspect before sharing.
Read contribute-cases.txt before suggesting a case. Publication needs explicit consent.

Collection runs unattended on the existing Render server, nominally every10minutes,
subject to outages and completed sweeps. It does not require the Mac or chat to be
open. The deleted chat review is separate. Same operator, one region, no independent
observers. Daily summaries and timestamps do not turn samples into customers.
