@unified-product-graph/core 0.9.1 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1442,10 +1442,10 @@ declare const UPG_EDGE_CATALOG: {
1442
1442
  source_type: string;
1443
1443
  target_type: string;
1444
1444
  };
1445
- journey_phase_has_step: {
1445
+ journey_phase_spans_journey_step: {
1446
1446
  forward_verb: string;
1447
1447
  reverse_verb: string;
1448
- classification: "hierarchy";
1448
+ classification: "cross-domain";
1449
1449
  source_type: string;
1450
1450
  target_type: string;
1451
1451
  };
@@ -1456,6 +1456,20 @@ declare const UPG_EDGE_CATALOG: {
1456
1456
  source_type: string;
1457
1457
  target_type: string;
1458
1458
  };
1459
+ journey_action_surfaces_need: {
1460
+ forward_verb: string;
1461
+ reverse_verb: string;
1462
+ classification: "cross-domain";
1463
+ source_type: string;
1464
+ target_type: string;
1465
+ };
1466
+ journey_action_realised_by_feature: {
1467
+ forward_verb: string;
1468
+ reverse_verb: string;
1469
+ classification: "cross-domain";
1470
+ source_type: string;
1471
+ target_type: string;
1472
+ };
1459
1473
  product_systematised_in_design_system: {
1460
1474
  forward_verb: string;
1461
1475
  reverse_verb: string;
@@ -10694,14 +10708,19 @@ interface UserJourneyProperties {
10694
10708
  /** Scenario context */
10695
10709
  scenario?: string;
10696
10710
  }
10697
- /** Phase within a user journey. Groups journey steps into stages.
10711
+ /** Phase within a user journey. A temporal BAND over the journey's step
10712
+ * timeline, not a container that owns steps (UPG-663). A journey map renders
10713
+ * phases as a horizontal band above one timeline; a phase spans a range of
10714
+ * that timeline. Steps belong to the journey, not the phase.
10698
10715
  *
10699
10716
  * Per UPG principle P14, structural relationships are edges:
10700
- * parent journey: `user_journey_contains_journey_phase`
10701
- * contained steps: `journey_phase_contains_journey_step`
10702
- * sequenced phase: ordering via `phase_order` here; the
10703
- * `journey_phase_precedes_journey_phase` edge captures the explicit
10704
- * phase-to-phase chain when it matters for branching journeys.
10717
+ * parent journey: `user_journey_passes_through_journey_phase`
10718
+ * (the journey carries the phase as a non-owning band overlay)
10719
+ * spanned steps: `journey_phase_spans_journey_step` (non-owning; the steps
10720
+ * are owned by `user_journey_contains_journey_step`, mirroring the
10721
+ * marketing precedent `customer_journey_stage_spans_journey_step`)
10722
+ * phase ordering: the `phase_order` scalar below (the convention shared
10723
+ * with `journey_step.step_order` and `journey_action.action_order`)
10705
10724
  *
10706
10725
  * @example
10707
10726
  * const properties: JourneyPhaseProperties = {
@@ -10739,16 +10758,27 @@ interface JourneyPhaseProperties {
10739
10758
  */
10740
10759
  timeframe?: string;
10741
10760
  }
10742
- /** Single step within a user journey.
10761
+ /** Single step within a user journey. A user-moment on the journey's single
10762
+ * step timeline. Steps belong to the journey via
10763
+ * `user_journey_contains_journey_step` (the stable 0.1.0 spine); a
10764
+ * `journey_phase` spans a range of them but does not own them (UPG-663).
10743
10765
  *
10744
10766
  * @example
10745
10767
  * const properties: JourneyStepProperties = {
10768
+ * step_order: 1,
10746
10769
  * touchpoint: 'in-product',
10747
10770
  * channel: 'in-product',
10748
10771
  * emotion_score: 4,
10749
10772
  * }
10750
10773
  */
10751
10774
  interface JourneyStepProperties {
10775
+ /**
10776
+ * Display order within the journey's step timeline (0-indexed). The scalar
10777
+ * ordering convention shared with `journey_phase.phase_order` and
10778
+ * `journey_action.action_order` (UPG-663). For branching journeys, the
10779
+ * explicit `journey_step_precedes_journey_step` edge captures the chain.
10780
+ */
10781
+ step_order?: number;
10752
10782
  /** Interaction touchpoint */
10753
10783
  touchpoint?: string;
10754
10784
  /** Channel (e.g. "web", "email", "in-store") */
@@ -10763,16 +10793,24 @@ interface JourneyStepProperties {
10763
10793
  owner?: string;
10764
10794
  }
10765
10795
  /** Discrete action at a journey step, classified by service layer.
10796
+ * The finest blueprint layer (a service-blueprint row within a moment).
10766
10797
  * Enables service blueprint rendering and cross-domain linking.
10767
10798
  *
10768
10799
  * Per UPG principle P14, structural relationships are edges:
10769
- * parent step: `journey_step_contains_journey_action`
10770
- * performing system: `service_performs_journey_action` (the `system` property
10771
- * is a display label; the canonical link is the edge when a `service` entity exists)
10772
- * downstream pain: `journey_action_surfaces_need`
10800
+ * parent step: `journey_step_has_action` (the step owns its actions)
10801
+ * downstream need: `journey_action_surfaces_need`. Opportunity discovery
10802
+ * routes through `need`, which reaches `opportunity` via
10803
+ * `opportunity_addresses_need`; the `pain_score` / `opportunity_score`
10804
+ * scalars below are blueprint-cell diagnostics that fuel that discovery.
10805
+ * realising feature: `journey_action_realised_by_feature`
10806
+ *
10807
+ * The `system` property is a display label naming the performing system; when
10808
+ * a `service` entity exists, model the relationship structurally rather than
10809
+ * relying on the label.
10773
10810
  *
10774
10811
  * @example
10775
10812
  * const properties: JourneyActionProperties = {
10813
+ * action_order: 0,
10776
10814
  * layer: 'user',
10777
10815
  * action_description: 'User pastes a meeting transcript into the empty canvas',
10778
10816
  * channel: 'in-app',
@@ -10784,6 +10822,13 @@ interface JourneyStepProperties {
10784
10822
  * }
10785
10823
  */
10786
10824
  interface JourneyActionProperties {
10825
+ /**
10826
+ * Display order of this action within its step (0-indexed). The scalar
10827
+ * ordering convention shared with `journey_phase.phase_order` and
10828
+ * `journey_step.step_order` (UPG-663). Orders the service-blueprint rows
10829
+ * within a single moment.
10830
+ */
10831
+ action_order?: number;
10787
10832
  /** Service layer */
10788
10833
  layer: 'user' | 'frontstage' | 'backstage' | 'support';
10789
10834
  /** Plain-language description. Primary content of the action. */
@@ -18005,7 +18050,7 @@ type UPGNode<T extends keyof UPGPropertyMap = keyof UPGPropertyMap> = UPGBaseNod
18005
18050
  * AUTO-GENERATED by scripts/generate-property-registry.ts
18006
18051
  * Do not edit manually. Run: npx tsx scripts/generate-property-registry.ts
18007
18052
  *
18008
- * Generated: 2026-06-09T14:25:02.253Z
18053
+ * Generated: 2026-06-09T16:53:52.006Z
18009
18054
  * Entity types with properties: 316
18010
18055
  */
18011
18056
  interface PropertyDefinition {
@@ -20446,7 +20491,7 @@ declare function isCanonical(text: string): boolean;
20446
20491
  * it stamps the `upg_version` field of every `.upg` file written by the SDK.
20447
20492
  * The `check:version-lockstep` gate enforces this at release time.
20448
20493
  */
20449
- declare const UPG_VERSION: "0.9.1";
20494
+ declare const UPG_VERSION: "0.9.2";
20450
20495
  /**
20451
20496
  * The `.upg` JSON document format version. Written to the `upg_version` field.
20452
20497
  * Evolves independently from `UPG_VERSION` (the catalogue version).
package/dist/index.d.ts CHANGED
@@ -1442,10 +1442,10 @@ declare const UPG_EDGE_CATALOG: {
1442
1442
  source_type: string;
1443
1443
  target_type: string;
1444
1444
  };
1445
- journey_phase_has_step: {
1445
+ journey_phase_spans_journey_step: {
1446
1446
  forward_verb: string;
1447
1447
  reverse_verb: string;
1448
- classification: "hierarchy";
1448
+ classification: "cross-domain";
1449
1449
  source_type: string;
1450
1450
  target_type: string;
1451
1451
  };
@@ -1456,6 +1456,20 @@ declare const UPG_EDGE_CATALOG: {
1456
1456
  source_type: string;
1457
1457
  target_type: string;
1458
1458
  };
1459
+ journey_action_surfaces_need: {
1460
+ forward_verb: string;
1461
+ reverse_verb: string;
1462
+ classification: "cross-domain";
1463
+ source_type: string;
1464
+ target_type: string;
1465
+ };
1466
+ journey_action_realised_by_feature: {
1467
+ forward_verb: string;
1468
+ reverse_verb: string;
1469
+ classification: "cross-domain";
1470
+ source_type: string;
1471
+ target_type: string;
1472
+ };
1459
1473
  product_systematised_in_design_system: {
1460
1474
  forward_verb: string;
1461
1475
  reverse_verb: string;
@@ -10694,14 +10708,19 @@ interface UserJourneyProperties {
10694
10708
  /** Scenario context */
10695
10709
  scenario?: string;
10696
10710
  }
10697
- /** Phase within a user journey. Groups journey steps into stages.
10711
+ /** Phase within a user journey. A temporal BAND over the journey's step
10712
+ * timeline, not a container that owns steps (UPG-663). A journey map renders
10713
+ * phases as a horizontal band above one timeline; a phase spans a range of
10714
+ * that timeline. Steps belong to the journey, not the phase.
10698
10715
  *
10699
10716
  * Per UPG principle P14, structural relationships are edges:
10700
- * parent journey: `user_journey_contains_journey_phase`
10701
- * contained steps: `journey_phase_contains_journey_step`
10702
- * sequenced phase: ordering via `phase_order` here; the
10703
- * `journey_phase_precedes_journey_phase` edge captures the explicit
10704
- * phase-to-phase chain when it matters for branching journeys.
10717
+ * parent journey: `user_journey_passes_through_journey_phase`
10718
+ * (the journey carries the phase as a non-owning band overlay)
10719
+ * spanned steps: `journey_phase_spans_journey_step` (non-owning; the steps
10720
+ * are owned by `user_journey_contains_journey_step`, mirroring the
10721
+ * marketing precedent `customer_journey_stage_spans_journey_step`)
10722
+ * phase ordering: the `phase_order` scalar below (the convention shared
10723
+ * with `journey_step.step_order` and `journey_action.action_order`)
10705
10724
  *
10706
10725
  * @example
10707
10726
  * const properties: JourneyPhaseProperties = {
@@ -10739,16 +10758,27 @@ interface JourneyPhaseProperties {
10739
10758
  */
10740
10759
  timeframe?: string;
10741
10760
  }
10742
- /** Single step within a user journey.
10761
+ /** Single step within a user journey. A user-moment on the journey's single
10762
+ * step timeline. Steps belong to the journey via
10763
+ * `user_journey_contains_journey_step` (the stable 0.1.0 spine); a
10764
+ * `journey_phase` spans a range of them but does not own them (UPG-663).
10743
10765
  *
10744
10766
  * @example
10745
10767
  * const properties: JourneyStepProperties = {
10768
+ * step_order: 1,
10746
10769
  * touchpoint: 'in-product',
10747
10770
  * channel: 'in-product',
10748
10771
  * emotion_score: 4,
10749
10772
  * }
10750
10773
  */
10751
10774
  interface JourneyStepProperties {
10775
+ /**
10776
+ * Display order within the journey's step timeline (0-indexed). The scalar
10777
+ * ordering convention shared with `journey_phase.phase_order` and
10778
+ * `journey_action.action_order` (UPG-663). For branching journeys, the
10779
+ * explicit `journey_step_precedes_journey_step` edge captures the chain.
10780
+ */
10781
+ step_order?: number;
10752
10782
  /** Interaction touchpoint */
10753
10783
  touchpoint?: string;
10754
10784
  /** Channel (e.g. "web", "email", "in-store") */
@@ -10763,16 +10793,24 @@ interface JourneyStepProperties {
10763
10793
  owner?: string;
10764
10794
  }
10765
10795
  /** Discrete action at a journey step, classified by service layer.
10796
+ * The finest blueprint layer (a service-blueprint row within a moment).
10766
10797
  * Enables service blueprint rendering and cross-domain linking.
10767
10798
  *
10768
10799
  * Per UPG principle P14, structural relationships are edges:
10769
- * parent step: `journey_step_contains_journey_action`
10770
- * performing system: `service_performs_journey_action` (the `system` property
10771
- * is a display label; the canonical link is the edge when a `service` entity exists)
10772
- * downstream pain: `journey_action_surfaces_need`
10800
+ * parent step: `journey_step_has_action` (the step owns its actions)
10801
+ * downstream need: `journey_action_surfaces_need`. Opportunity discovery
10802
+ * routes through `need`, which reaches `opportunity` via
10803
+ * `opportunity_addresses_need`; the `pain_score` / `opportunity_score`
10804
+ * scalars below are blueprint-cell diagnostics that fuel that discovery.
10805
+ * realising feature: `journey_action_realised_by_feature`
10806
+ *
10807
+ * The `system` property is a display label naming the performing system; when
10808
+ * a `service` entity exists, model the relationship structurally rather than
10809
+ * relying on the label.
10773
10810
  *
10774
10811
  * @example
10775
10812
  * const properties: JourneyActionProperties = {
10813
+ * action_order: 0,
10776
10814
  * layer: 'user',
10777
10815
  * action_description: 'User pastes a meeting transcript into the empty canvas',
10778
10816
  * channel: 'in-app',
@@ -10784,6 +10822,13 @@ interface JourneyStepProperties {
10784
10822
  * }
10785
10823
  */
10786
10824
  interface JourneyActionProperties {
10825
+ /**
10826
+ * Display order of this action within its step (0-indexed). The scalar
10827
+ * ordering convention shared with `journey_phase.phase_order` and
10828
+ * `journey_step.step_order` (UPG-663). Orders the service-blueprint rows
10829
+ * within a single moment.
10830
+ */
10831
+ action_order?: number;
10787
10832
  /** Service layer */
10788
10833
  layer: 'user' | 'frontstage' | 'backstage' | 'support';
10789
10834
  /** Plain-language description. Primary content of the action. */
@@ -18005,7 +18050,7 @@ type UPGNode<T extends keyof UPGPropertyMap = keyof UPGPropertyMap> = UPGBaseNod
18005
18050
  * AUTO-GENERATED by scripts/generate-property-registry.ts
18006
18051
  * Do not edit manually. Run: npx tsx scripts/generate-property-registry.ts
18007
18052
  *
18008
- * Generated: 2026-06-09T14:25:02.253Z
18053
+ * Generated: 2026-06-09T16:53:52.006Z
18009
18054
  * Entity types with properties: 316
18010
18055
  */
18011
18056
  interface PropertyDefinition {
@@ -20446,7 +20491,7 @@ declare function isCanonical(text: string): boolean;
20446
20491
  * it stamps the `upg_version` field of every `.upg` file written by the SDK.
20447
20492
  * The `check:version-lockstep` gate enforces this at release time.
20448
20493
  */
20449
- declare const UPG_VERSION: "0.9.1";
20494
+ declare const UPG_VERSION: "0.9.2";
20450
20495
  /**
20451
20496
  * The `.upg` JSON document format version. Written to the `upg_version` field.
20452
20497
  * Evolves independently from `UPG_VERSION` (the catalogue version).
package/dist/index.js CHANGED
@@ -1292,8 +1292,24 @@ var UPG_EDGE_CATALOG = {
1292
1292
  journey_step_realised_by_feature: { forward_verb: "realised_by", reverse_verb: "realises", classification: "cross-domain", source_type: "journey_step", target_type: "feature" },
1293
1293
  opportunity_improves_user_journey: { forward_verb: "improves", reverse_verb: "improved_by", classification: "cross-domain", source_type: "opportunity", target_type: "user_journey" },
1294
1294
  user_journey_passes_through_journey_phase: { forward_verb: "passes_through", reverse_verb: "is_phase_of", classification: "hierarchy", source_type: "user_journey", target_type: "journey_phase" },
1295
- journey_phase_has_step: { forward_verb: "has_step", reverse_verb: "is_step_in", classification: "hierarchy", source_type: "journey_phase", target_type: "journey_step" },
1295
+ // (since v0.9.2, UPG-663) A journey_phase is a temporal BAND over the
1296
+ // journey's single step timeline, not a container that owns steps. Steps
1297
+ // belong to the journey via `user_journey_contains_journey_step` (the stable
1298
+ // 0.1.0 spine); a phase merely SPANS a range of them. Mirrors the marketing
1299
+ // precedent `customer_journey_stage_spans_journey_step`. Renamed from the
1300
+ // owning `journey_phase_has_step` (hierarchy) so a step has exactly one
1301
+ // containment parent. See UPG_EDGE_MIGRATIONS['0.9.2'].
1302
+ journey_phase_spans_journey_step: { forward_verb: "spans", reverse_verb: "spanned_by", classification: "cross-domain", source_type: "journey_phase", target_type: "journey_step" },
1296
1303
  journey_step_has_action: { forward_verb: "has_action", reverse_verb: "is_action_in", classification: "hierarchy", source_type: "journey_step", target_type: "journey_action" },
1304
+ // (since v0.9.2, UPG-663) journey_action outbound edges. Fixes the
1305
+ // discovery dead-end (D2). The finest blueprint layer carries pain_score /
1306
+ // opportunity_score "to drive opportunity discovery" but previously had zero
1307
+ // outbound edges. Opportunity discovery routes through `need` (mirroring
1308
+ // `journey_step_reveals_need`), which already reaches `opportunity` via the
1309
+ // user chain; the action does not link an opportunity directly. The feature
1310
+ // edge mirrors `journey_step_realised_by_feature` one level deeper.
1311
+ journey_action_surfaces_need: { forward_verb: "surfaces", reverse_verb: "surfaced_in", classification: "cross-domain", source_type: "journey_action", target_type: "need" },
1312
+ journey_action_realised_by_feature: { forward_verb: "realised_by", reverse_verb: "realises", classification: "cross-domain", source_type: "journey_action", target_type: "feature" },
1297
1313
  // 2.5 UI System Domain
1298
1314
  product_systematised_in_design_system: { forward_verb: "systematised_in", reverse_verb: "systematises", classification: "hierarchy", source_type: "product", target_type: "design_system" },
1299
1315
  product_built_with_design_component: { forward_verb: "built_with", reverse_verb: "built_for", classification: "hierarchy", source_type: "product", target_type: "design_component" },
@@ -3051,8 +3067,13 @@ var UPG_VALID_CHILDREN = {
3051
3067
  // parallel to `observation: ['quote']`. Research-synthesis canon.
3052
3068
  // Pairs with `insight_evidenced_by_quote` in the edge catalog.
3053
3069
  // ── Design hierarchy ────────────────────────────────────────────────────────
3070
+ // (UPG-663, v0.9.2) A user_journey owns its steps (the stable 0.1.0 spine)
3071
+ // and carries phases as a non-owning band overlay. A journey_phase is NO
3072
+ // LONGER a containment parent of journey_step: it SPANS steps via the
3073
+ // `journey_phase_spans_journey_step` edge (mirroring the marketing
3074
+ // `customer_journey_stage_spans_journey_step` precedent), so each step has
3075
+ // exactly one containment parent and the journey has one canonical step list.
3054
3076
  user_journey: ["journey_step", "journey_phase"],
3055
- journey_phase: ["journey_step"],
3056
3077
  journey_step: ["journey_action"],
3057
3078
  // v0.5.8 (UPG-528 Part 2d): insights own their evidencing quotes;
3058
3079
  // parallel to `observation: ['quote']`. Research-synthesis canon
@@ -7605,6 +7626,20 @@ function getSplitMigrations(fromVersion, toVersion) {
7605
7626
  return result;
7606
7627
  }
7607
7628
  var UPG_EDGE_MIGRATIONS = {
7629
+ "0.9.2": [
7630
+ // (since v0.9.2, UPG-663) Journey-model disambiguation. A journey_phase
7631
+ // is a temporal BAND over the journey's single step timeline, not a
7632
+ // container that owns steps. The owning hierarchy edge
7633
+ // `journey_phase_has_step` is renamed to the non-owning
7634
+ // `journey_phase_spans_journey_step` (mirroring the marketing precedent
7635
+ // `customer_journey_stage_spans_journey_step`). Steps stay owned by the
7636
+ // journey via `user_journey_contains_journey_step` (the stable 0.1.0
7637
+ // spine), so each step keeps a single containment parent and the journey
7638
+ // renders one canonical step list. Endpoints are unchanged
7639
+ // (journey_phase → journey_step); only the edge key and its grammar
7640
+ // (verb has_step → spans, classification hierarchy → cross-domain) change.
7641
+ { kind: "rename", from: "journey_phase_has_step", to: "journey_phase_spans_journey_step", requires_source_type: "journey_phase", requires_target_type: "journey_step", reason: "Journey-model disambiguation (UPG-663): a phase spans steps, it does not own them. The phase to step edge becomes non-owning (verb has_step to spans), so the step keeps a single containment parent (the journey) and the journey has one canonical step list." }
7642
+ ],
7608
7643
  "0.9.0": [
7609
7644
  // (since v0.9.0, UPG-660) theme → roadmap_theme. The four canonical edges that
7610
7645
  // touch the roadmap theme are renamed to the roadmap_theme form. Endpoint guards
@@ -10103,6 +10138,7 @@ var UPG_PROPERTY_SCHEMA = {
10103
10138
  },
10104
10139
  // JourneyActionProperties: Discrete action at a journey step, classified by service layer.
10105
10140
  journey_action: {
10141
+ action_order: { type: "number", description: "Display order of this action within its step (0-indexed). The scalar ordering convention shared with `journey_phase.phase_order` and `journey_step.step_order` (UPG-663). Orders the service-blueprint rows within a single moment." },
10106
10142
  layer: { type: "string", enum: ["user", "frontstage", "backstage", "support"], description: "Service layer" },
10107
10143
  action_description: { type: "string", description: "Plain-language description. Primary content of the action." },
10108
10144
  channel: { type: "string", enum: ["in-app", "email", "web", "mobile", "phone", "in-person", "sms", "social", "other"], description: "Channel or surface. Keeps service-blueprint columns consistent across the journey." },
@@ -10134,7 +10170,7 @@ var UPG_PROPERTY_SCHEMA = {
10134
10170
  system: { type: "string", description: "Performing system or service" },
10135
10171
  notes: { type: "string", description: "Free-text notes, observations, or follow-up questions" }
10136
10172
  },
10137
- // JourneyPhaseProperties: Phase within a user journey. Groups journey steps into stages.
10173
+ // JourneyPhaseProperties: Phase within a user journey. A temporal BAND over the journey's step
10138
10174
  journey_phase: {
10139
10175
  phase_order: { type: "number", description: "Display order within the journey (0-indexed)" },
10140
10176
  label: { type: "string", description: 'Short human-readable name. @example "Discovery", "Onboarding", "Activation"' },
@@ -10145,8 +10181,9 @@ var UPG_PROPERTY_SCHEMA = {
10145
10181
  key_questions: { type: "string[]", description: "Open questions the user asks themselves. Fuel for design and content priorities." },
10146
10182
  timeframe: { type: "string", description: 'Typical time window. @example "first 30 seconds", "days 1\u20137", "onboarding week"' }
10147
10183
  },
10148
- // JourneyStepProperties: Single step within a user journey.
10184
+ // JourneyStepProperties: Single step within a user journey. A user-moment on the journey's single
10149
10185
  journey_step: {
10186
+ step_order: { type: "number", description: "Display order within the journey's step timeline (0-indexed). The scalar ordering convention shared with `journey_phase.phase_order` and `journey_action.action_order` (UPG-663). For branching journeys, the explicit `journey_step_precedes_journey_step` edge captures the chain." },
10150
10187
  touchpoint: { type: "string", description: "Interaction touchpoint" },
10151
10188
  channel: { type: "string", description: 'Channel (e.g. "web", "email", "in-store")' },
10152
10189
  emotion_score: {
@@ -18069,8 +18106,13 @@ var STANDARD_LABELS = {
18069
18106
  interview_guide: { alt_labels: ["discussion guide", "interview script", "moderator guide"] },
18070
18107
  survey_response: { alt_labels: ["survey answer", "questionnaire response"] },
18071
18108
  // Design layer
18072
- user_journey: { alt_labels: ["journey map", "customer journey", "experience map", "journey"] },
18073
- journey_step: { alt_labels: ["touchpoint", "journey stage", "journey phase"] },
18109
+ // (UPG-663) alt_labels must not collide with other entity types' canonical
18110
+ // names or alt_labels, or the string->type resolver is ambiguous.
18111
+ // Dropped 'customer journey' (collides with customer_journey_stage),
18112
+ // 'touchpoint' and 'journey phase' (both distinct entity surfaces: a
18113
+ // touchpoint is the journey_step.touchpoint property, a phase is journey_phase).
18114
+ user_journey: { alt_labels: ["journey map", "experience map", "journey"] },
18115
+ journey_step: { alt_labels: ["journey moment", "journey stage"] },
18074
18116
  design_component: { alt_labels: ["component", "ui component", "design element"] },
18075
18117
  design_token: { alt_labels: ["token", "style token", "css variable"] },
18076
18118
  wireframe: { alt_labels: ["wireflow", "lo-fi mockup", "skeleton"] },
@@ -20135,7 +20177,11 @@ var PRODUCT_SPEC_GUIDE = {
20135
20177
  var UX_DESIGN_GUIDE = {
20136
20178
  domain_id: "ux_design",
20137
20179
  anchor_entity: "user_journey",
20138
- creation_sequence: ["user_journey", "journey_phase", "journey_action", "journey_step", "screen", "screen_state", "user_flow", "wireframe", "prototype", "design_question", "design_concept"],
20180
+ // (UPG-663) creation order follows containment: a journey_action is a child
20181
+ // of a journey_step, so the step must precede the action. The journey is the
20182
+ // anchor; phases are the band overlay; steps are the timeline; actions
20183
+ // decompose a step into service-blueprint rows.
20184
+ creation_sequence: ["user_journey", "journey_phase", "journey_step", "journey_action", "screen", "screen_state", "user_flow", "wireframe", "prototype", "design_question", "design_concept"],
20139
20185
  patterns: [
20140
20186
  {
20141
20187
  name: "Journey to Screen Flow",
@@ -23432,6 +23478,40 @@ var UPG_ANTI_PATTERNS = [
23432
23478
  stages: ["concept", "validation", "build", "beta", "launch", "growth", "mature"],
23433
23479
  severity: "medium",
23434
23480
  source: { kind: "fundamental" }
23481
+ },
23482
+ // ── Experience-design layer ─────────────────────────────────────────────
23483
+ {
23484
+ id: "journey-phases-without-canonical-steps",
23485
+ name: "Journey phases without a step spine",
23486
+ description: 'The graph has journey phases spanning steps (`journey_phase_spans_journey_step`), but no journey owns its steps via `user_journey_contains_journey_step`. A phase is a band over a step timeline, not a container. When the timeline itself is missing there is no canonical answer to "what are the steps of this journey?". The phase overlay points at steps the journey does not own.',
23487
+ structured_condition: {
23488
+ operator: "and",
23489
+ checks: [
23490
+ {
23491
+ check: {
23492
+ type: "relationship",
23493
+ source_type: "journey_phase",
23494
+ edge_type: "journey_phase_spans_journey_step",
23495
+ target_type: "journey_step",
23496
+ comparison: "exists"
23497
+ }
23498
+ },
23499
+ {
23500
+ check: {
23501
+ type: "relationship",
23502
+ source_type: "user_journey",
23503
+ edge_type: "user_journey_contains_journey_step",
23504
+ target_type: "journey_step",
23505
+ comparison: "not_exists"
23506
+ }
23507
+ }
23508
+ ]
23509
+ },
23510
+ why_it_matters: "Steps owned by no journey render a different step list per consumer: the phase overlay sees them, a journey-direct walk does not. The journey has no deterministic step spine to traverse, score, or map to screens.",
23511
+ remediation: "Own every step under its journey with `user_journey_contains_journey_step`, then let phases span ranges of that single timeline via `journey_phase_spans_journey_step`. The phase is a non-owning band overlay, not the step container.",
23512
+ stages: ["concept", "validation", "build", "beta", "launch", "growth"],
23513
+ severity: "high",
23514
+ source: { kind: "fundamental" }
23435
23515
  }
23436
23516
  ];
23437
23517
  function getAntiPatternById(id) {
@@ -25954,7 +26034,7 @@ function isCanonical(text) {
25954
26034
  }
25955
26035
 
25956
26036
  // src/index.ts
25957
- var UPG_VERSION = "0.9.1";
26037
+ var UPG_VERSION = "0.9.2";
25958
26038
  var UPG_FORMAT_VERSION = "0.4.0";
25959
26039
  var MARKDOWN_FORMAT_VERSION = "0.1";
25960
26040
  var UPG_TYPES = getTypes();