diff options
Diffstat (limited to 'README.md')
| -rw-r--r-- | README.md | 108 |
1 files changed, 63 insertions, 45 deletions
@@ -22,9 +22,9 @@ Five formats: `--text`, `--md`, `--html`, `--epub`, `--typst`. They are **samples**, and they are **checked**. Spine is the output pipeline; nothing here replaces it. What these demonstrate is that the -abstraction is sufficient: given a `.ssp` or a `.ocda.db` and nothing else, -a program of a few hundred lines reproduces spine's own output for that -format. +abstraction is sufficient: given a `.ssp`, a `.ocda.db` or a `.sisupod` and +nothing else, a program of a few hundred lines makes a complete document in +that format, in the spirit of spine's own. ``` .ssp ─┐ @@ -33,9 +33,11 @@ format. ``` **A writer is never told which serialisation it was given.** That is the -claim, and every writer here is run twice against every document to check -it: once from the `.ssp`, once from the `.ocda.db`, and the two outputs must -be identical to each other and to spine's. +claim, and every writer here is run against every form of every document to +check it: the outputs must be identical from every form, and the D and Gleam +writers must produce the same bytes. They are not held to spine's bytes. +Each format has its own judge (below), and where the output differs from +spine's it does so to read better, and the code says why at that point. ## The oracle comes first @@ -54,17 +56,20 @@ and from every input form the library accepts, not only the two it started with: a document renders identically from its `.ssp`, its `.ocda.db` and its `.sisupod`. -**As at 2026-09-26**, over the 36 document-languages of the reference -collection: +The checks are run over the markup document samples +([sisudoc-spine-samples](https://git.sisudoc.org/sisudoc-spine-samples)), +built by spine with `--show-abstraction --ocda-db --pod2`, which writes each +document's `.ssp`, its `.ocda.db` and its pod. **As at 2026-09-26**, over +every document-language of them: `--text`, which is **no longer spine's bytes**, by decision (2026-09-27): | | | |---|---| -| the same bytes from every input form | **36 of 36** | -| **D == Gleam, byte for byte** | **36 of 36** | -| the words == the html writer's objects, as a multiset | **36 of 36** | -| every object number once, and no other | **36 of 36** | +| the same bytes from every input form | **all** | +| **D == Gleam, byte for byte** | **all** | +| the words == the html writer's objects, as a multiset | **all** | +| every object number once, and no other | **all** | | lines differing from `spine --text` | 131,474, **reported and not required** | Byte identity was the first oracle and earned its place while there was @@ -83,11 +88,11 @@ contents indents by ranked level rather than by spine's `indent_hang`. | | | |---|---| -| the same bytes from every input form | **36 of 36** | -| **D == Gleam, byte for byte** | **36 of 36** | -| every `(#x)` resolves to an `<a id=x>`, and no id is defined twice | **36 of 36** | -| the words == the html writer's objects | **36 of 36** | -| every object number anchored, and no other | **36 of 36** | +| the same bytes from every input form | **all** | +| **D == Gleam, byte for byte** | **all** | +| every `(#x)` resolves to an `<a id=x>`, and no id is defined twice | **all** | +| the words == the html writer's objects | **all** | +| every object number anchored, and no other | **all** | The third is the markdown one: markdown has no anchor syntax, so the anchors are the two pieces of raw html the writer emits, and a mistake in them is @@ -100,16 +105,16 @@ writer emits a private-use marker for the directory and substitutes it once, at the end, so nothing carries the constant through the call graph. spine, whose markdown goes to `<lang>/markdown/` and shares the images with its html, passes `../../image`; and **spine's `.md` is byte identical to what this produces with -that prefix, on all 36 document-languages.** +that prefix, on every document-language.** `--epub`: | | | |----------------------------------------|--------------------| -| epubcheck clean | **36 of 36** | -| from a `.ocda.db` == from a `.sisupod` | **35 of 35 pairs** | -| from a `.ssp` == from a `.ocda.db` | **36 of 36** | -| **D == Gleam, byte for byte** | **36 of 36** | +| epubcheck clean | **all** | +| from a `.ocda.db` == from a `.sisupod` | **every pair** | +| from a `.ssp` == from a `.ocda.db` | **all** | +| **D == Gleam, byte for byte** | **all** | The third is the interesting one: a `.ssp` carries no images and a `.ocda.db` and a `.sisupod` do, yet the epub is the same either way. It is the same @@ -118,7 +123,7 @@ before it emits one, and a `.ssp` inside a pod can: the images are beside it, at `media/image/`. So the three input forms are three ways to the same publication rather than three publications. -(Thirty-five pairs rather than thirty-six, because spine names a `.sisupod` +(One pair fewer than there are documents, because spine names a `.sisupod` after the pod directory and a `.ocda.db` after the document uid, and for one document those differ, so it has no pair to compare.) @@ -126,10 +131,10 @@ document those differ, so it has no pair to compare.) | | | |--------------------------------------------------------------------|--------------| -| parses (`xmllint --html`) | **36 of 36** | -| every `href="#x"` resolves, no id twice, no heading outside h1..h6 | **36 of 36** | -| the objects' text == spine's scroll html | **36 of 36** | -| **D == Gleam, byte for byte** | **36 of 36** | +| parses (`xmllint --html`) | **all** | +| every `href="#x"` resolves, no id twice, no heading outside h1..h6 | **all** | +| the objects' text == spine's scroll html | **all** | +| **D == Gleam, byte for byte** | **all** | and so the two writers agree with each other, in two languages, without either having been written from the other. That is the agreement that says @@ -139,12 +144,12 @@ the model is enough. | | | |----------------------------------------------------|--------------| -| `typst compile`, silently | **36 of 36** | -| from a `.ssp` == from a `.ocda.db` | **36 of 36** | -| the `.typ`'s text == the html writer's object text | **36 of 36** | -| every OCN on a page of the pdf | **36 of 36** | -| the same pdf twice, byte for byte | **36 of 36** | -| **D == Gleam, byte for byte** | **36 of 36** | +| `typst compile`, silently | **all** | +| from a `.ssp` == from a `.ocda.db` | **all** | +| the `.typ`'s text == the html writer's object text | **all** | +| every OCN on a page of the pdf | **all** | +| the same pdf twice, byte for byte | **all** | +| **D == Gleam, byte for byte** | **all** | 4,870 pages typeset. The first row is the strong one: **a link to a label that does not exist is a typst compile error**, so a silent compile means @@ -183,7 +188,7 @@ and the *direction* of the allowance is the finding. ```sh cd dlang -nix build --override-input ocda-lib path:../../sisudoc-ocda-lib +nix build ./result/bin/ocda-write --text <doc>.ssp ./result/bin/ocda-write --text <doc>.ocda.db en ./result/bin/ocda-write --typst <doc>.ocda.db en --out <dir>/<doc>.typ @@ -194,24 +199,32 @@ typst compile --root <dir> <dir>/<doc>.typ <dir>/<doc>.pdf the epub is a zip, and a `.typ` names its images by path, so `--out` also writes the `image/` directory the `.typ` refers to. -Output goes to stdout, so the comparison is a pipeline: +Output goes to stdout, so the check that a writer cannot tell the forms +apart is a comparison: ```sh -./result/bin/ocda-write --text <doc>.ssp | cmp - <spine's .txt for that doc> +./result/bin/ocda-write --text <doc>.ssp > a +./result/bin/ocda-write --text <doc>.ocda.db en > b +cmp a b ``` -### the library, before it is published +### the library -`sisudoc-ocda-lib` is not yet at a public URL, so the flake declares the -URL it will have and the local copy is supplied on the command line with -`--override-input`. Nix accepts this without ever fetching the declared -url. When the library is published the override goes away. +Each flake takes `sisudoc-ocda-lib` from +`git://git.sisudoc.org/tools/sisudoc-ocda-lib`, and `flake.lock` pins the +commit the writer was built and checked against. To build against a working +copy of the library instead: + +```sh +nix build --override-input ocda-lib path:../../sisudoc-ocda-lib +``` ## The pipeline -`pipeline/` holds fixed shell scripts that build every reader, library and -writer in both languages, run all of them over a directory of abstraction -artefacts, and put the output where it can be read. +`pipeline/` holds fixed shell scripts that build the library (whose +`ocda-read` is the reader) and the writer in both languages, run all of them +over a directory of abstraction artefacts, and put the output where it can +be read. ```sh ARTEFACTS=<dir of .ssp and .ocda.db> OUT=<dir> sh pipeline/run.sh @@ -356,4 +369,9 @@ the comparison is of the writer and not of the signature. ## The format Specified in **sisudoc-abstraction-format**: `ocda-model.md` for the model, -and the two format specifications for the serialisations. At format **2.x**. +and the two format specifications for the serialisations. At format **2.1**; +the writer's version follows the format's major and minor parts. + +## Licence + +AGPL-3.0-or-later. See [`COPYRIGHT`](COPYRIGHT). |
