# Verify a PactVerity receipt without uploading it

Run locally with Node.js 24 or later. After downloading the files, verification requires no network, API key, wallet connection, token purchase or installed npm packages. This is a first-party reference verifier, not an independent security audit or an independent implementation.

## Try the synthetic example

```sh
node pactverity-verify-offline.mjs synthetic-pass.json --require-pass
```

The included example is fabricated test data, not a customer, integration or real service measurement. A valid receipt means its fields, deterministic checks and digest agree. It does not prove the measurements were honest. An optional signature proves control of a key, not the signer's real-world identity.

## Three synthetic cases

The downloadable fixtures use the same terms and contain no real customer measurements. Download `synthetic-pass.json`, `synthetic-fail.json` and `synthetic-tampered.json`, then test them individually:

```sh
node pactverity-verify-offline.mjs synthetic-pass.json --require-pass
node pactverity-verify-offline.mjs synthetic-fail.json
node pactverity-verify-offline.mjs synthetic-fail.json --require-pass
node pactverity-verify-offline.mjs synthetic-tampered.json
```

Expected exits, respectively: 0, 0, 3, 1. The passing case measures 100 ms against a 500 ms limit. The failing case measures 900 ms and has correctly recomputed checks and digest. The deliberately tampered case changes the passing receipt's measured latency to 900 ms but retains the old checks and digest; it must be rejected. An adversary able to replace both an unsigned receipt and its digest can create another internally consistent record: this check is not independent provenance.

The overall outcome is only `pass` or `fail`; an individual output-hash check may be `not_evaluated` when no expected hash was supplied. `--require-pass` does not require every optional check to have been evaluated. Review the criteria as well as the overall outcome.

## Your own receipt commands

Save a complete `pactverity.assurance-receipt.v1` receipt as `receipt.json`, then run:

```sh
node pactverity-verify-offline.mjs receipt.json
node pactverity-verify-offline.mjs receipt.json --require-pass --require-signature
```

A receipt can be authentic and correctly record a failed service check. Default verification accepts that receipt; `--require-pass` fails the CI gate. `--require-signature` additionally requires a valid Ed25519 signature in the Solana-format signature envelope. Neither option signs anything or submits a transaction.

`--require-signature` alone accepts any valid signing key. For trusted-issuer enforcement, use `--expect-signer` followed by the exact public key independently agreed with the issuer. This requires both a valid signature and a matching key; an attacker re-signing an altered receipt with a different valid key cannot satisfy it. A wrong or absent signer exits 3, like other unsatisfied policy gates. Store the expected key in protected CI configuration, not in the untrusted receipt. The output identifies the signing public key; it does not establish legal identity.

| Exit code | Meaning |
| --- | --- |
| 0 | Receipt is consistent; all requested gates satisfied |
| 1 | Invalid schema, altered checks, digest mismatch or invalid signature |
| 2 | Bad arguments, unreadable/oversized file or invalid UTF-8 |
| 3 | Valid receipt, but requested pass/signature gate not satisfied |

Standard output is JSON. Original evidence, buyer/provider references and signature bytes are not echoed. Input is limited to 100,000 bytes. Keep input files private when they contain confidential information. Do not run files received from untrusted senders without reviewing their origin.

## Reproduce from source

In the PactVerity repository, with its pinned dependencies installed:

```sh
node scripts/build-offline-verifier.mjs
node --test tests/offline-verifier.test.mjs
```

The build bundles the existing Proof Engine, rather than introducing a different set of validation rules. Dependencies include the existing Solana address codec and strict Ed25519 verifier. Download integrity can be checked against `SHA256SUMS.txt`; a checksum served alongside a file is not independent provenance. Inspect the source and pin a reviewed repository commit for CI use. Registry publication and GitHub Marketplace acceptance are separate from this build.

`DERIVATION.md` explains the digest and signature boundaries. `synthetic-hash-input.txt` enables a SHA-256 known-answer check without executing this verifier. `THIRD-PARTY-NOTICES.txt` preserves bundled dependency licences. Repeated builds on the same installed toolchain are tested for byte equality; cross-platform, clean-checkout reproduction remains a separate external review step unless documented in a release record.

## Corrections and independent reproduction

Report a reproducible discrepancy at https://github.com/PactVerityHQ/pactverity/issues. Include the source commit, Node version, exact command, exit code and a redacted or synthetic fixture. Never include credentials, private keys or private customer receipts. A successful outside reproduction is evidence only of that tested behavior, not of adoption at scale.

Receipt consistency does not establish service delivery, uptime, SLA compliance, truthful inputs, investment suitability or PVTY token value.
