@unified-product-graph/core 0.17.1 → 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 +146 -67
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +149 -15
- package/dist/index.d.ts +149 -15
- package/dist/index.js +143 -67
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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" },
|
|
@@ -2312,6 +2315,16 @@ var UPG_EDGE_CATALOG = {
|
|
|
2312
2315
|
// UPG_EDGE_MIGRATIONS['0.9.9'].
|
|
2313
2316
|
product_organised_into_department: { forward_verb: "organised_into", reverse_verb: "organises", classification: "hierarchy", source_type: "product", target_type: "department" },
|
|
2314
2317
|
department_contains_team: { forward_verb: "contains", reverse_verb: "belongs_to", classification: "hierarchy", source_type: "department", target_type: "team" },
|
|
2318
|
+
// Second-level team nesting (0.17.2). department_contains_team covers the first
|
|
2319
|
+
// level (department -> team); this covers a team nested inside another team in
|
|
2320
|
+
// the same department (a sub-team or squad under a parent team). Modelled
|
|
2321
|
+
// parent -> child like feature_area_contains_feature_area, so the org map builds
|
|
2322
|
+
// correctly in get_tree (which reads source as the parent); the reverse verb
|
|
2323
|
+
// belongs_to gives the upward "this team is part of that team" read. The
|
|
2324
|
+
// same-department expectation is advisory (a write-time warning), never a hard
|
|
2325
|
+
// block; cross-department reporting lines belong to person_reports_to_person at
|
|
2326
|
+
// the individual level.
|
|
2327
|
+
team_contains_team: { forward_verb: "contains", reverse_verb: "belongs_to", classification: "hierarchy", source_type: "team", target_type: "team" },
|
|
2315
2328
|
department_includes_stakeholder: { forward_verb: "includes", reverse_verb: "included_in", classification: "hierarchy", source_type: "department", target_type: "stakeholder" },
|
|
2316
2329
|
// NOTE: `person` is a containment-free entity type (see
|
|
2317
2330
|
// UPG_CONTAINMENT_FREE_TYPES in grammar/hierarchy.ts). It is referenced
|
|
@@ -2570,10 +2583,10 @@ var UPG_EDGE_CATALOG = {
|
|
|
2570
2583
|
experiment_run_measured_by_metric: { forward_verb: "measured_by", reverse_verb: "measures", classification: "hierarchy", source_type: "experiment_run", target_type: "metric" },
|
|
2571
2584
|
solution_measured_by_metric: { forward_verb: "measured_by", reverse_verb: "measures", classification: "hierarchy", source_type: "solution", target_type: "metric" },
|
|
2572
2585
|
// ── Cross-domain: Ownership ──────────────────────────────────────────────────
|
|
2573
|
-
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 },
|
|
2574
2587
|
node_owned_by_role: { forward_verb: "owned_by", reverse_verb: "owns", classification: "cross-domain", source_type: "node", target_type: "role" },
|
|
2575
2588
|
node_owned_by_stakeholder: { forward_verb: "owned_by", reverse_verb: "owns", classification: "cross-domain", source_type: "node", target_type: "stakeholder" },
|
|
2576
|
-
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 },
|
|
2577
2590
|
node_owned_by_person: { forward_verb: "owned_by", reverse_verb: "owns", classification: "cross-domain", source_type: "node", target_type: "person" },
|
|
2578
2591
|
// ── Cross-domain: Architecture (DDD) ─────────────────────────────────────────
|
|
2579
2592
|
// Service, domain_event, domain_entity, aggregate, read_model, api_contract,
|
|
@@ -3237,7 +3250,7 @@ var UPG_EDGE_CATALOG = {
|
|
|
3237
3250
|
// not the outcome it exists to move; the strategic spine was severed at its
|
|
3238
3251
|
// anchor (0 outbound to outcome). An objective ADVANCES an outcome. Intra-
|
|
3239
3252
|
// domain (both in strategy) and directional → causal.
|
|
3240
|
-
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 },
|
|
3241
3254
|
// ── F6: Priority 2 — scored / synthesis / verdict dead-end leaves (P-A) ─────
|
|
3242
3255
|
// desired_outcome (Ulwick-scored: importance × satisfaction) had 0 outbound —
|
|
3243
3256
|
// the scores could not flow anywhere. An under-served desired_outcome REVEALS
|
|
@@ -3320,9 +3333,16 @@ var UPG_EDGE_CATALOG = {
|
|
|
3320
3333
|
specification_governed_by_organization: { forward_verb: "governed_by", reverse_verb: "governs", classification: "semantic", source_type: "specification", target_type: "organization" },
|
|
3321
3334
|
// Operating-lifecycle cross-edges (0.11.6): a product's journey phase realises a canonical
|
|
3322
3335
|
// operating stage (the cross-surface join key); a stage is measured by a rollup metric (loop close).
|
|
3323
|
-
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 },
|
|
3324
3337
|
operating_stage_measured_by_metric: { forward_verb: "measured_by", reverse_verb: "measures", classification: "cross-domain", source_type: "operating_stage", target_type: "metric" }
|
|
3325
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
|
+
}
|
|
3326
3346
|
var UPG_POLYMORPHIC_EDGE_KEYS = [
|
|
3327
3347
|
// Universal semantic verbs
|
|
3328
3348
|
"node_informs_node",
|
|
@@ -3382,46 +3402,47 @@ function isLegacyProductStage(stage) {
|
|
|
3382
3402
|
}
|
|
3383
3403
|
|
|
3384
3404
|
// src/shapes/document.ts
|
|
3385
|
-
var
|
|
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).
|
|
3386
3409
|
"shares_persona",
|
|
3387
3410
|
"shares_competitor",
|
|
3388
3411
|
"shares_metric",
|
|
3412
|
+
"shares_job",
|
|
3413
|
+
"shares_need",
|
|
3414
|
+
// Product-to-product relationships.
|
|
3389
3415
|
"depends_on_product",
|
|
3416
|
+
// runtime dependency (built-on / dogfood), not containment
|
|
3390
3417
|
"cannibalises",
|
|
3391
3418
|
"succeeds",
|
|
3392
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.
|
|
3393
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`.
|
|
3394
3429
|
"instance_of",
|
|
3395
3430
|
"area_serves_persona",
|
|
3396
3431
|
"area_targets_market_segment",
|
|
3397
|
-
|
|
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.
|
|
3398
3435
|
"product_implements_specification",
|
|
3399
3436
|
"product_exposes_specification",
|
|
3400
3437
|
"feature_conforms_to_specification",
|
|
3401
3438
|
"api_contract_speaks_specification",
|
|
3402
3439
|
"product_exposes_primitive",
|
|
3403
3440
|
"feature_manipulates_primitive",
|
|
3404
|
-
"primitive_stored_as_data_type"
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
"node_classified_as_classification_value",
|
|
3410
|
-
"journey_phase_realises_operating_stage",
|
|
3411
|
-
"screen_markets_product",
|
|
3412
|
-
"screen_renders_design_component",
|
|
3413
|
-
"product_expresses_brand_identity",
|
|
3414
|
-
// Connective cross-product layer (0.13.1) — see UPGCrossEdgeType above.
|
|
3415
|
-
"shares_job",
|
|
3416
|
-
"shares_need",
|
|
3417
|
-
"persona_delegates_to_persona",
|
|
3418
|
-
"screen_targets_competitor",
|
|
3419
|
-
"feature_surfaces_product",
|
|
3420
|
-
"feature_uses_design_component",
|
|
3421
|
-
"product_implements_design_system",
|
|
3422
|
-
// Org-link (0.17.0): dual-registered ownership edges (see UPGCrossEdgeType above).
|
|
3423
|
-
"node_owned_by_team",
|
|
3424
|
-
"node_owned_by_department"
|
|
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
|
|
3425
3446
|
];
|
|
3426
3447
|
var REGISTRY_PRODUCT_ID = "registry";
|
|
3427
3448
|
var UPG_PORTFOLIO_KINDS = ["owned", "watched", "strategic", "internal", "gtm"];
|
|
@@ -3875,7 +3896,11 @@ var UPG_VALID_CHILDREN = {
|
|
|
3875
3896
|
"skill",
|
|
3876
3897
|
"ceremony",
|
|
3877
3898
|
"capacity_plan",
|
|
3878
|
-
"decision"
|
|
3899
|
+
"decision",
|
|
3900
|
+
// Self-nesting (0.17.2): a parent team contains its sub-teams / squads, one
|
|
3901
|
+
// level below department_contains_team. Backs team_contains_team. Mirrors
|
|
3902
|
+
// feature_area_contains_feature_area (same-type child listed last).
|
|
3903
|
+
"team"
|
|
3879
3904
|
],
|
|
3880
3905
|
// ── Data & Analytics hierarchy ───────────────────────────────────────────────
|
|
3881
3906
|
data_source: ["metric", "data_pipeline", "data_lineage", "event_schema"],
|
|
@@ -10868,6 +10893,7 @@ var UPG_PROPERTY_SCHEMA = {
|
|
|
10868
10893
|
// ConstraintProperties: Constraint: a named limitation or boundary on product creation.
|
|
10869
10894
|
constraint: {
|
|
10870
10895
|
constraint_kind: { type: "string", enum: ["resource", "technical", "regulatory", "temporal", "compliance", "other"], description: "Limitation category" },
|
|
10896
|
+
constraint_origin: { type: "string", enum: ["internal", "external"], description: "Provenance: internal (a self-imposed principle or operating tenet) or external (a limit, requirement, or ceiling imposed from outside)." },
|
|
10871
10897
|
constraint_status: { type: "string", enum: ["binding", "advisory", "lifted"], description: "Whether binding, advisory, or lifted" },
|
|
10872
10898
|
rule_strength: { type: "string", enum: ["must", "must_not", "exception", "warning", "guideline"], description: "Enforcement strictness. Reuses the governance/guideline rule vocabulary." },
|
|
10873
10899
|
source: { type: "string", description: "Free-text origin: policy document, regulation, stakeholder, technical doc." },
|
|
@@ -21258,6 +21284,30 @@ var UPG_TREE_PATTERNS = [
|
|
|
21258
21284
|
metric: [opt("metric"), opt("outcome")]
|
|
21259
21285
|
},
|
|
21260
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
|
|
21261
21311
|
}
|
|
21262
21312
|
];
|
|
21263
21313
|
var UPG_TREE_PATTERNS_BY_ID = Object.fromEntries(
|
|
@@ -23047,6 +23097,12 @@ var STRATEGY_GUIDE = {
|
|
|
23047
23097
|
description: "Vision grounds mission, product pursues outcomes and targets objectives, objectives achieved through key results measured by metrics",
|
|
23048
23098
|
entity_types: ["vision", "mission", "outcome", "objective", "key_result", "metric"],
|
|
23049
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"]
|
|
23050
23106
|
}
|
|
23051
23107
|
],
|
|
23052
23108
|
required_bridges: [
|
|
@@ -23057,7 +23113,8 @@ var STRATEGY_GUIDE = {
|
|
|
23057
23113
|
anti_patterns: [
|
|
23058
23114
|
{ description: "Outcomes without metrics. Measurement is the signal an outcome happened." },
|
|
23059
23115
|
{ description: "Objectives without key results: an objective without measurement is a wish" },
|
|
23060
|
-
{ description: "Too many strategic themes: focus beats breadth, aim for 2-4 active themes" }
|
|
23116
|
+
{ description: "Too many strategic themes: focus beats breadth, aim for 2-4 active themes" },
|
|
23117
|
+
{ description: "Constraints without an origin: a qualitative guardrail lives on a constraint, so set constraint_origin to say where it comes from. internal marks a self-imposed principle or operating tenet the team commits to; external marks a limit, requirement, or ceiling imposed from outside (a regulation, a budget cap, a platform bound)." }
|
|
23061
23118
|
]
|
|
23062
23119
|
};
|
|
23063
23120
|
var PRODUCT_SPEC_GUIDE = {
|
|
@@ -23608,6 +23665,12 @@ var TEAM_ORG_GUIDE = {
|
|
|
23608
23665
|
description: "Teams are staffed with roles, target OKRs, reflect in retrospectives, and are blocked by dependencies",
|
|
23609
23666
|
entity_types: ["team", "role", "team_okr", "retrospective", "dependency"],
|
|
23610
23667
|
edge_chain: ["team_staffed_with_role", "team_targets_team_okr", "team_reflects_in_retrospective", "dependency_blocks_team"]
|
|
23668
|
+
},
|
|
23669
|
+
{
|
|
23670
|
+
name: "Org Nesting",
|
|
23671
|
+
description: "A department contains its teams; a parent team contains its sub-teams or squads one level deeper. Keep a sub-team in the same department as its parent team. Cross-department reporting lines are modelled at the individual level with person_reports_to_person, not by nesting a team under a parent in another department.",
|
|
23672
|
+
entity_types: ["department", "team"],
|
|
23673
|
+
edge_chain: ["department_contains_team", "team_contains_team"]
|
|
23611
23674
|
}
|
|
23612
23675
|
],
|
|
23613
23676
|
required_bridges: [
|
|
@@ -23618,6 +23681,7 @@ var TEAM_ORG_GUIDE = {
|
|
|
23618
23681
|
{ description: "Teams without OKRs: every team needs clear goals" },
|
|
23619
23682
|
{ description: "Dependencies without both teams linked: a dependency must connect blocker and blocked" },
|
|
23620
23683
|
{ description: "Retrospectives without action items: reflection without action is just venting" },
|
|
23684
|
+
{ description: "Nesting a sub-team under a parent team in a different department: a team_contains_team nesting should stay within one department (both teams sharing a department_contains_team parent). A cross-department nesting is almost always a modelling error; model a cross-department reporting line at the individual level with person_reports_to_person instead." },
|
|
23621
23685
|
{ description: "Double-modelling the org as product_area and team_org: a product_area is the classification axis ON products (which area a product belongs to, the axis used to group products); a team_org department/team is the people structure (the org chart, who reports to whom). Use product_area to classify products and department/team for the org chart, and relate them through the team that owns an area rather than restating one as the other." }
|
|
23622
23686
|
]
|
|
23623
23687
|
};
|
|
@@ -26340,7 +26404,7 @@ var UPG_ANTI_PATTERNS = [
|
|
|
26340
26404
|
{
|
|
26341
26405
|
id: "competitors-missing-past-validation",
|
|
26342
26406
|
name: "Competitor catalogue empty past validation",
|
|
26343
|
-
description: "The graph has zero competitor entities at
|
|
26407
|
+
description: "The graph has zero competitor entities at build stage or later. Past validation, the absence of named competitors usually means alternatives haven't been thought through, not that none exist. A graph still at concept or validation is exempt: cataloguing the field can wait until you commit to building.",
|
|
26344
26408
|
structured_condition: {
|
|
26345
26409
|
check: {
|
|
26346
26410
|
type: "benchmark",
|
|
@@ -26350,14 +26414,18 @@ var UPG_ANTI_PATTERNS = [
|
|
|
26350
26414
|
},
|
|
26351
26415
|
why_it_matters: "Without competitors in the graph, positioning, differentiation, and switching-cost analysis lack referents. The team is reasoning in a vacuum.",
|
|
26352
26416
|
remediation: "Catalogue the 3\u20135 closest alternatives users would pick today. Use `/upg-compete` to author.",
|
|
26353
|
-
|
|
26417
|
+
// Fires from build onward, matching the name (past the validation stage). A
|
|
26418
|
+
// concept or validation graph is still framing the problem; holding it to a
|
|
26419
|
+
// competitor benchmark there is the false alarm this anti-pattern caused on
|
|
26420
|
+
// legitimately-young graphs.
|
|
26421
|
+
stages: ["build", "beta", "launch", "growth", "mature"],
|
|
26354
26422
|
severity: "medium",
|
|
26355
26423
|
source: { kind: "industry_practice", category: "product_strategy" }
|
|
26356
26424
|
},
|
|
26357
26425
|
{
|
|
26358
26426
|
id: "persona-count-below-stage-benchmark",
|
|
26359
26427
|
name: "Persona count below stage benchmark",
|
|
26360
|
-
description: "The graph has fewer personas than the stage-appropriate benchmark expects. Persona under-coverage signals the team has not segmented its audience.",
|
|
26428
|
+
description: "The graph has fewer personas than the stage-appropriate benchmark expects, from beta onward. Persona under-coverage at that point signals the team has not segmented its audience. Concept through build are exempt: the sound move there is to start with one beachhead persona and expand as you find fit.",
|
|
26361
26429
|
structured_condition: {
|
|
26362
26430
|
check: {
|
|
26363
26431
|
type: "benchmark",
|
|
@@ -26365,9 +26433,13 @@ var UPG_ANTI_PATTERNS = [
|
|
|
26365
26433
|
comparison: "below_min"
|
|
26366
26434
|
}
|
|
26367
26435
|
},
|
|
26368
|
-
why_it_matters:
|
|
26436
|
+
why_it_matters: "A graph still on a single persona by beta is usually carrying an unexamined assumption that every user is the same.",
|
|
26369
26437
|
remediation: "Add personas representing the next 1\u20132 most distinct user segments. Use `/upg-new-persona`.",
|
|
26370
|
-
|
|
26438
|
+
// Fires from beta onward. The persona benchmark expects 2+ from validation,
|
|
26439
|
+
// but the canonical beachhead move is to start with one persona and expand as
|
|
26440
|
+
// fit is found, so holding a build-stage graph to a multi-persona bar is a
|
|
26441
|
+
// false alarm. By beta an unsegmented audience is a real signal.
|
|
26442
|
+
stages: ["beta", "launch", "growth", "mature"],
|
|
26371
26443
|
severity: "medium",
|
|
26372
26444
|
source: { kind: "practitioner", attribution: "Alan Cooper, The Inmates Are Running the Asylum" }
|
|
26373
26445
|
},
|
|
@@ -26392,7 +26464,7 @@ var UPG_ANTI_PATTERNS = [
|
|
|
26392
26464
|
{
|
|
26393
26465
|
id: "single-domain-graph",
|
|
26394
26466
|
name: "Single-domain graph",
|
|
26395
|
-
description: "The graph has more than five entities but they all live in a single UPG domain. A real product spans multiple domains; a single-domain graph is usually a deep notebook in one corner with the rest of the picture missing.",
|
|
26467
|
+
description: "The graph has more than five entities but they all live in a single UPG domain, at beta stage or later. A real product spans multiple domains by then; a single-domain graph that far along is usually a deep notebook in one corner with the rest of the picture missing. Concept through build are exempt: a graph legitimately starts deep in one domain and broadens as it matures.",
|
|
26396
26468
|
structured_condition: {
|
|
26397
26469
|
operator: "and",
|
|
26398
26470
|
checks: [
|
|
@@ -26402,7 +26474,11 @@ var UPG_ANTI_PATTERNS = [
|
|
|
26402
26474
|
},
|
|
26403
26475
|
why_it_matters: 'Single-domain coverage prevents cross-domain reasoning. The graph cannot answer questions like "which feature serves which persona?" or "which experiment validates which hypothesis?".',
|
|
26404
26476
|
remediation: "Identify the next adjacent domain (usually `user`, `validation`, or `product_spec`) and add 2\u20133 anchor entities to bridge.",
|
|
26405
|
-
|
|
26477
|
+
// Fires from beta onward. Early on a graph is legitimately deep in one domain
|
|
26478
|
+
// (a discovery notebook, a thin internal tool); only once it reaches beta is
|
|
26479
|
+
// single-domain coverage a smell rather than a normal starting shape. Extends
|
|
26480
|
+
// through growth and mature, where a single-domain graph is most telling.
|
|
26481
|
+
stages: ["beta", "launch", "growth", "mature"],
|
|
26406
26482
|
severity: "medium",
|
|
26407
26483
|
source: { kind: "fundamental" }
|
|
26408
26484
|
},
|
|
@@ -29800,7 +29876,7 @@ function isCanonical(text) {
|
|
|
29800
29876
|
}
|
|
29801
29877
|
|
|
29802
29878
|
// src/index.ts
|
|
29803
|
-
var UPG_VERSION = "0.17.
|
|
29879
|
+
var UPG_VERSION = "0.17.3";
|
|
29804
29880
|
var UPG_FORMAT_VERSION = "0.4.0";
|
|
29805
29881
|
var MARKDOWN_FORMAT_VERSION = "0.1";
|
|
29806
29882
|
var UPG_TYPES = getTypes();
|
|
@@ -29903,6 +29979,8 @@ var UPG_META_COUNT = UPG_ENTITY_META.length;
|
|
|
29903
29979
|
UPG_CONTAINMENT_FREE_TYPES,
|
|
29904
29980
|
UPG_COUNT_BENCHMARKS,
|
|
29905
29981
|
UPG_CROSS_EDGE_TYPES,
|
|
29982
|
+
UPG_CROSS_ELIGIBLE_CATALOG_EDGE_TYPES,
|
|
29983
|
+
UPG_CROSS_ONLY_EDGE_TYPES,
|
|
29906
29984
|
UPG_DEPRECATED_TYPES,
|
|
29907
29985
|
UPG_DOMAINS,
|
|
29908
29986
|
UPG_DOMAIN_ACTIVATION,
|
|
@@ -30033,6 +30111,7 @@ var UPG_META_COUNT = UPG_ENTITY_META.length;
|
|
|
30033
30111
|
isCanonical,
|
|
30034
30112
|
isCanonicalProductStage,
|
|
30035
30113
|
isContainmentFreeType,
|
|
30114
|
+
isCrossProductEligible,
|
|
30036
30115
|
isDeprecatedType,
|
|
30037
30116
|
isDomainGuideStep,
|
|
30038
30117
|
isEntitySequenceStep,
|