Files
paperspec/context/README.md
T
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

10 KiB

JSON-LD context

Three readers use this page. A newcomer, such as a student who has not met these formats, can read it from the top. Each term is defined where it first appears, and the example comes from the fixtures. An implementer who is writing a reader, writer, converter or checker will find the exact behavior, the defining chapter, the files that pin it, and the traps in "Using the context". An expert who knows the neighboring standards will find the status of the formats and a short comparison in "Status and comparison".

What the context is

Annotations are notes attached to a passage of a paper, such as a plain-language explanation of a term or a question for a study group. Annotation layers store them as JSON, a text format for structured data, one annotation per line. A shared standard, the World Wide Web Consortium (W3C) Web Annotation Data Model, says what an annotation contains: a body (the note), a target (what it is about) and a selector (how to find the passage inside the target).

JSON-LD is JSON plus a rule that gives every field name a global meaning, written as an IRI (an identifier shaped like a web address). The rule lives in a context, a file that maps short field names to IRIs. Two tools that read the same context agree on what target or status means, even if they know nothing else about each other.

scienting-1.jsonld is the context that makes every annotation layer valid JSON-LD, together with the W3C Web Annotation context. The Web Annotation context supplies Annotation, body, target and selector. This one supplies the terms the formats add. Its address is https://paperspec.scient.ing/context/scienting-1.jsonld, which is this file as the project's website serves it, with the media type application/ld+json and a header that lets a browser fetch it from any page. The terms it maps are listed at https://paperspec.scient.ing/vocab, and each term's IRI is a fragment of that page. A processor that cannot reach the site loads the copy in this folder in its place. Every layer and every annotation lists both contexts, Web Annotation first:

{"@context": ["http://www.w3.org/ns/anno.jsonld", "https://paperspec.scient.ing/context/scienting-1.jsonld"]}

The scienting- prefix is the formats' namespace, as in scienting-layer/1 and scienting-anchor/1. The repository's name, paperspec, is a separate matter.

An example from the fixtures

fixtures/records/layer/annotations.jsonl holds nine annotations on the example paper hale2026harmonic-damb. The first is a gloss, an explanation for a novice, of the phrase "bond force constant". Shortened, it reads:

{"@context": ["http://www.w3.org/ns/anno.jsonld", "https://paperspec.scient.ing/context/scienting-1.jsonld"],
 "type": "Annotation", "motivation": "describing", "status": "confirmed",
 "body": {"type": "TextualBody", "kind": "gloss", "audience": "novice",
          "value": "A *harmonic* term treats a bond like a spring: ..."},
 "target": {"type": "SpecificResource",
            "source": "tag:scient.ing,2026:doc:smithlab/hale2026harmonic-damb",
            "selector": [
              {"type": "AnchorSelector",
               "anchor": {"format": "scienting-anchor/1", "node": "rr20tev",
                          "span": [111, 130], "quote": {"exact": "bond force constant", "...": "..."}, "...": "..."}},
              {"type": "TextQuoteSelector", "exact": "bond force constant",
               "prefix": "rm{eq}})^2$$ where $K_r$ is the ", "suffix": " and $r_\\mathrm{eq}$ the equilib"}]}}

The Web Annotation context defines type, motivation, body, target, source, selector, exact, prefix and suffix. This context defines kind, status, audience, AnchorSelector and anchor.

What it defines

The file defines 23 terms. Twenty-two map to IRIs under https://paperspec.scient.ing/vocab#: format, kind, status, receipt, layer, audience, visibility, purpose, project, docs, pin, role, symbol, verdict, reason, reference, for, generator, exercise, anchor, rights_use and the class AnchorSelector. Three are renamed: for is sct:questionFor, generator is sct:generatedBy, and rights_use is sct:rightsUse. The twenty-third, total, maps to totalItems in the ActivityStreams namespace. Two terms carry a type rule. A processor reads layer as an IRI, and it always reads docs as a set, so a one-element list stays a list.

The file declares anchor and exercise as JSON literals ("@type": "@json", a JSON-LD 1.1 feature, which is why the file sets "@version": 1.1). A JSON-LD processor then keeps a scienting-anchor/1 record intact instead of expanding it. An anchor holds hashes (fixed-length fingerprints of text) and a span, a pair of character offsets whose order carries meaning. Expansion would drop the anchor's unmapped field names (JSON-LD 1.1 API, expansion step 13.3) and would give its arrays no order (JSON-LD 1.1 §4.3).

The anchor selector and its fallback

A selector says how to find a passage inside a source. The standard selectors work from the passage's text or its position. TextQuoteSelector holds the quoted text (exact, required) and optionally some text before and after it (prefix, suffix). TextPositionSelector holds start and end offsets, which the model itself calls "very brittle with regards to changes to the resource" (Web Annotation Data Model).

AnchorSelector is the custom selector of these formats. It carries a scienting-anchor/1 record: the document key, the node ID, the node's own_hash and node_hash as they were when the anchor was made, an optional span in Unicode code points, a quote, and the document revision rev (spec/06 §6.2). A reader can use the hashes to resolve the anchor against a corrected document and report one of five outcomes: current, changed-below, moved, reattached or stale (spec/06 §6.5). A standard selector cannot do that.

A tool that does not know AnchorSelector cannot use it. An annotation's selector list puts the AnchorSelector first and, where the anchor has a quote, a standard TextQuoteSelector after it, for tools that do not know ours (spec/18 §18.3). The formats use no TextPositionSelector and no FragmentSelector. Such a tool still reads the annotation's body and its TextQuoteSelector; the context matters only to tools that process the data as linked data. That is the repository's statement; no Web Annotation client has been tested against these files.

The fallback is not always there. Three of the nine fixture annotations have only an AnchorSelector (the section-level question, the generated annotation on a figure and the exercise on a table), because the anchor points at a container and has no quote.

Using the context

  • Writer: Put both URLs (web addresses), in the order shown, in @context of layer.json and of every line of annotations.jsonl. Chapter 18 defines layers (§18.2), annotations (§18.3) and bodies (§18.4).
  • Reader: Follow chapter 6 to resolve an anchor. The file vectors/resolve.jsonl resolves seventeen anchors against fixtures/packages/hale2026harmonic-damb and gives every outcome.
  • JSON-LD processor: Use a JSON-LD 1.1 processor; the context relies on @json and @version 1.1.
  • Checker: schemas/annotation.schema.json and schemas/layer.schema.json validate the files. tools/check.py also checks that each annotation's ID derives from its content and that the receipt at fixtures/records/layer/receipt.json covers each confirmed annotation.

The traps:

  • No test vector pins the context, and nothing in tools/ reads scienting-1.jsonld. The schemas require only that @context be an array of at least two non-empty strings; they do not check the URLs. A file with a wrong context can pass the checker and still expand wrongly.
  • @context is part of an annotation's content hash (the hash covers everything except status, receipt and modified). Rewriting or reordering the array changes the hash that a receipt covers.
  • format is one term for two jobs: the layer's format (scienting-layer/1) and a text body's format (text/markdown). The scienting context maps it to sct:format. The Web Annotation context maps format to dc:format and protects none of its terms, and in an array of contexts the later definition wins (JSON-LD 1.1 §4.1), so listing this context second makes format mean sct:format.
  • A consumer that does not use a field must still preserve it when it rewrites a file. A tool that rewrites layers must not drop the scienting terms (spec/00 §0.4).
  • The TextQuoteSelector repeats the anchor's plain quotation, and is left out when the quote is hashed (over 200 code points) or keyed (spec/18 §18.3), so a public layer never shows text that a keyed anchor withholds.

Status and comparison

The specification is version 0.1.0. scienting-layer/1, scienting-anchor/1 and scienting-exercise/1 are candidate in registry/formats.json. The specification defines candidate as "Complete, with vectors and fixtures, and ready to implement." The context file is normative (spec/00 §0.5).

The W3C Web Annotation Data Model is a 2017 W3C Recommendation and the general standard for annotating web resources, with existing clients that form an ecosystem these formats do not have (Web Annotation Data Model). Its standard selectors carry no content hash of the target text and define no outcomes such as moved or stale. Its remedy for a changing resource is to record a state of the whole resource. Hypothesis stores a quote selector with 32 characters of context and reattaches by fuzzy matching (Hypothesis, fuzzy anchoring, 2013). These formats store a hash pin and define the outcomes exactly. The full comparison is in docs/comparison.md.

Chapter 18 defines layers and annotations.