summaryrefslogtreecommitdiffhomepage
path: root/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'README.md')
-rw-r--r--README.md108
1 files changed, 63 insertions, 45 deletions
diff --git a/README.md b/README.md
index 7ba2841..eaedaac 100644
--- a/README.md
+++ b/README.md
@@ -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).