Summary:
When a model is exported to minimal JSON with include_cross_ref_uris=False, then re-imported with syside.json.loads(…), models that reference stdlib/library
elements emit unresolved-reference warnings during deserialization.
A stronger recovery path:
- syside.json.loads(…)
- DeserializedModel.link(IdMap of default environment docs)
- syside.Sema().resolve(…)
- syside.serialize(…, full options)
recovers the model much more accurately, including implied relationships and total element counts. However, the reconstructed full JSON is still not always
identical to the original full export from the text-loaded model. The remaining differences are localized in derived relationship fields such as feature,
featureMembership, inheritedFeature, usage, and some Subsetting targets.
Minimal reproducer for unresolved-reference warnings:
import warnings
import syside
src = “package P { private import ScalarValues::*; }”
model, diagnostics = syside.load_model(sysml_source=src)
assert not diagnostics.contains_errors(warnings_as_errors=True)
json_options = syside.JsonStringOptions()
json_options.include_cross_ref_uris = False
json_options.indent = False
writer = syside.JsonStringWriter(json_options)
options = syside.SerializationOptions.minimal()
with model.user_docs[0].lock() as locked:
syside.serialize(locked.root_node, writer, options)
raw_min = writer.result
with warnings.catch_warnings(record=True) as wlist:
warnings.simplefilter(“always”)
deserialized_model, _ = syside.json.loads(raw_min, “memory:///import.sysml”)
print([str(w.message) for w in wlist])
Minimal reproducer for external typed feature warning:
import warnings
import syside
src = “package P { part x { attribute mass :> ISQBase::mass; } }”
model, diagnostics = syside.load_model(sysml_source=src)
assert not diagnostics.contains_errors(warnings_as_errors=True)
json_options = syside.JsonStringOptions()
json_options.include_cross_ref_uris = False
json_options.indent = False
writer = syside.JsonStringWriter(json_options)
options = syside.SerializationOptions.minimal()
with model.user_docs[0].lock() as locked:
syside.serialize(locked.root_node, writer, options)
raw_min = writer.result
with warnings.catch_warnings(record=True) as wlist:
warnings.simplefilter(“always”)
deserialized_model, _ = syside.json.loads(raw_min, “memory:///import.sysml”)
print([str(w.message) for w in wlist])
Observed facts:
- The unresolved IDs are external/library elements, not missing local model elements.
- These IDs do exist in Environment.get_default().
- Examples observed:
- 40bb440c-… → ScalarValues
- 2a413ac9-… → SI
- 95bd17de-… → USCustomaryUnits
- 9af08108-… → ISQBase::mass
Recovery path that improves fidelity:
import syside
env = syside.Environment.get_default()
id_map = syside.IdMap()
for mutex in env.documents:
with mutex.lock() as dep:
id_map.insert_or_assign(dep)
deserialized_model.link(id_map)
syside.Sema().resolve([deserialized_model.document], env.index(), env.lib)
Actual behavior:
- syside.json.loads(…) emits unresolved-reference warnings when minimal JSON contains external/library references serialized without cross-ref URIs.
- The link(IdMap) + Sema.resolve(…) workaround reconstructs implied relationships and usually restores overall structure much better.
- But reconstructed full JSON can still differ from the original full export from the text-loaded model.
Real-model evidence:
Using Flashlight.sysml:
-
Original full export and reconstructed export had:
- same total element count: 2366
- same implied element count: 671
- same @id set and order
-
Remaining differences were limited to 13 type/field combinations
-
The differences were localized to derived relationship fields, including:
-
one PartUsage differing in:
- feature
- featureMembership
- inheritedFeature
- usage
-
one Subsetting differing in:
- general
- subsettedFeature
- relatedElement
- target
-
Expected behavior:
One of these should be true:
- JSON exported with include_cross_ref_uris=False should be documented as not cleanly round-trippable for models with external/library references.
- syside.json.loads(…) should avoid unresolved-reference warnings for references that are expected to be resolved later from the default environment.
- The combination of JSON deserialization, environment linking, and semantic resolution should reconstruct the same derived relationship bindings as the
original text-loaded model, if minimal JSON is intended to be a lossless model persistence format.
Likely root cause:
- With include_cross_ref_uris=False, external references are serialized as bare @id references.
- During json.loads(…), these become pending references with empty URI.
- This is not enough information for deserialization-time resolution.
- Later environment-based linking and semantic resolution recover most of the structure, but some derived relationships appear to be rebound differently from
the original text-loaded model.
Why this matters:
Minimal JSON appears to work as a compact persistence format, but for models with external/library references it is currently:
- noisy at deserialization time due to warnings
- not fully stable under round-trip reconstruction, even with environment linking and semantic resolution
Flashlight.sysml (19.6 KB)