Skip to content

feat(contracts): SKOS-typed lifecycle properties; remove dprod:select#199

Merged
jgeluk merged 2 commits into
EKGF:developfrom
tonyseale:add-dprod-contracts
Jun 16, 2026
Merged

feat(contracts): SKOS-typed lifecycle properties; remove dprod:select#199
jgeluk merged 2 commits into
EKGF:developfrom
tonyseale:add-dprod-contracts

Conversation

@tonyseale

@tonyseale tonyseale commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Summary

Follows on from #156 (merged 2026-05-28). Resolves two open changes-plan.md items:

  • §5.5 — dprod:select removed. Every documented use was a verbatim restatement of an existing dprod:path sequence; the few SPARQL-only capabilities (filters, joins, aggregates, inverse/alternative traversal) are unexercised by any policy in dprod-contracts/examples/; and the previous specification was underdefined when measured against SHACL's sh:SPARQLConstraint machinery (variable-name inconsistency ?v vs ?value, no prefix mechanism, contradictory composition with dprod:path, hand-waved multi-row and graph-context semantics). Future-revisit trigger and the SHACL-rigour template are recorded in changes-plan.md §5.5.

  • §1.3 — dprod:State class and dprod:state union-domain property removed. Replaced with three domain-specific object properties:

    • dprod:offerLifeCycleStatus on dprod:DataOffer
    • dprod:contractLifeCycleStatus on dprod:DataContract
    • dprod:dutyState on odrl:Duty

    Range on all three is the open class skos:Concept. This preserves the group's open-world intent better than the originally-discussed subclass split, and aligns with how DPROD already uses skos:Concept for operands and actions. The four canonical state individuals (dprod:Pending, dprod:Active, dprod:Fulfilled, dprod:Violated) are retyped from dprod:State to skos:Concept and grouped into a new example skos:ConceptScheme, dprod:DataContractLifeCycleStatus — shipped as one ready-made vocabulary that implementations are free to use, extend via skos:inScheme, or replace entirely.

    Property descriptions lead with the distinguishing question each property answers — publication lifecycle (assigned by publisher) vs administrative lifecycle (assigned by contract management) vs evaluation result (computed by an evaluator) — surfacing the declared-vs-computed contrast that was previously hidden.

Side-effects also landed in this PR

  • SHACL shape for dprod:path value structure (changes-plan §2.3, also closed). LeftOperandShape now constrains dprod:path to a single IRI or an rdf:List of IRIs via sh:or, with a non-recursive dprod-shapes:RdfListOfIris helper that walks the list using ( [ sh:zeroOrMorePath rdf:rest ] rdf:first ) — avoids pyshacl's ShapeRecursionWarning (which fires on the naïve recursive variant at depth 14).
  • State-shape split. dprod-shapes:StatePropertyGroup (with closed sh:in over the four states) replaced with OfferLifeCycleStatusPropertyGroup, ContractLifeCycleStatusPropertyGroup, DutyStatePropertyGroup — each constraining sh:maxCount 1 and sh:nodeKind sh:IRI (no enumeration; the rdfs:range skos:Concept in the ontology remains the authoritative range).
  • Examples rewritten by enclosing-entity type. 9 dprod:state assertions in baseline.ttl became dprod:offerLifeCycleStatus, 6 became dprod:dutyState; in data-contract.ttl 1 became dprod:offerLifeCycleStatus and 3 became dprod:dutyState; single offer-status replacements in odcs.ttl and contracts-guide.md.
  • Doc sweep. README.md, docs/specification.md (§3.1 Example Lifecycle Concept Scheme, §3.2/§3.3 Recommended properties, §4.1 grouped property table, property-incidence matrix), docs/overview.md, docs/term-mapping.md, docs/contracts-guide.md, examples/odcs.md, docs/policy-writers-guide.md all updated. Detailed DONE entries appended to changes-plan.md §§1.3, 2.3, 5.5.

Diff: 16 files, +333 / −184 (14 contracts files scoped to dprod-contracts/, plus the validation tooling noted below).

Added by maintainer (jgeluk)

  • Rebased onto current develop to resolve the merge conflicts (the branch had diverged before Add dprod-contracts folder #156's squash-merge landed; the rebased tree is byte-identical to the prior fork tip — no content changed).
  • dprod-contracts/validate.py + pyshacl dep added: parses every contracts TTL and SHACL-validates each example against the shapes (ontology as ont_graph, RDFS inference on); exits non-zero on any parse error or violation. Confirms the new SKOS lifecycle shapes/examples validate cleanly, and is wired for CI in CI: run dprod-contracts SHACL validation (validate.py) on push/PR #200.

Test plan

  • dprod-contracts.ttl and dprod-contracts-shapes.ttl parse cleanly (rdflib, 569-triple combined graph).
  • All four example policies — baseline.ttl, data-contract.ttl, data-use-policy.ttl, odcs.ttl — validate under the updated shapes with conforms=True and zero ShapeRecursionWarning.
  • Negative path tests: a LeftOperand whose dprod:path is a literal triggers a violation; a sequence containing a literal triggers a violation.
  • Positive path tests: bare IRI and rdf:List of IRIs both accepted.
  • Sweep confirms no remaining functional references to dprod:select, dprod:state, or dprod:State outside changes-plan.md historical context entries.
  • Spec generator build (CI) — to confirm the spec still generates without warnings now that dprod:select and dprod:State are gone from the property-incidence matrix.

🤖 Generated with Claude Code

@vercel

vercel Bot commented Jun 16, 2026

Copy link
Copy Markdown

@tonyseale is attempting to deploy a commit to the EKGF Team on Vercel.

A member of the Team first needs to authorize it.

@jgeluk jgeluk changed the title feat(contracts): SKOS-typed lifecycle properties; remove dprod:select test(contracts): add SHACL validation script for dprod-contracts Jun 16, 2026
@jgeluk jgeluk changed the title test(contracts): add SHACL validation script for dprod-contracts feat(contracts): SKOS-typed lifecycle properties; remove dprod:select Jun 16, 2026
tonyseale and others added 2 commits June 16, 2026 16:32
…oncept-typed lifecycle properties

Resolves changes-plan items 5.5 and 1.3.

5.5 — dprod:select removed. Every documented use was a verbatim restatement of an
existing dprod:path sequence; the few SPARQL-only capabilities (filters, joins,
aggregates, inverse/alternative traversal) are unexercised by any policy in
dprod-contracts/examples/; and the spec was underdefined when measured against
SHACL's sh:SPARQLConstraint machinery (variable-name inconsistency, no prefix
mechanism, contradictory dprod:path composition, hand-waved multi-row and
graph-context semantics). Future-revisit trigger: a real policy example needs
filters/joins/aggregates/inverse/alternatives — at that point reinstate either
a properly-specified dprod:select modelled on sh:SPARQLConstraint, or extend
dprod:path with sh:inversePath/sh:alternativePath first.

1.3 — dprod:State class and dprod:state union-domain property deleted. Replaced
with three domain-specific object properties: dprod:offerLifeCycleStatus
(dprod:DataOffer), dprod:contractLifeCycleStatus (dprod:DataContract), and
dprod:dutyState (odrl:Duty). Range is the open class skos:Concept rather than a
closed DPROD enumeration; this preserves the group's open-world intent better
than the originally-discussed subclass split, and aligns with how DPROD already
uses skos:Concept for operands and actions. The four canonical state instances
(dprod:Pending, dprod:Active, dprod:Fulfilled, dprod:Violated) are retyped as
skos:Concept and grouped into a new skos:ConceptScheme
dprod:DataContractLifeCycleStatus, shipped as an example vocabulary —
implementations are free to use it, extend it via skos:inScheme, or substitute
a different scheme. The vocabulary lives in its own comment-block section
between Classes and Properties. Property descriptions lead with the
distinguishing question each property answers — publication lifecycle (assigned
by publisher) vs administrative lifecycle (assigned by contract management) vs
evaluation result (computed by an evaluator) — surfacing the declared-vs-computed
contrast that was previously hidden.

Shape side-effects: dprod-shapes:StatePropertyGroup (with closed sh:in over the
four states) split into dprod-shapes:OfferLifeCycleStatusPropertyGroup,
ContractLifeCycleStatusPropertyGroup, and DutyStatePropertyGroup — each
constraining sh:maxCount 1 and sh:nodeKind sh:IRI with no enumeration. SHACL
shape for dprod:path value structure (changes-plan §2.3) also closed: the
sh:path dprod:path property in LeftOperandShape now carries sh:or
( [ sh:nodeKind sh:IRI ] [ sh:node dprod-shapes:RdfListOfIris ] ), where the
non-recursive RdfListOfIris helper walks the list with
( [ sh:zeroOrMorePath rdf:rest ] rdf:first ) to avoid pyshacl's recursion warning.

Examples rewritten by enclosing-entity type: 9 dprod:state assertions in
baseline.ttl became dprod:offerLifeCycleStatus, 6 became dprod:dutyState; in
data-contract.ttl 1 became dprod:offerLifeCycleStatus and 3 became dprod:dutyState;
single offer-status replacements in odcs.ttl and contracts-guide.md. All four
example files (baseline, data-contract, data-use-policy, odcs) validate under
the updated shapes with zero pyshacl recursion warnings.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds dprod-contracts/validate.py: parses every contracts TTL and
validates each example against dprod-contracts-shapes.ttl (ontology
supplied as ont_graph, RDFS inference on). Exits non-zero on any parse
error or SHACL violation. Adds pyshacl to requirements.txt.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants