# exhibit402 System Description

Version: 1.0
Date: 2026-07-30
Stable URL: https://exhibit402.dylan-caponi.workers.dev/system-description.md

This document describes the automated process that produces every exhibit402
certificate. It exists so that a certification under Federal Rules of
Evidence 902(13) or 902(14) has a concrete, versioned process description to
incorporate by reference. Every certificate manifest records this document's
version and SHA-256, so the exact text in force at capture time is
identifiable forever. This document is a technical description, not legal
advice.

## 1. What the service does

exhibit402 produces evidence of what a public URL served at a specific
moment. Two independently hosted, byte-identical browser environments (the
"observers") load the URL at the same frozen timestamp and each takes a
screenshot. The screenshots' SHA-256 digests decide the certificate tier:

- **CERTIFIED**: both observers produced byte-identical PNGs. Two machines
  on different networks, run by different hosting companies, agreed on every
  pixel.
- **WITNESSED**: the observers' PNGs differ after one retry round. The
  certificate then includes the pixel agreement percentage, the bounding box
  and row bands of the differing regions, and a visual diff map. WITNESSED
  is honest evidence that the page varies between visitors; it is a
  deliverable, not a failure.

The tier is decided by screenshot bytes alone. No other collected material
participates in the tier decision.

Artifacts (canonical screenshot, per-observer serving evidence, diff map
when WITNESSED, and the certificate manifest) are stored permanently on
Arweave via Irys. For x402 (crypto) purchases, an ERC-721 certificate is
minted on Base to the paying wallet; the token URI points at the manifest
and the contract (`0xd580927e7ece44d4b93af617a37f3f3da3f02d8c`) has no
setter, burn, or upgrade path, so the reference can never be changed. Card
purchases receive the same permanent Arweave record and no token.

## 2. The observer fleet

Two observers run the same container image, pinned by digest:

- Google Cloud Run, region us-west2, egress AS396982 (Google)
- Fly.io, region lax, egress AS60068 (Datacamp)

Both are geolocated in the Los Angeles metro. Same-metro placement is
deliberate: cross-metro observers are geolocated differently by target
sites and disagree about pages that personalize by location, which would
produce false WITNESSED results.

The container base image is `mcr.microsoft.com/playwright:v1.62.0-noble`,
pinned by digest
`sha256:baed2032d533817f3dbe6425de795788430ba345e819a1201337009ba17c9d07`,
so a repointed tag can never silently change the software under a
certificate. The built capture-box image id for this document version is
recorded in section 9; it is reported by every observer on every capture and
recorded in every manifest as `capture_box_image_id`. A capture where the
two observers report different image ids is refused and refunded.

## 3. Frozen browser configuration

Captures run Chromium under Playwright with a configuration chosen to make
rendering deterministic across machines. Each flag exists for a reason:

- `--disable-gpu` and `--force-color-profile=srgb`: software rasterization
  only; GPU paths and color profiles differ between hosts.
- `--disable-lcd-text`, `--font-render-hinting=none`,
  `--disable-font-subpixel-positioning`: font rendering must not depend on
  display configuration.
- `--hide-scrollbars`, `--disable-partial-raster`,
  `--disable-skia-runtime-opts`: remove rasterization variance sources.
- `--js-flags=--random-seed=1157259157`: page JavaScript calling
  Math.random() gets the same sequence on both observers.
- Viewport 1280x800, device scale factor 1, locale en-US, timezone UTC,
  light color scheme, reduced motion.
- The page clock is frozen to the agreed `fixed_time` (Playwright
  clock.setFixedTime), so "3 minutes ago" style rendered text is identical
  on both observers. Real timers keep running so pages load normally.
- A fixed list of advertising and tracking hosts is blocked identically on
  every observer (ads are the top source of per-visit pixel variance), and
  reCAPTCHA badge resources are blocked because the badge rotates its icon.
  The list is part of the frozen configuration.
- The declared User-Agent is a realistic Chrome UA plus an honest tool tag
  identifying automated capture.

Capture sequence: navigate and wait for network idle (45s limit; pages that
never go idle are recorded as timed out and are not certified), a fixed 3s
settle, then in fullpage mode a fixed-step scroll to the bottom (800px
steps, at most 40, so infinite-scroll pages terminate) and back to top to
force lazy-loaded content in, then wait for all declared webfonts and two
requestAnimationFrame turns so the compositor has produced the final
layout, then screenshot with animations disabled and the caret hidden.
Fullpage captures above 60,000px of page height are clipped to that cap and
the certificate says so (`height_capped`). Viewport mode captures only the
first 1280x800 screen and skips the scroll.

## 4. Warmup: why cold captures are refused

A box's first Chromium run after boot builds the fontconfig cache, and
captures taken before that differ subtly from every later capture (measured
at 99.8153% pixel agreement on an unchanged page, all of it font
rasterization). Each observer therefore completes a throwaway warmup
capture before it opens its service port, and reports `warm` on every
response. The orchestrator refuses to certify any capture from an observer
reporting itself cold; that consumes a retry round instead, and a second
cold round fails the job with a full refund.

## 5. SSRF guard

Observers refuse to capture private, internal, or unresolvable addresses.
The guard runs before payment (in the orchestrator), again on the observer
before the browser launches, and again inside the browser on every request
the page makes, including redirect hops and subresources. A hostname that
fails to resolve counts as private (fail closed). This exists so the
service can never be used to attest to, or probe, anything not publicly
served.

## 6. Hashing and identification

All digests are SHA-256. The canonical screenshot is observer A's (Google
Cloud, listed first in the manifest) in both tiers. The manifest records,
for each artifact: the Arweave transaction id (`ar://` URI), the SHA-256 of
the exact bytes, and an IPFS CIDv1 (raw codec, computed locally as a second
content address; the bytes are not separately uploaded to IPFS). The minted
token stores the canonical screenshot digest on chain, so the chain, the
manifest, and the bytes cross-verify.

## 7. Serving evidence (manifest version 2)

A screenshot proves what a browser drew. To evidence what the domain
actually served, each observer also records, immediately AFTER its
screenshot is written so the rendered bytes cannot change:

- the final URL and the full redirect chain (each hop's status and
  Location header)
- the HTTP status and complete response headers of the main document
- the TLS certificate chain actually presented at a fresh handshake with
  correct SNI: subject, issuer, validity window, serial, SHA-256
  fingerprint, and PEM of every chain certificate
- DNS A and AAAA answers for the final host, and the IP the browser
  actually connected to
- the DOM serialization at capture time (capped at 5MB; the full DOM's
  SHA-256 is always recorded, so a truncated copy remains verifiable)

Each observer's evidence is stored permanently as its own artifact and
referenced from the manifest (`evidence_ar_tx`, `evidence_sha256`) per
observer. Evidence is intentionally NOT compared between observers and
never affects the tier: header order, timing fields, and load-balanced
addresses legitimately differ between two independent clients.

## 8. Independent trusted time

Each certificate requests an RFC 3161 timestamp token over the canonical
screenshot's SHA-256 from an accredited time-stamping authority (currently
freetsa.org). The token is embedded in the manifest
(`rfc3161_timestamp.token_b64`, DER, base64). Anyone can verify it with
OpenSSL and the TSA's published certificate chain, using nothing produced
by exhibit402:

    # token.der = base64-decoded token_b64 from the manifest
    openssl ts -verify -digest <canonical screenshot sha256> \
      -in token.der -token_in -CAfile <TSA CA certificate>

For freetsa.org the CA certificate is published at
https://freetsa.org/files/cacert.pem. The token is requested over the
capture digest, never over the manifest's own hash (which would be
circular: the token lives inside the manifest). A TSA outage does not block
a certificate; the manifest simply omits the token, and the mint block
timestamp remains as coarser time evidence.

## 9. Software identity for this document version

- Capture-box image id (identical across both observers, asserted on every
  capture): `sha256:17275ad26c798b0ec5e447155d9bf8d3359e404f32f8d1787ed262f1bf8318da`
- Capture-box source: github.com/dylancaponi/capture-poc, commit
  `6e261b60c89d2cde734ff1a0be17a376363c4869`
- Orchestrator source: private repository (x402/exhibit402), code commit
  `cd4162fdfaccc544550a6ab98d527969695c9420` (this document is finalized in
  the immediately following commit of the same repository)
- Contract: `Exhibit402.sol` (OpenZeppelin v5.5.0, Foundry), deployed at
  `0xd580927e7ece44d4b93af617a37f3f3da3f02d8c` on Base (chain id 8453),
  source verified on Blockscout. The test suite asserts by ABI that no
  setter, burn, or upgrade selector exists.

## 10. Retention

- Arweave artifacts (screenshots, evidence, diff maps, manifests): stored
  permanently by design; this is the certificate of record.
- Working copies (orchestrator object storage) and job records: retained
  indefinitely at present. Job records duplicate each certificate's
  manifest and are potential evidence in their own right; a published
  retention schedule, when adopted, will appear in a new version of this
  document rather than being applied silently.
- Rejected captures (content screen, oversize): all captured bytes are
  deleted at rejection time; nothing is stored permanently, and the refund
  policy disclosed in the quote applies.

## 11. Verifying a certificate end to end

1. Fetch the manifest from its `ar://` transaction (any Arweave gateway).
2. Hash the screenshot bytes from their `ar://` transaction; compare to
   `canonical_screenshot.sha256` in the manifest and to the digest stored
   on chain in the token's `Certified` event.
3. Check each observer's `evidence_sha256` against the evidence artifact's
   bytes.
4. Verify `rfc3161_timestamp.token_b64` with the OpenSSL command in
   section 8.
5. Hash this document as served at the stable URL above; compare to
   `system_description.sha256` in the manifest to confirm which process
   version produced the certificate.
