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.
Files changed (154) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +883 -0
  3. package/cli/abi/ContributionRegistry.json +881 -0
  4. package/cli/agent.js +2173 -0
  5. package/cli/anchor-artifact.js +853 -0
  6. package/cli/anchor.js +400 -0
  7. package/cli/claim.js +881 -0
  8. package/cli/core/agent-commit.js +448 -0
  9. package/cli/core/agent-session.js +598 -0
  10. package/cli/core/anchor-binding.js +663 -0
  11. package/cli/core/attestation.js +580 -0
  12. package/cli/core/evidence-plans.js +495 -0
  13. package/cli/core/fixtures/evidence-plans/baseline.json +19 -0
  14. package/cli/core/fulfill-intake.js +1082 -0
  15. package/cli/core/go-live-preflight.js +481 -0
  16. package/cli/core/license.js +534 -0
  17. package/cli/core/manifest.js +243 -0
  18. package/cli/core/packetseal.js +591 -0
  19. package/cli/core/registryArtifact.js +49 -0
  20. package/cli/core/revocation.js +539 -0
  21. package/cli/core/rfc3161.js +389 -0
  22. package/cli/core/timestamp.js +482 -0
  23. package/cli/core/trust-asof.js +479 -0
  24. package/cli/dataset.js +2950 -0
  25. package/cli/evidence.js +2227 -0
  26. package/cli/fulfill-webhook-http.js +438 -0
  27. package/cli/git.js +220 -0
  28. package/cli/hash.js +550 -0
  29. package/cli/identity.js +1072 -0
  30. package/cli/journal-cli.js +1110 -0
  31. package/cli/journal-log.js +454 -0
  32. package/cli/journal.js +334 -0
  33. package/cli/lineage.js +447 -0
  34. package/cli/list.js +287 -0
  35. package/cli/parcel.js +1509 -0
  36. package/cli/proof.js +578 -0
  37. package/cli/prove.js +300 -0
  38. package/cli/receipt.js +631 -0
  39. package/cli/registry.js +331 -0
  40. package/cli/reputation.js +344 -0
  41. package/cli/revocation.js +495 -0
  42. package/cli/serve-verify-http.js +298 -0
  43. package/cli/serve-verify.js +333 -0
  44. package/cli/show.js +339 -0
  45. package/cli/verify.js +383 -0
  46. package/cli/vh.js +3927 -0
  47. package/docs/ADOPT.md +183 -0
  48. package/docs/ADOPTION.json +11 -0
  49. package/docs/AGENTTRACE.md +247 -0
  50. package/docs/ANCHORING.md +167 -0
  51. package/docs/AUDIT.md +55 -0
  52. package/docs/CONFORMANCE.md +107 -0
  53. package/docs/DATALEDGER.md +638 -0
  54. package/docs/DECIDE.md +47 -0
  55. package/docs/DECISIONS-PENDING.md +27 -0
  56. package/docs/DEPLOY-PUBLIC-SITE.md +301 -0
  57. package/docs/ENGINE-LEDGER.json +12 -0
  58. package/docs/EVIDENCE.md +519 -0
  59. package/docs/GO-LIVE.md +66 -0
  60. package/docs/IDENTITY.md +123 -0
  61. package/docs/INDEPENDENT-VERIFICATION.md +377 -0
  62. package/docs/INTEGRITY-JOURNAL.md +337 -0
  63. package/docs/KEY-LIFECYCLE.md +179 -0
  64. package/docs/LICENSING.md +46 -0
  65. package/docs/LINEAGE.md +307 -0
  66. package/docs/LOOP-AUDIT-2026-07-03.json +580 -0
  67. package/docs/LOOP-HARDENING-PLAN.md +44 -0
  68. package/docs/MERKLE-LEAVES.md +113 -0
  69. package/docs/METRICS.jsonl +31 -0
  70. package/docs/MORNING.md +204 -0
  71. package/docs/PILOT.md +444 -0
  72. package/docs/PROOFPARCEL.md +227 -0
  73. package/docs/PROOFS.md +262 -0
  74. package/docs/RECEIPTS.md +341 -0
  75. package/docs/REPUTATION.md +158 -0
  76. package/docs/SDK.md +301 -0
  77. package/docs/STRATEGY-ARCHIVE.md +5055 -0
  78. package/docs/SUPERVISOR-RUNBOOK.md +52 -0
  79. package/docs/TRUST-BOUNDARIES.md +335 -0
  80. package/docs/TRUSTLEDGER.md +1976 -0
  81. package/docs/USAGE-BUDGET.json +121 -0
  82. package/docs/VERIFY-SERVICE.md +168 -0
  83. package/index.js +160 -0
  84. package/package.json +41 -0
  85. package/trustledger/build-standalone.js +796 -0
  86. package/trustledger/cli.js +3179 -0
  87. package/trustledger/close.js +391 -0
  88. package/trustledger/corpus.js +159 -0
  89. package/trustledger/dist/BUILD-PROVENANCE.json +99 -0
  90. package/trustledger/dist/trustledger-standalone.html +6197 -0
  91. package/trustledger/dist/trustledger-standalone.html.sha256 +1 -0
  92. package/trustledger/door-core.js +442 -0
  93. package/trustledger/fixtures/bank.csv +7 -0
  94. package/trustledger/fixtures/bank.malformed.csv +3 -0
  95. package/trustledger/fixtures/bank.noalias.csv +5 -0
  96. package/trustledger/fixtures/bank.ofx +34 -0
  97. package/trustledger/fixtures/bank.real.csv +5 -0
  98. package/trustledger/fixtures/corpus/_shared/prior-close.json +22 -0
  99. package/trustledger/fixtures/corpus/bank-book-mismatch--benign-twin/inputs.json +14 -0
  100. package/trustledger/fixtures/corpus/bank-book-mismatch--benign-twin/meta.json +7 -0
  101. package/trustledger/fixtures/corpus/bank-book-mismatch--out-of-trust/inputs.json +14 -0
  102. package/trustledger/fixtures/corpus/bank-book-mismatch--out-of-trust/meta.json +7 -0
  103. package/trustledger/fixtures/corpus/continuity-break--benign-twin/inputs.json +15 -0
  104. package/trustledger/fixtures/corpus/continuity-break--benign-twin/meta.json +7 -0
  105. package/trustledger/fixtures/corpus/continuity-break--out-of-trust/inputs.json +15 -0
  106. package/trustledger/fixtures/corpus/continuity-break--out-of-trust/meta.json +7 -0
  107. package/trustledger/fixtures/corpus/negative-tenant-ledger--benign-twin/inputs.json +13 -0
  108. package/trustledger/fixtures/corpus/negative-tenant-ledger--benign-twin/meta.json +7 -0
  109. package/trustledger/fixtures/corpus/negative-tenant-ledger--out-of-trust/inputs.json +13 -0
  110. package/trustledger/fixtures/corpus/negative-tenant-ledger--out-of-trust/meta.json +7 -0
  111. package/trustledger/fixtures/corpus/owner-overdraw--benign-twin/inputs.json +15 -0
  112. package/trustledger/fixtures/corpus/owner-overdraw--benign-twin/meta.json +7 -0
  113. package/trustledger/fixtures/corpus/owner-overdraw--out-of-trust/inputs.json +15 -0
  114. package/trustledger/fixtures/corpus/owner-overdraw--out-of-trust/meta.json +7 -0
  115. package/trustledger/fixtures/corpus/security-deposit-segregation--benign-twin/inputs.json +16 -0
  116. package/trustledger/fixtures/corpus/security-deposit-segregation--benign-twin/meta.json +7 -0
  117. package/trustledger/fixtures/corpus/security-deposit-segregation--out-of-trust/inputs.json +13 -0
  118. package/trustledger/fixtures/corpus/security-deposit-segregation--out-of-trust/meta.json +7 -0
  119. package/trustledger/fixtures/corpus/subledger-out-of-balance--benign-twin/inputs.json +13 -0
  120. package/trustledger/fixtures/corpus/subledger-out-of-balance--benign-twin/meta.json +7 -0
  121. package/trustledger/fixtures/corpus/subledger-out-of-balance--out-of-trust/inputs.json +13 -0
  122. package/trustledger/fixtures/corpus/subledger-out-of-balance--out-of-trust/meta.json +7 -0
  123. package/trustledger/fixtures/e2e/bank.aliased.csv +4 -0
  124. package/trustledger/fixtures/e2e/bank.csv +4 -0
  125. package/trustledger/fixtures/e2e/bank.nsf.csv +4 -0
  126. package/trustledger/fixtures/e2e/quickbooks.csv +6 -0
  127. package/trustledger/fixtures/e2e/quickbooks.nsf.csv +8 -0
  128. package/trustledger/fixtures/e2e/rentroll.csv +6 -0
  129. package/trustledger/fixtures/e2e/rentroll.nsf.csv +8 -0
  130. package/trustledger/fixtures/e2e/rentroll.short.csv +5 -0
  131. package/trustledger/fixtures/plans/baseline.json +25 -0
  132. package/trustledger/fixtures/plans/price-binding.example.json +27 -0
  133. package/trustledger/fixtures/policy/ambiguous-deposit-example.json +12 -0
  134. package/trustledger/fixtures/policy/baseline.json +19 -0
  135. package/trustledger/fixtures/policy/ca-example.json +12 -0
  136. package/trustledger/fixtures/policy/negative-tenant-ledger-example.json +12 -0
  137. package/trustledger/fixtures/policy/owner-overdraw-example.json +12 -0
  138. package/trustledger/fixtures/quickbooks.csv +7 -0
  139. package/trustledger/fixtures/quickbooks.real.csv +5 -0
  140. package/trustledger/fixtures/rentroll.csv +6 -0
  141. package/trustledger/fixtures/rentroll.real.csv +4 -0
  142. package/trustledger/ingest.js +1163 -0
  143. package/trustledger/lib/policy-bundled-loader.js +44 -0
  144. package/trustledger/lib/sha256-vendored.js +227 -0
  145. package/trustledger/license.js +563 -0
  146. package/trustledger/match.js +551 -0
  147. package/trustledger/plans.js +551 -0
  148. package/trustledger/policy.js +398 -0
  149. package/trustledger/public/index.html +512 -0
  150. package/trustledger/reconcile.js +1486 -0
  151. package/trustledger/report.js +887 -0
  152. package/trustledger/seal.js +854 -0
  153. package/trustledger/server.js +391 -0
  154. package/trustledger/valueproof.js +350 -0
package/docs/DECIDE.md ADDED
@@ -0,0 +1,47 @@
1
+ # DECIDE — the one human decision
2
+
3
+ This is the **only** page a human needs to read to unblock the loop. Everything below is BUILT and
4
+ locally TESTED; the loop cannot take the one remaining step for you, because it must never provision a
5
+ key, set a price, or contact a buyer. There is exactly one open human item, and it is `needs-human` P-8
6
+ (see [`docs/MORNING.md`](MORNING.md) § Needs-human). This page does not add a new ask — it just makes P-8
7
+ legible on one screen. **It is GENERATED from the P-8 block in MORNING.md (`scripts/sync-decide.cjs`), so
8
+ it can never silently drift from the real ask.**
9
+
10
+ ## The decision (pick this)
11
+
12
+ **Run ONE time-boxed design-partner pilot of the EVIDENCE vertical (P-7).** EVIDENCE is the
13
+ lighter-gated path: no CPA, no counsel, no per-state liability layer, no real-funds deploy — just a
14
+ vendor key, a price, and one partner. (The heavier TrustLedger vertical, P-5, is the fallback channel.)
15
+
16
+ ## The 3 first actions (verbatim from P-8)
17
+
18
+ 1. **Pick the lighter-gated vertical FIRST: EVIDENCE (P-7), not TrustLedger (P-5)** — no CPA/legal/per-state
19
+ 2. **One concrete first target this week:** an incident-response / digital-forensics team OR an
20
+ 3. **3-step first contact (no slide deck):** (a) `vh identity publish` once the vendor key exists; (b) hand
21
+
22
+ ## The one command to run on their folder
23
+
24
+ ```
25
+ node pilot/run-pilot.js --certificate <path>
26
+ ```
27
+
28
+ Add `--evidence-dir /path/to/their/folder` to seal THEIR files; the result is a single, forwardable
29
+ `*.vhevidence.json` certificate their security team verifies independently with `verify-vh` — offline, no
30
+ key, no network. The full runbook is [`docs/PILOT.md`](PILOT.md).
31
+
32
+ ## Time box / stop criterion
33
+
34
+ 3–5 prospects over ~2 weeks. **Success = ONE** who keeps using the free verify/challenge weekly OR agrees
35
+ to a paid pilot. **Zero after the box → stop**: the signal is "wrong buyer archetype" → switch to the
36
+ TrustLedger broker channel, NOT "build more product."
37
+
38
+ ## Revenue-integrity boundary
39
+
40
+ Income is a subscription / license / meter for delivered software value; the license is an
41
+ ACCESS credential, NOT a token/coin/NFT, not tradeable, not an appreciating asset. The loop ships only the
42
+ mechanism + ephemeral test keys and must NEVER provision a key, set a price, contact a prospect, host,
43
+ take payment, or run the pilot itself — those are the human steps in P-8.
44
+
45
+
46
+ ---
47
+ <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,27 @@
1
+ # The 3 decisions that unblock everything (one page)
2
+
3
+ Audit 2026-07-03: the ~11 stacked `needs-human` proposals in STRATEGY.md reduce to THREE distinct
4
+ decisions. Each has a pre-filled recommended default — **replying "accept all defaults" is a valid,
5
+ complete answer.** Everything else in the queue is a duplicate or depends on these.
6
+
7
+ ## 1. Reputation unit: soulbound or tradeable? (P-1 / D-2)
8
+ **Default: (A) soulbound, non-transferable contribution score.** Zero securities exposure, matches the
9
+ project goal, buildable immediately. Option (B) tradeable token requires securities counsel BEFORE any
10
+ design work and pulls the project toward being a token project. → One word unblocks EPIC-3.
11
+
12
+ ## 2. First-dollar config: price + vendor key (collapses P-3/P-5/P-6/P-7/P-9/P-10)
13
+ **Default:** self-serve **evidence license** at **$29/month or $290/year** (draft catalog price),
14
+ vendor key provisioned by YOU on your machine (never the loop):
15
+ `node -e "const {Wallet}=require('ethers');const w=Wallet.createRandom();console.log(w.address, w.privateKey)"`
16
+ — keep the private key in your password manager; publish only the address. The whole mint→deliver→verify
17
+ pipeline is already built and gated (`npm run go-live` proves it end-to-end). → A price + a key = sellable.
18
+
19
+ ## 3. Distribution: put the free tool in front of real people (the audit's #1 finding)
20
+ **Default:** (a) publish the package to npm (`npm publish` from your logged-in account — the package is
21
+ ready), (b) show the zero-install browser verifier (verifyhash.com/verify-vh-standalone.html) to ~10
22
+ people in ONE segment — recommended: AI-agent builders (AGENTTRACE angle) or property managers
23
+ (TrustLedger angle) — and count who uses it twice. That count becomes `docs/ADOPTION.json`, the loop's
24
+ first external signal. **No new product epics until it is non-zero.**
25
+
26
+ ---
27
+ *Answering #2 + #3 makes the first dollar mechanically possible. #1 just unblocks a parked epic.*
@@ -0,0 +1,301 @@
1
+ # verifyhash.com — Public Static Site Deployment Runbook (REPLACE mode)
2
+
3
+ > **Audience:** a Claude instance (or operator) with privileges this repo's autonomous loop does
4
+ > **not** have — i.e. can write to `/var/www/`, edit files under `/etc/nginx/`, and `sudo systemctl
5
+ > reload nginx`. Hand this whole file over; it is self-contained.
6
+ >
7
+ > **This file is an internal ops/deploy doc — do NOT serve it.** It is not in the publish set.
8
+ >
9
+ > Generated by the verifyhash loop supervisor, 2026-06-26. Hash source of truth = the committed
10
+ > `*.sha256` sidecars in `verifier/dist/`; the build script re-verifies, so don't trust this doc's copy.
11
+
12
+ ## ENVIRONMENT — already in place (confirmed 2026-06-26 19:49Z)
13
+
14
+ - **Domain `verifyhash.com`** (+`www`) → resolves to **this host** (85.215.206.196). DNS done.
15
+ - **TLS done** — Let's Encrypt cert live at `/etc/letsencrypt/live/verifyhash.com/`; HTTPS serves HTTP/2 200.
16
+ - **nginx vhost exists**: `/etc/nginx/conf.d/verifyhash.com.conf` (http→https redirect, `root /var/www/verifyhash.com/html`, a static-asset cache `location`, a `location /api/ → localhost:3005` proxy, and a `.git` deny).
17
+ - **The webroot already holds a DIFFERENT, older site** — *"VerifyHash — Decentralized JSON Storage Network"* (`index.html` + `js/`) with a Node backend proxied at `/api/ → :3005` that is currently **down (502)**. **Decision: REPLACE it.** This runbook retires that old site and serves the provenance product at the `verifyhash.com` root.
18
+
19
+ So there is **no DNS, no certbot, no nginx install** to do. The job is: (1) swap the webroot contents, (2) two small vhost edits, (3) reload, (4) verify.
20
+
21
+ ---
22
+
23
+ ## 0. What you are deploying (and what you are NOT)
24
+
25
+ A **static, read-only** site publishing verifyhash's independent-verification artifacts:
26
+ - the single-file, zero-dependency, **offline** verifier `verify-vh-standalone.js` + its `sha256`,
27
+ - the companion offline **sealer** `seal-vh-standalone.js` + `sha256`,
28
+ - the **build-provenance manifest** `build-provenance.json`,
29
+ - the version-controlled **landing page** (`site/index.html` — download links, verify one-liner, reproduce-from-source steps, honest boundary),
30
+ - the **prospect-facing docs** (CONFORMANCE, PILOT, KEY-LIFECYCLE, INDEPENDENT-VERIFICATION, …),
31
+ - a generated **`RELEASE-MANIFEST.json`** (sorted paths, per-file sha256 + source, total bytes) so the upload can be verified file-by-file.
32
+
33
+ The exact publish set is the committed allowlist **`site/publish-set.json`** (published path → committed
34
+ repo source). `scripts/site-release.js` assembles the webroot from EXACTLY that mapping — nothing outside
35
+ it can enter `public/`, which makes the "must NEVER be served" table below *structural*, not just prose.
36
+
37
+ **NOT** in scope (deliberately): no backend, no uploads, no API, no DB, no key, no payment, no token.
38
+ The product's trust model is *offline* verification — a server that "verifies for you" would weaken it.
39
+ (The repo's one server, `trustledger/server.js`, is a separate localhost-only broker demo, not part of this site.)
40
+
41
+ ---
42
+
43
+ ## 1. ⚠️ CRITICAL SAFETY RULES — read before touching anything
44
+
45
+ The nginx `root` for verifyhash.com must stay **`/var/www/verifyhash.com/html`** and that directory
46
+ must contain **only** the allowlisted static files below. A scan of this box found **real secrets** that
47
+ would be catastrophic to expose if the webroot were ever pointed at the repo or home dir.
48
+
49
+ **NEVER set `root`/`alias`/`try_files` to** `/home/loopdev/verifyhash` (repo), `/home/loopdev` (home),
50
+ or anything but the dedicated webroot. **Deploy by copying real files — never symlink into the repo.**
51
+
52
+ **Must NEVER be served:**
53
+
54
+ | Path | Why |
55
+ |---|---|
56
+ | `/home/loopdev/.claude/.credentials.json` | **LIVE Claude.ai OAuth token** — the single most dangerous file on the box. |
57
+ | `/home/loopdev/.claude.json`, `/home/loopdev/.claude/` | CLI config + full transcripts / session history / memory. |
58
+ | `/home/loopdev/verifyhash/.git/` | 38 MB history — clonable = the whole repo incl. every internal doc. |
59
+ | `test/cli.commit.parent.test.js`, `test/cli.claim.test.js` | committed `0x…` **private keys** (Hardhat dev keys; no real funds, but scanners flag them). |
60
+ | `.env` (none today; pre-deny), `**/*.vhclaim.json` (secret salt; pre-deny) | would leak keys/salts. |
61
+ | `STRATEGY.md`, `BACKLOG.md`, `HANDOFF.md`, `AGENT_TEAM.md`, `team.json` | internal roadmap / ops. |
62
+ | `build-loop.workflow.js`, `build-loop.prev.js` | the autonomous loop engine + guardrails. |
63
+ | `docs/USAGE-BUDGET.json`, `docs/METRICS.jsonl`, `docs/MORNING.md`, `docs/AUDIT.md`, `docs/DEPLOY-PUBLIC-SITE.md` | internal ops telemetry + this runbook. |
64
+ | `node_modules/`, `artifacts/`, `cache/`, `scripts/`, `hardhat.config.js`, `.scope-baseline.json` | build internals. |
65
+
66
+ The safe pattern below `rsync --delete`s a vetted, allowlist-only tree into the webroot — nothing else
67
+ can leak because nothing else is ever copied there. (Scan also confirmed: no real `.env`, no PEM/SSH
68
+ keys, no mnemonics, no API keys anywhere. The only risk is *where nginx points*.)
69
+
70
+ ---
71
+
72
+ ## 2. Prerequisites (most are already satisfied)
73
+
74
+ - ✅ Domain, DNS, TLS, nginx — all already in place for verifyhash.com (see ENVIRONMENT).
75
+ - You need: `sudo` (to write `/var/www/verifyhash.com/html` and edit the vhost), `rsync`, and `node`
76
+ (only to run the one-time `--check` integrity gate; the site needs no node at runtime).
77
+ - Read access to `/home/loopdev/verifyhash` (to copy the artifacts from).
78
+
79
+ ---
80
+
81
+ ## 3. Deploy the webroot (replaces the old site)
82
+
83
+ **The upload step is:** run `node scripts/site-release.js`, upload `public/`, verify against
84
+ `RELEASE-MANIFEST.json`. The assembler regenerates `public/` **deterministically** from the committed
85
+ allowlist `site/publish-set.json` (nothing outside the allowlist can enter the webroot), and
86
+ `--check` re-proves byte-for-byte integrity before you copy anything.
87
+
88
+ ### 3a — assemble + integrity gate, then atomic replace
89
+
90
+ ```bash
91
+ set -euo pipefail
92
+ REPO=/home/loopdev/verifyhash
93
+ SRC="$REPO/public" # the assembled, allowlist-only webroot
94
+ WEBROOT=/var/www/verifyhash.com/html
95
+
96
+ # 1) ASSEMBLE the webroot from the committed publish set (deterministic; writes only inside the repo)
97
+ node "$REPO/scripts/site-release.js"
98
+
99
+ # 2) INTEGRITY GATE — refuse to deploy a tampered/stale webroot (offline, writes nothing)
100
+ node "$REPO/scripts/site-release.js" --check # MUST print OK and exit 0
101
+ ( cd "$REPO/verifier/dist" && sha256sum -c verify-vh-standalone.js.sha256 && sha256sum -c seal-vh-standalone.js.sha256 )
102
+ node "$REPO/verifier/build-standalone.js" --check # MUST print all-MATCH and exit 0
103
+ ( cd "$SRC" && sha256sum -c verify-vh-standalone.js.sha256 && sha256sum -c seal-vh-standalone.js.sha256 )
104
+
105
+ # 3) back up the OLD site once, then REPLACE it (—delete removes anything not in the publish set)
106
+ sudo cp -a "$WEBROOT" "/var/www/verifyhash.com/html.bak.$(date +%Y%m%d-%H%M%S)" || true
107
+ sudo rsync -a --delete "$SRC"/ "$WEBROOT"/
108
+
109
+ # 4) ownership nginx expects
110
+ sudo chown -R www-data:www-data "$WEBROOT"
111
+
112
+ # 5) VERIFY THE UPLOAD against the manifest that shipped inside it (per-file sha256, all must match)
113
+ ( cd "$WEBROOT" && node -e '
114
+ const fs=require("fs"),c=require("crypto");
115
+ const m=JSON.parse(fs.readFileSync("RELEASE-MANIFEST.json","utf8"));let bad=0;
116
+ for(const f of m.files){const h=c.createHash("sha256").update(fs.readFileSync(f.path)).digest("hex");
117
+ if(h!==f.sha256){bad++;console.error("MISMATCH "+f.path);}}
118
+ console.log(bad?"UPLOAD BROKEN — do not announce":"upload verified: "+m.files.length+" files match RELEASE-MANIFEST.json");
119
+ process.exit(bad?1:0);' )
120
+
121
+ echo "Deployed. Old site backed up to /var/www/verifyhash.com/html.bak.*"
122
+ ```
123
+
124
+ > There is no hand-copy recipe anymore — the publish set lives in **`site/publish-set.json`**
125
+ > (published path → committed source, incl. the renames like `challenge/README.md` →
126
+ > `docs/challenge-README.md`) and `scripts/site-release.js` is the only generator. To change what the
127
+ > site serves, edit the allowlist, re-run the assembler, and commit the regenerated
128
+ > `site/RELEASE-MANIFEST.json`. **Never glob `docs/*.md` into the webroot — it contains internal files;
129
+ > the assembler refuses forbidden entries (`.git*`, env/key-shaped names, this runbook, ops telemetry) by construction.**
130
+ > After the upload, record what went live: `node scripts/site-release.js --mark-deployed` rewrites
131
+ > `site/DEPLOYED.json` (the drift baseline) — see §3c.
132
+
133
+ ### 3b — the landing page
134
+
135
+ The landing page is **version-controlled at `site/index.html`** (the assembler stages it as
136
+ `public/index.html`). It carries the verifyhash.com URLs, the published sha256, the verify one-liner,
137
+ the reproduce-from-source steps, and the honest boundary. To change it, edit `site/index.html`,
138
+ re-run `node scripts/site-release.js`, and commit. If you want to set a real producer address in the
139
+ example, edit the `0x<…>` placeholder in §2 of that page (in `site/index.html`, then re-assemble).
140
+
141
+ > ⚠️ **Whenever the verifier bundle changes, update the page's `Published SHA-256:` to match.** The
142
+ > page's whole pitch is "don't trust us — download `verify-vh-standalone.js` and compare its hash
143
+ > yourself", so its advertised hash must equal the sha256 of the `verify-vh-standalone.js` this release
144
+ > ships (and the `.sha256` sidecar). If you rebuild the bundle but forget the page, the assembled
145
+ > webroot would fail its own cross-check — a false "tampered?" signal for buyers. **`node
146
+ > scripts/site-release.js` now REFUSES to assemble (and `--check` goes RED, naming `LANDING PAGE DRIFT`)
147
+ > when the page's `Published SHA-256:` ≠ the shipped bundle's sha256**, so this drift can never ship
148
+ > silently — but fix it at the source by editing `site/index.html`'s `Published SHA-256:` value.
149
+
150
+ ### 3c — close the loop: `--mark-deployed`, then keep `--diff` clean (the P-11 refresh)
151
+
152
+ The full refresh flow is: **release → upload → `--mark-deployed` → `--diff` clean.**
153
+
154
+ 1. **release** — `node scripts/site-release.js` assembles `public/` + writes both manifests (§3a step 1),
155
+ and `--check` gates it (§3a step 2).
156
+ 2. **upload** — the rsync + upload-verify of §3a steps 3–5. This is the human-owned step.
157
+ 3. **`--mark-deployed`** — `node scripts/site-release.js --mark-deployed` rewrites `site/DEPLOYED.json`
158
+ to the manifest you just uploaded + an ISO date note (`markedDeployedAt`). **Commit it.** This is the
159
+ ONE command you run AFTER uploading — it records what went live so the next `--diff` is truthful.
160
+ It records only; it never uploads anything.
161
+ 4. **`--diff` clean** — `node scripts/site-release.js --diff` compares `site/DEPLOYED.json` (what is
162
+ believed LIVE) against a fresh assembly and prints a per-file `ADDED`/`CHANGED`/`REMOVED`/`UNCHANGED`
163
+ table + a one-line verdict. Right after a correct upload + `--mark-deployed` it must print
164
+ `live site matches the current release`. From then on, whenever it prints
165
+ `live site is stale: N of M published files differ — refresh per P-11`, redo this section.
166
+ Staleness is a HUMAN decision signal, not a CI failure: `--diff` exits `0` whether stale or clean;
167
+ only a malformed/missing `site/DEPLOYED.json` exits `3` (with a named error). The standing test
168
+ suite pins the committed `site/RELEASE-MANIFEST.json` to a fresh assembly (so the drift signal can
169
+ never itself go stale), but a stale `site/DEPLOYED.json` never fails the suite.
170
+
171
+ **Boundary (verbatim):** the loop assembles and diffs INSIDE the repo only; uploading to the live host
172
+ is the human-owned P-11 step — never auto-executed. (P-11 in `STRATEGY.md` is the recurring ~10-minute
173
+ refresh action this section implements.)
174
+
175
+ ---
176
+
177
+ ## 4. nginx vhost — two small edits to the EXISTING block
178
+
179
+ Edit `/etc/nginx/conf.d/verifyhash.com.conf`. Keep the `listen`/`server_name`/`ssl_*`/redirect lines.
180
+ Make these changes inside the `server { … }` that serves 443:
181
+
182
+ **(a) Remove the dead backend proxy** (the old JSON-storage app):
183
+ ```nginx
184
+ # DELETE this whole block — there is no backend in the provenance product:
185
+ # location /api/ { proxy_pass http://localhost:3005/api/; ... }
186
+ ```
187
+
188
+ **(b) Make `/` 404 on missing files (not an SPA fallback), and serve the verifier as a named download.**
189
+ Replace the existing `location /` and the static-asset cache block with:
190
+ ```nginx
191
+ autoindex off;
192
+ server_tokens off;
193
+ add_header X-Content-Type-Options "nosniff" always;
194
+
195
+ # never serve dotfiles even if one ever lands in the webroot
196
+ location ~ /\. { deny all; return 404; }
197
+
198
+ # verifier + sealer: force download under the EXACT pinned filename so `sha256sum -c` works verbatim
199
+ location = /verify-vh-standalone.js {
200
+ default_type application/javascript;
201
+ add_header Content-Disposition 'attachment; filename="verify-vh-standalone.js"';
202
+ add_header X-Content-Type-Options "nosniff" always;
203
+ }
204
+ location = /seal-vh-standalone.js {
205
+ default_type application/javascript;
206
+ add_header Content-Disposition 'attachment; filename="seal-vh-standalone.js"';
207
+ add_header X-Content-Type-Options "nosniff" always;
208
+ }
209
+ location ~ \.sha256$ { default_type text/plain; }
210
+ location = /build-provenance.json { default_type application/json; }
211
+ location ~ \.md$ { default_type "text/markdown; charset=utf-8"; }
212
+
213
+ location / { try_files $uri $uri/ =404; } # NOT `/index.html` — a real 404 for missing paths
214
+ ```
215
+ Keep `root /var/www/verifyhash.com/html;` and `index index.html;` as they are.
216
+
217
+ **Apply:**
218
+ ```bash
219
+ sudo nginx -t && sudo systemctl reload nginx
220
+ ```
221
+
222
+ ---
223
+
224
+ ## 5. DNS + TLS — already done
225
+
226
+ Nothing to do. DNS resolves here and the Let's Encrypt cert is live (certbot's renewal timer already
227
+ covers it). If you ever add a `verify.verifyhash.com` second origin (§7), that one needs its own cert.
228
+
229
+ ---
230
+
231
+ ## 6. Pre-go-live verification checklist
232
+
233
+ Run **all**; every line must pass before you announce it.
234
+
235
+ ```bash
236
+ D=https://verifyhash.com
237
+
238
+ # a) verifier downloads and its published hash checks out end-to-end
239
+ curl -fsS -o /tmp/v.js "$D/verify-vh-standalone.js"
240
+ curl -fsS -o /tmp/v.js.sha256 "$D/verify-vh-standalone.js.sha256"
241
+ ( cd /tmp && sha256sum -c v.js.sha256 ) # must say: verify-vh-standalone.js: OK
242
+
243
+ # b) landing page is the NEW site (provenance), not the old JSON-storage one, and its advertised
244
+ # Published SHA-256 matches the bundle you just uploaded (read the served sidecar's hash and
245
+ # confirm the landing page advertises that exact string — no hard-coded hash to go stale)
246
+ VERIFY_SHA=$(curl -fsS "$D/verify-vh-standalone.js.sha256" | cut -d' ' -f1)
247
+ curl -fsS "$D/" | grep -q "$VERIFY_SHA" && echo "landing OK (advertises the shipped bundle hash)" || echo "STOP: landing page hash != shipped bundle"
248
+ curl -fsS "$D/" | grep -qi "JSON Storage Network" && echo "STOP: old site still served" || echo "old site gone OK"
249
+
250
+ # c) the dead backend is detached — /api/ must NOT proxy anymore
251
+ curl -s -o /dev/null -w 'api/ -> %{http_code} (expect 404)\n' "$D/api/health"
252
+
253
+ # d) NONE of the forbidden paths are reachable (expect 404/403 for ALL)
254
+ for p in .git/HEAD .git/config .env ../STRATEGY.md ../BACKLOG.md \
255
+ ../build-loop.workflow.js ../../.claude/.credentials.json \
256
+ ../docs/USAGE-BUDGET.json ../test/cli.claim.test.js; do
257
+ echo "$(curl -s -o /dev/null -w '%{http_code}' "$D/$p") $p" # a 200 anywhere is STOP-SHIP
258
+ done
259
+
260
+ # e) no directory listing
261
+ curl -s "$D/docs/" | grep -qi "index of" && echo "FAIL: autoindex on" || echo "no listing OK"
262
+ ```
263
+
264
+ Any forbidden path returning `200`, or the old "JSON Storage Network" string still present → **stop**,
265
+ fix, re-run. Once clean, the old-site backup `/var/www/verifyhash.com/html.bak.*` can be deleted.
266
+
267
+ ---
268
+
269
+ ## 7. Optional: retire the old `:3005` backend + a second download origin
270
+
271
+ - **The old Node backend** on `localhost:3005` (the JSON-storage app) is already down and now detached
272
+ from the domain (§4a). Stopping/disabling its service + deleting its files is the owner's call — it is
273
+ unrelated to this site and **not** required for go-live. Don't delete anything you can't identify.
274
+ - **Second origin (nice-to-have):** serving the verifier from `verify.verifyhash.com` (its own vhost +
275
+ cert) makes the "don't trust the vendor" pitch literally true at the network layer. The hash is the
276
+ trust anchor, so same-origin is already safe — this is a fast-follow, not a blocker.
277
+
278
+ ---
279
+
280
+ ## 8. Guardrail boundary — division of labor
281
+
282
+ - **The loop (unprivileged) builds artifacts in-tree** — the `verifier/dist/*` bundles and the prebuilt
283
+ `public/` webroot — as local commits. It **did not** and **cannot** write to `/var/www`, edit nginx,
284
+ bind a port, hold a key, or touch the `:3005` service. (`public/` is git-ignored; rebuild it anytime.)
285
+ - **You (privileged agent / human) do the outward-facing steps** — `rsync` into `/var/www`, edit the
286
+ vhost, reload nginx. That is the human action the loop is forbidden from taking.
287
+ - **Nothing here is a deployed service.** Static publication of already-public, git-tracked files crosses
288
+ no no-deploy / no-funds / no-token line: no key, no payment, no data custody, no token issuance.
289
+
290
+ ---
291
+
292
+ ## Appendix — file inventory & hashes
293
+
294
+ The canonical inventory is **generated, not hand-typed**: `site/RELEASE-MANIFEST.json` (committed twin;
295
+ the same bytes ship inside the webroot as `public/RELEASE-MANIFEST.json`) lists every published path,
296
+ its committed source path, its byte count, and its SHA-256, in sorted order. The allowlist it is built
297
+ from is `site/publish-set.json`; the snapshot of what is believed live is `site/DEPLOYED.json`.
298
+
299
+ **Always re-derive hashes from `node scripts/site-release.js --check` + the committed sidecars; never
300
+ trust a hand-copied table.** Assembled webroot to deploy: **`/home/loopdev/verifyhash/public/`** →
301
+ **`/var/www/verifyhash.com/html`**.
@@ -0,0 +1,12 @@
1
+ {
2
+ "_doc": "Append-only ledger of engine md5s that passed BOTH self-upgrade gates at launch time (scripts/pre-run-gate.cjs). The supervisor refuses to launch an engine not gated here. Never rewrite prior entries.",
3
+ "engines": [
4
+ {
5
+ "md5": "88bf8ee0db9038b8847a8e7468428457",
6
+ "gatedAt": "2026-07-03T04:33:10.820Z",
7
+ "prevMd5": "db5b3aceda33973e6be0df366caebd93",
8
+ "validate": "PASS",
9
+ "smoke": "SMOKE-PASS (4 scenarios: all-pass commits with verify-before-commit [20 calls]; FAILING verdict BLOCKs with NO commit; t"
10
+ }
11
+ ]
12
+ }