@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/CHANGELOG.md CHANGED
@@ -7,6 +7,38 @@ This project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
8
  ---
9
9
 
10
+ ## [0.9.17] - 2026-06-11
11
+
12
+ **CLI-next: the CLI catches up to the spec, the tree learns its frameworks, and ordering finally means something.** The `upg` CLI had frozen at the 0.8.x command set while the MCP tool surface grew to 121; its `list`/`tree` ordered lexically and re-rendered shared subtrees into noise. This release closes all of it, and folds in the `get_tree` pattern-definition fixes from a post-ship report on a real 304-node graph.
13
+
14
+ ### Added
15
+ - **Meaning-aware node ordering** (`compareNodesWithinType`, SDK). The intra-type sort ladder: explicit order field (`<type>_order` / order / sequence / ...) -> semantic version (title or `version`) -> lifecycle/status phase position -> `created_at` -> numeric-aware locale. A release series now reads `v5.0.0, v5.1.0, ... v5.9.0, v5.10.0, ... v5.30.0, v6.0.0` instead of the lexical `v5.1.0, v5.10.0, ... v5.2.0`. `list`/`tree` and `get_tree` share it.
16
+ - **DAG-honest tree assembly.** A UPG graph is a DAG; a multi-parent node now renders its subtree ONCE and appears as a `shared` reference under its other parents, in both `get_tree` (`stats.shared_refs`) and the CLI `tree` (`↗ shown above`). Nothing is silently dropped, nothing re-explodes, cycles terminate. `assembleTree` moved to the SDK so the local server, cloud server, and CLI share one implementation.
17
+ - **A `delivery` tree pattern** for the roadmap/release region; `UPG_TREE_PATTERNS` is now 8.
18
+ - **CLI tool-parity surface**: the full 0.9.x MCP surface as commands. New groups `spec` (offline catalogue browser, 36 nouns), `query`, `registry`, `portfolio`, `area`, `migrate`; `tree --pattern <id>` (framework-aware trees via the shared assembler); and singletons `move`, `disconnect`, `dedupe`, `clone`, `context`, `log`, `prioritise`, `sync status`, `product update`, `batch`. Six MCP tools are deliberately not mirrored (recorded by ADR): the agent-cognitive `plan`/`reflect`/`trace`, the remote-mutating `apply_pull_changeset`/`push_to_cloud`, and the skill-dev `skill_audit`.
19
+
20
+ ### Changed
21
+ - **`get_tree` pattern definitions corrected (G1-G7)** against the real graph: child slots gain a `required` flag so gaps flag only genuinely-missing required children (no more ~50 false `epic` gaps); the `strategy` pattern reaches the polymorphically-parented bets and auto-flags a bet with no initiative; `okr` extends to the `metric` leaf and `ost` to `hypothesis`/`experiment_plan`; `validation` accepts `experiment` or `experiment_run`; anchor selection picks the candidate that surfaces the most of the pattern, not the first non-empty.
22
+
23
+ No entity, domain, region, playbook, framework, or local-tool count change (entities 315, edges 980, local tools 121, regions 11, frameworks 46). The work is in the CLI, the SDK, and the tree presentation layer.
24
+
25
+ ---
26
+
27
+ ## [0.9.16] - 2026-06-11
28
+
29
+ **get_tree reaches the cloud, the show-tree skill calls it, and the three "area" taxonomies get a documented cross-walk.** 0.9.15 shipped `get_tree` local-only and left the show-tree skill on its interim hardcoded chains; this release finishes the loop and closes the deferred A4 introspection gap.
30
+
31
+ ### Added
32
+ - **`get_tree` on the cloud server** (cloud tools 94 to 95; local unchanged at 121). The assembler (`assembleTree` + the `GraphReader` interface) moved to the shared `@unified-product-graph/mcp-tooling` package, so the local file-backed server and the cloud Postgres-backed server assemble byte-identical trees from one source. The cloud handler builds an in-memory `GraphReader` from a one-shot product node+edge load. `get_tree` leaves the CLOUD_NA parity list.
33
+ - **`UPG_AREA_TAXONOMY`** (core): the documented cross-walk between the three overlapping "area" groupings that skills kept conflating into a stale coverage denominator: the 10 `get_graph_digest.coverage` keys, the 11 canonical regions, and the 8 "business areas". Keyed by coverage key; each row names the matching business area (null for `validation` and `operations`, which the 8-area grouping folds into discovery / omits) and the region ids its entities live in. Helpers `getCoverageKeysForRegion` / `getBusinessAreasForRegion`. Surfaced on `list_regions` (an `area_taxonomy` block plus per-region `coverage_keys` / `business_areas`) and `get_region` (per-region `coverage_keys` / `business_areas`), local and cloud. An SDK drift test pins the key sets against the runtime sources (`BUSINESS_AREAS`, `BUSINESS_AREA_META`).
34
+
35
+ ### Changed
36
+ - **`/upg-show-tree` calls `get_tree`** instead of building traverse chains and resolving edge names. The skill now renders the returned roots / children, surfaces `gaps`, and notes anchor fallback; it no longer carries the edge-name chains that drifted (the exact failure `get_tree` exists to prevent). Adds the `feature_areas` pattern. Skills ship in the mcp-server package, so this reaches users with the release.
37
+
38
+ No entity, domain, region, playbook, framework, or edge-count change, and no change to the local tool surface (entities 315, edges 980, local tools 121, regions 11).
39
+
40
+ ---
41
+
10
42
  ## [0.9.15] - 2026-06-11
11
43
 
12
44
  **get_tree: server-side tree assembly.** Tree views (OST, OKR, user, product, validation, strategy, feature areas) were assembled client-side by the show-tree skill out of multiple query calls and hardcoded edge chains that drifted with the spec. This release relocates assembly to the server, which owns the catalogue.
package/dist/index.cjs CHANGED
@@ -44,6 +44,8 @@ __export(index_exports, {
44
44
  UPG_ANTI_PATTERNS: () => UPG_ANTI_PATTERNS,
45
45
  UPG_APPROACHES: () => UPG_APPROACHES,
46
46
  UPG_APPROACHES_BY_ID: () => UPG_APPROACHES_BY_ID,
47
+ UPG_AREA_TAXONOMY: () => UPG_AREA_TAXONOMY,
48
+ UPG_AREA_TAXONOMY_BY_COVERAGE_KEY: () => UPG_AREA_TAXONOMY_BY_COVERAGE_KEY,
47
49
  UPG_CANONICAL_FORMAT_VERSION: () => UPG_CANONICAL_FORMAT_VERSION,
48
50
  UPG_CONTAINMENT_FREE_TYPES: () => UPG_CONTAINMENT_FREE_TYPES,
49
51
  UPG_COUNT_BENCHMARKS: () => UPG_COUNT_BENCHMARKS,
@@ -121,9 +123,12 @@ __export(index_exports, {
121
123
  getAntiPatterns: () => getAntiPatterns,
122
124
  getAntiPatternsBySeverity: () => getAntiPatternsBySeverity,
123
125
  getAntiPatternsForStage: () => getAntiPatternsForStage,
126
+ getAreaTaxonomyEntry: () => getAreaTaxonomyEntry,
124
127
  getBenchmark: () => getBenchmark,
125
128
  getBenchmarksByDomain: () => getBenchmarksByDomain,
129
+ getBusinessAreasForRegion: () => getBusinessAreasForRegion,
126
130
  getCanonicalPlaybookForRegion: () => getCanonicalPlaybookForRegion,
131
+ getCoverageKeysForRegion: () => getCoverageKeysForRegion,
127
132
  getDefaultLens: () => getDefaultLens,
128
133
  getDeprecatedTypes: () => getDeprecatedTypes,
129
134
  getDomainForType: () => getDomainForType,
@@ -18403,13 +18408,13 @@ function validateFrameworkScores(nodes, edges, warnings) {
18403
18408
  const divisors = divisorInputs(framework);
18404
18409
  const path = `$.edges[${i}].properties`;
18405
18410
  const scoreObj = score;
18406
- for (const req of requirements) {
18407
- const value = scoreObj[req.property];
18411
+ for (const req2 of requirements) {
18412
+ const value = scoreObj[req2.property];
18408
18413
  if (value === void 0 || value === null) continue;
18409
- const finding = checkScoreValue(req, value, divisors.has(req.property), framework.id);
18414
+ const finding = checkScoreValue(req2, value, divisors.has(req2.property), framework.id);
18410
18415
  if (finding) {
18411
18416
  warnings.push({
18412
- path: `${path}.${req.property}`,
18417
+ path: `${path}.${req2.property}`,
18413
18418
  message: finding,
18414
18419
  rule: "framework-score"
18415
18420
  });
@@ -18429,58 +18434,58 @@ function divisorInputs(framework) {
18429
18434
  return out;
18430
18435
  }
18431
18436
  var EMPTY_STRING_SET = /* @__PURE__ */ new Set();
18432
- function checkScoreValue(req, value, isDivisor, frameworkId) {
18433
- switch (req.type) {
18437
+ function checkScoreValue(req2, value, isDivisor, frameworkId) {
18438
+ switch (req2.type) {
18434
18439
  case "enum": {
18435
- const allowed = req.enum_values ?? [];
18440
+ const allowed = req2.enum_values ?? [];
18436
18441
  if (typeof value !== "string") {
18437
- return `${frameworkId} score "${req.property}" must be one of ${allowed.join(", ")}; got ${describeKind(value)}.`;
18442
+ return `${frameworkId} score "${req2.property}" must be one of ${allowed.join(", ")}; got ${describeKind(value)}.`;
18438
18443
  }
18439
18444
  if (allowed.length > 0 && !allowed.includes(value)) {
18440
- return `${frameworkId} score "${req.property}" has value "${value}" outside its allowed set: ${allowed.join(", ")}.`;
18445
+ return `${frameworkId} score "${req2.property}" has value "${value}" outside its allowed set: ${allowed.join(", ")}.`;
18441
18446
  }
18442
18447
  return null;
18443
18448
  }
18444
18449
  case "assessment": {
18445
18450
  const num = numericScore(value);
18446
18451
  if (num === null) {
18447
- return `${frameworkId} score "${req.property}" must be a number; got ${describeKind(value)}.`;
18452
+ return `${frameworkId} score "${req2.property}" must be a number; got ${describeKind(value)}.`;
18448
18453
  }
18449
- const scale = req.scale_id ? getScale(req.scale_id) : void 0;
18454
+ const scale = req2.scale_id ? getScale(req2.scale_id) : void 0;
18450
18455
  if (scale) {
18451
18456
  if (num < scale.min || num > scale.max) {
18452
- return `${frameworkId} score "${req.property}" is ${num}, outside the ${req.scale_id} scale range [${scale.min}, ${scale.max}].`;
18457
+ return `${frameworkId} score "${req2.property}" is ${num}, outside the ${req2.scale_id} scale range [${scale.min}, ${scale.max}].`;
18453
18458
  }
18454
18459
  } else if (num <= 0) {
18455
- return `${frameworkId} score "${req.property}" must be greater than 0; got ${num}.`;
18460
+ return `${frameworkId} score "${req2.property}" must be greater than 0; got ${num}.`;
18456
18461
  }
18457
18462
  if (isDivisor && num === 0) {
18458
- return `${frameworkId} score "${req.property}" must not be 0 (it is a divisor in the framework's formula).`;
18463
+ return `${frameworkId} score "${req2.property}" must not be 0 (it is a divisor in the framework's formula).`;
18459
18464
  }
18460
18465
  return null;
18461
18466
  }
18462
18467
  case "number": {
18463
18468
  const num = numericScore(value);
18464
18469
  if (num === null) {
18465
- return `${frameworkId} score "${req.property}" must be a number; got ${describeKind(value)}.`;
18470
+ return `${frameworkId} score "${req2.property}" must be a number; got ${describeKind(value)}.`;
18466
18471
  }
18467
18472
  if (isDivisor && num === 0) {
18468
- return `${frameworkId} score "${req.property}" must not be 0 (it is a divisor in the framework's formula).`;
18473
+ return `${frameworkId} score "${req2.property}" must not be 0 (it is a divisor in the framework's formula).`;
18469
18474
  }
18470
18475
  if (num < 0) {
18471
- return `${frameworkId} score "${req.property}" must not be negative; got ${num}.`;
18476
+ return `${frameworkId} score "${req2.property}" must not be negative; got ${num}.`;
18472
18477
  }
18473
18478
  return null;
18474
18479
  }
18475
18480
  case "boolean": {
18476
18481
  if (typeof value !== "boolean") {
18477
- return `${frameworkId} score "${req.property}" must be a boolean; got ${describeKind(value)}.`;
18482
+ return `${frameworkId} score "${req2.property}" must be a boolean; got ${describeKind(value)}.`;
18478
18483
  }
18479
18484
  return null;
18480
18485
  }
18481
18486
  case "string": {
18482
18487
  if (typeof value !== "string") {
18483
- return `${frameworkId} score "${req.property}" must be a string; got ${describeKind(value)}.`;
18488
+ return `${frameworkId} score "${req2.property}" must be a string; got ${describeKind(value)}.`;
18484
18489
  }
18485
18490
  return null;
18486
18491
  }
@@ -19866,33 +19871,38 @@ function buildTypeAliases() {
19866
19871
  var UPG_TYPE_ALIASES = buildTypeAliases();
19867
19872
 
19868
19873
  // src/presentation/tree-patterns.ts
19874
+ var req = (type) => ({ type, required: true });
19875
+ var opt = (type) => ({ type });
19869
19876
  var UPG_TREE_PATTERNS = [
19870
19877
  {
19871
19878
  id: "ost",
19872
19879
  label: "Opportunity Solution Tree",
19873
- description: "A desired outcome branching into the opportunities under it and the solutions that address them (Teresa Torres).",
19880
+ 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).",
19874
19881
  framework_id: "opportunity-solution-tree",
19875
19882
  anchor_type: "outcome",
19876
19883
  fallback_anchors: ["desired_outcome", "opportunity"],
19877
19884
  child_map: {
19878
- outcome: ["opportunity"],
19879
- desired_outcome: ["opportunity"],
19880
- opportunity: ["solution"]
19885
+ outcome: [req("opportunity")],
19886
+ desired_outcome: [req("opportunity")],
19887
+ opportunity: [req("solution")],
19888
+ solution: [opt("hypothesis")],
19889
+ hypothesis: [opt("experiment_plan")]
19881
19890
  },
19882
- natural_depth: 3
19891
+ natural_depth: 5
19883
19892
  },
19884
19893
  {
19885
19894
  id: "okr",
19886
19895
  label: "Objectives and Key Results",
19887
- description: "Strategic themes containing objectives, each measured by its key results (John Doerr).",
19896
+ description: "Strategic themes containing objectives, each measured by its key results and the metric that quantifies them (John Doerr).",
19888
19897
  framework_id: "okr-framework",
19889
19898
  anchor_type: "strategic_theme",
19890
19899
  fallback_anchors: ["objective"],
19891
19900
  child_map: {
19892
- strategic_theme: ["objective"],
19893
- objective: ["key_result"]
19901
+ strategic_theme: [req("objective")],
19902
+ objective: [req("key_result")],
19903
+ key_result: [opt("metric")]
19894
19904
  },
19895
- natural_depth: 3
19905
+ natural_depth: 4
19896
19906
  },
19897
19907
  {
19898
19908
  id: "user",
@@ -19901,54 +19911,55 @@ var UPG_TREE_PATTERNS = [
19901
19911
  anchor_type: "persona",
19902
19912
  fallback_anchors: ["job"],
19903
19913
  child_map: {
19904
- persona: ["job", "need", "desired_outcome"],
19905
- job: ["need", "desired_outcome"]
19914
+ persona: [req("job"), opt("need"), opt("desired_outcome")],
19915
+ job: [opt("need"), opt("desired_outcome")]
19906
19916
  },
19907
19917
  natural_depth: 3
19908
19918
  },
19909
19919
  {
19910
19920
  id: "product",
19911
19921
  label: "Product breakdown",
19912
- description: "The product organised into feature areas, then features, epics, and user stories.",
19922
+ description: "The product organised into feature areas, then features, and the optional epic + user story tiers beneath them.",
19913
19923
  anchor_type: "product",
19914
19924
  fallback_anchors: ["feature_area", "feature"],
19915
19925
  child_map: {
19916
- product: ["feature_area"],
19917
- feature_area: ["feature"],
19918
- feature: ["epic"],
19919
- epic: ["user_story"]
19926
+ product: [opt("feature_area")],
19927
+ feature_area: [req("feature")],
19928
+ feature: [opt("epic")],
19929
+ epic: [opt("user_story")]
19920
19930
  },
19921
19931
  natural_depth: 5
19922
19932
  },
19923
19933
  {
19924
19934
  id: "validation",
19925
19935
  label: "Validation chain",
19926
- description: "A hypothesis through its experiment plan, experiment, run, and the learning it produced.",
19936
+ description: "A hypothesis through its experiment plan, the experiment (or its runs), and the learning it produced.",
19927
19937
  framework_id: "build-measure-learn",
19928
19938
  anchor_type: "hypothesis",
19929
19939
  fallback_anchors: ["experiment_plan", "experiment"],
19930
19940
  child_map: {
19931
- hypothesis: ["experiment_plan"],
19932
- experiment_plan: ["experiment"],
19933
- experiment: ["experiment_run"],
19934
- experiment_run: ["learning"]
19941
+ hypothesis: [req("experiment_plan")],
19942
+ experiment_plan: [req("experiment"), req("experiment_run")],
19943
+ experiment: [opt("experiment_run"), opt("learning")],
19944
+ experiment_run: [opt("learning")]
19935
19945
  },
19936
19946
  natural_depth: 5
19937
19947
  },
19938
19948
  {
19939
19949
  id: "strategy",
19940
19950
  label: "Strategy cascade",
19941
- 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.",
19951
+ 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.",
19942
19952
  anchor_type: "vision",
19943
19953
  fallback_anchors: ["product", "strategic_theme"],
19944
19954
  child_map: {
19945
- vision: ["mission", "strategic_theme"],
19946
- product: ["strategic_theme"],
19947
- mission: ["strategic_theme"],
19948
- strategic_theme: ["initiative"],
19949
- initiative: ["outcome"]
19955
+ vision: [opt("mission"), opt("strategic_theme")],
19956
+ mission: [opt("strategic_pillar")],
19957
+ strategic_pillar: [opt("strategic_theme")],
19958
+ product: [opt("strategic_theme")],
19959
+ strategic_theme: [req("initiative")],
19960
+ initiative: [opt("outcome")]
19950
19961
  },
19951
- natural_depth: 4
19962
+ natural_depth: 5
19952
19963
  },
19953
19964
  {
19954
19965
  id: "feature_areas",
@@ -19957,9 +19968,26 @@ var UPG_TREE_PATTERNS = [
19957
19968
  anchor_type: "feature_area",
19958
19969
  fallback_anchors: ["feature"],
19959
19970
  child_map: {
19960
- feature_area: ["feature"]
19971
+ feature_area: [opt("feature")]
19961
19972
  },
19962
19973
  natural_depth: 2
19974
+ },
19975
+ {
19976
+ id: "delivery",
19977
+ label: "Delivery roadmap",
19978
+ 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.",
19979
+ anchor_type: "roadmap",
19980
+ fallback_anchors: ["product", "release"],
19981
+ child_map: {
19982
+ product: [opt("roadmap"), opt("release")],
19983
+ roadmap: [opt("roadmap_theme"), opt("roadmap_item"), opt("release")],
19984
+ roadmap_theme: [opt("feature")],
19985
+ roadmap_item: [opt("feature")],
19986
+ release: [opt("feature")],
19987
+ feature: [opt("epic")],
19988
+ epic: [opt("user_story")]
19989
+ },
19990
+ natural_depth: 5
19963
19991
  }
19964
19992
  ];
19965
19993
  var UPG_TREE_PATTERNS_BY_ID = Object.fromEntries(
@@ -19969,6 +19997,36 @@ function getTreePattern(id) {
19969
19997
  return UPG_TREE_PATTERNS_BY_ID[id];
19970
19998
  }
19971
19999
 
20000
+ // src/presentation/area-taxonomy.ts
20001
+ var UPG_AREA_TAXONOMY = [
20002
+ { coverage_key: "identity", label: "Identity", business_area: "identity", regions: ["strategy_outcomes"] },
20003
+ { coverage_key: "understanding", label: "Understanding", business_area: "understanding", regions: ["users_needs", "discovery_research_validation"] },
20004
+ { coverage_key: "discovery", label: "Discovery", business_area: "discovery", regions: ["discovery_research_validation", "market_competitive"] },
20005
+ { coverage_key: "validation", label: "Validation", business_area: null, regions: ["discovery_research_validation"] },
20006
+ { coverage_key: "reaching", label: "Reaching", business_area: "reaching", regions: ["business_gtm_growth"] },
20007
+ { coverage_key: "converting", label: "Converting", business_area: "converting", regions: ["business_gtm_growth"] },
20008
+ { coverage_key: "building", label: "Building", business_area: "building", regions: ["product_delivery", "experience_design_brand"] },
20009
+ { coverage_key: "sustaining", label: "Sustaining", business_area: "sustaining", regions: ["business_gtm_growth"] },
20010
+ { coverage_key: "learning", label: "Learning", business_area: "learning", regions: ["strategy_outcomes", "analytics_data", "operations_quality"] },
20011
+ { coverage_key: "operations", label: "Operations", business_area: null, regions: ["operations_quality"] }
20012
+ ];
20013
+ var UPG_AREA_TAXONOMY_BY_COVERAGE_KEY = Object.fromEntries(UPG_AREA_TAXONOMY.map((e) => [e.coverage_key, e]));
20014
+ function getAreaTaxonomyEntry(coverageKey) {
20015
+ return UPG_AREA_TAXONOMY_BY_COVERAGE_KEY[coverageKey];
20016
+ }
20017
+ function getCoverageKeysForRegion(regionId) {
20018
+ return UPG_AREA_TAXONOMY.filter((e) => e.regions.includes(regionId)).map((e) => e.coverage_key);
20019
+ }
20020
+ function getBusinessAreasForRegion(regionId) {
20021
+ const out = [];
20022
+ for (const e of UPG_AREA_TAXONOMY) {
20023
+ if (e.regions.includes(regionId) && e.business_area && !out.includes(e.business_area)) {
20024
+ out.push(e.business_area);
20025
+ }
20026
+ }
20027
+ return out;
20028
+ }
20029
+
19972
20030
  // src/playbooks/definitions/index.ts
19973
20031
  function seqStep(order, phase, entity_types, prompt_hint, options) {
19974
20032
  return {
@@ -28242,7 +28300,7 @@ function isCanonical(text) {
28242
28300
  }
28243
28301
 
28244
28302
  // src/index.ts
28245
- var UPG_VERSION = "0.9.15";
28303
+ var UPG_VERSION = "0.9.17";
28246
28304
  var UPG_FORMAT_VERSION = "0.4.0";
28247
28305
  var MARKDOWN_FORMAT_VERSION = "0.1";
28248
28306
  var UPG_TYPES = getTypes();
@@ -28331,6 +28389,8 @@ var UPG_META_COUNT = UPG_ENTITY_META.length;
28331
28389
  UPG_ANTI_PATTERNS,
28332
28390
  UPG_APPROACHES,
28333
28391
  UPG_APPROACHES_BY_ID,
28392
+ UPG_AREA_TAXONOMY,
28393
+ UPG_AREA_TAXONOMY_BY_COVERAGE_KEY,
28334
28394
  UPG_CANONICAL_FORMAT_VERSION,
28335
28395
  UPG_CONTAINMENT_FREE_TYPES,
28336
28396
  UPG_COUNT_BENCHMARKS,
@@ -28408,9 +28468,12 @@ var UPG_META_COUNT = UPG_ENTITY_META.length;
28408
28468
  getAntiPatterns,
28409
28469
  getAntiPatternsBySeverity,
28410
28470
  getAntiPatternsForStage,
28471
+ getAreaTaxonomyEntry,
28411
28472
  getBenchmark,
28412
28473
  getBenchmarksByDomain,
28474
+ getBusinessAreasForRegion,
28413
28475
  getCanonicalPlaybookForRegion,
28476
+ getCoverageKeysForRegion,
28414
28477
  getDefaultLens,
28415
28478
  getDeprecatedTypes,
28416
28479
  getDomainForType,