PROMPTKING VERIFY
Versioned receipt and lineage hash specification

Any third party can implement this specification without PromptKing credentials. The public verifier executes the same algorithm again in the reader's browser; it does not rely on the server's verdict.

1. Versioned canonical serialization

governed-run-v1 has 22 immutable fields. governed-run-v2 has 26 immutable fields and adds chain_depth, chain_id, parent_receipt_hash, and parent_receipt_id. Missing fields are JSON null. Keys are inserted in the exact ASCII order below.

const V1_KEYS = [
  "actual_cost_usd","agent_id","agent_name","autonomy_tier",
  "correlation_id","declared_estimate_usd","halt_breach_detected",
  "halt_compliance_at","halt_compliance_status","intent_declaration",
  "issued_at","org_id","outcome_report_id","policy_evaluation_id",
  "policy_verdict","prepared_action","provenance_lane","receipt_version",
  "run_id","spiffe_id","trajectory_id","variance_pct"
];
const V2_KEYS = [
  "actual_cost_usd","agent_id","agent_name","autonomy_tier",
  "chain_depth","chain_id","correlation_id","declared_estimate_usd",
  "halt_breach_detected","halt_compliance_at","halt_compliance_status",
  "intent_declaration","issued_at","org_id","outcome_report_id",
  "parent_receipt_hash","parent_receipt_id","policy_evaluation_id",
  "policy_verdict","prepared_action","provenance_lane","receipt_version",
  "run_id","spiffe_id","trajectory_id","variance_pct"
];

async function receiptHash(hashInputs) {
  const keys = hashInputs.receipt_version === "governed-run-v2" ? V2_KEYS : V1_KEYS;
  const canonical = {};
  for (const key of keys) canonical[key] = hashInputs[key] ?? null;
  const bytes = new TextEncoder().encode(JSON.stringify(canonical));
  const digest = await crypto.subtle.digest("SHA-256", bytes);
  return "sha256:" + [...new Uint8Array(digest)]
    .map(byte => byte.toString(16).padStart(2, "0")).join("");
}

2. Hash-bound lineage rule

For every child-to-parent edge, independently verify all of the following:

  1. Both receipt hashes recompute from their own public canonical bytes.
  2. The child is governed-run-v2.
  3. The child's parent ID and parent hash equal the next receipt.
  4. The chain ID is inherited and child depth is exactly parent depth + 1.

A v1 receipt may be a root. A v1 receipt with a database-side parent is legacy-unbound: it may be corroborated, but it is not publicly hash-bound and must never produce a green whole-chain verdict.

3. Public endpoints

/api/verify/<receipt-id> publishes one receipt's allow-listed canonical inputs.

/api/verify/chain/<child-id> publishes a child-to-root envelope. /verify/chain/<child-id> recomputes every node and edge again in the browser.

4. Meaning and limits

A green verdict means every public receipt hash and every parent edge in that receipt chain is internally consistent under the published contract. It requires no PromptKing login, private database record, IBM trace, or vendor runtime access.

It does not prove issuer signature, non-repudiation, or external timestamping. Vendor traces remain corroboration, not part of the proof.

5. Cache and statelessness boundary

Receipt verification is point-in-time: a green verdict proves the payload served now matches the hash stored alongside it. Database-level append-only enforcement and an externally anchored, tamper-evident record are on the roadmap; until then, historical immutability is not part of this proof. Public canonical verification envelopes may use a bounded public cache. Credential, enrollment, session, and authorization surfaces remain private with zero TTL. Every verification request is self-contained; transport session identity is never part of the proof.

Evidence Receipt Verification Specification | PromptKing | PromptKing — Independent Evidence Plane