@unified-product-graph/core 0.9.15 → 0.9.17

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.js CHANGED
@@ -18203,13 +18203,13 @@ function validateFrameworkScores(nodes, edges, warnings) {
18203
18203
  const divisors = divisorInputs(framework);
18204
18204
  const path = `$.edges[${i}].properties`;
18205
18205
  const scoreObj = score;
18206
- for (const req of requirements) {
18207
- const value = scoreObj[req.property];
18206
+ for (const req2 of requirements) {
18207
+ const value = scoreObj[req2.property];
18208
18208
  if (value === void 0 || value === null) continue;
18209
- const finding = checkScoreValue(req, value, divisors.has(req.property), framework.id);
18209
+ const finding = checkScoreValue(req2, value, divisors.has(req2.property), framework.id);
18210
18210
  if (finding) {
18211
18211
  warnings.push({
18212
- path: `${path}.${req.property}`,
18212
+ path: `${path}.${req2.property}`,
18213
18213
  message: finding,
18214
18214
  rule: "framework-score"
18215
18215
  });
@@ -18229,58 +18229,58 @@ function divisorInputs(framework) {
18229
18229
  return out;
18230
18230
  }
18231
18231
  var EMPTY_STRING_SET = /* @__PURE__ */ new Set();
18232
- function checkScoreValue(req, value, isDivisor, frameworkId) {
18233
- switch (req.type) {
18232
+ function checkScoreValue(req2, value, isDivisor, frameworkId) {
18233
+ switch (req2.type) {
18234
18234
  case "enum": {
18235
- const allowed = req.enum_values ?? [];
18235
+ const allowed = req2.enum_values ?? [];
18236
18236
  if (typeof value !== "string") {
18237
- return `${frameworkId} score "${req.property}" must be one of ${allowed.join(", ")}; got ${describeKind(value)}.`;
18237
+ return `${frameworkId} score "${req2.property}" must be one of ${allowed.join(", ")}; got ${describeKind(value)}.`;
18238
18238
  }
18239
18239
  if (allowed.length > 0 && !allowed.includes(value)) {
18240
- return `${frameworkId} score "${req.property}" has value "${value}" outside its allowed set: ${allowed.join(", ")}.`;
18240
+ return `${frameworkId} score "${req2.property}" has value "${value}" outside its allowed set: ${allowed.join(", ")}.`;
18241
18241
  }
18242
18242
  return null;
18243
18243
  }
18244
18244
  case "assessment": {
18245
18245
  const num = numericScore(value);
18246
18246
  if (num === null) {
18247
- return `${frameworkId} score "${req.property}" must be a number; got ${describeKind(value)}.`;
18247
+ return `${frameworkId} score "${req2.property}" must be a number; got ${describeKind(value)}.`;
18248
18248
  }
18249
- const scale = req.scale_id ? getScale(req.scale_id) : void 0;
18249
+ const scale = req2.scale_id ? getScale(req2.scale_id) : void 0;
18250
18250
  if (scale) {
18251
18251
  if (num < scale.min || num > scale.max) {
18252
- return `${frameworkId} score "${req.property}" is ${num}, outside the ${req.scale_id} scale range [${scale.min}, ${scale.max}].`;
18252
+ return `${frameworkId} score "${req2.property}" is ${num}, outside the ${req2.scale_id} scale range [${scale.min}, ${scale.max}].`;
18253
18253
  }
18254
18254
  } else if (num <= 0) {
18255
- return `${frameworkId} score "${req.property}" must be greater than 0; got ${num}.`;
18255
+ return `${frameworkId} score "${req2.property}" must be greater than 0; got ${num}.`;
18256
18256
  }
18257
18257
  if (isDivisor && num === 0) {
18258
- return `${frameworkId} score "${req.property}" must not be 0 (it is a divisor in the framework's formula).`;
18258
+ return `${frameworkId} score "${req2.property}" must not be 0 (it is a divisor in the framework's formula).`;
18259
18259
  }
18260
18260
  return null;
18261
18261
  }
18262
18262
  case "number": {
18263
18263
  const num = numericScore(value);
18264
18264
  if (num === null) {
18265
- return `${frameworkId} score "${req.property}" must be a number; got ${describeKind(value)}.`;
18265
+ return `${frameworkId} score "${req2.property}" must be a number; got ${describeKind(value)}.`;
18266
18266
  }
18267
18267
  if (isDivisor && num === 0) {
18268
- return `${frameworkId} score "${req.property}" must not be 0 (it is a divisor in the framework's formula).`;
18268
+ return `${frameworkId} score "${req2.property}" must not be 0 (it is a divisor in the framework's formula).`;
18269
18269
  }
18270
18270
  if (num < 0) {
18271
- return `${frameworkId} score "${req.property}" must not be negative; got ${num}.`;
18271
+ return `${frameworkId} score "${req2.property}" must not be negative; got ${num}.`;
18272
18272
  }
18273
18273
  return null;
18274
18274
  }
18275
18275
  case "boolean": {
18276
18276
  if (typeof value !== "boolean") {
18277
- return `${frameworkId} score "${req.property}" must be a boolean; got ${describeKind(value)}.`;
18277
+ return `${frameworkId} score "${req2.property}" must be a boolean; got ${describeKind(value)}.`;
18278
18278
  }
18279
18279
  return null;
18280
18280
  }
18281
18281
  case "string": {
18282
18282
  if (typeof value !== "string") {
18283
- return `${frameworkId} score "${req.property}" must be a string; got ${describeKind(value)}.`;
18283
+ return `${frameworkId} score "${req2.property}" must be a string; got ${describeKind(value)}.`;
18284
18284
  }
18285
18285
  return null;
18286
18286
  }
@@ -19666,33 +19666,38 @@ function buildTypeAliases() {
19666
19666
  var UPG_TYPE_ALIASES = buildTypeAliases();
19667
19667
 
19668
19668
  // src/presentation/tree-patterns.ts
19669
+ var req = (type) => ({ type, required: true });
19670
+ var opt = (type) => ({ type });
19669
19671
  var UPG_TREE_PATTERNS = [
19670
19672
  {
19671
19673
  id: "ost",
19672
19674
  label: "Opportunity Solution Tree",
19673
- description: "A desired outcome branching into the opportunities under it and the solutions that address them (Teresa Torres).",
19675
+ description: "A desired outcome branching into the opportunities under it, the solutions that address them, and the hypotheses + experiment plans that validate them (Teresa Torres).",
19674
19676
  framework_id: "opportunity-solution-tree",
19675
19677
  anchor_type: "outcome",
19676
19678
  fallback_anchors: ["desired_outcome", "opportunity"],
19677
19679
  child_map: {
19678
- outcome: ["opportunity"],
19679
- desired_outcome: ["opportunity"],
19680
- opportunity: ["solution"]
19680
+ outcome: [req("opportunity")],
19681
+ desired_outcome: [req("opportunity")],
19682
+ opportunity: [req("solution")],
19683
+ solution: [opt("hypothesis")],
19684
+ hypothesis: [opt("experiment_plan")]
19681
19685
  },
19682
- natural_depth: 3
19686
+ natural_depth: 5
19683
19687
  },
19684
19688
  {
19685
19689
  id: "okr",
19686
19690
  label: "Objectives and Key Results",
19687
- description: "Strategic themes containing objectives, each measured by its key results (John Doerr).",
19691
+ description: "Strategic themes containing objectives, each measured by its key results and the metric that quantifies them (John Doerr).",
19688
19692
  framework_id: "okr-framework",
19689
19693
  anchor_type: "strategic_theme",
19690
19694
  fallback_anchors: ["objective"],
19691
19695
  child_map: {
19692
- strategic_theme: ["objective"],
19693
- objective: ["key_result"]
19696
+ strategic_theme: [req("objective")],
19697
+ objective: [req("key_result")],
19698
+ key_result: [opt("metric")]
19694
19699
  },
19695
- natural_depth: 3
19700
+ natural_depth: 4
19696
19701
  },
19697
19702
  {
19698
19703
  id: "user",
@@ -19701,54 +19706,55 @@ var UPG_TREE_PATTERNS = [
19701
19706
  anchor_type: "persona",
19702
19707
  fallback_anchors: ["job"],
19703
19708
  child_map: {
19704
- persona: ["job", "need", "desired_outcome"],
19705
- job: ["need", "desired_outcome"]
19709
+ persona: [req("job"), opt("need"), opt("desired_outcome")],
19710
+ job: [opt("need"), opt("desired_outcome")]
19706
19711
  },
19707
19712
  natural_depth: 3
19708
19713
  },
19709
19714
  {
19710
19715
  id: "product",
19711
19716
  label: "Product breakdown",
19712
- description: "The product organised into feature areas, then features, epics, and user stories.",
19717
+ description: "The product organised into feature areas, then features, and the optional epic + user story tiers beneath them.",
19713
19718
  anchor_type: "product",
19714
19719
  fallback_anchors: ["feature_area", "feature"],
19715
19720
  child_map: {
19716
- product: ["feature_area"],
19717
- feature_area: ["feature"],
19718
- feature: ["epic"],
19719
- epic: ["user_story"]
19721
+ product: [opt("feature_area")],
19722
+ feature_area: [req("feature")],
19723
+ feature: [opt("epic")],
19724
+ epic: [opt("user_story")]
19720
19725
  },
19721
19726
  natural_depth: 5
19722
19727
  },
19723
19728
  {
19724
19729
  id: "validation",
19725
19730
  label: "Validation chain",
19726
- description: "A hypothesis through its experiment plan, experiment, run, and the learning it produced.",
19731
+ description: "A hypothesis through its experiment plan, the experiment (or its runs), and the learning it produced.",
19727
19732
  framework_id: "build-measure-learn",
19728
19733
  anchor_type: "hypothesis",
19729
19734
  fallback_anchors: ["experiment_plan", "experiment"],
19730
19735
  child_map: {
19731
- hypothesis: ["experiment_plan"],
19732
- experiment_plan: ["experiment"],
19733
- experiment: ["experiment_run"],
19734
- experiment_run: ["learning"]
19736
+ hypothesis: [req("experiment_plan")],
19737
+ experiment_plan: [req("experiment"), req("experiment_run")],
19738
+ experiment: [opt("experiment_run"), opt("learning")],
19739
+ experiment_run: [opt("learning")]
19735
19740
  },
19736
19741
  natural_depth: 5
19737
19742
  },
19738
19743
  {
19739
19744
  id: "strategy",
19740
19745
  label: "Strategy cascade",
19741
- description: "Vision and mission into the strategic themes (bets), the initiatives that pursue them, and the outcomes they drive. Themes anchor on vision OR the product, whichever the graph wired.",
19746
+ description: "Vision and mission into the strategic themes (bets), the initiatives that pursue them, and the outcomes they drive. Themes are polymorphically parented: they hang off vision, the product, or a strategic pillar, whichever the graph wired.",
19742
19747
  anchor_type: "vision",
19743
19748
  fallback_anchors: ["product", "strategic_theme"],
19744
19749
  child_map: {
19745
- vision: ["mission", "strategic_theme"],
19746
- product: ["strategic_theme"],
19747
- mission: ["strategic_theme"],
19748
- strategic_theme: ["initiative"],
19749
- initiative: ["outcome"]
19750
+ vision: [opt("mission"), opt("strategic_theme")],
19751
+ mission: [opt("strategic_pillar")],
19752
+ strategic_pillar: [opt("strategic_theme")],
19753
+ product: [opt("strategic_theme")],
19754
+ strategic_theme: [req("initiative")],
19755
+ initiative: [opt("outcome")]
19750
19756
  },
19751
- natural_depth: 4
19757
+ natural_depth: 5
19752
19758
  },
19753
19759
  {
19754
19760
  id: "feature_areas",
@@ -19757,9 +19763,26 @@ var UPG_TREE_PATTERNS = [
19757
19763
  anchor_type: "feature_area",
19758
19764
  fallback_anchors: ["feature"],
19759
19765
  child_map: {
19760
- feature_area: ["feature"]
19766
+ feature_area: [opt("feature")]
19761
19767
  },
19762
19768
  natural_depth: 2
19769
+ },
19770
+ {
19771
+ id: "delivery",
19772
+ label: "Delivery roadmap",
19773
+ description: "How product work is scheduled and shipped: the roadmap and its themes/items, the releases they schedule, and the features (with optional epic + user story tiers) they deliver.",
19774
+ anchor_type: "roadmap",
19775
+ fallback_anchors: ["product", "release"],
19776
+ child_map: {
19777
+ product: [opt("roadmap"), opt("release")],
19778
+ roadmap: [opt("roadmap_theme"), opt("roadmap_item"), opt("release")],
19779
+ roadmap_theme: [opt("feature")],
19780
+ roadmap_item: [opt("feature")],
19781
+ release: [opt("feature")],
19782
+ feature: [opt("epic")],
19783
+ epic: [opt("user_story")]
19784
+ },
19785
+ natural_depth: 5
19763
19786
  }
19764
19787
  ];
19765
19788
  var UPG_TREE_PATTERNS_BY_ID = Object.fromEntries(
@@ -19769,6 +19792,36 @@ function getTreePattern(id) {
19769
19792
  return UPG_TREE_PATTERNS_BY_ID[id];
19770
19793
  }
19771
19794
 
19795
+ // src/presentation/area-taxonomy.ts
19796
+ var UPG_AREA_TAXONOMY = [
19797
+ { coverage_key: "identity", label: "Identity", business_area: "identity", regions: ["strategy_outcomes"] },
19798
+ { coverage_key: "understanding", label: "Understanding", business_area: "understanding", regions: ["users_needs", "discovery_research_validation"] },
19799
+ { coverage_key: "discovery", label: "Discovery", business_area: "discovery", regions: ["discovery_research_validation", "market_competitive"] },
19800
+ { coverage_key: "validation", label: "Validation", business_area: null, regions: ["discovery_research_validation"] },
19801
+ { coverage_key: "reaching", label: "Reaching", business_area: "reaching", regions: ["business_gtm_growth"] },
19802
+ { coverage_key: "converting", label: "Converting", business_area: "converting", regions: ["business_gtm_growth"] },
19803
+ { coverage_key: "building", label: "Building", business_area: "building", regions: ["product_delivery", "experience_design_brand"] },
19804
+ { coverage_key: "sustaining", label: "Sustaining", business_area: "sustaining", regions: ["business_gtm_growth"] },
19805
+ { coverage_key: "learning", label: "Learning", business_area: "learning", regions: ["strategy_outcomes", "analytics_data", "operations_quality"] },
19806
+ { coverage_key: "operations", label: "Operations", business_area: null, regions: ["operations_quality"] }
19807
+ ];
19808
+ var UPG_AREA_TAXONOMY_BY_COVERAGE_KEY = Object.fromEntries(UPG_AREA_TAXONOMY.map((e) => [e.coverage_key, e]));
19809
+ function getAreaTaxonomyEntry(coverageKey) {
19810
+ return UPG_AREA_TAXONOMY_BY_COVERAGE_KEY[coverageKey];
19811
+ }
19812
+ function getCoverageKeysForRegion(regionId) {
19813
+ return UPG_AREA_TAXONOMY.filter((e) => e.regions.includes(regionId)).map((e) => e.coverage_key);
19814
+ }
19815
+ function getBusinessAreasForRegion(regionId) {
19816
+ const out = [];
19817
+ for (const e of UPG_AREA_TAXONOMY) {
19818
+ if (e.regions.includes(regionId) && e.business_area && !out.includes(e.business_area)) {
19819
+ out.push(e.business_area);
19820
+ }
19821
+ }
19822
+ return out;
19823
+ }
19824
+
19772
19825
  // src/playbooks/definitions/index.ts
19773
19826
  function seqStep(order, phase, entity_types, prompt_hint, options) {
19774
19827
  return {
@@ -28042,7 +28095,7 @@ function isCanonical(text) {
28042
28095
  }
28043
28096
 
28044
28097
  // src/index.ts
28045
- var UPG_VERSION = "0.9.15";
28098
+ var UPG_VERSION = "0.9.17";
28046
28099
  var UPG_FORMAT_VERSION = "0.4.0";
28047
28100
  var MARKDOWN_FORMAT_VERSION = "0.1";
28048
28101
  var UPG_TYPES = getTypes();
@@ -28130,6 +28183,8 @@ export {
28130
28183
  UPG_ANTI_PATTERNS,
28131
28184
  UPG_APPROACHES,
28132
28185
  UPG_APPROACHES_BY_ID,
28186
+ UPG_AREA_TAXONOMY,
28187
+ UPG_AREA_TAXONOMY_BY_COVERAGE_KEY,
28133
28188
  UPG_CANONICAL_FORMAT_VERSION,
28134
28189
  UPG_CONTAINMENT_FREE_TYPES,
28135
28190
  UPG_COUNT_BENCHMARKS,
@@ -28207,9 +28262,12 @@ export {
28207
28262
  getAntiPatterns,
28208
28263
  getAntiPatternsBySeverity,
28209
28264
  getAntiPatternsForStage,
28265
+ getAreaTaxonomyEntry,
28210
28266
  getBenchmark,
28211
28267
  getBenchmarksByDomain,
28268
+ getBusinessAreasForRegion,
28212
28269
  getCanonicalPlaybookForRegion,
28270
+ getCoverageKeysForRegion,
28213
28271
  getDefaultLens,
28214
28272
  getDeprecatedTypes,
28215
28273
  getDomainForType,