Files
paperspec/spec/18-layers.md
T
alexmandClaude 7890fa1ad7 feat: trace annotation body for traced citations; paperspec.traces
A trace follows one citation of a sentence of a citing paper to a passage of the
cited paper (spec/18 section 18.5). Minor change: a new body kind, optional
properties and two rules, with no valid file made invalid.

- annotation schema branch (source, selector, reference, note, verdict, proposer;
  proposer required for a Software creator); body_kind in sql/store.sql; the note
  and proposer terms of the JSON-LD context; rules layer.trace.source and
  layer.trace.target.
- paperspec.traces: resolve(annotation, citing_state, cited_state, same_as) gives
  current, changed, stale, unlinked or misresolved with open and cites; problems,
  disputes, disputed.
- fixtures/records/traces/ on writer2027fixed-ynr7.v3 and vectors/traces.jsonl
  (29 cases); check.py runs the record checks over both layers; counts, glossary,
  examples and CHANGELOG updated.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uy4ZYbWRoCdUtWLEfigysY
2026-10-17 20:12:04 -04:00

135 lines
13 KiB
Markdown

# 18. Layers and annotations
Everything people and models add to a document is an annotation, and annotations are grouped in layers.
`scienting-layer/1` is the W3C Web Annotation Data Model with the anchor as a selector, so any Web Annotation tool can read it.
The JSON-LD context is [context/scienting-1.jsonld](../context/scienting-1.jsonld), published at `https://paperspec.scient.ing/context/scienting-1.jsonld`.
## 18.1 One rule decides what is a claim and what is a layer
If a statement is true independently of this paper, it belongs in a claim store as a claim, where it is checked and leveled.
If it is about reading this paper, it belongs in a layer, where it is attributed and signed but not checked.
## 18.2 The layer
A layer is a folder with `layer.json` and `annotations.jsonl`.
`layer.json` is an `AnnotationCollection` with the two contexts, `format`, an `id` of the form `tag:scient.ing,2026:layer:<store>/<record id>`, a `label`, a `purpose`, an `audience` (`novice`, `student`, `expert` or `mixed`), a `visibility` (`private`, `team` or `public`), a `license` (CC BY 4.0 by default when public), its `creator`, `created`, its `project`, the `docs` it annotates and its `total`.
A reader turns layers on and off, and the audience dial picks the level of glosses.
## 18.3 The annotation
Each line of `annotations.jsonl` is a W3C `Annotation`:
| Property | Holds |
| --- | --- |
| `@context` | `["http://www.w3.org/ns/anno.jsonld", "https://paperspec.scient.ing/context/scienting-1.jsonld"]`. |
| `id` | `tag:scient.ing,2026:annotation:<store>/<record id>` ([4.6](04-identity.md#46-record-ids)). |
| `type`, `layer` | `Annotation`, and the layer's ID. |
| `motivation` | A W3C motivation: `commenting`, `describing`, `linking`, `questioning`, `assessing`, `replying` and the others. |
| `creator`, `created`, `modified` | An agent `{id, type, name}`, with `type` `Person` or `Software`, and times. |
| `body` | One body ([18.4](#184-bodies)). |
| `target` | A `SpecificResource` whose `source` is `tag:scient.ing,2026:doc:<store>/<key>` and whose `selector` lists an `AnchorSelector` holding a `scienting-anchor/1`, optionally followed by a W3C `TextQuoteSelector` for tools that do not know ours; or, for a reply, a `SpecificResource` whose source is another annotation. |
| `status` | `proposed`, `confirmed`, `rejected` or `withdrawn`. A model's annotation is `proposed` until a person confirms it. |
| `receipt` | For a confirmed annotation, the receipt that covers it. |
The `TextQuoteSelector`, when present, repeats the anchor quote's `exact`, `prefix` and `suffix`, with an empty string for a `prefix` or `suffix` the quote lacks.
It is present only when the anchor's quote is plain text; an anchor whose quote is hashed or keyed ([6.3](06-anchors.md#63-keyed-anchors)) has none, so the fallback never shows text the anchor withholds.
An annotation's content hash is SHA-256 of the canonical JSON of the annotation without `status`, `receipt` and `modified`.
A confirmed annotation is covered by its confirmer's receipt, which lists `["annotation", <record id>, <content hash>]`.
Replies are annotations that target annotations, so discussions are threads anchored to sentences.
## 18.4 Bodies
| `kind` | W3C type | Adds | Says |
| --- | --- | --- | --- |
| `gloss` | `TextualBody` | `audience` | An explanation at `novice`, `student` or `expert` level. |
| `claim-link` | `SpecificResource` | `source`, `pin`, `role` | That the span `states`, `uses` or `disputes` a claim. |
| `symbol` | `SpecificResource` | `source`, `pin`, `key`, `symbol` | That this occurrence of a symbol, the one whose key is `key`, is the symbol a symbol claim defines. |
| `comment` | `TextualBody` | `category` | A remark, opinion or interpretation. |
| `caveat` | `TextualBody` | `category` | A warning a reader should see. |
| `question` | `TextualBody` | `for`, `category` | A question for a `reader`, a `group` or the `authors`. |
| `exercise` | `TextualBody` | `exercise` | A task with a key and a rule ([19](19-exercises.md)). |
| `citation-context` | `TextualBody` | `reference`, `verdict`, `reason` | Why a sentence cites a reference, and whether it supports it. |
| `prerequisite` | `SpecificResource` | `source` | What to read or know first. |
| `crosslink` | `SpecificResource` | `source`, `selector` | That the span corresponds to a span in another document. |
| `trace` | `SpecificResource` | `source`, `selector`, `reference`, `note`, `verdict`, `proposer` | That the target's sentence cites `reference` on the strength of a passage of the cited document ([18.5](#185-traced-citations)). |
| `translation` | `TextualBody` | `language` | The span in another language. |
| `description` | `TextualBody` | `role` | A description of a figure, panel or table for readers who cannot see it: `alt`, a short text equivalent, or `long`, a full description. |
| `generated` | `TextualBody` | `generator` | Text a model wrote about the span; never mistaken for source. `generator` is `{model, run}` as a correction's model author is ([11.2](11-corrections.md#112-every-correction-records)). |
A textual body has a `value`, and optionally a `format` (`text/plain` or `text/markdown`) and a `language`.
The `source` of a `claim-link` or `symbol` body is a claim in a paperclaim claim store, written as paperclaim writes a reference: `claim:` and the claim's tag, eight Crockford base32 capitals (the digits and the letters without I, L, O and U), as in `claim:272XTX7C`, or `claim:<host>/<tag>` for a claim in another store, `<host>` being a domain name.
A tag never changes, while a claim's slug, such as `amber/k-bond`, may be renamed, so a slug is never a reference.
The optional `pin` fixes the claim as the annotator read it: the same reference, `@`, and the first six lowercase hex digits of the claim's statement hash, as in `claim:272XTX7C@02f47b`.
`common.schema.json` defines both, as `claimRef` and `claimPin`.
A `symbol` body names its symbol twice, as the target's span and by `key`, the symbol's key in the math form `scienting-math/1` ([9.4](09-figures-tables-equations.md#94-the-math-form)), which a claim store gives the symbol a symbol claim defines: `K_{r}` for a span `$K_r$`.
So a reader finds every occurrence of a symbol across a library by its key, however its source spaced or braced it, and a claim store matches the annotation to its claim without parsing the span.
The span is still required, since the key says which symbol and the span says where; `symbol`, optional, is the symbol as the span writes it.
A `comment`, `caveat` or `question` body MAY carry a `category`, which says what it is about, from a fixed list:
| `category` | Says |
| --- | --- |
| `comment` | A general remark. |
| `context` | Background, related work, or what a reader should know to follow the span. |
| `critique` | A flaw in the method, the analysis or the argument. |
| `question` | A question. |
| `correction` | An error of fact, number, citation or reference in the paper. |
| `feedback` | A suggestion addressed to the authors. |
| `resource` | Data, code or a related paper. |
A producer that supports categories SHOULD set one on every comment, caveat and question; the property is optional only so that layers written before it stay valid.
The category is independent of the kind, so a caveat may be a `correction` and a question a `critique`.
A `correction` category says that a reader found an error in the paper; correcting the document's reading of it is a correction of [11](11-corrections.md).
The store's `annotations` table keeps the category beside the body's kind ([13.4](13-database.md#134-the-store-tables)).
Nothing a model writes is ever stored as source text.
A model may propose a `description`, and like any annotation it stays `proposed` until a person confirms it; an accessible export uses confirmed descriptions only, and a figure with none has no description.
Other text a model writes about a span, such as a summary, is a `generated` annotation, which names its `generator`.
`fixtures/records/layer/` holds a layer with one annotation of each common kind, each comment, caveat and question with its category, a claim link and a symbol that reference a paperclaim claim and pin it, and the receipt that confirms some of them.
## 18.5 Traced citations
"As previously reported [12]": a reader who finds where the cited paper reports it marks the passage, and the `trace` body keeps the mark.
A `crosslink` says only that two spans correspond, in both directions, whereas a trace goes from one sentence's citation to one passage, and says which reference it follows, why, and who or what found it.
The annotation's target is a leaf or span anchor ([6.4](06-anchors.md#64-four-kinds-of-anchor)) on the citing sentence, which MUST be a leaf with runs, a sentence or a cell, and MUST cite the reference the body names: one of its `cite` runs lists `reference` ([3.5](03-nodes.md#35-inline-runs)).
`reference` is the ID of a `reference` node of the citing document, because a sentence may cite several references at once, as in `[3, 12]`, and the target says only which sentence.
`source` is the cited document, written as a target's source is, `tag:scient.ing,2026:doc:<store>/<key>`, and never the citing document itself.
`selector` selects the passage in it: an `AnchorSelector` whose anchor holds the passage's pin (its `node_hash`) and, for part of a leaf, its `span`, then a `TextQuoteSelector` when the anchor's quote is plain ([18.3](#183-the-annotation)).
The passage may be a container, such as a table, whose anchor has no quote.
| Property | Required | Holds |
| --- | --- | --- |
| `reference` | Yes | The reference node of the citing document that the sentence cites and the trace follows. |
| `source`, `selector` | Yes | The cited document and the passage in it. |
| `note` | No | What the passage reports, in a person's or a tool's words. |
| `verdict` | No | `supports`, `partly`, `does-not` or `cannot-tell`, as a `citation-context` body has it ([19.2](19-exercises.md#192-verdicts)). |
| `proposer` | When the creator is `Software` | `{model, run, score?, rank?}`: the model and run that found the passage as a candidate, as a `generated` body's `generator` names them, the candidate's `score` as a decimal string, and its `rank`, from 1, among the candidates the run proposed for this citation. |
The state of a trace is the annotation's `status`.
A trace a tool proposes is `proposed` until a person confirms it, and `rejected` when a person turns the candidate down; a rejected candidate is kept, so that the tool is not offered it again.
A trace is *disputed* while a reply to it, an annotation whose target is the trace and whose motivation is `assessing`, is `proposed` or `confirmed`.
The dispute is computed from the replies and never written on the trace, so a reply can be withdrawn.
Whether a trace still leads where it did is also computed, from the current state of both documents.
Resolve the target's anchor against the citing document and the body's anchor against the cited document ([6.5](06-anchors.md#65-resolution)).
The first row that applies gives the outcome:
| Outcome | When |
| --- | --- |
| `stale` | An anchor is stale, on the citing side, the cited side or both. |
| `unlinked` | The sentence no longer cites `reference`: a `relink` removed the citation ([11.7](11-corrections.md#117-citations-and-references)), or the reference was deleted. |
| `misresolved` | A `resolve` made the reference name a DOI or a document that is not the cited work. A resolution of `none` names nothing and contradicts nothing ([10](10-references.md)). |
| `changed` | Both anchors resolve and at least one is not `current`. |
| `current` | Both anchors are `current`, and the reference still resolves to the cited work or to nothing. |
A resolution names the cited work when its document is the cited document, another version of the same work (a key with the same work key, [2.4](02-model.md#24-work-and-document-keys)), or one the caller knows to be the work; and a `doi` resolution does when the work is known by that DOI (`same_as`, [2.4](02-model.md#24-work-and-document-keys)).
Besides the outcome, a resolution gives the passage's current address, `key#node@pin[start:end]`, while its anchor resolves, and the citations inside the passage.
A chain of "as previously reported" is then followed one trace at a time: the reader opens the passage, and a citation in it that has a trace of its own leads on.
A trace breaks `layer.trace.source` when its selector has no `AnchorSelector`, an anchor is in another document than `source` names, `source` is the citing document, or the `TextQuoteSelector` does not repeat the anchor's plain quote.
It breaks `layer.trace.target` when the target is not a leaf with runs of the citing document selected by an `AnchorSelector`, or the sentence does not cite `reference` ([22.4](22-conformance.md#224-rules)).
`vectors/traces.jsonl` resolves traces against the fixture packages after corrections, with every outcome and every refusal, and `fixtures/records/traces/` holds a layer of four annotations on `writer2027fixed-ynr7.v3` that cites `hale2026harmonic-damb`: a trace a model proposed to the paper's abstract and a person confirmed with a receipt, a candidate a person rejected, a person's trace to Table 1, and a reply that disputes the first.