From c88ae83d444a54502550fecd9f0f92df68240c9f Mon Sep 17 00:00:00 2001 From: ehennestad Date: Mon, 31 Aug 2026 10:50:52 +0200 Subject: [PATCH] fix: make collection document node order deterministic The nodes of a collection document appeared in whatever order the collection returned them, and that order depends on the MATLAB release. Collection stores its nodes in a dictionary from R2022b, which preserves insertion order, and in a containers.Map on older releases, which returns values sorted by key. The same collection therefore serialized to a different document on R2022a than on R2022b and later. A @graph is semantically an unordered set, so no reader is affected by the order. But a document that differs by release cannot be compared against a golden file, defeats reproducible output for users who keep their metadata under version control, and produces noisy diffs when the same collection is saved from two machines. The nodes of a collection document are now sorted by @id before the document is assembled. Documents emitted separately, one per instance, are not reordered, because the folder store pairs them with their instances by position. Co-Authored-By: Claude Opus 5 --- .../+internal/+serializer/JsonLdSerializer.m | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/code/internal/+openminds/+internal/+serializer/JsonLdSerializer.m b/code/internal/+openminds/+internal/+serializer/JsonLdSerializer.m index 723e5f70..c366daa1 100644 --- a/code/internal/+openminds/+internal/+serializer/JsonLdSerializer.m +++ b/code/internal/+openminds/+internal/+serializer/JsonLdSerializer.m @@ -244,7 +244,7 @@ if obj.SerializationConfiguration.PropertyNameSyntax == "compact" document = obj.addVocabularyMapping(document); end - document.at_graph = documentList; + document.at_graph = obj.sortDocumentsByIdentifier(documentList); end function S = normalizeEmptyProperties(obj, S) @@ -263,6 +263,32 @@ end methods (Static, Access = private) + function documentList = sortDocumentsByIdentifier(documentList) + % sortDocumentsByIdentifier - Order the nodes of a collection document + % + % The nodes otherwise appear in whatever order the collection + % returns them, which depends on the container backing the + % collection and therefore on the MATLAB release: dictionary + % preserves insertion order, while containers.Map returns values + % sorted by key. A @graph is an unordered set, so an explicit + % order is imposed to make the document identical on every + % release. + % + % This applies only to the collection document. Documents + % emitted separately are not reordered, because stores pair them + % with their instances by position. + + identifiers = strings(1, numel(documentList)); + for i = 1:numel(documentList) + if isfield(documentList{i}, 'at_id') + identifiers(i) = documentList{i}.at_id; + end + end + + [~, sortOrder] = sort(identifiers); + documentList = documentList(sortOrder); + end + function allStructs = sortKeys(allStructs) % sortKeys - Sorts the keys of the given structs based on a predefined order. %