Skip to content

v2 tag model does not preserve v1 class subsumption: category-level tags validate but cannot round-trip to JSON-LD/SHACL #82

Description

@jdsika

Summary

The v2 LinkML model (linkml/openlabel-v2/openlabel-v2.yaml) re-models the ASAM
OpenLABEL v1.0.0 scenario-tagging hierarchy as a hybrid of classes + enum-ranged
slots + enum values
. This does not preserve the uniform rdfs:subClassOf
taxonomy that v1 uses. As a result, 24 of 256 tag.type values (the ODD/Behaviour
category classes and the structural roots) validate against the generated JSON
Schema but cannot be represented as v2 JSON-LD instance data — the converter
emits _unmapped_tags and SHACL validation fails (return code 210) — and the v1
leaf→category inference is lost.

This is a pre-existing v2 design characteristic that PR #81 surfaced: PR #81
added the category classes to the vocabulary so that v1 files using them validate;
that change is correct for validating v1 files, but it exposed that v2 has no
instance-data representation for those tags.

Background: v1 vs v2 representation

v1 (authoritative ASAM ontology, submodules/.../ontologies/openlabel_ontology_scenario_tags.ttl) — every tag is an rdfs:Class in a single subsumption chain:

Odd → OddScenery → SceneryJunction → JunctionIntersection → IntersectionCrossroad
                                                          → IntersectionTJunction …

You can tag at any level, and rdfs inference rolls a leaf up to all of its
ancestors. Spec §8.2 ("Scenario tagging"): tag the most specific applicable tag;
the more general tags are inferred and need not be stored.

v2 (linkml/openlabel-v2/openlabel-v2.yaml) fragments the same hierarchy into
three different mechanisms:

v1 concept v1 v2
SceneryJunction (category) rdfs:Class owl:Class (subClassOf OddScenery)
JunctionIntersection (mid-level) rdfs:Class slot (range: JunctionIntersectionEnum)
IntersectionCrossroad (leaf) rdfs:Class enum value

The subsumption chain is severed at the slot/enum boundary: enum values are
not rdfs:subClassOf the category classes.

The gap (evidence)

  1. No category-level assertion. There is no slot to record "scenario has a
    junction (type unspecified)". scripts/convert_openlabel_v1_to_v2.py routes
    such tags to a _unmapped_tags property, which violates the closed v2 SHACL
    shape:
    ❌ SHACL validation failed … Node [ openlabel_v2:_unmapped_tags … ]
    ❌ Check Data Conformance phase failed (code 210).
    
  2. Broken category inference. Tagging the leaf IntersectionCrossroad does
    not infer SceneryJunction, because the enum value is not a subclass of
    the category class. v1's roll-up (§8.2) is lost.

OWL evidence (artifacts/openlabel-v2/openlabel-v2.owl.ttl):

  • openlabel_v2:SceneryJunction a owl:Class ; rdfs:subClassOf openlabel_v2:OddScenery — a floating category; none of its v1 children link back to it.
  • openlabel_v2:IntersectionCrossroad a owl:Class ; owl:unionOf ( … ) ; linkml:permissible_values … — modelled as an enumeration, not subClassOf JunctionIntersection.

Impact

  • 24 / 256 vocabulary tag.type values are affected — every class-type tag:
    • Structural roots: Tag, AdminTag, Odd, Behaviour, RoadUser, Scenario
    • ODD/Behaviour categories: OddScenery, OddEnvironment, OddDynamicElements, SceneryJunction, SceneryDrivableArea, EnvironmentWeather, EnvironmentIllumination, EnvironmentConnectivity, DynamicElementsTraffic, DynamicElementsSubjectVehicle, BehaviourMotion, DrivableAreaGeometry, DrivableAreaLaneSpecification, DrivableAreaSigns, DrivableAreaSurface, GeometryHorizontal, GeometryLongitudinal, IlluminationDay
  • These validate against the generated JSON Schema (correct for validating v1
    files) but cannot round-trip to v2 JSON-LD / SHACL.
  • The other 232 leaf/enum/admin tags round-trip correctly (schema → convert →
    SHACL all pass).
  • Search use case (ontology-based-nl-search): "find scenarios with any junction"
    cannot use a single SceneryJunction query point; callers must enumerate and OR
    all junction leaf-slots. v1 resolves this via subClassOf inference.

Possible solutions

Option A — v1-faithful class taxonomy (highest fidelity, largest change)

Model every tag as an is_a class with subClassOf, mirroring v1. Tagging becomes
uniform (any level) and rdfs inference rolls up natively.

  • Pros: exact v1 parity; clean inference; category assertion works; single mechanism; best for ASAM WG upstreaming.
  • Cons: large remodel of openlabel-v2.yaml; loses closed-enum JSON-LD ergonomics; significant OWL/SHACL/context regeneration; converter rewrite.

Option B — bridge enums to categories (incremental)

Keep enum-ranged slots for leaves, but (1) add rdfs:subClassOf/skos:broader from
each enum value's meaning IRI to its category class, and (2) add a SHACL-accepted
representation for category presence (e.g. a hasTag / category-membership construct);
teach the converter to emit it.

  • Pros: preserves enum ergonomics; restores inference; smaller than A.
  • Cons: dual representation (enum value + subclass link) is redundant; SHACL must be opened for category membership; converter changes; two mechanisms coexist.

Option C — leaf-only by design (smallest change, documents the boundary)

Accept v2 as a leaf-tag model: category-level tags are not assertable v2 data;
category search is done by OR-ing leaf slots. Scope category classes to
schema-validation-only (valid tag.type for v1 files, not v2 instance data).
Make the converter skip category tags with a warning instead of emitting an
invalid _unmapped_tags, and document the boundary in SCHEMA_MODELING.md.

  • Pros: minimal change; converter output always conforms; honest scoping.
  • Cons: v2 cannot express the "type-unknown" tags that v1 can; not full v1 parity.

Recommendation

  • Short term: Option C — stop emitting SHACL-invalid _unmapped_tags; document
    the v1↔v2 boundary. This makes the pipeline self-consistent immediately.
  • Medium term: evaluate Option B if category-level search/assertion is required
    for the NL-search use case.
  • Long term: reserve Option A for a future major v2 revision if exact v1 parity
    becomes a goal (e.g. upstreaming the model to the ASAM working group).

Acceptance criteria

  • SCHEMA_MODELING.md documents the v1↔v2 hierarchy difference and the chosen boundary.
  • The converter no longer produces SHACL-invalid output for category tags (warns/skips, or emits a conforming representation).
  • A round-trip test asserts the chosen behavior for a category tag (e.g. SceneryJunction).
  • (Options A/B) leaf→category inference verified by a test (tag a leaf, infer the category).

References

  • PR feat(openlabel): add structural LinkML schema for ASAM v1 JSON format #81 — added the category vocabulary that surfaced this gap.
  • submodules/asam-openx-standards/standards/asam-openlabel/08-scenario-tagging.md §8.2 — tag hierarchy & inference semantics.
  • submodules/asam-openx-standards/standards/asam-openlabel/ontologies/openlabel_ontology_scenario_tags.ttl — v1 class taxonomy.
  • linkml/openlabel-v2/openlabel-v2.yaml, artifacts/openlabel-v2/openlabel-v2.owl.ttl, scripts/convert_openlabel_v1_to_v2.py.

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentationenhancementNew feature or request

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions