feat(openlabel-v2): add the structural LinkML schema for the ASAM JSON format - #81
feat(openlabel-v2): add the structural LinkML schema for the ASAM JSON format#81jdsika wants to merge 1 commit into
Conversation
bb363db to
7ddb7f7
Compare
Addresses all findings from the PR #81 review. Blocking (CI red): - Reflow `extract_tag_value` signature in convert_openlabel_v1_to_v2.py so `ruff format` no longer rewrites the file (line exceeded the 88-char limit, which failed the Standards & Syntax "unexpected modified file" gate). Medium: - Add `encoding="utf-8"` to all file reads in sync_tag_type_enum.py and convert_openlabel_v1_to_v2.py (and the schema-reading test). The semantic model contains em-dashes; bare open() crashed on Windows (cp1252) — breaking the sync-tag-type-enum pre-commit hook and the converter for Windows users. - Disclose the stricter `tag.ontology_uid` requirement in SCHEMA_MODELING.md (added equivalence-table row + note) and back it with a LINKML_STRICTER test. Low / nits: - Converter: accumulate repeated class+slot values into a list instead of silently overwriting (last-wins data loss); add coverage. - Converter: collapse the identical if/else and four identical class-building branches. - Converter: make `--pretty` a real toggle via argparse.BooleanOptionalAction (`--no-pretty`); previously it could never be False. - Add a SHACL-conformance test that validates converter output against the openlabel-v2 shapes (the converter's stated purpose), not just @context/@type. - sync_tag_type_enum.py: rewrite the TagTypeEnum end-detection to be position-independent (no longer relies on TagTypeEnum being the last enum). - Docs: fix `gen_tag_type_enum.py` -> `sync_tag_type_enum.py` reference and document the structural-schema `$id` namespace choice in SCHEMA_MODELING.md. No generated artifacts change; TagTypeEnum sync remains idempotent. Signed-off-by: jdsika <carlo.van-driesten@vdl.digital>
…format The semantic model describes the RDF tag vocabulary; it cannot say what a conforming OpenLABEL *file* looks like before that file is read as RDF. A second LinkML schema, openlabel-v2-schema.yaml, models the ASAM JSON document format and generates artifacts/openlabel-v2/openlabel-v2.schema.json alongside the existing OWL, SHACL and JSON-LD context. Both schemas stay generated: neither artifact is hand-edited. `just generate` now builds a JSON Schema for any domain that carries a <domain>-schema.yaml, with per-domain generator flags in jsonschema.genopts so the recipe stays domain-neutral. gen-owl gains --no-use-native-uris so class URIs follow the declared namespace rather than LinkML's native form. sync_tag_type_enum.py keeps the structural schema's TagTypeEnum in step with the semantic model, wired as a pre-commit hook that runs *before* generation - the reverse order would generate artifacts from a stale enum. convert_openlabel_v1_to_v2.py converts ASAM v1 files into the v2 instance shape. Rebased onto main, which moved the package from src/tools to omb and replaced the Makefile with just; the test that shells out to the validation suite now names omb.validators. The submodules/linkml gitlink is not reinstated - main removed it, and the LinkML fork is already carried as a dependency in pyproject. Signed-off-by: jdsika <carlo.van-driesten@vdl.digital>
2ae23c8 to
426e820
Compare
What happened to
|
Description
Adds the structural LinkML schema for the ASAM OpenLABEL JSON file format, alongside the existing semantic model, and generates a JSON Schema from it.
The semantic model (
openlabel-v2.yaml) describes the RDF tag vocabulary. It cannot say what a conforming OpenLABEL file looks like before that file is read as RDF — a malformed document fails as unparseable RDF rather than as a schema violation, with no useful message. The structural model (openlabel-v2-schema.yaml) describes the JSON document format and closes that gap.Both stay generated. Neither artifact is hand-edited.
Diff to
mainRebased onto
e74f6ea— one commit, nothing behindmain, no merge commit.34 files: 9 added, 25 modified (+14,338 / −3,905). Of the 25 modified, 17 are
tests/data/openlabel-v2/**fixtures; the other 8 are:.pre-commit-config.yaml·justfile·linkml/openlabel-v2/openlabel-v2.yaml·tests/catalog-v001.xml· and the four regenerated artifacts(
PROPERTIES.md,.context.jsonld,.owl.ttl,.shacl.ttl).The bulk of the insertions are generated or fixture content:
openlabel-v2.schema.json,the regenerated SHACL, and
tests/unit/test_openlabel_schema.py. Reviewable surface isthe two LinkML sources, the two scripts, the
justfilerecipe and the pre-commit ordering.pyproject.tomlis not touched —main's version is used as-is.What lands
linkml/openlabel-v2/openlabel-v2-schema.yamllinkml/openlabel-v2/jsonschema.genoptsartifacts/openlabel-v2/openlabel-v2.schema.jsonscripts/sync_tag_type_enum.pyTagTypeEnumin step with the semantic modelscripts/convert_openlabel_v1_to_v2.pylinkml/openlabel-v2/SCHEMA_MODELING.mdjust generatenow builds a JSON Schema for any domain carrying a<domain>-schema.yaml, with flags read fromjsonschema.genoptsso the recipe stays domain-neutral.gen-owlgains--no-use-native-urisso class URIs follow the declared namespace.sync-tag-type-enumis wired as a pre-commit hook that runs beforegenerate-linkml— the reverse order would generate artifacts from a stale enum.Consolidated into v2 rather than a parallel v3
A
feat/openlabel-v3-schemabranch proposed a separateopenlabel-v3namespace for validating ASAM's native JSON shape. The need it identified is real, but the mechanism duplicated too much:openlabel-v3.owl.ttlwas the v2 ontology copied verbatim — identical named class sets (205 classes); every difference was blank-node relabelling — plus three boolean flags. Two sources of truth for one vocabulary, with nothing keeping them in step.owl:Ontologyheaders, including v2's at version 2.0.0, while the catalog mapped the v3 IRI to it. Loading v2 and v3 together yielded the same classes from two files.OpenLabelFile,OpenLabel,OntologyEntryandResourceUid, all of which v2's structural schema already defines.So the structural work belongs in v2, which is where it is here. No second namespace, no duplicated ontology.
Rebased onto current main
The branch predated two refactors and would not have merged:
src/tools/→omb/(feat: make OMB an installable, publishable package + adopt just (W1 + W3b) #86): the test that shells out to the validation suite now namesomb.validators.Makefile→justfile: the JSON-Schema generation and thegen-owlflag are ported into thegeneraterecipe.submodules/linkmlwas removed (chore: remove unused submodules/linkml gitlink #89) and is not reinstated; the LinkML fork is already carried as a dependency and pinned byuv.lock.Artifacts were regenerated under the locked toolchain (
uv.lockpins linkml6aa7702c) rather than carried over from the old branch, which had been generated with a different generator commit. That is why the OWL and SHACL differ from the previous branch state: same triples, different blank-node ordering from a different generator version. They now reproduce from source.Removed from the previous branch state
These were on the previous branch state and are not carried over. They never existed
on
main, so they do not appear as deletions in the diff above — the point is simply thatthis PR does not reintroduce them:
REFINEMENT_PROOF.md— an auto-generated verdict report with gap tablesscripts/schema_refinement_prover.py(1,040 lines) andtests/unit/test_schema_refinement.pylinkml/openlabel-v2/proof_seeds/,proof_spec.yamlhypothesis/hypothesis-jsonschemadev dependencies and theslowpytest marker that existed only for the proverSCHEMA_MODELING.mdis kept — it documents how the two schemas divide responsibility, which is design documentation rather than analysis.🧪 How Has This Been Tested?
just generate— artifacts reproduce byte-identically from the LinkML source under the locked toolchainpytest tests/unit/test_openlabel_schema.py— 48 passed, including the functional-equivalence checks against ASAM's normativeopenlabel_json_schema-v1.0.0.jsonfrom the standards submoduleNot in this PR
objects/actions/events/contexts/relationsuid-keyed containers, and the constraint that each entry'stypestring resolves to the right vocabulary category, are the remaining half of the v3 branch's intent. They belong inopenlabel-v2-schema.yamland its generated SHACL; tracked separately so this PR stays reviewable.Dockerfile/compose.yaml/.dockerignorefrom the v3 branch are unrelated to schema work and reference the pre-refactorsrc/path. Separate PR.