<feed xmlns='http://www.w3.org/2005/Atom'>
<title>sisudoc-ocda-writer, branch main</title>
<subtitle>SiSU Spine: tools</subtitle>
<link rel='alternate' type='text/html' href='https://git.sisudoc.org/sisudoc-ocda-writer/'/>
<entry>
<title>release 2.1.0: versions, the library locked, the pipeline</title>
<updated>2026-10-13T20:54:02+00:00</updated>
<author>
<name>Ralph Amissah</name>
<email>ralph.amissah@gmail.com</email>
</author>
<published>2026-10-13T20:54:02+00:00</published>
<link rel='alternate' type='text/html' href='https://git.sisudoc.org/sisudoc-ocda-writer/commit/?id=3f34ec6afde21801eff0b655949a6d219e47943c'/>
<id>3f34ec6afde21801eff0b655949a6d219e47943c</id>
<content type='text'>
The writer's version follows the format's: 2.1.0 in dub.json,
gleam.toml and both flakes (it was 2.0.0), and manifest.toml locks the
library at 2.1.0 to match. A release is numbered major.minor.patch,
major.minor being the format and shared with the specification and
the library, the patch the writer's own.

flake.lock, in dlang/ and gleam/, pins the library at its 2.1.0
release and nixpkgs as that release locks it, so the writer builds
with what the library was built and checked with. The READMEs say
plain nix build, and how to build against a working copy of the
library instead.

The pipeline no longer builds or runs sisudoc-ssp-reader and
sisudoc-ocda-db-reader, which are frozen: ocda-read, the library's
reader, covers both, and read.sh already ran it from both forms and in
both languages. Gone from build.sh, config.sh, one.sh and read.sh, and
from pipeline/README.md, which with config.sh now names spine's
--show-abstraction as the README does. build.sh still gives the writer
the library beside it, so that the library run and the library built in
are the same one.

README, to what was decided for these writers: the outputs must be
identical from every form and the D and Gleam writers must agree byte
for byte, but they are not held to spine's bytes; each format has its
own judge, and a difference from spine is there to read better. The
introduction said "identical to each other and to spine's", and the
example compared --text with spine's text file, which fails by
design; the example now compares the .ssp and the .ocda.db. The
documents the checks run over are the markup document samples, named
with their repository and the spine flags that build the artefacts,
and the counts read "all" or "every document" rather than a number,
here and in dlang/, gleam/ and pipeline/README.md. The format is 2.1,
and the license is stated.

Checked: D and Gleam build from the lock; over the markup document
samples, D == Gleam in text, markdown, html, epub and typst for every
document-language, and the .ssp and the .ocda.db give the same output.

(assisted by Claude-Code)
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The writer's version follows the format's: 2.1.0 in dub.json,
gleam.toml and both flakes (it was 2.0.0), and manifest.toml locks the
library at 2.1.0 to match. A release is numbered major.minor.patch,
major.minor being the format and shared with the specification and
the library, the patch the writer's own.

flake.lock, in dlang/ and gleam/, pins the library at its 2.1.0
release and nixpkgs as that release locks it, so the writer builds
with what the library was built and checked with. The READMEs say
plain nix build, and how to build against a working copy of the
library instead.

The pipeline no longer builds or runs sisudoc-ssp-reader and
sisudoc-ocda-db-reader, which are frozen: ocda-read, the library's
reader, covers both, and read.sh already ran it from both forms and in
both languages. Gone from build.sh, config.sh, one.sh and read.sh, and
from pipeline/README.md, which with config.sh now names spine's
--show-abstraction as the README does. build.sh still gives the writer
the library beside it, so that the library run and the library built in
are the same one.

README, to what was decided for these writers: the outputs must be
identical from every form and the D and Gleam writers must agree byte
for byte, but they are not held to spine's bytes; each format has its
own judge, and a difference from spine is there to read better. The
introduction said "identical to each other and to spine's", and the
example compared --text with spine's text file, which fails by
design; the example now compares the .ssp and the .ocda.db. The
documents the checks run over are the markup document samples, named
with their repository and the spine flags that build the artefacts,
and the counts read "all" or "every document" rather than a number,
here and in dlang/, gleam/ and pipeline/README.md. The format is 2.1,
and the license is stated.

Checked: D and Gleam build from the lock; over the markup document
samples, D == Gleam in text, markdown, html, epub and typst for every
document-language, and the .ssp and the .ocda.db give the same output.

(assisted by Claude-Code)
</pre>
</div>
</content>
</entry>
<entry>
<title>format 2.1: the pipeline reads with ocda-read</title>
<updated>2026-10-05T20:00:39+00:00</updated>
<author>
<name>Ralph Amissah</name>
<email>ralph.amissah@gmail.com</email>
</author>
<published>2026-10-05T20:00:39+00:00</published>
<link rel='alternate' type='text/html' href='https://git.sisudoc.org/sisudoc-ocda-writer/commit/?id=ad7df51055c5908059d5cb88793d7a14f21b5824'/>
<id>ad7df51055c5908059d5cb88793d7a14f21b5824</id>
<content type='text'>
sisudoc-ocda-lib now has a reader, ocda-read, in D and in Gleam, which
reads every form. The pipeline runs it: one.sh read-d and read-g,
passing the modes after the file, and read.sh taking its --tree from
the .ssp and the .ocda.db in both languages. The two older readers
are still built and run beside it.

build.sh built the D library's two programs separately into the one
result link, so the second replaced the first and one.sh dump-d found
no ocda-dump after a clean build. The library's default is now all
three programs, built once.

flake.lock, in dlang/ and gleam/, now pins the library at the commit
that brings ocda-read, and nixpkgs as that commit locks it.

(assisted by Claude-Code)

</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
sisudoc-ocda-lib now has a reader, ocda-read, in D and in Gleam, which
reads every form. The pipeline runs it: one.sh read-d and read-g,
passing the modes after the file, and read.sh taking its --tree from
the .ssp and the .ocda.db in both languages. The two older readers
are still built and run beside it.

build.sh built the D library's two programs separately into the one
result link, so the second replaced the first and one.sh dump-d found
no ocda-dump after a clean build. The library's default is now all
three programs, built once.

flake.lock, in dlang/ and gleam/, now pins the library at the commit
that brings ocda-read, and nixpkgs as that commit locks it.

(assisted by Claude-Code)

</pre>
</div>
</content>
</entry>
<entry>
<title>format 2.1: the poem, and a note mark of a symbol and a number</title>
<updated>2026-09-29T21:56:11+00:00</updated>
<author>
<name>Ralph Amissah</name>
<email>ralph.amissah@gmail.com</email>
</author>
<published>2026-09-29T21:56:11+00:00</published>
<link rel='alternate' type='text/html' href='https://git.sisudoc.org/sisudoc-ocda-writer/commit/?id=cc0b844be3822ac45603a095ceee77dc0f231288'/>
<id>cc0b844be3822ac45603a095ceee77dc0f231288</id>
<content type='text'>
From format 2.1 a poem comes before its verses, carries object number
0 and states the range of its verses, where it came after them sharing
the last verse's number. The text writer's rule, an object with no
text writes nothing, covers both forms and is unchanged; its comment,
in both languages, and the README now describe the poem as it is.

Spine now writes the markup's editor's notes, ~[* ]~ and ~[+ ]~, as
their own numbered series, marked *1, *2 ... and +1, +2 ..., in the
form the special notes already had. The note patterns took symbols
alone, so in every writer, both languages, these went through as text.
They now take [*+]+[0-9]* where they took symbols.

Over the markup document samples written by spine at 2.1: D == Gleam
byte for byte in all five formats; the same .typ from .ssp and
.ocda.db; spine's .typ body == this writer's; epubcheck clean; every
html link resolves. Against the same writers over 2.0 artefacts, two
things move, both the abstraction's doing: the_public_domain's html
and epub gain note 84, which 2.0 never gathered; and seven epubs lose
an empty body.xhtml page listed in the navigation, which was where the
2.0 poems went for want of a segment.

The repository is sisudoc-ocda-writer, in the singular: named for its
role, as its siblings are. It holds one writer, ocda-write, in each
language, taking the format as an option.

flake.lock, in dlang/ and gleam/, now pins the library at its
model 2.1 commit.

(assisted by Claude-Code)

</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
From format 2.1 a poem comes before its verses, carries object number
0 and states the range of its verses, where it came after them sharing
the last verse's number. The text writer's rule, an object with no
text writes nothing, covers both forms and is unchanged; its comment,
in both languages, and the README now describe the poem as it is.

Spine now writes the markup's editor's notes, ~[* ]~ and ~[+ ]~, as
their own numbered series, marked *1, *2 ... and +1, +2 ..., in the
form the special notes already had. The note patterns took symbols
alone, so in every writer, both languages, these went through as text.
They now take [*+]+[0-9]* where they took symbols.

Over the markup document samples written by spine at 2.1: D == Gleam
byte for byte in all five formats; the same .typ from .ssp and
.ocda.db; spine's .typ body == this writer's; epubcheck clean; every
html link resolves. Against the same writers over 2.0 artefacts, two
things move, both the abstraction's doing: the_public_domain's html
and epub gain note 84, which 2.0 never gathered; and seven epubs lose
an empty body.xhtml page listed in the navigation, which was where the
2.0 poems went for want of a segment.

The repository is sisudoc-ocda-writer, in the singular: named for its
role, as its siblings are. It holds one writer, ocda-write, in each
language, taking the format as an option.

flake.lock, in dlang/ and gleam/, now pins the library at its
model 2.1 commit.

(assisted by Claude-Code)

</pre>
</div>
</content>
</entry>
<entry>
<title>format 2.0: sample writers over the abstraction, in D and in Gleam</title>
<updated>2026-09-27T19:39:02+00:00</updated>
<author>
<name>Ralph Amissah</name>
<email>ralph.amissah@gmail.com</email>
</author>
<published>2026-09-27T19:39:02+00:00</published>
<link rel='alternate' type='text/html' href='https://git.sisudoc.org/sisudoc-ocda-writer/commit/?id=8d03e44a28c3d1de7d59b07f5e7f611cde0c38c6'/>
<id>8d03e44a28c3d1de7d59b07f5e7f611cde0c38c6</id>
<content type='text'>
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 &lt;file&gt; [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 &lt;a id=x&gt;, 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 &lt;h0&gt;; 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)
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
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 &lt;file&gt; [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 &lt;a id=x&gt;, 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 &lt;h0&gt;; 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)
</pre>
</div>
</content>
</entry>
</feed>
