- Rename manuspec to paperspec everywhere outside pixi.toml: prose, the tools, provenance tool names and the fixture key derivations, so every fixture and vector is rebuilt. - Move the namespace addresses under the site, mirroring the repository: schema $id https://paperspec.scient.ing/schemas/<file>, the JSON-LD context https://paperspec.scient.ing/context/scienting-1.jsonld, and term IRIs https://paperspec.scient.ing/vocab#<term>. Format identifiers (scienting-*) and URNs (urn:scienting:) are unchanged. - tools/site.py (standard library only) builds _site/: every file of the repository at its own path, each Markdown file rendered as a page with sidebar navigation, heading anchors matching the forge's, folder listings, a vocabulary page for the context's IRIs, a heading search and a 404 page; light and dark themes. - check.py builds the site and checks that every Markdown file has a page, every internal link and fragment resolves, no Markdown is left unrendered, and every $id, the context address and the vocabulary IRIs are files of the site. - deploy/: a Caddyfile with the media types and CORS the data needs, and a guide; .gitea/workflows/site.yml builds on main and publishes with rsync when the SITE_* secrets are set. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
130 lines
10 KiB
Markdown
130 lines
10 KiB
Markdown
# 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](https://www.w3.org/TR/annotation-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:
|
|
|
|
```json
|
|
{"@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`](../fixtures/records/layer/annotations.jsonl) holds nine annotations on the example paper `hale2026harmonic`.
|
|
The first is a `gloss`, an explanation for a novice, of the phrase "bond force constant".
|
|
Shortened, it reads:
|
|
|
|
```json
|
|
{"@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": "urn:scienting:doc:smithlab/hale2026harmonic",
|
|
"selector": [
|
|
{"type": "AnchorSelector",
|
|
"anchor": {"format": "scienting-anchor/1", "node": "sxgcc9h",
|
|
"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](https://www.w3.org/TR/json-ld11-api/#alg-expand-each-key-value)) and would give its arrays no order ([JSON-LD 1.1 §4.3](https://www.w3.org/TR/json-ld11/#sets-and-lists)).
|
|
|
|
## 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](https://www.w3.org/TR/annotation-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](../spec/06-anchors.md#62-the-anchor)).
|
|
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](../spec/06-anchors.md#65-resolution)).
|
|
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](../spec/18-layers.md#183-the-annotation)).
|
|
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](../spec/18-layers.md) defines layers (§18.2), annotations (§18.3) and bodies (§18.4).
|
|
- Reader: Follow [chapter 6](../spec/06-anchors.md) to resolve an anchor.
|
|
The file `vectors/resolve.jsonl` resolves seventeen anchors against `fixtures/packages/hale2026harmonic` 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](https://www.w3.org/TR/json-ld11/#advanced-context-usage)), 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](../spec/00-introduction.md)).
|
|
- 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](../spec/18-layers.md#183-the-annotation)), 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`](../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](../spec/00-introduction.md)).
|
|
|
|
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](https://www.w3.org/TR/annotation-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](https://web.hypothes.is/blog/fuzzy-anchoring/), 2013).
|
|
These formats store a hash pin and define the outcomes exactly.
|
|
The full comparison is in [docs/comparison.md](../docs/comparison.md).
|
|
|
|
[Chapter 18](../spec/18-layers.md) defines layers and annotations.
|