@unified-product-graph/core 0.9.0 → 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;
@@ -6962,7 +6976,7 @@ interface UPGProduct {
6962
6976
  /** Product lifecycle stages. Covers the full arc from napkin idea to end-of-life. */
6963
6977
  type UPGProductStage = 'concept' | 'validation' | 'build' | 'beta' | 'launch' | 'growth' | 'mature' | 'maintenance' | 'sunset';
6964
6978
  /** The set of valid cross-product relationship types */
6965
- type UPGCrossEdgeType = 'shares_persona' | 'shares_competitor' | 'shares_metric' | 'depends_on_product' | 'cannibalises' | 'succeeds' | 'hosts';
6979
+ type UPGCrossEdgeType = 'shares_persona' | 'shares_competitor' | 'shares_metric' | 'depends_on_product' | 'cannibalises' | 'succeeds' | 'hosts' | 'contributes_to';
6966
6980
  /**
6967
6981
  * Runtime-checkable list of valid cross-product edge types. Mirrors
6968
6982
  * `UPGCrossEdgeType` for use in validators and writers that need to test
@@ -7308,7 +7322,6 @@ interface EntityTypeMeta {
7308
7322
  * creation. The score lives on the framework application (a `framework_exercise`
7309
7323
  * includes-edge), never on the entity. Not field-absorption: this is a pointer,
7310
7324
  * not embedded columns.
7311
- * @see TPC-context/upg/08-decisions/2026-06-05-framework-scoped-scoring-completion.md
7312
7325
  */
7313
7326
  default_frameworks?: string[];
7314
7327
  }
@@ -10695,14 +10708,19 @@ interface UserJourneyProperties {
10695
10708
  /** Scenario context */
10696
10709
  scenario?: string;
10697
10710
  }
10698
- /** 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.
10699
10715
  *
10700
10716
  * Per UPG principle P14, structural relationships are edges:
10701
- * parent journey: `user_journey_contains_journey_phase`
10702
- * contained steps: `journey_phase_contains_journey_step`
10703
- * sequenced phase: ordering via `phase_order` here; the
10704
- * `journey_phase_precedes_journey_phase` edge captures the explicit
10705
- * 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`)
10706
10724
  *
10707
10725
  * @example
10708
10726
  * const properties: JourneyPhaseProperties = {
@@ -10740,16 +10758,27 @@ interface JourneyPhaseProperties {
10740
10758
  */
10741
10759
  timeframe?: string;
10742
10760
  }
10743
- /** 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).
10744
10765
  *
10745
10766
  * @example
10746
10767
  * const properties: JourneyStepProperties = {
10768
+ * step_order: 1,
10747
10769
  * touchpoint: 'in-product',
10748
10770
  * channel: 'in-product',
10749
10771
  * emotion_score: 4,
10750
10772
  * }
10751
10773
  */
10752
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;
10753
10782
  /** Interaction touchpoint */
10754
10783
  touchpoint?: string;
10755
10784
  /** Channel (e.g. "web", "email", "in-store") */
@@ -10764,16 +10793,24 @@ interface JourneyStepProperties {
10764
10793
  owner?: string;
10765
10794
  }
10766
10795
  /** Discrete action at a journey step, classified by service layer.
10796
+ * The finest blueprint layer (a service-blueprint row within a moment).
10767
10797
  * Enables service blueprint rendering and cross-domain linking.
10768
10798
  *
10769
10799
  * Per UPG principle P14, structural relationships are edges:
10770
- * parent step: `journey_step_contains_journey_action`
10771
- * performing system: `service_performs_journey_action` (the `system` property
10772
- * is a display label; the canonical link is the edge when a `service` entity exists)
10773
- * 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.
10774
10810
  *
10775
10811
  * @example
10776
10812
  * const properties: JourneyActionProperties = {
10813
+ * action_order: 0,
10777
10814
  * layer: 'user',
10778
10815
  * action_description: 'User pastes a meeting transcript into the empty canvas',
10779
10816
  * channel: 'in-app',
@@ -10785,6 +10822,13 @@ interface JourneyStepProperties {
10785
10822
  * }
10786
10823
  */
10787
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;
10788
10832
  /** Service layer */
10789
10833
  layer: 'user' | 'frontstage' | 'backstage' | 'support';
10790
10834
  /** Plain-language description. Primary content of the action. */
@@ -18006,7 +18050,7 @@ type UPGNode<T extends keyof UPGPropertyMap = keyof UPGPropertyMap> = UPGBaseNod
18006
18050
  * AUTO-GENERATED by scripts/generate-property-registry.ts
18007
18051
  * Do not edit manually. Run: npx tsx scripts/generate-property-registry.ts
18008
18052
  *
18009
- * Generated: 2026-06-09T14:25:02.253Z
18053
+ * Generated: 2026-06-09T16:53:52.006Z
18010
18054
  * Entity types with properties: 316
18011
18055
  */
18012
18056
  interface PropertyDefinition {
@@ -20447,7 +20491,7 @@ declare function isCanonical(text: string): boolean;
20447
20491
  * it stamps the `upg_version` field of every `.upg` file written by the SDK.
20448
20492
  * The `check:version-lockstep` gate enforces this at release time.
20449
20493
  */
20450
- declare const UPG_VERSION: "0.9.0";
20494
+ declare const UPG_VERSION: "0.9.2";
20451
20495
  /**
20452
20496
  * The `.upg` JSON document format version. Written to the `upg_version` field.
20453
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;
@@ -6962,7 +6976,7 @@ interface UPGProduct {
6962
6976
  /** Product lifecycle stages. Covers the full arc from napkin idea to end-of-life. */
6963
6977
  type UPGProductStage = 'concept' | 'validation' | 'build' | 'beta' | 'launch' | 'growth' | 'mature' | 'maintenance' | 'sunset';
6964
6978
  /** The set of valid cross-product relationship types */
6965
- type UPGCrossEdgeType = 'shares_persona' | 'shares_competitor' | 'shares_metric' | 'depends_on_product' | 'cannibalises' | 'succeeds' | 'hosts';
6979
+ type UPGCrossEdgeType = 'shares_persona' | 'shares_competitor' | 'shares_metric' | 'depends_on_product' | 'cannibalises' | 'succeeds' | 'hosts' | 'contributes_to';
6966
6980
  /**
6967
6981
  * Runtime-checkable list of valid cross-product edge types. Mirrors
6968
6982
  * `UPGCrossEdgeType` for use in validators and writers that need to test
@@ -7308,7 +7322,6 @@ interface EntityTypeMeta {
7308
7322
  * creation. The score lives on the framework application (a `framework_exercise`
7309
7323
  * includes-edge), never on the entity. Not field-absorption: this is a pointer,
7310
7324
  * not embedded columns.
7311
- * @see TPC-context/upg/08-decisions/2026-06-05-framework-scoped-scoring-completion.md
7312
7325
  */
7313
7326
  default_frameworks?: string[];
7314
7327
  }
@@ -10695,14 +10708,19 @@ interface UserJourneyProperties {
10695
10708
  /** Scenario context */
10696
10709
  scenario?: string;
10697
10710
  }
10698
- /** 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.
10699
10715
  *
10700
10716
  * Per UPG principle P14, structural relationships are edges:
10701
- * parent journey: `user_journey_contains_journey_phase`
10702
- * contained steps: `journey_phase_contains_journey_step`
10703
- * sequenced phase: ordering via `phase_order` here; the
10704
- * `journey_phase_precedes_journey_phase` edge captures the explicit
10705
- * 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`)
10706
10724
  *
10707
10725
  * @example
10708
10726
  * const properties: JourneyPhaseProperties = {
@@ -10740,16 +10758,27 @@ interface JourneyPhaseProperties {
10740
10758
  */
10741
10759
  timeframe?: string;
10742
10760
  }
10743
- /** 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).
10744
10765
  *
10745
10766
  * @example
10746
10767
  * const properties: JourneyStepProperties = {
10768
+ * step_order: 1,
10747
10769
  * touchpoint: 'in-product',
10748
10770
  * channel: 'in-product',
10749
10771
  * emotion_score: 4,
10750
10772
  * }
10751
10773
  */
10752
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;
10753
10782
  /** Interaction touchpoint */
10754
10783
  touchpoint?: string;
10755
10784
  /** Channel (e.g. "web", "email", "in-store") */
@@ -10764,16 +10793,24 @@ interface JourneyStepProperties {
10764
10793
  owner?: string;
10765
10794
  }
10766
10795
  /** Discrete action at a journey step, classified by service layer.
10796
+ * The finest blueprint layer (a service-blueprint row within a moment).
10767
10797
  * Enables service blueprint rendering and cross-domain linking.
10768
10798
  *
10769
10799
  * Per UPG principle P14, structural relationships are edges:
10770
- * parent step: `journey_step_contains_journey_action`
10771
- * performing system: `service_performs_journey_action` (the `system` property
10772
- * is a display label; the canonical link is the edge when a `service` entity exists)
10773
- * 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.
10774
10810
  *
10775
10811
  * @example
10776
10812
  * const properties: JourneyActionProperties = {
10813
+ * action_order: 0,
10777
10814
  * layer: 'user',
10778
10815
  * action_description: 'User pastes a meeting transcript into the empty canvas',
10779
10816
  * channel: 'in-app',
@@ -10785,6 +10822,13 @@ interface JourneyStepProperties {
10785
10822
  * }
10786
10823
  */
10787
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;
10788
10832
  /** Service layer */
10789
10833
  layer: 'user' | 'frontstage' | 'backstage' | 'support';
10790
10834
  /** Plain-language description. Primary content of the action. */
@@ -18006,7 +18050,7 @@ type UPGNode<T extends keyof UPGPropertyMap = keyof UPGPropertyMap> = UPGBaseNod
18006
18050
  * AUTO-GENERATED by scripts/generate-property-registry.ts
18007
18051
  * Do not edit manually. Run: npx tsx scripts/generate-property-registry.ts
18008
18052
  *
18009
- * Generated: 2026-06-09T14:25:02.253Z
18053
+ * Generated: 2026-06-09T16:53:52.006Z
18010
18054
  * Entity types with properties: 316
18011
18055
  */
18012
18056
  interface PropertyDefinition {
@@ -20447,7 +20491,7 @@ declare function isCanonical(text: string): boolean;
20447
20491
  * it stamps the `upg_version` field of every `.upg` file written by the SDK.
20448
20492
  * The `check:version-lockstep` gate enforces this at release time.
20449
20493
  */
20450
- declare const UPG_VERSION: "0.9.0";
20494
+ declare const UPG_VERSION: "0.9.2";
20451
20495
  /**
20452
20496
  * The `.upg` JSON document format version. Written to the `upg_version` field.
20453
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" },
@@ -2759,7 +2775,8 @@ var UPG_CROSS_EDGE_TYPES = [
2759
2775
  "depends_on_product",
2760
2776
  "cannibalises",
2761
2777
  "succeeds",
2762
- "hosts"
2778
+ "hosts",
2779
+ "contributes_to"
2763
2780
  ];
2764
2781
 
2765
2782
  // src/registry/entity-type-resolution.ts
@@ -3050,8 +3067,13 @@ var UPG_VALID_CHILDREN = {
3050
3067
  // parallel to `observation: ['quote']`. Research-synthesis canon.
3051
3068
  // Pairs with `insight_evidenced_by_quote` in the edge catalog.
3052
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.
3053
3076
  user_journey: ["journey_step", "journey_phase"],
3054
- journey_phase: ["journey_step"],
3055
3077
  journey_step: ["journey_action"],
3056
3078
  // v0.5.8 (UPG-528 Part 2d): insights own their evidencing quotes;
3057
3079
  // parallel to `observation: ['quote']`. Research-synthesis canon
@@ -7604,6 +7626,20 @@ function getSplitMigrations(fromVersion, toVersion) {
7604
7626
  return result;
7605
7627
  }
7606
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
+ ],
7607
7643
  "0.9.0": [
7608
7644
  // (since v0.9.0, UPG-660) theme → roadmap_theme. The four canonical edges that
7609
7645
  // touch the roadmap theme are renamed to the roadmap_theme form. Endpoint guards
@@ -10102,6 +10138,7 @@ var UPG_PROPERTY_SCHEMA = {
10102
10138
  },
10103
10139
  // JourneyActionProperties: Discrete action at a journey step, classified by service layer.
10104
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." },
10105
10142
  layer: { type: "string", enum: ["user", "frontstage", "backstage", "support"], description: "Service layer" },
10106
10143
  action_description: { type: "string", description: "Plain-language description. Primary content of the action." },
10107
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." },
@@ -10133,7 +10170,7 @@ var UPG_PROPERTY_SCHEMA = {
10133
10170
  system: { type: "string", description: "Performing system or service" },
10134
10171
  notes: { type: "string", description: "Free-text notes, observations, or follow-up questions" }
10135
10172
  },
10136
- // 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
10137
10174
  journey_phase: {
10138
10175
  phase_order: { type: "number", description: "Display order within the journey (0-indexed)" },
10139
10176
  label: { type: "string", description: 'Short human-readable name. @example "Discovery", "Onboarding", "Activation"' },
@@ -10144,8 +10181,9 @@ var UPG_PROPERTY_SCHEMA = {
10144
10181
  key_questions: { type: "string[]", description: "Open questions the user asks themselves. Fuel for design and content priorities." },
10145
10182
  timeframe: { type: "string", description: 'Typical time window. @example "first 30 seconds", "days 1\u20137", "onboarding week"' }
10146
10183
  },
10147
- // JourneyStepProperties: Single step within a user journey.
10184
+ // JourneyStepProperties: Single step within a user journey. A user-moment on the journey's single
10148
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." },
10149
10187
  touchpoint: { type: "string", description: "Interaction touchpoint" },
10150
10188
  channel: { type: "string", description: 'Channel (e.g. "web", "email", "in-store")' },
10151
10189
  emotion_score: {
@@ -18068,8 +18106,13 @@ var STANDARD_LABELS = {
18068
18106
  interview_guide: { alt_labels: ["discussion guide", "interview script", "moderator guide"] },
18069
18107
  survey_response: { alt_labels: ["survey answer", "questionnaire response"] },
18070
18108
  // Design layer
18071
- user_journey: { alt_labels: ["journey map", "customer journey", "experience map", "journey"] },
18072
- 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"] },
18073
18116
  design_component: { alt_labels: ["component", "ui component", "design element"] },
18074
18117
  design_token: { alt_labels: ["token", "style token", "css variable"] },
18075
18118
  wireframe: { alt_labels: ["wireflow", "lo-fi mockup", "skeleton"] },
@@ -20134,7 +20177,11 @@ var PRODUCT_SPEC_GUIDE = {
20134
20177
  var UX_DESIGN_GUIDE = {
20135
20178
  domain_id: "ux_design",
20136
20179
  anchor_entity: "user_journey",
20137
- 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"],
20138
20185
  patterns: [
20139
20186
  {
20140
20187
  name: "Journey to Screen Flow",
@@ -23431,6 +23478,40 @@ var UPG_ANTI_PATTERNS = [
23431
23478
  stages: ["concept", "validation", "build", "beta", "launch", "growth", "mature"],
23432
23479
  severity: "medium",
23433
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" }
23434
23515
  }
23435
23516
  ];
23436
23517
  function getAntiPatternById(id) {
@@ -25953,7 +26034,7 @@ function isCanonical(text) {
25953
26034
  }
25954
26035
 
25955
26036
  // src/index.ts
25956
- var UPG_VERSION = "0.9.0";
26037
+ var UPG_VERSION = "0.9.2";
25957
26038
  var UPG_FORMAT_VERSION = "0.4.0";
25958
26039
  var MARKDOWN_FORMAT_VERSION = "0.1";
25959
26040
  var UPG_TYPES = getTypes();