summaryrefslogtreecommitdiffhomepage
path: root/pipeline/README.md
diff options
context:
space:
mode:
authorRalph Amissah <ralph.amissah@gmail.com>2026-09-27 15:39:02 -0400
committerRalph Amissah <ralph.amissah@gmail.com>2026-09-27 15:39:02 -0400
commit8d03e44a28c3d1de7d59b07f5e7f611cde0c38c6 (patch)
tree9db9f5c1e0ce10542c9bde49182ab53e0fd9187c /pipeline/README.md
format 2.0: sample writers over the abstraction, in D and in Gleam
Writers over sisudoc-ocda-lib: functions from the document model to bytes, in five formats, one program, ocda-write, in each language. Begun 2026-09-25; this is the writer as it stood at format 2.0. ocda-write --text|--md|--html|--epub|--typst <file> [lang] They are samples. Spine is the output pipeline and nothing here replaces it. What they show is that the abstraction is sufficient: given a .ssp, a .ocda.db or a .sisupod and nothing else, a few hundred lines per format make a complete document. A writer is never told which form it was given, and every writer is run against every form of every document. Each format is held to an oracle that can say no: --text the words equal the html writer's objects, as a multiset; every object number exactly once --md CommonMark; every (#x) resolves to an <a id=x>, no id twice --html it parses; every internal link resolves; the objects' text equals spine's scroll html --epub epubcheck --typst typst itself: a link to a missing label does not compile and in every format the same bytes from every input form, and the D and Gleam writers byte for byte alike. Over the markup document samples every check holds for every document-language. The two languages' writers were not written from each other, and their agreement is the strongest check: twice it caught what nothing else did (an ampersand in an attribute mangled by Erlang's replacement string; typst label names built from bytes in one language and graphemes in the other). Byte identity with spine is not the aim, by decision. The text writer began byte identical to spine --text, and was rewritten: a note is written once, markup comments and dummy headings are not written, an image keeps its caption, a table is padded to display width. The html writer is valid html5 rather than a copy of spine's (h1..h6 where spine writes <h0>; one charset; no placeholder metadata; an id for every anchor tag; self-contained). Each difference is a better presentation, and the code says why at the point of choice. The typst writer puts the object number in the margin as the label every citation points at, a note as a real footnote with a link back, and a table of contents that locates by object number rather than by page, as the markdown writer's does: a page number is a fact about one typesetting, the object number is not. The markdown writer is CommonMark with yaml front matter; a note is at its reference, with the document's own number, and --image-prefix gives the image path, which the model rightly does not know. Holding the writers to these checks found defects in spine, several since fixed there, and spine's typst and markdown writers were ported from these. Use: nix build, in dlang/ or in gleam/. Each flake takes the library from git.sisudoc.org, and flake.lock pins the commit of it these were built and checked against. gleam/ builds with nix-gleam's builder, kept in gleam/nix-gleam/ (MIT); in a working tree, gleam.toml reads the library through the symlink ./ocda-lib. See README.md, dlang/README.md and gleam/README.md, and pipeline/ for building everything and running it over a directory of artefacts. (assisted by Claude-Code)
Diffstat (limited to 'pipeline/README.md')
-rw-r--r--pipeline/README.md99
1 files changed, 99 insertions, 0 deletions
diff --git a/pipeline/README.md b/pipeline/README.md
new file mode 100644
index 0000000..59b98dc
--- /dev/null
+++ b/pipeline/README.md
@@ -0,0 +1,99 @@
+# The pipeline: how to run the readers, the library and the writers
+
+Fixed scripts rather than a test suite. They produce output that is meant to
+be **looked at**, and they double as the answer to "what do I type?".
+
+```
+config.sh where everything is, and where the output goes
+build.sh build every reader, library and writer, in both languages
+one.sh one tool, one document - the answer to "how do I run this?"
+read.sh every reader and both libraries, over every document
+write.sh every writer, in both languages, over every document
+pdf.sh compile the .typ files that write.sh produced
+run.sh all of the above, in order
+```
+
+## What you need first
+
+An **abstraction** to read: a directory holding a `.ssp` for each
+document-language and a `.ocda.db` for each document, and, where there is
+one, a `.sisupod` beside it. That is what spine writes:
+
+```sh
+spine --abstraction --ocda-db --pod2 --output=<dir> <pod>...
+```
+
+Everything downstream reads those files and nothing else. **No tool here
+parses markup**: parsing is spine's work, and the point of the exercise is
+that the abstraction is enough without it.
+
+## Running it
+
+```sh
+ARTEFACTS=<dir> OUT=<dir> sh pipeline/run.sh
+```
+
+`ARTEFACTS` is the directory above. `OUT` is where the output goes and
+defaults to `./pipeline-out`. Both, and every path to a sibling repository,
+are variables with defaults in `config.sh`; override them in the environment
+rather than editing anything.
+
+`LIMIT=3` takes the first three documents, which is what to use while looking
+at something.
+
+## Where the output goes
+
+```
+$OUT/read/ssp-d/ ssp-g/ the .ssp readers' summaries
+$OUT/read/db-d/ db-g/ the .ocda.db readers' summaries
+$OUT/read/dump-d/ dump-g/ the library's dump, from each serialisation
+$OUT/write/text/{d,g}/ <doc>.txt
+$OUT/write/md/{d,g}/ <doc>.md
+$OUT/write/html/{d,g}/ <doc>.html
+$OUT/write/epub/{d,g}/ <doc>.epub
+$OUT/write/typst/{d,g}/<doc>/ <doc>.typ, and image/ beside it
+$OUT/write/pdf/ <doc>.pdf
+```
+
+`d` is the D implementation and `g` the Gleam one, throughout.
+
+## One tool, one document
+
+```sh
+sh pipeline/one.sh text-d <doc>.ssp
+sh pipeline/one.sh md-g <doc>.ocda.db en
+sh pipeline/one.sh html-d <doc>.sisupod
+sh pipeline/one.sh dump-d <doc>.ocda.db en
+sh pipeline/one.sh agree-g <doc>.ssp <doc>.ocda.db
+```
+
+The tool names are `<format>-<language>`: `text`, `md`, `html`, `epub`,
+`typst` for the writers, and `ssp`, `db`, `dump`, `agree` for the readers and
+the library; `-d` for D and `-g` for Gleam.
+
+Output goes to stdout, so a comparison is a pipeline. The epub and the typst
+name a file instead, because an epub is a zip and a `.typ` names its images by
+path:
+
+```sh
+"$WRITERS/dlang/result/bin/ocda-write" --epub <doc>.ocda.db en --out x.epub
+"$WRITERS/dlang/result/bin/ocda-write" --typst <doc>.ocda.db en --out d/x.typ
+typst compile --root d d/x.typ d/x.pdf
+```
+
+## What the counts at the end mean
+
+Each stage prints a few numbers. They are not a pass, they are a way to see a
+regression without reading 36 documents.
+
+| `all four dumps identical` | the library's whole claim: two serialisations, two languages, one model |
+|---|---|
+| `D == Gleam, <format>` | the writers agree, in unrelated languages, neither written from the other. This is what says the model is sufficient |
+| `.ssp and .ocda.db give the same .typ` | a writer is not told which serialisation it was handed |
+| `typst compiled silently` | a link to a label that does not exist is a typst compile error, so this says every internal link in every document resolves |
+
+## What this is not
+
+It is not the project's checking. The sweeps that hold each writer against an
+oracle - `spine --text`, spine's scroll html, epubcheck, typst - are separate
+and stricter. This is the pipeline you run to *look* at all of it at once.