diff --git a/src/lightcone/engine/crate.py b/src/lightcone/engine/crate.py index cbed1b7..473b490 100644 --- a/src/lightcone/engine/crate.py +++ b/src/lightcone/engine/crate.py @@ -48,6 +48,13 @@ #: undefined and silently dropped on JSON-LD expansion — typed but inert. _WORKFLOW_RUN_CONTEXT = "https://w3id.org/ro/terms/workflow-run" +#: The RO-Crate version written, pinned rather than left to rocrate's +#: default: the Workflow RO-Crate and Run Crate profiles are written +#: against 1.1's vocabulary, and the 1.3 context maps +#: ``ComputationalWorkflow`` to a term their shapes do not recognise, so +#: following the default turns the workflow into an untyped file. +_RO_CRATE_VERSION = "1.1" + #: What the root conforms to, each also declared as a CreativeWork in the #: graph — consumers resolve the reference inside the crate, not on the #: network. @@ -133,7 +140,7 @@ def __init__( self.license = license self.writer = writer self.keys = dict(keys) - self.crate = ROCrate() + self.crate = ROCrate(version=_RO_CRATE_VERSION) self.crate.metadata.extra_contexts.append(_WORKFLOW_RUN_CONTEXT) #: Every materialized task, sorted: the one iteration order. self.made: list[tuple[Key, assets.Manifest]] = sorted( @@ -190,14 +197,6 @@ def document(self) -> str: # ----- the workflow and its structure ----- def _workflow(self) -> Any: - # Before `add_workflow` rewrites the descriptor's conformsTo: 1.1 - # is what RO-Crate validators key on, 1.2 is the context actually - # emitted — the crate is structurally both, and saying only the - # newer one reads as conforming to neither. - self.crate.metadata["conformsTo"] = [ - {"@id": "https://w3id.org/ro/crate/1.1"}, - {"@id": "https://w3id.org/ro/crate/1.2"}, - ] lang = ComputerLanguage( self.crate, "#astra", diff --git a/tests/test_crate.py b/tests/test_crate.py index eef3b1c..4878b3b 100644 --- a/tests/test_crate.py +++ b/tests/test_crate.py @@ -185,6 +185,22 @@ def test_the_context_carries_the_workflow_run_vocabulary(project: Path) -> None: assert "https://w3id.org/ro/terms/workflow-run" in document["@context"] +def test_the_crate_version_is_pinned_not_rocrates_default(project: Path) -> None: + """rocrate 0.16 moved its default to 1.3, whose context maps + `ComputationalWorkflow` to a term the workflow profiles do not + recognise — so the version is ours, and both halves must agree.""" + _made(project, "baseline", "first", git_sha="aaa111") + document = _render(project, _graph(project)) + entities = _entities(document) + + assert "https://w3id.org/ro/crate/1.1/context" in document["@context"] + claimed = {ref["@id"] for ref in entities["ro-crate-metadata.json"]["conformsTo"]} + assert claimed == { + "https://w3id.org/ro/crate/1.1", + "https://w3id.org/workflowhub/workflow-ro-crate/1.0", + } + + def test_the_root_conforms_to_every_claimed_profile_and_declares_each( project: Path, ) -> None: