@unified-product-graph/core 0.9.19 → 0.9.20

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,21 @@ This project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
8
  ---
9
9
 
10
+ ## [0.9.20] - 2026-06-11
11
+
12
+ **The tree-pattern catalogue is now introspectable and drift-guarded.** A pattern can no longer cite an edge the grammar lacks, and clients can read the catalogue instead of reverse-engineering it.
13
+
14
+ ### Added
15
+ - **Two introspection tools** (local + cloud, spec-introspection family, local 121 to 123 / cloud 95 to 97):
16
+ - **`list_tree_patterns`** returns every `get_tree` pattern as a summary row: id, label, the region it is the tree view of, anchor, fallback anchors, natural depth, gap policy, and slot count. Paired with `list_regions`, coverage becomes a queryable diff.
17
+ - **`get_tree_pattern(id)`** returns the full declarative record: region, anchor, fallbacks, gap policy, depth, and the child map resolved to concrete edges. Each parent-to-child slot carries the canonical `via` edge and its `kind`, resolved live from the edge catalogue, so a client reads the real wiring rather than reverse-engineering it from behaviour.
18
+ - **Declarative pattern records.** `UPGTreePattern` gains `region` (ties a pattern to its region and that region's `shape`) and `gap_policy` (`required-children-only` or `all-optional`). Helpers `listTreePatternSummaries`, `describeTreePattern`, and `resolveTreePatternEdges` expose the catalogue from core.
19
+ - **A drift-guard test.** Every pattern's every `(parent -> child)` slot must resolve to a canonical edge in the catalogue. A pattern that cites an ungrounded pair fails the build. This makes the whole class of bug structural (it already caught an `aggregate -> read_model` slot in the 0.9.19 architecture sketch that the grammar does not wire).
20
+
21
+ No entity, domain, region, or edge-count change (entities 315, edges 980); local tools 121 to 123, cloud 95 to 97.
22
+
23
+ ---
24
+
10
25
  ## [0.9.19] - 2026-06-11
11
26
 
12
27
  **The tree-pattern catalogue covers every tree-shaped region, and `delivery` finally roots at the roadmap.** `get_tree` now offers 11 patterns (was 8), one per hierarchical region.
package/dist/index.cjs CHANGED
@@ -113,6 +113,7 @@ __export(index_exports, {
113
113
  collectSlugsForType: () => collectSlugsForType,
114
114
  compareVersions: () => compareVersions,
115
115
  computeBodyChecksum: () => computeBodyChecksum,
116
+ describeTreePattern: () => describeTreePattern,
116
117
  edgeCarriesProperties: () => edgeCarriesProperties,
117
118
  evaluateAntiPatterns: () => evaluateAntiPatterns,
118
119
  findInvalidStatusMigrationTargets: () => findInvalidStatusMigrationTargets,
@@ -180,6 +181,7 @@ __export(index_exports, {
180
181
  isSubSequenceStep: () => isSubSequenceStep,
181
182
  isUPGDocument: () => isUPGDocument,
182
183
  listStatusMigrations: () => listStatusMigrations,
184
+ listTreePatternSummaries: () => listTreePatternSummaries,
183
185
  migrateEdge: () => migrateEdge,
184
186
  migrateNode: () => migrateNode,
185
187
  migrateNodeProperties: () => migrateNodeProperties,
@@ -193,6 +195,7 @@ __export(index_exports, {
193
195
  resolveEntityType: () => resolveEntityType,
194
196
  resolveLabel: () => resolveLabel,
195
197
  resolveSlugCollision: () => resolveSlugCollision,
198
+ resolveTreePatternEdges: () => resolveTreePatternEdges,
196
199
  ringOrderedDomainIds: () => ringOrderedDomainIds,
197
200
  rotateSlug: () => rotateSlug,
198
201
  serializeCanonical: () => serializeCanonical,
@@ -19879,6 +19882,8 @@ var UPG_TREE_PATTERNS = [
19879
19882
  label: "Opportunity Solution Tree",
19880
19883
  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).",
19881
19884
  framework_id: "opportunity-solution-tree",
19885
+ region: "discovery_research_validation",
19886
+ gap_policy: "required-children-only",
19882
19887
  anchor_type: "outcome",
19883
19888
  fallback_anchors: ["desired_outcome", "opportunity"],
19884
19889
  child_map: {
@@ -19895,6 +19900,8 @@ var UPG_TREE_PATTERNS = [
19895
19900
  label: "Objectives and Key Results",
19896
19901
  description: "Strategic themes containing objectives, each measured by its key results and the metric that quantifies them (John Doerr).",
19897
19902
  framework_id: "okr-framework",
19903
+ region: "strategy_outcomes",
19904
+ gap_policy: "required-children-only",
19898
19905
  anchor_type: "strategic_theme",
19899
19906
  fallback_anchors: ["objective"],
19900
19907
  child_map: {
@@ -19908,6 +19915,8 @@ var UPG_TREE_PATTERNS = [
19908
19915
  id: "user",
19909
19916
  label: "User chain",
19910
19917
  description: "A persona and the jobs it pursues, branching into the needs and desired outcomes behind them.",
19918
+ region: "users_needs",
19919
+ gap_policy: "required-children-only",
19911
19920
  anchor_type: "persona",
19912
19921
  fallback_anchors: ["job"],
19913
19922
  child_map: {
@@ -19920,6 +19929,8 @@ var UPG_TREE_PATTERNS = [
19920
19929
  id: "product",
19921
19930
  label: "Product breakdown",
19922
19931
  description: "The product organised into feature areas, then features, and the optional epic + user story tiers beneath them.",
19932
+ region: "product_delivery",
19933
+ gap_policy: "required-children-only",
19923
19934
  anchor_type: "product",
19924
19935
  fallback_anchors: ["feature_area", "feature"],
19925
19936
  child_map: {
@@ -19935,6 +19946,8 @@ var UPG_TREE_PATTERNS = [
19935
19946
  label: "Validation chain",
19936
19947
  description: "A hypothesis through its experiment plan, the experiment (or its runs), and the learning it produced.",
19937
19948
  framework_id: "build-measure-learn",
19949
+ region: "discovery_research_validation",
19950
+ gap_policy: "required-children-only",
19938
19951
  anchor_type: "hypothesis",
19939
19952
  fallback_anchors: ["experiment_plan", "experiment"],
19940
19953
  child_map: {
@@ -19949,6 +19962,8 @@ var UPG_TREE_PATTERNS = [
19949
19962
  id: "strategy",
19950
19963
  label: "Strategy cascade",
19951
19964
  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.",
19965
+ region: "strategy_outcomes",
19966
+ gap_policy: "required-children-only",
19952
19967
  anchor_type: "vision",
19953
19968
  fallback_anchors: ["product", "strategic_theme"],
19954
19969
  child_map: {
@@ -19965,6 +19980,8 @@ var UPG_TREE_PATTERNS = [
19965
19980
  id: "feature_areas",
19966
19981
  label: "Feature areas",
19967
19982
  description: "Feature areas and the features they contain.",
19983
+ region: "product_delivery",
19984
+ gap_policy: "all-optional",
19968
19985
  anchor_type: "feature_area",
19969
19986
  fallback_anchors: ["feature"],
19970
19987
  child_map: {
@@ -19976,6 +19993,8 @@ var UPG_TREE_PATTERNS = [
19976
19993
  id: "delivery",
19977
19994
  label: "Delivery roadmap",
19978
19995
  description: "How product work is scheduled and shipped: the roadmap and its themes/items, the releases they schedule, the features (and the changelog + bugs) those releases deliver, and the feature areas a theme spans. Optional epic + user story tiers appear on request.",
19996
+ region: "product_delivery",
19997
+ gap_policy: "all-optional",
19979
19998
  anchor_type: "roadmap",
19980
19999
  // Fallback is the product alone: a graph with no roadmap roots at the
19981
20000
  // product (product -> release -> feature), reported as anchor_resolved_from:
@@ -20004,6 +20023,8 @@ var UPG_TREE_PATTERNS = [
20004
20023
  id: "architecture",
20005
20024
  label: "Architecture",
20006
20025
  description: "The engineering platform: services and the API contracts, endpoints, schemas, queues, deployments, and dependencies they own, grouped by bounded context, with domain aggregates and their members. A DAG (a schema or queue shared by several services renders once, then as a reference).",
20026
+ region: "engineering_platform",
20027
+ gap_policy: "all-optional",
20007
20028
  anchor_type: "service",
20008
20029
  fallback_anchors: ["bounded_context"],
20009
20030
  child_map: {
@@ -20027,7 +20048,7 @@ var UPG_TREE_PATTERNS = [
20027
20048
  opt("library_dependency"),
20028
20049
  opt("feature_flag")
20029
20050
  ],
20030
- aggregate: [opt("domain_entity"), opt("value_object"), opt("command"), opt("read_model"), opt("domain_event")]
20051
+ aggregate: [opt("domain_entity"), opt("value_object"), opt("command"), opt("domain_event")]
20031
20052
  },
20032
20053
  natural_depth: 3
20033
20054
  },
@@ -20035,6 +20056,8 @@ var UPG_TREE_PATTERNS = [
20035
20056
  id: "journey",
20036
20057
  label: "User journey",
20037
20058
  description: "A user journey over time: its phases and steps, the actions within each step, and the screens those steps surface. Falls back to a user_flow when journeys are not yet mapped.",
20059
+ region: "experience_design_brand",
20060
+ gap_policy: "all-optional",
20038
20061
  anchor_type: "user_journey",
20039
20062
  fallback_anchors: ["user_flow"],
20040
20063
  child_map: {
@@ -20050,6 +20073,8 @@ var UPG_TREE_PATTERNS = [
20050
20073
  id: "design_system",
20051
20074
  label: "Design system",
20052
20075
  description: "A design system broken into its components, their nested sub-components (atom to molecule to organism), and the design tokens they consume.",
20076
+ region: "experience_design_brand",
20077
+ gap_policy: "all-optional",
20053
20078
  anchor_type: "design_system",
20054
20079
  fallback_anchors: ["design_component"],
20055
20080
  child_map: {
@@ -20065,6 +20090,43 @@ var UPG_TREE_PATTERNS_BY_ID = Object.fromEntries(
20065
20090
  function getTreePattern(id) {
20066
20091
  return UPG_TREE_PATTERNS_BY_ID[id];
20067
20092
  }
20093
+ function resolvePatternEdge(source, target) {
20094
+ for (const [id, def] of Object.entries(UPG_EDGE_CATALOG)) {
20095
+ if (def.source_type === source && def.target_type === target) {
20096
+ return { via: id, kind: def.classification };
20097
+ }
20098
+ }
20099
+ return null;
20100
+ }
20101
+ function resolveTreePatternEdges(pattern) {
20102
+ const out = [];
20103
+ for (const [parent, children] of Object.entries(pattern.child_map)) {
20104
+ for (const c of children) {
20105
+ const e = resolvePatternEdge(parent, c.type);
20106
+ out.push({ parent, child: c.type, via: e?.via ?? null, kind: e?.kind ?? null, required: !!c.required });
20107
+ }
20108
+ }
20109
+ return out;
20110
+ }
20111
+ function describeTreePattern(id) {
20112
+ const p = getTreePattern(id);
20113
+ if (!p) return void 0;
20114
+ return { ...p, fallback_anchors: [...p.fallback_anchors], edges: resolveTreePatternEdges(p) };
20115
+ }
20116
+ function listTreePatternSummaries() {
20117
+ return UPG_TREE_PATTERNS.map((p) => ({
20118
+ id: p.id,
20119
+ label: p.label,
20120
+ description: p.description,
20121
+ framework_id: p.framework_id,
20122
+ region: p.region,
20123
+ anchor_type: p.anchor_type,
20124
+ fallback_anchors: [...p.fallback_anchors],
20125
+ natural_depth: p.natural_depth,
20126
+ gap_policy: p.gap_policy,
20127
+ slot_count: Object.values(p.child_map).reduce((n, cs) => n + cs.length, 0)
20128
+ }));
20129
+ }
20068
20130
 
20069
20131
  // src/presentation/area-taxonomy.ts
20070
20132
  var UPG_AREA_TAXONOMY = [
@@ -28369,7 +28431,7 @@ function isCanonical(text) {
28369
28431
  }
28370
28432
 
28371
28433
  // src/index.ts
28372
- var UPG_VERSION = "0.9.19";
28434
+ var UPG_VERSION = "0.9.20";
28373
28435
  var UPG_FORMAT_VERSION = "0.4.0";
28374
28436
  var MARKDOWN_FORMAT_VERSION = "0.1";
28375
28437
  var UPG_TYPES = getTypes();
@@ -28527,6 +28589,7 @@ var UPG_META_COUNT = UPG_ENTITY_META.length;
28527
28589
  collectSlugsForType,
28528
28590
  compareVersions,
28529
28591
  computeBodyChecksum,
28592
+ describeTreePattern,
28530
28593
  edgeCarriesProperties,
28531
28594
  evaluateAntiPatterns,
28532
28595
  findInvalidStatusMigrationTargets,
@@ -28594,6 +28657,7 @@ var UPG_META_COUNT = UPG_ENTITY_META.length;
28594
28657
  isSubSequenceStep,
28595
28658
  isUPGDocument,
28596
28659
  listStatusMigrations,
28660
+ listTreePatternSummaries,
28597
28661
  migrateEdge,
28598
28662
  migrateNode,
28599
28663
  migrateNodeProperties,
@@ -28607,6 +28671,7 @@ var UPG_META_COUNT = UPG_ENTITY_META.length;
28607
28671
  resolveEntityType,
28608
28672
  resolveLabel,
28609
28673
  resolveSlugCollision,
28674
+ resolveTreePatternEdges,
28610
28675
  ringOrderedDomainIds,
28611
28676
  rotateSlug,
28612
28677
  serializeCanonical,