@coproduct_inc/verify 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/dist/cli.js ADDED
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * `nucleus-verify` — offline verifier for capability-boundary in-bounds
4
+ * attestation receipts. Exit code is the gate:
5
+ * 0 → receipt verified AND the agent stayed in bounds
6
+ * 1 → receipt failed verification, or the agent went out of bounds
7
+ * 2 → usage / I/O error
8
+ *
9
+ * Usage:
10
+ * nucleus-verify <receipt.json> [--expect-principal <spiffe-id>]
11
+ * [--expect-key <base64url>] [--json] [--quiet]
12
+ * nucleus-verify --help
13
+ *
14
+ * Reads from stdin if `<receipt.json>` is "-" or omitted with piped input.
15
+ * Designed as a drop-in CI / GitHub Action step.
16
+ */
17
+ import { readFileSync } from "node:fs";
18
+ import { verifyReceiptJson } from "./attestation.js";
19
+ const HELP = `nucleus-verify — offline capability-boundary in-bounds attestation verifier
20
+
21
+ USAGE:
22
+ nucleus-verify <receipt.json> [options]
23
+ cat receipt.json | nucleus-verify [options]
24
+
25
+ OPTIONS:
26
+ --expect-principal <id> require the boundary principal to equal <id> (SPIFFE ID)
27
+ --expect-key <b64url> require the signer public key to equal <b64url>
28
+ --json print the full VerifyReport as JSON
29
+ --quiet suppress the human-readable line (exit code only)
30
+ -h, --help show this help
31
+
32
+ EXIT CODES:
33
+ 0 verified and in bounds 1 verification failed / out of bounds 2 usage / I/O error`;
34
+ function parseArgs(argv) {
35
+ const args = { json: false, quiet: false, opts: {}, help: false };
36
+ for (let i = 0; i < argv.length; i++) {
37
+ const a = argv[i];
38
+ switch (a) {
39
+ case "-h":
40
+ case "--help":
41
+ args.help = true;
42
+ break;
43
+ case "--json":
44
+ args.json = true;
45
+ break;
46
+ case "--quiet":
47
+ args.quiet = true;
48
+ break;
49
+ case "--expect-principal":
50
+ args.opts.expectPrincipal = argv[++i];
51
+ break;
52
+ case "--expect-key":
53
+ args.opts.expectPublicKey = argv[++i];
54
+ break;
55
+ default:
56
+ if (a.startsWith("--")) {
57
+ throw new Error(`unknown option ${a}`);
58
+ }
59
+ args.path = a;
60
+ }
61
+ }
62
+ return args;
63
+ }
64
+ function readInput(path) {
65
+ if (!path || path === "-") {
66
+ return readFileSync(0, "utf8"); // fd 0 = stdin
67
+ }
68
+ return readFileSync(path, "utf8");
69
+ }
70
+ function summarize(report) {
71
+ if (report.ok) {
72
+ const n = report.recomputed.events.length;
73
+ return `✓ in bounds — verified ${n} event${n === 1 ? "" : "s"}; signature, hash-chain, and recomputed verdict all agree`;
74
+ }
75
+ return `✗ refused to attest — ${report.reason ?? "verification failed"}`;
76
+ }
77
+ function main() {
78
+ let args;
79
+ try {
80
+ args = parseArgs(process.argv.slice(2));
81
+ }
82
+ catch (e) {
83
+ process.stderr.write(`error: ${e.message}\n\n${HELP}\n`);
84
+ return 2;
85
+ }
86
+ if (args.help) {
87
+ process.stdout.write(HELP + "\n");
88
+ return 0;
89
+ }
90
+ let receiptJson;
91
+ try {
92
+ receiptJson = readInput(args.path);
93
+ }
94
+ catch (e) {
95
+ process.stderr.write(`error: cannot read receipt: ${e.message}\n`);
96
+ return 2;
97
+ }
98
+ const report = verifyReceiptJson(receiptJson, args.opts);
99
+ if (args.json) {
100
+ process.stdout.write(JSON.stringify(report, null, 2) + "\n");
101
+ }
102
+ else if (!args.quiet) {
103
+ const line = summarize(report);
104
+ (report.ok ? process.stdout : process.stderr).write(line + "\n");
105
+ }
106
+ return report.ok ? 0 : 1;
107
+ }
108
+ process.exit(main());
@@ -0,0 +1,96 @@
1
+ /**
2
+ * `@coproduct_inc/verify` — offline, zero-trust verification for Nucleus.
3
+ *
4
+ * Two receipt families share one package. The headline is the
5
+ * **capability-boundary in-bounds attestation** — see `./attestation`
6
+ * (re-exported below): given an agent run's tool-call trace + a declared
7
+ * capability boundary, emit and offline-verify an Ed25519-signed receipt
8
+ * that the agent stayed within bounds, keyed on a cryptographic principal
9
+ * rather than a mutable display name. The auction-receipt surface documented
10
+ * here is the original use case and remains available.
11
+ *
12
+ * ---
13
+ *
14
+ * Auction receipts: the agent NEVER trusts the hub's clearing price.
15
+ *
16
+ * The agent NEVER trusts the hub's clearing price. This package's WASM
17
+ * core (the SAME `nucleus-wasm` binary the browser demo runs) re-runs the
18
+ * auction clearing locally from the SIGNED bid set and asserts the
19
+ * recomputed price equals the price the receipt claims — on top of the
20
+ * Ed25519 signature + BLAKE3 root-hash check.
21
+ *
22
+ * ```ts
23
+ * import { verify } from "@coproduct_inc/verify";
24
+ * const r = await verify(receiptJson, jwksJson);
25
+ * if (!r.ok) throw new Error(r.reason ?? "receipt failed verification");
26
+ * // r.ok === signature_ok && root_hash_ok && price_recomputed_ok
27
+ * ```
28
+ *
29
+ * The Node target loads the wasm synchronously on first import; the
30
+ * `verify` API is async-shaped so a future web/bundler entry can stream
31
+ * the wasm without changing call sites.
32
+ */
33
+ /** Which clearing rule the receipt commits to. */
34
+ export type RecomputePath = "vickrey" | "pigou-vcg";
35
+ /**
36
+ * Full verification result. `ok` is the single boolean to gate on; the
37
+ * component flags + recovered fields are for diagnostics / UI. All prices
38
+ * are integer micro-USD that fit a JS `number` (the kernel's internal
39
+ * u128 math never crosses this boundary).
40
+ */
41
+ export interface FullVerifyReport {
42
+ /** `signatureOk && rootHashOk && priceRecomputedOk`. */
43
+ ok: boolean;
44
+ /** Ed25519 signature verified under the JWKS key matched by `kid`. */
45
+ signature_ok: boolean;
46
+ /** BLAKE3 of the canonical envelope equals the receipt's root hash. */
47
+ root_hash_ok: boolean;
48
+ /** The locally recomputed clearing price equals the receipt's price. */
49
+ price_recomputed_ok: boolean;
50
+ /** Price the recompute produced (micro-USD). */
51
+ recomputed_price_micro_usd: number;
52
+ /** Price the receipt claims (micro-USD), or null. */
53
+ signed_price_micro_usd: number | null;
54
+ /** Clearing rule the receipt commits to (`"vickrey"` today). */
55
+ path: RecomputePath;
56
+ /** Theorem-backed Pigou-VCG cross-check clearing, if externality data
57
+ * was present (reported, not gated on). */
58
+ pigou_vcg_clearing_micro_usd: number | null;
59
+ /** First failing reason, or null when `ok`. */
60
+ reason: string | null;
61
+ }
62
+ /** Recompute-only result (no signature check). */
63
+ export interface RecomputeReport {
64
+ recomputed_price_micro_usd: number;
65
+ receipt_price_micro_usd: number | null;
66
+ matches_receipt: boolean;
67
+ path: RecomputePath;
68
+ recomputed_winner_spiffe_id: string | null;
69
+ winner_matches: boolean;
70
+ pigou_vcg_clearing_micro_usd: number | null;
71
+ reason: string | null;
72
+ }
73
+ /**
74
+ * Verify a signed auction receipt fully: signature + root hash + a LOCAL
75
+ * recomputation of the clearing price from the signed bids.
76
+ *
77
+ * @param receiptJson the receipt as a JSON string (the hub's wire form).
78
+ * @param jwksJson the pinned issuer JWKS document as a JSON string.
79
+ * @returns the structured report; `ok === true` only when all three
80
+ * checks pass. Never throws on a bad receipt — failures surface as
81
+ * `ok: false` with a `reason`.
82
+ */
83
+ export declare function verify(receiptJson: string, jwksJson: string): Promise<FullVerifyReport>;
84
+ /**
85
+ * Recompute the clearing price from the signed bids WITHOUT checking the
86
+ * signature. Use when you have already verified the signature separately,
87
+ * or to inspect the recomputed-vs-claimed delta. Most callers want
88
+ * {@link verify} instead.
89
+ */
90
+ export declare function recomputeClearing(receiptJson: string): Promise<RecomputeReport>;
91
+ /**
92
+ * Signature + root-hash check only (the pre-recompute verifier). Kept for
93
+ * back-compat / when you only need authenticity, not price-correctness.
94
+ */
95
+ export declare function verifySignature(receiptJson: string, jwksJson: string): Promise<unknown>;
96
+ export * from "./attestation.js";
package/dist/index.js ADDED
@@ -0,0 +1,69 @@
1
+ /**
2
+ * `@coproduct_inc/verify` — offline, zero-trust verification for Nucleus.
3
+ *
4
+ * Two receipt families share one package. The headline is the
5
+ * **capability-boundary in-bounds attestation** — see `./attestation`
6
+ * (re-exported below): given an agent run's tool-call trace + a declared
7
+ * capability boundary, emit and offline-verify an Ed25519-signed receipt
8
+ * that the agent stayed within bounds, keyed on a cryptographic principal
9
+ * rather than a mutable display name. The auction-receipt surface documented
10
+ * here is the original use case and remains available.
11
+ *
12
+ * ---
13
+ *
14
+ * Auction receipts: the agent NEVER trusts the hub's clearing price.
15
+ *
16
+ * The agent NEVER trusts the hub's clearing price. This package's WASM
17
+ * core (the SAME `nucleus-wasm` binary the browser demo runs) re-runs the
18
+ * auction clearing locally from the SIGNED bid set and asserts the
19
+ * recomputed price equals the price the receipt claims — on top of the
20
+ * Ed25519 signature + BLAKE3 root-hash check.
21
+ *
22
+ * ```ts
23
+ * import { verify } from "@coproduct_inc/verify";
24
+ * const r = await verify(receiptJson, jwksJson);
25
+ * if (!r.ok) throw new Error(r.reason ?? "receipt failed verification");
26
+ * // r.ok === signature_ok && root_hash_ok && price_recomputed_ok
27
+ * ```
28
+ *
29
+ * The Node target loads the wasm synchronously on first import; the
30
+ * `verify` API is async-shaped so a future web/bundler entry can stream
31
+ * the wasm without changing call sites.
32
+ */
33
+ // The wasm-pack `nodejs` target: CommonJS, wasm instantiated eagerly on
34
+ // require. Bundled as a sibling artifact so this package is self-contained.
35
+ import * as wasm from "../wasm/nodejs/nucleus_wasm.js";
36
+ /**
37
+ * Verify a signed auction receipt fully: signature + root hash + a LOCAL
38
+ * recomputation of the clearing price from the signed bids.
39
+ *
40
+ * @param receiptJson the receipt as a JSON string (the hub's wire form).
41
+ * @param jwksJson the pinned issuer JWKS document as a JSON string.
42
+ * @returns the structured report; `ok === true` only when all three
43
+ * checks pass. Never throws on a bad receipt — failures surface as
44
+ * `ok: false` with a `reason`.
45
+ */
46
+ export async function verify(receiptJson, jwksJson) {
47
+ return wasm.verify_auction_receipt_full(receiptJson, jwksJson);
48
+ }
49
+ /**
50
+ * Recompute the clearing price from the signed bids WITHOUT checking the
51
+ * signature. Use when you have already verified the signature separately,
52
+ * or to inspect the recomputed-vs-claimed delta. Most callers want
53
+ * {@link verify} instead.
54
+ */
55
+ export async function recomputeClearing(receiptJson) {
56
+ return wasm.verify_clearing_recompute(receiptJson);
57
+ }
58
+ /**
59
+ * Signature + root-hash check only (the pre-recompute verifier). Kept for
60
+ * back-compat / when you only need authenticity, not price-correctness.
61
+ */
62
+ export async function verifySignature(receiptJson, jwksJson) {
63
+ return wasm.verify_auction_receipt(receiptJson, jwksJson);
64
+ }
65
+ // ---------------------------------------------------------------------------
66
+ // Capability-boundary in-bounds attestation (the headline evidence layer).
67
+ // Pure Node (`node:crypto`), no WASM — runs in CI, the CLI, and the Action.
68
+ // ---------------------------------------------------------------------------
69
+ export * from "./attestation.js";
@@ -0,0 +1,80 @@
1
+ // OpenClaw replay demo — capability-boundary in-bounds attestation.
2
+ //
3
+ // Replays the OpenClaw-class trust-boundary bypass (CVE-2026-25253): an agent
4
+ // run where a malicious tool call presents a `displayName` that MATCHES an
5
+ // allowlisted agent, but whose cryptographic `principal` (SPIFFE ID) differs.
6
+ // A gate that keys on the display name is fooled. Ours keys on the principal,
7
+ // so the receipt REFUSES to attest the bypass — while a clean run attests.
8
+ //
9
+ // Run after building: pnpm build && node examples/openclaw-replay.mjs
10
+ // (No persisted keys: an ephemeral Ed25519 keypair is generated in-memory.)
11
+
12
+ import {
13
+ makeBoundary,
14
+ generateKeypair,
15
+ signReceipt,
16
+ verifyReceipt,
17
+ } from "../dist/index.js";
18
+
19
+ // The legitimate agent's cryptographic identity and what it may do.
20
+ const PRINCIPAL = "spiffe://acme.example/agent/billing-assistant";
21
+ const boundary = makeBoundary(PRINCIPAL, [
22
+ "read_invoice",
23
+ "list_invoices",
24
+ "summarize",
25
+ ]);
26
+
27
+ // Ephemeral attestor key (in-memory only — no custody, no provisioning).
28
+ const { privateKey } = generateKeypair();
29
+
30
+ function show(title, report) {
31
+ const verdict = report.ok ? "ATTESTED ✓" : "REFUSED ✗";
32
+ console.log(`\n── ${title} ──`);
33
+ console.log(` verdict: ${verdict}`);
34
+ console.log(` ok: ${report.ok}`);
35
+ console.log(` signature: ${report.signatureOk} hash-chain: ${report.rootHashOk} verdict-consistent: ${report.verdictConsistentOk}`);
36
+ if (!report.ok) console.log(` reason: ${report.reason}`);
37
+ return report;
38
+ }
39
+
40
+ // 1) CLEAN RUN — every call is the real principal, every tool allowed.
41
+ const cleanTrace = [
42
+ { seq: 0, tool: "list_invoices", principal: PRINCIPAL, displayName: "Billing Assistant" },
43
+ { seq: 1, tool: "read_invoice", principal: PRINCIPAL, displayName: "Billing Assistant" },
44
+ { seq: 2, tool: "summarize", principal: PRINCIPAL, displayName: "Billing Assistant" },
45
+ ];
46
+ const cleanReceipt = signReceipt(boundary, cleanTrace, privateKey);
47
+ const cleanReport = show("CLEAN RUN", verifyReceipt(cleanReceipt));
48
+
49
+ // 2) OPENCLAW BYPASS — the injected call wears the allowlisted DISPLAY NAME
50
+ // ("Billing Assistant") but carries an ATTACKER principal. A name-keyed
51
+ // gate would wave it through; the boundary is bound to the SPIFFE ID, so
52
+ // the recomputed verdict is out-of-bounds and the receipt refuses.
53
+ const ATTACKER = "spiffe://acme.example/agent/unknown-7f3a";
54
+ const bypassTrace = [
55
+ { seq: 0, tool: "list_invoices", principal: PRINCIPAL, displayName: "Billing Assistant" },
56
+ { seq: 1, tool: "read_invoice", principal: ATTACKER, displayName: "Billing Assistant" },
57
+ ];
58
+ const bypassReceipt = signReceipt(boundary, bypassTrace, privateKey);
59
+ const bypassReport = show("OPENCLAW BYPASS (display-name match, principal mismatch)", verifyReceipt(bypassReceipt));
60
+
61
+ // 3) FORGERY — attacker hand-edits the bypass receipt to claim inBounds:true.
62
+ // The verifier recomputes the verdict independently AND the signature was
63
+ // taken over the honest body, so both the verdict-consistency check and the
64
+ // signature check fail.
65
+ const forged = JSON.parse(JSON.stringify(bypassReceipt));
66
+ forged.verdict.inBounds = true;
67
+ forged.verdict.events = forged.verdict.events.map((e) => ({ ...e, inBounds: true, code: "ok", detail: "in bounds" }));
68
+ const forgedReport = show("FORGED inBounds:true (tampered claim)", verifyReceipt(forged));
69
+
70
+ console.log("\n── summary ──");
71
+ const pass =
72
+ cleanReport.ok === true &&
73
+ bypassReport.ok === false &&
74
+ bypassReport.recomputed.events[1]?.code === "principal_mismatch" &&
75
+ forgedReport.ok === false;
76
+ console.log(` clean attests: ${cleanReport.ok === true}`);
77
+ console.log(` bypass refused: ${bypassReport.ok === false} (${bypassReport.recomputed.events[1]?.code})`);
78
+ console.log(` forged claim rejected: ${forgedReport.ok === false}`);
79
+ console.log(pass ? "\nDEMO OK ✓" : "\nDEMO FAILED ✗");
80
+ process.exit(pass ? 0 : 1);
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@coproduct_inc/verify",
3
+ "version": "0.1.0",
4
+ "description": "Offline, zero-trust verification of agent capability-boundary in-bounds attestation receipts: emit and verify an Ed25519-signed, hash-chained receipt that an agent run stayed within a declared boundary, keyed on a cryptographic principal (not a mutable display name) — the evidence layer above probabilistic guardrails. Also verifies Nucleus auction receipts by re-running the clearing locally. Zero runtime deps for the attestation core (node:crypto).",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "bin": {
10
+ "nucleus-verify": "dist/cli.js"
11
+ },
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js"
16
+ },
17
+ "./attestation": {
18
+ "types": "./dist/attestation.d.ts",
19
+ "import": "./dist/attestation.js"
20
+ }
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "wasm/nodejs/package.json",
25
+ "wasm/nodejs/nucleus_wasm.js",
26
+ "wasm/nodejs/nucleus_wasm.d.ts",
27
+ "wasm/nodejs/nucleus_wasm_bg.wasm",
28
+ "wasm/nodejs/nucleus_wasm_bg.wasm.d.ts",
29
+ "examples/openclaw-replay.mjs",
30
+ "README.md"
31
+ ],
32
+ "scripts": {
33
+ "build:wasm": "wasm-pack build ../../crates/nucleus-wasm --target nodejs --out-dir ../../packages/nucleus-verify/wasm/nodejs && rm -f wasm/nodejs/.gitignore wasm/nodejs/package.json",
34
+ "build": "tsc -p tsconfig.json",
35
+ "typecheck": "tsc -p tsconfig.json --noEmit",
36
+ "test": "node --test",
37
+ "demo": "node examples/openclaw-replay.mjs"
38
+ },
39
+ "keywords": [
40
+ "nucleus",
41
+ "agent-security",
42
+ "capability-boundary",
43
+ "in-bounds-attestation",
44
+ "verification",
45
+ "ed25519",
46
+ "spiffe",
47
+ "openclaw",
48
+ "auction",
49
+ "vcg",
50
+ "agentic-commerce"
51
+ ],
52
+ "repository": {
53
+ "type": "git",
54
+ "url": "git+https://github.com/coproduct/nucleus-platform.git",
55
+ "directory": "packages/nucleus-verify"
56
+ },
57
+ "devDependencies": {
58
+ "@types/node": "^25.9.1",
59
+ "typescript": "^5.7.2"
60
+ }
61
+ }
@@ -0,0 +1,199 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+
4
+ /**
5
+ * **Day 3-4 export**: run the selective-recomputation analyzer.
6
+ *
7
+ * Takes the JSONL chain + a JSON-serialized [`CorrectionEvent`].
8
+ * Returns a [`RecomputationPlan`] serialized as a `JsValue`. The
9
+ * browser orchestrator renders the partition + lets the visitor
10
+ * expand any decision to see its `PreservationProof` or
11
+ * `RecomputationProof` inline.
12
+ */
13
+ export function analyze_correction_event(chain_jsonl: string, correction_json: string): any;
14
+
15
+ /**
16
+ * **Day 3-4 export**: build the dependency graph from a JSONL chain.
17
+ *
18
+ * Returns a [`DependencyGraph`] serialized as a `JsValue` — the JS
19
+ * side gets a plain object with `nodes: Vec<StepNode>` it can
20
+ * visualize without further parsing.
21
+ */
22
+ export function compute_dependency_graph(chain_jsonl: string): any;
23
+
24
+ /**
25
+ * **Day 10 export**: compute the typed savings summary from a
26
+ * recomputation plan + a per-step cost map.
27
+ *
28
+ * `plan_json` is a serialized [`RecomputationPlan`]; `cost_map_json` is
29
+ * `{ step_id: cost_micro_usd, ... }`. Returns:
30
+ * ```json
31
+ * {
32
+ * "total_steps": N,
33
+ * "preserved_steps": M,
34
+ * "recomputed_steps": K,
35
+ * "preservation_ratio": 0.0..=1.0,
36
+ * "baseline_cost_micro_usd": sum-of-all-step-costs,
37
+ * "selective_cost_micro_usd": sum-of-recompute-step-costs,
38
+ * "naive_restart_cost_micro_usd": 2 × baseline (the modeled "start over" worst case),
39
+ * "savings_vs_naive_ratio": 1 - selective / naive_restart
40
+ * }
41
+ * ```
42
+ *
43
+ * Costs are integer micro-USD (per workspace f64-discipline rule —
44
+ * money math stays in integers). The ratio is computed as `f64` only
45
+ * because it's a display-layer value (the page renders `XX.X%`).
46
+ *
47
+ * Steps absent from `cost_map` contribute zero — the JS side should
48
+ * pre-populate every step_id; the missing-key case is a no-op rather
49
+ * than a hard error so a malformed cost map doesn't blow up the
50
+ * browser tab.
51
+ */
52
+ export function compute_savings_summary(plan_json: string, cost_map_json: string): any;
53
+
54
+ /**
55
+ * Install a browser-friendly panic hook. The hook routes any wasm-side
56
+ * `panic!` into `console.error`, which means failed assertions in the
57
+ * dependency analysis or signature verification path become visible in
58
+ * the visitor's DevTools instead of an opaque `RuntimeError: unreachable`.
59
+ *
60
+ * Idempotent — calling it more than once is harmless. Browsers should
61
+ * invoke this once on module load.
62
+ */
63
+ export function init(): void;
64
+
65
+ /**
66
+ * **Day 10 export**: parse a raw Claude Code session JSONL (the format
67
+ * Claude Code writes under `~/.claude/projects/.../<UUID>.jsonl`) into
68
+ * a renderable step list.
69
+ *
70
+ * This is the drag-and-drop path: the visitor's browser receives a
71
+ * session log it didn't sign and runs the dependency analyzer against
72
+ * it locally. The mapper produces unsigned [`nucleus_lineage::LineageEdge`]s;
73
+ * `signed = false` is set on the returned [`RenderableChain`] so the UI
74
+ * can label the source ("unsigned — your local session" vs. "signed
75
+ * corpus from coproduct-opensource/nucleus-recompute-corpus").
76
+ *
77
+ * Source-of-truth: the parse + map logic lives in `claude-code-capture`
78
+ * (the same code the server-side capture binary uses). One canonical
79
+ * implementation, shared between native + wasm.
80
+ */
81
+ export function parse_claude_code_session(session_jsonl: string): any;
82
+
83
+ /**
84
+ * **Day 10 export**: parse a JSONL chain of signed lineage edges into
85
+ * a renderable step list (one [`RenderableStep`] per edge in chain
86
+ * order). The orchestrator on the JS side consumes this directly to
87
+ * render the dependency graph + per-step drawer.
88
+ *
89
+ * Wire format: `chain_jsonl` is one `LineageEdge` per line (the same
90
+ * format `verify_chain_signatures` expects). Signature verification is
91
+ * NOT performed here — call `verify_chain_signatures` first if the
92
+ * chain's provenance matters.
93
+ */
94
+ export function parse_lineage_chain(chain_jsonl: string): any;
95
+
96
+ /**
97
+ * **Offline auction-receipt verifier — the "verify this receipt"
98
+ * button.** Given a signed `AuctionReceipt` JSON + a pinned JWKS
99
+ * document, re-build the canonical envelope, re-hash it (BLAKE3), and
100
+ * Ed25519-verify the signature against the issuer key matched by `kid`
101
+ * — all in the visitor's tab, with zero hub access.
102
+ *
103
+ * Returns a [`ReceiptVerifyReport`] serialized as a `JsValue`:
104
+ * ```json
105
+ * {
106
+ * "ok": true,
107
+ * "reason": null,
108
+ * "auction_id": "...", "issuer_kid": "...", "root_hash_hex": "...",
109
+ * "issued_at_micros": 1717…, "winner_spiffe_id": "spiffe://…",
110
+ * "clearing_price_micro_usd": 250000, "bid_count": 3
111
+ * }
112
+ * ```
113
+ *
114
+ * Never throws on a bad receipt — `ok = false` with a `reason` string
115
+ * is the FAIL path (so the page renders PASS/FAIL rather than a thrown
116
+ * error). A `JsValue` error is only returned if the report itself
117
+ * can't be serialized, which shouldn't happen.
118
+ */
119
+ export function verify_auction_receipt(receipt_json: string, jwks_json: string): any;
120
+
121
+ /**
122
+ * **Bet C — the full offline verifier.** Combines the signature +
123
+ * root-hash check ([`verify_auction_receipt`]) with the local
124
+ * clearing-price recomputation ([`verify_clearing_recompute`]) into a
125
+ * single call, so an agent NEVER trusts the hub's price: the wasm
126
+ * recomputes it locally from the signed bids and asserts equality.
127
+ *
128
+ * The drop-in story (`@nucleus/verify`):
129
+ * ```js
130
+ * import { verify } from '@nucleus/verify';
131
+ * const r = await verify(receiptJson, jwksJson);
132
+ * if (!r.ok) throw new Error(r.reason);
133
+ * // r.ok === signature_ok && root_hash_ok && price_recomputed_ok
134
+ * ```
135
+ *
136
+ * Returns a [`FullVerifyReport`] as a `JsValue`. All prices are `u64`
137
+ * micro-USD (fit JS `Number` / Python `int`); the kernel's internal
138
+ * `u128` math never crosses this boundary.
139
+ */
140
+ export function verify_auction_receipt_full(receipt_json: string, jwks_json: string): any;
141
+
142
+ /**
143
+ * Day-1 entry point. Parses a JSONL chain + a JWKS document and runs
144
+ * per-edge Ed25519 signature verification.
145
+ *
146
+ * Wire format:
147
+ * - `chain_jsonl`: one signed [`nucleus_lineage::LineageEdge`] per line.
148
+ * - `jwks_json`: a JSON document with a top-level `{ "keys": [...] }` array,
149
+ * each entry an Ed25519 JWK.
150
+ *
151
+ * Returns a [`VerifyReport`] serialized as a `JsValue` (so the JS side
152
+ * gets a plain object, not a string it has to re-parse). Errors are
153
+ * surfaced as `JsValue` strings — wrap with `wasm_bindgen::throw_str`
154
+ * downstream if richer error types are needed.
155
+ */
156
+ export function verify_chain_signatures(chain_jsonl: string, jwks_json: string): any;
157
+
158
+ /**
159
+ * **Bet C moat-closer — recompute-only export.** Re-runs the auction
160
+ * clearing locally from the receipt's signed bid set and reports whether
161
+ * the recomputed price matches the receipt's claimed price. Does NOT
162
+ * check the signature — pair with [`verify_auction_receipt`] (or use
163
+ * [`verify_auction_receipt_full`], which does both).
164
+ *
165
+ * Returns a [`recompute::RecomputeReport`] as a `JsValue`:
166
+ * ```json
167
+ * {
168
+ * "recomputed_price_micro_usd": 400000,
169
+ * "receipt_price_micro_usd": 400000,
170
+ * "matches_receipt": true,
171
+ * "path": "vickrey",
172
+ * "recomputed_winner_spiffe_id": "spiffe://…",
173
+ * "winner_matches": true,
174
+ * "pigou_vcg_clearing_micro_usd": null,
175
+ * "reason": null
176
+ * }
177
+ * ```
178
+ */
179
+ export function verify_clearing_recompute(receipt_json: string): any;
180
+
181
+ /**
182
+ * **Day 3-4 export**: independently verify a single
183
+ * [`PreservationProof`].
184
+ *
185
+ * The browser surfaces this on the demo's "expand any preserved step
186
+ * to see its proof" affordance. The proof is JSON-serializable; the
187
+ * WASM call re-runs the structural check and returns `null` on
188
+ * success or an error string on falsification.
189
+ */
190
+ export function verify_preservation(proof_json: string): void;
191
+
192
+ /**
193
+ * **Day 3-4 export**: independently verify a single
194
+ * [`RecomputationProof`].
195
+ *
196
+ * Same shape as [`verify_preservation`] — re-runs the witness-hash
197
+ * check, returns a `JsValue` error on falsification.
198
+ */
199
+ export function verify_recomputation_necessity(proof_json: string): void;