🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@veritasacta/verify

Package Overview
Dependencies
Maintainers
1
Versions
16
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@veritasacta/verify - npm Package Compare versions

Comparing version
0.9.0
to
0.9.1
+35
samples/sample-restraint-receipt.json
{
"type": "scopeblind.agent_vault.receipt.v1",
"id": "restraint-850d4d9a240d1390",
"tool": "gate.restrain",
"decision": "DENY",
"input_sha256": "9575d64a26f53163614e26c4709831cfd0688f537f4cb1e035546bb13562983c",
"result_sha256": "0a2210cc9d2c2cdf08489dff0f2465ca6c6b36c4ec31d79de77dd71fbf9cd518",
"at": "2026-06-21T12:00:00.000Z",
"signature": "6e8cbe47c16ab29064c197379b55cde79fbb1a4f90dfeb979f6d11f4880ec98e086dc8e9ce5abd58caf0f42b0b0e6adb173d2620b60e9f2ed90688d418d2e803",
"verification_key": "409cb9511071b8687f7884cd9cde813d7a0907bef16bd68a80a8b0bac045cd34",
"restraint": {
"salt": "sample-restraint-salt-000000000000",
"proposed": {
"symbol": "TSLA",
"side": "buy",
"qty": 5000,
"notional": 2000000
},
"outcome": {
"determining": [
"manifest:forbidden-instrument",
"concentration-single-name",
"gross-leverage",
"sector-concentration",
"cash-floor"
],
"risk_band": "authority",
"mandate_digest": "1b92a72197028340",
"layers": {
"manifest": "deny",
"mandate": "deny"
}
}
}
}
/**
* @veritasacta/verify — Re-executable Policy Decision Receipt engine (AIP-0010).
*
* Verifies an authorization decision by RE-EXECUTING the policy engine over the
* policy and inputs carried in the receipt and comparing the result to the
* recorded decision. Correctness of the decision therefore rests on re-execution
* of open, deterministic code, not on trusting the party that produced the
* receipt. See specs/aip/AIP-0010-reexecutable-policy-decision-receipts.md.
*
* The bundled evaluator implements a faithful SUBSET of Cedar's evaluation
* semantics (default-deny, forbid-overrides-permit, scope plus when/unless
* conditions over context and entity attributes), sufficient to exercise and
* demonstrate the re-execution mechanism. Production verifiers pass the official
* Cedar engine identified by `receipt.engine` via the `engine` option.
*
* @module verify-cli/src/engines/policy-decision-reexec
* @license Apache-2.0
*/
import { canonicalize, sha256Hex } from "../util/canonical.js";
const RECEIPT_TYPE = "scopeblind.policy_decision.v1";
/** Commitment helper: "sha256:" + hex(JCS(obj)). */
export function commit(obj) {
return `sha256:${sha256Hex(canonicalize(obj))}`;
}
// ───────────────────────── faithful Cedar subset evaluator ─────────────────────────
/**
* Evaluate a Cedar-subset policy set over a request and entity store.
*
* policySet: { policies: [ { id, effect: "permit"|"forbid",
* principal?: scope, action?: scope, resource?: scope,
* conditions?: [ { kind: "when"|"unless", expr } ] } ] }
* scope: { op: "All" } | { op: "==", entity } | { op: "in", entity }
* expr: { op: "==|!=|<|<=|>|>=", left: ref, right: ref }
* | { op: "and"|"or", clauses: [expr...] } | { op: "not", clause: expr }
* ref: { attr: "context.x" | "resource.x" | "principal.x" } | { value: literal }
*
* Returns { outcome: "permit"|"deny", determining_policies: string[], errors: [] }.
* Semantics: default deny; a request is permitted iff at least one permit policy
* is satisfied and no forbid policy is satisfied (forbid overrides).
*/
export function evaluateCedarSubset(policySet, request, entities) {
const errors = [];
const entityMap = new Map((entities || []).map((e) => [e.uid, e]));
const policies = (policySet && policySet.policies) || [];
const satisfiedForbid = [];
const satisfiedPermit = [];
for (const p of policies) {
let sat;
try {
sat = policySatisfied(p, request, entityMap);
} catch (e) {
errors.push({ policy: p.id, error: String(e.message || e) });
sat = false; // a policy that errors is not satisfied (Cedar skips erroring policies)
}
if (!sat) continue;
if (p.effect === "forbid") satisfiedForbid.push(p.id);
else if (p.effect === "permit") satisfiedPermit.push(p.id);
}
if (satisfiedForbid.length > 0) {
return { outcome: "deny", determining_policies: satisfiedForbid.sort(), errors };
}
if (satisfiedPermit.length > 0) {
return { outcome: "permit", determining_policies: satisfiedPermit.sort(), errors };
}
return { outcome: "deny", determining_policies: [], errors };
}
function policySatisfied(policy, request, entityMap) {
if (!scopeSatisfied(policy.principal, request.principal, entityMap)) return false;
if (!scopeSatisfied(policy.action, request.action, entityMap)) return false;
if (!scopeSatisfied(policy.resource, request.resource, entityMap)) return false;
for (const cond of policy.conditions || []) {
const value = Boolean(evalExpr(cond.expr, request, entityMap));
if (cond.kind === "when" && !value) return false;
if (cond.kind === "unless" && value) return false;
}
return true;
}
function scopeSatisfied(scope, uid, entityMap) {
if (!scope || scope.op === "All") return true;
if (scope.op === "==") return uid === scope.entity;
if (scope.op === "in") return uid === scope.entity || isDescendantOf(uid, scope.entity, entityMap);
throw new Error(`unsupported_scope_op:${scope.op}`);
}
function isDescendantOf(uid, ancestor, entityMap, seen = new Set()) {
if (seen.has(uid)) return false;
seen.add(uid);
const ent = entityMap.get(uid);
const parents = (ent && ent.parents) || [];
if (parents.includes(ancestor)) return true;
return parents.some((p) => isDescendantOf(p, ancestor, entityMap, seen));
}
function evalExpr(expr, request, entityMap) {
if (!expr || typeof expr !== "object") throw new Error("bad_expr");
switch (expr.op) {
case "and": return (expr.clauses || []).every((c) => Boolean(evalExpr(c, request, entityMap)));
case "or": return (expr.clauses || []).some((c) => Boolean(evalExpr(c, request, entityMap)));
case "not": return !evalExpr(expr.clause, request, entityMap);
case "==": case "!=": case "<": case "<=": case ">": case ">=": {
const l = resolveRef(expr.left, request, entityMap);
const r = resolveRef(expr.right, request, entityMap);
return compare(expr.op, l, r);
}
default: throw new Error(`unsupported_op:${expr.op}`);
}
}
function compare(op, l, r) {
switch (op) {
case "==": return l === r;
case "!=": return l !== r;
case "<": return l < r;
case "<=": return l <= r;
case ">": return l > r;
case ">=": return l >= r;
default: return false;
}
}
function resolveRef(ref, request, entityMap) {
if (ref == null || typeof ref !== "object") throw new Error("bad_ref");
if ("value" in ref) return ref.value;
if ("attr" in ref) {
const [root, ...path] = String(ref.attr).split(".");
let base;
if (root === "context") base = request.context || {};
else if (root === "principal") base = attrsOf(request.principal, entityMap);
else if (root === "resource") base = attrsOf(request.resource, entityMap);
else if (root === "action") base = attrsOf(request.action, entityMap);
else throw new Error(`unknown_ref_root:${root}`);
let cur = base;
for (const key of path) {
if (cur == null) return undefined;
cur = cur[key];
}
return cur;
}
throw new Error("bad_ref");
}
function attrsOf(uid, entityMap) {
const e = entityMap.get(uid);
return (e && e.attrs) || {};
}
// ───────────────────────── the verifier ─────────────────────────
/**
* Verify a Re-executable Policy Decision Receipt.
*
* @param {object} receipt
* @param {object} [opts]
* @param {function} [opts.engine] policy engine (default: bundled Cedar subset)
* @param {function} [opts.verifySignature] (receipt) => boolean, authenticity check
* @param {string} [opts.expectedPolicyDigest] catalog/transparency-pinned digest
* @param {{name:string,version:string,digest?:string}} [opts.engineInfo] local engine identity
* @param {boolean} [opts.allowCommitted=true] treat committed-mode as authenticity-only valid
* @returns {{ valid:boolean, reason:string, checks:object, claims:object, recomputed?:object }}
*/
export function verifyPolicyDecisionReceipt(receipt, opts = {}) {
const engine = opts.engine || evaluateCedarSubset;
const checks = {};
const claims = {};
const done = (valid, reason, extra = {}) => ({ valid, reason, checks, claims, ...extra });
if (!receipt || receipt.type !== RECEIPT_TYPE) return done(false, "wrong_type");
if (!receipt.policy || !receipt.decision || !receipt.engine) return done(false, "missing_fields");
// 1. Authenticity (optional, independent of correctness).
if (opts.verifySignature && receipt.signature) {
const ok = Boolean(opts.verifySignature(receipt));
checks.authenticity = ok ? "verified" : "failed";
if (!ok) return done(false, "signature_invalid");
claims.authenticity = "signature";
} else {
checks.authenticity = "skipped";
}
// 2. Policy integrity (digest of inline policy, plus optional catalog pin).
if (receipt.policy.inline !== undefined) {
const digest = commit(receipt.policy.inline);
if (receipt.policy.digest && digest !== receipt.policy.digest) {
checks.policy_integrity = "mismatch";
return done(false, "policy_digest_mismatch");
}
checks.policy_integrity = "verified";
} else {
checks.policy_integrity = "unresolved"; // policy carried by ref; caller must resolve+hash
}
if (opts.expectedPolicyDigest && receipt.policy.digest !== opts.expectedPolicyDigest) {
checks.policy_identity = "substituted";
return done(false, "policy_substitution");
}
// 3. Engine pin.
if (opts.engineInfo) {
const e = receipt.engine;
const pinned = opts.engineInfo.name === e.name && opts.engineInfo.version === e.version
&& (!e.digest || !opts.engineInfo.digest || e.digest === opts.engineInfo.digest);
if (!pinned) {
checks.engine = "unavailable";
claims.correctness = "engine_unavailable";
return done(false, "engine_unavailable");
}
checks.engine = "pinned";
}
// 4. Committed mode: inputs withheld -> correctness CANNOT be checked here.
if (receipt.disclosure === "committed") {
checks.input_integrity = "committed";
checks.correctness = "not_checked_inputs_hidden";
claims.correctness = "not_checked_inputs_hidden";
const valid = opts.allowCommitted !== false; // authenticity-only validity
return done(valid, "inputs_committed_authenticity_only", { authenticityOnly: true });
}
// 5. Input integrity: the disclosed inputs must match the commitment.
const recomputedCommit = commit({ request: receipt.request, entities: receipt.entities });
if (receipt.input_commitment && recomputedCommit !== receipt.input_commitment) {
checks.input_integrity = "mismatch";
return done(false, "input_commitment_mismatch");
}
checks.input_integrity = "verified";
// 6. RE-EXECUTION (the core): recompute the decision and compare.
let recomputed;
try {
recomputed = engine(receipt.policy.inline, receipt.request, receipt.entities);
} catch (e) {
return done(false, `engine_error:${e.message || e}`);
}
const outcomeMatch = normOutcome(recomputed.outcome) === normOutcome(receipt.decision.outcome);
const detMatch = sameSet(recomputed.determining_policies, receipt.decision.determining_policies);
if (!outcomeMatch || !detMatch) {
checks.correctness = "decision_mismatch";
return done(false, "decision_mismatch", { recomputed });
}
checks.correctness = "verified_by_reexecution";
claims.correctness = "re-execution";
return done(true, "valid", { recomputed });
}
function normOutcome(o) {
return o === "forbid" ? "deny" : o; // treat forbid/deny as the same negative outcome
}
function sameSet(a, b) {
const sa = [...new Set(a || [])].sort();
const sb = [...new Set(b || [])].sort();
return sa.length === sb.length && sa.every((x, i) => x === sb[i]);
}
/**
* EAT output mode (packaging sprint A4).
*
* Re-serializes a verified Veritas Acta / Legate receipt as an RFC 9711 EAT
* (Entity Attestation Token) claims-set, so a Legate receipt is ALSO a valid
* EAT/TRACE record that EAT-aware tooling can ingest. Two serializations:
* - JSON: CWT/EAT claim NAMES (RFC 8392 JSON mapping), human-readable.
* - CBOR: CWT claim KEYS (integers), the canonical EAT/CWT wire form.
*
* Honest boundary: this maps and re-serializes an already-Ed25519-signed
* receipt; it does NOT mint a fresh COSE_Sign1 (that requires the issuer key,
* which the offline verifier does not hold). Authenticity round-trips to the
* embedded Acta receipt and its signature, which the verifier already checked.
* A hardware attestation quote, if the receipt carries one, is passed through
* verbatim as the EAT `submods`/`tee_evidence` claim (carry, do not appraise).
*/
// ── CWT / EAT claim keys (IANA CWT registry; RFC 8392 + RFC 9711) ────────────
const CWT_ISS = 1;
const CWT_SUB = 2;
const CWT_IAT = 6;
const CWT_CTI = 7;
const EAT_NONCE = 10;
const EAT_PROFILE = 265;
const EAT_MEASUREMENTS = 273;
// Private-use claim keys (negative ints are reserved for private use, RFC 8392).
const PRIV_ACTA_RECEIPT = -70000; // the full original Acta receipt (canonical JSON)
const PRIV_VERIFICATION = -70001; // the offline verification summary
const PRIV_TEE_EVIDENCE = -70002; // a carried hardware attestation quote, verbatim
const EAT_PROFILE_URI = 'https://veritasacta.com/eat-profile/legate-receipt/v1';
// Governed/gate receipts nest their action fields under `payload`; look there too.
function f(receipt, name) {
const v = receipt[name];
if (v !== undefined && v !== null) return v;
return receipt.payload ? receipt.payload[name] : undefined;
}
function iatFrom(receipt) {
const s = f(receipt, 'signed_at') || f(receipt, 'at') || f(receipt, 'timestamp') || f(receipt, 'issued_at') || f(receipt, 'created_at');
if (!s) return null;
const t = Date.parse(s);
return Number.isNaN(t) ? null : Math.floor(t / 1000);
}
function subjectFrom(receipt) {
return f(receipt, 'tool') || f(receipt, 'action') || f(receipt, 'action_id') || f(receipt, 'summary') || f(receipt, 'id') || null;
}
function ctiFrom(receipt) {
return f(receipt, 'id') || f(receipt, 'receipt_id') || f(receipt, 'cti') || null;
}
function issuerFrom(receipt) {
return receipt.verification_key || f(receipt, 'signer') || f(receipt, 'issuer') || null;
}
function teeEvidenceFrom(receipt) {
return f(receipt, 'tee_evidence') || f(receipt, 'attestation') || f(receipt, 'attestation_quote') || null;
}
function measurementsFrom(receipt) {
const m = {};
const inp = f(receipt, 'input_sha256');
const res = f(receipt, 'result_sha256');
const pol = f(receipt, 'policy_sha256');
const cfr = f(receipt, 'committed_fields_root');
if (inp) m.input_sha256 = inp;
if (res) m.result_sha256 = res;
if (pol) m.policy_sha256 = pol;
if (cfr) m.committed_fields_root = cfr;
return Object.keys(m).length ? m : null;
}
function verificationSummary(result) {
return {
valid: result?.valid === true,
format: result?.format ?? result?.modeLabel ?? null,
signer: result?.signer ?? result?.publicKey ?? null,
error: result?.error ?? null,
};
}
/** Build the EAT claims-set with JSON claim NAMES. */
export function toEatClaims(receipt, result) {
const claims = { eat_profile: EAT_PROFILE_URI };
const iss = issuerFrom(receipt);
if (iss) claims.iss = iss;
const sub = subjectFrom(receipt);
if (sub) claims.sub = sub;
const iat = iatFrom(receipt);
if (iat != null) claims.iat = iat;
const cti = ctiFrom(receipt);
if (cti) claims.cti = cti;
if (receipt.nonce || receipt.eat_nonce) claims.eat_nonce = receipt.nonce || receipt.eat_nonce;
const meas = measurementsFrom(receipt);
if (meas) claims.measurements = meas;
const tee = teeEvidenceFrom(receipt);
if (tee) claims.tee_evidence = tee;
claims.verification = verificationSummary(result);
claims.acta_receipt = receipt; // full receipt, preserving its Ed25519 signature
return claims;
}
export function emitEatJson(receipt, result) {
return JSON.stringify(toEatClaims(receipt, result), null, 2);
}
// ── Minimal deterministic CBOR (RFC 8949 core, definite-length, sorted maps) ─
function cborHead(major, n) {
const mt = major << 5;
if (n < 24) return Uint8Array.of(mt | n);
if (n < 0x100) return Uint8Array.of(mt | 24, n);
if (n < 0x10000) return Uint8Array.of(mt | 25, n >> 8, n & 0xff);
if (n < 0x100000000) return Uint8Array.of(mt | 26, (n >>> 24) & 0xff, (n >>> 16) & 0xff, (n >>> 8) & 0xff, n & 0xff);
// 64-bit length (major 27); split into two 32-bit halves.
const hi = Math.floor(n / 0x100000000);
const lo = n >>> 0;
return Uint8Array.of(mt | 27, (hi >>> 24) & 0xff, (hi >>> 16) & 0xff, (hi >>> 8) & 0xff, hi & 0xff, (lo >>> 24) & 0xff, (lo >>> 16) & 0xff, (lo >>> 8) & 0xff, lo & 0xff);
}
function concatBytes(arrs) {
let len = 0;
for (const a of arrs) len += a.length;
const out = new Uint8Array(len);
let o = 0;
for (const a of arrs) { out.set(a, o); o += a.length; }
return out;
}
/** Encode a value to deterministic CBOR. Supports the JSON value set + integers. */
export function cborEncode(value) {
if (value === null || value === undefined) return Uint8Array.of(0xf6); // null
if (value === true) return Uint8Array.of(0xf5);
if (value === false) return Uint8Array.of(0xf4);
if (typeof value === 'number') {
if (!Number.isInteger(value)) {
// Avoid float ambiguity: carry non-integers as their JSON text.
return cborEncode(String(value));
}
return value >= 0 ? cborHead(0, value) : cborHead(1, -value - 1);
}
if (typeof value === 'string') {
const bytes = new TextEncoder().encode(value);
return concatBytes([cborHead(3, bytes.length), bytes]);
}
if (value instanceof Uint8Array) {
return concatBytes([cborHead(2, value.length), value]);
}
if (Array.isArray(value)) {
return concatBytes([cborHead(4, value.length), ...value.map(cborEncode)]);
}
if (typeof value === 'object') {
// Map: encode each entry, sort by encoded-key bytes (RFC 8949 §4.2.1).
const entries = [];
for (const [k, v] of Object.entries(value)) {
if (v === undefined) continue;
// Numeric-looking keys carried as integers (used for CWT claim keys).
const keyEnc = /^-?\d+$/.test(k) ? cborEncode(parseInt(k, 10)) : cborEncode(k);
entries.push([keyEnc, cborEncode(v)]);
}
entries.sort((a, b) => {
const x = a[0], y = b[0];
const n = Math.min(x.length, y.length);
for (let i = 0; i < n; i++) if (x[i] !== y[i]) return x[i] - y[i];
return x.length - y.length;
});
return concatBytes([cborHead(5, entries.length), ...entries.flatMap((e) => e)]);
}
throw new Error(`cborEncode: unsupported type ${typeof value}`);
}
/** Build the CWT/EAT claims-set keyed by integer claim keys, for CBOR. */
export function toEatClaimsCbor(receipt, result) {
const m = {};
m[EAT_PROFILE] = EAT_PROFILE_URI;
const iss = issuerFrom(receipt);
if (iss) m[CWT_ISS] = iss;
const sub = subjectFrom(receipt);
if (sub) m[CWT_SUB] = sub;
const iat = iatFrom(receipt);
if (iat != null) m[CWT_IAT] = iat;
const cti = ctiFrom(receipt);
if (cti) m[CWT_CTI] = new TextEncoder().encode(String(cti)); // CWT cti is a byte string
if (receipt.nonce || receipt.eat_nonce) m[EAT_NONCE] = String(receipt.nonce || receipt.eat_nonce);
const meas = measurementsFrom(receipt);
if (meas) m[EAT_MEASUREMENTS] = JSON.stringify(meas);
const tee = teeEvidenceFrom(receipt);
if (tee) m[PRIV_TEE_EVIDENCE] = JSON.stringify(tee);
m[PRIV_VERIFICATION] = JSON.stringify(verificationSummary(result));
// Carry the full receipt as canonical JSON text to preserve its exact bytes
// (and its Ed25519 signature) without float-encoding ambiguity.
m[PRIV_ACTA_RECEIPT] = JSON.stringify(receipt);
return m;
}
/** Hex-encoded CBOR CWT/EAT claims-set. */
export function emitEatCbor(receipt, result) {
const bytes = cborEncode(toEatClaimsCbor(receipt, result));
return Buffer.from(bytes).toString('hex');
}
+22
-65
# Changelog
## 0.9.0 (2026-06-22)
## Unreleased
### Legate adherence / restraint proof packs
### Restraint receipts: prove what was prevented, offline and position-blind
Recognizes and verifies `scopeblind.legate.proof-pack.v1`: the allocator-facing,
position-blind record a Legate desk produces of what the gate prevented over a
session (held / blocked, attributed to the committed-mandate rules) plus order-path
shadow evidence (what it would have blocked on a FIX feed), bound to the mandate
digest, the signed book provenance, and a receipt Merkle root. The signature is
Ed25519 over the canonical (deep-sorted, no-whitespace) bytes of the pack minus its
`signature`, `sha256`, and `hybrid_signature` fields, against the embedded runtime
`verification_key` (pin it with `--key`). Cross-implementation tested against a real
desktop-runtime-signed fixture (`samples/legate-proof-pack.json`); tampering with any
field, and a wrong pinned key, fail. An optional `hybrid_signature` (Ed25519 +
ML-DSA-65) is recognized and reported; classical Ed25519 is verified here, with PQ
verification documented as an optional add-on in the restraint-receipts draft.
A restraint receipt (`tool: gate.restrain`) is already verified as a Legate
governed receipt. This release re-verifies and surfaces its openable detail, so
the receipt proves not merely that a deny was signed but exactly WHAT was
prevented and WHY:
## 0.8.0 (2026-06-13)
- The disclosed denial outcome (the determining rules, risk band, mandate
digest) is re-hashed and confirmed to bind to the signed `result_sha256`, and
the proposed blocked order is re-hashed under its salt and confirmed to bind to
`input_sha256`. Re-hashing uses the same JCS canonicalization the runtime used,
so altering the disclosed detail flips the binding to a failure while the
signature stays valid over the original hashes (you cannot lie about what was
blocked).
- Position-blind by construction: the blocked order can be withheld, and the
outcome still verifies because the order is salt-committed into the signed input
hash and openable to a regulator on demand.
- Terminal output gains a `Prevented:` block (risk band, determining rules, the
blocked order or a position-blind note, and the two binding checks). New
`verifyRestraintBindings` export. A sample lives at
`samples/sample-restraint-receipt.json`; see `RESTRAINT-DEMO.md`.
- Added a `verify` bin alias (alongside `verify-artifact`) so
`npx @veritasacta/verify <receipt>` reads naturally.
### RFC 6962 transparency log for macro track records
Recognizes `scopeblind.macro.transparency-head/1` and
`scopeblind.macro.transparency-witness/1`, and verifies the `transparency`
evidence carried in a macro track-record bundle: every record's Merkle
inclusion proof against the signed head (RFC 6962 hashing: leaf =
sha256(0x00||digest), node = sha256(0x01||l||r)), plus an independent witness
co-signature. The bundle result reports `Transparency: witness-anchored /
self-signed / not anchored`; a tampered head or a missing inclusion fails the
chain check. No new signing crypto — inclusion is recomputed from the path and
checked against the head root. This is what makes a dropped or rewritten record
detectable to anyone who retained a head, not merely a single un-trimmed export.
### ScopeBlind macro-engine snapshots and track-record bundles
New engine `src/engines/macro-snapshot.js` recognizes the macro-engine
schemas (`scopeblind.macro.market-state/1`, `regime-snapshot/1`,
`tape-snapshot/1`, `vulnerability/1`, `alert/1`, `journal-entry/1`) and the
signed track-record bundle (`scopeblind.macro.track-record-bundle/1`). Macro
snapshots already verified cryptographically as generic Gate tuples; this adds
schema recognition, a per-schema semantic-contract check, and a schema-aware
summary in the output (no more "unrecognized schema" for macro records). No
new cryptography: crypto is delegated to `verifyGateTuple` and canonicalization
to `canonicalGateJSON`.
The track-record bundle verifier mirrors the Gate evidence-bundle: it checks
every record's signature, single-signer custody (every record including the
manifest shares one model key), exact manifest completeness (entries enumerate
the snapshots then journal entries in order), the snapshot/journal counts, and
the `history_head_digest` over the ordered record digests. Dropping or
tampering any record breaks the bundle. `--mode macro` forces the bundle path.
Anchored exports additionally carry a monotonic manifest sequence, previous
manifest/history-head links, retained prior manifests, and a signed checkpoint
chain. Verification rejects deletion of any previously manifested record.
`--key` is now reported explicitly as the operator-identity trust boundary;
without it the result proves embedded-key integrity only. `--history-head` and
`--anchor-head` pin independently retained anti-rollback checkpoints.
## 0.7.0 (2026-06-12)
### Release rule for execution evidence
Bundles whose entries carry fills under an unreleased decision fail the
chain check: fills require an ALLOW parent, or an APPROVAL_REQUIRED
parent with a present approval whose decision is approved. A DENY or
REVIEW parent with fills always fails. Without this rule a bundle could
present individually valid signatures as evidence of an unauthorized
execution.
### ScopeBlind Gate receipt tuples and evidence bundles

@@ -73,0 +30,0 @@

+18
-40

@@ -47,6 +47,3 @@ #!/usr/bin/env node

import { verifyGateTuple, verifyGateBundle } from './src/engines/gate-receipt.js';
import { verifyMacroTrackRecord } from './src/engines/macro-snapshot.js';
import { verifyLegateGovernedReceipt } from './src/engines/legate-governed-receipt.js';
import { verifyLegateProofPack } from './src/engines/legate-proof-pack.js';
import { verifyTrustedContextPack } from './src/engines/trusted-context-pack.js';
import { verifyVoprfToken } from './src/engines/voprf-token.js';

@@ -81,3 +78,2 @@ import { verifyKnowledgeUnit } from './src/engines/knowledge-unit.js';

import { resolveFromJwks } from './src/util/jwks.js';
import { loadKnownIssuers, labelFor } from './src/util/known-issuers.js';
import { appendAuditEntry } from './src/util/audit-log.js';

@@ -93,5 +89,3 @@ import { fipsStatus } from './src/util/fips.js';

formatGateBundleResult,
formatMacroTrackRecordResult,
formatGovernedReceiptResult,
formatTrustedContextPackResult,
formatKuResult,

@@ -121,6 +115,3 @@ formatSelfCheckResult,

'gate-evidence-bundle': 'ScopeBlind Gate evidence bundle (receipt tuples + chain links)',
'macro-track-record': 'ScopeBlind macro-engine track-record bundle (signed snapshots + completeness manifest)',
'legate-governed-receipt': 'Legate governed receipt (Ed25519 over canonical action payload)',
'legate-proof-pack': 'Legate adherence / restraint proof pack (Ed25519 over canonical bytes, position-blind)',
'trusted-context-pack': 'ScopeBlind Trusted Context Pack (signed parsed-context attestation)',
};

@@ -166,2 +157,3 @@

emitVerificationReceipt: false,
emitEat: null,
fips: false,

@@ -174,4 +166,2 @@ subcommand: null,

frameworkOverride: null,
historyHead: null,
anchorHead: null,
};

@@ -189,7 +179,4 @@

case '-k': opts.publicKey = next(); break;
case '--known-issuers': opts.knownIssuers = next(); break;
case '--jwks': opts.jwksUrl = next(); break;
case '--trust-anchor': opts.trustAnchor = next(); break;
case '--history-head': opts.historyHead = next(); break;
case '--anchor-head': opts.anchorHead = next(); break;
case '--stdin': opts.stdin = true; break;

@@ -221,2 +208,4 @@ case '--mode': opts.mode = next(); break;

case '--emit-verification-receipt': opts.emitVerificationReceipt = true; break;
case '--emit-eat': opts.emitEat = 'json'; break;
case '--emit-eat-cbor': opts.emitEat = 'cbor'; break;
case '--fips': opts.fips = true; break;

@@ -315,4 +304,2 @@ case '--allow-partial-voprf': opts.allowPartialVoprf = true; break;

--trust-anchor <file> Local trust-anchor JSON with public keys
--history-head <hex> Pin the expected macro track-record history head
--anchor-head <hex> Pin the expected signed macro anchor digest
--mode <m> Force mode: receipt|voprf|ku|auto (default: auto)

@@ -521,5 +508,3 @@ --bundle Verify as audit bundle

else if (forced === 'gate-bundle') detected.mode = 'gate-evidence-bundle';
else if (forced === 'macro' || forced === 'macro-track-record') detected.mode = 'macro-track-record';
else if (forced === 'governed') detected.mode = 'legate-governed-receipt';
else if (forced === 'context' || forced === 'context-pack') detected.mode = 'trusted-context-pack';
}

@@ -559,6 +544,2 @@ if (opts.bundle) detected.mode = 'ed25519-bundle';

}
case 'macro-track-record': {
const r = verifyMacroTrackRecord(input, subOpts);
return { ...r, modeLabel: MODE_LABELS['macro-track-record'] };
}
case 'gate-receipt-tuple': {

@@ -572,10 +553,2 @@ const r = verifyGateTuple(input, subOpts);

}
case 'legate-proof-pack': {
const r = verifyLegateProofPack(input, subOpts);
return { ...r, modeLabel: MODE_LABELS['legate-proof-pack'] };
}
case 'trusted-context-pack': {
const r = verifyTrustedContextPack(input, subOpts);
return { ...r, modeLabel: MODE_LABELS['trusted-context-pack'] };
}
case 'knowledge-unit': {

@@ -1215,2 +1188,17 @@ const r = await verifyKnowledgeUnit(input, subOpts);

// EAT output mode (A4): re-serialize the verified receipt as an RFC 9711 EAT
// claims-set so it is also a valid EAT/TRACE record (JSON names, or CBOR with
// integer claim keys). Authenticity round-trips to the embedded Acta receipt.
if (opts.emitEat) {
const { emitEatJson, emitEatCbor } = await import('./src/output/eat.js');
const out = opts.emitEat === 'cbor' ? emitEatCbor(input, result) : emitEatJson(input, result);
if (opts.output) {
writeFileSync(opts.output, out);
console.error(dim(`wrote ${opts.output}`));
} else {
console.log(out);
}
process.exit(result.valid ? 0 : exitCodeFor(result.error));
}
// Audit log

@@ -1246,10 +1234,2 @@ if (opts.auditLog) {

// Resolve a human label for the signer key, if one is known. Display aid only;
// it never changes the verification result.
if (result && typeof result === 'object' && typeof result.publicKey === 'string') {
const issuers = loadKnownIssuers(opts.knownIssuers, join(__dirname, 'known-issuers.json'));
const label = labelFor(result.publicKey, issuers);
if (label) result.signerLabel = label;
}
// Output

@@ -1276,6 +1256,4 @@ if (opts.json) {

else if (result.format === 'gate-evidence-bundle') console.log(formatGateBundleResult(result, opts));
else if (result.format === 'macro-track-record') console.log(formatMacroTrackRecordResult(result, opts));
else if (result.format === 'gate-tuple') console.log(formatGateTupleResult(result, opts));
else if (result.format === 'legate-governed-receipt') console.log(formatGovernedReceiptResult(result, opts));
else if (result.format === 'trusted-context-pack') console.log(formatTrustedContextPackResult(result, opts));
else if (result.total !== undefined) console.log(formatBundleResult(result, opts));

@@ -1282,0 +1260,0 @@ else console.log(formatReceiptResult(result, opts));

{
"name": "@veritasacta/verify",
"version": "0.9.0",
"version": "0.9.1",
"mcpName": "io.github.tomjwxf/veritasacta-verify",

@@ -9,2 +9,3 @@ "description": "Offline verifier for Veritas Acta signed receipts. Powers protect-mcp, ScopeBlind cold-chain hardware, and Microsoft AGT Lesson 18.",

"bin": {
"verify": "cli.js",
"verify-artifact": "cli.js"

@@ -22,5 +23,8 @@ },

"ROADMAP.md",
"samples/",
"test/conformance.js",
"known-issuers.json"
"samples/sample-bundle.json",
"samples/sample-gate-bundle.json",
"samples/sample-gate-tuple.json",
"samples/sample-receipt.json",
"samples/sample-restraint-receipt.json",
"test/conformance.js"
],

@@ -53,3 +57,3 @@ "dependencies": {

"scripts": {
"test": "node --test test/unit/*.test.js test/integration/*.test.js",
"test": "node --test 'test/unit/**/*.test.js' 'test/integration/**/*.test.js'",
"test:conformance": "node test/conformance.js",

@@ -56,0 +60,0 @@ "self-test": "node cli.js --self-test",

@@ -41,3 +41,2 @@ # @veritasacta/verify

| Gate receipt / bundle | ScopeBlind Gate receipt tuples (`scopeblind.gate.*`) and signed-manifest `scopeblind.gate.evidence-bundle/2` exports with semantic and exact chain checks | T1 |
| Macro track record | Signed macro snapshots, append-only manifest sequence, and signed history checkpoints | T1 |

@@ -102,20 +101,2 @@ ## Subcommands

### ScopeBlind macro track records
Macro exports verify offline. An embedded key proves internal signature
integrity, not who controls that key. Pin the operator key and an independently
retained anti-rollback head for identity and historical assurance:
```bash
npx @veritasacta/verify@0.8.0 legate-macro-track-record.json \
--key <operator-ed25519-public-key> \
--history-head <expected-history-head> \
--anchor-head <expected-anchor-digest>
```
The verifier checks every record, the exact current manifest inventory, prior
manifest links, retention of previously manifested records, and the signed
checkpoint chain. Publication at a mutable URL is not itself a transparency
log; retain or independently timestamp checkpoint heads.
### Pre-built sandbox profiles

@@ -122,0 +103,0 @@

{
"sigil_version": 1,
"fingerprint": "b309bd8b",
"name": "Woven Meadow",
"sigil_hash": "b309bd8b8644efcc07e737cff69cb7a87eaa9c8c9d728baf751c89b882c2c1cd",
"fingerprint": "677a8a81",
"name": "Open Wind",
"sigil_hash": "677a8a812c7a9d896bee2d7f8dfde02d347ac742fa4cd8830c9e292e92b9e676",
"project_public_key": "fe665e861867cec7e171c0c13bbc873c3362079faef21f54df7804b7fb9ae8af",

@@ -10,4 +10,4 @@ "policy": {

"package": "@veritasacta/verify",
"package_version": "0.7.0",
"source_hash": "ab926d490a512418c8028cd46eb766a100602e28b9c5f26381585030763a2fab",
"package_version": "0.5.4",
"source_hash": "4eca3a4aa71e50cf983285520ff8ec93e2ece12d2912f0b7b60b5c7034b879f9",
"monitored_files": [

@@ -19,3 +19,2 @@ "cli.js",

"src/engines/ed25519-receipt.js",
"src/engines/gate-receipt.js",
"src/engines/voprf-token.js",

@@ -62,6 +61,6 @@ "src/engines/knowledge-unit.js",

],
"created_at": 1781269520160
"created_at": 1776673390228
},
"policy_hash": "7d517dbbb5824d09186ec8b2344febeb5e62e5dc54bcb191c59da13f2ee03b9a",
"derived_at": "2026-06-12T13:05:20.160Z"
"policy_hash": "3d9bbcbea4af4032c7e77fc1f0a8606553e9a53bf8df0f09ed0bcd0859faa92a",
"derived_at": "2026-04-20T08:23:10.228Z"
}

@@ -14,3 +14,2 @@ /**

* - 'gate-evidence-bundle' — ScopeBlind Gate evidence bundle (scopeblind.gate.evidence-bundle/2)
* - 'macro-track-record' — ScopeBlind macro-engine track-record bundle (scopeblind.macro.track-record-bundle/1)
* - 'unknown'

@@ -80,29 +79,2 @@ *

// ScopeBlind macro-engine track-record bundle: explicit schema marker +
// snapshots[] + a signed manifest tuple.
if (
input.schema === 'scopeblind.macro.track-record-bundle/1'
&& Array.isArray(input.snapshots)
&& input.manifest && typeof input.manifest === 'object' && !Array.isArray(input.manifest)
) {
signals.push(`schema=${input.schema}`, 'snapshots[]', 'manifest');
return { mode: 'macro-track-record', signals, hasSelectiveDisclosure: false, isBundle: true };
}
// ScopeBlind Trusted Context Pack: a Gate-tuple-shaped envelope whose payload
// carries the TCB schema marker. Detected BEFORE the generic gate tuple (it
// matches that shape too) and routed to engines/trusted-context-pack.js so a
// third party re-verifies the parsed-context attestation, its confidence, and
// its gate decision offline.
if (
input.payload && typeof input.payload === 'object' && !Array.isArray(input.payload)
&& input.payload.schema === 'scopeblind.trusted_context_pack.v1'
&& typeof input.digest === 'string'
&& typeof input.signature === 'string'
&& typeof input.verification_key === 'string'
) {
signals.push('schema=scopeblind.trusted_context_pack.v1');
return { mode: 'trusted-context-pack', signals, hasSelectiveDisclosure: false, isBundle: false };
}
// ScopeBlind Gate receipt tuple: { payload, digest, signature, verification_key }.

@@ -122,17 +94,2 @@ // The flat hex signature string distinguishes it from the Passport

// Legate adherence / restraint proof pack: type scopeblind.legate.proof-pack.v1,
// signed by the runtime key (verification_key) over the canonical bytes of the pack
// minus signature/sha256. A position-blind record of what the gate prevented (held /
// blocked, by rule) plus order-path shadow evidence. Detected before the v1-flat
// catch-all so it routes to engines/legate-proof-pack.js. Routed by its type.
if (
input.type === 'scopeblind.legate.proof-pack.v1'
&& typeof input.signature === 'string'
&& (typeof input.verification_key === 'string'
|| (input.runtime && typeof input.runtime.verification_key === 'string'))
) {
signals.push('type=scopeblind.legate.proof-pack.v1', 'signature+verification_key');
return { mode: 'legate-proof-pack', signals, hasSelectiveDisclosure: false, isBundle: false };
}
// Legate governed receipt: a FLAT, pipe-delimited canonical payload

@@ -139,0 +96,0 @@ // scopeblind.receipt.v1|<id>|<tool>|<decision>|<input_sha256>|<result_sha256>|<at>

@@ -7,3 +7,2 @@ /** ScopeBlind Gate receipt and evidence-bundle verifier. */

import { hexToBytes, bytesToHex } from '../util/hex.js';
import { isMacroSchema, macroSchemaErrors, macroSummary, MACRO_PROVES, MACRO_LIMITATIONS } from './macro-snapshot.js';

@@ -20,4 +19,2 @@ export const GATE_BUNDLE_SCHEMA = 'scopeblind.gate.evidence-bundle/2';

'scopeblind.gate.evidence-manifest/1': 'signed bundle manifest',
'scopeblind.gate.reconciliation/1': 'custodian-statement reconciliation',
'scopeblind.gate.stress/1': 'regime stress-test result',
'scopeblind.mandate.delegation/1': 'issuer-signed mandate delegation',

@@ -141,6 +138,4 @@ };

const schema = isString(payload.schema) ? payload.schema : null;
const macro = schema !== null && isMacroSchema(schema);
const schemaRecognized = schema !== null && (Object.hasOwn(GATE_SCHEMAS, schema) || macro);
Object.assign(base, { schema, schemaRecognized, macroSchema: macro, type: schema || undefined, payloadFields: collectGatePayloadFields(payload), chainFields: macro ? null : collectGateChainFields(payload) });
if (macro) base.macroSummary = macroSummary(payload);
const schemaRecognized = schema !== null && Object.hasOwn(GATE_SCHEMAS, schema);
Object.assign(base, { schema, schemaRecognized, type: schema || undefined, payloadFields: collectGatePayloadFields(payload), chainFields: collectGateChainFields(payload) });
if (!isString(tuple.signature)) return { valid: false, error: 'missing_signature', ...base };

@@ -158,16 +153,5 @@ if (!isString(tuple.digest) || !HEX_64.test(tuple.digest)) return { valid: false, error: 'malformed_hex', ...base, detail: 'tuple digest must be 64 lowercase hex characters' };

}
const semanticErrors = macro ? macroSchemaErrors(payload) : schemaErrors(payload);
const semanticErrors = schemaErrors(payload);
if (semanticErrors.length) return { valid: false, error: 'schema_invalid', ...base, digest: tuple.digest, publicKey: tuple.verification_key, detail: semanticErrors.join('; '), semanticErrors };
return {
valid: true,
...base,
digest: tuple.digest,
publicKey: tuple.verification_key,
keySource: pinned ? 'embedded-tuple (pinned via --key)' : 'embedded-tuple',
signerPinned: pinned,
identityStatus: pinned ? 'pinned_expected_key' : 'embedded_key_only',
algorithm: 'ed25519',
proves: macro ? MACRO_PROVES : GATE_PROVES,
limitations: macro ? MACRO_LIMITATIONS : GATE_LIMITATIONS,
};
return { valid: true, ...base, digest: tuple.digest, publicKey: tuple.verification_key, keySource: pinned ? 'embedded-tuple (pinned via --key)' : 'embedded-tuple', algorithm: 'ed25519', proves: GATE_PROVES, limitations: GATE_LIMITATIONS };
}

@@ -292,23 +276,2 @@

if (e.approval) add(e.approval, 'approval', i, approvalCheck(e.approval, parent, parent?.digest), false);
// Execution evidence requires a RELEASED decision. An ALLOW parent is
// released by definition; an APPROVAL_REQUIRED parent is released only by
// a present approval whose decision is "approved" (its own crypto and
// chain validity are checked above). Fills under a DENY, REVIEW, held, or
// declined parent are evidence of an unauthorized execution and fail the
// bundle even when every signature is individually valid.
const fillsPresent = Array.isArray(e.fills) && e.fills.length > 0;
if (fillsPresent) {
const decision = parent?.payload?.decision;
const released = decision === 'ALLOW'
|| (decision === 'APPROVAL_REQUIRED' && e.approval?.payload?.decision === 'approved');
results.chainChecks++;
if (!released) {
results.valid = false;
results.chainFailed++;
const why = decision === 'APPROVAL_REQUIRED'
? (e.approval ? `approval decision is ${JSON.stringify(e.approval?.payload?.decision)}` : 'no approval is present')
: `parent decision is ${JSON.stringify(decision)}`;
results.errors.push(`[chain] Entry ${i + 1}: fills present but the decision was never released (${why})`);
}
}
const fillsByDigest = new Map();

@@ -315,0 +278,0 @@ for (const fill of Array.isArray(e.fills) ? e.fills : []) { const err = fillCheck(fill, parent, legsById, legTuples); add(fill, 'fill', i, err, false); fillsByDigest.set(fill?.digest, fill); }

@@ -28,2 +28,3 @@ /**

import { hexToBytes } from '../util/hex.js';
import { canonicalize, sha256Hex } from '../util/canonical.js';

@@ -58,3 +59,32 @@ /** The canonical payload prefix this engine recognizes (v1). */

const isString = (v) => typeof v === 'string' && v.length > 0;
const isObject = (v) => v !== null && typeof v === 'object' && !Array.isArray(v);
/**
* Re-verify the openable detail of a restraint receipt. A restraint receipt
* binds the disclosed denial outcome into result_sha256 and the (optionally
* withheld) proposed order into input_sha256, both via the same canonical
* hashing the runtime used. Re-hashing here proves the disclosed detail is
* exactly what was signed — so the receipt proves WHAT was prevented and WHY,
* not merely that some deny was signed.
*
* @param {object} receipt a governed receipt with a `restraint` detail block
* @returns {{ outcome_bound: boolean, proposed_bound: boolean|null, determining: string[], risk_band: string|null, mandate_digest: string|null, proposed: object|null }}
*/
export function verifyRestraintBindings(receipt) {
const r = isObject(receipt?.restraint) ? receipt.restraint : {};
const outcome_bound = isObject(r.outcome) && sha256Hex(canonicalize(r.outcome)) === receipt.result_sha256;
let proposed_bound = null; // null = position-blind (proposed withheld)
if (r.proposed != null) {
proposed_bound = isString(r.salt) && sha256Hex(`${r.salt}|${canonicalize(r.proposed)}`) === receipt.input_sha256;
}
return {
outcome_bound,
proposed_bound,
determining: Array.isArray(r.outcome?.determining) ? r.outcome.determining : [],
risk_band: isString(r.outcome?.risk_band) ? r.outcome.risk_band : null,
mandate_digest: isString(r.outcome?.mandate_digest) ? r.outcome.mandate_digest : null,
proposed: r.proposed ?? null,
};
}
/** Reconstruct the exact bytes the daemon + phone signed. */

@@ -134,3 +164,3 @@ export function legateReceiptPayload(r) {

return {
const result = {
valid: true,

@@ -141,5 +171,32 @@ ...base,

signedPayload: payload,
proves: GOVERNED_PROVES,
limitations: GOVERNED_LIMITATIONS,
proves: [...GOVERNED_PROVES],
limitations: [...GOVERNED_LIMITATIONS],
};
// Restraint receipts carry openable detail: the disclosed outcome (the rules
// that blocked the action) and, unless position-blind, the proposed order.
// Re-hash both and confirm they bind to the signed hashes, so the receipt
// proves exactly WHAT was prevented and WHY, not merely that a deny was signed.
if (kind === 'restraint' && isObject(receipt.restraint)) {
const bindings = verifyRestraintBindings(receipt);
result.restraint = bindings;
if (bindings.outcome_bound) {
result.proves.push(
'Restraint: the gate blocked this action before it could execute, and the disclosed outcome (the determining rules and risk band) re-hashes to the signed result hash, so it is exactly what was committed.',
);
} else {
result.limitations.push(
'The disclosed restraint outcome did NOT re-hash to the signed result hash: the detail shown was altered after signing (the signature itself is still valid over the original hashes).',
);
}
if (bindings.proposed_bound === null) {
result.proves.push(
'Position-blind: the blocked order is withheld but salt-committed into the signed input hash, so the restraint is provable without disclosing the position.',
);
} else if (bindings.proposed_bound === false) {
result.limitations.push('The disclosed blocked order did NOT re-hash to the signed input hash (the shown order was altered after signing).');
}
}
return result;
}

@@ -213,59 +213,2 @@ /**

/**
* Render the salient-field lines for a recognized macro snapshot summary.
*
* @param {Object} s macroSummary object from engines/macro-snapshot.js
* @returns {string[]}
*/
function macroSummaryLines(s) {
const lines = [];
if (s.description) lines.push(` Snapshot: ${dim(s.description)}`);
if (s.as_of) lines.push(` As of: ${dim(s.as_of)}`);
switch (s.schema) {
case 'scopeblind.macro.market-state/1':
lines.push(` Class: ${s.classification}${s.confidence !== undefined ? dim(` (confidence ${s.confidence})`) : ''}`);
if (s.pillars) lines.push(` Pillars: ${dim(Object.entries(s.pillars).map(([k, v]) => `${k} ${v >= 0 ? '+' : ''}${v}`).join(', '))}`);
break;
case 'scopeblind.macro.regime-snapshot/1':
lines.push(` Regime: ${s.regime}${s.candidate_regime && s.candidate_regime !== s.regime ? dim(` (candidate ${s.candidate_regime})`) : ''}`);
if (s.liquidity_overlay) lines.push(` Liquidity: ${s.liquidity_overlay}`);
if (s.confidence !== undefined) lines.push(` Confidence: ${dim(String(s.confidence))}`);
break;
case 'scopeblind.macro.tape-snapshot/1':
lines.push(` Tape type: ${s.tape_type}${s.material !== undefined ? dim(` (${s.material ? 'material' : 'immaterial'})`) : ''}`);
if (s.coherence !== undefined) lines.push(` Coherence: ${dim(String(s.coherence))}`);
if (s.attribution_tier) lines.push(` Attributed: ${dim(s.attribution_tier)}`);
break;
case 'scopeblind.macro.vulnerability/1':
if (s.regime || s.market_state) lines.push(` Posture: ${dim([s.regime, s.market_state].filter(Boolean).join(' / '))}`);
if (Array.isArray(s.top_vulnerabilities) && s.top_vulnerabilities.length) {
lines.push(` Top risk: ${dim(s.top_vulnerabilities.map((v) => `${v.factor} (pain ${v.pain})`).join(', '))}`);
}
break;
case 'scopeblind.macro.alert/1':
lines.push(` Severity: ${s.severity}${s.kind ? dim(` (${s.kind})`) : ''}`);
if (s.title) lines.push(` Title: ${s.title}`);
break;
case 'scopeblind.macro.journal-entry/1':
if (s.author) lines.push(` Author: ${s.author}`);
lines.push(` References: ${dim(`${s.reference_count} signed snapshot(s)`)}`);
break;
case 'scopeblind.macro.track-record-manifest/1':
lines.push(` Inventory: ${dim(`${s.snapshot_count} snapshots, ${s.journal_count} journal entries`)}`);
break;
case 'scopeblind.macro.transparency-head/1':
if (s.log_id) lines.push(` Log: ${dim(s.log_id)}`);
lines.push(` Tree size: ${dim(`${s.tree_size} leaves`)}`);
if (s.root_hash) lines.push(` Root: ${dim(`${String(s.root_hash).slice(0, 16)}...`)}`);
break;
case 'scopeblind.macro.transparency-witness/1':
if (s.head_digest) lines.push(` Head: ${dim(`${String(s.head_digest).slice(0, 16)}...`)}`);
lines.push(` Tree size: ${dim(`${s.tree_size} leaves`)}`);
break;
default:
break;
}
return lines;
}
/**
* Format a ScopeBlind Gate receipt-tuple result.

@@ -292,9 +235,7 @@ *

lines.push(`\n${icon} Signature: ${status}`);
lines.push(` Format: ${result.macroSchema ? 'ScopeBlind macro-engine snapshot' : 'ScopeBlind Gate receipt tuple'}`);
lines.push(` Format: ScopeBlind Gate receipt tuple`);
if (result.schema) {
const recog = result.macroSchema && result.schemaRecognized
? dim('(recognized macro schema)')
: result.schemaRecognized
? dim('(recognized)')
: yellow('(unrecognized schema; verified as a generic tuple)');
const recog = result.schemaRecognized
? dim('(recognized)')
: yellow('(unrecognized schema; verified as a generic tuple)');
lines.push(` Schema: ${result.schema} ${recog}`);

@@ -304,9 +245,6 @@ } else {

}
if (result.macroSummary) {
for (const line of macroSummaryLines(result.macroSummary)) lines.push(line);
}
if (result.algorithm) lines.push(` Algorithm: ${result.algorithm} (over the SHA-256 payload digest)`);
if (result.digest) lines.push(` Digest: ${dim(result.digest)}`);
if (result.recomputedDigest) lines.push(` Recomputed: ${red(result.recomputedDigest)}`);
if (result.publicKey) lines.push(` Signer: ${result.signerLabel ? bold(result.signerLabel) + ' ' : ''}${dim(result.publicKey)}`);
if (result.publicKey) lines.push(` Signer: ${dim(result.publicKey)}`);
if (result.keySource) lines.push(` Key: ${result.keySource}`);

@@ -392,84 +330,33 @@

if (result.algorithm) lines.push(` Algorithm: ${result.algorithm} ${dim('(over the canonical action payload, not a digest)')}`);
if (result.publicKey) lines.push(` Signer: ${result.signerLabel ? bold(result.signerLabel) + ' ' : ''}${dim(result.publicKey)}`);
if (result.publicKey) lines.push(` Signer: ${dim(result.publicKey)}`);
if (result.keySource) lines.push(` Key: ${result.keySource}`);
if (result.error && !result.valid) {
lines.push(` Error: ${red(result.error)}`);
if (result.error === 'invalid_signature') lines.push(` Detail: ${yellow('the signed bytes were altered or the key does not match — this receipt was tampered with')}`);
else if (result.detail) lines.push(` Detail: ${yellow(result.detail)}`);
if (result.expectedKey) lines.push(` Expected: ${yellow(result.expectedKey)} ${dim('(--key)')}`);
}
if (result.valid && Array.isArray(result.proves)) {
lines.push(` ${bold('This proves:')}`);
for (const p of result.proves) lines.push(` ${green('•')} ${dim(p)}`);
lines.push(` ${bold('This does not prove:')}`);
for (const l of (result.limitations || [])) lines.push(` ${yellow('!')} ${dim(l)}`);
}
lines.push('');
lines.push(WAYFINDING);
lines.push('');
return lines.join('\n');
}
/**
* Format a Trusted Context Pack result: the signed attestation that a source file
* parsed to this context at this confidence and freshness. The output leads with
* the signer and the gate decision (usable / needs approval / blocked), names the
* source type, and is explicit that this attests the parse, not the provenance.
*
* @param {Object} result from src/engines/trusted-context-pack.js
* @param {Object} opts cli options
* @returns {string}
*/
export function formatTrustedContextPackResult(result, opts = {}) {
const lines = [];
if (result.valid && result.publicKey && result.publicKey.length === 64 && !isCI && !opts.noSigil) {
// Restraint receipts: surface WHAT was prevented and re-verify that the
// disclosed detail binds to the signed hashes. This is the negative-space
// proof: most governance can only show what an agent did; this shows, offline
// and position-blind, what it was stopped from doing and why.
if (result.valid && result.restraint) {
const rb = result.restraint;
lines.push('');
lines.push(renderTerminalSigil(result.publicKey));
lines.push(` ${bold('Prevented:')} ${dim('an out-of-mandate action the gate blocked before it could execute')}`);
if (rb.risk_band) lines.push(` Risk band: ${rb.risk_band}`);
if (rb.determining.length) lines.push(` Blocked by: ${rb.determining.join(', ')}`);
if (rb.proposed) {
const p = rb.proposed;
const notional = typeof p.notional === 'number' ? ` ${dim(`($${p.notional.toLocaleString('en-US')})`)}` : '';
lines.push(` Blocked order: ${[p.side, p.qty, p.symbol].filter((x) => x != null && x !== '').join(' ')}${notional}`);
} else {
lines.push(` Blocked order: ${dim('withheld (position-blind)')}`);
}
lines.push(` ${rb.outcome_bound ? green('✓') : red('✗')} the outcome above re-hashes to the signed result hash`);
if (rb.proposed_bound === null) {
lines.push(` ${green('✓')} the blocked order is salt-committed to the signed input hash ${dim('(openable to a regulator)')}`);
} else {
lines.push(` ${rb.proposed_bound ? green('✓') : red('✗')} the disclosed order re-hashes (under its salt) to the signed input hash`);
}
}
const icon = result.valid ? green('✓') : red('✗');
const status = result.valid ? green('VALID') : red('INVALID');
lines.push(`\n${icon} Signature: ${status}`);
lines.push(` Format: ScopeBlind Trusted Context Pack`);
if (result.schema) {
lines.push(` Schema: ${result.schema} ${result.schemaRecognized ? dim('(recognized)') : yellow('(unrecognized)')}`);
}
const pf = result.payloadFields || {};
if (pf.source_type) lines.push(` Source: ${pf.source_type}${pf.source_format ? dim(` (${pf.source_format})`) : ''}`);
if (pf.file_name) lines.push(` File: ${pf.file_name}`);
if (pf.file_hash) lines.push(` File hash: ${dim(`sha256:${String(pf.file_hash).slice(0, 16)}…`)}`);
// The gate decision is the headline: usable feeds a decision, the others do not.
const gate = result.gateStatus || pf.gate_status;
if (gate) {
const tone = gate === 'usable' ? green(gate) : gate === 'needs_approval' ? yellow(gate) : red(gate);
const note = gate === 'usable' ? 'may feed a gate decision'
: gate === 'needs_approval' ? 'held: requires explicit human approval before use'
: 'blocked: cannot feed a decision';
lines.push(` Gate: ${tone} ${dim(`(${note})`)}`);
}
if (result.confidence !== undefined) lines.push(` Confidence: ${result.confidence}`);
if (pf.freshness) {
const dated = pf.freshness.as_of ? `as of ${String(pf.freshness.as_of).slice(0, 10)}` : yellow('no as-of date');
const fresh = pf.freshness.stale ? red('(stale)') : dim('(fresh)');
lines.push(` Freshness: ${dated} ${fresh}`);
}
if (Array.isArray(pf.warnings) && pf.warnings.length) {
lines.push(` ${bold('Warnings:')}`);
for (const w of pf.warnings) lines.push(` ${yellow('!')} ${dim(w)}`);
}
if (result.algorithm) lines.push(` Algorithm: ${result.algorithm} ${dim('(over the SHA-256 payload digest)')}`);
if (result.digest) lines.push(` Digest: ${dim(result.digest)}`);
if (result.recomputedDigest) lines.push(` Recomputed: ${red(result.recomputedDigest)}`);
if (result.publicKey) lines.push(` Signer: ${result.signerLabel ? bold(result.signerLabel) + ' ' : ''}${dim(result.publicKey)}`);
if (result.keySource) lines.push(` Key: ${result.keySource}`);
if (result.error && !result.valid) {
lines.push(` Error: ${red(result.error)}`);
if (result.error === 'invalid_signature') lines.push(` Detail: ${yellow('the signed bytes were altered or the key does not match; this pack was tampered with')}`);
if (result.error === 'invalid_signature') lines.push(` Detail: ${yellow('the signed bytes were altered or the key does not match — this receipt was tampered with')}`);
else if (result.detail) lines.push(` Detail: ${yellow(result.detail)}`);

@@ -552,70 +439,2 @@ if (result.expectedKey) lines.push(` Expected: ${yellow(result.expectedKey)} ${dim('(--key)')}`);

/**
* Format a ScopeBlind macro-engine track-record bundle result. Like the Gate
* bundle formatter, crypto failures and chain (single-signer / manifest /
* history) failures are reported separately.
*
* @param {Object} result from src/engines/macro-snapshot.js
* @param {Object} opts cli options
* @returns {string}
*/
export function formatMacroTrackRecordResult(result, opts = {}) {
const lines = [];
const icon = result.valid ? green('✓') : red('✗');
const status = result.valid ? green('VALID') : red('INVALID');
lines.push(`\n${icon} Macro track-record bundle: ${status}`);
lines.push(` Schema: ${result.schema || '(missing)'}`);
if (result.exportedAt) lines.push(` Exported: ${dim(result.exportedAt)}`);
if (result.period) lines.push(` Period: ${dim(`${result.period.from} → ${result.period.to}`)}`);
if (result.custody) lines.push(` Custody: ${dim(result.custody)}`);
lines.push(` Identity: ${result.signerPinned ? green('pinned expected key') : yellow('embedded key only — integrity, not operator identity')}`);
if (result.sequence) lines.push(` Sequence: ${result.sequence}`);
lines.push(` Snapshots: ${result.snapshotCount}`);
lines.push(` Journal: ${result.journalCount}`);
lines.push(` Records: ${result.total} (${green(String(result.passed))} passed, ${result.failed > 0 ? red(String(result.failed)) : '0'} failed)`);
const cryptoOk = result.total - result.cryptoFailed;
lines.push(` Signatures: ${result.cryptoFailed > 0 ? red(`${cryptoOk}/${result.total} valid`) : green(`${cryptoOk}/${result.total} valid`)}`);
const chainOk = result.chainChecks - result.chainFailed;
lines.push(` Chain links: ${result.chainFailed > 0 ? red(`${chainOk}/${result.chainChecks} consistent`) : green(`${chainOk}/${result.chainChecks} consistent`)}`);
if (result.manifestValid !== null) lines.push(` Signed manifest: ${result.manifestValid ? green('valid and exact') : red('missing or inconsistent')}`);
lines.push(` Single-key consistency: ${result.singleSigner ? green('yes') : red('no')}`);
lines.push(` Append-only history: ${result.historyChainValid === true ? green('linked and retained') : result.historyChainValid === false ? red('invalid') : yellow('not established by this export')}`);
lines.push(` Signed checkpoint: ${result.historyAnchored ? green('present') : yellow('absent')}`);
if (result.transparencyAnchor) {
const t = result.transparencyAnchor;
const leaves = t.tree_size !== null ? `${t.tree_size} leaves` : 'Merkle log';
if (t.anchor === 'witnessed') lines.push(` Transparency: ${green(`witness-anchored (Merkle log, ${leaves})`)}`);
else if (t.anchor === 'self_signed') lines.push(` Transparency: ${yellow(`self-signed (Merkle log, ${leaves})`)}`);
else lines.push(` Transparency: ${red('not anchored')}`);
}
if (result.historyHeadPinned) lines.push(` History head: ${green('matches independently pinned head')}`);
if (result.anchorHeadPinned) lines.push(` Anchor head: ${green('matches independently pinned head')}`);
if (Array.isArray(result.signers) && result.signers.length > 0) {
lines.push(` ${bold('Signing keys seen:')}`);
for (const s of result.signers) {
const tag = s.isModelKey ? green('model key') : yellow('other key');
lines.push(` ${dim(s.key)} ${tag} ${dim(`(${s.roles.join(', ')})`)}`);
}
}
if (Array.isArray(result.errors) && result.errors.length > 0) {
lines.push(`\n ${red('Failures:')} ${dim('([crypto] record forged or modified; [chain] custody, manifest, or history-head inconsistent)')}`);
for (const e of result.errors) lines.push(` ${red('•')} ${e}`);
}
if (result.valid) {
lines.push('');
lines.push(` ${bold('This proves:')}`);
for (const p of (result.proves || [])) lines.push(` ${green('•')} ${dim(p)}`);
lines.push(` ${bold('This does not prove:')}`);
for (const l of (result.limitations || [])) lines.push(` ${yellow('!')} ${dim(l)}`);
}
lines.push('');
lines.push(WAYFINDING);
lines.push('');
return lines.join('\n');
}
export function formatKuResult(result, opts = {}) {

@@ -622,0 +441,0 @@ const lines = [];

{
"_comment": "Map an Ed25519 verification_key (lowercase hex) to a human label so the CLI prints 'Signer: <label>' instead of raw hex. Add your desk/issuer keys here, or pass your own file with --known-issuers <path>. This is a display aid layered on --key pinning, never a trust shortcut: an unlabeled key still verifies, and a label is only as good as the map you chose to load.",
"_example": "0000000000000000000000000000000000000000000000000000000000000000 -> Example Desk (remove this)"
}
{
"type": "scopeblind.legate.proof-pack.v1",
"generated_at": "2026-06-22T23:31:19.884Z",
"period": null,
"position_blind": true,
"runtime": {
"name": "Toms-MacBook-Pro.local",
"verification_key": "ecfc8fe8e791d84204e4889c2ccae46da41d90c8bb88f028bee1f96790c3ae2a"
},
"mandate": {
"name": "Global Macro IMA",
"sha256": "5ac8a3803737c74cbb5221ed0983ac8c1cc28954b42ed75e372ef275fd918df2",
"mode": "enforce",
"rule_count": 9,
"coverage": {
"local": [
"gross-exposure",
"net-exposure",
"soft-gross-band",
"class-gross-rates",
"class-gross-fx",
"class-gross-equity",
"class-gross-credit",
"class-gross-commodity",
"dv01-book"
],
"order_context": [],
"delegated": []
}
},
"policy": {
"name": "Legate default agent mandate",
"sha256": "650d036c3b05675f3719168a41bf0266482728b5f0156c646b2649cd804c040d",
"version": "1",
"rule_count": 5
},
"book": null,
"governed_actions": {
"evaluated": 0,
"allowed": 0,
"held": 0,
"blocked": 0,
"would_block": 0
},
"restraint": {
"blocked": 0,
"held": 0,
"by_rule": []
},
"shadow": {
"observed": 2,
"would_block": 0,
"would_hold": 2,
"by_rule": [
{
"rule": "gross-exposure",
"count": 2
},
{
"rule": "net-exposure",
"count": 2
},
{
"rule": "class-gross-rates",
"count": 2
},
{
"rule": "class-gross-fx",
"count": 2
},
{
"rule": "class-gross-equity",
"count": 2
},
{
"rule": "class-gross-credit",
"count": 2
},
{
"rule": "class-gross-commodity",
"count": 2
}
],
"first_at": "2026-06-22T23:31:19.814Z",
"last_at": "2026-06-22T23:31:19.849Z"
},
"session_merkle_root": "66308d59fa859823fe9ff774f4f4e91cb025f391327858c0e4192ab84504346d",
"receipt_count": 1,
"signer_kid": "sb:legate:ecfc8fe8",
"verification_key": "ecfc8fe8e791d84204e4889c2ccae46da41d90c8bb88f028bee1f96790c3ae2a",
"sha256": "b6c421a1d86cbfe34f9748b3976f2a8a3d3cd64cb6467f07c85e58f43ab7c360",
"signature": "31f1b2090f74157a55445411c1555141f656a88f089a459488e88e155f37d5a633fa62786d4974699e19536221328882651e6d8f471cc1226450f5d203e8eb0b"
}
{
"payload": {
"schema": "scopeblind.macro.alert/1",
"engine_version": "macro-engine/0.1.0",
"as_of": "2025-08-23",
"alert_id": "915720cc951de3dfb99437ebac0362f02947160eca28841e6803c37979019cbb",
"kind": "market_state_change",
"severity": "critical",
"title": "Market state: mixed -> stress",
"detail": "Daily market-state classification changed (confidence 0.8).",
"refs": [
{
"schema": "scopeblind.macro.market-state/1",
"as_of": "2025-08-23",
"digest": "d9602f7915b69bcbf7f86c0cf1b0387965e1b448918be92339ed96d138449d80"
},
{
"schema": "scopeblind.macro.market-state/1",
"as_of": "2025-02-05",
"digest": "d47770c9fdcbe921596497fc1f63d18f86d8bbef302abc060d4d0e1cb7dc9e53"
}
],
"budget": {
"position": 1,
"max_per_day": 2
}
},
"digest": "bb942d2f4fe547ffba9e7eec6518d32d5d61019c6c85da6aad4dfa051b3df460",
"signature": "a3ddc18d8087ae63a4b4d967d3d12a28db2476ef143f0ed21d2d1b4ecae7187eb8310a2e87ee5534c2250a533deeadb450c6e1003bcf1c43b731f96929738800",
"verification_key": "e324c4149db27151f65df25d528d3037d3b3bc4165b0d28c0769369cba958ae3"
}
{
"payload": {
"schema": "scopeblind.macro.journal-entry/1",
"engine_version": "macro-engine/0.1.0",
"as_of": "2025-08-23",
"author": "demo-model",
"note": "Regime read stagflation while the daily tape printed stress. Cut gross and lengthened nothing; the book is long the wrong factors here.",
"references": [
{
"schema": "scopeblind.macro.market-state/1",
"as_of": "2025-08-23",
"digest": "f469ddc93ce803456bf6eed265c1ffa94690bb3ed972e9dff95c7dab52972e94"
},
{
"schema": "scopeblind.macro.vulnerability/1",
"as_of": "2025-08-23",
"digest": "d277793511a0dcda199889d8beedbe849146cf0fc4cb216ce1dc77cadf20b237"
},
{
"schema": "scopeblind.macro.regime-snapshot/1",
"as_of": "2026-05-01",
"digest": "27a4b9dd293ae77487e919adbf428e4911da62907c39dd017c50376ad9e77591"
}
],
"tags": [
"risk-off",
"stagflation",
"vulnerability"
]
},
"digest": "95415964066eaf10e5de3e49dd18763c8c7d79099baa0bbe670b402f52243923",
"signature": "adce443ba5de6d2e2edea9b5cc19744ae0a7842ad552860c03e895e5393434f4f0448bb5eb5d81f2aae7cbf222494931bfcab30ad465931f073ca2350e042b0c",
"verification_key": "e324c4149db27151f65df25d528d3037d3b3bc4165b0d28c0769369cba958ae3"
}
{
"payload": {
"schema": "scopeblind.macro.market-state/1",
"engine_version": "macro-engine/0.1.0",
"as_of": "2025-08-23",
"universe_digest": "e71b066c5c05624984187e810d8dc3422964825d7cefa5338f738d57a1e1dd76",
"inputs_digest": "51b8add91569d3da3b761f5c0a1fefba25fabbe486214fe36a6204347cc904e3",
"pillars": {
"trend": -2,
"breadth": 0,
"liquidity": -2,
"credit": -2,
"volatility": -2
},
"evidence": {
"trend": {
"inputs": [
{
"symbol": "SPY",
"feature": "ma_structure",
"value": -2,
"vote": -2
}
],
"missing": [
"QQQ",
"ACWI"
]
},
"breadth": {
"inputs": [
{
"symbol": "RSP/SPY",
"feature": "ret20d_z",
"value": 0,
"vote": 0
},
{
"symbol": "IWM/SPY",
"feature": "ret20d_z",
"value": 0,
"vote": 0
}
],
"missing": []
},
"liquidity": {
"inputs": [
{
"symbol": "UUP",
"feature": "ret20d_z_inv",
"value": -6.554929,
"vote": -2
},
{
"symbol": "BTCUSD",
"feature": "ret20d_z",
"value": -6.478535,
"vote": -2
}
],
"missing": [
"EEM/EFA",
"SMH/SPY"
]
},
"credit": {
"inputs": [
{
"symbol": "HYG/IEF",
"feature": "ret20d_z",
"value": -6.352958,
"vote": -2
}
],
"missing": [
"LQD/IEF",
"XLF/SPY"
]
},
"volatility": {
"inputs": [
{
"symbol": "SPY",
"feature": "rvol20_pctile_1y",
"value": 0.932806,
"vote": -2
}
],
"missing": [
"VIX"
]
}
},
"classification": "stress",
"confidence": 0.8,
"would_change": [
"robust: no single-pillar one-notch change alters this classification"
],
"notes": [
"HYG: HYG/IEF ratio proxies HY OAS direction intraday; true OAS (daily, lagged) comes from FRED BAMLH0A0HYM2 in the regime layer.",
"RSP: Equal-weight ratio proxies constituent breadth; true %>200dma needs constituent data (licensing-gated).",
"UUP: DXY proxy; futures DX licensing-gated at this tier.",
"degraded: missing inputs ACWI, EEM/EFA, LQD/IEF, QQQ, SMH/SPY, VIX, XLF/SPY"
]
},
"digest": "f469ddc93ce803456bf6eed265c1ffa94690bb3ed972e9dff95c7dab52972e94",
"signature": "0f93202e78e81ea84ba36e2c2e787ef493aba32c61140a948553f314a3403f042220ac64cf04e8d22e9044b2e6e9712587b1e023cb0dd796353543609aec380a",
"verification_key": "e324c4149db27151f65df25d528d3037d3b3bc4165b0d28c0769369cba958ae3"
}
{
"payload": {
"schema": "scopeblind.macro.price-snapshot/1",
"engine_version": "macro-engine/0.1.0",
"as_of": "2026-06-12T20:00:00Z",
"source": "Massive Market Data daily settle (delayed feed; not a live tick)",
"delay_minutes": 15,
"levels": {
"rates": {
"level": 85.77,
"instrument": "TLT",
"unit": "price",
"note": "long-duration UST proxy; loads via DV01, not notional"
},
"equity": {
"level": 741.75,
"instrument": "SPY",
"unit": "price",
"multiplier": 500,
"note": "ES notional = level x 500 (x10 index ratio, $50 point value)"
},
"fx_eur": {
"level": 1.15655,
"instrument": "EURUSD",
"unit": "fx_rate"
},
"fx_jpy": {
"level": 160.215,
"instrument": "USDJPY",
"unit": "fx_rate"
},
"credit_ig": {
"level": 109.01,
"instrument": "LQD",
"unit": "price",
"note": "IG proxy; loads via CS01, not notional"
},
"credit_hy": {
"level": 79.94,
"instrument": "HYG",
"unit": "price",
"note": "HY proxy; loads via CS01, not notional"
},
"commodity_oil": {
"level": 125.43,
"instrument": "USO",
"unit": "price",
"note": "crude proxy ETF (roll-affected); provenance only"
},
"commodity_gold": {
"level": 386.54,
"instrument": "GLD",
"unit": "price",
"note": "gold proxy ETF; provenance only"
}
},
"coverage": [
"commodity_gold",
"commodity_oil",
"credit_hy",
"credit_ig",
"equity",
"fx_eur",
"fx_jpy",
"rates"
],
"missing": [],
"notes": [
"levels are official daily closes (settle) for the 2026-06-12 session, from a delayed feed",
"instruments are liquid ETF/FX proxies, not the futures themselves; the snapshot never overstates what it observed",
"only the equity (ES) factor carries a notional multiplier; the rest are signed provenance and load via DV01/CS01"
]
},
"digest": "32a46e47fd2639b9991dfd8133c600c8ed7e9a86b56f3ec5372870c35624c165",
"signature": "676678d1d4ce516869d80f185bf3fd207d33c02109e4deb4e6fc5a8a2a557ed3ac6c12b3f8f12d55c03b7670a20e457dd86ccfbd5fe994015d0ed2e8f782a50b",
"verification_key": "e324c4149db27151f65df25d528d3037d3b3bc4165b0d28c0769369cba958ae3"
}
{
"payload": {
"schema": "scopeblind.macro.regime-snapshot/1",
"engine_version": "macro-engine/0.1.0",
"as_of": "2026-05-01",
"pillars": {
"growth": -2,
"inflation": 2,
"liquidity": -2,
"policy_freedom": -2,
"credit_conditions": -2
},
"inputs": [
{
"series_id": "ICSA",
"transform": "diff13w",
"value": 35123.671753,
"z": -6.764746,
"vote": -2,
"asof_digest": "73fa36d5ba21ff19e82757760ffc56899c4d33ca617cbdf79523e2eb1550f573",
"latest_vintage": "2026-04-29"
},
{
"series_id": "PAYEMS",
"transform": "mom3_ann",
"value": -0.036344,
"z": -3.501479,
"vote": -2,
"asof_digest": "64ca109e3b7d52348a813e5c7fa3695ce0801b30a9ac8cc2aa7cc248e6292abf",
"latest_vintage": "2026-04-08"
},
{
"series_id": "INDPRO",
"transform": "mom6_ann",
"value": -0.036233,
"z": -4.775509,
"vote": -2,
"asof_digest": "880c1c9898d45bca6a5d9803d3a687e7702ada5b4dee082d68e685fb8540be82",
"latest_vintage": "2026-04-17"
},
{
"series_id": "RSXFS",
"transform": "mom3_ann",
"value": -0.036344,
"z": -3.485408,
"vote": -2,
"asof_digest": "87bb798c4e9efdfb41f31a11cc3f49f96fe9db48d753cd5aaa0643f3b4a59e1d",
"latest_vintage": "2026-04-17"
},
{
"series_id": "USALOLITONOSTSAM",
"transform": "diff6m",
"value": -1.152544,
"z": -5.744365,
"vote": -2,
"asof_digest": "4e7ae6048b479286b801201eebf6db1d28ada976b1841d8b41cb5d95c99d9929",
"latest_vintage": "2026-04-10"
},
{
"series_id": "CPILFESL",
"transform": "mom3_ann",
"value": 0.069551,
"z": 3.342129,
"vote": 2,
"asof_digest": "b0a91055ce6a6a879010796266ef9236bb911a888a54ce6af7b24e6010183ca3",
"latest_vintage": "2026-04-14"
},
{
"series_id": "PCEPILFE",
"transform": "mom3_ann",
"value": 0.067001,
"z": 3.342148,
"vote": 2,
"asof_digest": "b53a27bb365e01fa1e2ac25f446930ff6f852c4ed2a6fd2eefff38cc96c9da57",
"latest_vintage": "2026-04-29"
},
{
"series_id": "T10YIE",
"transform": "diff3m",
"value": 0.153311,
"z": 5.226471,
"vote": 2,
"asof_digest": "b839addb59d3c4a84a0a4b27e6ad47636b83a3729b1cc7144bea8dd58db2ff73",
"latest_vintage": "2026-05-01"
},
{
"series_id": "DCOILWTICO",
"transform": "mom3_ann",
"value": 0.653636,
"z": 5.382054,
"vote": 2,
"asof_digest": "97178dd3c33fa82c7479b66c6132a7d8d96e47ccc39ffc4ba93d64cc38ab65b8",
"latest_vintage": "2026-05-01"
},
{
"series_id": "AHETPI",
"transform": "mom3_ann",
"value": 0.067001,
"z": 3.3094,
"vote": 2,
"asof_digest": "783bab21a0e6c7c761d4c62ceab7c582cefa6d050b2e03898a4a62f80971ef90",
"latest_vintage": "2026-04-08"
},
{
"series_id": "WALCL",
"transform": "diff13w",
"value": -355139.244176,
"z": -6.539508,
"vote": -2,
"asof_digest": "af2dd3799a152fdb8171b203aec25bd0b0e276e87df7be9bdc8a989f48a51346",
"latest_vintage": "2026-04-25"
},
{
"series_id": "WTREGEN",
"transform": "diff13w",
"value": 98346.28091,
"z": -6.764746,
"vote": -2,
"asof_digest": "0e493e335271dcbeeae69f95d4683b35988eba5248e525fed6151b840f127989",
"latest_vintage": "2026-04-25"
},
{
"series_id": "RRPONTSYD",
"transform": "diff13w",
"value": 158.625566,
"z": -5.60151,
"vote": -2,
"asof_digest": "62bd49d946bd279358ff87d32d370fa6d0a68c37682b1ba7ad99e3bfd1687daa",
"latest_vintage": "2026-05-01"
},
{
"series_id": "M2SL",
"transform": "mom6_ann",
"value": -0.036233,
"z": -4.775509,
"vote": -2,
"asof_digest": "8b96e538db1b6659919cb95408ff3d5ee407783a03e7f26e0920aa50123e9a19",
"latest_vintage": "2026-04-27"
},
{
"series_id": "DTWEXBGS",
"transform": "diff3m",
"value": 7.998853,
"z": -5.226471,
"vote": -2,
"asof_digest": "05d20fa0c9d7d5f2dff3d84ec7ff62579e7eaea87ff66bb50a2a8e869165de5d",
"latest_vintage": "2026-05-01"
},
{
"series_id": "DFEDTARU",
"transform": "level",
"value": 0.999608,
"z": null,
"vote": null,
"asof_digest": "3922373305be0976cddffb6778d61343e9289d3f6d3fe8039a2ca95a765c735f",
"latest_vintage": "2026-05-01"
},
{
"series_id": "DFII10",
"transform": "diff3m",
"value": 0.119983,
"z": -5.226471,
"vote": -2,
"asof_digest": "474a4dd5f297eb398235b01334b7fc283979b30c96c1b1ac57351eedc6064cdf",
"latest_vintage": "2026-05-01"
},
{
"series_id": "T5YIFR",
"transform": "level",
"value": 3.201024,
"z": null,
"vote": -2,
"asof_digest": "b8e076fbcd90990be22e3f6fc53461a74d5f0a4553cb0152b70c4fea50f4530f",
"latest_vintage": "2026-05-01"
},
{
"series_id": "BAMLH0A0HYM2",
"transform": "diff13w",
"value": 1.110379,
"z": -5.60151,
"vote": -2,
"asof_digest": "8ec3d58658b36d414849b002fef15350817a81ddcb81e9e203a9ada8bd8d1c3f",
"latest_vintage": "2026-05-01"
},
{
"series_id": "BAMLC0A0CM",
"transform": "diff13w",
"value": 0.073323,
"z": -5.226471,
"vote": -2,
"asof_digest": "370a4e107534d46a1a542d1e16ce9f9f4a17aeeb377f9e5c4481f1e0f3a2facb",
"latest_vintage": "2026-05-01"
},
{
"series_id": "NFCI",
"transform": "level",
"value": 0.550016,
"z": null,
"vote": -2,
"asof_digest": "f0f61455659b69270627f8c5cf767fc2f5dc72985c36d682edad857629df4d9d",
"latest_vintage": "2026-04-29"
},
{
"series_id": "NET_LIQUIDITY",
"transform": "diff13w",
"value": -650.297517,
"z": -6.328823,
"vote": -2,
"asof_digest": "1e43b543c63afcf7659de4c5ddaf99ba96dc4d1c7f55052aa392b0aadd1207a9",
"latest_vintage": "2026-04-25"
},
{
"series_id": "REAL_POLICY_RATE",
"transform": "level",
"value": -3.905295,
"z": null,
"vote": -2,
"asof_digest": "9427fbf69d076b6f3a9536742e8d4f2ac15c4e4085075a8b60273d34970b0f4d",
"latest_vintage": "2026-05-01"
}
],
"vintage_digest": "77304f7e1203df3211824c78c7c9e800a0dd52b744f5173324524174ad96d3bc",
"candidate_regime": "stagflation",
"regime": "stagflation",
"liquidity_overlay": "contraction",
"hysteresis": {
"current": "stagflation",
"candidate": null,
"candidate_weeks": 0,
"weeks_since_switch": 999
},
"transition": null,
"playbook": {
"prefer": [
"energy",
"gold",
"dollar",
"defensives",
"cash"
],
"avoid": [
"unhedged cyclicals",
"levered credit"
],
"confidence": "medium"
},
"confidence": 0.956522,
"would_change": [
"robust: no single-pillar one-notch change alters this candidate regime"
],
"notes": [
"degraded: no usable vote from DFEDTARU",
"Net liquidity (WALCL - TGA - RRP) validity is regime-dependent: strongest when reserve scarcity binds.",
"PMI family is licensing-gated: growth diffusion uses claims, payrolls, production, retail, and OECD CLI."
]
},
"digest": "27a4b9dd293ae77487e919adbf428e4911da62907c39dd017c50376ad9e77591",
"signature": "806c531043618f2c4da47180ace2020def35fbf12bbf603061e4fb3264b97940c2bcfd50e395d16c8f2e45bdbe2ff69a84c00ddbe330fcaa29bc95296da66207",
"verification_key": "e324c4149db27151f65df25d528d3037d3b3bc4165b0d28c0769369cba958ae3"
}
{
"payload": {
"schema": "scopeblind.macro.tape-snapshot/1",
"engine_version": "macro-engine/0.1.0",
"as_of": "2025-08-23",
"session": "daily_close",
"tape_type": "mixed",
"coherence": 0,
"material": true,
"signals": [
{
"id": "breadth_rel",
"z": 0
},
{
"id": "credit",
"z": -2.631816
},
{
"id": "dollar",
"z": 3.61392
},
{
"id": "duration",
"z": 3.20995
},
{
"id": "equity",
"z": -3.860863
},
{
"id": "high_beta",
"z": -4.467346
},
{
"id": "smallcap_rel",
"z": 0
}
],
"unavailable": [
"banks_rel",
"copper",
"gold",
"growth_beta",
"oil"
],
"untestable_types": [
"inflation_shock"
],
"attribution": {
"tier": "unknown",
"detail": "material moves without a coherent cross-asset pattern or scheduled catalyst",
"events": []
},
"inputs_digest": "c202156a133cdee47311f843fbc18082311ca653dd4293496ea1c47346fa68c7",
"would_change": [
"a coherent cross-asset pattern forming would move this off mixed"
],
"notes": [
"degraded: unavailable signals banks_rel, copper, gold, growth_beta, oil",
"untestable tape types with current data: inflation_shock",
"session basis: daily close-to-close; intraday windows plug into the same rules when a live feed is configured"
]
},
"digest": "43e98d770cb3b4e47c915164d7fe0aa7ec257968978a5cd1aa914e9e2403decd",
"signature": "f7cf06b796186a7a6b76053f30b5dd3b96affb6b3853df78550719576d0059bc4a36d34c74afd3d122770e34cbdda03e3f0adcd794c314396a411d3ee5f2590f",
"verification_key": "e324c4149db27151f65df25d528d3037d3b3bc4165b0d28c0769369cba958ae3"
}
{
"schema": "scopeblind.macro.track-record-bundle/1",
"version": "0.1.0",
"exported_at": "2026-05-01T00:00:00Z",
"model_verification_key": "e324c4149db27151f65df25d528d3037d3b3bc4165b0d28c0769369cba958ae3",
"custody": "dev-deterministic",
"period": {
"from": "2025-01-02",
"to": "2026-05-01"
},
"snapshots": [
{
"payload": {
"schema": "scopeblind.macro.market-state/1",
"engine_version": "macro-engine/0.1.0",
"as_of": "2025-08-23",
"universe_digest": "e71b066c5c05624984187e810d8dc3422964825d7cefa5338f738d57a1e1dd76",
"inputs_digest": "51b8add91569d3da3b761f5c0a1fefba25fabbe486214fe36a6204347cc904e3",
"pillars": {
"trend": -2,
"breadth": 0,
"liquidity": -2,
"credit": -2,
"volatility": -2
},
"evidence": {
"trend": {
"inputs": [
{
"symbol": "SPY",
"feature": "ma_structure",
"value": -2,
"vote": -2
}
],
"missing": [
"QQQ",
"ACWI"
]
},
"breadth": {
"inputs": [
{
"symbol": "RSP/SPY",
"feature": "ret20d_z",
"value": 0,
"vote": 0
},
{
"symbol": "IWM/SPY",
"feature": "ret20d_z",
"value": 0,
"vote": 0
}
],
"missing": []
},
"liquidity": {
"inputs": [
{
"symbol": "UUP",
"feature": "ret20d_z_inv",
"value": -6.554929,
"vote": -2
},
{
"symbol": "BTCUSD",
"feature": "ret20d_z",
"value": -6.478535,
"vote": -2
}
],
"missing": [
"EEM/EFA",
"SMH/SPY"
]
},
"credit": {
"inputs": [
{
"symbol": "HYG/IEF",
"feature": "ret20d_z",
"value": -6.352958,
"vote": -2
}
],
"missing": [
"LQD/IEF",
"XLF/SPY"
]
},
"volatility": {
"inputs": [
{
"symbol": "SPY",
"feature": "rvol20_pctile_1y",
"value": 0.932806,
"vote": -2
}
],
"missing": [
"VIX"
]
}
},
"classification": "stress",
"confidence": 0.8,
"would_change": [
"robust: no single-pillar one-notch change alters this classification"
],
"notes": [
"HYG: HYG/IEF ratio proxies HY OAS direction intraday; true OAS (daily, lagged) comes from FRED BAMLH0A0HYM2 in the regime layer.",
"RSP: Equal-weight ratio proxies constituent breadth; true %>200dma needs constituent data (licensing-gated).",
"UUP: DXY proxy; futures DX licensing-gated at this tier.",
"degraded: missing inputs ACWI, EEM/EFA, LQD/IEF, QQQ, SMH/SPY, VIX, XLF/SPY"
]
},
"digest": "f469ddc93ce803456bf6eed265c1ffa94690bb3ed972e9dff95c7dab52972e94",
"signature": "0f93202e78e81ea84ba36e2c2e787ef493aba32c61140a948553f314a3403f042220ac64cf04e8d22e9044b2e6e9712587b1e023cb0dd796353543609aec380a",
"verification_key": "e324c4149db27151f65df25d528d3037d3b3bc4165b0d28c0769369cba958ae3"
},
{
"payload": {
"schema": "scopeblind.macro.tape-snapshot/1",
"engine_version": "macro-engine/0.1.0",
"as_of": "2025-08-23",
"session": "daily_close",
"tape_type": "mixed",
"coherence": 0,
"material": true,
"signals": [
{
"id": "breadth_rel",
"z": 0
},
{
"id": "credit",
"z": -2.631816
},
{
"id": "dollar",
"z": 3.61392
},
{
"id": "duration",
"z": 3.20995
},
{
"id": "equity",
"z": -3.860863
},
{
"id": "high_beta",
"z": -4.467346
},
{
"id": "smallcap_rel",
"z": 0
}
],
"unavailable": [
"banks_rel",
"copper",
"gold",
"growth_beta",
"oil"
],
"untestable_types": [
"inflation_shock"
],
"attribution": {
"tier": "unknown",
"detail": "material moves without a coherent cross-asset pattern or scheduled catalyst",
"events": []
},
"inputs_digest": "c202156a133cdee47311f843fbc18082311ca653dd4293496ea1c47346fa68c7",
"would_change": [
"a coherent cross-asset pattern forming would move this off mixed"
],
"notes": [
"degraded: unavailable signals banks_rel, copper, gold, growth_beta, oil",
"untestable tape types with current data: inflation_shock",
"session basis: daily close-to-close; intraday windows plug into the same rules when a live feed is configured"
]
},
"digest": "43e98d770cb3b4e47c915164d7fe0aa7ec257968978a5cd1aa914e9e2403decd",
"signature": "f7cf06b796186a7a6b76053f30b5dd3b96affb6b3853df78550719576d0059bc4a36d34c74afd3d122770e34cbdda03e3f0adcd794c314396a411d3ee5f2590f",
"verification_key": "e324c4149db27151f65df25d528d3037d3b3bc4165b0d28c0769369cba958ae3"
},
{
"payload": {
"schema": "scopeblind.macro.regime-snapshot/1",
"engine_version": "macro-engine/0.1.0",
"as_of": "2026-05-01",
"pillars": {
"growth": -2,
"inflation": 2,
"liquidity": -2,
"policy_freedom": -2,
"credit_conditions": -2
},
"inputs": [
{
"series_id": "ICSA",
"transform": "diff13w",
"value": 35123.671753,
"z": -6.764746,
"vote": -2,
"asof_digest": "73fa36d5ba21ff19e82757760ffc56899c4d33ca617cbdf79523e2eb1550f573",
"latest_vintage": "2026-04-29"
},
{
"series_id": "PAYEMS",
"transform": "mom3_ann",
"value": -0.036344,
"z": -3.501479,
"vote": -2,
"asof_digest": "64ca109e3b7d52348a813e5c7fa3695ce0801b30a9ac8cc2aa7cc248e6292abf",
"latest_vintage": "2026-04-08"
},
{
"series_id": "INDPRO",
"transform": "mom6_ann",
"value": -0.036233,
"z": -4.775509,
"vote": -2,
"asof_digest": "880c1c9898d45bca6a5d9803d3a687e7702ada5b4dee082d68e685fb8540be82",
"latest_vintage": "2026-04-17"
},
{
"series_id": "RSXFS",
"transform": "mom3_ann",
"value": -0.036344,
"z": -3.485408,
"vote": -2,
"asof_digest": "87bb798c4e9efdfb41f31a11cc3f49f96fe9db48d753cd5aaa0643f3b4a59e1d",
"latest_vintage": "2026-04-17"
},
{
"series_id": "USALOLITONOSTSAM",
"transform": "diff6m",
"value": -1.152544,
"z": -5.744365,
"vote": -2,
"asof_digest": "4e7ae6048b479286b801201eebf6db1d28ada976b1841d8b41cb5d95c99d9929",
"latest_vintage": "2026-04-10"
},
{
"series_id": "CPILFESL",
"transform": "mom3_ann",
"value": 0.069551,
"z": 3.342129,
"vote": 2,
"asof_digest": "b0a91055ce6a6a879010796266ef9236bb911a888a54ce6af7b24e6010183ca3",
"latest_vintage": "2026-04-14"
},
{
"series_id": "PCEPILFE",
"transform": "mom3_ann",
"value": 0.067001,
"z": 3.342148,
"vote": 2,
"asof_digest": "b53a27bb365e01fa1e2ac25f446930ff6f852c4ed2a6fd2eefff38cc96c9da57",
"latest_vintage": "2026-04-29"
},
{
"series_id": "T10YIE",
"transform": "diff3m",
"value": 0.153311,
"z": 5.226471,
"vote": 2,
"asof_digest": "b839addb59d3c4a84a0a4b27e6ad47636b83a3729b1cc7144bea8dd58db2ff73",
"latest_vintage": "2026-05-01"
},
{
"series_id": "DCOILWTICO",
"transform": "mom3_ann",
"value": 0.653636,
"z": 5.382054,
"vote": 2,
"asof_digest": "97178dd3c33fa82c7479b66c6132a7d8d96e47ccc39ffc4ba93d64cc38ab65b8",
"latest_vintage": "2026-05-01"
},
{
"series_id": "AHETPI",
"transform": "mom3_ann",
"value": 0.067001,
"z": 3.3094,
"vote": 2,
"asof_digest": "783bab21a0e6c7c761d4c62ceab7c582cefa6d050b2e03898a4a62f80971ef90",
"latest_vintage": "2026-04-08"
},
{
"series_id": "WALCL",
"transform": "diff13w",
"value": -355139.244176,
"z": -6.539508,
"vote": -2,
"asof_digest": "af2dd3799a152fdb8171b203aec25bd0b0e276e87df7be9bdc8a989f48a51346",
"latest_vintage": "2026-04-25"
},
{
"series_id": "WTREGEN",
"transform": "diff13w",
"value": 98346.28091,
"z": -6.764746,
"vote": -2,
"asof_digest": "0e493e335271dcbeeae69f95d4683b35988eba5248e525fed6151b840f127989",
"latest_vintage": "2026-04-25"
},
{
"series_id": "RRPONTSYD",
"transform": "diff13w",
"value": 158.625566,
"z": -5.60151,
"vote": -2,
"asof_digest": "62bd49d946bd279358ff87d32d370fa6d0a68c37682b1ba7ad99e3bfd1687daa",
"latest_vintage": "2026-05-01"
},
{
"series_id": "M2SL",
"transform": "mom6_ann",
"value": -0.036233,
"z": -4.775509,
"vote": -2,
"asof_digest": "8b96e538db1b6659919cb95408ff3d5ee407783a03e7f26e0920aa50123e9a19",
"latest_vintage": "2026-04-27"
},
{
"series_id": "DTWEXBGS",
"transform": "diff3m",
"value": 7.998853,
"z": -5.226471,
"vote": -2,
"asof_digest": "05d20fa0c9d7d5f2dff3d84ec7ff62579e7eaea87ff66bb50a2a8e869165de5d",
"latest_vintage": "2026-05-01"
},
{
"series_id": "DFEDTARU",
"transform": "level",
"value": 0.999608,
"z": null,
"vote": null,
"asof_digest": "3922373305be0976cddffb6778d61343e9289d3f6d3fe8039a2ca95a765c735f",
"latest_vintage": "2026-05-01"
},
{
"series_id": "DFII10",
"transform": "diff3m",
"value": 0.119983,
"z": -5.226471,
"vote": -2,
"asof_digest": "474a4dd5f297eb398235b01334b7fc283979b30c96c1b1ac57351eedc6064cdf",
"latest_vintage": "2026-05-01"
},
{
"series_id": "T5YIFR",
"transform": "level",
"value": 3.201024,
"z": null,
"vote": -2,
"asof_digest": "b8e076fbcd90990be22e3f6fc53461a74d5f0a4553cb0152b70c4fea50f4530f",
"latest_vintage": "2026-05-01"
},
{
"series_id": "BAMLH0A0HYM2",
"transform": "diff13w",
"value": 1.110379,
"z": -5.60151,
"vote": -2,
"asof_digest": "8ec3d58658b36d414849b002fef15350817a81ddcb81e9e203a9ada8bd8d1c3f",
"latest_vintage": "2026-05-01"
},
{
"series_id": "BAMLC0A0CM",
"transform": "diff13w",
"value": 0.073323,
"z": -5.226471,
"vote": -2,
"asof_digest": "370a4e107534d46a1a542d1e16ce9f9f4a17aeeb377f9e5c4481f1e0f3a2facb",
"latest_vintage": "2026-05-01"
},
{
"series_id": "NFCI",
"transform": "level",
"value": 0.550016,
"z": null,
"vote": -2,
"asof_digest": "f0f61455659b69270627f8c5cf767fc2f5dc72985c36d682edad857629df4d9d",
"latest_vintage": "2026-04-29"
},
{
"series_id": "NET_LIQUIDITY",
"transform": "diff13w",
"value": -650.297517,
"z": -6.328823,
"vote": -2,
"asof_digest": "1e43b543c63afcf7659de4c5ddaf99ba96dc4d1c7f55052aa392b0aadd1207a9",
"latest_vintage": "2026-04-25"
},
{
"series_id": "REAL_POLICY_RATE",
"transform": "level",
"value": -3.905295,
"z": null,
"vote": -2,
"asof_digest": "9427fbf69d076b6f3a9536742e8d4f2ac15c4e4085075a8b60273d34970b0f4d",
"latest_vintage": "2026-05-01"
}
],
"vintage_digest": "77304f7e1203df3211824c78c7c9e800a0dd52b744f5173324524174ad96d3bc",
"candidate_regime": "stagflation",
"regime": "stagflation",
"liquidity_overlay": "contraction",
"hysteresis": {
"current": "stagflation",
"candidate": null,
"candidate_weeks": 0,
"weeks_since_switch": 999
},
"transition": null,
"playbook": {
"prefer": [
"energy",
"gold",
"dollar",
"defensives",
"cash"
],
"avoid": [
"unhedged cyclicals",
"levered credit"
],
"confidence": "medium"
},
"confidence": 0.956522,
"would_change": [
"robust: no single-pillar one-notch change alters this candidate regime"
],
"notes": [
"degraded: no usable vote from DFEDTARU",
"Net liquidity (WALCL - TGA - RRP) validity is regime-dependent: strongest when reserve scarcity binds.",
"PMI family is licensing-gated: growth diffusion uses claims, payrolls, production, retail, and OECD CLI."
]
},
"digest": "27a4b9dd293ae77487e919adbf428e4911da62907c39dd017c50376ad9e77591",
"signature": "806c531043618f2c4da47180ace2020def35fbf12bbf603061e4fb3264b97940c2bcfd50e395d16c8f2e45bdbe2ff69a84c00ddbe330fcaa29bc95296da66207",
"verification_key": "e324c4149db27151f65df25d528d3037d3b3bc4165b0d28c0769369cba958ae3"
},
{
"payload": {
"schema": "scopeblind.macro.vulnerability/1",
"engine_version": "macro-engine/0.1.0",
"as_of": "2025-08-23",
"posture": {
"regime": "stagflation",
"market_state": "stress",
"refs": [
{
"schema": "scopeblind.macro.market-state/1",
"as_of": "2025-08-23",
"digest": "f469ddc93ce803456bf6eed265c1ffa94690bb3ed972e9dff95c7dab52972e94"
},
{
"schema": "scopeblind.macro.tape-snapshot/1",
"as_of": "2025-08-23",
"digest": "43e98d770cb3b4e47c915164d7fe0aa7ec257968978a5cd1aa914e9e2403decd"
},
{
"schema": "scopeblind.macro.regime-snapshot/1",
"as_of": "2026-05-01",
"digest": "27a4b9dd293ae77487e919adbf428e4911da62907c39dd017c50376ad9e77591"
}
]
},
"factor_exposures": [
{
"factor": "equity_beta",
"net": 0.55,
"gross": 0.55,
"contributors": [
{
"symbol": "SPY",
"weight": 0.45
},
{
"symbol": "EEM",
"weight": 0.1
}
]
},
{
"factor": "duration",
"net": 0.3,
"gross": 0.3,
"contributors": [
{
"symbol": "IEF",
"weight": 0.3
}
]
},
{
"factor": "credit",
"net": 0.15,
"gross": 0.15,
"contributors": [
{
"symbol": "HYG",
"weight": 0.15
}
]
},
{
"factor": "usd_sensitivity",
"net": 0.1,
"gross": 0.1,
"contributors": [
{
"symbol": "EEM",
"weight": 0.1
}
]
},
{
"factor": "global",
"net": 0.1,
"gross": 0.1,
"contributors": [
{
"symbol": "EEM",
"weight": 0.1
}
]
}
],
"betas": [
{
"factor": "equity_beta",
"proxy": "SPY",
"beta": 0.562937,
"r2": 0.926912,
"n": 120
},
{
"factor": "duration",
"proxy": "IEF",
"beta": -1.916486,
"r2": 0.368425,
"n": 120
},
{
"factor": "credit",
"proxy": "HYG",
"beta": 0.344651,
"r2": 0.727716,
"n": 120
},
{
"factor": "usd",
"proxy": "UUP",
"beta": -1.562837,
"r2": 0.635209,
"n": 120
},
{
"factor": "liquidity_beta",
"proxy": "BTCUSD",
"beta": 0.318435,
"r2": 0.917171,
"n": 120
},
{
"factor": "commodity",
"proxy": "DBC",
"beta": null,
"r2": null,
"n": 0,
"note": "proxy DBC unavailable or short"
},
{
"factor": "real_assets",
"proxy": "GLD",
"beta": null,
"r2": null,
"n": 0,
"note": "proxy GLD unavailable or short"
}
],
"vulnerabilities": [
{
"factor": "equity_beta",
"exposure": 0.55,
"scenario_sensitivity": -2,
"pain": 1.1,
"note": "net long equity_beta; scenario expects equity_beta down (-2)"
},
{
"factor": "duration",
"exposure": 0.3,
"scenario_sensitivity": -1,
"pain": 0.3,
"note": "net long duration; scenario expects duration down (-1)"
},
{
"factor": "credit",
"exposure": 0.15,
"scenario_sensitivity": -2,
"pain": 0.3,
"note": "net long credit; scenario expects credit down (-2)"
}
],
"inputs_digest": "10f7e77fbbec4240ac6e203bf443a6ee03fb19184dceec2950774c066796f8c6",
"would_change": [
"reducing net equity_beta exposure toward zero removes the top vulnerability",
"a regime or market-state transition reselects the scenario stress vector"
],
"notes": [
"decision aid with stated scenario priors; not a covariance risk model and not a VaR claim"
]
},
"digest": "d277793511a0dcda199889d8beedbe849146cf0fc4cb216ce1dc77cadf20b237",
"signature": "416c38e1ed67583d2cff5b8c4020accd9d550eb49dde5956af750f4dae5b0d0ca994f564fe3db7b4a40aaab062b6236f0f8962ee5a4f4d9d00fde5400ef64506",
"verification_key": "e324c4149db27151f65df25d528d3037d3b3bc4165b0d28c0769369cba958ae3"
}
],
"journal": [
{
"payload": {
"schema": "scopeblind.macro.journal-entry/1",
"engine_version": "macro-engine/0.1.0",
"as_of": "2025-08-23",
"author": "demo-model",
"note": "Regime read stagflation while the daily tape printed stress. Cut gross and lengthened nothing; the book is long the wrong factors here.",
"references": [
{
"schema": "scopeblind.macro.market-state/1",
"as_of": "2025-08-23",
"digest": "f469ddc93ce803456bf6eed265c1ffa94690bb3ed972e9dff95c7dab52972e94"
},
{
"schema": "scopeblind.macro.vulnerability/1",
"as_of": "2025-08-23",
"digest": "d277793511a0dcda199889d8beedbe849146cf0fc4cb216ce1dc77cadf20b237"
},
{
"schema": "scopeblind.macro.regime-snapshot/1",
"as_of": "2026-05-01",
"digest": "27a4b9dd293ae77487e919adbf428e4911da62907c39dd017c50376ad9e77591"
}
],
"tags": [
"risk-off",
"stagflation",
"vulnerability"
]
},
"digest": "95415964066eaf10e5de3e49dd18763c8c7d79099baa0bbe670b402f52243923",
"signature": "adce443ba5de6d2e2edea9b5cc19744ae0a7842ad552860c03e895e5393434f4f0448bb5eb5d81f2aae7cbf222494931bfcab30ad465931f073ca2350e042b0c",
"verification_key": "e324c4149db27151f65df25d528d3037d3b3bc4165b0d28c0769369cba958ae3"
}
],
"manifest": {
"payload": {
"schema": "scopeblind.macro.track-record-manifest/1",
"engine_version": "macro-engine/0.1.0",
"exported_at": "2026-05-01T00:00:00Z",
"model_verification_key": "e324c4149db27151f65df25d528d3037d3b3bc4165b0d28c0769369cba958ae3",
"period": {
"from": "2025-01-02",
"to": "2026-05-01"
},
"entries": [
{
"schema": "scopeblind.macro.market-state/1",
"as_of": "2025-08-23",
"digest": "f469ddc93ce803456bf6eed265c1ffa94690bb3ed972e9dff95c7dab52972e94"
},
{
"schema": "scopeblind.macro.tape-snapshot/1",
"as_of": "2025-08-23",
"digest": "43e98d770cb3b4e47c915164d7fe0aa7ec257968978a5cd1aa914e9e2403decd"
},
{
"schema": "scopeblind.macro.regime-snapshot/1",
"as_of": "2026-05-01",
"digest": "27a4b9dd293ae77487e919adbf428e4911da62907c39dd017c50376ad9e77591"
},
{
"schema": "scopeblind.macro.vulnerability/1",
"as_of": "2025-08-23",
"digest": "d277793511a0dcda199889d8beedbe849146cf0fc4cb216ce1dc77cadf20b237"
},
{
"schema": "scopeblind.macro.journal-entry/1",
"as_of": "2025-08-23",
"digest": "95415964066eaf10e5de3e49dd18763c8c7d79099baa0bbe670b402f52243923"
}
],
"snapshot_count": 4,
"journal_count": 1,
"history_head_digest": "15fdd1acd962b562e05b73ca37b9ce3cce064b072fee5b27528edc9cd61eb62f",
"sequence": 1,
"previous_manifest_digest": null,
"previous_history_head_digest": null
},
"digest": "e5697c073e213bc94b2e73a53a2bd140f80821b905daf4e547a9c5674f29643f",
"signature": "c7356a7845c73f0c055144c9e784c8b77826ed85cd6e6271acf2a2c5e4b60be8131bb78a0a914e58de57bc9c0294753700b5ae1f5d72ddf4af494a7a2b8e2e0f",
"verification_key": "e324c4149db27151f65df25d528d3037d3b3bc4165b0d28c0769369cba958ae3"
},
"prior_manifests": [],
"anchor_chain": [
{
"payload": {
"schema": "scopeblind.macro.track-record-anchor/1",
"engine_version": "macro-engine/0.1.0",
"anchored_at": "2026-05-01T00:00:00Z",
"sequence": 1,
"manifest_digest": "e5697c073e213bc94b2e73a53a2bd140f80821b905daf4e547a9c5674f29643f",
"history_head_digest": "15fdd1acd962b562e05b73ca37b9ce3cce064b072fee5b27528edc9cd61eb62f",
"previous_anchor_digest": null
},
"digest": "062188f17b7d0ef9d1acb11e4e85b4ab8c61abb5c192c4ce0d7a784bbf7fb07c",
"signature": "b41012fe8a60cf65da5d28368251994e6d51ab81b81427078297aab11aa74f4dcdc163959cf14d742bb7a67a5c1ccccb332cde49a701d570535af2691a4a6d09",
"verification_key": "e324c4149db27151f65df25d528d3037d3b3bc4165b0d28c0769369cba958ae3"
}
],
"transparency": {
"head": {
"payload": {
"schema": "scopeblind.macro.transparency-head/1",
"engine_version": "macro-engine/0.1.0",
"log_id": "scopeblind.macro.demo-log",
"tree_size": 5,
"root_hash": "40efcc8314749f9b68e2d9555e16d6d223dba67069434108808e18249eb46c3c",
"timestamp": "2026-05-01T00:00:00Z",
"previous_root_hash": null
},
"digest": "6fd187a85cb09a7e01f383e6dee761801b044c04e3c518f00473db4edd626e78",
"signature": "629823481769449e85c793ccd06cfe819b60192ae0a0e72f62b6108b3082b66e8fab5f86c7ae738f599b8ec0a079747ecf308b9540168d8fdc59afbc75dfd409",
"verification_key": "e324c4149db27151f65df25d528d3037d3b3bc4165b0d28c0769369cba958ae3"
},
"witness": {
"payload": {
"schema": "scopeblind.macro.transparency-witness/1",
"engine_version": "macro-engine/0.1.0",
"head_digest": "6fd187a85cb09a7e01f383e6dee761801b044c04e3c518f00473db4edd626e78",
"root_hash": "40efcc8314749f9b68e2d9555e16d6d223dba67069434108808e18249eb46c3c",
"tree_size": 5,
"witnessed_at": "2026-05-01T00:00:00Z",
"note": "demo transparency witness (independent dev key)"
},
"digest": "dd0978d2a1aaefa180e346f8b28d64f31c3bdf7f90b3d2c1f632e45c05cac911",
"signature": "87348b1ac8cc85a280cac613489696ece8a6c668d42cb87d5799930b96978aa39ea4598419425b664365a97c8c0c9618b1ab534506264755d6c108178e4c1002",
"verification_key": "f65f4bc4a3a2d5dc899cb8d99682cd8492789c2d73e5f9e939caa3adc875c322"
},
"inclusions": [
{
"digest": "f469ddc93ce803456bf6eed265c1ffa94690bb3ed972e9dff95c7dab52972e94",
"proof": {
"leaf_index": 0,
"tree_size": 5,
"audit_path": [
"5ed6de6f809567a968c710ba86d0737c2f811bcabcddc437a8cfa53f83ffe09f",
"888f0215bbdc34f19b01cfbe9010e5883d2404aec1b1b17fb28c9798f46895df",
"d043a0e988ecdfe94fb63804f73d51365e514243e9a248e2ab16b317ce0b3f8d"
]
}
},
{
"digest": "43e98d770cb3b4e47c915164d7fe0aa7ec257968978a5cd1aa914e9e2403decd",
"proof": {
"leaf_index": 1,
"tree_size": 5,
"audit_path": [
"74d3d8019a6944bbfb0324a1bf9a54e2bf61fb7c46cb43f700df1f158894b5e6",
"888f0215bbdc34f19b01cfbe9010e5883d2404aec1b1b17fb28c9798f46895df",
"d043a0e988ecdfe94fb63804f73d51365e514243e9a248e2ab16b317ce0b3f8d"
]
}
},
{
"digest": "27a4b9dd293ae77487e919adbf428e4911da62907c39dd017c50376ad9e77591",
"proof": {
"leaf_index": 2,
"tree_size": 5,
"audit_path": [
"a5947d673a413432359ca27bb4d2903f119fa05a8770bb3bae40c90f0e019038",
"7c8ed8da587a98ec9a30df018b41bd793f33a938459fdfa96c549abcd0f05f85",
"d043a0e988ecdfe94fb63804f73d51365e514243e9a248e2ab16b317ce0b3f8d"
]
}
},
{
"digest": "d277793511a0dcda199889d8beedbe849146cf0fc4cb216ce1dc77cadf20b237",
"proof": {
"leaf_index": 3,
"tree_size": 5,
"audit_path": [
"31f0efb1db7235d4c11de485b83bbb9a9989a38069b24f443835a73b118fca22",
"7c8ed8da587a98ec9a30df018b41bd793f33a938459fdfa96c549abcd0f05f85",
"d043a0e988ecdfe94fb63804f73d51365e514243e9a248e2ab16b317ce0b3f8d"
]
}
},
{
"digest": "95415964066eaf10e5de3e49dd18763c8c7d79099baa0bbe670b402f52243923",
"proof": {
"leaf_index": 4,
"tree_size": 5,
"audit_path": [
"43feda61a2b32f67b92add7d712447aa9ddcc96af2bda2553b5cca926cfdc897"
]
}
}
]
}
}
{
"payload": {
"schema": "scopeblind.macro.transparency-head/1",
"engine_version": "macro-engine/0.1.0",
"log_id": "scopeblind.macro.demo-log",
"tree_size": 5,
"root_hash": "40efcc8314749f9b68e2d9555e16d6d223dba67069434108808e18249eb46c3c",
"timestamp": "2026-05-01T00:00:00Z",
"previous_root_hash": null
},
"digest": "6fd187a85cb09a7e01f383e6dee761801b044c04e3c518f00473db4edd626e78",
"signature": "629823481769449e85c793ccd06cfe819b60192ae0a0e72f62b6108b3082b66e8fab5f86c7ae738f599b8ec0a079747ecf308b9540168d8fdc59afbc75dfd409",
"verification_key": "e324c4149db27151f65df25d528d3037d3b3bc4165b0d28c0769369cba958ae3"
}
{
"payload": {
"schema": "scopeblind.macro.transparency-witness/1",
"engine_version": "macro-engine/0.1.0",
"head_digest": "6fd187a85cb09a7e01f383e6dee761801b044c04e3c518f00473db4edd626e78",
"root_hash": "40efcc8314749f9b68e2d9555e16d6d223dba67069434108808e18249eb46c3c",
"tree_size": 5,
"witnessed_at": "2026-05-01T00:00:00Z",
"note": "demo transparency witness (independent dev key)"
},
"digest": "dd0978d2a1aaefa180e346f8b28d64f31c3bdf7f90b3d2c1f632e45c05cac911",
"signature": "87348b1ac8cc85a280cac613489696ece8a6c668d42cb87d5799930b96978aa39ea4598419425b664365a97c8c0c9618b1ab534506264755d6c108178e4c1002",
"verification_key": "f65f4bc4a3a2d5dc899cb8d99682cd8492789c2d73e5f9e939caa3adc875c322"
}
{
"payload": {
"schema": "scopeblind.macro.vulnerability/1",
"engine_version": "macro-engine/0.1.0",
"as_of": "2025-08-23",
"posture": {
"regime": "stagflation",
"market_state": "stress",
"refs": [
{
"schema": "scopeblind.macro.market-state/1",
"as_of": "2025-08-23",
"digest": "f469ddc93ce803456bf6eed265c1ffa94690bb3ed972e9dff95c7dab52972e94"
},
{
"schema": "scopeblind.macro.tape-snapshot/1",
"as_of": "2025-08-23",
"digest": "43e98d770cb3b4e47c915164d7fe0aa7ec257968978a5cd1aa914e9e2403decd"
},
{
"schema": "scopeblind.macro.regime-snapshot/1",
"as_of": "2026-05-01",
"digest": "27a4b9dd293ae77487e919adbf428e4911da62907c39dd017c50376ad9e77591"
}
]
},
"factor_exposures": [
{
"factor": "equity_beta",
"net": 0.55,
"gross": 0.55,
"contributors": [
{
"symbol": "SPY",
"weight": 0.45
},
{
"symbol": "EEM",
"weight": 0.1
}
]
},
{
"factor": "duration",
"net": 0.3,
"gross": 0.3,
"contributors": [
{
"symbol": "IEF",
"weight": 0.3
}
]
},
{
"factor": "credit",
"net": 0.15,
"gross": 0.15,
"contributors": [
{
"symbol": "HYG",
"weight": 0.15
}
]
},
{
"factor": "usd_sensitivity",
"net": 0.1,
"gross": 0.1,
"contributors": [
{
"symbol": "EEM",
"weight": 0.1
}
]
},
{
"factor": "global",
"net": 0.1,
"gross": 0.1,
"contributors": [
{
"symbol": "EEM",
"weight": 0.1
}
]
}
],
"betas": [
{
"factor": "equity_beta",
"proxy": "SPY",
"beta": 0.562937,
"r2": 0.926912,
"n": 120
},
{
"factor": "duration",
"proxy": "IEF",
"beta": -1.916486,
"r2": 0.368425,
"n": 120
},
{
"factor": "credit",
"proxy": "HYG",
"beta": 0.344651,
"r2": 0.727716,
"n": 120
},
{
"factor": "usd",
"proxy": "UUP",
"beta": -1.562837,
"r2": 0.635209,
"n": 120
},
{
"factor": "liquidity_beta",
"proxy": "BTCUSD",
"beta": 0.318435,
"r2": 0.917171,
"n": 120
},
{
"factor": "commodity",
"proxy": "DBC",
"beta": null,
"r2": null,
"n": 0,
"note": "proxy DBC unavailable or short"
},
{
"factor": "real_assets",
"proxy": "GLD",
"beta": null,
"r2": null,
"n": 0,
"note": "proxy GLD unavailable or short"
}
],
"vulnerabilities": [
{
"factor": "equity_beta",
"exposure": 0.55,
"scenario_sensitivity": -2,
"pain": 1.1,
"note": "net long equity_beta; scenario expects equity_beta down (-2)"
},
{
"factor": "duration",
"exposure": 0.3,
"scenario_sensitivity": -1,
"pain": 0.3,
"note": "net long duration; scenario expects duration down (-1)"
},
{
"factor": "credit",
"exposure": 0.15,
"scenario_sensitivity": -2,
"pain": 0.3,
"note": "net long credit; scenario expects credit down (-2)"
}
],
"inputs_digest": "10f7e77fbbec4240ac6e203bf443a6ee03fb19184dceec2950774c066796f8c6",
"would_change": [
"reducing net equity_beta exposure toward zero removes the top vulnerability",
"a regime or market-state transition reselects the scenario stress vector"
],
"notes": [
"decision aid with stated scenario priors; not a covariance risk model and not a VaR claim"
]
},
"digest": "d277793511a0dcda199889d8beedbe849146cf0fc4cb216ce1dc77cadf20b237",
"signature": "416c38e1ed67583d2cff5b8c4020accd9d550eb49dde5956af750f4dae5b0d0ca994f564fe3db7b4a40aaab062b6236f0f8962ee5a4f4d9d00fde5400ef64506",
"verification_key": "e324c4149db27151f65df25d528d3037d3b3bc4165b0d28c0769369cba958ae3"
}
/**
* Legate adherence / restraint proof pack verifier.
*
* A proof pack (type "scopeblind.legate.proof-pack.v1") is the allocator-facing,
* POSITION-BLIND record a Legate desk produces: what the gate prevented over a
* session (held / blocked, attributed to rules), what the order-path shadow would
* have blocked, and the digests it is bound to (committed mandate, signed book
* provenance, receipt Merkle root). It carries its own runtime verification key, so
* a third party re-verifies it offline with nothing but this CLI.
*
* Signature recipe (legate-proof-pack.cjs signProofPack): Ed25519 over the UTF-8
* bytes of the canonical (deep-sorted, no-whitespace) JSON of the pack MINUS its
* `signature`, `sha256`, and `hybrid_signature` fields; `sha256` is that canonical's
* SHA-256 digest. The runtime public key is `verification_key` (and runtime.
* verification_key), raw 32-byte hex. Signing is over the bytes directly, like the
* Legate governed receipt, NOT over a pre-hash like the Gate tuple.
*
* @module verify-cli/src/engines/legate-proof-pack
*/
import { ed25519 } from '@noble/curves/ed25519';
import { sha256 } from '@noble/hashes/sha256';
import { utf8ToBytes } from '@noble/hashes/utils';
import { canonicalize } from '../util/canonical.js';
import { hexToBytes, bytesToHex } from '../util/hex.js';
export const PROOF_PACK_TYPE = 'scopeblind.legate.proof-pack.v1';
const isString = (v) => typeof v === 'string' && v.length > 0;
const HEX = (s) => typeof s === 'string' && /^[0-9a-f]+$/i.test(s) && s.length % 2 === 0;
const num = (v) => (Number.isFinite(Number(v)) ? Number(v) : 0);
const PROVES = [
'The pack was signed by the holder of the runtime key (verification_key) and not altered since: every field is bound by the Ed25519 signature over the canonical bytes.',
'The restraint counts (held / blocked, by rule) and the order-path shadow counts are the runtime\'s own, attributed to the committed mandate digest.',
'The artifact is position-blind: it contains digests and counts only, never positions, so adherence is verifiable without disclosing the book.',
];
const LIMITATIONS = [
'That the underlying receipts behind the Merkle root and the signed book behind book.sha256 are themselves correct, unless those are separately verified.',
'That the runtime key belongs to the desk you expect; pin it with --key to bind the pack to a known runtime.',
];
/**
* Reconstruct the exact canonical string that was signed: the pack minus the
* signature, the bound digest, and any hybrid signature.
*/
export function proofPackSignedCanonical(pack) {
const { signature, sha256: _digest, hybrid_signature, ...rest } = pack;
return canonicalize(rest);
}
/**
* @param {object} pack the proof pack envelope
* @param {object} opts { publicKey?: pinned runtime key (hex) }
*/
export function verifyLegateProofPack(pack, opts = {}) {
const base = {
format: 'legate-proof-pack',
schema: isString(pack?.type) ? pack.type : PROOF_PACK_TYPE,
algorithm: 'ed25519',
};
if (pack === null || typeof pack !== 'object' || Array.isArray(pack)) {
return { valid: false, error: 'unknown_format', ...base, detail: 'proof pack is not an object' };
}
if (pack.type !== PROOF_PACK_TYPE) {
return { valid: false, error: 'unknown_format', ...base, detail: `type is not ${PROOF_PACK_TYPE}` };
}
const vk = isString(pack.verification_key)
? pack.verification_key
: (pack.runtime && isString(pack.runtime.verification_key) ? pack.runtime.verification_key : undefined);
if (!isString(pack.signature)) return { valid: false, error: 'missing_signature', ...base };
if (!isString(vk)) return { valid: false, error: 'no_public_key', ...base };
if (!HEX(pack.signature) || !HEX(vk)) {
return { valid: false, error: 'malformed_hex', ...base, detail: 'signature and verification_key must be hex' };
}
const pinned = isString(opts.publicKey);
if (pinned && opts.publicKey.toLowerCase() !== vk.toLowerCase()) {
return { valid: false, error: 'key_mismatch', ...base, publicKey: vk, expectedKey: opts.publicKey };
}
// The bound digest must match the canonical the signature covers.
const canonical = proofPackSignedCanonical(pack);
if (isString(pack.sha256)) {
const recomputed = bytesToHex(sha256(utf8ToBytes(canonical)));
if (recomputed !== pack.sha256) {
return { valid: false, error: 'digest_mismatch', ...base, detail: 'sha256 does not match the canonical bytes (the pack was modified after signing)', publicKey: vk };
}
}
let ok = false;
try {
ok = ed25519.verify(hexToBytes(pack.signature), utf8ToBytes(canonical), hexToBytes(vk));
} catch (e) {
return { valid: false, error: 'malformed_hex', ...base, detail: e.message, publicKey: vk };
}
if (!ok) {
return { valid: false, error: 'invalid_signature', ...base, publicKey: vk };
}
const mandate = pack.mandate || {};
const restraint = pack.restraint || {};
const shadow = pack.shadow || null;
const book = pack.book || {};
return {
valid: true,
...base,
publicKey: vk,
keySource: pinned ? 'embedded-pack (pinned via --key)' : 'embedded-pack',
signerKid: isString(pack.signer_kid) ? pack.signer_kid : undefined,
generatedAt: isString(pack.generated_at) ? pack.generated_at : undefined,
positionBlind: pack.position_blind !== false,
mandate: { name: mandate.name, sha256: mandate.sha256, mode: mandate.mode, ruleCount: num(mandate.rule_count) },
restraint: { blocked: num(restraint.blocked), held: num(restraint.held), byRule: Array.isArray(restraint.by_rule) ? restraint.by_rule : [] },
shadow: shadow ? { observed: num(shadow.observed), wouldBlock: num(shadow.would_block), wouldHold: num(shadow.would_hold) } : null,
bookDigest: isString(book.sha256) ? book.sha256 : null,
sessionMerkleRoot: isString(pack.session_merkle_root) ? pack.session_merkle_root : null,
receiptCount: num(pack.receipt_count),
// A hybrid post-quantum signature, when present, is recognized and reported.
// Classical Ed25519 is verified here; ML-DSA-65 verification is an optional add-on
// (the runtime is dependency-free and signs classically; PQ is documented in the
// restraint-receipts draft as an optional field for surfaces that can produce it).
hybridSignaturePresent: Boolean(pack.hybrid_signature),
proves: PROVES,
limitations: LIMITATIONS,
};
}
/**
* ScopeBlind macro-engine snapshot and track-record verifier.
*
* The macro engine signs its snapshots (market-state, regime, tape,
* vulnerability, alert, journal) and its exported track-record bundle with
* the EXACT same tuple format the Gate uses: { payload, digest, signature,
* verification_key }, where digest = sha256(canonicalGateJSON(payload)) and
* signature = Ed25519 over the bytes of the hex digest.
*
* These tuples already verify cryptographically through
* engines/gate-receipt.js verifyGateTuple. This module ADDS:
* - recognition of the scopeblind.macro.* schemas,
* - a semantic-contract check per schema (macroSchemaErrors),
* - a schema-aware salient-field summary for display (macroSummary),
* - a track-record BUNDLE verifier (verifyMacroTrackRecord) that mirrors
* verifyGateBundle: every record's signature, single-signer custody, an
* exact manifest inventory, count checks, and the history_head_digest.
*
* No new cryptography is introduced. Crypto is delegated to verifyGateTuple
* and canonicalization to canonicalGateJSON, both from gate-receipt.js.
*
* @module verify-cli/src/engines/macro-snapshot
* @license Apache-2.0
*/
import { sha256 } from '@noble/hashes/sha256';
import { utf8ToBytes, bytesToHex } from '@noble/hashes/utils';
import { canonicalGateJSON, verifyGateTuple } from './gate-receipt.js';
export const MACRO_BUNDLE_SCHEMA = 'scopeblind.macro.track-record-bundle/1';
export const MACRO_MANIFEST_SCHEMA = 'scopeblind.macro.track-record-manifest/1';
export const MACRO_ANCHOR_SCHEMA = 'scopeblind.macro.track-record-anchor/1';
export const MACRO_TRANSPARENCY_HEAD_SCHEMA = 'scopeblind.macro.transparency-head/1';
export const MACRO_TRANSPARENCY_WITNESS_SCHEMA = 'scopeblind.macro.transparency-witness/1';
export const MACRO_SCHEMA_PREFIX = 'scopeblind.macro.';
/** Human descriptions for every recognized macro schema. */
export const MACRO_SCHEMAS = {
'scopeblind.macro.market-state/1': 'daily cross-asset market-state classification',
'scopeblind.macro.regime-snapshot/1': 'macro regime snapshot from economic series',
'scopeblind.macro.tape-snapshot/1': 'intraday/session tape attribution snapshot',
'scopeblind.macro.vulnerability/1': 'book vulnerability decision aid',
'scopeblind.macro.alert/1': 'state-change alert',
'scopeblind.macro.journal-entry/1': 'model journal entry referencing snapshots',
'scopeblind.macro.price-snapshot/1': 'signed point-in-time price levels per risk factor',
[MACRO_MANIFEST_SCHEMA]: 'signed track-record export manifest',
[MACRO_ANCHOR_SCHEMA]: 'signed append-only track-record checkpoint',
[MACRO_TRANSPARENCY_HEAD_SCHEMA]: 'signed RFC 6962 transparency-log head over snapshot digests',
[MACRO_TRANSPARENCY_WITNESS_SCHEMA]: 'independent witness co-signature over a transparency-log head',
};
const HEX_64 = /^[0-9a-f]{64}$/;
const MARKET_STATE_CLASSES = new Set(['risk_on', 'constructive', 'mixed', 'deteriorating', 'stress']);
const MARKET_STATE_PILLARS = ['trend', 'breadth', 'liquidity', 'credit', 'volatility'];
const REGIMES = new Set(['goldilocks', 'reflation', 'stagflation', 'deflation_bust', 'liquidity_led_recovery', 'tightening_squeeze', 'transitional']);
const TAPE_TYPES = new Set(['credit_stress', 'tightening_shock', 'growth_scare', 'inflation_shock', 'liquidity_risk_on', 'reflation_risk_on', 'mixed']);
const ALERT_SEVERITIES = new Set(['info', 'action', 'critical']);
const ALERT_KINDS = new Set(['regime_transition', 'market_state_change', 'tape_type_change']);
const isObject = (v) => v !== null && typeof v === 'object' && !Array.isArray(v);
const isString = (v) => typeof v === 'string' && v.length > 0;
const isNumber = (v) => typeof v === 'number' && Number.isFinite(v);
const isInteger = (v) => Number.isInteger(v);
const isArray = (v) => Array.isArray(v);
/** Whether a schema string is a recognized macro snapshot/journal/manifest schema. */
export function isMacroSchema(schema) {
return typeof schema === 'string' && schema.startsWith(MACRO_SCHEMA_PREFIX);
}
/** A market-state/regime/tape/etc snapshot proves authenticity + integrity + schema validity. */
export const MACRO_PROVES = [
'Signature integrity: the snapshot verifies under its carried Ed25519 key.',
'Integrity: neither payload nor digest has been modified since signing.',
'Schema validity: the recognized macro snapshot satisfies its required semantic contract.',
];
export const MACRO_LIMITATIONS = [
'The real-world identity controlling the carried key unless the expected key is independently pinned with --key.',
'Correctness of the underlying market or economic series the snapshot was computed from.',
'That the classification, regime, or tape attribution is a good or predictive read of the market.',
'Independent corroboration of the inputs unless separately attested; the model signs what it computed.',
];
export const MACRO_BUNDLE_PROVES = [
'Signature integrity: every included snapshot, journal entry, manifest, and anchor verifies under one Ed25519 key.',
'Integrity: no record payload or digest has been modified since signing.',
'Single-key consistency: all records, including the manifest, share one model verification key.',
'Manifest completeness: the signed manifest exactly enumerates every exported snapshot and journal entry, in order.',
'History binding: the manifest history_head_digest commits to the exact ordered set of record digests.',
];
export const MACRO_BUNDLE_LIMITATIONS = [
'Correctness of the underlying market or economic data the snapshots were computed from.',
'That the recorded calls were good predictions; the bundle is a tamper-evident track record, not a performance claim.',
'The real-world identity controlling an embedded key unless the expected key is independently pinned with --key.',
'Global history completeness unless prior manifests are chained and the latest history/anchor head is independently retained or timestamped.',
];
function requireFields(payload, fields, errors) {
for (const field of fields) {
if (payload[field] === undefined || payload[field] === null || payload[field] === '') errors.push(`missing ${field}`);
}
}
/** Validate an array of { schema, as_of, digest } reference objects with 64-hex digests. */
function refErrors(refs, label, errors, { nonEmpty = true } = {}) {
if (!isArray(refs)) { errors.push(`${label} must be an array`); return; }
if (nonEmpty && refs.length === 0) { errors.push(`${label} must be non-empty`); return; }
for (const ref of refs) {
if (!isObject(ref) || !isString(ref.schema) || !isString(ref.as_of) || !HEX_64.test(ref.digest || '')) {
errors.push(`${label} entry must be { schema, as_of, digest(64-hex) }`);
break;
}
}
}
/**
* Semantic-contract validation for a recognized macro payload.
* Returns [] for valid payloads and for unrecognized (non-macro or unknown
* macro) schemas; returns one or more human-readable error strings otherwise.
*
* @param {Object} payload signed macro payload
* @returns {string[]}
*/
export function macroSchemaErrors(payload) {
const errors = [];
if (!isObject(payload)) return errors;
const schema = payload.schema;
if (!Object.hasOwn(MACRO_SCHEMAS, schema)) return errors;
if (schema === 'scopeblind.macro.market-state/1') {
requireFields(payload, ['schema', 'engine_version', 'as_of', 'universe_digest', 'inputs_digest', 'pillars', 'evidence', 'classification', 'confidence', 'would_change', 'notes'], errors);
if (!MARKET_STATE_CLASSES.has(payload.classification)) errors.push('invalid classification');
if (!isObject(payload.pillars)) errors.push('pillars must be an object');
else {
for (const p of MARKET_STATE_PILLARS) {
if (!isInteger(payload.pillars[p]) || payload.pillars[p] < -2 || payload.pillars[p] > 2) errors.push(`invalid pillar ${p} (integer in [-2,2])`);
}
}
if (!isNumber(payload.confidence) || payload.confidence < 0 || payload.confidence > 1) errors.push('confidence must be a number in [0,1]');
} else if (schema === 'scopeblind.macro.regime-snapshot/1') {
requireFields(payload, ['schema', 'engine_version', 'as_of', 'pillars', 'inputs', 'vintage_digest', 'candidate_regime', 'regime', 'liquidity_overlay', 'hysteresis', 'playbook', 'confidence', 'would_change', 'notes'], errors);
if (!REGIMES.has(payload.regime)) errors.push('invalid regime');
if (!REGIMES.has(payload.candidate_regime)) errors.push('invalid candidate_regime');
if (!HEX_64.test(payload.vintage_digest || '')) errors.push('invalid vintage_digest');
if (!isObject(payload.pillars)) errors.push('pillars must be an object');
if (!isArray(payload.inputs)) errors.push('inputs must be an array');
if (!isNumber(payload.confidence) || payload.confidence < 0 || payload.confidence > 1) errors.push('confidence must be a number in [0,1]');
} else if (schema === 'scopeblind.macro.tape-snapshot/1') {
requireFields(payload, ['schema', 'engine_version', 'as_of', 'session', 'tape_type', 'coherence', 'material', 'signals', 'unavailable', 'untestable_types', 'attribution', 'inputs_digest', 'would_change', 'notes'], errors);
if (!TAPE_TYPES.has(payload.tape_type)) errors.push('invalid tape_type');
if (!isNumber(payload.coherence) || payload.coherence < 0 || payload.coherence > 1) errors.push('coherence must be a number in [0,1]');
if (typeof payload.material !== 'boolean') errors.push('material must be a boolean');
if (!isArray(payload.signals)) errors.push('signals must be an array');
if (!isObject(payload.attribution) || !isString(payload.attribution.tier)) errors.push('attribution must carry a tier');
} else if (schema === 'scopeblind.macro.vulnerability/1') {
requireFields(payload, ['schema', 'engine_version', 'as_of', 'posture', 'factor_exposures', 'betas', 'vulnerabilities', 'inputs_digest', 'would_change', 'notes'], errors);
if (!isObject(payload.posture)) errors.push('posture must be an object');
if (!isArray(payload.factor_exposures)) errors.push('factor_exposures must be an array');
if (!isArray(payload.betas)) errors.push('betas must be an array');
if (!isArray(payload.vulnerabilities)) errors.push('vulnerabilities must be an array');
} else if (schema === 'scopeblind.macro.alert/1') {
requireFields(payload, ['schema', 'engine_version', 'as_of', 'alert_id', 'kind', 'severity', 'title', 'detail', 'refs', 'budget'], errors);
if (!HEX_64.test(payload.alert_id || '')) errors.push('invalid alert_id');
if (!ALERT_SEVERITIES.has(payload.severity)) errors.push('invalid severity');
if (!ALERT_KINDS.has(payload.kind)) errors.push('invalid kind');
refErrors(payload.refs, 'refs', errors);
} else if (schema === 'scopeblind.macro.journal-entry/1') {
requireFields(payload, ['schema', 'engine_version', 'as_of', 'author', 'note', 'references', 'tags'], errors);
if (!isArray(payload.tags)) errors.push('tags must be an array');
refErrors(payload.references, 'references', errors);
} else if (schema === 'scopeblind.macro.price-snapshot/1') {
requireFields(payload, ['schema', 'engine_version', 'as_of', 'source', 'delay_minutes', 'levels', 'coverage', 'missing', 'notes'], errors);
if (!isInteger(payload.delay_minutes) || payload.delay_minutes < 0) errors.push('delay_minutes must be a non-negative integer');
if (!isString(payload.source)) errors.push('source must be a non-empty string');
if (!isArray(payload.coverage)) errors.push('coverage must be an array');
if (!isArray(payload.missing)) errors.push('missing must be an array');
if (!isObject(payload.levels)) {
errors.push('levels must be an object');
} else {
const factors = Object.keys(payload.levels);
if (factors.length === 0) errors.push('levels must price at least one factor');
const VALID_UNITS = new Set(['price', 'yield_pct', 'fx_rate', 'spread_bp']);
for (const f of factors) {
const lv = payload.levels[f];
if (!isObject(lv)) { errors.push(`level ${f} must be an object`); continue; }
if (!isNumber(lv.level)) errors.push(`level ${f} must carry a numeric level`);
if (!isString(lv.instrument)) errors.push(`level ${f} must name an instrument`);
if (!VALID_UNITS.has(lv.unit)) errors.push(`level ${f} has invalid unit`);
if (lv.multiplier !== undefined && (!isNumber(lv.multiplier) || lv.multiplier <= 0)) errors.push(`level ${f} multiplier must be a positive number`);
}
// coverage must list exactly the priced factors (sorted), never overstate.
if (isArray(payload.coverage)) {
const cov = [...payload.coverage].sort();
const keys = [...factors].sort();
if (cov.length !== keys.length || cov.some((c, i) => c !== keys[i])) errors.push('coverage must list exactly the priced factors');
}
}
} else if (schema === MACRO_MANIFEST_SCHEMA) {
requireFields(payload, ['schema', 'engine_version', 'exported_at', 'model_verification_key', 'period', 'entries', 'snapshot_count', 'journal_count', 'history_head_digest'], errors);
if (!HEX_64.test(payload.model_verification_key || '')) errors.push('invalid model_verification_key');
if (!HEX_64.test(payload.history_head_digest || '')) errors.push('invalid history_head_digest');
refErrors(payload.entries, 'entries', errors, { nonEmpty: false });
if (payload.sequence !== undefined && (!isInteger(payload.sequence) || payload.sequence < 1)) errors.push('sequence must be a positive integer');
} else if (schema === MACRO_ANCHOR_SCHEMA) {
requireFields(payload, ['schema', 'engine_version', 'anchored_at', 'sequence', 'manifest_digest', 'history_head_digest'], errors);
if (!isInteger(payload.sequence) || payload.sequence < 1) errors.push('sequence must be a positive integer');
if (!HEX_64.test(payload.manifest_digest || '')) errors.push('invalid manifest_digest');
if (!HEX_64.test(payload.history_head_digest || '')) errors.push('invalid history_head_digest');
if (payload.previous_anchor_digest !== null && !HEX_64.test(payload.previous_anchor_digest || '')) errors.push('invalid previous_anchor_digest');
} else if (schema === MACRO_TRANSPARENCY_HEAD_SCHEMA) {
requireFields(payload, ['schema', 'engine_version', 'log_id', 'tree_size', 'root_hash', 'timestamp'], errors);
if (!isInteger(payload.tree_size) || payload.tree_size < 0) errors.push('tree_size must be a non-negative integer');
if (!HEX_64.test(payload.root_hash || '')) errors.push('invalid root_hash');
// previous_root_hash is a required key but is null at the genesis head.
if (!Object.hasOwn(payload, 'previous_root_hash')) errors.push('missing previous_root_hash');
else if (payload.previous_root_hash !== null && !HEX_64.test(payload.previous_root_hash || '')) errors.push('invalid previous_root_hash');
} else if (schema === MACRO_TRANSPARENCY_WITNESS_SCHEMA) {
requireFields(payload, ['schema', 'engine_version', 'head_digest', 'root_hash', 'tree_size', 'witnessed_at', 'note'], errors);
if (!HEX_64.test(payload.head_digest || '')) errors.push('invalid head_digest');
if (!HEX_64.test(payload.root_hash || '')) errors.push('invalid root_hash');
if (!isInteger(payload.tree_size) || payload.tree_size < 0) errors.push('tree_size must be a non-negative integer');
}
return errors;
}
/**
* Extract the salient display fields for a recognized macro snapshot.
* Returns null for unrecognized schemas.
*
* @param {Object} payload signed macro payload
* @returns {Object|null}
*/
export function macroSummary(payload) {
if (!isObject(payload) || !Object.hasOwn(MACRO_SCHEMAS, payload.schema)) return null;
const schema = payload.schema;
const base = { schema, description: MACRO_SCHEMAS[schema], as_of: payload.as_of };
if (schema === 'scopeblind.macro.market-state/1') {
return { ...base, classification: payload.classification, pillars: payload.pillars, confidence: payload.confidence };
}
if (schema === 'scopeblind.macro.regime-snapshot/1') {
return { ...base, regime: payload.regime, candidate_regime: payload.candidate_regime, liquidity_overlay: payload.liquidity_overlay, confidence: payload.confidence };
}
if (schema === 'scopeblind.macro.tape-snapshot/1') {
return { ...base, tape_type: payload.tape_type, coherence: payload.coherence, material: payload.material, attribution_tier: payload.attribution?.tier };
}
if (schema === 'scopeblind.macro.vulnerability/1') {
const top = (isArray(payload.vulnerabilities) ? payload.vulnerabilities : [])
.slice()
.sort((a, b) => (b?.pain ?? 0) - (a?.pain ?? 0))
.slice(0, 3)
.map((v) => ({ factor: v?.factor, pain: v?.pain }));
return { ...base, regime: payload.posture?.regime, market_state: payload.posture?.market_state, top_vulnerabilities: top };
}
if (schema === 'scopeblind.macro.alert/1') {
return { ...base, severity: payload.severity, kind: payload.kind, title: payload.title };
}
if (schema === 'scopeblind.macro.journal-entry/1') {
return { ...base, author: payload.author, reference_count: isArray(payload.references) ? payload.references.length : 0, tags: payload.tags };
}
if (schema === 'scopeblind.macro.price-snapshot/1') {
return {
...base,
source: payload.source,
delay_minutes: payload.delay_minutes,
priced: isArray(payload.coverage) ? payload.coverage.length : 0,
missing: isArray(payload.missing) ? payload.missing.length : 0,
};
}
if (schema === MACRO_MANIFEST_SCHEMA) {
return { ...base, sequence: payload.sequence ?? 1, snapshot_count: payload.snapshot_count, journal_count: payload.journal_count };
}
if (schema === MACRO_ANCHOR_SCHEMA) {
return { ...base, sequence: payload.sequence, manifest_digest: payload.manifest_digest, history_head_digest: payload.history_head_digest };
}
if (schema === MACRO_TRANSPARENCY_HEAD_SCHEMA) {
return { ...base, log_id: payload.log_id, tree_size: payload.tree_size, root_hash: payload.root_hash };
}
if (schema === MACRO_TRANSPARENCY_WITNESS_SCHEMA) {
return { ...base, head_digest: payload.head_digest, tree_size: payload.tree_size };
}
return base;
}
const refsEqual = (a, b) =>
isObject(a) && isObject(b) && a.schema === b.schema && a.as_of === b.as_of && a.digest === b.digest;
// ── RFC 6962 transparency-log inclusion verification ─────────────────
//
// The macro engine signs an RFC 6962 Merkle transparency log over the
// snapshot/journal record digests. This block reconstructs a leaf's root from
// its audit path EXACTLY as the engine builds it, so the verifier can confirm
// that every exported record is committed under the signed head's root_hash.
// Hashing is domain-separated over RAW digest bytes (not the hex string).
/** Decode a hex string to a Uint8Array (no prefix handling; lengths are caller-checked). */
function hexToBytes(hex) {
const bytes = new Uint8Array(hex.length / 2);
for (let i = 0; i < bytes.length; i++) bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
return bytes;
}
/** Concatenate Uint8Arrays into one. */
function concatBytes(...arrays) {
let length = 0;
for (const a of arrays) length += a.length;
const out = new Uint8Array(length);
let offset = 0;
for (const a of arrays) { out.set(a, offset); offset += a.length; }
return out;
}
/** RFC 6962 leaf hash: sha256(0x00 || raw record-digest bytes). */
function leafHash(recordDigestHex) {
return sha256(concatBytes(Uint8Array.of(0x00), hexToBytes(recordDigestHex)));
}
/** RFC 6962 interior node hash: sha256(0x01 || left || right). */
function nodeHash(left, right) {
return sha256(concatBytes(Uint8Array.of(0x01), left, right));
}
/** Largest power of two STRICTLY less than n (RFC 6962 split point). */
function splitPoint(n) {
let k = 1;
while ((k << 1) < n) k <<= 1;
return k;
}
/**
* Verify an RFC 6962 inclusion proof: reconstruct the Merkle root for the leaf
* at proof.leaf_index in a tree of proof.tree_size leaves, consuming the audit
* path deepest-sibling-first (top sibling LAST, i.e. from the END of the array).
*
* @param {string} recordDigestHex 64-hex record digest committed as the leaf
* @param {Object} proof { leaf_index, tree_size, audit_path: string[] }
* @param {string} expectedRootHex 64-hex root_hash from the signed head
* @returns {boolean}
*/
export function verifyInclusion(recordDigestHex, proof, expectedRootHex) {
if (!isObject(proof)) return false;
const { leaf_index, tree_size, audit_path } = proof;
if (!isInteger(leaf_index) || !isInteger(tree_size)) return false;
if (leaf_index < 0 || leaf_index >= tree_size) return false;
if (!HEX_64.test(recordDigestHex || '')) return false;
if (!HEX_64.test(expectedRootHex || '')) return false;
if (!isArray(audit_path) || !audit_path.every((h) => HEX_64.test(h || ''))) return false;
const nodes = audit_path.map(hexToBytes);
// hi = number of path nodes still available; the top sibling is nodes[hi-1].
function root(m, size, hi) {
if (size === 1) return hi === 0 ? leafHash(recordDigestHex) : null;
if (hi < 1) return null;
const k = splitPoint(size);
const sib = nodes[hi - 1];
if (m < k) {
const left = root(m, k, hi - 1);
return left && nodeHash(left, sib);
}
const right = root(m - k, size - k, hi - 1);
return right && nodeHash(sib, right);
}
const r = root(leaf_index, tree_size, nodes.length);
return r !== null && bytesToHex(r) === expectedRootHex;
}
/**
* Verify a track-record bundle's transparency evidence: the signed log head,
* every record's inclusion under that head's root, and (optionally) an
* independent witness co-signature over the same head.
*
* @param {Object} evidence bundle.transparency: { head, witness, inclusions }
* @param {string[]} recordDigests every snapshot + journal record digest that
* must be committed in the log
* @returns {{ head_valid: boolean, all_included: boolean, witness_present: boolean,
* witness_independent: boolean, anchor: 'none'|'self_signed'|'witnessed',
* tree_size: number|null, root_hash: string|null, errors: string[] }}
*/
export function verifyTransparencyEvidence(evidence, recordDigests = []) {
const result = {
head_valid: false,
all_included: false,
witness_present: false,
witness_independent: false,
anchor: 'none',
tree_size: null,
root_hash: null,
errors: [],
};
if (!isObject(evidence) || !isObject(evidence.head)) {
result.errors.push('transparency evidence is missing a signed head');
return result;
}
const head = evidence.head;
const headResult = verifyGateTuple(head);
const headPayload = isObject(head.payload) ? head.payload : {};
const root = headPayload.root_hash;
result.tree_size = isInteger(headPayload.tree_size) ? headPayload.tree_size : null;
result.root_hash = isString(root) ? root : null;
if (!headResult.valid) {
result.errors.push(`transparency head signature invalid: ${headResult.error}`);
} else if (headPayload.schema !== MACRO_TRANSPARENCY_HEAD_SCHEMA) {
result.errors.push('transparency head is not a transparency-head schema');
} else if (!HEX_64.test(root || '')) {
result.errors.push('transparency head root_hash is not 64-hex');
} else {
result.head_valid = true;
}
// Inclusion of every checked record under the signed root.
if (result.head_valid) {
const inclusions = isArray(evidence.inclusions) ? evidence.inclusions : [];
const byDigest = new Map();
for (const inc of inclusions) {
if (isObject(inc) && isString(inc.digest)) byDigest.set(inc.digest.toLowerCase(), inc);
}
let allIncluded = recordDigests.length > 0 || inclusions.length > 0;
for (const digest of recordDigests) {
const inc = byDigest.get(String(digest).toLowerCase());
if (!inc || !verifyInclusion(digest, inc.proof, root)) {
allIncluded = false;
result.errors.push(`record ${String(digest).slice(0, 16)}... is not provably included in the signed log`);
}
}
result.all_included = allIncluded;
}
// Optional independent witness co-signature over the same head.
if (isObject(evidence.witness)) {
result.witness_present = true;
const witness = evidence.witness;
const witnessResult = verifyGateTuple(witness);
const witnessPayload = isObject(witness.payload) ? witness.payload : {};
const witnessValid = witnessResult.valid
&& witnessPayload.schema === MACRO_TRANSPARENCY_WITNESS_SCHEMA
&& witnessPayload.head_digest === head.digest
&& witnessPayload.root_hash === root;
if (!witnessValid) {
result.errors.push('transparency witness does not co-sign this head');
} else {
result.witness_independent = isString(witness.verification_key)
&& isString(head.verification_key)
&& witness.verification_key.toLowerCase() !== head.verification_key.toLowerCase();
}
}
result.anchor = (!result.head_valid || !result.all_included)
? 'none'
: result.witness_independent ? 'witnessed' : 'self_signed';
return result;
}
/**
* Verify a macro track-record bundle.
*
* Mirrors verifyGateBundle: it checks each record's signature, that every
* record (including the manifest) is signed by the single declared model
* key, that the manifest entries exactly enumerate the snapshots followed by
* the journal entries in order, the snapshot/journal counts, and that the
* history_head_digest recomputes over the ordered record digests.
*
* @param {Object} bundle parsed track-record bundle
* @param {Object} [opts] { publicKey } optional pinned model key
* @returns {Object} result with the same error-shape conventions as gate-receipt.js
*/
export function verifyMacroTrackRecord(bundle, opts = {}) {
const results = {
valid: true,
format: 'macro-track-record',
schema: bundle?.schema,
exportedAt: bundle?.exported_at,
period: isObject(bundle?.period) ? bundle.period : null,
custody: isString(bundle?.custody) ? bundle.custody : null,
modelVerificationKey: isString(bundle?.model_verification_key) ? bundle.model_verification_key : null,
snapshotCount: 0,
journalCount: 0,
total: 0,
passed: 0,
failed: 0,
cryptoFailed: 0,
chainChecks: 0,
chainFailed: 0,
errors: [],
records: [],
signers: [],
singleSigner: true,
manifestValid: null,
signerPinned: isString(opts.publicKey),
identityStatus: isString(opts.publicKey) ? 'pinned_operator_key' : 'embedded_key_only',
historyChainValid: null,
historyAnchored: false,
historyHeadPinned: false,
anchorHeadPinned: false,
sequence: 1,
transparencyAnchor: null,
proves: MACRO_BUNDLE_PROVES,
limitations: MACRO_BUNDLE_LIMITATIONS,
};
if (!isObject(bundle) || bundle.schema !== MACRO_BUNDLE_SCHEMA || !isArray(bundle.snapshots) || !isObject(bundle.manifest)) {
return { ...results, valid: false, error: 'unknown_format', detail: 'unsupported macro bundle schema or missing snapshots/manifest' };
}
const snapshots = bundle.snapshots;
const journal = isArray(bundle.journal) ? bundle.journal : [];
const priorManifests = isArray(bundle.prior_manifests) ? bundle.prior_manifests : [];
const anchors = isArray(bundle.anchor_chain) ? bundle.anchor_chain : [];
results.snapshotCount = snapshots.length;
results.journalCount = journal.length;
if (!HEX_64.test(results.modelVerificationKey || '')) {
return { ...results, valid: false, error: 'no_public_key', detail: 'bundle requires model_verification_key' };
}
const modelKey = results.modelVerificationKey.toLowerCase();
if (isString(opts.publicKey) && opts.publicKey.toLowerCase() !== modelKey) {
return { ...results, valid: false, error: 'key_mismatch', detail: 'bundle model_verification_key does not match --key' };
}
const signerRoles = new Map();
let firstError = null;
const add = (tuple, role, index) => {
results.total++;
const r = verifyGateTuple(tuple, { publicKey: modelKey });
const key = isString(tuple?.verification_key) ? tuple.verification_key.toLowerCase() : null;
if (key) {
if (!signerRoles.has(key)) signerRoles.set(key, new Set());
signerRoles.get(key).add(role);
if (key !== modelKey) results.singleSigner = false;
} else {
results.singleSigner = false;
}
const record = {
index: index + 1,
role,
schema: r.schema,
schemaRecognized: r.schemaRecognized || isMacroSchema(r.schema),
cryptoValid: r.valid,
cryptoError: r.valid ? undefined : r.error,
signer: tuple?.verification_key,
digest: tuple?.digest,
};
results.records.push(record);
if (!r.valid) {
results.cryptoFailed++;
results.valid = false;
firstError ||= r.error;
results.errors.push(`[crypto] ${role} ${index + 1}: ${r.error}${r.detail ? ` (${r.detail})` : ''}`);
results.failed++;
} else {
results.passed++;
}
return r;
};
for (let i = 0; i < snapshots.length; i++) add(snapshots[i], 'snapshot', i);
for (let i = 0; i < journal.length; i++) add(journal[i], 'journal', i);
for (let i = 0; i < priorManifests.length; i++) add(priorManifests[i], 'prior-manifest', i);
const mr = add(bundle.manifest, 'manifest', -1);
for (let i = 0; i < anchors.length; i++) add(anchors[i], 'history-anchor', i);
results.manifestValid = mr.valid;
// Single-signer custody check (every record, including the manifest, shares
// the declared model key).
results.chainChecks++;
if (!results.singleSigner) {
results.valid = false;
results.chainFailed++;
results.errors.push('[chain] not all records are signed by model_verification_key (single-signer custody violated)');
}
// Manifest inventory + counts + history head.
if (mr.valid) {
const p = bundle.manifest.payload;
const ordered = [...snapshots, ...journal];
const expectedEntries = ordered.map((t) => ({ schema: t?.payload?.schema, as_of: t?.payload?.as_of, digest: t?.digest }));
const historyHead = bytesToHex(sha256(utf8ToBytes(canonicalGateJSON(ordered.map((t) => t?.digest)))));
results.chainChecks++;
const entries = isArray(p.entries) ? p.entries : [];
let manifestError = null;
if (p.model_verification_key?.toLowerCase() !== modelKey) manifestError = 'manifest model_verification_key mismatch';
else if (p.exported_at !== bundle.exported_at) manifestError = 'manifest exported_at mismatch';
else if (entries.length !== expectedEntries.length) manifestError = `manifest entries count (${entries.length}) does not match exported records (${expectedEntries.length})`;
else if (!entries.every((e, idx) => refsEqual(e, expectedEntries[idx]))) manifestError = 'manifest entries do not exactly enumerate the exported records in order';
else if (p.snapshot_count !== snapshots.length) manifestError = `manifest snapshot_count (${p.snapshot_count}) does not match (${snapshots.length})`;
else if (p.journal_count !== journal.length) manifestError = `manifest journal_count (${p.journal_count}) does not match (${journal.length})`;
else if (p.history_head_digest !== historyHead) manifestError = 'manifest history_head_digest mismatch';
else if (p.sequence !== undefined && (!isInteger(p.sequence) || p.sequence < 1)) manifestError = 'manifest sequence is not a positive integer';
if (manifestError) {
results.valid = false;
results.manifestValid = false;
results.chainFailed++;
results.errors.push(`[chain] Manifest: ${manifestError}`);
}
results.sequence = p.sequence ?? 1;
results.chainChecks++;
if (isString(opts.historyHead)) {
results.historyHeadPinned = opts.historyHead.toLowerCase() === String(p.history_head_digest).toLowerCase();
if (!results.historyHeadPinned) {
results.valid = false;
results.chainFailed++;
results.errors.push('[chain] current history head does not match --history-head');
}
}
const manifests = [...priorManifests, bundle.manifest];
let historyChainError = null;
if (priorManifests.length > 0 || p.sequence !== undefined) {
const retained = new Set(expectedEntries.map((entry) => entry.digest));
for (let i = 0; i < manifests.length && !historyChainError; i++) {
const current = manifests[i];
const payload = current?.payload;
const expectedSequence = i + 1;
if ((payload?.sequence ?? expectedSequence) !== expectedSequence) {
historyChainError = `manifest sequence mismatch at ${expectedSequence}`;
break;
}
if (i > 0) {
const previous = manifests[i - 1];
if (payload?.previous_manifest_digest !== previous?.digest
|| payload?.previous_history_head_digest !== previous?.payload?.history_head_digest) {
historyChainError = `manifest previous-head mismatch at sequence ${expectedSequence}`;
break;
}
}
for (const entry of (isArray(payload?.entries) ? payload.entries : [])) {
if (!retained.has(entry.digest)) {
historyChainError = `current export omits prior record ${entry.digest}`;
break;
}
}
}
results.historyChainValid = historyChainError === null;
results.chainChecks++;
if (historyChainError) {
results.valid = false;
results.chainFailed++;
results.errors.push(`[chain] History: ${historyChainError}`);
}
}
if (anchors.length > 0) {
results.historyAnchored = true;
const offset = manifests.length - anchors.length;
let anchorError = null;
for (let i = 0; i < anchors.length && !anchorError; i++) {
const anchor = anchors[i];
const anchorPayload = anchor?.payload;
const manifest = manifests[offset + i];
if (!manifest) {
anchorError = `anchor ${i + 1} has no corresponding manifest`;
break;
}
const previousAnchor = i > 0 ? anchors[i - 1]?.digest : null;
if (anchorPayload?.schema !== MACRO_ANCHOR_SCHEMA
|| anchorPayload?.sequence !== manifest.payload?.sequence
|| anchorPayload?.manifest_digest !== manifest.digest
|| anchorPayload?.history_head_digest !== manifest.payload?.history_head_digest
|| anchorPayload?.previous_anchor_digest !== previousAnchor) {
anchorError = `anchor mismatch at sequence ${anchorPayload?.sequence ?? i + 1}`;
}
}
results.chainChecks++;
if (anchorError) {
results.valid = false;
results.chainFailed++;
results.errors.push(`[chain] Anchor: ${anchorError}`);
}
const anchorHead = anchors.at(-1)?.digest;
if (isString(opts.anchorHead)) {
results.anchorHeadPinned = opts.anchorHead.toLowerCase() === String(anchorHead).toLowerCase();
results.chainChecks++;
if (!results.anchorHeadPinned) {
results.valid = false;
results.chainFailed++;
results.errors.push('[chain] current anchor head does not match --anchor-head');
}
}
}
} else {
// Manifest signature failed; inventory cannot be trusted.
results.chainChecks++;
results.chainFailed++;
results.valid = false;
results.errors.push('[chain] Manifest signature invalid; inventory cannot be verified');
}
// Optional RFC 6962 transparency evidence: confirm every exported record
// digest is committed under a signed (and optionally witnessed) log head.
// A bundle WITHOUT a transparency field stays valid (backward compatible).
if (isObject(bundle.transparency)) {
const recordDigests = [...snapshots, ...journal]
.map((t) => (isString(t?.digest) ? t.digest : null))
.filter(Boolean);
const transparency = verifyTransparencyEvidence(bundle.transparency, recordDigests);
results.transparencyAnchor = transparency;
results.chainChecks++;
if (!transparency.head_valid || !transparency.all_included) {
results.valid = false;
results.chainFailed++;
const why = !transparency.head_valid
? 'transparency head is not a valid signed log head'
: 'one or more exported records are not provably included in the signed log';
results.errors.push(`[chain] Transparency: ${why}${transparency.errors.length ? ` (${transparency.errors[0]})` : ''}`);
}
}
results.signers = [...signerRoles.entries()].map(([key, roles]) => ({ key, roles: [...roles].sort(), isModelKey: key === modelKey }));
if (!results.valid) results.error = firstError || 'chain_link_mismatch';
return results;
}
/**
* Trusted Context Pack verifier (TCB v1).
*
* A fund's desktop runtime turns an approved file (a positions export, a blotter,
* a mandate, a research folder) into a SIGNED TrustedContextPack before any agent
* or gate operates over it. This engine lets a third party (an allocator, an LP,
* an auditor) re-verify that pack offline, holding only this open tool and no
* ScopeBlind code: the digest is recomputed over the canonical payload and the
* Ed25519 signature is checked over that digest against the embedded (or pinned)
* key, exactly like a Gate receipt tuple.
*
* The TCB-specific check is the relabel guard: gate_status MUST equal the status
* derived from the signed confidence and freshness. A pack cannot be re-signed to
* claim a low-confidence or stale parse is `usable`. This is what makes the
* confidence-gating trustworthy to someone who did not produce the pack.
*
* What a verified pack proves: these exact bytes, with this file hash, parsed to
* this context at this confidence and freshness, signed by this key. What it does
* NOT prove: that the source file is authentic, complete, or the fund's true book.
* That requires a custodian-signed feed or a DKIM/PAdES source (a stronger tier).
*
* @module verify-cli/src/engines/trusted-context-pack
* @license Apache-2.0
*/
import { ed25519 } from '@noble/curves/ed25519';
import { sha256 } from '@noble/hashes/sha256';
import { utf8ToBytes } from '@noble/hashes/utils';
import { sortKeysDeep } from '../util/canonical.js';
import { hexToBytes, bytesToHex } from '../util/hex.js';
export const TCB_SCHEMA = 'scopeblind.trusted_context_pack.v1';
const TCB_USABLE_THRESHOLD = 0.75;
const HEX_64 = /^[0-9a-f]{64}$/;
const SOURCE_TYPES = new Set(['book_positions', 'nav_account', 'blotter', 'risk_report', 'mandate_limits', 'research', 'operations', 'unknown']);
const GATE_STATUSES = new Set(['usable', 'needs_approval', 'blocked']);
const isObject = (v) => v !== null && typeof v === 'object' && !Array.isArray(v);
const isString = (v) => typeof v === 'string' && v.length > 0;
const isNumber = (v) => typeof v === 'number' && Number.isFinite(v);
export function canonicalTcbJSON(payload) {
return JSON.stringify(sortKeysDeep(payload));
}
/** The single source of truth for the gate decision (kept in sync with
* scopeblind-pm/src/trusted-context.ts:gateStatusFor). */
export function gateStatusFor(confidence, freshness) {
if (confidence <= 0) return 'blocked';
if (confidence < TCB_USABLE_THRESHOLD || freshness?.stale === true) return 'needs_approval';
return 'usable';
}
export const TCB_PROVES = [
'Authenticity: the pack was signed by the Ed25519 key it carries (the fund runtime that built it).',
'Integrity: the file hash, parsed context, confidence, freshness, and gate decision are bound by the signature and unmodified.',
'Honest gating: gate_status matches the confidence and freshness, so a low-confidence or stale parse cannot be relabeled usable.',
];
export const TCB_LIMITATIONS = [
'That the source file is authentic, complete, or the fund\'s true book; a pack attests the parse, not the provenance.',
'Correctness of the original file behind file_hash unless its bytes are separately disclosed and re-hashed.',
'Whether the embedded verification_key is the runtime you expect; pin it with --key to bind trust to a known signer.',
'A stronger source tier (custodian-signed feed, DKIM or PAdES) is needed to attest where the data came from.',
];
function collectFields(payload) {
const out = {};
for (const k of ['source_type', 'source_format', 'source_lineage', 'file_name', 'file_hash', 'parser_version', 'confidence', 'gate_status', 'workspace_id', 'source_id']) {
if (payload[k] !== undefined && payload[k] !== null) out[k] = payload[k];
}
if (isObject(payload.freshness)) out.freshness = { as_of: payload.freshness.as_of ?? null, stale: payload.freshness.stale === true };
if (Array.isArray(payload.warnings)) out.warnings = payload.warnings;
if (isObject(payload.summary)) out.summary = payload.summary;
return out;
}
function schemaErrors(payload) {
const errors = [];
for (const f of ['workspace_id', 'source_id', 'source_format', 'file_hash', 'parser_version']) {
if (!isString(payload[f])) errors.push(`missing or empty ${f}`);
}
if (!SOURCE_TYPES.has(payload.source_type)) errors.push(`invalid source_type ${JSON.stringify(payload.source_type)}`);
if (!GATE_STATUSES.has(payload.gate_status)) errors.push(`invalid gate_status ${JSON.stringify(payload.gate_status)}`);
if (!HEX_64.test(payload.file_hash || '')) errors.push('file_hash must be 64 lowercase hex characters');
if (!isNumber(payload.confidence) || payload.confidence < 0 || payload.confidence > 1) errors.push('confidence must be a number in [0,1]');
if (!Array.isArray(payload.warnings)) errors.push('warnings must be an array');
if (!isObject(payload.parsed_artifacts)) errors.push('parsed_artifacts must be an object');
if (!isObject(payload.freshness) || !isString(payload.freshness.ingested_at)) errors.push('freshness.ingested_at is required');
else if (typeof payload.freshness.stale !== 'boolean') errors.push('freshness.stale must be a boolean');
// The relabel guard: gate_status must follow from the signed confidence/freshness.
if (errors.length === 0) {
const expected = gateStatusFor(payload.confidence, payload.freshness);
if (payload.gate_status !== expected) errors.push(`gate_status ${JSON.stringify(payload.gate_status)} does not match the signed confidence and freshness (expected ${expected})`);
}
return errors;
}
/**
* Verify a TrustedContextPack tuple { payload, digest, signature, verification_key }.
*
* @param {object} tuple
* @param {{ publicKey?: string }} [opts]
*/
export function verifyTrustedContextPack(tuple, opts = {}) {
const base = { format: 'trusted-context-pack', schema: null, schemaRecognized: false, algorithm: 'ed25519' };
if (!isObject(tuple)) return { valid: false, error: 'unknown_format', ...base, detail: 'pack is not an object' };
const payload = tuple.payload;
if (!isObject(payload)) return { valid: false, error: 'missing_payload', ...base };
const schema = isString(payload.schema) ? payload.schema : null;
base.schema = schema;
base.schemaRecognized = schema === TCB_SCHEMA;
base.payloadFields = collectFields(payload);
if (schema !== TCB_SCHEMA) return { valid: false, error: 'unknown_format', ...base, detail: `expected schema ${TCB_SCHEMA}` };
if (!isString(tuple.signature)) return { valid: false, error: 'missing_signature', ...base };
if (!isString(tuple.digest) || !HEX_64.test(tuple.digest)) return { valid: false, error: 'malformed_hex', ...base, detail: 'digest must be 64 lowercase hex characters' };
if (!isString(tuple.verification_key)) return { valid: false, error: 'no_public_key', ...base };
const pinned = isString(opts.publicKey);
if (pinned && opts.publicKey.toLowerCase() !== tuple.verification_key.toLowerCase()) {
return { valid: false, error: 'key_mismatch', ...base, publicKey: tuple.verification_key, expectedKey: opts.publicKey };
}
const recomputed = bytesToHex(sha256(utf8ToBytes(canonicalTcbJSON(payload))));
if (recomputed !== tuple.digest) return { valid: false, error: 'digest_mismatch', ...base, digest: tuple.digest, recomputedDigest: recomputed, publicKey: tuple.verification_key };
let ok = false;
try {
ok = ed25519.verify(hexToBytes(tuple.signature), hexToBytes(tuple.digest), hexToBytes(tuple.verification_key));
} catch (e) {
return { valid: false, error: 'malformed_hex', ...base, digest: tuple.digest, detail: e.message, publicKey: tuple.verification_key };
}
if (!ok) return { valid: false, error: 'invalid_signature', ...base, digest: tuple.digest, publicKey: tuple.verification_key };
const semanticErrors = schemaErrors(payload);
if (semanticErrors.length) return { valid: false, error: 'schema_invalid', ...base, digest: tuple.digest, publicKey: tuple.verification_key, detail: semanticErrors.join('; '), semanticErrors };
return {
valid: true,
...base,
digest: tuple.digest,
publicKey: tuple.verification_key,
keySource: pinned ? 'embedded-tuple (pinned via --key)' : 'embedded-tuple',
gateStatus: payload.gate_status,
confidence: payload.confidence,
sourceType: payload.source_type,
proves: TCB_PROVES,
limitations: TCB_LIMITATIONS,
};
}
/**
* Known-issuer labels.
*
* Verifying a signature proves the bytes were signed by a given key, not WHO holds
* it (the engines say this in their limitations). A known-issuers map turns a raw
* hex key into a human label in the output ("Signer: Meridian Global Macro Desk")
* so a reader who has pinned trust to a known desk sees the name, not just hex. It
* is a display aid layered on top of `--key` pinning, never a trust shortcut: an
* unlabeled key still verifies, and a labeled key is only as trustworthy as the map
* the verifier chose to load.
*
* @module verify-cli/src/util/known-issuers
* @license Apache-2.0
*/
import { readFileSync } from 'node:fs';
/**
* Load and merge issuer label maps (hex public key -> label). A bundled default is
* overlaid with an optional user file (the user file wins). Keys are normalized to
* lowercase hex. Unreadable or malformed files are ignored (labels are non-critical).
*
* @param {string|undefined} userPath path passed via --known-issuers
* @param {string|undefined} bundledPath path to the package's known-issuers.json
* @returns {Record<string,string>} lowercase-hex key -> label
*/
export function loadKnownIssuers(userPath, bundledPath) {
const merged = {};
for (const p of [bundledPath, userPath]) {
if (!p) continue;
try {
const obj = JSON.parse(readFileSync(p, 'utf8'));
if (obj && typeof obj === 'object') {
for (const [k, v] of Object.entries(obj)) {
if (k.startsWith('_')) continue; // _comment / _note keys are documentation
if (typeof v === 'string' && /^[0-9a-fA-F]+$/.test(k)) merged[k.toLowerCase()] = v;
}
}
} catch { /* labels are non-critical; ignore unreadable/malformed files */ }
}
return merged;
}
/** Resolve a label for a hex key, or null. Case-insensitive. */
export function labelFor(key, issuers) {
if (typeof key !== 'string' || !issuers) return null;
return issuers[key.toLowerCase()] || null;
}