| Commit message (Collapse) | Author | Age | Files | Lines |
| | |
|
| |
|
|
|
|
|
|
|
|
| |
serial processing, it turns out, is significantly faster and more
efficient for tested use-cases, which came as a surprise. As the
parallelization option buys nothing, serial processing is set as
default. Parallel processing remains as an option (where
available, as before).
(assisted by Claude-Code)
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Fix issue with consistency (flags run serial & parallel
inconsistenly).
Both write one file per document per language and share no
handle, so they belong on the list with html, epub, text and
sqlite_discrete.
The guard above the list still takes out --pod, --pod2,
--source and the shared sqlite db actions before it is reached, so
those stay serial as they were; checked.
However measurement tests show parallel turn out to result in a
processing slowdown, on the (35) sample markup documents, run on
multiple passes: run on 16 cores a slow down of about 20% for
eleven times the cpu!
--text 4.83-5.10 s wall 48-52 s user
--text --serial 3.94-4.05 s wall 4.2-4.4 s user
will make serial run the default.
(assisted by Claude-Code)
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
fix of a couple of issues with tests.
test-search-cgi.sh reported PASS while printing "Schema version gate:
skipped, sqlite3 not on PATH", and the values it searches for were the
hardcoded fallbacks rather than values read out of the database it had
just built. Both halves need sqlite3, both are checks, and a run that
leaves them out still exits 0. The other three scripts re-run
themselves under nix shell "nixpkgs#sqlite"; this one now does the
same. sqlite3 is still not required: with neither sqlite3 nor nix the
test runs as before and says what it skipped.
test-abstraction-ssp.sh depends on --abstraction for its meaning, and
nothing in it said so. --show-abstraction does not appear in spine's
parallelise() list, so dropping that one flag turns the current run
serial, and the parallel-versus-serial comparison below it then
compares a serial run with itself - the guard gone, with nothing
failing to report it. That is how the multi-lingual write race survived.
A comment at the call now says not to drop it.
(assisted by Claude-Code)
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
abstraction directory cleared once, by whichever language is first
The .ssp writer clears stale files out of
pod/<doc>/media/abstraction/, and that one directory is shared by
every language of a document. The clearing is now done once per
directory per run, by whichever language reaches it first, with
the lock held across it. A language that finds the directory
already prepared has passed through that same lock before writing,
so the clearing it skipped had completed before its own write
began: no .ssp produced on a given run can be removed during it.
(removes possibility of a race condition on parallelisation)
(assisted by Claude-Code)
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Spine now declares sqlite_db_schema_version and stamps it into the
database as PRAGMA user_version when the tables are created, in
both the shared and the discrete DDL blocks. On opening an
existing database it compares, and says once per run which version
it found and which it writes.
Failures are now tallied (shared, the output can run in parallel),
reported one line each on stderr naming the operation, and main
exits 1 without printing "run complete, ok".
Two tests under test/, both taking the spine binary as their first
argument and building their own database from data/pod unless
$SpinePOD says otherwise:
test-search-db-schema.sh names: every column the search form
uses exists, and spine's declaration, the database's stamp
and the search form's expectation all agree
test-search-cgi.sh behaviour: the real search binary answers
real requests against a fresh database, no web server
involved, the probe values read out of whichever database it
is given
(assisted by Claude-Code)
|
| |
|
|
|
|
|
| |
The metadata page gains a line between the markup source and the
source digests.
(assisted by Claude-Code)
|
| |
|
|
|
|
|
|
|
| |
ocda (object centric document abstraction)
flag --ocda-db (or --abstraction-db)
replaces --show-abstraction-db
rename results in consequently large diff
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
pod/ holds all document source representations:
pod/<doc>/ source tree
pod/<doc>/media/abstraction/<uid>.ssp abstraction, as text
pod/<doc>.zip tree, zipped, .ssp included
pod/<doc>.digests.txt sha256s of what is in them
pod/<uid>.ocda.db abstraction, as sqlite db
<lang>/abstraction/ is gone.
pod/<doc>/media/abstraction/<uid>.ssp preferred as having the
images (found within the pod tree) which .ssp needs to reproduce a
document but does not carry on its own.
The .ocda.db sits carries the images as well and (like the
pod.zip) can be used to reproduce a document directly.
digests.txt now covers the database as well as the zip, the source
and the .ssp; (as does the metadata html page).
Two ordering issues addressed:
- the pod builder clean-slates pod/<doc>/ before regenerating it,
and the .ssp is now written before that runs. The clean slate
now leaves media/abstraction/ alone, and the .ssp writer clears
that directory itself on the first language of a run, so a .ssp
for a language the document no longer is removed and cannot be
bundled.
- for a multi-language document the .ssp files accumulate one
language at a time and are bundled on the last, which is why the
directory cannot simply be emptied by whichever (language) gets
there first.
(assisted by Claude-Code)
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
sisudoc.ocda.abstraction.load names the five things a document can
be read from, tells them apart, and loads the two that are
self-describing artefacts:
.sst / .ssm + images the markup source
pod (dir) + images the same, bundled
pod .zip the same, zipped
.ssp + images the abstraction, as text
.ocda.db the abstraction, sqlite, images inside
abstractionSourceOf(path) is the detection, by name and for a
directory by whether it holds pod.manifest. abstractionLoad(path)
returns a LoadedAbstraction: the source kind, whether it was
loaded, why not when it was not, and the document itself.
The three source forms are deliberately not loaded here. Reading
them is the parser's job (sisudoc.ocda.meta.metadoc
spineAbstraction) and it needs the manifest, environment and
configuration that spine.d assembles, none of which belongs in a
loader. What this gives that case is the dispatch and a plain
statement of where it is handled, rather than a silent empty
result.
spine --abstraction-source=<path>
says what a path is and, for an artefact, loads it and reports
what came back: the document, title and author, header block
sizes, object counts and the objects in each section. Exit 0 when
an abstraction was loaded, 1 when not.
(assisted by Claude-Code)
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The per document database is now written as <doc_uid>.ocda.db
rather than <doc_uid>.abstraction.db. Shorter, and it says what is
in the file: the object centric document abstraction, not "some
abstraction". .ocda.db pairs with .ssp and cannot be mistaken for
the collection search database (spine.search.db).
test/run-tests.sh runs the four in sequence, one line of result
each, and a summary. It re-runs itself inside nix shell
"nixpkgs#sqlite" if sqlite3 is not on PATH, so this is all that
is needed:
SpinePOD=../../markup/sisudoc-spine-samples/markup/pod-samples/pod \
./test/run-tests.sh ./bin/spine-ldc
The tests are independent (with test-abstraction-ssp.sh run
first):
1 test-abstraction-ssp.sh is first because it is the
one that says whether the abstraction itself moved; if it
fails the others are answering a different question than you
think
2 test-abstraction-ssp-roundtrip.sh reads the committed
reference set, so it is a statement about the current binary
only if 1 passes
3 test-abstraction-db.sh and
4 test-abstraction-db-roundtrip.sh generate both artefacts
themselves and depend on nothing committed
(assisted by Claude-Code)
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The ocda database is now built from the .ssp itself: the writer's
lines are emitted, read straight back by ssp_in, and the objects
that come out populate the database. Anything the .ssp does not
carry, the database will not have either, by construction (rather
than by test).
[instead of as previously through a second walk over the in-memory
abstraction]
- spineAbstractionTxt is split: sspDocumentLines(doc) returns the
whole .ssp as lines, and the file writer emits them. Output
neutral, the reference test confirms.
- spineAbstractionDb takes the abstraction as an argument rather
than taking doc.abstraction.
- sspRoundTripAbstraction(doc) in ssp_in is the join: lines out,
lines in, abstraction returned. Both call sites in spine.d use
it.
- the header blocks and the image blobs still come from
doc_matters (as: the .ssp does not carry image bytes).
All (35) markup sample sourced databases built through the .ssp
have byte identical SQL dumps to the one built directly before the
change.
That comparison also found one reader inaccuracy, which the .ssp
round trip could not see because the writer omits the field either
way: an absent identifier was restored as the ocn in every case,
but for an object with no ocn it was empty ("a"~N identifiers are
always written). Fixed; the two artefacts checking each other is
what caught it.
(assisted by Claude-Code)
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
sisudoc.ocda.abstraction.db_in reads a <doc>.abstraction.db back
into ObjGenericComposite[][string], the same value ssp_in returns
from a .ssp, so a consumer need not know which artefact it was
handed. It mixes in the .ssp reader for that shared document
struct rather than declaring a second one.
--db-round-trip=<file.abstraction.db> reads a database and emits
it as .ssp on stdout, through sspObjectRecord as the other round
trip does. Held against the .ssp written from the same document,
this says whether the two artefacts really carry the same thing:
not a count of fields, as test-abstraction-db.sh does, but the
whole document reconstructed from the database and compared to the
text.
SpinePOD=... ./test/test-abstraction-db-roundtrip.sh ./bin/spine-ldc
PASS: all 35 databases re-emit their document's .ssp exactly
It passed on the first run over the whole sample set, which is evidence
that the database is now field-complete against the .ssp rather than
merely counting the same.
Four tests with different checks:
test-abstraction-ssp.sh the abstraction has not changed
test-abstraction-db.sh the two serialisations agree, field by field
test-abstraction-ssp-roundtrip.sh the .ssp can be read back whole
test-abstraction-db-roundtrip.sh the .db can be read back whole
(assisted by Claude-Code)
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Reads each committed reference .ssp back into the abstraction, emits
it again, and requires byte identity. Both directions go through
template sspObjectRecord, the writer's own definition of a record, so
what is being checked is the reader against the writer and not against
a second description of the format.
./test/test-abstraction-ssp-roundtrip.sh ./bin/spine-ldc
PASS: all 35 .ssp files read back and re-emit byte identically
It needs no sample documents and no output directory; the reference
set is the input. So the three tests now say three different things:
test-abstraction-ssp.sh the abstraction has not changed
test-abstraction-db.sh the two serialisations agree
test-abstraction-ssp-roundtrip.sh the .ssp can be read back whole
Added with -f, as test/ is covered by .gitignore's catch-all.
(assisted by Claude-Code)
|
| | |
|
| |
|
|
|
|
| |
heading text used for navigation is normalised, and | escaped
(assisted by Claude-Code)
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
markedup_ancestors, collapsed_ancestors, the two dom status arrays
and heading_ancestors_text were declared as int[] / string[] with
a literal default:
int[] markedup_ancestors = [ 0, 0, 0, 0, 0, 0, 0, 0, ];
which is one array, shared by every default constructed object:
write into one by index and you write into all of them. They are
now int[8] / string[8], where that is impossible.
Output neutral confirmed by reference test.
Provides a fix: Previously the parser always assigned these whole
and with .dup so it never went through the shared array. This left
a trap in previous code which caught the new .ssp reader, whose
first version wrote by index and gave every object in a document
the last one's ancestors.
(assisted by Claude-Code)
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
sisudoc.ocda.abstraction.ssp_in reads a .ssp file back into
ObjGenericComposite[][string], the same value the parser produces,
so anything that consumes the abstraction can be fed from a .ssp
instead of from markup. The three header blocks come back as
key/value with their order preserved.
--ssp-round-trip=<file.ssp> loads a file and emits it again on
stdout, using sspObjectRecord, the writer's own definition of a
record. So the check is against the writer, not against a second
description of the format:
./bin/spine-ldc --ssp-round-trip=test/reference/abstraction/<doc>.ssp \
| diff test/reference/abstraction/<doc>.ssp -
BUG as yet to FIX
27 of the 35 reference documents round trip byte identically. The
other 8 fail on two defects in the *writer* that the round trip
found, and which are left for a decision:
1. .heading_ancestors_text and .lev4_subtoc can carry a raw newline,
because a heading's text may contain a line break. The value then
spans two physical lines and the format's rule that a value runs to
the end of the line is broken. 194 and 22 occurrences, in the seven
live-manual translations.
2. .heading_ancestors_text joins its eight slots with "|" while the
text in them may itself contain "|". 22 occurrences in
revisiting_the_autonomous_contract.
Both need an escape (or normalisation at source) and both change the
.ssp, so require a decision and another reference regeneration.
ocda: export the .ssp reader from the abstraction package
package.d is the re-export surface for consumers that want to reach
the abstraction without depending on the directory layout; the reader
belongs there beside the writer.
(assisted by Claude-Code)
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
one definition of an object record, so a reader can be held to it.
Pure refactor: the per-object emission moves out of the write
loop into template sspObjectRecord, taking the object and its
section and returning the lines. The writer mixes it in and
calls it.
The point is the reader that follows. With one definition of what
an object record looks like, a round trip can be checked against
the writer itself rather than against a second, hand-kept
description of the format, which is how the .ssp and the
abstraction db drifted apart in the first place.
(emitted text is byte identical)
(assisted by Claude-Code)
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
With these the .ssp carries every field the output writers read.
The two that were missing were both read by the sqlite search
writer, and one of them is needed by anything that wants to know
where an object sits in a segmented output:
- .segment_html_is / .segment_epub_is
(tags.html_segment_anchor_tag_is, epub_segment_anchor_tag_is),
the segment an object *belongs to*, as against .segment
(in_segment_html), which is the segment a heading *opens* and is
set on headings only: 32 of 36 headings and 0 of 109 paragraphs
in the autonomous contract. Without them a reader cannot tell
which segment a paragraph is in.
- .identifier for non-heading objects, the "a"~N series given to
objects whose number is suppressed. A heading already carried it
on its declaration line; every other object now carries it as a
property, on the same condition, that it differs from the ocn.
The same two segment fields are added to the abstraction db
(segment_html_is, segment_epub_is) and to the cross-check test, so the
two serialisations stay level.
.ssp reference regenerated
output run (--text --latex --epub --html --curate) byte identical
to before the change, as it must be since no output writer reads
either artefact.
(assisted by Claude-Code)
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
cross-check .ssp & ocda (abstraction) db against each other
To prevent drift, this compares them directly to detect one writer
gaining a field and the other not (rather than each against a
committed reference, so there is no new fixture to keep current)
For every sample document it generates both artefacts and asserts:
- the same number of objects, and the same number in each of the eight
sections
- for 32 single valued properties, that the count of the .ssp property
equals the count of rows where the corresponding column is set
- for the four repeatable properties (.image, .stow_link, .anchor_tag,
.lev4_subtoc), that the count equals the rows in its table
- that every image the abstraction referred to and found is carried in
the files table
- that the text of the first and last citable body object is byte
identical in the two
- that the database says what it is (metadata schema.version)
SpinePOD=../../markup/sisudoc-spine-samples/markup/pod-samples/pod \
nix shell "nixpkgs#sqlite" -c ./test/test-abstraction-db.sh ./bin/spine-ldc
A sqlite error on a missing column is reported as a mismatch
rather than aborting the run.
The other half of this step, one shared field description behind
both writers, is not done here: the cross-check gives the same
guarantee without touching either writer, and the question becomes
moot if, as planned, the database comes to be generated from the
.ssp through the loader.
Added with -f: test/ is covered by .gitignore's catch-all, as
test/test-abstraction-ssp.sh was before it.
(assisted by Claude-Code)
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
An FTS5 virtual table over the object text, external content
(content='objects', content_rowid='id') so the text is not stored
twice, built from the rows once they are written. This is per
document, for exploring one abstraction; the collection wide
search database is a separate thing and is unaffected.
SELECT o.ocn, o.text FROM objects_fts f JOIN objects o ON o.id=f.rowid
WHERE f.text MATCH 'mercatoria';
War and Peace, 12,135 objects: 100 full text queries in 0.23s
including 100 process starts, 400 hits for Napoleon.
Three views name the shapes worth asking for, so that datasette or
anyone opening the file finds them without writing SQL:
outline (headings with their levels and interval),
citable (ocn > 0),
document_files (what the file carries).
Over the document sample the index size is/adds about a quarter
that of the files.
(assisted by Claude-Code)
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Four things in the abstraction are open ended lists that a single
row cannot hold, and which the database therefore could not
express at all: a paragraph's extracted links, its anchor tags, a
heading's lev4 subtoc entries, and the image records. Each now has
a table keyed on the object, ordered by seq:
object_images, object_links, object_anchors, object_subtoc
And the images themselves are carried in the file, in a files
table with role, name, bytes, sha256, pixel size and the blob. The
point is self-sufficiency: html copies every image into its output
tree, epub and odt place them in their zips, and xelatex reads
them from disk, so an abstraction without the bytes cannot produce
a document, only its text and structure. The table is deliberately
generic rather than an images feature, so that the same mechanism
can later carry the source .sst or the pod's configuration by
adding a row with another role, and so that a reader can ask
whether a database carries its images (select count(*) from files
where role='image') and fall back to a directory beside it when
the answer is zero.
Bytes are stored exactly as read and the digest is taken over them.
Only images the document references are carried: the sisu manual's
media/image holds 10 files and 5 are in its image list, so 5 are
stored.
(assisted by Claude-Code)
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Added the structure ocda was extended to compute as JSON arrays
(a column each).
JSON arrays, allows SQL can reach inside them
(with CHECK(json_valid()) on each)
select ocn from objects where json_extract(ancestors,'$[4]') = 9;
select ocn from objects where json_array_length(children) > 3;
ancestors and table_widths change format for this reason; nothing
outside spine reads the file yet, and metadata now records what it is:
schema.name, schema.version, source.filename, source.language.
INTEGER PRIMARY KEY in place of AUTOINCREMENT, which was paying
for a guarantee not needed here and creating sqlite_sequence, and
UNIQUE(section, seq), which is the table's actual key.
Note for anyone editing this file: the schema is a D string handed to
sqlite, so comments inside it must be SQL comments. A D /+ +/ comment
there aborts the statement and leaves the table missing, silently.
(assisted by Claude-Code)
|
| |
|
|
|
|
|
|
|
|
| |
drop WAL so the file can be read read-only: journal_mode=WAL was
set in the file header and A WAL database cannot be opened by a
reader that cannot also write beside it (this ruled out a
read-only directory, read-only media, and anything that wants to
read the artefact where it sits).
(assisted by Claude-Code)
|
| |
|
|
|
|
|
| |
remove four dead fields, two of them serialised, none of the
them were assigned (or called for reading).
(assisted by Claude-Code)
|
| |
|
|
| |
track on sisu markup sample
|
| | |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Several structure fields (now) computed in ocda do not yet have a
consumer outside the `.ssp` writer (which shares ocda fields in a
PEG parsable .ssp file). Their addition is to facilitate future
output processing: each representing document structure
information that document output generators of various formats,
such as html, epub, latex, sql and any DOM based / tree-graph
(node based hierarchical) representations, previously had to, or
would have to, work out for themselves based on what ocda offered
(without them).
Computing them (upstream) in ocda once and sharing them (and
providing the .ssp), means that:
- future output formats can start from prepared structure rather
than deriving it;
- existing generators can be simplified to consume them instead
of re-deriving;
- a (dlang) generator could in principle be populated either from
ocda directly or from a `.ssp` file;
- `.ssp` being PEG parsable puts the same prepared structure in
reach of implementations in other languages.
`test/test-abstraction-ssp.sh` the `.ssp` reference regression
test is used to catch regression in ocda including these as yet
unused fields, which otherwise would remain unseen until used by
other output-format consumers. This also is the reason issues now
made easily visible and are being addressed (without issue to
existing output generators).
(assisted by Claude-Code)
|
| |
|
|
|
|
|
|
| |
ocda: fixed inverted object_number_off on body paragraphs
ssp: make use of curly braces (code-style)
(assisted by Claude-Code)
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
--+# clears dummy_heading_multiple_objects, fixed
until fix, following any ---# ... --+# block every ~# object in
the document was marked dummy_heading, (and the output generators
that honour that flag suppressed its text: so ~# behaved as -#.
One line added to correct the --+# branch.
~# suppresses the object's number only, content is still shown.
-# is for a heading introduced solely to segment an output:
object number suppressed and the heading text omitted from the
body where the output format allows, the toc entry kept. Both were
already correct in isolation; only the leaked block flag broke ~#.
(assisted by Claude-Code)
|
| |
|
|
|
|
|
|
| |
sisu-spine-markup.sst needs review and update, it was taken from
the much older sisu (ruby) writing and was itself a part of a more
comprehensive document (sisu-manual). Some updates.
(assisted by Claude-Code)
|
| | |
|
| |
|
|
|
| |
test-abstraction-ssp re-generated: document abstraction (ocda)
document structure representation fixes (verify)
|
| |
|
|
|
|
|
|
|
|
|
|
| |
fix to --abstraction/.ssp: fix document structure, representation
parent, ancestors, children. Make parent_ocn, the marked-up and
collapsed ancestor arrays, and the children correctly represent
the document structure. fixed
(assisted by Claude-Code)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01836BxBb8LvVKJ8sBg7Dx6U
|
| | |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
for document abstraction and its .ssp output, removed the
requirement of including --abstraction & --serial flags to produce
correct output (for: .dom_status, .dom_status_collapsed &
.last_descendant)
- meta_processing_xml_dom() includes show_abstraction, so --pod2
and --show-abstraction run the dom pass; last_descendant is
derived from that pass via after_doc_get_descendants()
The accumulators are now verified as eight wide locals of
docAbstraction(), so each document starts clean and no two threads
share one.
- bug: the four dom accumulators were template scope (shared) and
nine wide, while their end of document reset was eight wide, so
the first document of a run differed from the rest and parallel
runs raced on one buffer, (which also mis-nested epub toc_nav)
test/ reference .ssp regenerated: accelerando only, trailing zero
dropped.
test-abstraction-ssp.sh now runs parallel and diffs output against
a serial run.
(assisted by Claude-Code)
|
| | |
|
| | |
|
| | |
|
| |
|
|
|
|
|
| |
- dmd 2.112.1
- ldc 1.43.0 beta1
- dub 1.41.0
- dtools 2.112.1
|
| |
|
|
|
| |
generrate new reference set of .ssp
test-abstraction-ssp.sh --generate
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
test-abstraction-ssp.sh should fail if $SpinePOD is unset.
SAMPLES_RAW="$SPINE_DIR/$SpinePOD" resolves to the spine directory
itself when the variable is unset. That directory exists, so the
"sample documents not found" check did not fire and spine was
handed every file in the spine tree.
Fail early instead, naming the variable and giving the path the
samples are usually at.
(assisted by Claude-Code)
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
Assumed that headings do not include images, obj_digest() looked
for images only in the non-heading branch, however, the markup
does not forbid one, and an object type left out of the scan
carries neither digest nor .ssp record, silently.
Open Issue: image_list, which drives pod bundling and the @doc_has
images count, is gathered only from para objects (and only the
first image of each), so an image in a heading or in a block body
is recorded in the abstraction but not bundled.
(assisted by Claude-Code)
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
Count them over the assembled body objects, (the body alone).
Previously dochas["inline_links"], ["inline_notes"] and
["inline_notes_star"] were initialised and read but never
incremented, so @doc_has reported 0 inline links and 0 notes for
every document while the block counters (codeblock, poem, group,
block, quote, table) were counted. create_abstraction_db.d records
the same values as document metadata.
(assisted by Claude-Code)
|
| |
|
|
|
|
|
|
|
|
|
| |
every object with an .image record should now carry the images
flag.
Previously DocObj_Has_.images was read but never written anywhere
in the tree, so no object carried it: .ssp emitted has_images = 0
for every object of every document.
(assisted by Claude-Code)
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
For image digests cache file read & hash, one read per image
file
Fix issue: images referenced from several objects were read and
hashed once per reference.
[as an example in the sisu-manual sm_tux.png accounts for 6 of
the document's image records (12 across the sample set), each
of them a fresh read of the same bytes, and source_pod.d hashes
the file again for digests.txt.]
Memoise on the full path within safeComputeHashAndSize. static is
thread-local in D, so documents processed in parallel each get
their own cache and no synchronisation is involved. Files are not
expected to change during a run.
Output is unchanged: identical .ssp output. (An image that is
missing or unreadable now warns once to stdout rather than once
per reference).
(assisted by Claude-Code)
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Complete image file digest identity record: add
px:<width>x<height> to the .ssp image record, read from the
image file header (imageformats.read_image_info, no decode):
.image: won_benkler_2_1.png sha256:5BA4...D128 bytes:93861 px:420x342
(The w##h## dimensions in the markup are display dimensions, not the
file's: they are author set, or where given as w0h0 are derived by
_image_dimensions and capped to a maximum display width, and they
become the width/height attributes of the output format image display).
(assisted by Claude-Code)
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
image digest: record missing or unreadable image, do not abort
safeComputeHashAndSize() open image with guard, so a document
naming an image absent from media/image/ throws
ErrnoException out of the abstraction stage.
as with _image_dimensions() (which warns and continues where issue
with image) warn to stdout and record the fact in the abstraction:
.image: ffa.png missing:true
the abstraction would now state that the object embeds an image it
could not read, rather than the .ssp resemble one produced from a
complete pod. The sha256 summary line marks the same case
MISSING OR UNREADABLE.
(assisted by Claude-Code)
|
| |
|
|
|
|
|
|
|
|
|
| |
a repeatable record, one line per image, filename first:
.image: won_benkler_2_1.png sha256:5BA492C2...D128 bytes:93861
an object embedding more than one image emits more than one .image
line.
(assisted by Claude-Code)
|