127 lines
9.4 KiB
Markdown
127 lines
9.4 KiB
Markdown
# Walkthrough: one paper, start to finish
|
||
|
||
This guide follows the example paper `hale2026harmonic` from a flawed first reading to a corrected, reviewed and signed document.
|
||
The paper is synthetic, written for the fixtures, but everything that happens to it happens to real papers.
|
||
Open [fixtures/packages/hale2026harmonic/](../fixtures/packages/hale2026harmonic/) beside this page: every ID below is in it.
|
||
The hand-written source of the first reading is [fixtures/src/hale2026harmonic.json](../fixtures/src/hale2026harmonic.json).
|
||
|
||
## 1. A PDF arrives
|
||
|
||
The team downloads the publisher's PDF.
|
||
It becomes a witness, identified by its SHA-256, with the short ID `qptsanv`, and a rights record: the library's subscription allows reading, text mining, and AI processing on the team's own machines, until August 31, 2027; whether it allows processing in the team's cloud is unknown.
|
||
|
||
The publisher stamped the download in the margin with the institution and the time.
|
||
Fingerprinting each page removes those lines first (the rules `downloaded-via` and `sharing-guidelines` fired on both pages), so page 101's fingerprint is `6272e6f3…` in this copy and in a colleague's download stamped a year later.
|
||
See [`pages.jsonl`](../fixtures/packages/hale2026harmonic/pages.jsonl).
|
||
|
||
## 2. The first reading, with its mistakes
|
||
|
||
A converter reads the PDF into sections, paragraphs, sentences, a figure, a table, an equation, a footnote and references, and mints a permanent ID for every node.
|
||
Like every reading, this one has mistakes:
|
||
|
||
| What the reading did | What the page says |
|
||
| --- | --- |
|
||
| A cell read `3l0.0`. | `310.0`, with the digit 1. |
|
||
| A sentence read `Values below 10-3 kcal mol⁻¹…`. | A superscript: 10⁻³. |
|
||
| Two sentences ran together: "…treated as zero. Table 1 lists…". | Two sentences. |
|
||
| One sentence was cut in two at a line break: "…and the energies were" and "fitted by least squares." | One sentence. |
|
||
| A paragraph was split at a column break. | One paragraph. |
|
||
| The running head "J. Example Chem. 2026, 14, 101–109" became a paragraph. | A running head, not text. |
|
||
| The equation's number read `(l)` and the figure's `Figure l`. | `(1)` and `Figure 1`. |
|
||
| The CT–HC row merged two cells into "338.7 1.0900". | Two cells. |
|
||
| The OW–HW row was missing. | It is there. |
|
||
| "Set B" spanned one column. | It spans two. |
|
||
|
||
The doubtful places become suspects with crops of the page, for a person to answer.
|
||
The converter does not guess, and nothing changes until a correction passes the gate.
|
||
|
||
## 3. Twelve corrections
|
||
|
||
Each fix is appended to [`corrections.jsonl`](../fixtures/packages/hale2026harmonic/corrections.jsonl), numbered, with its evidence, its author and its reason.
|
||
|
||
| # | Operation | On | What it did |
|
||
| --- | --- | --- | --- |
|
||
| 1 | `replace` | cell `nkm3xn5` | `3l0.0` to `310.0`. A digit changed, so the gate required a crop, and it has one. |
|
||
| 2 | `replace` | sentence `e4fkseg` | `10-3` to the runs `10` and superscript `−3`. |
|
||
| 3 | `split` | sentence `e4fkseg` | Split before "Table 1"; the first part keeps `e4fkseg`, the second is new: `r1gacps`. |
|
||
| 4 | `merge` | sentence `eajq93t` | Joined with `e9rh611`, which is retired with `eajq93t` as its successor. |
|
||
| 5 | `merge` | paragraph `zyqr0yc` | Joined with `g44k023`, retired the same way. |
|
||
| 6 | `delete` | paragraph `nm7vyzk` | The running head is gone; its IDs are retired with no successor. |
|
||
| 7 | `relabel` | equation `qn08tj9` | `(l)` to `(1)`. |
|
||
| 8 | `delete` | row `tfjge3c` | The garbled CT–HC row and its four cells. |
|
||
| 9 | `insert` | row `fbg2mwq` | The CT–HC row, read again: five new cells. |
|
||
| 10 | `insert` | row `j0x5twd` | The missing OW–HW row. |
|
||
| 11 | `set` | cell `vtszvw9` | Set B's `colspan` from 1 to 2. |
|
||
| 12 | `relabel` | figure `ajfvq4s` | `Figure l` to `Figure 1`. |
|
||
|
||
The document is now at revision 12.
|
||
Notice what did not happen: no other cell, sentence or row changed its ID or its hashes.
|
||
Inserting a row adds a row node; the table's own hash covers only its label and column definitions, so every other cell, and every value already taken from them, is untouched.
|
||
|
||
## 4. IDs that never move
|
||
|
||
After twelve corrections, the sentence about water is still `f929eq9`, the corrected cell is still `nkm3xn5`, and the sentence that lost its superscript is still `e4fkseg`.
|
||
The retired IDs are recorded in [`ids.jsonl`](../fixtures/packages/hale2026harmonic/ids.jsonl), so anything that pointed at them can follow the trail.
|
||
So is a legacy alias: `b-p01-text-003`, the ID an older tool gave the water sentence, still leads to `f929eq9`.
|
||
|
||
If a better converter comes along next year, its reading is aligned with this document sentence by sentence; every sentence it reads the same way keeps its ID, and every difference becomes a suspect rather than a silent change.
|
||
|
||
## 5. What happened to the notes
|
||
|
||
Before any correction, at revision 0, the team had already made seventeen anchors: notes, extracts and citations pointing into the first reading.
|
||
Here is how each resolves at revision 12 ([vectors/resolve.jsonl](../vectors/resolve.jsonl) records them all).
|
||
|
||
| Anchor on | Result | Why |
|
||
| --- | --- | --- |
|
||
| "H$_2$O" in the water sentence | `current` | Nothing in that sentence changed. |
|
||
| The cell `1.5260` | `current` | Untouched, though its table changed around it. |
|
||
| The water sentence, through the alias `b-p01-text-003` | `current` | The alias leads to the same node. |
|
||
| The cell that read `3l0.0` | `stale` | Its text changed and "3l0.0" is no longer in it; a person must look again, which is right, because the number changed. |
|
||
| "treated as zero" | `reattached` | The sentence changed twice, but the quote occurs in it exactly once, so the anchor is re-pinned. |
|
||
| "fitted constants" | `stale` | After the split, those words are in the new sentence `r1gacps`, not in `e4fkseg`. |
|
||
| "least squares", in the half-sentence `e9rh611` | `moved` | That ID was merged into `eajq93t`, which still holds the quote. |
|
||
| The paragraph `g44k023` | `moved` | Merged into `zyqr0yc`, which holds all of its sentences. |
|
||
| The running head | `stale` | Deleted, with no successor. |
|
||
| The equation | `reattached` | Only its number changed. |
|
||
| The figure | `reattached` | Only its label changed, by a `relabel`. |
|
||
| The CT–HC cell `1.090` in the garbled row | `reattached` | Its row was deleted, but exactly one cell in Table 1 has the same row and column headers and the same text: the new `e0n07n0`. |
|
||
| Section 2 | `changed-below`, drift high | The section itself is unchanged, but 53% of what is in it was touched. |
|
||
| Table 1 | `changed-below`, drift high | Rows were replaced and added. |
|
||
| The table body | `changed-below`, drift high | 75% of its cells were touched. |
|
||
| The paragraph whose broken sentence was rejoined | `changed-below`, drift high | Two of the three sentences it has held were touched. |
|
||
| The CT–CT row | `changed-below`, drift low | One of its five cells was corrected. |
|
||
|
||
A reader shows each note accordingly, and a Lode check, which is about exact words, accepts only `current`, `moved` and `reattached`.
|
||
|
||
## 6. Review and signatures
|
||
|
||
Now people check what matters.
|
||
The receipts are in [`receipts.jsonl`](../fixtures/packages/hale2026harmonic/receipts.jsonl), and the keys that signed them in [`roster.json`](../fixtures/packages/hale2026harmonic/roster.json).
|
||
|
||
- **Before the corrections**, `ana` had signed receipt `c5cx7n4tga6y9` for three cells at revision 0.
|
||
Two of them never changed, so the receipt still counts for them; for the corrected cell it no longer does, because its hash moved on.
|
||
- **After the corrections**, `ana` signs `eqgbbpwb6725v` at F3 for 23 nodes: the cells of Table 1's three data rows, its four column headers, the equation and the sentences around it.
|
||
`ben` spot-checks it with receipt `p38t0s91trb6j`: his signature over the receipt picks 10 nodes nobody could have chosen, and he finds no errors.
|
||
- `ana` signs `zaxky8c1y12tc` for two sentences of section 1, including the new `r1gacps`.
|
||
- `cara` signs `adtrpq41np7sd` for three sentences on page 2, then revokes it herself (`q0yg0w6ygwwxh`): she had compared them with the crops of another paper.
|
||
Those sentences fall back to their earlier levels, which is why `eajq93t` is still F0.
|
||
- `ana` signs `gena76nkb6cnc` for the figure's caption; `ben`'s spot-check `qab588b6xy94y` finds a missing period in `nmm4md0`, which suspends the receipt until she reviews the sitting again.
|
||
|
||
The document's report, in [`document.json`](../fixtures/packages/hale2026harmonic/document.json), counts the result: 28 leaves at F3, 12 at F2, 4 at F1 and 1 at F0.
|
||
|
||
## 7. Data out of the table
|
||
|
||
Table 1 becomes a dataset, `ds-hale-bond-params`, inside the package.
|
||
Its CSV keeps every digit as printed (`1.526` and `1.5260` stay different), and every value has an anchor to the cell that prints it, so a claim that rests on a value can show the cell.
|
||
All twelve value anchors resolve as `current`; the checker confirms each CSV value equals its cell's text.
|
||
|
||
## 8. Sharing without the text
|
||
|
||
The team wants to share its notes with a collaborator's machine but not the paper.
|
||
[`hale2026harmonic.checks-only`](../fixtures/packages/hale2026harmonic.checks-only/) is the same document with every leaf's text withheld and every hash replaced by an HMAC under the team's key.
|
||
IDs, labels, pages and boxes survive, so annotations still land in the right place; only someone holding the key and the text can check the values.
|
||
|
||
## 9. Your turn
|
||
|
||
[The examples](examples.md) show how to recompute one of these hashes with `sha256sum`, print the outline with a few lines of Python, and load the whole package into SQLite to query it.
|