@unified-product-graph/core 0.17.2 → 0.17.3

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.cjs CHANGED
@@ -68,6 +68,8 @@ __export(index_exports, {
68
68
  UPG_CONTAINMENT_FREE_TYPES: () => UPG_CONTAINMENT_FREE_TYPES,
69
69
  UPG_COUNT_BENCHMARKS: () => UPG_COUNT_BENCHMARKS,
70
70
  UPG_CROSS_EDGE_TYPES: () => UPG_CROSS_EDGE_TYPES,
71
+ UPG_CROSS_ELIGIBLE_CATALOG_EDGE_TYPES: () => UPG_CROSS_ELIGIBLE_CATALOG_EDGE_TYPES,
72
+ UPG_CROSS_ONLY_EDGE_TYPES: () => UPG_CROSS_ONLY_EDGE_TYPES,
71
73
  UPG_DEPRECATED_TYPES: () => UPG_DEPRECATED_TYPES,
72
74
  UPG_DOMAINS: () => UPG_DOMAINS,
73
75
  UPG_DOMAIN_ACTIVATION: () => UPG_DOMAIN_ACTIVATION,
@@ -198,6 +200,7 @@ __export(index_exports, {
198
200
  isCanonical: () => isCanonical,
199
201
  isCanonicalProductStage: () => isCanonicalProductStage,
200
202
  isContainmentFreeType: () => isContainmentFreeType,
203
+ isCrossProductEligible: () => isCrossProductEligible,
201
204
  isDeprecatedType: () => isDeprecatedType,
202
205
  isDomainGuideStep: () => isDomainGuideStep,
203
206
  isEntitySequenceStep: () => isEntitySequenceStep,
@@ -1273,7 +1276,7 @@ var UPG_EDGE_CATALOG = {
1273
1276
  persona_aspires_to_desired_outcome: { forward_verb: "aspires_to", reverse_verb: "aspirational_for", classification: "hierarchy", source_type: "persona", target_type: "desired_outcome" },
1274
1277
  // Delegation (0.11.6): a persona delegates work to another. The common case is human -> agent
1275
1278
  // (Content Ops Lead -> Content Agent), but it also expresses human -> human (editor -> reviewer).
1276
- persona_delegates_to_persona: { forward_verb: "delegates_to", reverse_verb: "delegated_by", classification: "semantic", source_type: "persona", target_type: "persona" },
1279
+ persona_delegates_to_persona: { forward_verb: "delegates_to", reverse_verb: "delegated_by", classification: "semantic", source_type: "persona", target_type: "persona", cross_product_eligible: true },
1277
1280
  persona_incurs_switching_cost: { forward_verb: "incurs", reverse_verb: "incurred_by", classification: "hierarchy", source_type: "persona", target_type: "switching_cost" },
1278
1281
  job_surfaces_need: { forward_verb: "surfaces", reverse_verb: "surfaces_from", classification: "causal", source_type: "job", target_type: "need" },
1279
1282
  job_motivates_desired_outcome: { forward_verb: "motivates", reverse_verb: "motivated_by", classification: "causal", source_type: "job", target_type: "desired_outcome" },
@@ -1391,15 +1394,15 @@ var UPG_EDGE_CATALOG = {
1391
1394
  // Dual-registered as a cross-edge (UPG_CROSS_EDGE_TYPES) so it also spans our
1392
1395
  // product graph and a watched competitor-intelligence graph. Distinct from
1393
1396
  // `competitor_feature_inspires_feature` (ideation lineage, not parity).
1394
- feature_rivals_competitor_feature: { forward_verb: "rivals", reverse_verb: "is_rivalled_by", classification: "cross-domain", source_type: "feature", target_type: "competitor_feature", carries_properties: true },
1397
+ feature_rivals_competitor_feature: { forward_verb: "rivals", reverse_verb: "is_rivalled_by", classification: "cross-domain", source_type: "feature", target_type: "competitor_feature", carries_properties: true, cross_product_eligible: true },
1395
1398
  // 0.10.0 (spec issue #41): competitor_signal is a dated competitor move (feature
1396
1399
  // launch / pricing change / acquisition / partnership / market entry) emitted by a
1397
1400
  // competitor and mapped onto our portfolio. `emits` is within the watched graph;
1398
1401
  // `maps_to_feature` / `surfaces_opportunity` cross from the watched signal into our
1399
1402
  // product graph (dual-registered as cross-edges in UPG_CROSS_EDGE_TYPES).
1400
1403
  competitor_emits_competitor_signal: { forward_verb: "emits", reverse_verb: "emitted_by", classification: "hierarchy", source_type: "competitor", target_type: "competitor_signal" },
1401
- competitor_signal_maps_to_feature: { forward_verb: "maps_to", reverse_verb: "targeted_by_signal", classification: "cross-domain", source_type: "competitor_signal", target_type: "feature" },
1402
- competitor_signal_surfaces_opportunity: { forward_verb: "surfaces", reverse_verb: "prompted_by_signal", classification: "cross-domain", source_type: "competitor_signal", target_type: "opportunity" },
1404
+ competitor_signal_maps_to_feature: { forward_verb: "maps_to", reverse_verb: "targeted_by_signal", classification: "cross-domain", source_type: "competitor_signal", target_type: "feature", cross_product_eligible: true },
1405
+ competitor_signal_surfaces_opportunity: { forward_verb: "surfaces", reverse_verb: "prompted_by_signal", classification: "cross-domain", source_type: "competitor_signal", target_type: "opportunity", cross_product_eligible: true },
1403
1406
  competitive_analysis_analyses_competitor: { forward_verb: "analyses", reverse_verb: "analysed_in", classification: "hierarchy", source_type: "competitive_analysis", target_type: "competitor" },
1404
1407
  competitive_analysis_identifies_market_trend: { forward_verb: "identifies", reverse_verb: "identified_in", classification: "hierarchy", source_type: "competitive_analysis", target_type: "market_trend" },
1405
1408
  competitive_analysis_scopes_market_segment: { forward_verb: "scopes", reverse_verb: "scoped_in", classification: "hierarchy", source_type: "competitive_analysis", target_type: "market_segment" },
@@ -1432,13 +1435,13 @@ var UPG_EDGE_CATALOG = {
1432
1435
  // competitor can be classified directly against a `registry/{classification_value}`
1433
1436
  // canonical, eliminating the per-graph taxonomy node. Within-graph (the catalogue
1434
1437
  // case) here; cross-product against the registry canonical via create_cross_product_edge.
1435
- competitor_classified_as_classification_value: { forward_verb: "classified_as", reverse_verb: "classification_of", classification: "semantic", source_type: "competitor", target_type: "classification_value", carries_properties: true, property_schema: CLASSIFICATION_EDGE_PROPERTY_SCHEMA },
1438
+ competitor_classified_as_classification_value: { forward_verb: "classified_as", reverse_verb: "classification_of", classification: "semantic", source_type: "competitor", target_type: "classification_value", carries_properties: true, property_schema: CLASSIFICATION_EDGE_PROPERTY_SCHEMA, cross_product_eligible: true },
1436
1439
  // 0.10.3: the polymorphic, type-agnostic sibling. ANY node (a feature, a
1437
1440
  // product, a market_segment) classified against a classification_value, so
1438
1441
  // classification is not welded to the competitor type. Also dual-registered as
1439
1442
  // a cross-edge for the registry-canonical case. source_type:'node' (wildcard);
1440
1443
  // listed in UPG_POLYMORPHIC_EDGE_KEYS.
1441
- node_classified_as_classification_value: { forward_verb: "classified_as", reverse_verb: "classification_of", classification: "semantic", source_type: "node", target_type: "classification_value", carries_properties: true, property_schema: CLASSIFICATION_EDGE_PROPERTY_SCHEMA },
1444
+ node_classified_as_classification_value: { forward_verb: "classified_as", reverse_verb: "classification_of", classification: "semantic", source_type: "node", target_type: "classification_value", carries_properties: true, property_schema: CLASSIFICATION_EDGE_PROPERTY_SCHEMA, cross_product_eligible: true },
1442
1445
  persona_anti_fit_for_classification_value: { forward_verb: "is_anti_fit_for", reverse_verb: "should_not_be_picked_by", classification: "semantic", source_type: "persona", target_type: "classification_value" },
1443
1446
  persona_anti_fit_for_product: { forward_verb: "is_anti_fit_for", reverse_verb: "should_not_be_picked_by", classification: "semantic", source_type: "persona", target_type: "product" },
1444
1447
  persona_anti_fit_for_competitor: { forward_verb: "is_anti_fit_for", reverse_verb: "should_not_be_picked_by", classification: "semantic", source_type: "persona", target_type: "competitor" },
@@ -1491,28 +1494,28 @@ var UPG_EDGE_CATALOG = {
1491
1494
  feedback_program_has_beta_program: { forward_verb: "has", reverse_verb: "part_of", classification: "hierarchy", source_type: "feedback_program", target_type: "beta_program" },
1492
1495
  // ── Part 2: Strategic & Execution Spine (Ring 2) ───────────────────────────
1493
1496
  // 2.1 Strategic Domain
1494
- product_pursues_outcome: { forward_verb: "pursues", reverse_verb: "pursued_by", classification: "hierarchy", source_type: "product", target_type: "outcome" },
1495
- product_targets_objective: { forward_verb: "targets", reverse_verb: "targeted_by", classification: "hierarchy", source_type: "product", target_type: "objective" },
1496
- product_guided_by_vision: { forward_verb: "guided_by", reverse_verb: "guides", classification: "hierarchy", source_type: "product", target_type: "vision" },
1497
+ product_pursues_outcome: { forward_verb: "pursues", reverse_verb: "pursued_by", classification: "hierarchy", source_type: "product", target_type: "outcome", cross_product_eligible: true },
1498
+ product_targets_objective: { forward_verb: "targets", reverse_verb: "targeted_by", classification: "hierarchy", source_type: "product", target_type: "objective", cross_product_eligible: true },
1499
+ product_guided_by_vision: { forward_verb: "guided_by", reverse_verb: "guides", classification: "hierarchy", source_type: "product", target_type: "vision", cross_product_eligible: true },
1497
1500
  // product→{mission,strategic_theme,strategic_pillar,initiative,capability,value_stream,assumption}
1498
1501
  // are semantic "how the product relates to the strategic cascade", not containment.
1499
1502
  // The containment chain is product → vision → mission → strategic_pillar → … so these
1500
1503
  // targets are reachable via the vision/mission hierarchy already.
1501
- product_fulfils_mission: { forward_verb: "fulfils", reverse_verb: "fulfilled_by", classification: "semantic", source_type: "product", target_type: "mission" },
1502
- product_organises_around_strategic_theme: { forward_verb: "organises_around", reverse_verb: "organises", classification: "semantic", source_type: "product", target_type: "strategic_theme" },
1503
- product_stands_on_strategic_pillar: { forward_verb: "stands_on", reverse_verb: "supports", classification: "semantic", source_type: "product", target_type: "strategic_pillar" },
1504
- product_invests_in_initiative: { forward_verb: "invests_in", reverse_verb: "investment_of", classification: "semantic", source_type: "product", target_type: "initiative" },
1504
+ product_fulfils_mission: { forward_verb: "fulfils", reverse_verb: "fulfilled_by", classification: "semantic", source_type: "product", target_type: "mission", cross_product_eligible: true },
1505
+ product_organises_around_strategic_theme: { forward_verb: "organises_around", reverse_verb: "organises", classification: "semantic", source_type: "product", target_type: "strategic_theme", cross_product_eligible: true },
1506
+ product_stands_on_strategic_pillar: { forward_verb: "stands_on", reverse_verb: "supports", classification: "semantic", source_type: "product", target_type: "strategic_pillar", cross_product_eligible: true },
1507
+ product_invests_in_initiative: { forward_verb: "invests_in", reverse_verb: "investment_of", classification: "semantic", source_type: "product", target_type: "initiative", cross_product_eligible: true },
1505
1508
  product_develops_capability: { forward_verb: "develops", reverse_verb: "developed_by", classification: "semantic", source_type: "product", target_type: "capability" },
1506
1509
  product_delivers_through_value_stream: { forward_verb: "delivers_through", reverse_verb: "delivers_for", classification: "semantic", source_type: "product", target_type: "value_stream" },
1507
1510
  product_holds_assumption: { forward_verb: "holds", reverse_verb: "held_by", classification: "semantic", source_type: "product", target_type: "assumption" },
1508
- product_measures_with_metric: { forward_verb: "measures_with", reverse_verb: "measures", classification: "hierarchy", source_type: "product", target_type: "metric" },
1509
- outcome_measured_by_metric: { forward_verb: "measured_by", reverse_verb: "measures", classification: "hierarchy", source_type: "outcome", target_type: "metric" },
1511
+ product_measures_with_metric: { forward_verb: "measures_with", reverse_verb: "measures", classification: "hierarchy", source_type: "product", target_type: "metric", cross_product_eligible: true },
1512
+ outcome_measured_by_metric: { forward_verb: "measured_by", reverse_verb: "measures", classification: "hierarchy", source_type: "outcome", target_type: "metric", cross_product_eligible: true },
1510
1513
  // (UPG-677) outcome_tracked_by_metric retired — near-synonym of
1511
1514
  // outcome_measured_by_metric (the kept canonical key). Captain's lean =
1512
1515
  // collapse. See UPG_EDGE_MIGRATIONS['0.9.9'].
1513
- objective_achieved_through_key_result: { forward_verb: "achieved_through", reverse_verb: "achieves", classification: "hierarchy", source_type: "objective", target_type: "key_result" },
1514
- objective_measured_by_metric: { forward_verb: "measured_by", reverse_verb: "measures", classification: "hierarchy", source_type: "objective", target_type: "metric" },
1515
- key_result_quantified_by_metric: { forward_verb: "quantified_by", reverse_verb: "quantifies", classification: "hierarchy", source_type: "key_result", target_type: "metric" },
1516
+ objective_achieved_through_key_result: { forward_verb: "achieved_through", reverse_verb: "achieves", classification: "hierarchy", source_type: "objective", target_type: "key_result", cross_product_eligible: true },
1517
+ objective_measured_by_metric: { forward_verb: "measured_by", reverse_verb: "measures", classification: "hierarchy", source_type: "objective", target_type: "metric", cross_product_eligible: true },
1518
+ key_result_quantified_by_metric: { forward_verb: "quantified_by", reverse_verb: "quantifies", classification: "hierarchy", source_type: "key_result", target_type: "metric", cross_product_eligible: true },
1516
1519
  // (UPG-677) key_result_tracked_by_metric retired — near-synonym of
1517
1520
  // key_result_quantified_by_metric (the kept canonical key). Captain's lean =
1518
1521
  // collapse. See UPG_EDGE_MIGRATIONS['0.9.9'].
@@ -1522,7 +1525,7 @@ var UPG_EDGE_CATALOG = {
1522
1525
  strategic_pillar_enables_capability: { forward_verb: "enables", reverse_verb: "enabled_by", classification: "hierarchy", source_type: "strategic_pillar", target_type: "capability" },
1523
1526
  strategic_pillar_delivers_value_stream: { forward_verb: "delivers", reverse_verb: "delivered_by", classification: "hierarchy", source_type: "strategic_pillar", target_type: "value_stream" },
1524
1527
  strategic_pillar_decided_via_decision: { forward_verb: "decided_via", reverse_verb: "decided_for", classification: "hierarchy", source_type: "strategic_pillar", target_type: "decision" },
1525
- strategic_theme_pursues_initiative: { forward_verb: "pursues", reverse_verb: "pursued_under", classification: "hierarchy", source_type: "strategic_theme", target_type: "initiative" },
1528
+ strategic_theme_pursues_initiative: { forward_verb: "pursues", reverse_verb: "pursued_under", classification: "hierarchy", source_type: "strategic_theme", target_type: "initiative", cross_product_eligible: true },
1526
1529
  // v0.9.0 (UPG-660): the soft bridge from the annual strategy focus area to the
1527
1530
  // roadmap grouping that realises it. Semantic, NOT hierarchy: strategic_theme and
1528
1531
  // roadmap_theme sit on different spines (strategy cascade vs roadmap cascade), so
@@ -1550,11 +1553,11 @@ var UPG_EDGE_CATALOG = {
1550
1553
  // surfaces the upward-rollup read. Mirrors `strategic_pillar_organises_
1551
1554
  // strategic_theme` (pillar → theme), completing the strategic cascade:
1552
1555
  // strategic_pillar → strategic_theme → objective → key_result.
1553
- strategic_theme_delivers_outcome: { forward_verb: "delivers", reverse_verb: "delivered_by", classification: "causal", source_type: "strategic_theme", target_type: "outcome" },
1554
- strategic_theme_measured_by_key_result: { forward_verb: "measured_by", reverse_verb: "measures", classification: "causal", source_type: "strategic_theme", target_type: "key_result" },
1555
- strategic_theme_contains_objective: { forward_verb: "contains", reverse_verb: "rolls_up_to", classification: "hierarchy", source_type: "strategic_theme", target_type: "objective" },
1556
+ strategic_theme_delivers_outcome: { forward_verb: "delivers", reverse_verb: "delivered_by", classification: "causal", source_type: "strategic_theme", target_type: "outcome", cross_product_eligible: true },
1557
+ strategic_theme_measured_by_key_result: { forward_verb: "measured_by", reverse_verb: "measures", classification: "causal", source_type: "strategic_theme", target_type: "key_result", cross_product_eligible: true },
1558
+ strategic_theme_contains_objective: { forward_verb: "contains", reverse_verb: "rolls_up_to", classification: "hierarchy", source_type: "strategic_theme", target_type: "objective", cross_product_eligible: true },
1556
1559
  initiative_assumes_assumption: { forward_verb: "assumes", reverse_verb: "assumed_by", classification: "hierarchy", source_type: "initiative", target_type: "assumption" },
1557
- initiative_drives_outcome: { forward_verb: "drives", reverse_verb: "driven_by", classification: "cross-domain", source_type: "initiative", target_type: "outcome" },
1560
+ initiative_drives_outcome: { forward_verb: "drives", reverse_verb: "driven_by", classification: "cross-domain", source_type: "initiative", target_type: "outcome", cross_product_eligible: true },
1558
1561
  capability_enables_value_stream: { forward_verb: "enables", reverse_verb: "enabled_by", classification: "cross-domain", source_type: "capability", target_type: "value_stream" },
1559
1562
  // v0.5.2 (UPG-528): three capability-anchored edges that complete the
1560
1563
  // Wardley-style value chain: need → capability → capability → feature.
@@ -1692,7 +1695,7 @@ var UPG_EDGE_CATALOG = {
1692
1695
  // brand_identity. Dual-registered: also a cross-edge for the common case where the
1693
1696
  // brand is a registry singleton in another graph (the ratified pattern: brand is a
1694
1697
  // singleton expressed, not instance_of-d); this catalog entry is the within-graph case.
1695
- product_expresses_brand_identity: { forward_verb: "expresses", reverse_verb: "expressed_by", classification: "semantic", source_type: "product", target_type: "brand_identity" },
1698
+ product_expresses_brand_identity: { forward_verb: "expresses", reverse_verb: "expressed_by", classification: "semantic", source_type: "product", target_type: "brand_identity", cross_product_eligible: true },
1696
1699
  design_system_encompasses_user_journey: { forward_verb: "encompasses", reverse_verb: "encompassed_in", classification: "hierarchy", source_type: "design_system", target_type: "user_journey" },
1697
1700
  design_system_encompasses_user_flow: { forward_verb: "encompasses", reverse_verb: "encompassed_in", classification: "hierarchy", source_type: "design_system", target_type: "user_flow" },
1698
1701
  design_system_informed_by_insight: { forward_verb: "informed_by", reverse_verb: "informs", classification: "hierarchy", source_type: "design_system", target_type: "insight" },
@@ -1704,12 +1707,12 @@ var UPG_EDGE_CATALOG = {
1704
1707
  design_component_specified_by_interaction_spec: { forward_verb: "specified_by", reverse_verb: "specifies", classification: "hierarchy", source_type: "design_component", target_type: "interaction_spec" },
1705
1708
  design_component_composes_design_component: { forward_verb: "composes", reverse_verb: "composed_in", classification: "hierarchy", source_type: "design_component", target_type: "design_component" },
1706
1709
  prototype_annotated_with_annotation: { forward_verb: "annotated_with", reverse_verb: "annotates", classification: "hierarchy", source_type: "prototype", target_type: "annotation" },
1707
- screen_renders_design_component: { forward_verb: "renders", reverse_verb: "rendered_on", classification: "hierarchy", source_type: "screen", target_type: "design_component" },
1710
+ screen_renders_design_component: { forward_verb: "renders", reverse_verb: "rendered_on", classification: "hierarchy", source_type: "screen", target_type: "design_component", cross_product_eligible: true },
1708
1711
  // Marketing surface to product (0.12.7, UPG-696/698). A marketing/landing screen
1709
1712
  // markets a product. Dual-registered: also a cross-edge (UPG_CROSS_EDGE_TYPES) for
1710
1713
  // the common case where the product lives in another graph; this catalog entry is
1711
1714
  // the within-graph degenerate case (a product's own landing page).
1712
- screen_markets_product: { forward_verb: "markets", reverse_verb: "marketed_by", classification: "semantic", source_type: "screen", target_type: "product" },
1715
+ screen_markets_product: { forward_verb: "markets", reverse_verb: "marketed_by", classification: "semantic", source_type: "screen", target_type: "product", cross_product_eligible: true },
1713
1716
  // Connective cross-product references (0.13.1, Data's connective-layer brief).
1714
1717
  // Dual-registered (also in UPG_CROSS_EDGE_TYPES) for the common cross-graph case;
1715
1718
  // these catalog entries are the within-graph degenerate case.
@@ -1725,10 +1728,10 @@ var UPG_EDGE_CATALOG = {
1725
1728
  // system (the adoption semantic, mirroring product_implements_specification). Distinct
1726
1729
  // from the hierarchy `product_systematised_in_design_system` (structural containment):
1727
1730
  // same pattern as brand (branded_as = hierarchy, expresses = semantic).
1728
- screen_targets_competitor: { forward_verb: "targets", reverse_verb: "targeted_by", classification: "semantic", source_type: "screen", target_type: "competitor" },
1729
- feature_surfaces_product: { forward_verb: "surfaces", reverse_verb: "surfaced_by", classification: "semantic", source_type: "feature", target_type: "product" },
1730
- feature_uses_design_component: { forward_verb: "uses", reverse_verb: "used_by", classification: "semantic", source_type: "feature", target_type: "design_component" },
1731
- product_implements_design_system: { forward_verb: "implements", reverse_verb: "implemented_by", classification: "semantic", source_type: "product", target_type: "design_system" },
1731
+ screen_targets_competitor: { forward_verb: "targets", reverse_verb: "targeted_by", classification: "semantic", source_type: "screen", target_type: "competitor", cross_product_eligible: true },
1732
+ feature_surfaces_product: { forward_verb: "surfaces", reverse_verb: "surfaced_by", classification: "semantic", source_type: "feature", target_type: "product", cross_product_eligible: true },
1733
+ feature_uses_design_component: { forward_verb: "uses", reverse_verb: "used_by", classification: "semantic", source_type: "feature", target_type: "design_component", cross_product_eligible: true },
1734
+ product_implements_design_system: { forward_verb: "implements", reverse_verb: "implemented_by", classification: "semantic", source_type: "product", target_type: "design_system", cross_product_eligible: true },
1732
1735
  screen_navigates_to_screen: { forward_verb: "navigates_to", reverse_verb: "navigated_from", classification: "hierarchy", source_type: "screen", target_type: "screen" },
1733
1736
  screen_surfaces_feature: { forward_verb: "surfaces", reverse_verb: "surfaced_on", classification: "cross-domain", source_type: "screen", target_type: "feature" },
1734
1737
  screen_wireframed_as_wireframe: { forward_verb: "wireframed_as", reverse_verb: "wireframes", classification: "hierarchy", source_type: "screen", target_type: "wireframe" },
@@ -2580,10 +2583,10 @@ var UPG_EDGE_CATALOG = {
2580
2583
  experiment_run_measured_by_metric: { forward_verb: "measured_by", reverse_verb: "measures", classification: "hierarchy", source_type: "experiment_run", target_type: "metric" },
2581
2584
  solution_measured_by_metric: { forward_verb: "measured_by", reverse_verb: "measures", classification: "hierarchy", source_type: "solution", target_type: "metric" },
2582
2585
  // ── Cross-domain: Ownership ──────────────────────────────────────────────────
2583
- node_owned_by_team: { forward_verb: "owned_by", reverse_verb: "owns", classification: "cross-domain", source_type: "node", target_type: "team" },
2586
+ node_owned_by_team: { forward_verb: "owned_by", reverse_verb: "owns", classification: "cross-domain", source_type: "node", target_type: "team", cross_product_eligible: true },
2584
2587
  node_owned_by_role: { forward_verb: "owned_by", reverse_verb: "owns", classification: "cross-domain", source_type: "node", target_type: "role" },
2585
2588
  node_owned_by_stakeholder: { forward_verb: "owned_by", reverse_verb: "owns", classification: "cross-domain", source_type: "node", target_type: "stakeholder" },
2586
- node_owned_by_department: { forward_verb: "owned_by", reverse_verb: "owns", classification: "cross-domain", source_type: "node", target_type: "department" },
2589
+ node_owned_by_department: { forward_verb: "owned_by", reverse_verb: "owns", classification: "cross-domain", source_type: "node", target_type: "department", cross_product_eligible: true },
2587
2590
  node_owned_by_person: { forward_verb: "owned_by", reverse_verb: "owns", classification: "cross-domain", source_type: "node", target_type: "person" },
2588
2591
  // ── Cross-domain: Architecture (DDD) ─────────────────────────────────────────
2589
2592
  // Service, domain_event, domain_entity, aggregate, read_model, api_contract,
@@ -3247,7 +3250,7 @@ var UPG_EDGE_CATALOG = {
3247
3250
  // not the outcome it exists to move; the strategic spine was severed at its
3248
3251
  // anchor (0 outbound to outcome). An objective ADVANCES an outcome. Intra-
3249
3252
  // domain (both in strategy) and directional → causal.
3250
- objective_advances_outcome: { forward_verb: "advances", reverse_verb: "advanced_by", classification: "causal", source_type: "objective", target_type: "outcome" },
3253
+ objective_advances_outcome: { forward_verb: "advances", reverse_verb: "advanced_by", classification: "causal", source_type: "objective", target_type: "outcome", cross_product_eligible: true },
3251
3254
  // ── F6: Priority 2 — scored / synthesis / verdict dead-end leaves (P-A) ─────
3252
3255
  // desired_outcome (Ulwick-scored: importance × satisfaction) had 0 outbound —
3253
3256
  // the scores could not flow anywhere. An under-served desired_outcome REVEALS
@@ -3330,9 +3333,16 @@ var UPG_EDGE_CATALOG = {
3330
3333
  specification_governed_by_organization: { forward_verb: "governed_by", reverse_verb: "governs", classification: "semantic", source_type: "specification", target_type: "organization" },
3331
3334
  // Operating-lifecycle cross-edges (0.11.6): a product's journey phase realises a canonical
3332
3335
  // operating stage (the cross-surface join key); a stage is measured by a rollup metric (loop close).
3333
- journey_phase_realises_operating_stage: { forward_verb: "realises", reverse_verb: "realised_by", classification: "cross-domain", source_type: "journey_phase", target_type: "operating_stage" },
3336
+ journey_phase_realises_operating_stage: { forward_verb: "realises", reverse_verb: "realised_by", classification: "cross-domain", source_type: "journey_phase", target_type: "operating_stage", cross_product_eligible: true },
3334
3337
  operating_stage_measured_by_metric: { forward_verb: "measured_by", reverse_verb: "measures", classification: "cross-domain", source_type: "operating_stage", target_type: "metric" }
3335
3338
  };
3339
+ var UPG_CROSS_ELIGIBLE_CATALOG_EDGE_TYPES = Object.keys(UPG_EDGE_CATALOG).filter(
3340
+ (k) => UPG_EDGE_CATALOG[k].cross_product_eligible === true
3341
+ );
3342
+ function isCrossProductEligible(type) {
3343
+ const def = UPG_EDGE_CATALOG[type];
3344
+ return def?.cross_product_eligible === true;
3345
+ }
3336
3346
  var UPG_POLYMORPHIC_EDGE_KEYS = [
3337
3347
  // Universal semantic verbs
3338
3348
  "node_informs_node",
@@ -3392,52 +3402,47 @@ function isLegacyProductStage(stage) {
3392
3402
  }
3393
3403
 
3394
3404
  // src/shapes/document.ts
3395
- var UPG_CROSS_EDGE_TYPES = [
3405
+ var UPG_CROSS_ONLY_EDGE_TYPES = [
3406
+ // Peer overlap: "these two products share / overlap on this thing." Symmetric,
3407
+ // no canonical instance_of identity. shares_job / shares_need are the job/need
3408
+ // siblings of the persona/competitor/metric peers (connective layer, 0.13.1).
3396
3409
  "shares_persona",
3397
3410
  "shares_competitor",
3398
3411
  "shares_metric",
3412
+ "shares_job",
3413
+ "shares_need",
3414
+ // Product-to-product relationships.
3399
3415
  "depends_on_product",
3416
+ // runtime dependency (built-on / dogfood), not containment
3400
3417
  "cannibalises",
3401
3418
  "succeeds",
3402
3419
  "hosts",
3420
+ // host runs the hosted product inside itself (container -> contained)
3421
+ // OKR / measurement rollup primitives: the cascade ACROSS products (subordinate
3422
+ // -> superior). `contributes_to` rolls a product strategy entity up to a higher-
3423
+ // level one; `rolls_up_to` feeds a product metric into a higher-level north-star.
3403
3424
  "contributes_to",
3425
+ "rolls_up_to",
3426
+ // Canonical instance + area-to-audience: the target lives in the portfolio
3427
+ // `registry` section (`registry/{node_id}`). `instance_of` is same-type
3428
+ // canonical-to-instance; the area edges are minted via `link_area_to_audience`.
3404
3429
  "instance_of",
3405
3430
  "area_serves_persona",
3406
3431
  "area_targets_market_segment",
3407
- "rolls_up_to",
3432
+ // Foundations (0.9.12): a product-graph entity links to a canonical specification
3433
+ // or primitive in the registry (`registry/{node_id}` target, same shape as
3434
+ // instance_of). Registry-internal spec-to-spec links are catalog edges, not these.
3408
3435
  "product_implements_specification",
3409
3436
  "product_exposes_specification",
3410
3437
  "feature_conforms_to_specification",
3411
3438
  "api_contract_speaks_specification",
3412
3439
  "product_exposes_primitive",
3413
3440
  "feature_manipulates_primitive",
3414
- "primitive_stored_as_data_type",
3415
- "feature_rivals_competitor_feature",
3416
- "competitor_signal_maps_to_feature",
3417
- "competitor_signal_surfaces_opportunity",
3418
- "competitor_classified_as_classification_value",
3419
- "node_classified_as_classification_value",
3420
- "journey_phase_realises_operating_stage",
3421
- "screen_markets_product",
3422
- "screen_renders_design_component",
3423
- "product_expresses_brand_identity",
3424
- // Connective cross-product layer (0.13.1) — see UPGCrossEdgeType above.
3425
- "shares_job",
3426
- "shares_need",
3427
- "persona_delegates_to_persona",
3428
- "screen_targets_competitor",
3429
- "feature_surfaces_product",
3430
- "feature_uses_design_component",
3431
- "product_implements_design_system",
3432
- // Org-link (0.17.0): dual-registered ownership edges (see UPGCrossEdgeType above).
3433
- "node_owned_by_team",
3434
- "node_owned_by_department",
3435
- // Cross-graph strategy & measurement (0.17.2): dual-registered OKR/measurement
3436
- // hierarchy edges so the strategy spine can span files (see UPGCrossEdgeType above).
3437
- "strategic_theme_contains_objective",
3438
- "objective_achieved_through_key_result",
3439
- "key_result_quantified_by_metric",
3440
- "objective_measured_by_metric"
3441
+ "primitive_stored_as_data_type"
3442
+ ];
3443
+ var UPG_CROSS_EDGE_TYPES = [
3444
+ ...UPG_CROSS_ONLY_EDGE_TYPES,
3445
+ ...UPG_CROSS_ELIGIBLE_CATALOG_EDGE_TYPES
3441
3446
  ];
3442
3447
  var REGISTRY_PRODUCT_ID = "registry";
3443
3448
  var UPG_PORTFOLIO_KINDS = ["owned", "watched", "strategic", "internal", "gtm"];
@@ -21279,6 +21284,30 @@ var UPG_TREE_PATTERNS = [
21279
21284
  metric: [opt("metric"), opt("outcome")]
21280
21285
  },
21281
21286
  natural_depth: 3
21287
+ },
21288
+ {
21289
+ id: "org",
21290
+ label: "Org chart",
21291
+ description: "Departments and the teams they contain, plus the sub-teams nested within those teams. The people-structure org chart, walked by containment (department_contains_team, then team_contains_team). Distinct from product_area, which is the product classification axis, not the org.",
21292
+ region: "operations_quality",
21293
+ gap_policy: "all-optional",
21294
+ anchor_type: "department",
21295
+ // A graph with no department roots at the team (team -> sub-team), reported
21296
+ // anchor_resolved_from: department. A sub-team also renders as a bare team
21297
+ // root when its parent department is not modelled.
21298
+ fallback_anchors: ["team"],
21299
+ child_map: {
21300
+ // department -> team (department_contains_team) is the first level; team ->
21301
+ // team (team_contains_team, 0.17.2) is the second, so a sub-team nested one
21302
+ // level deeper than department_contains_team renders under its parent team.
21303
+ // Self-nesting: the assembler's `seen` set terminates a team -> team cycle
21304
+ // for free (a team met again becomes a shared reference).
21305
+ department: [opt("team")],
21306
+ team: [opt("team")]
21307
+ },
21308
+ // Default to 3 tiers (department -> team -> sub-team); `depth` extends into
21309
+ // deeper team_contains_team nesting.
21310
+ natural_depth: 3
21282
21311
  }
21283
21312
  ];
21284
21313
  var UPG_TREE_PATTERNS_BY_ID = Object.fromEntries(
@@ -23068,6 +23097,12 @@ var STRATEGY_GUIDE = {
23068
23097
  description: "Vision grounds mission, product pursues outcomes and targets objectives, objectives achieved through key results measured by metrics",
23069
23098
  entity_types: ["vision", "mission", "outcome", "objective", "key_result", "metric"],
23070
23099
  edge_chain: ["product_guided_by_vision", "product_fulfils_mission", "vision_realised_through_mission", "product_pursues_outcome", "product_targets_objective", "objective_achieved_through_key_result", "outcome_measured_by_metric"]
23100
+ },
23101
+ {
23102
+ name: "Rendering the company spine",
23103
+ description: "The company OKR / strategy / north-star spine already renders with get_tree, no new pattern needed: switch to the org_rollup member (the company rollup graph) and run the okr, strategy, or north_star tree pattern there. In a portfolio the spine can span files, a rollup theme laddering into product-graph objectives through the cross-product strategic_theme_contains_objective edge; get_tree walks the active member, so render the rollup for the whole-company view and a product for its slice.",
23104
+ entity_types: ["strategic_theme", "objective", "key_result", "metric"],
23105
+ edge_chain: ["strategic_theme_contains_objective", "objective_achieved_through_key_result", "key_result_quantified_by_metric"]
23071
23106
  }
23072
23107
  ],
23073
23108
  required_bridges: [
@@ -29841,7 +29876,7 @@ function isCanonical(text) {
29841
29876
  }
29842
29877
 
29843
29878
  // src/index.ts
29844
- var UPG_VERSION = "0.17.2";
29879
+ var UPG_VERSION = "0.17.3";
29845
29880
  var UPG_FORMAT_VERSION = "0.4.0";
29846
29881
  var MARKDOWN_FORMAT_VERSION = "0.1";
29847
29882
  var UPG_TYPES = getTypes();
@@ -29944,6 +29979,8 @@ var UPG_META_COUNT = UPG_ENTITY_META.length;
29944
29979
  UPG_CONTAINMENT_FREE_TYPES,
29945
29980
  UPG_COUNT_BENCHMARKS,
29946
29981
  UPG_CROSS_EDGE_TYPES,
29982
+ UPG_CROSS_ELIGIBLE_CATALOG_EDGE_TYPES,
29983
+ UPG_CROSS_ONLY_EDGE_TYPES,
29947
29984
  UPG_DEPRECATED_TYPES,
29948
29985
  UPG_DOMAINS,
29949
29986
  UPG_DOMAIN_ACTIVATION,
@@ -30074,6 +30111,7 @@ var UPG_META_COUNT = UPG_ENTITY_META.length;
30074
30111
  isCanonical,
30075
30112
  isCanonicalProductStage,
30076
30113
  isContainmentFreeType,
30114
+ isCrossProductEligible,
30077
30115
  isDeprecatedType,
30078
30116
  isDomainGuideStep,
30079
30117
  isEntitySequenceStep,