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
This commit is contained in:
25 files changed
+966
-50
No files matched your search
@@ -52,6 +52,7 @@ Replies are annotations that target annotations, so discussions are threads anch
|
||||
| `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)). |
|
||||
@@ -87,3 +88,47 @@ 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.
|
||||
@@ -6,7 +6,7 @@
|
||||
| --- | --- | --- |
|
||||
| `vectors/*.jsonl` | Inputs and expected outputs, one case per line. | Computes every expected output from its input. |
|
||||
| `fixtures/packages/` | Valid packages: a converted chemistry paper with corrections, receipts, a multi-level-header table and a dataset; its checks-only export; an open-access paper with two witnesses; a Typst draft; a tiny document, as a folder and as the zip of [12.2](12-package.md#122-paths). | Accepts each, and recomputes every value it contains. |
|
||||
| `fixtures/records/` | A valid record of every other format that is a JSON file of its own; the stage requirements and stamp rules are in `registry/`, and a bundle is built by `paperspec load --bundle`. | Accepts each. |
|
||||
| `fixtures/records/` | A valid record of every other format that is a JSON file of its own, and a second layer, of traced citations ([18.5](18-layers.md#185-traced-citations)), whose traces resolve as `vectors/traces.jsonl` says; the stage requirements and stamp rules are in `registry/`, and a bundle is built by `paperspec load --bundle`. | Accepts each. |
|
||||
| `fixtures/invalid/` | Invalid packages, each with `expect.json` naming the rule it breaks. | Refuses each, and SHOULD name that rule. |
|
||||
| `fixtures/keys/` | The test keys that signed the fixtures and the team secret of the checks-only export. | Never uses them for anything else. |
|
||||
|
||||
@@ -49,6 +49,10 @@ Rule IDs are stable: a rule's meaning never changes, and a retired rule's ID is
|
||||
| `doc.receipt.`, `doc.qa.`, `doc.fidelity.` | Receipts, spot-checks and levels. |
|
||||
| `doc.witness.`, `doc.page.`, `doc.location.`, `doc.reference.` | Witnesses and geometry. |
|
||||
| `grade.` | Grading. |
|
||||
| `layer.` | Annotations that refer to documents: `layer.trace.source` and `layer.trace.target` ([18.5](18-layers.md#185-traced-citations)). |
|
||||
|
||||
A package is validated by [22.2](#222-validating-a-package), but a layer is not part of one.
|
||||
The `layer.` rules are reported for an annotation, in the form `annotation: rule: message`, by a validator that has the annotation and the states of the documents it names; the reference implementation does so for traces in `paperspec.traces.problems`.
|
||||
|
||||
## 22.5 Stability
|
||||
|
||||
|
||||
Reference in new issue
Block a user