@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.js
CHANGED
|
@@ -1029,7 +1029,7 @@ var UPG_EDGE_CATALOG = {
|
|
|
1029
1029
|
persona_aspires_to_desired_outcome: { forward_verb: "aspires_to", reverse_verb: "aspirational_for", classification: "hierarchy", source_type: "persona", target_type: "desired_outcome" },
|
|
1030
1030
|
// Delegation (0.11.6): a persona delegates work to another. The common case is human -> agent
|
|
1031
1031
|
// (Content Ops Lead -> Content Agent), but it also expresses human -> human (editor -> reviewer).
|
|
1032
|
-
persona_delegates_to_persona: { forward_verb: "delegates_to", reverse_verb: "delegated_by", classification: "semantic", source_type: "persona", target_type: "persona" },
|
|
1032
|
+
persona_delegates_to_persona: { forward_verb: "delegates_to", reverse_verb: "delegated_by", classification: "semantic", source_type: "persona", target_type: "persona", cross_product_eligible: true },
|
|
1033
1033
|
persona_incurs_switching_cost: { forward_verb: "incurs", reverse_verb: "incurred_by", classification: "hierarchy", source_type: "persona", target_type: "switching_cost" },
|
|
1034
1034
|
job_surfaces_need: { forward_verb: "surfaces", reverse_verb: "surfaces_from", classification: "causal", source_type: "job", target_type: "need" },
|
|
1035
1035
|
job_motivates_desired_outcome: { forward_verb: "motivates", reverse_verb: "motivated_by", classification: "causal", source_type: "job", target_type: "desired_outcome" },
|
|
@@ -1147,15 +1147,15 @@ var UPG_EDGE_CATALOG = {
|
|
|
1147
1147
|
// Dual-registered as a cross-edge (UPG_CROSS_EDGE_TYPES) so it also spans our
|
|
1148
1148
|
// product graph and a watched competitor-intelligence graph. Distinct from
|
|
1149
1149
|
// `competitor_feature_inspires_feature` (ideation lineage, not parity).
|
|
1150
|
-
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 },
|
|
1150
|
+
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 },
|
|
1151
1151
|
// 0.10.0 (spec issue #41): competitor_signal is a dated competitor move (feature
|
|
1152
1152
|
// launch / pricing change / acquisition / partnership / market entry) emitted by a
|
|
1153
1153
|
// competitor and mapped onto our portfolio. `emits` is within the watched graph;
|
|
1154
1154
|
// `maps_to_feature` / `surfaces_opportunity` cross from the watched signal into our
|
|
1155
1155
|
// product graph (dual-registered as cross-edges in UPG_CROSS_EDGE_TYPES).
|
|
1156
1156
|
competitor_emits_competitor_signal: { forward_verb: "emits", reverse_verb: "emitted_by", classification: "hierarchy", source_type: "competitor", target_type: "competitor_signal" },
|
|
1157
|
-
competitor_signal_maps_to_feature: { forward_verb: "maps_to", reverse_verb: "targeted_by_signal", classification: "cross-domain", source_type: "competitor_signal", target_type: "feature" },
|
|
1158
|
-
competitor_signal_surfaces_opportunity: { forward_verb: "surfaces", reverse_verb: "prompted_by_signal", classification: "cross-domain", source_type: "competitor_signal", target_type: "opportunity" },
|
|
1157
|
+
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 },
|
|
1158
|
+
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 },
|
|
1159
1159
|
competitive_analysis_analyses_competitor: { forward_verb: "analyses", reverse_verb: "analysed_in", classification: "hierarchy", source_type: "competitive_analysis", target_type: "competitor" },
|
|
1160
1160
|
competitive_analysis_identifies_market_trend: { forward_verb: "identifies", reverse_verb: "identified_in", classification: "hierarchy", source_type: "competitive_analysis", target_type: "market_trend" },
|
|
1161
1161
|
competitive_analysis_scopes_market_segment: { forward_verb: "scopes", reverse_verb: "scoped_in", classification: "hierarchy", source_type: "competitive_analysis", target_type: "market_segment" },
|
|
@@ -1188,13 +1188,13 @@ var UPG_EDGE_CATALOG = {
|
|
|
1188
1188
|
// competitor can be classified directly against a `registry/{classification_value}`
|
|
1189
1189
|
// canonical, eliminating the per-graph taxonomy node. Within-graph (the catalogue
|
|
1190
1190
|
// case) here; cross-product against the registry canonical via create_cross_product_edge.
|
|
1191
|
-
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 },
|
|
1191
|
+
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 },
|
|
1192
1192
|
// 0.10.3: the polymorphic, type-agnostic sibling. ANY node (a feature, a
|
|
1193
1193
|
// product, a market_segment) classified against a classification_value, so
|
|
1194
1194
|
// classification is not welded to the competitor type. Also dual-registered as
|
|
1195
1195
|
// a cross-edge for the registry-canonical case. source_type:'node' (wildcard);
|
|
1196
1196
|
// listed in UPG_POLYMORPHIC_EDGE_KEYS.
|
|
1197
|
-
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 },
|
|
1197
|
+
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 },
|
|
1198
1198
|
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" },
|
|
1199
1199
|
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" },
|
|
1200
1200
|
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" },
|
|
@@ -1247,28 +1247,28 @@ var UPG_EDGE_CATALOG = {
|
|
|
1247
1247
|
feedback_program_has_beta_program: { forward_verb: "has", reverse_verb: "part_of", classification: "hierarchy", source_type: "feedback_program", target_type: "beta_program" },
|
|
1248
1248
|
// ── Part 2: Strategic & Execution Spine (Ring 2) ───────────────────────────
|
|
1249
1249
|
// 2.1 Strategic Domain
|
|
1250
|
-
product_pursues_outcome: { forward_verb: "pursues", reverse_verb: "pursued_by", classification: "hierarchy", source_type: "product", target_type: "outcome" },
|
|
1251
|
-
product_targets_objective: { forward_verb: "targets", reverse_verb: "targeted_by", classification: "hierarchy", source_type: "product", target_type: "objective" },
|
|
1252
|
-
product_guided_by_vision: { forward_verb: "guided_by", reverse_verb: "guides", classification: "hierarchy", source_type: "product", target_type: "vision" },
|
|
1250
|
+
product_pursues_outcome: { forward_verb: "pursues", reverse_verb: "pursued_by", classification: "hierarchy", source_type: "product", target_type: "outcome", cross_product_eligible: true },
|
|
1251
|
+
product_targets_objective: { forward_verb: "targets", reverse_verb: "targeted_by", classification: "hierarchy", source_type: "product", target_type: "objective", cross_product_eligible: true },
|
|
1252
|
+
product_guided_by_vision: { forward_verb: "guided_by", reverse_verb: "guides", classification: "hierarchy", source_type: "product", target_type: "vision", cross_product_eligible: true },
|
|
1253
1253
|
// product→{mission,strategic_theme,strategic_pillar,initiative,capability,value_stream,assumption}
|
|
1254
1254
|
// are semantic "how the product relates to the strategic cascade", not containment.
|
|
1255
1255
|
// The containment chain is product → vision → mission → strategic_pillar → … so these
|
|
1256
1256
|
// targets are reachable via the vision/mission hierarchy already.
|
|
1257
|
-
product_fulfils_mission: { forward_verb: "fulfils", reverse_verb: "fulfilled_by", classification: "semantic", source_type: "product", target_type: "mission" },
|
|
1258
|
-
product_organises_around_strategic_theme: { forward_verb: "organises_around", reverse_verb: "organises", classification: "semantic", source_type: "product", target_type: "strategic_theme" },
|
|
1259
|
-
product_stands_on_strategic_pillar: { forward_verb: "stands_on", reverse_verb: "supports", classification: "semantic", source_type: "product", target_type: "strategic_pillar" },
|
|
1260
|
-
product_invests_in_initiative: { forward_verb: "invests_in", reverse_verb: "investment_of", classification: "semantic", source_type: "product", target_type: "initiative" },
|
|
1257
|
+
product_fulfils_mission: { forward_verb: "fulfils", reverse_verb: "fulfilled_by", classification: "semantic", source_type: "product", target_type: "mission", cross_product_eligible: true },
|
|
1258
|
+
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 },
|
|
1259
|
+
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 },
|
|
1260
|
+
product_invests_in_initiative: { forward_verb: "invests_in", reverse_verb: "investment_of", classification: "semantic", source_type: "product", target_type: "initiative", cross_product_eligible: true },
|
|
1261
1261
|
product_develops_capability: { forward_verb: "develops", reverse_verb: "developed_by", classification: "semantic", source_type: "product", target_type: "capability" },
|
|
1262
1262
|
product_delivers_through_value_stream: { forward_verb: "delivers_through", reverse_verb: "delivers_for", classification: "semantic", source_type: "product", target_type: "value_stream" },
|
|
1263
1263
|
product_holds_assumption: { forward_verb: "holds", reverse_verb: "held_by", classification: "semantic", source_type: "product", target_type: "assumption" },
|
|
1264
|
-
product_measures_with_metric: { forward_verb: "measures_with", reverse_verb: "measures", classification: "hierarchy", source_type: "product", target_type: "metric" },
|
|
1265
|
-
outcome_measured_by_metric: { forward_verb: "measured_by", reverse_verb: "measures", classification: "hierarchy", source_type: "outcome", target_type: "metric" },
|
|
1264
|
+
product_measures_with_metric: { forward_verb: "measures_with", reverse_verb: "measures", classification: "hierarchy", source_type: "product", target_type: "metric", cross_product_eligible: true },
|
|
1265
|
+
outcome_measured_by_metric: { forward_verb: "measured_by", reverse_verb: "measures", classification: "hierarchy", source_type: "outcome", target_type: "metric", cross_product_eligible: true },
|
|
1266
1266
|
// (UPG-677) outcome_tracked_by_metric retired — near-synonym of
|
|
1267
1267
|
// outcome_measured_by_metric (the kept canonical key). Captain's lean =
|
|
1268
1268
|
// collapse. See UPG_EDGE_MIGRATIONS['0.9.9'].
|
|
1269
|
-
objective_achieved_through_key_result: { forward_verb: "achieved_through", reverse_verb: "achieves", classification: "hierarchy", source_type: "objective", target_type: "key_result" },
|
|
1270
|
-
objective_measured_by_metric: { forward_verb: "measured_by", reverse_verb: "measures", classification: "hierarchy", source_type: "objective", target_type: "metric" },
|
|
1271
|
-
key_result_quantified_by_metric: { forward_verb: "quantified_by", reverse_verb: "quantifies", classification: "hierarchy", source_type: "key_result", target_type: "metric" },
|
|
1269
|
+
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 },
|
|
1270
|
+
objective_measured_by_metric: { forward_verb: "measured_by", reverse_verb: "measures", classification: "hierarchy", source_type: "objective", target_type: "metric", cross_product_eligible: true },
|
|
1271
|
+
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 },
|
|
1272
1272
|
// (UPG-677) key_result_tracked_by_metric retired — near-synonym of
|
|
1273
1273
|
// key_result_quantified_by_metric (the kept canonical key). Captain's lean =
|
|
1274
1274
|
// collapse. See UPG_EDGE_MIGRATIONS['0.9.9'].
|
|
@@ -1278,7 +1278,7 @@ var UPG_EDGE_CATALOG = {
|
|
|
1278
1278
|
strategic_pillar_enables_capability: { forward_verb: "enables", reverse_verb: "enabled_by", classification: "hierarchy", source_type: "strategic_pillar", target_type: "capability" },
|
|
1279
1279
|
strategic_pillar_delivers_value_stream: { forward_verb: "delivers", reverse_verb: "delivered_by", classification: "hierarchy", source_type: "strategic_pillar", target_type: "value_stream" },
|
|
1280
1280
|
strategic_pillar_decided_via_decision: { forward_verb: "decided_via", reverse_verb: "decided_for", classification: "hierarchy", source_type: "strategic_pillar", target_type: "decision" },
|
|
1281
|
-
strategic_theme_pursues_initiative: { forward_verb: "pursues", reverse_verb: "pursued_under", classification: "hierarchy", source_type: "strategic_theme", target_type: "initiative" },
|
|
1281
|
+
strategic_theme_pursues_initiative: { forward_verb: "pursues", reverse_verb: "pursued_under", classification: "hierarchy", source_type: "strategic_theme", target_type: "initiative", cross_product_eligible: true },
|
|
1282
1282
|
// v0.9.0 (UPG-660): the soft bridge from the annual strategy focus area to the
|
|
1283
1283
|
// roadmap grouping that realises it. Semantic, NOT hierarchy: strategic_theme and
|
|
1284
1284
|
// roadmap_theme sit on different spines (strategy cascade vs roadmap cascade), so
|
|
@@ -1306,11 +1306,11 @@ var UPG_EDGE_CATALOG = {
|
|
|
1306
1306
|
// surfaces the upward-rollup read. Mirrors `strategic_pillar_organises_
|
|
1307
1307
|
// strategic_theme` (pillar → theme), completing the strategic cascade:
|
|
1308
1308
|
// strategic_pillar → strategic_theme → objective → key_result.
|
|
1309
|
-
strategic_theme_delivers_outcome: { forward_verb: "delivers", reverse_verb: "delivered_by", classification: "causal", source_type: "strategic_theme", target_type: "outcome" },
|
|
1310
|
-
strategic_theme_measured_by_key_result: { forward_verb: "measured_by", reverse_verb: "measures", classification: "causal", source_type: "strategic_theme", target_type: "key_result" },
|
|
1311
|
-
strategic_theme_contains_objective: { forward_verb: "contains", reverse_verb: "rolls_up_to", classification: "hierarchy", source_type: "strategic_theme", target_type: "objective" },
|
|
1309
|
+
strategic_theme_delivers_outcome: { forward_verb: "delivers", reverse_verb: "delivered_by", classification: "causal", source_type: "strategic_theme", target_type: "outcome", cross_product_eligible: true },
|
|
1310
|
+
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 },
|
|
1311
|
+
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 },
|
|
1312
1312
|
initiative_assumes_assumption: { forward_verb: "assumes", reverse_verb: "assumed_by", classification: "hierarchy", source_type: "initiative", target_type: "assumption" },
|
|
1313
|
-
initiative_drives_outcome: { forward_verb: "drives", reverse_verb: "driven_by", classification: "cross-domain", source_type: "initiative", target_type: "outcome" },
|
|
1313
|
+
initiative_drives_outcome: { forward_verb: "drives", reverse_verb: "driven_by", classification: "cross-domain", source_type: "initiative", target_type: "outcome", cross_product_eligible: true },
|
|
1314
1314
|
capability_enables_value_stream: { forward_verb: "enables", reverse_verb: "enabled_by", classification: "cross-domain", source_type: "capability", target_type: "value_stream" },
|
|
1315
1315
|
// v0.5.2 (UPG-528): three capability-anchored edges that complete the
|
|
1316
1316
|
// Wardley-style value chain: need → capability → capability → feature.
|
|
@@ -1448,7 +1448,7 @@ var UPG_EDGE_CATALOG = {
|
|
|
1448
1448
|
// brand_identity. Dual-registered: also a cross-edge for the common case where the
|
|
1449
1449
|
// brand is a registry singleton in another graph (the ratified pattern: brand is a
|
|
1450
1450
|
// singleton expressed, not instance_of-d); this catalog entry is the within-graph case.
|
|
1451
|
-
product_expresses_brand_identity: { forward_verb: "expresses", reverse_verb: "expressed_by", classification: "semantic", source_type: "product", target_type: "brand_identity" },
|
|
1451
|
+
product_expresses_brand_identity: { forward_verb: "expresses", reverse_verb: "expressed_by", classification: "semantic", source_type: "product", target_type: "brand_identity", cross_product_eligible: true },
|
|
1452
1452
|
design_system_encompasses_user_journey: { forward_verb: "encompasses", reverse_verb: "encompassed_in", classification: "hierarchy", source_type: "design_system", target_type: "user_journey" },
|
|
1453
1453
|
design_system_encompasses_user_flow: { forward_verb: "encompasses", reverse_verb: "encompassed_in", classification: "hierarchy", source_type: "design_system", target_type: "user_flow" },
|
|
1454
1454
|
design_system_informed_by_insight: { forward_verb: "informed_by", reverse_verb: "informs", classification: "hierarchy", source_type: "design_system", target_type: "insight" },
|
|
@@ -1460,12 +1460,12 @@ var UPG_EDGE_CATALOG = {
|
|
|
1460
1460
|
design_component_specified_by_interaction_spec: { forward_verb: "specified_by", reverse_verb: "specifies", classification: "hierarchy", source_type: "design_component", target_type: "interaction_spec" },
|
|
1461
1461
|
design_component_composes_design_component: { forward_verb: "composes", reverse_verb: "composed_in", classification: "hierarchy", source_type: "design_component", target_type: "design_component" },
|
|
1462
1462
|
prototype_annotated_with_annotation: { forward_verb: "annotated_with", reverse_verb: "annotates", classification: "hierarchy", source_type: "prototype", target_type: "annotation" },
|
|
1463
|
-
screen_renders_design_component: { forward_verb: "renders", reverse_verb: "rendered_on", classification: "hierarchy", source_type: "screen", target_type: "design_component" },
|
|
1463
|
+
screen_renders_design_component: { forward_verb: "renders", reverse_verb: "rendered_on", classification: "hierarchy", source_type: "screen", target_type: "design_component", cross_product_eligible: true },
|
|
1464
1464
|
// Marketing surface to product (0.12.7, UPG-696/698). A marketing/landing screen
|
|
1465
1465
|
// markets a product. Dual-registered: also a cross-edge (UPG_CROSS_EDGE_TYPES) for
|
|
1466
1466
|
// the common case where the product lives in another graph; this catalog entry is
|
|
1467
1467
|
// the within-graph degenerate case (a product's own landing page).
|
|
1468
|
-
screen_markets_product: { forward_verb: "markets", reverse_verb: "marketed_by", classification: "semantic", source_type: "screen", target_type: "product" },
|
|
1468
|
+
screen_markets_product: { forward_verb: "markets", reverse_verb: "marketed_by", classification: "semantic", source_type: "screen", target_type: "product", cross_product_eligible: true },
|
|
1469
1469
|
// Connective cross-product references (0.13.1, Data's connective-layer brief).
|
|
1470
1470
|
// Dual-registered (also in UPG_CROSS_EDGE_TYPES) for the common cross-graph case;
|
|
1471
1471
|
// these catalog entries are the within-graph degenerate case.
|
|
@@ -1481,10 +1481,10 @@ var UPG_EDGE_CATALOG = {
|
|
|
1481
1481
|
// system (the adoption semantic, mirroring product_implements_specification). Distinct
|
|
1482
1482
|
// from the hierarchy `product_systematised_in_design_system` (structural containment):
|
|
1483
1483
|
// same pattern as brand (branded_as = hierarchy, expresses = semantic).
|
|
1484
|
-
screen_targets_competitor: { forward_verb: "targets", reverse_verb: "targeted_by", classification: "semantic", source_type: "screen", target_type: "competitor" },
|
|
1485
|
-
feature_surfaces_product: { forward_verb: "surfaces", reverse_verb: "surfaced_by", classification: "semantic", source_type: "feature", target_type: "product" },
|
|
1486
|
-
feature_uses_design_component: { forward_verb: "uses", reverse_verb: "used_by", classification: "semantic", source_type: "feature", target_type: "design_component" },
|
|
1487
|
-
product_implements_design_system: { forward_verb: "implements", reverse_verb: "implemented_by", classification: "semantic", source_type: "product", target_type: "design_system" },
|
|
1484
|
+
screen_targets_competitor: { forward_verb: "targets", reverse_verb: "targeted_by", classification: "semantic", source_type: "screen", target_type: "competitor", cross_product_eligible: true },
|
|
1485
|
+
feature_surfaces_product: { forward_verb: "surfaces", reverse_verb: "surfaced_by", classification: "semantic", source_type: "feature", target_type: "product", cross_product_eligible: true },
|
|
1486
|
+
feature_uses_design_component: { forward_verb: "uses", reverse_verb: "used_by", classification: "semantic", source_type: "feature", target_type: "design_component", cross_product_eligible: true },
|
|
1487
|
+
product_implements_design_system: { forward_verb: "implements", reverse_verb: "implemented_by", classification: "semantic", source_type: "product", target_type: "design_system", cross_product_eligible: true },
|
|
1488
1488
|
screen_navigates_to_screen: { forward_verb: "navigates_to", reverse_verb: "navigated_from", classification: "hierarchy", source_type: "screen", target_type: "screen" },
|
|
1489
1489
|
screen_surfaces_feature: { forward_verb: "surfaces", reverse_verb: "surfaced_on", classification: "cross-domain", source_type: "screen", target_type: "feature" },
|
|
1490
1490
|
screen_wireframed_as_wireframe: { forward_verb: "wireframed_as", reverse_verb: "wireframes", classification: "hierarchy", source_type: "screen", target_type: "wireframe" },
|
|
@@ -2068,6 +2068,16 @@ var UPG_EDGE_CATALOG = {
|
|
|
2068
2068
|
// UPG_EDGE_MIGRATIONS['0.9.9'].
|
|
2069
2069
|
product_organised_into_department: { forward_verb: "organised_into", reverse_verb: "organises", classification: "hierarchy", source_type: "product", target_type: "department" },
|
|
2070
2070
|
department_contains_team: { forward_verb: "contains", reverse_verb: "belongs_to", classification: "hierarchy", source_type: "department", target_type: "team" },
|
|
2071
|
+
// Second-level team nesting (0.17.2). department_contains_team covers the first
|
|
2072
|
+
// level (department -> team); this covers a team nested inside another team in
|
|
2073
|
+
// the same department (a sub-team or squad under a parent team). Modelled
|
|
2074
|
+
// parent -> child like feature_area_contains_feature_area, so the org map builds
|
|
2075
|
+
// correctly in get_tree (which reads source as the parent); the reverse verb
|
|
2076
|
+
// belongs_to gives the upward "this team is part of that team" read. The
|
|
2077
|
+
// same-department expectation is advisory (a write-time warning), never a hard
|
|
2078
|
+
// block; cross-department reporting lines belong to person_reports_to_person at
|
|
2079
|
+
// the individual level.
|
|
2080
|
+
team_contains_team: { forward_verb: "contains", reverse_verb: "belongs_to", classification: "hierarchy", source_type: "team", target_type: "team" },
|
|
2071
2081
|
department_includes_stakeholder: { forward_verb: "includes", reverse_verb: "included_in", classification: "hierarchy", source_type: "department", target_type: "stakeholder" },
|
|
2072
2082
|
// NOTE: `person` is a containment-free entity type (see
|
|
2073
2083
|
// UPG_CONTAINMENT_FREE_TYPES in grammar/hierarchy.ts). It is referenced
|
|
@@ -2326,10 +2336,10 @@ var UPG_EDGE_CATALOG = {
|
|
|
2326
2336
|
experiment_run_measured_by_metric: { forward_verb: "measured_by", reverse_verb: "measures", classification: "hierarchy", source_type: "experiment_run", target_type: "metric" },
|
|
2327
2337
|
solution_measured_by_metric: { forward_verb: "measured_by", reverse_verb: "measures", classification: "hierarchy", source_type: "solution", target_type: "metric" },
|
|
2328
2338
|
// ── Cross-domain: Ownership ──────────────────────────────────────────────────
|
|
2329
|
-
node_owned_by_team: { forward_verb: "owned_by", reverse_verb: "owns", classification: "cross-domain", source_type: "node", target_type: "team" },
|
|
2339
|
+
node_owned_by_team: { forward_verb: "owned_by", reverse_verb: "owns", classification: "cross-domain", source_type: "node", target_type: "team", cross_product_eligible: true },
|
|
2330
2340
|
node_owned_by_role: { forward_verb: "owned_by", reverse_verb: "owns", classification: "cross-domain", source_type: "node", target_type: "role" },
|
|
2331
2341
|
node_owned_by_stakeholder: { forward_verb: "owned_by", reverse_verb: "owns", classification: "cross-domain", source_type: "node", target_type: "stakeholder" },
|
|
2332
|
-
node_owned_by_department: { forward_verb: "owned_by", reverse_verb: "owns", classification: "cross-domain", source_type: "node", target_type: "department" },
|
|
2342
|
+
node_owned_by_department: { forward_verb: "owned_by", reverse_verb: "owns", classification: "cross-domain", source_type: "node", target_type: "department", cross_product_eligible: true },
|
|
2333
2343
|
node_owned_by_person: { forward_verb: "owned_by", reverse_verb: "owns", classification: "cross-domain", source_type: "node", target_type: "person" },
|
|
2334
2344
|
// ── Cross-domain: Architecture (DDD) ─────────────────────────────────────────
|
|
2335
2345
|
// Service, domain_event, domain_entity, aggregate, read_model, api_contract,
|
|
@@ -2993,7 +3003,7 @@ var UPG_EDGE_CATALOG = {
|
|
|
2993
3003
|
// not the outcome it exists to move; the strategic spine was severed at its
|
|
2994
3004
|
// anchor (0 outbound to outcome). An objective ADVANCES an outcome. Intra-
|
|
2995
3005
|
// domain (both in strategy) and directional → causal.
|
|
2996
|
-
objective_advances_outcome: { forward_verb: "advances", reverse_verb: "advanced_by", classification: "causal", source_type: "objective", target_type: "outcome" },
|
|
3006
|
+
objective_advances_outcome: { forward_verb: "advances", reverse_verb: "advanced_by", classification: "causal", source_type: "objective", target_type: "outcome", cross_product_eligible: true },
|
|
2997
3007
|
// ── F6: Priority 2 — scored / synthesis / verdict dead-end leaves (P-A) ─────
|
|
2998
3008
|
// desired_outcome (Ulwick-scored: importance × satisfaction) had 0 outbound —
|
|
2999
3009
|
// the scores could not flow anywhere. An under-served desired_outcome REVEALS
|
|
@@ -3076,9 +3086,16 @@ var UPG_EDGE_CATALOG = {
|
|
|
3076
3086
|
specification_governed_by_organization: { forward_verb: "governed_by", reverse_verb: "governs", classification: "semantic", source_type: "specification", target_type: "organization" },
|
|
3077
3087
|
// Operating-lifecycle cross-edges (0.11.6): a product's journey phase realises a canonical
|
|
3078
3088
|
// operating stage (the cross-surface join key); a stage is measured by a rollup metric (loop close).
|
|
3079
|
-
journey_phase_realises_operating_stage: { forward_verb: "realises", reverse_verb: "realised_by", classification: "cross-domain", source_type: "journey_phase", target_type: "operating_stage" },
|
|
3089
|
+
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 },
|
|
3080
3090
|
operating_stage_measured_by_metric: { forward_verb: "measured_by", reverse_verb: "measures", classification: "cross-domain", source_type: "operating_stage", target_type: "metric" }
|
|
3081
3091
|
};
|
|
3092
|
+
var UPG_CROSS_ELIGIBLE_CATALOG_EDGE_TYPES = Object.keys(UPG_EDGE_CATALOG).filter(
|
|
3093
|
+
(k) => UPG_EDGE_CATALOG[k].cross_product_eligible === true
|
|
3094
|
+
);
|
|
3095
|
+
function isCrossProductEligible(type) {
|
|
3096
|
+
const def = UPG_EDGE_CATALOG[type];
|
|
3097
|
+
return def?.cross_product_eligible === true;
|
|
3098
|
+
}
|
|
3082
3099
|
var UPG_POLYMORPHIC_EDGE_KEYS = [
|
|
3083
3100
|
// Universal semantic verbs
|
|
3084
3101
|
"node_informs_node",
|
|
@@ -3138,46 +3155,47 @@ function isLegacyProductStage(stage) {
|
|
|
3138
3155
|
}
|
|
3139
3156
|
|
|
3140
3157
|
// src/shapes/document.ts
|
|
3141
|
-
var
|
|
3158
|
+
var UPG_CROSS_ONLY_EDGE_TYPES = [
|
|
3159
|
+
// Peer overlap: "these two products share / overlap on this thing." Symmetric,
|
|
3160
|
+
// no canonical instance_of identity. shares_job / shares_need are the job/need
|
|
3161
|
+
// siblings of the persona/competitor/metric peers (connective layer, 0.13.1).
|
|
3142
3162
|
"shares_persona",
|
|
3143
3163
|
"shares_competitor",
|
|
3144
3164
|
"shares_metric",
|
|
3165
|
+
"shares_job",
|
|
3166
|
+
"shares_need",
|
|
3167
|
+
// Product-to-product relationships.
|
|
3145
3168
|
"depends_on_product",
|
|
3169
|
+
// runtime dependency (built-on / dogfood), not containment
|
|
3146
3170
|
"cannibalises",
|
|
3147
3171
|
"succeeds",
|
|
3148
3172
|
"hosts",
|
|
3173
|
+
// host runs the hosted product inside itself (container -> contained)
|
|
3174
|
+
// OKR / measurement rollup primitives: the cascade ACROSS products (subordinate
|
|
3175
|
+
// -> superior). `contributes_to` rolls a product strategy entity up to a higher-
|
|
3176
|
+
// level one; `rolls_up_to` feeds a product metric into a higher-level north-star.
|
|
3149
3177
|
"contributes_to",
|
|
3178
|
+
"rolls_up_to",
|
|
3179
|
+
// Canonical instance + area-to-audience: the target lives in the portfolio
|
|
3180
|
+
// `registry` section (`registry/{node_id}`). `instance_of` is same-type
|
|
3181
|
+
// canonical-to-instance; the area edges are minted via `link_area_to_audience`.
|
|
3150
3182
|
"instance_of",
|
|
3151
3183
|
"area_serves_persona",
|
|
3152
3184
|
"area_targets_market_segment",
|
|
3153
|
-
|
|
3185
|
+
// Foundations (0.9.12): a product-graph entity links to a canonical specification
|
|
3186
|
+
// or primitive in the registry (`registry/{node_id}` target, same shape as
|
|
3187
|
+
// instance_of). Registry-internal spec-to-spec links are catalog edges, not these.
|
|
3154
3188
|
"product_implements_specification",
|
|
3155
3189
|
"product_exposes_specification",
|
|
3156
3190
|
"feature_conforms_to_specification",
|
|
3157
3191
|
"api_contract_speaks_specification",
|
|
3158
3192
|
"product_exposes_primitive",
|
|
3159
3193
|
"feature_manipulates_primitive",
|
|
3160
|
-
"primitive_stored_as_data_type"
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
"node_classified_as_classification_value",
|
|
3166
|
-
"journey_phase_realises_operating_stage",
|
|
3167
|
-
"screen_markets_product",
|
|
3168
|
-
"screen_renders_design_component",
|
|
3169
|
-
"product_expresses_brand_identity",
|
|
3170
|
-
// Connective cross-product layer (0.13.1) — see UPGCrossEdgeType above.
|
|
3171
|
-
"shares_job",
|
|
3172
|
-
"shares_need",
|
|
3173
|
-
"persona_delegates_to_persona",
|
|
3174
|
-
"screen_targets_competitor",
|
|
3175
|
-
"feature_surfaces_product",
|
|
3176
|
-
"feature_uses_design_component",
|
|
3177
|
-
"product_implements_design_system",
|
|
3178
|
-
// Org-link (0.17.0): dual-registered ownership edges (see UPGCrossEdgeType above).
|
|
3179
|
-
"node_owned_by_team",
|
|
3180
|
-
"node_owned_by_department"
|
|
3194
|
+
"primitive_stored_as_data_type"
|
|
3195
|
+
];
|
|
3196
|
+
var UPG_CROSS_EDGE_TYPES = [
|
|
3197
|
+
...UPG_CROSS_ONLY_EDGE_TYPES,
|
|
3198
|
+
...UPG_CROSS_ELIGIBLE_CATALOG_EDGE_TYPES
|
|
3181
3199
|
];
|
|
3182
3200
|
var REGISTRY_PRODUCT_ID = "registry";
|
|
3183
3201
|
var UPG_PORTFOLIO_KINDS = ["owned", "watched", "strategic", "internal", "gtm"];
|
|
@@ -3631,7 +3649,11 @@ var UPG_VALID_CHILDREN = {
|
|
|
3631
3649
|
"skill",
|
|
3632
3650
|
"ceremony",
|
|
3633
3651
|
"capacity_plan",
|
|
3634
|
-
"decision"
|
|
3652
|
+
"decision",
|
|
3653
|
+
// Self-nesting (0.17.2): a parent team contains its sub-teams / squads, one
|
|
3654
|
+
// level below department_contains_team. Backs team_contains_team. Mirrors
|
|
3655
|
+
// feature_area_contains_feature_area (same-type child listed last).
|
|
3656
|
+
"team"
|
|
3635
3657
|
],
|
|
3636
3658
|
// ── Data & Analytics hierarchy ───────────────────────────────────────────────
|
|
3637
3659
|
data_source: ["metric", "data_pipeline", "data_lineage", "event_schema"],
|
|
@@ -10624,6 +10646,7 @@ var UPG_PROPERTY_SCHEMA = {
|
|
|
10624
10646
|
// ConstraintProperties: Constraint: a named limitation or boundary on product creation.
|
|
10625
10647
|
constraint: {
|
|
10626
10648
|
constraint_kind: { type: "string", enum: ["resource", "technical", "regulatory", "temporal", "compliance", "other"], description: "Limitation category" },
|
|
10649
|
+
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)." },
|
|
10627
10650
|
constraint_status: { type: "string", enum: ["binding", "advisory", "lifted"], description: "Whether binding, advisory, or lifted" },
|
|
10628
10651
|
rule_strength: { type: "string", enum: ["must", "must_not", "exception", "warning", "guideline"], description: "Enforcement strictness. Reuses the governance/guideline rule vocabulary." },
|
|
10629
10652
|
source: { type: "string", description: "Free-text origin: policy document, regulation, stakeholder, technical doc." },
|
|
@@ -21014,6 +21037,30 @@ var UPG_TREE_PATTERNS = [
|
|
|
21014
21037
|
metric: [opt("metric"), opt("outcome")]
|
|
21015
21038
|
},
|
|
21016
21039
|
natural_depth: 3
|
|
21040
|
+
},
|
|
21041
|
+
{
|
|
21042
|
+
id: "org",
|
|
21043
|
+
label: "Org chart",
|
|
21044
|
+
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.",
|
|
21045
|
+
region: "operations_quality",
|
|
21046
|
+
gap_policy: "all-optional",
|
|
21047
|
+
anchor_type: "department",
|
|
21048
|
+
// A graph with no department roots at the team (team -> sub-team), reported
|
|
21049
|
+
// anchor_resolved_from: department. A sub-team also renders as a bare team
|
|
21050
|
+
// root when its parent department is not modelled.
|
|
21051
|
+
fallback_anchors: ["team"],
|
|
21052
|
+
child_map: {
|
|
21053
|
+
// department -> team (department_contains_team) is the first level; team ->
|
|
21054
|
+
// team (team_contains_team, 0.17.2) is the second, so a sub-team nested one
|
|
21055
|
+
// level deeper than department_contains_team renders under its parent team.
|
|
21056
|
+
// Self-nesting: the assembler's `seen` set terminates a team -> team cycle
|
|
21057
|
+
// for free (a team met again becomes a shared reference).
|
|
21058
|
+
department: [opt("team")],
|
|
21059
|
+
team: [opt("team")]
|
|
21060
|
+
},
|
|
21061
|
+
// Default to 3 tiers (department -> team -> sub-team); `depth` extends into
|
|
21062
|
+
// deeper team_contains_team nesting.
|
|
21063
|
+
natural_depth: 3
|
|
21017
21064
|
}
|
|
21018
21065
|
];
|
|
21019
21066
|
var UPG_TREE_PATTERNS_BY_ID = Object.fromEntries(
|
|
@@ -22803,6 +22850,12 @@ var STRATEGY_GUIDE = {
|
|
|
22803
22850
|
description: "Vision grounds mission, product pursues outcomes and targets objectives, objectives achieved through key results measured by metrics",
|
|
22804
22851
|
entity_types: ["vision", "mission", "outcome", "objective", "key_result", "metric"],
|
|
22805
22852
|
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"]
|
|
22853
|
+
},
|
|
22854
|
+
{
|
|
22855
|
+
name: "Rendering the company spine",
|
|
22856
|
+
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.",
|
|
22857
|
+
entity_types: ["strategic_theme", "objective", "key_result", "metric"],
|
|
22858
|
+
edge_chain: ["strategic_theme_contains_objective", "objective_achieved_through_key_result", "key_result_quantified_by_metric"]
|
|
22806
22859
|
}
|
|
22807
22860
|
],
|
|
22808
22861
|
required_bridges: [
|
|
@@ -22813,7 +22866,8 @@ var STRATEGY_GUIDE = {
|
|
|
22813
22866
|
anti_patterns: [
|
|
22814
22867
|
{ description: "Outcomes without metrics. Measurement is the signal an outcome happened." },
|
|
22815
22868
|
{ description: "Objectives without key results: an objective without measurement is a wish" },
|
|
22816
|
-
{ description: "Too many strategic themes: focus beats breadth, aim for 2-4 active themes" }
|
|
22869
|
+
{ description: "Too many strategic themes: focus beats breadth, aim for 2-4 active themes" },
|
|
22870
|
+
{ 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)." }
|
|
22817
22871
|
]
|
|
22818
22872
|
};
|
|
22819
22873
|
var PRODUCT_SPEC_GUIDE = {
|
|
@@ -23364,6 +23418,12 @@ var TEAM_ORG_GUIDE = {
|
|
|
23364
23418
|
description: "Teams are staffed with roles, target OKRs, reflect in retrospectives, and are blocked by dependencies",
|
|
23365
23419
|
entity_types: ["team", "role", "team_okr", "retrospective", "dependency"],
|
|
23366
23420
|
edge_chain: ["team_staffed_with_role", "team_targets_team_okr", "team_reflects_in_retrospective", "dependency_blocks_team"]
|
|
23421
|
+
},
|
|
23422
|
+
{
|
|
23423
|
+
name: "Org Nesting",
|
|
23424
|
+
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.",
|
|
23425
|
+
entity_types: ["department", "team"],
|
|
23426
|
+
edge_chain: ["department_contains_team", "team_contains_team"]
|
|
23367
23427
|
}
|
|
23368
23428
|
],
|
|
23369
23429
|
required_bridges: [
|
|
@@ -23374,6 +23434,7 @@ var TEAM_ORG_GUIDE = {
|
|
|
23374
23434
|
{ description: "Teams without OKRs: every team needs clear goals" },
|
|
23375
23435
|
{ description: "Dependencies without both teams linked: a dependency must connect blocker and blocked" },
|
|
23376
23436
|
{ description: "Retrospectives without action items: reflection without action is just venting" },
|
|
23437
|
+
{ 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." },
|
|
23377
23438
|
{ 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." }
|
|
23378
23439
|
]
|
|
23379
23440
|
};
|
|
@@ -26096,7 +26157,7 @@ var UPG_ANTI_PATTERNS = [
|
|
|
26096
26157
|
{
|
|
26097
26158
|
id: "competitors-missing-past-validation",
|
|
26098
26159
|
name: "Competitor catalogue empty past validation",
|
|
26099
|
-
description: "The graph has zero competitor entities at
|
|
26160
|
+
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.",
|
|
26100
26161
|
structured_condition: {
|
|
26101
26162
|
check: {
|
|
26102
26163
|
type: "benchmark",
|
|
@@ -26106,14 +26167,18 @@ var UPG_ANTI_PATTERNS = [
|
|
|
26106
26167
|
},
|
|
26107
26168
|
why_it_matters: "Without competitors in the graph, positioning, differentiation, and switching-cost analysis lack referents. The team is reasoning in a vacuum.",
|
|
26108
26169
|
remediation: "Catalogue the 3\u20135 closest alternatives users would pick today. Use `/upg-compete` to author.",
|
|
26109
|
-
|
|
26170
|
+
// Fires from build onward, matching the name (past the validation stage). A
|
|
26171
|
+
// concept or validation graph is still framing the problem; holding it to a
|
|
26172
|
+
// competitor benchmark there is the false alarm this anti-pattern caused on
|
|
26173
|
+
// legitimately-young graphs.
|
|
26174
|
+
stages: ["build", "beta", "launch", "growth", "mature"],
|
|
26110
26175
|
severity: "medium",
|
|
26111
26176
|
source: { kind: "industry_practice", category: "product_strategy" }
|
|
26112
26177
|
},
|
|
26113
26178
|
{
|
|
26114
26179
|
id: "persona-count-below-stage-benchmark",
|
|
26115
26180
|
name: "Persona count below stage benchmark",
|
|
26116
|
-
description: "The graph has fewer personas than the stage-appropriate benchmark expects. Persona under-coverage signals the team has not segmented its audience.",
|
|
26181
|
+
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.",
|
|
26117
26182
|
structured_condition: {
|
|
26118
26183
|
check: {
|
|
26119
26184
|
type: "benchmark",
|
|
@@ -26121,9 +26186,13 @@ var UPG_ANTI_PATTERNS = [
|
|
|
26121
26186
|
comparison: "below_min"
|
|
26122
26187
|
}
|
|
26123
26188
|
},
|
|
26124
|
-
why_it_matters:
|
|
26189
|
+
why_it_matters: "A graph still on a single persona by beta is usually carrying an unexamined assumption that every user is the same.",
|
|
26125
26190
|
remediation: "Add personas representing the next 1\u20132 most distinct user segments. Use `/upg-new-persona`.",
|
|
26126
|
-
|
|
26191
|
+
// Fires from beta onward. The persona benchmark expects 2+ from validation,
|
|
26192
|
+
// but the canonical beachhead move is to start with one persona and expand as
|
|
26193
|
+
// fit is found, so holding a build-stage graph to a multi-persona bar is a
|
|
26194
|
+
// false alarm. By beta an unsegmented audience is a real signal.
|
|
26195
|
+
stages: ["beta", "launch", "growth", "mature"],
|
|
26127
26196
|
severity: "medium",
|
|
26128
26197
|
source: { kind: "practitioner", attribution: "Alan Cooper, The Inmates Are Running the Asylum" }
|
|
26129
26198
|
},
|
|
@@ -26148,7 +26217,7 @@ var UPG_ANTI_PATTERNS = [
|
|
|
26148
26217
|
{
|
|
26149
26218
|
id: "single-domain-graph",
|
|
26150
26219
|
name: "Single-domain graph",
|
|
26151
|
-
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.",
|
|
26220
|
+
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.",
|
|
26152
26221
|
structured_condition: {
|
|
26153
26222
|
operator: "and",
|
|
26154
26223
|
checks: [
|
|
@@ -26158,7 +26227,11 @@ var UPG_ANTI_PATTERNS = [
|
|
|
26158
26227
|
},
|
|
26159
26228
|
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?".',
|
|
26160
26229
|
remediation: "Identify the next adjacent domain (usually `user`, `validation`, or `product_spec`) and add 2\u20133 anchor entities to bridge.",
|
|
26161
|
-
|
|
26230
|
+
// Fires from beta onward. Early on a graph is legitimately deep in one domain
|
|
26231
|
+
// (a discovery notebook, a thin internal tool); only once it reaches beta is
|
|
26232
|
+
// single-domain coverage a smell rather than a normal starting shape. Extends
|
|
26233
|
+
// through growth and mature, where a single-domain graph is most telling.
|
|
26234
|
+
stages: ["beta", "launch", "growth", "mature"],
|
|
26162
26235
|
severity: "medium",
|
|
26163
26236
|
source: { kind: "fundamental" }
|
|
26164
26237
|
},
|
|
@@ -29556,7 +29629,7 @@ function isCanonical(text) {
|
|
|
29556
29629
|
}
|
|
29557
29630
|
|
|
29558
29631
|
// src/index.ts
|
|
29559
|
-
var UPG_VERSION = "0.17.
|
|
29632
|
+
var UPG_VERSION = "0.17.3";
|
|
29560
29633
|
var UPG_FORMAT_VERSION = "0.4.0";
|
|
29561
29634
|
var MARKDOWN_FORMAT_VERSION = "0.1";
|
|
29562
29635
|
var UPG_TYPES = getTypes();
|
|
@@ -29658,6 +29731,8 @@ export {
|
|
|
29658
29731
|
UPG_CONTAINMENT_FREE_TYPES,
|
|
29659
29732
|
UPG_COUNT_BENCHMARKS,
|
|
29660
29733
|
UPG_CROSS_EDGE_TYPES,
|
|
29734
|
+
UPG_CROSS_ELIGIBLE_CATALOG_EDGE_TYPES,
|
|
29735
|
+
UPG_CROSS_ONLY_EDGE_TYPES,
|
|
29661
29736
|
UPG_DEPRECATED_TYPES,
|
|
29662
29737
|
UPG_DOMAINS,
|
|
29663
29738
|
UPG_DOMAIN_ACTIVATION,
|
|
@@ -29788,6 +29863,7 @@ export {
|
|
|
29788
29863
|
isCanonical,
|
|
29789
29864
|
isCanonicalProductStage,
|
|
29790
29865
|
isContainmentFreeType,
|
|
29866
|
+
isCrossProductEligible,
|
|
29791
29867
|
isDeprecatedType,
|
|
29792
29868
|
isDomainGuideStep,
|
|
29793
29869
|
isEntitySequenceStep,
|