<feed xmlns='http://www.w3.org/2005/Atom'>
<title>sisudoc-ssp-reader, branch main</title>
<subtitle>SiSU Spine: tools</subtitle>
<link rel='alternate' type='text/html' href='https://git.sisudoc.org/projects/sisudoc-ssp-reader/'/>
<entry>
<title>frozen: superseded by ocda-read in sisudoc-ocda-lib</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/projects/sisudoc-ssp-reader/commit/?id=b95546cdb4995cf7fe598823f5d3264d53c274a8'/>
<id>b95546cdb4995cf7fe598823f5d3264d53c274a8</id>
<content type='text'>
This reader is no longer maintained. Its modes are carried by
ocda-read, the reader of sisudoc-ocda-lib, which is built on the
library's model and so reads a .ssp, a .ocda.db and a pod alike. On
every .ssp of the markup document samples it gives the D reader's
output byte for byte after the first line (Read: where this says
Parsed:) in --tree, --html, --llm-text, --llm-jsonl, --images,
--verify and --validate; its summary differs only in the closing hint.

The repository is kept as the record of what it showed: two readers,
in D and in Gleam, written from the specification and from nothing
else, agreeing; and a validator that found two rules the
specification had left unstated. Its commits are matched to the
points the specification reached, format 2.0 and format 2.1.

The README says so at its head, and says "every document-language"
where it gave a count; the ruby/ row goes, that reader not now to be
written. The version is 2.1.0, the format this reader was brought to;
it was 2.0.0.

(assisted by Claude-Code)
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
This reader is no longer maintained. Its modes are carried by
ocda-read, the reader of sisudoc-ocda-lib, which is built on the
library's model and so reads a .ssp, a .ocda.db and a pod alike. On
every .ssp of the markup document samples it gives the D reader's
output byte for byte after the first line (Read: where this says
Parsed:) in --tree, --html, --llm-text, --llm-jsonl, --images,
--verify and --validate; its summary differs only in the closing hint.

The repository is kept as the record of what it showed: two readers,
in D and in Gleam, written from the specification and from nothing
else, agreeing; and a validator that found two rules the
specification had left unstated. Its commits are matched to the
points the specification reached, format 2.0 and format 2.1.

The README says so at its head, and says "every document-language"
where it gave a count; the ruby/ row goes, that reader not now to be
written. The version is 2.1.0, the format this reader was brought to;
it was 2.0.0.

(assisted by Claude-Code)
</pre>
</div>
</content>
</entry>
<entry>
<title>format 2.1: .ocn_range is one of the properties</title>
<updated>2026-09-29T18:09:17+00:00</updated>
<author>
<name>Ralph Amissah</name>
<email>ralph.amissah@gmail.com</email>
</author>
<published>2026-09-29T18:09:17+00:00</published>
<link rel='alternate' type='text/html' href='https://git.sisudoc.org/projects/sisudoc-ssp-reader/commit/?id=8b3b995b6aff5c15ba31692fd29113db3c42517f'/>
<id>8b3b995b6aff5c15ba31692fd29113db3c42517f</id>
<content type='text'>
Format 2.1 adds .ocn_range, the first and last ocn a container holds,
emitted after .last_descendant: a poem, which now carries ocn 0 and
comes before its verses, is cited as the range of them. Both readers
now know it as the forty-third property, so --validate accepts a 2.1
file and --report-unknown does not list it. The validator's message
counts the list rather than naming a number.

Every document-language of the markup document samples written by
spine at 2.1 validates; neither reader uses the property, which
within a major version is conforming.

(assisted by Claude-Code)

</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Format 2.1 adds .ocn_range, the first and last ocn a container holds,
emitted after .last_descendant: a poem, which now carries ocn 0 and
comes before its verses, is cited as the range of them. Both readers
now know it as the forty-third property, so --validate accepts a 2.1
file and --report-unknown does not list it. The validator's message
counts the list rather than naming a number.

Every document-language of the markup document samples written by
spine at 2.1 validates; neither reader uses the property, which
within a major version is conforming.

(assisted by Claude-Code)

</pre>
</div>
</content>
</entry>
<entry>
<title>a blank first text line was being lost</title>
<updated>2026-09-26T00:49:49+00:00</updated>
<author>
<name>Ralph Amissah</name>
<email>ralph.amissah@gmail.com</email>
</author>
<published>2026-09-26T00:49:49+00:00</published>
<link rel='alternate' type='text/html' href='https://git.sisudoc.org/projects/sisudoc-ssp-reader/commit/?id=ead2f79ee41db99a292d763fe41f0613a74ef7b3'/>
<id>ead2f79ee41db99a292d763fe41f0613a74ef7b3</id>
<content type='text'>
An object whose first text line is blank lost it. The parser decided
whether to start a new line by asking whether the accumulated text
was empty, which is not the same question as whether a text line has
been seen: for an object opening on a blank line the first line left
the text empty and the second overwrote it rather than appending.

Seven documents of the markup document samples have verse opening on a
blank line, and in every one of them the blank was dropped, so the html,
the plain text and the JSONL chunks all began the verse a line early.
Spine's own text output has the blank line; this now matches.

Found by loading one document as .ssp and as .ocda.db and comparing
the two models object by object, which is what sisudoc-ocda-lib exists
to do. The comparison between the two .ssp readers had not caught it,
being on section counts, which the defect does not disturb.

Also: the repository is named sisudoc-ssp-reader, prefixed as every
repository of this project's own is (binary, package and module names
are unchanged), and the sources follow the specification directory's
name, sisudoc-abstraction-format. And the /+ ↓ +/ comment arrows in
ssp_parser.d, double-encoded by the in-place edit that applied the
fix, are restored; comment text only.

(assisted by Claude-Code)

</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
An object whose first text line is blank lost it. The parser decided
whether to start a new line by asking whether the accumulated text
was empty, which is not the same question as whether a text line has
been seen: for an object opening on a blank line the first line left
the text empty and the second overwrote it rather than appending.

Seven documents of the markup document samples have verse opening on a
blank line, and in every one of them the blank was dropped, so the html,
the plain text and the JSONL chunks all began the verse a line early.
Spine's own text output has the blank line; this now matches.

Found by loading one document as .ssp and as .ocda.db and comparing
the two models object by object, which is what sisudoc-ocda-lib exists
to do. The comparison between the two .ssp readers had not caught it,
being on section counts, which the defect does not disturb.

Also: the repository is named sisudoc-ssp-reader, prefixed as every
repository of this project's own is (binary, package and module names
are unchanged), and the sources follow the specification directory's
name, sisudoc-abstraction-format. And the /+ ↓ +/ comment arrows in
ssp_parser.d, double-encoded by the in-place edit that applied the
fix, are restored; comment text only.

(assisted by Claude-Code)

</pre>
</div>
</content>
</entry>
<entry>
<title>--validate, and a second reader, in Gleam</title>
<updated>2026-09-24T20:33:53+00:00</updated>
<author>
<name>Ralph Amissah</name>
<email>ralph.amissah@gmail.com</email>
</author>
<published>2026-09-24T20:33:53+00:00</published>
<link rel='alternate' type='text/html' href='https://git.sisudoc.org/projects/sisudoc-ssp-reader/commit/?id=bbe505c8d48e822c012c9820dfe93b83dc61bcab'/>
<id>bbe505c8d48e822c012c9820dfe93b83dc61bcab</id>
<content type='text'>
--validate: the specification, executed. A validator written from
ssp-format-specification.md and from nothing else, so that a file can
be held against the document rather than against an implementation.
Each finding names the specification section it comes from, so a
disagreement can be taken back to the text.

It checks the version banner and its major part, the file shape and
the order of the preamble blocks and the nine sections, the two
spaces of a preamble pair, the object declaration and its sixteen
kinds and eight heading levels, that a property is one of the 42 and
in the emitted order, that text lines carry their prefix, the ten
keys of doc_has, and that no line is of a shape the specification
does not define.

Every .ssp of the markup document samples validates clean. Five
classes of deliberate breakage are caught: an unknown major version, a
property that is not one of the 42, a property out of order, a kind
that is not one of the sixteen, and a block that is neither preamble
nor section. Writing it found two rules the specification implied
and did not state (repeated properties are consecutive; no property
follows the text), and both were written into it.

One repository, a reader per language. The readers are not separate
tools that share a name. They are the same specification implemented
more than once, and the interesting thing about them is that they
agree, so they are published as one thing with that claim at the top
of it. The D reader moves to dlang/; the Gleam reader arrives at
gleam/. The language directory is named for the language and not
for the tool: gleam refuses a hyphenated package name, so ssp-reader
cannot be a gleam package and must be ssp_reader.

A .gitignore for the repository, denying everything and whitelisting
what belongs, covering both languages.

Both build under nix, sandboxed and without network. There is no gleam
builder in nixpkgs and gleam build fetches from Hex, so the Gleam build
uses nix-gleam's builder, kept in gleam/nix-gleam/ (MIT), which fetches
each Hex package by the checksum manifest.toml already carries, with no
hash to maintain; the result is an escript wrapped with erlang. The D
reader depends on nothing beyond phobos, so --skip-registry=all is the
whole of what it takes: ldc by default, dmd available as ssp-reader-dmd
(given gcc14, GCC 15 having introduced nullptr in headers dmd's ImportC
does not yet parse).

(assisted by Claude-Code)
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
--validate: the specification, executed. A validator written from
ssp-format-specification.md and from nothing else, so that a file can
be held against the document rather than against an implementation.
Each finding names the specification section it comes from, so a
disagreement can be taken back to the text.

It checks the version banner and its major part, the file shape and
the order of the preamble blocks and the nine sections, the two
spaces of a preamble pair, the object declaration and its sixteen
kinds and eight heading levels, that a property is one of the 42 and
in the emitted order, that text lines carry their prefix, the ten
keys of doc_has, and that no line is of a shape the specification
does not define.

Every .ssp of the markup document samples validates clean. Five
classes of deliberate breakage are caught: an unknown major version, a
property that is not one of the 42, a property out of order, a kind
that is not one of the sixteen, and a block that is neither preamble
nor section. Writing it found two rules the specification implied
and did not state (repeated properties are consecutive; no property
follows the text), and both were written into it.

One repository, a reader per language. The readers are not separate
tools that share a name. They are the same specification implemented
more than once, and the interesting thing about them is that they
agree, so they are published as one thing with that claim at the top
of it. The D reader moves to dlang/; the Gleam reader arrives at
gleam/. The language directory is named for the language and not
for the tool: gleam refuses a hyphenated package name, so ssp-reader
cannot be a gleam package and must be ssp_reader.

A .gitignore for the repository, denying everything and whitelisting
what belongs, covering both languages.

Both build under nix, sandboxed and without network. There is no gleam
builder in nixpkgs and gleam build fetches from Hex, so the Gleam build
uses nix-gleam's builder, kept in gleam/nix-gleam/ (MIT), which fetches
each Hex package by the checksum manifest.toml already carries, with no
hash to maintain; the result is an escript wrapped with erlang. The D
reader depends on nothing beyond phobos, so --skip-registry=all is the
whole of what it takes: ldc by default, dmd available as ssp-reader-dmd
(given gcc14, GCC 15 having introduced nullptr in headers dmd's ImportC
does not yet parse).

(assisted by Claude-Code)
</pre>
</div>
</content>
</entry>
<entry>
<title>dealing with six properties including .is_of_type</title>
<updated>2026-09-24T15:40:02+00:00</updated>
<author>
<name>Ralph Amissah</name>
<email>ralph.amissah@gmail.com</email>
</author>
<published>2026-09-24T15:40:02+00:00</published>
<link rel='alternate' type='text/html' href='https://git.sisudoc.org/projects/sisudoc-ssp-reader/commit/?id=5556b2e14d3c3df5d74e669f7d542b0e526cd216'/>
<id>5556b2e14d3c3df5d74e669f7d542b0e526cd216</id>
<content type='text'>
--report-unknown, added in the previous commit, found a defect on its
first run (rather than a gap): .is_of_type was among the properties
being ignored, and it is the property that says whether an object is
rendered at all.

An object of type "comment" is markup commentary. The abstraction
carries it so that nothing of the source is lost, and no output puts
it in the document. This reader was putting it in three of four:
a comment appeared in the HTML scroll, in the breadcrumbed plain
text, and as an embedding chunk in the JSONL, where it would be
indexed as though the author had written it into the document.
Spine's own HTML for the same document has none.

The decision now lives in one place, SspObject.renders(), and the
three outputs ask it.

Five more properties parsed while here: .section, which is an
object's own section when it differs from the block it sits in;
.identifier, which a non-heading carries when it has one that is not
its ocn, and which now fills the same field a heading fills from its
declaration line; .segment_html_is; .table_aligns, which completes
the table set beside cols, widths and header; and .stow_link, which
is repeatable and accumulates.

That leaves twelve properties ignored across the markup document
samples, down from eighteen, and each for a reason now written
into the README: level bookkeeping this reader does not need, naming
for segmented HTML and EPUB output it does not produce, and .attrib
at one occurrence in all the samples.

(assisted by Claude-Code)

</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
--report-unknown, added in the previous commit, found a defect on its
first run (rather than a gap): .is_of_type was among the properties
being ignored, and it is the property that says whether an object is
rendered at all.

An object of type "comment" is markup commentary. The abstraction
carries it so that nothing of the source is lost, and no output puts
it in the document. This reader was putting it in three of four:
a comment appeared in the HTML scroll, in the breadcrumbed plain
text, and as an embedding chunk in the JSONL, where it would be
indexed as though the author had written it into the document.
Spine's own HTML for the same document has none.

The decision now lives in one place, SspObject.renders(), and the
three outputs ask it.

Five more properties parsed while here: .section, which is an
object's own section when it differs from the block it sits in;
.identifier, which a non-heading carries when it has one that is not
its ocn, and which now fills the same field a heading fills from its
declaration line; .segment_html_is; .table_aligns, which completes
the table set beside cols, widths and header; and .stow_link, which
is repeatable and accumulates.

That leaves twelve properties ignored across the markup document
samples, down from eighteen, and each for a reason now written
into the README: level bookkeeping this reader does not need, naming
for segmented HTML and EPUB output it does not produce, and .attrib
at one occurrence in all the samples.

(assisted by Claude-Code)

</pre>
</div>
</content>
</entry>
<entry>
<title>format 2.0: the version gate</title>
<updated>2026-09-24T15:12:28+00:00</updated>
<author>
<name>Ralph Amissah</name>
<email>ralph.amissah@gmail.com</email>
</author>
<published>2026-09-24T15:12:28+00:00</published>
<link rel='alternate' type='text/html' href='https://git.sisudoc.org/projects/sisudoc-ssp-reader/commit/?id=da833f8b157ae501c9f6eec827dd4a965bfa7265'/>
<id>da833f8b157ae501c9f6eec827dd4a965bfa7265</id>
<content type='text'>
The reader as it stood when the format reached 2.0, in D: a parser of
the .ssp with no dependency beyond phobos, and outputs from it - a
heading tree, an html scroll, breadcrumbed text, chunked jsonl for
embedding pipelines, an image manifest, and a check of image records
against the images on disk.

Brought to abstraction format 2.0, and made able to say what it does
not understand, so a reader can check that its format specification is
complete. Previously the reader ignored what it did not recognise and
reported nothing, which made it seem it had understood a 2.0 file (and
drop things in silence).

Now:
- the banner is read, and the major part checked. A major this
  reader does not know is refused, exit 3, because an unknown major
  means a property may have changed meaning or gone away and loading
  it half populated in silence is the failure the check exists to
  prevent. --any-version reads it regardless, for looking at a file
  rather than trusting one. A file with no banner warns and is read.
- @source is a preamble block beside @meta, @make and @doc_has, and
  the summary line shows the language and the markup digest.
- tail is a section like the rest.
- --report-unknown lists every property, block and line shape met and
  not understood, with counts. Ignoring them remains the conforming
  behaviour within a major version; the counting is so that it is not
  silent.

Over the markup document samples that report names 18 properties,
from .is_of_type at 56,882 occurrences down to .attrib at
1. Several are legitimately of no interest to a renderer and several
are not. Deciding which is which is the next pass, and it now has a
measured work list rather than a guess.

(assisted by Claude-Code)

</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The reader as it stood when the format reached 2.0, in D: a parser of
the .ssp with no dependency beyond phobos, and outputs from it - a
heading tree, an html scroll, breadcrumbed text, chunked jsonl for
embedding pipelines, an image manifest, and a check of image records
against the images on disk.

Brought to abstraction format 2.0, and made able to say what it does
not understand, so a reader can check that its format specification is
complete. Previously the reader ignored what it did not recognise and
reported nothing, which made it seem it had understood a 2.0 file (and
drop things in silence).

Now:
- the banner is read, and the major part checked. A major this
  reader does not know is refused, exit 3, because an unknown major
  means a property may have changed meaning or gone away and loading
  it half populated in silence is the failure the check exists to
  prevent. --any-version reads it regardless, for looking at a file
  rather than trusting one. A file with no banner warns and is read.
- @source is a preamble block beside @meta, @make and @doc_has, and
  the summary line shows the language and the markup digest.
- tail is a section like the rest.
- --report-unknown lists every property, block and line shape met and
  not understood, with counts. Ignoring them remains the conforming
  behaviour within a major version; the counting is so that it is not
  silent.

Over the markup document samples that report names 18 properties,
from .is_of_type at 56,882 occurrences down to .attrib at
1. Several are legitimately of no interest to a renderer and several
are not. Deciding which is which is the next pass, and it now has a
measured work list rather than a guess.

(assisted by Claude-Code)

</pre>
</div>
</content>
</entry>
<entry>
<title>commencement: a reader for the .ssp</title>
<updated>2026-04-22T20:30:13+00:00</updated>
<author>
<name>Ralph Amissah</name>
<email>ralph.amissah@gmail.com</email>
</author>
<published>2026-04-22T20:30:13+00:00</published>
<link rel='alternate' type='text/html' href='https://git.sisudoc.org/projects/sisudoc-ssp-reader/commit/?id=b7d9c3b1c01573ce6499e1b031556c3863df57e7'/>
<id>b7d9c3b1c01573ce6499e1b031556c3863df57e7</id>
<content type='text'>
Work on a reader for spine's .ssp began on this date: a parser of the
text form and outputs from it (a heading tree, html), to show that the
abstraction carries what is needed to present a document without the
markup it was made from.

The reader's versions for the formats before 2.0 are not carried. The
reader as published begins at format 2.0, in the next commit, dated
when it reached 2.0.

(assisted by Claude-Code)
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Work on a reader for spine's .ssp began on this date: a parser of the
text form and outputs from it (a heading tree, html), to show that the
abstraction carries what is needed to present a document without the
markup it was made from.

The reader's versions for the formats before 2.0 are not carried. The
reader as published begins at format 2.0, in the next commit, dated
when it reached 2.0.

(assisted by Claude-Code)
</pre>
</div>
</content>
</entry>
</feed>
