Skip to main content
Facets are distributed artifacts. Consumers need confidence that what they install is what was published — no tampering, no corruption, no substitution. This page defines how artifacts are hashed and when hashes are verified. Two distinct integrity concerns are addressed:
  1. Content integrity — does the artifact match what was published? MUST be verified at download, on every cache hit, and at lockfile-entry creation.
  2. Cache integrity — has cached content been tampered with since it was written? MUST be verified on every materialization from cache.

Content hashing

What it covers

Facet archives — anything published to the facets registry — participate in the full hashing lifecycle below. Git and local sources are built from source rather than downloaded, so they participate through the lockfile-integrity checks described in Git and frozen variants rather than through registry hashes.

Two hashes, two domains

The registry publishes two hashes for each version, serving different purposes:
  • content_integrity (canonical fingerprint) — SHA-256 of the canonical uncompressed inner tar archive. This is the domain the lockfile, cache sidecar, and build manifest all record. It is the trust anchor for integrity confirmation and lockfile comparison. Alongside it, the build manifest records a per-entry hash for every inner-tar entryfacet.json, each primary asset, and each supplementary file — and verification recomputes every one. Integrity therefore covers every file the archive ships, asset or not, including archive-only files like README.md.
  • content_hash (transport hash) — SHA-256 of the uploaded .facet tarball (the gzipped delivery bytes). Used only at download time for a raw-bytes transport check. Never persisted to the lockfile.
These are not interchangeable: gzip is a delivery concern outside the hash contract. The canonical fingerprint cannot be recomputed from the transport bytes without decompressing first.

Format

sha256:<hex-encoded hash> (e.g., sha256:a1b2c3d4e5f6...)

When it is applied

1

Build & publish

The author’s CLI assembles the archive and computes the canonical fingerprint at build time. At publish, the registry verifies the upload and records both hashes — no part of the archive is re-derived from trust.
2

Download

The transport hash (content_hash) MUST be verified against the raw downloaded bytes.
3

Post-extract recompute

The canonical fingerprint MUST be genuinely recomputed from the extracted content (per-entry hashes + canonical-archive hash) — never taken from the build manifest’s self-declared claim — and MUST match both the manifest’s claim and the registry’s published content_integrity. An unsupported facetVersion produces a structured failure carrying the observed and supported versions, which the CLI renders as upgrade guidance.
4

Cache write

The canonical fingerprint (content_integrity) and per-entry hashes are written to a sidecar alongside the cached content.
5

Cache hit

The cached content MUST be re-hashed against its sidecar (self-audit). Tampered content MUST be evicted and re-fetched.
6

Lockfile comparison

When the lockfile pins a version, the audited integrity MUST equal the locked integrity. On reproduction — when the facet resolves to the integrity already locked — install additionally reconciles the recomputed archive-entry hash against each lockfile per-file record and the verified build-manifest hash before any file is written; a mismatch fails with the exact drifting path. A legitimate change resolves to a different integrity and has nothing to reconcile against.
7

Integrity confirmation

When a lockfile entry is being created or replaced, the audited integrity MUST match the registry’s published content_integrity. An unreachable registry MUST fail the operation.
8

Lockfile record

The canonical fingerprint is recorded for reproducible verification.
Two variants sit outside this lifecycle, and they are distinct checks rather than one: git installs MUST verify built content against the lockfile integrity (the one-check reproduction guard), and frozen installs MUST require every facet — including local sources — to reproduce its locked integrity. Each reports under its own check label, so a frozen local-source failure is never mislabeled as a git failure. The pipeline mechanics for all of these live in Commit — Verify.
Integrity is entirely authored-domain and, in fact, name-agnostic. Archive paths and every hash derive from the name the publisher declared, so aliasing an asset changes nothing here — and an alias can never be used to smuggle different content under a familiar name. An omitted asset is fully verified too: verification covers the resolved set, not the subset written to disk.

What it guarantees

  • Transit integrity: the downloaded bytes match what the registry stored (transport hash).
  • At-rest integrity: cached content is verified on every use, not just at write time (cache self-audit).
  • Lockfile trust: a lockfile entry for a registry facet MUST NOT be created without same-operation registry confirmation of its canonical fingerprint.
  • Immutability enforcement: the registry’s invariant that a published name@version never changes is enforced client-side via the lockfile comparison and integrity confirmation.

Where hashes live

Lockfile

Canonical fingerprint (content_integrity) per facet, plus a { path, integrity } record per authored file inside each asset entry — present even for an omitted asset, which materializes nothing.

Cache sidecar

Canonical fingerprint + per-entry hash map (cache-integrity.json) per cache slot. Written at cache-populate time; re-verified on every cache hit.

Build manifest

Canonical fingerprint + complete files hash map (one entry per inner-tar file). Embedded in the .facet archive.

Install receipt

Per-asset authored identity, owned authored paths, and the disposition each asset was materialized under (not hashes — used for offline drift removal). Omitted assets never appear.