| name | ujg-ed-modeling |
| description | Generate, review, correct, and reason about User Journey Graph JSON-LD for the Editor's Draft. Use when modeling UJG documents, checking vocabulary discipline, selecting modules, or correcting Core/Graph/Surface/Runtime/Mapping/Metrics/Experience/Localization/Observability and optional module separation, including Design System, Effect, Condition, Routing, and Artifact. |
UJG ED Modeling
Skill tree context
Target: Editor's Draft
Public spec URL: https://ujg.specs.openuji.org/ed
Scope: whole UJG document modeling across Core, Graph, Surface and Experience, Runtime, Mapping, Metrics, Localization, Observability, Experience Annotation, and optional modules
Module scope: whole target
Related generated skills:
- ujg-ed-core-modeling: Core module document containers, imports, top-level nodes, and extensions
- ujg-ed-graph-modeling: Graph module topology, journeys, states, transitions, exits, outgoing navigation, and indexes
- ujg-ed-design-system-modeling: Design System module semantics and its relationship to Graph and Surface
- ujg-ed-l10n-modeling: Localization module semantics for MessageBundle copy metadata and locale-switch metadata
- ujg-ed-observability-modeling: Observability module semantics for ObservationBinding, ObservationEvent input modality requirements, accessible-object locators, surface recognition contracts, and SurfaceInstanceResolver
When the task crosses module boundaries, read references/related-skills.md and references/skill-tree.json before continuing.
UJG ED Modeling Skill
Use this skill when generating, reviewing, correcting, or reasoning about User Journey Graph JSON-LD for the UJG Editor’s Draft.
Source of truth
Use the active Editor’s Draft unless the user explicitly asks for a dated snapshot:
https://ujg.specs.openuji.org/ed
Treat /ed as moving. Do not silently mix dated snapshots with current ED. Generate only terms defined by active ED contexts unless the user explicitly requests an extension.
Module selection
Select only required modules.
Core: document container and top-level nodes.
Graph: journeys, states, transitions, composition, exits, outgoing navigation, and indexes.
Surface: materialized surfaces for supported Graph nodes, concrete surface instances, surface attachments, touchpoints, human users, user references, channels, and composite-state touchpoint scopes.
Runtime: observed events, values, clicks, URLs, timestamps, payloads.
Mapping: state-observation steps resolved from Runtime through Surface to Graph, with optional immediately preceding affordance event references.
Metrics: metric observations, especially Mapping-derived counts and rates over resolved journey mappings.
Phase: journey-map Step and Phase grouping over Graph CompositeState nodes. Their
optional order values are display metadata only and must not determine Graph traversal, Mapping
step order, Runtime event order, occurrence, or phase start. Experience Annotation optionally adds
PainPoint annotations over those steps.
Localization: locale metadata, localized copy references, locale switch affordance metadata.
Observability: accessible-object recognition contracts for surfaces, using localized message bundles
for accessible names and descriptions, plus event-level input modality requirements.
Design System: design systems, components, templates, slots, token sources, and surface realizations.
Effect: declared side effects attached to Transition or OutgoingTransition edges, including generic produced and consumed resource references.
Condition: guarded transitions and conditional branch sets.
Routing: route, deep-link, path, fallback, guard, and parameter metadata attached to UJG nodes.
Artifact: portable resources referenced by Effect producedRefs and consumedRefs, including artifact-owned source and target touchpoint metadata; also a concrete EffectResource.
Core is required for UJG documents. Include Graph when modeling topology. Include Surface when using Surface, SurfaceInstance, Touchpoint, User, graphNodeRef, surfaceRef, compositeStateRefs, touchpointRefs, userRef, or channel. Include Phase when using Step, Phase, compositeStateRef, phaseRef, or order. Include Runtime only for observed behavior or traces. Include Mapping when resolving Runtime state observations through Surface to Graph, or deriving Step occurrence and Phase start, with JourneyMapping, MappedStep, mappedEventRef, mappedStateRef, observedAffordanceEventRef, or explainedByTransitionRef. Include Metrics when emitting MetricObservation records, Mapping-derived step counts, movement counts, rates, or aggregate metric values. Include Experience Annotation only when using PainPoint, painpointStepRefs, severity, or description. Include Localization only when using l10n terms such as l10n:targetLocale, copyRef, defaultLocale, fallbackLocales, or locales. Include Observability only when modeling ObservationBinding, observeSurfaceRef, ObservationEvent, requiredInputModalityProfileRefs, InputModalityProfile, inputModalityRefs, InputModality, SurfaceInstanceResolver, surfaceInstanceResolverRef, instanceKeyFeatureRef, AccessibleLocator, accessibleNameRef, or accessibleDescriptionRef; Observability also requires Localization for name and description bundles.
Include Design System only when using design-system terms such as DesignSystem, TokenSource, Component, Template, Slot, SurfaceRealization, SlotBinding, componentRef, templateRef, slotRef, targetSurfaceRef, or targetComponentRef. Include Effect only when declaring an Effect node, effectRef on a Transition or OutgoingTransition, or Effect producedRefs / consumedRefs; do not use Effect for Runtime payloads or implementation protocol details. Include Condition only when using Condition, ConditionSet, conditionRef, or conditionTransitionRefs; a Condition guards a Graph transition and must not replace the transition target. Include Routing only when using Route, routeRef, fallbackNodeRef, routeName, path, deepLink, guards, or params; Routing metadata must not create hidden traversal or repair Graph topology.
Include Artifact when using Artifact, sourceTouchpointRef, targetTouchpointRefs, or when an Effect produces or consumes an artifact. Include Surface too when artifact touchpoint refs point to Touchpoint nodes. Use sourceTouchpointRef and targetTouchpointRefs only on Artifact; effects use producedRefs and consumedRefs.
Do not use EffectResource as the only @type of a resource node; use a concrete resource type such as Artifact.
Do not include Runtime, Mapping, Metrics, Phase, Experience Annotation, Localization, Design System, Effect, Condition, Routing, or Artifact merely because screenshots, links, typed values, journey-map labels, pain points, counts, translated UI, design components, form logic, URLs, files, or multiple touchpoints are present. Screenshots can inform Graph structure, but Graph describes intended topology, not observed runtime facts.
Core JSON-LD rules
A UJGDocument is the document container. All addressable objects belong in top-level nodes.
Use extensions only on nodes, never on UJGDocument.
Do not put interoperable graph semantics in extensions. If a concept affects traversal, graph meaning, target resolution, or validation, use a defined module term.
Graph vocabulary discipline
Use only active ED Graph classes and properties.
Common classes: JourneyEntryIndex, Journey, JourneyEntry, LocalVertex, State, CompositeState, Transition, JourneyExit, OutgoingTransition, OutgoingTransitionGroup.
Common properties: label, tags, defaultEntryRef, entryRefs, stateRef, stateRefs, transitionRefs, exitRefs, outgoingTransitionGroupRefs, from, to, toCurrentState, toEntryRef, fromExitRef, subjourneyId, outgoingTransitionRefs.
Do not invent Graph fields such as startState, states, transitions, toJourney, toState, trigger, outcome, eventType, selector, Graph-native url, or RuntimeTrace.
Modeling bias
Default to the shallowest valid graph.
Start flat. Add nesting only when nesting preserves meaning that a flatter model would lose.
Prefer ordinary State and local Transition for stable conditions on the same page, route, surface, modal, panel, or screen.
Same surface plus stable alternate UI usually means same journey.
Do not introduce CompositeState, JourneyExit, or fromExitRef merely to make the graph look complete, represent ordinary component outcomes, or connect screenshots.
Use nesting only when the child flow is opaque, reusable, independently zoomable, has substantial hidden topology, or completes before genuine parent-owned continuation.
A child outcome that leaves the current surface or selects an external/server-chosen destination may justify nesting only when the parent actually treats that completed outcome as a child result.
A flatter model wins when it preserves the same meaning.
Model decision stability
Classify each modeled item before writing JSON-LD: index entry, page/surface entry, same-journey state, local transition, child journey, exported child outcome, outgoing affordance, current-state affordance, runtime observation, experience annotation, localization metadata, design-system realization, effect side effect, guarded transition, route metadata, artifact, or distributed touchpoint metadata.
Do not mix roles accidentally.
If a component is modeled as a child journey, keep the full pattern coherent: parent CompositeState; exactly one subjourneyId; no child states in parent stateRefs; child states and transitions stay in child journey; child traversal starts at the child journey's defaultEntryRef unless the parent transition into the composite declares toEntryRef; exported outcome is a child-local terminal JourneyExit listed in child exitRefs; parent continuation is a parent-local Transition from the CompositeState to another parent-local local vertex using fromExitRef.
Either keep the complete child-journey pattern or fold it back into same-journey states. Do not keep only part of the pattern.
Do not create extra parent/root exits merely to connect pages, screenshots, or observed order.
JourneyEntryIndex
Use JourneyEntryIndex for catalogues, route maps, product-surface indexes, documentation indexes, or collections of known entry states.
A JourneyEntryIndex is not a traversable journey. Do not infer order, reachability, progression, parent continuation, or user path from stateRefs.
Do not replace a JourneyEntryIndex with a fake root Journey.
For a page-level index, list page, route, surface, or component entry states. Do not list child journey states unless the index is explicitly component-level.
Journey
Use Journey for local traversable topology.
A Journey must have an IRI @id, exactly one defaultEntryRef, at least one entryRefs value, and at least one stateRefs value. It may have transitionRefs, exitRefs, and outgoingTransitionGroupRefs. Its local vertices are stateRefs union exitRefs.
Each entryRefs value must reference a JourneyEntry. The defaultEntryRef must reference one of those entries.
A JourneyEntry must have exactly one stateRef pointing to a State or CompositeState listed in the same journey's stateRefs. A JourneyEntry is not a local vertex and must not be used as Transition.from or Transition.to.
A journey owns stable states in its local scope, local progression, local outgoing affordances, nested journeys reachable inside its scope, and exported exits when a parent reacts to completed child outcomes.
Do not use Journey as a fake root index.
Do not list a destination page, external result, linked document, or later observed screen in a journey’s stateRefs merely because it is reachable.
Do not split one page into multiple journeys merely because it has sections, a form, success, failure, empty, loaded, or validation states. Keep same-surface states in the same journey unless there is a real nested flow.
State and CompositeState
Use State for a stable observable condition.
Use Surface userRef on Journey to assign the journey to a human user. Entries, states, transitions, exits, outgoing groups, and child journeys inherit the effective user unless they declare their own userRef.
Use Surface Touchpoint.compositeStateRefs to attach a touchpoint to meaningful CompositeState boundaries. Do not put touchpoint identity on Surface or individual Graph states.
Same-journey states usually include page sections, form ready, input-present condition, validation error, submission success/failure, empty/populated result, loading complete, confirmation message, inline error panel, and simple same-page modal/dialog.
Use CompositeState only when a parent journey contains or exposes a nested journey.
A CompositeState must reference exactly one child journey with subjourneyId. Place it where the nested journey becomes reachable.
A parent journey must not list child journey states directly.
Do not create a CompositeState merely because a component has internal labels, fields, empty, success, failure, submitted, completed, cancelled, valid, or invalid states.
Before using CompositeState, ask whether ordinary State would preserve the same graph meaning. If yes, use State.
Transition
Use Transition for local intended topology inside one journey.
A Transition must have from and to. from must be listed in the same journey's stateRefs. to must be listed in the same journey's stateRefs or exitRefs. Never use a JourneyExit or JourneyEntry as from.
Use Transition for local page order, local state progression, local rendering progression, terminal progression to a JourneyExit, parent-owned continuation between parent-local states, parent entry into a child journey using toEntryRef, and parent continuation after child exit using fromExitRef.
Do not use Transition for runtime facts, clicks, URLs, selectors, ordinary link metadata, header navigation, footer navigation, language switchers, result links, or ordinary external navigation.
Do not reference child states from a parent transition. Do not create parent transitions merely to connect observed screens.
JourneyEntry, JourneyExit, and boundary refs
Use JourneyEntry to name valid entry points into a journey. Top-level traversal begins at defaultEntryRef.stateRef.
Use toEntryRef only on a parent-local transition whose to is the corresponding CompositeState. The toEntryRef value selects a JourneyEntry listed in the child journey referenced by that composite's subjourneyId. If toEntryRef is absent, child traversal starts at the child journey's defaultEntryRef.
Use JourneyExit only when a parent journey must react to a completed child outcome, or when a journey needs to expose a terminal completion contract.
A JourneyExit is a terminal local vertex, not a State. It is listed in exactly one journey's exitRefs.
A child exports an outcome by transitioning directly to a child-local JourneyExit listed in the child journey's exitRefs.
Use fromExitRef only on a parent-local transition from the corresponding CompositeState to another parent-local local vertex.
Do not use exits for clicks, links, menu choices, selected values, header/footer navigation, language switches, ordinary navigation, runtime observations, simple same-page result states, convenient page-to-page connection, or screenshot order.
Before using JourneyExit, ask whether ordinary local Transition would preserve the same meaning. If yes, use local Transition.
Use exactly one exit per actual exported child outcome. Do not add extra parent/root exits unless another enclosing parent genuinely reacts to the parent’s completion.
Forms and result states
For a simple form on a page, keep the form and stable result states in the same page journey.
Preferred pattern:
Form -> Success
Form -> Failure
Failure -> Form
Use OutgoingTransition for actions that navigate away from a result state.
Use a child journey for a form only when it is reusable, independently zoomable, opaque to the parent, has substantial hidden topology, or completes before genuine parent-owned continuation.
A form outcome that leaves the current surface or selects an external/server-chosen destination may justify a child journey only when the parent actually treats that completed outcome as a child result.
Do not create a child journey merely because a form has empty, query, valid, invalid, submitted, success, failure, completed, or cancelled states.
If submitted form output stays on the same page, keep result states in the same journey.
If submit navigates away, decide whether it is ordinary outgoing navigation or parent-owned continuation. Use child exit plus fromExitRef only when the parent genuinely continues after an opaque child outcome.
OutgoingTransition
Use OutgoingTransition for navigation affordances exposed by a state or shared group.
Use OutgoingTransitionGroup for shared affordance sets such as header, footer, utility navigation, repeated CTAs, or language switchers.
Do not use OutgoingTransition as a substitute for ordinary local Transition.
If the source state and target state are both local vertices of the same journey, and the user action represents recovery, retry, back, next, validation handling, or normal progression inside that journey, model it as Transition, not OutgoingTransition.
Use OutgoingTransition when the affordance leaves the local progression context: for example, help, support, account recovery, external document, another route, another page, another journey entry, or a distinct modeled destination that is not part of the current journey’s local topology.
An OutgoingTransition must declare exactly one target mechanism: either one to, or toCurrentState: true.
Do not declare both. Do not omit both. Do not use toCurrentState: false.
Use state-scoped outgoingTransitionRefs only on ordinary State nodes. Do not put outgoingTransitionRefs on CompositeState or JourneyExit.
Do not inject outgoing transitions from JourneyExit.
Localization and locale switchers
Use Localization for localization metadata, not graph topology.
Use l10n:targetLocale only with the Localization context. It declares locale metadata for an outgoing affordance; it does not define traversal.
For a locale switch that preserves the current graph state:
{
"@type": "OutgoingTransition",
"@id": "urn:example:ot:locale-en",
"label": "English",
"toCurrentState": true,
"l10n:targetLocale": "en"
}
For a locale switch that targets a distinct modeled state, use to and optionally l10n:targetLocale.
Do not create duplicate locale-specific states unless locale changes graph topology, available states, journeys, or affordances.
Do not model locale choice in Runtime unless the task asks for observed events, selected values, timestamps, or payloads.
Runtime, Surface, and Phase separation
Graph models intended topology. Runtime models observed behavior.
Keep runtime facts out of Graph, including typed query, input value, clicked element, submitted value, selected result, timestamp, URL at interaction time, DOM selector, analytics metadata, runtime locale selection, and payload.
For Runtime traces, a RuntimeEvent must identify the execution with executionId and the observed concrete occurrence with surfaceInstanceRef. Resolve Graph meaning through SurfaceInstance.surfaceRef and the referenced Surface.graphNodeRef. Use previousId only to reconstruct observed event order.
To derive user perspective for an observed state occurrence, resolve RuntimeEvent.surfaceInstanceRef -> SurfaceInstance.surfaceRef -> Surface.graphNodeRef, then use the graph node's effective user from userRef or inherited journey user assignment. Do not add collector or observer attribution fields to Runtime; keep collector/source metadata in payload or extensions.
Use Phase Step and Phase only for journey-map grouping over Graph CompositeState
nodes. Treat their optional order values as display metadata, not traversal, Mapping step order, or
Runtime occurrence. Use Experience Annotation PainPoint only for qualitative friction annotations.
These annotations must not change Graph traversal or repair missing Graph topology.
Page and route modeling
Use JourneyEntryIndex to list known page, route, surface, or journey entry states.
A page or route can be a CompositeState only if it exposes a meaningful page-level Journey.
For simple pages with no internal topology, a plain State in the index is enough.
Shared header, footer, language switchers, and result links should not turn a website into one traversable root journey.
Do not create a fake site-wide root journey merely to connect pages reached by links, search results, headers, footers, language switchers, or screenshot order.
Locality rule
Model structure in the lowest journey that owns it.
Ask: where is this condition observable; where is this affordance available; which journey owns this progression; is it local topology, outgoing navigation, current-state targeting, nested composition, index entry, completed child outcome, runtime observation, experience annotation, or localization metadata; would a flatter model lose meaning?
A later screenshot is not automatically a next state.
A destination normally belongs to the destination journey or index as an outgoing target, not to the source journey’s local topology.
When evidence is insufficient, say so instead of inventing structure.
Decision procedure
- Identify requested ED version.
- Select required modules.
- Separate visible stable states from runtime-only observations.
- Identify shared outgoing navigation and current-state affordances.
- Identify needed page, route, surface, or component entries.
- Decide whether each surface needs
Journey or plain State.
- Keep same-surface conditions in one journey unless nesting preserves meaning.
- Use child journeys only for real nested flows.
- If using a child journey, preserve the full child-journey invariant.
- Use exits only for exported child outcomes.
- Use
OutgoingTransition for ordinary navigation.
- Use
toCurrentState: true only when the effective graph state is preserved.
- Use
l10n:targetLocale only as Localization metadata.
- Use Effect, Condition, Routing, and Artifact only as defined semantic attachments, not as hidden graph edges.
- Re-check that no parent lists child states directly.
- Re-check that no fake root journey connects observed screens.
- Re-check that Runtime, Surface experience annotations, Experience Annotation, Localization, and optional modules were not confused with Graph topology.
Output workflow
When generating JSON-LD:
- State the modules used.
- Generate strict ED JSON-LD.
- Provide a short self-audit.
- State uncertainty explicitly.
Before returning JSON-LD, check: only necessary contexts; all nodes top-level; defined terms only; JourneyEntryIndex not traversable; Journey only local topology; each Journey has defaultEntryRef, entryRefs, and stateRefs; each JourneyEntry.stateRef is in the same journey's stateRefs; transition endpoints local; Transition.from in stateRefs; Transition.to in stateRefs or exitRefs; no child states in parent transitions; each CompositeState has one subjourneyId; forms not child journeys by default; toEntryRef targets a child journey entry; child exits complete when used; fromExitRef parent-local; no fake root/parent exits; outgoing navigation uses OutgoingTransition; shared navigation uses OutgoingTransitionGroup; each outgoing transition has exactly one of to or toCurrentState: true; state-scoped outgoingTransitionRefs only on ordinary State; l10n terms only with Localization context; runtime facts not in Graph; Effect, Condition, Routing, and Artifact do not create hidden graph edges; artifact touchpoint refs stay on Artifact; Surface experience and Experience Annotation annotations do not affect traversal; graph is shallowest valid model.
Anti-overengineering and uncertainty
Before finalizing, simplify.
Ask whether a composite can be a state, a child journey can be folded into the parent, an exit can be a local transition, parent continuation is really ordinary navigation, a destination is really local topology, a locale change is topology or metadata, screenshots are being connected as structure, runtime is being modeled as Graph, or toCurrentState is being used for convenience instead of semantics.
If a flatter model preserves the same meaning, use it.
If evidence is incomplete, say what is inferred and what is unknown. Do not invent hidden flows, failure states, external destinations, server decisions, locale-specific pages, runtime events, or nested journeys.
When screenshots are provided, distinguish visible stable states, inferred local transitions, shared outgoing navigation, current-state outgoing affordances, localization metadata, unavailable states, runtime-only observations, and experience-only annotations.