fix: preserve controlled term values when deserializing - #107
Open
ehennestad wants to merge 2 commits into
Open
Conversation
A controlled term read back from a document lost every property. All 112 controlled term types were affected, so no controlled term survived a save and load cycle. initializeControlledTerm received the decoded structure, took only the identifier from it, and passed that to deserializeFromName. The rest of the structure was discarded. For a term defined by a user, the identifier is a blank node identifier that matches nothing in the controlled instance library, so deserializeFromName warned and returned, leaving an empty object with a freshly generated identifier. A structure is now treated as authoritative when it carries property values, because that is a serialized instance and its values are the only record of a user-defined term. A structure carrying nothing but JSON-LD keywords describes no values, so it is still resolved against the controlled instance library as a reference. This takes the round-trip suite from 150 to 261 of 292 types. The controlled term predicate is removed from the known-gap list. TermSuggestion still fails, for an unrelated reason: its addExistingTerminology property is typed as an openMINDS type but is not registered in LINKED_PROPERTIES, because the generated controlled term classes do not declare that constant at all. It serializes inline without a type or an identifier and cannot be read back. That needs a generator change and is now listed on its own. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Contributor
Test Results (R2022a)745 tests +2 741 ✅ +15 2m 19s ⏱️ -11s For more details on these failures, see this check. Results for commit 80eb833. ± Comparison against base commit cf77ac2. ♻️ This comment has been updated with latest results. |
ehennestad
force-pushed
the
fix-controlled-term-deserialization
branch
from
August 27, 2026 23:51
8973203 to
80eb833
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## fix-schema-resolve-array-handling #107 +/- ##
=====================================================================
+ Coverage 78.91% 79.02% +0.10%
=====================================================================
Files 417 417
Lines 4031 4042 +11
=====================================================================
+ Hits 3181 3194 +13
+ Misses 850 848 -2 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
ehennestad
force-pushed
the
fix-controlled-term-deserialization
branch
6 times, most recently
from
August 28, 2026 12:59
c9ab714 to
80eb833
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A controlled term read back from a JSON-LD document lost every property. This affected all 112 controlled term types, so no controlled term survived a save and load cycle.
The defect
Saving a user-defined
MRIFatSuppressionTechniqueproduced a complete document, and loading it produced this:{ "@id": "_:6322ef38-...", "@type": "https://openminds.om-i.org/types/MRIFatSuppressionTechnique" }Name, definition, description, synonyms, cross-references and ontology identifiers were all gone, and the identifier had changed.
initializeControlledTermreceived the decoded structure and took only the identifier from it:deserializeFromNamethen looks the identifier up in the controlled instance library. For a term defined by a user that identifier is a blank node identifier which matches nothing, so the method warned and returned, leaving an empty object. The constructor had already generated a new identifier, which is why the@idchanged too.The fix
The two cases a structure can represent are now distinguished.
A structure that carries property values is a serialized instance. Its values are authoritative and are used as they stand, which is the only way a term that is not in the controlled instance library can survive being written out and read back.
A structure that carries nothing but JSON-LD keywords is a reference. It describes no values, so there is nothing to populate from and the term is resolved against the controlled instance library exactly as before.
Terms constructed from a name or an instance IRI are unaffected: that path does not go through the structure branch.
Effect on coverage
The round-trip suite goes from 150 to 261 of 292 types. 111 of the 112 controlled terms now round trip, and the controlled term predicate is removed from
ommtest.helper.knownRoundTripGap.What is still failing
TermSuggestionis the one controlled term that still fails, for an unrelated reason. ItsaddExistingTerminologyproperty is declared asopenminds.controlledterms.Terminologybut is not registered inLINKED_PROPERTIES, so the serializer does not recognise it as a link. It serializes inline as a bare property bag with no@typeand no@id, and on reload the value cannot be converted back, so the whole instance is dropped with a warning.The cause is that none of the 112 generated controlled term classes declare
LINKED_PROPERTIESorEMBEDDED_PROPERTIES. They inherit hardcoded empty structs fromControlledTermBase, which encodes the assumption that a controlled term never points at another openMINDS type. That assumption holds for 111 of them. Fixing it means changing the generator, so it is out of scope here and is now listed on its own in the known-gap list.Worth noting separately: because the instance is dropped, the collection ends up empty, and
Collection.getAllthen fails on an unset dictionary rather than returning nothing. That is a small independent defect.Tests
Two cases added to
ControlledTermTest, one for each branch of the new distinction: a structure carrying values populates the term from those values, and a structure carrying only an identifier is looked up in the library. They construct the structure directly rather than going through the synthesizer, so they document the contract independently of the round-trip suite.🤖 Generated with Claude Code