aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRalph Amissah <ralph.amissah@gmail.com>2026-08-28 19:07:05 -0400
committerRalph Amissah <ralph.amissah@gmail.com>2026-08-28 20:15:35 -0400
commit45a73e4464fb662d481d31ebf8d3ef204296159a (patch)
tree0aa0ef5111f55a6ad6cfce4110fa961d9e2001b1
parenttest build .ssp requires --serial (--no-parallel) run (diff)
.ssp: doc structure related fixes (& to epub toc_nav)
for document abstraction and its .ssp output, removed the requirement of including --abstraction & --serial flags to produce correct output (for: .dom_status, .dom_status_collapsed & .last_descendant) - meta_processing_xml_dom() includes show_abstraction, so --pod2 and --show-abstraction run the dom pass; last_descendant is derived from that pass via after_doc_get_descendants() The accumulators are now verified as eight wide locals of docAbstraction(), so each document starts clean and no two threads share one. - bug: the four dom accumulators were template scope (shared) and nine wide, while their end of document reset was eight wide, so the first document of a run differed from the rest and parallel runs raced on one buffer, (which also mis-nested epub toc_nav) test/ reference .ssp regenerated: accelerando only, trailing zero dropped. test-abstraction-ssp.sh now runs parallel and diffs output against a serial run. (assisted by Claude-Code)
-rw-r--r--org/ocda.org9
-rw-r--r--org/ocda_functions.org4
-rw-r--r--org/spine.org2
-rw-r--r--org/test_shell_script_ssp_document_abstraction.org39
-rw-r--r--src/sisudoc/ocda/meta/metadoc_from_src.d9
-rw-r--r--src/sisudoc/ocda/meta/metadoc_from_src_functions.d4
-rw-r--r--src/sisudoc/spine.d2
-rw-r--r--test/reference/abstraction/accelerando.charles_stross.en.ssp80
-rwxr-xr-xtest/test-abstraction-ssp.sh39
9 files changed, 124 insertions, 64 deletions
diff --git a/org/ocda.org b/org/ocda.org
index 1e9d79e..3a287e8 100644
--- a/org/ocda.org
+++ b/org/ocda.org
@@ -221,6 +221,11 @@ string[string] object_number_poem = [
"end" : ""
];
string[] lv_ancestors_txt = [ "", "", "", "", "", "", "", "", ];
+/+ ↓ dom structure state, per document (not shared, parallel safe) +/
+int[] dom_structure_markedup_tags_status = [ 0, 0, 0, 0, 0, 0, 0, 0,];
+int[] dom_structure_markedup_tags_status_buffer = [ 0, 0, 0, 0, 0, 0, 0, 0,];
+int[] dom_structure_collapsed_tags_status = [ 0, 0, 0, 0, 0, 0, 0, 0,];
+int[] dom_structure_collapsed_tags_status_buffer = [ 0, 0, 0, 0, 0, 0, 0, 0,];
int[string] lv = [
"lv" : eN.bi.off,
"h0" : eN.bi.off,
@@ -1619,10 +1624,6 @@ obj_cite_digit_ = 0;
html_segnames_ptr = 0;
html_segnames_ptr_cntr = 0;
content_non_header = "8";
-dom_structure_markedup_tags_status = [ 0, 0, 0, 0, 0, 0, 0, 0,];
-dom_structure_markedup_tags_status_buffer = [ 0, 0, 0, 0, 0, 0, 0, 0,];
-dom_structure_collapsed_tags_status = [ 0, 0, 0, 0, 0, 0, 0, 0,];
-dom_structure_collapsed_tags_status_buffer = [ 0, 0, 0, 0, 0, 0, 0, 0,];
lev_anchor_tag = "";
anchor_tag = "";
// identify parts
diff --git a/org/ocda_functions.org b/org/ocda_functions.org
index fc174fd..bda15b7 100644
--- a/org/ocda_functions.org
+++ b/org/ocda_functions.org
@@ -83,10 +83,6 @@ string content_non_header = "8";
// ocn
OCNset obj_cite_digits;
int obj_cite_digit_, obj_cite_digit_off, obj_cite_digit_bkidx, obj_cite_digit_type;
-int[] dom_structure_markedup_tags_status = [ 0, 0, 0, 0, 0, 0, 0, 0, 0,];
-int[] dom_structure_markedup_tags_status_buffer = [ 0, 0, 0, 0, 0, 0, 0, 0, 0,];
-int[] dom_structure_collapsed_tags_status = [ 0, 0, 0, 0, 0, 0, 0, 0, 0,];
-int[] dom_structure_collapsed_tags_status_buffer = [ 0, 0, 0, 0, 0, 0, 0, 0, 0,];
static auto obj_im = ObjInlineMarkup();
static auto obj_att = ObjAttributes();
auto object_citation_number = OCNemitter();
diff --git a/org/spine.org b/org/spine.org
index 6d67e3b..4f2d551 100644
--- a/org/spine.org
+++ b/org/spine.org
@@ -1015,6 +1015,8 @@ struct OptActions {
@trusted bool meta_processing_xml_dom() {
return (
opts["abstraction"]
+ || show_abstraction
+ || show_abstraction_db
|| html
|| epub
|| odt
diff --git a/org/test_shell_script_ssp_document_abstraction.org b/org/test_shell_script_ssp_document_abstraction.org
index eb7ca77..ccbe6dd 100644
--- a/org/test_shell_script_ssp_document_abstraction.org
+++ b/org/test_shell_script_ssp_document_abstraction.org
@@ -26,6 +26,9 @@
# Regression test for spine's document abstraction.
# Generates .ssp files for all sample documents and diffs
# against committed reference files.
+# Also checks that a parallel run and a serial run of the same documents
+# produce identical .ssp (guards against per-document state leaking
+# between documents or between worker threads).
#
# Usage:
# ./test/test-abstraction-ssp.sh # uses result/bin/spine
@@ -102,7 +105,7 @@ if [ "$GENERATE" = true ]; then
echo "Generating reference .ssp files..."
rm -rf "$REF_DIR"
mkdir -p "$REF_DIR"
- $SPINE_BIN --abstraction --serial --show-abstraction --skip-output --output="$SCRIPT_DIR/reference" "$SAMPLES_DIR"/* 2>&1 | tail -1
+ $SPINE_BIN --show-abstraction --skip-output --output="$SCRIPT_DIR/reference" "$SAMPLES_DIR"/* 2>&1 | tail -1
# flatten language subdirs into reference dir
find "$SCRIPT_DIR/reference" -name "*.ssp" ! -path "$REF_DIR/*" -exec mv {} "$REF_DIR/" \;
# clean up empty language dirs
@@ -123,11 +126,22 @@ fi
echo "Generating current .ssp files..."
rm -rf "$TMP_DIR"
mkdir -p "$TMP_DIR"
-$SPINE_BIN --abstraction --serial --show-abstraction --skip-output --output="$SCRIPT_DIR/current" "$SAMPLES_DIR"/* 2>&1 | tail -1
+$SPINE_BIN --abstraction --show-abstraction --skip-output --output="$SCRIPT_DIR/current" "$SAMPLES_DIR"/* 2>&1 | tail -1
# flatten
find "$SCRIPT_DIR/current" -name "*.ssp" ! -path "$TMP_DIR/*" -exec mv {} "$TMP_DIR/" \;
find "$SCRIPT_DIR/current" -mindepth 1 -type d -empty -delete 2>/dev/null || true
+# generate the same .ssp serially, to check that parallel and serial
+# processing agree (per-document state leaking between documents, or
+# between worker threads, shows up here)
+SER_DIR="$SCRIPT_DIR/current-serial/abstraction"
+echo "Generating current .ssp files (serial)..."
+rm -rf "$SCRIPT_DIR/current-serial"
+mkdir -p "$SER_DIR"
+$SPINE_BIN --show-abstraction --serial --skip-output --output="$SCRIPT_DIR/current-serial" "$SAMPLES_DIR"/* 2>&1 | tail -1
+find "$SCRIPT_DIR/current-serial" -name "*.ssp" ! -path "$SER_DIR/*" -exec mv {} "$SER_DIR/" \;
+find "$SCRIPT_DIR/current-serial" -mindepth 1 -type d -empty -delete 2>/dev/null || true
+
# diff
echo "Comparing against reference..."
FAILURES=0
@@ -157,12 +171,29 @@ for cur_file in "$TMP_DIR"/*.ssp; do
fi
done
+# parallel vs serial determinism
+for cur_file in "$TMP_DIR"/*.ssp; do
+ basename=$(basename "$cur_file")
+ ser_file="$SER_DIR/$basename"
+ if [ ! -f "$ser_file" ]; then
+ echo "MISSING (serial run): $basename"
+ FAILURES=$((FAILURES + 1))
+ continue
+ fi
+ if ! diff -q "$cur_file" "$ser_file" > /dev/null 2>&1; then
+ echo "NON-DETERMINISTIC: $basename (parallel and serial runs differ)"
+ diff --unified=3 "$cur_file" "$ser_file" | head -30
+ echo " ..."
+ FAILURES=$((FAILURES + 1))
+ fi
+done
+
# clean up
-rm -rf "$SCRIPT_DIR/current"
+rm -rf "$SCRIPT_DIR/current" "$SCRIPT_DIR/current-serial"
if [ "$FAILURES" -eq 0 ]; then
REF_COUNT=$(ls "$REF_DIR"/*.ssp | wc -l)
- echo "PASS: all $REF_COUNT .ssp files match reference"
+ echo "PASS: all $REF_COUNT .ssp files match reference (parallel and serial agree)"
exit 0
else
echo "FAIL: $FAILURES difference(s) found"
diff --git a/src/sisudoc/ocda/meta/metadoc_from_src.d b/src/sisudoc/ocda/meta/metadoc_from_src.d
index e104c94..7fcf3bb 100644
--- a/src/sisudoc/ocda/meta/metadoc_from_src.d
+++ b/src/sisudoc/ocda/meta/metadoc_from_src.d
@@ -136,6 +136,11 @@ template docAbstraction() {
"end" : ""
];
string[] lv_ancestors_txt = [ "", "", "", "", "", "", "", "", ];
+ /+ ↓ dom structure state, per document (not shared, parallel safe) +/
+ int[] dom_structure_markedup_tags_status = [ 0, 0, 0, 0, 0, 0, 0, 0,];
+ int[] dom_structure_markedup_tags_status_buffer = [ 0, 0, 0, 0, 0, 0, 0, 0,];
+ int[] dom_structure_collapsed_tags_status = [ 0, 0, 0, 0, 0, 0, 0, 0,];
+ int[] dom_structure_collapsed_tags_status_buffer = [ 0, 0, 0, 0, 0, 0, 0, 0,];
int[string] lv = [
"lv" : eN.bi.off,
"h0" : eN.bi.off,
@@ -1506,10 +1511,6 @@ template docAbstraction() {
html_segnames_ptr = 0;
html_segnames_ptr_cntr = 0;
content_non_header = "8";
- dom_structure_markedup_tags_status = [ 0, 0, 0, 0, 0, 0, 0, 0,];
- dom_structure_markedup_tags_status_buffer = [ 0, 0, 0, 0, 0, 0, 0, 0,];
- dom_structure_collapsed_tags_status = [ 0, 0, 0, 0, 0, 0, 0, 0,];
- dom_structure_collapsed_tags_status_buffer = [ 0, 0, 0, 0, 0, 0, 0, 0,];
lev_anchor_tag = "";
anchor_tag = "";
// identify parts
diff --git a/src/sisudoc/ocda/meta/metadoc_from_src_functions.d b/src/sisudoc/ocda/meta/metadoc_from_src_functions.d
index 9824d61..cf46fda 100644
--- a/src/sisudoc/ocda/meta/metadoc_from_src_functions.d
+++ b/src/sisudoc/ocda/meta/metadoc_from_src_functions.d
@@ -90,10 +90,6 @@ template docAbstractionFunctions() {
// ocn
OCNset obj_cite_digits;
int obj_cite_digit_, obj_cite_digit_off, obj_cite_digit_bkidx, obj_cite_digit_type;
- int[] dom_structure_markedup_tags_status = [ 0, 0, 0, 0, 0, 0, 0, 0, 0,];
- int[] dom_structure_markedup_tags_status_buffer = [ 0, 0, 0, 0, 0, 0, 0, 0, 0,];
- int[] dom_structure_collapsed_tags_status = [ 0, 0, 0, 0, 0, 0, 0, 0, 0,];
- int[] dom_structure_collapsed_tags_status_buffer = [ 0, 0, 0, 0, 0, 0, 0, 0, 0,];
static auto obj_im = ObjInlineMarkup();
static auto obj_att = ObjAttributes();
auto object_citation_number = OCNemitter();
diff --git a/src/sisudoc/spine.d b/src/sisudoc/spine.d
index c80814e..17950d0 100644
--- a/src/sisudoc/spine.d
+++ b/src/sisudoc/spine.d
@@ -821,6 +821,8 @@ string program_name = "spine";
@trusted bool meta_processing_xml_dom() {
return (
opts["abstraction"]
+ || show_abstraction
+ || show_abstraction_db
|| html
|| epub
|| odt
diff --git a/test/reference/abstraction/accelerando.charles_stross.en.ssp b/test/reference/abstraction/accelerando.charles_stross.en.ssp
index b45d383..d1043f9 100644
--- a/test/reference/abstraction/accelerando.charles_stross.en.ssp
+++ b/test/reference/abstraction/accelerando.charles_stross.en.ssp
@@ -40,8 +40,8 @@
.section: body
.last_descendant: 2734
.children: 2 4 8 10 0 13 224 477 730 0 733 973 1413 1712 0 1715 2162 2492
-.dom_status: 1 0 0 0 0 0 0 0 0
-.dom_status_collapsed: 1 0 0 0 0 0 0 0 0
+.dom_status: 1 0 0 0 0 0 0 0
+.dom_status_collapsed: 1 0 0 0 0 0 0 0
.heading_lev_collapsed: 0
.is_of_type: para
.sha256: 157C19435123E42C013D0E6C1432C806C8EE160B7E8FE46B2C41D9B6F0E3ADF3
@@ -57,8 +57,8 @@
[0] heading :1
.part: frontmatter
.parent: 1
-.dom_status: 4 0 0 0 1 0 0 0 0
-.dom_status_collapsed: 4 1 0 0 0 0 0 0 0
+.dom_status: 4 0 0 0 1 0 0 0
+.dom_status_collapsed: 4 1 0 0 0 0 0 0
.heading_lev_collapsed: 1
.ocn_off: true
.is_of_type: para
@@ -226,8 +226,8 @@
.last_descendant: 3
.ancestors: 1 0 0 0 2 0 0 0
.ancestors_collapsed: 1 2 0 0 0 0 0 0
-.dom_status: 4 0 0 0 3 0 0 0 0
-.dom_status_collapsed: 4 3 0 0 0 0 0 0 0
+.dom_status: 4 0 0 0 3 0 0 0
+.dom_status_collapsed: 4 3 0 0 0 0 0 0
.heading_lev_collapsed: 1
.is_of_type: para
.sha256: 051FAFDBDE71CBFCBD5226D9E0636017B594C31FECD7DBFD75347756B9580FB1
@@ -252,8 +252,8 @@
.last_descendant: 7
.ancestors: 1 0 0 0 4 0 0 0
.ancestors_collapsed: 1 4 0 0 0 0 0 0
-.dom_status: 4 0 0 0 3 0 0 0 0
-.dom_status_collapsed: 4 3 0 0 0 0 0 0 0
+.dom_status: 4 0 0 0 3 0 0 0
+.dom_status_collapsed: 4 3 0 0 0 0 0 0
.heading_lev_collapsed: 1
.is_of_type: para
.sha256: C9015D53B90846454375A2FDF2829C66FAD7A2E52DE1E89E73949CA59C905E49
@@ -292,8 +292,8 @@
.last_descendant: 9
.ancestors: 1 0 0 0 8 0 0 0
.ancestors_collapsed: 1 8 0 0 0 0 0 0
-.dom_status: 4 0 0 0 3 0 0 0 0
-.dom_status_collapsed: 4 3 0 0 0 0 0 0 0
+.dom_status: 4 0 0 0 3 0 0 0
+.dom_status_collapsed: 4 3 0 0 0 0 0 0
.heading_lev_collapsed: 1
.is_of_type: para
.sha256: 73011B17F477D131D2381FB32DA235FE9FB8D4108171600C7B628F911882C8C3
@@ -324,8 +324,8 @@
.last_descendant: 729
.ancestors: 1 10 0 0 0 0 0 0
.ancestors_collapsed: 1 10 0 0 0 0 0 0
-.dom_status: 4 1 0 0 2 0 0 0 0
-.dom_status_collapsed: 4 3 0 0 0 0 0 0 0
+.dom_status: 4 1 0 0 2 0 0 0
+.dom_status_collapsed: 4 3 0 0 0 0 0 0
.heading_lev_collapsed: 1
.is_of_type: para
.sha256: FB174039B83AADDC201C558357B12F6855FF606CBE516B4ECD59210078F260C6
@@ -341,8 +341,8 @@
.last_descendant: 1714
.ancestors: 1 0 0 0 0 0 0 0
.ancestors_collapsed: 1 0 0 0 0 0 0 0
-.dom_status: 4 4 0 0 1 0 0 0 0
-.dom_status_collapsed: 4 4 1 0 0 0 0 0 0
+.dom_status: 4 4 0 0 1 0 0 0
+.dom_status_collapsed: 4 4 1 0 0 0 0 0
.heading_lev_collapsed: 2
.dummy: true
.ocn_off: true
@@ -376,8 +376,8 @@
.last_descendant: 223
.ancestors: 1 0 0 0 13 0 0 0
.ancestors_collapsed: 1 0 13 0 0 0 0 0
-.dom_status: 4 4 0 0 3 0 0 0 0
-.dom_status_collapsed: 4 4 3 0 0 0 0 0 0
+.dom_status: 4 4 0 0 3 0 0 0
+.dom_status_collapsed: 4 4 3 0 0 0 0 0
.heading_lev_collapsed: 2
.is_of_type: para
.sha256: 526D2F3D6A2AB617CA69DAE98B934334B6C509199946C39AFC72B83AC453BD47
@@ -1917,8 +1917,8 @@
.last_descendant: 476
.ancestors: 1 0 0 0 224 0 0 0
.ancestors_collapsed: 1 0 224 0 0 0 0 0
-.dom_status: 4 4 0 0 3 0 0 0 0
-.dom_status_collapsed: 4 4 3 0 0 0 0 0 0
+.dom_status: 4 4 0 0 3 0 0 0
+.dom_status_collapsed: 4 4 3 0 0 0 0 0
.heading_lev_collapsed: 2
.is_of_type: para
.sha256: 4CB12C67D327E153D0CF0D2E7631788AB4F02D2CF0EC459716275A0C85A38FD7
@@ -3800,8 +3800,8 @@
.last_descendant: 729
.ancestors: 1 0 0 0 477 0 0 0
.ancestors_collapsed: 1 0 477 0 0 0 0 0
-.dom_status: 4 4 0 0 3 0 0 0 0
-.dom_status_collapsed: 4 4 3 0 0 0 0 0 0
+.dom_status: 4 4 0 0 3 0 0 0
+.dom_status_collapsed: 4 4 3 0 0 0 0 0
.heading_lev_collapsed: 2
.is_of_type: para
.sha256: 61B6ED4E134448326158671FA6E1E741371010BDE710F72F373631E003274B29
@@ -5692,8 +5692,8 @@
.last_descendant: 1711
.ancestors: 1 730 0 0 0 0 0 0
.ancestors_collapsed: 1 730 0 0 0 0 0 0
-.dom_status: 4 3 0 0 2 0 0 0 0
-.dom_status_collapsed: 4 3 2 0 0 0 0 0 0
+.dom_status: 4 3 0 0 2 0 0 0
+.dom_status_collapsed: 4 3 2 0 0 0 0 0
.heading_lev_collapsed: 1
.is_of_type: para
.sha256: 1CF1D6CA6C5DA4A374FA980872CA15222356F52D7CA3EF52978B1F9910A1D990
@@ -5709,8 +5709,8 @@
.last_descendant: 1714
.ancestors: 1 0 0 0 0 0 0 0
.ancestors_collapsed: 1 0 0 0 0 0 0 0
-.dom_status: 4 4 0 0 1 0 0 0 0
-.dom_status_collapsed: 4 4 1 0 0 0 0 0 0
+.dom_status: 4 4 0 0 1 0 0 0
+.dom_status_collapsed: 4 4 1 0 0 0 0 0
.heading_lev_collapsed: 2
.dummy: true
.ocn_off: true
@@ -5744,8 +5744,8 @@
.last_descendant: 972
.ancestors: 1 0 0 0 733 0 0 0
.ancestors_collapsed: 1 0 733 0 0 0 0 0
-.dom_status: 4 4 0 0 3 0 0 0 0
-.dom_status_collapsed: 4 4 3 0 0 0 0 0 0
+.dom_status: 4 4 0 0 3 0 0 0
+.dom_status_collapsed: 4 4 3 0 0 0 0 0
.heading_lev_collapsed: 2
.is_of_type: para
.sha256: 94C6CEF9D3DAA74E940D99101AD956843F58CC20666B68CC2E0A893A12E39374
@@ -7537,8 +7537,8 @@
.last_descendant: 1412
.ancestors: 1 0 0 0 973 0 0 0
.ancestors_collapsed: 1 0 973 0 0 0 0 0
-.dom_status: 4 4 0 0 3 0 0 0 0
-.dom_status_collapsed: 4 4 3 0 0 0 0 0 0
+.dom_status: 4 4 0 0 3 0 0 0
+.dom_status_collapsed: 4 4 3 0 0 0 0 0
.heading_lev_collapsed: 2
.is_of_type: para
.sha256: 76DAE01177002AA275718DC46F8CAD749B2F9632C83AD3176888D59BAE768493
@@ -10806,8 +10806,8 @@
.last_descendant: 1711
.ancestors: 1 0 0 0 1413 0 0 0
.ancestors_collapsed: 1 0 1413 0 0 0 0 0
-.dom_status: 4 4 0 0 3 0 0 0 0
-.dom_status_collapsed: 4 4 3 0 0 0 0 0 0
+.dom_status: 4 4 0 0 3 0 0 0
+.dom_status_collapsed: 4 4 3 0 0 0 0 0
.heading_lev_collapsed: 2
.is_of_type: para
.sha256: 8C2851009974A7E2649AF1D86257B1B507591D3A5B2B2BC65AF55285653C093F
@@ -13055,8 +13055,8 @@
.last_descendant: 1712
.ancestors: 1 1712 0 0 0 0 0 0
.ancestors_collapsed: 1 1712 0 0 0 0 0 0
-.dom_status: 4 3 0 0 2 0 0 0 0
-.dom_status_collapsed: 4 3 2 0 0 0 0 0 0
+.dom_status: 4 3 0 0 2 0 0 0
+.dom_status_collapsed: 4 3 2 0 0 0 0 0
.heading_lev_collapsed: 1
.is_of_type: para
.sha256: 89042D50D6682E3113ED6425380A8445A9B940C9B5143AD9AEB274C9CA571010
@@ -13072,8 +13072,8 @@
.last_descendant: 1714
.ancestors: 1 0 0 0 0 0 0 0
.ancestors_collapsed: 1 0 0 0 0 0 0 0
-.dom_status: 4 4 0 0 1 0 0 0 0
-.dom_status_collapsed: 4 4 1 0 0 0 0 0 0
+.dom_status: 4 4 0 0 1 0 0 0
+.dom_status_collapsed: 4 4 1 0 0 0 0 0
.heading_lev_collapsed: 2
.dummy: true
.ocn_off: true
@@ -13107,8 +13107,8 @@
.last_descendant: 2161
.ancestors: 1 0 0 0 1715 0 0 0
.ancestors_collapsed: 1 0 1715 0 0 0 0 0
-.dom_status: 4 4 0 0 3 0 0 0 0
-.dom_status_collapsed: 4 4 3 0 0 0 0 0 0
+.dom_status: 4 4 0 0 3 0 0 0
+.dom_status_collapsed: 4 4 3 0 0 0 0 0
.heading_lev_collapsed: 2
.is_of_type: para
.sha256: B2AAEF4D9C7C22FBBDDAF17210982D147EFDFAF3701C0DB4BB4E420C51A0ABEF
@@ -16362,8 +16362,8 @@
.last_descendant: 2491
.ancestors: 1 0 0 0 2162 0 0 0
.ancestors_collapsed: 1 0 2162 0 0 0 0 0
-.dom_status: 4 4 0 0 3 0 0 0 0
-.dom_status_collapsed: 4 4 3 0 0 0 0 0 0
+.dom_status: 4 4 0 0 3 0 0 0
+.dom_status_collapsed: 4 4 3 0 0 0 0 0
.heading_lev_collapsed: 2
.is_of_type: para
.sha256: A6B1385452152FDACCE796B9F648B7AC2AB36853E4AE88B5077C126C80BC16F6
@@ -18768,8 +18768,8 @@
.last_descendant: 2492
.ancestors: 1 0 0 0 2492 0 0 0
.ancestors_collapsed: 1 0 2492 0 0 0 0 0
-.dom_status: 4 4 0 0 3 0 0 0 0
-.dom_status_collapsed: 4 4 3 0 0 0 0 0 0
+.dom_status: 4 4 0 0 3 0 0 0
+.dom_status_collapsed: 4 4 3 0 0 0 0 0
.heading_lev_collapsed: 2
.is_of_type: para
.sha256: 7388DE67B1EAEEE974E40DD3A05AA493C110D68364C0467097A14CF2F32DCA21
diff --git a/test/test-abstraction-ssp.sh b/test/test-abstraction-ssp.sh
index 5267403..133cfb6 100755
--- a/test/test-abstraction-ssp.sh
+++ b/test/test-abstraction-ssp.sh
@@ -4,6 +4,9 @@
# Regression test for spine's document abstraction.
# Generates .ssp files for all sample documents and diffs
# against committed reference files.
+# Also checks that a parallel run and a serial run of the same documents
+# produce identical .ssp (guards against per-document state leaking
+# between documents or between worker threads).
#
# Usage:
# ./test/test-abstraction-ssp.sh # uses result/bin/spine
@@ -80,7 +83,7 @@ if [ "$GENERATE" = true ]; then
echo "Generating reference .ssp files..."
rm -rf "$REF_DIR"
mkdir -p "$REF_DIR"
- $SPINE_BIN --abstraction --serial --show-abstraction --skip-output --output="$SCRIPT_DIR/reference" "$SAMPLES_DIR"/* 2>&1 | tail -1
+ $SPINE_BIN --show-abstraction --skip-output --output="$SCRIPT_DIR/reference" "$SAMPLES_DIR"/* 2>&1 | tail -1
# flatten language subdirs into reference dir
find "$SCRIPT_DIR/reference" -name "*.ssp" ! -path "$REF_DIR/*" -exec mv {} "$REF_DIR/" \;
# clean up empty language dirs
@@ -101,11 +104,22 @@ fi
echo "Generating current .ssp files..."
rm -rf "$TMP_DIR"
mkdir -p "$TMP_DIR"
-$SPINE_BIN --abstraction --serial --show-abstraction --skip-output --output="$SCRIPT_DIR/current" "$SAMPLES_DIR"/* 2>&1 | tail -1
+$SPINE_BIN --abstraction --show-abstraction --skip-output --output="$SCRIPT_DIR/current" "$SAMPLES_DIR"/* 2>&1 | tail -1
# flatten
find "$SCRIPT_DIR/current" -name "*.ssp" ! -path "$TMP_DIR/*" -exec mv {} "$TMP_DIR/" \;
find "$SCRIPT_DIR/current" -mindepth 1 -type d -empty -delete 2>/dev/null || true
+# generate the same .ssp serially, to check that parallel and serial
+# processing agree (per-document state leaking between documents, or
+# between worker threads, shows up here)
+SER_DIR="$SCRIPT_DIR/current-serial/abstraction"
+echo "Generating current .ssp files (serial)..."
+rm -rf "$SCRIPT_DIR/current-serial"
+mkdir -p "$SER_DIR"
+$SPINE_BIN --show-abstraction --serial --skip-output --output="$SCRIPT_DIR/current-serial" "$SAMPLES_DIR"/* 2>&1 | tail -1
+find "$SCRIPT_DIR/current-serial" -name "*.ssp" ! -path "$SER_DIR/*" -exec mv {} "$SER_DIR/" \;
+find "$SCRIPT_DIR/current-serial" -mindepth 1 -type d -empty -delete 2>/dev/null || true
+
# diff
echo "Comparing against reference..."
FAILURES=0
@@ -135,12 +149,29 @@ for cur_file in "$TMP_DIR"/*.ssp; do
fi
done
+# parallel vs serial determinism
+for cur_file in "$TMP_DIR"/*.ssp; do
+ basename=$(basename "$cur_file")
+ ser_file="$SER_DIR/$basename"
+ if [ ! -f "$ser_file" ]; then
+ echo "MISSING (serial run): $basename"
+ FAILURES=$((FAILURES + 1))
+ continue
+ fi
+ if ! diff -q "$cur_file" "$ser_file" > /dev/null 2>&1; then
+ echo "NON-DETERMINISTIC: $basename (parallel and serial runs differ)"
+ diff --unified=3 "$cur_file" "$ser_file" | head -30
+ echo " ..."
+ FAILURES=$((FAILURES + 1))
+ fi
+done
+
# clean up
-rm -rf "$SCRIPT_DIR/current"
+rm -rf "$SCRIPT_DIR/current" "$SCRIPT_DIR/current-serial"
if [ "$FAILURES" -eq 0 ]; then
REF_COUNT=$(ls "$REF_DIR"/*.ssp | wc -l)
- echo "PASS: all $REF_COUNT .ssp files match reference"
+ echo "PASS: all $REF_COUNT .ssp files match reference (parallel and serial agree)"
exit 0
else
echo "FAIL: $FAILURES difference(s) found"