Evidence

Receipt Specification

Current WitnessOps receipt contracts, the legacy public_exposure_review profile, and the bounded checks performed by the public verifier.

This Page Answers

Which receipt contracts are current, what does the legacy public_exposure_review profile require, and what can the public verifier assert?

This page describes the receipt contracts that the current WitnessOps code accepts. It keeps the canonical, legacy-named public_exposure_review contract separate from older compatibility receipt families.

If you need the concept first, start with Receipts. If you need the public procedure, go to Verification.

1. Current contract boundary

The canonical cross-repository receipt envelope is witnessops.receipt.v0. The public_exposure_review compatibility profile applies the additive context witnessops.verification_context.v1 and workflow class public_exposure_review.

The public /verify surface also retains bounded compatibility adapters. Acceptance by a compatibility adapter does not make that receipt family the canonical cross-repository contract.

Receipt familyCurrent public handlingBoundary
witnessops.receipt.v0 + witnessops.verification_context.v1 + public_exposure_reviewProduct-specific receipt-only adapterCanonical legacy profile; currently indeterminate when structurally conforming because full evidence and production trust are not checked
PV 1.0.0 / 1.1.0, QV 2.0.0, WV 2.1.0Generic receipt compatibility adapterReceipt-only checks; partial artifact coverage maps to indeterminate
witnessops.local_server_audit.receipt.v1 and its exact legacy markersStructural dual-read adapterStructural and cross-field checks only; artifact bytes are not checked

Objects such as a conceptual witnessops.receipt.v2 ledger envelope are not accepted by the current public API unless they also match one of the executable contracts above. They must not be presented as the universal current receipt format.

The public_exposure_review identity crosswalk is exact:

Authority layerIdentifier
Existing product IDOFFSEC-EXTERNAL-EXPOSURE
Receipt workflow classpublic_exposure_review
OffSec source runbookexternal-exposure-assessment version 2
Receipt verification methodexternal_exposure_assessment version 2.0.0

The product ID and hyphenated source-runbook ID belong to the offer and producer context; they are not extra top-level receipt fields.

2. Legacy public_exposure_review envelope

A receipt using this profile has exactly these top-level fields:

FieldPurpose
receipt_versionMust be witnessops.receipt.v0
receipt_profileMust be witnessops.verification_context.v1
workflow_classMust be public_exposure_review
proof_run_idStable run identifier in the pr_per_<24 lowercase hex> form
verification_contextSubject, scope, method, timestamps, and preserved limitations
resultBounded review outcome and named failure states
claimsExact workflow claim set with manifest artifact references
manifest_hashDeclared SHA-256 digest of the evidence manifest
signatureDeclared Ed25519 signature and public-key identifier

The following example is a shape illustration, not a pasteable valid receipt. Real receipts must contain the exact frozen method text, complete claims and limitations, real manifest artifact IDs, a real manifest digest, and a real signature.

{
  "receipt_version": "witnessops.receipt.v0",
  "receipt_profile": "witnessops.verification_context.v1",
  "workflow_class": "public_exposure_review",
  "proof_run_id": "pr_per_<24-lowercase-hex>",
  "verification_context": {
    "subject": {
      "type": "public_facing_system",
      "reference": "urn:witnessops:public-exposure-review:<proof-run-id>"
    },
    "scope": {
      "included": ["declared included scope"],
      "criteria": ["declared review criteria"],
      "excluded": ["declared exclusions"],
      "observation_window": {
        "started_at": "<UTC timestamp>",
        "ended_at": "<UTC timestamp>"
      }
    },
    "verification_method": {
      "id": "external_exposure_assessment",
      "version": "2.0.0",
      "procedure": ["<exact frozen procedure>"],
      "pass_criteria": ["<exact frozen pass criteria>"],
      "fail_criteria": ["<exact frozen fail criteria>"]
    },
    "timestamps": {
      "performed_at": "<UTC timestamp>",
      "issued_at": "<UTC timestamp>",
      "expires_at": null
    },
    "limitations": ["<all required limitation codes>"]
  },
  "result": {
    "outcome": "inconclusive",
    "failure_states": ["<named unresolved state>"]
  },
  "claims": [
    {
      "claim": "offer_contract_applied",
      "status": "inconclusive",
      "evidence_refs": ["offsec_<24-lowercase-hex>"]
    }
  ],
  "manifest_hash": "sha256:<64-lowercase-hex>",
  "signature": {
    "algorithm": "ed25519",
    "public_key_id": "<registry-key-id>",
    "encoding": "hex",
    "signature": "<128-lowercase-hex>"
  }
}

Receipt outcomes are exactly pass, partial, fail, or inconclusive. blocked is an operational workflow state and is not a receipt outcome. The bounded review outcome is separate from the verifier verdict: even a receipt whose review outcome is pass remains publicly indeterminate while required evidence, execution, signature, or trust checks are incomplete.

3. Workflow context and claims

The profile binds the receipt to one product workflow, not to a generic verification offer.

The subject must be a public_facing_system. The subject reference must be derived from the proof-run ID. Scope must preserve included items, review criteria, exclusions, and a UTC observation window.

The method is frozen as external_exposure_assessment version 2.0.0. The public adapter compares the complete procedure, pass criteria, and fail criteria with its server-owned contract snapshot. Request input cannot replace that contract.

Every receipt must contain each of these six claims exactly once:

  1. offer_contract_applied
  2. authority_and_scope_recorded
  3. recorded_checks_within_approved_schedule
  4. findings_reference_evidence
  5. unknowns_and_limitations_preserved
  6. source_artifacts_hash_bound

Each claim must reference at least one real OffSec manifest artifact ID in the form offsec_<24 lowercase hex>. The bounded producer adapter precomputes each staged source artifact's exact future manifest ID; the proof engine later emits that ID from the extensionless staged filename. Synthetic labels or invented path names are not acceptable substitutes.

The public receipt-only adapter checks identifier syntax and claim membership. It does not receive the manifest entry or artifact bytes, so it cannot establish that a reference resolves or supports the claim.

4. Required limitations

The profile preserves these eight product non-claims:

  1. not_a_penetration_test
  2. not_a_certification
  3. not_an_attestation
  4. not_a_compliance_determination
  5. not_proof_of_security
  6. not_proof_of_completeness
  7. not_proof_of_third_party_acceptance
  8. not_proof_of_absence_of_vulnerabilities

Additional limitations may be present. Removing or weakening any required limitation makes the profiled receipt invalid.

5. Time, manifest, and signature fields

All timestamps are UTC RFC 3339 values. The required chronology is:

started_at <= ended_at <= performed_at <= issued_at < expires_at

expires_at may be null. The public adapter checks syntax and chronology only; it does not supply an independent time source.

manifest_hash must declare a lowercase SHA-256 digest. The receipt-only adapter checks that syntax but does not receive or hash manifest bytes.

The signature block must declare Ed25519, a canonical key identifier, lowercase hexadecimal encoding, and a 64-byte signature. The public adapter checks that shape. It does not verify the signature cryptographically while no server-owned active production key is authorized.

6. Production key acceptance

The current public_exposure_review trust snapshot is deliberately non-authorizing:

  • workflow acceptance policy public_exposure_review.production.v1 is draft, with no trusted revision, policy hash, or registry-manifest hash pinned
  • key-trust policy public_exposure_review.production_signing.v1 is draft, with no trusted registry revision or manifest hash pinned
  • the registry status is draft
  • no production public-key IDs are allowlisted
  • the production custody-approval reference is unset

Production acceptance requires server-owned policy and registry snapshots, not caller-supplied trust material. Before a receipt can be accepted as production-valid:

  1. the workflow acceptance policy must be active and pin the exact key-policy bytes, trusted registry revision, and registry-manifest SHA-256
  2. the key-trust policy and registry must be active and their revision and manifest pins must agree with the verifier snapshot
  3. the signer must be explicitly allowlisted with an active key record using Ed25519, hexadecimal encoding, production trust scope, and usage public_exposure_review_receipt_signing
  4. verification_context.timestamps.issued_at must be on or after valid_from and before valid_until
  5. the production custody-approval reference must be recorded
  6. revocation must be null and propagation rules must confirm that the verifier snapshot matches the approved current pins

Missing, stale, unavailable, or unconfirmed required trust input is indeterminate. A cryptographic mismatch, known revoked or disallowed key, trust-scope or usage mismatch, or signature outside the accepted validity window is invalid once those checks are actually performed. A rotated key without an applicable historical policy is unsupported under the draft key policy.

7. Public verification result

For a structurally conforming public_exposure_review receipt, /verify currently reports indeterminate, with scope: receipt-only and artifactRevalidation: not_performed.

The adapter checks:

  • exact envelope, version, profile, workflow class, and proof-run ID shape
  • bounded result and failure-state shape
  • exact required claim set and manifest artifact-ID syntax
  • subject and declared scope syntax
  • exact frozen verification method
  • preservation of the eight required limitations
  • timestamp syntax and chronology
  • manifest-digest syntax
  • signature-block syntax

It does not independently check:

  • the originating request record
  • authority packet, frozen target schedule, or approved-check schedule
  • complete workflow execution records
  • whether the frozen verification method was actually executed
  • the manifest bytes or their digest
  • artifact bytes or per-artifact hashes
  • whether referenced evidence supports each claim
  • the Ed25519 signature against an active production key
  • production key authorization and revocation state

Caller-supplied evidence, keys, registries, policies, or verifier results are rejected rather than promoted to server trust inputs.

8. What the receipt can and cannot establish

Receipt shape validation establishes that the submitted JSON conforms to the declared profile. It does not establish issuance, evidence truth, signer authorization, scope authorization, or complete execution.

When a full package is independently verified against authentic, active trust inputs, stronger conclusions may be possible about signature integrity, manifest and artifact consistency, workflow evidence, and claim support. That is a separate internal package-verification path; the canonical internal verifier is not a supported public distribution today.

A receipt never proves that the reviewed system is secure, that a finding is correct, that no vulnerability exists, or that the engagement is complete beyond its declared scope and evidence.

9. Next-page handoff

Read How to Verify a Receipt for the public procedure and exact verdict boundaries.

Then continue with:

Receipt Specification | WitnessOps