UJG / UJG 1.0 Release Candidate 2 /
GitHub
Table of Contents
  • 1Overview
  • 2Terminology
  • 3JourneyMapping
  • 4MappedStep
  • 5Mapping Model
  • 6Processing Rules
  • 7Step Occurrence and Phase Start
  • 8Normative Artifacts
    • 8.1Ontology
    • 8.2JSON-LD Context
    • 8.3Validation
  • 9Examples
    • 9.1Minimal Example
    • 9.2Affordance Event Example
W3C Community Group Draft Report

Mapping

draft

Status 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 .

Status
CG-DRAFT
Version
1.0-rc2
Published
2026-09-11
Last Update
2026-09-11
Editors
  • Seva Dolgopolov
Group
User Journal Graph Community Group
Repository
View Source
License
W3C-Software-and-Document

1. Overview

This module defines the basic vocabulary and processing model for mapping causally ordered Runtime events back to the intended Graph journey model.

Runtime records what happened. Graph defines the intended journey topology. Mapping connects the two by resolving state-observation RuntimeEvent.surfaceInstanceRef values to SurfaceInstance nodes, then resolving each instance's surfaceRef to a Surface and that surface's graphNodeRef to the observed Graph state-like node. Mapping associates the resolved execution with an explicit root Graph Journey.

Mapping roots are traversable Graph Journeys. A JourneyEntryIndex can help discover known JourneyEntry contracts before mapping, but it is not a local traversal scope and is not the target of mappedJourneyRef.

Mapping surfaces model drift, tracking gaps, direct invocations, menu jumps, and other out-of-model movement. It does not assume every jump is an error.

Examples in this page compose the shared baseline context https://ujg.specs.openuji.org/tr/1.0-rc2/ns/context.jsonld with the Mapping context.

2. Terminology

  • JourneyMapping: An addressable mapping record that binds one Runtime execution chain to the root Graph Journey used to interpret it. The mapped journey is a traversable topology, not a JourneyEntryIndex.

  • MappedStep: An addressable mapping record for one state-observation RuntimeEvent in the mapped chain.

  • Mapped runtime: The JourneyExecution whose causal RuntimeEvent chain is being resolved.

  • Mapped state: A Graph State or CompositeState resolved from a RuntimeEvent.surfaceInstanceRef through SurfaceInstance.surfaceRef and Surface.graphNodeRef.

  • Observed affordance: A Command resolved from a runtime event's surface.

  • Relevant effective transition: A Graph transition that can explain an observed movement between two resolved runtime states.

  • Jump: A non-root mapped step where no relevant effective transition explains the observed movement.

3. JourneyMapping

A JourneyMapping binds one Runtime execution chain to the root Graph Journey used to interpret it and to the set of MappedStep records derived from that chain.

  1. A JourneyMapping MUST be identified by an IRI.

  2. A JourneyMapping MUST declare exactly one mappedRuntimeRef to a JourneyExecution.

  3. A JourneyMapping MUST declare exactly one mappedJourneyRef to a traversable Journey.

  4. mappedJourneyRef MUST NOT reference a JourneyEntryIndex.

  5. A JourneyMapping MUST declare one or more mappedStepRef values.

  6. The JSON order of mappedStepRef values MUST NOT define step order.

classDiagram
  class JourneyExecution
  class Journey
  class MappedStep
  class JourneyMapping {
    id
    mappedRuntimeRef
    mappedJourneyRef
    mappedStepRef
  }
  JourneyMapping --> JourneyExecution : mappedRuntimeRef
  JourneyMapping --> Journey : mappedJourneyRef
  JourneyMapping --> "1..*" MappedStep : mappedStepRef

Example JSON node:

json
{
  "@type": "JourneyMapping",
  "@id": "urn:mapping:checkout-1",
  "mappedRuntimeRef": "urn:execution:checkout-1",
  "mappedJourneyRef": "urn:journey:checkout",
  "mappedStepRef": [
    "urn:mapping:checkout-1:100",
    "urn:mapping:checkout-1:200"
  ]
}
{
  "@type": "JourneyMapping",
  "@id": "urn:mapping:checkout-1",
  "mappedRuntimeRef": "urn:execution:checkout-1",
  "mappedJourneyRef": "urn:journey:checkout",
  "mappedStepRef": [
    "urn:mapping:checkout-1:100",
    "urn:mapping:checkout-1:200"
  ]
}

4. MappedStep

A MappedStep records the Graph state-like node resolved for one state-observation RuntimeEvent. Affordance events remain in the Runtime causal chain and may be referenced as evidence, but are not serialized as separate MappedStep records.

  1. A MappedStep MUST be identified by an IRI.

  2. A MappedStep MUST declare exactly one mappedEventRef to a state-observation RuntimeEvent.

  3. A MappedStep MUST declare exactly one mappedStateRef to the resolved State or CompositeState.

  4. A MappedStep MAY declare at most one observedAffordanceEventRef to its immediate predecessor event.

  5. A MappedStep MAY declare at most one explainedByTransitionRef to a relevant effective transition.

classDiagram
  class RuntimeEvent
  class State
  class CompositeState
  class Transition
  class OutgoingTransition
  class MappedStep {
    id
    mappedEventRef
    mappedStateRef
    observedAffordanceEventRef
    explainedByTransitionRef
  }
  MappedStep --> RuntimeEvent : mappedEventRef
  MappedStep --> RuntimeEvent : observedAffordanceEventRef
  MappedStep --> State : mappedStateRef
  MappedStep --> CompositeState : mappedStateRef
  MappedStep --> Transition : explainedByTransitionRef
  MappedStep --> OutgoingTransition : explainedByTransitionRef

Example JSON node:

json
{
  "@type": "MappedStep",
  "@id": "urn:mapping:checkout-1:200",
  "mappedEventRef": "urn:event:checkout-1:200",
  "observedAffordanceEventRef": "urn:event:checkout-1:150",
  "mappedStateRef": "urn:state:payment",
  "explainedByTransitionRef": "urn:transition:cart-to-payment"
}
{
  "@type": "MappedStep",
  "@id": "urn:mapping:checkout-1:200",
  "mappedEventRef": "urn:event:checkout-1:200",
  "observedAffordanceEventRef": "urn:event:checkout-1:150",
  "mappedStateRef": "urn:state:payment",
  "explainedByTransitionRef": "urn:transition:cart-to-payment"
}

5. Mapping Model

A JourneyMapping links:

  • mapping:mappedRuntimeRef to the Runtime JourneyExecution being mapped.

  • mapping:mappedJourneyRef to the root Graph Journey for the interpreted execution.

  • mapping:mappedStepRef to the state-resolving MappedStep records derived from the runtime chain.

Each MappedStep links:

  • mapping:mappedEventRef to the state-observation Runtime RuntimeEvent being interpreted.

  • mapping:observedAffordanceEventRef, when present, to the immediately preceding Runtime RuntimeEvent whose surface resolves to an observed affordance Command.

  • mapping:mappedStateRef to the resolved Graph State or CompositeState.

  • mapping:explainedByTransitionRef, when present, to the effective Transition or OutgoingTransition that explains the movement.

Runtime events whose surfaces resolve to Command are affordance events. They remain in the Runtime causal chain but are not serialized as separate MappedStep records. When an affordance event appears immediately before a state-observation event, the following MappedStep can reference it with observedAffordanceEventRef.

Mapping does not serialize a separate step scope. For each MappedStep, the local Graph Journey scope is derived from the mapped state's containment path rooted at mappedJourneyRef.

The Runtime event order remains defined by Runtime's causal chain: a root event followed by the unique successor sequence obtained through previousId. mappedStepRef is a set of step records; its JSON order is not normative.

6. Processing Rules

The rules below define the remaining module semantics beyond the structural constraints captured by the SHACL shape.

  1. Runtime chain source: A consumer mapping runtime behavior MUST reconstruct event order using the Runtime causal chain model.

  2. Step correspondence: Each MappedStep MUST identify one state-observation RuntimeEvent in the mapped runtime chain through mappedEventRef.

  3. Surface resolution: For each MappedStep, the Consumer MUST resolve the referenced RuntimeEvent.surfaceInstanceRef to a SurfaceInstance, then follow surfaceRef to a Surface.

  4. State resolution: Each MappedStep.mappedStateRef MUST be the Graph State or CompositeState resolved from the mappedEventRef event surface's graphNodeRef in the mapped journey's containment path or imported documents. Runtime events whose surfaces resolve to Command MUST NOT be serialized as MappedStep records.

  5. Journey ownership: mappedJourneyRef identifies the root Graph Journey for the mapped execution. mappedJourneyRef MUST NOT reference a JourneyEntryIndex.

  6. Step order: Mapping does not define a separate step order. Consumers MUST order mapped steps by applying Runtime chain reconstruction to each step's mappedEventRef.

  7. Local journey scope: For each MappedStep, a Consumer MUST derive the local Journey scope from the mapped state and the containment path rooted at mappedJourneyRef. If the mapped state is listed in the mapped root journey's stateRefs, the local scope is the mapped root journey. If the mapped state is listed in a child journey reached through a containing CompositeState's subjourneyRefs, the local scope is that child journey for that containing composite occurrence. A mapped CompositeState belongs to the parent journey scope that lists it in stateRefs.

  8. Composite occurrence scope: When the same CompositeState occurs more than once in the Runtime chain, Consumers MUST treat each occurrence as a separate containing scope for child journey predecessor lookup. Mapping does not serialize occurrence identifiers.

  9. Origin derivation: The root event step is derived from the absence of RuntimeEvent.previousId. It records the starting resolved state and is not an observed movement. The first ordered mapped observation in each local child journey scope for a containing composite occurrence is a local origin even when it is not the root event step.

  10. Local origin evidence: A local origin in a child journey MUST NOT use a mapped step from a sibling child journey as its predecessor. The origin is consistent with a parent transition's toEntryRef, the child journey's defaultEntryRef, or materialization or execution context selecting a child entry. A local origin needs no explainedByTransitionRef.

  11. Affordance event correlation: If the immediate RuntimeEvent.previousId predecessor of a MappedStep.mappedEventRef event resolves through Surface to a Command, the MappedStep MAY reference that predecessor with observedAffordanceEventRef. observedAffordanceEventRef MUST NOT reference any event other than that immediate predecessor.

  12. Transition lookup: A non-root mapped step is explained when explainedByTransitionRef points to one relevant effective transition in the current local journey scope. The previous resolved state for this lookup is the latest earlier MappedStep in Runtime causal order that resolves to a State or CompositeState in the same local journey scope and the same containing composite occurrence. Observations from sibling child journeys may appear between that local predecessor and the current mapped step without creating a jump. A relevant effective transition is either:

  • a Graph Transition whose from is the local predecessor's resolved state and whose to is the current resolved state; or

  • an effective OutgoingTransition contributed by an OutgoingTransitionGroup referenced by the local scope, where the local predecessor's resolved state is in the local scope and the outgoing transition's to is the current resolved state.

  1. Child exit occurrence: A child JourneyExit reached in a local child journey scope ends that containing CompositeState occurrence for Mapping. Later observations from any child Journey in the ended composite scope require a later occurrence of the containing composite or are out-of-scope movement under existing Mapping rules. A child exit does not imply simultaneous, joint, or all-child completion for sibling child journeys.

  2. Observed affordance evidence: When observedAffordanceEventRef is present and resolves to a Command, explainedByTransitionRef SHOULD identify a relevant Transition or OutgoingTransition whose commandRef references that same Command, if one exists for the movement from the local predecessor to the current mapped state.

  3. Outgoing group availability: An OutgoingTransition whose commandRef matches an observed affordance event can explain a movement when it is available directly from the local predecessor state or when it is a child of an OutgoingTransitionGroup referenced by the local journey scope. Consumers use OutgoingTransitionGroup.outgoingTransitionRefs only to determine child outgoing-transition availability; an OutgoingTransitionGroup itself is not surfaced.

  4. Boundary ambiguity: If a movement crosses a journey boundary and the available surface data are insufficient to identify a relevant effective transition, the movement is a jump.

  5. Condition eligibility: If a consumer implements [UJG Conditions], a guarded transition only explains a mapped step when the transition is eligible under Condition semantics.

  6. Jump derivation: A non-root mapped step is a jump when no relevant effective transition explains the observed movement. A jump is a derived processing result, not serialized Mapping vocabulary.

  7. No intent assumption: A derived jump reports that the observed movement is not explained by the mapped graph. It does not by itself decide whether the movement is legitimate or erroneous.

7. Step Occurrence and Phase Start

For documents that use [UJG Phase], Mapping also derives when Steps occur and when their Phases start. These are processing results, not serialized Mapping vocabulary, and they do not change Runtime records, Graph traversal, or the JourneyMapping and MappedStep wire shapes.

  1. A Consumer deriving experience occurrence MUST order MappedSteps by applying Runtime chain reconstruction to each step's mappedEventRef.

  2. A Step occurs at the earliest ordered MappedStep whose mappedStateRef equals that Step's compositeStateRef.

  3. A Phase starts at the earliest occurrence of any Step whose phaseRef resolves to that Phase.

  4. Repeated matching RuntimeEvents MUST NOT restart an already occurred Step or Phase.

  5. A Step without phaseRef may occur but MUST NOT start a Phase.

  6. A Phase with no occurring Step MUST NOT be considered started.

  7. RuntimeEvents whose surfaces resolve to Command MUST NOT trigger a Step directly; only ordered MappedStep state observations are considered.

  8. Serialized node order, mappedStepRef order, Step.order, and Phase.order MUST NOT determine occurrence or start time.

flowchart LR
  E[RuntimeEvent] -->|surfaceInstanceRef| SI[SurfaceInstance]
  SI -->|surfaceRef| S[Surface]
  S -->|graphNodeRef| G[Graph State or CompositeState]
  G -->|mappedStateRef| MS[MappedStep]
  MS -->|equals compositeStateRef| ES[Step occurs]
  ES -->|phaseRef; earliest step| P[Phase starts]

In the following fragment, the shipping step and checkout phase both begin at event :100. The repeated mapped step for the same composite state at event :200 does not restart either result.

json
{
  "@context": [
    "https://ujg.specs.openuji.org/tr/1.0-rc2/ns/context.jsonld",
    "https://ujg.specs.openuji.org/tr/1.0-rc2/ns/phase.context.jsonld",
    "https://ujg.specs.openuji.org/tr/1.0-rc2/ns/mapping.context.jsonld"
  ],
  "@type": "UJGDocument",
  "nodes": [
    {
      "@type": "CompositeState",
      "@id": "urn:state:shipping-segment",
      "label": "Shipping segment",
      "subjourneyRefs": ["urn:journey:shipping-segment"]
    },
    {
      "@type": "Journey",
      "@id": "urn:journey:shipping-segment",
      "defaultEntryRef": "urn:entry:shipping-default",
      "entryRefs": ["urn:entry:shipping-default"],
      "stateRefs": ["urn:state:shipping-form"]
    },
    {
      "@type": "JourneyEntry",
      "@id": "urn:entry:shipping-default",
      "stateRef": "urn:state:shipping-form"
    },
    { "@type": "State", "@id": "urn:state:shipping-form", "label": "Shipping form" },
    { "@type": "Phase", "@id": "urn:phase:checkout", "order": 2 },
    {
      "@type": "Step",
      "@id": "urn:step:shipping",
      "compositeStateRef": "urn:state:shipping-segment",
      "phaseRef": "urn:phase:checkout"
    },
    { "@type": "Surface", "@id": "urn:surface:shipping", "graphNodeRef": "urn:state:shipping-segment" },
    { "@type": "SurfaceInstance", "@id": "urn:instance:shipping", "surfaceRef": "urn:surface:shipping" },
    { "@type": "JourneyExecution", "@id": "urn:execution:checkout" },
    {
      "@type": "RuntimeEvent",
      "@id": "urn:event:checkout:100",
      "executionId": "urn:execution:checkout",
      "surfaceInstanceRef": "urn:instance:shipping"
    },
    {
      "@type": "RuntimeEvent",
      "@id": "urn:event:checkout:200",
      "executionId": "urn:execution:checkout",
      "previousId": "urn:event:checkout:100",
      "surfaceInstanceRef": "urn:instance:shipping"
    },
    {
      "@type": "MappedStep",
      "@id": "urn:mapping:checkout:100",
      "mappedEventRef": "urn:event:checkout:100",
      "mappedStateRef": "urn:state:shipping-segment"
    },
    {
      "@type": "MappedStep",
      "@id": "urn:mapping:checkout:200",
      "mappedEventRef": "urn:event:checkout:200",
      "mappedStateRef": "urn:state:shipping-segment"
    }
  ]
}
{
  "@context": [
    "https://ujg.specs.openuji.org/tr/1.0-rc2/ns/context.jsonld",
    "https://ujg.specs.openuji.org/tr/1.0-rc2/ns/phase.context.jsonld",
    "https://ujg.specs.openuji.org/tr/1.0-rc2/ns/mapping.context.jsonld"
  ],
  "@type": "UJGDocument",
  "nodes": [
    {
      "@type": "CompositeState",
      "@id": "urn:state:shipping-segment",
      "label": "Shipping segment",
      "subjourneyRefs": ["urn:journey:shipping-segment"]
    },
    {
      "@type": "Journey",
      "@id": "urn:journey:shipping-segment",
      "defaultEntryRef": "urn:entry:shipping-default",
      "entryRefs": ["urn:entry:shipping-default"],
      "stateRefs": ["urn:state:shipping-form"]
    },
    {
      "@type": "JourneyEntry",
      "@id": "urn:entry:shipping-default",
      "stateRef": "urn:state:shipping-form"
    },
    { "@type": "State", "@id": "urn:state:shipping-form", "label": "Shipping form" },
    { "@type": "Phase", "@id": "urn:phase:checkout", "order": 2 },
    {
      "@type": "Step",
      "@id": "urn:step:shipping",
      "compositeStateRef": "urn:state:shipping-segment",
      "phaseRef": "urn:phase:checkout"
    },
    { "@type": "Surface", "@id": "urn:surface:shipping", "graphNodeRef": "urn:state:shipping-segment" },
    { "@type": "SurfaceInstance", "@id": "urn:instance:shipping", "surfaceRef": "urn:surface:shipping" },
    { "@type": "JourneyExecution", "@id": "urn:execution:checkout" },
    {
      "@type": "RuntimeEvent",
      "@id": "urn:event:checkout:100",
      "executionId": "urn:execution:checkout",
      "surfaceInstanceRef": "urn:instance:shipping"
    },
    {
      "@type": "RuntimeEvent",
      "@id": "urn:event:checkout:200",
      "executionId": "urn:execution:checkout",
      "previousId": "urn:event:checkout:100",
      "surfaceInstanceRef": "urn:instance:shipping"
    },
    {
      "@type": "MappedStep",
      "@id": "urn:mapping:checkout:100",
      "mappedEventRef": "urn:event:checkout:100",
      "mappedStateRef": "urn:state:shipping-segment"
    },
    {
      "@type": "MappedStep",
      "@id": "urn:mapping:checkout:200",
      "mappedEventRef": "urn:event:checkout:200",
      "mappedStateRef": "urn:state:shipping-segment"
    }
  ]
}

8. Normative Artifacts

This module is published through the following artifacts.

8.1. Ontology

The normative Mapping ontology is defined below and is published at https://ujg.specs.openuji.org/tr/1.0-rc2/ns/mapping.

turtle
@prefix ujg: <https://ujg.specs.openuji.org/tr/1.0-rc2/ns/core#> .
@prefix ujggraph: <https://ujg.specs.openuji.org/tr/1.0-rc2/ns/graph#> .
@prefix ujgruntime: <https://ujg.specs.openuji.org/tr/1.0-rc2/ns/runtime#> .
@prefix ujgmapping: <https://ujg.specs.openuji.org/tr/1.0-rc2/ns/mapping#> .
@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/tr/1.0-rc2/ns/mapping#> a owl:Ontology ;
  rdfs:label "UJG Mapping 1.0 Vocabulary"@en ;
  dct:description "UJG Mapping ontology declaration" .

### Classes

ujgmapping:JourneyMapping a owl:Class ;
  rdfs:subClassOf ujg:Node .

ujgmapping:MappedStep a owl:Class ;
  rdfs:subClassOf ujg:Node .

### Properties

ujgmapping:mappedJourneyRef a owl:ObjectProperty ;
  rdfs:domain ujgmapping:JourneyMapping ;
  rdfs:range ujggraph:Journey .

ujgmapping:mappedRuntimeRef a owl:ObjectProperty ;
  rdfs:domain ujgmapping:JourneyMapping ;
  rdfs:range ujgruntime:JourneyExecution .

ujgmapping:mappedStepRef a owl:ObjectProperty ;
  rdfs:domain ujgmapping:JourneyMapping ;
  rdfs:range ujgmapping:MappedStep .

ujgmapping:mappedEventRef a owl:ObjectProperty ;
  rdfs:domain ujgmapping:MappedStep ;
  rdfs:range ujgruntime:RuntimeEvent .

ujgmapping:observedAffordanceEventRef a owl:ObjectProperty ;
  rdfs:domain ujgmapping:MappedStep ;
  rdfs:range ujgruntime:RuntimeEvent .

ujgmapping:mappedStateRef a owl:ObjectProperty ;
  rdfs:domain ujgmapping:MappedStep ;
  rdfs:range [
    a owl:Class ;
    owl:unionOf ( ujggraph:State ujggraph:CompositeState )
  ] .

ujgmapping:explainedByTransitionRef a owl:ObjectProperty ;
  rdfs:domain ujgmapping:MappedStep ;
  rdfs:range [
    a owl:Class ;
    owl:unionOf ( ujggraph:Transition ujggraph:OutgoingTransition )
  ] .
@prefix ujg: <https://ujg.specs.openuji.org/tr/1.0-rc2/ns/core#> .
@prefix ujggraph: <https://ujg.specs.openuji.org/tr/1.0-rc2/ns/graph#> .
@prefix ujgruntime: <https://ujg.specs.openuji.org/tr/1.0-rc2/ns/runtime#> .
@prefix ujgmapping: <https://ujg.specs.openuji.org/tr/1.0-rc2/ns/mapping#> .
@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/tr/1.0-rc2/ns/mapping#> a owl:Ontology ;
  rdfs:label "UJG Mapping 1.0 Vocabulary"@en ;
  dct:description "UJG Mapping ontology declaration" .

### Classes

ujgmapping:JourneyMapping a owl:Class ;
  rdfs:subClassOf ujg:Node .

ujgmapping:MappedStep a owl:Class ;
  rdfs:subClassOf ujg:Node .

### Properties

ujgmapping:mappedJourneyRef a owl:ObjectProperty ;
  rdfs:domain ujgmapping:JourneyMapping ;
  rdfs:range ujggraph:Journey .

ujgmapping:mappedRuntimeRef a owl:ObjectProperty ;
  rdfs:domain ujgmapping:JourneyMapping ;
  rdfs:range ujgruntime:JourneyExecution .

ujgmapping:mappedStepRef a owl:ObjectProperty ;
  rdfs:domain ujgmapping:JourneyMapping ;
  rdfs:range ujgmapping:MappedStep .

ujgmapping:mappedEventRef a owl:ObjectProperty ;
  rdfs:domain ujgmapping:MappedStep ;
  rdfs:range ujgruntime:RuntimeEvent .

ujgmapping:observedAffordanceEventRef a owl:ObjectProperty ;
  rdfs:domain ujgmapping:MappedStep ;
  rdfs:range ujgruntime:RuntimeEvent .

ujgmapping:mappedStateRef a owl:ObjectProperty ;
  rdfs:domain ujgmapping:MappedStep ;
  rdfs:range [
    a owl:Class ;
    owl:unionOf ( ujggraph:State ujggraph:CompositeState )
  ] .

ujgmapping:explainedByTransitionRef a owl:ObjectProperty ;
  rdfs:domain ujgmapping:MappedStep ;
  rdfs:range [
    a owl:Class ;
    owl:unionOf ( ujggraph:Transition ujggraph:OutgoingTransition )
  ] .

8.2. JSON-LD Context

The normative Mapping JSON-LD context is defined below and is published at https://ujg.specs.openuji.org/tr/1.0-rc2/ns/mapping.context.jsonld.

json-ld
{
  "@context": {
    "@version": 1.1,

    "ujgmapping": "https://ujg.specs.openuji.org/tr/1.0-rc2/ns/mapping#",
    "mapping": "https://ujg.specs.openuji.org/tr/1.0-rc2/ns/mapping#",

    "JourneyMapping": "ujgmapping:JourneyMapping",
    "MappedStep": "ujgmapping:MappedStep",

    "mappedJourneyRef": {
      "@id": "ujgmapping:mappedJourneyRef",
      "@type": "@id"
    },
    "mappedRuntimeRef": {
      "@id": "ujgmapping:mappedRuntimeRef",
      "@type": "@id"
    },
    "mappedStepRef": {
      "@id": "ujgmapping:mappedStepRef",
      "@type": "@id",
      "@container": "@set"
    },
    "mappedEventRef": {
      "@id": "ujgmapping:mappedEventRef",
      "@type": "@id"
    },
    "observedAffordanceEventRef": {
      "@id": "ujgmapping:observedAffordanceEventRef",
      "@type": "@id"
    },
    "mappedStateRef": {
      "@id": "ujgmapping:mappedStateRef",
      "@type": "@id"
    },
    "explainedByTransitionRef": {
      "@id": "ujgmapping:explainedByTransitionRef",
      "@type": "@id"
    }
  }
}
{
  "@context": {
    "@version": 1.1,

    "ujgmapping": "https://ujg.specs.openuji.org/tr/1.0-rc2/ns/mapping#",
    "mapping": "https://ujg.specs.openuji.org/tr/1.0-rc2/ns/mapping#",

    "JourneyMapping": "ujgmapping:JourneyMapping",
    "MappedStep": "ujgmapping:MappedStep",

    "mappedJourneyRef": {
      "@id": "ujgmapping:mappedJourneyRef",
      "@type": "@id"
    },
    "mappedRuntimeRef": {
      "@id": "ujgmapping:mappedRuntimeRef",
      "@type": "@id"
    },
    "mappedStepRef": {
      "@id": "ujgmapping:mappedStepRef",
      "@type": "@id",
      "@container": "@set"
    },
    "mappedEventRef": {
      "@id": "ujgmapping:mappedEventRef",
      "@type": "@id"
    },
    "observedAffordanceEventRef": {
      "@id": "ujgmapping:observedAffordanceEventRef",
      "@type": "@id"
    },
    "mappedStateRef": {
      "@id": "ujgmapping:mappedStateRef",
      "@type": "@id"
    },
    "explainedByTransitionRef": {
      "@id": "ujgmapping:explainedByTransitionRef",
      "@type": "@id"
    }
  }
}

8.3. Validation

The normative Mapping SHACL shape is defined below and is published at https://ujg.specs.openuji.org/tr/1.0-rc2/ns/mapping.shape.

turtle
@prefix ujggraph: <https://ujg.specs.openuji.org/tr/1.0-rc2/ns/graph#> .
@prefix ujgruntime: <https://ujg.specs.openuji.org/tr/1.0-rc2/ns/runtime#> .
@prefix ujgmapping: <https://ujg.specs.openuji.org/tr/1.0-rc2/ns/mapping#> .
@prefix ujgmappingshape: <https://ujg.specs.openuji.org/tr/1.0-rc2/ns/mapping.shape#> .
@prefix sh: <http://www.w3.org/ns/shacl#> .

ujgmappingshape:StateLikeShape a sh:NodeShape ;
  sh:nodeKind sh:IRI ;
  sh:or (
    [ sh:class ujggraph:State ]
    [ sh:class ujggraph:CompositeState ]
  ) .

ujgmappingshape:TransitionLikeShape a sh:NodeShape ;
  sh:nodeKind sh:IRI ;
  sh:or (
    [ sh:class ujggraph:Transition ]
    [ sh:class ujggraph:OutgoingTransition ]
  ) .

ujgmappingshape:JourneyMappingShape a sh:NodeShape ;
  sh:targetClass ujgmapping:JourneyMapping ;
  sh:nodeKind sh:IRI ;

  sh:property [
    sh:path ujgmapping:mappedJourneyRef ;
    sh:class ujggraph:Journey ;
    sh:nodeKind sh:IRI ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
  ] ;

  sh:property [
    sh:path ujgmapping:mappedRuntimeRef ;
    sh:class ujgruntime:JourneyExecution ;
    sh:nodeKind sh:IRI ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
  ] ;

  sh:property [
    sh:path ujgmapping:mappedStepRef ;
    sh:class ujgmapping:MappedStep ;
    sh:nodeKind sh:IRI ;
    sh:minCount 1 ;
  ] .

ujgmappingshape:MappedStepShape a sh:NodeShape ;
  sh:targetClass ujgmapping:MappedStep ;
  sh:nodeKind sh:IRI ;

  sh:property [
    sh:path ujgmapping:mappedEventRef ;
    sh:class ujgruntime:RuntimeEvent ;
    sh:nodeKind sh:IRI ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
  ] ;

  sh:property [
    sh:path ujgmapping:observedAffordanceEventRef ;
    sh:class ujgruntime:RuntimeEvent ;
    sh:nodeKind sh:IRI ;
    sh:maxCount 1 ;
  ] ;

  sh:property [
    sh:path ujgmapping:mappedStateRef ;
    sh:node ujgmappingshape:StateLikeShape ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
  ] ;

  sh:property [
    sh:path ujgmapping:explainedByTransitionRef ;
    sh:node ujgmappingshape:TransitionLikeShape ;
    sh:maxCount 1 ;
  ] .
@prefix ujggraph: <https://ujg.specs.openuji.org/tr/1.0-rc2/ns/graph#> .
@prefix ujgruntime: <https://ujg.specs.openuji.org/tr/1.0-rc2/ns/runtime#> .
@prefix ujgmapping: <https://ujg.specs.openuji.org/tr/1.0-rc2/ns/mapping#> .
@prefix ujgmappingshape: <https://ujg.specs.openuji.org/tr/1.0-rc2/ns/mapping.shape#> .
@prefix sh: <http://www.w3.org/ns/shacl#> .

ujgmappingshape:StateLikeShape a sh:NodeShape ;
  sh:nodeKind sh:IRI ;
  sh:or (
    [ sh:class ujggraph:State ]
    [ sh:class ujggraph:CompositeState ]
  ) .

ujgmappingshape:TransitionLikeShape a sh:NodeShape ;
  sh:nodeKind sh:IRI ;
  sh:or (
    [ sh:class ujggraph:Transition ]
    [ sh:class ujggraph:OutgoingTransition ]
  ) .

ujgmappingshape:JourneyMappingShape a sh:NodeShape ;
  sh:targetClass ujgmapping:JourneyMapping ;
  sh:nodeKind sh:IRI ;

  sh:property [
    sh:path ujgmapping:mappedJourneyRef ;
    sh:class ujggraph:Journey ;
    sh:nodeKind sh:IRI ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
  ] ;

  sh:property [
    sh:path ujgmapping:mappedRuntimeRef ;
    sh:class ujgruntime:JourneyExecution ;
    sh:nodeKind sh:IRI ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
  ] ;

  sh:property [
    sh:path ujgmapping:mappedStepRef ;
    sh:class ujgmapping:MappedStep ;
    sh:nodeKind sh:IRI ;
    sh:minCount 1 ;
  ] .

ujgmappingshape:MappedStepShape a sh:NodeShape ;
  sh:targetClass ujgmapping:MappedStep ;
  sh:nodeKind sh:IRI ;

  sh:property [
    sh:path ujgmapping:mappedEventRef ;
    sh:class ujgruntime:RuntimeEvent ;
    sh:nodeKind sh:IRI ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
  ] ;

  sh:property [
    sh:path ujgmapping:observedAffordanceEventRef ;
    sh:class ujgruntime:RuntimeEvent ;
    sh:nodeKind sh:IRI ;
    sh:maxCount 1 ;
  ] ;

  sh:property [
    sh:path ujgmapping:mappedStateRef ;
    sh:node ujgmappingshape:StateLikeShape ;
    sh:minCount 1 ;
    sh:maxCount 1 ;
  ] ;

  sh:property [
    sh:path ujgmapping:explainedByTransitionRef ;
    sh:node ujgmappingshape:TransitionLikeShape ;
    sh:maxCount 1 ;
  ] .

9. Examples

9.1. Minimal Example

json
{
  "@context": [
    "https://ujg.specs.openuji.org/tr/1.0-rc2/ns/context.jsonld",
    "https://ujg.specs.openuji.org/tr/1.0-rc2/ns/mapping.context.jsonld"
  ],
  "@id": "https://example.com/ujg/mapping/execution-12345.jsonld",
  "@type": "UJGDocument",
  "nodes": [
    {
      "@id": "urn:mapping:execution-12345",
      "@type": "JourneyMapping",
      "mappedRuntimeRef": "urn:ujg:execution:12345",
      "mappedJourneyRef": "urn:ujg:journey:checkout",
      "mappedStepRef": [
        "urn:mapping:execution-12345:100",
        "urn:mapping:execution-12345:200",
        "urn:mapping:execution-12345:300"
      ]
    },
    {
      "@id": "urn:mapping:execution-12345:100",
      "@type": "MappedStep",
      "mappedEventRef": "urn:ujg:event:12345:100",
      "mappedStateRef": "urn:ujg:state:cart"
    },
    {
      "@id": "urn:mapping:execution-12345:200",
      "@type": "MappedStep",
      "mappedEventRef": "urn:ujg:event:12345:200",
      "mappedStateRef": "urn:ujg:state:payment",
      "explainedByTransitionRef": "urn:ujg:transition:cart-to-payment"
    },
    {
      "@id": "urn:mapping:execution-12345:300",
      "@type": "MappedStep",
      "mappedEventRef": "urn:ujg:event:12345:300",
      "mappedStateRef": "urn:ujg:state:confirmation",
      "explainedByTransitionRef": "urn:ujg:transition:payment-to-confirmation"
    }
  ]
}
{
  "@context": [
    "https://ujg.specs.openuji.org/tr/1.0-rc2/ns/context.jsonld",
    "https://ujg.specs.openuji.org/tr/1.0-rc2/ns/mapping.context.jsonld"
  ],
  "@id": "https://example.com/ujg/mapping/execution-12345.jsonld",
  "@type": "UJGDocument",
  "nodes": [
    {
      "@id": "urn:mapping:execution-12345",
      "@type": "JourneyMapping",
      "mappedRuntimeRef": "urn:ujg:execution:12345",
      "mappedJourneyRef": "urn:ujg:journey:checkout",
      "mappedStepRef": [
        "urn:mapping:execution-12345:100",
        "urn:mapping:execution-12345:200",
        "urn:mapping:execution-12345:300"
      ]
    },
    {
      "@id": "urn:mapping:execution-12345:100",
      "@type": "MappedStep",
      "mappedEventRef": "urn:ujg:event:12345:100",
      "mappedStateRef": "urn:ujg:state:cart"
    },
    {
      "@id": "urn:mapping:execution-12345:200",
      "@type": "MappedStep",
      "mappedEventRef": "urn:ujg:event:12345:200",
      "mappedStateRef": "urn:ujg:state:payment",
      "explainedByTransitionRef": "urn:ujg:transition:cart-to-payment"
    },
    {
      "@id": "urn:mapping:execution-12345:300",
      "@type": "MappedStep",
      "mappedEventRef": "urn:ujg:event:12345:300",
      "mappedStateRef": "urn:ujg:state:confirmation",
      "explainedByTransitionRef": "urn:ujg:transition:payment-to-confirmation"
    }
  ]
}

This example states that the causal event chain for urn:ujg:execution:12345 has been resolved against the checkout root journey. The first mapped step is the root event. The later mapped steps record the relevant effective transitions that explain the observed movements.

If a mapped movement is explained by a reusable outgoing transition, explainedByTransitionRef points to the OutgoingTransition resource. A movement explained by an effective OutgoingTransition from the mapped journey's OutgoingTransitionGroup is explained by the Graph model and does not need a serialized status value.

9.2. Affordance Event Example

json
{
  "@context": [
    "https://ujg.specs.openuji.org/tr/1.0-rc2/ns/context.jsonld",
    "https://ujg.specs.openuji.org/tr/1.0-rc2/ns/mapping.context.jsonld"
  ],
  "@id": "https://example.com/ujg/mapping/affordance-events.jsonld",
  "@type": "UJGDocument",
  "nodes": [
    {
      "@type": "Journey",
      "@id": "urn:journey:checkout",
      "label": "Checkout",
      "defaultEntryRef": "urn:entry:checkout",
      "entryRefs": ["urn:entry:checkout"],
      "stateRefs": ["urn:state:cart", "urn:state:payment", "urn:state:help"],
      "transitionRefs": ["urn:transition:cart-to-payment"],
      "outgoingTransitionGroupRefs": ["urn:outgoing-group:global-nav"]
    },
    {
      "@type": "JourneyEntry",
      "@id": "urn:entry:checkout",
      "stateRef": "urn:state:cart"
    },
    {
      "@type": "State",
      "@id": "urn:state:cart",
      "label": "Cart"
    },
    {
      "@type": "State",
      "@id": "urn:state:payment",
      "label": "Payment"
    },
    {
      "@type": "State",
      "@id": "urn:state:help",
      "label": "Help"
    },
    {
      "@type": "Transition",
      "@id": "urn:transition:cart-to-payment",
      "from": "urn:state:cart",
      "to": "urn:state:payment",
      "commandRef": "urn:command:checkout-action"
    },
    {
      "@type": "OutgoingTransition",
      "@id": "urn:outgoing:help",
      "to": "urn:state:help",
      "commandRef": "urn:command:help-action"
    },
    {
      "@type": "Command",
      "@id": "urn:command:checkout-action",
      "label": "Continue to payment"
    },
    {
      "@type": "Command",
      "@id": "urn:command:help-action",
      "label": "Open help"
    },
    {
      "@type": "OutgoingTransitionGroup",
      "@id": "urn:outgoing-group:global-nav",
      "outgoingTransitionRefs": ["urn:outgoing:help"]
    },
    {
      "@type": "Surface",
      "@id": "urn:surface:cart",
      "graphNodeRef": "urn:state:cart"
    },
    {
      "@type": "Surface",
      "@id": "urn:surface:checkout-action",
      "graphNodeRef": "urn:command:checkout-action"
    },
    {
      "@type": "Surface",
      "@id": "urn:surface:payment",
      "graphNodeRef": "urn:state:payment"
    },
    {
      "@type": "Surface",
      "@id": "urn:surface:help-action",
      "graphNodeRef": "urn:command:help-action"
    },
    {
      "@type": "Surface",
      "@id": "urn:surface:help",
      "graphNodeRef": "urn:state:help"
    },
    {
      "@type": "SurfaceInstance",
      "@id": "urn:surface-instance:cart",
      "surfaceRef": "urn:surface:cart"
    },
    {
      "@type": "SurfaceInstance",
      "@id": "urn:surface-instance:checkout-action",
      "surfaceRef": "urn:surface:checkout-action"
    },
    {
      "@type": "SurfaceInstance",
      "@id": "urn:surface-instance:payment",
      "surfaceRef": "urn:surface:payment"
    },
    {
      "@type": "SurfaceInstance",
      "@id": "urn:surface-instance:help-action",
      "surfaceRef": "urn:surface:help-action"
    },
    {
      "@type": "SurfaceInstance",
      "@id": "urn:surface-instance:help",
      "surfaceRef": "urn:surface:help"
    },
    {
      "@type": "JourneyExecution",
      "@id": "urn:execution:checkout-1"
    },
    {
      "@type": "RuntimeEvent",
      "@id": "urn:event:checkout-1:100",
      "executionId": "urn:execution:checkout-1",
      "surfaceInstanceRef": "urn:surface-instance:cart"
    },
    {
      "@type": "RuntimeEvent",
      "@id": "urn:event:checkout-1:150",
      "executionId": "urn:execution:checkout-1",
      "previousId": "urn:event:checkout-1:100",
      "surfaceInstanceRef": "urn:surface-instance:checkout-action"
    },
    {
      "@type": "RuntimeEvent",
      "@id": "urn:event:checkout-1:200",
      "executionId": "urn:execution:checkout-1",
      "previousId": "urn:event:checkout-1:150",
      "surfaceInstanceRef": "urn:surface-instance:payment"
    },
    {
      "@type": "RuntimeEvent",
      "@id": "urn:event:checkout-1:250",
      "executionId": "urn:execution:checkout-1",
      "previousId": "urn:event:checkout-1:200",
      "surfaceInstanceRef": "urn:surface-instance:help-action"
    },
    {
      "@type": "RuntimeEvent",
      "@id": "urn:event:checkout-1:300",
      "executionId": "urn:execution:checkout-1",
      "previousId": "urn:event:checkout-1:250",
      "surfaceInstanceRef": "urn:surface-instance:help"
    },
    {
      "@type": "JourneyMapping",
      "@id": "urn:mapping:checkout-1",
      "mappedRuntimeRef": "urn:execution:checkout-1",
      "mappedJourneyRef": "urn:journey:checkout",
      "mappedStepRef": [
        "urn:mapping:checkout-1:100",
        "urn:mapping:checkout-1:200",
        "urn:mapping:checkout-1:300"
      ]
    },
    {
      "@type": "MappedStep",
      "@id": "urn:mapping:checkout-1:100",
      "mappedEventRef": "urn:event:checkout-1:100",
      "mappedStateRef": "urn:state:cart"
    },
    {
      "@type": "MappedStep",
      "@id": "urn:mapping:checkout-1:200",
      "mappedEventRef": "urn:event:checkout-1:200",
      "observedAffordanceEventRef": "urn:event:checkout-1:150",
      "mappedStateRef": "urn:state:payment",
      "explainedByTransitionRef": "urn:transition:cart-to-payment"
    },
    {
      "@type": "MappedStep",
      "@id": "urn:mapping:checkout-1:300",
      "mappedEventRef": "urn:event:checkout-1:300",
      "observedAffordanceEventRef": "urn:event:checkout-1:250",
      "mappedStateRef": "urn:state:help",
      "explainedByTransitionRef": "urn:outgoing:help"
    }
  ]
}
{
  "@context": [
    "https://ujg.specs.openuji.org/tr/1.0-rc2/ns/context.jsonld",
    "https://ujg.specs.openuji.org/tr/1.0-rc2/ns/mapping.context.jsonld"
  ],
  "@id": "https://example.com/ujg/mapping/affordance-events.jsonld",
  "@type": "UJGDocument",
  "nodes": [
    {
      "@type": "Journey",
      "@id": "urn:journey:checkout",
      "label": "Checkout",
      "defaultEntryRef": "urn:entry:checkout",
      "entryRefs": ["urn:entry:checkout"],
      "stateRefs": ["urn:state:cart", "urn:state:payment", "urn:state:help"],
      "transitionRefs": ["urn:transition:cart-to-payment"],
      "outgoingTransitionGroupRefs": ["urn:outgoing-group:global-nav"]
    },
    {
      "@type": "JourneyEntry",
      "@id": "urn:entry:checkout",
      "stateRef": "urn:state:cart"
    },
    {
      "@type": "State",
      "@id": "urn:state:cart",
      "label": "Cart"
    },
    {
      "@type": "State",
      "@id": "urn:state:payment",
      "label": "Payment"
    },
    {
      "@type": "State",
      "@id": "urn:state:help",
      "label": "Help"
    },
    {
      "@type": "Transition",
      "@id": "urn:transition:cart-to-payment",
      "from": "urn:state:cart",
      "to": "urn:state:payment",
      "commandRef": "urn:command:checkout-action"
    },
    {
      "@type": "OutgoingTransition",
      "@id": "urn:outgoing:help",
      "to": "urn:state:help",
      "commandRef": "urn:command:help-action"
    },
    {
      "@type": "Command",
      "@id": "urn:command:checkout-action",
      "label": "Continue to payment"
    },
    {
      "@type": "Command",
      "@id": "urn:command:help-action",
      "label": "Open help"
    },
    {
      "@type": "OutgoingTransitionGroup",
      "@id": "urn:outgoing-group:global-nav",
      "outgoingTransitionRefs": ["urn:outgoing:help"]
    },
    {
      "@type": "Surface",
      "@id": "urn:surface:cart",
      "graphNodeRef": "urn:state:cart"
    },
    {
      "@type": "Surface",
      "@id": "urn:surface:checkout-action",
      "graphNodeRef": "urn:command:checkout-action"
    },
    {
      "@type": "Surface",
      "@id": "urn:surface:payment",
      "graphNodeRef": "urn:state:payment"
    },
    {
      "@type": "Surface",
      "@id": "urn:surface:help-action",
      "graphNodeRef": "urn:command:help-action"
    },
    {
      "@type": "Surface",
      "@id": "urn:surface:help",
      "graphNodeRef": "urn:state:help"
    },
    {
      "@type": "SurfaceInstance",
      "@id": "urn:surface-instance:cart",
      "surfaceRef": "urn:surface:cart"
    },
    {
      "@type": "SurfaceInstance",
      "@id": "urn:surface-instance:checkout-action",
      "surfaceRef": "urn:surface:checkout-action"
    },
    {
      "@type": "SurfaceInstance",
      "@id": "urn:surface-instance:payment",
      "surfaceRef": "urn:surface:payment"
    },
    {
      "@type": "SurfaceInstance",
      "@id": "urn:surface-instance:help-action",
      "surfaceRef": "urn:surface:help-action"
    },
    {
      "@type": "SurfaceInstance",
      "@id": "urn:surface-instance:help",
      "surfaceRef": "urn:surface:help"
    },
    {
      "@type": "JourneyExecution",
      "@id": "urn:execution:checkout-1"
    },
    {
      "@type": "RuntimeEvent",
      "@id": "urn:event:checkout-1:100",
      "executionId": "urn:execution:checkout-1",
      "surfaceInstanceRef": "urn:surface-instance:cart"
    },
    {
      "@type": "RuntimeEvent",
      "@id": "urn:event:checkout-1:150",
      "executionId": "urn:execution:checkout-1",
      "previousId": "urn:event:checkout-1:100",
      "surfaceInstanceRef": "urn:surface-instance:checkout-action"
    },
    {
      "@type": "RuntimeEvent",
      "@id": "urn:event:checkout-1:200",
      "executionId": "urn:execution:checkout-1",
      "previousId": "urn:event:checkout-1:150",
      "surfaceInstanceRef": "urn:surface-instance:payment"
    },
    {
      "@type": "RuntimeEvent",
      "@id": "urn:event:checkout-1:250",
      "executionId": "urn:execution:checkout-1",
      "previousId": "urn:event:checkout-1:200",
      "surfaceInstanceRef": "urn:surface-instance:help-action"
    },
    {
      "@type": "RuntimeEvent",
      "@id": "urn:event:checkout-1:300",
      "executionId": "urn:execution:checkout-1",
      "previousId": "urn:event:checkout-1:250",
      "surfaceInstanceRef": "urn:surface-instance:help"
    },
    {
      "@type": "JourneyMapping",
      "@id": "urn:mapping:checkout-1",
      "mappedRuntimeRef": "urn:execution:checkout-1",
      "mappedJourneyRef": "urn:journey:checkout",
      "mappedStepRef": [
        "urn:mapping:checkout-1:100",
        "urn:mapping:checkout-1:200",
        "urn:mapping:checkout-1:300"
      ]
    },
    {
      "@type": "MappedStep",
      "@id": "urn:mapping:checkout-1:100",
      "mappedEventRef": "urn:event:checkout-1:100",
      "mappedStateRef": "urn:state:cart"
    },
    {
      "@type": "MappedStep",
      "@id": "urn:mapping:checkout-1:200",
      "mappedEventRef": "urn:event:checkout-1:200",
      "observedAffordanceEventRef": "urn:event:checkout-1:150",
      "mappedStateRef": "urn:state:payment",
      "explainedByTransitionRef": "urn:transition:cart-to-payment"
    },
    {
      "@type": "MappedStep",
      "@id": "urn:mapping:checkout-1:300",
      "mappedEventRef": "urn:event:checkout-1:300",
      "observedAffordanceEventRef": "urn:event:checkout-1:250",
      "mappedStateRef": "urn:state:help",
      "explainedByTransitionRef": "urn:outgoing:help"
    }
  ]
}

urn:event:checkout-1:150 and urn:event:checkout-1:250 remain Runtime events, but they are not separate MappedStep records because their surfaces resolve to commands. The second and third mapped steps point back to those immediate predecessor events. The help outgoing transition is available through urn:outgoing-group:global-nav, but the group itself has no surface.

Copyright © 2026 the Contributors to the ujg/mapping/1.0-rc2, published by the User Journal Graph Community Group under the W3C Community Contributor License Agreement (CLA) . A human-readable summary is available.

generated by Speculator