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
14 KiB
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). |
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). 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). |
Unchanged. |
resolve |
target, resolution |
Sets a reference node's resolution in references.jsonl (11.7). |
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.
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).
Runs are made canonical after every operation, and the result MUST satisfy every rule of 3.
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). |
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) 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), when:
- it does not match the correction schema,
schemas/correction.schema.json; - a target, parent or sibling is not live, or the root would be deleted, moved, merged or reclassified;
findis empty or does not occur exactly once;- an
inserthas no crop evidence, or names a run or offset its target does not have; - a digit changes without crop evidence: in a
replacewhosefindand replacement have different digits, adeleteof leaves that hold digits, or arelabelwhose labels have different digits; or anemendchanges, adds or removes a digit, or edits beside one, whatever its evidence (11.6); - any leaf outside
touchedhas different digits afterwards; - a
splitfalls outside the sentence, inside a run other than text or inside an emended run, or leaves a part empty; - a
mergejoins nodes that differ in kind, are not mergeable, or are not adjacent siblings; - a
movewould put a node inside itself; - a
reclassifychanges the content shape, or arelabelorsettargets a kind that does not take it; - the result breaks a rule of 3;
- an
emendtargets a node without runs, or finds its text only in a math or equation source or only across runs; or areplaceor textinsertwould change an emended run, or a correction other than an emend writesprinted; - a
relinknames a run that is neither text nor a cite, or unlinks a run that is not a cite; or - a
resolvenames 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 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) 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.
- The leaf keeps its level (8.1, 8.2): a level measures the reading against its witnesses and the page, and the leaf as printed is what it was.
- 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).
- The leaf's
text_hash,own_hashandnode_hashchange, as for any change of text, because the text read, quoted and pinned is the emended one; itsmatch_hashandalign_key, which are of the runs as printed, do not (5.1). - Anchors on the leaf relocate by their quote, as after a
replace(6.5).
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).
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), 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); 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).
A resolve sets a reference node's resolution in references.jsonl (10) 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).
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.