scienting-layer/1: an optional, fixed category on comment, caveat and question bodies (comment, context, critique, question, correction, feedback, resource). Corrections: emend fixes the authors' own slip and keeps what was printed (a run's printed), never lowering fidelity or a witness match; relink sets or removes what a citation names; resolve sets a reference's resolution. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017R7sgDNvUGWY2zFPCq2JH6
138 lines
14 KiB
Markdown
138 lines
14 KiB
Markdown
# 11. Corrections
|
|
|
|
A correction, `scienting-correction/1`, is an operation on an established document, with its evidence and its author.
|
|
Corrections are added and never edited, so a document's history is its original reading plus its corrections.
|
|
Each has an `index`, counted from 1 in the order corrections are applied, and the document's revision is the index of the last.
|
|
|
|
## 11.1 Operations
|
|
|
|
| `op` | Fields | Does | IDs |
|
|
| --- | --- | --- | --- |
|
|
| `replace` | `target`, `find`, `replace`, optional `run` | Replaces the one occurrence of `find` among the target's editable strings with `replace`, a string or, inside a text run, a list of runs. | Unchanged. |
|
|
| `insert` | `parent`, `place_after` (a sibling, or null for first), `node` | Adds a subtree: kinds, labels, attributes and content, with each equation run naming its child as `{"kind": "equation", "child": i}`. | New IDs, minted ([4.2](04-identity.md#42-minting-node-ids)). |
|
|
| `insert` | `target`, `run`, `offset`, `text` | Inserts text into one run of the target, at a code-point offset in that run's editable string. | Unchanged. |
|
|
| `delete` | `target` | Removes an artifact and its subtree, such as a running head read as text. | All retired, without successors. |
|
|
| `split` | `target`, `offset` | Splits a sentence at an offset in its plain projection, which falls between runs or inside a text run; whitespace at the split is removed from both parts, and each equation child goes with its run. | The first part keeps the ID; the second gets a new one. |
|
|
| `merge` | `target`, `with`, optional `joiner` | Joins a node with its next sibling of the same kind: the runs of two run-bearing nodes, with the joiner (default one space) between, or the children of two `paragraph`, `list`, `item`, `quote`, `caption`, `figure-note` or `table-note` nodes. | `with` is retired, with the target as successor. |
|
|
| `move` | `target`, `parent`, `place_after` | Changes reading order or containment. | Unchanged. |
|
|
| `reclassify` | `target`, `kind` | Changes a node's kind, such as a paragraph that is really a caption, to a kind with the same content shape. | Unchanged. |
|
|
| `relabel` | `target`, `label` | Changes a printed label. | Unchanged. |
|
|
| `set` | `target`, `attr`, `value` | Sets one structural attribute: a section's `level`, a table's `columns`, a cell's `column`, `rowspan`, `colspan` or `role`, a row's `header_path`, a list's `ordered`, an item's `marker` or a theorem's `variant`. | Unchanged. |
|
|
| `emend` | `target`, `find`, `replace`, `kind`, optional `run` and `note` | Corrects the authors' own slip, where the reading matches the page and the page is wrong: replaces the one occurrence of `find` among the target's prose strings with `replace`, a non-empty string, and keeps what was printed ([11.6](#116-emendations)). `kind` is `typo`, `spelling`, `grammar`, `punctuation`, `wording` or `other`. | Unchanged. |
|
|
| `relink` | `target`, `run`, `refs` | Makes run `run` of the target a `cite` run naming `refs`, a non-empty list of reference nodes, or with `refs` null makes a `cite` run a `text` run, keeping its text ([11.7](#117-citations-and-references)). | Unchanged. |
|
|
| `resolve` | `target`, `resolution` | Sets a reference node's resolution in `references.jsonl` ([11.7](#117-citations-and-references)). | Unchanged. |
|
|
|
|
A leaf's editable strings are the `text` of its `text`, `link`, `cite`, `xref` and `fnmark` runs and the `source` of its `math` runs, each searched on its own; an equation's `source`; a verbatim node's `text`.
|
|
Its prose strings, which an emend searches, are the `text` of those five run kinds alone: never a math or equation source, and never a verbatim node's text.
|
|
`set` exists because readings drop spans, roles and header paths; see the [rationale](../docs/rationale.md#corrections).
|
|
`emend` exists because a faithful reading of a wrong page is not a misreading: it corrects the paper while keeping what was printed ([11.6](#116-emendations)).
|
|
Runs are made canonical after every operation, and the result MUST satisfy every rule of [3](03-nodes.md).
|
|
|
|
## 11.2 Every correction records
|
|
|
|
| Property | Holds |
|
|
| --- | --- |
|
|
| `evidence` | At least one item: `crop`, `witness` or `source-file` by SHA-256, or `person`. |
|
|
| `author` | `{key}` for a person in the roster, or `{model, run}` for a model's session, where `model` is `{name, provider?, version?, weights?, prompt?, parameters?, processor?}`: the model's name, who served it, its version, and SHA-256 of the weights, the instructions and the sampling parameters it ran with, as far as the team can obtain them, and where it ran ([14](14-rights.md)). |
|
|
| `reason`, `at` | Why, and when. |
|
|
|
|
A proposal, such as one a tool makes, carries these and `status: "proposed"`, and no applied fields.
|
|
|
|
## 11.3 Applied fields
|
|
|
|
When a correction is applied, its record gains:
|
|
|
|
| Property | Holds |
|
|
| --- | --- |
|
|
| `index`, `id` | Its position, and its record ID. |
|
|
| `before`, `after` | The target's `node_hash` before and after, or null; for an inserted subtree, `target` is its root. |
|
|
| `path` | The target's ancestors when it was applied, root first; for an insert, the new subtree's. |
|
|
| `to_path` | For a move, the new ancestors. |
|
|
| `touched` | The leaves whose content the correction changed, sorted: the target of a `replace`, text `insert`, `relabel` or `set` on a leaf, and of an `emend` or `relink`; the new leaves of a node `insert`; the deleted leaves of a `delete`; both parts of a `split`; both nodes of a run `merge`, or the moved-in leaves of a container `merge`; the moved leaves of a `move`; the leaves of a reclassified node; none for a `resolve`. |
|
|
| `created`, `retired` | IDs minted or retired. |
|
|
| `from` | The label, kind or attribute value before a `relabel`, `reclassify` or `set`; the references the run named before a `relink`, or null for a text run; the resolution before a `resolve`. |
|
|
|
|
Retirements are also entered in `ids.jsonl` with the correction's index as `rev`.
|
|
Drift ([6.6](06-anchors.md#66-drift)) is computed from `path`, `to_path` and `touched` alone, so it needs no replay.
|
|
|
|
## 11.4 The gate
|
|
|
|
A correction is refused, naming the rule ([22](22-conformance.md)), when:
|
|
|
|
1. it does not match the correction schema, `schemas/correction.schema.json`;
|
|
2. a target, parent or sibling is not live, or the root would be deleted, moved, merged or reclassified;
|
|
3. `find` is empty or does not occur exactly once;
|
|
4. an `insert` has no crop evidence, or names a run or offset its target does not have;
|
|
5. a digit changes without crop evidence: in a `replace` whose `find` and replacement have different digits, a `delete` of leaves that hold digits, or a `relabel` whose labels have different digits; or an `emend` changes, adds or removes a digit, or edits beside one, whatever its evidence ([11.6](#116-emendations));
|
|
6. any leaf outside `touched` has different digits afterwards;
|
|
7. a `split` falls outside the sentence, inside a run other than text or inside an emended run, or leaves a part empty;
|
|
8. a `merge` joins nodes that differ in kind, are not mergeable, or are not adjacent siblings;
|
|
9. a `move` would put a node inside itself;
|
|
10. a `reclassify` changes the content shape, or a `relabel` or `set` targets a kind that does not take it;
|
|
11. the result breaks a rule of [3](03-nodes.md);
|
|
12. an `emend` targets a node without runs, or finds its text only in a math or equation source or only across runs; or a `replace` or text `insert` would change an emended run, or a correction other than an emend writes `printed`;
|
|
13. a `relink` names a run that is neither text nor a cite, or unlinks a run that is not a cite; or
|
|
14. a `resolve` names a node that is not a reference.
|
|
|
|
The gate needs only the document's current state, so a tool can run it on a proposal before applying anything, and get back the record the correction would append or the rule it breaks.
|
|
`paperspec validate --correction` does this against a package.
|
|
|
|
Digits are characters of General Category Nd in the plain projection.
|
|
A package's corrections are also checked as a whole: indexes run from 1 without gaps, each `id` derives from its record, `rev` equals their number, every retired ID is in `ids.jsonl`, the last correction of each leaf ends at its current `node_hash`, and the last `resolve` of each reference ends at its resolution in `references.jsonl`.
|
|
`corrections.jsonl` in the vectors applies each operation, and each refusal, to a small document.
|
|
|
|
## 11.5 The history root
|
|
|
|
`document.json` carries `history`: the root of the tree of [8.5](08-fidelity.md#85-merkle-roots) whose items are `["correction", index, id]` for each correction in order, or SHA-256 of the empty string when there are none, which is how RFC 9162 hashes the empty tree.
|
|
Because corrections are only appended, a consistency proof (RFC 9162 §2.1.4) between the roots at two revisions shows that the later history extends the earlier one rather than rewriting it.
|
|
The proof is a `scienting-proof/1` with `kind` `consistency`, holding the `doc`, `from_rev`, `to_rev`, `from_root`, `to_root` and the `path` as hex hashes; a verifier applies RFC 9162 §2.1.4.2.
|
|
A checks-only package carries no corrections, so its history is the empty root.
|
|
`proofs.jsonl` gives consistency proofs for every prefix of small trees and for the example paper between revisions 8 and 12; `fixtures/records/proof-consistency.json` is the latter.
|
|
|
|
## 11.6 Emendations
|
|
|
|
A `replace` fixes the reading: the converter misread the page, and the page is right.
|
|
An `emend` fixes the paper: the reading matches the page, and the authors printed a typo, a misspelling, a slip of grammar or punctuation, or a wording an editor corrects for readers.
|
|
The two claim different things, so different things follow from them.
|
|
|
|
**What is kept.**
|
|
In a `text` run, the found text becomes a run of its own, with the style of the run it was in, whose `text` is the replacement and whose `printed` is the found text.
|
|
In a `link`, `cite`, `xref` or `fnmark` run, or a text run emended before, the run's text changes and `printed` keeps its whole text as it was first printed.
|
|
The record keeps `find`, the printed string, and `replace`, the emended one, so the history says what each emendation was, while the runs say where it is after any later split, merge or move.
|
|
A leaf as printed ([3.6](03-nodes.md#36-the-plain-projection)) is therefore recovered from `nodes.jsonl` alone: each run's `printed` in place of its text.
|
|
|
|
**The gate.**
|
|
An emend searches the target's prose strings for exactly one occurrence, as a `replace` searches its editable strings, but never a math or equation source, which `replace` corrects.
|
|
The replacement is a string, never runs, and is not empty; to delete a word, an editor finds it with a neighbor and keeps the neighbor.
|
|
The edit stays inside one run, so a `find` that occurs only across runs is refused.
|
|
No digit may change, be added or removed, and the edit may not touch one: setting aside the longest common prefix of the run's string before and after, and then the longest common suffix of the rest, what remains holds no digit in either string, and the unchanged character on each side of it is not a digit.
|
|
So an emend never turns "3,5" into "3.5": a number is data, corrected by `replace` with crop evidence, even where the authors printed it wrong.
|
|
Only an emend writes `printed`.
|
|
A `replace` or text `insert` that would change an emended run, a `split` inside one, and replacement runs or inserted nodes that carry `printed` are refused, and a second emend of an emended run keeps what was first printed.
|
|
|
|
**What follows.**
|
|
|
|
1. The leaf keeps its level ([8.1](08-fidelity.md#81-levels-of-fidelity), [8.2](08-fidelity.md#82-levels)): a level measures the reading against its witnesses and the page, and the leaf as printed is what it was.
|
|
2. Whatever compares the leaf with a witness or the page compares it as printed, so an emendation is never reported as a misreading ([8.1](08-fidelity.md#81-levels-of-fidelity)).
|
|
3. The leaf's `text_hash`, `own_hash` and `node_hash` change, as for any change of text, because the text read, quoted and pinned is the emended one; its `match_hash` and `align_key`, which are of the runs as printed, do not ([5.1](05-hashes.md#51-the-five-values)).
|
|
4. Anchors on the leaf relocate by their quote, as after a `replace` ([6.5](06-anchors.md#65-resolution)).
|
|
|
|
`corrections.jsonl` emends a word and a cross-reference's printed form, and refuses a changed digit, a `find` across runs, a `find` in math, an emend of a node without runs and a `replace` of an emended run; each emend's expectation adds the leaf as printed.
|
|
|
|
## 11.7 Citations and references
|
|
|
|
A `relink` changes what a citation names, never its text, so it needs no crop.
|
|
With `refs` a non-empty list of reference nodes, run `run` becomes a `cite` run naming them, or stays one, and keeps its text: a text run's whole text becomes the cite's printed form, and its style is dropped, since a cite run has none ([3.5](03-nodes.md#35-inline-runs)).
|
|
With `refs` null, a cite run becomes a text run with the same text.
|
|
Anything an emend kept in `printed` stays.
|
|
Every reference must be a `reference` node, as for any cite run (rule 11 of [11.4](#114-the-gate)), and `from` keeps the references the run named before, or null for a text run.
|
|
A relink changes no plain projection, so the leaf keeps its level.
|
|
Turning a text run into a cite, or back, still changes the leaf's `match_hash` and `align_key`, because the strict projection marks a citation ([5.3](05-hashes.md#53-the-strict-projection)); changing only which references a cite run names changes neither.
|
|
To cite part of a text run, a `replace` gives that part as runs that include the cite run ([11.1](#111-operations)).
|
|
|
|
A `resolve` sets a reference node's resolution in `references.jsonl` ([10](10-references.md)) to any valid one: `doi`, `document` or `none`.
|
|
The record keeps the resolution before in `from`, which is `{type: "none"}` for a reference without a record; the resolve then adds the record, in document order.
|
|
No content value covers `references.jsonl`, so a resolve changes no node's values: its `before` and `after` are the reference's unchanged `node_hash`, and `touched` is empty.
|
|
It changes `references.jsonl`, that file's entry in the manifest, the revision and the history root, as every correction does ([11.5](#115-the-history-root)).
|
|
`corrections.jsonl` links a citation printed as a superscript, unlinks a cite run, resolves a reference to a DOI, and refuses a relink of a cross-reference, a cite of a node that is not a reference and a resolve of a sentence.
|