Files
paperspec/deploy
alexmandClaude a09d158e16 feat: minted keys, VRF seeds, RFC 9162 proofs, history roots, tag URIs and a transparency log
Keys (spec/02 §2.4), the rule paperstack settled on:
- A work key is a Scholar-style citation key, a hyphen and the first four
  Crockford base32 characters of SHA-256("scienting-key/1:" + identity),
  where the identity is the first of doi, arxiv, isbn, pmid, pmcid and
  openalex in same_as, else the folded title, year and family name. A
  collision lengthens the later key by two characters; a key is minted
  once and never recomputed. A document key adds .si, .v<seq> or .<type>
  for versions other than the version of record.
- Every fixture key is now minted (hale2026harmonic-damb,
  okafor2025solvent-acth, writer2027fixed-ynr7.v3, tiny2026tiny-j4qm), so
  every node and record ID was re-minted and the docs rewritten to match.
  The validator checks the document key against the work key and version
  (doc.key.work) and the hash part against the identifier (doc.key.suffix).
  vectors/keys.jsonl pins the cases paperstack's tests pin.

Review:
- Spot-check seeds are ECVRF-EDWARDS25519-SHA512-TAI proofs (RFC 9381),
  implemented in tools/oracle/vrf.py in plain Python and reproduced
  against the RFC's Example 16; the sample ranks by the VRF output. The
  earlier Ed25519 seed could be ground by a dishonest checker.
- RFC 9162 inclusion and consistency proofs (crypto.inclusion_path,
  verify_inclusion, consistency_proof, verify_consistency) with
  scienting-proof/1, vectors/proofs.jsonl and two fixture records.
- document.json carries `history`, the root over the corrections, with
  the empty-tree hash for none (spec/11 §11.5, rule doc.history).
- A provisional transparency log (spec/23): log entries, signed-note
  checkpoints with key hashes as transparency logs share them, the rule
  that a logged revocation beats a self-asserted time, and vectors.
- Reserved signature schemes cose and ml-dsa-65 (spec/08 §8.4).

Identifiers and text:
- urn:scienting: becomes tag:scient.ing,2026: (RFC 4151), since the URN
  namespace was never registered.
- Unicode 16.0 is pinned for normalization and categories (spec/01 §1.4);
  the checker refuses another version.

Checking:
- check.py: keys, proofs, VRF and checkpoint vectors; the proof and
  checkpoint records; a check that every ID and hash the prose quotes
  exists in the fixtures or vectors; three more broken packages
  (history-wrong, key-suffix, key-work).
- stress.py: key, VRF, proof and checkpoint properties.
- Docs: a keys section in the concepts and FAQ, rationale entries for
  keys, VRF, proofs, tag URIs and the Unicode pin, a "Looking ahead"
  section, media-type registration and OCI distribution notes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-14 23:21:57 -04:00
..

Deploying the website

This folder holds what it takes to serve the paperspec website at https://paperspec.scient.ing. The site is static: tools/site.py builds it into _site/, and any web server can serve that folder.

What the site serves

The site mirrors the repository, so a file at schemas/anchor.schema.json in the repository is served at https://paperspec.scient.ing/schemas/anchor.schema.json. Three addresses that the formats themselves name depend on that:

Address What is there
https://paperspec.scient.ing/schemas/<file> Each JSON Schema, at the address in its $id.
https://paperspec.scient.ing/context/scienting-1.jsonld The JSON-LD context every layer and annotation lists.
https://paperspec.scient.ing/vocab The vocabulary page, whose fragments are the IRIs of the context's terms.

Beside every Markdown file the builder writes a rendered page: README.md becomes its folder's index.html, and X.md becomes X.html. A folder without a README gets a listing page, so every fixture and vector can be browsed. The pages need no server-side code; search runs in the browser over a small index of headings, search.json.

Build it

pixi run python tools/site.py           # writes _site/
pixi run python tools/site.py --out /tmp/paperspec-site

pixi run check builds the site into a temporary folder and checks that every Markdown file has a page, that every internal link and fragment resolves, that no Markdown is left unrendered, and that each schema's $id, the context's address and the vocabulary's IRIs are files of the site.

To look at it locally, serve the folder with any static server, for example:

pixi run python -m http.server --directory _site 8000

Serve it with Caddy

Caddyfile serves /srv/paperspec at paperspec.scient.ing. It sets the media types the data needs (application/ld+json for the context, application/schema+json for schemas, application/jsonl for vectors and package files), allows every file to be fetched from any origin, and serves 404.html for missing paths. Add it to the server's Caddy configuration, for example with an import line, and reload Caddy.

Publish from CI

The workflow .gitea/workflows/site.yml builds the site on every push to main, and publishes it with rsync over SSH when four repository secrets are set:

Secret Holds
SITE_HOST The server's host name.
SITE_USER The account that owns the site folder.
SITE_PATH The folder Caddy serves, such as /srv/paperspec.
SITE_SSH_KEY A private SSH key whose public half is in that account's authorized_keys, and that can do nothing else.

Without SITE_HOST the workflow still builds and checks the site, and says that it did not publish.

Distributing packages

A zipped package is an ordinary file, and the site serves the fixtures as such. For a team's own packages, the Gitea instance speaks the OCI distribution protocol, so packages can be pushed to and pulled from its package registry as OCI artifacts with ORAS, and signed there with cosign; the media type of the artifact is the package's, application/vnd.scienting.doc+zip. Nothing in the formats depends on how packages travel.