Conditions
incubatingStatus of this Document
This report was published by the User Journal Graph Community Group . It is not a W3C Standard nor is it on the W3C Standards Track. Please note that under the W3C Community Contributor License Agreement (CLA) there is a limited opt-out and other conditions apply. Learn more about W3C Community and Business Groups .
1. Overview
This optional module defines a graph-native vocabulary for attaching domain-level conditions to UJG Graph transitions.
A condition describes when a transition is eligible to be taken. A condition does not create a new
graph edge, does not act as a state, and does not point directly to a target state. All movement
between journey states remains represented by Transition nodes from the Graph module.
This module also defines ConditionSet, an addressable grouping node for conditional branches. A
ConditionSet groups two or more guarded transitions that share the same source state. In this
first version, a ConditionSet represents a branching point where one path is intended to be taken.
This module is optional. It extends Graph traversal semantics for consumers that understand conditions, but it does not replace Graph's topology model.
Non-goals:
This module does not define a condition expression language.
This module does not define domain state models such as Git branch state, payment provider state, inventory state, authentication state, or feature-flag state.
This module does not define runtime evaluation APIs.
This module does not create hidden state-to-state edges outside Graph
Transitionnodes.This module does not model user-choice branches that can already be represented by ordinary labeled transitions.
2. Normative Artifacts
This module is published through the following artifacts:
condition.ttl: ontology, published athttps://ujg.specs.openuji.org/ed/ns/conditioncondition.context.jsonld: JSON-LD term mappings, published athttps://ujg.specs.openuji.org/ed/ns/condition.context.jsonldcondition.shape.ttl: SHACL validation rules, published athttps://ujg.specs.openuji.org/ed/ns/condition.shape
Examples in this page compose the shared baseline context:
[
"https://ujg.specs.openuji.org/ed/ns/context.jsonld",
"https://ujg.specs.openuji.org/ed/ns/condition.context.jsonld"
] [
"https://ujg.specs.openuji.org/ed/ns/context.jsonld",
"https://ujg.specs.openuji.org/ed/ns/condition.context.jsonld"
] 3. Terminology
Condition: An addressable predicate-like node that describes when a transition is eligible.
Guarded transition: A Graph
Transitionthat has aconditionRef.ConditionSet: An addressable grouping of guarded transitions that form one conditional branch point.
Condition branch: A group of conditional transitions from the same source state where one path is intended to be taken.
4. Attachment Model
The module introduces real JSON-LD terms and RDF edges for conditional branching:
condition:conditionReflinks a GraphTransitionto aCondition.condition:conditionTransitionRefslinks aConditionSetto the guarded transitions that form one branch point.
A Condition MUST NOT reference a target state directly.
A ConditionSet MUST NOT reference a source state directly. Its effective source state is
derived from the common from value of all referenced transitions.
A ConditionSet MUST reference transitions that all share the same from state.
A transition referenced by a ConditionSet MUST have exactly one conditionRef.
A consumer that implements this module MUST treat transitions in a ConditionSet as conditional
branch alternatives. In this first version of the module, a ConditionSet means that one referenced
transition is intended to be taken.
A consumer that does not implement this module MAY ignore condition semantics, but it SHOULD preserve recognized JSON-LD data during read-transform-write when possible.
Opaque runtime bindings, expression syntax, platform-specific evaluators, and domain-state
references SHOULD remain in Core extensions unless a future optional module defines them as
interoperable vocabulary.
5. Ontology
The normative Conditions ontology is defined below and is published at
https://ujg.specs.openuji.org/ed/ns/condition. It is the authoritative structural definition for
Condition, ConditionSet, and the properties declared by this module.
@prefix ujg: <https://ujg.specs.openuji.org/ed/ns/core#> .
@prefix ujggraph: <https://ujg.specs.openuji.org/ed/ns/graph#> .
@prefix ujgcond: <https://ujg.specs.openuji.org/ed/ns/condition#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix dct: <http://purl.org/dc/terms/> .
<https://ujg.specs.openuji.org/ed/ns/condition#> a owl:Ontology ;
rdfs:label "UJG Conditions Editor's Draft Vocabulary"@en ;
dct:description "UJG Conditions ontology declaration" .
### Classes
ujgcond:Condition a owl:Class ;
rdfs:subClassOf ujg:Node .
ujgcond:ConditionSet a owl:Class ;
rdfs:subClassOf ujg:Node .
### Properties
ujgcond:conditionRef a owl:ObjectProperty ;
rdfs:domain ujggraph:Transition ;
rdfs:range ujgcond:Condition .
ujgcond:conditionTransitionRefs a owl:ObjectProperty ;
rdfs:domain ujgcond:ConditionSet ;
rdfs:range ujggraph:Transition . @prefix ujg: <https://ujg.specs.openuji.org/ed/ns/core#> .
@prefix ujggraph: <https://ujg.specs.openuji.org/ed/ns/graph#> .
@prefix ujgcond: <https://ujg.specs.openuji.org/ed/ns/condition#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix dct: <http://purl.org/dc/terms/> .
<https://ujg.specs.openuji.org/ed/ns/condition#> a owl:Ontology ;
rdfs:label "UJG Conditions Editor's Draft Vocabulary"@en ;
dct:description "UJG Conditions ontology declaration" .
### Classes
ujgcond:Condition a owl:Class ;
rdfs:subClassOf ujg:Node .
ujgcond:ConditionSet a owl:Class ;
rdfs:subClassOf ujg:Node .
### Properties
ujgcond:conditionRef a owl:ObjectProperty ;
rdfs:domain ujggraph:Transition ;
rdfs:range ujgcond:Condition .
ujgcond:conditionTransitionRefs a owl:ObjectProperty ;
rdfs:domain ujgcond:ConditionSet ;
rdfs:range ujggraph:Transition . 6. JSON-LD Context
The normative Conditions JSON-LD context is defined below and is published at
https://ujg.specs.openuji.org/ed/ns/condition.context.jsonld. It provides the compact JSON-LD term
mappings and coercions for Conditions-specific properties and classes.
{
"@context": {
"@version": 1.1,
"ujgcond": "https://ujg.specs.openuji.org/ed/ns/condition#",
"Condition": "ujgcond:Condition",
"ConditionSet": "ujgcond:ConditionSet",
"conditionRef": {
"@id": "ujgcond:conditionRef",
"@type": "@id"
},
"conditionTransitionRefs": {
"@id": "ujgcond:conditionTransitionRefs",
"@type": "@id",
"@container": "@set"
}
}
} {
"@context": {
"@version": 1.1,
"ujgcond": "https://ujg.specs.openuji.org/ed/ns/condition#",
"Condition": "ujgcond:Condition",
"ConditionSet": "ujgcond:ConditionSet",
"conditionRef": {
"@id": "ujgcond:conditionRef",
"@type": "@id"
},
"conditionTransitionRefs": {
"@id": "ujgcond:conditionTransitionRefs",
"@type": "@id",
"@container": "@set"
}
}
} 7. Validation
The normative Conditions SHACL shape is defined below and is published at
https://ujg.specs.openuji.org/ed/ns/condition.shape. It is the authoritative validation artifact
for Conditions structural constraints.
@prefix ujggraph: <https://ujg.specs.openuji.org/ed/ns/graph#> .
@prefix ujgcond: <https://ujg.specs.openuji.org/ed/ns/condition#> .
@prefix ujgcondshape: <https://ujg.specs.openuji.org/ed/ns/condition.shape#> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
ujgcondshape:ConditionShape a sh:NodeShape ;
sh:targetClass ujgcond:Condition ;
sh:nodeKind sh:IRI .
ujgcondshape:GuardedTransitionShape a sh:NodeShape ;
sh:targetClass ujggraph:Transition ;
sh:nodeKind sh:IRI ;
sh:property [
sh:path ujgcond:conditionRef ;
sh:class ujgcond:Condition ;
sh:nodeKind sh:IRI ;
sh:maxCount 1 ;
] .
ujgcondshape:ConditionSetShape a sh:NodeShape ;
sh:targetClass ujgcond:ConditionSet ;
sh:nodeKind sh:IRI ;
sh:property [
sh:path ujgcond:conditionTransitionRefs ;
sh:class ujggraph:Transition ;
sh:nodeKind sh:IRI ;
sh:minCount 2 ;
] ;
sh:sparql [
a sh:SPARQLConstraint ;
sh:message "Every transition referenced by a ConditionSet MUST have a conditionRef." ;
sh:select """
SELECT $this ?transition
WHERE {
$this ujgcond:conditionTransitionRefs ?transition .
FILTER NOT EXISTS {
?transition ujgcond:conditionRef ?condition .
}
}
""" ;
] ;
sh:sparql [
a sh:SPARQLConstraint ;
sh:message "All transitions referenced by one ConditionSet MUST have the same from state." ;
sh:select """
SELECT $this ?transitionA ?transitionB ?fromA ?fromB
WHERE {
$this ujgcond:conditionTransitionRefs ?transitionA .
$this ujgcond:conditionTransitionRefs ?transitionB .
?transitionA ujggraph:from ?fromA .
?transitionB ujggraph:from ?fromB .
FILTER (?transitionA != ?transitionB)
FILTER (?fromA != ?fromB)
}
""" ;
] . @prefix ujggraph: <https://ujg.specs.openuji.org/ed/ns/graph#> .
@prefix ujgcond: <https://ujg.specs.openuji.org/ed/ns/condition#> .
@prefix ujgcondshape: <https://ujg.specs.openuji.org/ed/ns/condition.shape#> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
ujgcondshape:ConditionShape a sh:NodeShape ;
sh:targetClass ujgcond:Condition ;
sh:nodeKind sh:IRI .
ujgcondshape:GuardedTransitionShape a sh:NodeShape ;
sh:targetClass ujggraph:Transition ;
sh:nodeKind sh:IRI ;
sh:property [
sh:path ujgcond:conditionRef ;
sh:class ujgcond:Condition ;
sh:nodeKind sh:IRI ;
sh:maxCount 1 ;
] .
ujgcondshape:ConditionSetShape a sh:NodeShape ;
sh:targetClass ujgcond:ConditionSet ;
sh:nodeKind sh:IRI ;
sh:property [
sh:path ujgcond:conditionTransitionRefs ;
sh:class ujggraph:Transition ;
sh:nodeKind sh:IRI ;
sh:minCount 2 ;
] ;
sh:sparql [
a sh:SPARQLConstraint ;
sh:message "Every transition referenced by a ConditionSet MUST have a conditionRef." ;
sh:select """
SELECT $this ?transition
WHERE {
$this ujgcond:conditionTransitionRefs ?transition .
FILTER NOT EXISTS {
?transition ujgcond:conditionRef ?condition .
}
}
""" ;
] ;
sh:sparql [
a sh:SPARQLConstraint ;
sh:message "All transitions referenced by one ConditionSet MUST have the same from state." ;
sh:select """
SELECT $this ?transitionA ?transitionB ?fromA ?fromB
WHERE {
$this ujgcond:conditionTransitionRefs ?transitionA .
$this ujgcond:conditionTransitionRefs ?transitionB .
?transitionA ujggraph:from ?fromA .
?transitionB ujggraph:from ?fromB .
FILTER (?transitionA != ?transitionB)
FILTER (?fromA != ?fromB)
}
""" ;
] . The rules below define the remaining module semantics beyond the structural constraints captured by the SHACL shape.
Graph preservation: A condition MUST NOT create an implicit edge. Every possible movement between states MUST be represented by a Graph
Transition.Transition guard semantics: A transition with
conditionRefis eligible only when the referenced condition is satisfied by the implementation's domain/runtime context.Branch semantics: A
ConditionSetgroups guarded transitions that form one branch point. In this version, aConditionSetrepresents a branch where one referenced transition is intended to be taken.No expression language: The meaning and evaluation of a condition are intentionally outside this module unless another optional module defines expression semantics.
Graceful degradation: Consumers that do not understand this module MAY render the underlying Graph normally and MAY ignore conditional eligibility.
8. Appendix: Combined JSON Example
Codex chat branch-check example:
{
"@context": [
"https://ujg.specs.openuji.org/ed/ns/context.jsonld",
"https://ujg.specs.openuji.org/ed/ns/condition.context.jsonld"
],
"@id": "https://example.com/ujg/codex/branch-condition.jsonld",
"@type": "UJGDocument",
"specVersion": "1.0",
"nodes": [
{
"@type": "Journey",
"@id": "urn:ujg:journey:codex-chat-in-ide",
"startState": "urn:ujg:state:user-asks-codex-to-code",
"stateRefs": [
"urn:ujg:state:user-asks-codex-to-code",
"urn:ujg:state:codex-starts-coding",
"urn:ujg:state:branch-confirmation-popup",
"urn:ujg:state:switch-back-to-original-branch",
"urn:ujg:state:codex-starts-coding-on-original-branch"
],
"transitionRefs": [
"urn:ujg:transition:ask-code-to-start-coding",
"urn:ujg:transition:ask-code-to-branch-popup",
"urn:ujg:transition:popup-keep-current-branch",
"urn:ujg:transition:popup-go-back",
"urn:ujg:transition:switch-back-to-start-coding"
]
},
{
"@type": "State",
"@id": "urn:ujg:state:user-asks-codex-to-code",
"label": "User asks Codex to make code changes"
},
{
"@type": "State",
"@id": "urn:ujg:state:codex-starts-coding",
"label": "Codex starts coding on the current branch"
},
{
"@type": "State",
"@id": "urn:ujg:state:branch-confirmation-popup",
"label": "Codex asks whether to continue on the current branch or return to the original branch"
},
{
"@type": "State",
"@id": "urn:ujg:state:switch-back-to-original-branch",
"label": "IDE switches back to the original branch associated with the chat"
},
{
"@type": "State",
"@id": "urn:ujg:state:codex-starts-coding-on-original-branch",
"label": "Codex starts coding on the original branch"
},
{
"@type": "Transition",
"@id": "urn:ujg:transition:ask-code-to-start-coding",
"from": "urn:ujg:state:user-asks-codex-to-code",
"to": "urn:ujg:state:codex-starts-coding",
"label": "Branch is unchanged",
"conditionRef": "urn:ujg:condition:current-branch-equals-chat-branch"
},
{
"@type": "Transition",
"@id": "urn:ujg:transition:ask-code-to-branch-popup",
"from": "urn:ujg:state:user-asks-codex-to-code",
"to": "urn:ujg:state:branch-confirmation-popup",
"label": "Branch differs",
"conditionRef": "urn:ujg:condition:current-branch-differs-from-chat-branch"
},
{
"@type": "Transition",
"@id": "urn:ujg:transition:popup-keep-current-branch",
"from": "urn:ujg:state:branch-confirmation-popup",
"to": "urn:ujg:state:codex-starts-coding",
"label": "Keep me on the current branch"
},
{
"@type": "Transition",
"@id": "urn:ujg:transition:popup-go-back",
"from": "urn:ujg:state:branch-confirmation-popup",
"to": "urn:ujg:state:switch-back-to-original-branch",
"label": "Go back to the original branch"
},
{
"@type": "Transition",
"@id": "urn:ujg:transition:switch-back-to-start-coding",
"from": "urn:ujg:state:switch-back-to-original-branch",
"to": "urn:ujg:state:codex-starts-coding-on-original-branch",
"label": "Continue coding"
},
{
"@type": "ConditionSet",
"@id": "urn:ujg:condition-set:resolve-branch-context-before-coding",
"label": "Resolve branch context before coding",
"conditionTransitionRefs": [
"urn:ujg:transition:ask-code-to-start-coding",
"urn:ujg:transition:ask-code-to-branch-popup"
]
},
{
"@type": "Condition",
"@id": "urn:ujg:condition:current-branch-equals-chat-branch",
"label": "Current IDE Git branch equals the branch associated with this Codex chat session"
},
{
"@type": "Condition",
"@id": "urn:ujg:condition:current-branch-differs-from-chat-branch",
"label": "Current IDE Git branch differs from the branch associated with this Codex chat session"
}
]
} {
"@context": [
"https://ujg.specs.openuji.org/ed/ns/context.jsonld",
"https://ujg.specs.openuji.org/ed/ns/condition.context.jsonld"
],
"@id": "https://example.com/ujg/codex/branch-condition.jsonld",
"@type": "UJGDocument",
"specVersion": "1.0",
"nodes": [
{
"@type": "Journey",
"@id": "urn:ujg:journey:codex-chat-in-ide",
"startState": "urn:ujg:state:user-asks-codex-to-code",
"stateRefs": [
"urn:ujg:state:user-asks-codex-to-code",
"urn:ujg:state:codex-starts-coding",
"urn:ujg:state:branch-confirmation-popup",
"urn:ujg:state:switch-back-to-original-branch",
"urn:ujg:state:codex-starts-coding-on-original-branch"
],
"transitionRefs": [
"urn:ujg:transition:ask-code-to-start-coding",
"urn:ujg:transition:ask-code-to-branch-popup",
"urn:ujg:transition:popup-keep-current-branch",
"urn:ujg:transition:popup-go-back",
"urn:ujg:transition:switch-back-to-start-coding"
]
},
{
"@type": "State",
"@id": "urn:ujg:state:user-asks-codex-to-code",
"label": "User asks Codex to make code changes"
},
{
"@type": "State",
"@id": "urn:ujg:state:codex-starts-coding",
"label": "Codex starts coding on the current branch"
},
{
"@type": "State",
"@id": "urn:ujg:state:branch-confirmation-popup",
"label": "Codex asks whether to continue on the current branch or return to the original branch"
},
{
"@type": "State",
"@id": "urn:ujg:state:switch-back-to-original-branch",
"label": "IDE switches back to the original branch associated with the chat"
},
{
"@type": "State",
"@id": "urn:ujg:state:codex-starts-coding-on-original-branch",
"label": "Codex starts coding on the original branch"
},
{
"@type": "Transition",
"@id": "urn:ujg:transition:ask-code-to-start-coding",
"from": "urn:ujg:state:user-asks-codex-to-code",
"to": "urn:ujg:state:codex-starts-coding",
"label": "Branch is unchanged",
"conditionRef": "urn:ujg:condition:current-branch-equals-chat-branch"
},
{
"@type": "Transition",
"@id": "urn:ujg:transition:ask-code-to-branch-popup",
"from": "urn:ujg:state:user-asks-codex-to-code",
"to": "urn:ujg:state:branch-confirmation-popup",
"label": "Branch differs",
"conditionRef": "urn:ujg:condition:current-branch-differs-from-chat-branch"
},
{
"@type": "Transition",
"@id": "urn:ujg:transition:popup-keep-current-branch",
"from": "urn:ujg:state:branch-confirmation-popup",
"to": "urn:ujg:state:codex-starts-coding",
"label": "Keep me on the current branch"
},
{
"@type": "Transition",
"@id": "urn:ujg:transition:popup-go-back",
"from": "urn:ujg:state:branch-confirmation-popup",
"to": "urn:ujg:state:switch-back-to-original-branch",
"label": "Go back to the original branch"
},
{
"@type": "Transition",
"@id": "urn:ujg:transition:switch-back-to-start-coding",
"from": "urn:ujg:state:switch-back-to-original-branch",
"to": "urn:ujg:state:codex-starts-coding-on-original-branch",
"label": "Continue coding"
},
{
"@type": "ConditionSet",
"@id": "urn:ujg:condition-set:resolve-branch-context-before-coding",
"label": "Resolve branch context before coding",
"conditionTransitionRefs": [
"urn:ujg:transition:ask-code-to-start-coding",
"urn:ujg:transition:ask-code-to-branch-popup"
]
},
{
"@type": "Condition",
"@id": "urn:ujg:condition:current-branch-equals-chat-branch",
"label": "Current IDE Git branch equals the branch associated with this Codex chat session"
},
{
"@type": "Condition",
"@id": "urn:ujg:condition:current-branch-differs-from-chat-branch",
"label": "Current IDE Git branch differs from the branch associated with this Codex chat session"
}
]
} 9. Appendix: Opaque Runtime Hints
Runtime condition bindings are intentionally not standardized by this module. Implementations that
need to bind a Condition to product-specific runtime state can use Core extensions.
{
"@type": "Condition",
"@id": "urn:ujg:condition:current-branch-differs-from-chat-branch",
"label": "Current IDE Git branch differs from the branch associated with this Codex chat session",
"extensions": {
"com.example.runtime-condition": {
"conditionKey": "ide.git.currentBranchDiffersFromChatBranch",
"domain": "ide.git",
"evaluator": "product-private"
}
}
} {
"@type": "Condition",
"@id": "urn:ujg:condition:current-branch-differs-from-chat-branch",
"label": "Current IDE Git branch differs from the branch associated with this Codex chat session",
"extensions": {
"com.example.runtime-condition": {
"conditionKey": "ide.git.currentBranchDiffersFromChatBranch",
"domain": "ide.git",
"evaluator": "product-private"
}
}
}