The evidence
Cross-version must-fail: the workflow vectors
workflow-merkle-seq-output-v1.json (7 vectors, file SHA-256 30b63977d7ccc4177e2c2524520dcbbb0a352c572561aa3d3c4fe4d60cf55f40) carries two dedicated cross-version cases. xversion-seq-output-v1-evaluated-as-receipt-id-v0: a close declaring merkle_version seq-output-v1, evaluated under the legacy receipt-id-v0 leaf rule, computes root 242397c374053da292c53b4854271684b030f3cc014d5d3f8dcda83f9f7a95de, which must not equal the declared root 05c3b7f7dd7e18ba3ff6a7459d6950d3fa89f72ac2c88dc6c5576da25878a637; expected verdict invalid, rejected_by "merkle_root mismatch". The reverse case, xversion-receipt-id-v0-evaluated-as-seq-output-v1, is likewise invalid, rejected because the seq-output-v1 leaf cannot be formed from steps that carry no output_hash. The closes themselves remain valid under their declared versions: it is the cross-version evaluation that must fail.
Corpus vector: version-downgrade.json
Receipt id 62e028e2-9bc0-4d70-9762-17d1a84b411f declares receipt_schema_version "0.3" on the record, while its own canonical bytes decode to a payload whose receipt_schema_version is "0.4". The version on the outside is not the version committed inside, and the vector is filed in the corpus invalid set: version-downgrade.json (file SHA-256 228160b1c6fa8985df13a11342fae58844dc05bd34a3017f344c8d08deb1d3b9). A relabeled record gets rejected, not reinterpreted.
Corpus vector: anchored-bad-id-version.json
The anchored set's sibling vectors share receipt id b6c63ac5-f324-4fa7-ad58-c4bf83faa86a. This one carries b6c63ac5-f324-1fa7-ad58-c4bf83faa86a: the version digit in the id itself is altered, and the vector is filed with the invalid anchored set. Read it live: anchored-bad-id-version.json (file SHA-256 36d9c375fdcc49423e11d73aea78d8ffd69c80bb4400d57b48c7ca9aafbe1400).
What the verifier reports
Evaluated under its declared version, a sound record can report verified. Evaluated under the wrong version's rule, the same record must be rejected, with the reason stated, as the cross-version vectors state theirs. And a version the verifier does not implement at all is not checked: the only honest report for a check that was not, and could not be, run.
How to fix it
- Read the declared version first. receipt_schema_version on a receipt, merkle_version on a workflow close (seq-output-v1 is current, receipt-id-v0 is legacy, and a close with no merkle_version member verifies under the legacy rule exactly as issued).
- Evaluate only under the declared rule. Never apply one version's construction to another version's record and report the mismatch as a defect in the record.
- Never relabel a record. If a record needs a newer format, issue a new record under the new version; editing the version member breaks the commitment the original was saved under.
- Keep the verifier current. The published kit is v1.5.7 with 126 vectors and 129 checks. If your verifier meets a version it does not know, report not checked and update the verifier, in that order.
Put your own calls on a checkable record
Start at zambo.dev/add
Add Zambo to your AI at https://zambo.dev/add/. The free tier is 20 free calls per day, then they upgrade. A Day Pass is $0.99 for 24 hours. Every call returns a verifiable receipt, including a call that is rejected, so a failure like the ones on this page leaves a record you can open, check, and learn from instead of a claim you have to trust.
A verifiable receipt proves the saved result was not changed since it was saved. It does not prove the result was right.
Questions
What happens when a workflow close is checked under the wrong merkle_version?
It must be rejected. The corpus carries two cross-version must-fail vectors: a seq-output-v1 close evaluated under the receipt-id-v0 rule computes a different root and is rejected for merkle_root mismatch, and a receipt-id-v0 close evaluated under seq-output-v1 cannot form its leaves and fails closed. Both closes remain valid under their declared versions.
Can I upgrade a receipt by changing its receipt_schema_version?
No. The corpus vector version-downgrade.json declares 0.3 outside its canonical bytes while the committed payload says 0.4, and it is filed in the invalid set. A version member is part of the record; changing it makes a record that must be rejected, not an upgraded one.
What should a verifier do with a version it does not know?
Report the check as not checked, in the Section 6 vocabulary, and say the version was not evaluated. Never report an evaluated outcome for an unevaluated check, and never silently evaluate the record under a different version's rule.