aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRalph Amissah <ralph.amissah@gmail.com>2026-09-11 10:23:25 -0400
committerRalph Amissah <ralph.amissah@gmail.com>2026-09-12 12:14:39 -0400
commitb6b2ff06054edb20c880aff26b8b02d8f093fcc2 (patch)
tree6cc5abb9323808e28227a1791a8717ef4e00485f
parentocda: .ssp should have all sections of abstraction (diff)
ocda: the abstraction carries the document metadata output reads
.ssp format v0.1 -> v1.1, and the .ocda.db with it: they are two serialisations of one format and now move together. The gap this closes, measured against the writers' read set: of the 59 conf_make_meta fields outputs/io_out/ reads, 29 were in neither artefact. Five are conf.* and stay out, being site and run scoped (urls, papersize, the search db filename): the same abstraction published to two sites must take each site's. Of the rest, three are never assigned anywhere (title_short, publisher, original_publisher; read only by sqlite.d, always empty) and one is a copy of a field already carried (title_sub = title_subtitle), so 17 properties actually had to travel and now do: make breaks, footer, home_button_text meta title.edition, date.added_to_site, language.document_char, original.{title,source,language,language_char}, rights.copyright_{text,translation,illustrations, photographs,cover,audio,video} make splits by when it acts, which is worth keeping in mind: these three are read in outputs/io_out/ and must travel, while italics, bold, emphasis, substitute and headings are read at parse time and their effect is already in the objects. New @source block, and source.* rows in the database, so a reader can say which markup an abstraction came from rather than working from stale content in silence: language the document's own languages the pod's list, which is what the inter-language links in html need and neither artefact carried digest sha256 of the .sst; equals its digests.txt entry The database adds source.ssp_digest, the sha256 of the .ssp it was built from, since a file cannot hold its own hash. So the chain .sst -> .ssp -> .ocda.db is checkable end to end. The database's metadata table is now filled from the header blocks the .ssp gives back, not from a second list read off doc_matters. One list, in ssp.d: a property added there arrives in the database with nothing else changed, and one that is not in the .ssp cannot be in the database at all. That was the last place the two could drift; the objects stopped being able to on 2026-09-07. Version is checked on load. The major part must match, a newer minor is accepted (a minor bump only adds properties, and an unknown property line is ignored). A v0.1 artefact is now refused with a message saying to regenerate it, rather than loading half populated. test-abstraction-db.sh now compares the two artefacts' header blocks property by property, 36 per document on the wealth of networks, where it previously only checked that a schema.version row existed. Verified non-vacuous: dropping one property is reported. Reference regenerated, and the whole diff is this change and nothing else: 320 lines added, 35 removed over 35 files, being 35 format lines changed, 35 @source blocks (4 lines each), 35 language.document_char, 35 home_button_text (it has a default), 18 breaks, 16 footer, 4 date.added_to_site, 1 title.edition, 1 original.source. Existing outputs unaffected. (assisted by Claude-Code)
-rw-r--r--org/in_source_files.org94
-rw-r--r--org/out_src_abstraction_ocda_peg_ssp.org88
-rw-r--r--org/out_src_abstraction_sqlite_db.org94
-rw-r--r--org/spine.org4
-rw-r--r--org/tests_for_document_abstraction_shell_scripts.org37
-rw-r--r--src/sisudoc/ocda/abstraction/db_in.d17
-rw-r--r--src/sisudoc/ocda/abstraction/ssp.d88
-rw-r--r--src/sisudoc/ocda/abstraction/ssp_in.d77
-rw-r--r--src/sisudoc/outputs/io_out/create_ocda_db.d94
-rw-r--r--src/sisudoc/spine.d6
-rw-r--r--test/reference/abstraction/accelerando.charles_stross.en.ssp13
-rw-r--r--test/reference/abstraction/alices_adventures_in_wonderland.lewis_carroll.en.ssp11
-rw-r--r--test/reference/abstraction/content.cory_doctorow.en.ssp12
-rw-r--r--test/reference/abstraction/democratizing_innovation.eric_von_hippel.en.ssp12
-rw-r--r--test/reference/abstraction/down_and_out_in_the_magic_kingdom.cory_doctorow.en.ssp12
-rw-r--r--test/reference/abstraction/for_the_win.cory_doctorow.en.ssp12
-rw-r--r--test/reference/abstraction/free_as_in_freedom_2.richard_stallman_and_the_free_software_revolution.sam_williams.richard_stallman.en.ssp12
-rw-r--r--test/reference/abstraction/free_culture.lawrence_lessig.en.ssp12
-rw-r--r--test/reference/abstraction/free_for_all.peter_wayner.en.ssp12
-rw-r--r--test/reference/abstraction/gpl2.fsf.en.ssp10
-rw-r--r--test/reference/abstraction/gpl3.fsf.en.ssp11
-rw-r--r--test/reference/abstraction/gullivers_travels.jonathan_swift.en.ssp12
-rw-r--r--test/reference/abstraction/little_brother.cory_doctorow.en.ssp11
-rw-r--r--test/reference/abstraction/live-manual.ca.ssp10
-rw-r--r--test/reference/abstraction/live-manual.de.ssp10
-rw-r--r--test/reference/abstraction/live-manual.en.ssp10
-rw-r--r--test/reference/abstraction/live-manual.es.ssp10
-rw-r--r--test/reference/abstraction/live-manual.fr.ssp10
-rw-r--r--test/reference/abstraction/live-manual.it.ssp10
-rw-r--r--test/reference/abstraction/live-manual.ja.ssp10
-rw-r--r--test/reference/abstraction/live-manual.pl.ssp10
-rw-r--r--test/reference/abstraction/live-manual.ro.ssp10
-rw-r--r--test/reference/abstraction/not_without_help.austin_amissah.en.ssp12
-rw-r--r--test/reference/abstraction/on_the_net_and_information.ralph_amissah.en.ssp10
-rw-r--r--test/reference/abstraction/outputs_of_ai_systems_qualify_as_artwork.anna_linne.en.ssp10
-rw-r--r--test/reference/abstraction/revisiting_the_autonomous_contract.ralph_amissah.en.ssp10
-rw-r--r--test/reference/abstraction/sisu-manual:sisu_markup.en.ssp12
-rw-r--r--test/reference/abstraction/the_autonomous_contract.ralph_amissah.en.ssp10
-rw-r--r--test/reference/abstraction/the_cathedral_and_the_bazaar.eric_s_raymond.en.ssp12
-rw-r--r--test/reference/abstraction/the_public_domain.james_boyle.en.ssp12
-rw-r--r--test/reference/abstraction/the_wealth_of_networks.yochai_benkler.en.ssp12
-rw-r--r--test/reference/abstraction/through_the_looking_glass.lewis_carroll.en.ssp12
-rw-r--r--test/reference/abstraction/two_bits.christopher_kelty.en.ssp12
-rw-r--r--test/reference/abstraction/viral_spiral.david_bollier.en.ssp12
-rw-r--r--test/reference/abstraction/war_and_peace.leo_tolstoy.en.ssp12
-rwxr-xr-xtest/test-abstraction-db.sh37
46 files changed, 842 insertions, 184 deletions
diff --git a/org/in_source_files.org b/org/in_source_files.org
index e8b5272..6b645b6 100644
--- a/org/in_source_files.org
+++ b/org/in_source_files.org
@@ -813,8 +813,11 @@ template spineAbstractionRead() {
object sections in the order the file gives them
+/
struct SSPdocument {
- string format; // "% SiSU Document Abstraction v0.1"
+ string format; // "% SiSU Document Abstraction v1.1"
string source; // "% Source: ..."
+ string[string] source_info; // the @source block
+ string[] source_info_order;
+ string ssp_digest; // sha256 of the .ssp read, hex
string[string] meta;
string[] meta_order;
string[string] make;
@@ -889,7 +892,7 @@ template spineAbstractionRead() {
_closeObject();
string _name = line[1 .. $-2];
switch (_name) {
- case "meta": case "make": case "doc_has":
+ case "source": case "meta": case "make": case "doc_has":
block = _name; section = ""; break;
default:
block = ""; section = _name;
@@ -904,6 +907,10 @@ template spineAbstractionRead() {
auto _kv = line.stripLeft.findSplit(": "); // leading only: a value may end in a space
if (_kv[1].length > 0) {
final switch (block) {
+ case "source":
+ doc.source_info[_kv[0].to!string] = _kv[2].to!string;
+ doc.source_info_order ~= _kv[0].to!string;
+ break;
case "meta":
doc.meta[_kv[0].to!string] = _kv[2].to!string;
doc.meta_order ~= _kv[0].to!string;
@@ -1069,25 +1076,75 @@ template spineAbstractionRead() {
}
return doc;
}
- /+ ↓ the abstraction as it survives a trip through the .ssp text: emitted
- as lines by the writer, read straight back. what a consumer built
- from this cannot see, the .ssp does not carry, which is what makes a
- second artefact built from it unable to drift
+ /+ ↓ the whole document as it survives a trip through the .ssp text:
+ emitted as lines by the writer, read straight back. what a consumer
+ built from this cannot see, the .ssp does not carry, which is what
+ makes a second artefact built from it unable to drift. the header
+ blocks come back with it, so the database is filled from these and
+ not from a second list read off doc_matters
+/
- auto sspRoundTripAbstraction(D)(D doc) {
+ SSPdocument sspRoundTripDocument(D)(D doc) {
import sisudoc.ocda.abstraction.ssp;
mixin spineAbstractionTxt;
- return sspRead(sspDocumentLines(doc)).abstraction;
+ string[] _lines = sspDocumentLines(doc);
+ auto _out = sspRead(_lines);
+ /+ ↓ the writer emits one line per entry, each with its newline, so this
+ is the digest of the file that is written beside the pod +/
+ _out.ssp_digest = sspDigestOfText(_lines.join("\n") ~ "\n");
+ return _out;
+ }
+ /+ ↓ sha256 of a .ssp, upper case hex, as digests.txt gives it +/
+ string sspDigestOfText(string _text) {
+ import std.digest : toHexString;
+ import std.digest.sha : sha256Of;
+ return _text.sha256Of.toHexString.to!string;
+ }
+ auto sspRoundTripAbstraction(D)(D doc) {
+ return sspRoundTripDocument(doc).abstraction;
+ }
+ /+ ↓ the version a reader will accept.
+
+ the major part must match: a format whose properties have changed
+ meaning is not readable by guesswork, and loading it half populated in
+ silence is the failure this check exists to stop. a newer minor
+ version is accepted, since a minor bump only adds properties and an
+ unknown property line is ignored.
+ +/
+ bool sspFormatVersionOk(string _format_line, string _what) {
+ import sisudoc.ocda.abstraction.ssp : ssp_format_version, ssp_format_version_major;
+ enum _prefix = "% SiSU Document Abstraction v";
+ if (_format_line.length == 0) {
+ writeln("ERROR: ", _what, ": no format line, not a .ssp");
+ return false;
+ }
+ if (!_format_line.startsWith(_prefix)) {
+ writeln("ERROR: ", _what, ": unrecognised format line: ", _format_line);
+ return false;
+ }
+ string _ver = _format_line[_prefix.length .. $].strip;
+ string _major = _ver.findSplit(".")[0];
+ if (_major != ssp_format_version_major) {
+ writeln("ERROR: ", _what, ": .ssp format v", _ver,
+ ", this spine reads v", ssp_format_version_major, ".x (v",
+ ssp_format_version, "). Regenerate the abstraction from its markup.");
+ return false;
+ }
+ return true;
}
SSPdocument sspReadFile(string file_path) {
+ string _text;
string[] _lines;
try {
- _lines = (cast(char[]) file_path.read).to!string.split("\n");
+ _text = (cast(char[]) file_path.read).to!string;
+ _lines = _text.split("\n");
} catch (Exception ex) {
writeln("ERROR: could not read ", file_path, ": ", ex.msg);
return SSPdocument();
}
- return sspRead(_lines);
+ auto _doc = sspRead(_lines);
+ if (!sspFormatVersionOk(_doc.format, file_path)) { return SSPdocument(); }
+ _doc.ssp_digest = sspDigestOfText(_text);
+ return _doc;
}
}
#+END_SRC
@@ -1188,7 +1245,7 @@ template spineAbstractionDbRead() {
return doc;
}
auto db = Database(db_file, SQLITE_OPEN_READONLY);
- /+ ↓ the three header blocks, from the metadata table. the key prefix
+ /+ ↓ the four header blocks, from the metadata table. the key prefix
says which block a row belongs to, and insertion order is kept +/
foreach (row; db.execute("SELECT key, value FROM metadata ORDER BY rowid")) {
string _k = row["key"].as!string;
@@ -1202,16 +1259,25 @@ template spineAbstractionDbRead() {
doc.doc_has[_kk] = _v;
doc.doc_has_order ~= _kk;
} else if (_k.startsWith("schema.")) {
- if (_k == "schema.version") { doc.format = "% SiSU Document Abstraction v0.1"; }
+ if (_k == "schema.version") {
+ doc.format = "% SiSU Document Abstraction v" ~ _v;
+ }
} else if (_k == "source.filename") {
doc.source = _v;
- } else if (_k == "source.language") {
- // carried in the path, not in the .ssp header
+ } else if (_k == "source.ssp_digest") {
+ /+ ↓ this database's own note of the .ssp it was built from. it is
+ not part of the .ssp, so it does not go back into the block +/
+ doc.ssp_digest = _v;
+ } else if (_k.startsWith("source.")) {
+ string _kk = _k["source.".length .. $];
+ doc.source_info[_kk] = _v;
+ doc.source_info_order ~= _kk;
} else {
doc.meta[_k] = _v;
doc.meta_order ~= _k;
}
}
+ if (!sspFormatVersionOk(doc.format, db_file)) { return SSPdocument(); }
/+ ↓ the objects, section by section, in the order they were written +/
string[] _sections;
foreach (row; db.execute(
diff --git a/org/out_src_abstraction_ocda_peg_ssp.org b/org/out_src_abstraction_ocda_peg_ssp.org
index 95efb93..5e26a4f 100644
--- a/org/out_src_abstraction_ocda_peg_ssp.org
+++ b/org/out_src_abstraction_ocda_peg_ssp.org
@@ -32,6 +32,21 @@ rename source_abstraction_peg_txt.d
module sisudoc.ocda.abstraction.ssp;
@safe:
/+ ↓ write document abstraction as human-readable .ssp text file +/
+/+ ↓ the format version, carried by both serialisations: the .ssp says it in
+ its "% SiSU Document Abstraction v" header line and the .ocda.db in its
+ metadata schema.version row, so that one bump moves both.
+
+ a reader checks the major part and refuses what it does not know, rather
+ than loading an older artefact half populated in silence. bump the minor
+ part when a property is added (a reader of the newer format still reads
+ the older one), the major part when one changes meaning or goes away.
+
+ 1.1 2026-09-10 @source block; the document metadata the output writers
+ read carried in full (14 meta and 3 make properties
+ added); was 0.1
++/
+enum ssp_format_version = "1.1";
+enum ssp_format_version_major = "1";
/+ ↓ escaping for values that are folded onto one line
a .ssp property value runs to the end of its line, and
@@ -413,9 +428,22 @@ template spineAbstractionTxt() {
auto doc_matters = doc.matters;
string[] output;
/+ ↓ header comment +/
- output ~= "% SiSU Document Abstraction v0.1";
+ output ~= "% SiSU Document Abstraction v" ~ ssp_format_version;
output ~= "% Source: " ~ doc_matters.src.filename;
output ~= "";
+ /+ ↓ @source block: what this abstraction was made from, so a reader can
+ say whether it is looking at the right images and whether the
+ markup has moved on since. the filename is in the % Source: line
+ above and is not repeated here
+ +/
+ output ~= "@source {";
+ output ~= " language: " ~ doc_matters.src.language;
+ if (doc_matters.pod.manifest_list_of_languages.length > 0) {
+ output ~= " languages: " ~ doc_matters.pod.manifest_list_of_languages.join(" ");
+ }
+ output ~= " digest: " ~ doc_matters.doc_digest.markup_doc.toHexString.to!string;
+ output ~= "}";
+ output ~= "";
/+ ↓ @meta block +/
output ~= "@meta {";
auto meta = doc_matters.conf_make_meta.meta;
@@ -431,6 +459,9 @@ template spineAbstractionTxt() {
if (meta.title_language.length > 0) {
output ~= " title.language: " ~ meta.title_language;
}
+ if (meta.title_edition.length > 0) {
+ output ~= " title.edition: " ~ meta.title_edition;
+ }
if (meta.creator_author.length > 0) {
output ~= " creator.author: " ~ meta.creator_author;
}
@@ -467,9 +498,33 @@ template spineAbstractionTxt() {
if (meta.date_valid.length > 0) {
output ~= " date.valid: " ~ meta.date_valid;
}
+ if (meta.date_added_to_site.length > 0) {
+ output ~= " date.added_to_site: " ~ meta.date_added_to_site;
+ }
if (meta.rights_copyright.length > 0) {
output ~= " rights.copyright: " ~ meta.rights_copyright;
}
+ if (meta.rights_copyright_text.length > 0) {
+ output ~= " rights.copyright_text: " ~ meta.rights_copyright_text;
+ }
+ if (meta.rights_copyright_translation.length > 0) {
+ output ~= " rights.copyright_translation: " ~ meta.rights_copyright_translation;
+ }
+ if (meta.rights_copyright_illustrations.length > 0) {
+ output ~= " rights.copyright_illustrations: " ~ meta.rights_copyright_illustrations;
+ }
+ if (meta.rights_copyright_photographs.length > 0) {
+ output ~= " rights.copyright_photographs: " ~ meta.rights_copyright_photographs;
+ }
+ if (meta.rights_copyright_cover.length > 0) {
+ output ~= " rights.copyright_cover: " ~ meta.rights_copyright_cover;
+ }
+ if (meta.rights_copyright_audio.length > 0) {
+ output ~= " rights.copyright_audio: " ~ meta.rights_copyright_audio;
+ }
+ if (meta.rights_copyright_video.length > 0) {
+ output ~= " rights.copyright_video: " ~ meta.rights_copyright_video;
+ }
if (meta.rights_license.length > 0) {
output ~= " rights.license: " ~ meta.rights_license;
}
@@ -497,6 +552,21 @@ template spineAbstractionTxt() {
if (meta.language_document.length > 0) {
output ~= " language.document: " ~ meta.language_document;
}
+ if (meta.language_document_char.length > 0) {
+ output ~= " language.document_char: " ~ meta.language_document_char;
+ }
+ if (meta.original_title.length > 0) {
+ output ~= " original.title: " ~ meta.original_title;
+ }
+ if (meta.original_source.length > 0) {
+ output ~= " original.source: " ~ meta.original_source;
+ }
+ if (meta.original_language.length > 0) {
+ output ~= " original.language: " ~ meta.original_language;
+ }
+ if (meta.original_language_char.length > 0) {
+ output ~= " original.language_char: " ~ meta.original_language_char;
+ }
if (meta.notes_abstract.length > 0) {
output ~= " notes.abstract: " ~ meta.notes_abstract;
}
@@ -519,6 +589,22 @@ template spineAbstractionTxt() {
} // check
output ~= " auto_num_top_lv: " ~ make.auto_num_top_lv.to!string;
output ~= " auto_num_depth: " ~ make.auto_num_depth.to!string;
+ /+ ↓ the make settings the output writers read. the rest of make
+ (italics, bold, emphasis, substitute, headings) is read at parse
+ time and its effect is already in the objects, so it does not
+ travel; these three are read in outputs/io_out/ and must
+ +/
+ if (make.breaks.length > 0) {
+ output ~= " breaks: " ~ make.breaks;
+ }
+ if (make.footer.length > 0) { // a list: joined, each slot escaped
+ string[] _ft;
+ foreach (_f; make.footer) { _ft ~= sspEscapeValue(_f); }
+ output ~= " footer: " ~ _ft.join("|");
+ }
+ if (make.home_button_text.length > 0) {
+ output ~= " home_button_text: " ~ make.home_button_text;
+ }
output ~= "}";
output ~= "";
/+ ↓ @doc_has block +/
diff --git a/org/out_src_abstraction_sqlite_db.org b/org/out_src_abstraction_sqlite_db.org
index ad719c7..dab8291 100644
--- a/org/out_src_abstraction_sqlite_db.org
+++ b/org/out_src_abstraction_sqlite_db.org
@@ -43,13 +43,17 @@ template spineAbstractionDb() {
import d2sqlite3;
import sisudoc.outputs.io_out.paths_output;
import sisudoc.ocda.io_in.paths_source;
- /+ ↓ the abstraction is passed in rather than taken from doc, because the
+ import sisudoc.ocda.abstraction.ssp : ssp_format_version;
+ /+ ↓ the document is passed in rather than taken from doc, because the
caller hands over one that has been through the .ssp: written as text
and read back. so the database is a function of the .ssp and cannot
- carry anything the .ssp does not
+ carry anything the .ssp does not, header blocks included: the metadata
+ table below is filled from what came back, not from a second list read
+ off doc_matters, which is how the two drifted apart before
+/
- void spineAbstractionDb(D,A)(D doc, A doc_abstraction) {
+ void spineAbstractionDb(D,S)(D doc, S ssp_doc) {
auto doc_matters = doc.matters;
+ auto doc_abstraction = ssp_doc.abstraction;
/+ ↓ output path: beside the pod's zip and digests, not under
<lang>/abstraction/. the database carries its own images, so it is a
distributable artefact in its own right and belongs with the others:
@@ -241,13 +245,18 @@ template spineAbstractionDb() {
SELECT role, name, bytes, sha256, width, height FROM files ORDER BY role, name;
");
- /+ ↓ populate metadata +/
+ /+ ↓ populate metadata, from the header blocks the .ssp gave back.
+ one list, in ssp.d, not two: a property added to the .ssp header
+ arrives here without anything being changed, and one that is not in
+ the .ssp cannot be here at all. the keys are the .ssp's own
+ (title.main, make.doc_type, doc_has.images), prefixed by their block
+ where the block name is not already part of the key.
+ +/
db.run("BEGIN TRANSACTION");
auto meta_stmt = db.prepare(
"INSERT INTO metadata (key, value) VALUES (:key, :value)"
);
- auto meta = doc_matters.conf_make_meta.meta;
void insertMeta(string key, string value) {
if (value.length > 0) {
@@ -257,62 +266,31 @@ template spineAbstractionDb() {
meta_stmt.reset();
}
}
+ void insertBlock(string prefix, string[] keys_in_order, string[string] kv) {
+ foreach (k; keys_in_order) {
+ if (k in kv) { insertMeta(prefix ~ k, kv[k]); }
+ }
+ }
- /+ ↓ what this file is, so a reader can tell before it starts +/
+ /+ ↓ what this file is, so a reader can tell before it starts. the
+ version is the .ssp's own: the two serialisations are one format and
+ move together
+ +/
insertMeta("schema.name", "sisu-abstraction-db");
- insertMeta("schema.version", "1");
- insertMeta("source.filename", doc_matters.src.filename);
- insertMeta("source.language", doc_matters.src.language);
-
- insertMeta("title.main", meta.title_main);
- insertMeta("title.subtitle", meta.title_subtitle);
- insertMeta("title.full", meta.title_full);
- insertMeta("title.language", meta.title_language);
- insertMeta("creator.author", meta.creator_author);
- insertMeta("creator.author_surname", meta.creator_author_surname);
- insertMeta("creator.author_surname_fn", meta.creator_author_surname_fn);
- insertMeta("creator.author_email", meta.creator_author_email);
- insertMeta("creator.illustrator", meta.creator_illustrator);
- insertMeta("creator.translator", meta.creator_translator);
- insertMeta("date.published", meta.date_published);
- insertMeta("date.created", meta.date_created);
- insertMeta("date.issued", meta.date_issued);
- insertMeta("date.available", meta.date_available);
- insertMeta("date.modified", meta.date_modified);
- insertMeta("date.valid", meta.date_valid);
- insertMeta("rights.copyright", meta.rights_copyright);
- insertMeta("rights.license", meta.rights_license);
- insertMeta("classify.topic_register", meta.classify_topic_register);
- insertMeta("classify.subject", meta.classify_subject);
- insertMeta("classify.keywords", meta.classify_keywords);
- insertMeta("classify.loc", meta.classify_loc);
- insertMeta("classify.dewey", meta.classify_dewey);
- insertMeta("identifier.isbn", meta.identifier_isbn);
- insertMeta("identifier.oclc", meta.identifier_oclc);
- insertMeta("language.document", meta.language_document);
- insertMeta("notes.abstract", meta.notes_abstract);
- insertMeta("notes.description", meta.notes_description);
- insertMeta("notes.summary", meta.notes_summary);
-
- /+ ↓ make settings +/
- auto make = doc_matters.conf_make_meta.make;
- insertMeta("make.doc_type", make.doc_type);
- insertMeta("make.auto_num_top_at_level", make.auto_num_top_at_level);
- insertMeta("make.auto_num_top_lv", make.auto_num_top_lv.to!string);
- insertMeta("make.auto_num_depth", make.auto_num_depth.to!string);
-
- /+ ↓ doc_has counts +/
- insertMeta("doc_has.inline_links", doc_matters.has.inline_links.to!string);
- insertMeta("doc_has.inline_notes_reg", doc_matters.has.inline_notes_reg.to!string);
- insertMeta("doc_has.inline_notes_star", doc_matters.has.inline_notes_star.to!string);
- insertMeta("doc_has.tables", doc_matters.has.tables.to!string);
- insertMeta("doc_has.codeblocks", doc_matters.has.codeblocks.to!string);
- insertMeta("doc_has.images", doc_matters.has.images.to!string);
- insertMeta("doc_has.poems", doc_matters.has.poems.to!string);
- insertMeta("doc_has.groups", doc_matters.has.groups.to!string);
- insertMeta("doc_has.blocks", doc_matters.has.blocks.to!string);
- insertMeta("doc_has.quotes", doc_matters.has.quotes.to!string);
+ insertMeta("schema.version", ssp_format_version);
+ insertMeta("source.filename", ssp_doc.source);
+ insertBlock("source.", ssp_doc.source_info_order, ssp_doc.source_info);
+ /+ ↓ the digest of the .ssp this database was built from. a file cannot
+ hold its own hash, so this one is not in the .ssp and is taken here:
+ source.digest says which markup the abstraction came from,
+ source.ssp_digest says which abstraction this database came from,
+ and the chain .sst -> .ssp -> .ocda.db is checkable end to end
+ +/
+ insertMeta("source.ssp_digest", ssp_doc.ssp_digest);
+ insertBlock("", ssp_doc.meta_order, ssp_doc.meta);
+ insertBlock("make.", ssp_doc.make_order, ssp_doc.make);
+ insertBlock("doc_has.", ssp_doc.doc_has_order, ssp_doc.doc_has);
meta_stmt.finalize();
/+ ↓ populate objects +/
diff --git a/org/spine.org b/org/spine.org
index c26944c..50b9ce2 100644
--- a/org/spine.org
+++ b/org/spine.org
@@ -583,6 +583,7 @@ if (settings["ssp-round-trip"].length > 0) {
_out ~= "}";
_out ~= "";
}
+ _block("source", _doc.source_info_order, _doc.source_info);
_block("meta", _doc.meta_order, _doc.meta);
_block("make", _doc.make_order, _doc.make);
_block("doc_has", _doc.doc_has_order, _doc.doc_has);
@@ -631,6 +632,7 @@ if (settings["db-round-trip"].length > 0) {
_out ~= "}";
_out ~= "";
}
+ _blockdb("source", _doc.source_info_order, _doc.source_info);
_blockdb("meta", _doc.meta_order, _doc.meta);
_blockdb("make", _doc.make_order, _doc.make);
_blockdb("doc_has", _doc.doc_has_order, _doc.doc_has);
@@ -1763,7 +1765,7 @@ if (doc.matters.opt.action.ocda_db) {
import sisudoc.ocda.abstraction.ssp_in;
import sisudoc.outputs.io_out.create_ocda_db;
mixin spineAbstractionRead;
- spineAbstractionDb!()(doc, sspRoundTripAbstraction(doc));
+ spineAbstractionDb!()(doc, sspRoundTripDocument(doc));
}
#+END_SRC
diff --git a/org/tests_for_document_abstraction_shell_scripts.org b/org/tests_for_document_abstraction_shell_scripts.org
index 7228170..5f355c8 100644
--- a/org/tests_for_document_abstraction_shell_scripts.org
+++ b/org/tests_for_document_abstraction_shell_scripts.org
@@ -621,11 +621,48 @@ for ssp in $(find "$OUT_DIR/pod" -name "*.ssp" 2>/dev/null | sort); do
rm -f "$OUT_DIR/.dbtxt.$$" "$OUT_DIR/.ssptxt.$$"
done
+ # the header blocks: every @source/@meta/@make/@doc_has property in the .ssp
+ # must be in the database under its own key, with the same value. this is
+ # what catches a header property that reaches one artefact and not the
+ # other, which a count of objects cannot see.
+ awk '
+ /^@(source|meta|make|doc_has) \{$/ { blk=substr($1,2); next }
+ /^\}$/ { blk=""; next }
+ blk != "" && /^ [a-z_.]+: / {
+ k=$1; sub(/:$/,"",k)
+ v=substr($0, index($0,": ")+2)
+ pfx = (blk=="meta") ? "" : blk "."
+ print pfx k "\t" v
+ }
+ ' "$ssp" | sort > "$OUT_DIR/.sspmeta.$$"
+ sqlite3 -separator "$(printf '\t')" "$db" \
+ "select key, value from metadata where key not in
+ ('schema.name','schema.version','source.filename','source.ssp_digest');" \
+ 2>/dev/null | sort > "$OUT_DIR/.dbmeta.$$"
+ if ! diff -q "$OUT_DIR/.sspmeta.$$" "$OUT_DIR/.dbmeta.$$" > /dev/null 2>&1; then
+ [ $doc_fail -eq 0 ] && echo "$base"
+ echo " MISMATCH header blocks (.ssp against metadata table):"
+ diff "$OUT_DIR/.sspmeta.$$" "$OUT_DIR/.dbmeta.$$" | head -8 | sed 's/^/ /'
+ doc_fail=1
+ fi
+ rm -f "$OUT_DIR/.sspmeta.$$" "$OUT_DIR/.dbmeta.$$"
+
+ # the source filename, and the version the two share
+ sf=$(sqlite3 "$db" "select value from metadata where key='source.filename';" 2>/dev/null || echo '')
+ sf_ssp=$(sed -n 's/^% Source: //p' "$ssp" | head -1)
+ if [ "$sf" != "$sf_ssp" ]; then
+ [ $doc_fail -eq 0 ] && echo "$base"
+ echo " MISMATCH source.filename: db '$sf' .ssp '$sf_ssp'"; doc_fail=1
+ fi
+ sv_ssp=$(sed -n 's/^% SiSU Document Abstraction v//p' "$ssp" | head -1)
# the file says what it is
sv=$(sqlite3 "$db" "select value from metadata where key='schema.version';" 2>/dev/null || echo '')
if [ -z "$sv" ]; then
[ $doc_fail -eq 0 ] && echo "$base"
echo " MISSING metadata schema.version"; doc_fail=1
+ elif [ "$sv" != "$sv_ssp" ]; then
+ [ $doc_fail -eq 0 ] && echo "$base"
+ echo " MISMATCH format version: db '$sv' .ssp '$sv_ssp'"; doc_fail=1
fi
FAILURES=$((FAILURES + doc_fail))
diff --git a/src/sisudoc/ocda/abstraction/db_in.d b/src/sisudoc/ocda/abstraction/db_in.d
index 0da123d..3d10540 100644
--- a/src/sisudoc/ocda/abstraction/db_in.d
+++ b/src/sisudoc/ocda/abstraction/db_in.d
@@ -136,7 +136,7 @@ template spineAbstractionDbRead() {
return doc;
}
auto db = Database(db_file, SQLITE_OPEN_READONLY);
- /+ ↓ the three header blocks, from the metadata table. the key prefix
+ /+ ↓ the four header blocks, from the metadata table. the key prefix
says which block a row belongs to, and insertion order is kept +/
foreach (row; db.execute("SELECT key, value FROM metadata ORDER BY rowid")) {
string _k = row["key"].as!string;
@@ -150,16 +150,25 @@ template spineAbstractionDbRead() {
doc.doc_has[_kk] = _v;
doc.doc_has_order ~= _kk;
} else if (_k.startsWith("schema.")) {
- if (_k == "schema.version") { doc.format = "% SiSU Document Abstraction v0.1"; }
+ if (_k == "schema.version") {
+ doc.format = "% SiSU Document Abstraction v" ~ _v;
+ }
} else if (_k == "source.filename") {
doc.source = _v;
- } else if (_k == "source.language") {
- // carried in the path, not in the .ssp header
+ } else if (_k == "source.ssp_digest") {
+ /+ ↓ this database's own note of the .ssp it was built from. it is
+ not part of the .ssp, so it does not go back into the block +/
+ doc.ssp_digest = _v;
+ } else if (_k.startsWith("source.")) {
+ string _kk = _k["source.".length .. $];
+ doc.source_info[_kk] = _v;
+ doc.source_info_order ~= _kk;
} else {
doc.meta[_k] = _v;
doc.meta_order ~= _k;
}
}
+ if (!sspFormatVersionOk(doc.format, db_file)) { return SSPdocument(); }
/+ ↓ the objects, section by section, in the order they were written +/
string[] _sections;
foreach (row; db.execute(
diff --git a/src/sisudoc/ocda/abstraction/ssp.d b/src/sisudoc/ocda/abstraction/ssp.d
index d29737b..6b487d7 100644
--- a/src/sisudoc/ocda/abstraction/ssp.d
+++ b/src/sisudoc/ocda/abstraction/ssp.d
@@ -50,6 +50,21 @@
module sisudoc.ocda.abstraction.ssp;
@safe:
/+ ↓ write document abstraction as human-readable .ssp text file +/
+/+ ↓ the format version, carried by both serialisations: the .ssp says it in
+ its "% SiSU Document Abstraction v" header line and the .ocda.db in its
+ metadata schema.version row, so that one bump moves both.
+
+ a reader checks the major part and refuses what it does not know, rather
+ than loading an older artefact half populated in silence. bump the minor
+ part when a property is added (a reader of the newer format still reads
+ the older one), the major part when one changes meaning or goes away.
+
+ 1.1 2026-09-10 @source block; the document metadata the output writers
+ read carried in full (14 meta and 3 make properties
+ added); was 0.1
++/
+enum ssp_format_version = "1.1";
+enum ssp_format_version_major = "1";
/+ ↓ escaping for values that are folded onto one line
a .ssp property value runs to the end of its line, and
@@ -431,9 +446,22 @@ template spineAbstractionTxt() {
auto doc_matters = doc.matters;
string[] output;
/+ ↓ header comment +/
- output ~= "% SiSU Document Abstraction v0.1";
+ output ~= "% SiSU Document Abstraction v" ~ ssp_format_version;
output ~= "% Source: " ~ doc_matters.src.filename;
output ~= "";
+ /+ ↓ @source block: what this abstraction was made from, so a reader can
+ say whether it is looking at the right images and whether the
+ markup has moved on since. the filename is in the % Source: line
+ above and is not repeated here
+ +/
+ output ~= "@source {";
+ output ~= " language: " ~ doc_matters.src.language;
+ if (doc_matters.pod.manifest_list_of_languages.length > 0) {
+ output ~= " languages: " ~ doc_matters.pod.manifest_list_of_languages.join(" ");
+ }
+ output ~= " digest: " ~ doc_matters.doc_digest.markup_doc.toHexString.to!string;
+ output ~= "}";
+ output ~= "";
/+ ↓ @meta block +/
output ~= "@meta {";
auto meta = doc_matters.conf_make_meta.meta;
@@ -449,6 +477,9 @@ template spineAbstractionTxt() {
if (meta.title_language.length > 0) {
output ~= " title.language: " ~ meta.title_language;
}
+ if (meta.title_edition.length > 0) {
+ output ~= " title.edition: " ~ meta.title_edition;
+ }
if (meta.creator_author.length > 0) {
output ~= " creator.author: " ~ meta.creator_author;
}
@@ -485,9 +516,33 @@ template spineAbstractionTxt() {
if (meta.date_valid.length > 0) {
output ~= " date.valid: " ~ meta.date_valid;
}
+ if (meta.date_added_to_site.length > 0) {
+ output ~= " date.added_to_site: " ~ meta.date_added_to_site;
+ }
if (meta.rights_copyright.length > 0) {
output ~= " rights.copyright: " ~ meta.rights_copyright;
}
+ if (meta.rights_copyright_text.length > 0) {
+ output ~= " rights.copyright_text: " ~ meta.rights_copyright_text;
+ }
+ if (meta.rights_copyright_translation.length > 0) {
+ output ~= " rights.copyright_translation: " ~ meta.rights_copyright_translation;
+ }
+ if (meta.rights_copyright_illustrations.length > 0) {
+ output ~= " rights.copyright_illustrations: " ~ meta.rights_copyright_illustrations;
+ }
+ if (meta.rights_copyright_photographs.length > 0) {
+ output ~= " rights.copyright_photographs: " ~ meta.rights_copyright_photographs;
+ }
+ if (meta.rights_copyright_cover.length > 0) {
+ output ~= " rights.copyright_cover: " ~ meta.rights_copyright_cover;
+ }
+ if (meta.rights_copyright_audio.length > 0) {
+ output ~= " rights.copyright_audio: " ~ meta.rights_copyright_audio;
+ }
+ if (meta.rights_copyright_video.length > 0) {
+ output ~= " rights.copyright_video: " ~ meta.rights_copyright_video;
+ }
if (meta.rights_license.length > 0) {
output ~= " rights.license: " ~ meta.rights_license;
}
@@ -515,6 +570,21 @@ template spineAbstractionTxt() {
if (meta.language_document.length > 0) {
output ~= " language.document: " ~ meta.language_document;
}
+ if (meta.language_document_char.length > 0) {
+ output ~= " language.document_char: " ~ meta.language_document_char;
+ }
+ if (meta.original_title.length > 0) {
+ output ~= " original.title: " ~ meta.original_title;
+ }
+ if (meta.original_source.length > 0) {
+ output ~= " original.source: " ~ meta.original_source;
+ }
+ if (meta.original_language.length > 0) {
+ output ~= " original.language: " ~ meta.original_language;
+ }
+ if (meta.original_language_char.length > 0) {
+ output ~= " original.language_char: " ~ meta.original_language_char;
+ }
if (meta.notes_abstract.length > 0) {
output ~= " notes.abstract: " ~ meta.notes_abstract;
}
@@ -537,6 +607,22 @@ template spineAbstractionTxt() {
} // check
output ~= " auto_num_top_lv: " ~ make.auto_num_top_lv.to!string;
output ~= " auto_num_depth: " ~ make.auto_num_depth.to!string;
+ /+ ↓ the make settings the output writers read. the rest of make
+ (italics, bold, emphasis, substitute, headings) is read at parse
+ time and its effect is already in the objects, so it does not
+ travel; these three are read in outputs/io_out/ and must
+ +/
+ if (make.breaks.length > 0) {
+ output ~= " breaks: " ~ make.breaks;
+ }
+ if (make.footer.length > 0) { // a list: joined, each slot escaped
+ string[] _ft;
+ foreach (_f; make.footer) { _ft ~= sspEscapeValue(_f); }
+ output ~= " footer: " ~ _ft.join("|");
+ }
+ if (make.home_button_text.length > 0) {
+ output ~= " home_button_text: " ~ make.home_button_text;
+ }
output ~= "}";
output ~= "";
/+ ↓ @doc_has block +/
diff --git a/src/sisudoc/ocda/abstraction/ssp_in.d b/src/sisudoc/ocda/abstraction/ssp_in.d
index 220bfe3..71daf50 100644
--- a/src/sisudoc/ocda/abstraction/ssp_in.d
+++ b/src/sisudoc/ocda/abstraction/ssp_in.d
@@ -76,8 +76,11 @@ template spineAbstractionRead() {
object sections in the order the file gives them
+/
struct SSPdocument {
- string format; // "% SiSU Document Abstraction v0.1"
+ string format; // "% SiSU Document Abstraction v1.1"
string source; // "% Source: ..."
+ string[string] source_info; // the @source block
+ string[] source_info_order;
+ string ssp_digest; // sha256 of the .ssp read, hex
string[string] meta;
string[] meta_order;
string[string] make;
@@ -152,7 +155,7 @@ template spineAbstractionRead() {
_closeObject();
string _name = line[1 .. $-2];
switch (_name) {
- case "meta": case "make": case "doc_has":
+ case "source": case "meta": case "make": case "doc_has":
block = _name; section = ""; break;
default:
block = ""; section = _name;
@@ -167,6 +170,10 @@ template spineAbstractionRead() {
auto _kv = line.stripLeft.findSplit(": "); // leading only: a value may end in a space
if (_kv[1].length > 0) {
final switch (block) {
+ case "source":
+ doc.source_info[_kv[0].to!string] = _kv[2].to!string;
+ doc.source_info_order ~= _kv[0].to!string;
+ break;
case "meta":
doc.meta[_kv[0].to!string] = _kv[2].to!string;
doc.meta_order ~= _kv[0].to!string;
@@ -332,24 +339,74 @@ template spineAbstractionRead() {
}
return doc;
}
- /+ ↓ the abstraction as it survives a trip through the .ssp text: emitted
- as lines by the writer, read straight back. what a consumer built
- from this cannot see, the .ssp does not carry, which is what makes a
- second artefact built from it unable to drift
+ /+ ↓ the whole document as it survives a trip through the .ssp text:
+ emitted as lines by the writer, read straight back. what a consumer
+ built from this cannot see, the .ssp does not carry, which is what
+ makes a second artefact built from it unable to drift. the header
+ blocks come back with it, so the database is filled from these and
+ not from a second list read off doc_matters
+/
- auto sspRoundTripAbstraction(D)(D doc) {
+ SSPdocument sspRoundTripDocument(D)(D doc) {
import sisudoc.ocda.abstraction.ssp;
mixin spineAbstractionTxt;
- return sspRead(sspDocumentLines(doc)).abstraction;
+ string[] _lines = sspDocumentLines(doc);
+ auto _out = sspRead(_lines);
+ /+ ↓ the writer emits one line per entry, each with its newline, so this
+ is the digest of the file that is written beside the pod +/
+ _out.ssp_digest = sspDigestOfText(_lines.join("\n") ~ "\n");
+ return _out;
+ }
+ /+ ↓ sha256 of a .ssp, upper case hex, as digests.txt gives it +/
+ string sspDigestOfText(string _text) {
+ import std.digest : toHexString;
+ import std.digest.sha : sha256Of;
+ return _text.sha256Of.toHexString.to!string;
+ }
+ auto sspRoundTripAbstraction(D)(D doc) {
+ return sspRoundTripDocument(doc).abstraction;
+ }
+ /+ ↓ the version a reader will accept.
+
+ the major part must match: a format whose properties have changed
+ meaning is not readable by guesswork, and loading it half populated in
+ silence is the failure this check exists to stop. a newer minor
+ version is accepted, since a minor bump only adds properties and an
+ unknown property line is ignored.
+ +/
+ bool sspFormatVersionOk(string _format_line, string _what) {
+ import sisudoc.ocda.abstraction.ssp : ssp_format_version, ssp_format_version_major;
+ enum _prefix = "% SiSU Document Abstraction v";
+ if (_format_line.length == 0) {
+ writeln("ERROR: ", _what, ": no format line, not a .ssp");
+ return false;
+ }
+ if (!_format_line.startsWith(_prefix)) {
+ writeln("ERROR: ", _what, ": unrecognised format line: ", _format_line);
+ return false;
+ }
+ string _ver = _format_line[_prefix.length .. $].strip;
+ string _major = _ver.findSplit(".")[0];
+ if (_major != ssp_format_version_major) {
+ writeln("ERROR: ", _what, ": .ssp format v", _ver,
+ ", this spine reads v", ssp_format_version_major, ".x (v",
+ ssp_format_version, "). Regenerate the abstraction from its markup.");
+ return false;
+ }
+ return true;
}
SSPdocument sspReadFile(string file_path) {
+ string _text;
string[] _lines;
try {
- _lines = (cast(char[]) file_path.read).to!string.split("\n");
+ _text = (cast(char[]) file_path.read).to!string;
+ _lines = _text.split("\n");
} catch (Exception ex) {
writeln("ERROR: could not read ", file_path, ": ", ex.msg);
return SSPdocument();
}
- return sspRead(_lines);
+ auto _doc = sspRead(_lines);
+ if (!sspFormatVersionOk(_doc.format, file_path)) { return SSPdocument(); }
+ _doc.ssp_digest = sspDigestOfText(_text);
+ return _doc;
}
}
diff --git a/src/sisudoc/outputs/io_out/create_ocda_db.d b/src/sisudoc/outputs/io_out/create_ocda_db.d
index 8f915fa..f184854 100644
--- a/src/sisudoc/outputs/io_out/create_ocda_db.d
+++ b/src/sisudoc/outputs/io_out/create_ocda_db.d
@@ -61,13 +61,17 @@ template spineAbstractionDb() {
import d2sqlite3;
import sisudoc.outputs.io_out.paths_output;
import sisudoc.ocda.io_in.paths_source;
- /+ ↓ the abstraction is passed in rather than taken from doc, because the
+ import sisudoc.ocda.abstraction.ssp : ssp_format_version;
+ /+ ↓ the document is passed in rather than taken from doc, because the
caller hands over one that has been through the .ssp: written as text
and read back. so the database is a function of the .ssp and cannot
- carry anything the .ssp does not
+ carry anything the .ssp does not, header blocks included: the metadata
+ table below is filled from what came back, not from a second list read
+ off doc_matters, which is how the two drifted apart before
+/
- void spineAbstractionDb(D,A)(D doc, A doc_abstraction) {
+ void spineAbstractionDb(D,S)(D doc, S ssp_doc) {
auto doc_matters = doc.matters;
+ auto doc_abstraction = ssp_doc.abstraction;
/+ ↓ output path: beside the pod's zip and digests, not under
<lang>/abstraction/. the database carries its own images, so it is a
distributable artefact in its own right and belongs with the others:
@@ -259,13 +263,18 @@ template spineAbstractionDb() {
SELECT role, name, bytes, sha256, width, height FROM files ORDER BY role, name;
");
- /+ ↓ populate metadata +/
+ /+ ↓ populate metadata, from the header blocks the .ssp gave back.
+ one list, in ssp.d, not two: a property added to the .ssp header
+ arrives here without anything being changed, and one that is not in
+ the .ssp cannot be here at all. the keys are the .ssp's own
+ (title.main, make.doc_type, doc_has.images), prefixed by their block
+ where the block name is not already part of the key.
+ +/
db.run("BEGIN TRANSACTION");
auto meta_stmt = db.prepare(
"INSERT INTO metadata (key, value) VALUES (:key, :value)"
);
- auto meta = doc_matters.conf_make_meta.meta;
void insertMeta(string key, string value) {
if (value.length > 0) {
@@ -275,62 +284,31 @@ template spineAbstractionDb() {
meta_stmt.reset();
}
}
+ void insertBlock(string prefix, string[] keys_in_order, string[string] kv) {
+ foreach (k; keys_in_order) {
+ if (k in kv) { insertMeta(prefix ~ k, kv[k]); }
+ }
+ }
- /+ ↓ what this file is, so a reader can tell before it starts +/
+ /+ ↓ what this file is, so a reader can tell before it starts. the
+ version is the .ssp's own: the two serialisations are one format and
+ move together
+ +/
insertMeta("schema.name", "sisu-abstraction-db");
- insertMeta("schema.version", "1");
- insertMeta("source.filename", doc_matters.src.filename);
- insertMeta("source.language", doc_matters.src.language);
-
- insertMeta("title.main", meta.title_main);
- insertMeta("title.subtitle", meta.title_subtitle);
- insertMeta("title.full", meta.title_full);
- insertMeta("title.language", meta.title_language);
- insertMeta("creator.author", meta.creator_author);
- insertMeta("creator.author_surname", meta.creator_author_surname);
- insertMeta("creator.author_surname_fn", meta.creator_author_surname_fn);
- insertMeta("creator.author_email", meta.creator_author_email);
- insertMeta("creator.illustrator", meta.creator_illustrator);
- insertMeta("creator.translator", meta.creator_translator);
- insertMeta("date.published", meta.date_published);
- insertMeta("date.created", meta.date_created);
- insertMeta("date.issued", meta.date_issued);
- insertMeta("date.available", meta.date_available);
- insertMeta("date.modified", meta.date_modified);
- insertMeta("date.valid", meta.date_valid);
- insertMeta("rights.copyright", meta.rights_copyright);
- insertMeta("rights.license", meta.rights_license);
- insertMeta("classify.topic_register", meta.classify_topic_register);
- insertMeta("classify.subject", meta.classify_subject);
- insertMeta("classify.keywords", meta.classify_keywords);
- insertMeta("classify.loc", meta.classify_loc);
- insertMeta("classify.dewey", meta.classify_dewey);
- insertMeta("identifier.isbn", meta.identifier_isbn);
- insertMeta("identifier.oclc", meta.identifier_oclc);
- insertMeta("language.document", meta.language_document);
- insertMeta("notes.abstract", meta.notes_abstract);
- insertMeta("notes.description", meta.notes_description);
- insertMeta("notes.summary", meta.notes_summary);
-
- /+ ↓ make settings +/
- auto make = doc_matters.conf_make_meta.make;
- insertMeta("make.doc_type", make.doc_type);
- insertMeta("make.auto_num_top_at_level", make.auto_num_top_at_level);
- insertMeta("make.auto_num_top_lv", make.auto_num_top_lv.to!string);
- insertMeta("make.auto_num_depth", make.auto_num_depth.to!string);
-
- /+ ↓ doc_has counts +/
- insertMeta("doc_has.inline_links", doc_matters.has.inline_links.to!string);
- insertMeta("doc_has.inline_notes_reg", doc_matters.has.inline_notes_reg.to!string);
- insertMeta("doc_has.inline_notes_star", doc_matters.has.inline_notes_star.to!string);
- insertMeta("doc_has.tables", doc_matters.has.tables.to!string);
- insertMeta("doc_has.codeblocks", doc_matters.has.codeblocks.to!string);
- insertMeta("doc_has.images", doc_matters.has.images.to!string);
- insertMeta("doc_has.poems", doc_matters.has.poems.to!string);
- insertMeta("doc_has.groups", doc_matters.has.groups.to!string);
- insertMeta("doc_has.blocks", doc_matters.has.blocks.to!string);
- insertMeta("doc_has.quotes", doc_matters.has.quotes.to!string);
+ insertMeta("schema.version", ssp_format_version);
+ insertMeta("source.filename", ssp_doc.source);
+ insertBlock("source.", ssp_doc.source_info_order, ssp_doc.source_info);
+ /+ ↓ the digest of the .ssp this database was built from. a file cannot
+ hold its own hash, so this one is not in the .ssp and is taken here:
+ source.digest says which markup the abstraction came from,
+ source.ssp_digest says which abstraction this database came from,
+ and the chain .sst -> .ssp -> .ocda.db is checkable end to end
+ +/
+ insertMeta("source.ssp_digest", ssp_doc.ssp_digest);
+ insertBlock("", ssp_doc.meta_order, ssp_doc.meta);
+ insertBlock("make.", ssp_doc.make_order, ssp_doc.make);
+ insertBlock("doc_has.", ssp_doc.doc_has_order, ssp_doc.doc_has);
meta_stmt.finalize();
/+ ↓ populate objects +/
diff --git a/src/sisudoc/spine.d b/src/sisudoc/spine.d
index 9bbe10f..5560f99 100644
--- a/src/sisudoc/spine.d
+++ b/src/sisudoc/spine.d
@@ -383,6 +383,7 @@ string program_name = "spine";
_out ~= "}";
_out ~= "";
}
+ _block("source", _doc.source_info_order, _doc.source_info);
_block("meta", _doc.meta_order, _doc.meta);
_block("make", _doc.make_order, _doc.make);
_block("doc_has", _doc.doc_has_order, _doc.doc_has);
@@ -425,6 +426,7 @@ string program_name = "spine";
_out ~= "}";
_out ~= "";
}
+ _blockdb("source", _doc.source_info_order, _doc.source_info);
_blockdb("meta", _doc.meta_order, _doc.meta);
_blockdb("make", _doc.make_order, _doc.make);
_blockdb("doc_has", _doc.doc_has_order, _doc.doc_has);
@@ -1449,7 +1451,7 @@ string program_name = "spine";
import sisudoc.ocda.abstraction.ssp_in;
import sisudoc.outputs.io_out.create_ocda_db;
mixin spineAbstractionRead;
- spineAbstractionDb!()(doc, sspRoundTripAbstraction(doc));
+ spineAbstractionDb!()(doc, sspRoundTripDocument(doc));
}
if (doc.matters.opt.action.curate) {
auto _hvst = spineMetaDocCurate!()(doc.matters, hvst);
@@ -1564,7 +1566,7 @@ string program_name = "spine";
import sisudoc.ocda.abstraction.ssp_in;
import sisudoc.outputs.io_out.create_ocda_db;
mixin spineAbstractionRead;
- spineAbstractionDb!()(doc, sspRoundTripAbstraction(doc));
+ spineAbstractionDb!()(doc, sspRoundTripDocument(doc));
}
if (doc.matters.opt.action.curate) {
auto _hvst = spineMetaDocCurate!()(doc.matters, hvst);
diff --git a/test/reference/abstraction/accelerando.charles_stross.en.ssp b/test/reference/abstraction/accelerando.charles_stross.en.ssp
index 61d5b54..faae2e7 100644
--- a/test/reference/abstraction/accelerando.charles_stross.en.ssp
+++ b/test/reference/abstraction/accelerando.charles_stross.en.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: accelerando.charles_stross.sst
+@source {
+ language: en
+ languages: en
+ digest: 67AFE8D70C74F03B5B1D34064E55AC896F4CA001E7EE22E51768DFC0EFCA6057
+}
+
@meta {
title.main: Accelerando
title.full: Accelerando
@@ -12,12 +18,17 @@
rights.copyright: Charles Stross, 2005.
rights.license: Creative Commons License, Attribution-NonCommercial-NoDerivs 2.0: * Attribution. You must attribute the work in the manner specified by the author or licensor; * Noncommercial. You may not use this work for commercial purposes; * No Derivative Works. You may not alter, transform, or build upon this work; * For any reuse or distribution, you must make clear to others the license terms of this work. (* For any reuse or distribution, you must make clear to others the license terms of this work. * Any of these conditions can be waived if you get permission from the copyright holder.) https://creativecommons.org/licenses/by-nc-nd/2.0/ These SiSU presentations of Accelerando are done with the kind permission of the author Charles Stross
classify.topic_register: SiSU markup sample:book:novel;book:novel:fiction:science fiction|short stories;fiction:science fiction|artificial intelligence;artificial intelligence:science fiction
+ language.document_char: en
+ original.source: http://www.accelerando.org/
}
@make {
doc_type: book
auto_num_top_lv: 9
auto_num_depth: 2
+ breaks: new=:A,:B; break=:C,1
+ footer: ┥Accelerando┝┤https://www.antipope.org/charlie/blog-static/index.html├|┥Charles Stross┝┤https://www.antipope.org/charlie/blog-static/index.html├
+ home_button_text: ┥Accelerando┝┤https://www.antipope.org/charlie/blog-static/index.html├┘┥Charles Stross┝┤https://www.antipope.org/charlie/blog-static/index.html├┘
}
@doc_has {
diff --git a/test/reference/abstraction/alices_adventures_in_wonderland.lewis_carroll.en.ssp b/test/reference/abstraction/alices_adventures_in_wonderland.lewis_carroll.en.ssp
index 668b277..bb85760 100644
--- a/test/reference/abstraction/alices_adventures_in_wonderland.lewis_carroll.en.ssp
+++ b/test/reference/abstraction/alices_adventures_in_wonderland.lewis_carroll.en.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: alices_adventures_in_wonderland.lewis_carroll.sst
+@source {
+ language: en
+ languages: en
+ digest: 30B3C621A7A6DF7ADC19A852F544033C2C0C0E6E1D01A49892305698CDA24B57
+}
+
@meta {
title.main: Alice's Adventures in Wonderland
title.full: Alice's Adventures in Wonderland
@@ -10,15 +16,18 @@
date.published: 1865
date.created: 1865
date.available: 1865
+ date.added_to_site: 2004-04-12
rights.copyright: Lewis Carroll
rights.license: Public Domain
classify.topic_register: SiSU markup sample:book:novel; book:novel:fiction:fantasy|children's fiction
+ language.document_char: en
}
@make {
doc_type: book
auto_num_top_lv: 9
auto_num_depth: 2
+ home_button_text: ┥sisudoc.org┝┤https://sisudoc.org├ ┥doc-reform.org┝┤https://doc-reform.org├ ┥sources / git┝┤https://git.sisudoc.org/projects├
}
@doc_has {
diff --git a/test/reference/abstraction/content.cory_doctorow.en.ssp b/test/reference/abstraction/content.cory_doctorow.en.ssp
index 134e6ad..0cf6222 100644
--- a/test/reference/abstraction/content.cory_doctorow.en.ssp
+++ b/test/reference/abstraction/content.cory_doctorow.en.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: content.cory_doctorow.sst
+@source {
+ language: en
+ languages: en
+ digest: 7DCA7CA24D74AD7C0A9E61A8B26DA5001A72F609079EBABEB3ADB85C8E46883D
+}
+
@meta {
title.main: CONTENT
title.subtitle: Selected Essays on Technology, Creativity, Copyright and the Future of the Future
@@ -13,6 +19,7 @@
rights.copyright: Cory Doctorow, 2008.
rights.license: This entire work (with the exception of the introduction by John Perry Barlow) is copyright 2008 by Cory Doctorow and released under the terms of a Creative Commons US Attribution-NonCommercial-ShareAlike license (https://creativecommons.org/licenses/by-nc-sa/3.0/us/). Some Rights Reserved. ┙ The introduction is copyright 2008 by John Perry Barlow and released under the terms of a Creative Commons US Attribution-NonCommercial-ShareAlike license (https://creativecommons.org/licenses/by-nc-sa/3.0/us/). Some Rights Reserved.
classify.topic_register: SiSU markup sample:book:discourse;book:discourse:copyright|content|creative commons|intellectual property;copyright;content;creative commons;intellectual property:copyright;intellectual property:copyright:creative commons;book:subject:culture|copyright|society|content|social aspects of technology;culture;society;technology:social aspects
+ language.document_char: en
}
@make {
@@ -20,6 +27,9 @@
auto_num_top_at_level: 1
auto_num_top_lv: 4
auto_num_depth: 2
+ breaks: break=1
+ footer: ┥CONTENT┝┤https://craphound.com/content├|┥Cory Doctorow┝┤https://craphound.com/├
+ home_button_text: ┥CONTENT┝┤https://craphound.com/content├┘┥Cory Doctorow┝┤https://craphound.com/bio/├┘┥Craphound┝┤https://craphound.com/├┘
}
@doc_has {
diff --git a/test/reference/abstraction/democratizing_innovation.eric_von_hippel.en.ssp b/test/reference/abstraction/democratizing_innovation.eric_von_hippel.en.ssp
index 733e914..391b6d1 100644
--- a/test/reference/abstraction/democratizing_innovation.eric_von_hippel.en.ssp
+++ b/test/reference/abstraction/democratizing_innovation.eric_von_hippel.en.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: democratizing_innovation.eric_von_hippel.sst
+@source {
+ language: en
+ languages: en
+ digest: 9A1BBE1C2045627E06C1CCDC95667A3C19DD115270D8C26AF67986725C044156
+}
+
@meta {
title.main: Democratizing Innovation
title.full: Democratizing Innovation
@@ -16,12 +22,16 @@
date.valid: 2005
rights.copyright: 2005 Eric von Hippel. Exclusive rights to publish and sell this book in print form in English are licensed to The MIT Press. All other rights are reserved by the author. An electronic version of this book is available under a Creative Commons license.
classify.topic_register: SiSU markup sample:book:discourse;book:discourse:innovation|democracy|open source software;innovation;technological innovations:economic aspects;diffusion of innovations;democracy;open source software:innovation
+ language.document_char: en
}
@make {
doc_type: book
auto_num_top_lv: 9
auto_num_depth: 2
+ breaks: new=:B,C; break=1
+ footer: ┥Eric von Hippel┝┤https://evhippel.mit.edu/├
+ home_button_text: ┥Original @ MIT Press┝┤https://mitpress.mit.edu/9780262720472/democratizing-innovation/├┘┥E. von Hippel┝┤https://evhippel.mit.edu/├┘
}
@doc_has {
diff --git a/test/reference/abstraction/down_and_out_in_the_magic_kingdom.cory_doctorow.en.ssp b/test/reference/abstraction/down_and_out_in_the_magic_kingdom.cory_doctorow.en.ssp
index 878152b..839446e 100644
--- a/test/reference/abstraction/down_and_out_in_the_magic_kingdom.cory_doctorow.en.ssp
+++ b/test/reference/abstraction/down_and_out_in_the_magic_kingdom.cory_doctorow.en.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: down_and_out_in_the_magic_kingdom.cory_doctorow.sst
+@source {
+ language: en
+ languages: en
+ digest: 2FCED173DF76B88E3458629D0CAD6ED097BAB20934051A6A4E7246D8599342CD
+}
+
@meta {
title.main: Down and Out in the Magic Kingdom
title.full: Down and Out in the Magic Kingdom
@@ -15,6 +21,7 @@
classify.topic_register: SiSU markup sample:book:novel;book:novel:fiction:counterculture|young adult|science fiction
classify.loc: PS3604.O27 D68 2003
classify.dewey: 813/.6 21
+ language.document_char: en
notes.description: Realizing his boyhood dream of moving to the twentieth-century artistic creation of Disney World, Jules becomes incensed by a new group that would change the Hall of Presidents by replacing the audioanimatronics with brain interfaces.
}
@@ -22,6 +29,9 @@
doc_type: book
auto_num_top_lv: 9
auto_num_depth: 2
+ breaks: break=1
+ footer: ┥Down and Out in the Magic Kingdom┝┤https://craphound.com/down├|┥Cory Doctorow┝┤https://craphound.com/├
+ home_button_text: ┥Down and Out in the Magic Kingdom┝┤https://craphound.com/down├┘┥Cory Doctorow┝┤https://craphound.com/bio/├┘┥Craphound┝┤https://craphound.com/├┘
}
@doc_has {
diff --git a/test/reference/abstraction/for_the_win.cory_doctorow.en.ssp b/test/reference/abstraction/for_the_win.cory_doctorow.en.ssp
index c8d4ecc..337fa87 100644
--- a/test/reference/abstraction/for_the_win.cory_doctorow.en.ssp
+++ b/test/reference/abstraction/for_the_win.cory_doctorow.en.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: for_the_win.cory_doctorow.sst
+@source {
+ language: en
+ languages: en
+ digest: B2C4C4F2F08A36F035A145DB529368242F1901A6A48338AEE4F9CD7E718160A7
+}
+
@meta {
title.main: For the Win
title.full: For the Win
@@ -12,6 +18,7 @@
date.modified: 2010-09-16
rights.copyright: 2010 Cory Doctorow
classify.topic_register: SiSU markup sample:book:novel;book:novel:fiction:counterculture|young adult|science fiction
+ language.document_char: en
notes.description: A group of teens from around the world find themselves drawn into an online revolution arranged by a mysterious young woman known as Big Sister Nor, who hopes to challenge the status quo and change the world using her virtual connections.
}
@@ -20,6 +27,9 @@
auto_num_top_at_level: 1
auto_num_top_lv: 4
auto_num_depth: 2
+ breaks: new=:B; break=1
+ footer: ┥For the Win┝┤https://craphound.com/ftw├|┥Cory Doctorow┝┤https://craphound.com/├
+ home_button_text: ┥For the Win┝┤https://craphound.com/ftw├┘┥Cory Doctorow┝┤https://craphound.com/bio/├┘┥Craphound┝┤https://craphound.com/├┘
}
@doc_has {
diff --git a/test/reference/abstraction/free_as_in_freedom_2.richard_stallman_and_the_free_software_revolution.sam_williams.richard_stallman.en.ssp b/test/reference/abstraction/free_as_in_freedom_2.richard_stallman_and_the_free_software_revolution.sam_williams.richard_stallman.en.ssp
index 44421d4..81fae49 100644
--- a/test/reference/abstraction/free_as_in_freedom_2.richard_stallman_and_the_free_software_revolution.sam_williams.richard_stallman.en.ssp
+++ b/test/reference/abstraction/free_as_in_freedom_2.richard_stallman_and_the_free_software_revolution.sam_williams.richard_stallman.en.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: free_as_in_freedom_2.richard_stallman_and_the_free_software_revolution.sam_williams.richard_stallman.sst
+@source {
+ language: en
+ languages: en
+ digest: F59D49849E71E58C68562EC585B3803EE25B6DA49A96F229F289F3C9DCD414A4
+}
+
@meta {
title.main: Free as in Freedom (2.0)
title.subtitle: Richard Stallman and the Free Software Revolution
@@ -12,12 +18,16 @@
rights.copyright: Sam Williams 2002; 2010 Richard M. Stallman
rights.license: Published under the GNU Free Documentation License. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License."
classify.topic_register: SiSU markup sample:book:biography;book:biography;copyright;GNU/linux:GPL|copyleft|free software;free software;software:software libré;GPL;linux:GNU|software libré;programming
+ language.document_char: en
}
@make {
doc_type: book
auto_num_top_lv: 9
auto_num_depth: 2
+ breaks: new=:A,:B,:C,1
+ footer: ┥Free Software Foundation┝┤https://www.fsf.org├|┥Richard Stallman (RMS)┝┤https://stallman.org/├
+ home_button_text: ┥Free as in Freedom 2.0┝┤https://static.fsf.org/nosvn/faif-2.0.pdf├┘┥Free Software Foundation┝┤https://www.fsf.org├┘┥Richard Stallman (RMS)┝┤https://stallman.org/├┘
}
@doc_has {
diff --git a/test/reference/abstraction/free_culture.lawrence_lessig.en.ssp b/test/reference/abstraction/free_culture.lawrence_lessig.en.ssp
index b3e5873..d01a518 100644
--- a/test/reference/abstraction/free_culture.lawrence_lessig.en.ssp
+++ b/test/reference/abstraction/free_culture.lawrence_lessig.en.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: free_culture.lawrence_lessig.sst
+@source {
+ language: en
+ languages: en
+ digest: C2F8CF44A58BD6B84D676A69E11CAC94C6708336EBC5F3801D048D8EDA2CC6BC
+}
+
@meta {
title.main: Free Culture
title.subtitle: How Big Media Uses Technology and the Law to Lock Down Culture and Control Creativity
@@ -17,12 +23,16 @@
rights.copyright: Lawrence Lessig, 2004.
rights.license: Free Culture is Licensed under a Creative Commons License. This License permits non-commercial use of this work, so long as attribution is given. For more information about the license, visit https://creativecommons.org/licenses/by-nc/1.0/
classify.topic_register: SiSU markup sample:book:discourse;book:discourse:intellectual property|copyright|creative commons|free culture;copyright;free culture;creative commons;intellectual property:copyright|public domain;intellectual property:copyright:creative commons;book:subject:culture|copyright|society|public policy|mass media;culture;society
+ language.document_char: en
}
@make {
doc_type: book
auto_num_top_lv: 9
auto_num_depth: 2
+ breaks: new=:B; break=1
+ footer: ┥Free Culture┝┤https://www.free-culture.cc├|┥Lawrence Lessig┝┤https://www.lessig.org├
+ home_button_text: ┥Free Culture┝┤https://www.free-culture.cc├┘┥Lawrence Lessig┝┤https://www.lessig.org├┘
}
@doc_has {
diff --git a/test/reference/abstraction/free_for_all.peter_wayner.en.ssp b/test/reference/abstraction/free_for_all.peter_wayner.en.ssp
index 1e128e0..c08d1a8 100644
--- a/test/reference/abstraction/free_for_all.peter_wayner.en.ssp
+++ b/test/reference/abstraction/free_for_all.peter_wayner.en.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: free_for_all.peter_wayner.sst
+@source {
+ language: en
+ languages: en
+ digest: ADC1F2D9F1E6A5FD2E7F02A79D773EBE017FB1509F13F9CB5E6BECCC5C8C553F
+}
+
@meta {
title.main: Free For All
title.subtitle: How Linux and the Free Software Movement Undercut the High Tech Titans
@@ -17,6 +23,7 @@
rights.copyright: Peter Wayner, 2000.
rights.license: Free For All is Licensed under a Creative Commons License. This License permits non-commercial use of this work, so long as attribution is given. For more information about the license, visit https://creativecommons.org/licenses/by-nc/1.0/
classify.topic_register: SiSU markup sample:book:discourse; book:discourse:free software|open source software|Linux|Software Libré; book:subject:Linux|Software Libré|technology; GNU/Linux:GPL;free software; open source software; software license:GPL; Linux:GNU|Software Libré
+ language.document_char: en
}
@make {
@@ -24,6 +31,9 @@
auto_num_top_at_level: 1
auto_num_top_lv: 4
auto_num_depth: 2
+ breaks: new=:A,:B,:C,1
+ footer: ┥Free For All┝┤https://www.wayner.org/books/ffa/├|┥Peter Wayner┝┤https://www.wayner.org├
+ home_button_text: ┥Free For All┝┤https://www.wayner.org/books/ffa/├┘┥Peter Wayner┝┤https://www.wayner.org├┘
}
@doc_has {
diff --git a/test/reference/abstraction/gpl2.fsf.en.ssp b/test/reference/abstraction/gpl2.fsf.en.ssp
index d3c8d3a..0cf90a3 100644
--- a/test/reference/abstraction/gpl2.fsf.en.ssp
+++ b/test/reference/abstraction/gpl2.fsf.en.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: gpl2.fsf.sst
+@source {
+ language: en
+ languages: en
+ digest: 9A3D72192551225878EAA2E9211A58F57B30F6D2E61E0DCD6280EC8537993DB3
+}
+
@meta {
title.main: GNU GENERAL PUBLIC LICENSE v2
title.full: GNU GENERAL PUBLIC LICENSE v2
@@ -11,12 +17,14 @@
rights.copyright: 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
rights.license: Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
classify.topic_register: SiSU markup sample:document;GPL;software:license;software:GPL;GNU/Linux:license:GPL
+ language.document_char: en
}
@make {
doc_type: article
auto_num_top_lv: 9
auto_num_depth: 2
+ home_button_text: ┥sisudoc.org┝┤https://sisudoc.org├ ┥doc-reform.org┝┤https://doc-reform.org├ ┥sources / git┝┤https://git.sisudoc.org/projects├
}
@doc_has {
diff --git a/test/reference/abstraction/gpl3.fsf.en.ssp b/test/reference/abstraction/gpl3.fsf.en.ssp
index 118bf02..d727386 100644
--- a/test/reference/abstraction/gpl3.fsf.en.ssp
+++ b/test/reference/abstraction/gpl3.fsf.en.ssp
@@ -1,10 +1,17 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: gpl3.fsf.sst
+@source {
+ language: en
+ languages: en
+ digest: 6CAC3C34C7A811CE1592C59402C77362324EBF04A159BBB1B743D8BBC0165477
+}
+
@meta {
title.main: GNU GENERAL PUBLIC LICENSE v3
title.full: GNU GENERAL PUBLIC LICENSE v3
title.language: English
+ title.edition: 3
creator.author: Free Software Foundation
creator.author_surname: Free Software Foundation
creator.author_surname_fn: Free Software Foundation
@@ -14,12 +21,14 @@
rights.copyright: 2007 Free Software Foundation, Inc. https://fsf.org/
rights.license: Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
classify.topic_register: SiSU markup sample:document;GPL;software:license;software:GPL
+ language.document_char: en
}
@make {
doc_type: article
auto_num_top_lv: 9
auto_num_depth: 2
+ home_button_text: ┥sisudoc.org┝┤https://sisudoc.org├ ┥doc-reform.org┝┤https://doc-reform.org├ ┥sources / git┝┤https://git.sisudoc.org/projects├
}
@doc_has {
diff --git a/test/reference/abstraction/gullivers_travels.jonathan_swift.en.ssp b/test/reference/abstraction/gullivers_travels.jonathan_swift.en.ssp
index 4fd2a92..299fa12 100644
--- a/test/reference/abstraction/gullivers_travels.jonathan_swift.en.ssp
+++ b/test/reference/abstraction/gullivers_travels.jonathan_swift.en.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: gullivers_travels.jonathan_swift.sst
+@source {
+ language: en
+ languages: en
+ digest: E30038491EE8396BD1814EFBA5815D6E1AAF14099188FB8B3A285BE5C44E0F98
+}
+
@meta {
title.main: Gulliver's Travels
title.full: Gulliver's Travels
@@ -12,15 +18,19 @@
date.issued: 1726
date.available: 1726
date.modified: 1735
+ date.added_to_site: 2005-10-30
rights.copyright: Jonathan Swift
rights.license: Public Domain
classify.topic_register: SiSU markup sample:book:novel;book:novel:fiction:fantasy
+ language.document_char: en
}
@make {
doc_type: book
auto_num_top_lv: 9
auto_num_depth: 2
+ breaks: new=:B; break=1
+ home_button_text: ┥sisudoc.org┝┤https://sisudoc.org├ ┥doc-reform.org┝┤https://doc-reform.org├ ┥sources / git┝┤https://git.sisudoc.org/projects├
}
@doc_has {
diff --git a/test/reference/abstraction/little_brother.cory_doctorow.en.ssp b/test/reference/abstraction/little_brother.cory_doctorow.en.ssp
index 67c1093..cae51ad 100644
--- a/test/reference/abstraction/little_brother.cory_doctorow.en.ssp
+++ b/test/reference/abstraction/little_brother.cory_doctorow.en.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: little_brother.cory_doctorow.sst
+@source {
+ language: en
+ languages: en
+ digest: 74F36EFB6D0BFE7817B230470470226FCF9E80AFA2E5F263AAD7307FD0D1F339
+}
+
@meta {
title.main: Little Brother
title.full: Little Brother
@@ -14,6 +20,7 @@
rights.license: This book is distributed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 license. That means: ┙ You are free: ┙ * to Share - to copy, distribute and transmit the work ┙ * to Remix - to adapt the work ┙ Under the following conditions: ┙ * Attribution. You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work). ┙ * Noncommercial. You may not use this work for commercial purposes. ┙ * Share Alike. If you alter, transform, or build upon this work, you may distribute the resulting work only under the same or similar license to this one. ┙ * For any reuse or distribution, you must make clear to others the license terms of this work. The best way to do this is with a link https://craphound.com/littlebrother ┙ * Any of the above conditions can be waived if you get my permission ┙ More info here: https://creativecommons.org/licenses/by-nc-sa/3.0/us/ ┙ See the end of this file for the complete legalese. [Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License] ┙ Cover image: Wordle, Attribution United States (CC BY) 3.0 ┙ Illustration: Richard Wilkinson, Creative Commons Attribution-Share Alike 2.0 Generic license.
classify.topic_register: SiSU markup sample:book:novel;book:novel:fiction:civil rights|counterculture|young adult|science fiction|computer hackers|terrorism;democracy
classify.loc: PZ7.D66237 Lit 2008
+ language.document_char: en
notes.description: After being interrogated for days by the Department of Homeland Security in the aftermath of a major terrorist attack on San Francisco, California, seventeen-year-old Marcus, released into what is now a police state, decides to use his expertise in computer hacking to set things right.
}
@@ -21,6 +28,8 @@
doc_type: book
auto_num_top_lv: 9
auto_num_depth: 2
+ footer: ┥Little Brother┝┤https://craphound.com/littlebrother├|┥Cory Doctorow┝┤https://craphound.com/├
+ home_button_text: ┥Little Brother┝┤https://craphound.com/littlebrother├┘┥Cory Doctorow┝┤https://craphound.com/bio/├┘┥Craphound┝┤https://craphound.com/├┘
}
@doc_has {
diff --git a/test/reference/abstraction/live-manual.ca.ssp b/test/reference/abstraction/live-manual.ca.ssp
index 5382af5..9f6d302 100644
--- a/test/reference/abstraction/live-manual.ca.ssp
+++ b/test/reference/abstraction/live-manual.ca.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: live-manual.ssm
+@source {
+ language: ca
+ languages: en ca de es fr it ja pl ro
+ digest: 7BE26E54ECB410EFFC99D3B3B63DEAB26BB1B34C3E03EBBF71CA0CD871C0F9CA
+}
+
@meta {
title.main: Manual de Live Systems
title.full: Manual de Live Systems
@@ -11,12 +17,14 @@
rights.copyright: 2006-2015 Live Systems Project
rights.license: Aquest programa és un programari lliure: es pot redistribuir i/o modificar sota els termes de la Llicència Pública General de la GNU com és publicada per la Free Software Foundation, ja sigui la versió 3 de la Llicència, o (si ho preferiu) qualsevol versió posterior. ┙ ┙ Aquest programa es distribueix amb l'esperança que sigui útil, però sense cap garantia, fins i tot sense la garantia implícita de COMERCIALITZACIÓ o ADEQUACIÓ PER A PROPÒSITS DETERMINATS. Vegeu la Llicència General Pública de la GNU per a més detalls. ┙ ┙ Haurieu de rebre una còpia de la Llicència Pública General de la GNU amb aquest programa. Si no és així, consulteu http://www.gnu.org/licenses/. ┙ ┙ El text complet de la Llicència Pública General de la GNU es pot trobar a /usr/share/common-licenses/GPL-3.
classify.topic_register: SiSU markup sample:technical writing;software:program
+ language.document_char: ca
}
@make {
doc_type: book
auto_num_top_lv: 9
auto_num_depth: 2
+ home_button_text: ┥sisudoc.org┝┤https://sisudoc.org├ ┥doc-reform.org┝┤https://doc-reform.org├ ┥sources / git┝┤https://git.sisudoc.org/projects├
}
@doc_has {
diff --git a/test/reference/abstraction/live-manual.de.ssp b/test/reference/abstraction/live-manual.de.ssp
index 4a19a7e..70570c6 100644
--- a/test/reference/abstraction/live-manual.de.ssp
+++ b/test/reference/abstraction/live-manual.de.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: live-manual.ssm
+@source {
+ language: de
+ languages: en ca de es fr it ja pl ro
+ digest: F8F8C332C8C10EF3C76C69E7AEA33B12835904E756A252C67B5A50C33F61F85C
+}
+
@meta {
title.main: Live Systems Handbuch
title.full: Live Systems Handbuch
@@ -11,12 +17,14 @@
rights.copyright: 2006-2015 Live Systems Project
rights.license: This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. ┙ ┙ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ┙ ┙ You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/. ┙ ┙ The complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL-3 file.
classify.topic_register: SiSU markup sample:technical writing;software:program
+ language.document_char: de
}
@make {
doc_type: book
auto_num_top_lv: 9
auto_num_depth: 2
+ home_button_text: ┥sisudoc.org┝┤https://sisudoc.org├ ┥doc-reform.org┝┤https://doc-reform.org├ ┥sources / git┝┤https://git.sisudoc.org/projects├
}
@doc_has {
diff --git a/test/reference/abstraction/live-manual.en.ssp b/test/reference/abstraction/live-manual.en.ssp
index 771d352..631f01f 100644
--- a/test/reference/abstraction/live-manual.en.ssp
+++ b/test/reference/abstraction/live-manual.en.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: live-manual.ssm
+@source {
+ language: en
+ languages: en ca de es fr it ja pl ro
+ digest: 5A7382F1D8029DAAE5F621B92E3C7210664585B43CAA4C327FDB5807AC2EBBEC
+}
+
@meta {
title.main: Live Systems Manual
title.full: Live Systems Manual
@@ -11,12 +17,14 @@
rights.copyright: 2006-2015 Live Systems Project
rights.license: This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. ┙ ┙ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ┙ ┙ You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/. ┙ ┙ The complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL-3 file.
classify.topic_register: SiSU markup sample:technical writing;software:program
+ language.document_char: en
}
@make {
doc_type: book
auto_num_top_lv: 9
auto_num_depth: 2
+ home_button_text: ┥sisudoc.org┝┤https://sisudoc.org├ ┥doc-reform.org┝┤https://doc-reform.org├ ┥sources / git┝┤https://git.sisudoc.org/projects├
}
@doc_has {
diff --git a/test/reference/abstraction/live-manual.es.ssp b/test/reference/abstraction/live-manual.es.ssp
index 0db0682..25a1ef6 100644
--- a/test/reference/abstraction/live-manual.es.ssp
+++ b/test/reference/abstraction/live-manual.es.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: live-manual.ssm
+@source {
+ language: es
+ languages: en ca de es fr it ja pl ro
+ digest: ACD3E7B7641694926D7ED693E770E0A98920C46BC5C872AA67B8921E2FDF6C6C
+}
+
@meta {
title.main: Manual de Live Systems
title.full: Manual de Live Systems
@@ -11,12 +17,14 @@
rights.copyright: 2006-2015 Live Systems Project
rights.license: Este programa es software libre: puede ser redistribuido y/o modificado bajo los términos de la GNU General Public License publicada por la Free Software Foundation, bien de la versión 3 de la Licencia, o (a su elección) cualquier versión posterior. ┙ ┙ Este programa se distribuye con la esperanza de que sea útil, pero SIN NINGUNA GARANTÍA, incluso sin la garantía implícita de COMERCIALIZACIÓN o IDONEIDAD PARA UN PROPÓSITO PARTICULAR. Consulte la GNU General Public License para más detalles. ┙ ┙ Debería haber recibido una copia de la General Public License GNU junto con este programa. Si no, vea http://www.gnu.org/licenses/. ┙ ┙ El texto completo de la GNU Licencia Pública General se pueden encontrar en /usr/share/common-licenses/GPL-3
classify.topic_register: SiSU markup sample:technical writing;software:program
+ language.document_char: es
}
@make {
doc_type: book
auto_num_top_lv: 9
auto_num_depth: 2
+ home_button_text: ┥sisudoc.org┝┤https://sisudoc.org├ ┥doc-reform.org┝┤https://doc-reform.org├ ┥sources / git┝┤https://git.sisudoc.org/projects├
}
@doc_has {
diff --git a/test/reference/abstraction/live-manual.fr.ssp b/test/reference/abstraction/live-manual.fr.ssp
index 5660f6b..d0ef266 100644
--- a/test/reference/abstraction/live-manual.fr.ssp
+++ b/test/reference/abstraction/live-manual.fr.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: live-manual.ssm
+@source {
+ language: fr
+ languages: en ca de es fr it ja pl ro
+ digest: 7EC2AA5B4E5B772430DA9D142241A85EA92A44F049B515F0CAF6FC15A7F0F1B5
+}
+
@meta {
title.main: Manuel Live Systems
title.full: Manuel Live Systems
@@ -11,12 +17,14 @@
rights.copyright: 2006-2015 Live Systems Project
rights.license: Ce programme est un logiciel libre; vous pouvez le redistribuer ou le modifier suivant les termes de la Licence Générale Publique GNU telle que publiée par la Free Software Foundation: soit la version 3 de cette licence, soit (à votre gré) toute version ultérieure. ┙ ┙ Ce programme est distribué dans l’espoir qu’il vous sera utile, mais SANS AUCUNE GARANTIE: sans même la garantie implicite de COMMERCIALISABILITÉ ni d’ADÉQUATION À UN OBJECTIF PARTICULIER. Consultez la Licence Générale Publique GNU pour plus de détails. ┙ ┙ Vous devriez avoir reçu une copie de la Licence Générale Publique GNU avec ce programme ; si ce n’est pas le cas, consultez http://www.gnu.org/licenses/. ┙ ┙ Le texte complet de la Licence Générale Publique GNU peut être trouvé dans le fichier / usr/share/common-licenses/GPL-3
classify.topic_register: SiSU markup sample:technical writing;software:program
+ language.document_char: fr
}
@make {
doc_type: book
auto_num_top_lv: 9
auto_num_depth: 2
+ home_button_text: ┥sisudoc.org┝┤https://sisudoc.org├ ┥doc-reform.org┝┤https://doc-reform.org├ ┥sources / git┝┤https://git.sisudoc.org/projects├
}
@doc_has {
diff --git a/test/reference/abstraction/live-manual.it.ssp b/test/reference/abstraction/live-manual.it.ssp
index 254539b..817e9e6 100644
--- a/test/reference/abstraction/live-manual.it.ssp
+++ b/test/reference/abstraction/live-manual.it.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: live-manual.ssm
+@source {
+ language: it
+ languages: en ca de es fr it ja pl ro
+ digest: FBBCD0F409C97038AA441F58103BD413CCD4F9D354C7D0B3DA42BAE248413CE1
+}
+
@meta {
title.main: Manuale di Live Systems
title.full: Manuale di Live Systems
@@ -11,12 +17,14 @@
rights.copyright: 2006-2015 Live Systems Project
rights.license: Questo programma è software libero: è possibile ridistribuirlo e modificarlo secondo i termini della GNU General Public License come pubblicata dalla Free Software Foundation, sia la versione 3 della licenza o (a scelta) una versione successiva. ┙ ┙ Questo programma è distribuito nella speranza che possa essere utile, ma SENZA ALCUNA GARANZIA, nemmeno la garanzia implicita di COMMERCIABILITÀ o IDONEITÀ PER UN PARTICOLARE SCOPO. Vedere la GNU General Public License per ulteriori dettagli. ┙ ┙ Si dovrebbe aver ricevuto una copia della GNU General Public License con questo programma. In caso contrario, vedere http://www.gnu.org/licenses/. ┙ ┙ Il testo completo della GNU General Public License può essere trovato nel file /usr/share/common-licenses/GPL-3.
classify.topic_register: SiSU markup sample:technical writing;software:program
+ language.document_char: it
}
@make {
doc_type: book
auto_num_top_lv: 9
auto_num_depth: 2
+ home_button_text: ┥sisudoc.org┝┤https://sisudoc.org├ ┥doc-reform.org┝┤https://doc-reform.org├ ┥sources / git┝┤https://git.sisudoc.org/projects├
}
@doc_has {
diff --git a/test/reference/abstraction/live-manual.ja.ssp b/test/reference/abstraction/live-manual.ja.ssp
index 5e485cf..c0cfd5e 100644
--- a/test/reference/abstraction/live-manual.ja.ssp
+++ b/test/reference/abstraction/live-manual.ja.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: live-manual.ssm
+@source {
+ language: ja
+ languages: en ca de es fr it ja pl ro
+ digest: 4770949CCDC27EAE72E8D68E223516832F13B25AB492B92DB2B81CC07B956814
+}
+
@meta {
title.main: Live システムマニュアル
title.full: Live システムマニュアル
@@ -11,12 +17,14 @@
rights.copyright: 2006-2015 Live Systems Project
rights.license: This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. ┙ ┙ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ┙ ┙ You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/. ┙ ┙ The complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL-3 file.
classify.topic_register: SiSU markup sample:technical writing;software:program
+ language.document_char: ja
}
@make {
doc_type: book
auto_num_top_lv: 9
auto_num_depth: 2
+ home_button_text: ┥sisudoc.org┝┤https://sisudoc.org├ ┥doc-reform.org┝┤https://doc-reform.org├ ┥sources / git┝┤https://git.sisudoc.org/projects├
}
@doc_has {
diff --git a/test/reference/abstraction/live-manual.pl.ssp b/test/reference/abstraction/live-manual.pl.ssp
index 7d37ae9..7782f13 100644
--- a/test/reference/abstraction/live-manual.pl.ssp
+++ b/test/reference/abstraction/live-manual.pl.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: live-manual.ssm
+@source {
+ language: pl
+ languages: en ca de es fr it ja pl ro
+ digest: 3ED87991867CD8EDB2AACE99A91AD78CF7995E803A28C555D1EB3B21BB147B59
+}
+
@meta {
title.main: Podręcznik Systemów Live
title.full: Podręcznik Systemów Live
@@ -11,12 +17,14 @@
rights.copyright: Copyright (C) 2006-2015 Projekt Systemów Live
rights.license: Ten program jest wolnym oprogramowaniem: możesz go rozprowadzać dalej i / lub modyfikować zgodnie z warunkami Powszechnej Licencji Publicznej GNU opublikowanej przez Free Software Foundation, według wersji 3 tej Licencji lub (według Twojego wyboru) dowolnej późniejszej wersji ┙ ┙ Ten program jest rozpowszechniany w nadziei, że będzie użyteczny, ale BEZ JAKIEJKOLWIEK GWARANCJI; bez nawet domyślnej gwarancji PRZYDATNOŚCI HANDLOWEJ albo PRZYDATNOŚCI DO OKREŚLONYCH ZASTOSOWAŃ. Patrz GNU General Public License aby uzyskać więcej szczegółów. ┙ ┙ Powinieneś otrzymać kopię Licencji GNU General Public License wraz z tym programem. Jeśli nie, odwiedź http://www.gnu.org/licenses/. ┙ ┙ Pełny tekst licencji GNU General Public można znaleźć w pliku /usr/share/common-licenses/GPL-3.
classify.topic_register: SiSU markup sample:technical writing;software:program
+ language.document_char: pl
}
@make {
doc_type: book
auto_num_top_lv: 9
auto_num_depth: 2
+ home_button_text: ┥sisudoc.org┝┤https://sisudoc.org├ ┥doc-reform.org┝┤https://doc-reform.org├ ┥sources / git┝┤https://git.sisudoc.org/projects├
}
@doc_has {
diff --git a/test/reference/abstraction/live-manual.ro.ssp b/test/reference/abstraction/live-manual.ro.ssp
index 093b3e5..4e262cb 100644
--- a/test/reference/abstraction/live-manual.ro.ssp
+++ b/test/reference/abstraction/live-manual.ro.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: live-manual.ssm
+@source {
+ language: ro
+ languages: en ca de es fr it ja pl ro
+ digest: 9B23407526BC46AAFD8D3E73BD7E2DF5365BCEBBD1C0A92204764284EA0B9DD4
+}
+
@meta {
title.main: Manualul Live Systems
title.full: Manualul Live Systems
@@ -11,12 +17,14 @@
rights.copyright: Copyright (C) 2006-2015 Live Systems Project
rights.license: This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. ┙ ┙ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ┙ ┙ You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/. ┙ ┙ The complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL-3 file.
classify.topic_register: SiSU markup sample:technical writing;software:program
+ language.document_char: ro
}
@make {
doc_type: book
auto_num_top_lv: 9
auto_num_depth: 2
+ home_button_text: ┥sisudoc.org┝┤https://sisudoc.org├ ┥doc-reform.org┝┤https://doc-reform.org├ ┥sources / git┝┤https://git.sisudoc.org/projects├
}
@doc_has {
diff --git a/test/reference/abstraction/not_without_help.austin_amissah.en.ssp b/test/reference/abstraction/not_without_help.austin_amissah.en.ssp
index 74d1124..0c3c990 100644
--- a/test/reference/abstraction/not_without_help.austin_amissah.en.ssp
+++ b/test/reference/abstraction/not_without_help.austin_amissah.en.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: not_without_help.austin_amissah.sst
+@source {
+ language: en
+ languages: en
+ digest: E603800488EEF7DD58630B608687D255DCB0EBB991E4FB6E545ABC2496719F33
+}
+
@meta {
title.main: Not Without Help
title.subtitle: Austin Amissah (1930 - 2001), an Autobiography of my Earlier Years
@@ -14,12 +20,16 @@
rights.copyright: 2001, The Estate of Austin Amissah
rights.license: All rights reserved. LEGAL CODE Attribution-NonCommercial-NoDerivs 4.0 International (CC BY-NC-ND 4.0) https://creativecommons.org/licenses/by-nc-nd/4.0/
classify.topic_register: SiSU markup sample:book:autobiography;book:autobiography
+ language.document_char: en
}
@make {
doc_type: book
auto_num_top_lv: 9
auto_num_depth: 2
+ breaks: new=:B; break=1
+ footer: ┥Amissah┝┤https://amissah.com├|┥sisudoc.org┝┤https://sisudoc.org├
+ home_button_text: ┥sisudoc.org┝┤https://sisudoc.org├ ┥doc-reform.org┝┤https://doc-reform.org├ ┥sources / git┝┤https://git.sisudoc.org/projects├
}
@doc_has {
diff --git a/test/reference/abstraction/on_the_net_and_information.ralph_amissah.en.ssp b/test/reference/abstraction/on_the_net_and_information.ralph_amissah.en.ssp
index fddf73e..c02aa9a 100644
--- a/test/reference/abstraction/on_the_net_and_information.ralph_amissah.en.ssp
+++ b/test/reference/abstraction/on_the_net_and_information.ralph_amissah.en.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: on_the_net_and_information.ralph_amissah.sst
+@source {
+ language: en
+ languages: en
+ digest: C1820B12F408AA7026AA780A9470B58699492DA3391073855CDF09089F4E2CC9
+}
+
@meta {
title.main: On the Net and the liberation of information that "wants" to be free
title.subtitle: A call for action by the United Nations, Universities, researchers, and development agencies, with reference primarily to international trade law
@@ -11,6 +17,7 @@
date.published: 1997-02-22
rights.copyright: 1997 Ralph Amissah
classify.topic_register: SiSU markup sample:article;Internet:paper
+ language.document_char: en
notes.summary: Writing on the implications of the positive potential of the web for knowledge and information dissemination given the different motives for publication.
}
@@ -18,6 +25,7 @@
doc_type: article
auto_num_top_lv: 9
auto_num_depth: 2
+ home_button_text: ┥sisudoc.org┝┤https://sisudoc.org├ ┥doc-reform.org┝┤https://doc-reform.org├ ┥sources / git┝┤https://git.sisudoc.org/projects├
}
@doc_has {
diff --git a/test/reference/abstraction/outputs_of_ai_systems_qualify_as_artwork.anna_linne.en.ssp b/test/reference/abstraction/outputs_of_ai_systems_qualify_as_artwork.anna_linne.en.ssp
index 037aab5..bb926ae 100644
--- a/test/reference/abstraction/outputs_of_ai_systems_qualify_as_artwork.anna_linne.en.ssp
+++ b/test/reference/abstraction/outputs_of_ai_systems_qualify_as_artwork.anna_linne.en.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: outputs_of_ai_systems_qualify_as_artwork.anna_linne.sst
+@source {
+ language: en
+ languages: en
+ digest: 50204DECEBC80BDF7CF58370EF38252491CAA287C124419C72C0D84CC59757B7
+}
+
@meta {
title.main: Can the outputs of AI systems qualify as artworks?
title.full: Can the outputs of AI systems qualify as artworks?
@@ -11,6 +17,7 @@
rights.copyright: 2021 Anna Linne
rights.license: Creative Commons License, Attribution 4.0 International (CC-BY-4.0)
classify.topic_register: SiSU markup sample:article:philosophy;SiSU markup sample:scholarly writing:philosophy;philosophy:artificial intelligence;art:artificial intelligence;artificial intelligence:art
+ language.document_char: en
notes.summary: on Art and Artificial Intelligence
}
@@ -18,6 +25,7 @@
doc_type: article
auto_num_top_lv: 9
auto_num_depth: 2
+ home_button_text: ┥sisudoc.org┝┤https://sisudoc.org├ ┥doc-reform.org┝┤https://doc-reform.org├ ┥sources / git┝┤https://git.sisudoc.org/projects├
}
@doc_has {
diff --git a/test/reference/abstraction/revisiting_the_autonomous_contract.ralph_amissah.en.ssp b/test/reference/abstraction/revisiting_the_autonomous_contract.ralph_amissah.en.ssp
index 70cd5d0..516b56f 100644
--- a/test/reference/abstraction/revisiting_the_autonomous_contract.ralph_amissah.en.ssp
+++ b/test/reference/abstraction/revisiting_the_autonomous_contract.ralph_amissah.en.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: revisiting_the_autonomous_contract.ralph_amissah.sst
+@source {
+ language: en
+ languages: en
+ digest: A7088B8D9262325C9BF6747225C2946BEC3F4E9E7DFCA28D301EC6603381F896
+}
+
@meta {
title.main: Revisiting the Autonomous Contract
title.subtitle: Transnational contract law, trends and supportive structures
@@ -11,6 +17,7 @@
date.published: 2000-08-27
rights.copyright: 2000 Ralph Amissah
classify.topic_register: SiSU markup sample:article:law;SiSU markup sample:scholarly writing:law;law:international:commercial arbitration|uniform law|harmonization;private law;arbitration:international commercial
+ language.document_char: en
notes.summary: International commercial law writing on the implications of harmonization of law, globalization and international contracting.
}
@@ -19,6 +26,7 @@
auto_num_top_at_level: 1
auto_num_top_lv: 4
auto_num_depth: 2
+ home_button_text: ┥sisudoc.org┝┤https://sisudoc.org├ ┥doc-reform.org┝┤https://doc-reform.org├ ┥sources / git┝┤https://git.sisudoc.org/projects├
}
@doc_has {
diff --git a/test/reference/abstraction/sisu-manual:sisu_markup.en.ssp b/test/reference/abstraction/sisu-manual:sisu_markup.en.ssp
index cf84157..cbcd6b3 100644
--- a/test/reference/abstraction/sisu-manual:sisu_markup.en.ssp
+++ b/test/reference/abstraction/sisu-manual:sisu_markup.en.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: sisu_markup.sst
+@source {
+ language: en
+ languages: en
+ digest: F93CFE033E239243B1B23CFD1820DF7D30B53B86F3395970924AFCB0CA7FC807
+}
+
@meta {
title.main: Spine, Doc Reform
title.subtitle: SiSU Markup
@@ -16,6 +22,7 @@
rights.copyright: Ralph Amissah 2007
rights.license: GPL 3 (part of SiSU documentation)
classify.topic_register: electronic documents:SiSU:document:markup;SiSU:document:markup;SiSU:manual:markup;electronic documents:SiSU:manual:markup;SiSU markup sample:technical writing;software:program
+ language.document_char: en
}
@make {
@@ -23,6 +30,9 @@
auto_num_top_at_level: 1
auto_num_top_lv: 4
auto_num_depth: 2
+ breaks: new=:B; break=1
+ footer: ┥SiSU┝┤https://sisudoc.org├|┥git┝┤https://git.sisudoc.org├
+ home_button_text: ┥doc-reform┝┤https://doc-reform.org├┘┥sources / git┝┤https://git.sisudoc.org├┘┥SiSU┝┤https://sisudoc.org├┘
}
@doc_has {
diff --git a/test/reference/abstraction/the_autonomous_contract.ralph_amissah.en.ssp b/test/reference/abstraction/the_autonomous_contract.ralph_amissah.en.ssp
index 2be8f92..11abbb2 100644
--- a/test/reference/abstraction/the_autonomous_contract.ralph_amissah.en.ssp
+++ b/test/reference/abstraction/the_autonomous_contract.ralph_amissah.en.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: the_autonomous_contract.ralph_amissah.sst
+@source {
+ language: en
+ languages: en
+ digest: BB7040C0F095BA2957D1875972EFF994D8B2FA97187E727B65BA92F9E94562EF
+}
+
@meta {
title.main: The Autonomous Contract
title.subtitle: Reflecting the borderless electronic-commercial environment in contracting
@@ -11,6 +17,7 @@
date.published: 1997-10-07
rights.copyright: 1997 Ralph Amissah
classify.topic_register: SiSU markup sample:article:law;SiSU markup sample:scholarly writing:law;law:international:commercial arbitration|uniform law|harmonization;private law;arbitration:international commercial
+ language.document_char: en
notes.summary: International commercial law writing on the implications of harmonization of law, globalization and international contracting.
}
@@ -19,6 +26,7 @@
auto_num_top_at_level: 1
auto_num_top_lv: 4
auto_num_depth: 2
+ home_button_text: ┥sisudoc.org┝┤https://sisudoc.org├ ┥doc-reform.org┝┤https://doc-reform.org├ ┥sources / git┝┤https://git.sisudoc.org/projects├
}
@doc_has {
diff --git a/test/reference/abstraction/the_cathedral_and_the_bazaar.eric_s_raymond.en.ssp b/test/reference/abstraction/the_cathedral_and_the_bazaar.eric_s_raymond.en.ssp
index d40f452..c2d8f2e 100644
--- a/test/reference/abstraction/the_cathedral_and_the_bazaar.eric_s_raymond.en.ssp
+++ b/test/reference/abstraction/the_cathedral_and_the_bazaar.eric_s_raymond.en.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: the_cathedral_and_the_bazaar.eric_s_raymond.sst
+@source {
+ language: en
+ languages: en
+ digest: B194C3FB0C43A2249A22DF5CFFFA08A65DD891C13EB0F4982FCB365F30833402
+}
+
@meta {
title.main: The Cathedral and the Bazaar
title.full: The Cathedral and the Bazaar
@@ -15,6 +21,7 @@
rights.copyright: © 2000 Eric S. Raymond.
rights.license: Permission is granted to copy, distribute and/or modify this document under the terms of the Open Publication License, version 2.0.
classify.topic_register: SiSU markup sample:book:discourse;programming;software:open source;open source software:development
+ language.document_char: en
notes.abstract: I anatomize a successful open-source project, fetchmail, that was run as a deliberate test of the surprising theories about software engineering suggested by the history of Linux. I discuss these theories in terms of two fundamentally different development styles, the "cathedral" model of most of the commercial world versus the "bazaar" model of the Linux world. I show that these models derive from opposing assumptions about the nature of the software-debugging task. I then make a sustained argument from the Linux experience for the proposition that "Given enough eyeballs, all bugs are shallow", suggest productive analogies with other self-correcting systems of selfish agents, and conclude with some exploration of the implications of this insight for the future of software.
}
@@ -22,6 +29,9 @@
doc_type: article
auto_num_top_lv: 9
auto_num_depth: 2
+ breaks: break=1
+ footer: ┥The Cathedral and the Bazaar┝┤https://www.catb.org/esr/writings/homesteading/├|┥Eric S. Raymond┝┤https://www.catb.org/~esr/├
+ home_button_text: ┥The Cathedral and the Bazaar┝┤https://www.catb.org/esr/writings/homesteading/├┘┥Eric S. Raymond┝┤https://www.catb.org/~esr/├┘
}
@doc_has {
diff --git a/test/reference/abstraction/the_public_domain.james_boyle.en.ssp b/test/reference/abstraction/the_public_domain.james_boyle.en.ssp
index d0d911d..ff2d027 100644
--- a/test/reference/abstraction/the_public_domain.james_boyle.en.ssp
+++ b/test/reference/abstraction/the_public_domain.james_boyle.en.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: the_public_domain.james_boyle.sst
+@source {
+ language: en
+ languages: en
+ digest: 57F0D3242A4486F8D946FC9A55BB64DCC75573B9EE8CB00655A02BD5277AB9C2
+}
+
@meta {
title.main: The Public Domain
title.subtitle: Enclosing the Commons of the Mind
@@ -12,12 +18,16 @@
rights.copyright: 2008, James Boyle
rights.license: Creative Commons Attribution-Noncommercial-Share Alike (CC-BY-NC-SA) 3.0 https://creativecommons.org/licenses/by-nc-sa/3.0/
classify.topic_register: SiSU markup sample:book:discourse;public domain;intellectual property:public domain
+ language.document_char: en
}
@make {
doc_type: book
auto_num_top_lv: 9
auto_num_depth: 2
+ breaks: break=1
+ footer: ┥The Public Domain┝┤https://www.thepublicdomain.org/├|┥James Boyle┝┤http://james-boyle.com/├
+ home_button_text: ┥The Public Domain┝┤https://www.thepublicdomain.org/├┘┥James Boyle┝┤http://james-boyle.com/├┘
}
@doc_has {
diff --git a/test/reference/abstraction/the_wealth_of_networks.yochai_benkler.en.ssp b/test/reference/abstraction/the_wealth_of_networks.yochai_benkler.en.ssp
index 112c561..e3a3c96 100644
--- a/test/reference/abstraction/the_wealth_of_networks.yochai_benkler.en.ssp
+++ b/test/reference/abstraction/the_wealth_of_networks.yochai_benkler.en.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: the_wealth_of_networks.yochai_benkler.sst
+@source {
+ language: en
+ languages: en
+ digest: 4FF21EC9BDF8C2FBCB4F55E2AC34C9BADE29C2B2EA9A9A420293627D86FF01BC
+}
+
@meta {
title.main: The Wealth of Networks
title.subtitle: How Social Production Transforms Markets and Freedom
@@ -18,12 +24,16 @@
rights.copyright: 2006 Yochai Benkler.
rights.license: All rights reserved. Subject to the exception immediately following, this book may not be reproduced, in whole or in part, including illustrations, in any form (beyond that copying permitted by Sections 107 and 108 of the U.S. Copyright Law and except by reviewers for the public press), without written permission from the publishers. https://creativecommons.org/licenses/by-nc-sa/2.5/ The author has made an online version of the book available under a Creative Commons Noncommercial Sharealike license; it can be accessed through the author's website at https://www.benkler.org.
classify.topic_register: SiSU markup sample:book:discourse;networks;Internet;intellectual property:patents|copyright;intellectual property:copyright:creative commons;economics;society;copyright;patents;book:subject:information society|information networks|economics|public policy|society|copyright|patents
+ language.document_char: en
}
@make {
doc_type: book
auto_num_top_lv: 9
auto_num_depth: 2
+ breaks: new=:B; break=1
+ footer: ┥The Wealth of Networks┝┤https://cyber.law.harvard.edu/wealth_of_networks/Main_Page├|┥Yochai Benkler┝┤https://www.benkler.org├
+ home_button_text: ┥The Wealth of Networks┝┤https://cyber.law.harvard.edu/wealth_of_networks/Main_Page├┘┥Yochai Benkler┝┤https://www.benkler.org├┘
}
@doc_has {
diff --git a/test/reference/abstraction/through_the_looking_glass.lewis_carroll.en.ssp b/test/reference/abstraction/through_the_looking_glass.lewis_carroll.en.ssp
index 94e4ae5..fa0e68a 100644
--- a/test/reference/abstraction/through_the_looking_glass.lewis_carroll.en.ssp
+++ b/test/reference/abstraction/through_the_looking_glass.lewis_carroll.en.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: through_the_looking_glass.lewis_carroll.sst
+@source {
+ language: en
+ languages: en
+ digest: 74A6E0F80ED3D8398F01D00BAA5C48E8508BE430BB239C5419F1DAD1F85C58D0
+}
+
@meta {
title.main: Through The Looking-Glass
title.full: Through The Looking-Glass
@@ -11,15 +17,19 @@
date.created: 1871
date.issued: 1871
date.available: 1871
+ date.added_to_site: 2004-04-12
rights.copyright: Lewis Carroll
rights.license: Public Domain
classify.topic_register: SiSU markup sample:book:novel;book:novel:fiction:fantasy|children's fiction
+ language.document_char: en
}
@make {
doc_type: book
auto_num_top_lv: 9
auto_num_depth: 2
+ breaks: new=B; break=1
+ home_button_text: ┥sisudoc.org┝┤https://sisudoc.org├ ┥doc-reform.org┝┤https://doc-reform.org├ ┥sources / git┝┤https://git.sisudoc.org/projects├
}
@doc_has {
diff --git a/test/reference/abstraction/two_bits.christopher_kelty.en.ssp b/test/reference/abstraction/two_bits.christopher_kelty.en.ssp
index f4b9fe4..04a2391 100644
--- a/test/reference/abstraction/two_bits.christopher_kelty.en.ssp
+++ b/test/reference/abstraction/two_bits.christopher_kelty.en.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: two_bits.christopher_kelty.sst
+@source {
+ language: en
+ languages: en
+ digest: FA6E71B3642D5B70152B13F62100FDD19A4F9632DEBF2FE111161A723065931C
+}
+
@meta {
title.main: Two Bits
title.subtitle: The Cultural Significance of Free Software
@@ -12,12 +18,16 @@
rights.copyright: 2008 Duke University Press ┙ Printed in the United States of America on acid-free paper ∞ ┙ Designed by C. H. Westmoreland ┙ Typeset in Charis (an Open Source font) by Achorn International ┙ Library of Congress Cataloging-in-Publication data and republication acknowledgments appear on the last printed pages of this book.
rights.license: Licensed under the Creative Commons Attribution-NonCommercial-Share Alike License, available at https://creativecommons.org/licenses/by-nc-sa/3.0/ or by mail from Creative Commons, 559 Nathan Abbott Way, Stanford, Calif. 94305, U.S.A. "NonCommercial" as defined in this license specifically excludes any sale of this work or any portion thereof for money, even if sale does not result in a profit by the seller or if the sale is by a 501(c)(3) nonprofit or NGO. ┙ Duke University Press gratefully acknowledges the support of HASTAC (Humanities, Arts, Science, and Technology Advanced Collaboratory), which provided funds to help support the electronic interface of this book. ┙ Two Bits is accessible on the Web at twobits.net.
classify.topic_register: SiSU markup sample:book:discourse;open source software:social aspects;software:development:geeks;anthropology:geeks;book:subject:anthropology|information society|geeks;society;programming;society:information society;
+ language.document_char: en
}
@make {
doc_type: book
auto_num_top_lv: 9
auto_num_depth: 2
+ breaks: new=:B; break=1
+ footer: ┥Two Bits┝┤https://twobits.net├|┥Christopher M. Kelty┝┤https://kelty.org/├
+ home_button_text: ┥Two Bits┝┤https://twobits.net├┘┥Christopher M. Kelty┝┤https://kelty.org/├┘
}
@doc_has {
diff --git a/test/reference/abstraction/viral_spiral.david_bollier.en.ssp b/test/reference/abstraction/viral_spiral.david_bollier.en.ssp
index 952ac5f..3b2d6ab 100644
--- a/test/reference/abstraction/viral_spiral.david_bollier.en.ssp
+++ b/test/reference/abstraction/viral_spiral.david_bollier.en.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: viral_spiral.david_bollier.sst
+@source {
+ language: en
+ languages: en
+ digest: 7FA855D24BEF0779772D6E231BB6961BA8B1845C3774C0E6D32CC360B5A43E37
+}
+
@meta {
title.main: Viral Spiral
title.subtitle: How the Commoners Built a Digital Republic of Their Own
@@ -13,12 +19,16 @@
rights.copyright: © 2008 by David Bollier All rights reserved. No part of this book may be reproduced, in any form, without written permission from the publisher. The author has made an online version of the book available under a Creative Commons Attribution-NonCommercial license. It can be accessed at http://www.viralspiral.cc and http://www.onthecommons.org. Requests for permission to reproduce selections from this book should be mailed to "Permissions Department, The New Press, 38 Greene Street, New York, NY 10013". Published in the United States by The New Press, New York, 2008 Distributed by W. W. Norton & Company, Inc., New York ISBN 978-1-59558-396-3 (hc.) CIP data available The New Press was established in 1990 as a not-for-profit alternative to the large, commercial publishing houses currently dominating the book publishing industry. The New Press operates in the public interest rather than for private gain, and is committed to publishing, in innovative ways, works of educational, cultural, and community value that are often deemed insufficiently profitable. www.thenewpress.com A Caravan book. For more information, visit www.caravanbooks.org.
rights.license: Creative Commons Attribution-NonCommercial license.
classify.topic_register: SiSU markup sample:book:discourse;networks;Internet:social aspects|copyright|intellectual property;intellectual property:patents|public domain;intellectual property:copyright:creative commons;society:information society;copyright:creative commons|public domain|licenses;patents;book:subject:information society|information networks|society|copyright|creative commons|patents|culture;open source software:social aspects;software:free software|GPL|open source;license:GPL;programming;democracy;democratization;creative commons;public domain:copyright law (U.S.);free culture;culture
+ language.document_char: en
}
@make {
doc_type: book
auto_num_top_lv: 9
auto_num_depth: 2
+ breaks: new=:B,C; break=1
+ footer: ┥Viral Spiral┝┤https://www.bollier.org/viral-spiral-how-commoners-built-digital-republic-their-own├|┥David Bollier┝┤https://www.bollier.org/├
+ home_button_text: ┥Viral Spiral┝┤https://www.bollier.org/viral-spiral-how-commoners-built-digital-republic-their-own├┘┥David Bollier┝┤https://www.bollier.org/├┘
}
@doc_has {
diff --git a/test/reference/abstraction/war_and_peace.leo_tolstoy.en.ssp b/test/reference/abstraction/war_and_peace.leo_tolstoy.en.ssp
index fc00d14..b2914ce 100644
--- a/test/reference/abstraction/war_and_peace.leo_tolstoy.en.ssp
+++ b/test/reference/abstraction/war_and_peace.leo_tolstoy.en.ssp
@@ -1,6 +1,12 @@
-% SiSU Document Abstraction v0.1
+% SiSU Document Abstraction v1.1
% Source: war_and_peace.leo_tolstoy.sst
+@source {
+ language: en
+ languages: en
+ digest: D00B3781F607563F5517F909F96FB70031F8A44871B993E5595DF3ED7EDA30D1
+}
+
@meta {
title.main: War and Peace
title.full: War and Peace
@@ -13,15 +19,19 @@
date.issued: 1865
date.available: 1865
date.modified: 1869
+ date.added_to_site: 2004-04-12
rights.copyright: Leo Tolstoy 1869, translated by Aylmer Maude, Louise Shanks Maude
rights.license: Public Domain
classify.topic_register: SiSU:markup sample:book;book:novel:historical romance|war novel;Russian:original text;original text language:Russian
+ language.document_char: en
}
@make {
doc_type: book
auto_num_top_lv: 9
auto_num_depth: 2
+ breaks: new=:B; break=1
+ home_button_text: ┥sisudoc.org┝┤https://sisudoc.org├ ┥doc-reform.org┝┤https://doc-reform.org├ ┥sources / git┝┤https://git.sisudoc.org/projects├
}
@doc_has {
diff --git a/test/test-abstraction-db.sh b/test/test-abstraction-db.sh
index 31e5fa5..6a0e4e6 100755
--- a/test/test-abstraction-db.sh
+++ b/test/test-abstraction-db.sh
@@ -211,11 +211,48 @@ for ssp in $(find "$OUT_DIR/pod" -name "*.ssp" 2>/dev/null | sort); do
rm -f "$OUT_DIR/.dbtxt.$$" "$OUT_DIR/.ssptxt.$$"
done
+ # the header blocks: every @source/@meta/@make/@doc_has property in the .ssp
+ # must be in the database under its own key, with the same value. this is
+ # what catches a header property that reaches one artefact and not the
+ # other, which a count of objects cannot see.
+ awk '
+ /^@(source|meta|make|doc_has) \{$/ { blk=substr($1,2); next }
+ /^\}$/ { blk=""; next }
+ blk != "" && /^ [a-z_.]+: / {
+ k=$1; sub(/:$/,"",k)
+ v=substr($0, index($0,": ")+2)
+ pfx = (blk=="meta") ? "" : blk "."
+ print pfx k "\t" v
+ }
+ ' "$ssp" | sort > "$OUT_DIR/.sspmeta.$$"
+ sqlite3 -separator "$(printf '\t')" "$db" \
+ "select key, value from metadata where key not in
+ ('schema.name','schema.version','source.filename','source.ssp_digest');" \
+ 2>/dev/null | sort > "$OUT_DIR/.dbmeta.$$"
+ if ! diff -q "$OUT_DIR/.sspmeta.$$" "$OUT_DIR/.dbmeta.$$" > /dev/null 2>&1; then
+ [ $doc_fail -eq 0 ] && echo "$base"
+ echo " MISMATCH header blocks (.ssp against metadata table):"
+ diff "$OUT_DIR/.sspmeta.$$" "$OUT_DIR/.dbmeta.$$" | head -8 | sed 's/^/ /'
+ doc_fail=1
+ fi
+ rm -f "$OUT_DIR/.sspmeta.$$" "$OUT_DIR/.dbmeta.$$"
+
+ # the source filename, and the version the two share
+ sf=$(sqlite3 "$db" "select value from metadata where key='source.filename';" 2>/dev/null || echo '')
+ sf_ssp=$(sed -n 's/^% Source: //p' "$ssp" | head -1)
+ if [ "$sf" != "$sf_ssp" ]; then
+ [ $doc_fail -eq 0 ] && echo "$base"
+ echo " MISMATCH source.filename: db '$sf' .ssp '$sf_ssp'"; doc_fail=1
+ fi
+ sv_ssp=$(sed -n 's/^% SiSU Document Abstraction v//p' "$ssp" | head -1)
# the file says what it is
sv=$(sqlite3 "$db" "select value from metadata where key='schema.version';" 2>/dev/null || echo '')
if [ -z "$sv" ]; then
[ $doc_fail -eq 0 ] && echo "$base"
echo " MISSING metadata schema.version"; doc_fail=1
+ elif [ "$sv" != "$sv_ssp" ]; then
+ [ $doc_fail -eq 0 ] && echo "$base"
+ echo " MISMATCH format version: db '$sv' .ssp '$sv_ssp'"; doc_fail=1
fi
FAILURES=$((FAILURES + doc_fail))