@unified-product-graph/core 0.17.2 → 0.17.4
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/README.md +1 -1
- package/dist/index.cjs +203 -71
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +268 -17
- package/dist/index.d.ts +268 -17
- package/dist/index.js +197 -71
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
The TypeScript core for the **Unified Product Graph (UPG)**, an open specification that gives product tools a shared vocabulary for entities, edges, and frameworks.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
319 entity types across 37 domains. 1024 typed edges. 46 canonical framework definitions, with more added as each is reviewed.
|
|
11
11
|
|
|
12
12
|
## Install
|
|
13
13
|
|
package/dist/index.cjs
CHANGED
|
@@ -39,6 +39,7 @@ __export(index_exports, {
|
|
|
39
39
|
COVERAGE_ANTI_PATTERNS: () => COVERAGE_ANTI_PATTERNS,
|
|
40
40
|
DEFAULT_ENTITY_EMOJI: () => DEFAULT_ENTITY_EMOJI,
|
|
41
41
|
DEFERRED_PROPOSED_BY_CONTRACT: () => DEFERRED_PROPOSED_BY_CONTRACT,
|
|
42
|
+
DEFER_EDGE_PROPERTY_SCHEMA: () => DEFER_EDGE_PROPERTY_SCHEMA,
|
|
42
43
|
DISCOVERY_RESEARCH_VALIDATION_PLAYBOOK: () => DISCOVERY_RESEARCH_VALIDATION_PLAYBOOK,
|
|
43
44
|
ENGINEERING_PLATFORM_PLAYBOOK: () => ENGINEERING_PLATFORM_PLAYBOOK,
|
|
44
45
|
ENTITY_EMOJI: () => ENTITY_EMOJI,
|
|
@@ -68,6 +69,9 @@ __export(index_exports, {
|
|
|
68
69
|
UPG_CONTAINMENT_FREE_TYPES: () => UPG_CONTAINMENT_FREE_TYPES,
|
|
69
70
|
UPG_COUNT_BENCHMARKS: () => UPG_COUNT_BENCHMARKS,
|
|
70
71
|
UPG_CROSS_EDGE_TYPES: () => UPG_CROSS_EDGE_TYPES,
|
|
72
|
+
UPG_CROSS_ELIGIBLE_CATALOG_EDGE_TYPES: () => UPG_CROSS_ELIGIBLE_CATALOG_EDGE_TYPES,
|
|
73
|
+
UPG_CROSS_ONLY_EDGE_TYPES: () => UPG_CROSS_ONLY_EDGE_TYPES,
|
|
74
|
+
UPG_DELIBERATE_ONLY_EDGE_TYPES: () => UPG_DELIBERATE_ONLY_EDGE_TYPES,
|
|
71
75
|
UPG_DEPRECATED_TYPES: () => UPG_DEPRECATED_TYPES,
|
|
72
76
|
UPG_DOMAINS: () => UPG_DOMAINS,
|
|
73
77
|
UPG_DOMAIN_ACTIVATION: () => UPG_DOMAIN_ACTIVATION,
|
|
@@ -198,6 +202,8 @@ __export(index_exports, {
|
|
|
198
202
|
isCanonical: () => isCanonical,
|
|
199
203
|
isCanonicalProductStage: () => isCanonicalProductStage,
|
|
200
204
|
isContainmentFreeType: () => isContainmentFreeType,
|
|
205
|
+
isCrossProductEligible: () => isCrossProductEligible,
|
|
206
|
+
isDeliberateOnlyEdge: () => isDeliberateOnlyEdge,
|
|
201
207
|
isDeprecatedType: () => isDeprecatedType,
|
|
202
208
|
isDomainGuideStep: () => isDomainGuideStep,
|
|
203
209
|
isEntitySequenceStep: () => isEntitySequenceStep,
|
|
@@ -264,7 +270,8 @@ var UPG_DOMAINS = [
|
|
|
264
270
|
"strategic_pillar",
|
|
265
271
|
"assumption",
|
|
266
272
|
"decision",
|
|
267
|
-
"constraint"
|
|
273
|
+
"constraint",
|
|
274
|
+
"strategic_question"
|
|
268
275
|
]
|
|
269
276
|
},
|
|
270
277
|
{
|
|
@@ -783,6 +790,10 @@ var UPG_ENTITY_META = [
|
|
|
783
790
|
{ name: "assumption", type_id: "ent_014", maturity: "stable", since: "0.1.0" },
|
|
784
791
|
{ name: "decision", type_id: "ent_015", maturity: "stable", since: "0.1.0" },
|
|
785
792
|
{ name: "constraint", type_id: "ent_348", maturity: "stable", since: "0.4.3" },
|
|
793
|
+
// (0.17.4) Strategy-domain sibling of research_question / design_question,
|
|
794
|
+
// completing the domain-question triad. An open coordination/ownership question
|
|
795
|
+
// a plan is exposed to (distinct from `assumption`, which the plan is built on).
|
|
796
|
+
{ name: "strategic_question", type_id: "ent_357", maturity: "proposed", since: "0.17.4" },
|
|
786
797
|
// ── User ──
|
|
787
798
|
{ name: "persona", type_id: "ent_016", maturity: "stable", since: "0.1.0" },
|
|
788
799
|
{ name: "job", type_id: "ent_017", maturity: "stable", since: "0.1.0" },
|
|
@@ -1257,6 +1268,12 @@ var CLASSIFICATION_EDGE_PROPERTY_SCHEMA = {
|
|
|
1257
1268
|
description: "Optional. A source URL, or a competitor_signal / evidence node id backing the classification. Mirrors feature_rivals_competitor_feature.evidence (free text or a node id)."
|
|
1258
1269
|
}
|
|
1259
1270
|
};
|
|
1271
|
+
var DEFER_EDGE_PROPERTY_SCHEMA = {
|
|
1272
|
+
deferred_to: {
|
|
1273
|
+
type: "string",
|
|
1274
|
+
description: 'Target period the parked work is deferred to. Freeform, mirroring strategic_theme.time_horizon. @example "Q4 2026", "FY27", "next release".'
|
|
1275
|
+
}
|
|
1276
|
+
};
|
|
1260
1277
|
var UPG_EDGE_CATALOG = {
|
|
1261
1278
|
// ── Part 1: Core Narrative Spine (Ring 1) ──────────────────────────────────
|
|
1262
1279
|
// 1.1 User Domain
|
|
@@ -1273,7 +1290,7 @@ var UPG_EDGE_CATALOG = {
|
|
|
1273
1290
|
persona_aspires_to_desired_outcome: { forward_verb: "aspires_to", reverse_verb: "aspirational_for", classification: "hierarchy", source_type: "persona", target_type: "desired_outcome" },
|
|
1274
1291
|
// Delegation (0.11.6): a persona delegates work to another. The common case is human -> agent
|
|
1275
1292
|
// (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" },
|
|
1293
|
+
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
1294
|
persona_incurs_switching_cost: { forward_verb: "incurs", reverse_verb: "incurred_by", classification: "hierarchy", source_type: "persona", target_type: "switching_cost" },
|
|
1278
1295
|
job_surfaces_need: { forward_verb: "surfaces", reverse_verb: "surfaces_from", classification: "causal", source_type: "job", target_type: "need" },
|
|
1279
1296
|
job_motivates_desired_outcome: { forward_verb: "motivates", reverse_verb: "motivated_by", classification: "causal", source_type: "job", target_type: "desired_outcome" },
|
|
@@ -1391,15 +1408,15 @@ var UPG_EDGE_CATALOG = {
|
|
|
1391
1408
|
// Dual-registered as a cross-edge (UPG_CROSS_EDGE_TYPES) so it also spans our
|
|
1392
1409
|
// product graph and a watched competitor-intelligence graph. Distinct from
|
|
1393
1410
|
// `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 },
|
|
1411
|
+
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
1412
|
// 0.10.0 (spec issue #41): competitor_signal is a dated competitor move (feature
|
|
1396
1413
|
// launch / pricing change / acquisition / partnership / market entry) emitted by a
|
|
1397
1414
|
// competitor and mapped onto our portfolio. `emits` is within the watched graph;
|
|
1398
1415
|
// `maps_to_feature` / `surfaces_opportunity` cross from the watched signal into our
|
|
1399
1416
|
// product graph (dual-registered as cross-edges in UPG_CROSS_EDGE_TYPES).
|
|
1400
1417
|
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" },
|
|
1418
|
+
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 },
|
|
1419
|
+
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
1420
|
competitive_analysis_analyses_competitor: { forward_verb: "analyses", reverse_verb: "analysed_in", classification: "hierarchy", source_type: "competitive_analysis", target_type: "competitor" },
|
|
1404
1421
|
competitive_analysis_identifies_market_trend: { forward_verb: "identifies", reverse_verb: "identified_in", classification: "hierarchy", source_type: "competitive_analysis", target_type: "market_trend" },
|
|
1405
1422
|
competitive_analysis_scopes_market_segment: { forward_verb: "scopes", reverse_verb: "scoped_in", classification: "hierarchy", source_type: "competitive_analysis", target_type: "market_segment" },
|
|
@@ -1432,13 +1449,13 @@ var UPG_EDGE_CATALOG = {
|
|
|
1432
1449
|
// competitor can be classified directly against a `registry/{classification_value}`
|
|
1433
1450
|
// canonical, eliminating the per-graph taxonomy node. Within-graph (the catalogue
|
|
1434
1451
|
// 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 },
|
|
1452
|
+
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
1453
|
// 0.10.3: the polymorphic, type-agnostic sibling. ANY node (a feature, a
|
|
1437
1454
|
// product, a market_segment) classified against a classification_value, so
|
|
1438
1455
|
// classification is not welded to the competitor type. Also dual-registered as
|
|
1439
1456
|
// a cross-edge for the registry-canonical case. source_type:'node' (wildcard);
|
|
1440
1457
|
// 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 },
|
|
1458
|
+
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
1459
|
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
1460
|
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
1461
|
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 +1508,28 @@ var UPG_EDGE_CATALOG = {
|
|
|
1491
1508
|
feedback_program_has_beta_program: { forward_verb: "has", reverse_verb: "part_of", classification: "hierarchy", source_type: "feedback_program", target_type: "beta_program" },
|
|
1492
1509
|
// ── Part 2: Strategic & Execution Spine (Ring 2) ───────────────────────────
|
|
1493
1510
|
// 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" },
|
|
1511
|
+
product_pursues_outcome: { forward_verb: "pursues", reverse_verb: "pursued_by", classification: "hierarchy", source_type: "product", target_type: "outcome", cross_product_eligible: true },
|
|
1512
|
+
product_targets_objective: { forward_verb: "targets", reverse_verb: "targeted_by", classification: "hierarchy", source_type: "product", target_type: "objective", cross_product_eligible: true },
|
|
1513
|
+
product_guided_by_vision: { forward_verb: "guided_by", reverse_verb: "guides", classification: "hierarchy", source_type: "product", target_type: "vision", cross_product_eligible: true },
|
|
1497
1514
|
// product→{mission,strategic_theme,strategic_pillar,initiative,capability,value_stream,assumption}
|
|
1498
1515
|
// are semantic "how the product relates to the strategic cascade", not containment.
|
|
1499
1516
|
// The containment chain is product → vision → mission → strategic_pillar → … so these
|
|
1500
1517
|
// 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" },
|
|
1518
|
+
product_fulfils_mission: { forward_verb: "fulfils", reverse_verb: "fulfilled_by", classification: "semantic", source_type: "product", target_type: "mission", cross_product_eligible: true },
|
|
1519
|
+
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 },
|
|
1520
|
+
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 },
|
|
1521
|
+
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
1522
|
product_develops_capability: { forward_verb: "develops", reverse_verb: "developed_by", classification: "semantic", source_type: "product", target_type: "capability" },
|
|
1506
1523
|
product_delivers_through_value_stream: { forward_verb: "delivers_through", reverse_verb: "delivers_for", classification: "semantic", source_type: "product", target_type: "value_stream" },
|
|
1507
1524
|
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" },
|
|
1525
|
+
product_measures_with_metric: { forward_verb: "measures_with", reverse_verb: "measures", classification: "hierarchy", source_type: "product", target_type: "metric", cross_product_eligible: true },
|
|
1526
|
+
outcome_measured_by_metric: { forward_verb: "measured_by", reverse_verb: "measures", classification: "hierarchy", source_type: "outcome", target_type: "metric", cross_product_eligible: true },
|
|
1510
1527
|
// (UPG-677) outcome_tracked_by_metric retired — near-synonym of
|
|
1511
1528
|
// outcome_measured_by_metric (the kept canonical key). Captain's lean =
|
|
1512
1529
|
// 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" },
|
|
1530
|
+
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 },
|
|
1531
|
+
objective_measured_by_metric: { forward_verb: "measured_by", reverse_verb: "measures", classification: "hierarchy", source_type: "objective", target_type: "metric", cross_product_eligible: true },
|
|
1532
|
+
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
1533
|
// (UPG-677) key_result_tracked_by_metric retired — near-synonym of
|
|
1517
1534
|
// key_result_quantified_by_metric (the kept canonical key). Captain's lean =
|
|
1518
1535
|
// collapse. See UPG_EDGE_MIGRATIONS['0.9.9'].
|
|
@@ -1522,7 +1539,7 @@ var UPG_EDGE_CATALOG = {
|
|
|
1522
1539
|
strategic_pillar_enables_capability: { forward_verb: "enables", reverse_verb: "enabled_by", classification: "hierarchy", source_type: "strategic_pillar", target_type: "capability" },
|
|
1523
1540
|
strategic_pillar_delivers_value_stream: { forward_verb: "delivers", reverse_verb: "delivered_by", classification: "hierarchy", source_type: "strategic_pillar", target_type: "value_stream" },
|
|
1524
1541
|
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" },
|
|
1542
|
+
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
1543
|
// v0.9.0 (UPG-660): the soft bridge from the annual strategy focus area to the
|
|
1527
1544
|
// roadmap grouping that realises it. Semantic, NOT hierarchy: strategic_theme and
|
|
1528
1545
|
// roadmap_theme sit on different spines (strategy cascade vs roadmap cascade), so
|
|
@@ -1550,11 +1567,11 @@ var UPG_EDGE_CATALOG = {
|
|
|
1550
1567
|
// surfaces the upward-rollup read. Mirrors `strategic_pillar_organises_
|
|
1551
1568
|
// strategic_theme` (pillar → theme), completing the strategic cascade:
|
|
1552
1569
|
// 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" },
|
|
1570
|
+
strategic_theme_delivers_outcome: { forward_verb: "delivers", reverse_verb: "delivered_by", classification: "causal", source_type: "strategic_theme", target_type: "outcome", cross_product_eligible: true },
|
|
1571
|
+
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 },
|
|
1572
|
+
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
1573
|
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" },
|
|
1574
|
+
initiative_drives_outcome: { forward_verb: "drives", reverse_verb: "driven_by", classification: "cross-domain", source_type: "initiative", target_type: "outcome", cross_product_eligible: true },
|
|
1558
1575
|
capability_enables_value_stream: { forward_verb: "enables", reverse_verb: "enabled_by", classification: "cross-domain", source_type: "capability", target_type: "value_stream" },
|
|
1559
1576
|
// v0.5.2 (UPG-528): three capability-anchored edges that complete the
|
|
1560
1577
|
// Wardley-style value chain: need → capability → capability → feature.
|
|
@@ -1692,7 +1709,7 @@ var UPG_EDGE_CATALOG = {
|
|
|
1692
1709
|
// brand_identity. Dual-registered: also a cross-edge for the common case where the
|
|
1693
1710
|
// brand is a registry singleton in another graph (the ratified pattern: brand is a
|
|
1694
1711
|
// 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" },
|
|
1712
|
+
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
1713
|
design_system_encompasses_user_journey: { forward_verb: "encompasses", reverse_verb: "encompassed_in", classification: "hierarchy", source_type: "design_system", target_type: "user_journey" },
|
|
1697
1714
|
design_system_encompasses_user_flow: { forward_verb: "encompasses", reverse_verb: "encompassed_in", classification: "hierarchy", source_type: "design_system", target_type: "user_flow" },
|
|
1698
1715
|
design_system_informed_by_insight: { forward_verb: "informed_by", reverse_verb: "informs", classification: "hierarchy", source_type: "design_system", target_type: "insight" },
|
|
@@ -1704,12 +1721,12 @@ var UPG_EDGE_CATALOG = {
|
|
|
1704
1721
|
design_component_specified_by_interaction_spec: { forward_verb: "specified_by", reverse_verb: "specifies", classification: "hierarchy", source_type: "design_component", target_type: "interaction_spec" },
|
|
1705
1722
|
design_component_composes_design_component: { forward_verb: "composes", reverse_verb: "composed_in", classification: "hierarchy", source_type: "design_component", target_type: "design_component" },
|
|
1706
1723
|
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" },
|
|
1724
|
+
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
1725
|
// Marketing surface to product (0.12.7, UPG-696/698). A marketing/landing screen
|
|
1709
1726
|
// markets a product. Dual-registered: also a cross-edge (UPG_CROSS_EDGE_TYPES) for
|
|
1710
1727
|
// the common case where the product lives in another graph; this catalog entry is
|
|
1711
1728
|
// 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" },
|
|
1729
|
+
screen_markets_product: { forward_verb: "markets", reverse_verb: "marketed_by", classification: "semantic", source_type: "screen", target_type: "product", cross_product_eligible: true },
|
|
1713
1730
|
// Connective cross-product references (0.13.1, Data's connective-layer brief).
|
|
1714
1731
|
// Dual-registered (also in UPG_CROSS_EDGE_TYPES) for the common cross-graph case;
|
|
1715
1732
|
// these catalog entries are the within-graph degenerate case.
|
|
@@ -1725,10 +1742,10 @@ var UPG_EDGE_CATALOG = {
|
|
|
1725
1742
|
// system (the adoption semantic, mirroring product_implements_specification). Distinct
|
|
1726
1743
|
// from the hierarchy `product_systematised_in_design_system` (structural containment):
|
|
1727
1744
|
// 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" },
|
|
1745
|
+
screen_targets_competitor: { forward_verb: "targets", reverse_verb: "targeted_by", classification: "semantic", source_type: "screen", target_type: "competitor", cross_product_eligible: true },
|
|
1746
|
+
feature_surfaces_product: { forward_verb: "surfaces", reverse_verb: "surfaced_by", classification: "semantic", source_type: "feature", target_type: "product", cross_product_eligible: true },
|
|
1747
|
+
feature_uses_design_component: { forward_verb: "uses", reverse_verb: "used_by", classification: "semantic", source_type: "feature", target_type: "design_component", cross_product_eligible: true },
|
|
1748
|
+
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
1749
|
screen_navigates_to_screen: { forward_verb: "navigates_to", reverse_verb: "navigated_from", classification: "hierarchy", source_type: "screen", target_type: "screen" },
|
|
1733
1750
|
screen_surfaces_feature: { forward_verb: "surfaces", reverse_verb: "surfaced_on", classification: "cross-domain", source_type: "screen", target_type: "feature" },
|
|
1734
1751
|
screen_wireframed_as_wireframe: { forward_verb: "wireframed_as", reverse_verb: "wireframes", classification: "hierarchy", source_type: "screen", target_type: "wireframe" },
|
|
@@ -2580,10 +2597,10 @@ var UPG_EDGE_CATALOG = {
|
|
|
2580
2597
|
experiment_run_measured_by_metric: { forward_verb: "measured_by", reverse_verb: "measures", classification: "hierarchy", source_type: "experiment_run", target_type: "metric" },
|
|
2581
2598
|
solution_measured_by_metric: { forward_verb: "measured_by", reverse_verb: "measures", classification: "hierarchy", source_type: "solution", target_type: "metric" },
|
|
2582
2599
|
// ── Cross-domain: Ownership ──────────────────────────────────────────────────
|
|
2583
|
-
node_owned_by_team: { forward_verb: "owned_by", reverse_verb: "owns", classification: "cross-domain", source_type: "node", target_type: "team" },
|
|
2600
|
+
node_owned_by_team: { forward_verb: "owned_by", reverse_verb: "owns", classification: "cross-domain", source_type: "node", target_type: "team", cross_product_eligible: true },
|
|
2584
2601
|
node_owned_by_role: { forward_verb: "owned_by", reverse_verb: "owns", classification: "cross-domain", source_type: "node", target_type: "role" },
|
|
2585
2602
|
node_owned_by_stakeholder: { forward_verb: "owned_by", reverse_verb: "owns", classification: "cross-domain", source_type: "node", target_type: "stakeholder" },
|
|
2586
|
-
node_owned_by_department: { forward_verb: "owned_by", reverse_verb: "owns", classification: "cross-domain", source_type: "node", target_type: "department" },
|
|
2603
|
+
node_owned_by_department: { forward_verb: "owned_by", reverse_verb: "owns", classification: "cross-domain", source_type: "node", target_type: "department", cross_product_eligible: true },
|
|
2587
2604
|
node_owned_by_person: { forward_verb: "owned_by", reverse_verb: "owns", classification: "cross-domain", source_type: "node", target_type: "person" },
|
|
2588
2605
|
// ── Cross-domain: Architecture (DDD) ─────────────────────────────────────────
|
|
2589
2606
|
// Service, domain_event, domain_entity, aggregate, read_model, api_contract,
|
|
@@ -3247,7 +3264,7 @@ var UPG_EDGE_CATALOG = {
|
|
|
3247
3264
|
// not the outcome it exists to move; the strategic spine was severed at its
|
|
3248
3265
|
// anchor (0 outbound to outcome). An objective ADVANCES an outcome. Intra-
|
|
3249
3266
|
// domain (both in strategy) and directional → causal.
|
|
3250
|
-
objective_advances_outcome: { forward_verb: "advances", reverse_verb: "advanced_by", classification: "causal", source_type: "objective", target_type: "outcome" },
|
|
3267
|
+
objective_advances_outcome: { forward_verb: "advances", reverse_verb: "advanced_by", classification: "causal", source_type: "objective", target_type: "outcome", cross_product_eligible: true },
|
|
3251
3268
|
// ── F6: Priority 2 — scored / synthesis / verdict dead-end leaves (P-A) ─────
|
|
3252
3269
|
// desired_outcome (Ulwick-scored: importance × satisfaction) had 0 outbound —
|
|
3253
3270
|
// the scores could not flow anywhere. An under-served desired_outcome REVEALS
|
|
@@ -3330,9 +3347,61 @@ var UPG_EDGE_CATALOG = {
|
|
|
3330
3347
|
specification_governed_by_organization: { forward_verb: "governed_by", reverse_verb: "governs", classification: "semantic", source_type: "specification", target_type: "organization" },
|
|
3331
3348
|
// Operating-lifecycle cross-edges (0.11.6): a product's journey phase realises a canonical
|
|
3332
3349
|
// operating stage (the cross-surface join key); a stage is measured by a rollup metric (loop close).
|
|
3333
|
-
journey_phase_realises_operating_stage: { forward_verb: "realises", reverse_verb: "realised_by", classification: "cross-domain", source_type: "journey_phase", target_type: "operating_stage" },
|
|
3334
|
-
operating_stage_measured_by_metric: { forward_verb: "measured_by", reverse_verb: "measures", classification: "cross-domain", source_type: "operating_stage", target_type: "metric" }
|
|
3350
|
+
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 },
|
|
3351
|
+
operating_stage_measured_by_metric: { forward_verb: "measured_by", reverse_verb: "measures", classification: "cross-domain", source_type: "operating_stage", target_type: "metric" },
|
|
3352
|
+
// ── OKR planning coverage (0.17.4) ──────────────────────────────────────────
|
|
3353
|
+
// Reconciling the strategy graph against a live planning doc surfaced texture
|
|
3354
|
+
// the objective — the node every OKR doc organises itself around — could not
|
|
3355
|
+
// reach: cross-team dependencies and deferred (out-of-scope) work.
|
|
3356
|
+
// objective ↔ dependency. Every OKR in the source doc carries a dependency
|
|
3357
|
+
// table ("which other team's work this depends on"). `dependency` (team_org)
|
|
3358
|
+
// already carries dependency_type / criticality / target_date; it was
|
|
3359
|
+
// reachable only from `team`. An objective DEPENDS ON a dependency; the
|
|
3360
|
+
// dependency BLOCKS the objective (explicit mirror, not left implicit).
|
|
3361
|
+
// Cross-domain, not hierarchy: a dependency is parented under its owning team,
|
|
3362
|
+
// so an objective references it laterally rather than containing it. Both are
|
|
3363
|
+
// cross_product_eligible — a Studio objective can depend on a dependency owned
|
|
3364
|
+
// by another team's graph within the portfolio (0.17.3 locked predicate).
|
|
3365
|
+
objective_depends_on_dependency: { forward_verb: "depends_on", reverse_verb: "dependency_of", classification: "cross-domain", source_type: "objective", target_type: "dependency", cross_product_eligible: true },
|
|
3366
|
+
dependency_blocks_objective: { forward_verb: "blocks", reverse_verb: "blocked_by", classification: "cross-domain", source_type: "dependency", target_type: "objective", cross_product_eligible: true },
|
|
3367
|
+
// objective / initiative → strategic_question. A planning doc's "Risks & Open
|
|
3368
|
+
// Questions" section names unresolved coordination questions the plan is
|
|
3369
|
+
// exposed to (who owns a capability across teams after a reorg). The
|
|
3370
|
+
// strategy-domain sibling of research_question / design_question. The question
|
|
3371
|
+
// is raised under (contained by) the objective or initiative that surfaces it,
|
|
3372
|
+
// so hierarchy — mirroring initiative_assumes_assumption. Within-graph: the
|
|
3373
|
+
// question node is authored alongside its objective, so NOT
|
|
3374
|
+
// cross_product_eligible (the cross-team nature lives in the question text, not
|
|
3375
|
+
// in a cross-graph edge).
|
|
3376
|
+
objective_raises_strategic_question: { forward_verb: "raises", reverse_verb: "raised_by", classification: "hierarchy", source_type: "objective", target_type: "strategic_question" },
|
|
3377
|
+
initiative_raises_strategic_question: { forward_verb: "raises", reverse_verb: "raised_by", classification: "hierarchy", source_type: "initiative", target_type: "strategic_question" },
|
|
3378
|
+
// objective → feature / capability (the defer / out-of-scope edge). Every OKR
|
|
3379
|
+
// in the source doc carries an explicit "Out of scope" list, load-bearing for
|
|
3380
|
+
// keeping a quarter from silently expanding (localization deferred to Q4,
|
|
3381
|
+
// another team's feature work parked). Modelled as an edge to the real feature
|
|
3382
|
+
// or capability parked for later, not a scalar exclusion string, so the parked
|
|
3383
|
+
// work stays queryable and connected. The `deferred_to` edge property carries
|
|
3384
|
+
// the temporal target. feature is product_spec (cross-domain); capability is
|
|
3385
|
+
// intra-strategy (semantic). Both cross_product_eligible: deferring another
|
|
3386
|
+
// product's feature or capability, authored in a different graph within the
|
|
3387
|
+
// portfolio, fits the 0.17.3 locked predicate.
|
|
3388
|
+
objective_defers_feature: { forward_verb: "defers", reverse_verb: "deferred_by", classification: "cross-domain", source_type: "objective", target_type: "feature", carries_properties: true, property_schema: DEFER_EDGE_PROPERTY_SCHEMA, cross_product_eligible: true, deliberate_only: true },
|
|
3389
|
+
objective_defers_capability: { forward_verb: "defers", reverse_verb: "deferred_by", classification: "semantic", source_type: "objective", target_type: "capability", carries_properties: true, property_schema: DEFER_EDGE_PROPERTY_SCHEMA, cross_product_eligible: true, deliberate_only: true }
|
|
3335
3390
|
};
|
|
3391
|
+
var UPG_CROSS_ELIGIBLE_CATALOG_EDGE_TYPES = Object.keys(UPG_EDGE_CATALOG).filter(
|
|
3392
|
+
(k) => UPG_EDGE_CATALOG[k].cross_product_eligible === true
|
|
3393
|
+
);
|
|
3394
|
+
function isCrossProductEligible(type) {
|
|
3395
|
+
const def = UPG_EDGE_CATALOG[type];
|
|
3396
|
+
return def?.cross_product_eligible === true;
|
|
3397
|
+
}
|
|
3398
|
+
var UPG_DELIBERATE_ONLY_EDGE_TYPES = Object.keys(UPG_EDGE_CATALOG).filter(
|
|
3399
|
+
(k) => UPG_EDGE_CATALOG[k].deliberate_only === true
|
|
3400
|
+
);
|
|
3401
|
+
function isDeliberateOnlyEdge(type) {
|
|
3402
|
+
const def = UPG_EDGE_CATALOG[type];
|
|
3403
|
+
return def?.deliberate_only === true;
|
|
3404
|
+
}
|
|
3336
3405
|
var UPG_POLYMORPHIC_EDGE_KEYS = [
|
|
3337
3406
|
// Universal semantic verbs
|
|
3338
3407
|
"node_informs_node",
|
|
@@ -3392,52 +3461,47 @@ function isLegacyProductStage(stage) {
|
|
|
3392
3461
|
}
|
|
3393
3462
|
|
|
3394
3463
|
// src/shapes/document.ts
|
|
3395
|
-
var
|
|
3464
|
+
var UPG_CROSS_ONLY_EDGE_TYPES = [
|
|
3465
|
+
// Peer overlap: "these two products share / overlap on this thing." Symmetric,
|
|
3466
|
+
// no canonical instance_of identity. shares_job / shares_need are the job/need
|
|
3467
|
+
// siblings of the persona/competitor/metric peers (connective layer, 0.13.1).
|
|
3396
3468
|
"shares_persona",
|
|
3397
3469
|
"shares_competitor",
|
|
3398
3470
|
"shares_metric",
|
|
3471
|
+
"shares_job",
|
|
3472
|
+
"shares_need",
|
|
3473
|
+
// Product-to-product relationships.
|
|
3399
3474
|
"depends_on_product",
|
|
3475
|
+
// runtime dependency (built-on / dogfood), not containment
|
|
3400
3476
|
"cannibalises",
|
|
3401
3477
|
"succeeds",
|
|
3402
3478
|
"hosts",
|
|
3479
|
+
// host runs the hosted product inside itself (container -> contained)
|
|
3480
|
+
// OKR / measurement rollup primitives: the cascade ACROSS products (subordinate
|
|
3481
|
+
// -> superior). `contributes_to` rolls a product strategy entity up to a higher-
|
|
3482
|
+
// level one; `rolls_up_to` feeds a product metric into a higher-level north-star.
|
|
3403
3483
|
"contributes_to",
|
|
3484
|
+
"rolls_up_to",
|
|
3485
|
+
// Canonical instance + area-to-audience: the target lives in the portfolio
|
|
3486
|
+
// `registry` section (`registry/{node_id}`). `instance_of` is same-type
|
|
3487
|
+
// canonical-to-instance; the area edges are minted via `link_area_to_audience`.
|
|
3404
3488
|
"instance_of",
|
|
3405
3489
|
"area_serves_persona",
|
|
3406
3490
|
"area_targets_market_segment",
|
|
3407
|
-
|
|
3491
|
+
// Foundations (0.9.12): a product-graph entity links to a canonical specification
|
|
3492
|
+
// or primitive in the registry (`registry/{node_id}` target, same shape as
|
|
3493
|
+
// instance_of). Registry-internal spec-to-spec links are catalog edges, not these.
|
|
3408
3494
|
"product_implements_specification",
|
|
3409
3495
|
"product_exposes_specification",
|
|
3410
3496
|
"feature_conforms_to_specification",
|
|
3411
3497
|
"api_contract_speaks_specification",
|
|
3412
3498
|
"product_exposes_primitive",
|
|
3413
3499
|
"feature_manipulates_primitive",
|
|
3414
|
-
"primitive_stored_as_data_type"
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
"node_classified_as_classification_value",
|
|
3420
|
-
"journey_phase_realises_operating_stage",
|
|
3421
|
-
"screen_markets_product",
|
|
3422
|
-
"screen_renders_design_component",
|
|
3423
|
-
"product_expresses_brand_identity",
|
|
3424
|
-
// Connective cross-product layer (0.13.1) — see UPGCrossEdgeType above.
|
|
3425
|
-
"shares_job",
|
|
3426
|
-
"shares_need",
|
|
3427
|
-
"persona_delegates_to_persona",
|
|
3428
|
-
"screen_targets_competitor",
|
|
3429
|
-
"feature_surfaces_product",
|
|
3430
|
-
"feature_uses_design_component",
|
|
3431
|
-
"product_implements_design_system",
|
|
3432
|
-
// Org-link (0.17.0): dual-registered ownership edges (see UPGCrossEdgeType above).
|
|
3433
|
-
"node_owned_by_team",
|
|
3434
|
-
"node_owned_by_department",
|
|
3435
|
-
// Cross-graph strategy & measurement (0.17.2): dual-registered OKR/measurement
|
|
3436
|
-
// hierarchy edges so the strategy spine can span files (see UPGCrossEdgeType above).
|
|
3437
|
-
"strategic_theme_contains_objective",
|
|
3438
|
-
"objective_achieved_through_key_result",
|
|
3439
|
-
"key_result_quantified_by_metric",
|
|
3440
|
-
"objective_measured_by_metric"
|
|
3500
|
+
"primitive_stored_as_data_type"
|
|
3501
|
+
];
|
|
3502
|
+
var UPG_CROSS_EDGE_TYPES = [
|
|
3503
|
+
...UPG_CROSS_ONLY_EDGE_TYPES,
|
|
3504
|
+
...UPG_CROSS_ELIGIBLE_CATALOG_EDGE_TYPES
|
|
3441
3505
|
];
|
|
3442
3506
|
var REGISTRY_PRODUCT_ID = "registry";
|
|
3443
3507
|
var UPG_PORTFOLIO_KINDS = ["owned", "watched", "strategic", "internal", "gtm"];
|
|
@@ -3705,7 +3769,9 @@ var UPG_VALID_CHILDREN = {
|
|
|
3705
3769
|
// where self-nesting genuinely lives, not on `experiment`).
|
|
3706
3770
|
experiment_run: ["learning", "evidence", "metric", "experiment_run"],
|
|
3707
3771
|
// ── OKR hierarchy ──────────────────────────────────────────────────────────
|
|
3708
|
-
|
|
3772
|
+
// strategic_question (0.17.4): an open coordination question raised under an
|
|
3773
|
+
// objective (objective_raises_strategic_question, hierarchy).
|
|
3774
|
+
objective: ["key_result", "metric", "strategic_question"],
|
|
3709
3775
|
key_result: ["metric"],
|
|
3710
3776
|
// ── Strategic cascade: vision → mission → strategic_pillar → strategic_theme →
|
|
3711
3777
|
// { initiative, objective } ───────────────────────────────────────────────
|
|
@@ -3730,7 +3796,7 @@ var UPG_VALID_CHILDREN = {
|
|
|
3730
3796
|
// catalog (hierarchy, strategic_theme → objective, reverse_verb: rolls_up_to;
|
|
3731
3797
|
// renamed from objective_rolls_up_to_strategic_theme in UPG-676).
|
|
3732
3798
|
strategic_theme: ["initiative", "objective"],
|
|
3733
|
-
initiative: ["assumption"],
|
|
3799
|
+
initiative: ["assumption", "strategic_question"],
|
|
3734
3800
|
// v0.5.2 (UPG-528): capability decomposes into sub-capabilities (Wardley
|
|
3735
3801
|
// value-chain spine) and is realised by user-facing features. Pairs with
|
|
3736
3802
|
// `capability_depends_on_capability` and `capability_implemented_by_feature`
|
|
@@ -4803,6 +4869,15 @@ var ASSUMPTION_LIFECYCLE = {
|
|
|
4803
4869
|
}
|
|
4804
4870
|
]
|
|
4805
4871
|
};
|
|
4872
|
+
var STRATEGIC_QUESTION_LIFECYCLE = {
|
|
4873
|
+
entity_type: "strategic_question",
|
|
4874
|
+
initial_phase: "open",
|
|
4875
|
+
terminal_phases: ["resolved"],
|
|
4876
|
+
phases: [
|
|
4877
|
+
{ id: "open", label: "Open", description: "The question has been raised but not yet answered. The plan is exposed to it.", transitions_to: ["resolved"] },
|
|
4878
|
+
{ id: "resolved", label: "Resolved", description: "The question has been answered; the resolution is captured. The plan is no longer exposed to it. May reopen if the answer unravels.", transitions_to: ["open"] }
|
|
4879
|
+
]
|
|
4880
|
+
};
|
|
4806
4881
|
var OUTCOME_LIFECYCLE = {
|
|
4807
4882
|
entity_type: "outcome",
|
|
4808
4883
|
initial_phase: "identified",
|
|
@@ -6480,6 +6555,7 @@ var UPG_LIFECYCLES = [
|
|
|
6480
6555
|
INITIATIVE_LIFECYCLE,
|
|
6481
6556
|
STRATEGIC_PILLAR_LIFECYCLE,
|
|
6482
6557
|
ASSUMPTION_LIFECYCLE,
|
|
6558
|
+
STRATEGIC_QUESTION_LIFECYCLE,
|
|
6483
6559
|
FEATURE_AREA_LIFECYCLE,
|
|
6484
6560
|
FEATURE_LIFECYCLE,
|
|
6485
6561
|
EPIC_LIFECYCLE,
|
|
@@ -12956,6 +13032,15 @@ var UPG_PROPERTY_SCHEMA = {
|
|
|
12956
13032
|
time_horizon: { type: "string", description: 'Standing / multi-year horizon, often open-ended (a pillar is durable). @example "3 years", "2026-2028", "ongoing"' },
|
|
12957
13033
|
success_indicator: { type: "string", description: "How the business knows this durable pillar is on track. Narrative, not a metric edge. A strategic_theme deliberately has no success_indicator: it is measured through its child objectives, not on its own." }
|
|
12958
13034
|
},
|
|
13035
|
+
// StrategicQuestionProperties: StrategicQuestion entity. An open coordination or
|
|
13036
|
+
// ownership question a plan is exposed to (strategy sibling of research_question /
|
|
13037
|
+
// design_question). `status` is the node lifecycle (open -> resolved).
|
|
13038
|
+
strategic_question: {
|
|
13039
|
+
question: { type: "string", description: "The question itself. Primary content." },
|
|
13040
|
+
context: { type: "string", description: "Context that surfaced the question: the reorg, the boundary, the unowned area." },
|
|
13041
|
+
resolution: { type: "string", description: "The answer, captured when the question moves to `resolved`." },
|
|
13042
|
+
priority: { type: "string", enum: ["urgent", "high", "medium", "low", "none"], description: "Importance to resolve relative to other open questions." }
|
|
13043
|
+
},
|
|
12959
13044
|
// StrategicThemeProperties: StrategicTheme entity. A time-bound thrust WITHIN a
|
|
12960
13045
|
// strategic_pillar (distinct cascade level, UPG-692 T3.3) — measured through its
|
|
12961
13046
|
// child objectives, so it carries no success_indicator of its own.
|
|
@@ -19984,6 +20069,7 @@ var ENTITY_EMOJI = {
|
|
|
19984
20069
|
stakeholder: "\u{1F9D1}\u200D\u{1F4BC}",
|
|
19985
20070
|
status_report: "\u{1F4C4}",
|
|
19986
20071
|
strategic_pillar: "\u{1F3DB}\uFE0F",
|
|
20072
|
+
strategic_question: "\u2754",
|
|
19987
20073
|
strategic_theme: "\u{1F9F5}",
|
|
19988
20074
|
subscription: "\u{1F502}",
|
|
19989
20075
|
success_milestone: "\u{1F389}",
|
|
@@ -20541,6 +20627,7 @@ var STANDARD_LABELS = {
|
|
|
20541
20627
|
value_stream: { alt_labels: ["value chain", "stream"] },
|
|
20542
20628
|
strategic_pillar: { alt_labels: ["pillar", "foundation"] },
|
|
20543
20629
|
assumption: { alt_labels: ["belief", "working assumption", "premise"] },
|
|
20630
|
+
strategic_question: { alt_labels: ["open question", "coordination question", "ownership question"] },
|
|
20544
20631
|
// User layer
|
|
20545
20632
|
job_step: { alt_labels: ["job stage", "job phase", "job map step"] },
|
|
20546
20633
|
switching_cost: { alt_labels: ["lock-in", "migration cost", "switching barrier"] },
|
|
@@ -21279,6 +21366,30 @@ var UPG_TREE_PATTERNS = [
|
|
|
21279
21366
|
metric: [opt("metric"), opt("outcome")]
|
|
21280
21367
|
},
|
|
21281
21368
|
natural_depth: 3
|
|
21369
|
+
},
|
|
21370
|
+
{
|
|
21371
|
+
id: "org",
|
|
21372
|
+
label: "Org chart",
|
|
21373
|
+
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.",
|
|
21374
|
+
region: "operations_quality",
|
|
21375
|
+
gap_policy: "all-optional",
|
|
21376
|
+
anchor_type: "department",
|
|
21377
|
+
// A graph with no department roots at the team (team -> sub-team), reported
|
|
21378
|
+
// anchor_resolved_from: department. A sub-team also renders as a bare team
|
|
21379
|
+
// root when its parent department is not modelled.
|
|
21380
|
+
fallback_anchors: ["team"],
|
|
21381
|
+
child_map: {
|
|
21382
|
+
// department -> team (department_contains_team) is the first level; team ->
|
|
21383
|
+
// team (team_contains_team, 0.17.2) is the second, so a sub-team nested one
|
|
21384
|
+
// level deeper than department_contains_team renders under its parent team.
|
|
21385
|
+
// Self-nesting: the assembler's `seen` set terminates a team -> team cycle
|
|
21386
|
+
// for free (a team met again becomes a shared reference).
|
|
21387
|
+
department: [opt("team")],
|
|
21388
|
+
team: [opt("team")]
|
|
21389
|
+
},
|
|
21390
|
+
// Default to 3 tiers (department -> team -> sub-team); `depth` extends into
|
|
21391
|
+
// deeper team_contains_team nesting.
|
|
21392
|
+
natural_depth: 3
|
|
21282
21393
|
}
|
|
21283
21394
|
];
|
|
21284
21395
|
var UPG_TREE_PATTERNS_BY_ID = Object.fromEntries(
|
|
@@ -23061,25 +23172,34 @@ var STRATEGY_GUIDE = {
|
|
|
23061
23172
|
// entries are later additions appended in chronological-introduction
|
|
23062
23173
|
// order. Placement reflects the order in which they would naturally be
|
|
23063
23174
|
// authored after the canonical strategy spine.
|
|
23064
|
-
creation_sequence: ["product", "vision", "mission", "outcome", "objective", "key_result", "metric", "metric_quality_assessment", "strategic_theme", "strategic_pillar", "initiative", "capability", "value_stream", "assumption", "decision", "constraint"],
|
|
23175
|
+
creation_sequence: ["product", "vision", "mission", "outcome", "objective", "key_result", "metric", "metric_quality_assessment", "strategic_theme", "strategic_pillar", "initiative", "capability", "value_stream", "assumption", "strategic_question", "decision", "constraint"],
|
|
23065
23176
|
patterns: [
|
|
23066
23177
|
{
|
|
23067
23178
|
name: "Strategic Cascade",
|
|
23068
23179
|
description: "Vision grounds mission, product pursues outcomes and targets objectives, objectives achieved through key results measured by metrics",
|
|
23069
23180
|
entity_types: ["vision", "mission", "outcome", "objective", "key_result", "metric"],
|
|
23070
23181
|
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"]
|
|
23182
|
+
},
|
|
23183
|
+
{
|
|
23184
|
+
name: "Rendering the company spine",
|
|
23185
|
+
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.",
|
|
23186
|
+
entity_types: ["strategic_theme", "objective", "key_result", "metric"],
|
|
23187
|
+
edge_chain: ["strategic_theme_contains_objective", "objective_achieved_through_key_result", "key_result_quantified_by_metric"]
|
|
23071
23188
|
}
|
|
23072
23189
|
],
|
|
23073
23190
|
required_bridges: [
|
|
23074
23191
|
{ edge_type: "outcome_reveals_opportunity", target_domain: "discovery", when: "Outcomes should connect to the opportunities that deliver them" },
|
|
23075
23192
|
{ edge_type: "outcome_delivered_by_feature", target_domain: "product_spec", when: "Strategic outcomes should decompose into shipped features" },
|
|
23076
|
-
{ edge_type: "assumption_becomes_hypothesis", target_domain: "validation", when: "Risky assumptions should become testable hypotheses" }
|
|
23193
|
+
{ edge_type: "assumption_becomes_hypothesis", target_domain: "validation", when: "Risky assumptions should become testable hypotheses" },
|
|
23194
|
+
{ edge_type: "objective_depends_on_dependency", target_domain: "team_org", when: "An objective that hinges on cross-team work should name the dependency it is exposed to" },
|
|
23195
|
+
{ edge_type: "objective_defers_feature", target_domain: "product_spec", when: "Work an objective explicitly puts out of scope for now should point at the deferred feature with a deferred_to period, not silently vanish from the quarter" }
|
|
23077
23196
|
],
|
|
23078
23197
|
anti_patterns: [
|
|
23079
23198
|
{ description: "Outcomes without metrics. Measurement is the signal an outcome happened." },
|
|
23080
23199
|
{ description: "Objectives without key results: an objective without measurement is a wish" },
|
|
23081
23200
|
{ description: "Too many strategic themes: focus beats breadth, aim for 2-4 active themes" },
|
|
23082
|
-
{ 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)." }
|
|
23201
|
+
{ 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)." },
|
|
23202
|
+
{ description: "Overloading assumption for open questions: an assumption is a premise the plan is built on and resolves by being tested (assumption_becomes_hypothesis). An unresolved coordination or ownership question the plan is exposed to (who owns a capability across teams, where a boundary falls after a reorg) is a strategic_question, raised under the objective or initiative it hangs off. Do not force one into the other." }
|
|
23083
23203
|
]
|
|
23084
23204
|
};
|
|
23085
23205
|
var PRODUCT_SPEC_GUIDE = {
|
|
@@ -27132,6 +27252,10 @@ var UPG_REGIONS = [
|
|
|
27132
27252
|
type: "assumption",
|
|
27133
27253
|
role: "leaf"
|
|
27134
27254
|
},
|
|
27255
|
+
{
|
|
27256
|
+
type: "strategic_question",
|
|
27257
|
+
role: "leaf"
|
|
27258
|
+
},
|
|
27135
27259
|
{
|
|
27136
27260
|
type: "constraint",
|
|
27137
27261
|
role: "leaf"
|
|
@@ -27157,6 +27281,8 @@ var UPG_REGIONS = [
|
|
|
27157
27281
|
"strategic_pillar_decided_via_decision",
|
|
27158
27282
|
"strategic_theme_pursues_initiative",
|
|
27159
27283
|
"initiative_assumes_assumption",
|
|
27284
|
+
"objective_raises_strategic_question",
|
|
27285
|
+
"initiative_raises_strategic_question",
|
|
27160
27286
|
"initiative_drives_outcome",
|
|
27161
27287
|
"objective_achieved_through_key_result",
|
|
27162
27288
|
"objective_measured_by_metric",
|
|
@@ -29841,7 +29967,7 @@ function isCanonical(text) {
|
|
|
29841
29967
|
}
|
|
29842
29968
|
|
|
29843
29969
|
// src/index.ts
|
|
29844
|
-
var UPG_VERSION = "0.17.
|
|
29970
|
+
var UPG_VERSION = "0.17.4";
|
|
29845
29971
|
var UPG_FORMAT_VERSION = "0.4.0";
|
|
29846
29972
|
var MARKDOWN_FORMAT_VERSION = "0.1";
|
|
29847
29973
|
var UPG_TYPES = getTypes();
|
|
@@ -29915,6 +30041,7 @@ var UPG_META_COUNT = UPG_ENTITY_META.length;
|
|
|
29915
30041
|
COVERAGE_ANTI_PATTERNS,
|
|
29916
30042
|
DEFAULT_ENTITY_EMOJI,
|
|
29917
30043
|
DEFERRED_PROPOSED_BY_CONTRACT,
|
|
30044
|
+
DEFER_EDGE_PROPERTY_SCHEMA,
|
|
29918
30045
|
DISCOVERY_RESEARCH_VALIDATION_PLAYBOOK,
|
|
29919
30046
|
ENGINEERING_PLATFORM_PLAYBOOK,
|
|
29920
30047
|
ENTITY_EMOJI,
|
|
@@ -29944,6 +30071,9 @@ var UPG_META_COUNT = UPG_ENTITY_META.length;
|
|
|
29944
30071
|
UPG_CONTAINMENT_FREE_TYPES,
|
|
29945
30072
|
UPG_COUNT_BENCHMARKS,
|
|
29946
30073
|
UPG_CROSS_EDGE_TYPES,
|
|
30074
|
+
UPG_CROSS_ELIGIBLE_CATALOG_EDGE_TYPES,
|
|
30075
|
+
UPG_CROSS_ONLY_EDGE_TYPES,
|
|
30076
|
+
UPG_DELIBERATE_ONLY_EDGE_TYPES,
|
|
29947
30077
|
UPG_DEPRECATED_TYPES,
|
|
29948
30078
|
UPG_DOMAINS,
|
|
29949
30079
|
UPG_DOMAIN_ACTIVATION,
|
|
@@ -30074,6 +30204,8 @@ var UPG_META_COUNT = UPG_ENTITY_META.length;
|
|
|
30074
30204
|
isCanonical,
|
|
30075
30205
|
isCanonicalProductStage,
|
|
30076
30206
|
isContainmentFreeType,
|
|
30207
|
+
isCrossProductEligible,
|
|
30208
|
+
isDeliberateOnlyEdge,
|
|
30077
30209
|
isDeprecatedType,
|
|
30078
30210
|
isDomainGuideStep,
|
|
30079
30211
|
isEntitySequenceStep,
|