Repository navigation
Conversation
jdsika
force-pushed
the
feat/linkml-domain-models
branch
from
October 2, 2026 18:35
bace4ad to
4dba4fa
Compare
This was referenced Oct 5, 2026
jdsika
force-pushed
the
feat/linkml-domain-models
branch
from
October 14, 2026 15:00
6606a49 to
b5f07cc
Compare
jdsika
force-pushed
the
feat/linkml-domain-models
branch
2 times, most recently
from
October 14, 2026 16:56
5f405e3 to
38224a9
Compare
…e inference The fast ABox inference behind per-resource validation applied rdfs3 only when the object was an IRI. RDF 1.1 Semantics rdfs3 entails the range type for every non-literal object, and the canonical apply_rdfs_inference already does so (FILTER(!isLiteral(?object))); the fast path's docstring claims the same rules. Inline JSON-LD values are blank nodes, so in per-resource mode they were never typed through rdfs:range, and any sh:class constraint on them failed only in that mode. Hand-written shapes mostly use sh:node and never noticed; shapes generated by LinkML use sh:class and fail immediately. - apply rdfs3 to every non-literal object in ShaclValidator._abox_inference - add a unit test asserting the fast and the canonical path type IRI and blank-node objects alike and never literals Signed-off-by: jdsika <carlo.van-driesten@vdl.digital>
… form Two parts of pySHACL's generic messages change from one process to the next, so a report snapshot holding them failed on some runs and passed on others: - an sh:in message lists the allowed values in the order of a Python set, which follows string hashing - a blank node is rendered to a fixed depth and the rendering cached under the node alone; a node reached by several paths is cut off (<http://recursion.too.deep>) wherever the first path happened to reach it The report formatter's normalization now sorts the sh:in values and replaces a rendering that pySHACL cut off with "[ ... ]". A complete rendering is sorted already and stays as it is, as does a custom sh:message that merely mentions a list. The structured violations applied both steps on their own; they now take them from the same normalization. Signed-off-by: jdsika <carlo.van-driesten@vdl.digital>
…main with one script
Pins linkml to the tag envited-x/2026.10.14 of the ASCS-eV fork
(536d6f194, the reviewed ENVITED-X pipeline), with the diff-stable extra.
The branch the tag was cut from is rebuilt by force-push; the tag names
one commit.
- scripts/build_linkml_domain.sh runs gen-owl, gen-shacl and
gen-jsonld-context for one domain with its linkml/<domain>/gen-flags.env:
always --no-use-native-uris and --diff-stable; it stages the three
artifacts in a temporary directory, fails on an empty artifact, on an
unexpanded IRI and on any rule or class expression gen-shacl skips, and
prints a failing generator's log
- `just generate` and `just generate-domain` build every LinkML domain with
that script; artifacts/gx/update-from-submodule.sh takes
deterministic_turtle from diffable_rdf
- openlabel-v2 is built by the script: --no-use-native-uris makes its OWL
declare the schema.org and Commons IRIs (schema:QuantitativeValue,
schema:minValue, ...) its SHACL and context already use, instead of local
openlabel_v2: stand-ins; rules on a class also constrain its subclasses'
shapes; the header predicates are declared annotation properties
- openlabel-v2 Rule 17 ("DrivableAreaEdge includes EdgeNone") is
has_member: a bare equals_string on a multivalued slot means every value,
and the reviewed rule converter skips it; the SHACL is unchanged by it
- three openlabel-v2 snapshots re-recorded: added result paths and the
schema:QuantitativeValue IRI; each still fails on the same constraint
Signed-off-by: jdsika <carlo.van-driesten@vdl.digital>
Check out submodules/service-characteristics in the Standards & Syntax and Generate Artifacts jobs: the envited-x and ositrace LinkML schemas import the Gaia-X LinkML schemas from it, so `just generate` failed there. Signed-off-by: jdsika <carlo.van-driesten@vdl.digital>
…acts scripts/compare_artifacts.py (`just verify-linkml <domain>`) compares a candidate artifact set with the committed one: - header: the ontology node's annotations - vocab: classes, properties, the class and property hierarchies, owl:equivalentClass axioms, and no unexpanded IRI - context: the JSON-LD expansion of every test instance - shacl: verdict and violations per test instance - probe: adversarial instances derived in RDF space from every committed shape, judged by the violations a mutation adds - changed or removed constrained values, a second value where at most one is allowed, and a removed optional property, which must add no violation on either side - --dependents also runs the shacl and probe layers on the instances of every domain that imports the measured one Checked against deliberately broken candidates: a dropped sub-property axiom, a required hasFormat (caught on the leakage-test, service and survey fixtures through --dependents) and a required cid (caught by exactly the five cid absence probes). Signed-off-by: jdsika <carlo.van-driesten@vdl.digital>
…y headers A LinkML schema profile, as LinkML's implements/instantiates guide describes it: the metaclass ontology-header:OntologyHeader declares the header annotations whose values are resources - owl:priorVersion, prov:wasDerivedFrom, dcterms:references and dcterms:publisher - each with range nodeidentifier and implements: [owl:AnnotationProperty], and requires the release and the publisher. A schema that imports the profile and instantiates OntologyHeader gets those annotations as IRIs on declared annotation properties, with no logical axioms about them. Built with --no-mergeimports and --exclude-imports, an importing domain keeps the metaclass out of its own vocabulary: its OWL has owl:imports of the profile and types the ontology OntologyHeader, and the profile's shapes check that header. - linkml/ontology-header: the profile; its own header follows it - artifacts/ontology-header: generated OWL, SHACL and context, https://w3id.org/ascs-ev/envited-x/ontology-header/v1 (the generic ascs-ev/envited-x w3id rules already resolve it) - tests/data/ontology-header: a conforming header, one with a literal publisher and one without its release - docs/registry.json, the catalogs, the catalog and properties overviews and the README table list ontology-header v1 Signed-off-by: jdsika <carlo.van-driesten@vdl.digital>
…and ositrace v7 from LinkML The four ontologies are generated from linkml/<domain>/<domain>.yaml by `just generate`; their hand-written artifacts are replaced. The prior versions stay published under their w3id IRIs and are named by owl:priorVersion. Each construct is modelled by its intent with the LinkML mechanism for it, and the generators are the only thing that runs; what LinkML cannot state is recorded in linkml/GAPS.md. Modelling (linkml/GAPS.md M1-M14): - dependencies are imported (manifest and Gaia-X by envited-x; envited-x and georeference by ositrace) and kept out of the importing artifacts with --no-mergeimports / --exclude-imports; gx classes are extended by is_a and gx slots inherited by name - what a nested value - a link, its file metadata, its dimensions - must satisfy is a range_expression on the slot that holds it; a class range gives sh:class, and a typed nested node is checked by its class's shape - the JSON-LD artifact condition is a class expression on ArtifactLink and on the artifact properties; the self-reference hangs from hasManifestReference, which does not carry it - license, manifest-reference and ENVITED-X vocabulary narrowings sit on the owning properties; ENVITED-X access roles and categories are enums whose values instantiate manifest's open classes - filePath and ositrace:validationReport are UriReference, an xsd:anyURI literal; iri and conformsTo are IRI nodes - headers follow the ontology-header profile: no owl:versionIRI (the schema id is the version's ontology IRI, and OWL 2 makes the version IRI header structure, not an annotation); owl:priorVersion, prov:wasDerivedFrom, dcterms:references and dcterms:publisher are IRIs on annotation properties; contributors are their GitHub accounts - name collisions across the import closure get unique LinkML names, with class_uri/slot_uri keeping the IRIs and alias keeping the JSON-LD terms Data-contract changes: - envited-x: every artifact and referenced link uses the ENVITED-X roles and categories; a referenced artifact stays optional - envited-x: the simulation data / documentation / metadata / media links are required of a simulation asset's manifest (envited-x:SimulationManifest) only, no longer of software, service and code assets - envited-x: a license link no longer needs an IRI; the license is gx:license on the resource description, a list as in Gaia-X - envited-x: hasFormat is optional on a domain specification, and description on the software, service and code bases, as their shapes and Gaia-X state - manifest: Manifest is defined by subClassOf; the equivalentClass axioms made every individual a Manifest; isMiscellaneous is a MiscellaneousCategory - manifest: the artifact properties have the range Link plus their conditions, so membership in ArtifactLink no longer follows from the range - manifest: an empty CID is rejected; width, height and depth are unbounded (no exclusive bound in the metamodel, GAPS G8) - without RDFS inference, an untyped nested value fails its sh:class check; the default validation types it by rdfs:range The importing domains move to the new versions in place, without version bumps of their own: imports, prefixes, fixtures and snapshots. New negative fixtures cover the closed link vocabulary, a referenced artifact, a simulation manifest without media and an empty CID. Each re-recorded snapshot still fails on its root violation; a holding node reports no "does not conform to shape" violation of its own. The registry, docs build and class pages use the ontology IRI as version IRI where none is stated, so the published version IRIs do not change. linkml/openlabel-v2/GAP_ANALYSIS.md names the current flags. docs/registry.json and the catalog and properties overviews list the new versions; the documentation site is built from them. The LinkML page states which domains are generated and how they are built, the contribute guide sends a change to a generated domain to its schema, and the Gaia-X pages name envited-x v4. Signed-off-by: jdsika <carlo.van-driesten@vdl.digital>
jdsika
force-pushed
the
feat/linkml-domain-models
branch
from
October 15, 2026 10:32
38224a9 to
6554dd2
Compare
6 of 9 tasks
jdsika
added a commit
that referenced
this pull request
Oct 21, 2026
* fix(registry): carry the generated timestamp forward so updates are idempotent update_registry() refreshes `generated` only when the registry content changed, but it built the new registry without ever carrying the existing timestamp over. An unchanged registry therefore lost the key entirely: the first `just registry-update` added a timestamp and a second one removed it again, so the command never reached a fixed point and reported a change on every other run. Carry the existing timestamp forward when the content is unchanged, which is what "records when the content last changed" was meant to express. The registry now regenerates byte-for-byte, so the pre-commit hook and CI agree with the committed file. Add three regression tests: the timestamp survives an unchanged regeneration, it is still refreshed when the release tag changes, and two consecutive write_registry() runs leave the file untouched. The first and third fail against the previous behaviour. Signed-off-by: Carlo van Driesten <carlo.van-driesten@bmw.de> * chore(release): bump version to 0.5.2 - Bump the package version to 0.5.2 in pyproject.toml and in the project's own entry in uv.lock (uv lock --check passes). - Regenerate docs/registry.json and config/ontoenv.toml for v0.5.2. The release workflow cannot push the registry to main, and the documentation and the W3ID artifacts of a release are built from the registry at its tag, so the registry has to name the release before the tag is created. - Release scope: v0.5.2 ships ValidationSession, which reuses parsed schemas across validations (#110). Below 1.0.0 the minor version takes the place of the major version, so a backward-compatible addition raises the patch version and keeps v0.6.0 free for the breaking ontology changes still in review (#106, #107). --------- Signed-off-by: Carlo van Driesten <carlo.van-driesten@bmw.de>
This branch has not been deployed
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.
Description
Switches manifest, georeference, envited-x and ositrace to artifacts generated
from LinkML, and bumps them to manifest v6, georeference v6, envited-x v4 and
ositrace v7. The hand-written OWL, SHACL and contexts of these four are replaced;
the prior versions stay published under their w3id IRIs and are named by
owl:priorVersion. The importing domains move to the new versions in place.The models follow what the hand-written files meant: each construct is traced to
its intent and modelled with the LinkML mechanism for it, and the generators are
the only thing that runs — no pre- or post-processing. What LinkML cannot state is
recorded in
linkml/GAPS.md.The generators are the reviewed ENVITED-X pipeline of the ASCS-eV LinkML fork,
pinned to the tag
envited-x/2026.10.14(536d6f194).Commits
Based on v0.5.1.
fix(validators)— per-resource inference types blank-node objects byrdfs:range, as the default mode does.fix(report)— the two hash-dependent parts of pySHACL's generic messages (the order ofsh:invalues; where a shared blank node's rendering is cut off) are rendered in a fixed form, so report snapshots are reproducible. The structured violations take the same normalization.build(linkml)— linkml pinned to the tagenvited-x/2026.10.14; one build script for every LinkML domain; openlabel-v2 rebuilt with it.ci— the jobs that runjust generatecheck out the pinned Gaia-X sources.test(harness)—scripts/compare_artifacts.pymeasures a candidate against the committed artifacts.feat(ontology)— the ontology-header profile (below).feat(ontology)!— the switch-over and version bumps; the registry, catalog and properties overviews list the new versions, and the docs describe the generated domains.Ontology headers: the ontology-header profile
The hand-written ontologies share one header convention: a permanent identifier,
the repository and release they come from, their version and prior version, their
shapes, related resources and their authors, with resources named by IRI. LinkML
gives a schema-level annotation a literal unless a metaclass the schema
instantiatesdeclares its range — the route the LinkML maintainers recommend(linkml/linkml#2892, #3379) and that the fork implements (ASCS-eV/linkml#33).
linkml/ontology-header/is that metaclass as a schema profile, the pattern ofLinkML's implements/instantiates guide and of
linkml-microschema-profile, whichdownstream schemas import:
OntologyHeaderdeclaresowl:priorVersion,prov:wasDerivedFrom,dcterms:referencesanddcterms:publisher: rangenodeidentifier,implements: [owl:AnnotationProperty]; the release and the publisher are required.instantiates: [ontology-header:OntologyHeader].Its header values are IRIs on declared annotation properties (OWL 2 requires the
declaration in the import closure), and its OWL states no logical axioms about them.
--no-mergeimports/--exclude-imports, so the metaclassstays in the profile: a domain's OWL has
owl:importsof the profile and typesthe ontology
ontology-header:OntologyHeader; no domain class, shape or contextterm is added.
literal publisher or a missing release does not (tests and fixtures included).
https://w3id.org/ascs-ev/envited-x/ontology-header/v1resolves through theexisting generic w3id rules.
owl:versionIRIis not stated. Every hand-written ontology used its version IRI asits ontology IRI, and the schema
idis that IRI, so the triple only repeated it;OWL 2 makes the version IRI ontology-header structure, not an annotation, and the
reviewed generator rejects it as one. The registry, docs build and class pages use
the ontology IRI as version IRI, so no published version IRI changes. OWL 2 §3.3,
OBO FP-004 and FOOPS VER1 prefer a permanent ontology IRI with a distinct version
IRI; LinkML has no field for that (GAPS G22, linkml/linkml#768).
Generator features this needs
All in the ASCS-eV LinkML fork, each its own PR, combined on the pipeline branch (ASCS-eV/linkml#14) after review:
any_of/all_of/exactly_one_of/none_of→sh:or/sh:and/sh:xone/sh:notrange_expressionenforced on each value (sh:nodeover an anonymous shape)has_member→sh:qualifiedValueShape+sh:qualifiedMinCount 1instantiateson emitted schema resources (the schema, permissible values) →rdf:typexsd:anyURItypes stay typed literalsinstantiatesmetaclass gives an annotation its RDF term,implements: [owl:AnnotationProperty]its OWL role; reserved OWL vocabulary such asowl:versionIRIis rejected as an annotationdcterms:creator,publisher, …) with declared ranges--diff-stableoutput throughdiffable-rdf--normalize-prefixesgen-shacl --inlined-as-nodewas rejected in review and is not used: what a nestedvalue must satisfy is stated with
range_expressionon the slot that holds it.Modelling
sh:class; the range class's shape reachesa nested value only when the value is typed (in the data, or by
rdfs:rangeunderthe validator's RDFS inference). What a link, its file metadata or its dimensions
must satisfy regardless of type is a
range_expression. The JSON-LD artifactcondition is a class expression on
ArtifactLinkand on the artifact properties;the license, manifest-reference and ENVITED-X vocabulary narrowings sit on the
owning properties.
--no-use-native-uris: its OWLdeclares the schema.org and Commons IRIs (
schema:QuantitativeValue,schema:minValue, …) its SHACL and context already use. Rule 17 ("DrivableAreaEdgeincludes EdgeNone") is
has_member; a bareequals_stringon a multivalued slotmeans every value and the reviewed converter skips it. Rules on a class also
constrain its subclasses' shapes.
slot_uri(skos:note,sh:conformsTo,ositrace:identifier), the IRIs the ontologies declare.Data-contract changes
envited-x v4
envited-x:SimulationManifest) only, no longer of software, service and code assets. An external simulation manifest declares the type to be checked; the fixtures do.gx:licenseon the resource description — a list, as in Gaia-X.hasFormatis optional on a domain specification, anddescriptionon the software, service and code bases, as their shapes, the leaf domains and Gaia-X state. leakage-test, service and survey define no format.hasSoftwareResource,hasServiceOfferingandhasCodeArtifactstay sub-properties ofhasResourceDescription, whose range now covers all four kinds of description.manifest v6
ArtifactLink,LicenseLink,ManifestLink: the JSON-LD artifact condition applies to the artifact properties, so the self-reference (hasManifestReference) is exempt by structure.manifest:Linkplus their conditions, so membership inArtifactLinkno longer follows from the range in OWL.Manifestis defined bysubClassOf; theequivalentClassaxioms (one withminCardinality 0) made every individual a Manifest.manifest:isMiscellaneousis aMiscellaneousCategory(it was typed with an undefined class).width,heightanddepthare unbounded: the metamodel has no exclusive bound (GAPS G8).Nested values (all four) — without RDFS inference, an untyped nested value fails its
sh:classcheck; OMB's default validation infers the type fromrdfs:rangeand accepts it.All four headers —
owl:importsof the ontology-header profile andrdf:type ontology-header:OntologyHeader;owl:priorVersion,prov:wasDerivedFrom(releases/tag/v0.6.0),dcterms:referencesanddcterms:publisherare IRIs; noowl:versionIRI.dcterms:identifier(DCMI range: literal),dcterms:licenseanddcterms:conformsToare literals. Contributors are GitHub account IRIs (GAPS G16).🏷️ Versioning & Compatibility
manifest v5→v6, envited-x v3→v4, georeference v5→v6, ositrace v6→v7; ontology-header v1 is new. A self-description against the old versions keeps validating against them. The importing domains are repointed without bumps of their own, as when hdmap moved to v6.
🏗️ Type of change
🧪 How Has This Been Tested?
hasContent, the wrong CID, MIME type, file size or name, the bad lat/lon and bounding box, the missing topic, the manifest-vocabulary role or category, the literal publisher, the missing release). Without--inlined-as-node'ssh:node, a holding node reports no "does not conform to shape" violation of its own; the ENVITED-X vocabulary violations reportsh:in; manifestfail_04reports thesh:orinstead of the rule's sentence (GAPS G21).PYTHONHASHSEEDvalues.tests/integration/test_linkml_models.pychecks every header against the profile (imports, type, no redeclared metaclass, conformance), the header terms (IRIs on declared annotation properties, noowl:versionIRI), the JSON-LD artifact condition, license categories, MCAP channels, geodetic alternatives and the documented dimension gap with real SHACL validation.Docs and registry
docs/registry.json,docs/ontologies/catalog.mdanddocs/ontologies/properties.mdare committed with the change, as for every ontology change: the documentation site is built from them, and with the previous registrymkdocs build --strictstops on 59 links to the replaced versions. The LinkML page (formerly under Future) states which domains are generated and how they are built; the contribute guide sends a change to a generated domain to its schema; the Gaia-X pages name envited-x v4.Next steps
Before v0.6.0 — these change manifest v6 / envited-x v4, which are not released yet:
width,heightanddepthgreater than 0 again:minimum_value: 0plus a classnone_ofthat excludesmaximum_value: 0. A probe accepts 1.5 and 1e-9 and rejects 0, -1 and NaN in SHACL; the OWL stays weaker (G19).isPublic,isLicense,isManifestandisMiscellaneousindividuals.xsd:anyURIliterals.One fork round and one re-pin, for generator bugs visible in these artifacts:
nodeidentifierto@id.sh:message.In this repository, not necessarily in this PR:
--per-resourcevalidation loads fixtures and the ontology's named individuals; needed before the comparison harness measures the next domain.cd-release— its push of the registry to main is declined by the branch rules.At release
releases/tag/v0.6.0asprov:wasDerivedFrom.docs/ecosystem/release-process.md); until then the registry names v0.5.1.https://w3id.org/ascs-ev/envited-x/ontology-header/v1resolves through the generic w3id rules.Known gaps after merge
Recorded in
linkml/GAPS.md; none of them blocks the switch-over:xsd:anyURIliterals).license/conforms_toare literals although DCMI recommends URIs (gen-owl emits rdfs:isDefinedBy and dcterms:license as string literals instead of URIs linkml/linkml#3546); non-linguistic annotations carry@en.skos:inScheme).shex:nonLiteralinstead of@id.minValue≤maxValueis not enforced.sh:message.--per-resourcevalidation merges neither fixtures nor ontology individuals.isPublic,isLicense,isManifest,isMiscellaneous.owl:versionIRI; the registry, docs build and class pages use the ontology IRI, andregistry_updaterlogs a warning for each.✅ Checklist