Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Execution Envelope

The ExecutionEnvelope is Palimpsest’s critical abstraction. It seals every input that affects a fetch — seed, timestamp, target URL, DNS state, TLS fingerprint, browser config, and custom headers — into an immutable record constructed before the fetch begins.

Without the envelope, you cannot replay a fetch, verify its output, or prove it was executed correctly.

Construction

Envelopes are built via the fluent EnvelopeBuilder:

#![allow(unused)]
fn main() {
let envelope = EnvelopeBuilder::new()
    .seed(CrawlSeed::new(42))
    .timestamp(CaptureInstant::new(wall_time, logical_clock))
    .target_url(Url::parse("https://example.com/").unwrap())
    .dns_snapshot(DnsSnapshot {
        host: "example.com".into(),
        addrs: vec!["93.184.216.34".into()],
        ttl: 300,
    })
    .tls_fingerprint(TlsFingerprint {
        protocol: "TLSv1.3".into(),
        cipher: "TLS_AES_256_GCM_SHA384".into(),
        cert_chain_hash: "blake3:...".into(),
    })
    .header("User-Agent".into(), "PalimpsestBot/0.1".into())
    .build()?;
}

Required Fields

FieldTypePurpose
seedCrawlSeedDeterministic randomness source
timestampCaptureInstantWall clock + logical clock
target_urlUrlThe URL being fetched
dns_snapshotDnsSnapshotRecorded DNS resolution state

Calling .build() without any required field returns an EnvelopeError.

Optional Fields

FieldTypePurpose
tls_fingerprintTlsFingerprintTLS protocol, cipher, cert chain hash
browser_configBrowserConfigViewport, user agent, JS enabled
request_headersVec<(String, String)>Custom HTTP headers

Immutability

Once build() succeeds, the ExecutionEnvelope is frozen. There are no setter methods — only getters:

#![allow(unused)]
fn main() {
envelope.seed()             // CrawlSeed
envelope.timestamp()        // CaptureInstant
envelope.target_url()       // &Url
envelope.request_headers()  // &[(String, String)]
envelope.dns_snapshot()     // &DnsSnapshot
envelope.tls_fingerprint()  // Option<&TlsFingerprint>
envelope.browser_config()   // Option<&BrowserConfig>
envelope.content_hash()     // ContentHash (computed from canonical JSON)
}

Content Hash

The envelope’s content_hash() is computed from its canonical JSON serialization. This means two envelopes with identical fields produce the same hash, and any field change produces a different hash.

WARC++ Envelope Record

The envelope is serialized as the first record in every WARC++ capture group:

WARC/1.1
WARC-Type: envelope
Palimpsest-Envelope-Version: 1
Content-Type: application/json

{
  "seed": 42,
  "timestamp": {"wall": "2026-04-12T10:30:00Z", "logical": 1234},
  "target_url": "https://example.com/",
  "dns_snapshot": {"host": "example.com", "addrs": ["93.184.216.34"], "ttl": 300},
  "tls_fingerprint": {"protocol": "TLSv1.3", "cipher": "...", "cert_chain_hash": "..."},
  "browser_config": null
}