verifyhash 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +883 -0
- package/cli/abi/ContributionRegistry.json +881 -0
- package/cli/agent.js +2173 -0
- package/cli/anchor-artifact.js +853 -0
- package/cli/anchor.js +400 -0
- package/cli/claim.js +881 -0
- package/cli/core/agent-commit.js +448 -0
- package/cli/core/agent-session.js +598 -0
- package/cli/core/anchor-binding.js +663 -0
- package/cli/core/attestation.js +580 -0
- package/cli/core/evidence-plans.js +495 -0
- package/cli/core/fixtures/evidence-plans/baseline.json +19 -0
- package/cli/core/fulfill-intake.js +1082 -0
- package/cli/core/go-live-preflight.js +481 -0
- package/cli/core/license.js +534 -0
- package/cli/core/manifest.js +243 -0
- package/cli/core/packetseal.js +591 -0
- package/cli/core/registryArtifact.js +49 -0
- package/cli/core/revocation.js +539 -0
- package/cli/core/rfc3161.js +389 -0
- package/cli/core/timestamp.js +482 -0
- package/cli/core/trust-asof.js +479 -0
- package/cli/dataset.js +2950 -0
- package/cli/evidence.js +2227 -0
- package/cli/fulfill-webhook-http.js +438 -0
- package/cli/git.js +220 -0
- package/cli/hash.js +550 -0
- package/cli/identity.js +1072 -0
- package/cli/journal-cli.js +1110 -0
- package/cli/journal-log.js +454 -0
- package/cli/journal.js +334 -0
- package/cli/lineage.js +447 -0
- package/cli/list.js +287 -0
- package/cli/parcel.js +1509 -0
- package/cli/proof.js +578 -0
- package/cli/prove.js +300 -0
- package/cli/receipt.js +631 -0
- package/cli/registry.js +331 -0
- package/cli/reputation.js +344 -0
- package/cli/revocation.js +495 -0
- package/cli/serve-verify-http.js +298 -0
- package/cli/serve-verify.js +333 -0
- package/cli/show.js +339 -0
- package/cli/verify.js +383 -0
- package/cli/vh.js +3927 -0
- package/docs/ADOPT.md +183 -0
- package/docs/ADOPTION.json +11 -0
- package/docs/AGENTTRACE.md +247 -0
- package/docs/ANCHORING.md +167 -0
- package/docs/AUDIT.md +55 -0
- package/docs/CONFORMANCE.md +107 -0
- package/docs/DATALEDGER.md +638 -0
- package/docs/DECIDE.md +47 -0
- package/docs/DECISIONS-PENDING.md +27 -0
- package/docs/DEPLOY-PUBLIC-SITE.md +301 -0
- package/docs/ENGINE-LEDGER.json +12 -0
- package/docs/EVIDENCE.md +519 -0
- package/docs/GO-LIVE.md +66 -0
- package/docs/IDENTITY.md +123 -0
- package/docs/INDEPENDENT-VERIFICATION.md +377 -0
- package/docs/INTEGRITY-JOURNAL.md +337 -0
- package/docs/KEY-LIFECYCLE.md +179 -0
- package/docs/LICENSING.md +46 -0
- package/docs/LINEAGE.md +307 -0
- package/docs/LOOP-AUDIT-2026-07-03.json +580 -0
- package/docs/LOOP-HARDENING-PLAN.md +44 -0
- package/docs/MERKLE-LEAVES.md +113 -0
- package/docs/METRICS.jsonl +31 -0
- package/docs/MORNING.md +204 -0
- package/docs/PILOT.md +444 -0
- package/docs/PROOFPARCEL.md +227 -0
- package/docs/PROOFS.md +262 -0
- package/docs/RECEIPTS.md +341 -0
- package/docs/REPUTATION.md +158 -0
- package/docs/SDK.md +301 -0
- package/docs/STRATEGY-ARCHIVE.md +5055 -0
- package/docs/SUPERVISOR-RUNBOOK.md +52 -0
- package/docs/TRUST-BOUNDARIES.md +335 -0
- package/docs/TRUSTLEDGER.md +1976 -0
- package/docs/USAGE-BUDGET.json +121 -0
- package/docs/VERIFY-SERVICE.md +168 -0
- package/index.js +160 -0
- package/package.json +41 -0
- package/trustledger/build-standalone.js +796 -0
- package/trustledger/cli.js +3179 -0
- package/trustledger/close.js +391 -0
- package/trustledger/corpus.js +159 -0
- package/trustledger/dist/BUILD-PROVENANCE.json +99 -0
- package/trustledger/dist/trustledger-standalone.html +6197 -0
- package/trustledger/dist/trustledger-standalone.html.sha256 +1 -0
- package/trustledger/door-core.js +442 -0
- package/trustledger/fixtures/bank.csv +7 -0
- package/trustledger/fixtures/bank.malformed.csv +3 -0
- package/trustledger/fixtures/bank.noalias.csv +5 -0
- package/trustledger/fixtures/bank.ofx +34 -0
- package/trustledger/fixtures/bank.real.csv +5 -0
- package/trustledger/fixtures/corpus/_shared/prior-close.json +22 -0
- package/trustledger/fixtures/corpus/bank-book-mismatch--benign-twin/inputs.json +14 -0
- package/trustledger/fixtures/corpus/bank-book-mismatch--benign-twin/meta.json +7 -0
- package/trustledger/fixtures/corpus/bank-book-mismatch--out-of-trust/inputs.json +14 -0
- package/trustledger/fixtures/corpus/bank-book-mismatch--out-of-trust/meta.json +7 -0
- package/trustledger/fixtures/corpus/continuity-break--benign-twin/inputs.json +15 -0
- package/trustledger/fixtures/corpus/continuity-break--benign-twin/meta.json +7 -0
- package/trustledger/fixtures/corpus/continuity-break--out-of-trust/inputs.json +15 -0
- package/trustledger/fixtures/corpus/continuity-break--out-of-trust/meta.json +7 -0
- package/trustledger/fixtures/corpus/negative-tenant-ledger--benign-twin/inputs.json +13 -0
- package/trustledger/fixtures/corpus/negative-tenant-ledger--benign-twin/meta.json +7 -0
- package/trustledger/fixtures/corpus/negative-tenant-ledger--out-of-trust/inputs.json +13 -0
- package/trustledger/fixtures/corpus/negative-tenant-ledger--out-of-trust/meta.json +7 -0
- package/trustledger/fixtures/corpus/owner-overdraw--benign-twin/inputs.json +15 -0
- package/trustledger/fixtures/corpus/owner-overdraw--benign-twin/meta.json +7 -0
- package/trustledger/fixtures/corpus/owner-overdraw--out-of-trust/inputs.json +15 -0
- package/trustledger/fixtures/corpus/owner-overdraw--out-of-trust/meta.json +7 -0
- package/trustledger/fixtures/corpus/security-deposit-segregation--benign-twin/inputs.json +16 -0
- package/trustledger/fixtures/corpus/security-deposit-segregation--benign-twin/meta.json +7 -0
- package/trustledger/fixtures/corpus/security-deposit-segregation--out-of-trust/inputs.json +13 -0
- package/trustledger/fixtures/corpus/security-deposit-segregation--out-of-trust/meta.json +7 -0
- package/trustledger/fixtures/corpus/subledger-out-of-balance--benign-twin/inputs.json +13 -0
- package/trustledger/fixtures/corpus/subledger-out-of-balance--benign-twin/meta.json +7 -0
- package/trustledger/fixtures/corpus/subledger-out-of-balance--out-of-trust/inputs.json +13 -0
- package/trustledger/fixtures/corpus/subledger-out-of-balance--out-of-trust/meta.json +7 -0
- package/trustledger/fixtures/e2e/bank.aliased.csv +4 -0
- package/trustledger/fixtures/e2e/bank.csv +4 -0
- package/trustledger/fixtures/e2e/bank.nsf.csv +4 -0
- package/trustledger/fixtures/e2e/quickbooks.csv +6 -0
- package/trustledger/fixtures/e2e/quickbooks.nsf.csv +8 -0
- package/trustledger/fixtures/e2e/rentroll.csv +6 -0
- package/trustledger/fixtures/e2e/rentroll.nsf.csv +8 -0
- package/trustledger/fixtures/e2e/rentroll.short.csv +5 -0
- package/trustledger/fixtures/plans/baseline.json +25 -0
- package/trustledger/fixtures/plans/price-binding.example.json +27 -0
- package/trustledger/fixtures/policy/ambiguous-deposit-example.json +12 -0
- package/trustledger/fixtures/policy/baseline.json +19 -0
- package/trustledger/fixtures/policy/ca-example.json +12 -0
- package/trustledger/fixtures/policy/negative-tenant-ledger-example.json +12 -0
- package/trustledger/fixtures/policy/owner-overdraw-example.json +12 -0
- package/trustledger/fixtures/quickbooks.csv +7 -0
- package/trustledger/fixtures/quickbooks.real.csv +5 -0
- package/trustledger/fixtures/rentroll.csv +6 -0
- package/trustledger/fixtures/rentroll.real.csv +4 -0
- package/trustledger/ingest.js +1163 -0
- package/trustledger/lib/policy-bundled-loader.js +44 -0
- package/trustledger/lib/sha256-vendored.js +227 -0
- package/trustledger/license.js +563 -0
- package/trustledger/match.js +551 -0
- package/trustledger/plans.js +551 -0
- package/trustledger/policy.js +398 -0
- package/trustledger/public/index.html +512 -0
- package/trustledger/reconcile.js +1486 -0
- package/trustledger/report.js +887 -0
- package/trustledger/seal.js +854 -0
- package/trustledger/server.js +391 -0
- package/trustledger/valueproof.js +350 -0
package/docs/ADOPT.md
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# Adopt verifyhash in one line
|
|
2
|
+
|
|
3
|
+
You do **not** need an account, a license, a sales call, or our `ethers`/`hardhat` toolchain to start.
|
|
4
|
+
Pick the row that matches where you are, copy the one line, and run it. The **free** rows below are
|
|
5
|
+
**offline** and need at most **Node.js >= 18** — no account, no key, no network.
|
|
6
|
+
|
|
7
|
+
| You want to… | Copy this one line | Price |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| **No Node/terminal at all? Verify in your browser** (the 60-second challenge built in) | open [`verifier/dist/verify-vh-standalone.html`](../verifier/dist/verify-vh-standalone.html) | free |
|
|
10
|
+
| **See it work in 5 seconds** (no clone, no flags, no key) | `npx --yes verify-vh demo` | free |
|
|
11
|
+
| **Gate your CI on tampered/forged seals** (GitHub Actions) | `uses: <owner>/<repo>/verifier/action@<ref>` | free |
|
|
12
|
+
| **Issue signed, customer-verifiable seals of your own** (the paid producer surface) | `vh evidence seal <dir> --sign --license <f> --vendor 0xYOU` | **paid** |
|
|
13
|
+
|
|
14
|
+
The on-ramp is **deliberately one direction**: the free rows convince you the verdict is real, then the
|
|
15
|
+
paid row is the **only** part that turns into revenue — and the line below it (price, key, the sale) is a
|
|
16
|
+
**human** step, never the loop's. Each path is detailed below.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 0. The no-terminal path — one offline page in your browser
|
|
21
|
+
|
|
22
|
+
The browser row needs **no Node, no terminal, no install, no account**: save the ONE committed file
|
|
23
|
+
[`verifier/dist/verify-vh-standalone.html`](../verifier/dist/verify-vh-standalone.html) and double-click
|
|
24
|
+
it. The page opens with the **60-second challenge built in** — click **"Load the sample packet &
|
|
25
|
+
verify"** (**ACCEPT**), change one character of the editable sample file on the page and re-verify
|
|
26
|
+
(**REJECT**, naming the file you changed) — then drag a REAL sealed packet + its files in for the same
|
|
27
|
+
verdict the CLI prints. It contains **no network API at all**, so your bytes never leave your machine —
|
|
28
|
+
check the browser **devtools Network tab**: it stays empty. Honest scope, same as every row here:
|
|
29
|
+
tamper-evidence (+ signer-pin for a signed seal), NOT a trusted "sealed at T"; for CI/production gating
|
|
30
|
+
use the node standalone (`verify-vh-standalone.js`) — that is row two and §2 below. The guided walkthrough
|
|
31
|
+
is [`challenge/README.md`](../challenge/README.md).
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## 1. The 5-second proof — `npx --yes verify-vh demo`
|
|
36
|
+
|
|
37
|
+
Run, with nothing checked out at all:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx --yes verify-vh demo
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
It downloads the **standalone, offline** `verify-vh` verifier (one runtime dependency, `js-sha3` — **no**
|
|
44
|
+
ethers, **no** hardhat, **no** network), ships a tiny **genuinely-signed** evidence packet baked into the
|
|
45
|
+
file, plays it through the **exact same verify path** every real check uses, and prints the honest verdict:
|
|
46
|
+
a genuine packet is **ACCEPTED and its signer named**, then a one-byte change is **REJECTED**. No flags, no
|
|
47
|
+
`--vendor` to paste, no key knowledge. It writes only a throwaway temp dir it deletes, opens **no network**,
|
|
48
|
+
and exits `0`.
|
|
49
|
+
|
|
50
|
+
> The `verify-vh` package's `bin` is `verify-vh`, and `demo` is a real subcommand of
|
|
51
|
+
> [`verifier/verify-vh.js`](../verifier/verify-vh.js) — a test runs the literal command above so this line
|
|
52
|
+
> can never drift from the tool.
|
|
53
|
+
|
|
54
|
+
Want a copy you can tamper with by hand? Add a directory and the demo writes the same signed packet there,
|
|
55
|
+
then prints the exact verify / tamper / restore commands:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
npx --yes verify-vh demo ./vh-demo
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
When it clicks, point the tool at a **real** packet you were handed:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
npx --yes verify-vh <packet> --vendor 0xPRODUCER_ADDRESS # exit 0 = ACCEPT; 3 = REJECT
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Prefer no `npx`? The same verifier is a single self-contained file you can save and run with bare `node` —
|
|
68
|
+
see [`verifier/README.md`](../verifier/README.md).
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## 2. Gate your CI in one line — `uses: <owner>/<repo>/verifier/action@<ref>`
|
|
73
|
+
|
|
74
|
+
Drop this workflow at `.github/workflows/verify-vh.yml` in the repo that **receives** sealed verifyhash
|
|
75
|
+
artifacts. Every push / pull request then fails the build the instant any artifact is tampered, forged, or
|
|
76
|
+
signed by the wrong key — blocking the merge:
|
|
77
|
+
|
|
78
|
+
```yaml
|
|
79
|
+
# .github/workflows/verify-vh.yml
|
|
80
|
+
name: verify-vh merge gate
|
|
81
|
+
on: [push, pull_request]
|
|
82
|
+
jobs:
|
|
83
|
+
verify-vh:
|
|
84
|
+
runs-on: ubuntu-latest
|
|
85
|
+
steps:
|
|
86
|
+
- uses: actions/checkout@v4
|
|
87
|
+
- uses: <owner>/<repo>/verifier/action@<ref>
|
|
88
|
+
with:
|
|
89
|
+
vendor: "0xYOUR_PRODUCER_SIGNER_ADDRESS" # the key that must have signed (omit to check tamper only)
|
|
90
|
+
manifest: "release.manifest" # OR set `artifacts:` instead
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Replace `<owner>/<repo>` with this repository's slug and `<ref>` with a tag or commit SHA you trust (pin a
|
|
94
|
+
SHA for supply-chain safety). The composite action installs **only** the standalone verifier (`js-sha3`) and
|
|
95
|
+
resolves its bundled `verifier/` tree via `${{ github.action_path }}` at run time — so you do **not** vendor
|
|
96
|
+
`verifier/` into your repo. The action lives at [`verifier/action/`](../verifier/action/action.yml); its full
|
|
97
|
+
input table and exit-code contract are in [`verifier/action/README.md`](../verifier/action/README.md).
|
|
98
|
+
|
|
99
|
+
> ⚠️ **Pin `vendor:` for any SIGNED release.** A signed artifact gated **without** `vendor:` is accepted as
|
|
100
|
+
> long as its signature recovers to the signer the packet **self-asserts** — so an attacker who re-signs a
|
|
101
|
+
> tampered release with **their own key** passes the gate. Leave `vendor:` empty **only** for genuinely
|
|
102
|
+
> unsigned evidence seals (where there is no signer to pin).
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## 3. Turn "it works" into revenue — the free→paid bridge
|
|
107
|
+
|
|
108
|
+
The two lines above cost nothing and stay free forever. They exist to get a prospect to one thought:
|
|
109
|
+
*"the verdict is real, and I want to hand my OWN signed seals to MY customers."* That is the line that
|
|
110
|
+
becomes a paying relationship — and it is the **only** part of this funnel that does.
|
|
111
|
+
|
|
112
|
+
**What is free vs. paid (no surprises).** The free surface is everything a *recipient* needs: `verify-vh`,
|
|
113
|
+
the CI gate, and the producer CLI's baseline verbs — an **unsigned** evidence seal of up to **25 files**
|
|
114
|
+
and offline verify. The **paid** surface is what a *producer who sells trust* needs: a **`--sign`** wrap
|
|
115
|
+
(a signed attestation your customers pin to YOUR published key) and sealing **more than 25 files**. Those
|
|
116
|
+
two are gated by a signed, offline-verifiable entitlement and refuse — never silently downgrade — without
|
|
117
|
+
one.
|
|
118
|
+
|
|
119
|
+
**The whole loop, end to end.** A customer pays you out-of-band. Your billing webhook (after it
|
|
120
|
+
authenticates the provider's own signature) runs ONE command to mint that customer a license against a
|
|
121
|
+
plan in the catalog:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
# You, the producer, mint a per-sale entitlement with a key YOU provisioned outside this loop:
|
|
125
|
+
vh evidence license fulfill --plan evidence-pro-annual --customer "Acme Co" \
|
|
126
|
+
--key-env EVIDENCE_VENDOR_KEY --out ./acme.vhevidence-license.json
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
`evidence-pro-annual` is a **real** plan in the bundled DRAFT catalog (`cli/core/fixtures/evidence-plans/baseline.json`);
|
|
130
|
+
`fulfill` copies that plan's entitlements **verbatim** and signs them — the loop **sets no price** and
|
|
131
|
+
**holds no key**. The customer then unlocks the paid surface OFFLINE, pinning your **published** address —
|
|
132
|
+
no per-sale terminal step for you:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
# Your paying customer runs the PAID producer surface, gated by the license you minted:
|
|
136
|
+
vh evidence seal <dir> --sign --license <f> --vendor 0xYOU
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
> The **needs-human** line, on purpose: the **price** on each plan, the **vendor signing key**, and the
|
|
140
|
+
> actual **sale/subscription agreement** are all human steps (the loop builds and tests the mechanism but
|
|
141
|
+
> sets no price, holds no key, and takes no payment). Revenue comes from **delivering this software value
|
|
142
|
+
> to a paying customer** — never from issuing a token, a coin, or any tradeable/appreciating asset; an
|
|
143
|
+
> entitlement is an **access description for delivered value**, not a security. Full schema, the closed
|
|
144
|
+
> entitlement table, and the worked webhook→fulfill→deliver flow are in [`docs/EVIDENCE.md`](EVIDENCE.md).
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## What a green result actually proves (the honest boundary)
|
|
149
|
+
|
|
150
|
+
Whether you run `npx --yes verify-vh demo` or the CI gate, the seal proves **tamper-evidence + signer-pin**,
|
|
151
|
+
NOT a trusted "sealed at T" and NOT a legal opinion — it attests *this key vouched for exactly these bytes*,
|
|
152
|
+
re-derived from the bytes you hold, offline, with no producer stack. The trusted-timestamp claim ("sealed at
|
|
153
|
+
time T") is a separate, human-gated step (see
|
|
154
|
+
[`docs/INDEPENDENT-VERIFICATION.md`](INDEPENDENT-VERIFICATION.md)).
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Where to go next
|
|
159
|
+
|
|
160
|
+
- [`verifier/README.md`](../verifier/README.md) — the full independent-verifier guide (zero-install bundle,
|
|
161
|
+
reproduce-from-source, the conformance corpus).
|
|
162
|
+
- [`docs/INDEPENDENT-VERIFICATION.md`](INDEPENDENT-VERIFICATION.md) — the counterparty-facing spec: exactly
|
|
163
|
+
what a seal proves and what it does not.
|
|
164
|
+
- [`verifier/action/README.md`](../verifier/action/README.md) — the GitHub Action's inputs, exit codes, and
|
|
165
|
+
the no-drift source-of-truth guarantee.
|
|
166
|
+
- [`docs/EVIDENCE.md`](EVIDENCE.md) — the **paid** producer surface: the signed evidence packet schema, the
|
|
167
|
+
free-vs-paid line, the closed entitlement table, and the worked **webhook → `license fulfill` → deliver**
|
|
168
|
+
flow that turns an adopter into a paying customer.
|
|
169
|
+
- [`docs/AGENTTRACE.md`](AGENTTRACE.md) — sealing **AI-agent session logs** (`vh agent`, `*.vhagent.json`):
|
|
170
|
+
tamper-evident, selectively-redactable session records the same free `verify-vh` paths on this page
|
|
171
|
+
verify. Adoption is a ~20-line mapping over the transcript you already have — the committed example is
|
|
172
|
+
[`examples/agent-session/`](../examples/agent-session/) (map → seal → redact → verify → prove). A session
|
|
173
|
+
can also be BOUND to a git commit (`vh agent commit-claim` / `verify-commit`, free + key-less;
|
|
174
|
+
containment, not causation — the auditor re-derives the oid + tracked-set root from their OWN clone):
|
|
175
|
+
see *Binding a session to a git commit* in [`AGENTTRACE.md`](AGENTTRACE.md) and the scripted flow
|
|
176
|
+
[`examples/agent-session/commit-bound-session.js`](../examples/agent-session/commit-bound-session.js).
|
|
177
|
+
- [`docs/TRUSTLEDGER.md`](TRUSTLEDGER.md) › *Zero-install: the offline app* — the TrustLedger pilot path with
|
|
178
|
+
**zero** install: email ONE file ([`trustledger/dist/trustledger-standalone.html`](../trustledger/dist/trustledger-standalone.html)),
|
|
179
|
+
the partner double-clicks it, drags their real exports in, and the page makes **no network request** (free tier only).
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
<sub>© 2026 verifyhash.com · Licensed under Apache-2.0 (SPDX-License-Identifier: Apache-2.0) — see the [LICENSE](https://verifyhash.com/LICENSE) and [NOTICE](https://verifyhash.com/NOTICE) served with this file.</sub>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_doc": "The loop's EXTERNAL adoption signal (audit 2026-07-03: 'the loop cannot fail its own test because its test has no market term'). Updated by the human (or future analytics). The Strategist/panel MUST read this and weigh it: novelty with zero adoption scores LOW; no new vertical/epic while every number here is zero.",
|
|
3
|
+
"updatedAt": "2026-07-03T04:35:00Z",
|
|
4
|
+
"distinctExternalUsers7d": 0,
|
|
5
|
+
"npmPublished": false,
|
|
6
|
+
"npmDownloads7d": null,
|
|
7
|
+
"pilotsActive": 0,
|
|
8
|
+
"buyerConversations": 0,
|
|
9
|
+
"revenueUsdTotal": 0,
|
|
10
|
+
"notes": "Live surfaces: verifyhash.com (site + zero-install verifier), Polygon-mainnet registry 0x77d8eF881D5aeEda64788968D13f9146fE1A609B. Nothing measured yet."
|
|
11
|
+
}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
# AgentTrace — tamper-evident, selectively-redactable agent-session evidence (`vh agent`)
|
|
2
|
+
|
|
3
|
+
AgentTrace turns an **ordered log of AI-agent session events** — prompts, completions, tool calls,
|
|
4
|
+
tool results, notes — into **one** tamper-evident, selectively-redactable, independently-verifiable
|
|
5
|
+
packet: `*.vhagent.json`. It is the agent-evidence vertical on the same provenance core as every other
|
|
6
|
+
verifyhash product, for the buyer who has to *keep* and *show* agent records (compliance/record-keeping,
|
|
7
|
+
incident forensics, audit, disputes) and cannot rely on operator-editable observability traces.
|
|
8
|
+
|
|
9
|
+
This page is the buyer-facing spec: exactly what a packet **proves**, what it does **not** prove, what
|
|
10
|
+
is **free vs. paid**, **where a counterparty independently verifies** it, and a committed, test-gated
|
|
11
|
+
**worked example** showing that adoption is a ~20-line mapping over the log you already have.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## What a `*.vhagent.json` packet PROVES
|
|
16
|
+
|
|
17
|
+
The packet carries an RFC-6962-style ordered Merkle `head` `{ size, root }` over **redaction-safe**
|
|
18
|
+
per-event leaves (each event's payload participates only via its keccak-256 hash commitment). From
|
|
19
|
+
that, `vh agent verify` — and the independent verifier, which shares no code with the producer stack —
|
|
20
|
+
re-derive everything from the bytes you hold. A green verdict proves, offline:
|
|
21
|
+
|
|
22
|
+
1. **The log is unaltered since it was sealed.** Every event leaf and the root re-derive from the
|
|
23
|
+
events in the packet; editing, reordering, inserting, or dropping any event is a REJECT that names
|
|
24
|
+
the first offending event `seq`.
|
|
25
|
+
2. **Any disclosed event is verbatim as recorded.** A full event's payload hash commitment is
|
|
26
|
+
recomputed from the payload bytes — a one-byte payload edit is a REJECT naming the seq. A
|
|
27
|
+
single-event disclosure (`vh agent prove` → `verify-proof`) binds the event to its exact position
|
|
28
|
+
under the head, so a quoted transcript line can be checked without the rest of the session.
|
|
29
|
+
3. **Append-only growth between a checkpoint and the final head.** `vh agent checkpoint` commits the
|
|
30
|
+
session so far; `vh agent verify-growth` proves a later packet extends that checkpoint append-only —
|
|
31
|
+
a rewritten, reordered, dropped, or inserted past is a REJECT. That is the anti-retroactive-edit
|
|
32
|
+
property: the operator cannot quietly rewrite history between checkpoints.
|
|
33
|
+
4. **Redaction can only withhold — it can never silently alter.** `vh agent redact` withholds chosen
|
|
34
|
+
payloads behind their hash commitments; leaves and root are UNCHANGED, so the redacted copy still
|
|
35
|
+
verifies (and one head signature stays valid across every redacted copy). A **forged** commitment on
|
|
36
|
+
a redacted event is a REJECT naming the seq. What you cannot see is *declared* withheld — never
|
|
37
|
+
silently substituted.
|
|
38
|
+
|
|
39
|
+
## What it does NOT prove (read this before relying on a packet)
|
|
40
|
+
|
|
41
|
+
- **It does NOT prove the log faithfully records what the agent ACTUALLY did — garbage-in is out of
|
|
42
|
+
scope.** The head proves the LOG is intact and append-only since seal. If the software that wrote the
|
|
43
|
+
log lied, omitted events, or was compromised *before sealing*, the packet faithfully preserves that
|
|
44
|
+
lie. Sealing early (checkpoint as the session runs) narrows this window; it never closes it.
|
|
45
|
+
- **Event `ts` fields are self-asserted metadata.** They are recorded and bound verbatim, never
|
|
46
|
+
verified against any clock. Order is proven by tree position (`seq`), not by `ts`.
|
|
47
|
+
- **NOT a trusted timestamp.** There is no "this session existed at time T" claim without the
|
|
48
|
+
human-owned **P-3** trust-root ([`STRATEGY.md`](../STRATEGY.md) › Proposals — needs-human: a
|
|
49
|
+
provisioned signing key, an RFC-3161 TSA, or an on-chain anchor). A signed head proves *who vouched*
|
|
50
|
+
for the session head, not *when*.
|
|
51
|
+
- **NOT a legal opinion**, and not a claim the agent behaved well, safely, or compliantly.
|
|
52
|
+
|
|
53
|
+
**The same wording rides in-band.** Per the family's trust-note discipline, every packet, checkpoint,
|
|
54
|
+
and proof artifact carries this boundary as its `note` field — and `vh agent verify` refuses a packet
|
|
55
|
+
whose note has drifted — so the caveat travels with the evidence instead of living only in a doc. The
|
|
56
|
+
standing in-band note, verbatim:
|
|
57
|
+
|
|
58
|
+
> This agent-session packet is TAMPER-EVIDENT + OFFLINE-RECOMPUTABLE, NOT a trusted timestamp and NOT a claim the agent behaved well. Its ordered Merkle `head` {size, root} (RFC-6962-style, position-bound) commits to every event: verify RE-DERIVES each event leaf — recomputing the payload hash commitment for a FULL event, checking the carried commitment for a REDACTED one — and the root from the events you hold, and a REJECT names the first offending event seq. Redaction WITHHOLDS a payload behind its hash commitment without changing any leaf or the root: it can hide, never silently alter. Event `ts` fields are SELF-ASSERTED metadata (recorded, never verified against any clock); "sealed at time T" rides the human-owned signing/timestamp trust-root (STRATEGY.md P-3). Garbage-in is out of scope: the head proves the LOG is intact and append-only, not that the log faithfully records what the agent actually did. The packet is an UNTRUSTED transport container: verify never trusts the packet's own stored hashes.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## The command surface
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
vh agent seal <session.jsonl> [--out <p>] [--sign (--key-env <VAR>|--key-file <p>) --license <f> --vendor <0xaddr>] [--json]
|
|
66
|
+
vh agent verify <packet> [--vendor <0xaddr>] [--json] # exit 0 ACCEPTED / 3 named REJECT (+ offending seq)
|
|
67
|
+
vh agent redact <packet> --seq <list> [--out <p>] [--json] # withhold payloads; head UNCHANGED, still verifies
|
|
68
|
+
vh agent prove <packet> --seq <n> [--out <p>] [--json] # disclose ONE event + its inclusion proof
|
|
69
|
+
vh agent verify-proof <proof> [--root <hex>] [--json] # check a disclosure offline against a head you trust
|
|
70
|
+
vh agent checkpoint <session.jsonl> [--out <p>] [--json] # commit the head so far (mid-session)
|
|
71
|
+
vh agent verify-growth <earlier-head-or-packet> <later-packet> [--json] # append-only extension or REJECT
|
|
72
|
+
vh agent commit-claim --repo <dir> [--ref <ref=HEAD>] --seq <n> [--ts <iso>] [--actor <s>] [--out <p>] [--json]
|
|
73
|
+
# bind the session to a git commit (FREE, key-less)
|
|
74
|
+
vh agent verify-commit <packet> --repo <dir> [--ref <ref>] [--vendor <0xaddr>] [--json]
|
|
75
|
+
# auditor re-derives oid + root from THEIR OWN clone
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The input is JSONL (or a JSON array) of canonical events — a **closed** five-type schema:
|
|
79
|
+
`{ seq, ts, actor, type: prompt|completion|tool_call|tool_result|note, payload | payloadHash, redacted?, meta? }`
|
|
80
|
+
with `seq` contiguous from 0 (the tree position). Exit codes are the family contract: 0 ok/ACCEPTED,
|
|
81
|
+
3 named REJECT or gate-fail, 2 usage, 1 IO/invalid artifact. Artifacts are written only to an explicit
|
|
82
|
+
`--out` path, never implicitly to the working directory.
|
|
83
|
+
|
|
84
|
+
## Free vs. paid (no surprises)
|
|
85
|
+
|
|
86
|
+
- **FREE — the whole read/verify surface, forever:** unsigned `seal`, `verify`, `redact`, `prove`,
|
|
87
|
+
`verify-proof`, `checkpoint`, and `verify-growth`, plus every independent-verifier path below. Any
|
|
88
|
+
third party can check a packet without paying anyone; redaction and single-event disclosure are free
|
|
89
|
+
because withholding must never cost the *counterparty* anything to check.
|
|
90
|
+
- **PAID — `--sign`:** wrapping the packet's head in a detached EIP-191 attestation ("this key vouches
|
|
91
|
+
for THIS session head"), so a recipient can pin YOUR published address with `--vendor`. Because
|
|
92
|
+
leaves are redaction-safe, ONE signature stays valid for every redacted copy. `--sign` is gated
|
|
93
|
+
OFFLINE behind a valid `--license <f> --vendor <0xaddr>` carrying the DRAFT **`agent_signed`**
|
|
94
|
+
capability — the SAME fail-closed license mechanism as `vh evidence seal --sign` (`vh-evidence-license`
|
|
95
|
+
kind; a missing/invalid/under-entitled license is a named refusal, never a silent downgrade).
|
|
96
|
+
|
|
97
|
+
The `agent_signed` capability is DRAFT and priceless in the bundled catalog: the vendor key, the price,
|
|
98
|
+
and the sale remain the standing human-owned go-live steps of the evidence vertical (P-7/P-8 in
|
|
99
|
+
[`STRATEGY.md`](../STRATEGY.md), one flip in [`GO-LIVE.md`](GO-LIVE.md)) — this vertical adds **no new
|
|
100
|
+
human gate**, and revenue is a license for delivered software value, never a token or tradeable asset.
|
|
101
|
+
|
|
102
|
+
## Where the buyer independently verifies (no producer stack)
|
|
103
|
+
|
|
104
|
+
A counterparty handed a `*.vhagent.json` never has to trust the producer's tooling — the packet is
|
|
105
|
+
self-contained (no sibling files), and the independent [`verifier/`](../verifier/) tree re-implements
|
|
106
|
+
verification against its own keccak with **zero** imports from the producer stack:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
node verifier/verify-vh.js session.vhagent.json # unsigned packet — free, offline
|
|
110
|
+
node verifier/verify-vh.js session.vhagent.json --vendor 0xPRODUCER # signed packet, signer PINNED
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
- **Zero-install CLI:** the single self-contained file
|
|
114
|
+
[`verifier/dist/verify-vh-standalone.js`](../verifier/dist/verify-vh-standalone.js) (Node core only)
|
|
115
|
+
gives the same verdict with no clone and no `npm install`.
|
|
116
|
+
- **No terminal at all:** the offline browser page
|
|
117
|
+
[`verifier/dist/verify-vh-standalone.html`](../verifier/dist/verify-vh-standalone.html) has a
|
|
118
|
+
built-in agent-session demo (a sample packet with one payload already redacted — verify it, tamper
|
|
119
|
+
one byte on the page, watch the REJECT name the seq) and accepts a dropped real packet; it contains
|
|
120
|
+
no network API at all, so the transcript never leaves the machine.
|
|
121
|
+
|
|
122
|
+
Exit 0 = ACCEPTED, 3 = REJECTED naming the reason (and the offending event seq when event-local); a
|
|
123
|
+
`--vendor` pin on an unsigned packet is a clean REJECT, so a stripped signature never passes a pinned
|
|
124
|
+
verify. Details: [`verifier/README.md`](../verifier/README.md) §2c.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Binding a session to a git commit (`commit-claim` / `verify-commit`)
|
|
129
|
+
|
|
130
|
+
The first question the AI-code-governance / IP-provenance / audit buyer asks of an agent-session
|
|
131
|
+
record is: *which code change does this session correspond to — and can I check the record wasn't
|
|
132
|
+
doctored?* The commit-binding verbs answer it with machinery the family already ships. A
|
|
133
|
+
**commit-claim** is an ORDINARY `note` event whose payload is a canonical claim string naming exactly
|
|
134
|
+
ONE git **commit oid** plus that commit's **tracked-set root** — the same clone-reproducible Merkle
|
|
135
|
+
root `vh hash <repo> --git` computes over the files git tracks. Appended to the session log *before*
|
|
136
|
+
`vh agent seal`, the claim becomes one more redaction-safe leaf under the same head: no new packet
|
|
137
|
+
kind, no new crypto, no new dependency.
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
# producer (FREE, key-less): derive oid + tracked-set root from YOUR repo, emit ONE JSONL claim event
|
|
141
|
+
vh agent commit-claim --repo . --seq <next-seq> >> session.jsonl # then: vh agent seal session.jsonl …
|
|
142
|
+
|
|
143
|
+
# auditor (FREE, key-less): re-derive BOTH facts from THEIR OWN clone and check the sealed claim
|
|
144
|
+
vh agent verify-commit session.vhagent.json --repo /their/clone # exit 0 ACCEPTED / 3 named REJECT
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### What a commit-bound packet PROVES
|
|
148
|
+
|
|
149
|
+
- **The sealed, unaltered log contains a claim to exactly commit oid X with tracked-set root R at
|
|
150
|
+
position k.** The claim is an ordinary event leaf under the same head: editing, moving, or dropping
|
|
151
|
+
it — or doctoring any event around it — is the same named REJECT as any other tamper, and `k` (the
|
|
152
|
+
claim's `seq`) is bound by tree position, not by self-asserted metadata.
|
|
153
|
+
- **Anyone with a clean checkout of X re-derives R via the shipped `vh hash <repo> --git` machinery.**
|
|
154
|
+
`vh agent verify-commit` FIRST re-runs the full packet verification (a tampered or forged packet —
|
|
155
|
+
including a failed `--vendor` pin — never reaches the claim check), THEN re-resolves the oid and
|
|
156
|
+
RECOMPUTES the tracked-set root from the auditor's OWN clone; it never trusts the packet's stored
|
|
157
|
+
facts. A REJECT names the failed check: `packet-invalid` / `no-disclosed-claim` / `oid-mismatch` /
|
|
158
|
+
`root-mismatch`. Because `hashGit` reads work-tree bytes, a dirty checkout of the right commit is an
|
|
159
|
+
HONEST `root-mismatch` (the named fix: check out the claimed commit in a CLEAN tree), never a false
|
|
160
|
+
ACCEPT.
|
|
161
|
+
- **Redaction of any other payload leaves the claim checkable.** Leaves are redaction-safe, so the
|
|
162
|
+
producer can withhold every prompt/completion/tool payload and hand over a packet that still proves
|
|
163
|
+
the commit binding; redacting the CLAIM itself is, by definition, `no-disclosed-claim` — a withheld
|
|
164
|
+
claim is committed-to but not disclosable.
|
|
165
|
+
|
|
166
|
+
### What it does NOT prove
|
|
167
|
+
|
|
168
|
+
- **Containment, NOT causation — it does NOT prove the session's events produced the commit.** The
|
|
169
|
+
packet proves the sealed log CONTAINS the claim at position k; whether the recorded session actually
|
|
170
|
+
authored commit X is a real-world fact no hash can witness.
|
|
171
|
+
- **Not faithful recording.** The boundary above is unchanged: garbage-in is out of scope — if the
|
|
172
|
+
software that wrote the log lied before sealing, the packet faithfully preserves the lie, claim
|
|
173
|
+
included.
|
|
174
|
+
- **The claim's `ts` is self-asserted**, like every event `ts`: recorded verbatim, never verified
|
|
175
|
+
against any clock.
|
|
176
|
+
- **NOT a trusted timestamp.** "This session (or claim) existed at time T" still rides the human-owned
|
|
177
|
+
**P-3** trust-root ([`STRATEGY.md`](../STRATEGY.md) › Proposals — needs-human); a signed head proves
|
|
178
|
+
*who vouched* for the head, not *when*.
|
|
179
|
+
|
|
180
|
+
**The same wording rides in-band**: every `commit-claim` emission and every `verify-commit` verdict
|
|
181
|
+
carries this boundary as its `note`. Verbatim:
|
|
182
|
+
|
|
183
|
+
> A commit-claim is an ORDINARY session event binding a claim to EXACTLY one git commit oid and its tracked-set root (the `vh hash --git` work-tree root over the files git tracks at that commit). Sealed into a packet it proves CONTAINMENT, NOT CAUSATION: the unaltered log CONTAINS this claim — it does NOT prove the session's events PRODUCED that commit. The auditor re-derives BOTH facts from THEIR OWN clone via `vh agent verify-commit` (free, read-only, key-less); because hashGit reads WORK-TREE bytes, a dirty checkout is an HONEST root mismatch, never a false ACCEPT. `scope` is an UNVERIFIED hint; `ts` is SELF-ASSERTED metadata like every event ts. Every caveat of the agent-session packet applies (see `vh agent verify`).
|
|
184
|
+
|
|
185
|
+
### Free vs. paid, and where each leg verifies
|
|
186
|
+
|
|
187
|
+
`commit-claim` and `verify-commit` are **FREE**, read-only, and key-less end-to-end — the whole
|
|
188
|
+
commit-binding surface joins the free verify tier above. **`--sign` is unchanged behind the existing
|
|
189
|
+
gate** (the DRAFT `agent_signed` capability, same fail-closed license mechanism as above): commit
|
|
190
|
+
binding adds no new paid surface and no new human gate.
|
|
191
|
+
|
|
192
|
+
**The standalone-page boundary, honestly:** the zero-install page verifies the PACKET — seal, leaves,
|
|
193
|
+
head, signature, and the disclosed claim bytes; re-deriving the COMMIT facts requires git + a clone,
|
|
194
|
+
i.e. the CLI (`vh agent verify-commit`) is the auditor tool for that leg. A counterparty without git
|
|
195
|
+
can still check the packet is unaltered and read the claim; only the re-derivation leg needs a
|
|
196
|
+
checkout.
|
|
197
|
+
|
|
198
|
+
The scripted worked flow — map → `commit-claim` → seal → redact-all-but-claim → `verify-commit` — is
|
|
199
|
+
committed at
|
|
200
|
+
[`examples/agent-session/commit-bound-session.js`](../examples/agent-session/commit-bound-session.js)
|
|
201
|
+
and driven end-to-end (plus the tamper/dirty-checkout negatives) by
|
|
202
|
+
[`test/cli.agent.commit.docs.test.js`](../test/cli.agent.commit.docs.test.js), so it cannot rot.
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Adoption is a ~20-line mapping, not a platform migration (the worked example)
|
|
207
|
+
|
|
208
|
+
Your agent framework already writes a session log. The only integration you own is mapping its shape
|
|
209
|
+
into the canonical five-type event schema — and the committed, test-gated example
|
|
210
|
+
[`examples/agent-session/`](../examples/agent-session/) shows exactly that on a **realistic
|
|
211
|
+
third-party transcript**:
|
|
212
|
+
|
|
213
|
+
- [`examples/agent-session/transcript.openai.jsonl`](../examples/agent-session/transcript.openai.jsonl)
|
|
214
|
+
— an OpenAI-chat-completions-style `messages[]` + tool-calls JSONL export (system/user/assistant
|
|
215
|
+
roles, assistant `tool_calls`, `role:"tool"` results carrying PII worth redacting).
|
|
216
|
+
- [`examples/agent-session/map-transcript.js`](../examples/agent-session/map-transcript.js) — the
|
|
217
|
+
dependency-free mapper; the whole mapping sits between its `MAPPING BEGIN`/`MAPPING END` markers,
|
|
218
|
+
about twenty lines, with the size pinned by test.
|
|
219
|
+
|
|
220
|
+
The end-to-end flow (each command from the example's README, driven verbatim by
|
|
221
|
+
[`test/cli.agent.docs.test.js`](../test/cli.agent.docs.test.js) so it cannot rot):
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
node examples/agent-session/map-transcript.js --out $W/events.jsonl # 1. MAP (your 20 lines)
|
|
225
|
+
node cli/vh.js agent seal $W/events.jsonl --out $W/session.vhagent.json # 2. SEAL (free)
|
|
226
|
+
node cli/vh.js agent redact $W/session.vhagent.json --seq 3 \
|
|
227
|
+
--out $W/session.redacted.vhagent.json # 3. REDACT the PII tool result
|
|
228
|
+
node cli/vh.js agent verify $W/session.redacted.vhagent.json # 4. VERIFY — ACCEPTED, seq 3 withheld
|
|
229
|
+
node cli/vh.js agent prove $W/session.redacted.vhagent.json --seq 8 \
|
|
230
|
+
--out $W/event-8.proof.json # 5. PROVE the final completion…
|
|
231
|
+
node cli/vh.js agent verify-proof $W/event-8.proof.json # …and check it offline
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
The redacted copy verifies with the **identical head** as the full one; the withheld PII stays
|
|
235
|
+
checkable ("something was here, committed to, and withheld") without being disclosed.
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## How it relates to the rest of the family
|
|
240
|
+
|
|
241
|
+
Same core, different artifact: the leaf/root/proof math is the shipped RFC-6962 ordered-log core
|
|
242
|
+
([`cli/journal-log.js`](../cli/journal-log.js), the transparency-log engine in
|
|
243
|
+
[`INTEGRITY-JOURNAL.md`](INTEGRITY-JOURNAL.md)); the packet/trust-note/license disciplines are the
|
|
244
|
+
evidence family's ([`EVIDENCE.md`](EVIDENCE.md)); signing reuses the shared attestation envelope; and a
|
|
245
|
+
`vh.agent-session-packet` is kind-disjoint from every other artifact, so nothing cross-verifies as
|
|
246
|
+
something it is not. Boundary language across the family lives in
|
|
247
|
+
[`TRUST-BOUNDARIES.md`](TRUST-BOUNDARIES.md).
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Anchoring sealed artifacts on-chain — `vh anchor-artifact` / `vh verify-anchored`
|
|
2
|
+
|
|
3
|
+
Every verifyhash product ends in a **sealed artifact** whose integrity folds up into ONE 32-byte
|
|
4
|
+
digest. Anchoring writes that digest into the **ContributionRegistry** — the project's immutable,
|
|
5
|
+
permissionless, append-only contract — so an on-chain record binds the artifact at a block whose
|
|
6
|
+
timestamp **bounds its existence**. This is Option **(C)** of the STRATEGY.md **P-3** trust-root
|
|
7
|
+
menu: no timestamp authority, no signing-key custody — the chain itself is the witness.
|
|
8
|
+
|
|
9
|
+
The bridge is deliberately thin: the pure core (`cli/core/anchor-binding.js`) knows how to extract
|
|
10
|
+
the one canonical digest from each sealed artifact kind — re-validating it through the artifact's
|
|
11
|
+
**own shipped validator first** — and how to verify, **offline**, that an anchored receipt binds
|
|
12
|
+
exactly the artifact bytes in hand. The CLI (`cli/anchor-artifact.js`) adds the chain legs.
|
|
13
|
+
|
|
14
|
+
## The closed kind table (what can be anchored)
|
|
15
|
+
|
|
16
|
+
| artifact | kind string | anchored digest |
|
|
17
|
+
|---|---|---|
|
|
18
|
+
| Evidence packet (`vh evidence seal`) | `vh.evidence-seal` | the seal's Merkle `root` |
|
|
19
|
+
| Agent-session packet (`vh agent seal`) | `vh.agent-session-packet` | the **verified** head root |
|
|
20
|
+
| Journal tree head (`vh journal tree-head`) | `vh.journal-tree-head` | the head `root` (size bound into the derivation rule) |
|
|
21
|
+
| TrustLedger sealfile | `trustledger.reconcile-seal` | the seal's `root` |
|
|
22
|
+
| Dataset attestation (`vh dataset attest`) | `verifyhash.dataset-attestation` | `0x` + sha256 of the canonical bytes — the **same** digest `vh dataset timestamp-request` emits |
|
|
23
|
+
| Parcel attestation (`vh parcel attest`) | `verifyhash.parcel-attestation` | `0x` + sha256 of the canonical bytes — the **same** digest `vh parcel timestamp-request` emits |
|
|
24
|
+
|
|
25
|
+
The table is **closed**: an unknown or invalid artifact is a **named reject**, never a guess. One
|
|
26
|
+
artifact, one digest — the attestation legs reuse the exact digest your RFC-3161 TSA flow already
|
|
27
|
+
stamps, so Options (B) and (C) anchor the **same** identity.
|
|
28
|
+
|
|
29
|
+
## The command surface
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
vh anchor-artifact <sealed-file> --contract <addr> --rpc <url> (--key-env <VAR> | --key-file <p>)
|
|
33
|
+
[--author-bound] [--uri <s>] [--out <receipt>] [--json] [--i-understand-mainnet]
|
|
34
|
+
vh verify-anchored <receipt> <sealed-file> [--rpc <url> --contract <addr>] [--json]
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`anchor-artifact` extracts the digest, submits it as the registry `contentHash`, waits for the tx,
|
|
38
|
+
reads the record **back from the chain** (contributor / authorBound / blockNumber / block
|
|
39
|
+
timestamp), and emits the canonical, sorted-key **`vh-anchored-receipt@1`** container — digest +
|
|
40
|
+
derivation rule + chain facts + the trust note below, verbatim. The signing key comes **only** from
|
|
41
|
+
`--key-env <VAR>` / `--key-file <p>` (read, used, discarded — never generated, persisted, or
|
|
42
|
+
logged), and a chainId outside the known local/testnet set refuses without `--i-understand-mainnet`.
|
|
43
|
+
Exit contract: `0` anchored / `3` named reject (an invalid artifact, or the registry's own revert
|
|
44
|
+
such as `AlreadyAnchored`) / `2` usage / `1` IO-network-key.
|
|
45
|
+
|
|
46
|
+
`verify-anchored` is **OFFLINE by default** — no key, no network (but it runs through the producer
|
|
47
|
+
`cli/` stack, which loads `ethers`; "OFFLINE" here means **no key and no network**, NOT "no producer
|
|
48
|
+
stack" — the standalone `verifier/` tree does not yet verify anchored receipts, see **Independent
|
|
49
|
+
verification** below): it validates the receipt strictly and **recomputes** the artifact's digest
|
|
50
|
+
through the same closed table; any deviation is a specific named reject (`digest-mismatch` /
|
|
51
|
+
`kind-mismatch` / `how-mismatch` / `bad-receipt` / the artifact's own named reject). With **both** `--rpc` and `--contract` it additionally authenticates the registry
|
|
52
|
+
(the standing identity probe — no record is believed until the contract self-identifies) and
|
|
53
|
+
re-checks every chain fact the receipt claims. Exit `0` ACCEPTED / `3` REJECTED / `2` / `1` — the
|
|
54
|
+
shared CI-gateable verify contract.
|
|
55
|
+
|
|
56
|
+
## What an anchored receipt PROVES
|
|
57
|
+
|
|
58
|
+
- **The binding.** An on-chain registry record binds **this exact artifact digest**: `verify-anchored`
|
|
59
|
+
re-derives the digest from the artifact bytes you hold (through the artifact's own validator) and
|
|
60
|
+
matches it against the receipt and — with `--rpc` — against the chain record itself.
|
|
61
|
+
- **Existence by block time.** The record's block timestamp **BOUNDS existence**: the digest existed
|
|
62
|
+
by that block — as trustworthy as the chain + YOUR pinned contract address.
|
|
63
|
+
- **Attribution, exactly as strong as D-1.** With `--author-bound` the record reads back `authorBound:true` — front-run-resistant, first-claimant attribution per D-1 (commit-reveal: the commitment binds digest + committer + a secret salt, so a mempool copier cannot redirect the claim to themselves). The default one-shot `anchor()` records only the **first broadcaster** (`authorBound:false`).
|
|
64
|
+
|
|
65
|
+
## What it does NOT prove (the honest boundary)
|
|
66
|
+
|
|
67
|
+
Every receipt carries this note **in-band, verbatim** (an edited note is a named `bad-receipt`):
|
|
68
|
+
|
|
69
|
+
> This anchored receipt binds the artifact digest above to an on-chain registry record. A receipt from a LOCAL dev chain proves MECHANISM only and is worth NOTHING publicly until a human deploys the registry (STRATEGY.md P-2). On a public chain it proves ONLY that an on-chain record binds this exact digest at a block whose timestamp BOUNDS existence — as trustworthy as the chain + YOUR pinned contract address — NOT the artifact's truth, NOT faithful recording, NOT attribution beyond the anchoring key. The `chain` facts in this receipt are the anchorer's claim until re-checked against the chain (`vh verify-anchored --rpc`).
|
|
70
|
+
|
|
71
|
+
Spelled out:
|
|
72
|
+
|
|
73
|
+
- **A LOCAL dev-chain receipt proves MECHANISM only.** The committed fixtures below and every test
|
|
74
|
+
in this repo anchor on an ephemeral local chain (chainId `31337`) — that demonstrates the pipeline
|
|
75
|
+
works end to end, and **nothing more**. Until a human deploys the registry to a public chain
|
|
76
|
+
(STRATEGY.md **P-2**), no receipt from this repo is worth anything publicly.
|
|
77
|
+
- **NOT the artifact's truth or faithful recording.** Anchoring binds bytes, not reality: a sealed
|
|
78
|
+
evidence packet's files, an agent log's events, a dataset's provenance hints are exactly as true
|
|
79
|
+
as they were before anchoring (see each product's own trust note — garbage in is out of scope).
|
|
80
|
+
- **NOT attribution beyond the anchoring key.** Even `authorBound:true` proves only that the
|
|
81
|
+
**key-holder** was the front-run-resistant first claimant — it does not identify a person or
|
|
82
|
+
organization; pin the key out of band (see `docs/KEY-LIFECYCLE.md`).
|
|
83
|
+
- **NOT legal advice** and NOT a compliance verdict.
|
|
84
|
+
- **Options (A) and (B) of P-3 remain INDEPENDENT trust-roots a buyer may also require.** A
|
|
85
|
+
publisher signature (A: `vh dataset/parcel sign`) proves *who vouched*; an RFC-3161 TSA token (B:
|
|
86
|
+
`timestamp-request`/`timestamp-wrap`/`verify-timestamp`) is a third party's *existed-by-genTime*
|
|
87
|
+
attestation. An on-chain anchor (C) complements them; it does not replace them.
|
|
88
|
+
|
|
89
|
+
## Independent verification — the one axis this does NOT yet cover
|
|
90
|
+
|
|
91
|
+
The verifyhash family's headline is that a counterparty can verify a sealed artifact **OFFLINE,
|
|
92
|
+
without installing the producer's stack**: the standalone `verifier/` bundle
|
|
93
|
+
([`../verifier/dist/verify-vh-standalone.js`](../verifier/dist/verify-vh-standalone.js)) is a single,
|
|
94
|
+
dependency-free file — **no `ethers`, no `npm install`** — that re-derives an evidence packet's or
|
|
95
|
+
agent packet's digest by itself. That promise **DOES** cover the **sealed artifact underneath** an
|
|
96
|
+
anchored receipt: hand a counterparty the `*.vhevidence.json` (or any closed-table artifact) and they
|
|
97
|
+
verify it standalone, exactly as before, with no producer code.
|
|
98
|
+
|
|
99
|
+
It does **NOT yet extend to the anchored receipt itself.** `vh verify-anchored` — including its
|
|
100
|
+
OFFLINE binding leg — runs **only through the producer `cli/` stack, which loads `ethers` at module
|
|
101
|
+
load** (`cli/anchor-artifact.js` → `cli/core/attestation.js`); and `vh-anchored-receipt@1` is **NOT a
|
|
102
|
+
recognized kind** in the standalone `verifier/verify-vh.js` tree, which scopes itself to sealed
|
|
103
|
+
artifacts and explicitly puts on-chain anchoring out of scope. So the family's zero-install
|
|
104
|
+
"verify without the producer's stack" promise **does not YET reach the anchored-receipt binding
|
|
105
|
+
leg**: a counterparty who wants to check the receipt's binding today must run the producer cli
|
|
106
|
+
(`node cli/vh.js verify-anchored`).
|
|
107
|
+
|
|
108
|
+
This is a **packaging gap, not a proof gap.** (1) The binding check is pure hashing — the standalone
|
|
109
|
+
verifier already re-derives evidence-seal and agent-packet digests with no `ethers` — so
|
|
110
|
+
`vh-anchored-receipt@1` can be added to the standalone tree to actually close it (tracked as
|
|
111
|
+
**T-70.4**). (2) The `--rpc` chain re-check needs the chain anyway, so the offline binding leg's
|
|
112
|
+
standalone value is limited until then. Until T-70.4 lands: verify the **sealed artifact** standalone
|
|
113
|
+
(zero-install, independent), and verify the **anchor** via the producer cli.
|
|
114
|
+
|
|
115
|
+
## The free line
|
|
116
|
+
|
|
117
|
+
Both verbs are FREE — no paid gate, no license, no entitlement: the only cost is the chain's own gas, and the gas is YOUR OWN (paid from a key you provision and hold; `vh verify-anchored` needs no key at all).
|
|
118
|
+
|
|
119
|
+
## The worked local flow (seal → anchor → verify offline → verify against the chain)
|
|
120
|
+
|
|
121
|
+
The whole flow runs on a **local** hardhat node — remember the boundary: this proves **mechanism
|
|
122
|
+
only**.
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# 0. a LOCAL dev chain + a local registry (terminal 1, then terminal 2):
|
|
126
|
+
npx hardhat node --hostname 127.0.0.1 --port 8545
|
|
127
|
+
npx hardhat run scripts/deploy.js --network localhost # prints the registry address
|
|
128
|
+
export VH_DEV_KEY=0x... # a LOCAL pre-funded dev key — never a real key
|
|
129
|
+
|
|
130
|
+
# 1. seal — any closed-table artifact works; here, an evidence packet:
|
|
131
|
+
node cli/vh.js evidence seal ./report --out report.vhevidence.json
|
|
132
|
+
|
|
133
|
+
# 2. anchor — write the digest on-chain, emit the anchored receipt:
|
|
134
|
+
node cli/vh.js anchor-artifact report.vhevidence.json --contract <addr> --rpc http://127.0.0.1:8545 \
|
|
135
|
+
--key-env VH_DEV_KEY --author-bound --out report.anchored.json
|
|
136
|
+
|
|
137
|
+
# 3. verify OFFLINE — no key, no network; the receipt binds EXACTLY this artifact:
|
|
138
|
+
node cli/vh.js verify-anchored report.anchored.json report.vhevidence.json
|
|
139
|
+
|
|
140
|
+
# 4. verify against the CHAIN — authenticate the registry, re-check every chain fact:
|
|
141
|
+
node cli/vh.js verify-anchored report.anchored.json report.vhevidence.json \
|
|
142
|
+
--rpc http://127.0.0.1:8545 --contract <addr>
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**Zero-setup offline leg.** The repo commits a real sample pair under
|
|
146
|
+
[`examples/anchoring/`](../examples/anchoring/) — a sealed evidence packet and the
|
|
147
|
+
`vh-anchored-receipt@1` a local run produced (chainId `31337`, `authorBound:true`). Step 3 runs
|
|
148
|
+
against them with no chain at all:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
node cli/vh.js verify-anchored examples/anchoring/anchored-receipt.local.json examples/anchoring/sample-seal.vhevidence.json
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
It prints `ACCEPTED (offline binding check)` and exits `0`; flip one byte of either file and it is a
|
|
155
|
+
named reject, exit `3`. (`test/anchoring.docs.test.js` runs exactly this leg.)
|
|
156
|
+
|
|
157
|
+
## Going public — the standing human gate (P-2)
|
|
158
|
+
|
|
159
|
+
Everything above is built, tested, and free to run — against a **local** chain. The single missing
|
|
160
|
+
step for receipts that are worth something publicly is the standing **P-2** deploy, which is a
|
|
161
|
+
**human** action the loop never takes: provision a THROWAWAY faucet-funded testnet key, deploy to
|
|
162
|
+
**Polygon Amoy first** (`scripts/deploy.js`), verify the source on the explorer, and publish the
|
|
163
|
+
address so consumers can **pin** it. From that moment the exact commands above work unchanged —
|
|
164
|
+
point `--rpc` at Amoy and `--contract` at YOUR pinned address — and every sealed artifact in the
|
|
165
|
+
family gains "digest existed by public-chain block time T", with `--author-bound` front-run
|
|
166
|
+
resistance, for the price of gas. The loop itself still NEVER deploys, holds funds, or anchors
|
|
167
|
+
publicly (see STRATEGY.md P-2/P-3).
|